PAYATHON 2026

如何用 SuiteQL 获取 Invoice、payments 及 applied_to

支付阿杰

结论

在 SuiteQL 中,不能用 payment 的 ForeignTotal 判断某张 Invoice 实际收到的金额。应读取 NextTransactionLineLink.ForeignAmount,它表示当前交易关联关系上的金额,也就是该 payment 应用于指定 Invoice 的金额。

transaction_links 属于旧版 SuiteAnalytics Connect/ODBC schema。SuiteQL 的 Analytics Data Source 中没有同名对象,通常需要通过以下两个视图查询对应关系:

  • NextTransactionLineLink
  • PreviousTransactionLineLink

如果还需要 REST Record API 中 payment 的申请明细,可以读取 Customer Payment 的 apply sublist。SuiteQL 中并不存在名为 applied_to 的对应子表。

查询指定 Invoice 的 payment 及实付金额

SELECT
    INV.ID                AS InvoiceID,
    INV.TranID            AS InvoiceNumber,
    PMT.ID                AS PaymentID,
    PMT.TranID            AS PaymentNumber,
    PMT.TranDate          AS PaymentDate,
    PMT.ForeignTotal      AS PaymentTotal,
    PMT.ExchangeRate      AS PaymentExchangeRate,
    NTLL.ForeignAmount    AS AppliedAmount,
    NTLL.LinkType         AS LinkType,
    NTLL.PreviousLine     AS InvoiceLine,
    NTLL.NextLine         AS PaymentLine
FROM NextTransactionLineLink NTLL
INNER JOIN Transaction INV
    ON INV.ID = NTLL.PreviousDoc
INNER JOIN Transaction PMT
    ON PMT.ID = NTLL.NextDoc
WHERE INV.ID = 2373356
  AND INV.Type = 'CustInvc'
  AND PMT.Type = 'CustPymt'
ORDER BY PMT.TranDate ASC, PMT.ID ASC

查询中几个金额字段的含义不同:

  • PMT.ForeignTotal:整笔 Customer Payment 的总金额。
  • NTLL.ForeignAmount:Invoice 与 payment 之间这条关联关系的金额。
  • PMT.ExchangeRate:payment 使用的汇率,可能与 Invoice 的汇率不同。

例如,一笔总额为 1,000 的 payment 分别应用于两张 Invoice,金额为 600 和 400。查询其中一张 Invoice 时,PMT.ForeignTotal 仍是 1,000,NTLL.ForeignAmount 才会返回对应的 600 或 400。

从 payment 反查其应用到的所有 Invoice

如果已经知道 payment 的内部 ID,可以反向查询:

SELECT
    PMT.ID               AS PaymentID,
    PMT.TranID           AS PaymentNumber,
    INV.ID               AS InvoiceID,
    INV.TranID           AS InvoiceNumber,
    INV.TranDate         AS InvoiceDate,
    INV.ForeignTotal     AS InvoiceTotal,
    NTLL.ForeignAmount   AS AppliedAmount,
    NTLL.LinkType        AS LinkType
FROM NextTransactionLineLink NTLL
INNER JOIN Transaction PMT
    ON PMT.ID = NTLL.NextDoc
INNER JOIN Transaction INV
    ON INV.ID = NTLL.PreviousDoc
WHERE PMT.ID = 2374577
  AND PMT.Type = 'CustPymt'
  AND INV.Type = 'CustInvc'
ORDER BY INV.TranDate ASC, INV.ID ASC

如果只有 payment 编号,也可以按 PMT.TranID 筛选。不过,交易编号可能受编号规则、子公司或数据导入方式影响,因此使用内部 ID 更可靠。

获取 Customer Payment 的 apply 明细

SuiteQL 返回的是交易关系数据。如果还需要 REST Record API 中 Customer Payment 的完整申请行,可以展开它的 subresources:

GET /services/rest/record/v1/customerPayment/2374577?expandSubResources=true

Customer Payment 通常使用 apply sublist 表示申请明细。返回结构大致如下,具体字段名称应以当前账户的 REST metadata catalog 为准:

{
  "id": "2374577",
  "tranId": "PMT028551",
  "apply": {
    "items": [
      {
        "apply": true,
        "doc": {
          "id": "2373356"
        },
        "amount": 600.00
      }
    ]
  }
}

处理这些数据时:

  1. 在 apply.items 中找到 doc.id 等于目标 Invoice 内部 ID 的行。
  2. 确认该行的 apply 为 true。
  3. 读取该行的 amount,不要读取 payment 顶层的总金额。

部分账户或 REST Record Service 版本也支持直接访问 sublist:

GET /services/rest/record/v1/customerPayment/2374577/apply

当前账户是否支持这种访问方式,以及接口会返回哪些字段,应以该账户的 REST API Browser 或 metadata catalog 为准。

注意关联行和重复结果

NextTransactionLineLink 是行级关联视图,因此结果中会包含 PreviousLine 和 NextLine。普通 Customer Payment 的一次应用通常对应一条记录,但以下情况可能产生多条关联记录:

  • 同一组交易之间存在不同类型的关联;
  • Credit Memo、Customer Deposit 或其他交易参与了冲抵;
  • 查询又连接了未加限制的 TransactionLine,导致行数增加;
  • 账户中的交易由特殊脚本、数据导入或历史流程生成。

可以先查看实际存在的 LinkType:

SELECT DISTINCT
    LinkType
FROM NextTransactionLineLink
WHERE PreviousDoc = 2373356
ORDER BY LinkType

确认目标账户中的实际值后,再决定是否添加 LinkType 条件。不了解关联类型时,不要直接对所有记录执行 SUM(),否则可能将性质不同的关联金额合并在一起。

金额和币种

ForeignAmount 通常表示交易币种下的关联金额。在多币种环境中,还要结合以下信息判断 Salesforce 应展示哪一种金额:

  • Invoice currency;
  • payment currency;
  • payment 的 ExchangeRate;
  • 子公司本位币;
  • Salesforce 目标字段使用的币种。

同时应保留 NetSuite 返回的金额符号。Credit Memo、退款或冲销交易的符号方向可能与 Customer Payment 不同,因此不建议在 SQL 中无条件使用 ABS()。

两者的区别是:Transaction.ForeignTotal 表示整张 payment 的金额,NextTransactionLineLink.ForeignAmount 表示 payment 应用于某张 Invoice 的具体金额。

备注:内容仅供参考。