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 结构可能是实现细节。生产代码可以改用以下流程:
- 查询指定时间范围内更新过的付款。
- 收集付款的 internal ID。
- 以发票为搜索主体,通过
applyingTransaction找到对应的付款。 - 按付款 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 版本升级后进行回归验证。
备注:内容仅供参考。
