已全额支付发票触发Custom GL Lines插件报错问题咨询
问题:已全额支付发票触发GL重过账脚本报错
我开发了一款可根据入账科目重新过账特定交易的脚本,在常规发票上运行正常,但状态为“已全额支付”的发票会触发报错:
Cannot use 0 as input to setDebitAmount(). Amount to debit must be positive
即使将同一张发票切换为其他状态,问题仍然存在。请问发票状态为何会影响脚本运行?
脚本代码
/** * Custom GL lines Plug-In Implementation for rebooking Invoices (articles and discounts) * Configuration of Plug-In Implementation: * Transaction Type: Invoice * Subsidiaries: MTE * @param {*} transactionRecord * @param {*} standardLines * @param {*} customLines */ function customizeGlImpact( transactionRecord, standardLines, customLines ) { function sign(x) { // If x is NaN, the result is NaN. // If x is -0, the result is -0. // If x is +0, the result is +0. // If x is negative and not -0, the result is -1. // If x is positive and not +0, the result is +1. return ((x > 0) - (x < 0)) || +x; } if (standardLines.getCount() > 0) { var tranid = transactionRecord.getFieldValue("tranid"); var customername = transactionRecord.getFieldValue("entityname"); for (var i = 0; i < standardLines.getCount(); i++) { // get information for GL standard line var currLineStandard = standardLines.getLine(i); var taxCodeId = currLineStandard.getTaxItemId(); var accountID = currLineStandard.getAccountId(); nlapiLogExecution("debug", "Line: " + i, JSON.stringify({ "taxCodeId": taxCodeId, "accountID": accountID })); if (taxCodeId === null || accountID === null) {// specific lines don't have accountID continue; } var correctAccountId = targetAccountSearch(accountID, taxCodeId); nlapiLogExecution("debug", "Line: " + i, JSON.stringify({ "correctAccountId": correctAccountId })); if (correctAccountId === -1) { continue; } if (correctAccountId !== accountID) { var salestaxitem = nlapiLoadRecord("salestaxitem", taxCodeId); var newLine = customLines.addNewLine(); if (currLineStandard.creditAmount === "0") { if (sign(currLineStandard.debitAmount) === 1) { newLine.setCreditAmount(currLineStandard.debitAmount); } else { newLine.setDebitAmount(currLineStandard.debitAmount); } } else { if (sign(currLineStandard.creditAmount) === 1) { newLine.setDebitAmount(currLineStandard.creditAmount); } else { newLine.setCreditAmount(currLineStandard.creditAmount); } } newLine.setAccountId(accountID); newLine.setLocationId(currLineStandard.getLocationId()); newLine.setDepartmentId(currLineStandard.getDepartmentId()); newLine.setClassId(currLineStandard.getClassId()); newLine.setEntityId(currLineStandard.getEntityId()); newLine.setMemo(( "Umbuchung " + salestaxitem.getFieldValue("itemid") + " - " + tranid + " - " + customername + (currLineStandard.getMemo() !== null ? " - " + currLineStandard.getMemo() : "")).substring(0, 100) ); var newLine = customLines.addNewLine(); if (currLineStandard.creditAmount === "0") { if (sign(currLineStandard.debitAmount) === 1) { newLine.setDebitAmount(currLineStandard.debitAmount); } else { newLine.setCreditAmount(currLineStandard.debitAmount); } } else { if (sign(currLineStandard.creditAmount) === 1) { newLine.setCreditAmount(currLineStandard.creditAmount); } else { newLine.setDebitAmount(currLineStandard.creditAmount); } } newLine.setAccountId(correctAccountId); newLine.setLocationId(currLineStandard.getLocationId()); newLine.setDepartmentId(currLineStandard.getDepartmentId()); newLine.setClassId(currLineStandard.getClassId()); newLine.setEntityId(currLineStandard.getEntityId()); newLine.setMemo(( "Umbuchung " + salestaxitem.getFieldValue("itemid") + " - " + tranid + " - " + customername + (currLineStandard.getMemo() !== null ? " - " + currLineStandard.getMemo() : "")).substring(0, 100) ); } } } } /** * * @param {*} custrecord_pg_source_account * @param {*} custrecord_pg_lookup_tax_code * @returns */ function targetAccountSearch( custrecord_pg_source_account, custrecord_pg_lookup_tax_code ) { // saved search for mapping var accountRebookingSearch = nlapiCreateSearch( "customrecord_pg_account_rebooking", [ nlobjSearchFilter( "custrecord_pg_source_account", null, "is", custrecord_pg_source_account ), nlobjSearchFilter( "custrecord_pg_lookup_tax_code", null, "is", custrecord_pg_lookup_tax_code ), nlobjSearchFilter( "isinactive", null, "is", "F" ) ], [ new nlobjSearchColumn('custrecord_pg_source_account'), new nlobjSearchColumn('custrecord_pg_lookup_tax_code'), new nlobjSearchColumn('custrecord_pg_target_account') ] ); // run search var accountRebookingSearchResults = accountRebookingSearch .runSearch() .getResults(0, 2); accountRebookingSearchResults = JSON.parse( JSON.stringify(accountRebookingSearchResults) ); nlapiLogExecution("debug", "accountRebookingSearchResults", JSON.stringify({ "accountRebookingSearchResults": accountRebookingSearchResults })); if (accountRebookingSearchResults.length === 0) { return -1; // no mapping found } if (accountRebookingSearchResults.length > 1) { throw "more than one mapping found"; } var accountRebookingSearchResult = accountRebookingSearchResults[0]; return parseInt(accountRebookingSearchResult.columns.custrecord_pg_target_account.internalid); }
问题分析
- 已支付发票的GL行特性:发票全额支付后,系统生成的标准GL行中会出现金额为0的记录——原发票行与付款核销后,部分GL行的借贷方金额相互抵消,最终金额为0。脚本未过滤这类行,直接调用
setDebitAmount/setCreditAmount传入0值,触发NetSuite的金额校验规则(要求借贷金额必须为正数)。 - 字符串与数值的错误比较:脚本中使用
currLineStandard.creditAmount === "0"这种字符串对比逻辑,但NetSuite返回的金额实际是数值类型。当金额为0时,字符串与数值的严格相等判断会失效,导致逻辑进入错误分支,错误地将0值传入设置方法。 - GL缓存残留:即使切换发票状态,NetSuite的GL缓存可能未完全刷新,仍保留原已支付状态下的0金额GL行,导致脚本继续处理这些无效行。
修复方案
1. 过滤0金额GL行
在处理每一行GL记录前,先判断借贷金额是否均为0,直接跳过这类无效行:
// 在获取currLineStandard后添加 var debitAmt = Number(currLineStandard.debitAmount) || 0; var creditAmt = Number(currLineStandard.creditAmount) || 0; if (debitAmt === 0 && creditAmt === 0) { continue; }
2. 修正金额类型比较
将字符串比较改为数值比较,避免类型不匹配导致的逻辑错误:
// 原代码:if (currLineStandard.creditAmount === "0") // 修改为: if (creditAmt === 0) { // ...后续金额处理逻辑 }
3. 优化符号判断函数
原sign函数可简化,同时确保输入为数值类型,避免字符串传入导致的异常:
function sign(x) { x = Number(x); return x > 0 ? 1 : x < 0 ? -1 : 0; }
4. 强制刷新GL缓存(可选)
切换发票状态后,通过重新保存发票或调用nlapiSubmitRecord强制刷新GL记录,清除缓存中的无效行:
// 切换状态后执行,需确保有足够权限 nlapiSubmitRecord(transactionRecord, false, true);
内容的提问来源于stack exchange,提问作者DomMa
相关产品推荐
相关产品推荐

