U8-ERP-CO-API用友 U8+ 业务组件 HTTP API

接口参考#

本文列出全部路由、请求字段、响应字段和错误码。字段和校验以代码为准:API 服务的 Pydantic 模型在 api/u8co_api/co_models*.py,桥的校验在 co/bridge/src/Requests*.cs。API 服务运行时另提供 OpenAPI 3.1 文档(GET /v1/openapi.json,§17)。

目录#

1. 两层接口#

同一套业务路由有两个入口:

入口 路径 认证 错误体
API 服务(推荐) /v1/co/<路由> OIDC Bearer JWT,读写分级 {"error":{"code","message","retryable","field","hint","detail"}}
桥(仅限内网、受信任的调用方) /u8co/v1/<路由> HMAC 签名 + 来源 IP 白名单,见 architecture.md {"ok":false,"code","message","field","hint","detail"}

field、hint、detail 可能没有(§18)。例如 POST /v1/co/vouchers/load 转发到桥的 POST /u8co/v1/vouchers/load。两层的请求字段相同,区别只有:

下文路径省略前缀,写成 vouchers/load。成功响应在桥上都带 "ok": true,API 原样返回。请求和响应都是 UTF-8 JSON;桥的请求体上限 64 KiB,成功响应最多 8 MiB,错误响应最多 64 KiB。

2. 公共字段#

除 health、meta 外,每个请求都带:

字段 说明
acc 三位账套号。必须在 API 的账套白名单(U8CO_ACCOUNTS)和桥的 allowedAccounts 里,否则 403 account_not_allowed,不登录 U8。只读账套(API U8CO_READONLY_ACCOUNTS、桥 readOnlyAccounts)的写路由 403 account_read_only(configuration.md)
year 四位年度,即账套库年度(数据库名 UFDATA_<账套>_<年度> 里的年度),不一定等于当前会计年度。API 缺省取 date 的年份;账套库年度不同时要显式传
operator U8 操作员编码,1 到 20 个字符,不含空白、引号或分号
password 仅 API。U8 操作员口令,1 到 128 个字符,只在本次请求里使用,不保存、不写审计
password_enc 仅桥。加密后的口令,见 architecture.md
date 登录日期 yyyy-MM-dd。API 缺省为 U8CO_TIMEZONE(缺省 +08:00)的今天。总账的会计年度取这个日期的年份

顶层出现未知字段是 400(桥上 message 为「含未知字段」)。单据主键 id 是 1 到 2147483647 的整数。

每次请求都用该操作员登录 U8,按它在 U8 里的功能权限、数据权限(记录级)和字段权限判断能不能做:越权 403,读取时字段权限隐去的字段置为 null 并列在 masked_fields(§22)。桥和 API 不保存操作员和口令。

3. 路由总表#

「权限」一列是 API 的读写分级(§17),直接调桥没有这层分级。「第二级」见表后说明。

方法 路由 权限 作用
GET health 读 桥的健康检查
GET(桥上 POST) meta 读 字段元数据:单据类型、可写字段、档案标签、路由(§21)
POST login-check 读 校验操作员能否登录
POST meta/fields 读 字段标签:本账套单据模板里的中文名、类型、必填、枚举(§26)
POST sale-orders/verify 写 销售订单审核、弃审(专用路由)
POST dispatches/verify 写 蓝字发货单审核、弃审(专用路由)
POST vouchers/load 读 读取单据
POST vouchers/list 读 单据列表
POST vouchers/search 读 按编号、往来单位、部门、存货、日期等条件查单据(§27)
POST vouchers/load_many 读 一次读同一类型的 1 到 20 张单据(§28)
POST vouchers/attachments/list 读 单据附件列表(§5)
POST vouchers/verify 写 按类型审核、弃审
POST vouchers/create 写 新增
POST vouchers/update 写 修改
POST vouchers/delete 写 删除
POST vouchers/close 写 关闭、打开
POST vouchers/lock 写 销售订单锁定、解锁(§10;采购订单不支持)
POST vouchers/generate 写 参照生单
POST notes/get 读 读一张应收 / 应付票据及其处理记录(§16)
POST notes/create 写 票据登记,同时生成收款单;应付票据(生成付款单)是第二级(§16)
POST notes/delete 写 删除还没处理的票据及其收款单;应付票据的删除是第二级(§16)
POST notes/process 写 应收票据结算、贴现、背书冲应付、退回;应付票据结算、退回是第二级。返回处理号(§16)
POST arap/writeoff 写 核销:收付款单对发票、应收应付单(§12)
POST arap/writeoff/cancel 写 按核销号整批取消核销(§12)
POST arap/writeoff/auto 写 自动核销:对一个客户(供应商)配对,一次核多行,可 dry_run(§12)
POST arap/voucher 写 应收 / 应付制单:一张单据或同类型 2 到 20 张合并生成一张总账凭证(§12)
POST arap/voucher/delete 写 取消制单:按外部业务号删凭证、清单据上的凭证号;删汇兑损益、坏账、应付票据处理生成的凭证是第二级(§12)
POST arap/transfer、arap/merge、arap/red_offset 写 应收冲应付 / 应付冲应收、并账、红票对冲,返回处理号(§12)
POST arap/process/cancel 写 按处理号取消应收应付处理;取消坏账、应付票据处理是第二级(§12、§16)
POST arap/process/voucher 写 按处理号制单;汇兑损益、坏账、应付票据处理的制单是第二级(§12、§16)
POST arap/exchange_gain、arap/exchange_gain/cancel 写(第二级) 应收 / 应付汇兑损益及取消(§12)
POST arap/bad_debt 写(第二级) 坏账发生、坏账收回、计提坏账准备,返回处理号 HZAR…(§12)
POST arap/process/list 读 应收 / 应付处理记录与期间批次摘要,供事件服务增量比对(§16)
POST openings/post 写(第二级) 期初记账、取消记账:采购管理(pu)、存货核算(ia)(§29)
POST openings/arap 写(第二级) 应收 / 应付期初单据的新增、删除、审核、弃审(§29)
POST periods/close 写(第二级) 月末结账、取消结账、逐月结账(§31)
POST ia/post 写(第二级) 存货核算正常单据记账、恢复记账(§32)
POST ia/period_end 写(第二级) 存货核算期末处理、取消期末处理(§32)
POST stock/current 读 现存量
POST workflow/state、workflow/history、workflow/tasks 读 审批状态、审批历史、待办
POST workflow/submit、withdraw、approve、disagree、return、abandon、resubmit 写 审批动作
POST gl/vouchers/load、gl/vouchers/list 读 总账凭证读取、列表
POST gl/vouchers/attachments/list 读 总账凭证附件列表(§14)
POST gl/vouchers/digest 读 总账凭证摘要(指纹),供事件服务比对(§14)
POST gl/vouchers/create、update、void、unvoid、verify、unverify、sign、unsign、delete 写 总账凭证写操作
POST gl/vouchers/post 写 总账记账(§14)
POST gl/vouchers/reverse 写 红字冲销:整张复制一张已记账的凭证、金额取负(§14)
POST gl/vouchers/unpost 写(第二级) 取消记账,恢复到最近一次记账之前(§14)
POST gl/transfer/pnl、gl/transfer/custom 写(第二级) 期间损益结转、自定义转账:按 U8 的转账定义生成结转凭证(§14)
POST archives/get、archives/list 读 基础档案读取、列表
POST archives/create、update、delete 写 基础档案写操作
POST archives/get_many 读 一次按编码读同一档案的 1 到 20 条(§28)
POST archives/resolve 读 按名称、简称、助记码查编码,一次最多 20 项(§24)
POST idempotency/get 读 按幂等键查第一次请求的结果(§20)
POST reports/close_status、gl_balance、gl_aux_balance、gl_detail、arap_balance、arap_aging、arap_detail、arap_writeoffs、bom 读 只读报表:月结状态、科目余额表、辅助核算余额表、科目明细账、往来余额、账龄分析、往来明细账、核销记录、物料清单(§19)
POST reports/stock_ledger、stock_summary、position_stock、batch_stock、customer_credit、price_list 读 只读报表:库存台账、收发存汇总表、货位存量、批次存量、客户信用、价格表(§19)
POST reports/order_execution、doc_trace 读 只读报表:订单执行、单据追溯(§19)
POST reports/opening_balance 读 只读报表:期初余额(库存、应收应付、总账,§19)
POST reports/fa_changes、fa_depreciation 读 只读报表:固定资产变动单、按卡片和期间的折旧(§19)
POST reports/account_readiness 读 账套体检:空账套能不能跑回归,逐项给出状态和修复提示(§30)
POST reports/mgmt/pnl、mgmt/meta、mgmt/sales、mgmt/arap_terms、mgmt/cash_stock 仅桥 单账套的经营管理报表(§34)。API 不直接开放,经下一行的 /v1/co/mgmt/* 按账套调用
POST mgmt/meta、mgmt/pnl、mgmt/sales、mgmt/arap、mgmt/cash_stock、mgmt/overview 经营管理 仅 API:1 到 3 个账套的经营管理查询,可合并(§34)
POST reports/intercompany_match、reports/aggregate、reports/consolidation 经营管理 仅 API:公司间对账、多账套汇总、合并试算,按账套、往来单位返回数量和金额(§33)
POST intercompany/generate_buyer 写 仅 API:按卖方单据在买方账套参照公司间采购订单生成入库单或到货单(§33)
POST perm/snapshot 读 登录操作员自己的有效权限(§22)
POST perm/evaluate 权限评估 指定操作员的有效权限,只给信任项写了 perm_evaluate: true 的调用方(§22)
GET /v1/openapi.json 任意已认证调用方 仅 API:OpenAPI 文档

预演。 标「写」的路由都可以在请求体里带 dry_run: true:走同样的检查和锁,但不写入(§23)。例外:sale-orders/verify、dispatches/verify 不支持预演(经 API 是 400「请求参数无效:dry_run」);arap/writeoff/auto 的 dry_run 表示「只出计划」。

分级标记。 OpenAPI 里每个 /v1/co 操作带扩展字段 x-u8co-access(read、write、mgmt、perm_evaluate),与「权限」一列相同。配置了写入策略(configuration.md)时,写路由还要过策略的放行规则、冻结和时段。

第二级写入。 标「第二级」的写入(以及 §4 里期初结存单的写入)没有可调用的 U8 组件,或改的是跨模块的期初 / 结账状态,由桥执行与 U8 界面相同的 SQL(已在测试账套上与 U8 界面执行的 SQL 实测核对)。桥在登录 U8 之前(含预演)依次检查(例外:arap/voucher/delete 要读出凭证才知道它是否属于第二级,在登录之后、事务里任何写入之前检查,见 limitations.md「第二级:复现写入」):

  1. 桥配置 enableReplicatedWrites 为 true(缺省 false),否则 403 feature_disabled,message 为「第二级写入未开启:」加下面各路由的原文;
  2. 账套在桥的 testAccounts 里,否则 403 test_account_only。

health 的 replicated_writes 显示开关状态。这类写入只用于测试账套;正式账套请在 U8 客户端操作(风险见 limitations.md)。

4. 单据类型#

type 不在下表里是 400「单据类型无效」。「行主键」是修改时的 line_id,也是生单时来源行的 source_line_id。

type 单据 读取 审核 新增 修改 删除 关闭 生单来源 行主键
sale_order 销售订单 是 是 是 是 是 是 iSOsID
dispatch 发货单(蓝字) 是 是 无来源 是 是 sale_order iDLsID
sale_invoice 销售发票 是 复核 先开票 是 是 dispatch(缺省)、sale_return(红字发票)、sale_invoice(红冲蓝字发票) AutoID
sale_out 销售出库单 是 是 无来源(账套未启用销售管理时) 是 是 dispatch(整张或按行) AutoID
sale_return 退货单(红字发货单) 是 是 是 是 dispatch、sale_return_apply iDLsID
sale_return_apply 退货申请单(卡片 SA31) SQL 是 参照发货单 是 是 AutoID
purchase_order 采购订单 是 是 是 是 是 是 PO_Podetails.ID
arrival 到货单 是 是 无来源 是 是 是 purchase_order Autoid
purchase_return 采购退货单(红字到货单) 是 是 是 是 arrival(缺省)、purchase_order Autoid
purchase_requisition 请购单 是 是 是 是 是 整单 AutoID
purchase_invoice 采购发票 SQL 复核 是 是 purchase_in ID
purchase_settle 采购结算单(卡片 99) SQL 没有审核 手工结算 是 purchase_invoice(整张发票自动结算) ID
inventory_price_adjust 存货调价单(销售,卡片 SA18) SQL autoid
purchase_in 采购入库单 是 是 无来源 是 是 purchase_order(缺省)、qm_incoming_check、purchase_return(生成红字入库)、arrival(蓝字到货单) AutoID
other_in 其他入库单 是 是 是 是 是 AutoID
other_out 其他出库单 是 是 是 是 是 AutoID
transfer 调拨单 是 是 是 是 是 transfer_request autoID
shape_change 形态转换单 是 是 是 是 是 autoID
transfer_request 调拨申请单 是 是 是 是 是 autoID
stock_check 盘点单 是 不支持 是 是 autoID
position_adjust 货位调整单(单据类型 19) SQL 是 是 是 autoID
ia_adjust 出入库调整单(存货核算,单据类型 20 / 21 等) SQL 记账见 ia/post AutoID
stock_opening 期初结存单(库存期初,单据类型 34) 是 第二级(没有记账) 第二级,每行一张 第二级 AutoID
product_in 产成品入库单 是 是 是 是 qm_product_check(缺省)、qm_product_reject、production_order AutoID
material_out 材料出库单 是 是 无来源 是 是 production_order AutoID
production_order 生产订单 SQL 是(U8 API) 是(U8 API) 是(U8 API,§8) 是(U8 API) 是 MoDId
bom 物料清单(标准 BOM) SQL 是(U8 API) 是(U8 API) 是(U8 API) 是(U8 API) sort_seq(§8)
qm_incoming_inspect 来料报检单(QM01) SQL 保存时自动 生单 是 arrival AUTOID
qm_product_inspect 产品报检单(QM02) SQL 保存时自动;可单独弃审 生单 是 production_order AUTOID
qm_incoming_check 来料检验单(QM03) SQL 审批流 生单 只改表头 是 qm_incoming_inspect AUTOID(报检单表体)
qm_product_check 产品检验单(QM04) SQL 审批流 生单 只改表头 是 qm_product_inspect AUTOID(报检单表体)
qm_incoming_reject 来料不良品处理单(QM05) SQL 是(受审批流控制的走审批流) 生单 是 qm_incoming_check ID(检验单)
qm_product_reject 产品不良品处理单(QM06) SQL 是(受审批流控制的走审批流) 生单 是 qm_product_check ID(检验单)
qm_other_inspect 其他报检单(QM11) SQL 是(新增后桥按选项补审核) 无来源 只改表头 是 AUTOID
qm_other_check 其他检验单(QM15) SQL 是(没有审批流) 生单 只改表头 是 qm_other_inspect AUTOID(其他报检单表体)
ar_receipt 收款单 是(UFAPBO) 是 是 是 是 ID
ap_payment 付款单 是(UFAPBO) 是 是 是 是 ID
ar_refund 客户退款(应收的付款单,AR / 49) 是(UFAPBO) 是 是 是 是 ID
ap_refund 供应商退款(应付的收款单,AP / 48) 是(UFAPBO) 是 是 是 是 ID
ar_bill 应收单 是(UFAPBO) 是 是 是 是 Auto_ID
ap_bill 应付单 是(UFAPBO) 是 是 是 是 Auto_ID

共 41 种可读取类型。「SQL」表示读取直接查表,不走业务组件。「生单」表示只能经 vouchers/generate 参照来源新增(§11),vouchers/create 是 400。ia_adjust、inventory_price_adjust 只读,写路由一律 400。退货申请单、退款单、无来源销售出库、手工结算、红冲蓝字发票的细则见 §35。

质量单据:

各类型使用的 U8 登录子系统:销售和质量单据 SA,库存 ST,采购 PU,收款单、客户退款和应收单 AR,付款单、供应商退款和应付单 AP;生产订单读取和关闭 SA,审核、新增、修改和删除 MO;物料清单读取和列表 SA,审核、新增、修改和删除 BO。不带类型的路由:总账 GL,档案 AS,列表、现存量、login-check 和不带 type 的待办 SA。个别写入另用 QM、AR、AP,在各节注明。

5. 读取 vouchers/load#

请求:type、id。

响应:

字段 说明
type、id、code 类型、主键、单据号
head 表头。值是 U8 存成的字符串,空值省略。二进制列(含 ufts)用十六进制
lines 表体,每行同样是字符串字典。超过 500 行时只返回前 500 行,并带 lines_truncated: true
state verified、verifier、verified_at。生产订单另有 closed。采购发票的 verified 是采购复核,另有同义的 reviewed、reviewer、reviewed_at,以及应付审核 ap_verified、ap_verifier(cPBVVerifier);采购发票、销售发票另有 arap_verified、arap_verifier、arap_verified_at、gl_voucher(§6)
wf 仅检验单和不良品处理单(QM03 到 QM06):审批状态,结构同 workflow/state 的 wf
source 仅报检单:来源单据 {"type","id","code"}。来料报检单是到货单(id 是 PU_ArrivalVouch.ID),产品报检单是生产订单(id 是 MoId);表头没有来源主键时为 null,其他报检单恒为 null
allocations 仅生产订单:子件分配,另有 allocations_truncated
merge_sources 仅合并检验(BMERGECHECKFLAG=1)的产品检验单:每个合并来源(QMMergeCheckDetail)一项:source_line_id(来源 AUTOID,参照生成产成品入库时用)、mo_code、mo_seq、mo_detail_id(MoDId)、inspect_code(来源报检单号)、qualified(合格)、concession(让步接收)、stocked(累计入库)、remaining(合格 + 让步 − 累计入库,不小于 0)、done(U8 已标为入库完毕,BPROINFLAG=1)。非合并检验没有这个键
version 仅物料清单:版本号

销售订单和发货单的读取由 U8 按操作员的数据权限过滤。收付款单和应收应付单的主键对应的行若是别的 cFlag / cVouchType(例如供应商退款),按不存在处理,404。

报检单(QM01、QM02、QM11)只取固定的一组列(列名同 U8 单据模板):

其他检验单(QM15)的读取同来料、产品检验单(表头整行、检验项目表体),只是没有 wf。

物料清单(bom,id 是 bom_bom.BomId)只读标准 BOM(BomType=1),替代 BOM 400「只支持标准物料清单」。code 是母件存货编码(表头没有单号)。键是固定的小写下划线名:

采购结算单(purchase_settle,id 是 PurSettleVouch.PSVID,code 是结算号 cSVCode)读取只查表。写入有参照采购发票自动结算(vouchers/generate,§11)、手工结算(vouchers/create,§35)和删除(§9);修改、审核 400(U8 里也没有)。

出入库调整单(ia_adjust,表 JustInVouch / JustInVouchs,id 是表头自增列 id,code 是单号 cJVCode)只读。入库调整(cVouchType=20,卡片 0401)、出库调整(21,卡片 0402)和发出商品等其他调整类型同在一张表,不按类型拆分。

存货调价单(inventory_price_adjust,表 SA_InvPriceJustMain / SA_InvPriceJustDetail,id 是表头 id,code 是 ccode)只读:head、lines 是原列,另加 dep_name、inv_name、inv_std;state.verified 按审核人 cverifier 非空,verified_at 是审核日期 dverifydate(未审核为空串)。审核后 U8 把新价写进存货价格表(reports/price_list 的 kind=inventory)。列名按 U8 数据字典,尚未用实际数据核对。

单据附件 vouchers/attachments/list#

请求同 vouchers/load(type、id),权限同读取该单据(功能权限和记录级数据权限,越权 403)。只查数据库,不调用 U8 组件。单据不存在 404 not_found。

U8 单据卡片上的「附件」登记在通用附件表 VoucherAccessories:VoucherTypeID 是卡片号(vouchers.CardNumber,如销售订单 17),VoucherID 是该卡片主键列(vouchers.VchTblPrimarykeyNames,应收应付单是 cLink)的值。桥列出同一张表头表的全部卡片(例如发货单和退货单共用 DispatchList)下挂在这张单据上的附件。

响应 {"ok":true,"type","id","items","truncated"}。每项 card(卡片号)、file_id、name(原文件名)、memo、size(内容存在 U8 库里时的字节数,否则 null)、stored(database:内容在 FileContent 列;file_server:只登记了 U8 文件服务器上的文件标识)。按文件名排序,最多 500 个,超过时 truncated 为 true。只列清单,不提供下载(limitations.md)。各键按 U8 附件表结构写出,尚未用实际附件核对,使用前请先核对 card、file_id、stored。

客户端命令:attachments --type <类型> --id <主键>。

6. 审核 vouchers/verify#

请求:type、id、action(verify 审核,unverify 弃审;采购发票、销售发票另有 arap_verify、arap_unverify)。

成功响应:type、id、action,以及(有则返回)verified_by、verified_at、acc(收付款单、应收应付单和生产订单可能不返回)、state、generated、ar_verifier(销售发票的应收审核人)。

通用规则:

销售#

应收审核、应付审核(arap_verify、arap_unverify)#

只收采购发票(应付款管理的审核,登录子系统 AP)和销售发票(应收款管理的审核,登录子系统 AR);其他类型 400 bad_request「只有采购发票、销售发票支持应收应付审核」(经 API 时请求校验就失败)。只收专用、普通发票(采购 01 / 02,销售 26 / 27),其他发票类型 400「只支持专用发票和普通发票」(先于状态检查)。

采购#

库存#

质量#

应收应付单据、生产订单、物料清单#

专用审核路由#

sale-orders/verify(id 为 SO_SOMain.ID)和 dispatches/verify(id 为 DispatchList.DLID):请求 id、action,成功 {"ok":true,"acc","id","action","verified_by","verified_at"}。verified_by 取 cVerifier,verified_at 优先 dverifysystime,否则 dverifydate。

发货单只接受蓝字:红字(bReturnFlag)、cVouchType 不是 05、期初 bFirst = 1 都直接拒绝。已有退货单行(iCorID)指向其明细的发货单不能弃审,409「发货单已有退货单,请先删除退货单」(vouchers/verify 的 dispatch 同样)。

这两条路由检查 U8 审批流:AuditBizObjects 里没有该表的行,或审批流表不可用,409 workflow_unknown;有行并且 Table_WorkFlowRelease 里该业务对象有 Status = 0、事件为 <对象ID>.Submit 的发布,或单据自己的 iswfcontrolled 为真,409 workflow_enabled。查不到不当成「没有启用」。

7. 新增 vouchers/create#

请求:type、head(一层对象,值只能是字符串、数字或布尔)、lines(1 到 200 行,同样是一层对象)。

允许的类型:

其他类型 400「该单据类型不支持新增」。固定资产变动单不在 API 里(§15「固定资产卡片与设备台账的写入」)。

成功:{"ok":true,"type","id","code","state"}。采购订单、请购单、生产订单和应收应付四种另有 lines(保存后的表体行数);生产订单另有 allocates、details、warnings,物料清单另有 version、components。收付款单和应收应付单可能不带 state。新单据保持未审核(其他报检单例外,见下)。

字段值不能填主键和来源行 id(id、autoid、isosid、idlsid、iposid、poid、dlid、cbsysbarcode)、单号、制单人、审核人、ufts、editprop,也不能填销售订单行的关闭人和累计数量(cscloser、ifhquantity、ikpquantity、foutquantity)。行号 irowno 可以填。不在该类型允许名单里的字段是 400「不能设置字段 x」,在名单里但不在 U8 行集 schema 里的是 400「未知字段 x」。自定义项和自由项不接受前导零(cdefine01、cfree07)。

可写字段#

表头自定义项 cdefine1 到 cdefine16,表体自定义项 cdefine22 到 cdefine37,自由项 cfree1 到 cfree10。除此之外:

类型 表头 表体
sale_order ccuscode、cstcode、cdepcode、cpersoncode、cbustype、cexch_name、iexchrate、itaxrate、ddate、cmemo、ccusoaddress、cshipaddress、cscode、cpaycode、dpredatebt、dpremodatebt cinvcode、iquantity、inum、cunitid、cgroupcode、igrouptype、ccomunitcode、iinvexchrate、iquotedprice、iunitprice、itaxunitprice、imoney、itax、isum、inatunitprice、inatmoney、inattax、inatsum、inatdiscount、idiscount、kl、kl2、itaxrate、dpredate、dpremodate、cmemo
purchase_order cvencode、cdepcode、cpersoncode、cptcode、cbustype、cexch_name、nflat、itaxrate、dpodate、cmemo、darrivedate(只作行计划到货日的缺省) cinvcode、iquantity、iunitprice、itaxprice、ipertaxrate、darrivedate、cbmemo、cunitid、inum
other_in / other_out cwhcode、crdcode、cdepcode、cpersoncode、ddate、cmemo、cvencode、ccuscode、citemcode cinvcode、iquantity、inum、iunitcost、iprice、cbatch、cposition、cbmemo、dmadedate、dvdate、imassdate、cmassunit、cassunit、iinvexchrate
stock_opening(不能修改) cwhcode、crdcode、cdepcode、cpersoncode、ddate(不用)、cmemo、cvencode cwhcode(覆盖表头)、cinvcode、iquantity、inum、iunitcost、iprice、cbatch、cposition、dmadedate、dvdate、imassdate、cmassunit、cassunit、iinvexchrate、citem_class、citemcode
transfer cowhcode、ciwhcode、cordcode、cirdcode、codepcode、cidepcode、dtvdate、cmemo、cpersoncode cinvcode、itvquantity、cassunit、cbatch、cbmemo
shape_change davdate、cdepcode、cpersoncode、cirdcode、cordcode、cavmemo cinvcode、cwhcode、bavtype、igroupno、iavquantity、cassunit、cavbatch、cbmemo
transfer_request dtvdate、cowhcode、ciwhcode、codepcode、cidepcode、cordcode、cirdcode、cpersoncode、ctvmemo cinvcode、itvquantity、itvchkquantity(核准数量)、cassunit、ctvbatch、cbmemo
position_adjust(不能修改) cwhcode、ddate、cdepcode、cpersoncode、cmemo cinvcode、cbposcode(调出货位)、caposcode(调入货位)、iquantity、cassunit、cbatch、cbmemo
stock_check(不能修改) cwhcode、dcvdate、dacdate、cdepcode、cpersoncode、cirdcode、cordcode、ccvmemo cinvcode、icvquantity(账面)、icvcquantity(实盘)、cassunit、ccvbatch、ccvreason、cbmemo
purchase_requisition ddate、cdepcode、cpersoncode、cbustype(只能是「普通采购」)、cmemo cinvcode、fquantity、drequirdate、darrivedate、cvencode(建议供应商)、ioricost、ioritaxcost、ipertaxrate、cbmemo
purchase_in(无来源) cwhcode、crdcode、cdepcode、cpersoncode、ddate、cmemo、cvencode、cptcode cinvcode、iquantity、inum、iunitcost、iprice、ioritaxcost、itaxrate、cbatch、cposition、cbmemo、dmadedate、dvdate、imassdate、cmassunit、cassunit、iinvexchrate

修改用同一份名单。金额、价税、辅数量由桥计算(U8 的业务组件保存时不重算),算法见 u8-notes.md「金额」。有计量单位组的存货还要辅计量,缺了 U8 会拒绝。

必填项与缺省:

形态转换单、调拨申请单、盘点单#

三类都走 USERPCO.VoucherCO(登录子系统 ST),与调拨单同一组方法:Insert 13 参、Update 12 参、Delete / UnVerify 9 参,都在请求连接的事务里;单号按 U8 编号规则取(sVouchType 15、62、18,卡片 0305、0324、0307);空白模板取视图 AssemM / AssemD、transrequestm / transrequestd、checkm / checkd。备注、批号用各表自己的列名(cavmemo、ctvmemo、ccvmemo,cavbatch、ctvbatch、ccvbatch),不做 cmemo 别名。

货位调整单#

货位调整单(position_adjust,表 AdjustPVouch / AdjustPVouchs,U8 单据类型 19,卡片 0313)在同一仓库内把存货从一个货位挪到另一个货位,不动仓库现存量。新增、审核、弃审、删除是普通写入,按写入策略放行。不能修改:vouchers/update 400「货位调整单不能修改,请删除后重新录入」。

其他报检单#

其他报检单(qm_other_inspect,QM11,VT 361)没有来源单据,用 vouchers/create 新增。走 U8 质量管理组件 UFQMCo.clsOtherInspectVoucherCO(基于 VO 的接口,同不良品处理单),登录子系统 QM。

{"type": "qm_other_inspect",
 "head": {"dDate": "2026-01-15", "cInspectDepCode": "D901", "cDefine10": "LOT-001"},
 "lines": [{"cInvCode": "A01", "quantity": 100}]}

期初结存单#

期初结存单(stock_opening,表 rdrecord34 / rdrecords34,U8 单据类型 34)是库存管理的期初数据。读取、列表照常开放;新增、删除、审核、弃审是第二级写入(§3),在登录 U8 之前检查:开关关闭 403 feature_disabled,账套不在 testAccounts 里 403 test_account_only「期初结存单只对配置为测试账套的账套开放」。

无来源采购入库单#

purchase_in 的新增只做来源为库存的单据:表头 cSource 写「库存」,业务类型「普通采购」,VT_ID 27,本币、汇率 1。蓝字为缺省,表头 red: true 为红字退库(见本节末条)。参照采购订单或来料检验单入库用 vouchers/generate。

无来源发货单、先开票销售发票、无来源到货单、无来源材料出库单#

不挂来源单据的新增。账套选项不允许时一律 409 state_mismatch,消息带 U8 选项名:

type 做法 禁止它的账套选项(AccInformation) 409 消息
dispatch VoucherCO_Sa VT 9、卡片 01 的 GetDefaultVoucherDom 模板,表体不写 isosid,Save(…, 0) SA / bMustSO_ptxs(普通销售必有订单)为真 「账套设置了普通销售必有订单(SA.bMustSO_ptxs),不能无来源录入发货单」
sale_invoice 先开票:专票(cvouchtype 26,缺省)VT 0 / 卡片 07,普票(27)VT 2 / 卡片 13;表头 idisp=0,表体不写 idlsid。U8 按发票生成发货单(DispatchList.SBVID 指回发票),响应另给 dispatch_id(读不到时省略) 同上 「…不能无来源录入销售发票」
arrival VoucherCO_PU vt 2、sBillType="0",表头不写 cpocode,表体不写 iposid / cordercode,VoucherSave2(…, 2) PU / bPTHavePO(普通业务必有订单)为真 「账套设置了普通业务必有订单(PU.bPTHavePO),不能无来源录入到货单」
material_out USERPCO.Insert("11"),csource=库存、业务类型「领料」、vt_id 65,表体不写 iMPoIds ST / ballowAddnewVouch(领料必有订单)为真 「账套设置了领料必有订单(ST.ballowAddnewVouch),不能无来源录入材料出库单」

可写字段(另加表头 cdefine1–cdefine16;销售表体另加 cfree1–cfree10、cdefine22–cdefine37):

type 表头 表体 必填
dispatch / sale_invoice ccuscode、cstcode、cdepcode、cpersoncode、cexch_name、iexchrate、itaxrate、ddate、cmemo、cshipaddress、cscode、cpaycode;发票另有 cvouchtype(26 / 27) cwhcode、cinvcode、iquantity、inum、cunitid、iquotedprice、iunitprice、itaxunitprice、itaxrate、kl、kl2、cbatch、cmemo 表头 ccuscode、cstcode;行 cwhcode、cinvcode、iquantity
arrival cvencode、cdepcode、cpersoncode、cptcode、ddate、cmemo cwhcode、cinvcode、iquantity、ioricost(无税单价)、ioritaxcost(含税单价)、itaxrate 表头 cvencode;行 cinvcode、iquantity
material_out cwhcode、crdcode、cdepcode、cpersoncode、ddate、cmemo cinvcode、iquantity、cbatch、cposition、cbmemo 表头 cwhcode、crdcode(出库类末级收发类别,桥不补缺省;缺了 400「必须指定收发类别」,field 为 head.crdcode);行 cinvcode、iquantity

请购单#

purchase_requisition(PU_AppVouch / PU_AppVouchs,卡片 27)走 VoucherCO_PU,登录子系统 PU,新增 VoucherSave2 状态 2、修改状态 1,单号由 GetVoucherNO(头, "27", …) 取。

生产订单#

production_order 走 U8 API 框架的 MOrderAdd(与审核同一个 U8ApiComBroker,登录子系统 MO),不走通用字段名单,字段名是下面这些(不分大小写),其余 400「不能设置字段 x」:

位置 字段 说明
表头 mo_code 生产订单号,最长 30。省略则 U8 按单据编号规则(MO21)自动编号。已存在 409 state_mismatch「生产订单号已存在:x」。code 在全局禁写名单里,所以单号叫 mo_code
表头 remark 最长 255。mom_order 没有备注列,作各行备注 DRemark 的缺省
表体 inv_code 必填。存货要存在(400)、是自制件 bSelf(400)、在开工日期未停用(400)
表体 qty 必填。大于 0、不超过 1000000000000、最多 6 位小数的 JSON 数;另按账套的存货数量小数位(AccInformation 里 AA 的 iStrsQuanDecDgt)检查,多出的小数 400「第 n 行:qty 最多 d 位小数(U8 存货数量小数位)」
表体 start_date、due_date 必填,yyyy-MM-dd。完工早于开工 400「due_date 不能早于 start_date」
表体 mo_type 必填。生产订单类别编码(mom_motype.MotypeCode),不存在 400
表体 dept_code 必填。生产部门,要存在且是末级部门(400)
表体 wh_code 可选。预入仓库,要存在且未停用(400)
表体 remark 可选,最长 255。覆盖表头 remark

物料清单#

bom 走 U8 API 的 BomAdd(登录子系统 BO),为一个母件新建一个标准 BOM 版本(BomType=1),不收替代 BOM。字段名是下面这些(不分大小写),其余 400「不能设置字段 x」:

位置 字段 说明
表头 inv_code 必填。母件存货:要存在、自制(bSelf)且允许做 BOM 母件(bBomMain),在登录日期未停用,有不带自由项的物料(bas_part),否则 400
表头 version 可选,正整数。省略时取该母件现有标准 BOM 的最大版本加版本增量(mom_parameter.VersionIncrement,读不到按 10);给了且已存在 409 state_mismatch「物料清单版本已存在」
表头 version_desc 可选,最长 255,缺省空串
表头 eff_date 可选,yyyy-MM-dd,缺省登录日期。与该母件其他版本的生效日期相同 409 state_mismatch
表头 parent_scrap 可选,母件损耗率(%),0 到小于 100,最多 3 位小数,缺省 0
表体 inv_code 必填。子件:要存在、允许做 BOM 子件(bBomSub)、未停用、有不带自由项的物料,不能是母件本身(400)
表体 base_qty_n 必填。基本用量分子,大于 0、不超过 1000000000000、最多 6 位小数
表体 base_qty_d 可选,基本用量分母,同上,缺省 1
表体 comp_scrap 可选,子件损耗率(%),同 parent_scrap,缺省 0
表体 wip_type 可选,供应类型 1 入库倒冲、2 工序倒冲、3 领用、4 虚拟件、5 直接供应,缺省 3
表体 wh_code 可选,最长 10。要存在且未停用(400);省略时 U8 取存货档案的缺省仓库
表体 remark 可选,最长 255
表体 op_seq 可选,工序行号,最长 4,缺省 0000
表体 sort_seq 可选,子件行号 1 到 99999,同一请求里不能重复;省略的行接在已用的最大行号后面,每次加 10

应收应付单据的字段见 §12。

8. 修改 vouchers/update#

请求:type、id,head 与 lines 至少一项非空,两项都空 400「没有要修改的内容」;不在下表的类型 400「该单据类型不支持修改」。物料清单(bom)按 sort_seq 定位行,生产订单(production_order)只能 update 已有行,规则见下文对应小节。

组 类型 行操作
自由修改 sale_order、purchase_order、other_in、other_out、transfer、purchase_in(来源为库存)、sale_out(来源为库存)、purchase_requisition、shape_change、transfer_request add、update、delete
生单来的单据 dispatch、sale_return、sale_invoice、sale_out(来源为发货单)、product_in、material_out、purchase_in(来源为采购订单或来料检验单)、arrival、purchase_return、purchase_invoice update、delete;不能 add(发货单例外,见 §35「发货单修改新增行」)
应收应付手工单 ar_receipt、ap_payment、ar_bill、ap_bill、ar_refund、ap_refund add、update、delete
退货申请单 sale_return_apply 只有 update(§35)
质量单据 qm_incoming_check、qm_product_check、qm_other_check、qm_other_inspect 不收 lines,只改表头

lines 为 0 到 200 行,每行有 op:

op 要求
add 不能带 line_id,其余键是字段值,名单同新增
update line_id 为正整数,至少再改一个字段
delete 只能有 op 和 line_id

其他 op 400「op 只能是 add、update 或 delete」;同一请求 line_id 重复 400「明细行重复」;line_id 不属于本单 400「明细行不存在」;删光现有行又不新增 400「不能删除全部明细」。库存单据(其他入库、其他出库、调拨、形态转换、调拨申请)换存货 400「不能修改存货编码,请删除该行后新增」。

只改未审核、未关闭、没有下游的单据,否则 409 state_mismatch;在审批中 409 workflow_enabled。各类型的拒绝条件与其删除相同(§9)。其他入/出库还要求来源是库存,来源是调拨时 409「调拨生成的单据不能修改」。

成功:{"ok":true,"type","id","code","state","lines"},lines 是保存后的表体行数。U8 的销售、应收应付业务组件保存时不写修改人,桥补写修改人、修改日期和修改时间(行集里有这些列时)。提交后回读失败 504 outcome_unknown:修改已保存,不要重投。

自由修改的类型#

生单来的单据#

这些单据挂着来源行,修改只做缩减:

type 表头 表体 回写核对
dispatch cmemo、ddate、cdepcode、cpersoncode、cshipaddress iquantity、cwhcode、cbatch、cmemo、cfree1–cfree10(存货须启用该自由项,否则 400) 订单行 iFHQuantity
sale_return cmemo、ddate、cdepcode、cpersoncode iquantity(正数)、cwhcode、cmemo 原发货行 iRetQuantity 与 fretqtywkp / fretqtyykp(按表头 bneedbill),订单行 fretquantity、iFHQuantity
sale_invoice cmemo、ddate iquantity、cmemo 发货行 iSettleQuantity;订单行 iKPQuantity 只记审计
sale_out cmemo iquantity、cbmemo 发货行 fOutQuantity、fOutNum(来源值为空时只记审计)
purchase_in(来源采购订单、来料检验单) cmemo iquantity、cbmemo 来源采购订单:订单行 iReceivedQTY;来源来料检验单:检验单 FsumQuantity、到货行 fValidInQuan、订单行 freceivedqty
product_in cmemo iquantity、cbmemo(来源为产品不良品处理单的只能改备注和自定义项,改数量或删行 400「参照不良品处理单的入库单不能改数量」) 生产订单行 QualifiedInQty、检验单累计入库
material_out cmemo iquantity、cbmemo 子件 IssQty
arrival cmemo、ddate、cdepcode iquantity、cbmemo 订单行 iArrQTY
purchase_return cmemo、ddate、cdepcode iquantity(正数)、cbmemo 原到货行 fRetQuantity,订单行 fPoRetQuantity、iArrQTY
purchase_invoice cpbvmemo、dpbvdate ipbvquantity、cbmemo 入库行 iSumBillQuantity;红字发票 409「红字采购发票暂不支持修改」

各类型另外的拒绝条件:

物料清单#

bom(id 是 BomId)走 U8 API BomUpdate(登录子系统 BO)。只改未审核(Status=1)、未进审批流的标准 BOM:已审核 409 state_mismatch「已审核的物料清单不能修改」,停用 409,IsWFControlled=1 409 workflow_enabled(U8 API 本身不查状态,闸门由桥做)。

桥读出现有全部行和每行的标志,叠上本次修改,以差异更新(UpdateByDiff=true)送全部行:U8 按行号更新,未送的行号删除(不带差异更新时 U8 整表替换)。差异更新对行上附属内容的处理决定了哪些清单能改:

行上带的内容 差异更新时 U8 的处理 桥
替代料(bom_opcomponentsub) 未送的替代料被删除 拒绝(409)
定位符(bom_opcomponentloc) 未送的定位符被删除 拒绝(409)
分段损耗(bom_opcomponentscrap) 桥无法送分段损耗标志,行为未验证 拒绝(409)
子件自由项 按送来的 DInvCode 和自由项重取物料;桥不送自由项,子件会变成不带自由项的物料 拒绝(409)
表体自定义项(Define22…Define37) 只写送了的,未送保留原值 可以改,自定义项不变
领料部门(DrawDeptCode) 只在送了 DDeptCode 时写 可以改,部门不变
辅计量(AuxUnitCode) 只在送了辅计量单位时写,未送保留单位、辅用量和换算率;改主用量时辅用量不重算 可以改,但该行不能改 base_qty_n / base_qty_d(409「第 n 行带辅计量,用量请在 U8 客户端修改」)

任何一行带前四类(读取里 extras 为 "1")时 409 state_mismatch「第 n 行带替代料、定位符、分段损耗或自由项,请在 U8 客户端修改」,不论本次是否改那一行。

生产订单#

production_order(id 是 MoId)走 U8 API:MOrderLoad 取出整张订单(表头、行、全部子件),在加载出的实体上修改,再以新的 U8EnvContext / U8ApiComBroker 调用 MOrderUpdate 交回(登录子系统 MO,U8 自行提交,不在桥的事务里)。MOrderUpdate 按行号(DSortSeq)对行,并删除每一行的全部子件、按送去的子件重插(AllocateId 全部换新):不送子件即清空用料,所以桥总是重送加载出的全部子件;扩展实体带不回的子件列由桥在 U8 提交后写回(见下)。

闸门

请求

子件数量重算(改了数量的行,按 U8 的子件用量算法)

调用与核对

质量单据#

可修改来料检验单(QM03)、产品检验单(QM04)、其他检验单(QM15)、其他报检单(QM11)。只收 head,送了非空 lines 400「质量单据修改只收表头 head(检验项目放在 head.items),不收 lines」;字段名不分大小写,名单外 400「不能设置字段 x」。

类型 可写字段
检验单(QM03、QM04、QM15) ddate、ccheckpersoncode(检验员,桥同时写姓名)、cchkconclusion(最长 60)、creasoncode、fregquantity / fconquantiy / fdisquantity、cyieldercode(让步接收核准人的人员编码,桥按人员档案写姓名 CYIELDERNAME,不存在 400)、dyielddate(让步接收核准日期 yyyy-MM-dd;送了核准人而未送时取请求的 ddate,再无则取登录日期)、cdefine1–cdefine16、chdefine11–chdefine16、items
其他报检单(QM11) ddate、cinspectdepcode、cdefine1–cdefine16、chdefine11–chdefine16

应收应付#

收款单、付款单、应收单、应付单只改未审核的手工单据,拒绝条件同删除(§12:已制单、已核销、有往来明细、票据或网银生成、期初、单据月份已结账)。

9. 删除 vouchers/delete#

请求:type、id。成功 {"ok":true,"type","id","deleted"},deleted 为 true 表示表头已不存在。报检单、检验单、物料清单另带 code(见下)。

允许:sale_order、purchase_order、purchase_requisition、other_in、other_out、transfer、dispatch、sale_return、arrival、sale_out、purchase_in、sale_invoice、purchase_invoice、material_out、product_in、ar_receipt、ap_payment、ar_bill、ap_bill、purchase_return、production_order、bom、qm_incoming_inspect、qm_product_inspect、qm_incoming_check、qm_product_check、qm_incoming_reject、qm_product_reject、qm_other_inspect、qm_other_check、shape_change、transfer_request、stock_check、stock_opening、purchase_settle,以及 §35 所列类型。其他类型 400「该单据类型不支持删除」。

只删未审核的单据,并挡住下游(409 state_mismatch)。

货位:库存单据有货位记录(InvPosition 有该单据的行)时,桥在删除事务里先让 U8 清掉该单据的货位记录(ClearPosition)再删除,U8 回退货位存量(InvPositionSum);U8 拒绝清货位 409 u8_rejected(原文带回);删除后货位记录或表头仍在则回滚并 409 u8_rejected。采购入库、其他入库、其他出库、销售出库、材料出库、产成品入库均适用。

销售

采购

库存

应收应付:收付款单、应收应付单见 §12。

质量单据

生产制造

10. 关闭和打开 vouchers/close#

请求:type、id、action(close 或 open,否则 400「action 只能是 close 或 open」),可选 line_ids。允许 sale_order、purchase_order、purchase_requisition、production_order、arrival,其他类型 400「该单据类型不支持关闭」。

line_ids 省略表示整张单据;带上则为 1 到 200 个不重复的正整数(§4 的行主键)。写成 JSON null 是 400,不视为整单。

关闭要求单据已审核,未审核 409「单据未审核」(U8 组件本身会关闭未审核的销售订单,桥在调用前拒绝)。整单已关闭再关 409「单据已关闭」,未关闭就打开 409「单据未关闭」,按行同理。采购订单没有可处理的行 409「没有可处理的行」。

成功:{"ok":true,"type","id","action","closed","closed_by","closed_at","lines":[{"line_id","closed"}]},lines 是全部表体行。采购订单只关部分行时表头关闭人仍为空,全部行关闭后 U8 才写表头。

请购单(purchase_requisition):只做整单(VoucherCO_PU 的 CloseApp / OpenApp),带 line_ids 400「请购单只支持整单关闭或打开」。关闭要求已审核,表头已关闭再关 409;打开要求表头或任一行已关闭,否则 409「单据未关闭」,打开后在新连接上核对表头和各行关闭人都已清空。响应 lines 为空数组。

到货单(arrival):整单或按行,id 是到货单 ID,line_ids 是 Autoid。走 VoucherCO_PU(Init vt 2)的 CloseArrItems / OpenArrItems,与采购订单一样在请求连接的事务里,可预演(dry_run,回滚模式)。

生产订单(production_order):按行关闭和打开,id 是 MoId,line_ids 是 MoDId。U8 没有关闭 / 打开的 API,桥按 U8 界面的做法在请求连接的事务里调用 Usp_MO_Close / Usp_MO_UnClose(见 u8-notes.md)。

锁定和解锁 vouchers/lock#

请求:type、id、action(lock 或 unlock,否则 400「action 只能是 lock 或 unlock」)。只允许 sale_order(id 是 SO_SOMain.ID),整单锁定,不按行。purchase_order 400 bad_request「采购订单锁定暂不支持(U8 采购组件 DoLock 实测一律拒绝)」(API 参数校验即拒绝,不调用 U8;U8 采购组件的 DoLock 一律回「本张已经被修改,不能锁定.」,见 limitations.md);其他类型 400「该单据类型不支持锁定」。

锁定人写在表头 cLocker,值是操作员姓名(不是编码);读取的表头里为 clocker,列表的附加列为 locker(§16)。

闸门(调用 U8 之前,按顺序):

走 VoucherCO_Sa.LockVouch,在桥的事务里;提交前在同一连接上核对 cLocker 已到目标状态,否则 409 u8_rejected「U8 没有锁定单据」「U8 没有解锁单据」;U8 拒绝 409 u8_rejected,原文带回。提交后在新连接上回读,失败或状态不符 504 outcome_unknown(先 vouchers/load 核对再决定是否重试)。

成功:{"ok":true,"type","id","action","locked","locker"}(本人已锁定的重试另带 "already":true),locked 是回读的 cLocker 是否非空,locker 是锁定人姓名,解锁后为空串。

销售订单、采购订单被其他操作员锁定时(采购订单只能在 U8 客户端加锁;姓名比较同上),该单据的修改(vouchers/update)、删除(vouchers/delete)、审核和弃审(vouchers/verify、sale-orders/verify)返回 409 state_mismatch「单据已被 X 锁定」,与 U8 界面一致;锁定人本人不受影响。关闭、打开和参照生单不查锁定。

11. 参照生单 vouchers/generate#

请求:type 是要生成的单据,id 是来源单据主键,可选 source_type、head、lines。来源须已审核、未关闭。新单据为未审核(销售发票为未复核)。

source_type 省略取该目标的缺省来源;不在名单里的来源 400「该单据类型不能参照此来源类型生单」;类型不能生单 400「该单据类型不支持生单」。

目标 来源 lines 剩余数量 表头可写 行可写
dispatch 销售订单 1 到 200 行,必填 iQuantity - isnull(iFHQuantity,0) ddate、cmemo、cwhcode、cdepcode、cpersoncode、cshipaddress、cdefine1…16 cwhcode、cbatch、cmemo、cdefine22…37、cfree1…10
sale_invoice 发货单 同上,source_line_id 是 iDLsID iQuantity - isnull(iSettleQuantity,0) - isnull(fretqtywkp,0)(扣除未开票退货,同 U8 视图 sale_DispToSaleVouchJS_B) cvouchtype(26 专用或 27 普通,缺省 26,其他值 400「该发票类型不支持」)、ddate、cmemo、cdefine1…16 cmemo、cdefine22…37
sale_invoice(source_type: "sale_return") 退货单(红字发货单,id 是 DLID),生成红字发票 可省略(全部有剩余的退货行按剩余数量);带了是 1 到 200 行,source_line_id 是退货行 iDLsID,quantity 填正数 abs(iQuantity) - abs(isnull(iSettleQuantity,0)) 同蓝字发票;cvouchtype 省略时取原蓝字发票(退货行 iCorID 上的发票)的类型,没有则 26 cmemo、cdefine22…37
sale_invoice(source_type: "sale_invoice") 已复核的蓝字销售发票(id 是 SBVID),红冲 可省略(全部有剩余的蓝字行按剩余数量);带了是 1 到 200 行,source_line_id 是蓝字发票行 AutoID,quantity 填正数 蓝字行数量 − 已红冲数量(指向该行的红字行合计) cvouchtype(只能同蓝字)、ddate(不早于蓝字发票)、cmemo、cdefine1…16 cmemo、cdefine22…37。见 §35「红冲蓝字销售发票」
sale_out 发货单 可省略(整张剩余);带了是 1 到 200 行,source_line_id 是 iDLsID,只收 source_line_id、quantity、cbatch、cposition(同一发货行可按批号 / 货位拆行) 整张:sum(iQuantity - isnull(fOutQuantity,0)) > 0;按行:iQuantity - isnull(fOutQuantity,0) 不能带表头字段 两步、非原子,见下文
purchase_in 采购订单 1 到 200 行,source_line_id 是 PO_Podetails.ID iQuantity - isnull(iReceivedQTY,0) cwhcode 必填(400「必须指定仓库」),另可写 crdcode(缺省见下文「收发类别」)、ddate、cmemo、cdepcode、cpersoncode、cdefine1…16 cbatch、cbmemo、cposition。一张入库单一个仓库
purchase_in(source_type: "qm_incoming_check") 来料检验单 恰好 1 行,source_line_id 等于检验单 ID(即 id) 合格 + 让步接收 − 累计入库 同上,cwhcode 必填 cbatch(缺省检验单批号)、cbmemo、cposition
purchase_in(source_type: "purchase_return") 采购退货单(红字到货单,id 是退货单 ID),生成红字入库 1 到 200 行,source_line_id 是退货行 Autoid,quantity 填正数 -(iQuantity - isnull(fValidInQuan,0) - isnull(fInValidInQuan,0))(退货行数量为负,同 U8 视图 pu_v_preparestockbyarrforst) 同参照采购订单,cwhcode 必填 cbatch(缺省退货行批号)、cbmemo、cposition
purchase_in(source_type: "arrival") 蓝字到货单(iBillType=0,id 是到货单 ID) 可省略(全部未关闭、有剩余的到货行按剩余数量);带了是 1 到 200 行,source_line_id 是到货行 Autoid iQuantity - isnull(fRefuseQuantity,0) - isnull(fValidInQuan,0) - isnull(fInValidInQuan,0)(同 U8 视图 pu_arrbody 的 fininquantity) 同参照采购订单;表头无 cwhcode 时取各行一致的 cwhcode(都没有 400「必须指定仓库」,不一致 400「一张采购入库单只能有一个仓库」) cwhcode、cbatch(缺省到货行批号)、cbmemo、cposition;到货行的生产日期、失效日期、保质期、自由项照抄
material_out 生产订单(id 是 MoId) 1 到 200 行,source_line_id 是子件 AllocateId,须属于同一订单行 不限(允许超领) cwhcode、crdcode 必填,另可写 ddate、cmemo、cdepcode(缺省订单部门)、cpersoncode、cdefine1…16 cbatch、cbmemo、cposition
product_in(source_type: "production_order") 生产订单(id 是 MoId) 恰好 1 行,source_line_id 是 MoDId Qty - isnull(QualifiedInQty,0);库存选项 ST.bOverMPIn(允许超生产订单入库)为真时不按剩余拦,交给 U8 同材料出库 cbatch、cbmemo、cposition
product_in 产品检验单 非合并检验恰好 1 行,source_line_id 等于检验单 ID;合并检验 1 到 20 行,每个来源一行,source_line_id 是合并来源 AUTOID(vouchers/load 的 merge_sources) 合格 + 让步接收 − 累计入库;合并检验按来源(QMMergeCheckDetail 同名列) 同材料出库 cbatch、cbmemo、cposition
product_in(source_type: "qm_product_reject") 产品不良品处理单(QM06,id 是处理单 ID) 恰好 1 行,source_line_id 是处理单表体 AUTOID 处理后数量(FDIMQUANTITY,为空时取不良品数量)− 已入库数(rdrecords10.iRejectIds 汇总);U8 不接受部分入库,quantity 须等于剩余数,否则 409「参照不良品处理单须一次入库全部处理后数量,本行应为 …」 同材料出库 cbatch(缺省处理后批号)、cbmemo、cposition
arrival 采购订单 1 到 200 行,source_line_id 是 PO_Podetails.ID,只收 source_line_id、quantity iQuantity - isnull(iArrQTY,0),不允许超订单到货 只收 cWhCode(缺省存货默认仓库)、dDate(缺省登录日期)、cMemo、cDepCode(缺省订单部门),键名不分大小写
purchase_return 蓝字到货单(缺省,id 是到货单 ID) 1 到 200 行,source_line_id 是原到货行 Autoid,只收 source_line_id、quantity iQuantity - isnull(fRetQuantity,0) 同到货单(cWhCode 缺省原到货行仓库,cDepCode 缺省原到货单部门)
purchase_return(source_type: "purchase_order") 采购订单(id 是 POID) 同上,source_line_id 是 PO_Podetails.ID isnull(iArrQTY,0)(U8 退货时已从累计到货中扣减) 同到货单
sale_return 蓝字发货单 1 到 200 行,source_line_id 是原发货行 iDLsID 未开票退货 iQuantity - iSettleQuantity - fretqtywkp,已开票退货 (iSettleQuantity - (iQuantity - fretqtywkp) > 0 ? iQuantity - fretqtywkp : iSettleQuantity) - fretqtyykp,都不超过原发货行 iQuantity - iRetQuantity ddate、cmemo、cdepcode、cpersoncode、cdefine1…16,布尔 invoiced cwhcode(缺省原发货行仓库)、cmemo、cdefine22…37
sale_return(source_type: "sale_return_apply") 已审核的退货申请单(id 是申请单 ID) 1 到 200 行,source_line_id 是申请行 AutoID,所选行须指向同一张蓝字发货单 申请行 iQuantity 绝对值 − 已退数量 fretqty 绝对值 同参照发货单;invoiced 须与申请行的开票标志一致 同参照发货单,cwhcode 缺省取申请行仓库。见 §35「退货申请单」
purchase_invoice 采购入库单(蓝字生成蓝字发票,红字生成红字发票) 1 到 200 行,source_line_id 是入库行 AutoID,quantity 填正数 iQuantity - isnull(iSumBillQuantity,0);红字入库行取两者绝对值之差 只收字符串:cPBVCode(发票号,必填,≤ 30)、cPBVBillType(01 专用 / 02 普通,缺省 01)、dPBVDate(缺省登录日期)、cPBVMemo(≤ 255) 只有 source_line_id、quantity
qm_incoming_inspect 蓝字到货单(id 是到货单 ID) 1 到 200 行,source_line_id 是到货行 Autoid,行须要检验(bGsp=1)、未关闭、未报检(bInspect=0) iQuantity - isnull(fInspectQuantity,0) dDate(缺省登录日期)、cDepCode(缺省到货单部门)、cInspectDepCode(报检部门,缺省同 cDepCode)、cDefine1…16 cWhCode
qm_product_inspect 生产订单(id 是 MoId) 1 到 200 行,source_line_id 是 MoDId,行须已审核(Status=3)、未关闭、要质检(QcFlag=1) Qty - isnull(DeclaredQty,0) 同来料报检单(cDepCode 缺省订单行生产部门) cWhCode
qm_incoming_check 来料报检单(id 是报检单 ID) 恰好 1 行,source_line_id 是报检单表体 AUTOID,quantity 是本次检验数量 FQUANTITY - isnull(FSUMCHECKQTY,0) cCheckPersonCode(检验员,必填)、cDepCode(检验部门,缺省报检部门)、project_code(检验方案)、cChkConclusion、fDtQuantity(抽检量,缺省 1)、dDate、cDefine1…16、chDefine11…16、items、cYielderCode(让步接收核准人,有让步数量时来料 / 产品检验单必填,400)、dYieldDate(缺省检验日期) fRegQuantity(合格)、fConQuantiy(让步)、fDisQuantity(不良)
qm_product_check 产品报检单(id 是报检单 ID) 同来料检验单 同来料检验单 同来料检验单 同来料检验单
qm_incoming_reject 来料检验单(id 是检验单 ID) 1 到 200 行,每行一种处置;source_line_id 都等于检验单 ID(可重复),各行 quantity 之和须等于检验单不良品数量 检验单 FDISQUANTITYS(不良数量,同 U8 参照视图口径);一张检验单只能生成一张处理单 dDate、cDefine1…16、chDefine11…16 cScrapDisCode(处理方式,必填)、cReasonCode(不良原因,必填)、cDimInvCode(处理后存货,降级类必填)、cbWhCode
qm_product_reject 产品检验单(id 是检验单 ID) 同来料不良品处理单 同来料不良品处理单 同来料不良品处理单 同来料不良品处理单
qm_other_check 其他报检单(id 是报检单 ID) 恰好 1 行,source_line_id 是报检单表体 AUTOID 行 FQUANTITY;一行只能生成一张(已有检验单或 BFLAG=1 409) 同来料检验单;cDepCode(检验部门)省略时取检验员所属部门 同来料检验单
purchase_settle 采购发票(id 是 PBVID) 不能带(整张发票自动结算,见下文「采购结算单生单」) 发票未结算(表头、表体 dSDate 为空,没有结算行) 只收 settle_date(yyyy-MM-dd,可省,即本次 U8 登录日期)
transfer 调拨申请单(id 是申请单 ID) 1 到 200 行,source_line_id 是申请单行 autoID,只收 source_line_id、quantity、cbmemo iTvChkQuantity - isnull(iTvSumQuantity,0)(核准数量减累计调拨,比 U8 按存货超额比例 fInExcess 放宽的口径严,件数不单独查);账套选项 ST.bOverTransRequestTransfer 为真时不设上限 dtvdate、cmemo、codepcode、cidepcode、cpersoncode、cordcode、cirdcode、cdefine1…16;仓库取自申请单,不能填 见 lines

每行必填 source_line_id(正整数)和 quantity(大于 0,不超过 1000000000000)。来源行重复 400「来源明细重复」,例外:销售出库同一发货行可按批号 / 货位列多次,(行、批号、货位)都相同才算重复,400「明细行重复」,且在桥读取发货单之后才判(发货单不存在、未审核先回 404 / 409);不良品处理单的来源行就是检验单本身,每种处置一行,source_line_id 都等于检验单 ID。数量超过剩余 409「超过可生单数量」。

成功:{"ok":true,"type","id","code","source_type","source_id","state","lines"},source_type 是实际来源,lines 是新单据的表体行数。检验单、不良品处理单另有 wf(其他检验单没有审批流,不带)。

采购发票和到货单保存后,桥在同一事务里核对 U8 已把本次数量加到来源累计数上,否则回滚并 409 u8_rejected。若 U8 在保存中已自行提交(本连接 @@TRANCOUNT 为 0),核对不过时无法回滚,返回 500 internal「U8 已自行提交,无法核对回写」,单据已落库,需人工核对。

通用:收发类别、采购类型、货位#

销售#

销售出库

采购#

库存与生产#

质量单据#

不良品处理单生单#

qm_incoming_reject(QM05)参照来料检验单,qm_product_reject(QM06)参照产品检验单,source_type 省略取对应的检验单类型。走 U8 质量管理组件 clsArrRejectCO / clsProRejectCO 的 AddVoucher,登录子系统 QM。

{"type": "qm_product_reject", "source_type": "qm_product_check", "id": 5,
 "head": {"dDate": "2026-01-10", "cDefine1": "批次复核"},
 "lines": [
   {"source_line_id": 5, "quantity": 1, "cScrapDisCode": "Sys01", "cReasonCode": "01"},
   {"source_line_id": 5, "quantity": 2, "cScrapDisCode": "Sys03", "cReasonCode": "01", "cDimInvCode": "A02", "cbWhCode": "01"}
 ]}

其他检验单生单#

qm_other_check(QM15,VT 365)参照已审核的其他报检单(qm_other_inspect),一个报检单行生成一张检验单。走 U8 质量管理组件 UFQMCo.clsOtherCheckVoucherCO(基于 VO 的接口,同不良品处理单)的 AddVoucher,登录子系统 QM。

{"type": "qm_other_check", "source_type": "qm_other_inspect", "id": 1001,
 "head": {"cCheckPersonCode": "op001", "cDepCode": "D901", "project_code": "P01"},
 "lines": [{"source_line_id": 1101, "quantity": 100}]}

采购结算单生单#

purchase_settle(卡片 99)参照一张采购发票自动结算:每个发票行按其 RdsId 与采购入库行配对,结算数量等于发票数量,一张发票生成一张结算单。走 U8 采购组件 VoucherCO_PU(载入发票后 CheckSettle、bRdBVAutoSettle),在桥的事务里,可预演(dry_run 回滚模式)。

{"type": "purchase_settle", "source_type": "purchase_invoice", "id": 9000000007,
 "head": {"settle_date": "2026-01-31"}}

12. 收付款单和应收应付单#

ar_receipt(收款单)、ap_payment(付款单)在 Ap_CloseBill,ar_bill(应收单)、ap_bill(应付单)在 Ap_Vouch。新增、修改、删除只处理手工录入的蓝字单据。核销、取消核销、自动核销、制单、取消制单、坏账、转账(应收冲应付、并账、红票对冲)、汇兑损益见本节各小节。

新增字段名不分大小写,用 U8 列名。名单外 400「不能设置字段 x」,同名重复 400「字段重复 x」。自定义项表头 cdefine1…16,表体 cdefine22…37。

类型 表头 表体
ar_receipt / ap_payment 必填 cDwCode(客户或供应商)、cCode(结算科目,存在且末级)、cSSCode(结算方式)。可写 dVouchDate、cDeptCode、cPerson、cexch_name、iExchRate、cDigest、cItem_Class、cItemCode、cOrderNo、cBank、cBankAccount 必填 cKm(本系统受控科目)和金额(本币 iAmt,外币 iAmt_f)。可写 iType(0 应收付款,1 预收付款)、iAmt_f、cDepCode、cPersonCode、cXmClass、cXm、cMemo
ar_bill / ap_bill 必填 cDwCode、cCode(本系统受控科目)。可写 dVouchDate、cDeptCode、cPerson、cexch_name、iExchRate、cDigest、cItem_Class、cItemCode、cPayCode、cOrderNo 必填 cCode(对方科目,不能是应收/应付受控科目)和金额(本币 iAmount,外币 iAmount_f;也收 iAmt / iAmt_f,同义的两个只能填一个)。可写 iAmount_f(或 iAmt_f)、iTaxRate(0 到 100)、cDeptCode、cPerson、cItem_Class、cItemCode、cDigest

规则:

期初单据(bStartFlag=1)不经这几条路由,用 openings/arap(§29)。弃审和删除都拒绝已生成凭证、非手工录入(含期初)、来自票据或网银、已核销的单据;弃审还拒绝除本单审核行以外还有往来明细、审核期间已结账;删除要求未审核且没有任何往来明细。都是 409 state_mismatch。审核成功要求新连接上审核人等于登录操作员姓名。

例外:notes/create 登记生成的收款单(cSrcFlag='C'、cCoVouchType='50')同 U8 收付款单审核界面可以弃审,条件是票据号与来源号一致、来源票据的 iCloseID 指向本单(分包票据的收款单票据号是「票据号-起-止」,起止须与票据的子票区间一致)、票据不是期初、没有处理记录(AP_Note_Sub)、余额等于票面、没换票,其余弃审条件照旧(不满足 409 state_mismatch,如「票据 X 已有处理记录(结算、贴现、背书等),不能弃审其收款单」)。这类收款单不能修改、删除,删除走 notes/delete。

核销 arap/writeoff#

收款单(付款单)的一行,对若干张销售发票、应收单(采购发票、应付单)核销,相当于 U8 应收(应付)款管理的手工核销。调用 U8 核销组件 U8ApCancel.cLsCancel(Init 后 Save 核销报文),登录子系统随收付款单(收款单 AR、付款单 AP),在桥的事务里执行。

请求(不带 type、id):

{"receipt": {"type": "ar_receipt", "id": 9000000005, "line_id": 9000000103},
 "items": [{"type": "sale_invoice", "id": 9000000006, "line_id": 9000000104, "amount": 6.00}]}
字段 说明
receipt.type ar_receipt 或 ap_payment
receipt.id Ap_CloseBill.iID
receipt.line_id 收付款单表体行 Ap_CloseBills.ID。只有一行有未核销余额时可省略,否则 400
items 1 到 50 项。收款单只能核销 sale_invoice、ar_bill,付款单只能核销 purchase_invoice、ap_bill,否则 400;同一单据行不能重复
items[].id 销售发票 SBVID、采购发票 PBVID、应收单 / 应付单 Ap_Vouch.Auto_ID
items[].line_id 发票表体行(SaleBillVouchs.AutoID / PurBillVouchs.ID,即往来明细的 iBVid)。发票只有一行有未核销余额时可省略。应收单、应付单按整单核销(iBVid 为 0),带了 400
items[].amount 本次核销金额(原币),大于 0、不超过 1000000000000、最多两位小数
date 公共字段,登录日期即核销日期(缺省今天)

币种:收付款单的币种和汇率就是这次核销的币种和汇率(表头为空按本位币;本位币汇率必须是 1,外币汇率必须大于 0)。每张单据必须与它同币种,否则 409 state_mismatch「…的币种与收付款单不一致」。单据自己的汇率可以不同:同 U8,核销一律按收付款单的汇率记,汇兑差额留给期末汇兑损益(9M,见 arap/exchange_gain),本接口不做。报文 close 和每个 vouch 都写收付款单的 cexchname、iexchrate;本币 = 原币 × 收付款单汇率四舍五入到分,close 按合计折算,各 vouch 逐个折算,尾差并到第一个 vouch。余额核对一律按原币。

预收 / 预付行(Ap_CloseBills.bPrePay=1,即新增时 iType=1 的行)同样可以核销,报文带 bprepay="1"。U8 在这种行上核销时可能另插 Ap_CloseBills 行,桥核对余额时按行主键重读该行,再加上 Save 新插行(本收付款单上行主键大于调用前最大值的行)的余额。

以 AR / AP 登录时 U8 的 Save 不查日期、期间和锁,这些由桥在事务里带锁读单据后检查:

400 bad_request:字段、类型、数量、金额不合法;line_id 不属于该单据「明细行不存在」;没给 line_id 而收付款单或发票有多行未核销余额(「请指定 line_id」)。其余拒绝(含币种不一致)都是 409 state_mismatch。U8 的 Save 抛错或返回 false 时 409 u8_rejected,message 为 U8 原文。桥不查 Locked_by_Other(LockVouch 表),见 docs/limitations.md。

U8 写入 Ar_Detail / Ap_Detail 的 9P 行(同一个新核销号 cCancelNo,HXAR… / HXAP…;每个单据行一条,另有收付款单的冲减行),并更新收付款单行余额、发票累计核销、应收应付单余额。提交前核对:收付款单该行余额减少了合计、每个单据行余额减少了各自金额、本收付款单上新写的核销行只有一个核销号,否则回滚、409 u8_rejected;事务已被数据库回滚(如死锁牺牲品)503 u8_unavailable(未写入,可以重试)。提交后在新连接上回读本核销号的核销行,每个单据行的金额和收付款单冲减合计对得上才算成功;不符或回读失败 504 outcome_unknown(已提交,先用 reports/arap_detail 或 vouchers/load 核对,不要直接重投)。

响应:

{"ok": true, "acc": "801", "cancel_no": "HXAR0000000000001", "date": "2026-09-28",
 "receipt": {"type": "ar_receipt", "id": 9000000005, "line_id": 9000000103, "code": "SK0000000001", "remaining": 844.00},
 "items": [{"type": "sale_invoice", "id": 9000000006, "line_id": 9000000104, "code": "SOZP0000000001",
            "amount": 6.00, "remaining": 0.00}]}

remaining 是核销后的未核销余额;应收单、应付单没有 line_id。

取消核销 arap/writeoff/cancel#

按核销号整批撤销一次核销,相当于 U8 应收(应付)款管理「其他处理 → 取消操作」里取消一条核销(9P)。U8 没有可调用的取消组件,桥执行与 U8 界面相同的 SQL(9P 分支,实测核对),在请求连接上的一个事务里完成,提交前核对每个余额精确回到核销前。登录子系统就是 flag。

请求(不带 type、id):

{"flag": "AR", "cancel_no": "HXAR0000000000001"}
字段 说明
flag AR(应收,Ar_Detail)或 AP(应付,Ap_Detail)
cancel_no arap/writeoff 返回的核销号,或 U8 里核销的 cCancelNo。HXAR / HXAP 后接 1 到 20 位数字,前缀要与 flag 一致,否则 400

只收与 arap/writeoff 同形的批次。桥在事务里带锁读出该核销号的往来明细(条件 cProcStyle=N'9P'、cCancelNo、cFlag,走 U8 索引 INDEX_Ar_Detail_HXZD / INDEX_Ap_Detail_HXZD,只锁这一批)后检查:

写入内容和顺序同 U8:按冲减行加回 Ap_CloseBills.iRAmt_f / iRAmt / iRAmt_s(表头由触发器 TR_Ap_CloseBills 汇总);加回应收单 / 应付单 Ap_Vouch.iRAmount_f / iRAmount,iRAmount_s 按原币余额比例重算;销售发票经临时表 #ap_SaleBillVouchHXdata 交 U8 回写组件 Ussaupdispatch.clsWrite2Bill.UpdateBillForAR(同一事务)加回 iExchSum / iMoneySum,并连带销售订单、发货单的累计核销和信用额度;采购发票经 #ap_PurBillVouchHXdata 加回 PurBillVouchs.iOriTotal / iTotal;收付款单各行都回到未核销时清空 cCancelMan、bPrepay 置 0;最后删掉该核销号的 9P 行。不做 U8 的「保留线索」(选项 bAR2Cancel / bAP2Cancel)。

提交前在同一事务里核对:核销行已删光;收付款单每行余额 = 原值 + 冲减合计;每个单据行余额(同核销的口径)= 原值 + 本批金额;应收单 / 应付单 iRAmount_f = 原值 + 本批金额;发票累计核销 = 原值 + 临时表合计。不符回滚、409 u8_rejected;回写组件抛错 409 u8_rejected(原文),改变了事务 504;事务被数据库回滚 503 u8_unavailable。提交后在新连接上确认该核销号的行已不在:读不出或仍在 504 outcome_unknown(已提交,先核对,不要直接重投)。

响应:

{"ok": true, "acc": "801", "cancel_no": "HXAR0000000000001", "flag": "AR",
 "receipt": {"type": "ar_receipt", "id": 9000000005, "line_id": 9000000103, "code": "SK0000000001", "remaining": 850.00,
             "lines": [{"line_id": 9000000103, "amount": 6.00, "remaining": 850.00}]},
 "items": [{"type": "sale_invoice", "id": 9000000006, "line_id": 9000000104, "code": "SOZP0000000001",
            "amount": 6.00, "remaining": 6.00}]}

amount 是加回的金额,remaining 是取消后的未核销余额;批次涉及收付款单多行时 receipt.line_id、receipt.remaining 为 null,看 lines。

自动核销 arap/writeoff/auto#

对一个客户(供应商)按 U8 的自动核销规则配对,一次核掉多行,相当于 U8 应收(应付)款管理的「自动核销」。U8 的 cLsCancel.AutoCancel 无界面调用时不写入(见 u8-notes.md),所以由桥配对,每行收付款单一批,交给与 arap/writeoff 相同的核心(同一道闸门、同一个 Save 报文:一个 close 下挂这一批的全部 vouch,同样在事务里核对)。登录子系统就是 flag,核销日期是登录日期。

请求(不带 type、id):

{"flag": "AR", "partner": "C900001", "date_to": "2026-09-28",
 "receipt": {"type": "ar_receipt", "id": 9000000005, "line_id": 9000000103},
 "targets": [{"type": "sale_invoice", "id": 9000000006}],
 "max_amount": 100.00, "dry_run": true}
字段 说明
flag AR 或 AP,也是登录子系统
partner 必填,客户(AR)或供应商(AP)编码(cDwCode),1 到 20 个字符。不做整个账套的自动核销
date_to 可选,只取单据日期不晚于它的收付款单和单据;缺省登录日期,晚于登录日期 400
receipt 可选,{type, id[, line_id]}:只用这张收付款单(这一行)。type 须与 flag 一致(ar_receipt / ap_payment),否则 400
targets 可选,1 到 200 项 {type, id}:只核这些单据(不分行)。类型须与 flag 一致,不能重复,否则 400
max_amount 可选,本次核销合计上限(原币累计,不分币种),大于 0、最多两位小数
dry_run 可选布尔,缺省 false。true 只返回计划,不写
include_prepay 可选布尔,缺省 false。true 时预收 / 预付(bPrePay=1)的收付款单行也参加配对(报文带 bprepay="1",同 arap/writeoff)

配对规则(U8 核销规则 iHxRule=0 时的规则,只按往来单位,不按订单、合同、存货):

账套设置了按规则核销(iHxRule 不为 0,或 bAPAutoCancelWithHxRule 为真)时 409「账套设置了按规则核销(订单 / 合同 / 存货等),自动核销暂不支持」,dry_run 同样。

执行:全部批在一个事务里,逐批先过 arap/writeoff 的闸门(带锁重读,余额含前面各批 Save 的结果;同样的 404 / 409 / 403),再 Save、核对余额和新核销号;任一批失败整体回滚,返回 U8 原文(409 u8_rejected)或闸门的错误。提交后在新连接上逐批回读核销行,不符或回读失败 504 outcome_unknown(已提交,message 列出核销号,先核对,不要直接重投)。没有可配对的不是错误:200,batches 为空、total 为 0。

dry_run:候选查询和配对照做,每一批也过闸门和数据权限(只读,不开事务、不建组件),返回计划。

响应(执行):

{"ok": true, "acc": "801", "flag": "AR", "partner": "C900001", "date": "2026-09-28", "date_to": "2026-09-28",
 "batches": [{"cancel_no": "HXAR0000000000002",
              "receipt": {"type": "ar_receipt", "id": 9000000005, "line_id": 9000000103, "code": "SK0000000001",
                          "remaining": 750.00},
              "items": [{"type": "sale_invoice", "id": 9000000006, "line_id": 9000000104, "code": "SOZP0000000001",
                         "amount": 100.00, "remaining": 0.00}],
              "amount": 100.00}],
 "total": 100.00}

响应(dry_run):dry_run: true、mode: "plan"(区别于 §23 的预演响应),plan 每项 {receipt: {type, id, line_id, code, date, remaining}, targets: [{type, id, line_id, code, date, balance, amount}], amount}(remaining、balance 是分配前的余额),另有 total;没有 batches。

制单 arap/voucher#

一张已审核的单据生成一张总账凭证,相当于 U8 应收(应付)款管理「制单处理」里对一张单据制单;用 ids 可把同类型的 2 到 20 张单据合成一张凭证(「合并制单」,见下文)。U8 没有可无界面调用的制单组件,桥按 U8 的制单规则拼分录,经 U8 凭证导入组件 U8PzInsert.clsPZInsert.Transact 保存(同 §14,组件自行提交),再做与 U8 相同的回写。登录子系统就是 flag。

请求(带 type、id):

{"flag": "AR", "type": "sale_invoice", "id": 9000000006, "sign": "转", "voucher_date": "2026-09-24", "digest": "销售"}
字段 说明
flag AR 或 AP,也是登录子系统
type 应收 sale_invoice(26 / 27)、ar_receipt(48)、ar_bill(R0)、ar_refund(客户退款 49);应付 purchase_invoice(01 / 02)、ap_payment(49)、ap_bill(P0)、ap_refund(供应商退款 48)。须与 flag 同侧,否则 400
id 单据主键:发票 SBVID / PBVID,收付款单和退款单 Ap_CloseBill.iID,应收应付单 Ap_Vouch.Auto_ID。与 ids 只能给一个
ids 可选,合并制单:[{"type": …, "id": …}, …],2 到 20 项,type 都相同、id 不重复,否则 400。经 API 时顶层 type 可省略(取 ids 的);直接调桥时顶层 type 必填且与各项一致
sign 可选,凭证类别(dsign.csign,不能是调整期类别)。省略时:凭证里有现金或银行科目(code.bcash / bbank)时,第一行这种科目在借方用「收」、在贷方用「付」,否则「转」;该类别不存在 409,请指定
voucher_date 可选,制单日期 yyyy-MM-dd,缺省取单据日期(合并制单取最晚的单据日期)。请求的 date 是登录日期,不是制单日期
digest 可选,摘要,最多 120 字;缺省取往来明细上的摘要(往来行优先),都没有就是「销售 / 购 / 收 / 付」加往来单位名称。给了就每行相同;合并制单缺省时各单据的分录用各自的摘要
cash_items 可选,指定现金流量项目:{"<科目编码>": "<现金流量项目编码>"},最多 20 个科目,科目编码不超过 40 位、项目编码不超过 20 位、都不含空白,科目不分大小写不能重复,否则 400。要挂项目的分录(见下文「现金流量」)科目在表里就用给的项目;项目须存在(fitemss98)且未关闭,否则 400(field 为 cash_items.<科目>);科目在本次凭证里没有要挂项目的分录 400「科目 X 在本次凭证里没有现金流量行」(field 为 cash_items)

支持的单据和分录(与 U8 客户端制单结果一致;科目都按 code 中会计年度 = 制单日期年份的科目查):

单据 借方 贷方
销售发票 往来科目:往来明细(Ar_Detail,审核时登记,cProcStyle = cVouchType)的 cCode,金额 iDAmount 收入科目按表体 iNatMoney、销项税科目按 iNatTax
采购发票 采购科目按表体 iMoney、进项税科目按 iTaxPrice 往来科目:Ap_Detail.cCode,金额 iCAmount
收款单 结算科目:往来明细的结算行(iFlag=6,现金、银行、票据科目),带结算方式、票据号、单据日期 往来科目:往来行(iFlag=0);票据登记行(iFlag=3)不出分录
付款单 往来科目(往来行) 结算科目(结算行)
供应商退款 往来科目(往来行,负数),再结算科目(结算行,正数) —
客户退款 — 往来科目(往来行,负数),再结算科目(结算行,正数)
应收单 往来科目(往来明细) 对方科目:表体 Ap_Vouchs.cCode,不含税 iNoTaxAmount;税额 iNatTax 走销项税科目
应付单 对方科目 + 进项税科目 往来科目

闸门(在事务里带锁,409 state_mismatch,文案尽量用 U8 的):

功能权限:应收 AR0508、应付 AP0508(U8 授权目录「生成凭证」);数据权限按单据表头的往来单位(必控)、部门、业务员(同核销)。

执行分三步:

  1. 事务:带锁读单据、过闸门、拼分录,取外部业务号:Ap_CancelNo 里 cType='PZ'、cFlag=AR|AP 的号加一(AR / AP 加 13 位补零数字,如 AR0000000000001;已被占用就往后跳),提交。
  2. Transact 保存凭证(renewproofno="y",U8 取凭证号)。报文带外部来源:voucher_making_system = AR / AP、reserve1(coutsign:付款单 RP、应付单 AR,其余同 flag)、reserve2 = 外部业务号、每条分录 bill_type / bill_id / bill_date(单据类型、单号、制单日期)。按 AR / AP 被拒且确认未写入时改用 GL 再导一次(响应 making_system 说明实际值),仍被拒 409 u8_rejected,带 U8 原文(外部业务号已消耗,同 U8 不回退)。然后(不在事务里)核对 U8 返回的凭证号上正是这张凭证(行数、借贷合计、未记账),否则 504,不碰它。
  3. 事务:补齐凭证的来源列(coutsysname、coutsign、coutno_id、coutbillsign、coutid 等)和 GL_CashTable.csign,做与 U8 相同的回写:往来明细 cPZid、dPZDate、cGLSign、iGLno_id、ino_id(该明细行所在分录的分录号);发票表体 cClue = 外部业务号、cPZNum(如 转-0001)、dSignDate;收付款单、应收应付单表头 cPzID、cPZNum、doutbilldate。核对回写完整、外部业务号没有撞号(U8 客户端取号不等桥的锁:总账里只有本凭证用这个号,往来明细里用这个号的正好是本单的原始行),都对才提交。

第 3 步失败(包括单据在第 1、3 步之间被 U8 客户端制了单、外部业务号撞号):在新事务里删掉刚生成的凭证(同取消制单;撞号时只按凭证键删本凭证,不清别人的回写)并清掉回写,409 state_mismatch「制单回写失败(…),已删除刚生成的凭证 …」,单据仍未制单;删不掉 504 outcome_unknown,消息带凭证号和外部业务号,请在 U8 里删除该凭证。第 2 步调用异常、返回无法解析或没有凭证号 504 outcome_unknown(凭证可能已保存)。提交后在新连接上回读凭证行和往来明细,对不上或读不出 504。

响应:

{"ok": true, "acc": "801", "flag": "AR", "type": "sale_invoice", "id": 9000000006, "code": "SOZP0000000001",
 "pz_id": "AR0000000000001", "making_system": "AR",
 "voucher": {"year": 2026, "period": 9, "sign": "转", "no": 1, "num": "转-0001", "date": "2026-09-24"},
 "lines": [{"entry": 1, "account": "1122", "digest": "销售…", "debit": 113.00, "credit": 0, "customer": "C900001",
            "dept": null, "person": null, "supplier": null, "item_class": null, "item": null, "settle": null},
           {"entry": 2, "account": "6001", "digest": "销售…", "debit": 0, "credit": 100.00, "item_class": "ch",
            "item": "INV001", "...": "..."},
           {"entry": 3, "account": "2221", "digest": "销售…", "debit": 0, "credit": 13.00, "...": "..."}]}

lines 是提交后回读的凭证行,每行另有 bill_code(凭证行的 coutid,即来源单据号)。bills 是本凭证覆盖的单据 [{"type","id","code","vouch_type"}](按请求顺序,单张制单也有一项);type、id、code 是第一张。

合并制单(ids):与 U8 合并制单的凭证一致(例如多张收款单一张凭证,每行 coutid 是该行来源单据号)。逐张带锁读单据、过上面全部闸门(任一张不合格整笔拒绝,消息前加「ids 第 i 张(id …)」,field 是 ids.<i>);每张单据各自拼分录、只在本单内合并,再整张排序(借方在前,同方向按单据顺序);制单日期不早于任何一张单据日期;一个外部业务号、一张凭证,各单据逐张回写。锁键是每张单据的单据键加下面的凭证键。预演的 detail.voucher.sources 列出全部单据、每行分录带 bill_code。取消用 arap/voucher/delete 一次完成。不做混合类型(如发票和收款单一张凭证)、核销制单。

取消制单 arap/voucher/delete#

按外部业务号删除应收(应付)生成的凭证并清掉单据上的凭证号,相当于 U8 应收(应付)款管理「凭证查询」里删除凭证。桥在请求连接的一个事务里执行与 U8 相同的删除和清除。登录子系统就是 flag。

请求(不带 type、id):

{"flag": "AR", "pz_id": "AR0000000000001"}

pz_id 是 arap/voucher 返回的外部业务号,或 U8 里制单的单据往来明细上的 cPZid(= 凭证的 coutno_id);AR / AP 后接 1 到 20 位数字,前缀要与 flag 一致,否则 400。

闸门(带锁):

功能权限同制单(AR0508 / AP0508);数据权限按往来明细的往来单位、部门、业务员。

合并制单的凭证同样一次取消:清除语句按外部业务号执行,引用它的全部单据在同一个事务里清掉凭证号。

写入:删未记账凭证(GL_accvouch、GL_CashTable、GL_CodeRemark);同 U8 清除发票表体、Ar_BadPara、AR_RZDetail、Ap_Vouch、Ap_CloseBill、Ap_Note_Sub、CM_Balance 上的凭证号,往来明细的 cPZid、cGLSign、iGLno_id(dPZDate、ino_id 不清)。提交前核对凭证行、往来明细、发票线索号、表头凭证号都不再引用该外部业务号,否则回滚 409 u8_rejected;提交后在新连接上再核对:读不出或仍有引用 504 outcome_unknown(已提交,先核对,不要直接重投)。Ap_CancelNo 的号不回退(同 U8)。

响应:{"ok": true, "acc": "801", "flag": "AR", "pz_id": "AR0000000000001", "deleted": true, "voucher": {"year": 2026, "period": 9, "sign": "转", "no": 1}}。锁键只有 arap:voucher:AR|AP,受全局写闸门约束。

坏账 arap/bad_debt#

U8 应收款管理「坏账处理」的三种操作,只做应收(登录子系统 AR)。属于第二级写入(复刻 U8 界面执行的 SQL,已在测试账套实测核对):缺省关闭,桥 config.json 未开 enableReplicatedWrites 时 403 feature_disabled;打开后只对 testAccounts 里的账套开放,其他账套 403 test_account_only。两道检查在登录前做,含预演。正式账套请在 U8 客户端操作(见 docs/configuration.md、docs/limitations.md)。写入在请求的事务里执行,提交前核对。

action 处理 处理方式 处理号 字段
occur 坏账发生 9G HZAR… customer(必填)、lines(必填,1 到 50 项)、currency、digest(缺省「坏账发生」)、dept、person
recover 坏账收回 9H HZAR… customer、receipt、amount(都必填)、currency、digest(缺省「坏账收回」)
provision 计提坏账准备 9F HZAR… 无(只有登录字段和 dry_run)

某个 action 不收的字段给了就 400。三种处理共用 U8 的处理号 HZAR + 13 位数字(Ap_CancelNo 的 cType=HZ、cFlag=AR,在桥的事务里取号);currency 省略为本位币。

公共条件(409 state_mismatch,除注明外):

occur(坏账发生):lines 每项 {type, id, line_id?, amount}。type 是 26 / 27 / 28 / 29(销售发票)或 R0 到 R9(应收单,不含 RZ;不收收付款单,同 U8),id 是单据号;line_id 是发票表体行,省略时按行主键从小到大分摊,应收单按整单、不能带;amount 是原币,大于 0、最多两位小数、不超过该单据(行)的正余额。同一单据行不能重复,同一单据不能既整单又按行。单据须已审核、属于 customer、币种与 currency 相同;外币各单据的汇率须相同(否则 400),坏账行用单据的汇率折本币。dept(最多 12 位)须是存在的末级部门、person 须是存在的业务员,登记日期当天或之前已停用的也不行(都是 400,同应收单据新增)。写入:一个处理号,每个单据行一行 9G 贷方往来明细(iCAmount / iCAmount_f,cVouchType = cCoVouchType 为原单据,cCode 是原单据的应收科目),冲减单据余额(应收单 Ap_Vouch.iRAmount*;发票经 #ap_SaleBillVouchHXdata 和 U8 回写组件 UpdateBillForAR),坏账准备余额 iRemainAmount 减去本币合计。

recover(坏账收回):receipt 是该客户、该币种的收款单(48)单号(须唯一),须未审核(cCheckMan 为空)、未核销(cCancelNo 为空)、只有一行应收款(iType=0,多行 409)、不是票据或网银生成、不受审批流锁定;已有往来明细(做过审核、核销或其他处理)时在审核前拒绝(409)。amount 必须等于收款单全部余额,否则 409「坏账收回金额须等于收款单金额 X」(U8 整张收款单一起消耗,取消时整张复原)。写入(一个事务):先用 U8 收款单审核组件审核收款单(同 vouchers/verify 的 ar_receipt,写审核行(贷方)和审核人;审核日期是登录日期),再写一行 9H 借方往来明细挂在收款单上(cVouchType = cCoVouchType = 48,登记日期为 date,科目取收款单行的应收科目 Ap_CloseBills.cKm),收款单余额 iRAmt* 清零,坏账准备余额加上本币金额。9H 借方与审核行贷方相抵,客户应收余额不变;提交前核对这张收款单上的往来明细(iFlag<3)借贷合计本币、原币都为 0,否则回滚 409 u8_rejected,消息带合计。不另建应收单。制单时一并回写收款单审核行和表头凭证号(见下文「制单」),U8 的制单列表不再列出这张收款单。

provision(计提坏账准备):按参数行的计提方法算应计坏账准备 target:

iJtStyle 方法 基数 base target
1 应收余额百分比 应收往来明细借贷差(iFlag<3,不含合同等业务类型) base × nJtRate
2 账龄分析 按 Ar_BadAge 各账龄区间的应收余额(账套选项按收款条件的信用天数推算时同 U8) Σ 区间余额 × 区间比率
3 销售收入百分比 date 所在年度 1 月 1 日到 date 已审核、非期初、未作废的销售发票本币价税合计(SaleBillVouchs.iNatMoney) base × nJtRate

方法 3 的取数区间是本服务的约定,与 U8 界面结果不一致时以 U8 为准。本次计提 = round(target − 当前余额, 2),可以为负(冲回);为 0 时 409「本次计提金额为 0」。写入:只更新该年度的参数行(dJtDate、iRemainAmount 与 iJtAmount 各加本次计提、cProcStyle=9F、cCancelNo 为本次处理号),不写往来明细;没有该年度参数行时 409(U8 会新增一行,桥不新增)。

响应:{"ok": true, "acc": "801", "action": "occur", "cancel_no": "HZAR0000000000001", "style": "9G", "amount": 120.5, "remain_before": 500, "remain_after": 379.5, "rows": [{"type": "26", "id": "0000000012", "line_id": 1001, "amount": 100.5, "remaining": 0}, …]}。amount 在发生、收回是原币合计,在计提是本次计提(本币);remain_before / remain_after 是坏账准备余额;style_name 是处理方式名称(坏账发生、坏账收回、计提坏账);计提另有 base、rate、target、method_name(应收余额百分比法、账龄分析法、销售收入百分比法)。dry_run 是 rollback 模式。

取消(arap/process/cancel,flag=AR,cancel_no 为 HZAR…,开放条件同上):桥按处理号判断种类(往来明细里的 9G / 9H 行,或参数行 cCancelNo 对应 9F)。处理所在会计年度、期间按处理日期在 UA_Period 里查。

制单(arap/process/voucher,flag=AR,cancel_nos 为 HZAR…,一次只能是同一种坏账处理,否则 409;开放条件同上):凭证来源 coutsign 为 JT,coutsysname 为 AR。

读取:9G / 9H 是往来明细里的处理行,出现在 arap/process/list;9F 没有往来明细,只出现在 arap/process/list 的摘要项里(每个年度参数行一项,取最近一次计提),不在按 Auto_ID 增量的处理记录列表里。

功能权限(按 U8 窗体的权限号检查):发生 AR050602、收回 AR050603、计提 AR050601(上级「坏账处理」AR0506 也放行);取消同 arap/process/cancel(AR0807),制单同 arap/process/voucher(AR0508)。数据权限按客户、部门、业务员。

应收冲应付、并账、红票对冲 arap/transfer、arap/merge、arap/red_offset#

U8 应收(应付)款管理「转账」里的三种处理。都写往来明细的处理行,发票累计核销经 U8 的回写组件,在桥的事务里执行,提交前核对余额,不符回滚 409 u8_rejected。处理日期就是登录日期 date(缺省今天),须在本系统(转账为应收、应付两边)未结账的期间内,且不早于单据日期和系统启用日期。三者都返回处理号 cancel_no:取消用 arap/process/cancel,制单用 arap/process/voucher(处理号表见 §16「notes/process」末尾)。dry_run 是 rollback 模式。

单据项 {type, id, line_id?, amount}:type 是 U8 单据类型代码,应收一侧 26 / 27(销售发票)、R0(应收单),应付一侧 01 / 02(采购发票)、P0(应付单);收付款单(48 / 49)不收,请用核销。id 是单据号;line_id 是发票表体行,省略时按行主键从小到大依次分摊,应收单、应付单按整单、不能带;amount 是原币,大于 0、不超过 1000000000000、最多两位小数。同一单据行不能重复,同一单据不能既整单又按行。每侧 1 到 50 项。digest 最多 120 个字符。

路由 字段 处理方式 / 处理号
arap/transfer flag(AR 应收冲应付,AP 应付冲应收,也是登录子系统)、customer、vendor(都必填)、ar_lines、ap_lines(都必填,两侧 amount 合计须相等)、currency(省略为本位币,各单据须同币种)、digest(省略用 U8 的缺省摘要) 9I YCFAP… / 9J FCYAR…
arap/merge flag(AR / AP)、from(并出)、to(并入,不能与 from 相同)、lines(必填,类型随 flag;amount 可省略,表示并入该单据或行在 from 名下的全部余额)、digest(省略为「并账」) BZ BZAR… / BZAP…
arap/red_offset flag(AR / AP)、partner(客户或供应商,必填)、red、blue(都必填,类型随 flag,两侧合计须相等,同一单据不能同时出现在两侧)、currency、digest(U8 组件不收时忽略) 9N HRAR… / HPAP…

请求示例:

{"flag": "AR", "customer": "C900001", "vendor": "S900001",
 "ar_lines": [{"type": "26", "id": "0000000001", "amount": 100.00}],
 "ap_lines": [{"type": "P0", "id": "0000000002", "amount": 100.00}]}

并账每张单据(行)写一对 ± 处理行,单据本身不改;红票对冲调用 U8 的对冲组件 U8ApCancel.cLsCancel.AP_JZ_Red。

响应:

错误:404 not_found 单据不存在;409 workflow_enabled 单据受审批流控制;409 state_mismatch 单据未审核、往来单位或币种不符、余额不足、日期早于单据日期或系统启用日期、期间已结账(转账另有外币两侧折合本币不等,并账另有单据不属于 from、一次超过 500 行,红票对冲另有红蓝方向不对);U8 拒绝时 409 u8_rejected(带回 U8 原文)。

功能权限:应收冲应付 AR050502、应付冲应收 AP050502,红票对冲 AR050503 / AP050503,并账 AR050504 / AP050504;上级「转账」AR0505 / AP0505 同样放行。数据权限按各单据的往来单位、部门、业务员(并账另按 from、to)。

汇兑损益 arap/exchange_gain、arap/exchange_gain/cancel#

U8 应收(应付)款管理的汇兑损益(处理方式 9M):按外币余额和调整汇率计算本币差额,每个(往来单位、单据)一个处理号 SYRAR… / SYPAP…,写往来明细,发票累计核销经 U8 的回写组件。属于第二级写入(§3),开放条件同 arap/bad_debt。登录子系统就是 flag;登记日期就是登录日期 date,须在本系统未结账的期间内。

arap/exchange_gain 请求:

字段 说明
flag 必填,AR 或 AP
currency 必填,外币名称,如「美元」;本位币 409
rate 调整汇率,大于 0、不超过 1000000、最多 10 位小数;省略取该期外币设置里的调整汇率,没有则 409「本期没有调整汇率」
partners 1 到 200 个客户(供应商)编码,不能重复;省略为全部
settle_cleared 缺省 true:原币已结清只剩本币尾差的单据一并结清
{"flag": "AR", "currency": "美元", "rate": 7.0, "partners": ["C900001"]}

响应:acc、flag、date、fiscal_year、period、currency、rate(使用的调整汇率)、rows(写入的明细行数)、total(本币差额合计)、batches(每个处理号的 cancel_no、partner、type、id、lines、diff,diff 是本币差额,借正贷负)。

arap/exchange_gain/cancel 请求:flag,可选 cancel_nos(1 到 200 个处理号,SYRAR… 用 AR、SYPAP… 用 AP,不能重复);省略时取消登记日期为登录日期 date 的全部未制单汇兑损益。桥按 U8 界面执行的取消 SQL 写,在一个事务里加回余额、删掉明细行并核对。响应:acc、flag、by_date(按日期取消时的日期,按处理号取消时省略)、rows(删掉的行数)、batches、total。

错误:登记时 409 state_mismatch 为币种不存在或是本位币、日期不在会计期间或早于启用日期、期间已结账、批次过多;取消时 404 not_found 为处理号不存在或该日没有汇兑损益,409 state_mismatch 为已制单(先用 arap/voucher/delete 删凭证)、期间已结账、之后还有其他处理。核对不符回滚 409 u8_rejected。dry_run 是 rollback 模式。

制单用 arap/process/voucher,须给 pl_code(汇兑损益科目编码,U8 在制单界面选,桥不猜),只做本币批次。功能权限:汇兑损益 AR0507 / AP0507,取消同「取消操作」AR0807 / AP0807;数据权限按往来单位。

13. 审批流 workflow/*#

只接入了四种质量单据:qm_incoming_check(QM03)、qm_product_check(QM04)、qm_incoming_reject(QM05)、qm_product_reject(QM06)。其他类型 400「该单据类型未接入审批流」。审批流本身(节点、审批人、条件分支)在 U8 里配置,桥只按 U8 的规则推进。

路由 请求 作用
workflow/state type、id 审批状态
workflow/history type、id 审批历史
workflow/tasks 可选 type 当前操作员的待办。带了 type 时必须是已接入的类型,否则登录前 400
workflow/submit type、id 提交。不能带 opinion
workflow/withdraw type、id 撤销提交。不能带 opinion
workflow/approve type、id,可选 opinion 同意
workflow/disagree type、id、opinion 必填 不同意并继续(末节点时流程以「不通过」结束)
workflow/return type、id、opinion 必填 退回提交人
workflow/abandon type、id,可选 opinion 弃审:撤回本人上一次同意,终审后也可
workflow/resubmit type、id 退回后重新提交

opinion 最长 500 字,不写审计。

wf 对象(state 的响应,也出现在 vouchers/load 和各审批动作的响应里):

字段 说明
controlled 是否受审批流控制
status not_submitted 未提交、in_approval 审批中、approved 已通过、not_approved 不通过、returned 已退回、not_controlled 未启用审批流
verify_state、verify_state_new 表头 IVERIFYSTATE、iVerifyStateNew(0 未提交,1 审批中,2 已通过,-1 不通过)
return_count 退回次数
current_auditor、verifier、verified_at 当前审核人姓名、终审人、终审日期
instance 流程实例 {piid, running, started_by, started_at},未提交或已撤销时为空
pending 待办 [{task_id, activity_id, person, operator, task_type}],task_type 1 审批、4 弃审后重审、5 退回后重提

history 响应:{"ok":true,"type","id","code","history":[…]},每项 action(U8 动作编号)、action_name(submit、agree、disagree、reject、withdraw、return、abandon、resubmit,其他为 other)、task、opinion、person、operator、name、at。

tasks 响应:{"ok":true,"operator","person","tasks":[…],"other_count"},每项 task_id、type、biz(U8 业务对象,如 QM04)、id、code、task_type、activity_id、from(上一处理人)、created_at(待办到达时间)、title(待办标题,即 U8 消息中心显示的那一句)、piid(同 wf.instance.piid)。other_count 是业务对象无法映射到已知类型的待办条数。操作员没有关联人员时返回空列表。节点名称只存在 U8 的流程定义里,这里不返回;同一节点用 activity_id 区分。

给即时通讯或待办系统建待办:订阅事件服务的 workflow 事件(docs/events.md)得知哪张单据的审批状态或当前审核人变了,再用 workflow/state 的 pending(每个待办人的 person、operator、task_id)决定给谁建、撤哪条;某个操作员自己的待办清单用 workflow/tasks。

审批动作响应:{"ok":true,"type","id","code","action","u8_message","wf"},wf 是动作之后重新读到的状态。桥清理了本次审批留下的 U8 孤儿任务行时多一个 orphan_tasks_cleaned(行数,只在大于 0 时出现)。

审批相关的错误码(都是 409):workflow_disabled 单据未启用审批流,already_submitted 已经提交,not_submitted 未提交或没有在途实例,not_current_approver 当前操作员不是待办人(操作员未关联人员时 message 为「操作员未关联人员」)。U8 的审批服务自行提交:返回成功(或调用异常)后在新连接上回读审批状态,既不是目标状态也不是原状态时 504 outcome_unknown(先用 workflow/state 核对,不要直接重试);回读仍是原状态且调用异常时按 U8 拒绝 409。

审批引擎会尝试向 U8 移动端推送消息:缺省拦下;桥 config.json 设 "mobilePush": true 后照常推送(见 docs/configuration.md)。

14. 总账凭证 gl/vouchers/*#

登录子系统 GL。会计年度取登录日期 date 的年份;请求的 year 是账套库年度,不作会计年度用。

凭证键:period(1 到 12)、sign(1 到 2 个字的凭证类别字,必须在 U8 的凭证类别里)、no(1 到 32767)。

功能权限查 U8 的操作员权限表(本人或所属角色,或 admin),没有时 403 no_permission「没有…权限」:

操作 功能 id
新增、修改、作废、取消作废、红字冲销、期间损益结转、自定义转账 GL0201(填制凭证)
删除 GL0202(凭证整理)
出纳签字、取消签字 GL0203
审核、取消审核 GL0204
记账、取消记账 GL0208

第二级写入(取消记账、期间损益结转、自定义转账)复现 U8 界面执行的 SQL:桥的 enableReplicatedWrites 缺省关闭,关闭时 403 feature_disabled;打开后只对 testAccounts 里的账套开放(含预演),其他账套登录前 403 test_account_only。正式账套请在 U8 客户端操作。开关说明见 configuration.md,风险见 limitations.md。

create / update#

head 只有 sign、date(缺省登录日期,年份必须等于登录年度;修改时必须在原期间内)、attachments(附单据数,0 到 32767)。修改时 head.sign 必须等于 sign。

lines 2 到 200 行,每行:

字段 说明
account 科目编码,≤ 40,必须末级、未封存
digest 摘要,≤ 120
debit / credit 必须且只能填一个大于 0 的金额
dept、person、customer、supplier、item_class、item 辅助核算,须与科目设置一致
settle、doc_no、doc_date 结算方式、票号、票据日期
currency、rate 外币和汇率,要么都填要么都不填
qty 数量
cash_flow 现金流量,最多 50 项 {item, debit 或 credit}。现金流量科目必须带

借贷合计必须相等且大于 0。凭证号由 U8 编,新增成功 {"ok":true,"period","sign","no"}。

update 整张替换,只改总账自己的、未审核、未签字、未作废、未被红字冲销、未做银行对账或往来两清的凭证;红字冲销凭证和带自定义项的凭证不能修改。调用方不能填的列由桥从原凭证带过来,带这些值的分录在新报文里同一分录号必须仍是同一科目(409「修改不能改动分录的科目顺序」)。

新增和修改由 U8 的凭证导入组件自己提交,不在桥的事务里。调用抛错、应答无法解析、回读失败都是 504 outcome_unknown:先 load 或 list 核对,再决定是否重试。

其他操作#

void(作废)、unvoid(取消作废)、verify(审核)、unverify(取消审核)、sign(出纳签字)、unsign(取消签字)、delete(删除)只带凭证键。成功带 state:verified、checker、audit_date、signed、cashier、posted、void、error;删除另带 deleted: true。

门槛(都是 409 state_mismatch):

post(记账)#

请求:period(1 到 12)、vouchers(1 到 200 项 {sign, no},不能重复)、可选 fiscal_year(缺省登录日期的年份)。例:

{"acc": "801", "operator": "op001", "password": "…", "date": "2026-09-29", "period": 9,
 "vouchers": [{"sign": "转", "no": 3}, {"sign": "收", "no": 12}]}

成功 {"ok":true,"period","fiscal_year","posted":[{"sign","no","state"}],"local_txn":true},顺序同请求;state 同上,另带 poster(记账人姓名),posted 为 true。local_txn 恒为 true:桥在提交前核对过事务没有升级为 MSDTC 分布式事务。

桥在写线程上直接调用 U8 总账的 .NET 记账组件(与 U8 界面「记账」相同的组件,见 docs/u8-notes.md),不经 COM。全部凭证在一个事务里一次记账,任何一张不合格都不记。门槛(409 state_mismatch,凭证不存在 404):

与 U8 客户端并发:事务第一条语句给 U8 的记账范围表加表级更新锁(持有到提交),U8 客户端的汇总要等桥提交。本年度已汇总未记账的范围同 U8 自己的汇总一样被覆盖;桥记完后在同一事务里清掉本年度的范围。因此若 U8 用户在桥加锁之前已在「记账」向导里汇总,之后再点「记账」不会记任何凭证(向导可能仍报成功),并且 U8「恢复记账前状态」再也撤销不了桥这次的记账;这时让对方重新汇总再记账。

记账过程(一个事务,ReadCommitted,超时 5 分钟):加锁 → U8 按请求的凭证汇总记账范围 → 桥核对范围与请求完全一致(U8 会静默跳过不合格的凭证,对不上 409 并给原因) → U8 记科目总账、辅助账并回写记账标志 → 桥修正误写的凭证(见下) → 核对 → 清范围 → 核对事务仍是本地事务 → 提交。

U8 的已知缺陷:记账组件回写记账标志时按(期间、类别序号、凭证号)关联范围表,不带年度。多年度的账套库里,别的年度键相同的凭证会被改成本操作员记账(U8 客户端记账同样如此)。桥在同一事务里调用前快照这些行的记账标志和记账人,调用后改回,再核对本次凭证每行已记账、记账人是本操作员、其余行与快照一致,不符整体回滚。

错误(提交之前的错误都回滚、不留痕迹):

情况 结果
死锁、锁请求超时、执行超时、事务被中止或超时 503 u8_unavailable「已回滚,未写入,可以稍后重试」
事务升级为分布式事务 503 u8_unavailable「记账事务升级为分布式事务,已回滚」
U8 组件不在或签名不符 503 u8_unavailable「U8 总账记账组件不可用」
U8 组件里的其他 SQL 错误、桥的 SQL 出错、记账后核对不符 500 internal(经 API 是 502)
U8 组件抛的其他异常 409 u8_rejected(原文第一行)
提交时事务被中止 503 u8_unavailable
提交结果不确定;提交后在新连接上回读失败或不是本操作员记账 504 outcome_unknown(消息写明已提交)

收到 504 先 load 看 posted、poster 再决定是否重试。取消记账见 unpost(第二级写入);正式账套上记错了用 reverse 或在 U8 客户端处理。

reverse(红字冲销)#

把一张已记账的凭证整张复制为红字凭证(金额取负),同 U8 凭证界面的「冲销凭证」。请求:凭证键 period、sign、no 定位原凭证;可选 fiscal_year(原凭证的会计年度,缺省登录日期的年份,不能晚于登录年度,可以是上一年度,即跨年冲销)、voucher_date(红字凭证日期,缺省登录日期,必须在登录年度内、不早于原凭证日期)。例:

{"acc": "801", "operator": "op001", "password": "…", "date": "2026-02-10",
 "fiscal_year": 2026, "period": 1, "sign": "转", "no": 9}

成功 {"ok":true,"period","sign","no","fiscal_year","voucher_date","lines","out_no","reversal_of":{"fiscal_year","period","sign","no","out_no","out_no_assigned"}}:顶层是红字凭证(期间取 voucher_date 的月份,类别同原凭证,号由 U8 编),reversal_of 是原凭证。红字凭证未审核、未记账,之后照常审核、记账,也可以作废后删除,不能修改。

unpost(取消记账,第二级写入)#

相当于 U8「恢复记账前状态 → 最近一次记账」:把本年度最近一次记账(桥记的和 U8 客户端记的都算)整批恢复为未记账,不能挑单张凭证。

请求全部可选:fiscal_year(缺省登录日期的年份)、period、vouchers([{sign, no}],不重复,最多 200 张,给了就必须给 period)。period、vouchers 只用来核对:给了就必须与最近一次记账的期间、凭证集合完全一致,否则 409 并写明不一致之处,什么都不改。成功 {"ok":true,"fiscal_year","period","count","vouchers":[{"sign","no"}]}。

期间损益结转、自定义转账(gl/transfer/pnl、gl/transfer/custom,第二级写入)#

相当于 U8 总账「期末 → 转账生成」的期间损益结转和自定义转账。桥按 U8 的转账定义和已记账余额算出分录,经与 create 相同的凭证导入保存,再按 U8 生成的结转凭证补标记。

请求:fiscal_year(必填,必须是登录日期 date 的年份)、period(1 到 12);可选 voucher_date(缺省该期间最后一天,必须在该期间内)、exclude_existing(只能和 dry_run 一起用,见下);自定义转账另有可选 tran_id(U8 的转账序号,如 T001,缺省生成全部定义)。例:

{"acc": "801", "operator": "op001", "password": "…", "date": "2026-09-30", "fiscal_year": 2026, "period": 9}

成功 {"ok":true,"kind","fiscal_year","period","voucher_date","out_sign","count","vouchers":[{"sign","period","no","lines","out_no","digest","debit","credit","pack"|"tran_id"}],"skipped":[{"tran_id","account","reason"}]}。

load / list#

load 返回 voucher(period、sign、no、date、attachments、maker、checker、audit_date、cashier、poster、posted、void、error、source_system、source_sign、source_no、out_no、blue_out_no(红字冲销凭证指向的原凭证外部业务号))和 lines(entry、account、account_name、digest、debit、credit、debit_fc、credit_fc、qty_debit、qty_credit、currency、rate、dept、person、customer、supplier、item_class、item、settle、doc_no、doc_date、cash_flow)。

list 请求:period_from、period_to 必填,可选 sign、date_from、date_to、maker、state(all、unaudited、audited、posted、void)、after(上一页的 next,不透明字符串)、limit(1 到 200,缺省 50)。按(期间、类别、凭证号)翻页。每项 period、sign、no、date、maker、checker、cashier、posted、void、debit_total、lines(分录数)。

数据权限:总账选项「明细账查询权限控制到科目」打开、科目开了数据权限控制、操作员不是账套主管也不是科目的数据权限管理员时,load、list、digest、attachments/list 按整张凭证过滤:全部分录科目都有查询权限才可见(取较严的口径)。list、digest 里越权的凭证不出现(debit_total、watermark 只算可见凭证),load、attachments/list 403 no_permission「没有该单据的数据权限」,凭证不存在仍是 404。见 §22。

digest(凭证摘要)#

供事件服务使用。凭证表没有 rowversion,事件服务按期间逐张比对凭证指纹,发现新增、删除、审核、出纳签字、记账、作废和修改。走读线程池(只跑 SQL),权限同凭证查询(含按科目整张过滤:事件服务的操作员看不到的凭证不产生事件)。

请求全部可选:fiscal_year(缺省登录日期的年份)、periods(1 到 12 个不重复的期间)、closed_periods(0 到 12,缺省 1,不能与 periods 同时给)、after、limit(1 到 500,缺省 200)、keys_only。periods 省略时取该年度全部未结账期间(不含期初 0 期),再加最近 closed_periods 个已结账期间;年度没有期间记录时 periods、items 为空。缺省期间只在这一年度里取:上一年度未结账的期间和跨年度的最近已结账期间要另发请求,显式给 fiscal_year 和 periods。

响应 {"ok":true,"fiscal_year","periods","items","next","watermark","ident"}:periods 是实际扫描的期间(升序),翻页时原样放进下一页的 periods,避免翻页途中结账改变范围;watermark 是所扫期间的 MAX(i_id),ident 是 IDENT_CURRENT('GL_accvouch')(删凭证不回退),都在读这一页之前取,十进制字符串。每项 period、sign、no、fingerprint;不带 keys_only 时另有 date、maker、checker、cashier、bookkeeper(记账人)、posted、void、debit_total、lines。fingerprint 是 SUM(md)、SUM(mc)(4 位小数)、行数、MAX(i_id)、制单人、审核人、出纳、记账人、ibook、iflag 以 | 连接后的 SHA-256(小写十六进制)。按(期间、类别序号、凭证号)翻页,after 同 list。

attachments/list#

请求同 load(period、sign、no,年度取登录日期的年份),权限同凭证读取。凭证不存在 404 not_found。

凭证的 attachments 只是附单据数;电子附件(U8 填制凭证界面的「附件」)登记在 GL_AccAttachs,文件在 U8 文件服务器上。响应 {"ok":true,"voucher","items","truncated"}:voucher 是 period、sign、no、attachments;每项 id、name(原文件名)、file_id(文件服务器上的标识)、submitted_at(yyyy-MM-dd HH:mm:ss)、source(来源模块)。按上传顺序,最多 500 个。只列清单,不提供下载;没有附件时为空数组。

客户端命令:gl-attachments --period 9 --sign 转 --no 3。

15. 基础档案 archives/*#

登录子系统 AS。archive 为 customer、vendor、inventory、department、person、warehouse、customer_class、vendor_class、inventory_class(下称「九类可写档案」),以及下文各节的档案,其他 400「未知档案类型 x」。code 1 到 30 个字符(其他档案按下表的长度),不含控制字符,前后没有空格(中间可以有空格)。code_prefix 最长与该档案的编码相同,name_like 1 到 60 个字符,都不含控制字符。

路由 请求 响应
archives/get archive、code {"ok":true,"archive","code","fields"}
archives/list archive,可选 code_prefix、name_like、changed_since、after、limit、project_class(只给 project)、currency / fiscal_year(只给 exchange_rate)、type_code / dept_code / include_disposed(只给 fa_card)、keys_only {"ok":true,"archive","items":[{"code","name","class_code","ufts"}],"next","watermark"}
archives/create archive、code、fields,可选 template {"ok":true,"archive","code"}
archives/update archive、code、fields 同上
archives/delete archive、code 另带 deleted: true

九类可写档案的 fields 键是 U8 EAI 的标签名(不分大小写,发送时换成 U8 对照表的写法),值是字符串、数字或布尔,null 表示不发送。未知标签 400「未知字段 x」;code、建档/变更人和日期、统计类标签(例如客户的应收余额、最后交易日)400「不能设置字段 x」。

经 EAI 的写操作由 U8 自己提交。U8 拒绝时 409 u8_rejected,message 是 U8 原文;原文含「不可为空」时后面加「(U8 档案设置为必输)」,调用方要在 fields 里给出该字段。U8 说成功但回读对不上,或应答无法识别,504 outcome_unknown。EAI 对照文件读不到或格式不对 503 u8_unavailable。

其他档案的写入能力:

档案 新增 修改 删除 见
bank、project 是 是 是 开户银行与项目的写入
position、unit、unit_group、settle_style、rd_style、purchase_type、sale_type、district_class、aa_bank 是 是 是 货位、计量单位等 EAI 档案的写入
user_define、customer_inventory 是 否 是 同上
currency、voucher_sign 是 是 是 币种、凭证类别的写入
exchange_rate 是 是 是 汇率的写入
reason 是 是 是 原因码的写入
customer_bank、vendor_bank、customer_contact、vendor_contact 是 是 是 客户、供应商的银行账户和联系人
fa_card 是 否 撤销本期新增 固定资产卡片与设备台账的写入
equipment 是 否 否 同上
account、trade_class、customer_address、operator、role 否 否 否 只读,写路由 400「该档案只读」(API 在转发前拒绝)

只读档案#

以下档案的读取不用 EAI 对照表:get 的 fields 键是 U8 表的列名,返回全部非空列,去掉口令类列(列名含 password 或 pwd)和原始 rowversion;有 rowversion 的表另带十进制 ufts。exchange_rate、fa_card、operator、role 例外,见下文。

archive 表 code list 的 class_code changed_since
account 科目 code 科目编码 ccode,1 到 40 个字符 无 支持
unit 计量单位 ComputationUnit cComunitCode,1 到 35 个字符 计量单位组 cGroupCode 支持
unit_group 计量单位组 ComputationGroup cGroupCode,1 到 35 个字符 无 支持
settle_style 结算方式 SettleStyle cSSCode,1 到 3 个字符 无 支持
voucher_sign 凭证类别 dsign 凭证类别字 csign 无 不支持(400)
currency 币种 foreigncurrency 币种名称 cexch_name,1 到 8 个字符(单据、凭证引用的是名称;编码 cexch_code 在 fields 里) 无 支持
bank 本单位开户银行 Bank cBCode,1 到 3 个字符 无 支持
project 项目 fitemss<大类> <项目大类>:<项目编码>,例如 98:01 项目分类 citemccode 不支持(400)
position 货位 Position cPosCode,1 到 20 个字符 仓库 cWhCode 支持
rd_style 收发类别 Rd_Style cRdCode,1 到 5 个字符 无 支持
purchase_type 采购类型 PurchaseType cPTCode,1 到 2 个字符 无 支持
sale_type 销售类型 SaleType cSTCode,1 到 2 个字符 无 支持
district_class 地区分类 DistrictClass cDCCode,1 到 12 个字符 无 支持
trade_class 行业分类 TradeClass cTradeCCode,1 到 12 个字符 无 支持(列名 ufts)
aa_bank 银行档案(所属银行) AA_Bank cBankCode,1 到 5 个字符 无 支持
customer_address 客户收货地址 CusDeliverAdd <客户编码>:<地址编码>(cCusCode 20、cAddCode 30),例如 C900001:01 客户 cCusCode 不支持(400)
user_define 自定义项档案 UserDefine <自定义项号>:<档案值>(cID 10、cValue 400),例如 1002:快递 自定义项号 cID 支持
customer_inventory 客户存货对照 CusInvContrapose <客户编码>:<存货编码>(cCusCode 20、cInvCode 60) 客户 cCusCode 支持
exchange_rate 汇率 exch <币种>:<年度>:<期间>[:<日>],例如 美元:2026:9;get 另收 <币种>:<yyyy-mm-dd> 无 支持(取并入各行的最大 pubufts)
fa_card 固定资产卡片 fa_Cards 等 卡片编号 sCardNum,1 到 20 个字符 无(项里有 type_code) 不支持(400)
equipment 设备台账 EQ_EQData 设备编码 cEQCode,1 到 30 个字符 无 支持(列名 ufts)
operator U8 操作员 UFSYSTEM..UA_User 等 操作员编码 cUser_Id,1 到 20 个字符 无 不支持(400)
role 角色 UFSYSTEM..UA_Group 等 角色编码 cGroup_Id,1 到 20 个字符 无 不支持(400)

读取权限与数据权限(§22):

档案 功能权限(读取) 记录级数据权限
position AS030Q(货位档案查询)或 AS030 无
bank AS013Q 或 AS013 无
rd_style AS016Q 或 AS016 收发类别
trade_class AS050Q 或 AS050 无
customer_inventory AS1204Q 客户和存货(get 分别判断两段)
purchase_type、sale_type — 采购类型、销售类型
customer_address — 客户
currency、exchange_rate AS028M 无
fa_card FA1501(卡片管理「打开」)或 FA1505(「修改」) 部门开了数据权限控制时按使用部门:全部版本的全部使用部门都在授权内才给(同 §19 固定资产报表),list 去掉越权卡片,get、get_many 403;不按类别过滤
operator、role、aa_bank 只有请求年度的账套主管(按账套主管单独判定,不看 admin 授权行),否则 403 no_permission 无

地区分类、行业、银行档案、自定义项不受记录级控制。客户、供应商银行账户和开户银行(bank)的写入要填所属银行编码(bank_code,取自银行档案),非账套主管读不到银行档案,需向账套主管要编码。

开户银行与项目的写入#

archive 写入方式
bank 本单位开户银行 EAI(BankXmlRs.xml,根标签 bank),同九类可写档案
project 项目 桥的受控 SQL(U8 没有单个项目的写入组件,EAI 的项目导入只收大类)

货位、计量单位等 EAI 档案的写入#

以下档案经 EAI 写入(U8SrvTrans.IClsCommon.Transact,同九类可写档案),get、list 仍按表列名返回。fields 用 EAI 标签(见 meta 的 archives[].tags / writable)。修改发整条记录(proc=diffedit)。下面的校验都在调用 U8 之前做:请求不对 400,库里的状态不允许 409 state_mismatch;U8 自己拒绝 409 u8_rejected 带原文。

archive 根标签(RsXml) 可写标签 新增必须 编码
position 货位 position(PositionXmlRs.xml) name、warehouse_code、maxcubage、maxweight、remark、barcode;grade、end_flag 不能写 name、warehouse_code cPosCode,按编码方案分级
unit 计量单位 unit(UnitXmlRs.xml) name、group_code、main_flag、changerate、portion、SerialNum、barcode、censingular、cenplural、cunitrefinvcode name、group_code cComunitCode
user_define 自定义项档案 define(DefineXmlRs.xml) alias、barcode 无(名称就是档案值) <自定义项号>:<档案值>,发送时拆成 id、value
customer_inventory 客户存货对照 cusinvcontrapose(CusInvContraposeXmlRs.xml) ccusinvcode、ccusinvname、检验相关标签 ccusinvname <客户编码>:<存货编码>,发送时拆成 ccuscode、cinvcode
unit_group 计量单位组 unitgroup(UnitGroupXmlRs.xml) name、type、cgrprelinvcode name、type(0 无换算、1 固定换算、2 浮动换算) cGroupCode,最长 35
settle_style 结算方式 balancetype(BalanceTypeXmlRs.xml) name、flag(票据管理,缺省 0)、issbilltype(缺省 0);code_rank、end_rank_flag 不能写 name cSSCode,最长 3,按编码方案分级
rd_style 收发类别 receivesendtype(ReceiveSendTypeXmlRs.xml) name、rsflag(1 收、0 发)、oppsubject_code;sort、end_flag 不能写 name;一级还要 rsflag cRdCode,最长 5,按编码方案分级
purchase_type 采购类型 purchasetype(PurchaseTypeXmlRs.xml) name、rstype_code(入库类别)、bdefau、bpfdefault(缺省 0) name cPTCode,最长 2
sale_type 销售类型 saletype(SaleTypeXmlRs.xml) name、rstype_code(出库类别)、bdefau(缺省 0) name cSTCode,最长 2
district_class 地区分类 districtclass(DistrictClassXmlRs.xml) name;sort、endflag 不能写 name cDCCode,最长 12,按编码方案分级
aa_bank 银行档案(所属银行) aa_bank(AA_BankXmlRs.xml) name、账号定长类标签(bindfixlen、iindaccnolen、bcomdfixlen、icomaccnolen 等);i_id 不能写 name cBankCode,最长 5
档案 新增 修改 删除
position AS030 AS030 AS030
unit、unit_group AS032M AS032M AS032M
settle_style AS018 AS018 AS018
rd_style AS016 AS016 AS016
user_define AS025A — AS025D
customer_inventory AS1204A — AS1204D
purchase_type、sale_type、district_class、aa_bank 不查,由 U8 判断 同左 同左

客户存货对照另按客户、存货的数据权限判断编码的两段;收发类别写入只查功能权限。

币种、凭证类别的写入#

currency、voucher_sign 可以 create、update、delete。get、list 照旧按表列名返回;写入的 fields 用 RsXml 的 EAI 标签。两类都不收 template(400)。

archive 编码 可写标签 新增必填
currency 币种 币种名称 cexch_name(最长 8),EAI 报文发成 <name> code(币种符号 cexch_code,最长 4,新增必填、不能修改)、caltype(折算方式 0 / 1,缺省 1)、precision(小数位数 0 到 10,缺省 5)、error(最大误差,缺省 0.00001);id、otherused、name 不能写 code
voucher_sign 凭证类别 类别字 csign(最长 2),EAI 报文发成 <type> type_name(类别名称 ctext,最长 30,唯一);新增另收 order_code(排序号 1 到 255,缺省最大加一,不能与其他类别重复);修改只收 type_name type_name

汇率的写入#

exchange_rate 可以 create、update、delete。编码同读取:<币种>:<年度>:<期间> 是固定汇率的一个期间,fields 收 rate(记账汇率)和 adjust_rate(调整汇率);<币种>:<年度>:<期间>:<日> 是一天的浮动汇率,只收 rate(给 adjust_rate 400)。<币种>:<yyyy-mm-dd> 不能用于写入(400)。汇率必须大于 0、不超过 1000000000(400);不收 template,其他标签 400「未知字段 x」。

原因码的写入#

reason(原因码档案,表 Reason)可以 get、list、create、update、delete,都走 EAI(U8SrvTrans.IClsCommon.Transact,根标签 reason),同九类可写档案:按 AS 登录,组件自己提交,桥在调用前查完、调用后在新连接上回读,预演停在调用之前(validate)。get 的 fields 是 EAI 标签(code、name、Reasontype、ReasonMemo)。读取走 SQL。

标签 列 说明
code(顶层 code) cReasonCode 1 到 10 个字符,不能改,不能放进 fields
name cReasonName 1 到 30 个字符,新增必填
Reasontype iReasontype 所属类型,0 到 255 的整数,新增必填。1 不良品原因、2 让步放行原因、3 采购退货原因、4 销售退货原因、5 变更原因、6 拖欠原因;其他取值按 U8 原因码分类(如预置的 Refund 是 15 退款退货)。不良品处理单(QM05 / QM06)表体的 creasoncode 要 1
ReasonMemo cReasonMemo 说明,最长 240,给空串清空

客户、供应商的银行账户和联系人#

客户银行账户、供应商银行账户、客户联系人、供应商联系人可以 get、list、create、update、delete,一次只动一行,同一客户(供应商)的其他行不动。编码是两段(规则同 customer_address),get 的 fields 是表列名;写入的 fields 是下表的固定标签(不分大小写),其他标签 400「未知字段 x」,不收 template。

archive 表 code 列表 name changed_since 可写标签 新增必填
customer_bank 客户银行账户 CustomerBank <客户编码>:<银行账号>(20、50) 开户银行 cBranch 不支持(400) branch 开户银行(最长 100)、bank_code 所属银行编码(最长 5)、account_name 账户名称(60)、default 默认账户(布尔)、province、city(20)、cbb_dep_id、branch_id(60)、branch_id_sec(5) branch
vendor_bank 供应商银行账户 VendorBank <供应商编码>:<银行账号>(20、50) 同上 不支持(400) 同上 branch
customer_contact 客户联系人 Crm_Contact <客户编码>:<联系人编码>(20、30);新增写成 <客户编码>:(冒号后留空) cContactName 支持 name、title、sex(男 / 女 / 不详)、birthday(YYYY-MM-DD)、native、position、direct_leader、mobile、office_phone、family_phone、bp、email、web、work_address、postcode、marriage(已婚 / 未婚 / 离异 / 不详)、family_member、family_address、favorite、be_main_linker(布尔)、charge_person、memo、self_define1–self_define10;长度按列宽(name 50,title、bp、postcode、charge_person、self_define1–3 20,native、direct_leader 30,web 50,memo 240,self_define4–6 60、7–10 120,其余 100 到 255),超长 400;name 前后不能有空格 name
vendor_contact 供应商联系人 Ven_Contact <供应商编码>:<联系人编码>(20、30);新增写成 <供应商编码>: cContactName 支持 同客户联系人,但没有 position、favorite;列宽相同 name
档案 读取 新增 修改 删除
customer_bank AS011Q 或 AS011 AS011 AS011 AS011
vendor_bank AS005Q 或 AS005 AS005 AS005 AS005
customer_contact CS020202(联系人查询)、AS011Q 或 AS011 CS020204 CS020201 CS020205
vendor_contact AS020302、AS005Q 或 AS005 AS020305 AS020301 AS020306

固定资产卡片与设备台账的写入#

固定资产卡片(fa_card)可以新增、撤销本期新增,设备台账(equipment)可以新增,都经 U8 EAI 分发器(U8Distribute.iDistribute.ProcessEx;卡片根标签 capitalasserts,设备 eqdata),由 U8 自己提交。U8 拒绝时 409 u8_rejected;回读对不上或应答无法识别 504 outcome_unknown。

固定资产卡片 fa_card:

设备台账 equipment:

16. 列表和现存量#

vouchers/list#

type 是 §4 表里的可读取类型之一,另收只读的票据类型 ar_note / ap_note(见下文「票据」)。可选:

字段 说明
filter code、code_from、code_to、date_from、date_to、cus_code、ven_code、wh_code、dep_code、person_code、maker(字符串,1 到 60 字),以及 verified、closed、red(布尔)。该类型没有对应列的键 400「该单据类型不支持筛选字段 x」,未知键 400「未知筛选字段 x」
keys_only true 时每项只有 id、code、ufts
changed_since 上一轮的 watermark
after 上一页的 next(整数)
limit 1 到 500,缺省 100

响应 {"ok":true,"type","items","next","watermark"}。完整行的键固定,没有值时为 null:id、code、doc_date、cus_code、ven_code、wh_code、dep_code、person_code、maker、verifier、verified_at、closer、verified、closed、red、ufts,再加各类型的附加列。收付款单列表不含银行账号列。表体有 rowversion 的类型,增量按表头、表体较大的算;表体没有 rowversion 的只按表头。

各类型的特别说明:

类型 说明
arrival、purchase_return arrival 包括退货单,可用 filter.red=false 排除;purchase_return 只列 iBillType=1 的到货单,red 取 bNegative,附加列同到货单
dispatch、sale_return dispatch 含红字行(red 为 1,可用 filter.red=false 排除);sale_return 只列红字发货单(cVouchType=05 且 bReturnFlag=1)
sale_order、purchase_order 附加列 locker:锁定人姓名,未锁定时为 null 或空串(见 §10「锁定和解锁」)
purchase_invoice 附加列 reviewer、reviewed_at(采购复核,与 verifier、verified_at 相同)和 ap_verifier(应付款管理的审核人)
检验单、不良品处理单(QM03 到 QM06) 附加列 wf(布尔)、wf_state(字符串 "0" 未提交、"1" 审批中、"2" 通过、"-1" 不通过)、current_auditor(当前审核人姓名,原样返回,没有时为 null),事件服务靠它们发 workflow 事件;其他类型没有这三个键
qm_incoming_inspect、qm_product_inspect 只列 QM01 / QM02。没有审批流,不带 wf、wf_state、current_auditor;dep_code 是业务部门,wh_code、person_code 为 null(仓库、存货在表体);附加列 source、source_code、source_id(到货单 ID 或生产订单 MoId)、inspect_dep_code(报检部门)、check_type、created_at、modified_at,来料报检单另有 arrival_date
qm_other_inspect 只列 QM11,同产品报检单,source、source_code、source_id 恒为 null
qm_other_check 只列 QM15,没有审批流;dep_code 是检验部门;附加列 source(恒为 null)、inspect_code、inspect_id(对应的其他报检单)、inspect_dep_code、check_type(OTH)、created_at、modified_at
bom 只列标准 BOM:code 是母件存货编码(filter.code 按母件筛),doc_date 是版本生效日期,maker 是制单人编码,verified 是已审核状态,closed 是停用状态,closer 是停用人;附加列 version、version_desc、end_date、status、wf、created_at、modified_at;数据权限按母件存货
shape_change 只列 cVouchType=15,表头没有仓库(wh_code 为 null);附加列 in_rd_code、out_rd_code、source、created_at、modified_at;增量只按表头
transfer_request wh_code、dep_code 是调出方,附加列同调拨单,closer 是表头关闭人
stock_check verifier、verified_at 是 cAccounter、dveridate;附加列另有 check_date(盘点日期)
purchase_settle code 是结算号,doc_date 是结算日期,ven_code 是供应商,maker 是制单人;没有审核,verifier、verified_at 为 null,verified 恒为 false;没有 cus_code、wh_code、closed、red(对应筛选 400)。附加列 settle_type(常为 01)、bus_type、pt_code、opening(期初)、memo,以及按表体汇总的 line_count、accounted_lines(存货核算已处理结算成本的行数)、invoice_lines(有发票的行数)、receipt_count(涉及的入库单号个数)、first_invoice_code、first_in_code(单号最小的发票号、入库单号)、quantity(结算数量合计)、amount(结算金额合计)
position_adjust code 是 cVouchCode,doc_date 是 dDate,wh_code 是表头仓库,verifier / verified_at 是 chandler / dVeriDate;没有 cus_code、ven_code、closed、red;附加列 memo、source、created_at、modified_at;增量只按表头
ia_adjust 不按单据类型过滤,doc_date 是 dJVDate;verified 表示表体每行都已记账(filter.verified 同此),verifier 是表头记账人、为空时取第一个有记账人的表体行,verified_at 为 null;没有 cus_code、ven_code、closed、red(对应筛选 400)。附加列 vouch_type(20 入库调整、21 出库调整等)、rd_flag、rd_code、auto(TRUE 为期末处理自动生成)、bus_type、unit_code(客户或供应商编码)、vendor_code、handler(经手人)、memo,按表体汇总的 line_count、posted_lines、amount,以及 created_at、modified_at。增量只按表头:只改表体记账人的记账不出现在增量里
inventory_price_adjust doc_date 是 ddate,verifier 是 cverifier,verified_at 是 dverifydate;没有往来单位、仓库、closed、red;附加列 memo;增量按表头

vouchers/search 对上面几类的支持:purchase_settle 按供应商(partner)、部门、业务员、存货查找,不支持表头自定义项;ia_adjust 按部门、业务员、仓库、存货和表头自定义项;inventory_price_adjust 按部门、业务员、存货,不支持表头自定义项。

票据:ar_note / ap_note 列应收 / 应付票据,只读,不是单据类型(vouchers/load 和写路由 400,单张用 notes/get)。id 是 Auto_ID,code 是票据号,doc_date 是签发日期,往来单位在 cus_code(应收)或 ven_code(应付),常为空,单位名称在附加列 dw_name;maker 取经办人,为空时取登记人;票据没有审核,verified 恒为 false;closed 表示余额为 0;没有 red、wh_code。附加列 settle_code、amount、remainder、close_id(登记时生成的收款单)、opening(期初票据,布尔)、expire_date、dw_name、currency。增量只按表头(结算、贴现、背书、退回回写余额时表头随之变化)。登录子系统 AR / AP;功能权限 AR2231 / AP2231(票据列表查询),数据权限按往来单位、部门、业务员、项目。

notes/get#

只读(读线程池,只查数据库,不登录 U8)。type(ar_note / ap_note)加 id(Auto_ID)或 code(票据号,1 到 60 字)二选一。响应 {"ok":true,"type","head","subs","subs_truncated"}:

权限同票据列表:越权 403 no_permission,票据不存在 404 not_found(事件服务据此确认票据已删除)。

notes/create、notes/delete#

登记和删除应收票据(flag AR)与应付票据(flag AP,见本节末)。U8 的票据组件不能无界面调用,桥按 U8 登记票据的写入结果在请求连接的一个事务里完成:检查 → 加锁复查票据号 → 写票据(票据科目取基本科目,交票客户、出票人、票面、余额、登记人等同 U8 登记的当期票据)→ 经收款单新增的同一条路径生成收款单(48),标成票据来源(来源票据号即票据号,分包票据是「票据号-起-止」)→ 回写票据的关联收款单 → 核对 → 提交;任何一步失败整笔回滚。分包票据另写分包标志、子票区间和一行整段可用区间(金额 = 票面),同 U8 登记的分包票据(见 docs/u8-notes.md)。

notes/create 字段:

notes/delete 字段:note_no 或 id(Auto_ID)二选一。只删登记后还没处理的票据:不是期初、没有处理记录、没换过票、余额等于票面,分包票据的可用区间仍是登记时的整段(非分包票据不能有可用区间行),U8 客户端登记的分包票据同样可删;它的收款单未审核、未制单、未核销、没有往来明细、不在审批流中(vouchers/delete 拒绝删除来自票据的收款单,这里是唯一的入口)。在一个事务里锁住票据并确认未被修改,删收款单、可用区间、保证金、付款申请明细和票据,核对后提交,任何一步失败整笔回滚。响应 note_id、note_no、receipt_id、receipt_code、sub_start、sub_end(非分包为 null)、deleted。

两者 dry_run 是 rollback 模式:真实写入、核对后回滚,detail 带检查后的输入。锁键 note:AR,登记另加 new:ar_receipt,删除另加 arap:writeoff:AR。功能权限:登记「票据录入」AR0504,删除「票据删除」AR2403;数据权限按客户、部门、业务员。

应付票据(flag AP,第二级写入,feature_disabled / test_account_only 见 §18):

notes/process#

票据的结算、贴现、背书和退回。U8 票据处理窗体没有可调用的组件,桥按 U8 处理票据的写入结果,在一个事务里写票据处理行、票据余额、往来明细、分包票据的可用区间,提交前后核对;不制单(制单走 arap/process/voucher)。

op 处理 处理方式 处理号前缀 专用字段
settle 托收 / 结算 9A PJJAR bank_code(必填,末级银行科目)、bank_name(缺省科目上级名称)
discount 贴现 9D PJTAR 同上,另有 expense(贴现息、手续费)、interest(票据利息)、rate(贴现率 %,最多六位小数)
endorse 背书冲应付 9E PJBAR vendor(被背书的供应商)、ap_lines(1 到 50 项 {type, id, line_id?, amount},01 / 02 / P0,不收付款单 49)
return 退回 9C CLAR 无

公共字段:note(票据号字符串,或 Auto_ID 整数)、可选 amount(本位币;省略时背书取 ap_lines 合计,其余取票据余额,分包票据取第一段可用区间;可以部分处理,退回除外)、sub_start / sub_end(分包票据的子票区间,成对,每个号 0.01 元,同时给 amount 时须一致)、digest。某个 op 不用的专用字段给了就 400。贴现净额 = 金额 + interest − expense,须大于 0;背书的 ap_lines 合计须等于背书金额。处理日期就是登录日期,须在应收(背书另查应付)未结账的期间内,不早于签发、收票日期;登记生成的收款单须已审核。

退回:把票据(分包票据须是剩下的全部可用区间)退还客户,并生成一张应收单(R0)重新挂上应收款(见 docs/u8-notes.md)。应收单经 U8 应收单组件保存(同 vouchers/create 的 ar_bill,主键、单号由 U8 分配):往来单位是票据的客户,部门、业务员取票据,科目是登记收款单应收款行的应收控制科目(没有时取基本科目),表头摘要「转出票据{票据号}」;保存后补写处理标记、余额 0、审核人(操作员)和审核日期(退回日期),同 U8 退回生成的应收单。这张应收单不能经 vouchers/verify 审核、弃审(409「单据由票据退回等处理生成,不能审核或弃审」),只能取消退回。往来明细写应收单借方一行和票据贷方一行,缺省摘要「退回{客户名称}电子承兑」。登记时的收款单不动。409:退回日期早于票据已有的处理;分包票据没有退回全部可用区间(「分包票据退回须退回全部可用区间…」,可用区间不止一段时请在 U8 客户端退回);取不到应收控制科目或应收单模板;U8 拒绝保存应收单 409 u8_rejected。

响应 cancel_no、style、op、date、note(id、code、partner、partner_name)、amount、remaining(处理后的票据余额)、sub_start、sub_end、digest;结算、贴现另有 bank_code、bank_name,贴现另有 net、expense、interest、rate,背书另有 vendor、ap_rows(每张应付单据行的 amount、remaining),退回另有 r0_id、r0_code。404 not_found:票据、科目、供应商不存在;409 state_mismatch:外币票据、已换票、已退回、余额不足、子票区间不可用、收款单未审核、科目不是末级银行科目、期间已结账、票据在 U8 客户端被占用等;提交后回读不符 504 outcome_unknown。dry_run 是 rollback 模式(退回时 U8 取过的应收单号、主键计数不退,真做时跳号)。

锁键 arap:writeoff:AR,背书另加 arap:writeoff:AP,退回另加 new:ar_bill。功能权限(都另收「票据录入」AR0504):结算「票据结算」AR240203 或「票据收款」AR240201,贴现 AR240205,背书 AR240206,退回「票据退票」AR240207 或「票据转出」AR240202;数据权限按票据的客户、部门、业务员,背书另按每张应付单据。

应付票据(flag AP,第二级写入)只收 settle、return,贴现、背书 400「应付票据只支持结算(settle)、退回(return)…」:

处理号用于 arap/process/cancel(取消)和 arap/process/voucher(制单)。两者收的处理号前缀:

前缀 处理 处理方式 flag 取消 制单
YCFAP / FCYAR 应收冲应付 / 应付冲应收 9I / 9J AR / AP 是 是(来源 ZZ)
BZAR / BZAP 并账 BZ AR / AP 是 是(BZ)
HRAR / HPAP 红票对冲 9N AR / AP 是 是
SYRAR / SYPAP 汇兑损益 9M AR / AP 用 arap/exchange_gain/cancel 是(SY,须 pl_code,第二级写入)
PJJAR 票据结算 9A AR 是 是(PJ)
PJTAR 票据贴现 9D AR 是 是(PJ,可给 expense_code)
PJBAR 票据背书 9E AR 是(另加回被背书供应商的应付单据余额) 是(PJ)
CLAR 票据退回(U8 客户端或 notes/process 做的) 9C AR 是(另删它生成的应收单) 是(PJ)
PJJAP 应付票据结算(第二级写入) 9A AP 是 是(PJ,借应付票据、贷银行,缺省类别「付」)
CLAP 应付票据退回(第二级写入) 9C AP 是(另删它生成的应付单) 是(PJ,借应付票据、贷应付账款)
HZAR 坏账发生 / 收回 / 计提(第二级写入) 9G / 9H / 9F AR 是(计提只取消该年度最后一次) 是(JT,同一种坏账处理)

stock/current#

可选 wh、inv、batch、nonzero(只要现存量不为 0 的行)、changed_since、after、limit。响应 {"ok":true,"items","next","watermark"}。每项有仓库、存货、批次、自由项和各项数量,以及三种可用量:

字段 口径
qty_available_raw CurrentStock.fAvaQuantity 的原值。U8 通常不维护这一列
qty_available 按 U8 的可用量公式:整行冻结为 0,否则现存量 − 冻结量;待入、调拨待入、待出、调拨待出只在库存选项打开时计入
qty_forecast_available 现存 − 冻结 + 预计入库合计 − 预计出库合计。本项目的口径,U8 没有同名数值

arap/process/list#

只读(读线程池,只查数据库)。列出 flag(AR / AP)一侧往来明细里的处理行:核销、应收冲应付、应付冲应收、并账、红票对冲、汇兑损益、票据等,不含单据本身的审核行和没有处理号的行。登录子系统是 flag。功能权限「取消操作」AR0807、「应收核销明细表」AR060107 或「选择收款」AR0503(应付 AP0807 / AP060107 / AP0503);数据权限按往来单位、部门、业务员过滤行,过滤后照常 200。用作事件源时事件服务的操作员必须有全部往来数据权限:这条路由没有 403 / 404 的存在性证明,被过滤掉的批次和被取消的批次看起来一样。

明细(缺省):可选 changed_since(上一轮的 watermark,十进制字符串或整数,0 即全量)、after(本轮上一页的 next,整数)、limit(1 到 500,缺省 100)、keys_only(每行只有 id、flag、style、code)、open_only(只要登记期间该侧未结账的行;changed_since 大于 0 时缺省 true)。按 Auto_ID 升序,响应 {"ok":true,"flag","items","next","watermark","ident","open_periods","last_closed"}。完整行:id(Auto_ID)、flag、style(处理方式)、code(处理号)、vouch_type、vouch_id、co_vouch_type、co_vouch_id、partner、dept、person、line_id(发票行,0 为 null)、debit_f、credit_f(原币,字符串)、pz_id、gl_sign、gl_no、reg_date、period、fiscal_year、row_flag。fiscal_year 是处理所在的会计年度:reg_date 可能是单据日期(如红票对冲取所对冲单据的最大日期),早于处理所在期间;period 小于登记月份时(次年 1 月处理上年 12 月的单据)为登记年份加 1。归期间请用 fiscal_year 和 period,open_only 也按它判断。

往来明细没有 rowversion,增量按 Auto_ID。watermark 是查询前已提交可见的最大 Auto_ID,ident 是 IDENT_CURRENT(之后取,不小于 watermark),都是十进制字符串。在途事务可能先拿到较小的号、后提交,所以下一轮的 changed_since 要从 watermark 往回退 max(滞后量, ident − watermark),按批次的最小 Auto_ID 去重。制单(pz_id 原地改写)和取消(删行)在明细里看不出来,用摘要比对。

摘要(digest: true):可选 fiscal_year(2000 到 2099,缺省登录年度)、periods(1 到 12 个期间)、after(上一页的 next,字符串)、limit(批数,1 到 500,缺省 500);不能带 changed_since、keys_only、open_only,明细也不能带 fiscal_year、periods。periods 省略时取该侧全部未结账期间(给了 fiscal_year 只取该年度)。按(处理方式、处理号)排序,每批:flag、style、code、min_id、max_id、pz(未制单为 null)、sum_d_f、sum_c_f(原币合计,字符串)、rows、fiscal_year(批内最小的会计年度)、partners(往来单位编码,升序)。响应另有 digest: true 和 periods(实际汇总的期间 [{year, period}])。

两种用法都返回 open_periods(该侧未结账的期间,年度不晚于登录年度)和 last_closed(最近一个已结账期间,没有为 null)。

翻页和增量#

都按主键翻页:after 填上一页的 next,没有下一页时 next 为 null。

watermark 在查询前取(数据库的 MIN_ACTIVE_ROWVERSION() - 1,十进制字符串)。增量同步:一轮从 after 缺省开始,按 next 读到没有下一页;把第一页的 watermark 存下来,作为下一轮的 changed_since。表体有 rowversion 的类型按表头、表体两者较大的算,下游只回写了表体也能看到。keys_only 的整轮主键集合可以用来发现被删的单据。档案的 changed_since 用法相同(人员按两张人员表中较大的 ufts)。

17. 健康检查、登录检查和 OpenAPI#

GET health:不签名、不需要账套。有任务卡住超过 3 分钟或工作线程退出时 503 {"ok":false,"code":"unhealthy"}。桥返回:

字段 说明
version、workers、read_workers、queued、read_queued、running 版本,写、读线程数,写、读队列里的任务数,正在执行的任务数
signatures COM 签名自检摘要:pending、ok、mismatch:<n>、unknown(细节见 meta 的 features.signatures 和 getting-started.md)
license U8 许可点数:ok、near(将满)、full(已满)、unknown(读不到或还没采到)
license_detail 按子系统两位码给出点数,如 {"SA":{"used":3,"limit":10,"full_24h":0}}:used 已用、limit 总数、full_24h 近 24 小时出现「已满」的次数
license_source leases:加密服务器上实时的点数租约,按产品包计数,与 U8「许可管理」一致,license_detail 里某子系统的数字是它所在产品包的数(「加密点数已饱和」就是这个包满了),独立模块给自己的数。tasklog:读不到租约时的回落,used 是登记的工作站数(偏少,只是下限),limit 是 U8 许可总数或 licenseLimits
license_packs 只在 leases 时有内容(tasklog 时为 {}),形如 {"XX":{"used":3,"limit":10,"modules":["PU","SA","ST"]},"YY":{"used":1,"modules":["GL"]}}:包码、占点的租约数、总数(桥不知道时省略)和包内模块,最多 32 个包、每包 16 个模块
write_policy 写入策略状态(见 configuration.md)。没配 writePolicyFile 时 {"state":"off"};配了时 {"state","version","loaded_at","freeze":{"global","accounts"},"window_open"},state 为 ok、invalid(新内容无效,仍按上一份有效策略判定)、missing(没有可用策略,写入全拒),version、loaded_at(UTC)是当前有效策略的,没有时为 null,window_open 是此刻能否写入(已计入 denyDates)。不影响健康检查的状态码
read_only_accounts 只读账套(readOnlyAccounts),这些账套的写路由一律 403 account_read_only
replicated_writes 第二级写入总开关 enableReplicatedWrites(缺省 false)

license、license_detail 只统计桥自己会登录的子系统(桥用不到的包满了不影响 license),license_packs 列出全部产品包。leases 时 near、full 按包的数字算,已用 ≥ 总数也算 full。只有数字和子系统码,不含授权方信息。

API 的 /v1/co/health 返回 ok、version,以及桥报了的 license、license_detail、license_source、license_packs、write_policy、read_only_accounts、replicated_writes(桥未报告时省略),另有本服务的 api_write_policy(配了 U8CO_WRITE_POLICY_FILE 时,形状同 write_policy)和 api_read_only_accounts(配了 U8CO_READONLY_ACCOUNTS 时)。API 校验桥给的值:license 只收上面四个值;license_detail 只收两位大写字母的子系统码和三个非负整数;license_source 只收 leases、tasklog;license_packs 的包码和模块码只收两位大写字母或数字,used、limit 须为非负整数、modules 须为列表,最多 32 个包、每包 16 个子系统;write_policy 形状不对整项丢掉;其余丢掉。桥不可达一律 503 unavailable,不计入调用方的每分钟次数。配了按账套分流的桥(U8CO_BRIDGE_ROUTES_FILE,见 configuration.md)时多一个 routes 数组,每个分流桥一项:route(routes[序号])、accounts、ok,可用时带 version、write_policy、replicated_writes,不可用时带错误码 error;顶层字段只描述缺省桥,某个分流桥不通不影响整体状态码。分流桥并行探测,每个读取超时 8 秒,合计最多等 10 秒,超时记 ok: false、error: "unavailable"。

login-check:{"ok":true,"operator","operator_name"},operator_name 是 U8 的操作员姓名。

GET /v1/openapi.json(仅 API):任意已认证调用方都能读,不要求读写权限。OpenAPI 3.1,只含 /v1/co/*,每条路径带 Bearer 安全要求,说明末尾写明所需权限,password 标为 writeOnly。

API 的读写分级#

令牌的权限来自它命中的信任项(见 configuration.md):布尔声明(缺省 u8co_write、u8co_read),或 scope / scp 里配置的 scope。声明值必须是 JSON 布尔 true,字符串 "true" 不算。

权限 能调用 没有时
写权限 全部路由(另有要求的除外,见下) —
只读权限 §3 表里标「读」的路由 写路由 403 forbidden「只读权限不能调用写操作」,不访问桥
两个都没有 无 403 forbidden「无权使用 CO 接口」
经营管理权限(信任项的 mgmt_claim 声明为 true,或 scope 含 mgmt_scope) 经营管理查询 /v1/co/mgmt/*(§34),公司间对账、多账套汇总、合并试算 reports/intercompany_match、aggregate、consolidation(§33)。写权限不代替它 403 mgmt_forbidden「无权查询经营管理数据」
信任项写了 perm_evaluate: true,且令牌有读或写权限 perm/evaluate(查别的操作员的权限)。桥上另按 permEvaluateOperators 校验 403 forbidden「无权查询其他操作员的权限」,不访问桥

读写登记表只有一张:api/u8co_api/co_access.py 的 ACCESS,没登记的路由按写处理。

账套:请求的 acc 必须在 U8CO_ACCOUNTS 里,否则 403 account_not_allowed「账套不在允许列表」。信任项配置了 accounts_claim 时,acc 还必须在令牌的这个声明里,否则 403 account_not_allowed「令牌无权使用该账套」。acc 在 U8CO_READONLY_ACCOUNTS 里时写路由 403 account_read_only「该账套只开放读取」。这几种情况都不访问桥。

调用方与审计:

不需要令牌的路由#

GET /healthz 返回 {"ok":true,"configured":…},configured 表示 CO 已启用且桥地址和密钥都已配置。配了按账套分流的桥时多一个 bridge_routes(分流桥个数)。它不访问桥,只用于容器和负载均衡的存活检查。/docs、/redoc、/openapi.json 都是 404。

离线接口参考页#

不启动服务也能导出同一份 OpenAPI:cd api && uv run python -m u8co_api.openapi_export --out openapi.json。它在内存里建应用(空信任项、空桥地址,不取 JWKS、不连桥),输出与 /v1/openapi.json 相同,只有两处不同:说明里的账套一行换成「以部署配置为准」(--accounts 801,802 可写入具体账套),servers 是占位地址 https://u8co.example.com;另补顶层 tags 的中文分组说明。输出按键排序,重复导出逐字节相同。

scripts/docs/build-api-site.sh [目录] 生成静态文档站点,缺省 dist/api-site/:openapi.json、index.html(模板在 docs/site/)、scalar.standalone.js,以及由 scripts/docs/build_docs_pages.py 把 README 和 docs/*.md 渲染成的 docs/<名称>.html(同目录附 Markdown 原文)、404.html、robots.txt、llms.txt。环境变量 SITE_URL(站点根地址)给出时另生成 sitemap.xml 并写入 canonical 等绝对地址,REPO_URL(仓库地址)给出时指向仓库文件的链接指向仓库;都不给时省略这些内容。Scalar 按脚本里固定的版本从 npm 仓库下载,sha512 与脚本里的值不符就中止。页面不访问任何 CDN、字体或统计服务,CSP 只允许同源,「试一试」只能发给与页面同源的地址。

.github/workflows/api-docs.yml 在 main 分支上 api/、docs/、README.md、llms.txt、scripts/docs/ 有改动时(或手动触发)构建,两个地址都在构建时从 GitHub 上下文取得,上传工作流制品 api-reference(保留 30 天)。本工作流构建静态页;GitHub Pages 可选:仓库可见性为公开、且设置里 Pages 的来源选 GitHub Actions 时另行部署。

18. 错误码#

桥的错误体 {"ok":false,"code","message"},API 的错误体 {"error":{"code","message","retryable"}},两者都可能另带 field、hint、detail。message 为中文;U8 拒绝时带回 U8 的文本(API 转出前去掉控制字符、截到 300 字符,403、409 里 5 个及以上的编码清单折成「首项 等 N 项」);500 对调用方只写「内部错误」,细节只进桥的审计日志。

结构化错误#

{"error": {"code": "bad_request", "message": "请求参数无效:lines.0.cinvcode", "retryable": false,
           "field": "lines.0.cinvcode", "hint": "…"}}
键 在哪 说明
retryable 仅 API,总是有 布尔。busy、busy_timeout、stopping、u8_license_full、ia_timeout、rate_limited、unavailable、store_unavailable、write_policy_unavailable、write_frozen、write_window、write_quota、u8_license_hold 为 true(请求没有执行,按 Retry-After 稍后重发);其余一律 false,outcome_unknown 也是 false(见下文「重试」)
field 知道是哪个字段时。桥在 401 以外的 4xx 上都可能带;API 只在 400 上转出 出错字段在请求体里的路径:点号分隔,键名写法同调用方发来的(桥自己生成的路径用小写),数组下标从 0 开始,例如 lines、head.ccuscode、lines.2.iquantity(不知道下标时 lines.iquantity)、fields.ccusname(档案)、items.0.archive。只含字母、数字、_、.、-,最长 200
hint 桥和 API,可能没有 简短的中文处理建议。桥给了就用桥的(最长 300),否则 API 按码补缺省的,见下表。401 和 500 不带
detail 桥和 API,只在 4xx(401 除外),可能没有 结构化补充(JSON 对象),各路由自己定义键,例如存货核算记账 409 时的 uncosted([{wh, inv, batch}],最多 20 项)和 uncosted_total(§32)。API 转出桥给的对象(403 只保留标量值,字符串同 message 截断);不是对象、为空或序列化后超过 32 KiB 时丢掉

API 自己的请求校验失败时,field 取校验器报的第一个错误位置(去掉开头的 body;查询参数 fields、compact 出错时就是 fields / compact),message 为「请求参数无效:」;取不到位置时为「请求参数无效」。仍是 400 bad_request。

API 的缺省 hint(表在 api/u8co_api/errors.py;表里没有的码没有缺省提示):

code hint
busy、busy_timeout、stopping 稍后重试(见 Retry-After)
u8_license_full U8 许可点数已满,60 秒后重试
ia_timeout 已回滚,没有写入:稍后重试,或让管理员调大桥的 iaCommandSeconds
rate_limited 降低调用频率,按 Retry-After 重试
outcome_unknown 写入可能已生效:先用 load/list(或 idempotency/get)核对,不要直接重试
idempotency_mismatch 同一个 Idempotency-Key 只能用于同样的请求内容
login_failed 检查账套、年度、操作员和口令
account_not_allowed 这个账套不在允许范围内,换一个账套
test_account_only 结账、核算、期初、坏账、票据、汇兑等第二级写入只对 CO 桥 testAccounts 里的测试账套开放
feature_disabled 第二级写入默认关闭:桥设 enableReplicatedWrites 并配置 testAccounts
no_permission、forbidden 当前操作员(令牌)没有这项权限
state_mismatch 先 load 看单据当前状态
unavailable、store_unavailable 稍后重试
not_found 核对类型、id 或编码(只给桥返回的 not_found;API 自己的 404,如路由关闭,不带提示)
write_policy_unavailable 写入策略文件缺失或无效,所有写入暂停:请管理员检查策略文件
write_frozen 写入已被管理员冻结,解冻后再试
write_window 不在允许写入的时段:到允许的时段再试
write_not_allowed 写入策略没有放行这个账套的这类写入(见 detail 的 type、op),请管理员调整策略
operator_not_allowed 写入策略不允许这个操作员在此账套写入,换一个操作员或请管理员调整策略
write_limit 行数或金额超过写入策略的上限(见 detail 的 max、actual),拆成几笔再写
write_quota 账套写入限额已满,按 Retry-After 重试
u8_license_hold 接口占用的 U8 登录已达上限,稍后重试

调用方不要按 hint 的文字做判断,只按 code、retryable、field。

桥#

HTTP code 含义
400 bad_request 字段不合法
400 write_limit 写入策略的行数(field=lines)或金额上限,detail 带 max、actual
401 unauthorized 签名、时间、随机数或来源 IP 不对,不说明是哪一项
403 account_not_allowed 账套不在 allowedAccounts
403 account_read_only 账套在 readOnlyAccounts 里,写路由(含预演和幂等重放)一律拒绝,登录 U8 之前判定
403 feature_disabled 第二级写入(复现 U8 界面 SQL 的写入)而桥的 enableReplicatedWrites 未打开(缺省),账套在 testAccounts 里也一样;登录 U8 之前拒绝
403 test_account_only 第二级写入的账套不在 testAccounts 里(含预演),登录 U8 之前拒绝。第二级写入包括:月末结账(periods/close,§31)、存货核算记账和期末处理(ia/post、ia/period_end,§32)、期初记账和期初单据(openings/post、openings/arap,§29)、库存期初结存单、坏账、汇兑损益、应付票据、总账取消记账和自动转账(§14)。完整清单见 limitations.md;采购手工结算是第一级写入
403 write_not_allowed 写入策略没有放行这个账套的这类写入,detail 带 type、op;登录 U8 之前拒绝(见 configuration.md)
403 operator_not_allowed 写入策略不允许这个操作员在此账套写入
403 no_permission 写操作:操作员没有对应的 U8 功能权限(总账、档案写入、生产订单关闭和打开等),或记录不在数据权限内。读路由:没有该功能权限,或单张单据、档案不在数据权限内(§22)
404 not_found 单据不存在
409 state_mismatch 调用前已是目标状态,不满足门槛,或提交后回读对不上
409 u8_rejected U8 返回了拒绝文本,message 是原文
409 workflow_enabled 单据走审批流,不能直接审核
409 workflow_unknown 查不到审批流配置,按失败处理
409 workflow_disabled、already_submitted、not_submitted、not_current_approver 审批流状态不符(§13)
409 stock_shortage 库存不足
409 idempotency_mismatch 同一个幂等键已用于内容不同的请求(§20)
422 login_failed U8 登录失败,message 是 U8 的原文
429 busy 写队列或读队列已满;入队本身失败时同一个码以 503 返回。都没有执行,可以重试
429 write_quota 账套写入限额已满,detail.retry_after_seconds 是建议等待的秒数
500 internal 桥内部错误
503 com_unavailable COM 组件没有注册、创建失败,或所需程序集加载失败
503 u8_unavailable U8 自己的服务或文件不可用(例如生产制造服务没在运行、EAI 对照文件读不到)
503 busy_timeout 排队超过 75 秒,任务已放弃,可以重试;写入(新增、修改、删除、审核、关闭、生单、锁定、审批流操作、总账和档案写入、应收应付的核销和取消核销)排队超过 45 秒、剩余时间不足 30 秒时也不再开始,同样返回它(没有执行);开了 cleanOrphanTasks 时也可能是审批流操作等孤儿清理锁超时(没有调用 U8),同样可以重发
503 u8_license_full U8 许可点数已满(「加密点数已饱和」),桥已自己有限重试过,message 写明子系统。请求没有执行;写入策略 holdWritesWhen 暂停写入时也是这个码(「…接口暂停写入,请稍后重试」)
503 ia_timeout 存货核算脚本超过 iaCommandSeconds(§32):在提交之前超时,事务已回滚,没有写入;可以稍后重发,或调大 iaCommandSeconds
503 write_policy_unavailable、write_frozen、write_window 写入策略:没有可用的策略(失效即拒写)、写入已冻结(消息带原因)、不在可写时段。写入没有执行
503 u8_license_hold 写入策略的 license.maxConcurrentLogins:本进程的 U8 登录已达上限,没有登录、没有执行
503 stopping 服务正在停止
503 store_unavailable 幂等记录读写失败,请求没有执行,可以重试(§20)
503 unhealthy 健康检查失败
504 outcome_unknown 75 秒时任务已经在执行,或 U8 自己提交后回读失败。结果未知

API#

API 把桥的错误码原样带上,HTTP 状态按下表:

HTTP code 含义
400 bad_request 请求字段不合法(模型校验失败时 message 为「请求参数无效」)
400 ic_group_mismatch 请求里的账套不在同一公司组
400 idempotency_required intercompany/generate_buyer 正式生成没带 Idempotency-Key(field=dry_run)
401 unauthorized 缺少或无效的访问令牌,带 WWW-Authenticate: Bearer
403 forbidden 令牌没有所需权限
403 account_not_allowed 账套不在 API 的白名单,不访问桥
403 account_read_only 账套在 U8CO_READONLY_ACCOUNTS 里,写路由不访问桥
403 mgmt_forbidden 令牌没有经营管理权限(§17)
403、503、400 写入策略各码 配置了 U8CO_WRITE_POLICY_FILE 时 API 在调桥之前按同样的规则拒绝,码和消息与桥相同(不含 write_quota、u8_license_hold,那两项只在桥上)
404 ic_not_configured 没有配置公司间对照(U8CO_IC_MAP_FILE),公司间接口和多账套合并不可用
404 not_found U8CO_ENABLED=0 关闭了 CO 路由,或单据不存在
409 ic_party_unmapped、ic_inventory_unmapped、ic_no_open_po 公司间接口:对照里缺往来单位编码、缺买方存货编码(detail.codes),或没有能覆盖的公司间采购订单(§33)
422 ic_too_many_rows 公司间接口:某个账套的数据超过翻页上限,缩小日期或条件
429 rate_limited 本服务的频率或在途上限。与桥的 busy 不是一回事
502 internal 桥返回 500
502 bad_response 桥的错误响应不是可解析的 JSON、超过 64 KiB,或发生了重定向
503 unavailable 桥没有配置、连不上、健康检查失败,或桥拒绝了 API 的签名(两边密钥不一致)
503 u8_license_full 原样带上桥的码和 message,响应头 Retry-After: 60
503 ia_timeout 原样带上桥的码和 message,响应头 Retry-After: 60,retryable 为 true
504 outcome_unknown 请求已经送出但没有收到结果,或桥返回了无法解析的成功响应(含超过 8 MiB)

其余码(state_mismatch、u8_rejected、login_failed、feature_disabled、test_account_only、busy、busy_timeout、stopping、com_unavailable、u8_unavailable、审批相关码等)状态与桥相同。

Retry-After(秒):u8_license_full、ia_timeout 为 60;busy、busy_timeout、stopping 为 5;write_policy_unavailable、u8_license_hold 为 30,write_frozen、write_window 为 300,write_quota 取桥的 detail.retry_after_seconds(1 到 86400 的整数,否则 60);本服务的 rate_limited 是频率窗口空出的秒数(至少 1),并发超限为 5;其余错误不带。桥本身不发这个头。

重试#

情况 能否重试
连不上桥(API 503 unavailable、客户端 connect_failed) 可以,请求没有送出
429 busy / rate_limited,503 busy_timeout / stopping 可以,稍后再试;rate_limited 按 Retry-After
503 u8_license_full 可以,按 Retry-After 稍后再试;桥已自己重试过,不要立刻连发。请求没有执行,带幂等键的可以用同一个键重发
503 write_policy_unavailable / write_frozen / write_window / u8_license_hold,429 write_quota 可以,按 Retry-After 稍后再试;写入没有执行,带幂等键的可以用同一个键重发
403 write_not_allowed / operator_not_allowed / account_read_only / feature_disabled / test_account_only,400 write_limit 不要原样重发(要改请求或配置),不占幂等键
503 ia_timeout 可以,按 Retry-After 稍后再试(同样的数据多半还会超时,先调大桥的 iaCommandSeconds)。事务已回滚,带幂等键的可以用同一个键重发
504 outcome_unknown 不要盲目重试。写操作可能已经生效:带了幂等键的先用 idempotency/get(§20)查第一次的结果,再用 load、list、gl/vouchers/load、archives/get 核对,再决定
409 state_mismatch(审核回读对不上) 不要重发,事务已经提交
502 internal(桥 500) 不要重发,写入可能已落库(例如 U8 自行提交后回写核对不过),要人工核对
带幂等键的写请求(§20,全部写路由) 可以用同一个键重发:成功的原样重放,不会重复执行;结果未知的原样重放 504,仍要先核对;4xx 不占用键,修正后可用同一个键

桥在 75 秒时给出结果。API 读桥的超时要大于这个值(缺省 90 秒),这样调用方先看到桥的结果,而不是自己先断开。

19. 只读报表 reports/*#

报表路由只查数据库(读线程池),不调用 U8 组件,不写数据。参数在登录前全部校验,不合法返回 400 bad_request:整数必须是 JSON 整数,布尔必须是 true/false,未知字段一律拒绝。审计动作是 report_<名称>。

桥登录的子系统:

报表 子系统
close_status、bom、account_readiness(§30)、fa_changes、fa_depreciation、customer_credit SA
gl_balance、gl_aux_balance、gl_detail GL
arap_balance、arap_aging、arap_detail 按 side:AR 或 AP
arap_writeoffs 按 flag:AR 或 AP
order_execution 销售订单 SA,采购订单 PU
doc_trace 同起点单据的 vouchers/load
stock_ledger、stock_summary、position_stock、batch_stock ST
price_list kind=vendor 为 PU,其余 SA
opening_balance stock 为 ST,arap 按 side 为 AR 或 AP,gl 为 GL

公共约定:

项 说明
会计年度 可选 fiscal_year(2000 到 2099),缺省取登录日期 date 的年份,与总账凭证相同。year 是账套库年度,不参与判断。响应原样带回 fiscal_year。库存与销售支持报表不带 fiscal_year
金额 JSON 数字,本币,两位小数,与 gl/vouchers/load 的 debit/credit 一致。数量、物料清单用量六位小数
翻页 limit 加 after。after 填上一页的 next,是不透明字符串(1 到 512 个可见 ASCII 字符),不要解析;最后一页 next 为 null。bom 不分页
余额方向 余额按方向拆成借方、贷方两列(其中一列为 0),方向字段取 借、贷、平
开销 带期初、合计的报表(gl_detail、stock_summary、stock_ledger、arap_detail)每一页都重新汇总(不缓存),翻页越多总开销越大;数据量大时缩小范围或加大 limit

功能权限(任一即可,账套主管不受限):

报表 功能 id
close_status 总账「结账」GL1512、「反结账」GL1520、余额表 GL030301、明细账 GL0305
gl_balance GL030301、GL0305、GL030101
gl_aux_balance GL030301、GL0305
gl_detail GL0305
arap_balance 应收总账表 AR060201_01 或应收审核 AR050104(应付 AP060201_01 / AP050104)
arap_aging 应收账龄分析 AR060301 或 UAP 报表视图「查询:应收账龄分析」AR[__]bdfd5d21-763b-4d7b-a6ae-eb3abb026f91_001_01(应付 AP060301 / AP[__]5d20e375-da98-4d59-a5a5-345d9123f2d0_002_01)
arap_detail 应收明细账 AR060202_01、对账单 AR060203_01、总账表 AR060201_01(应付同理)
arap_writeoffs 应收核销明细表 AR060107、手工核销 AR050201、选择收款 AR0503、取消操作 AR0807(应付 AP060107、AP050201、AP0503、AP0807)
opening_balance 见「期初余额」
bom BO01001Q
order_execution 销售订单 SA03010104 / SA03010201 或采购订单 PU0310,再按 type 要求对应类型
doc_trace 登录即可,各节点按单据类型的读取规则
stock_ledger 打印 / 输出 ST020102_03、ST020102_04
stock_summary ST020301_01
position_stock 货位存量 ST020107_01、货位汇总表 ST010812_01
batch_stock ST020305_01、ST020107_01
customer_credit 信用余额表 SA040410_01
price_list 路由接受任一:客户价格 SA0312030101、存货价格 SA0312020101、供应商存货价格 PU060105 / PU060106;处理时再按 kind 要求对应的一组,缺了 403(如「没有客户价格表查询权限」)
account_readiness 账套主管,或 GL1512、GL0202
fa_changes 变动单查看 FA1603
fa_depreciation 折旧清单查看 FA2403、折旧清单表 FA18105

数据权限见 §22,各报表的过滤对象在各小节说明。

close_status 月结状态#

可选 fiscal_year。响应 {"ok":true,"fiscal_year","modules","periods"}。modules 固定为 SA 销售、PU 采购、ST 库存、IA 存货核算、GL 总账、AR 应收、AP 应付、CA 成本、FA 固定资产。periods 是该年度已建立的期间(1 到 12,升序),每项 {"period","closed":{模块:布尔}};年度没有建立时为空数组,不返回 404。

gl_balance 科目余额表#

字段 说明
period_from、period_to 必填,1 到 12,period_from 不大于 period_to
grade_from、grade_to 科目级次,1 到 9,缺省 1 和 9
code_prefix 科目编码前缀,1 到 40 位数字、字母、点或短横
leaf_only 只要末级科目,缺省 false
include_unposted 含未记账凭证(不含作废),缺省 false。未记账凭证汇总到上级科目:period_from 之前的计入期初,区间内的计入本期,累计和期末都含。只有未记账凭证、还没有科目总账记录的科目也列出
nonzero 去掉期初、本期、累计、期末全为 0 的行,缺省 false
after、limit 翻页,limit 1 到 1000,缺省 200

每项:code、name、grade、leaf、class(科目类型)、natural_dir(科目性质 借/贷)、open_dir、open_debit、open_credit、period_debit、period_credit、ytd_debit、ytd_credit、close_dir、close_debit、close_credit。按科目编码排序。期初是 period_from 月初,期末是 period_to 月末(期末 = 期初 + 本期借 − 本期贷),累计是 1 月到 period_to。上级科目已包含下级,不要跨级相加。

数据权限:按科目,只在总账选项「明细账查询权限控制到科目」打开时生效。

gl_aux_balance 辅助核算余额表#

必填 dim(customer、vendor、dept、person、project)、period_from、period_to;可选 fiscal_year、code_prefix、dim_code(维度编码等于,1 到 60 个字符)、project_class(项目大类,1 到 20 位字母或数字,只能和 dim=project 一起用)、nonzero、after、limit。只含已记账凭证,没有 include_unposted。

每项:code、name(科目)、dim_code、dim_name、project_class,以及与 gl_balance 相同的期初、本期、累计、期末列。按科目、项目大类、维度编码排序。项目的 dim_name 为 null(项目名称分散在各大类的表里);编码已不存在时也为 null。

数据权限:按 GL_accass 原始行的科目与各辅助项过滤。

arap_balance 往来余额#

字段 说明
side 必填。ar 应收(按客户),ap 应付(按供应商)
as_of 截止日期 yyyy-MM-dd,按登记日期含当天。缺省为 date
accounts 控制科目编码前缀,1 到 20 个。缺省应收 ["1122"],应付 ["2202"]
exclude_accounts 要排除的前缀,最多 20 个(例如暂估科目)
partner 客户或供应商编码等于
nonzero 去掉余额为 0 的往来单位,缺省 true
after、limit 翻页,limit 1 到 1000,缺省 200

每项 partner、name、debit、credit(截至 as_of 的累计)、balance。应收 balance = 借 − 贷(正数是客户欠我方),应付 balance = 贷 − 借(正数是我方欠供应商)。不含应收票据和现金类记录。按往来单位编码排序。数据权限按客户(应付为供应商)。

arap_aging 账龄分析#

字段同 arap_balance,另有:

字段 说明
basis document 按单据日期(缺省);due 按到期日,见下文
buckets 账龄区间上限天数,1 到 10 个严格递增的整数,每个 1 到 3650。缺省 [30,60,90,180,365]。逾期催收常用 basis=due 加 [30,60,90]
group_by partner 按往来单位(缺省);person 按业务员;partner_person 按往来单位 + 业务员
person 业务员编码,1 到 20 个(每个 1 到 20 个字符),按解析出的业务员过滤,任何分组都可用
overdue_only 只留 overdue 大于 0 且 balance 大于 0 的行(净额仍欠),缺省 false。只能和 basis=due 一起用,否则 400
default_credit_days 缺省信用天数,0 到 3650,缺省 0。只能和 basis=due 一起用,否则 400(field 为 default_credit_days)。给了时响应原样带回

到期日(basis=due):取明细行(Ar_Detail / Ap_Detail)的收款(付款)日期 dGatheringDate;没有时,信用期 iCreditPeriod 不为 0 的取信用起算日 dCreditStart(没有取单据日期)+ 信用期,不加 default_credit_days;信用期为 0 或空的取起算日 + default_credit_days。default_credit_days 为 0 时结果与不给相同。客户、供应商信用期为 0 且未填收款日期时,到期日落在单据日期、overdue 等于全部余额;这时用 default_credit_days(例如 30)按统一账期计算逾期。

业务员:取原单据明细上的业务员 cPerson(只看原单自己的行,核销行上的不用);原单没有时取客户(供应商)档案的专管业务员 cCusPPerson / cVenPPerson;都没有时归到业务员为空的一组。未核销的收付款单本身就是原单,按自己的业务员归组。

响应另有 basis、group_by、buckets([{"key","from","to"}]:第一项 not_due(账龄 ≤ 0),然后每个区间,最后一项没有上限,共 buckets 个数加 2 项)。每项先是分组键:partner 分组为 partner、name;person 分组为 person_code、person_name、person_source(document 全部取自单据,customer / vendor 全部取自档案,mixed 两者都有;业务员为空的一组三项都是 null);partner_person 两组都有。之后是 balance、aging(与 buckets 一一对应的金额)、prepaid(未核销的预收或预付,正数),basis=due 时另有 overdue(aging 除 not_due 外的合计)。balance = aging 合计 − prepaid。

bom 物料清单#

字段 说明
parent 必填,母件存货编码
as_of 生效日期,缺省为 date。只取主 BOM(BomType=1)当天有效的已审核版本;同一存货有多个物料(自由项不同)时先取不带自由项的,再取最高版本;子件取当天有效的
levels 展开层数 1 到 10,缺省 1
limit 最多返回行数 1 到 5000,缺省 1000。超出时 truncated 为 true,不翻页

响应 {"ok":true,"parent","as_of","levels","bom_id","version","items","truncated"},version 是整数版本号。每项 level、parent(这一层的母件)、component、name、spec、sort、qty_n、qty_d(基本用量的分子、分母)、qty(每 1 个根母件累计需要的数量,全精度相乘后保留六位小数,不含损耗率;分母为 0 时为 null)、path。按层级、母件、序号、子件排序。已在路径上的子件不再展开(防环);每个母件只查一次。该日期没有已审核的物料清单时 404 not_found。数据权限:母件存货不在授权内 403,不在授权内的子件不列出、也不展开。

arap_detail 往来明细账#

数据源同 arap_balance(应收 / 应付明细,不含应收票据和现金类记录)。

字段 说明
side 必填。ar 应收(按客户),ap 应付(按供应商)
partner 必填。往来单位编码,或 1 到 20 个编码的数组
date_from 必填,起始日期(含)。期初是这一天之前的累计
date_to 截止日期(含),缺省为 date,不能早于 date_from
basis 日期口径,只收 register 登记日期(缺省,与 arap_balance 的 as_of 相同);其他值 400
accounts、exclude_accounts 同 arap_balance
dept、person 明细行上的部门、业务员编码等于(1 到 20 个字符),期初也只算这些行
include_writeoff 在 items 里列出核销行(cProcStyle=9P),缺省 false。只决定输出哪些行:期初、借贷合计、期末和滚动余额一律含核销行。不列时相邻两行的余额差可能不等于后一行的借贷;游标到本页最后一行之间被隐去的核销行多于 20000 行时 400,请缩小范围或列出核销行
after、limit 翻页,limit 1 到 1000,缺省 200

响应 {"ok":true,"side","basis","date_from","date_to","partners","items","next"}。

数据权限按客户(供应商),期初、合计和明细一致;没有权限的单位不出现。

gl_detail 科目明细账#

字段 说明
code 必填,科目编码。该年度没有这个科目 404 not_found
include_sub 缺省 true:含下级科目(编码以 code 开头的末级科目);false 只查 code 本身(只对末级科目有意义)
period_from、period_to 期间 1 到 12,与日期二选一。年度同 gl_balance
date_from、date_to 日期(含),与期间二选一,两个都要给,必须在同一年度;带 fiscal_year 时须与日期的年份一致
include_unposted 含未记账凭证(不含作废),缺省 false。起始期间之前的计入期初,区间内的列为明细(posted 为 false)
customer、vendor、dept、person、project、project_class 辅助核算条件(等于);project_class 只能和 project 一起用
after、limit 翻页,limit 1 到 1000,缺省 200

响应顶层:fiscal_year、code、name、leaf、include_sub、include_unposted、period_from、period_to(按日期时是日期的月份)、date_from、date_to(按期间时为 null),整个区间的 open_dir、open_debit、open_credit、total_debit、total_credit、close_dir、close_debit、close_credit(每页相同),以及 items、next。items 按期间、日期、凭证类别、凭证号、分录号排序,列名同 gl/vouchers/load 的分录:period、date、sign、no、entry、digest、account、account_name、debit、credit、posted、dept、person、customer、supplier、item_class、item,另有滚动余额 dir 和 balance(绝对值),翻页后继续滚动。

期初规则同 gl_balance:起始期间的年初余额按末级科目合计,不带辅助核算的末级科目取科目总账,带辅助核算的取辅助总账,所以辅助项条件对期初同样生效。按日期查询时,起始期间里 date_from 之前的凭证也计入期初。不带辅助项条件、按期间查询时,期初、合计、期末与同期 gl_balance 的该科目一致。

数据权限:凭证分录和辅助总账按科目与各辅助项过滤;科目总账只按科目过滤。科目只在「明细账查询权限控制到科目」打开时受控。

客户端命令:report-close-status、report-gl-balance、report-gl-aux、report-gl-detail(--period-from/--period-to 或 --date-from/--date-to,--exact 不含下级科目,--include-unposted,--customer、--vendor、--dept、--person、--project、--project-class)、report-arap-balance、report-arap-aging(--buckets 30,60,90、--group-by person、--person 可重复、--overdue-only、--default-credit-days 30)、report-arap-detail(--partner 可重复、--include-writeoff)、report-bom。往来报表的 --account、--exclude-account 可重复,--include-zero 保留余额为 0 的单位。

order_execution 订单执行#

逐行列出订单的数量、金额和执行进度。执行数取 U8 订单行上的累计列(由 U8 回写),桥不另外汇总下游单据。

字段 说明
type 必填。sale_order 销售订单,purchase_order 采购订单
ids 订单 id(表头主键),1 到 100 个正整数。不能和 code、date_from、date_to、partner 一起用
code 订单号等于,1 到 30 个字符
date_from、date_to 订单日期范围(含两端),date_from 不能晚于 date_to
partner 客户(销售)或供应商(采购)编码等于,1 到 20 个字符
only_open 只要未执行完且未关闭的行,缺省 false
after、limit 翻页,limit 1 到 1000,缺省 200

响应 {"ok":true,"type","only_open","items","next"}。items 按订单 id、行 id 排序,每行一项:id、code、date、partner、partner_name、currency、verified、closed(订单或该行已关闭)、open、line_id、row_no、inv_code、inv_name、inv_std、due_date(销售为预发货日期,采购为计划到货日期)、qty、amount(原币价税合计)、nat_amount(本币价税合计),以及执行数:

销售订单 U8 列 采购订单 U8 列
shipped_qty、shipped_amount 累计发货 iFHQuantity、iFHMoney arrived_qty、arrived_amount 累计到货 iArrQTY、iArrMoney
out_qty 累计出库 foutquantity in_qty 累计入库 iReceivedQTY + freceivedqty
invoiced_qty、invoiced_amount 累计开票 iKPQuantity、iKPMoney invoiced_qty、invoiced_amount 累计开票 iInvQTY、iInvMoney
returned_qty 累计退货 fretquantity returned_qty 累计退货 fPoRetQuantity
received_amount、received_nat_amount 累计收款(原币、本币) iexchsum、imoneysum paid_amount、paid_nat_amount 累计付款(原币、本币) iOriTotal、iTotal

数据权限同该订单类型的 vouchers/list:记录级条件(客户、供应商、部门、业务员、销售 / 采购类型、表体存货)加在订单表头上,整张订单要么全列要么不列。

doc_trace 单据追溯#

从一张单据出发列出上游(来源)和下游(去向)单据。

字段 说明
type 必填,起点单据类型(节点类型之一)
id 必填,起点单据 id(表头主键)
depth 每个方向最多几跳,1 到 3,缺省 3
direction both(缺省)、up 只找上游、down 只找下游
max_nodes 最多返回的节点数(含起点),1 到 200,缺省 200

关联(上游 → 下游,括号里是关联列):

链路 关联
销售 销售订单 → 发货单(发货行 iSOsID)→ 销售出库单(iDLsID)、销售发票(iDLsID)→ 收款单;发货单 → 退货单(退货行 iCorID = 原发货行)→ 销售出库单(红字)、销售发票(红字);没有原发货行的退货单、没有发货行的发票直接挂订单行
退货申请 发货单(蓝字)→ 退货申请单(申请行 iDLsID = 发货行)→ 退货单(退货行 irtnappid = 申请行 AutoID 且 crtnappcode = 申请单号)
采购 请购单 → 采购订单(iAppIds)→ 到货单(iPOsID)→ 来料报检单(SOURCEAUTOID,只认 CSOURCE=到货单)→ 来料检验单(INSPECTAUTOID)→ 采购入库单(iCheckIdBaks)→ 采购发票(RdsId)→ 付款单;来料检验单 → 来料不良品处理单(CHECKID);到货单 → 采购退货单(iCorId)→ 采购入库单(红字)。没有检验单的入库挂到货单(iArrsId),没有到货单的入库、没有入库行的发票挂订单行
生产 物料清单 → 生产订单(BomId)→ 材料出库单(iMPoIds = 子件 AllocateId)、产成品入库单(iMPoIds = 订单行)、产品报检单(SOURCEAUTOID,只认 CSOURCE=生产订单)→ 产品检验单 → 产品不良品处理单(CHECKID)→ 产成品入库单(iRejectIds);产品检验单 → 产成品入库单(iCheckIdBaks,不含参照不良品处理单的行)
其他质检 其他报检单 → 其他检验单(检验单 INSPECTAUTOID = 报检单表体 AUTOID)。两者都没有出入库来源
收付款 销售发票 → 收款单、采购发票 → 付款单:按核销明细(Ar_Detail / Ap_Detail 中收款单 48 / 付款单 49 核销发票的行,cProcStyle=9P)关联。核销应收单 / 应付单、预收预付、红票对冲不在图里

节点类型(28 种):sale_order、dispatch、sale_return、sale_return_apply、sale_out、sale_invoice、ar_receipt、ar_refund、purchase_requisition、purchase_order、arrival、purchase_return、purchase_in、purchase_invoice、ap_payment、ap_refund、qm_incoming_inspect、qm_product_inspect、qm_incoming_check、qm_product_check、qm_incoming_reject、qm_product_reject、qm_other_inspect、qm_other_check、production_order、material_out、product_in、bom。ar_refund(客户退款)、ap_refund(供应商退款)只能作为起点(没有边)。

响应 {"ok":true,"type","id","depth","direction","nodes","edges","omitted","truncated"}。nodes 第一项是起点,每项 type、id、code(物料清单是母件存货编码)、date、state(unverified、verified、closed;生产订单全部行关闭为 closed、全部行已下达为 verified)、level(起点 0,下游第 n 跳为 n,上游为 −n)。edges 每项 from_type、from_id、to_type、to_id(总是上游指向下游)、lines(关联的明细行数,收付款为核销记录数);只列两端都在 nodes 里的边。

客户端命令:report-order-exec(--type,--id 可重复,--code、--date-from、--date-to、--partner,--only-open)、report-doc-trace(--type、--id,--depth、--direction、--max-nodes)。

库存与销售支持报表#

收发记录的来源(stock_ledger、stock_summary 共用):采购入库 01、其他入库 08、其他出库 09、产成品入库 10、材料出库 11、销售出库 32、库存期初 34 七类单据的表头 + 表体(RdRecord* / rdrecords*)。调拨、盘点、形态转换在 U8 里生成其他入库 / 其他出库,不另算。缺省只算已审核(表头 cHandler 非空)的单据,此时按(仓库、存货)合计与现存量 CurrentStock.iQuantity 一致;include_unverified 为 true 时连未审核的一起算(期初也含)。数量按单据原数,红字入库是负的入库、红字出库是负的出库。

数据权限:四张库存报表按仓库、存货过滤(同 stock/current),stock_ledger 的存货不在授权内 403;customer_credit 按客户;price_list 按客户、供应商(可空)和存货。

stock_ledger 库存台账#

字段 说明
inv 必填,存货编码。不存在 404 not_found
date_from 必填,yyyy-MM-dd(含)。期初是这一天之前的累计
date_to 截止日期(含),缺省为 date;早于 date_from 时 400
wh、batch 仓库、批号等于。不给仓库时全部仓库合在一起滚动结存
include_unverified 含未审核单据,缺省 false
after、limit 翻页,limit 1 到 1000,缺省 200

响应 {"ok":true,"inv","inv_name","inv_std","wh","batch","date_from","date_to","include_unverified","opening","carry","closing","items","next"}。opening 是 date_from 之前的结存;carry 是本页第一行之前的结存(第一页等于 opening,之后由桥按游标重算);closing 只在最后一页给出,其余页为 null。每项 date、type(purchase_in、other_in、other_out、product_in、material_out、sale_out、stock_opening)、id、line_id(表体 AutoID)、code、wh_code、wh_name、batch、rd_code(收发类别)、source(来源,如 调拨、生产订单)、verified、in_qty、out_qty、balance(本行之后的结存)。按日期、表体 AutoID 排序(七类表体共用一个号段,AutoID 不重复)。

stock_summary 收发存汇总表#

必填 date_from;可选 date_to、wh、inv、inv_class(存货分类编码前缀,含下级)、by_wh(缺省 true 按存货 + 仓库分行,false 每个存货一行)、include_unverified、nonzero(缺省 true,去掉期初、入库、出库都为 0 的行)、after、limit(1 到 1000,缺省 200)。

每项 inv_code、inv_name、inv_std、inv_class、wh_code、wh_name(by_wh=false 时为 null)、opening、in_qty、out_qty、closing(= 期初 + 入 − 出)。按存货、仓库编码排序。只有数量,不给金额(出库成本在存货核算记账后才有)。date_to 为今天时 closing 等于现存量。

position_stock 货位存量#

可选 wh、inv、batch、position(货位编码前缀,含下级)、nonzero(缺省 true)、after、limit(1 到 1000,缺省 200)。来源 InvPositionSum,按其主键翻页。每项 id、wh_code、wh_name、position、position_name、inv_code、inv_name、inv_std、batch、free1 到 free10、qty、qty_aux、made_date、valid_until、expires。只含已指定货位的数量:入库后尚未指定货位的部分只在现存量里,所以货位合计可能小于现存量。

batch_stock 批次存量#

可选 wh、inv、batch、expiring_before(只要失效日期不晚于这一天的批次,用于保质期预警;没有失效日期的批次不列)、nonzero(缺省 true)、after、limit。来源 CurrentStock,只取有批号的行,按(仓库、存货、批号)合并自由项不同的行。每项 wh_code、wh_name、inv_code、inv_name、inv_std、batch、qty、qty_aux、qty_frozen、made_date、valid_until、expires(多行时取最早)、rows(合并的现存量行数)。按仓库、存货、批号排序。可用量等逐行口径用 stock/current(可按 batch 过滤)。

customer_credit 客户信用#

可选 customer(1 到 20 个客户编码)、controlled_only(只列档案上勾了信用额度控制 bCredit 的客户)、after、limit(1 到 200,缺省 100)。按客户编码翻页。

各项占用与 U8 信用余额表(Sa_saleCreReport 及 CreditSoForReport、CreditDLForReport、CreditBillForReport、视图 Ap_CreditDetail)口径一致,本币价税合计:

键 内容
order 未执行完的销售订单:未关闭行按未发货数量(直运销售按未开票)折算,数量为 0 的行按金额
dispatch 未开票的发货单:需开票、未结算完的行扣掉已开票和退货
invoice 销售已开、应收未审核的销售发票(扣现结)
ar 应收账款余额(Ap_CreditDetail:应收明细 iFlag<2,检查点为保存时另加未审核的应收单、收款单)
expense 代垫费用单

信用检查点(销售选项 bCrCheckWhen)为「保存」时各项都含未审核单据,为「审核」时只含已审核的,订单和发货单改用 U8 的已审核累计列(fVeriDispQty、fVeriBillQty 等)。订单一项按「信用余额控制用余额表」(bUseBanlaceTable)打开时的口径;关闭时的 U8 算法未覆盖。

响应另有 credit_control(销售选项「是否有客户信用额度控制」)、check_point(save / verify)、balance_table、ar_enabled(应收款管理已启用)、formula(额度检查公式 cCrCheckFunction 各项是否打开:order、dispatch、invoice、ar、expense、contract、export_order、export_consignment、export_invoice)、unsupported(公式里打开了、本报表不计算的合同结算单和出口单据)。每项 code、name、controlled、credit_line(iCusCreLine)、credit_days(iCusCreDate)、credit_days_controlled(bCreditDate)、credit_grade(cCusCreGrade)、credit_company(信用单位)、上表五项、used(公式里打开的项之和,ar 另要求应收已启用)、available(受控客户为 credit_line − used,否则 null)。

price_list 价格表#

字段 说明
kind 必填。customer 客户价格表(SA_CusUPrice)、inventory 存货价格表(SA_InvUPrice)、vendor 供应商存货价格表(Ven_Inv_Price)
customer 客户编码,只能和 kind=customer 一起用;连同该客户所属客户分类的价格行
vendor 供应商编码,只能和 kind=vendor 一起用
inv 存货编码等于
as_of 生效日期,缺省 date:只列这一天有效(生效日期不晚于、失效日期为空或不早于这一天)、未标失效的行
all_dates true 时不按日期过滤,不能和 as_of 一起用
after、limit 翻页,limit 1 到 1000,缺省 200

响应 {"ok":true,"kind","as_of","items","next"}(all_dates 时 as_of 为 null)。每项 id、inv_code、inv_name、inv_std、currency、start_date、end_date、min_qty(数量下限)、tax_included、promotion、memo;customer 另有 customer、customer_class、invalid、quote(iInvSCost)、discount_rate(iCusDisRate)、price(iInvNowCost)、min_price(fcusminprice);inventory 另有 invalid、levels([{"level","price","tax_price"}],iUPrice1–10 无税、ISalePrice1–10 含税,两者都空的级别不列);vendor 另有 vendor、max_qty、price(无税)、tax_price、tax_rate、supply_type。按表主键排序。

客户端命令:report-stock-ledger(--inv、--date-from,--wh、--batch、--include-unverified)、report-stock-summary(--date-from,--inv-class、--no-wh、--include-zero)、report-position-stock(--position)、report-batch-stock(--expiring-before)、report-customer-credit(--customer 可重复、--controlled-only)、report-price-list(--kind,--customer、--vendor、--inv、--as-of、--all-dates)。

opening_balance 期初余额#

只读。期初的录入、修改不经本接口;采购、存货核算的期初记账、取消记账用 openings/post(§29),其他模块的期初记账不支持(见 docs/limitations.md)。

字段 说明
module 必填。stock 库存期初,arap 应收或应付期初,gl 总账期初余额
side module=arap 时必填:ar 应收(按客户),ap 应付(按供应商)
fiscal_year 只用于 gl:会计年度,缺省为 date 的年份,不能早于总账启用年度(400)
wh、inv、batch 只用于 stock:仓库、存货、批号等于
partner 只用于 arap:客户或供应商编码等于
code_prefix 只用于 arap、gl:科目编码前缀
leaf_only 只用于 gl:只要末级科目
dim 只用于 gl:按辅助项列期初(customer、vendor、dept、person、project),缺省按科目
nonzero 缺省 true:去掉期初为 0 的行
after、limit 翻页,limit 1 到 1000,缺省 200

带了别的模块的字段 400(例如 module=stock 带 code_prefix)。

响应公共字段:module、side(arap 以外为 null)、start_date(模块启用日期,AccInformation 的 dSTStartDate / dARStartDate / dAPStartDate / dGLStartDate,未启用为 null)、opening_year(库存、往来是启用年度,总账是 fiscal_year)、posted(期初是否已记账:GL_mend 在该年度第 0 期的 bflag_ST / bflag_AR / bflag_AP / bflag;已记账的期初在 U8 里不能再改),以及 items、next。

功能权限:路由接受下列任一 id,桥再按 module(和 side、dim)要求对应的一组:库存 ST000101(期初结存)或 ST020107_01,应收 AR0306 或 AR060201_01,应付 AP0306 或 AP060201_01,总账 GL010303、GL010304 或 GL030301。

客户端命令:report-opening-balance --module stock|arap|gl(--side、--fiscal-year、--wh、--inv、--batch、--partner、--code-prefix、--leaf-only、--dim、--include-zero)。

arap_writeoffs 核销记录#

按核销号(Ar_Detail / Ap_Detail 的 cCancelNo,cProcStyle=9P,HXAR… / HXAP…)列出应收或应付的核销批次,包括本服务 arap/writeoff 和 U8 客户端做的核销。用于查找核销号、核对一次核销冲了哪些单据行,以及预先判断能否用 arap/writeoff/cancel 取消。

字段 说明
flag 必填。AR 应收(Ar_Detail),AP 应付(Ap_Detail)
partner 客户或供应商编码等于(cDwCode)
receipt {"type","id"}:只看这张收付款单的核销。flag=AR 时 type 只能是 ar_receipt,AP 时只能是 ap_payment;id 是 Ap_CloseBill.iID。与 receipt_code 二选一
receipt_code 收付款单号等于(cVouchID)。与 receipt 二选一
target {"type","id"}:只看核销了这张单据的批次。flag=AR 时 sale_invoice / ar_bill,AP 时 purchase_invoice / ap_bill;id 是 SBVID、PBVID 或 Ap_Vouch.Auto_ID。与 target_code 二选一
target_code 被核销单据的单号等于(cCoVouchID,不含收付款单自身的冲减行)。与 target 二选一
date_from、date_to 登记日期(dRegDate)区间,含两端
cancel_no 核销号等于,HXAR / HXAP 后接数字,前缀须与 flag 一致
after、limit 翻页,limit 1 到 200,缺省 50

找不到的收付款单或单据不报 404,结果为空。按登记日期降序、核销号降序。

响应 {"ok":true,"flag","items","next"},每批一项:

字段 说明
cancel_no 核销号
date 登记日期(核销日期)
year、period 期间是往来明细的 iPeriod;年度是登记日期在 UFSYSTEM..UA_Period 上所在的年度(找不到取日期的年份),与取消核销判断结账用的一致
partner、currency、operator 往来单位编码、币种名称、核销人(cOperator,U8 里是姓名)
receipt 核销行所在的收付款单:type(ar_receipt / ap_payment;应收一侧的付款单为 ar_refund,应付一侧的收款单为 ap_refund)、vouch_type(48 / 49)、id(Ap_CloseBill.iID,找不到为 null)、code、line_ids(涉及的行 Ap_CloseBills.ID,取自自身冲减行的 iCoClosesID)、line_id(只涉及一行时即该行,否则 null)
targets 被核销单据,按(类型、单号、行)合计:type(sale_invoice、ar_bill、purchase_invoice、ap_bill;对方是另一张收付款单时 ar_receipt / ap_payment / ar_refund / ap_refund;其余为 null)、vouch_type(cCoVouchType 原值)、id(找不到为 null)、line_id(发票行 iBVid,应收应付单整单核销为 null)、code、amount
amount targets 的 amount 合计
gl_voucher、voucher 是否已制单(有行带 cPZid);已制单时 voucher 为 {"id","sign","no","date"}(cPZid、cGLSign、iGLno_id、dPZDate),否则 null
cancellable、reason 能否用 arap/writeoff/cancel 取消;不能时 reason 是取消核销会返回的原因,否则 null

金额是原币、两位小数:应收取被核销单据一侧的贷方减借方(iCAmount_f),应付取借方减贷方(iDAmount_f),与取消核销加回的金额相同。

cancellable 与取消核销用同一套判断,顺序和消息相同:超过 500 行、不是一张收付款单对单据的核销、已制单、涉及合同、外币、跨期间、收付款单或单据找不到、采购发票被网络锁定、期间已结账、之后还有其他处理(同取消核销,见 §12)、应收一侧账套里有未审核的收款单。只读判断不加锁,结果是查询时刻的快照,取消时桥在事务里带锁重查。

数据权限按客户或供应商(cDwCode),越权的批次不列。

fa_changes 固定资产变动单#

列出固定资产变动单(fa_Vouchers:原值增加 / 减少、计提减值准备、部门转移、使用状况调整等),一张一行,按变动单号排序。U8 每做一次变动,卡片新增一个版本(fa_Cards 一行),变动单记录变动前后的值和两个版本号;卡片在某一天的状态用 archives/get 的 fa_card(§15)。

字段 说明
fiscal_year 固定资产的业务年度:按变动日期 dTransdate 的年份,缺省登录年度。不是账套库年度(请求的 year):一个账套库里常有多个业务年度的固定资产数据
period 变动期间 iTransPeriod,1 到 12,缺省全年
card 卡片编号(fa_card 的 code)
code 变动单号
change_type 变动单类型 iVoucherType(1 到 99,如 1 原值增加、11 计提减值准备),名称见响应的 change_name
after、limit 翻页,limit 1 到 1000,缺省 200

响应 {"ok":true,"fiscal_year","items","next"}。每项 code、card_code、asset_name(变动后版本的名称)、opt_id(变动后的卡片版本 lOptID)、pre_opt_id(变动前版本)、change_type、change_name、before_value、after_value(变动前后内容,文本)、reason(最多 1000 字)、change_date、period、operator(经手人)、currency、exchange_rate、site_after、keeper_after、effective(当期生效 bAct)、gl_sign、gl_num(凭证类别字、凭证号,未制单为 null),以及 depts(fa_Vouchers_Detail:dept_code、dept_name、before_value、after_value)。没有固定资产的账套返回空列表。会计期间不按自然月划分的账套未实测。

fa_depreciation 固定资产折旧#

按卡片和期间列出已计提的折旧。U8 折旧表 fa_DeprTransactions 一张卡片一年一行、十二个月各一列,这里按该年度已计提的期间(fa_DeprList)展开,未计提的期间不出现;本年录入的卡片从录入期间起列,年中减少的卡片减少之后的期间不列。

字段 说明
fiscal_year 固定资产的业务年度(折旧表的 iyear),缺省登录年度;不是账套库年度
period 只要这一期,1 到 12,缺省全部已计提期间
card 卡片编号
nonzero true 时去掉当月折旧为 0 的行,缺省 false
after、limit 翻页,limit 1 到 1000,缺省 200

响应 {"ok":true,"fiscal_year","posted_periods","items","next"}。posted_periods 是该年度已计提的期间(升序)。每项按卡片编号、期间排序:card_code、asset_num(sDeprAssetNum)、asset_name(卡片最新版本的名称)、period、depr_date、amount(当月折旧 dblDepr<期间>)、accumulated(当月末累计折旧 dblDeprT<期间>,与 fa_card 同期的 accumulated_depreciation 同源)、rate(月折旧率,六位小数)、month_value(月初原值)、depr_months(月末已计提月份)、used_months(月末已使用月份)。

fa_changes、fa_depreciation 的数据权限:部门受控、操作员不是账套主管也不是部门的数据权限管理员时,按卡片使用部门过滤——卡片全部版本的全部使用部门(fa_DeptScale)都在授权内、且至少有一个使用部门,卡片的行才出现(部门转移过的卡片要转出、转入两边都有权限)。变动单另要求部门明细上的非空部门都在授权内。越权的行不出现,照常 200。卡片档案 fa_card 的 archives/list 同样过滤,archives/get、get_many 对越权卡片 403「没有该档案的数据权限」(卡片不存在仍 404)。

20. 幂等键#

写路由可以带幂等键:网络中断、超时之后用同一个键重发,U8 里只执行一次。全部写路由都支持(§3 表里标「写」的,含专用审核路由 sale-orders/verify、dispatches/verify);读路由带幂等键 400「该接口不支持 Idempotency-Key」。写路由名单每层只有一份:桥是写闸门的写路由表,API 是权限表里的写动作,MCP 是 routes.json 里 access 为 write 的路由,客户端是 WRITE_ROUTES。

层 写法
API 请求头 Idempotency-Key,只能出现一次。API 把它转成桥请求体的 idempotency_key,并加上 caller = <信任项名>:<客户端>(超过 200 字符时换成 sha256:<摘要>)
桥 请求体字段 idempotency_key,可选 caller(1 到 200 个字符,不含控制字符),都在签名的请求体里
客户端 client.keyed(键) 返回带键的副本;create_voucher、generate_voucher、gl_create、arc_create 另有 idempotency_key 参数;命令行全部写命令都有 --idempotency-key(见 docs/getting-started.md)

键是 1 到 128 个可见 ASCII 字符(! 到 ~,不含空格)。不带键时没有幂等记录。

记录的定位是 caller + 账套 + 路由 + 键:不同调用方、账套、路由用同一个键互不影响。直接调桥不带 caller 时一律记为 direct,这些调用方共用一个命名空间;多个直接调用方并存时各自带不同的 caller,或给键加前缀。

内容摘要:除 password_enc、date、idempotency_key、caller 以外的整个请求体(含 year、operator),按键排序的规范 JSON 的 SHA-256。口令每次加密都不同,登录日期只决定登录上下文(API 缺省填当天,过零点重发也算同一请求),所以不参与比较;单据自己的日期在 head 里,照常参与。

同一个键再次到达时 桥的响应
内容摘要不同 409 idempotency_mismatch,不执行
第一次已成功 校验本次登录后原样返回第一次的 HTTP 状态和响应体,不再调用业务组件
第一次结果未知(500、504 outcome_unknown、除下一行以外的 503,或服务在执行中中断) 同样校验登录后原样返回,不再调用 U8。先用 load、list、gl/vouchers/load、archives/get 核对
第一次以 4xx 结束(字段不合法、单据不存在、state_mismatch、workflow_enabled、u8_rejected、登录失败、无权限、busy 等),或 503 busy_timeout、stopping、u8_license_full、u8_license_hold、ia_timeout,以及写入策略拒绝的码(503 write_policy_unavailable、write_frozen、write_window,429 write_quota,§18) 不占用键,记录删除;修正后可用同一个键重发,照常执行
第一次还在执行(同一进程) 等第一次的结果,最多 75 秒:成功或结果未知则校验登录后同样返回;第一次没占用键则本次接着执行;仍在执行则 504 outcome_unknown。不会同时发起第二次 U8 调用

查询结果 idempotency/get#

读路由。收到 504 outcome_unknown 或连接中断后,先按幂等键查第一次的结果,再决定是否重发。登录照常校验(登录子系统跟原路由走:/u8co/v1/gl/ 下的路由按 GL,其余按 AS),不调用业务组件、不进写闸门、不加单据锁。

记录绑定操作员:只有第一次请求的 U8 操作员查得到(去空格、不分大小写),其他操作员(即使同一令牌、同一账套)得到 found: false。

API 请求(公共字段之外):

字段 说明
path 第一次请求的 API 路径,须是写路由,如 /v1/co/vouchers/create、/v1/co/gl/vouchers/void、/v1/co/arap/writeoff;读路由 400(field 为 path)
key 第一次请求头 Idempotency-Key 的值

API 按与第一次请求相同的规则算出 caller,转给桥 route(桥路径)、idempotency_key、caller,所以只有同一信任项、同一客户端查得到自己的记录。直接调桥时请求体是 route(写路由的桥路径,否则 400、field 为 route)、idempotency_key、可选 caller(缺省 direct)。

响应:

{"ok": true, "found": true, "state": "ok", "status": 200, "created_utc": "2026-09-29T08:00:00Z",
 "response": {"ok": true, "type": "sale_order", "id": 9000000004, "code": "0000000004"}}
字段 说明
found 记录在不在。没有或已过期是 {"ok":true,"found":false},HTTP 200
state ok(第一次成功)、outcome_unknown(结果未知,要按业务内容核对)、in_flight(第一次还在执行)
status 第一次请求的 HTTP 状态。经 API 时是 API 会返回的状态(桥的 500 对应 502 等)
created_utc 第一次请求到达的时间(UTC)
response 第一次的响应体,in_flight 时没有。经 API 时非 2xx 的响应换成 API 错误体 {"error":{…}},码和状态的对应同 §18

found: false 不等于「没有写入」:第一次请求没带幂等键、或以不占用键的结果结束时也查不到。state 为 outcome_unknown 时仍要按业务内容核对。客户端命令:idem-get。

21. 字段元数据 meta#

API:GET /v1/co/meta(读权限)。桥:POST /u8co/v1/meta,照常 HMAC 签名,请求体为空或 {},其他字段 400「含未知字段」;不带 acc、year、operator、password_enc、date。桥不登录 U8、不进工作队列,在 HTTP 线程上直接返回,只读进程内的表和 U8 安装目录下的 RsXml,不调用 COM。客户端命令:meta(不读口令)。

内容由桥按自己的校验表生成(可写字段直接取自各领域的白名单判断),API 不另存;API 请求模型里的 Literal 只是便利,以 meta 为准。

字段 说明
version 元数据格式版本,现为 "1"
revision 除 features 外全部内容的规范 JSON(键按序数排序)的 SHA-256,十六进制小写。内容不变则不变,可用来判断是否需要重新生成调用方的字段表
complete 档案标签是否全部读到。某个档案的 RsXml 读不到时为 false,该档案 tags、writable 为 null,另带 tags_error
kinds 单据类型,见下
archives 档案类型:name、root(EAI 根标签)、rs_file、table、key、name_col、need_template、read_only(只能 get、list,writable 为空数组)、deletable(project 为 false)、block(不能写的标签,另有公共的 code、CreatePerson、ModifyPerson、ModifyDate)、private(get 照常返回但不从模板复制)、tags(RsXml 全部标签)、writable(tags 去掉不能写的)。没有 RsXml 的只读档案 tags 为 null、不带 tags_error;project 的 tags、writable 固定为 name、bclose、citemccode
gl 总账凭证:head、line、cash_flow 字段名,required_head、required_line,lines_min 2、lines_max 200、cash_flow_max 50
list_kinds vouchers/list 支持的类型
routes 桥的全部路由(取自分派表,另加 login-check 和 meta),按路径排序:path、keys(请求体允许的顶层字段,含公共字段;为 null 表示分派表和字段表不一致,应当报告)、optional(keys 之外的可选字段:写路由的 idempotency_key、caller(§20)和 dry_run(§23,两条专用审核路由除外;arap/writeoff/auto 的 dry_run 在 keys 里))
field_refs 写字段名(小写)到档案类型的映射,例如 ccuscode → customer、cinvcode → inventory、cwhcode / cowhcode / ciwhcode → warehouse。用于把名称解析成编码时选档案(§24)
gl_field_refs 总账分录键到档案类型:account → account、dept → department、person → person、customer → customer、supplier → vendor、item → project、settle → settle_style、currency → currency、sign → voucher_sign
dry_run_routes 单据路由以外的写路由的预演模式(§23),例如 {"gl/vouchers/create": "validate", "archives/create": {"project": "rollback", "*": "validate"}, "arap/writeoff": "rollback"};值是模式名,或按档案类型分的对象(* 为其余类型)。不在表里的路由不支持预演
features 运行时自检结果(例如 COM 签名自检 signatures),可能随时变化,不计入 revision

kinds 每项:name、title、family、sub_id、verify_sub、tables(head、id、code、body、body_fk、line_id、verifier、verify_date)、ops(布尔值:create、update、delete、verify、close、workflow、generate、lock(只有销售订单为 true)、arap_verify / arap_unverify(能做应收应付审核、弃审的类型)、writeoff、writeoff_cancel、writeoff_auto(参与核销的收付款单、发票、应收应付单)、arap_voucher(能制单的六种类型,§12))、sources(生单来源,第一个是缺省)、blocked(任何写操作都不能填的字段,小写:全局名单加该类型的主键、单号、审核人、审核日期列)、dry_run、writable:

缓存:桥在所有档案标签都读到后把结果缓存到进程结束(RsXml 按文件缓存,U8 安装变更后要重启桥);API 在进程内缓存成功结果 60 秒,失败不缓存;缓存过期时同时到达的请求只调一次桥,其余等待(最多 100 秒,超时 503 unavailable)。桥返回 504 outcome_unknown 时 API 改报 503 unavailable(meta 只读,可直接重试)。

22. 操作员权限#

读路由按调用的 U8 操作员检查权限,效果与 U8 客户端一致:先查功能权限,再按数据权限(记录级)过滤,最后按字段权限把不可见的列置空。meta、健康检查、login-check 不查权限。写路由的权限见各写路由小节(总账写 §14 查 GL0201–GL0204,生产订单关闭和打开、销售订单和采购订单锁定解锁 §10,应收 / 应付核销、制单 §12,物料清单写入 §6–§9,档案写入 §15)。

功能权限。 读 UFSYSTEM..UA_HoldAuth:操作员本人(iIsUser=1)或所属角色(UA_Role,不做角色继承)持有该功能 id。年度窗口:请求的 year(账套库年度)或账套的建账年度(UFSYSTEM..UA_Account.iYear)——U8 的业务授权挂在建账年度下,所以登录新年度的库也按建账年度的授权判断;登录日期不参与。账套主管(持有 admin / Admin)只看本账套不晚于请求年度、最近一个有 admin 行的年度(某年收回的主管不会因早年的行仍算主管)。账套主管的功能与数据权限都不受限。

每个读路由(单据类型、档案、报表)可接受的功能 id 登记在桥的 PermRegistry*.cs,任一即可;读取和列表用同一组 id。例如销售订单 SA03010104(查询)或 SA03010201(列表),现存量 ST020107_01,总账凭证 GL0202 或 GL0201,档案 AS011Q 或 AS011(客户),会计科目任一总账功能,物料清单 BO01001Q,其他报检单 QM02060101 或 QM030601,其他检验单 QM02060201 或 QM030603,采购结算单 PU040305,出入库调整单(ia_adjust)入库调整单 IA1001 / IA02040201 或出库调整单 IA1004 / IA02040301,存货调价单 SA03120202 或 SA0312020301。没有时 403 no_permission「没有<功能名>权限」(如「没有销售订单查询权限」)。不带 type 的 workflow/tasks 只列操作员自己的待办,登录成功即可。登记的 id 已与 U8 授权目录(UA_Auth、UA_Menu)逐个核对含义,未在 U8 客户端逐个授权点验。

数据权限(记录级)。 只对账套里打开了「数据权限控制」的业务对象生效(AA_BusObject_base.bAuthControl=1)。开关打开时,账套主管和该对象的数据权限管理员(AA_holdBusobject.iAdmin=1)不受限;其他人只能看到 AA_HoldAuth 里授了查询(cFuncId 含 R)的编码,一个都没授就什么都看不到。受控对象:客户、供应商、部门、人员(授权行在 person 或 hr_hi_person)、仓库、存货、会计科目、项目(大类 + 编码)、销售类型、采购类型、收发类别、凭证类别。user 对象(制单人)在 U8 里管删改他人单据,读取不按它过滤。

会计科目(code)只在总账选项「明细账查询权限控制到科目」(bQryCtlSubj)打开时生效,管科目余额表、辅助余额表、明细账、经营管理损益,以及总账凭证的 gl/vouchers/load、list、digest、attachments/list:整张凭证的全部分录科目都在授权内才可见(U8 客户端是否逐张按科目控制未核对,取较严口径)。总账凭证不按「查询他人凭证控制到操作员」(bFindVouchCtrl)过滤;科目档案、应收应付单上的科目不按科目权限过滤。

情形 列表(vouchers/list、archives/list、stock/current、gl/vouchers/list、报表) 读取单张(vouchers/load、archives/get、gl/vouchers/load、workflow/state、history)
表头对象不在授权内 这一行不出现,200 403 no_permission「没有该单据的数据权限」(档案是「没有该档案的数据权限」)
受控列为空 这一行不出现(本来可为空的列除外:如采购入库单上的客户,采购、库存单据的业务员,收付款单与应收应付单的部门和业务员) 403
存货、表体仓库:表体一行都不在授权内 单据不出现 403
存货、表体仓库:部分行在授权内 单据出现 整张返回全部行(同 U8 卡片)
调拨单 调出、调入两个仓库都要在授权内 同左,否则 403
单据不存在 — 404

字段权限。 读 AA_ColumnAuth:只认字段权限开关已打开的对象(AA_BusObject_base 里 iAuthType=1、bAuthControl=1;记录级是 iAuthType=0),cFuncID 含 N 的行是「不能查看」。U8 是拒绝清单:没有行即可见。本人的拒绝与所属角色的拒绝取并集;本人在同一对象、同一字段上有不含 N 的行时角色的拒绝不算;本人已拒绝时角色放不开。账套主管不受限;对象的数据权限管理员(iAdmin,只管记录级)不免遮。

读路由成功(200)之后桥统一遮一次:拒绝的字段置为 null(行、单据照给,不 403),响应体加 masked_fields(本次响应里出现并被置空的字段名,排序去重;没有则不带)。字段名不分大小写比对,去掉 B;、T; 这类前缀,报表对象的中文列名(如「原币无税金额」)换成物理列名。

范围 U8 字段权限对象(cKey)
purchase_in、purchase_settle 24(采购入库单列表)及采购入库明细报表对象
arrival、purchase_return 26(到货单列表)
purchase_order、purchase_requisition;reports/order_execution 的 type=purchase_order 88(采购订单列表)
other_in、other_out、sale_out、product_in、material_out 0301、0302、0303、0411、0412
transfer、transfer_request;shape_change 0304;0305
dispatch、sale_return、sale_return_apply 01、VCH_01、dispatchpriceref、SARefDispB
stock_opening、stock_check、ia_adjust、inventory_price_adjust;reports/opening_balance 的 module=stock 出入库单列表的并集(24、0301、0302、0303、0411、0412)
reports/mgmt/sales 0303:遮 cogs、gross、gross_pct,收入、数量照给
reports/mgmt/cash_stock 只遮 purchases 段(24)和 inventory 段(出入库单并集)
应收应付、票据、总账、档案、perm/*、写路由 不遮(U8 没有对应的字段权限对象)
上表没有的单据类型(如 sale_order、sale_invoice、purchase_invoice、生产、质量单据) 从严:操作员在任一对象上拒绝的字段名,出现在响应里就置空(不展开金额组)

缓存。 读路由按(账套、请求年度、登录年度、操作员)缓存权限快照(含字段权限)60 秒,最多 256 条;该操作员登录失败时清掉。U8 里改了授权或开关,读路由最多 60 秒后生效;写路由的权限检查(总账写、生产订单关闭和打开、销售订单和采购订单锁定解锁、档案写入)每次现读。某个对象的授权超过 100 个编码时,列表改用 AA_HoldAuth 的实时条件,单张读取、档案读取和物料清单也实时查。

校验先于权限。 请求字段不合法(缺类型、档案类型写错等)返回 400,不会变成 403。

权限快照 perm/snapshot 与权限评估 perm/evaluate#

两条只读路由给出读路由过滤用的同一份权限快照(同一个 60 秒缓存),供下游按人员过滤(如审批应用的档案选择)。只跑 SQL,走读线程池;响应不含口令和档案名称。

响应(evaluate 另带 subject,operator 是被查询的操作员):

{
  "ok": true, "acc": "998", "year": 2026, "acct_year": 2026, "operator": "op001",
  "supervisor": false, "gl_subj_ctl": false,
  "roles": ["R01"], "functions": ["AS011Q", "SA03010104"],
  "objects_on": ["code", "customer", "user"], "data_admin": [],
  "data": {
    "customer": {"codes": ["C900001", "C900002"]},
    "fitem": {"all": true},
    "warehouse": {"all": true}
  },
  "columns": {"0303": ["iPrice", "iUnitCost"]},
  "ttl_s": 60,
  "fingerprint": "<64 位小写十六进制>"
}

23. 预演 dry_run#

写路由的请求体可以带 dry_run: true:桥照常登录、检查、加锁,走到写库那一步为止,不写入,返回「如果真做会是什么结果」。不带或 false 是正常写入(API 只在 true 时才把这个键转给桥)。用于在真正写入前核对字段、编码和金额,尤其适合 AI 代理。

两种模式#

模式 做法 能说明什么
rollback 桥在自己的事务里真的调用 U8 业务组件或执行 SQL,在同一连接上读出事务里的新单据(或改后的单据),然后回滚 高:U8 自己的校验、编号、金额计算都跑过了,返回的 docs 就是 U8 会存下的样子
validate U8 组件自己提交、桥的事务管不住(凭证导入、档案导入、U8 API 框架、审批服务等)。桥把调用组件之前的全部检查照做,停在调用之前 中:桥的检查都过了,但 U8 组件保存时自己的检查(必输项、结构完整性等)没有跑,真做时仍可能被拒绝

arap/writeoff/auto 的 dry_run 是第三种 plan:只出配对计划(§12),响应带 mode: "plan"。

各路由的模式#

路由 rollback validate
vouchers/create、update、delete、verify、close、lock、generate 除右列以外的全部单据类型和操作,包括:生产订单的关闭、打开;报检单(qm_*_inspect)的生单;期初结存单(stock_opening)的删除、审核、弃审;供应商退款、客户退款、无来源销售出库、采购手工结算、红冲蓝字发票、参照退货申请单生成退货单 期初结存单的新增(EAI 导入);生产订单的新增、修改、删除、审核、弃审;物料清单的全部写操作;检验单(qm_*_check)的生单、删除;不良品处理单(qm_*_reject)的生单、审核、弃审、删除;报检单的删除(含删除前的弃审);产品报检单(qm_product_inspect)的弃审;其他报检单(qm_other_inspect)的新增、审核、弃审、删除;其他检验单(qm_other_check)的生单、审核、弃审、删除;退货申请单(sale_return_apply)的新增、修改、删除、审核、弃审
gl/vouchers/* void、unvoid、verify、unverify、sign、unsign、delete、unpost create、update、post、reverse
gl/transfer/pnl、gl/transfer/custom — 全部:停在凭证导入之前,分录在 detail.transfer
archives/create、update、delete 项目(project)、客户和供应商银行账户(customer_bank、vendor_bank)的新增、修改、删除;币种、凭证类别、汇率、供应商联系人(currency、voucher_sign、exchange_rate、vendor_contact)的修改、删除 其余走 EAI 的档案(含原因码 reason);币种、凭证类别、汇率、供应商联系人的新增;客户联系人(customer_contact)
workflow/* 写操作 — submit、withdraw、approve、disagree、return、abandon、resubmit
arap/* writeoff、writeoff/cancel、voucher/delete voucher:桥算完分录、停在凭证导入之前,计划的凭证在 detail 里
openings/post post、unpost —
openings/arap create、delete、verify、unverify —
periods/close close、reopen(含 through) —
ia/post、ia/period_end post、unpost;run、cancel —
arap/writeoff/auto — —(plan,见上)

intercompany/generate_buyer(仅 API)缺省就是预演,模式同买方的 vouchers/generate。

权威的表在桥里(DryRunModes),经 meta 公开:单据看 kinds[].dry_run,其余看 dry_run_routes(§21)。表里没有的组合在登录之前拒绝,400「该操作不支持预演」。sale-orders/verify、dispatches/verify 两条专用审核路由不支持预演:经 API 时是 400「请求参数无效:dry_run」(field 为 dry_run),不到桥;直接调桥是 400「旧路由不支持预演,请用 vouchers/verify」。

响应#

预演成功是 HTTP 200,桥和 API 的形状相同:

{
  "ok": true,
  "dry_run": true,
  "mode": "rollback",
  "route": "vouchers/create",
  "type": "sale_order",
  "action": "create",
  "docs": [
    {"type": "sale_order", "id": 9000000004, "code": "0000000004", "state": "exists",
     "head": {"ccuscode": "C900001", "ddate": "2026-09-29", "cstcode": "01"},
     "lines": [{"autoid": 9000000101, "cinvcode": "A01", "iquantity": 5.0, "itaxunitprice": 11.3, "isum": 56.5}],
     "lines_total": 1}
  ],
  "warnings": ["number_may_skip", "locks_held"],
  "message": "预演完成,已回滚,没有写入"
}
字段 说明
dry_run、mode 恒为 true;rollback 或 validate
route、type、action 预演的路由(不带前缀)、单据类型、操作
docs 受影响单据在事务里的样子,最多 10 张:先是请求的 type / id 那张(生单时是来源单据),之后是新单据和其他受影响单据。state 是 exists(新建、修改、审核后的样子)或 deleted(事务里已删,没有 head、lines)。head、lines 是表头表、表体表的整行(SELECT *),列名小写,去掉空值和二进制列(ufts 等),数字是 JSON 数字,日期时间为 0 点时写成 yyyy-MM-dd、否则 yyyy-MM-ddTHH:mm:ss,字符串去掉右侧空格。每张最多 200 行,lines_total 是实际行数。注意这是表列,与 vouchers/load(U8 行集、值为字符串)写法不同。全部映像超过约 4 MiB 时去掉各单的 lines(保留 lines_total),detail.truncated 为 true
detail 各路由的补充和提醒,见下表;没有内容时不出现
warnings number_may_skip(rollback 的新增、生单:U8 在预演中取过的单号可能不退回,真做时号码可能跳一个)、validate_only(validate 模式:U8 保存时自己的检查没有跑)、locks_held(rollback 总有:预演期间持有与真写相同的锁)
message 中文说明:rollback「预演完成,已回滚,没有写入」;停在组件之前的 validate「预演完成:只做了提交前的校验,没有调用 U8 组件,没有写入」;在桥事务里算完再停的 validate(如 arap/voucher)「预演完成(校验模式),已回滚,没有写入」;没有改动「预演完成:没有需要写入的改动」。程序不要按文字判断

validate 模式不产生新单据,新增、生单的 docs 是空数组;对已有单据的操作 docs 可能带上它当前已提交的样子(state: "exists")。rollback 模式下没有需要写入的改动(例如再锁定一张已由本人锁定的销售订单)时,detail.no_change 为 true,docs 是单据当前的样子。

detail 的键:

键 出现在 含义
stopped_before validate 停在了哪个组件调用之前,如 U8PzInsert.Transact、GlPostTx.VouchPostAll、U8API MOrderAdd、UFQMCo.VoucherOperate(add)、AuditServiceProxy
gl 总账作废、审核、签字、删除等;arap/voucher/delete 操作后(事务里)的凭证:op、iyear、iperiod、csign、ino_id、lines、state
voucher 总账 create / update;arap/voucher 将要导入的凭证:op、iyear、iperiod、csign、ino_id(修改时)、date、maker、attachments、lines、lines_total
post 总账 post iyear、iperiod、poster、vouchers([{csign, ino_id}])、first_posting_checks: "not_run"(年度首张凭证的期初对账只有真做才执行)
transfer gl/transfer/* 将要生成的结转分录
archive 档案写入 archive、code、op;rollback 另有 after(事务里写后的记录)或删除时的 deleted: true
writeoff、writeoff_cancel arap/writeoff、arap/writeoff/cancel 与真做成功的响应同形(去掉 ok)
opening openings/post 与真做成功的响应同形(去掉 ok):module、action、posted(操作后的状态)、opening_year、start_date;存货核算另有 counts
periods periods/close 会结账(取消结账)的期间 [{module, fiscal_year, period}],按执行顺序;through 时可能是空数组;库存那几项带 stock_rows
stock_rows periods/close(单个库存) 库存快照会写入(取消结账:会删掉)的行数 {account, accounts, v, vs, check}(§31)
counts ia/post、ia/period_end 存货核算脚本在事务里算出的诊断计数,同真做成功的 counts(§32)
ia_counts periods/close(存货核算有数据的月份) 存货核算月末结账(取消结账)脚本的诊断计数(§31)
workflow 审批流写操作 action、code(单号)、state_before(调用前的审批状态)
input 生产订单、物料清单、检验单生单的 validate 桥规范化后的输入
unverify_first 质量单据删除 true:已审核的报检单,真做时先弃审再删(两步都由 U8 提交)
not_previewed 销售出库按行生单(带 lines) 预演只到整单 MakeOutVouch:docs 是整张发货单剩余数量生成的出库单,按行改回数量、批号和货位没有预演
no_change 任意 没有需要写入的改动
truncated 任意 映像太大,去掉了 lines
new_id_unknown 库存单据新增 新单据的主键没取到,docs 里没有这张新单
generated_unknown 库存单据审核、销售出库生单 连带生成的单据没读出来,不在 docs 里
preview_error 档案写入 事务里写后的档案记录没读出来,archive 里没有 after
docs_unavailable validate、no_change 已有单据的当前映像读不出来,docs 为空

最后几项提醒键出现时预演仍然成功(没有写入),只是 docs 不完整,应一并告知确认的人。预演中途失败是正常的错误响应,与真做时相同(例如 409 u8_rejected 带 U8 原文、400 带 field,§18),事务照常回滚。

规则#

预演与真做之间单据可能被他人修改,预演通过不保证真做成功;validate 模式只说明桥的检查通过了。

24. 名称解析 archives/resolve#

读路由。把名称(「甲公司」「示例存货 X1」)解析成写单据要用的编码:一次最多 20 项,按档案查出候选编码。权限同该档案的 archives/list:功能权限按每一项的档案类型查,记录级数据权限照样过滤(§22),越权的记录不会出现在候选里;任何一项的档案没有功能权限,整个请求 403 no_permission。

请求(公共字段之外):

{"items": [{"archive": "customer", "q": "甲公司"}, {"archive": "inventory", "q": "示例存货X1"}],
 "limit": 5, "include_disabled": false}
字段 说明
items 1 到 20 项 {archive, q}。archive 是能 list 的档案类型,但不收两列主键的类型(customer_address、customer_inventory、customer_bank、vendor_bank、customer_contact、vendor_contact、user_define)和 exchange_rate、fa_card;q 去掉前后空白后 1 到 100 个字符
limit 每项最多返回几个候选,1 到 20,缺省 5
include_disabled 缺省 false:停用的记录不参加匹配。true 时参加,候选上标 disabled: true

匹配分五档,按顺序找,第一档有命中就停,同档内按编码排序:

档 match 规则
1 code 编码完全相等(项目写 <大类>:<编码> 或只写编码)
2 name 名称完全相等
3 abbr 简称完全相等:客户 cCusAbbName、供应商 cVenAbbName
4 mnemonic、add_code 助记码完全相等(不分大小写):客户 cCusMnemCode、供应商 cVenMnemCode、存货 cInvMnemCode;存货代码 cInvAddCode(add_code)同一档
5 contains 名称包含 q;客户、供应商的简称包含 q;存货的「名称 + 规格」包含 q(直接相连或中间隔一个空格都算,所以「示例存货X1」能找到名称「示例存货」、规格「X1」的存货)

响应:

{"ok": true, "results": [
  {"archive": "customer", "q": "甲公司", "status": "exact",
   "match": {"code": "C900001", "name": "甲公司商贸有限公司", "match": "abbr"},
   "candidates": [{"code": "C900001", "name": "甲公司商贸有限公司", "match": "abbr", "abbr": "甲公司"}],
   "more": false},
  {"archive": "inventory", "q": "示例存货X1", "status": "partial",
   "match": {"code": "A01", "name": "示例存货", "match": "contains"},
   "candidates": [{"code": "A01", "name": "示例存货", "match": "contains", "spec": "X1", "unit": "01"}],
   "more": false}
]}
字段 说明
status exact:第 1 到 4 档恰好一个命中,可以直接用;ambiguous:命中的那一档不止一个,需要挑选;partial:只有第 5 档命中且恰好一个,建议确认后再用;none:没有命中
match 只在 exact、partial 时有:选中的 code、name 和命中的档
candidates 命中那一档的前 limit 个;none 时为空数组。每个候选 code、name、match,有值时另带 abbr、spec(存货规格 cInvStd)、unit(存货主计量单位 cComUnitCode)、class_code(分类)、disabled
more 命中那一档超过 limit 个

停用的判断:客户、供应商 dEndDate、存货 dEDate、部门 dDepEndDate、仓库 dWhEndDate 不晚于登录日期;会计科目 bclose = 1(科目另外只取末级 bend = 1);项目 bclose = 1;操作员已停用。没有这类列的档案不排除。会计科目按登录日期的年份(会计年度)查,同 archives/list。

写单据时字段该查哪个档案,看 meta 的 field_refs 和 gl_field_refs(§21)。客户端命令:resolve。

25. 裁剪响应 fields、compact#

仅 API。每个 /v1/co/* 的 POST 路由都收两个查询参数,用来减小响应体:

参数 说明
fields 逗号分隔的键名,最多 100 个,每个是 [A-Za-z0-9_]+,可带前缀 head.、lines.、items.、fields.、docs.head.、docs.lines.。不分大小写
compact 布尔,缺省 false。true 时去掉值为 null、空串(去掉空白后)、[]、{} 的键;0 和 false 保留

两者只作用在自由形态的容器上:head(对象)、lines(对象数组)、items(对象数组)、fields(archives/get 的对象)、预演的 docs[].head / docs[].lines。信封上的键(ok、type、id、code、next、watermark 等)永远不删。

例:POST /v1/co/vouchers/list?fields=id,code,cus_code,doc_date&compact=true。

26. 字段标签 meta/fields#

读路由,要登录;除能登录外不查功能权限,不进写闸门。meta(§21)只给字段名;中文名、类型、必填、枚举值取决于账套自己的单据模板(各账套会改自定义项名称、加必输项),所以由本路由按账套现查。标签全部现查,只有总账凭证的标签是固定的。

请求(公共字段之外),type、archive、gl 三选一:

字段 说明
type 单据类型(同 vouchers/load)
op 只配合 type:create(缺省)、update、generate
source op 为 generate 时必填:来源单据类型;其他情况不能给
archive 档案类型
gl true:总账凭证

单据的响应:

{"ok": true, "type": "sale_order", "op": "create", "vt_id": 95, "card": "17", "vt_source": "card_default",
 "head": [{"name": "ccuscode", "label": "客户编码", "type": "string", "required": false, "max_length": 20},
          {"name": "cbustype", "label": "业务类型", "type": "enum", "required": true,
           "enum": [{"code": "普通销售", "name": "普通销售"}]},
          {"name": "cdefine1", "label": "表头自定义项1", "type": "string", "required": false, "max_length": 20}],
 "lines": [{"name": "iquantity", "label": "数量", "type": "decimal", "required": true}],
 "fields_revision": "…"}

(标签、模板号为示意,实际取自账套。)

档案(archive)的响应是 {"ok", "archive", "fields": [...], "fields_revision"}:字段名是 meta 的 archives[].writable 标签;label 按标签 → 表列 → U8 列字典(AA_ColumnDic_base.cCaption)现查,取不到为 null;type 为 null,没有枚举;required 是桥新增时要求的标签(名称,以及开户银行的账号、所属银行、币种,计量单位组的类型,货位的仓库,计量单位的计量单位组,客户和供应商银行账户的开户行,项目的项目大类)。只读档案 fields 为空数组。

总账凭证(gl: true):{"ok", "gl": true, "head", "lines", "cash_flow", "fields_revision"},字段名同 meta 的 gl(分录的 cash_flow 类型为 array),标签固定(凭证类别、日期、附件数;科目、摘要、借方、贷方、部门、人员、客户、供应商、项目大类、项目、结算方式、票据号、票据日期、币种、汇率、数量、现金流量;现金流量里的流量项目、借、贷),必填同 gl.required_head / required_line。

错误(400 bad_request,带 field):type / archive / gl 都没给或给了不止一个;单据类型、档案类型不认识(hint 指向 /v1/co/meta);该类型不支持这个操作(op);generate 缺来源、来源不对、非 generate 带了来源(source)。经 API 时这些组合先由请求模型检查,message 为「请求参数无效:…」。

客户端命令 meta-fields;MCP 的 u8_describe type=… / archive=… / gl=true 一并返回。

27. 单据查询 vouchers/search#

读路由。按条件找某类单据,与 vouchers/list(§16)同一套取数:相同的条目、相同的记录级数据权限(§22)、按主键续读。增量同步用 vouchers/list 的 changed_since,本路由不给 watermark。

请求(公共字段之外):

字段 说明
type 必填,同 vouchers/list 的类型
code_like 单据编号包含这段文字,1 到 40 个字符(%、_ 按字面匹配)
partner 客户或供应商编码;收付款单、应收应付单是往来单位(cDwCode)
dept、person、maker 部门、业务员、制单人
warehouse 表头仓库
inventory 存货编码:明细里有这个存货的单据(表头有存货列的类型按表头)
date_from、date_to 单据日期,yyyy-MM-dd,含两端
verified、closed 布尔:只要已审核 / 未审核、已关闭 / 未关闭
after 上一页的 next
limit 1 到 200,缺省 50
defines 表头自定义项条件,1 到 4 个键,见下

除 type 外都可省略。文字条件都是 1 到 60 个字符。该类型没有对应的列时 400「该单据类型不支持按 <字段> 搜索」,field 为该字段;不支持的类型 400,field 为 type。

defines:按表头文本自定义项找单据(例如录在销售订单表头自定义项 1 里的纸质合同号)。键是 define1–define3、define8–define14;define4、define6 是日期,define5、define15 是整数,define7、define16 是小数,不能按文本搜索。值的写法:

值 含义
"HT202609039" 或 {"eq": "HT202609039"} 规整后相等
{"like": "框架"} 包含(%、_、[ 按字面匹配)
{"prefix": "HT2026"} 开头是

规整:全角空格(U+3000)和不换行空格(U+00A0)换成半角空格,再去掉两端的半角空格;请求值和列值都这样处理后再比较(中间的全角空格同样当半角空格比)。其他空白字符原样保留。规整后的值 1 到 120 个字符,不含控制字符。多个键之间、与其他条件之间都是 AND。

响应 {"ok": true, "type", "items", "next"}:items 按主键排序,每项同 vouchers/list 的完整条目,有往来单位列的类型另有 partner_name;请求带了 defines 时每项另有 defines(只含请求里的键,值是表头上规整后的值,空为 null)。还有下一页时 next 是本页最后的主键。fields、compact(§25)作用在 items 上。

按合同号找销售订单:

{"acc": "801", "operator": "op001", "password": "...", "type": "sale_order",
 "defines": {"define1": "HT202609039"}}
{"ok": true, "type": "sale_order",
 "items": [{"id": 9000000002, "code": "0000000002", "doc_date": "2026-09-29", "cus_code": "C900001",
            "partner_name": "甲公司商贸有限公司", "verified": true, "closed": false, "...": "...",
            "defines": {"define1": "HT202609039"}}],
 "next": null}

客户端命令 search:--define define1=HT202609039(相等)、--define-like define10=框架、--define-prefix define1=HT2026,都可重复,同一个键只能给一次。

28. 批量读取 vouchers/load_many、archives/get_many#

读路由。一次读同一类型的几张单据或几条档案,整个请求只登录一次。

vouchers/load_many:请求 type、ids(1 到 20 个主键,不能重复)。经 U8 组件读取的类型(销售、采购、库存、应收应付的单据)在写线程池上逐张读、逐张持单据锁,一次最多 5 张,多了 400「该类型逐张用 COM 读取,一次最多 5 张」(field 为 ids);按 SQL 读取的类型(采购发票、生产订单、物料清单、报检单、检验单、不良品处理单)在读线程池上,最多 20 张。每张的读取和权限检查与 vouchers/load 相同。

archives/get_many:请求 archive、codes(1 到 20 个编码,不能重复,写法同 archives/get 的 code),只读数据库。

响应按请求顺序,每项是单张读取的响应体或失败项:

{"ok": true, "type": "sale_order",
 "items": [{"ok": true, "type": "sale_order", "id": 9000000002, "code": "0000000002", "head": {"...": "..."}, "lines": ["..."]},
           {"id": 9000000003, "error": {"code": "not_found", "message": "单据不存在"}}]}

archives/get_many 同形:{"ok", "archive", "items"},失败项是 {"code": "<编码>", "error": {"code", "message"}}。

客户端命令 load-many、arc-get-many。

29. 期初记账与期初单据 openings/post、openings/arap#

写路由。模块启用后须先做「期初记账」才能开展该模块的日常业务(例如采购未期初记账时 U8 拒绝保存采购发票)。openings/post 做采购管理期初记账(module=pu,U8 菜单 PU0206)和存货核算期初余额记账(module=ia)及其取消;openings/arap 录入应收应付期初单据。其他模块见 limitations.md。

第二级写入。 本节、§31、§32 的路由复现 U8 界面执行的 SQL(实测核对),属于第二级写入(limitations.md「写入分级」,配置见 configuration.md)。两道条件依次检查,含预演,都在登录 U8 之前:

字段校验(400)在这两道条件之前,任何账套的坏请求都是 400。健康检查的 replicated_writes 反映开关状态。这类写入用于测试账套;正式账套请在 U8 客户端操作。

请求(不带 type、id;公共字段之外):

{"module": "pu", "action": "post"}
字段 说明
module 必填。pu(采购管理)或 ia(存货核算),其他值 400(field 为 module,hint 列出支持的模块)
action 必填。post 期初记账,unpost 取消记账;其他值 400(field 为 action)
dry_run 可选,rollback 模式(§23):检查、改标志、再读都在事务里做,然后回滚,结果在 detail.opening

另收幂等键(§20)。

采购管理期初记账(module=pu)#

登录子系统 PU;功能权限 PU0206(记账与取消记账同一个 id,账套主管放行),没有时 403 no_permission。

采购期初记账只是一个标志:记账把 GL_mend 启用年度中启用月份之前各期(含第 0 期)的 bflag_PU 置 1,取消记账改回 0,与 U8 界面执行的 SQL 一致。启用日期取 AccInformation 的 dPUStartDate,启用年度、启用月份由它算出。

闸门(在请求连接的一个事务里以 UPDLOCK, HOLDLOCK 读 GL_mend 该年度各期,均为 409 state_mismatch):

改完在同一事务里再读第 0 期,不是目标状态则回滚,409 u8_rejected;提交后在新连接上回读,读不出或不对是 504 outcome_unknown(已提交,先用 reports/opening_balance 核对,不要直接重投)。

响应:

{"ok": true, "module": "pu", "action": "post", "posted": true, "opening_year": 2026, "start_date": "2026-01-01"}

posted 是操作后第 0 期的标志;opening_year 是启用年度,start_date 是采购管理启用日期。锁键 opening:pu,受全局写闸门约束。预演的 detail.opening 是上面这几个字段(posted 为操作后会是的状态)。

客户端命令:openings-post --module pu(取消记账加 --unpost;--dry-run、--idempotency-key 同其他写命令)。

存货核算期初记账(module=ia)#

对应 U8 存货核算「期初余额」的「记账」(从库存期初结存单取数、汇总、置标志)和「恢复」,脚本 co/bridge/sql/ia/qc_keep.sql、qc_recover.sql 在请求事务里整批执行。

响应另有 counts(脚本的诊断计数):

{"ok": true, "module": "ia", "action": "post", "posted": true, "opening_year": 2026, "start_date": "2026-01-01",
 "counts": {"st34_verified": 2, "subsidiary_m0_34": 2, "summary_m0": 2, "fifo_lines_qcass_skipped": 0, "gl_mend_p0": 1, "gl_mend_lt_start": 1}}

记账的计数:st34_verified 取数的期初结存单行数,subsidiary_m0_34 写入的第 0 期明细行数,summary_m0 第 0 期汇总行数,fifo_lines_qcass_skipped 先进先出 / 后进先出的期初行数(大于 0 时已 409),gl_mend_p0 第 0 期标志,gl_mend_lt_start 启用月份之前已置标志的期间数。取消的计数:summary_m0_deleted、subsidiary_m0_deleted、summary_item_m0_deleted、summary_m0_left(应为 0)、gl_mend_p0(应为 0)、bQCInput_true。锁键 opening:ia,受全局写闸门约束。预演的 detail.opening 同样带 counts。

客户端命令:openings-post --module ia(登录日期用 --date 给存货核算启用日期)。

应收应付期初单据 openings/arap#

写路由,第二级写入(见本节开头)。对应 U8 应收款管理、应付款管理「期初余额」中期初单据的录入(菜单 AR0306 / AP0306):新增、删除、审核、弃审。期初单据是 Ap_Vouch 中 bStartFlag=1 的应收单 R0 / 应付单 P0,只有表头(Ap_Vouchs 无行),单据日期为模块启用日期的前一天。新增、审核、弃审、删除走与 ar_bill / ap_bill 相同的 U8 组件(UFAPBO);普通的 vouchers/* 路由照旧拒绝期初单据。

请求(不带 type;公共字段之外):

{"side": "ar", "action": "create", "partner": "C900001", "amount": 1200.00, "account": "112201"}
{"side": "ar", "action": "verify", "id": 41}
字段 说明
side 必填。ar 应收、ap 应付,也决定登录子系统(AR / AP)
action 必填。create 新增,delete 删除,verify 审核,unverify 弃审
id delete、verify、unverify 必填:期初单据主键(Ap_Vouch.Auto_ID)。create 带了 400
partner create 必填:客户编码(ar)或供应商编码(ap),最长 20;启用日期前不能已停用
amount create 必填:原币金额,非 0、绝对值不超过 1000000000000、最多两位小数。负数表示反方向余额(应收为贷方,如预收;应付为借方,如预付):同 U8 存为正数,借贷方向 bd_c 取反
account create 必填:科目编码,须为启用年度、末级、本系统受控(应收 / 应付)的科目
department、person 可选:部门编码(末级)、业务员编码
digest 可选:摘要,最长 120;省略为「期初应收」/「期初应付」
currency、exch_rate 可选:币种名称,省略为本位币。本位币的汇率只能省略或为 1;外币必须给汇率,本币金额为 amount 的绝对值乘汇率、四舍五入到两位
dry_run 可选,rollback 模式(§23)

delete、verify、unverify 只收 id,带了 create 的字段 400。没有日期字段:单据日期固定为启用日期前一天。另收幂等键(§20)。功能权限 AR0306 / AP0306(账套主管放行),没有时 403 no_permission。锁键与 ar_bill / ap_bill 相同(新增 new:<类型>,其余 <类型>:<id>),受全局写闸门约束。

期初形态:U8 的期初单据在往来明细中是第 0 期,登记和审核日期为启用日前一天。桥在同一事务里审核成功后把本单的审核行改成这一形态,并把 Ap_Vouch.dVerifyDate 改为启用日前一天;弃审时先把本单审核行改回登录月,再由 U8 组件照常弃审。新增保存后在同一事务里核对 bStartFlag 已写入,否则回滚 409。

闸门(均为 409 state_mismatch,状态检查在请求连接的事务里):

档案检查(400):币种、部门(末级)、业务员、往来单位、科目不存在或不合要求。

响应同 ar_bill / ap_bill 的新增、审核、删除(§7、§6、§9),另带 side 和 opening: true;新增还带 start_date(启用日期)和 date(单据日期):

{"ok": true, "type": "ar_bill", "id": 41, "code": "0000000041", "state": {"verified": false, "verifier": "", "verified_at": ""}, "side": "ar", "opening": true, "start_date": "2026-01-01", "date": "2025-12-31"}

提交后回读不出是 504 outcome_unknown(已提交,先核对再重投)。预演返回 §23 的预演响应(action 为 opening_arap_<action>)。期初余额用 reports/opening_balance(module=arap,§19)核对。

客户端命令:openings-arap --side ar --action create --partner C900001 --amount 1200 --account 112201;--action delete|verify|unverify --id N(--dry-run、--idempotency-key 同其他写命令)。

30. 账套体检 reports/account_readiness#

读路由。检查新建或引入的账套能否用于写操作、缺什么、怎么补。十项检查只读目录、配置表和小表,不扫单据表,不写数据,正式账套上也可运行。补齐流程见 getting-started.md。

请求(不带 type、id;公共字段之外):

字段 说明
as_of 可选,yyyy-MM-dd。年度账、工作日历按这一天和服务器当天两个日期检查;缺省为登录日期 date

其他字段(含 fiscal_year、after、limit)一律 400。

登录子系统 SA(同 close_status)。date 不在任何已建年度内时 U8 登录失败(422 login_failed「不存在的年度」),到不了体检;此时用已有年度中的一天登录(例如起始年度的最后一天),体检仍按服务器当天(GETDATE())检查缺的年度。

功能权限:账套主管,或有总账「结账」GL1512 或「凭证整理」GL0202 的操作员,没有时 403 no_permission。不按记录过滤。审计动作 report_account_readiness。

登录和权限通过即返回 200,问题都在 checks 里,不报 409:

{"ok": true, "overall": "fail", "as_of": "2026-06-15", "server_today": "2026-06-15", "acc": "801",
 "checks": [
  {"id": "patches", "title": "账套补丁", "status": "warn", "detail": "账套库补丁记录 10 条,系统库 12 条",
   "fix_hint": "用 DBEnginSys.exe -all 只勾本账套重放补丁…", "docs_anchor": "getting-started.md#patches", "safe": true},
  {"id": "years", "title": "年度账", "status": "ok", "detail": "已建年度 2026–2026",
   "fix_hint": null, "docs_anchor": "getting-started.md#years", "safe": true},
  {"id": "calendar", "title": "工作日历", "status": "fail", "detail": "SYSTEM 日历没有日子",
   "fix_hint": "在基础档案中延长工作日历…", "docs_anchor": "getting-started.md#calendar", "safe": true}
 ]}

(示例只列三项;实际 checks 总是十项,顺序同下表。)

字段 说明
overall 各项中最差的一个:fail > unknown > warn > ok
as_of 实际检查的日期(请求的 as_of,缺省为登录日期)
server_today 数据库服务器的当天(GETDATE())
acc 账套号
checks[].id 检查项,见下表;也是 getting-started.md 中对应小节的锚点
checks[].status ok;warn(能用,但有缺省值或余量不足);fail(会让写操作失败);unknown(查不了,例如桥的 SQL 登录读不到 UFSYSTEM)
checks[].detail 只有计数、日期、缺的编号,不含业务数据
checks[].fix_hint 修复建议(中文一句);ok 时为 null
checks[].docs_anchor getting-started.md#<id>
checks[].safe 恒为 true:检查只读
id 查什么 不通过时
patches 账套库有 UA_PatchList,WFAudit 有补丁加的 signatureid 列;UA_PatchList 条数与 UFSYSTEM..UA_PatchList 比 fail:没有补丁表,或账套库 0 条而系统库有。warn:缺 signatureid 列,或账套库条数少于系统库(可能没重放完;系统库也记录只改系统库的补丁)。修:用 U8 的 DBEnginSys.exe -all 只勾本账套重放补丁
years UFSYSTEM..UA_Period 本账套未删除的年度覆盖 as_of 和服务器当天;detail 给出已建年度范围 fail:任一日期不在已建年度内。修:系统管理建立年度账
calendar bas_calendardetail 中 SYSTEM 日历(CalendarId=1)的最后一天 fail:表不存在、没有日子,或早于 as_of / 当天;warn:离当天不到 30 天。修:基础档案延长工作日历
yearly_config 按年度的配置表(GL_CashItemDataSource、Ap_InputCode、AP_OppCodeSet、AP_CtrlCodeSet、Ap_SStyleCode、code、GradeDef_Base 的科目编码级次、AccInformation_Year)在每个已建年度的行数;年度名单取 UA_Period,读不到时取 GL_mend fail:起始年度有行、之后某个不晚于 as_of 和服务器当年的年度为 0(detail 列出「表 年度」);为 0 的只有更晚的年度时 warn;只有一个年度时 ok。修:建立年度账会拷 code / GradeDef / AccInformation_Year;应收应付科目、现金流量取数、结算方式科目在 U8 对应设置中补齐
pu_opening 采购管理启用日期(AccInformation 的 dPUStartDate)与启用年度 GL_mend 第 0 期的 bflag_PU,同 reports/opening_balance fail:没有启用日期,或期初未记账。修:openings/post {"module":"pu","action":"post"}(§29)
vendor_extradefine 账套库有 Vendor_extradefine 表 fail:没有这张表时供应商档案写入失败。修:建空表 Vendor_extradefine(主键 cVenCode,先备份)
modules UFSYSTEM..UA_Account_sub(iYear=9999)中 SA、PU、ST、AR、AP、GL、QM、MO、BO 都有启用日期;IA 可选 fail:必需的子系统没启用;warn:只缺 IA。修:系统管理 / 企业应用平台的系统启用(没有 API)
prior_gl_close 同记账闸门(§14 post):取 as_of 与服务器当天中较晚的那天的年、月,查 GL_mend 该年 1 到 12 期的第一个未结账期间,以及上年度和更早年度的未结账月份 fail:第一个未结账期间早于上月(detail 如「本年 1–9 期总账未结账,本月凭证不能记账」)、本月已结账,或本月是 1 月而上年度有未结账月份;warn:只差上月没结账(月初的正常时间差),或本月能记账、但更早年度还有未结账月份,或 GL_mend 没有该年度。修:按顺序在 U8 里结账,或在测试账套上用 periods/close 的 through 逐月结到上月(hint 给出具体的 fiscal_year、period;§31)
workflow 来料检验单(QM03)、产品检验单(QM04)各有启用的审批流(Table_WorkFlowRelease Status=0,判断同 §13);登录操作员在 UserHrPersonContro 中对应了人员 fail:缺任一项。修:在 U8 审批流设计器发布;在 U8 中为操作员关联人员
defaults 本位币(foreigncurrency.iotherused=-1)、缺省采购类型(PurchaseType.bDefault=1)、末级收发类别收、发各至少一个(Rd_Style)、单据编号规则(VoucherNumber) fail:没有本位币;warn:缺其余任一项。修:档案接口 currency、purchase_type、rd_style(§15),编号规则用 U8 单据编号设置

读 UFSYSTEM 的三项(patches 的系统库条数、years、modules)用请求连接的三段式名称,与权限快照(UFSYSTEM..UA_HoldAuth)同一个登录;读不到时该项 unknown,fix_hint 提示给桥的 SQL 登录授予 UFSYSTEM 的 SELECT。其他项查询出错同样只让该项 unknown。整个体检约十几条小查询,与其他报表共用 75 秒的期限。

ok 只说明这十项条件具备,不保证所有写操作都能成功。

31. 月末结账 periods/close#

写路由,第二级写入(§29 开头)。

总账记账只能记本年第一个未结账期间(§14 post),新建账套从起始年度起各月未结账时本月凭证无法记账(体检项 prior_gl_close,§30)。采购、销售、应收、应付、总账的月末结账改的是 GL_mend 该模块该期的结账标志(bflag、bflag_PU、bflag_SA、bflag_ST、bflag_IA、bflag_AR、bflag_AP);桥做完下列检查后改标志,库存和存货核算另写月结数据。

请求(不带 type、id;公共字段之外):

{"module": "gl", "fiscal_year": 2026, "period": 9, "action": "close"}
{"action": "close", "through": true, "fiscal_year": 2026, "period": 9}
字段 说明
module pu 采购、sa 销售、st 库存、ia 存货核算、ar 应收、ap 应付、gl 总账。其他值 400(field 为 module,hint 列出可用值)。through 为 true 时可省略(给了也须合法,不使用)
fiscal_year 必填,会计年度(4 位整数,GL_mend.iyear)。与公共字段 year(账套库年度)无关
period 必填,1 到 12。第 0 期(期初)不收,期初记账见 §29
action 必填,close 结账,reopen 取消结账
through 可选布尔,只能和 close 一起用。按 U8 的结账顺序(采购、销售 → 库存 → 存货核算 → 应收、应付 → 总账),把各已启用模块从 GL_mend 最早年度起到 fiscal_year 年 period 期为止的每个未结账期间逐个结账
dry_run 可选,rollback 模式(§23):检查、改标志、再读都在事务里做,然后回滚;会结账的期间在 detail.periods

另收幂等键(§20)。已启用模块取 UFSYSTEM..UA_Account_sub(iYear=9999 有启用日期);读不到 UFSYSTEM 时 409「读不到 UFSYSTEM..UA_Account_sub…」。请求的模块(through 时为总账)未启用 409「<模块>未启用」。

登录子系统为模块的子系统号,through 用 GL。功能权限(账套主管放行),没有时 403 no_permission:采购 PU0207、销售 SA020901、库存 ST0304、存货核算 IA2007、应收 AR0509、应付 AP0509、总账结账 GL1512、总账取消结账 GL1520;其余模块的取消结账使用结账的 id。through 需要所涉每个模块的结账权限。

闸门。 一个请求一个事务(含 through):加锁读 GL_mend 全部年度各期标志,逐步检查和修改(后面的步骤按改后状态判断),完成后在同一事务里复读,不是目标状态则回滚,409 u8_rejected。拒绝都是 409 state_mismatch,message 以「<模块> <年> 年 <期> 期:」开头;through 时指卡住的那一步,整批不做:

库存结账(有单据、有结存的月份都做):同 U8 库存月末结账,写该年该月的五张月结快照,再改 bflag_ST。

存货核算结账:该月有存货核算数据时,同 U8「月末结账」执行 IA_Close(结存结转到下月)再置 bflag_IA,支持范围同 §32(否则 409「…接口暂不支持」);没有数据的月份只改标志。

期间按自然月算(本月 1 日到下月 1 日)。提交后在新连接上回读全部标志,读不出或不对是 504 outcome_unknown(已提交,先用 reports/close_status 核对,不要直接重投)。

响应:

{"ok": true, "module": "gl", "action": "close", "fiscal_year": 2026, "period": 9, "closed": true}
{"ok": true, "action": "close", "through": [{"module": "pu", "fiscal_year": 2026, "period": 9}, {"module": "gl", "fiscal_year": 2026, "period": 9}], "count": 2}
{"ok": true, "module": "st", "action": "close", "fiscal_year": 2026, "period": 8, "closed": true, "stock_rows": {"account": 120, "accounts": 120, "v": 120, "vs": 120, "check": 560}}

closed 是操作后的状态(reopen 为 false)。库存另有 stock_rows:结账时写入(取消时删除)ST_MonthAccount、ST_MonthAccounts、ST_MonthAccountV、ST_MonthAccountVs、ST_MonthAccountCheck 的行数;through 时在库存各项里各带一份。有提示时另有 warnings(字符串数组,以提示码开头,目前只有 ia_opening_not_posted),没有则不出现。through 按执行顺序列出结了账的期间,没有要结的期间时 count 为 0、HTTP 仍为 200。锁键 period:<模块>(through 锁全部七个),受全局写闸门约束。预演的 detail.periods 是同样的 {module, fiscal_year, period} 列表(库存项带 stock_rows),单个库存请求另有 detail.stock_rows;库存快照照样写入、随事务回滚。审计动作 period_close / period_reopen。

不做:不改 UFSYSTEM..UA_Account_sub 的 iModiPeri(请求连接从不写 UFSYSTEM);库存的 ST_MonthAccountsbus / ST_MonthAccountVsbus、ST_TotalVenSum;年度结转。见 limitations.md。

客户端命令:periods-close --fiscal-year 2026 --period 9 --module gl(取消结账加 --reopen;逐月结账用 --through 代替 --module;--dry-run、--idempotency-key 同其他写命令)。

32. 存货核算记账与期末处理 ia/post、ia/period_end#

写路由,第二级写入(§29 开头)。

存货核算月末流程为「正常单据记账 → 期末处理 → 月末结账」,取消时反向。本节两条路由做前两步(月末结账见 §31 module=ia)。每一步按 U8 界面的调用顺序和参数(存货核算存储过程加界面 SQL)写成 T-SQL 脚本(co/bridge/sql/ia/),在请求事务里整批执行。

支持范围。 执行脚本之前检查四项账套选项,任一项不符即 409「…接口暂不支持」,不做任何修改:存货核算方式为按仓库核算(AccInformation 的 cValueStyle);每个仓库的计价方式都是全月平均法(Warehouse.cWhValueStyle);暂估方式为单到回冲(cEstimate);销售成本核算方式为发出商品或销售出库单(bSaleType)。记账时本月有直接供应的材料出库,脚本执行中 409「…接口暂不支持」,整个事务回滚。标准成本、委外加工等其他设置未实测且不检查,这类账套不要使用本接口。结果已与 U8 界面生成的明细账、汇总表逐键核对。

请求(公共字段之外,不带 type、id):

{"fiscal_year": 2026, "period": 9, "action": "post", "on_uncosted": "refuse"}
{"fiscal_year": 2026, "period": 9, "action": "run"}
字段 说明
fiscal_year 必填,会计年度(4 位整数)。与公共字段 year(账套库年度)无关
period 必填,1 到 12
action 必填。ia/post:post 正常单据记账,unpost 恢复记账;ia/period_end:run 期末处理,cancel 取消期末处理。其他值 400(field 为 action)
on_uncosted 仅 ia/post 且 action=post,可选:refuse(缺省)或 skip,见下
dry_run 可选,rollback 模式(§23):整段脚本在事务里执行,读出诊断计数后回滚;计数在 detail.counts

另收幂等键(§20)。登录子系统 IA,记账人为登录操作员的 U8 用户名,记账日期为该月最后一天。功能权限(账套主管放行),没有时 403 no_permission:正常单据记账 IA2004、恢复记账 IA2005、期末处理和取消期末处理 IA2006(月末结账、取消结账是 §31 的 IA2007)。锁键 ia:<年>-<两位期>(如 ia:2026-09)和 period:ia(与存货核算月末结账串行),另持全局写闸门。执行时间随该月单据量增长,大账套可达数分钟,期间同一桥上的其他写请求排不上队,会 503 busy_timeout(未执行,可稍后重试)。审计动作 ia_post、ia_unpost、ia_period_end、ia_period_end_cancel。

正常单据记账 post#

把该年该月已审核、未记账的出入库单据(采购入库、其他入库、其他出库、产成品入库、材料出库、销售出库,审核日期在本月;未审核的不记)记入存货明细账(IA_Subsidiary)并更新汇总表(IA_Summary),在单据行上写记账人。销售成本按发出商品时,销售出库按发出商品记,已复核的销售发票同批记账。有单价的入库按单据金额记;有 U8 无法确定成本的存货(U8 界面会要求手工输入单价)时,按 on_uncosted:

拒绝(409 state_mismatch):存货核算未启用;该月早于存货核算启用月份;该月存货核算已结账;本月有直接供应的材料出库(「接口暂不支持」,事务回滚);上面的 refuse。

没有可记账的单据时照常 200,counts.area 为 0,响应带中文 message。

恢复记账 unpost#

整月恢复,同 U8「恢复记账」:删除该月明细账中各类出入库单据(含发出商品、销售发票)的记账行,回退汇总表,清除单据行上的记账人。该月没有已记账单据时照常 200,counts.restore_rows 为 0,带中文 message。拒绝(409 state_mismatch):该月已做期末处理(先取消期末处理);发出商品的销售出库还有不在本次恢复范围内的销售发票(例如下月的发票),须先恢复这些发票的记账。

期末处理 run#

同 U8 存货核算「期末处理」:按全月平均法计算各结存键的出库单价,给本月出库单据定成本,按 U8 的规则生成出库调整,把该月汇总表标记为已期末处理(IA_Summary.iPeriod=1)。拒绝(409 state_mismatch):该月存货核算已结账;该月还没有记账数据(先 ia/post)。

取消期末处理 cancel#

删除期末处理生成的出库调整、清除期末处理定下的出库成本,汇总表改回未期末处理。拒绝(409 state_mismatch):该月存货核算已结账(先 periods/close 取消结账)。

错误和响应#

U8 存储过程自己的拒绝是 409 u8_rejected「U8 拒绝:」。脚本超过 iaCommandSeconds(桥 config.json,缺省 900 秒;一次请求中的几段脚本共用这个期限)是 503 ia_timeout「存货核算处理超时,已回滚;可稍后重试,或调大 iaCommandSeconds」:事务已回滚,未写入,带 Retry-After(60 秒)。脚本中其他 SQL 错误是 500 internal(细节只进审计),事务回滚。提交后在新连接上回读该月明细账行数和结账标志,读不出或对不上是 504 outcome_unknown「…请先在 U8 里核对该月的记账和期末处理」:已提交,先核对,不要直接重投。

{"ok": true, "action": "post", "fiscal_year": 2026, "period": 9, "counts": {"subsidiary_month": 1280, "summary_month": 312, "summary_iPeriod1": 0}}

counts 是脚本最后一步的诊断计数(名称 → 行数),例如 area(本次记账的单据行数)、restore_rows(本次恢复的行数)、subsidiary_month(该月明细账行数)、summary_month(该月汇总表行数)、summary_iPeriod1(已期末处理的汇总行数);各操作的名称不同,只作核对参考,不要依赖固定的键集合。预演的 detail.counts 是同样的计数(事务内、回滚之前)。

客户端命令:ia-post --fiscal-year 2026 --period 9(恢复记账加 --unpost;--on-uncosted refuse|skip)、ia-period-end --fiscal-year 2026 --period 9(取消加 --cancel);--dry-run、--idempotency-key 同其他写命令。

33. 公司间接口(仅 API)#

用于同组公司之间买卖的多个账套。须先配置公司间对照 U8CO_IC_MAP_FILE(configuration.md「公司间对照」),未配置时 404 ic_not_configured「未配置公司间对照」;请求中的账套必须同属一组,否则 400 ic_group_mismatch「账套不在同一公司组」。

共同规则:

reports/intercompany_match 公司间对账#

卖方的销售单据与买方的采购单据逐笔配对,找出单边存在的记录。

字段 说明
logins 2 到 3 个,须包含卖方和买方账套
seller {acc, type},type 为 sale_out、dispatch、sale_invoice
buyer {acc, type},type 为 purchase_in、arrival、purchase_invoice;不能与卖方同一账套
date_from、date_to 必填,最多 93 天
window_days 0 到 7,缺省 1:日期相差几天内仍算同一笔
invoice_mode line(逐行)或 month(按月比金额),只在两边都是发票时可给,缺省 month。发票只能与发票对

reports/aggregate 多账套汇总#

同一张只读报表在 1 到 3 个账套上各取一遍,再按对照合计。

reports/consolidation 合并试算#

logins(2 到 3 个)、fiscal_year、period_from、period_to。各账套取科目余额表,按对照的逻辑科目归并,再按对照中 rule: ar_ap 的抵销对冲掉内部往来:应收方按客户、应付方按供应商取辅助核算余额,同号时抵销绝对值较小的一方(借应付、贷应收),difference 为应收减应付;方向相反的不抵销(skipped: "opposite_sign",并提醒)。

响应:group、complete、by_account、trial(每个账套是否平衡、末级借贷合计)、eliminations、consolidated(按逻辑科目的合并数)、unmapped、warnings、notes(口径说明,如未抵销内部交易中未实现的利润)。有账套失败时 complete: false、consolidated: null,全部失败 503。只做往来抵销,不抵销内部收入成本和未实现利润(经营管理利润表的合并见 §34)。

intercompany/generate_buyer 买方生单(写)#

按卖方的出货,在买方账套参照一张公司间采购订单生成采购入库单或到货单(经买方账套的 vouchers/generate)。

字段 说明
login 买方账套的登录
seller_acc 卖方账套,不能等于买方
type purchase_in 或 arrival(other_in 400:公司间采购须参照订单)
po_id 可选,指定买方的采购订单
lines 1 到 200 行 {inv_code, quantity, seller_id?}:inv_code 是卖方的存货编码
date、head 可选,同 vouchers/generate;表头没有 dDate 时 date 写入表头
dry_run 缺省 true:只出计划和预演,正式生成须显式写 false

34. 经营管理查询#

面向经营者的汇总:利润表、销售与毛利、往来账期、资金与存货,1 到 3 个账套,可合并。分两层:

桥的报表 reports/mgmt/*#

公共:fiscal_year 2000 到 2099,缺省登录年度。pnl、meta、cash_stock 登录 GL,sales 登录 SA,arap_terms 按 side 登录 AR / AP。科目前缀参数每项只含字母、数字、.、-,最多 10 项。

报表 参数 内容
mgmt/pnl period_from、period_to(必填)、include_unposted(缺省 false)、detail(prefix4 按科目前 4 位,缺省;leaf 按末级科目)、dims(dept、item 的子集)、pl_accounts(损益科目前缀,缺省 ["6"])、profit_account(本年利润,缺省 4103) 损益科目按期间(× 科目 × 部门 / 项目)的借、贷发生额,net_income = 贷 − 借,normal 是科目的余额方向,posted 表示该组全部已记账。另给每期的总账结账状态、未记账凭证张数、是否已做期间损益结转。超过 2 万行 400。按部门且部门数据权限打开时,聚合前去掉无权部门的分录(§22)
mgmt/meta 只有 fiscal_year 各模块(GL、SA、PU、ST、IA、AR、AP、FA)是否启用和启用日期;1 到 12 期各模块的结账状态、未记账凭证张数、是否已结转损益;数据水位 watermarks(凭证行数、已记账和作废行数、校验和与分录内容校验和 gl_content_checksum(不给借贷合计,金额变动同样使水位变化)、最大主键和日期,发票、入库单、票据、科目和结账表的时间戳,存货核算和往来明细的行数和最大主键);登录操作员的权限指纹 perm_fingerprint(同 perm/snapshot 的 fingerprint)
mgmt/sales period_from、period_to(必填)、group_by(period、customer、inventory、person、department 的子集,缺省 ["customer"],[] 只出合计)、top(1 到 500,缺省 200)、include_unverified 收入、成本、毛利、毛利率按分组;按收入降序取前 top 组,其余并成 others,另有 totals。未启用销售管理时明细为空、sa_enabled: false。超过 2 万组 400
mgmt/arap_terms side(ar / ap)、as_of(缺省登录日期)、accounts(缺省应收 1122、应付 2202)、buckets(缺省 [30,60,90,180])、default_credit_days、top(缺省 200) 每个往来单位:余额、预收(付)、逾期、按到期日的账龄各段、未结票据,近 12 个月的单据张数和金额、已付和未付、信用期分布,回款(付款)天数的金额加权平均和中位数。按余额绝对值降序取前 top,其余并成 others。余额、预收付、逾期都为 0 且近 12 个月没有单据的单位不列
mgmt/cash_stock period(必填)、cash_accounts(缺省 1001、1002、1012)、notes_accounts(缺省 1121)、top(缺省 200)、purchase_source(auto 缺省:有采购发票用发票,否则用采购入库;invoice;receipt)、include_unverified 货币资金和应收票据科目的期末余额(末级科目,已记账);未结应收票据(查询时点);存货结存(存货核算汇总);产成品入库按存货排行;采购按供应商排行

口径:

API 的 /v1/co/mgmt/*#

路由 参数(另有公共的 logins、fiscal_year)
mgmt/meta 无。不缓存、不合并
mgmt/pnl period_from、period_to、consolidate、include_unposted、dims(最多 1 项:dept 或 item)。取数粒度由利润表行定义决定(configuration.md「利润表行定义」),不收 detail
mgmt/sales period_from、period_to、consolidate、group_by、top、include_unverified
mgmt/arap period_from、period_to、consolidate、side(ar、ap、both,缺省 both)、as_of(缺省 period_to 的月末,晚于今天时取今天,按 U8CO_TIMEZONE)、buckets(1 到 8 项、严格递增)、default_credit_days、top。另给净额:未核销的收款(付款)按先进先出冲抵该单位最早的账龄段,得到 aging_net、overdue_net(aging、overdue 不变);未核销金额超过账龄合计 10% 时附警告。余额小于等于 0 时 DSO / DPO 为 null
mgmt/cash_stock period_from、period_to、consolidate、top、purchase_source、include_unverified。只按 period_to 一个期间出具(period_from 小于它时 notes 说明)
mgmt/overview period_from、period_to、consolidate、as_of。一次给出关键指标:营业收入、营业成本、毛利和毛利率、净利润和净利率、货币资金、存货、应收票据、应收余额和逾期、应付余额和逾期、DSO、DPO(由利润表、资金存货、往来三部分组成;逾期用冲抵未核销收付款后的净额)

35. 其他单据和写入#

供应商退款、客户退款 ap_refund、ar_refund#

U8「付款单据录入」中的供应商退款(应付的收款单,Ap_CloseBill 上 cFlag=AP、cVouchType=48,卡片 AP48)和「收款单据录入」中的客户退款(应收的付款单,AR / 49,卡片 AR49)。读取、列表、查询、事件、新增、修改、删除、审核、弃审都同收付款单(UFAPBO clsCloseBill,§12),字段、行数、iType(0 应收付款、1 预收付款)也相同;往来单位应付为供应商、应收为客户。

退货申请单 sale_return_apply#

销售管理的退货申请单(卡片 SA31,SA_ReturnsApplyMain / SA_ReturnsApplyDetail),表体数量、金额为负。

无来源销售出库 sale_out#

账套未启用销售管理(只用库存管理)时,销售出库单可以无来源新增(cSource=库存、普通销售),以及修改、删除这类单据。

发货单修改新增行#

vouchers/update 的发货单可以带 op: add 的行,新增参照来源销售订单的行(退货单、销售发票仍不能新增行,400「该单据类型修改不能新增行」)。

采购手工结算 purchase_settle#

vouchers/create 的 purchase_settle:按调用方给的配对结算,同 U8「手工结算」。写入与 U8 手工结算界面执行的 SQL 一致(实测核对:配对、红蓝入库对冲、红蓝发票对冲,与 U8 生成的结算单比对一致)。第一级写入:所有 allowedAccounts 账套按写入策略(purchase_settle 的 create)放行。委外、外币、费用分摊、同一发票行既对冲又配对等 U8 界面能做而桥不做的结算会被拒绝(400 / 409,见下面的门槛),请在 U8 客户端处理。

红冲蓝字销售发票#

vouchers/generate 的 sale_invoice,source_type: sale_invoice,id 是已复核的蓝字发票 SBVID(专票 26 / 普票 27,红字发票同类型)。

相关说明#