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

已全额支付发票触发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);
}

问题分析

  1. 已支付发票的GL行特性:发票全额支付后,系统生成的标准GL行中会出现金额为0的记录——原发票行与付款核销后,部分GL行的借贷方金额相互抵消,最终金额为0。脚本未过滤这类行,直接调用setDebitAmount/setCreditAmount传入0值,触发NetSuite的金额校验规则(要求借贷金额必须为正数)。
  2. 字符串与数值的错误比较:脚本中使用currLineStandard.creditAmount === "0"这种字符串对比逻辑,但NetSuite返回的金额实际是数值类型。当金额为0时,字符串与数值的严格相等判断会失效,导致逻辑进入错误分支,错误地将0值传入设置方法。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 04:01:40