PAYATHON 2026

NetSuite SuiteScript 2.0 获取付款关联的全部发票

支付阿杰

结论

search.Result.getValue() 只能返回单个值,N/search.Result 也没有用于读取 joined column 多个值的 getValues() 方法。因此,当 appliedToTransaction.internalid 在序列化结果中是数组时,getValue() 可能只返回第一项。

如果要从当前 Result 中取出全部值,可以先将其序列化,再读取 values['appliedToTransaction.internalid'],最后提取各项的 value:

var rawResult = JSON.parse(JSON.stringify(result));
var appliedItems =
    rawResult.values['appliedToTransaction.internalid'] || [];

var appliedToInvoiceIds = (Array.isArray(appliedItems)
    ? appliedItems
    : [appliedItems]
).map(function (item) {
    return typeof item === 'object' ? item.value : item;
});

得到的结果是:

['2676', '2658']

但序列化后得到的 values 结构并不是 N/search 最稳妥的公开取值接口。对于需要长期运行的生产代码,更可靠的办法是单独搜索发票与付款的关联关系。

为什么 getValue() 只返回一个值

search.Result.getValue() 用于读取某个搜索结果列的单个值,例如:

result.getValue({
    name: 'internalid',
    join: 'appliedToTransaction'
});

即使底层序列化结果是数组,它也不会自动返回 JavaScript 数组。getText() 同样只能返回单个列值对应的显示文本,不是多值接口。

所以,下面两种情况可以同时出现:

  • 调试器或 JSON.stringify(result) 显示 joined column 内部有多个项目。
  • result.getValue(...) 只返回其中一个值。

N/search.Result 没有下面这样的标准方法:

result.getValues(...); // N/search.Result 没有这个方法

直接从当前结果中提取全部 ID

如果需要继续使用现有搜索,可以同时处理数组、单值和空值:

paymentSearch.run().each(function (result) {
    var serializedResult = JSON.parse(JSON.stringify(result));

    var joinedValue =
        serializedResult.values['appliedToTransaction.internalid'];

    var joinedItems;

    if (!joinedValue) {
        joinedItems = [];
    } else if (Array.isArray(joinedValue)) {
        joinedItems = joinedValue;
    } else {
        joinedItems = [joinedValue];
    }

    var appliedToInvoiceIds = joinedItems
        .map(function (item) {
            if (item && typeof item === 'object') {
                return item.value;
            }

            return item;
        })
        .filter(function (id) {
            return id !== null && id !== undefined && id !== '';
        });

    log.debug({
        title: 'Applied invoice IDs for payment ' + result.id,
        details: appliedToInvoiceIds
    });

    return true;
});

如果后续代码需要数值类型,可以显式转换:

var numericInvoiceIds = appliedToInvoiceIds.map(function (id) {
    return Number(id);
});

NetSuite 搜索 API 通常以字符串形式返回 internal ID,因此不转换也可以。将这些 ID 用于 ANYOF 等搜索条件时,保留字符串形式通常更方便。

更适合生产环境的做法:单独搜索关联发票

序列化后的 result.values 结构可能是实现细节。生产代码可以改用以下流程:

  1. 查询指定时间范围内更新过的付款。
  2. 收集付款的 internal ID。
  3. 以发票为搜索主体,通过 applyingTransaction 找到对应的付款。
  4. 按付款 ID 对结果分组。

示例:

var paymentIds = [];

paymentSearch.run().each(function (result) {
    paymentIds.push(result.id);
    return true;
});

var invoiceIdsByPaymentId = {};

if (paymentIds.length > 0) {
    var invoiceSearch = search.create({
        type: search.Type.INVOICE,
        filters: [
            ['mainline', search.Operator.IS, 'T'],
            'and',
            ['applyingtransaction.internalid',
                search.Operator.ANYOF,
                paymentIds]
        ],
        columns: [
            'internalid',
            search.createColumn({
                name: 'internalid',
                join: 'applyingTransaction'
            })
        ]
    });

    invoiceSearch.run().each(function (result) {
        var invoiceId = result.getValue({
            name: 'internalid'
        });

        var paymentId = result.getValue({
            name: 'internalid',
            join: 'applyingTransaction'
        });

        if (!invoiceIdsByPaymentId[paymentId]) {
            invoiceIdsByPaymentId[paymentId] = [];
        }

        if (invoiceIdsByPaymentId[paymentId].indexOf(invoiceId) === -1) {
            invoiceIdsByPaymentId[paymentId].push(invoiceId);
        }

        return true;
    });
}

最终得到的数据结构类似:

{
    "25911": ["2676", "2658"]
}

这样,每条搜索结果都对应一组明确的付款与发票关联,无需依赖 Result 对 joined values 的内部序列化格式。

注意事项

  • 搜索结果可能超过 4,000 条时,应使用 runPaged(),不要只依赖 run().each()。
  • applyingTransaction 可能包含其他应用交易。将搜索类型设为 search.Type.INVOICE,可以把目标记录限制为发票。
  • 其他搜索列可能导致同一组付款和发票出现重复行,因此分组时最好去重。
  • 如果要批量放入 ANYOF 的付款 ID 很多,应分批执行关联搜索,避免过滤条件过大。
  • 直接读取序列化后的 values['appliedToTransaction.internalid'] 可以解决当前问题,但需要封装好空值和单值处理,并在 NetSuite 版本升级后进行回归验证。

备注:内容仅供参考。