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

如何通过SuiteScript完成Transfer Order并将状态更新为Received?

问题:SuiteScript处理调拨单(Transfer Order)无法更新状态至“Received”

我一直在尝试用SuiteScript完成调拨单的履行,但始终没成功。不确定是否需要同时创建Item Fulfillment和Item Receipt,查了很多地方答案都不一致。我的需求是脚本能履行调拨单上所有物料的数量,并把调拨单状态更新为“Received”。

目前脚本已经能成功创建Item Fulfillment,调拨单物料的“complete”数量有更新,但“fulfilled”数量没变化,状态一直停留在“Pending Fulfillment”。

测试代码如下:

require(['N/record', 'N/search', 'N/log'], function(record, search, log) {
    try {
            var transferOrderId = 533010;

            var transferOrder = record.load({
                type: record.Type.TRANSFER_ORDER,
                id: transferOrderId
            });
            var transferOrderType = transferOrder.type;

            // Ensure the record being processed is a Transfer Order
            if (transferOrderType !== 'transferorder') {
                log.debug('Not a Transfer Order', 'Skipping processing.');
                return;
            }

            // ********** Item Fulfillment Logic **********
            // Check if an Item Fulfillment already exists for the Transfer Order
            var fulfillmentSearch = search.create({
                type: record.Type.ITEM_FULFILLMENT,
                filters: [
                    ['createdfrom', 'is', transferOrderId]
                ],
                columns: ['internalid']
            });

            var fulfillmentResults = fulfillmentSearch.run().getRange({ start: 0, end: 1 });

            if (fulfillmentResults && fulfillmentResults.length > 0) {
                log.debug('Item Fulfillment Exists', 'Item Fulfillment already exists for Transfer Order ID: ' + transferOrderId);
            } else {
                // Transform the Transfer Order to an Item Fulfillment
                var itemFulfillment = record.transform({
                    fromType: record.Type.TRANSFER_ORDER,
                    fromId: transferOrderId,
                    toType: record.Type.ITEM_FULFILLMENT,
                    isDynamic: true
                });

                // Iterate over the lines to ensure quantities are properly set
                var fulfillmentLineCount = itemFulfillment.getLineCount({ sublistId: 'item' });

                for (var i = 0; i < fulfillmentLineCount; i++) {
                    itemFulfillment.selectLine({ sublistId: 'item', line: i });

                    // Set the quantity to fulfill as the quantity remaining to be fulfilled
                    var quantityToFulfill = itemFulfillment.getCurrentSublistValue({
                        sublistId: 'item',
                        fieldId: 'quantityremaining'
                    });

                    itemFulfillment.setCurrentSublistValue({
                        sublistId: 'item',
                        fieldId: 'quantity',
                        value: quantityToFulfill
                    });

                    itemFulfillment.commitLine({ sublistId: 'item' });
                }

                // Save the Item Fulfillment
                var itemFulfillmentId = itemFulfillment.save();

                log.debug('Item Fulfillment Created', 'Item Fulfillment ID: ' + itemFulfillmentId);
            }

            // ********** Item Receipt Logic **********
            // Check if an Item Receipt already exists for the Transfer Order
            var receiptSearch = search.create({
                type: record.Type.ITEM_RECEIPT,
                filters: [
                    ['createdfrom', 'is', transferOrderId]
                ],
                columns: ['internalid']
            });

            var receiptResults = receiptSearch.run().getRange({ start: 0, end: 1 });

            if (receiptResults && receiptResults.length > 0) {
                log.debug('Item Receipt Exists', 'Item Receipt already exists for Transfer Order ID: ' + transferOrderId);
            } else {
                // Transform the Transfer Order to an Item Receipt
                var itemReceipt = record.transform({
                    fromType: record.Type.TRANSFER_ORDER,
                    fromId: transferOrderId,
                    toType: record.Type.ITEM_RECEIPT,
                    isDynamic: true
                });

                // Iterate over the lines to ensure quantities are properly set
                var receiptLineCount = itemReceipt.getLineCount({ sublistId: 'item' });

                for (var i = 0; i < receiptLineCount; i++) {
                    itemReceipt.selectLine({ sublistId: 'item', line: i });

                    // Set the quantity to receive as the quantity remaining to be received
                    var quantityRemaining = itemReceipt.getCurrentSublistValue({
                        sublistId: 'item',
                        fieldId: 'quantityremaining'
                    });

                    itemReceipt.setCurrentSublistValue({
                        sublistId: 'item',
                        fieldId: 'quantity',
                        value: quantityRemaining
                    });

                    itemReceipt.commitLine({ sublistId: 'item' });
                }

                // Save the Item Receipt
                var itemReceiptId = itemReceipt.save();

                log.debug('Item Receipt Created', 'Item Receipt ID: ' + itemReceiptId);
            }

        } catch (e) {
            log.error('Error Processing Transfer Order', e);
        }
});

解决方案

1. 调拨单流转核心逻辑

NetSuite中,调拨单的完整履行必须同时执行Item Fulfillment(源仓库出库)和Item Receipt(目标仓库入库):

  • Item Fulfillment:完成源仓库出库,更新调拨单fulfilled数量,将状态从Pending Fulfillment推进至Partially Fulfilled或Fulfilled
  • Item Receipt:完成目标仓库入库,更新调拨单received数量,最终将状态变为Received

你的脚本框架是对的,但问题出在Item Fulfillment的字段处理细节上。

2. 代码修复点

(1)动态模式的字段获取问题

动态模式下,quantityremaining字段的读取存在不稳定情况,建议切换为静态模式处理子列表,避免字段加载顺序或值映射的问题。

(2)增加状态前置检查

避免对已完成的调拨单重复执行操作,提升脚本效率。

3. 修正后的完整代码

require(['N/record', 'N/search', 'N/log'], function(record, search, log) {
    try {
        var transferOrderId = 533010;

        // 加载调拨单并检查当前状态
        var transferOrder = record.load({
            type: record.Type.TRANSFER_ORDER,
            id: transferOrderId,
            isDynamic: false
        });
        
        var currentStatus = transferOrder.getValue({fieldId: 'status'});
        log.debug('当前调拨单状态', currentStatus);
        
        // 已完成则直接跳过
        if (currentStatus === 'Received') {
            log.debug('无需处理', '调拨单ID: ' + transferOrderId + ' 已处于Received状态');
            return;
        }

        // ********** 处理Item Fulfillment **********
        var fulfillmentSearch = search.create({
            type: record.Type.ITEM_FULFILLMENT,
            filters: [['createdfrom', 'is', transferOrderId]],
            columns: ['internalid']
        });
        var fulfillmentResults = fulfillmentSearch.run().getRange({start: 0, end: 1});

        if (!fulfillmentResults || fulfillmentResults.length === 0) {
            // 使用静态模式转换,避免动态模式的字段问题
            var itemFulfillment = record.transform({
                fromType: record.Type.TRANSFER_ORDER,
                fromId: transferOrderId,
                toType: record.Type.ITEM_FULFILLMENT,
                isDynamic: false
            });

            // 设置每行履行数量为调拨单原始数量
            var lineCount = itemFulfillment.getLineCount({sublistId: 'item'});
            for (var i = 0; i < lineCount; i++) {
                var qty = itemFulfillment.getSublistValue({
                    sublistId: 'item',
                    fieldId: 'quantity',
                    line: i
                });
                itemFulfillment.setSublistValue({
                    sublistId: 'item',
                    fieldId: 'quantity',
                    line: i,
                    value: qty
                });
            }

            var itemFulfillmentId = itemFulfillment.save({enableSourcing: true, ignoreMandatoryFields: false});
            log.debug('Item Fulfillment创建成功', 'ID: ' + itemFulfillmentId);
        } else {
            log.debug('Item Fulfillment已存在', '调拨单ID: ' + transferOrderId);
        }

        // ********** 处理Item Receipt **********
        var receiptSearch = search.create({
            type: record.Type.ITEM_RECEIPT,
            filters: [['createdfrom', 'is', transferOrderId]],
            columns: ['internalid']
        });
        var receiptResults = receiptSearch.run().getRange({start: 0, end: 1});

        if (!receiptResults || receiptResults.length === 0) {
            // 使用静态模式转换
            var itemReceipt = record.transform({
                fromType: record.Type.TRANSFER_ORDER,
                fromId: transferOrderId,
                toType: record.Type.ITEM_RECEIPT,
                isDynamic: false
            });

            var receiptLineCount = itemReceipt.getLineCount({sublistId: 'item'});
            for (var j = 0; j < receiptLineCount; j++) {
                var recQty = itemReceipt.getSublistValue({
                    sublistId: 'item',
                    fieldId: 'quantity',
                    line: j
                });
                itemReceipt.setSublistValue({
                    sublistId: 'item',
                    fieldId: 'quantity',
                    line: j,
                    value: recQty
                });
            }

            var itemReceiptId = itemReceipt.save({enableSourcing: true, ignoreMandatoryFields: false});
            log.debug('Item Receipt创建成功', 'ID: ' + itemReceiptId);
        } else {
            log.debug('Item Receipt已存在', '调拨单ID: ' + transferOrderId);
        }

        // 验证最终状态
        var updatedTO = record.load({
            type: record.Type.TRANSFER_ORDER,
            id: transferOrderId
        });
        log.debug('最终调拨单状态', updatedTO.getValue({fieldId: 'status'}));

    } catch (e) {
        log.error('处理失败', e.message + '\n' + e.stack);
    }
});

4. 关键说明

  • 静态模式优势:静态模式下子列表字段的读取和设置更稳定,不会出现动态模式中字段未加载或值异常的情况
  • 保存参数配置:enableSourcing: true让系统自动填充关联字段,ignoreMandatoryFields: false确保必填字段合规
  • 状态校验:前置状态检查避免无效操作,同时可以在脚本末尾添加状态验证,确认处理结果

内容的提问来源于stack exchange,提问作者Jordan van Zyl

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 00:53:12