淘垦网
淘垦网

淘垦网

热搜1库存查询接口怎么调2怎么获取 openToken3EXSV0011 服务名称不正确4T+ 报表查询接口5仓库列表接口6openToken 过期怎么办7user_auth_permanent_code 是什么8T+Cloud 需要 bookId 吗
畅捷通 T+ / T+Cloud

授权绑定(获取 openToken)

chanjet.authorize

HTTPS GET(授权页)+ GET(换/刷 token) v1.0.0 ▾

接口地址

授权页 https://market.chanjet.com/app/openApp ;换token https://openapi.chanjet.com/auth/v2/getToken ;刷新 https://openapi.chanjet.com/auth/v2/refreshToken

鉴权方式

OAuth2 授权码流程(应用级 appKey/appSecret + 用户级 openToken)

获取 openToken 后才能调业务接口;换/刷 token 时 Header 必须带 appKey+appSecret

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥

请求体说明

  • 第1步:后端直接拼授权页 URL(market.chanjet.com/app/openApp?appKey=)返回前端,浏览器打开后用户登录授权
  • 第2步:畅捷通回跳 redirect_uri?code=xxx&state=xxx,后端用 code 调 /auth/v2/getToken 换 openToken
  • 第3步:openToken 快过期时(剩<2天)用 refresh_token 调 /auth/v2/refreshToken 续期,refresh_token 一并刷新且窗口重置(约29天)

请求示例

1) 后端返回:https://market.chanjet.com/app/openApp?appKey=TpCOEUuF&state=abc
2) 回跳 https://your-app/auth/chanjet/callback?code=AUTH_CODE&state=abc
3) GET https://openapi.chanjet.com/auth/v2/getToken?grantType=authorization_code&code=AUTH_CODE&redirectUri=https://your-app/auth/chanjet/callback
   Headers: appKey:TpCOEUuF, appSecret:****

响应示例

{
  "code": "200",
  "message": "成功",
  "result": {
    "access_token": "user_auth_token_xxx",
    "refresh_token": "refresh_xxx",
    "expires_in": 518400
  }
}

字段说明

  • access_token string — 用户授权令牌(即 openToken,业务接口 Header 用)
  • refresh_token string — 刷新令牌,约 29 天有效,每次刷新重置窗口,必须持久化
  • expires_in number — access_token 有效期秒数,实测约 518400(6 天)

错误码

  • 404 / code:50000 误调 openapi.chanjet.com/account/auth/getAuthUrl 接口(接口不存在) → 不要调 getAuthUrl 接口!直接拼 market.chanjet.com/app/openApp 授权页给用户浏览器
  • 401 appSecret不能为空 换/刷 token 未带 appSecret → Header 带 appSecret(后端需注入环境变量)
  • token_expired openToken 失效 → 用 refresh_token 刷新;refresh 也过期则引导重新授权
  • code不正确 / 400 授权码流程参数错(曾误用永久码) → 走标准 authorization_code 流程;redirectUri 须与授权时、控制台登记完全一致

实战 tips

  • 最常见坑:去 openapi.chanjet.com/account/auth/getAuthUrl 调'获取授权地址'会 404(code 50000 接口不存在)。标准做法就是拼 market.chanjet.com/app/openApp 授权页,不调该 API
  • redirect_uri 必须在畅捷通开放平台白名单,且与授权时、换 token 时传的 redirectUri 逐字符一致(含路径、https、无多余斜杠)
  • state 防 CSRF:后端生成、回调时校验,不匹配则拒绝
  • openToken 约 6 天;refresh_token 约 29 天且每次刷新重置 → 只要 29 天内有调用就不掉线,自建应用无需'永久授权码'
  • token 必须按用户隔离、加密落盘,不可明文、不可共享默认身份
官方文档 ↗
畅捷通 T+ / T+Cloud

科目余额表查询(GetBalanceSumRpt)

chanjet.balance_sheet_query

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetBalanceSumRpt

鉴权方式

openToken + appKey/appSecret(Header)

请求体整包再包裹一层 request 对象(不是 param)

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥
  • openToken 必填 — 用户授权令牌
  • Content-Type 必填 — 固定 application/json

请求体说明

  • 请求体顶层键为 request(不是 param)
  • ReportName 取 GL_BalanceSumRpt(科目余额表内部码)
  • SearchItems 为查询项数组,ColumnName 支持 period(期间,如2023-10)/level(级次)/accountTypeID(科目类别)/accountName(科目编码)/isEndAccount(末级科目1)/isIncludeUnPost(含未记账1)/isNohappenDisplayAccu(显示无余额无发生累计有发生1)
  • PageIndex 从1开始;PageSize 最大1000;翻页(>1)需回传首查返回的 SolutionID + TaskSessionID
  • ReportTableColNames 为需显示栏目(建议先不传拉首页,按 ColumnSource.Rows 取栏目全集,再合并所需列)

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetBalanceSumRpt
Headers: appKey / appSecret / openToken / Content-Type:application/json
Body:
{
  "request": {
    "ReportName": "GL_BalanceSumRpt",
    "PageSize": 1000,
    "PageIndex": 1,
    "SearchItems": [
      { "ColumnName": "period", "BeginDefault": "2023-02", "EndDefault": "2023-02" },
      { "ColumnName": "isIncludeUnPost", "BeginDefault": "1" },
      { "ColumnName": "isNohappenDisplayAccu", "BeginDefault": "1" }
    ]
  }
}

响应示例

{
  "ReportName": "GL_BalanceSumRpt",
  "TotalRecords": 5,
  "Pages": 1,
  "ColumnSource": {
    "Rows": [
      { "Title": "科目名称", "FieldName": "accountName" },
      { "Title": "期初余额", "FieldName": "PeriodBeginBalance" },
      { "Title": "本期发生", "FieldName": "CurrencyPeriod" },
      { "Title": "期末余额", "FieldName": "PeriodEndBalance" }
    ]
  },
  "DataSource": {
    "Rows": [
      { "accountCode": "1058", "accountName": "1058-借", "accountTypeName": "资产", "[PeriodBeginBalance-期初余额][periodBeginBalanceAmountDr-借方]": "9649.52", "[CurrencyPeriod-本期发生][amountDr-借方]": "11338.60", "[PeriodEndBalance-期末余额][periodEndBalanceAmountDr-借方]": "10987.12" }
    ]
  }
}

字段说明

  • request.ReportName string — 报表名称,科目余额表固定 GL_BalanceSumRpt
  • request.PageIndex / PageSize integer — 分页,从1开始 / 最大1000
  • request.SearchItems[] array<object> — 查询项(ColumnName + BeginDefault/EndDefault 区间)
  • DataSource.Rows[] array<object> — 数据行;金额字段用方括号键名如 [PeriodEndBalance-期末余额][periodEndBalanceAmountDr-借方]
  • ColumnSource.Rows[] array<object> — 列定义:FieldName(字段名)/Title(标题)/ParentFieldName(上级)
  • SolutionID / TaskSessionID string — 翻页凭证,PageSize>1 需回传
  • TotalRecords / Pages integer — 总记录数 / 总页数

错误码

  • EXSV0011 服务名称不正确 → 确认端点为 reportQuery/GetBalanceSumRpt 且 Body 顶层为 request

实战 tips

  • 与通用报表查询(reportQuery/GetReportData)不同:本接口专查科目余额表,ReportName=GL_BalanceSumRpt
  • 金额字段名带方括号层级,如 [PeriodEndBalance-期末余额][periodEndBalanceAmountDr-借方];解析时按方括号拆分
  • 翻页务必回传首查的 SolutionID + TaskSessionID,否则拿不到后续页
  • 报表码写错不报错:HTTP 200 + TotalRecords=0,先核对 ReportName 再下结论
官方文档 ↗
畅捷通 T+ / T+Cloud

业务单据明细报表(进货/付款/收款/生产加工/费用)

chanjet.business_vouchers_detail

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

五张业务单据明细表共用同一端点,只改 request.ReportName;openToken 见 chanjet.authorize;需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 五张业务单据明细表,接口路径与请求体结构完全相同,只换 request.ReportName:
  • ① 进货单明细表 ReportName=PU_PurchaseArrivalDetailRpt (采购到货单)
  • ② 付款单明细表 ReportName=ARAP_PaymentVoucherDetailRpt
  • ③ 收款单明细表 ReportName=ARAP_ReceiveVoucherDetailRpt
  • ④ 生产加工单执行表 ReportName=MP_ManufactureOrderExecuteRpt
  • ⑤ 费用单明细表 ReportName=CS_ExpenseVoucherDetailRpt
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);传 null = 不限日期
  • 销售订单明细表(SA_SaleOrderDetailRpt)、销货单明细表(SA_SaleDeliveryDetailRpt) 各有独立 spec(chanjet.sale_order_detail / chanjet.sale_delivery_detail),不在此重复

请求示例

① 进货单明细表
POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body: {"request":{"ReportName":"PU_PurchaseArrivalDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[],"GroupItems":[],"ReportTableColNames":""}}

② 付款单明细表
{"request":{"ReportName":"ARAP_PaymentVoucherDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[],"GroupItems":[],"ReportTableColNames":""}}

③ 收款单明细表
{"request":{"ReportName":"ARAP_ReceiveVoucherDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[],"GroupItems":[],"ReportTableColNames":""}}

④ 生产加工单执行表
{"request":{"ReportName":"MP_ManufactureOrderExecuteRpt","PageIndex":1,"PageSize":5,"SearchItems":[],"GroupItems":[],"ReportTableColNames":""}}

⑤ 费用单明细表
{"request":{"ReportName":"CS_ExpenseVoucherDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 8,
  "ColumnSource": { "Rows": [ { "FieldName": "VoucherDate", "Title": "单据日期" }, { "FieldName": "VoucherCode", "Title": "单据编号" } ] },
  "DataSource": { "Rows": [ { "VoucherDate": "2026-06-26", "VoucherCode": "PV-2026-06-0001", "PartnerName": "某供应商", "Amount": "1200.00", "rowType": "D" } ] }
}

字段说明

  • DataSource.Rows array — 数据行数组(各单据明细:日期/单号/往来单位/金额/存货等,列名以账户实际为准)
  • ColumnSource.Rows array — 列定义(FieldName/Title),列名以账户实际返回为准
  • TotalRecords number — 总记录数

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken
  • 0 行 0 列 ReportName 不匹配该账户 → 到 T+ 取真实 ReportName 内部码(Ctrl+右键查看框架源代码)

实战 tips

  • 别名/检索词:进货单明细、采购到货明细、付款单明细、收付款、收款单明细、生产加工单、生产执行表、费用单明细、费用明细、业务单据
  • 五张表都来自同一端点 /tplus/api/v2/reportQuery/GetReportData,需应用已开通「报表」权限;好业财(tpluscloud)无此接口
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时 T+ 会套用更严的过滤方案导致行集变少;须传「默认栏目全集 ∪ 需要列」。全集拿法:先不带该字段拉第 1 页,ColumnSource.Rows 即全部 FieldName,合并后再翻页
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:按「上一批最大日期+1 天」递推分段拉取 + 去重,直到超过 EndDefault
  • 各表数量/金额字段名不同,以响应 ColumnSource.Rows 的 FieldName 为准;所有数值多为字符串,计算前需 Number()
  • 付款单/收款单属收付款类(ARAP_ 前缀),可与 chanjet.partners_account_query(往来期间对账单)对照核账
官方文档 ↗
畅捷通 T+ / T+Cloud

财务报表查询(FindTUFOTable)

chanjet.financial_report_query

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/TaxOpenAPI/FindTUFOTable

鉴权方式

openToken + appKey(Header)

该接口 Header 仅需 appKey + openToken(不同于多数 T+ 接口还需 appSecret;若 401 可补 appSecret 重试)

请求头

  • appKey 必填 — 开放平台应用ID
  • openToken 必填 — 用户授权令牌

请求体说明

  • 请求体必须包裹在 param 对象内
  • KeyWord 为查询条件键值对:KeyYear 年、KeyMonth 期间、KeySubmitTask 报送任务、KeyKouJing 口径(个别/合并/详细底稿)
  • TUFOTableCode 为报表设计列表的编码列值(仅支持数字/汉字/字母,勿带特殊符号);与 KeySubmitTask 的报表页签是交集关系,最好二选一,否则可能取不到数据
  • ReturnType 返回格式:Json(默认)或 MD(Markdown)

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/TaxOpenAPI/FindTUFOTable
Headers:
  appKey: h8fP2Fq0
  openToken: user_auth_token_xxx
Body:
{
  "param": {
    "KeyWord": [
      { "Code": "KeyYear", "Value": "2026" },
      { "Code": "KeyMonth", "Value": "8" }
    ],
    "TUFOTableCode": ["会小企01表", "利润表"],
    "ReturnType": "MD"
  }
}

响应示例

{
  "code": "0",
  "message": null,
  "data": "<JSON 字符串,需二次 JSON.parse;含 period 与 reportData[],每个 reportData 有 header(报表头) + cells[](row/col/value 单元格坐标+值)>",
  "exception": null
}

字段说明

  • KeyWord[].Code string — 查询条件键:KeyYear 年 / KeyMonth 期间 / KeySubmitTask 报送任务 / KeyKouJing 口径
  • KeyWord[].Value string — 条件值,如 2026 / 5 / 0000 / 详细底稿
  • TUFOTableCode[] array<string> — 报表编码(报表设计列表编码列),可多选
  • ReturnType string — 返回格式:Json(默认)/ MD
  • data.reportData[].header object — 报表头:reportCode/reportName/keyYear/keyMonth/periodType/organCode/organName
  • data.reportData[].cells[] array<object> — 单元格数组,每个含 row/col/value(行列坐标+值)

错误码

  • 999 业务异常 如'增值税表在2022年11月没有找到对应的数据,请先生成数据,再申报!' → 确认查询期间已在 T+ 生成对应报表数据;核对 KeyYear/KeyMonth/KeySubmitTask

实战 tips

  • 支持版本:T+Cloud、T+专属云21.0(21.000.000.00146)以上
  • TUFOTableCode 与 KeySubmitTask 二选一即可,两者都传取交集,设置不当会取不到任何数据
  • 返回 data 是 JSON 字符串(需二次 JSON.parse),多报表时 reportData 含多个元素;header 字段:reportCode 报表编码、reportName 报表名称、keyYear 年份、keyMonth 期间(年报为空或0)、periodType 周期类型、organCode 机构编码、organName 机构名称
  • 该接口 Header 仅 appKey+openToken;若返回鉴权失败可补 appSecret 重试(与多数 T+ 接口一致)
官方文档 ↗
畅捷通 T+ / T+Cloud

对接总览与接入指南

chanjet.integration_guide

对接总览(OAuth2 授权码 + OpenAPI HTTPS POST) v1.0.0 ▾

接口地址

授权页 https://market.chanjet.com/app/openApp ;业务 https://openapi.chanjet.com/tplus/api/v2/* ;授权/换/刷 token 端点详见 chanjet.authorize

鉴权方式

两套凭证:应用级 appKey/appSecret(开放平台应用凭证,Header 必带)+ 用户级 openToken(授权后获取,业务接口 Header 必带)。授权流程细节(拼授权页、换/刷 token、token 生命周期)见 chanjet.authorize

一个应用可服务多个 T+ 用户,openToken 必须按用户隔离存储

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥
  • openToken 必填 — 用户授权令牌(业务接口用,获取方式见 chanjet.authorize)

请求体说明

  • 业务调用 Header 带 appKey+appSecret+openToken(openToken 由授权流程获取,见 chanjet.authorize)
  • 库存/采购类接口 Body 包裹在 param 内;报表类部分接口(reportQuery/GetBalanceSumRpt、PartnersAccountRpt/Query 等)用 request 对象包裹,日期区间用 BeginDefault/EndDefault
  • 多账套 bookId:URL 追加 ?bookId=xxx 同时 body.param.bookId 双写;T+Cloud 走 T+ API 不需 bookId,好业财(cloud) 才需

请求示例

(暂无)

响应示例

(暂无)

错误码

  • EXSV0011 服务名称不正确 → 检查 appKey/appSecret 是否缺失或未随 Header 发送
  • 401 appSecret不能为空 后端未注入 appSecret → 注入 CHANJET_CLIENT_SECRET 等环境变量后重启
  • token_expired openToken 失效 → 用 refresh_token 刷新(流程见 chanjet.authorize);refresh 也过期则引导用户重新授权

实战 tips

  • 最关键认知:getAuthUrl 不是可调用的 OpenAPI 接口,它是'授权页地址'概念;标准做法是后端直接拼 market.chanjet.com/app/openApp?appKey= 交给浏览器(详见 chanjet.authorize)
  • openToken(access_token) 实测有效期 6 天;refresh_token 约 29 天且每次刷新重置窗口 → 只要 29 天内有调用就永不断线,无需永久码(详见 chanjet.authorize)
  • 业务 Body 必须包裹在 param 内(库存/采购等);报表类部分接口用 request 对象包裹,且日期区间用 BeginDefault/EndDefault
  • 必须设超时(建议 60~90s),T+ 大数据量响应慢,不设会卡死线程
  • 数据安全红线:token 必须按用户隔离存储、加密落盘(AES-256-GCM),绝不用共享默认身份查账套;身份只能从可信会话取,不轻信前端传入 user_id
  • 严格只读:畅捷通授权不区分读写 scope,只读靠只调查询类接口保证;别碰审核/过账/保存类写接口
官方文档 ↗
畅捷通 T+ / T+Cloud

存货分类查询

chanjet.inventory_class_query

HTTPS POST(inventoryClass/Query) v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/inventoryClass/Query

鉴权方式

openToken(用户授权令牌)+ appKey/appSecret(应用凭证,放 Header)

openToken 由授权流程获取,见 chanjet.authorize;请求头 Content-Type 固定 application/json

请求头

  • appKey 必填 — 开放平台appKey
  • appSecret 必填 — 开放平台appSecret
  • openToken 必填 — 开放平台token
  • Content-Type 必填 — 请求格式,固定值 application/json

请求体说明

  • 请求体必须包裹在 param 对象内
  • Code / Name 二选一或都不传(都不传=查询所有分类);按编码查询 {param:{Code:"07"}},按名称 {param:{Name:"自制食品"}}
  • SelectFields 指定返回字段,范围:id,code,name,isendnode,ts,parent,parent.id,parent.code,parent.name,createdtime,madedate,updated,MarketingOrgan,MarketingOrgan.Code,MarketingOrgan.Name;默认返回 Code+Name
  • 【顺序坑】SelectFields 里 parent 必须放在 parent.id、parent.code、parent.name 之后,否则报错;且只有显式指定了 parent.id,parent 结构里才会带 parent.id(parent.code/parent.name 同理)
  • 模糊查询遵循 T+ 基础信息模糊查询规则(t+baseinfolikequery / LinkQuery),非 SQL 通配符

请求示例

1) 按分类编码查询
POST https://openapi.chanjet.com/tplus/api/v2/inventoryClass/Query
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body: { "param": {"Code":"07"} }

2) 按分类名称查询
{ "param": {"Name":"自制食品"} }

3) 查询所有分类
{ "param": {} }

4) 查询分类上下级完整信息
{ "param": {"Code":"001","selectfields":"id,code,name,isendnode,parent.id,parent.code,parent.name,parent"} }

响应示例

1) 按编码返回
[{"Code":"07","Name":"其他"}]

2) 按名称返回
[{"Code":"06","Name":"自制食品"}]

3) 查询所有返回
[{"Code":"07","Name":"其他"},{"Code":"06","Name":"自制食品"},{"Code":"05","Name":"原材料"},{"Code":"04","Name":"酒水"}]

4) 上下级完整信息
[{"id":49,"code":"001","name":"冻鱼类","isendnode":false,"parent.id":45,"parent.code":"13","parent.name":"冻鱼","parent":{"id":45,"code":"13","name":"冻鱼"}}]

字段说明

  • id string — 分类档案ID
  • code string — 分类档案编码
  • name string — 分类档案名称
  • isendnode boolean — 是否末级分类
  • parent object — 上级分类对象(含 id/code/name;需在 SelectFields 指定 parent.id 等才返回)
  • parent.id string — 上级分类ID
  • parent.code string — 上级分类编码
  • parent.name string — 上级分类名称
  • ts string — 数据库时间戳
  • marketingOrgan object — 所属营销机构(含 code/name/id)
  • createdtime string — 创建时间(格林威治时间戳)
  • updated string — 更新时间(格林威治时间戳)
  • madedate string — 建档日期(格林威治时间戳)

错误码

  • EXSV0011 服务名称不正确 → 检查 appKey/appSecret 是否缺失或未随 Header 发送
  • 401 appSecret不能为空 后端未注入 appSecret → 注入 CHANJET_CLIENT_SECRET 等环境变量后重启
  • token_expired openToken 失效 → 用 refresh_token 刷新(见 chanjet.authorize);refresh 也过期则重新授权
  • 1004 签名无效 → 检查签名算法与时间戳
  • parent 顺序错误 SelectFields 中 parent 排在 parent.id/parent.code/parent.name 之前 → 把 parent 放到 parent.id、parent.code、parent.name 之后

实战 tips

  • 真实返回结果【没有 result 外层】,直接是数组;返回字段与请求的 SelectFields 对应(默认 Code+Name),大小写与 SelectFields 一致
  • SelectFields 里 parent 必须放在 parent.id/parent.code/parent.name 之后,否则报错;只有指定了 parent.id,parent 结构里才会有 parent.id(code/name 同理)
  • 模糊查询走 T+ 基础信息模糊查询规则(t+baseinfolikequery),不是普通 SQL 通配符
  • 查上下级完整信息时,SelectFields 推荐写:id,code,name,isendnode,parent.id,parent.code,parent.name,parent
  • 与 chanjet.inventory_query(存货档案)区别:本接口查【分类树】,后者查【具体存货主数据】
官方文档 ↗
畅捷通 T+ / T+Cloud

存货档案查询

chanjet.inventory_query

HTTPS POST(inventory/Query) v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/inventory/Query

鉴权方式

openToken(用户授权令牌)+ appKey/appSecret(应用凭证,放 Header)

openToken 由授权流程获取,见 chanjet.authorize;请求头 Content-Type 固定 application/json

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥
  • openToken 必填 — 用户授权令牌
  • Content-Type 必填 — 固定 application/json

请求体说明

  • 请求体必须包裹在 param 对象内(与 inventoryClass/Query、currentStock/Query 同族约定)
  • 【核心坑·几千条存货】T+ Query 默认不自动翻页,只返回第一页;存货量大(几千条)时务必用 PageIndex 循环 + PageSize 拉全量,否则档案不全
  • PageSize 建议 100~200:太小要翻很多页,太大(尤其字段多)易超时(见 tips 超时设置)
  • 超大数据量建议按 InventoryClass.Code(分类)分段拉取,降低单次响应体积与超时概率
  • SelectFields 大小写敏感,返回字段名与请求一致;不传默认仅返回 Code+Name
  • 模糊查询(按名称/规格模糊)遵循 T+ 基础信息模糊查询规则(t+baseinfolikequery / LinkQuery),非 SQL 通配符

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/inventory/Query
Headers:
  appKey: h8fP2Fq0
  appSecret: A919E07C...
  openToken: user_auth_token_xxx
  Content-Type: application/json
Body:
{
  "param": {
    "PageIndex": 1,
    "PageSize": 100,
    "SelectFields": "id,code,name,spec,unit,InventoryClass.Code,InventoryClass.Name"
  }
}

响应示例

[
  {
    "Code": "001",
    "Name": "电脑",
    "Spec": "标准",
    "Unit": "台",
    "InventoryClass": { "Code": "03", "Name": "电子设备" }
  },
  {
    "Code": "002",
    "Name": "苹果手机",
    "Spec": "128G",
    "Unit": "台",
    "InventoryClass": { "Code": "03", "Name": "电子设备" }
  }
]

字段说明

  • Code string — 存货编码
  • Name string — 存货名称
  • Spec string — 规格型号(注意清洗多余空格/长小数等)
  • Unit string — 计量单位
  • InventoryClass object — 所属分类(含 Code/Name;SelectFields 指定 InventoryClass.Code 等才返回)
  • id string — 存货档案ID
  • ts string — 数据库时间戳

错误码

  • EXSV0011 服务名称不正确 → 检查 appKey/appSecret 是否缺失或未随 Header 发送
  • 401 appSecret不能为空 后端未注入 appSecret → 注入 CHANJET_CLIENT_SECRET 等环境变量后重启
  • token_expired openToken 失效 → 用 refresh_token 刷新(见 chanjet.authorize);refresh 也过期则重新授权
  • 1004 签名无效 → 检查签名算法与时间戳

实战 tips

  • 【最关键】存货几千条时务必分页拉全:循环 PageIndex(1,2,3...)直到某页返回空/不足 PageSize,把所有页结果本地合并;只取第一页会漏掉绝大多数档案
  • 大数据量按 InventoryClass.Code 分段(如先拉 01 类、再 02 类…),既能避免超时,也便于断点续拉
  • 必须设超时(建议 60~90s),T+ 大数据量响应慢,不设会卡死线程
  • SelectFields 大小写敏感,返回字段名与请求指定的大小写一致;默认只返回 Code、Name
  • 本接口查的是【存货档案主数据】(编码/名称/规格/分类),与 chanjet.stock_query(currentStock/Query,查各仓库现存数量)不是同一个接口,别混用
  • 若 SelectFields 含 InventoryClass.parent 等层级字段,注意 parent 须排在 parent.id/parent.code/parent.name 之后(同 inventoryClass 的坑,否则报错)
官方文档 ↗
畅捷通 T+ / T+Cloud

材料出库单明细表

chanjet.material_dispatch_detail

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 为用户授权令牌(参见 chanjet.authorize);本接口需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 材料出库单(生产领料)明细,ReportName=ST_MaterialDispatchDetailRpt
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);传 null 表示不按日期过滤(实测可返回全部)
  • ReportTableColNames 传空串 = 默认栏目(实测 29 栏,含车间/工作中心/班组/工人/设备等自定义栏)

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey: <appKey> / appSecret: <appSecret> / openToken: <access_token> / Content-Type: application/json
Body: {"request":{"ReportName":"ST_MaterialDispatchDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"VoucherDate","BeginDefault":null,"BeginDefaultText":null,"EndDefault":null,"EndDefaultText":null}],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 4,
  "ColumnSource": { "Rows": [ { "FieldName": "VoucherDate", "Title": "单据日期" }, { "FieldName": "Quantity", "Title": "数量" } ] },
  "DataSource": {
    "Rows": [
      { "VoucherDate": "2026-06-26", "VoucherCode": "MD-2026-06-0001", "BusinessType": "直接领料", "Warehouse": "原材料仓库", "DispatchStyle": "材料出库", "Inventory": "珍珠棉袋", "Specification": "200*200", "Unit": "件", "Quantity": "100.00", "Price": "", "Amount": "", "rowType": "D" }
    ]
  }
}

字段说明

  • VoucherDate string(YYYY-MM-DD) — 单据日期
  • VoucherCode string — 单据编号(如 MD-2026-06-0001)
  • CreatedTime string(datetime) — 创建时间
  • BusinessType string — 业务类型(如「直接领料」)
  • WarehouseCode string — 仓库编码
  • Warehouse string — 仓库名称
  • DispatchStyle string — 出库类别(如「材料出库」)
  • DepartmentCode string — 生产车间编码
  • Department string — 生产车间名称
  • RequestClerkCode string — 领料申请人编码
  • RequestClerk string — 领料申请人
  • ClerkCode string — 领用人编码
  • Clerk string — 领用人
  • Maker string — 制单人
  • Auditor string — 审核人
  • InventoryCode string — 材料编码
  • Inventory string — 材料名称
  • Specification string — 材料规格
  • AA_Department_Name string — 明细.生产车间(自定义扩展栏)
  • AA_WorkCenter_Name string — 工作中心(自定义扩展栏)
  • AA_ProcessTeam_Name string — 班组(自定义扩展栏)
  • AA_Person_Name string — 工人(自定义扩展栏)
  • AA_Equipment_Name string — 设备(自定义扩展栏)
  • Unit string — 计量单位
  • Quantity number — 数量(字符串,如 "100.00")
  • Price number — 单价(本例账户多为空)
  • Amount number — 金额(本例账户多为空)
  • DispatchAdjust number — 出库调整
  • DocCode string — 凭证字号

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:材料出库单、材料出库明细、领料单、生产领料、领料出库、出库单明细、出库单据、出入库单据(出库方向)
  • 数量字段是 Quantity,单价 Price、金额 Amount(与采购入库单不同:采购入库用小写 origPrice/origAmount)
  • 现场信息在自定义扩展栏:AA_Department_Name(车间) / AA_WorkCenter_Name(工作中心) / AA_ProcessTeam_Name(班组) / AA_Person_Name(工人) / AA_Equipment_Name(设备),未启用时为空串
  • 响应 DataSource.Rows 里 rowType='D' 才是明细行;GroupLevel/rowType/reportRowType 为内部结构字段,造报表建议过滤
  • 数量、金额均为字符串("100.00"),计算前需 Number();空值为空字符串 ""
  • 栏目以响应的 ColumnSource.Rows(FieldName/Title)为准,本报表默认 29 栏;可用 request.ReportTableColNames 指定栏目
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(实测:产成品入库默认方案 78 行/702698,只传 3 栏变 67 行/647698)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1),ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
  • 汇总核对口径:明细表按列求和后应与 T+ 同名「单据统计表」一致;对不上优先怀疑部分列丢行或分页截断,而不是统计口径(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

订单单据查询(总览)

chanjet.order_bills

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

采购订单与销售订单明细表共用同一端点,只改 request.ReportName;openToken 见 chanjet.authorize

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 订单类单据明细共 2 张表,接口路径与请求体结构完全相同,只换 request.ReportName:
  • ① 采购订单明细表 ReportName=PU_PurchaseOrderDetailRpt (⚠️ PU_ 前缀,实测 32 栏)
  • ② 销售订单明细表 ReportName=SA_SaleOrderDetailRpt (SA_ 前缀,实测 39 栏)
  • 日期过滤栏写 voucherdate(小写)或 VoucherDate 均可(实测一致);区间用 BeginDefault/EndDefault(YYYY-MM-DD),传 null = 不限日期
  • 一次只查一张表;要同时看采购与销售订单就分别调 2 次再合并
  • 订单 → 出入库的追溯:销售订单 SaleOrderCode 可关联销售出库单(ST_SaleDispatchDetailRpt);采购订单与采购入库单(ST_PurchaseReceiveDetailRpt)按存货编码 inventoryCode 关联

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body: {"request":{"ReportName":"SA_SaleOrderDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"voucherdate","BeginDefault":null,"EndDefault":null}],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 6,
  "ColumnSource": { "Rows": [ { "FieldName": "voucherdate", "Title": "单据日期" }, { "FieldName": "quantity", "Title": "数量" } ] },
  "DataSource": {
    "Rows": [
      { "voucherdate": "2026-06-27", "SaleOrderCode": "SO-2026-06-0003", "partnerName": "002", "inventoryName": "电脑", "unit1Name": "件", "quantity": "10.00", "origDiscountPrice": "5000.00", "origTaxAmount": "56500.00", "executedQuantity": "9.00", "rowType": "D" }
    ]
  }
}

字段说明

  • voucherdate string(YYYY-MM-DD) — 单据日期(两表通用,日期过滤栏)
  • PurchaseOrderCode string — 采购订单号(仅采购订单表,如 PO-2026-09-0001)
  • SaleOrderCode string — 销售订单号(仅销售订单表,如 SO-2026-06-0003)
  • PartnerName string — 供应商(采购订单表;无编码字段)
  • partnerName string — 客户(销售订单表)
  • inventoryCode string — 存货编码(两表通用,可跨表关联)
  • inventoryname string — 存货名称(采购订单表,全小写)
  • inventoryName string — 存货名称(销售订单表,大写 N)
  • Quantity number — 数量(采购订单表,大写 Q)
  • quantity number — 数量(销售订单表,小写 q)
  • VoucherStatename string — 订单状态(采购订单表:未审/生效)
  • SaleOrderState string — 单据状态(销售订单表:生效)
  • CountQuantity number — 累计执行数量(采购订单表)
  • executedQuantity number — 累计执行数量(销售订单表)
  • rowType string — 行类型:'D'=明细行(造报表须过滤保留)
  • GroupLevel string — 分组层级(内部结构字段,一般忽略)

错误码

  • 200 + TotalRecords=0 且栏目=0 报表码写错时【不报错】,静默返回空(实测 SA_PurchaseOrderDetailRpt 等即如此) → 采购订单必须用 PU_PurchaseOrderDetailRpt;销售订单用 SA_SaleOrderDetailRpt
  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:订单单据、订单明细、采购订单、销售订单、订货单、接单、PO 单、SO 单、客户订单、以销定采、订单执行进度
  • ⚠️ 两个表前缀不同:采购订单=PU_PurchaseOrderDetailRpt,销售订单=SA_SaleOrderDetailRpt;写错前缀不报错、只返回 0 条 + 0 栏
  • ⚠️ 字段名大小写两表还不一致(采购订单:departmentname/clerkname/inventoryname 全小写;销售订单:inventoryName/unit1Name 混用)→ 一律以 ColumnSource.Rows.FieldName 为准
  • 「订单执行进度」:销售订单用 executedQuantity÷quantity;采购订单用 CountQuantity÷Quantity(本账户 CountQuantity 常为空)
  • 金额口径两表一致:单价 origDiscountPrice、含税单价 origTaxPrice、金额 origDiscountAmount、税额 origTax、含税金额 origTaxAmount,TaxRate 0.1300=13%
  • 所有数量金额都是字符串("10.00"),计算前需 Number();空值是空字符串 ""
  • 响应 DataSource.Rows 含明细行与分组/合计行,rowType='D' 才是明细
  • 可做「订单 vs 出入库」对比:销售订单 → 销售出库单(SaleOrderCode 关联);采购订单 → 采购入库单(按存货编码关联)
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(实测:产成品入库默认方案 78 行/702698,只传 3 栏变 67 行/647698)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1),ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

往来期间对账单查询(PartnersAccountRpt/Query)

chanjet.partners_account_query

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/PartnersAccountRpt/Query

鉴权方式

openToken + appKey/appSecret(Header)

请求体整包再包裹一层 request 对象(不是 param)

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥
  • openToken 必填 — 用户授权令牌
  • Content-Type 必填 — 固定 application/json

请求体说明

  • 请求体顶层键为 request(不是 param)
  • ReportName 固定 ARAP_PartnersAccountRpt
  • SearchItems.ColumnName 支持:isIncludeNotAudit(含未审核0/1)、isIncludeDelivery(含已出库未开单)、isStoreInUnSettle(含采购已入库未结算)、isIncludeWRWarehouse(含委外已入库未结算)、DisplayCancleVoucher(显示已核销)、isDisplayInternalCancle(显示内部核销)、DisplayARAPCancelVoucher(显示核销单)、ReceiveVoucherDetailExpand(收款单按明细展开)、CheckDate(对账日期)、CheckType(对账方式 01以结算客户/02以供应商)、CheckAccountFlagMode(对账标记方式 01按单据/02按明细)、PartnerDTO.ID(往来单位)、DepartmentDTO.ID(部门)、PersonDTO.ID(业务员)、ProjectDTO.ID(项目)、DisplayStyle(栏目显示 01只应收/02只应付)、ContentDisplay(内容显示 01应收应付分列/02同列)、saleOrderCode(销售订单号)
  • 翻页(>1)需回传首查返回的 SolutionID + TaskSessionID

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/PartnersAccountRpt/Query
Headers: appKey / appSecret / openToken / Content-Type:application/json
Body:
{
  "request": {
    "ReportName": "ARAP_PartnersAccountRpt",
    "PageIndex": "1",
    "PageSize": 5,
    "SearchItems": [
      { "ColumnName": "CheckDate", "BeginDefault": "2024-10-01", "EndDefault": "2024-10-31" },
      { "ColumnName": "CheckType", "BeginDefault": "01" },
      { "ColumnName": "isIncludeNotAudit", "BeginDefault": "1" },
      { "ColumnName": "DisplayCancleVoucher", "BeginDefault": "1" }
    ]
  }
}

响应示例

{
  "ReportName": "ARAP_PartnersAccountRpt",
  "TotalRecords": 4,
  "ColumnSource": {
    "Rows": [
      { "Title": "结算往来单位", "FieldName": "SettlePartnerName" },
      { "Title": "单据编号", "FieldName": "VoucherCode" },
      { "Title": "应收(本币)", "FieldName": "RecAmount" },
      { "Title": "已收(本币)", "FieldName": "RecSettleAmount" },
      { "Title": "应付(本币)", "FieldName": "PayAmount" },
      { "Title": "余额", "FieldName": "TotalOrignalAmount" },
      { "Title": "是否已对账", "FieldName": "CheckFlag" }
    ]
  },
  "DataSource": {
    "Rows": [
      { "SettlePartnerName": "测试客户", "VoucherType": "收款单", "RecSettleAmount": "300.00", "TotalOrignalAmount": "23126.00", "CheckFlag": "否" }
    ]
  }
}

字段说明

  • request.ReportName string — 报表名称,固定 ARAP_PartnersAccountRpt
  • request.PageIndex / PageSize integer — 分页,从1开始
  • request.SearchItems[] array<object> — 查询项(ColumnName + BeginDefault/EndDefault 区间或 0/1)
  • DataSource.Rows[].SettlePartnerName / CustomerName string — 结算往来单位 / 客户
  • DataSource.Rows[].RecAmount / RecSettleAmount string — 应收(本币) / 已收(本币)
  • DataSource.Rows[].PayAmount / PaySettleAmount string — 应付(本币) / 已付(本币)
  • DataSource.Rows[].TotalOrignalAmount string — 余额
  • DataSource.Rows[].CheckFlag string — 是否已对账(是/否)
  • SolutionID / TaskSessionID string — 翻页凭证

错误码

  • EXSV0011 服务名称不正确 → 确认端点为 PartnersAccountRpt/Query 且 Body 顶层为 request

实战 tips

  • 往来应收应付对账单,ReportName=ARAP_PartnersAccountRpt;字段命名与通用报表一致(DataSource.Rows + ColumnSource.Rows)
  • 对账方式 CheckType:01 以结算客户为主 / 02 以供应商为主;内容显示 ContentDisplay:01 应收应付分列 / 02 同列
  • 翻页回传 SolutionID + TaskSessionID
  • 返回金额多为字符串(如 "300.00"),展示/计算前转 number
官方文档 ↗
畅捷通 T+ / T+Cloud

产成品入库单明细表

chanjet.product_receive_detail

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 为用户授权令牌(参见 chanjet.authorize);本接口需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 产成品入库(自制加工完入库)明细,ReportName=ST_ProductReceiveDetailRpt
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);传 null 表示不按日期过滤(实测可返回全部)
  • ReportTableColNames 传空串 = 默认栏目(实测 22 栏)

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey: <appKey> / appSecret: <appSecret> / openToken: <access_token> / Content-Type: application/json
Body: {"request":{"ReportName":"ST_ProductReceiveDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"VoucherDate","BeginDefault":null,"BeginDefaultText":null,"EndDefault":null,"EndDefaultText":null}],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 2,
  "ColumnSource": { "Rows": [ { "FieldName": "VoucherDate", "Title": "单据日期" }, { "FieldName": "ReceiveQuantity", "Title": "实收数量" } ] },
  "DataSource": {
    "Rows": [
      { "VoucherDate": "2026-06-26", "VoucherCode": "MC-2026-06-0001", "BusinessType": "自制加工", "Warehouse": "半成品仓库", "ReceiveStyle": "自制产品入库", "Inventory": "电脑", "Unit": "件", "ReceiveQuantity": "50.00", "Price": "", "Amount": "", "rowType": "D" }
    ]
  }
}

字段说明

  • VoucherDate string(YYYY-MM-DD) — 单据日期
  • VoucherCode string — 单据编号(如 MC-2026-06-0001)
  • CreatedTime string(datetime) — 创建时间
  • BusinessType string — 业务类型(如「自制加工」)
  • WarehouseCode string — 仓库编码
  • Warehouse string — 仓库名称
  • ReceiveStyle string — 入库类别(如「自制产品入库」)
  • DepartmentCode string — 生产车间编码
  • Department string — 生产车间名称
  • ClerkCode string — 经手人编码
  • Clerk string — 经手人
  • Memo string — 备注
  • Maker string — 制单人
  • Auditor string — 审核人
  • InventoryCode string — 存货编码
  • Inventory string — 存货(产成品)名称
  • Specification string — 规格型号
  • Unit string — 计量单位
  • ReceiveQuantity number — 实收数量(⚠️ 不是 Quantity)
  • Price number — 单价(本例账户多为空)
  • Amount number — 金额(本例账户多为空)
  • DocCode string — 凭证字号

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:产成品入库单、产成品入库明细、成品入库、自制入库、生产入库、完工入库、入库单明细、入库单据、出入库单据(入库方向)
  • 数量字段是 ReceiveQuantity(实收数量),不是 Quantity;单价 Price、金额 Amount
  • 响应 DataSource.Rows 里 rowType='D' 才是明细行;GroupLevel/rowType/reportRowType 为内部结构字段,造报表建议过滤
  • 数量、金额均为字符串("50.00"),计算前需 Number();空值为空字符串 ""
  • 栏目以响应的 ColumnSource.Rows(FieldName/Title)为准,本报表默认 22 栏;可用 request.ReportTableColNames 指定栏目
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」(如只传 日期+车间+数量 3 栏)时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(2026-09-28 实测:默认方案 78 行/合计 702698,只传 3 栏变 67 行/647698,少 55000)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1,只为了拿 ColumnSource),响应 ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页拉数据(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(映射不到的自定义列可原样附加进完整组合实测)(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:传整段区间只会从起始日返回约 1~3 天。可靠做法:按「上一批最大日期+1 天」向后递推分段拉取 + 全程按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
  • 汇总核对口径:明细表按列求和后应与 T+ 同名「单据统计表」一致;对不上优先怀疑 ReportTableColNames 部分列丢行或分页截断,而不是统计口径(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

采购订单明细表

chanjet.purchase_order_detail

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 为用户授权令牌(参见 chanjet.authorize);本接口需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • ⚠️ 采购订单明细表的报表码是 PU_PurchaseOrderDetailRpt(不是 SA_/ST_ 开头;SA_PurchaseOrderDetailRpt、ST_PurchaseOrderDetailRpt 实测均返回 0 条)
  • 日期过滤栏写 voucherdate(小写)或 VoucherDate 都可以,实测两者返回结果一致
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);传 null 表示不按日期过滤
  • ReportTableColNames 传空串 = 默认栏目(实测 32 栏)

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey: <appKey> / appSecret: <appSecret> / openToken: <access_token> / Content-Type: application/json
Body: {"request":{"ReportName":"PU_PurchaseOrderDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"voucherdate","BeginDefault":null,"BeginDefaultText":null,"EndDefault":null,"EndDefaultText":null}],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 2,
  "ColumnSource": { "Rows": [ { "FieldName": "voucherdate", "Title": "单据日期" }, { "FieldName": "Quantity", "Title": "数量" } ] },
  "DataSource": {
    "Rows": [
      { "voucherdate": "2026-09-09", "PurchaseOrderCode": "PO-2026-09-0001", "PartnerName": "dell", "VoucherStatename": "未审", "inventoryCode": "023", "inventoryname": "珍珠棉袋", "Specification": "200*200", "unitname": "件", "Quantity": "1000.00", "OrigDiscountPrice": "106.19", "TaxRate": "0.1300", "OrigTaxPrice": "120.00", "OrigDiscountAmount": "106194.69", "OrigTax": "13805.31", "OrigTaxAmount": "120000.00", "rowType": "D" }
    ]
  }
}

字段说明

  • voucherdate string(YYYY-MM-DD) — 单据日期(⚠️ 小写)
  • PurchaseOrderCode string — 单据编号(如 PO-2026-09-0001)
  • CreatedTime string(datetime) — 创建时间
  • PartnerName string — 供应商名称(⚠️ 本表无供应商编码字段)
  • departmentname string — 部门(⚠️ 小写)
  • clerkname string — 业务员(⚠️ 小写)
  • paytypename string — 付款方式
  • DeliveryModename string — 运输方式
  • AcceptAddress string — 到货地址
  • ContractId string — 合同号
  • VoucherStatename string — 订单状态(如「未审」「生效」)
  • inventoryCode string — 存货编码(⚠️ 小写 i)
  • inventoryname string — 存货名称(⚠️ 小写)
  • Specification string — 规格型号
  • unitname string — 采购单位(⚠️ 小写)
  • Quantity number — 数量(大写 Q)
  • OrigPrice number — 报价(常为空)
  • DiscountRate number — 折扣(%),1.0000 = 不打折
  • OrigDiscountPrice number — 单价(折扣后、不含税)
  • PreDiscountPrice number — 原单价(常为空)
  • TaxRate number — 税率,0.1300 = 13%
  • OrigTaxPrice number — 含税单价
  • PreTaxPrice number — 原含税单价(常为空)
  • OrigDiscountAmount number — 金额(不含税)
  • OrigTax number — 税额
  • OrigTaxAmount number — 含税金额
  • OrigDiscount number — 折扣金额(常为空)
  • AcceptDate string(YYYY-MM-DD) — 预计到货日期
  • IsPresent string — 赠品标记
  • CountQuantity number — 累计执行数量(已到货/已入库数量,常为空)
  • SaleOrderCode string — 销售订单号(以销定采时关联的销售订单)
  • DetailMemo string — 明细备注

错误码

  • 200 + TotalRecords=0 且栏目=0 报表码写错时【不报错】,静默返回空 → 核对 ReportName 是否为 PU_PurchaseOrderDetailRpt(PU_ 前缀)
  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:采购订单明细表、采购订单、采购订单明细、订货单、采购合同、PO 单、采购订单查询
  • ⚠️ 报表码前缀不是 SA_/ST_ 而是 PU_:PU_PurchaseOrderDetailRpt(实测 SA_PurchaseOrderDetailRpt / ST_PurchaseOrderDetailRpt / PO_PurchaseOrderDetailRpt 都是 0 条)
  • ⚠️ 报表码写错不会报错:返回 HTTP 200 + TotalRecords=0 + 栏目=0。看到「0 条且没有任何栏目」要先怀疑报表码,而不是「本月没有订单」
  • 字段名大小写不统一(voucherdate / departmentname / clerkname / inventoryCode / Quantity 混用),不要凭习惯拼字段名,一律以响应 ColumnSource.Rows 的 FieldName 为准
  • 金额口径:单价 OrigDiscountPrice(折扣后不含税)、含税单价 OrigTaxPrice、金额 OrigDiscountAmount、税额 OrigTax、含税金额 OrigTaxAmount;TaxRate 0.1300 表示 13%
  • 响应 DataSource.Rows 里 rowType='D' 才是明细行;GroupLevel/rowType/reportRowType 为内部结构字段,造报表建议过滤
  • 所有数量金额都是字符串("1000.00"),计算前需 Number();空值是空字符串 ""
  • 采购订单 → 采购入库单(ST_PurchaseReceiveDetailRpt)可做「订货 vs 到货」对比,用存货编码 inventoryCode 关联
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(实测:产成品入库默认方案 78 行/702698,只传 3 栏变 67 行/647698)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1),ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

采购订单执行情况

chanjet.purchase_order_executing

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 见 chanjet.authorize;需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 采购订单执行情况报表,来自 reportQuery/GetReportData,ReportName=PU_PurchaseOrderExecuteRpt
  • acceptDate = 采购订单的【预计到货日期】;过滤用 BeginDefault/EndDefault(YYYY-MM-DD,传 null = 不限)
  • voucherStateName = 单据状态,数值型(直接传数字,不引字符串);常用:181 单据未审 / 189 生效 / 231 中止 / 1125 生效未执行 / 1126 单据执行中 / 1127 单据执行完 / 1647 暂存 / 50041 审批中 / 51027 驳回 / 70392 待审核 / 609 未使用 / 606 已领用 / 608 已报销 / 607 作废 / 610 未封存 / 611 已封存
  • ⚠️ 与销售执行(saleOrder/QueryExecuting 业务 API)不同:本接口走 reportQuery,状态用【数字码】,且字段值多为【字符串】

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body:
{
  "request": {
    "ReportName": "PU_PurchaseOrderExecuteRpt",
    "PageIndex": 1,
    "PageSize": 5,
    "SearchItems": [
      { "ColumnName": "voucherStateName", "BeginDefault": 189, "BeginDefaultText": 189, "EndDefault": 189, "EndDefaultText": 189 },
      { "ColumnName": "acceptDate", "BeginDefault": null, "BeginDefaultText": null, "EndDefault": null, "EndDefaultText": null }
    ],
    "GroupItems": [],
    "ReportTableColNames": ""
  }
}

响应示例

{
  "TotalRecords": 10,
  "ColumnSource": { "Rows": [ { "FieldName": "voucherDate", "Title": "订单日期" }, { "FieldName": "acceptDate", "Title": "预计到货日期" }, { "FieldName": "partnerName", "Title": "供应商" }, { "FieldName": "salemanName", "Title": "分管人员" }, { "FieldName": "baseQuantity", "Title": "订单数量" }, { "FieldName": "QualityArrivalQtyInfo_BaseArrivalQuantity", "Title": "累计到货数量" }, { "FieldName": "voucherStateName", "Title": "状态" } ] },
  "DataSource": { "Rows": [ { "voucherDate": "2026-06-20", "acceptDate": "2026-06-30", "partnerName": "某供应商", "salemanName": "张三", "baseQuantity": "100.00", "QualityArrivalQtyInfo_BaseArrivalQuantity": "60.00", "voucherStateName": 189, "rowType": "D" } ] }
}

字段说明

  • voucherDate string — 订单日期
  • acceptDate string/null — 预计到货日期(过滤列)
  • partnerName string — 对应供应商
  • salemanName / clerkName string — 分管人员 / 业务员
  • baseQuantity string — 订单数量(主单位,字符串)
  • QualityArrivalQtyInfo_BaseArrivalQuantity string — 累计到货(入库)数量(主单位,字符串)
  • voucherStateName number — 状态(数值码,见状态字典)
  • DataSource.Rows / ColumnSource.Rows / TotalRecords array — 同 chanjet.report_query 通用结构

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken
  • 0 行 0 列 ReportName 不匹配该账户 → 到 T+ 取真实 ReportName 内部码(Ctrl+右键查看框架源代码)

实战 tips

  • 别名/检索词:采购订单执行、采购执行、订单执行情况、未入库、到货进度、采购跟踪
  • 🟢 180 账户实测可用:返回约 10 行,字段已全量映射(voucherDate/acceptDate/partnerName/salemanName/baseQuantity/QualityArrivalQtyInfo_BaseArrivalQuantity/voucherStateName)
  • 「未入库完毕」派生:过滤 voucherStateName=189(生效),客户端算 Number(baseQuantity) > Number(QualityArrivalQtyInfo_BaseArrivalQuantity||0),按 acceptDate 排序
  • ⚠️ 与销售执行接口(saleOrder/QueryExecuting)不是一族:本接口走 reportQuery 报表、状态用数字码、值多为字符串;销售执行走业务单据 API、状态用显示字符串、值为数字/null
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),先核对 ReportName
  • ⚠️ ReportTableColNames 只传「部分列」时 T+ 会套用更严过滤导致行集变少;须传「默认栏目全集 ∪ 需要列」。全集拿法:先不带该字段拉第 1 页,ColumnSource.Rows 即全部 FieldName,合并后再翻页
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:按「上一批最大日期+1 天」递推分段拉取 + 去重,直到超过 EndDefault
官方文档 ↗
畅捷通 T+ / T+Cloud

采购入库单明细表

chanjet.purchase_receive_detail

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 为用户授权令牌(参见 chanjet.authorize);本接口需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 入库/出库单据明细统一走 reportQuery/GetReportData,靠 ReportName 区分单据类型(本表=ST_PurchaseReceiveDetailRpt)
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);两值传 null 表示不按日期过滤(实测可返回全部)
  • ReportTableColNames 传空串 = 用报表默认栏目(实测返回 28 栏,见 fields)
  • GroupItems 为空数组即可;需要分组汇总时再放分组字段

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey: <appKey> / appSecret: <appSecret> / openToken: <access_token> / Content-Type: application/json
Body: {"request":{"ReportName":"ST_PurchaseReceiveDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"VoucherDate","BeginDefault":null,"BeginDefaultText":null,"EndDefault":null,"EndDefaultText":null}],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 1,
  "ColumnSource": { "Rows": [ { "FieldName": "VoucherDate", "Title": "单据日期" }, { "FieldName": "Quantity", "Title": "实收数量" } ] },
  "DataSource": {
    "Rows": [
      { "VoucherDate": "2026-06-26", "VoucherCode": "II-2026-06-0001", "BusinessType": "普通采购", "Warehouse": "原材料仓库", "Vendor": "dell", "Inventory": "电脑", "Unit": "件", "Quantity": "50.00", "origPrice": "30.00", "origAmount": "1500.00", "Totalamount": "1500.00", "rowType": "D" }
    ]
  }
}

字段说明

  • VoucherDate string(YYYY-MM-DD) — 单据日期
  • VoucherCode string — 单据编号(如 II-2026-06-0001)
  • CreatedTime string(datetime) — 创建时间
  • BusinessType string — 业务类型(如「普通采购」)
  • WarehouseCode string — 仓库编码
  • Warehouse string — 仓库名称
  • ReceiveStyle string — 入库类别(如「采购入库」)
  • VendorCode string — 供应商编码
  • Vendor string — 供应商名称
  • DepartmentCode string — 部门编码
  • Department string — 部门名称
  • ClerkCode string — 经手人编码
  • Clerk string — 经手人
  • Memo string — 备注
  • Maker string — 制单人
  • Auditor string — 审核人
  • InventoryCode string — 存货编码
  • Inventory string — 存货名称
  • Specification string — 规格型号
  • Unit string — 计量单位
  • Quantity number — 实收数量(字符串,如 "50.00")
  • origPrice number — 单价(⚠️ 字段名小写 orig)
  • origAmount number — 金额(⚠️ 字段名小写 orig)
  • ReceiveAdjust number — 入库调整
  • Feeadjust number — 费用调整
  • Totalamount number — 总成本
  • Feeamount number — 费用金额
  • DocCode string — 凭证字号

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:采购入库单、采购入库明细、入库单明细、入库单据、采购收货单、收货单、出入库单据(入库方向)、采购到货
  • 响应里 DataSource.Rows 是明细行(rowType='D');GroupLevel / rowType / reportRowType 是内部结构字段,造报表时建议只取 rowType='D' 的行
  • 单价/金额字段是小写 origPrice / origAmount(不是 Price / Amount),另有 Totalamount=总成本、Feeamount=费用金额
  • 所有数量与金额都是字符串("50.00"),计算前需 Number() 转换;空值是空字符串 "" 而不是 0
  • 栏目以响应的 ColumnSource.Rows(FieldName/Title)为准,本报表默认 28 栏;可用 request.ReportTableColNames 传逗号分隔的字段名只取需要的栏
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(实测:产成品入库默认方案 78 行/702698,只传 3 栏变 67 行/647698)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1),ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
  • 汇总核对口径:明细表按列求和后应与 T+ 同名「单据统计表」一致;对不上优先怀疑部分列丢行或分页截断,而不是统计口径(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

账龄分析与现金流量报表

chanjet.report_analysis_query

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

三张分析/明细报表共用同一端点,只改 request.ReportName;openToken 见 chanjet.authorize

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 应收/应付账龄分析 + 现金流量明细三张报表,接口路径与请求体结构完全相同,只换 request.ReportName:
  • ① 应收账龄分析 ReportName=ARAP_ReceiveAgeAnalysisSumRpt
  • ② 应付账龄分析 ReportName=ARAP_PaymentAgeAnalysisSumRpt
  • ③ 现金流量明细表 ReportName=GL_CashFlowDetailRpt
  • 通用机制(整包再包一层 request、日期区间 BeginDefault/EndDefault、ReportName 内部码、0 行 0 列静默空、ReportTableColNames 全集陷阱、EndDefault 分段拉取)见 chanjet.report_query

请求示例

① 应收账龄分析
POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body: {"request":{"ReportName":"ARAP_ReceiveAgeAnalysisSumRpt","PageIndex":1,"PageSize":5,"SearchItems":[],"GroupItems":[],"ReportTableColNames":""}}

② 应付账龄分析
{"request":{"ReportName":"ARAP_PaymentAgeAnalysisSumRpt","PageIndex":1,"PageSize":5,"SearchItems":[],"GroupItems":[],"ReportTableColNames":""}}

③ 现金流量明细表
{"request":{"ReportName":"GL_CashFlowDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 12,
  "ColumnSource": { "Rows": [ { "FieldName": "PartnerCode", "Title": "往来单位编码" }, { "FieldName": "Ageing1", "Title": "1-30天" } ] },
  "DataSource": { "Rows": [ { "PartnerCode": "C001", "PartnerName": "甲公司", "Ageing1": "1200.00", "Ageing2": "800.00" } ] }
}

字段说明

  • DataSource.Rows array — 数据行数组(账龄分析含往来单位与各账龄段金额;现金流量含各项目发生额)
  • ColumnSource.Rows array — 列定义(FieldName/Title),账龄段/项目名以实际返回为准
  • TotalRecords number — 总记录数

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken
  • 0 行 0 列 ReportName 不匹配该账户 → 到 T+ 取真实 ReportName 内部码(Ctrl+右键查看框架源代码)

实战 tips

  • 别名/检索词:应收账龄、应付账龄、账龄分析、现金流量表、现金流、现金流明细、资金流水
  • 三张表都来自同一端点 /tplus/api/v2/reportQuery/GetReportData,需应用已开通「报表」权限;好业财(tpluscloud)无此接口
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时 T+ 会套用过滤更严的方案导致行集变少;必须传「默认栏目全集 ∪ 需要列」;全集拿法:先不带该字段拉第 1 页,ColumnSource.Rows 即全部 FieldName,合并后再翻页
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行去重,直到超过 EndDefault
  • 账龄分析的账龄段(1-30天/31-60天…)列名以账户实际为准,建议先拉一页看 ColumnSource 再决定取哪些列;金额多为字符串,计算前需 Number()
  • 现金流量明细表的各项目(经营活动/投资活动/筹资活动现金流入流出)列名同样以账户 ColumnSource 为准,先用 PageSize=1 探明结构再取数
官方文档 ↗
畅捷通 T+ / T+Cloud

报表查询

chanjet.report_query

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

openToken + appKey/appSecret(同库存查询)

所有报表(含单据明细)都走同一端点,靠 request.ReportName 区分

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥
  • openToken 必填 — 用户授权令牌

请求体说明

  • 整包必须再包一层 request 对象
  • 日期区间用 BeginDefault / EndDefault(不是 BeginValue/EndValue)
  • ReportName 是账户特定的内部码:在 T+ 打开报表按 Ctrl+右键'查看框架源代码',链接里的 ReportName 即真实码

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers:
  appKey: h8fP2Fq0
  appSecret: A919E07C...
  openToken: user_auth_token_xxx
Body:
{
  "request": {
    "ReportName": "SA_SaleDeliveryDetailRpt",
    "PageIndex": 1,
    "PageSize": 50,
    "SearchItems": [{"ColumnName":"InvoiceDate","BeginDefault":"2026-01-01","EndDefault":"2026-07-24"}]
  }
}

响应示例

{
  "DataSource": { "Rows": [ { "Code":"XS-001", "InventoryName":"电脑", "Quantity":100, "WarehouseName":"汉南仓" } ] },
  "ColumnSource": { "Rows": [ {"FieldName":"Code","Title":"单据号"} ] },
  "TotalRecords": 4
}

字段说明

  • DataSource.Rows array — 数据行数组
  • ColumnSource.Rows array — 列定义(FieldName/Title)
  • TotalRecords number — 总记录数

错误码

  • EXSV0011 服务名称不正确 → 确认端点为 reportQuery/GetReportData 且 Body 包在 request 内
  • 0 行 0 列 ReportName 不匹配该账户 → 到 T+ 取真实 ReportName 内部码

实战 tips

  • 不要误用 reportQuery/GetReportData 之外的端点(如 SAReportQuery/*),会报 EXSV0011
  • 好业财(cloud/chanjetcc/zplus) 无报表 API,请改用 T+ 账户
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(实测:产成品入库默认方案 78 行/702698,只传 3 栏变 67 行/647698)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1),ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

销货单明细表

chanjet.sale_delivery_detail

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 为用户授权令牌(参见 chanjet.authorize);本接口需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 销货单明细表 ReportName=SA_SaleDeliveryDetailRpt(SA_ 前缀,与销售出库单 ST_SaleDispatchDetailRpt 不同,别混)
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);传 null 表示不按日期过滤
  • GroupItems 可按维度分组,例如 { ColumnName: "WarehouseInfo" } 按仓库分组
  • ReportTableColNames 指定返回列(逗号分隔 FieldName);传空串 = 默认栏目

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body: {"request":{"ReportName":"SA_SaleDeliveryDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"VoucherDate","BeginDefault":"2020-06-26","BeginDefaultText":"2020-06-26","EndDefault":"2020-06-30","EndDefaultText":"2020-06-30"}],"GroupItems":[{"ColumnName":"WarehouseInfo"}],"ReportTableColNames":"VoucherDate,saleDeliveryCode,partnerCode,partnerName"}}

响应示例

{
  "TotalRecords": 5,
  "ColumnSource": { "Rows": [ { "FieldName": "VoucherDate", "Title": "单据日期" }, { "FieldName": "saleDeliveryCode", "Title": "销货单号" } ] },
  "DataSource": { "Rows": [ { "VoucherDate": "2020-06-26", "saleDeliveryCode": "SD-2020-06-0001", "partnerCode": "0000003", "partnerName": "某客户", "rowType": "D" } ] }
}

字段说明

  • DataSource.Rows array — 数据行数组(销货单明细:日期/单号/客户/仓库/存货/数量金额等)
  • ColumnSource.Rows array — 列定义(FieldName/Title),实际列以账户 ColumnSource 为准
  • TotalRecords number — 总记录数

错误码

  • 200 + TotalRecords=0 且栏目=0 报表码写错时【不报错】,静默返回空 → 核对 ReportName 是否为 SA_SaleDeliveryDetailRpt
  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:销货单明细表、销货单、销货明细、发货单明细、SD 单、销售发货、销售出库(注意:销货单 SA_SaleDeliveryDetailRpt ≠ 销售出库单 ST_SaleDispatchDetailRpt,两者是不同单据)
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0;拿到「0 条且无栏目」应先核对 ReportName
  • 字段名大小写以响应 ColumnSource.Rows 的 FieldName 为准(示例列 VoucherDate/saleDeliveryCode/partnerCode/partnerName 为该账户实测,其他账户可能不同)
  • ⚠️ ReportTableColNames 只传「部分列」时 T+ 会套用更严的过滤方案导致行集变少;须传「默认栏目全集 ∪ 需要列」。全集拿法:先不带该字段拉第 1 页,ColumnSource.Rows 即全部 FieldName,合并后再翻页
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:按「上一批最大日期+1 天」递推分段拉取 + 去重,直到超过 EndDefault
  • GroupItems 分组后行集会按分组维度聚合,明细行 rowType='D';造报表按需过滤
  • 与销售订单(SA_SaleOrderDetailRpt)、销售出库(ST_SaleDispatchDetailRpt)可用单号关联做「订单→发货→出库」闭环
官方文档 ↗
畅捷通 T+ / T+Cloud

销售出库单明细表

chanjet.sale_dispatch_detail

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 为用户授权令牌(参见 chanjet.authorize);本接口需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 销售出库(发货)明细,ReportName=ST_SaleDispatchDetailRpt
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);传 null 表示不按日期过滤(实测可返回全部)
  • ReportTableColNames 传空串 = 默认栏目(实测 28 栏,含应发数量/数量/成本价/成本金额/销售订单号/入库单号)

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey: <appKey> / appSecret: <appSecret> / openToken: <access_token> / Content-Type: application/json
Body: {"request":{"ReportName":"ST_SaleDispatchDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"VoucherDate","BeginDefault":null,"BeginDefaultText":null,"EndDefault":null,"EndDefaultText":null}],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 9,
  "ColumnSource": { "Rows": [ { "FieldName": "VoucherDate", "Title": "单据日期" }, { "FieldName": "DeliveryQuantity", "Title": "应发数量" } ] },
  "DataSource": {
    "Rows": [
      { "VoucherDate": "2026-06-26", "VoucherCode": "IO-2026-06-0001", "BusinessType": "普通销售", "Warehouse": "原材料仓库", "DispatchStyle": "销售出库", "Customer": "test", "Department": "总经理室", "Clerk": "mike", "Inventory": "电脑", "Unit": "件", "DeliveryQuantity": "4.00", "Quantity": "4.00", "Price": "", "Amount": "", "rowType": "D" }
    ]
  }
}

字段说明

  • VoucherDate string(YYYY-MM-DD) — 单据日期
  • VoucherCode string — 单据编号(如 IO-2026-06-0001)
  • CreatedTime string(datetime) — 创建时间
  • BusinessType string — 业务类型(如「普通销售」)
  • WarehouseCode string — 仓库编码
  • Warehouse string — 仓库名称
  • DispatchStyle string — 出库类别(如「销售出库」)
  • CustomerCode string — 客户编码
  • Customer string — 客户名称
  • DepartmentCode string — 部门编码
  • Department string — 部门名称
  • ClerkCode string — 经手人编码
  • Clerk string — 经手人
  • MemberCardCode string — 会员卡号
  • Maker string — 制单人
  • Auditor string — 审核人
  • InventoryCode string — 存货编码
  • Inventory string — 存货名称
  • Specification string — 规格型号
  • Unit string — 计量单位
  • DeliveryQuantity number — 应发数量
  • Quantity number — 数量(出库数量)
  • Price number — 成本价(本例账户多为空)
  • Amount number — 成本金额(本例账户多为空)
  • DispatchAdjust number — 出库调整
  • SaleOrderCode string — 销售订单号(关联销售订单)
  • ReceiveVoucherCode string — 入库单号(关联入库单)
  • DocCode string — 凭证字号

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:销售出库单、销售出库明细、发货单、发货明细、销货出库、出库单明细、出库单据、出入库单据(出库方向)
  • 注意有两个数量:DeliveryQuantity(应发数量) 与 Quantity(数量);金额类是成本口径(Price 成本价 / Amount 成本金额),不是售价金额——要售价请查 SaleDetail(SA_SaleDetailRpt)
  • SaleOrderCode 关联销售订单号、ReceiveVoucherCode 关联入库单号,可做「订单→出库」追溯
  • 响应 DataSource.Rows 里 rowType='D' 才是明细行;GroupLevel/rowType/reportRowType 为内部结构字段,造报表建议过滤
  • 数量、金额均为字符串("4.00"),计算前需 Number();空值为空字符串 ""
  • 栏目以响应的 ColumnSource.Rows(FieldName/Title)为准,本报表默认 28 栏;可用 request.ReportTableColNames 指定栏目
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(实测:产成品入库默认方案 78 行/702698,只传 3 栏变 67 行/647698)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1),ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
  • 汇总核对口径:明细表按列求和后应与 T+ 同名「单据统计表」一致;对不上优先怀疑部分列丢行或分页截断,而不是统计口径(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

销售订单明细表

chanjet.sale_order_detail

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 为用户授权令牌(参见 chanjet.authorize);本接口需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 销售订单明细表 ReportName=SA_SaleOrderDetailRpt(SA_ 前缀)
  • 日期过滤栏写 voucherdate(小写)或 VoucherDate 均可,实测结果一致
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);传 null 表示不按日期过滤
  • ReportTableColNames 传空串 = 默认栏目(实测 39 栏)

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey: <appKey> / appSecret: <appSecret> / openToken: <access_token> / Content-Type: application/json
Body: {"request":{"ReportName":"SA_SaleOrderDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"voucherdate","BeginDefault":null,"BeginDefaultText":null,"EndDefault":null,"EndDefaultText":null}],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 6,
  "ColumnSource": { "Rows": [ { "FieldName": "voucherdate", "Title": "单据日期" }, { "FieldName": "quantity", "Title": "数量" } ] },
  "DataSource": {
    "Rows": [
      { "voucherdate": "2026-06-27", "SaleOrderCode": "SO-2026-06-0003", "partnerCode": "0000002", "partnerName": "002", "departmentName": "总经理室", "personName": "mike", "SaleOrderState": "生效", "inventoryCode": "021", "inventoryName": "电脑", "unit1Name": "件", "quantity": "10.00", "origDiscountPrice": "5000.00", "taxRate": "0.1300", "origTaxPrice": "5650.00", "origDiscountAmount": "50000.00", "origTax": "6500.00", "origTaxAmount": "56500.00", "executedQuantity": "9.00", "rowType": "D" }
    ]
  }
}

字段说明

  • voucherdate string(YYYY-MM-DD) — 单据日期(⚠️ 小写)
  • SaleOrderCode string — 单据编号(如 SO-2026-06-0003)
  • CreatedTime string(datetime) — 创建时间
  • partnerCode string — 客户编码
  • partnerName string — 客户名称
  • MemberCardCode string — 会员卡号
  • departmentCode string — 部门编码
  • departmentName string — 部门名称
  • personCode string — 业务员编码
  • personName string — 业务员
  • SettleCustomerCode string — 结算客户编码
  • SettleCustomer string — 结算客户
  • reciveTypeName string — 收款方式(⚠️ 原样拼写 recive)
  • deliveryModeName string — 运输方式
  • address string — 送货地址
  • contractCode string — 合同号
  • SaleOrderState string — 单据状态(如「生效」)
  • warehouseCode string — 仓库编码
  • WarehouseName string — 仓库名称(⚠️ 大写 W)
  • inventoryCode string — 存货编码
  • inventoryName string — 存货名称(⚠️ 大写 N)
  • specification string — 规格型号(⚠️ 小写 s)
  • unit1Name string — 销售单位
  • quantity number — 数量(⚠️ 小写 q)
  • LatestSaleOrigTaxPrice number — 最新含税售价(参考价)
  • origPrice number — 报价(常为空)
  • discountRate number — 折扣(%),1.0000 = 不打折
  • origDiscountPrice number — 单价(折扣后不含税)
  • taxRate number — 税率,0.1300 = 13%
  • origTaxPrice number — 含税单价
  • origDiscountAmount number — 金额(不含税)
  • origTax number — 税额
  • origTaxAmount number — 含税金额
  • origDiscount number — 折扣金额(常为空)
  • deliveryDate string(YYYY-MM-DD) — 交货日期
  • isPresent string — 赠品标记
  • executedQuantity number — 累计执行数量(已发货数量)
  • counteractQuantity number — 冲抵退货数量
  • DetailMemo string — 明细备注

错误码

  • 200 + TotalRecords=0 且栏目=0 报表码写错时【不报错】,静默返回空 → 核对 ReportName 是否为 SA_SaleOrderDetailRpt
  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:销售订单明细表、销售订单、订单明细、客户订单、接单、订货、SO 单、销售订单查询
  • 字段名大小写极不统一(voucherdate / partnerCode / WarehouseName / inventoryName / unit1Name / quantity 混用),必须按响应 ColumnSource.Rows 的 FieldName 取,不要凭习惯拼
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0;拿到「0 条且无栏目」应先核对 ReportName
  • 金额口径:单价 origDiscountPrice(折扣后不含税)、含税单价 origTaxPrice、金额 origDiscountAmount、税额 origTax、含税金额 origTaxAmount;LatestSaleOrigTaxPrice 是最新含税售价(非成交价)
  • 「订单执行进度」= executedQuantity(累计执行/已发货)÷ quantity(订货数量);counteractQuantity 为冲抵退货数量
  • 响应 DataSource.Rows 里 rowType='D' 才是明细行;GroupLevel/rowType/reportRowType 为内部结构字段,造报表建议过滤
  • 所有数量金额都是字符串("10.00"),计算前需 Number();空值是空字符串 ""
  • 销售订单 → 销售出库单(ST_SaleDispatchDetailRpt)可用 SaleOrderCode 关联做「接单 vs 发货」对比
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(实测:产成品入库默认方案 78 行/702698,只传 3 栏变 67 行/647698)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1),ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

销售订单执行情况查询

chanjet.sale_order_executing

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/saleOrder/QueryExecuting

鉴权方式

appKey + appSecret + openToken(Header)

openToken 见 chanjet.authorize;本接口是业务单据 API(非 reportQuery 报表),需应用有「销售订单」API 权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 这是业务单据 API(/tplus/api/v2/saleOrder/QueryExecuting),**不是 reportQuery 报表**;专门用于查销售订单的执行进度,避开了 reportQuery 里 SA_SaleOrderExecuteRpt 在开放平台「报表权限」未授权导致 0 列静默空的问题
  • WhereName 用点路径:SaleOrder.Code(订单编号)、SaleOrder.VoucherState(单据状态)、SaleOrder.Voucherdate(单据日期)、SaleOrder_Customer.Code(客户编码)、Warehouse.Code(仓库)、Inventory.Code/name(存货)、InventoryClass.Code(存货分类)
  • 枚举过滤须带 ValueType=enum + EnumName + BeginValue=显示值:单据状态 EnumName=VoucherState 取值 未审(00)/生效(01);出库状态 EnumName=VoucherOutStockState 取值 已出库(01)/未出库(00);结款状态 EnumName=VoucherSettleState 取值 已结清(settle)/未结清(nosettle)
  • ⚠️ 与 reportQuery 不同:这里 VoucherState 用【显示字符串】(生效/未审),不是数字码(181/189 那套);过滤时别混用
  • IsBetween=true 时 BeginValue/EndValue 构成区间;日期区间例:BeginValue=2020-03-17, EndValue=2020-03-20 59:59:59
  • 响应为 { Rows: [...] }(数组),无 reportQuery 那套 ColumnSource/TotalRecords 结构

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/saleOrder/QueryExecuting
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body:
{
  "queryParam": [
    { "WhereName": "SaleOrder.VoucherState", "ValueType": "enum", "EnumName": "VoucherState", "BeginValue": "生效" },
    { "IsBetween": "true", "BeginValue": "2026-06-01", "EndValue": "2026-12-31 59:59:59", "WhereName": "SaleOrder.Voucherdate" }
  ]
}

响应示例

{
  "Rows": [
    {
      "voucherDate": "/Date(1780934400000)/",
      "saleOrderCode": "SO-2026-06-0001",
      "partnerCode": "002",
      "partnerName": "002",
      "saleOrderState": "生效",
      "deliveryDate": null,
      "quantity": 8,
      "rDRecordQuantity": null,
      "SaleQuantity": null,
      "saleDeliveryCode": null,
      "inventoryCode": "021",
      "inventoryName": "电脑"
    }
  ]
}

字段说明

  • Rows array — 结果数组(每行=一张销售订单的明细执行行)
  • voucherDate string(/Date(ms)/) — 单据日期;⚠️ 实际返回 /Date(毫秒)/ 格式(如 /Date(1780934400000)/),需自行解析,不是文档示例的 '2015-03-20 00:00:00'
  • saleOrderCode string — 订单编号(如 SO-2026-06-0001)
  • partnerCode / partnerName string — 客户编码 / 名称
  • saleOrderState string — 订单状态:生效 / 未审 等
  • deliveryDate string/null — 交货日期;可能为 null
  • quantity number/null — 订单数量(销售单位);⚠️ 数字/ null,非字符串
  • rDRecordQuantity number/null — 累计出库数量(销售单位);未出库时为 null
  • SaleQuantity number/null — 实际销货数量(销售单位);未销货时为 null
  • saleDeliveryCode string/null — 销货单号;未生成时为 null
  • saleOrderNoSettleOrigAmount / saleInvoiceQuantity / saleInvoiceOrigTaxAmount number/null — 累计结算金额 / 累计开票数量 / 累计开票金额

错误码

  • 401/403 openToken 失效或无「销售订单」API 权限 → 重新授权绑定 ERP,或到开放平台给应用开通「销售订单」API 权限
  • 空 Rows(0 行) 过滤条件过严或无匹配 → 放宽 queryParam;检查 VoucherState 枚举值是否用显示字符串(生效/未审)而非数字码

实战 tips

  • 别名/检索词:销售订单执行、订单执行情况、订单执行进度、未发货、未出库、销售执行、SA 订单跟踪
  • 🟢 这是销售执行数据的【正解】:reportQuery 的 SA_SaleOrderExecuteRpt 在 180 账户经开放平台返回 0 列(报表权限未授权),本接口是独立授权的业务 API,实测可用(14 行/45 列)
  • 「未发货完毕」派生:先按 saleOrderState=生效 过滤,再在客户端算 Number(quantity) > Number(rDRecordQuantity || 0),按 deliveryDate(解析后)排序;deliveryDate 可能为 null 需兜底
  • 📅 日期解析:voucherDate / deliveryDate 实际是 /Date(毫秒)/ 文本,用正则提取数字 new Date(Number(ms));文档示例的 'yyyy-MM-dd HH:mm:ss' 与实测不符
  • 🔢 类型:quantity / rDRecordQuantity / SaleQuantity 是数字或 null(与 reportQuery 返回字符串不同),计算前无需字符串转数字,但需处理 null
  • 枚举过滤用显示值:VoucherState=生效/未审、VoucherOutStockState=已出库/未出库、VoucherSettleState=已结清(settle)/未结清(nosettle);务必带 ValueType=enum + EnumName
  • 与 chanjet.sale_order_detail(SA_SaleOrderDetailRpt 报表)互补:本接口直接给执行数量(出库/销货/开票),更适合作「未发货/未结清」类表格
官方文档 ↗
畅捷通 T+ / T+Cloud

现存量增量查询

chanjet.stock_increment_query

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/currentStock/QueryByTime

鉴权方式

openToken(用户授权令牌)+ appKey/appSecret(应用凭证,放 Header)

openToken 由授权流程获取,见 chanjet.authorize;appKey/appSecret 为畅捷通开放平台应用凭证

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥
  • openToken 必填 — 用户授权令牌
  • Content-Type 必填 — application/json

请求体说明

  • 请求体必须包裹在 queryParam 对象内(注意:不同于 currentStock/Query 用的 param,这里是 queryParam)
  • TimeBegin / TimeEnd 为必填,格式 YYYY-MM-DD HH:mm,返回【该时间段内发生变动的库存记录】(现存量增量/变动快照)
  • Warehouse 为可选数组,每项 {Code: 仓库编码};不传则查全部仓库
  • PageSize / PageIndex 可选,文档标注为 string;不传默认查所有数据
  • IsIncludeZero 可选 boolean,是否包含零库存行
  • OpenEcologIntePartnerCode / PartnerInventoryCodeList 为生态用字段,官方注明暂时无法使用,勿传

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/currentStock/QueryByTime
Headers:
  appKey: h8fP2Fq0
  appSecret: A919E07C...
  openToken: user_auth_token_xxx
  Content-Type: application/json
Body:
{
  "queryParam": {
    "TimeBegin": "2026-10-01 00:00",
    "TimeEnd": "2026-10-27 23:59",
    "PageSize": "50",
    "PageIndex": "1"
  }
}

响应示例

[
  {
    "WarehouseID": "1",
    "WarehouseName": "原材料仓库",
    "WarehouseCode": "1",
    "InventoryID": "537",
    "InventoryCode": "021",
    "InventoryName": "袋子",
    "InventoryClassCode": ".01",
    "InventoryClassName": "成品",
    "UnitName": "件",
    "Specification": "14246-GY-70",
    "Brand": "",
    "IsSingleUnit": true,
    "AvailableQuantity": "2.00000000000000",
    "ExistingQuantity": "2.00000000000000",
    "TS": "0x0000000000f51bc1",
    "TotalCount": 1,
    "Batch": null,
    "ProductionDate": null,
    "ExpiryDate": null,
    "DynamicPropertyKeys": [],
    "DynamicPropertyTitles": [],
    "DynamicPropertyValues": []
  }
]

字段说明

  • WarehouseID / WarehouseName / WarehouseCode string — 仓库 ID / 名称 / 编码
  • InvLocationName / InvLocationCode (IDInvLocation) string — 货位 名称 / 编码(无货位时为 null/空)
  • InventoryID / InventoryCode / InventoryName string — 存货 ID / 编码 / 名称
  • InventoryClassCode / InventoryClassName string — 存货分类 编码 / 名称
  • DefaultBarCode / InvBarCode string — 默认条码 / 存货条码
  • UnitID / UnitName / Specification / Brand string — 主单位 ID / 名称 / 规格型号 / 品牌
  • IsSingleUnit / IsSale boolean — 是否单单位(boolean)/ 是否可销售(boolean)
  • AvailableQuantity / ExistingQuantity string(数字字符串) — 可用数量 / 现存数量——【字符串,带超长小数,如 "2.00000000000000",必须转 number 并清洗后展示】
  • UnitID2 / UnitName2 / AvailableQuantity2 / ExistingQuantity2 string — 第二单位(双单位计量)ID / 名称 / 可用数量 / 现存数量,单单位时为 null
  • TS string — 数据版本戳(时间戳标记),可用于增量比对/缓存
  • TotalCount number — 行级计数(实测每行返回 1,疑似该记录标记;非总条数)
  • SkuCode / Batch / ProductionDate / ExpiryDate string — SKU / 批号 / 生产日期 / 失效日期(无则为 null)
  • IdBom/BomCode/BomName, IdDetailPartner/DetailPartnerCode/Name, IdProject/ProjectCode/Name, IdTraceNumber/... string — 扩展关联:BOM、明细往来单位、项目、追溯号等,按需取用
  • DynamicPropertyKeys / DynamicPropertyTitles / DynamicPropertyValues array — 自由项/自定义项 键、标题、值数组(对应 T+ 自由项 FreeItem)

错误码

  • EXSV0011 服务名称不正确 / 接口未授权 → 检查 appKey/appSecret 是否缺失或未随 Header 发送
  • token_expired openToken 失效 → 用 permanentCode 重新换发,或引导用户重新授权
  • 1004 签名无效 → 检查签名算法与时间戳

实战 tips

  • ⚠️ 响应是【顶层 JSON 数组】,不是文档写的 {result:[...]};文档把 result 标成 Array<string> 也错,实际是对象数组——解析时直接当数组处理(实测 json 顶层即为数组)
  • ⚠️ 数量字段是带超长小数的字符串(如 "2.00000000000000"),展示前务必 Number() 后清洗,避免浮点精度与长尾 0 问题(与 stock_query 同坑)
  • TimeBegin/TimeEnd 格式 YYYY-MM-DD HH:mm;返回的是【该时段内发生变动的库存快照】,不是某刻全量库存——要全量现存量用 chanjet.stock_query(currentStock/Query)
  • 与 stock_query 区别:本接口按「时间增量」返回变动记录,适合做库存变化同步、对账、增量拉取;stock_query 是某刻全量快照
  • IsIncludeZero=true 才返回零库存行;默认可能仅返回有变动/非零行
  • Warehouse 过滤用 [{Code:'仓库编码'}] 数组,可一次传多个仓库
  • TS 字段可作为增量比对键,配合定时轮询实现「上次 TS 之后的变动」同步
  • OpenEcologIntePartnerCode / PartnerInventoryCodeList 官方注明暂不可用,忽略
官方文档 ↗
畅捷通 T+ / T+Cloud

出入库单据查询(总览)

chanjet.stock_inout_bills

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

五张出入库单据明细表(采购入库/材料出库/产成品入库/销售出库/其他出库)共用同一个端点,只改 request.ReportName;openToken 见 chanjet.authorize

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 物料出入口共 5 张单据明细表,接口路径与请求体结构完全相同,只换 request.ReportName:
  • ① 采购入库单明细表 ReportName=ST_PurchaseReceiveDetailRpt (入库·外购)
  • ② 材料出库单明细表 ReportName=ST_MaterialDispatchDetailRpt(出库·生产领料)
  • ③ 产成品入库单明细表 ReportName=ST_ProductReceiveDetailRpt (入库·自制完工)
  • ④ 销售出库单明细表 ReportName=ST_SaleDispatchDetailRpt (出库·销售发货)
  • ⑤ 其他出库单明细表 ReportName=ST_OtherDispatchDetailRpt (出库·其他,如调拨/盘亏/领用)
  • 日期区间用 SearchItems[].BeginDefault/EndDefault(YYYY-MM-DD);传 null = 不限日期(实测返回全部)
  • 一次只查一张表;要「全部出入库」就分别调 5 次再合并(响应无统一单据类型字段)

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body: {"request":{"ReportName":"ST_OtherDispatchDetailRpt","PageIndex":1,"PageSize":5,"SearchItems":[{"ColumnName":"VoucherDate","BeginDefault":null,"EndDefault":null}],"GroupItems":[],"ReportTableColNames":""}}

响应示例

{
  "TotalRecords": 9,
  "ColumnSource": { "Rows": [ { "FieldName": "VoucherDate", "Title": "单据日期" }, { "FieldName": "DeliveryQuantity", "Title": "应发数量" } ] },
  "DataSource": {
    "Rows": [
      { "VoucherDate": "2026-06-26", "VoucherCode": "IO-2026-06-0001", "Warehouse": "原材料仓库", "Inventory": "电脑", "Unit": "件", "DeliveryQuantity": "4.00", "Quantity": "4.00", "rowType": "D" }
    ]
  }
}

字段说明

  • VoucherDate string(YYYY-MM-DD) — 单据日期(五表通用,日期过滤栏)
  • VoucherCode string — 单据编号(五表通用)
  • BusinessType string — 业务类型(普通采购 / 直接领料 / 自制加工 / 普通销售 / 其他)
  • WarehouseCode string — 仓库编码
  • Warehouse string — 仓库名称(五表通用)
  • InventoryCode string — 存货/材料编码(五表通用)
  • Inventory string — 存货/材料名称(五表通用)
  • Specification string — 规格型号
  • Unit string — 计量单位
  • Quantity number — 数量(采购入库=实收数量;材料出库=数量;销售出库=出库数量;其他出库=数量)
  • ReceiveQuantity number — 实收数量(仅产成品入库单)
  • DeliveryQuantity number — 应发数量(仅销售出库单)
  • rowType string — 行类型:'D'=明细行(造报表须过滤保留)
  • GroupLevel string — 分组层级(内部结构字段,一般忽略)

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限;确认 appKey/appSecret 正确
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken

实战 tips

  • 别名/检索词:出入库单据、出入库明细、物料出入库、物料进出、进销存单据、库存单据、收货单、入库单、出库单、领料单、发货单、完工入库、其他出库、盘点差异(不含)
  • 「某段时间物料收了多少、发了多少」= 用 VoucherDate 过滤 + 按 Inventory/Warehouse 汇总 Quantity(入库取采购入库+产成品入库,出库取材料出库+销售出库+其他出库)
  • ⚠️ 各表数量字段名不同:采购入库=Quantity、材料出库=Quantity、产成品入库=ReceiveQuantity、销售出库=DeliveryQuantity(应发)/Quantity(实出)、其他出库=Quantity。写通用汇总逻辑时要按表映射
  • ⚠️ 单价/金额字段名也不同:采购入库是小写 origPrice/origAmount(另有 Totalamount 总成本);材料出库/产成品入库/销售出库/其他出库是 Price/Amount。本例账户中 Price/Amount 多返回空串,采购入库的 origAmount 有值
  • 响应 DataSource.Rows 含明细行与分组/合计行,rowType='D' 才是明细;GroupLevel/rowType/reportRowType 为内部结构字段
  • 所有数量与金额都是字符串("50.00"),计算前需 Number();空值是空字符串 "" 而非 0
  • 栏目以每张表响应里的 ColumnSource.Rows(FieldName/Title)为准;可用 request.ReportTableColNames 传逗号分隔字段名只取需要的栏
  • 五张单据表都来自同一端点 /tplus/api/v2/reportQuery/GetReportData,需应用已开通「报表」权限;好业财(tpluscloud)无此接口
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),拿到「0 条且无栏目」先核对 ReportName 再下结论
  • ⚠️ ReportTableColNames 只传「部分列」时,T+ 会套用另一个过滤更严的方案 → 行集凭空变少(实测:产成品入库默认方案 78 行/702698,只传 3 栏变 67 行/647698)。传栏目必须传「默认栏目全集 ∪ 需要列」的完整组合(更新:畅小虾团队 2026-09-28)
  • 栏目全集拿法:先不带 ReportTableColNames 拉第 1 页(PageSize 可为 1),ColumnSource.Rows 即全部合法 FieldName/Title;把需要列合并进全集后再翻页(更新:畅小虾团队 2026-09-28)
  • 自定义字段/中文列名:ReportTableColNames 只认 FieldName;中文显示名须先按 ColumnSource 的 Title 映射成 FieldName 再传(更新:畅小虾团队 2026-09-28)
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:可靠做法是按「上一批最大日期+1 天」向后递推分段拉取 + 按行内容去重,直到超过 EndDefault(更新:畅小虾团队 2026-09-28)
  • 汇总核对口径:明细表按列求和后应与 T+ 同名「单据统计表」一致;对不上优先怀疑部分列丢行或分页截断,而不是统计口径(更新:畅小虾团队 2026-09-28)
官方文档 ↗
畅捷通 T+ / T+Cloud

库存查询

chanjet.stock_query

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/currentStock/Query

鉴权方式

openToken(用户授权令牌)+ appKey/appSecret(应用凭证,放 Header)

openToken 由授权流程获取,见 chanjet.authorize;appKey/appSecret 为畅捷通开放平台应用凭证

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥
  • openToken 必填 — 用户授权令牌

请求体说明

  • 请求体必须包裹在 param 对象内,不能直接用扁平字段 InventoryCode/WarehouseCode(会查空)
  • 不传 Inventory / Warehouse 则查全量
  • 按名称口语查询时(如'电脑'),建议先拉全量再在本地按名称/编码/条码过滤

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/currentStock/Query
Headers:
  appKey: h8fP2Fq0
  appSecret: A919E07C...
  openToken: user_auth_token_xxx
Body:
{
  "param": {
    "PageIndex": 1,
    "PageSize": 50,
    "Inventory": [{"Code": "001"}],
    "Warehouse": [{"Code": "01"}]
  }
}

响应示例

[
  {
    "InventoryCode": "001",
    "InventoryName": "电脑",
    "WarehouseName": "汉南仓",
    "ExistingQuantity": 195.0000,
    "UnitName": "台"
  }
]

字段说明

  • InventoryCode string — 商品编码
  • InventoryName string — 商品名称
  • WarehouseName string — 仓库名称
  • ExistingQuantity number — 现存数量(注意带长小数如 195.0000,需清洗)
  • UnitName string — 计量单位

错误码

  • EXSV0011 服务名称不正确 → 检查 appKey/appSecret 是否缺失或未随 Header 发送
  • token_expired openToken 失效 → 用 permanentCode 重新换发,或引导用户重新授权
  • 1004 签名无效 → 检查签名算法与时间戳

实战 tips

  • ExistingQuantity 返回如 195.0000,展示前务必清洗掉长小数
  • 口语仓库名('汉南仓')与 ERP 内仓库名可能不一致,建议拉全量后本地模糊匹配
  • T+Cloud 走 T+ API(currentStock/Query),不需要 bookId;好业财(cloud) 才需要账套
官方文档 ↗
畅捷通 T+ / T+Cloud

收发存汇总表

chanjet.stock_summary

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData

鉴权方式

appKey + appSecret + openToken(Header)

openToken 见 chanjet.authorize;需应用已开通「报表」权限

请求头

  • appKey 必填 — 开放平台应用 ID
  • appSecret 必填 — 应用密钥
  • openToken 必填 — 用户授权令牌 access_token
  • Content-Type 必填 — application/json

请求体说明

  • 收发存汇总表,来自 reportQuery/GetReportData,ReportName=ST_RDSSummaryRpt
  • ✅ 180 账户实测可用(关键突破):日期过滤用 VoucherDate 区间(YYYY-MM-DD..YYYY-MM-DD,单月值会报错),并把 7 个布尔开关全部置为字符串 "1"(对应 T+ 界面的勾选框),报表即返回 24 列、含期初/入库/出库/期末结存的数量、单价、金额
  • ⚠️ 布尔开关值格式:必须是字符串 "1"。实测 "true"、JSON true、"是" 均无效(仍只回 8 个维度列)。7 个开关:IsPeriodStart=期初结存、IsReceive=本期入库、IsDispatch=本期出库、IsStock=期末结存、IsBaseQuantity=数量(主单位)、IsAmount=金额、IsPrice=单价。⚠️ 只开 IsAmount/IsBaseQuantity 等「列型」开关不够,必须连 IsPeriodStart/IsReceive/IsDispatch/IsStock 这 4 个「组」开关一起开,否则度量列不出现
  • ⚠️ Period(期间)字段传任何非空值都会令报表服务内部报错(ReportName:null, ColumnSource:null)——不要用 Period,日期一律用 VoucherDate 区间
  • 行结构:rowType="S" 为小计/汇总行(GroupLevel=0,只有仓库维度、无存货),rowType="D" 为明细行(仓库×存货)。做库存合计请按 rowType 过滤,避免重复累计

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/reportQuery/GetReportData
Headers: appKey / appSecret / openToken / Content-Type: application/json
Body:
{
  "request": {
    "ReportName": "ST_RDSSummaryRpt",
    "PageIndex": 1,
    "PageSize": 5,
    "SearchItems": [
      { "ColumnName": "VoucherDate", "BeginDefault": "2026-10-01", "BeginDefaultText": "2026-10-01", "EndDefault": "2026-10-31", "EndDefaultText": "2026-10-31" },
      { "ColumnName": "IsPeriodStart", "BeginDefault": "1", "BeginDefaultText": "1", "EndDefault": null, "EndDefaultText": null },
      { "ColumnName": "IsReceive",    "BeginDefault": "1", "BeginDefaultText": "1", "EndDefault": null, "EndDefaultText": null },
      { "ColumnName": "IsDispatch",   "BeginDefault": "1", "BeginDefaultText": "1", "EndDefault": null, "EndDefaultText": null },
      { "ColumnName": "IsStock",      "BeginDefault": "1", "BeginDefaultText": "1", "EndDefault": null, "EndDefaultText": null },
      { "ColumnName": "IsBaseQuantity","BeginDefault": "1", "BeginDefaultText": "1", "EndDefault": null, "EndDefaultText": null },
      { "ColumnName": "IsAmount",     "BeginDefault": "1", "BeginDefaultText": "1", "EndDefault": null, "EndDefaultText": null },
      { "ColumnName": "IsPrice",      "BeginDefault": "1", "BeginDefaultText": "1", "EndDefault": null, "EndDefaultText": null }
    ],
    "GroupItems": [],
    "ReportTableColNames": ""
  }
}

响应示例

{
  "TotalRecords": 2834,
  "DataSource": { "Rows": [
    { "IDWarehouse": "1", "WarehouseCode": "1", "Warehouse": "原材料仓库", "[BeginColumn-期初结存][BeginBaseQuantity-数量(主单位)]": "8216.00", "[BeginColumn-期初结存][BeginPrice-平均单价]": "26.02", "[BeginColumn-期初结存][BeginAmount-金额]": "213772.34", "[ReceiveColumn-本期入库][ArrivalBaseQuantity-数量(主单位)]": "102756.00", "[ReceiveColumn-本期入库][ArrivalPrice-平均单价]": "57.55", "[ReceiveColumn-本期入库][ArrivalAmount-金额]": "5913503.81", "[DispatchColumn-本期出库][DispatchBaseQuantity-数量(主单位)]": "104060.00", "[DispatchColumn-本期出库][DispatchPrice-平均单价]": "58.71", "[DispatchColumn-本期出库][DispatchAmount-金额]": "6109808.30", "[StockColumn-期末结存][BaseQuantity-数量(主单位)]": "6912.00", "[StockColumn-期末结存][Price-平均单价]": "2.53", "[StockColumn-期末结存][Amount-金额]": "17467.85", "GroupLevel": "0", "rowType": "S" },
    { "IDInventory": "537", "InventoryCode": "0003", "Inventory": "袋子", "Specification": "14246-GY-70", "BaseUnit": "件", "[BeginColumn-期初结存][BeginBaseQuantity-数量(主单位)]": "168.00", "[StockColumn-期末结存][BaseQuantity-数量(主单位)]": "168.00", "GroupLevel": "1", "rowType": "D" }
  ] }
}

字段说明

  • IDWarehouse / WarehouseCode / Warehouse string — 仓库 ID / 编码 / 名称(维度列)
  • IDInventory / InventoryCode / Inventory / Specification / BaseUnit string — 存货 ID / 编码 / 名称 / 规格型号 / 主单位(维度列,小计行 rowType=S 时为空)
  • [BeginColumn-期初结存][BeginBaseQuantity-数量(主单位)] / [BeginPrice-平均单价] / [BeginAmount-金额] string(数字字符串) — 期初结存 数量 / 平均单价 / 金额。⚠️ 取值必须用「完整带中文方括号的键名」,如 row['[StockColumn-期末结存][Amount-金额]']
  • [ReceiveColumn-本期入库][ArrivalBaseQuantity-数量(主单位)] / [ArrivalPrice-平均单价] / [ArrivalAmount-金额] string(数字字符串) — 本期入库 数量 / 平均单价 / 金额
  • [DispatchColumn-本期出库][DispatchBaseQuantity-数量(主单位)] / [DispatchPrice-平均单价] / [DispatchAmount-金额] string(数字字符串) — 本期出库 数量 / 平均单价 / 金额
  • [StockColumn-期末结存][BaseQuantity-数量(主单位)] / [Price-平均单价] / [Amount-金额] string(数字字符串) — 期末结存 数量 / 平均单价 / 金额——「库存金额收发存口径」就取这三列(期末结存=所选日期区间末日的库存)
  • GroupLevel / rowType string — GroupLevel:分组层级(0=仓库级小计)。rowType:S=小计/汇总行(无存货维度),D=明细行。合计时只取一种,避免重复累计

错误码

  • EXSV0011 服务名称不正确 / 报表接口未开通 → 到畅捷通开放平台给应用开通「报表」API 权限
  • 401/403 openToken 失效或无权限 → 重新授权绑定 ERP,或用 refreshToken 换新 accessToken
  • ReportName:null / ColumnSource:null / TotalRecords:0 给 Period 字段传了非空值(开放平台不支持该报表的期间参数),或 VoucherDate 只传了月份(如 2026-10)而非完整日期区间 → 日期一律用 VoucherDate 区间(YYYY-MM-DD..YYYY-MM-DD);布尔开关用字符串 "1"
  • 0 行 0 列 ReportName 不匹配该账户 → 到 T+ 取真实 ReportName 内部码

实战 tips

  • 别名/检索词:收发存、收发存汇总、库存汇总、进销存汇总、结存、期末结存
  • ✅ 180 账户实测可用:VoucherDate 区间 + 7 个布尔开关全置 "1" → 24 列(含期初/入库/出库/期末结存 数量·单价·金额),TotalRecords=2834。期末结存=今日库存,直接支撑「库存金额收发存口径」
  • ⚠️ 布尔开关只认字符串 "1":"true"、JSON true、"是" 均无效。且必须连 IsPeriodStart/IsReceive/IsDispatch/IsStock 四个「组」开关一起开(只开 IsAmount/IsBaseQuantity 不出度量列)
  • ⚠️ 列名带中文方括号:取值必须用完整键名,如 row['[StockColumn-期末结存][Amount-金额]'];建议封装取值函数按「组名+指标名」定位
  • ⚠️ rowType 区分:S=小计行(仅仓库维度,存货列为空)、D=明细行。算全仓合计取 S 行(或对 D 行求和),别把 S 和 D 加在一起
  • ⚠️ Period 禁用:传任何非空值必报 ReportName:null;日期过滤用 VoucherDate 区间
  • 🔁 需要实时现存量(不按日期区间)可配合 chanjet.stock_query(即时库存)
  • ⚠️ 报表码写错不会报错:HTTP 200 + TotalRecords=0 + 栏目=0(静默空),先核对 ReportName
  • ⚠️ 日期区间 EndDefault 经常失效,且单页约 200 行后不再翻页:按「上一批最大日期+1 天」递推分段拉取 + 去重
官方文档 ↗
畅捷通 T+ / T+Cloud

仓库列表

chanjet.warehouse_list

HTTPS POST v1.0.0 ▾

接口地址

https://openapi.chanjet.com/tplus/api/v2/warehouse/Query

鉴权方式

openToken + appKey/appSecret

与库存查询共用鉴权

请求头

  • appKey 必填 — 开放平台应用ID
  • appSecret 必填 — 开放平台应用密钥
  • openToken 必填 — 用户授权令牌

请求体说明

  • 返回当前账户下全部仓库,用于库存查询时映射仓库编码/名称

请求示例

POST https://openapi.chanjet.com/tplus/api/v2/warehouse/Query
Headers:
  appKey: h8fP2Fq0
  appSecret: A919E07C...
  openToken: user_auth_token_xxx
Body:
{ "param": { "PageIndex": 1, "PageSize": 100 } }

响应示例

[
  { "Code": "01", "Name": "汉南仓" },
  { "Code": "02", "Name": "武昌仓" }
]

字段说明

  • Code string — 仓库编码(库存查询 Warehouse[].Code 用此值)
  • Name string — 仓库名称

错误码

  • EXSV0011 服务名称不正确 → 检查 appKey/appSecret 与端点

实战 tips

  • 口语'汉南仓'对应 Name='汉南仓'、Code='01',建议本地建立名称→编码映射
官方文档 ↗
涂鸦智能 Tuya Smart

设备查询与控制(按账户隔离)

tuya.device_control

HTTPS POST(涂鸦开放平台 /v1.0/devices/... 业务接口,服务端用云项目 token 签名) v1.0.0 ▾

接口地址

https://openapi.tuyacn.com/v1.0/devices/{device_id}/commands

鉴权方式

云项目 token(TUYA_ACCESS_ID/SECRET 签名);按 user_id 解析出的 vendor_uid 圈定可见设备

隔离 100% 由我们代码负责:C端用户授权账户给项目后,项目 token 能管所有已授权用户设备,API 层不隔离

请求体说明

  • 查询/控制一律「严格按手机号(user_id 主码)解析 uid → 用项目 token 操作该 uid 下设备」
  • assertDeviceOwnership 在 controlDevice/getDeviceStatus/sendIrCommand 执行前校验 device_id 归属当前 user_id,不一致即拒绝(fail-closed)
  • 红外(IR)因是云项目级接口,无法按账户隔离,隔离只能靠 devices 表归属校验 + strictEmpty

请求示例

POST /v1.0/devices/{device_id}/commands
Headers: client_id=TUYA_ACCESS_ID, sign=SHA256(...), access_token=<project_token>
Body: {'commands':[{'code':'switch_1','value':true}]}

响应示例

{ 'result': true, 'success': true }

字段说明

  • device_id string — 设备 ID(devices 表归属当前账户)
  • user_id string — 手机号主码,设备可见性边界

错误码

  • 1106 permission deny 用【用户 OAuth token】调红外(IR)接口;IR 必须走云项目 token → IR 接口统一走项目 token 回退通道(control_tuya_device 的 sendIrCommand 已内置回退)
  • 60001001 可控设备池配额耗尽(设备经 commands 进入可控模式占 1 名额,红外下发也占名额) → 在涂鸦控制台为项目提额(设备池配额,与调用频率限流是两套治理体系)
  • 该设备未绑定到当前账户,无法控制 assertDeviceOwnership fail-closed 拒绝:device_id 不在本手机号设备集合 → 确认该用户已完成授权+同步数据,设备已写入 devices 表归属;幽灵归属(多手机号误登记同一涂鸦账户)需清理 devices 行
  • sign invalid / 1004 签名串中 device_ids 的逗号被编码成 %2C → 排序后用原始字符逗号(sortQueryStringRaw),勿 urlencode 逗号

实战 tips

  • 铁律:API 层不隔离账户,涂鸦云项目 token 能管所有已授权用户设备;「按账户隔离」100% 由我们代码做(resolveUidsByPhone→该 uid 设备集合→assertDeviceOwnership fail-closed)(更新:畅小虾团队 2026-09-29)
  • 红外(IR)是云项目级接口,用户 OAuth token 调它会返 1106;必须走项目 token 回退通道(更新:畅小虾团队 2026-09-29)
  • 可控设备池是数量配额(占名额),与「每秒调用次数」限流是两回事;红外下发也占名额,池满即 60001001,需在涂鸦控制台提额(更新:畅小虾团队 2026-09-29)
  • 曾发生 182/189 被错误登记成 180 名下电视的归属者(无真实涂鸦授权)→越权控 180 设备;已清理 devices 行+sendIrCommand 加 strictEmpty fail-closed(更新:畅小虾团队 2026-09-29)
  • 排序签名时 device_ids=id1,id2 逗号必须保持原始字符,编码成 %2C 会 sign invalid 1004(更新:畅小虾团队 2026-09-29)
官方文档 ↗
涂鸦智能 Tuya Smart

账户授权与设备同步(终端用户接入)

tuya.device_oauth

OAuth2 授权码(涂鸦开放平台)+ 云项目 Token(服务端调用) v1.0.0 ▾

接口地址

https://openapi.tuyacn.com(中国大陆)/ smart321 白标授权 H5(平台授权扫码)

鉴权方式

每用户 OAuth broker:用户授权【自己】的涂鸦账户,token 按 user_id(手机号主码)存 FileTokenStore

服务端用云项目 token(TUYA_ACCESS_ID/SECRET)操作已授权用户名下设备;用户 OAuth token 仅用于换取 uid,红外下发才用(见 infrared_control)

请求体说明

  • 路径A(推荐,C端用户):在涂鸦/智能生活 App 把账户「授权给畅小虾项目」(IoT 控制台 C 端授权),再用小程序「平台授权(涂鸦App扫码)」完成 prepareOAuth(platform:true) → smart321 白标 H5 登录 → 回跳 exchangeCode(state 自带 user_id)→ 落 uid 到 tuya_tokens.json
  • 路径B(运营兜底):在 TUYA_PHONE_UID_MAP(env 或代码种子)写死 手机号→uid 映射,同步时按手机号解析 uid 拉设备
  • 切勿只做「授权项目组」而不同步 uid:云项目能看到设备,但不会向我们的 tuya_tokens.json 写 uid → syncDevices 返回空

请求示例

小程序「平台授权(涂鸦App扫码)」→ BFF POST /api/v2/device/tuya/bind {action:'preparePlatformOAuth'} → 返回 smart321 H5 授权页 URL/二维码 → 涂鸦 App 扫码登录 → 回跳 /oauth/callback/tuya → exchangeCode(uid 落盘)

响应示例

{ 'bound': true, 'uid': 'ay1782969147513wm15B' }

字段说明

  • user_id string — 手机号主码,token/设备归属的唯一键
  • vendor_uid string — 涂鸦账户 uid(由 exchangeCode 或 TUYA_PHONE_UID_MAP 得到)
  • state string — 授权回跳携带,内嵌 {openid,user_id,ts},用于还原账户

错误码

  • 同步数据返回空 / 无设备 只做了「授权项目组」(C端授权) 但没走小程序「平台授权扫码」→ tuya_tokens.json 无 uid → resolveUidsByPhone 解析不到 → 改用小程序「平台授权(涂鸦App扫码)」完成 exchangeCode 自动捕获 uid;或运营在 TUYA_PHONE_UID_MAP 补 手机号→uid
  • 白标 H5 登录报「用户不存在」 两种可能:① openclaw.json env 段缺 TUYA_*(client_id 为空)→ 生成的授权 URL client_id 为空;② 该涂鸦账号未在 smart321 白标用户体系注册 → ① 把 6 个 TUYA_* 并入 openclaw.json 的 env 段(不是 .env,网关不读 .env)并重启网关;② 新账号先在涂鸦 IoT 控制台 smart321 App「用户管理」添加或自行注册
  • client_id 为空 / 授权页打不开 TUYA_APP_ACCESS_ID 等未进网关进程 env → 确认写在 openclaw.json env 段(与 ERP_KEK 同通道),kill 网关 PID 重启,禁 systemctl restart

实战 tips

  • 最关键坑:C端用户「授权项目组」只是让云项目看到设备,不会向我们的 tuya_tokens.json 写 uid;必须再走小程序「平台授权扫码」完成 exchangeCode 才能落 uid,否则「同步数据」永远空(更新:畅小虾团队 2026-09-29)
  • TUYA_* 凭证必须写进 openclaw.json 的 env 段(网关 openclaw.service 启动注入 process.env),写 .env 无效——网关不读 .env(更新:畅小虾团队 2026-09-29)
  • 白标 H5「用户不存在」先判断是 client_id 空(凭证未进 env)还是账号未在 smart321 注册(需在控制台用户管理添加),二者解法不同(更新:畅小虾团队 2026-09-29)
  • 代际模型(v3.6):重绑/踢旧用 bind_version/token_version 做 CAS,绝误删新代际;v3.6 上线后旧按微信 openid 落盘的 token 需用户重新授权一次(一次性迁移,非回归)(更新:畅小虾团队 2026-09-29)
  • 小米与涂鸦同源但 token 端点返回 &&&START&&& 非标准前缀 + POST 走 chunked 会被 RST,均已修复;若「小米授权失败」类问题优先查这两处(更新:畅小虾团队 2026-09-29)
官方文档 ↗
涂鸦智能 Tuya Smart

红外遥控(云项目级通道)

tuya.infrared_control

HTTPS POST(涂鸦红外云接口 /v2.0/infrareds/...,服务端用云项目 token) v1.0.0 ▾

接口地址

https://openapi.tuyacn.com/v2.0/infrareds/{device_id}/remotes/{remote_id}/command

鉴权方式

云项目 token(TUYA_ACCESS_ID/SECRET);用户 OAuth token 调 IR 会返 1106

IR 是云项目级接口,无法按账户隔离,隔离靠 devices 表归属校验 + strictEmpty

请求体说明

  • 语义化下发:只传 deviceId + intent(power/volume_up/ok/back/home/up/down/left/right/menu 或中文),由 resolveIntentToKey 反查 IR_KEY_ALIASES 得标准 key;无需前端写死 remoteId/categoryId/key
  • 未传 remoteId 时自动取该设备第一个遥控器(getIrRemotes 已有 24h 缓存,不额外增云调用)
  • categoryId 从遥控器真实 category_id 取,不要硬编码

请求示例

GET  /v2.0/infrareds/{device_id}/remotes              -> 列遥控器(含 remote_id,name,category_id)
GET  /v2.0/infrareds/{device_id}/remotes/{remote_id}/keys -> 列按键(key_list: key_id,key,key_name,standard_key)
POST /v2.0/infrareds/{device_id}/remotes/{remote_id}/command
     Body: {'categoryId':2,'key':'Power'}   <- 注意是 key(字符串) 不是 key_list/key_id 结构

响应示例

{ 'result': { 'success': true }, 'success': true }

字段说明

  • device_id string — 红外设备 ID(如万能遥控虚拟ID 6c512d4e12d41e518aqxn8)
  • intent string — 语义意图,由 BFF/LLM 传,后端反查标准 key
  • remote_id string — 遥控器 ID(缺省取第一个)
  • category_id integer — 遥控器真实类目 ID(整数,必填)
  • key string — 标准按键字符串(Power/OK/Menu...)

错误码

  • 1106 permission deny 用用户 OAuth token 调红外接口;IR 必须走云项目 token → sendIrCommand 已内置「优先用户token、失败回退项目token」;确保项目凭证 TUYA_ACCESS_ID/SECRET 配齐
  • 60001001 可控设备池配额耗尽(红外下发占名额) → 涂鸦控制台为项目提额
  • categoryId 缺失 / 下发无反应 Body 用了 key_list/key_id 结构,或 categoryId 错 → POST command 用 {categoryId:整数必填, key:字符串},标准命令格式

实战 tips

  • 下发命令 Body 是 {categoryId:整数必填, key:字符串},不是 key_list/key_id 结构(更新:畅小虾团队 2026-09-29)
  • IR 走云项目 token(TUYA_ACCESS_ID/SECRET 签名),读取(remotes/keys)无配额限制、下发受「可控设备池」数量配额限制(更新:畅小虾团队 2026-09-29)
  • 语义化:LLM/前端只传 deviceId+intent,后台 resolveIntentToKey 反查标准 key,禁止前端写死 remoteId/categoryId/key(更新:畅小虾团队 2026-09-29)
  • 未传 remoteId 自动取设备第一个遥控器(getIrRemotes 24h 缓存),无需每次拉取(更新:畅小虾团队 2026-09-29)
  • IR 设备不随账户重绑代际清理(云项目全局设备),隔离靠 devices 表归属 + strictEmpty fail-closed;新用户授权须先完成平台授权扫码落 uid(更新:畅小虾团队 2026-09-29)
官方文档 ↗