SuiteScript 2.0 MapReduce脚本无法创建交易问题排查与修复
NetSuite MapReduce脚本Reduce阶段异常问题及修复
问题描述
我编写的NetSuite MapReduce脚本在进入Reduce阶段前运行正常,但Reduce阶段出现异常。日志调试执行到以下代码后停止,无任何日志输出也无错误提示:
var salesOrderId = salesOrderRec.save(); if (salesOrderId) { log.debug("Sales Order ID", salesOrderId); } else { log.debug("Failed to create Sales Order"); } } var salesOrderId = salesOrderRec.save(); log.debug("Sales Order ID", salesOrderId);
我尝试过调整代码(比如将销售订单保存操作移至循环内),但仍无法解决问题,求指出代码中的问题。
原问题脚本
/** *@NApiVersion 2.x *@NScriptType MapReduceScript */ define(["N/search", "N/record"], function (search, record) { function getInputData() { var salesorderSearchObj = search.create({ type: "salesorder", filters: [ ["type", "anyof", "SalesOrd"], "AND", ["mainline", "is", "F"], "AND", ["taxline", "is", "F"], "AND", ["shipping", "is", "F"], "AND", ["item", "noneof", "@NONE@"], "AND", ["status", "anyof", "SalesOrd:F"], ], columns: [ search.createColumn({ name: "tranid", label: "Document Number" }), search.createColumn({ name: "entity", label: "Name" }), search.createColumn({ name: "item", label: "Item" }), search.createColumn({ name: "rate", label: "Item Rate" }), search.createColumn({ name: "quantity", label: "Quantity" }), search.createColumn({ name: "amount", label: "Amount" }), search.createColumn({ name: "taxamount", label: "Amount (Tax)" }), search.createColumn({ name: "grossamount", label: "Amount (Gross)" }), search.createColumn({ name: "taxcode", label: "Tax Item" }), search.createColumn({ name: "memo", label: "Memo" }), search.createColumn({ name: "lineuniquekey", label: "Line Unique Key", }), ], }); return salesorderSearchObj; } /** * @param {MapReduceContext.map} context */ function map(context) { var result = JSON.parse(context.value); log.debug("result", result); const entityValue = result.values.entity.value; const itemValue = result.values.item.value; const quantityValue = result.values.quantity; const rateValue = result.values.rate; const taxValue = result.values.taxamount; const amountValue = result.values.amount; const taxcodeValue = result.values.taxcode.value; // 存储商品属性的对象 const itemObj = { item: itemValue, quantity: quantityValue, rate: rateValue, amount: amountValue, taxamount: taxValue, taxcode: taxcodeValue, }; // 按客户分组商品 const entityItems = {}; if (entityValue in entityItems) { entityItems[entityValue].push(itemObj); } else { entityItems[entityValue] = [itemObj]; } context.write({ key: entityValue, value: JSON.stringify(entityItems), }); log.debug("map context debug", context); } /** * @param {MapReduceContext.reduce} context */ function reduce(context) { log.debug("reduce context", context); var values = context.values; log.debug("context.values", values); var entity = context.key; log.debug("context.key", entity); log.debug("values.length", values.length) for (var i = 0; i < values.length; i++) { var jsonStr = values[i]; log.debug("jsonstr", jsonStr); var entityData = JSON.parse(jsonStr); var salesOrderRec = record.create({ type: record.Type.SALES_ORDER, isDynamic: true, }); log.debug({ title: "salesOrderRec", details: salesOrderRec, }); for (var entity in entityData) { if (entityData.hasOwnProperty(entity)) { var items = entityData[entity]; for (var j = 0; j < items.length; j++) { var itemData = items[j]; // 提取商品属性 var item = itemData.item; var quantity = itemData.quantity; var rate = itemData.rate; var amount = itemData.amount; var taxamount = itemData.taxamount; var taxcode = itemData.taxcode; log.debug("item:", item); log.debug("quantity:", quantity); log.debug("rate:", rate); log.debug("amount:", amount); log.debug("taxamt:", taxamount); salesOrderRec.setValue({ fieldId: "entity", value: entity, // 设置客户ID }); salesOrder.selectNewLine({ sublistId: "item", }); salesOrder.setCurrentSublistValue({ sublistId: "item", fieldId: "item", value: item, }); salesOrder.setCurrentSublistValue({ sublistId: "item", fieldId: "quantity", value: quantity, }); // 此处可补充设置其他行字段 salesOrderRec.commitLine({ sublistId: "item", }); } } } // 保存销售订单 var salesOrderId = salesOrderRec.save(); if (salesOrderId) { log.debug("Sales Order ID", salesOrderId); } else { log.debug("Failed to create Sales Order"); } } var salesOrderId = salesOrderRec.save(); log.debug("Sales Order ID", salesOrderId); } /** * @param {MapReduceContext.summarize} context */ function summarize(summary) {} return { getInputData: getInputData, map: map, reduce: reduce, summarize: summarize, }; });
问题关键原因
- 变量名不统一:创建的记录对象为
salesOrderRec,但操作子列表时错误使用了未定义的salesOrder变量,触发静默异常导致脚本终止。 - 重复创建订单:在
values循环内每次迭代都新建销售订单,同一客户的每个商品条目会生成独立订单,不符合分组需求。 - 重复保存操作:循环结束后再次调用
save(),此时salesOrderRec仅指向最后一次创建的对象,且重复保存无意义。 - 缺少异常捕获:未对记录操作添加异常捕获逻辑,无法定位错误原因。
可正常运行的修复版本
/** * @NApiVersion 2.x * @NScriptType MapReduceScript */ define(["N/search", "N/record"], function (search, record) { function getInputData() { var invoiceSearchObj = search.create({ type: "invoice", filters: [ ["type", "anyof", "CustInvc"], "AND", ["mainline", "is", "F"], "AND", ["taxline", "is", "F"], "AND", ["item", "noneof", "@NONE@"], "AND", ["item.revenuerecognitionrule", "anyof", "@NONE@"], "AND", ["currency", "anyof", "5"], "AND", ["datecreated", "within", "thisfiscalquarter"], ], columns: [ search.createColumn({ name: "internalid", join: "customerMain", label: "客户(主行):内部ID", }), search.createColumn({ name: "entity", label: "名称" }), search.createColumn({ name: "tranid", label: "单据编号" }), search.createColumn({ name: "item", label: "商品" }), search.createColumn({ name: "trandate", label: "日期" }), search.createColumn({ name: "amount", label: "金额" }), search.createColumn({ name: "taxamount", label: "税额" }), search.createColumn({ name: "rate", label: "商品单价" }), search.createColumn({ name: "quantity", label: "数量" }), search.createColumn({ name: "pricelevel", label: "价格等级" }), search.createColumn({ name: "taxcode", label: "税项" }), ], }); return invoiceSearchObj; } function map(context) { var result = JSON.parse(context.value); log.debug("result", result); const entityValue = result.values.entity.value; const itemValue = result.values.item.value; const quantityValue = result.values.quantity; const rateValue = result.values.rate; const taxValue = result.values.taxamount; const amountValue = result.values.amount; const taxcodeValue = result.values.taxcode.value; const itemObj = { item: itemValue, quantity: quantityValue, rate: rateValue, amount: amountValue, taxamount: taxValue, taxcode: taxcodeValue, }; const entityItems = {}; if (entityValue in entityItems) { entityItems[entityValue].push(itemObj); } else { entityItems[entityValue] = [itemObj]; } context.write({ key: entityValue, value: JSON.stringify(entityItems), }); log.debug("map context debug", context); } function reduce(context) { log.debug("reduce context", context); var values = context.values; log.debug("context.values", values); var entity = context.key; log.debug("context.key", entity); var salesOrderRec; // 在循环外声明订单对象 for (var i = 0; i < values.length; i++) { var jsonStr = values[i]; log.debug("jsonstr", jsonStr); var entityData = JSON.parse(jsonStr); for (var entity in entityData) { if (entityData.hasOwnProperty(entity)) { var items = entityData[entity]; for (var j = 0; j < items.length; j++) { var itemData = items[j]; // 提取商品属性 var item = itemData.item; var quantity = itemData.quantity; var rate = itemData.rate; var amount = itemData.amount; var taxamount = itemData.taxamount; var taxcode = itemData.taxcode; log.debug("item:", item); log.debug("quantity:", quantity); log.debug("rate:", rate); log.debug("amount:", amount); log.debug("taxamt:", taxamount); try { // 仅当订单未创建时初始化 if (!salesOrderRec) { salesOrderRec = record.create({ type: record.Type.SALES_ORDER, isDynamic: true, }); salesOrderRec.setValue({ fieldId: "entity", value: entity, // 设置客户ID }); salesOrderRec.setValue({ fieldId: "memo", value: JSON.stringify(item), }); } salesOrderRec.selectNewLine({ sublistId: "item", }); salesOrderRec.setCurrentSublistValue({ sublistId: "item", fieldId: "item", value: item, }); salesOrderRec.setCurrentSublistValue({ sublistId: "item", fieldId: "quantity", value: quantity, }); // 此处可补充设置其他行字段 salesOrderRec.commitLine({ sublistId: "item", }); } catch (e) { log.error({ title: "创建销售订单出错: ", details: e.message, }); } } } } } // 所有条目处理完成后统一保存订单 if (salesOrderRec) { var salesOrderId = salesOrderRec.save(); if (salesOrderId) { log.debug("销售订单ID", salesOrderId); } else { log.debug("创建销售订单失败"); } } } return { getInputData: getInputData, map: map, reduce: reduce, }; });
修复说明
- 统一变量名:将所有操作记录的变量统一为
salesOrderRec,避免未定义变量错误。 - 延迟创建订单:仅在首次处理客户条目时创建销售订单,同一客户的所有商品都添加到同一订单的子列表中。
- 移除重复保存:仅在所有商品条目处理完成后,执行一次订单保存操作。
- 添加异常捕获:对记录操作包裹
try-catch块,捕获并输出错误信息,便于问题排查。
内容的提问来源于stack exchange,提问作者Vernita
相关产品推荐
相关产品推荐

