You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NetSuite数据集内部代码转文本及CSV结果邮件调度脚本实现

NetSuite数据集API(SuiteScript 2.1)问题与解决方案

问题背景

我用SuiteScript 2.1的N/dataset API获取现有数据集结果,返回的JSON包含PO状态、账单状态、子产品、子公司等字段,但部分字段返回内部代码而非可读文本:

  • PO状态返回“F”或“D”(应为“部分收货”这类友好文本)
  • 账单状态返回“A”(应为“未结”)
  • 子产品返回20(应为子产品名称)
  • 子公司返回2/7(内部ID,应为子公司名称)
    由于未来可能新增值,无法用静态映射处理转换。

已尝试操作

  • 用row.values[index]提取字段值
  • 寻找getText()方法,但数据集API不支持该方法
  • 检查数据集查询的关联设置,确认未影响值的返回

预期与实际结果

字段预期结果实际结果
PO状态Purchase Order: Partially receivedD
账单状态Bill:OpenA
子产品Product Name20
子公司Subsidiary Name2

核心问题

  1. 为什么数据集返回内部代码(F/D、A、2/7)而非可读文本?
  2. 如何动态将这些内部值转换为对应的文本标签?
  3. 如何通过调度脚本将数据集结果转为CSV并邮件发送?

问题解答

1. 为什么返回内部代码?

数据集API默认返回字段的原始存储值:

  • 枚举类字段(如PO状态、账单状态)存储的是枚举代码,数据集直接返回代码而非显示文本
  • 关联记录字段(如子产品、子公司)存储的是记录内部ID,数据集返回ID而非记录名称
    这是因为数据集的设计定位是数据导出、分析场景,优先保证数据原始性,而非前端展示的友好性。

2. 动态转换内部值为可读文本的方案

根据字段类型分两种处理方式:

枚举类字段(PO状态、账单状态)

用N/record API加载对应记录类型,获取字段的所有选项值,动态建立代码到文本的映射:

// 获取枚举字段的选项映射
function getEnumOptions(recordType, fieldId) {
    const field = record.getField({
        type: recordType,
        fieldId: fieldId
    });
    const optionMap = {};
    field.options.forEach(opt => {
        optionMap[opt.value] = opt.text;
    });
    return optionMap;
}

// 示例:获取采购订单状态的映射
const poStatusMap = getEnumOptions(record.Type.PURCHASE_ORDER, 'status');
// 使用时:poStatusMap['D'] 即可拿到对应文本

关联记录字段(子产品、子公司)

用N/search API批量查询记录名称,避免单次加载记录的性能损耗:

// 批量获取关联记录的名称映射
function getRecordNameMap(recordType, ids) {
    const nameMap = {};
    if (!ids || ids.length === 0) return nameMap;
    
    // 去重ID,避免重复查询
    const uniqueIds = [...new Set(ids)];
    
    const searchObj = search.create({
        type: recordType,
        filters: [['internalid', 'anyof', uniqueIds]],
        columns: ['internalid', 'name']
    });
    
    searchObj.run().each(result => {
        const id = result.getValue('internalid');
        const name = result.getValue('name');
        nameMap[id] = name;
        return true;
    });
    return nameMap;
}

// 示例:批量获取子公司名称映射
const subsidiaryIds = [2,7];
const subsidiaryNameMap = getRecordNameMap(record.Type.SUBSIDIARY, subsidiaryIds);
// 使用时:subsidiaryNameMap['2'] 拿到子公司名称

3. 调度脚本实现CSV邮件发送

整合上述转换逻辑,加上CSV生成和邮件发送步骤:

define(['N/dataset', 'N/record', 'N/search', 'N/file', 'N/email', 'N/runtime'], 
function(dataset, record, search, file, email, runtime) {

    function execute(context) {
        // 1. 加载数据集并获取结果
        const myDataset = dataset.load({ id: 'custdataset70' });
        const results = myDataset.run();
        const iterator = results.iterator();
        const rows = [];
        
        // 2. 预加载需要的映射表
        const poStatusMap = getEnumOptions(record.Type.PURCHASE_ORDER, 'status');
        const billingStatusMap = getEnumOptions(record.Type.PURCHASE_ORDER, 'billingstatus');
        // 先收集所有需要查询的关联ID(请根据实际字段顺序调整索引)
        const productIds = [];
        const subsidiaryIds = [];
        
        // 第一遍遍历收集ID
        iterator.each(function(result) {
            const row = result.value;
            productIds.push(row.values[2]); // 假设Sub Product是第3个字段(索引2)
            subsidiaryIds.push(row.values[3]); // 假设Subsidiary是第4个字段(索引3)
            rows.push(row);
            return true;
        });
        
        // 批量获取名称映射
        const productNameMap = getRecordNameMap(record.Type.INVENTORY_ITEM, productIds);
        const subsidiaryNameMap = getRecordNameMap(record.Type.SUBSIDIARY, subsidiaryIds);
        
        // 3. 转换结果为可读文本并构造CSV内容
        let csvContent = "PO Status,Billing Status,Sub Product,Subsidiary\n";
        rows.forEach(row => {
            const poStatus = poStatusMap[row.values[0]] || row.values[0];
            const billingStatus = billingStatusMap[row.values[1]] || row.values[1];
            const subProduct = productNameMap[row.values[2]] || row.values[2];
            const subsidiary = subsidiaryNameMap[row.values[3]] || row.values[3];
            // 处理带特殊字符的内容,避免CSV格式错误
            csvContent += `"${poStatus.replace(/"/g, '""')}","${billingStatus.replace(/"/g, '""')}","${subProduct.replace(/"/g, '""')}","${subsidiary.replace(/"/g, '""')}"\n`;
        });
        
        // 4. 创建CSV文件
        const csvFile = file.create({
            name: 'Dataset_Results.csv',
            fileType: file.Type.CSV,
            contents: csvContent,
            folder: -15 // 临时文件夹,可替换为实际文件夹ID
        });
        const fileId = csvFile.save();
        
        // 5. 发送邮件(请替换为实际收件人ID)
        const senderId = runtime.getCurrentUser().id;
        const recipientIds = [123]; 
        email.send({
            author: senderId,
            recipients: recipientIds,
            subject: 'NetSuite数据集结果CSV',
            body: '附件是最新的数据集结果,请查收。',
            attachments: [fileId]
        });
    }

    // 辅助函数:获取枚举字段选项映射
    function getEnumOptions(recordType, fieldId) {
        const field = record.getField({
            type: recordType,
            fieldId: fieldId
        });
        const optionMap = {};
        field.options.forEach(opt => {
            optionMap[opt.value] = opt.text;
        });
        return optionMap;
    }

    // 辅助函数:批量获取关联记录名称映射
    function getRecordNameMap(recordType, ids) {
        const nameMap = {};
        if (!ids || ids.length === 0) return nameMap;
        
        const uniqueIds = [...new Set(ids)];
        
        const searchObj = search.create({
            type: recordType,
            filters: [['internalid', 'anyof', uniqueIds]],
            columns: ['internalid', 'name']
        });
        
        searchObj.run().each(result => {
            const id = result.getValue('internalid');
            const name = result.getValue('name');
            nameMap[id] = name;
            return true;
        });
        return nameMap;
    }

    return {
        execute: execute
    };
});

内容的提问来源于stack exchange,提问作者Maira S

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 08:20:07