SuiteScript 2.0 Map/Reduce创建含新Item销售订单报错咨询
我正在编写SuiteScript 2.0的Map/Reduce脚本,流程是通过API获取订单列表后:
- 先检查客户是否存在,存在则直接创建销售订单
- 不存在则先创建客户,再创建包含新商品的销售订单
但目前遇到报错:
"You have entered an Invalid Field Value 5260365201455 for the following field: item"
我原本以为创建销售订单时脚本会同步创建商品,现在已经更新了创建商品的函数,代码如下:
// updated function for creating item function createChildItems(itemName) { log.debug({ title: 'createChildItems', details: 'child item' }); var item = record.create({ type: record.Type.INVENTORY_ITEM, isDynamic: true }); item.setValue({ fieldId: 'itemid', value:itemName }); var itemId = item.save({ ignoreMandatoryFields: true }); return itemId; }
后续创建销售订单的代码:
var salesOrder = record.create({ type: record.Type.SALES_ORDER, isDynamic: true, defaultValues: { entity: customer.id } }); salesOrder.setValue({ fieldId: 'trandate', value: new Date(), ignoreFieldChange: true }); var subrec = salesOrder.getSubrecord({ fieldId: 'shippingaddress' }); subrec.setValue({ fieldId: 'addr1', value: order.shipping_address.address1 }); subrec.setValue({ fieldId: 'city', value: order.shipping_address.city }); subrec.setValue({ fieldId: 'state', value: order.shipping_address.province }); subrec.setValue({ fieldId: 'zip', value: order.shipping_address.zip }); subrec.setValue({ fieldId: 'addressee', value: order.shipping_address.first_name }); subrec.setValue({ fieldId: 'attention', value: order.shipping_address.first_name }); salesOrder.selectNewLine({ sublistId: 'item' }); var items = order.line_items; // this list of items are in array and all are new items, dos not exist in current netsuite items.forEach(function (item) { var internalID = createChildItems(item.name) // getting item internal ID here salesOrder.setCurrentSublistValue({ sublistId: 'item', fieldId: 'item', value: internalID // item.id.toString() // also tried without toString(), and tried with value of existing item }); salesOrder.setCurrentSublistValue({ sublistId: 'item', fieldId: 'quantity', value: item.quantity }); salesOrder.setCurrentSublistValue({ sublistId: 'item', fieldId: 'price', value: item.price }); salesOrder.setCurrentSublistValue({ sublistId: 'item', fieldId: 'rate', value: item.price }); salesOrder.commitLine({ sublistId: 'item' }); }); var id = salesOrder.save({ ignoreMandatoryFields: false });
请问是否必须先创建这些商品(Item),再创建销售订单?
没错,你猜的是对的——必须先创建商品记录,再将其关联到销售订单。NetSuite的销售订单行项目只能引用已经存在且处于有效状态的商品内部ID,无法在创建销售订单的同时自动生成商品记录,这是你遇到报错的核心原因。
再深入看你的代码,报错里的无效ID大概率是因为你创建商品时的两个问题:
1. 忽略必填字段导致商品状态无效
你在createChildItems里用了ignoreMandatoryFields: true来保存商品,这会导致创建出的商品缺少NetSuite要求的关键字段(比如库存单位unit、商品类型的默认设置、是否激活等)。这类商品虽然能拿到内部ID,但实际上处于未完成/无效状态,无法被关联到销售订单,所以NetSuite会判定这个ID无效。
2. 动态模式下商品字段设置不完整
即使是Inventory Item,动态模式下创建时也需要设置一些核心字段才能让商品处于可交易状态,比如unit(比如设置为“Each”)、isactive(默认可能是true,但最好显式设置)。
具体修正步骤
步骤1:修复商品创建函数
去掉ignoreMandatoryFields,补充必填字段,确保商品创建后是有效的:
function createChildItems(itemName) { log.debug({ title: 'createChildItems', details: `Creating item: ${itemName}` }); var item = record.create({ type: record.Type.INVENTORY_ITEM, isDynamic: true }); // 设置核心必填字段 item.setValue({ fieldId: 'itemid', value: itemName }); item.setValue({ fieldId: 'unit', value: 'Each' }); // 根据你的业务需求调整单位 item.setValue({ fieldId: 'isactive', value: true }); // 如果还有其他必填字段(比如Item Category、Location等),需要根据你的NetSuite配置补充 var itemId = item.save(); // 去掉ignoreMandatoryFields,确保字段完整 // 可选:验证商品是否创建成功 var loadedItem = record.load({ type: record.Type.INVENTORY_ITEM, id: itemId }); log.debug({ title: 'Created Item', details: `ID: ${itemId}, Name: ${loadedItem.getValue({fieldId: 'itemid'})}` }); return itemId; }
步骤2:优化流程,避免循环内频繁创建记录
在Map/Reduce脚本里,循环内频繁调用record.create和save容易触发API调用限制,建议先批量创建所有需要的商品,再处理销售订单:
// 先批量创建所有商品,存储名称到ID的映射 var itemIdMap = {}; order.line_items.forEach(function(item) { if (!itemIdMap[item.name]) { itemIdMap[item.name] = createChildItems(item.name); } }); // 再创建销售订单并关联商品 var salesOrder = record.create({ type: record.Type.SALES_ORDER, isDynamic: true, defaultValues: { entity: customer.id } }); salesOrder.setValue({ fieldId: 'trandate', value: new Date(), ignoreFieldChange: true }); // ... 省略 shipping address 设置代码 ... order.line_items.forEach(function(item) { salesOrder.selectNewLine({ sublistId: 'item' }); var internalID = itemIdMap[item.name]; salesOrder.setCurrentSublistValue({ sublistId: 'item', fieldId: 'item', value: internalID }); salesOrder.setCurrentSublistValue({ sublistId: 'item', fieldId: 'quantity', value: item.quantity }); salesOrder.setCurrentSublistValue({ sublistId: 'item', fieldId: 'rate', value: item.price }); // 注意:price字段通常关联价格等级,不需要和rate同时设置,避免冲突 salesOrder.commitLine({ sublistId: 'item' }); }); var id = salesOrder.save({ ignoreMandatoryFields: false });
步骤3:验证ID有效性
如果还是报错,可以在设置行项目前打印internalID的值,确认它是一个有效的数字(NetSuite内部ID是数字类型,不需要转字符串),并且通过NetSuite后台搜索这个ID,确认商品确实存在且处于激活状态。
内容的提问来源于stack exchange,提问作者Mangrio

