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

NetSuite定时脚本创建CustomerPayment后关联发票不符问题求助

NetSuite定时脚本关联发票异常问题排查

问题描述

通过NetSuite定时脚本循环创建customerpayment对象并关联指定发票,预期保存后能准确关联目标发票,但实际打开记录发现关联的是其他发票。日志显示应关联发票9236675,但实际关联的是9236677。该问题仅在客户环境复现,本地测试环境运行正常。

初始实现代码

if (paydata != null) {
    paymentfee = paydata.paymentFee;
    for (var y = 0; y < paydata.payments.length; y++) {
            var paymentrec = null;
            log.debug('entity', paydata.payments[y].customerRef);
            paymentrec = record.create({
                    type: "customerpayment",
                    defaultValues: {
                            "entity": paydata.payments[y].customerRef
                    }
            });
            paymentrec.setValue({
                    fieldId: "subsidiary",
                    value: paydata.subsidiaryId
            });


            // 创建带账户的付款时会自动存入
            paymentrec.setValue({
                fieldId: "account",
                value: paydata.account
            });

            // 支持自定义表单功能
            if (paydata.payments[y].customform) {
                paymentrec.setValue({
                    fieldId: "customform",
                    value: paydata.payments[y].customform
                });
                log.debug('Custom form applied', paydata.payments[y].customform);
            }

            paymentrec.setValue({
                    fieldId: "memo",
                    value: paydata.payments[y].note
            });
            paymentrec.setValue({
                    fieldId: "payment",
                    value: paydata.payments[y].paymentAmount
            });

            // // 调试发票自动应用逻辑
            // paymentrec.setValue({
            //     fieldId: "autoapply",
            //     value: false
            // })

            paymentrec.setValue({
                    fieldId: "custbody_peakflo_payref",
                    value: paydata.peakfloPaymentRef
            });
            paymentrec.setValue({
                    fieldId: "custbody_peakflo_payacct",
                    value: paydata.account
            });
            paymentrec.setValue({
                    fieldId: "custbody_peakflo_payfee",
                    value: paydata.paymentFee
            });
            paymentrec.setText({
                    fieldId: "currency",
                    value: paydata.currency
            });

            for (var z = 0; z < paydata.payments[y].invoiceLines.length; z++) {
                    if (paydata.payments[y].invoiceLines[z].NetSuiteInvoiceInternalId != '' && paydata.payments[y].invoiceLines[z].NetSuiteInvoiceInternalId != null) {
                            log.debug('count', paymentrec.getLineCount({
                                    sublistId: "apply"
                            }));

                            for (var al = 0; al < paymentrec.getLineCount({sublistId: "apply"}); al++) {
                                    log.debug('comparison data', JSON.stringify(
                                        {
                                            recordInternalId: paymentrec.getSublistValue({
                                                sublistId: "apply",
                                                fieldId: "internalid",
                                                line: al
                                            }),
                                            payloadInvoiceId: paydata.payments[y].invoiceLines[z].NetSuiteInvoiceInternalId,
                                            isEqual: paymentrec.getSublistValue({
                                                sublistId: "apply",
                                                fieldId: "internalid",
                                                line: al
                                            }) == paydata.payments[y].invoiceLines[z].NetSuiteInvoiceInternalId
                                        }));

                                if (paymentrec.getSublistValue({
                                            sublistId: "apply",
                                            fieldId: "internalid",
                                            line: al
                                    }) == paydata.payments[y].invoiceLines[z].NetSuiteInvoiceInternalId) {
                                            paymentrec.setSublistValue({
                                                    sublistId: "apply",
                                                    fieldId: "apply",
                                                    line: al,
                                                    value: true
                                            });
                                            paymentrec.setSublistValue({
                                                    sublistId: "apply",
                                                    fieldId: "amount",
                                                    line: al,
                                                    value: paydata.payments[y].invoiceLines[z].PaymentAmount
                                            });
                                            var inv_qm = record.create({type: "customrecord_peakflo_history_qm"});
                                            inv_qm.setValue({fieldId: "custrecord_pf_hqm_dg_pri", value: "2"});
                                            inv_qm.setValue({
                                                    fieldId: "custrecord_pf_hqm_recsub",
                                                    value: paymentrec.getValue({fieldId: "subsidiary"})
                                            });
                                            inv_qm.setValue({
                                                    fieldId: "custrecord_pf_hqm_rectype",
                                                    value: "transaction"
                                            });
                                            inv_qm.setValue({
                                                    fieldId: "custrecord_pf_hqm_recid",
                                                    value: paydata.payments[y].invoiceLines[z].NetSuiteInvoiceInternalId
                                            });
                                            var inv_qmid = inv_qm.save();
                                            log.debug('payment amt', paydata.payments[y].invoiceLines[z].PaymentAmount);
                                            log.debug('HQM created id', inv_qmid);

                                    }
                                    log.debug('Selected', paymentrec.getSublistValue({
                                        sublistId: "apply",
                                        fieldId: "apply",
                                        line: al
                                    }));
                            }
                    }
            }
            var paymentrecid = paymentrec.save({
                    ignoreMandatoryFields: true,
                    enableSourcing: true
            });
            record.submitFields({
                    type:"customrecord_peakflo_qm",
                    id:pfp_s_res[x].id,
                    values:{
                            custrecord_pf_processed:true
                    }
            });
            log.debug('payment id', paymentrecid);
            if (paymentrecid) {
                    paymentref.push(paymentrecid);
            }
    }
}

8月6日更新后的代码

var paymentrec = record.create({
    type: "customerpayment",
    defaultValues: {
            "entity": paymentData.customerRef
    }
});
paymentrec.setValue({
    fieldId: "subsidiary",
    value: paydata.subsidiaryId
});

// 创建带账户的付款时会自动存入
paymentrec.setValue({
    fieldId: "account",
    value: paydata.account
});

// 支持自定义表单功能
if (paymentData.customform) {
    paymentrec.setValue({
        fieldId: "customform",
        value: paymentData.customform
    });
    log.debug('Custom form applied', paymentData.customform);
}

paymentrec.setValue({
        fieldId: "memo",
        value: paymentData.note
});
paymentrec.setValue({
        fieldId: "payment",
        value: paymentData.paymentAmount
});

paymentrec.setValue({
        fieldId: "custbody_peakflo_payref",
        value: paydata.peakfloPaymentRef
});
paymentrec.setValue({
        fieldId: "custbody_peakflo_payacct",
        value: paydata.account
});
paymentrec.setValue({
        fieldId: "custbody_peakflo_payfee",
        value: paydata.paymentFee
});
paymentrec.setText({
        fieldId: "currency",
        value: paydata.currency
});

var anyApplied = false;

// 遍历paymentrec中所有未结发票行
peakflo.iter(paymentrec, 'apply', function(al, getV, setV) { // 将付款应用行作为外层循环,可关闭未匹配行的应用状态
    var didFind = false;

    // 遍历所有输入的付款数据发票行
    paymentData.invoiceLines.forEach(function(invLine, z) {
        if (!invLine.NetSuiteInvoiceInternalId || getV('doc') != invLine.NetSuiteInvoiceInternalId) return;


        didFind = true;
        anyApplied = true;

        setV('apply', true);
        setV('amount', invLine.PaymentAmount);

        log.debug('payment amt', 
            JSON.stringify(
                {
                    payloadAmount: invLine.PaymentAmount, 
                    recordLineAmount: paymentrec.getSublistValue({
                        sublistId: "apply",
                        fieldId: "amount",
                        line: al
                        })
                }
            )
        );

        log.debug('Selected', paymentrec.getSublistValue({
            sublistId: "apply",
            fieldId: "apply",
            line: al
        }));
    });

    // 如果在 payload 中未找到对应发票,设置为不应用
    if (!didFind) setV('apply', false);

});

// 如果有任何发票被应用
if (anyApplied) {

    // 保存付款记录
    var paymentrecid = paymentrec.save({
        ignoreMandatoryFields: true,
        enableSourcing: false // 默认值为false,设为true可能引发异常行为。已初始化客户默认值,无需进一步自动填充
    });
    record.submitFields({
        type: "customrecord_peakflo_qm",
        id: pfp_s_res[x].id,
        values: {
            custrecord_pf_processed: true
        }
    });
    log.debug('payment id', paymentrecid);
    if (paymentrecid) {
        paymentref.push(paymentrecid);
    }
} else {
    log.error({
        title: 'no open invoice found',
        details: JSON.stringify(pd)
    });
}
});

可能的原因及排查方向

1. 自动应用逻辑的环境差异

客户环境可能开启了全局Auto Apply Payments设置,或使用的自定义表单默认启用自动应用。即使代码手动设置了发票关联,NetSuite保存时可能触发自动应用逻辑,覆盖手动设置。建议强制关闭自动应用:

paymentrec.setValue({
    fieldId: "autoapply",
    value: false
});

创建customerpayment时就设置该字段,避免保存时自动重新匹配发票。

2. 字段类型不匹配导致的比较错误

检查NetSuiteInvoiceInternalId的数据类型:如果该值是字符串,而getSublistValue('doc')返回数值,使用==比较可能因隐式转换出现匹配错误。建议改用严格相等===确保类型一致:

if (!invLine.NetSuiteInvoiceInternalId || getV('doc') !== invLine.NetSuiteInvoiceInternalId) return;

3. 多子公司/多货币环境的加载顺序问题

客户环境可能是多子公司、多货币的复杂环境,创建customerpayment时的字段设置顺序(如子公司、实体、货币)可能影响发票列表加载顺序,导致循环匹配错位。建议调整顺序:先设置子公司,再设置实体,最后设置货币及其他字段,确保发票列表加载正确。

4. 第三方脚本/工作流的干扰

客户环境中可能存在其他自定义脚本(如用户事件脚本)或工作流,在customerpayment保存的beforeSubmit或afterSubmit阶段触发,修改了apply子列表的关联数据。需要排查客户环境中针对customerpayment的自定义脚本和工作流,确认是否有逻辑干扰发票关联。

5. 内存中记录的缓存问题

创建customerpayment后,apply子列表的发票数据可能未完全加载,导致代码读取的发票ID或排序与实际保存时不一致。可尝试在设置完实体和子公司后,调用paymentrec.reload()重新加载记录(仅适用于部分NetSuite版本),或改用record.load方式创建支付记录,确保发票列表加载完整。


内容的提问来源于stack exchange,提问作者Dmitry Vedenyapin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 17:37:00