openapi: 3.0.3 info: title: Finance Phase 1 Five-page Acceptance API version: 1.0.0-draft description: >- 订单与客户领导验收 5 页目标契约:客户账户、客户应收应付、客户对账单、结算单应收、 结算单应付。只支持 CNY。费用分析、利润表、钱包、预收和充值不属于本契约。 本文件冻结订单与客户目标契约及后续确认的费用编辑审核、客户确认和应收统计扩展。实现与 Admin 接入证据单独维护在财务核心P0实现证据矩阵.md,不得因代码文件出现反复修改本契约。 servers: - url: /api x-product-scope: included: - CUSTOMER_ACCOUNT_DERIVED_VIEW - CUSTOMER_ARAP_FEE_SOURCE_POOL - CUSTOMER_RECONCILIATION_STATEMENT - RECEIVABLE_SETTLEMENT - PAYABLE_SETTLEMENT excluded: - WALLET - PREPAYMENT - MANUAL_RECHARGE - COST_ANALYSIS - PROFIT_REPORT - FOREIGN_CURRENCY - EXCHANGE_RATE x-source-gate: eligible: APPROVED + PUBLISHED + AVAILABLE + CNY + amount>0 currentStatus: 审核通过后自动发布并进入结算候选;Finance 不再维护人工“是否结算”开关,并继续校验客户、版本、方向和来源归属。 x-payable-cost-contract: settlementModes: [ON_ACCOUNT, DIRECT_PAID] paymentMethods: [ONLINE, BANK_TRANSFER, CASH, OTHER] onAccount: 可进入正式 PAYABLE settlement;paidAt/paymentMethod/paymentReferenceNo/paymentVoucherFileIds 必须为空 directPaid: 必填 paidAt/paymentMethod,paymentReferenceNo 与 paymentVoucherFileIds 至少一项;只计成本,禁止进入 AP 和 outstandingPayable operatingFunds: 仅三类运营资金:待收客户款、待付供应商款、已线下支付供应商款;不存在客户线下支付分类,也不新增已收客户款卡片 outstandingReceivable: 只聚合非VOIDED正式RECEIVABLE结算单outstanding,不叠加pendingBilling;客户收款只减少该余额并保留收款历史 outstandingPayable: 非VOIDED正式PAYABLE结算单outstanding + 尚未进入非VOIDED AP的有效ON_ACCOUNT来源金额;按feeSourceId关联去重 paidSupplierAmount: 有效FIRSTLEG_DIRECT_PAID确认成本 + 非VOIDED ON_ACCOUNT AP paidAmount;明细分别标识SUPPLIER_DIRECT_PAID和SUPPLIER_ON_ACCOUNT_PAYMENT totals: 总成本=有效ON_ACCOUNT来源+有效DIRECT_PAID成本事实;待付与已付按上述运营资金公式计算,作废、SUPERSEDED、部分付款和结清不得重复累计 uniqueness: DIRECT_PAID 按 sourceSystem+sourceType+sourceFeeId+sourceVersion 唯一物化到 fin_cost,禁止与来源重复累计 x-customer-account-ui-contract: operatingCards: [outstandingReceivable, outstandingPayable, paidCost] operatingCardLabels: [待收客户款, 待付供应商款, 已线下支付供应商款] auxiliaryFields: [pendingBilling, receivedInPeriod, totalCost] rule: 辅助字段只允许用于列表、明细或历史说明,不得生成第四类运营资金卡片;paidCost只属于供应商,禁止解释为客户线下支付。 x-phase1-p0-contract: status: FROZEN rule: 所有已列 operation 均为当前目标契约;实现状态不得写入本文件。 contract: ../财务核心P0操作契约与验收用例.md evidenceMatrix: ../财务核心P0实现证据矩阵.md x-idempotency-contract: scope: method + normalizedPath + resolvedCustomerId + completeQueryAndBody sameKeySameRequest: replay original result sameKeyDifferentRequest: FIN_409 processing: FIN_409;超时后按现有 Finance 抢占恢复规则执行 failed: 按现有 Finance FAILED 恢复规则执行 x-error-contract: FIN_400: 参数、日期、CNY 或正金额校验失败 FIN_404: 对象不存在或跨客户对象隐藏 FIN_409: 非法状态、乐观锁、重复占用或幂等冲突 FIN_503: File 或内部依赖不可用且 fail-closed FIN_001: 未分类服务端错误 authentication: HTTP 401 permission: HTTP 403 paths: /internal/finance/v1/fee-source-events: post: servers: - url: / operationId: consumeFirstlegFeeSourceEvent summary: 消费 Firstleg 不可变费用来源事件 description: >- 使用内部服务令牌鉴权;按 eventId 和完整事件请求哈希幂等消费,回查 Firstleg 入库或柜子费用快照,校验客户、版本、审核、发布、CNY、方向和来源类型后, 写入 fin_inbox_event 与 fin_fee_source。调整新增版本并替代旧 AVAILABLE 版本,作废只改状态不删除历史。 x-authentication: X-Internal-Service-Token x-error-codes: - FIN-EVT-001 - FIN-EVT-002 - FIN-EVT-003 - FIN-EVT-004 - FIN-EVT-005 - FIN-EVT-006 - FIN-EVT-007 - FIN-EVT-008 - FIN-EVT-009 - FIN-EVT-010 - FIN-EVT-011 - FIN-EVT-012 - FIN-EVT-013 - FIN-EVT-014 - FIN-EVT-015 - FIN-EVT-016 - FIN-EVT-401 parameters: - $ref: '#/components/parameters/InternalServiceToken' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/FinanceFeeSourceEvent'} responses: '200': description: 成功消费、同参重放结果或稳定业务错误。 content: application/json: schema: oneOf: - $ref: '#/components/schemas/FeeSourceEventResultEnvelope' - $ref: '#/components/schemas/ErrorEnvelope' /internal/exports/v1/{exportType}/batches: post: servers: - url: / operationId: provideFinanceExportBatch summary: 向 File 下载中心提供 Finance 导出批次 description: >- 仅供 File Service 使用;按任务、申请人、完整筛选参数签名并校验 snapshotToken。 exportType 固定业务方向,参数不得包含 page、pageSize 或 direction(费用来源列表除外)。 x-authentication: X-Internal-Service-Token parameters: - $ref: '#/components/parameters/InternalServiceToken' - name: exportType in: path required: true schema: type: string enum: - FINANCE_CUSTOMER_ACCOUNT_LIST - FINANCE_CUSTOMER_ACCOUNT_LEDGER - FINANCE_FEE_SOURCE_LIST - FINANCE_RECONCILIATION_STATEMENT_LIST - FINANCE_RECEIVABLE_SETTLEMENT_LIST - FINANCE_RECEIVABLE_SETTLEMENT_DETAIL - FINANCE_PAYABLE_SETTLEMENT_LIST - FINANCE_PAYABLE_SETTLEMENT_DETAIL - FINANCE_RECEIVABLE_STATISTICS requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/FinanceExportBatchRequest'} responses: '200': description: 版本化导出批次;首批返回 columns、totalRows 和 snapshotToken。 content: application/json: schema: {$ref: '#/components/schemas/FinanceExportBatchEnvelope'} '403': {description: 内部服务令牌无效。} /platform/finance/v1/accounts: get: operationId: listDerivedCustomerAccounts summary: 查询客户财务账户派生汇总 description: 只读聚合,不返回钱包余额,不提供充值或余额调整动作。 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: AccountListQuery x-response-dto: AccountPageEnvelope x-idempotency: READ_ONLY_NOT_APPLICABLE x-customer-isolation: 平台权限下按真实客户主体聚合;不得返回 tenantId,不得产生可写余额。 x-state-machine: READ_ONLY_DERIVED_VIEW x-error-codes: [FIN_400, FIN_001] x-acceptance-cases: [AC-01, AC-02] x-permission: platform:finance:customer-account:list parameters: - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PageSize' - name: customerName in: query description: 按客户名称模糊查询,不支持客户编号或联系人搜索。 schema: {type: string} - name: status in: query schema: {type: string, enum: [ACTIVE, DISABLED]} responses: '200': {$ref: '#/components/responses/AccountPageResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/customer-accounts/{customerId}: get: operationId: getDerivedCustomerAccount summary: 查询客户财务账户详情 x-permission: platform:finance:customer-account:list parameters: - $ref: '#/components/parameters/CustomerId' responses: '200': {$ref: '#/components/responses/CustomerAccountReadResponse'} '404': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/customer-accounts/{customerId}/summary: get: operationId: getCustomerAccountSummary summary: 查询客户正式结算口径财务汇总 description: >- 固定 CNY。待收客户款只聚合本客户非 VOIDED 正式 RECEIVABLE fin_settlement 的 outstandingAmount,待出账只作为独立信息且不得叠加进待收。待付供应商款为非 VOIDED PAYABLE fin_settlement outstandingAmount,加尚未进入非 VOIDED AP 的合格 ON_ACCOUNT 来源金额并按 feeSourceId 去重。paidCost 仅表示已线下支付供应商款,由有效 FIRSTLEG_DIRECT_PAID 确认成本与非 VOIDED ON_ACCOUNT AP paidAmount 构成。 x-permission: platform:finance:customer-account:list x-customer-isolation: 所有聚合子查询都必须使用 customerId 约束,空客户返回零值。 parameters: - $ref: '#/components/parameters/CustomerId' responses: '200': {$ref: '#/components/responses/CustomerAccountSummaryResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/accounts/{customerId}/ledger: get: operationId: listDerivedCustomerAccountLedger summary: 查询客户财务派生流水 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: AccountLedgerQuery x-response-dto: LedgerPageEnvelope x-idempotency: READ_ONLY_NOT_APPLICABLE x-customer-isolation: customerId 必须解析为真实客户,流水只聚合该客户数据;跨客户对象不得出现。 x-state-machine: READ_ONLY_DERIVED_VIEW x-error-codes: [FIN_400, FIN_404, FIN_001] x-acceptance-cases: [AC-03, AC-04] x-permission: platform:finance:customer-account:list parameters: - $ref: '#/components/parameters/CustomerId' - $ref: '#/components/parameters/Page' - $ref: '#/components/parameters/PageSize' - name: businessType in: query schema: {$ref: '#/components/schemas/LedgerBusinessType'} - name: startDate in: query schema: {type: string, format: date} - name: endDate in: query schema: {type: string, format: date} responses: '200': {$ref: '#/components/responses/LedgerPageResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/fee-sources: get: operationId: listFinanceFeeSources summary: 分页查询客户应收应付费用来源 x-permission: platform:finance:customer-arap:list parameters: - name: page in: query schema: {type: integer, minimum: 1, default: 1} - name: pageSize in: query schema: {type: integer, minimum: 1, maximum: 200, default: 20} - name: customerId in: query schema: {$ref: '#/components/schemas/Id'} - name: direction in: query schema: {$ref: '#/components/schemas/FeeDirection'} - name: status in: query schema: {type: string, enum: [AVAILABLE, LOCKED, BILLED, VOIDED, SUPERSEDED]} - name: reviewStatus in: query schema: {$ref: '#/components/schemas/ReviewStatus'} - name: statementGenerated in: query schema: {type: boolean} - name: businessDateFrom in: query schema: {type: string, format: date} - name: businessDateTo in: query schema: {type: string, format: date} - name: keyword in: query schema: {type: string, maxLength: 200} responses: '200': {$ref: '#/components/responses/FeeSourcePageResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/fee-pool: get: operationId: listLegacyFinanceFeePool summary: 查询旧版费用池(非五页事实源) deprecated: true x-permission: platform:finance:customer-arap:list parameters: - name: customerId in: query schema: {$ref: '#/components/schemas/Id'} - name: direction in: query schema: {$ref: '#/components/schemas/FeeDirection'} responses: '200': {$ref: '#/components/responses/FeePoolReadResponse'} /platform/finance/v1/fee-sources/{feeSourceId}: get: operationId: getFinanceFeeSource summary: 查询费用来源详情、业务关联和操作记录 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: FeeSourceIdPath x-response-dto: FeeSourceDetailEnvelope x-idempotency: READ_ONLY_NOT_APPLICABLE x-customer-isolation: 按费用来源真实 customerId 返回;跨客户关联按 FIN_404 隐藏。 x-state-machine: READ_ONLY_ALL_SOURCE_STATES x-error-codes: [FIN_404, FIN_001] x-acceptance-cases: [AC-05] x-permission: platform:finance:customer-arap:list parameters: - $ref: '#/components/parameters/FeeSourceId' responses: '200': {$ref: '#/components/responses/FeeSourceDetailResponse'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} put: operationId: editFinanceFeeSource summary: 编辑草稿或驳回的费用来源 description: sourceSystem=FIRSTLEG 时拒绝本地金额编辑,必须回入库费用或柜次费用业务明细修改并由 Firstleg 发布新版本。 x-permission: platform:finance:fee-source:edit parameters: - $ref: '#/components/parameters/FeeSourceId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: {application/json: {schema: {$ref: '#/components/schemas/FeeSourceEditRequest'}}} responses: '200': {$ref: '#/components/responses/FeeSourceDetailResponse'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/fee-sources/{feeSourceId}/review: post: operationId: reviewFinanceFeeSource summary: 审核费用来源 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: ReviewRequest x-response-dto: FeeSourceDetailEnvelope x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT x-customer-isolation: 只按 feeSourceId 解析其真实客户;请求不得覆盖 customerId 或金额。 x-state-machine: PENDING -> APPROVED | REJECTED x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001] x-acceptance-cases: [AC-06, AC-07, AC-29] x-permission: platform:finance:fee-source:review parameters: - $ref: '#/components/parameters/FeeSourceId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ReviewRequest'} responses: '200': {$ref: '#/components/responses/FeeSourceDetailResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/fee-sources/{feeSourceId}/submit: post: operationId: submitFinanceFeeSource summary: 提交费用来源审核 x-permission: platform:finance:fee-source:edit parameters: - $ref: '#/components/parameters/FeeSourceId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/FeeSourceActionRequest'} responses: '200': {$ref: '#/components/responses/FeeSourceDetailResponse'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/fee-sources/{feeSourceId}/adjust: post: operationId: adjustFinanceFeeSource summary: 将已审核费用调整为新草稿版本 description: sourceSystem=FIRSTLEG 时拒绝本地金额调整,必须由 Firstleg 业务明细形成新版本并发布 FIRSTLEG_FEE_ADJUSTED。 x-permission: platform:finance:fee-source:edit parameters: - $ref: '#/components/parameters/FeeSourceId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: {application/json: {schema: {$ref: '#/components/schemas/FeeSourceEditRequest'}}} responses: '200': {$ref: '#/components/responses/FeeSourceDetailResponse'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/fee-sources/{feeSourceId}/void: post: operationId: voidFinanceFeeSource summary: 作废费用来源 description: sourceSystem=FIRSTLEG 时 Finance 仅发起幂等内部命令;Firstleg 原子作废业务费用并发布 FIRSTLEG_FEE_VOIDED,Finance 消费事件后同步本地状态,不执行本地先写或伪造事件。 x-permission: platform:finance:fee-source:edit parameters: - $ref: '#/components/parameters/FeeSourceId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: {application/json: {schema: {$ref: '#/components/schemas/FeeSourceActionRequest'}}} responses: '200': {$ref: '#/components/responses/FeeSourceDetailResponse'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/statements: get: operationId: listReconciliationStatements summary: 查询客户对账单 x-permission: platform:finance:customer-statement:list parameters: - name: customerId in: query required: false schema: {$ref: '#/components/schemas/Id'} responses: '200': {$ref: '#/components/responses/StatementListReadResponse'} post: operationId: createReconciliationStatement summary: 按截止时间或勾选来源生成客户对账单草稿 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: CreateReconciliationRequest x-response-dto: ReconciliationDetailEnvelope x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT x-customer-isolation: 所有来源必须属于 request.customerId;跨客户来源按 FIN_404,禁止部分落库。 x-state-machine: 合格且未占用来源 -> DRAFT;创建时锁定所选来源 x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001] x-acceptance-cases: [AC-10, AC-11, AC-12, AC-29] x-permission: platform:finance:reconciliation:create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateReconciliationRequest'} responses: '200': {$ref: '#/components/responses/ReconciliationDetailResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/bills/{billId}: get: operationId: getReconciliationStatement summary: 查询客户对账单详情、费用明细和支付历史 x-permission: platform:finance:customer-statement:list parameters: - $ref: '#/components/parameters/BillId' responses: '200': {$ref: '#/components/responses/StatementDetailReadResponse'} '404': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/reconciliation-statements/{statementId}/actions: post: operationId: actionReconciliationStatement summary: 提交、审核、出账、调整、作废或重开客户对账单 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: ReconciliationActionRequest x-response-dto: ReconciliationDetailEnvelope x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT x-customer-isolation: statementId 决定客户;调整行必须全部属于该对账单,跨客户按 FIN_404。 x-state-machine: DRAFT->PENDING_REVIEW->APPROVED->ISSUED;REJECTED/VOIDED 可 REOPEN 新 revision;ISSUED 仅 ADJUST 新 revision x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001] x-acceptance-cases: [AC-13, AC-14, AC-15, AC-16, AC-17, AC-29] x-permission-by-action: SUBMIT: platform:finance:reconciliation:create APPROVE: platform:finance:reconciliation:review REJECT: platform:finance:reconciliation:review ISSUE: platform:finance:reconciliation:issue ADJUST: platform:finance:reconciliation:adjust VOID: platform:finance:reconciliation:void REOPEN: platform:finance:reconciliation:void parameters: - $ref: '#/components/parameters/StatementId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/ReconciliationActionRequest'} responses: '200': {$ref: '#/components/responses/ReconciliationDetailResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/receivable-settlements: get: operationId: listReceivableSettlements summary: 查询结算单应收 x-permission: platform:finance:settlement-ar:list parameters: - name: customerId in: query required: true schema: {$ref: '#/components/schemas/Id'} responses: '200': {$ref: '#/components/responses/ReceivableSettlementListReadResponse'} post: operationId: createReceivableSettlement summary: 从审核通过的客户对账单生成应收结算单 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: CreateReceivableSettlementRequest x-response-dto: SettlementDetailEnvelope x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT x-customer-isolation: 客户从对账单派生,不接受前端覆盖;跨客户关联按 FIN_404。 x-state-machine: ISSUED reconciliation -> ISSUED RECEIVABLE settlement;一张对账单只允许一个有效 AR x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_001] x-acceptance-cases: [AC-18, AC-19, AC-29] x-permission: platform:finance:settlement-ar:create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateReceivableSettlementRequest'} responses: '200': {$ref: '#/components/responses/SettlementDetailResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/payable-settlements: get: operationId: listPayableSettlements summary: 查询结算单应付 x-permission: platform:finance:settlement-ap:list parameters: - name: customerId in: query required: true schema: {$ref: '#/components/schemas/Id'} responses: '200': {$ref: '#/components/responses/PayableSettlementListReadResponse'} post: operationId: createPayableSettlement summary: 从审核通过且已发布的应付来源生成应付结算单 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: CreatePayableSettlementRequest x-response-dto: SettlementDetailEnvelope x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT x-customer-isolation: 所有 PAYABLE 来源必须同 customerId、同 supplierId;supplierId 必须来自 Warehouse ACTIVE 供应商主数据。费用项目 supplierCategory 非空时必须匹配,空时允许任意 ACTIVE 供应商;跨客户来源按 FIN_404。 x-state-machine: 合格未占用 PAYABLE 来源 -> ISSUED PAYABLE settlement x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_503, FIN_001] x-acceptance-cases: [AC-20, AC-21, AC-29] x-permission: platform:finance:settlement-ap:create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreatePayableSettlementRequest'} responses: '200': {$ref: '#/components/responses/SettlementDetailResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/receipts: get: operationId: listPlatformReceipts summary: 平台按客户查询人工收款记录 x-permission: platform:finance:receipt:view parameters: - name: customerId in: query required: true schema: {$ref: '#/components/schemas/Id'} responses: '200': {$ref: '#/components/responses/PlatformReceiptListReadResponse'} post: operationId: createReceiptWithAllocations summary: 人工登记一笔收款并分配到一张或多张应收结算单 description: >- 收款总额必须等于 allocations 金额之和;所有结算单必须属于同一客户且为 CNY, 每笔分配不得超过对应未收余额。示例:收款 300 元可分配到 3 张结算单各 100 元, 共用同一组收款凭证图片。File 校验失败或不可用时必须 fail-closed,不得落库。 x-permission: platform:finance:receipt:create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateReceiptRequest'} responses: '200': {$ref: '#/components/responses/ResourceResultResponse'} '409': {$ref: '#/components/responses/BusinessError'} /client/finance/v1/receipts: get: operationId: listClientVisibleReceipts summary: 客户只读查询已确认收款和账单分配 description: 使用登录客户身份隔离,不接收 customerId;不返回凭证、操作人、内部备注或 tenantId。 x-permission: merchant:finance:statement:view responses: '200': {$ref: '#/components/responses/ClientReceiptListReadResponse'} /client/finance/v1/statements/{statementId}/confirm: post: operationId: confirmClientReconciliationStatement summary: 当前登录客户确认本人已出账对账单 description: 不接收 customerId;客户范围和确认人均取自登录态。重复请求按 Idempotency-Key 幂等处理。 x-permission: merchant:finance:statement:confirm parameters: - $ref: '#/components/parameters/StatementId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: {application/json: {schema: {$ref: '#/components/schemas/CustomerConfirmationRequest'}}} responses: '200': {description: 已确认或幂等返回原确认结果} '404': {$ref: '#/components/responses/BusinessError'} '409': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/receivable-statistics: get: operationId: getReceivableStatistics summary: 按结算单生成月份和客户统计 CNY 应收款 description: 只统计 direction=RECEIVABLE、status!=VOIDED 的 fin_settlement;按客户汇总应收、已收和余额未收。 x-permission: platform:finance:receivable-statistics:list parameters: - name: month in: query required: true schema: {type: string, pattern: '^\d{4}-\d{2}$', example: '2026-08'} - name: customerId in: query schema: {$ref: '#/components/schemas/Id'} - name: page in: query schema: {type: integer, minimum: 1, default: 1} - name: pageSize in: query schema: {type: integer, minimum: 1, maximum: 200, default: 20} responses: '200': {description: CNY 应收款统计结果} '400': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/settlements/{settlementId}: get: operationId: getSettlement summary: 查询应收或应付结算单详情 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: SettlementIdPath x-response-dto: SettlementDetailEnvelope x-idempotency: READ_ONLY_NOT_APPLICABLE x-customer-isolation: 按结算单真实客户返回;不得返回其他客户数据,客户侧仍使用独立脱敏接口。 x-state-machine: READ_ONLY_ALL_SETTLEMENT_STATES x-error-codes: [FIN_404, FIN_001] x-acceptance-cases: [AC-22, AC-23] x-permission-any-of: - platform:finance:settlement-ar:list - platform:finance:settlement-ap:list parameters: - $ref: '#/components/parameters/SettlementId' responses: '200': {$ref: '#/components/responses/SettlementDetailResponse'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/settlements/{settlementId}/transactions: post: operationId: createSettlementPayment summary: 人工登记应付结算单付款并上传凭证 x-contract-status: FROZEN x-delivery-priority: PHASE1_P0 x-request-dto: CreateSettlementPaymentRequest x-response-dto: SettlementDetailEnvelope x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT x-customer-isolation: settlementId 决定客户和供应商;凭证必须属于同一客户的 FINANCE_VOUCHER。 x-state-machine: PAYABLE ISSUED -> PARTIALLY_PAID -> PAID;金额不得超过 outstandingAmount x-error-codes: [FIN_400, FIN_404, FIN_409, FIN_503, FIN_001] x-acceptance-cases: [AC-24, AC-25, AC-26, AC-29] x-permission: platform:finance:payment:create parameters: - $ref: '#/components/parameters/SettlementId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/CreateSettlementPaymentRequest'} responses: '200': {$ref: '#/components/responses/SettlementDetailResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} '409': {$ref: '#/components/responses/BusinessError'} '503': {$ref: '#/components/responses/BusinessError'} /platform/finance/v1/settlements/{settlementId}/actions: post: operationId: actionSettlement summary: 作废或重开未发生收付款的结算单 x-contract-status: FROZEN x-idempotency: FULL_REQUEST_HASH_SAME_REPLAY_DIFFERENT_CONFLICT x-state-machine: ISSUED -> VOIDED -> ISSUED;paidAmount 必须为 0 x-permission: platform:finance:settlement:void parameters: - $ref: '#/components/parameters/SettlementId' - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: {$ref: '#/components/schemas/SettlementActionRequest'} responses: '200': {$ref: '#/components/responses/SettlementDetailResponse'} '400': {$ref: '#/components/responses/BusinessError'} '403': {$ref: '#/components/responses/BusinessError'} '404': {$ref: '#/components/responses/BusinessError'} '409': {$ref: '#/components/responses/BusinessError'} components: parameters: InternalServiceToken: name: X-Internal-Service-Token in: header required: true schema: {type: string, minLength: 1} CustomerId: name: customerId in: path required: true schema: {$ref: '#/components/schemas/Id'} FeeSourceId: name: feeSourceId in: path required: true schema: {$ref: '#/components/schemas/Id'} StatementId: name: statementId in: path required: true schema: {$ref: '#/components/schemas/Id'} BillId: name: billId in: path required: true schema: {$ref: '#/components/schemas/Id'} SettlementId: name: settlementId in: path required: true schema: {$ref: '#/components/schemas/Id'} Page: name: page in: query required: false schema: {type: integer, minimum: 1, default: 1} PageSize: name: pageSize in: query required: false schema: {type: integer, minimum: 1, maximum: 200, default: 20} IdempotencyKey: name: Idempotency-Key in: header required: true schema: {type: string, minLength: 1, maxLength: 128} description: 完整规范化 method/path/customer/body 哈希;同参重放,异参冲突。 schemas: FinanceExportBatchRequest: type: object required: [taskId, tenantId, appCode, requestedBy, dispatchVersion, parameters, limit] properties: taskId: {type: string, pattern: '^[1-9][0-9]*$'} tenantId: {type: string, enum: ['0']} appCode: {type: string, enum: [PLATFORM]} requestedBy: {type: string, pattern: '^[1-9][0-9]*$'} dispatchVersion: {type: integer, minimum: 1} parameters: type: object description: >- ACCOUNT_LIST: customerId?, status?;ACCOUNT_LEDGER: customerId, businessType?, startDate?, endDate?; FEE_SOURCE_LIST: customerId?, direction?, status?, reviewStatus?, statementGenerated?, businessDateFrom?, businessDateTo?, keyword?;RECONCILIATION_STATEMENT_LIST: customerId?, status?, billNo?, containerNo?, periodStartFrom?, periodStartTo?, periodEndFrom?, periodEndTo?, settled?, lastPaymentFrom?, lastPaymentTo?, createdFrom?, createdTo?;AR_LIST: customerId?, status?, settlementNo?;AP_LIST 另含 supplierName?;所有 DETAIL 仅 settlementId。业务 ID 为十进制字符串,日期为 YYYY-MM-DD。 additionalProperties: true cursor: {type: string, nullable: true, description: 非负十进制偏移量。} snapshotToken: {type: string, nullable: true, description: 首批为空,后续批次必须原样回传。} limit: {type: integer, minimum: 1, maximum: 500} FinanceExportColumn: type: object required: [key, title, type] properties: key: {type: string} title: {type: string} type: {type: string, enum: [STRING, INTEGER, DECIMAL, BOOLEAN, DATE, DATETIME]} width: {type: integer, nullable: true} FinanceExportBatch: type: object required: [schemaVersion, schemaHash, snapshotToken, columns, rows, nextCursor, hasMore] properties: schemaVersion: {type: integer, enum: [1]} schemaHash: {type: string} snapshotToken: {type: string} columns: {type: array, items: {$ref: '#/components/schemas/FinanceExportColumn'}} rows: {type: array, items: {type: object, additionalProperties: true}} nextCursor: {type: string} hasMore: {type: boolean} totalRows: {type: integer, format: int64, nullable: true} FinanceExportBatchEnvelope: type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/FinanceExportBatch'} Id: type: string pattern: '^[1-9][0-9]*$' FinanceFeeSourceEvent: type: object required: [eventId, eventType, eventVersion, producer, occurredAt, tenantId, aggregateType, aggregateId, sequence, idempotencyKey, payloadHash, payload] properties: eventId: {type: string, minLength: 1} eventType: type: string enum: [FIRSTLEG_FEE_PUBLISHED, FIRSTLEG_FEE_ADJUSTED, FIRSTLEG_FEE_VOIDED] eventVersion: {type: integer, minimum: 1} producer: {type: string, enum: [firstleg-service]} occurredAt: {type: string, format: date-time} tenantId: {$ref: '#/components/schemas/Id'} aggregateType: {type: string, enum: [INBOUND, CONTAINER]} aggregateId: {$ref: '#/components/schemas/Id'} sequence: {type: integer, minimum: 1} idempotencyKey: {type: string, minLength: 1} payloadHash: {type: string, pattern: '^[a-f0-9]{64}$'} payload: {$ref: '#/components/schemas/FinanceFeeSourceEventPayload'} FinanceFeeSourceEventPayload: type: object required: [feeId, feeVersion] properties: inboundId: {$ref: '#/components/schemas/Id'} containerId: {$ref: '#/components/schemas/Id'} feeId: {$ref: '#/components/schemas/Id'} feeVersion: {type: integer, minimum: 1} oneOf: - required: [inboundId] not: {required: [containerId]} - required: [containerId] not: {required: [inboundId]} FeeSourceEventResult: type: object required: [feeSourceId] properties: feeSourceId: {type: integer, format: int64, minimum: 1} Money: type: string pattern: '^(0|[1-9][0-9]*)(\.[0-9]{1,6})?$' PositiveMoney: type: string pattern: '^(0\.(?=[0-9]{0,5}[1-9])[0-9]{1,6}|[1-9][0-9]*(\.[0-9]{1,6})?)$' FeeDirection: type: string enum: [RECEIVABLE, PAYABLE] SettlementMode: type: string enum: [ON_ACCOUNT, DIRECT_PAID] description: 仅 PAYABLE 必填;RECEIVABLE 必须为空 CostPaymentMethod: type: string enum: [ONLINE, BANK_TRANSFER, CASH, OTHER] FeeSourceType: type: string minLength: 1 description: 来源系统定义的费用来源类型;Finance 原样保留,当前已知 INBOUND_FEE、CONTAINER_FEE,后续可接入海外仓等来源类型 ReviewStatus: type: string enum: [PENDING, APPROVED, REJECTED] ReconciliationStatus: type: string enum: [DRAFT, PENDING_REVIEW, APPROVED, ISSUED, REJECTED, VOIDED] SettlementStatus: type: string enum: [DRAFT, PENDING_REVIEW, ISSUED, PARTIALLY_PAID, PAID, REJECTED, VOIDED] PaymentStatus: type: string enum: [UNPAID, PARTIALLY_PAID, PAID, OVERDUE] LedgerBusinessType: type: string enum: [RECONCILIATION_CREATED, SETTLEMENT_ISSUED, RECEIPT, SUPPLIER_DIRECT_PAID, SUPPLIER_ON_ACCOUNT_PAYMENT, ADJUSTMENT, VOID] TraceMeta: type: object required: [requestId, traceId, timestamp] properties: requestId: {type: string, minLength: 1} traceId: {type: string, minLength: 1} timestamp: {type: string, format: date-time} PageMeta: type: object required: [page, pageSize, total] properties: page: {type: integer, minimum: 1} pageSize: {type: integer, minimum: 1} total: {type: integer, format: int64, minimum: 0} AccountSummary: type: object required: [customerId, customerCode, customerName, outstandingReceivable, pendingBilling, receivedInPeriod, totalCost, paidCost, outstandingPayable, status, lastChangedAt] properties: customerId: {$ref: '#/components/schemas/Id'} customerCode: {type: string} customerName: {type: string} contactName: {type: string} contactPhone: {type: string} outstandingReceivable: allOf: [{$ref: '#/components/schemas/Money'}] description: 待收客户款;仅正式非VOIDED应收结算单未收余额,不含待出账。 pendingBilling: allOf: [{$ref: '#/components/schemas/Money'}] description: 合格但未进入有效对账单的应收来源,仅作独立过程信息,不计入待收客户款。 receivedInPeriod: {$ref: '#/components/schemas/Money'} totalCost: {$ref: '#/components/schemas/Money'} paidCost: allOf: [{$ref: '#/components/schemas/Money'}] description: 已线下支付供应商款;仅有效DIRECT_PAID确认成本与非VOIDED账期AP已付金额。 outstandingPayable: allOf: [{$ref: '#/components/schemas/Money'}] description: 待付供应商款;有效AP未付与尚未制单ON_ACCOUNT来源按feeSourceId去重后的合计。 status: {type: string, enum: [ACTIVE, DISABLED]} lastChangedAt: {type: string, format: date-time} AccountDetail: allOf: - $ref: '#/components/schemas/AccountSummary' - type: object properties: email: {type: string} creditDays: {type: integer, minimum: 0} CustomerAccountRead: type: object required: [customerId, currency, accountMode, totalReceivable, totalReceived, outstandingAmount, entries] properties: customerId: {$ref: '#/components/schemas/Id'} currency: {type: string, enum: [CNY]} accountMode: {type: string, enum: [MANUAL_RECEIVABLE_LEDGER], description: 账户为人工财务操作台账;金额口径仍只取正式应收结算单。} totalReceivable: {$ref: '#/components/schemas/Money'} totalReceived: {$ref: '#/components/schemas/Money'} outstandingAmount: {$ref: '#/components/schemas/Money'} entries: type: array items: {$ref: '#/components/schemas/AccountEntryRead'} CustomerAccountSummary: type: object required: [customerId, currency, totalReceivable, receivedAmount, outstandingReceivable, pendingBilling, totalCost, paidCost, outstandingPayable, asOf, lastChangedAt] properties: customerId: {$ref: '#/components/schemas/Id'} currency: {type: string, enum: [CNY]} totalReceivable: {$ref: '#/components/schemas/Money'} receivedAmount: {$ref: '#/components/schemas/Money'} outstandingReceivable: allOf: [{$ref: '#/components/schemas/Money'}] description: 待收客户款;仅正式非VOIDED应收结算单未收余额,不含待出账。 pendingBilling: allOf: [{$ref: '#/components/schemas/Money'}] description: 独立待出账信息,不得与outstandingReceivable相加形成运营资金卡片。 totalCost: {$ref: '#/components/schemas/Money'} paidCost: allOf: [{$ref: '#/components/schemas/Money'}] description: 已线下支付供应商款;不存在客户线下支付含义。 outstandingPayable: allOf: [{$ref: '#/components/schemas/Money'}] description: 待付供应商款;AP outstanding加未制单有效ON_ACCOUNT来源并去重。 asOf: {type: string, format: date-time} lastChangedAt: {type: string, format: date-time} AccountEntryRead: type: object required: [entryType, resourceId, resourceNo, occurredAt, debitAmount, creditAmount, currency, status] properties: entryType: {type: string, enum: [RECEIVABLE, RECEIPT]} resourceId: {$ref: '#/components/schemas/Id'} resourceNo: {type: string} occurredAt: {type: string, format: date-time} debitAmount: {$ref: '#/components/schemas/Money'} creditAmount: {$ref: '#/components/schemas/Money'} currency: {type: string, enum: [CNY]} status: {type: string} LedgerEntry: type: object required: [ledgerId, occurredAt, businessType, documentType, documentId, receivableChange, payableChange, outstandingReceivableAfter, operatorName] properties: ledgerId: {$ref: '#/components/schemas/Id'} occurredAt: {type: string, format: date-time} businessType: {$ref: '#/components/schemas/LedgerBusinessType'} documentType: {type: string} documentId: {$ref: '#/components/schemas/Id'} documentNo: {type: string} receivableChange: {$ref: '#/components/schemas/Money'} payableChange: {$ref: '#/components/schemas/Money'} outstandingReceivableAfter: {$ref: '#/components/schemas/Money'} operatorName: {type: string} remark: {type: string} FeeSource: type: object required: [feeSourceId, sourceSystem, sourceType, sourceFeeId, sourceVersion, direction, customerId, businessDate, feeItemName, amount, currency, reviewStatus, sourceStatus, statementGenerated] properties: feeSourceId: {$ref: '#/components/schemas/Id'} sourceSystem: {type: string, minLength: 1} sourceType: {$ref: '#/components/schemas/FeeSourceType'} sourceBusinessId: {type: string, description: 来源系统内可展示的正式业务标识;不得用 Finance 技术主键替代} sourceFeeId: {$ref: '#/components/schemas/Id'} sourceVersion: {type: integer, minimum: 1} direction: {$ref: '#/components/schemas/FeeDirection'} settlementMode: {$ref: '#/components/schemas/SettlementMode'} paidAt: {type: string, format: date-time} paymentMethod: {$ref: '#/components/schemas/CostPaymentMethod'} paymentReferenceNo: {type: string, maxLength: 128} paymentVoucherFileIds: type: array items: {type: string, minLength: 1} customerId: {$ref: '#/components/schemas/Id'} customerName: {type: string} supplierId: {$ref: '#/components/schemas/Id'} supplierName: {type: string} orderId: {$ref: '#/components/schemas/Id'} inboundId: {$ref: '#/components/schemas/Id'} inboundCode: {type: string} containerId: {$ref: '#/components/schemas/Id'} containerNo: {type: string} businessDate: {type: string, format: date} feeItemName: {type: string} quantity: {$ref: '#/components/schemas/Money'} unitPrice: {$ref: '#/components/schemas/Money'} amount: {$ref: '#/components/schemas/Money'} currency: {type: string, enum: [CNY]} reviewStatus: {$ref: '#/components/schemas/ReviewStatus'} sourceStatus: {type: string, enum: [AVAILABLE, LOCKED, BILLED, VOIDED, SUPERSEDED]} statementGenerated: {type: boolean} FeeSourceDetail: allOf: - $ref: '#/components/schemas/FeeSource' - type: object properties: reviewReason: {type: string} sourceHash: {type: string} operationLogs: type: array items: {$ref: '#/components/schemas/OperationLog'} FeePoolItemRead: type: object required: [poolItemId, direction, sourceType, sourceId, sourceVersion, feeItemName, amount, currency, status, createdAt] properties: poolItemId: {type: string} direction: {$ref: '#/components/schemas/FeeDirection'} sourceType: {type: string, enum: [FIRSTLEG_FEE, MANUAL_COST]} sourceId: {$ref: '#/components/schemas/Id'} sourceVersion: {type: integer, minimum: 1} orderId: {$ref: '#/components/schemas/Id'} inboundId: {$ref: '#/components/schemas/Id'} containerId: {$ref: '#/components/schemas/Id'} feeItemName: {type: string} amount: {$ref: '#/components/schemas/Money'} currency: {type: string, enum: [CNY]} status: {type: string} createdAt: {type: string, format: date-time} OperationLog: type: object required: [occurredAt, action, operatorName, result] properties: occurredAt: {type: string, format: date-time} action: {type: string} operatorName: {type: string} result: {type: string} remark: {type: string} ReviewRequest: type: object required: [action, expectedVersion] properties: action: {type: string, enum: [APPROVE, REJECT]} reason: {type: string, maxLength: 500} expectedVersion: {type: integer, minimum: 0} FeeSourceEditRequest: type: object required: [amount, reason, expectedVersion] properties: amount: {$ref: '#/components/schemas/Money'} reason: {type: string, minLength: 1, maxLength: 500} expectedVersion: {type: integer, minimum: 0} FeeSourceActionRequest: type: object required: [reason, expectedVersion] properties: reason: {type: string, minLength: 1, maxLength: 500} expectedVersion: {type: integer, minimum: 0} CustomerConfirmationRequest: type: object required: [expectedVersion] properties: expectedVersion: {type: integer, minimum: 0} ReconciliationSummary: type: object required: [statementId, statementNo, customerId, customerName, periodStart, periodEnd, creditDays, currency, lineCount, sourceCount, sourceAmount, adjustmentAmount, totalReceivable, receivedAmount, outstandingAmount, settled, status, version, customerConfirmationStatus, createdBy, createdAt, updatedBy, updatedAt] properties: statementId: {$ref: '#/components/schemas/Id'} statementNo: {type: string, pattern: '^REC-\d{6}-\d{4}$', example: REC-260818-0001} customerId: {$ref: '#/components/schemas/Id'} customerName: {type: string} periodStart: {type: string, format: date} periodEnd: {type: string, format: date} creditDays: {type: integer, minimum: 0} currency: {type: string, enum: [CNY]} lineCount: {type: integer, minimum: 0, description: 对账单费用明细数量} sourceCount: {type: integer, minimum: 0, description: 去重后的费用来源数量} sourceAmount: {$ref: '#/components/schemas/Money'} adjustmentAmount: {$ref: '#/components/schemas/Money'} totalReceivable: {$ref: '#/components/schemas/Money'} receivedAmount: {$ref: '#/components/schemas/Money'} outstandingAmount: {$ref: '#/components/schemas/Money'} lastReceiptAt: {type: string, format: date-time} submittedAt: {type: string, format: date-time} reviewedAt: {type: string, format: date-time} issuedAt: {type: string, format: date-time} settled: {type: boolean} status: {$ref: '#/components/schemas/ReconciliationStatus'} version: {type: integer, minimum: 0} customerConfirmationStatus: {type: string, enum: [NOT_REQUIRED, PENDING_CONFIRMATION, CONFIRMED]} customerConfirmedBy: {$ref: '#/components/schemas/Id'} customerConfirmedByName: {type: string} customerConfirmedAt: {type: string, format: date-time} createdBy: {$ref: '#/components/schemas/Id'} createdByName: {type: string, description: 创建时操作人名称快照;历史数据可能为空} createdAt: {type: string, format: date-time} updatedBy: {$ref: '#/components/schemas/Id'} updatedByName: {type: string, description: 最后修改时操作人名称快照;历史数据可能为空} updatedAt: {type: string, format: date-time} remark: {type: string} ReconciliationDetail: allOf: - $ref: '#/components/schemas/ReconciliationSummary' - type: object required: [lines, paymentHistory, revisions] properties: remark: {type: string} lines: type: array items: {$ref: '#/components/schemas/ReconciliationLine'} paymentHistory: type: array items: {$ref: '#/components/schemas/SettlementTransaction'} revisions: type: array items: {$ref: '#/components/schemas/ReconciliationRevision'} ReconciliationLine: type: object required: [statementLineId, feeSourceId, sourceVersion, direction, sourceType, feeItemName, sourceAmount, statementAmount, currency] properties: statementLineId: {$ref: '#/components/schemas/Id'} feeSourceId: {$ref: '#/components/schemas/Id'} sourceVersion: {type: integer, minimum: 1} sourceHash: {type: string} direction: {type: string, enum: [RECEIVABLE, PAYABLE]} sourceType: {type: string, enum: [INBOUND_FEE, CONTAINER_FEE]} sourceNo: {type: string} orderId: {$ref: '#/components/schemas/Id'} inboundId: {$ref: '#/components/schemas/Id'} containerId: {$ref: '#/components/schemas/Id'} inboundCode: {type: string} containerNo: {type: string} businessDate: {type: string, format: date} quantity: {$ref: '#/components/schemas/Money'} unitPrice: {$ref: '#/components/schemas/Money'} feeItemName: {type: string} sourceAmount: {$ref: '#/components/schemas/Money'} statementAmount: {$ref: '#/components/schemas/Money'} currency: {type: string, enum: [CNY]} adjustmentReason: {type: string} ReconciliationRevision: type: object required: [revisionNo, action, beforeAmount, afterAmount, operatorId, occurredAt] properties: revisionNo: {type: integer, minimum: 1} action: {type: string, enum: [CREATE, SUBMIT, APPROVE, REJECT, ISSUE, ADJUST, VOID, REOPEN]} beforeAmount: {$ref: '#/components/schemas/Money'} afterAmount: {$ref: '#/components/schemas/Money'} reason: {type: string} operatorId: {$ref: '#/components/schemas/Id'} operatorName: {type: string, description: 操作发生时的名称快照} occurredAt: {type: string, format: date-time} StatementRead: type: object required: [id, customerId, billNo, billDate, dueDate, totalAmount, receivedAmount, outstandingAmount, currency, status, version] properties: id: {$ref: '#/components/schemas/Id'} customerId: {$ref: '#/components/schemas/Id'} billNo: {type: string} customerName: {type: string} billDate: {type: string, format: date} dueDate: {type: string, format: date} totalAmount: {$ref: '#/components/schemas/Money'} receivedAmount: {$ref: '#/components/schemas/Money'} outstandingAmount: {$ref: '#/components/schemas/Money'} currency: {type: string, enum: [CNY]} status: {type: string, enum: [DRAFT, ISSUED, PARTIALLY_PAID, PAID, VOIDED]} version: {type: integer, minimum: 0} createdBy: {$ref: '#/components/schemas/Id'} createdByName: {type: string, description: 创建时操作人名称快照;历史数据可能为空} createdAt: {type: string, format: date-time} updatedBy: {$ref: '#/components/schemas/Id'} updatedByName: {type: string, description: 最后修改时操作人名称快照;历史数据可能为空} updatedAt: {type: string, format: date-time} StatementLineRead: type: object required: [id, sourceType, sourceId, sourceVersion, feeItemName, amount, currency] properties: id: {$ref: '#/components/schemas/Id'} sourceType: {type: string} sourceId: {$ref: '#/components/schemas/Id'} sourceVersion: {type: integer, minimum: 1} orderId: {$ref: '#/components/schemas/Id'} inboundId: {$ref: '#/components/schemas/Id'} inboundCode: {type: string, description: 入仓码业务编号;费用未关联入仓码时为空} feeItemCode: {type: string} feeItemName: {type: string} amount: {$ref: '#/components/schemas/Money'} currency: {type: string, enum: [CNY]} StatementDetailRead: type: object required: [statement, lines] properties: statement: {$ref: '#/components/schemas/StatementRead'} lines: type: array items: {$ref: '#/components/schemas/StatementLineRead'} ReceivableSettlementRead: type: object required: [id, customerId, settlementNo, billDate, dueDate, receivableAmount, receivedAmount, outstandingAmount, currency, status, version] properties: id: {$ref: '#/components/schemas/Id'} customerId: {$ref: '#/components/schemas/Id'} settlementNo: {type: string, pattern: '^AR-\d{6}-\d{4}$', example: AR-260818-0001} billDate: {type: string, format: date} dueDate: {type: string, format: date} receivableAmount: {$ref: '#/components/schemas/Money'} receivedAmount: {$ref: '#/components/schemas/Money'} outstandingAmount: {$ref: '#/components/schemas/Money'} currency: {type: string, enum: [CNY]} status: {type: string} version: {type: integer, minimum: 0} PayableSettlementRead: type: object required: [id, customerId, settlementNo, costType, feeItemName, payableAmount, paidAmount, outstandingAmount, currency, status, createdAt, version] properties: id: {$ref: '#/components/schemas/Id'} customerId: {$ref: '#/components/schemas/Id'} settlementNo: {type: string, pattern: '^AP-\d{6}-\d{4}$', example: AP-260818-0001} costType: {type: string, enum: [SINGLE_ORDER, CONTAINER_SHARED]} orderId: {$ref: '#/components/schemas/Id'} inboundId: {$ref: '#/components/schemas/Id'} containerId: {$ref: '#/components/schemas/Id'} supplierName: {type: string} feeItemName: {type: string} payableAmount: {$ref: '#/components/schemas/Money'} paidAmount: {$ref: '#/components/schemas/Money'} outstandingAmount: {$ref: '#/components/schemas/Money'} currency: {type: string, enum: [CNY]} status: {type: string} createdAt: {type: string, format: date-time} version: {type: integer, minimum: 0} CreateReconciliationRequest: type: object required: [customerId, currency, generationMode, periodStart, periodEnd] description: SELECTED 模式 feeSourceIds 至少一项;BY_CUTOFF 模式由服务端按 periodEnd 选取合格来源。来源金额只能取服务端快照。 properties: customerId: {$ref: '#/components/schemas/Id'} currency: {type: string, enum: [CNY]} generationMode: {type: string, enum: [BY_CUTOFF, SELECTED]} feeSourceIds: type: array minItems: 1 uniqueItems: true items: {$ref: '#/components/schemas/Id'} periodStart: {type: string, format: date} periodEnd: {type: string, format: date} remark: {type: string, maxLength: 500} oneOf: - properties: generationMode: {type: string, enum: [BY_CUTOFF]} not: {required: [feeSourceIds]} - required: [feeSourceIds] properties: generationMode: {type: string, enum: [SELECTED]} ReconciliationActionRequest: type: object required: [action, expectedVersion] description: REJECT/ADJUST/VOID/REOPEN 必须填写 reason;ADJUST 必须提交至少一条 adjustmentLines,且调整后总额不得低于已收金额。 properties: action: {type: string, enum: [SUBMIT, APPROVE, REJECT, ISSUE, ADJUST, VOID, REOPEN]} reason: {type: string, maxLength: 500} expectedVersion: {type: integer, minimum: 0} adjustmentLines: type: array minItems: 1 items: {$ref: '#/components/schemas/StatementAdjustmentLineRequest'} oneOf: - properties: action: {type: string, enum: [SUBMIT, APPROVE, ISSUE]} - required: [reason] properties: action: {type: string, enum: [REJECT, VOID, REOPEN]} reason: {type: string, minLength: 1, maxLength: 500} - required: [reason, adjustmentLines] properties: action: {type: string, enum: [ADJUST]} reason: {type: string, minLength: 1, maxLength: 500} StatementAdjustmentLineRequest: type: object required: [statementLineId, adjustedAmount, reason] properties: statementLineId: {$ref: '#/components/schemas/Id'} adjustedAmount: {$ref: '#/components/schemas/Money'} reason: {type: string, minLength: 1, maxLength: 500} SettlementSummary: type: object required: [settlementId, settlementNo, direction, currency, totalAmount, paidAmount, outstandingAmount, generatedDate, dueDate, paymentStatus, status, version] properties: settlementId: {$ref: '#/components/schemas/Id'} settlementNo: {type: string, pattern: '^(AR|AP)-\d{6}-\d{4}$', example: AR-260818-0001} direction: {$ref: '#/components/schemas/FeeDirection'} customerId: {$ref: '#/components/schemas/Id'} customerName: {type: string} supplierId: {$ref: '#/components/schemas/Id'} supplierName: {type: string} reconciliationStatementId: {$ref: '#/components/schemas/Id'} businessPeriod: {type: string} currency: {type: string, enum: [CNY]} totalAmount: {$ref: '#/components/schemas/Money'} paidAmount: {$ref: '#/components/schemas/Money'} outstandingAmount: {$ref: '#/components/schemas/Money'} generatedDate: {type: string, format: date} dueDate: {type: string, format: date} paymentStatus: {$ref: '#/components/schemas/PaymentStatus'} status: {$ref: '#/components/schemas/SettlementStatus'} version: {type: integer, minimum: 0} SettlementDetail: allOf: - $ref: '#/components/schemas/SettlementSummary' - type: object required: [lines, transactions, revisions] properties: lines: type: array items: {$ref: '#/components/schemas/FeeSource'} transactions: type: array items: {$ref: '#/components/schemas/SettlementTransaction'} revisions: type: array items: {$ref: '#/components/schemas/SettlementRevision'} SettlementRevision: type: object required: [revisionNo, action, beforeAmount, afterAmount, operatorId, occurredAt] properties: revisionNo: {type: integer, minimum: 1} action: {type: string, enum: [CREATE, ISSUE, RECEIPT, PAYMENT, ADJUST, VOID, REOPEN]} beforeAmount: {$ref: '#/components/schemas/Money'} afterAmount: {$ref: '#/components/schemas/Money'} reason: {type: string} operatorId: {$ref: '#/components/schemas/Id'} operatorName: {type: string, description: 操作发生时的名称快照} occurredAt: {type: string, format: date-time} CreateReceivableSettlementRequest: type: object required: [reconciliationStatementId, currency] description: 客户、金额、期间和默认 30 天到期日均从已出账对账单与客户账期派生,不接受前端覆盖。 properties: reconciliationStatementId: {$ref: '#/components/schemas/Id'} currency: {type: string, enum: [CNY]} CreatePayableSettlementRequest: type: object required: [customerId, supplierId, feeSourceIds, dueDate, currency] properties: customerId: {$ref: '#/components/schemas/Id'} supplierId: allOf: [{$ref: '#/components/schemas/Id'}] description: Warehouse ACTIVE 供应商 ID;必须与全部费用来源解析出的唯一类别匹配。 feeSourceIds: type: array minItems: 1 uniqueItems: true items: {$ref: '#/components/schemas/Id'} dueDate: {type: string, format: date} currency: {type: string, enum: [CNY]} SettlementTransaction: type: object required: [transactionId, transactionType, transactionDate, amount, method, createdBy, createdAt] properties: transactionId: {$ref: '#/components/schemas/Id'} transactionType: {type: string, enum: [RECEIPT, PAYMENT]} transactionDate: {type: string, format: date} amount: {$ref: '#/components/schemas/PositiveMoney'} method: {type: string, enum: [BANK_TRANSFER, CASH, OTHER]} referenceNo: {type: string} voucherFileIds: type: array items: {$ref: '#/components/schemas/Id'} createdBy: {$ref: '#/components/schemas/Id'} createdByName: {type: string, description: 登记时操作人名称快照;历史数据可能为空} createdAt: {type: string, format: date-time} remark: {type: string} ReceiptAllocationRequest: type: object required: [settlementId, amount] properties: settlementId: {$ref: '#/components/schemas/Id'} amount: {$ref: '#/components/schemas/PositiveMoney'} CreateReceiptRequest: type: object required: [customerId, receivedDate, amount, paymentMethod, voucherFileIds, allocations] properties: customerId: {$ref: '#/components/schemas/Id'} receivedDate: {type: string, format: date} amount: {$ref: '#/components/schemas/PositiveMoney'} currency: {type: string, enum: [CNY], default: CNY} paymentMethod: {type: string, enum: [BANK_TRANSFER, CASH, OTHER]} voucherFileIds: type: array minItems: 1 uniqueItems: true items: {$ref: '#/components/schemas/Id'} allocations: type: array minItems: 1 items: {$ref: '#/components/schemas/ReceiptAllocationRequest'} remark: {type: string, maxLength: 500} ClientReceiptRead: type: object required: [id, receiptNo, receivedAmount, receivedAt, paymentMethod, currency, status, allocations] properties: id: {$ref: '#/components/schemas/Id'} receiptNo: {type: string} receivedAmount: {$ref: '#/components/schemas/Money'} receivedAt: {type: string, format: date-time} paymentMethod: {type: string, enum: [BANK_TRANSFER, CASH, OTHER]} currency: {type: string, enum: [CNY]} status: {type: string, enum: [CONFIRMED]} allocations: type: array items: {$ref: '#/components/schemas/ClientReceiptAllocationRead'} PlatformReceiptRead: type: object required: [id, customerId, receiptNo, receivedAmount, receivedAt, paymentMethod, voucherFileIds, currency, status, version, allocations] properties: id: {$ref: '#/components/schemas/Id'} customerId: {$ref: '#/components/schemas/Id'} receiptNo: {type: string} receivedAmount: {$ref: '#/components/schemas/Money'} receivedAt: {type: string, format: date-time} paymentMethod: {type: string, enum: [BANK_TRANSFER, CASH, OTHER]} voucherNo: {type: string} voucherFileIds: type: array items: {type: string} currency: {type: string, enum: [CNY]} status: {type: string} remark: {type: string} version: {type: integer, minimum: 0} allocations: type: array items: {$ref: '#/components/schemas/ClientReceiptAllocationRead'} ClientReceiptAllocationRead: type: object required: [billId, billNo, appliedAmount] properties: billId: {$ref: '#/components/schemas/Id'} billNo: {type: string} appliedAmount: {$ref: '#/components/schemas/Money'} ResourceResult: type: object required: [id, resourceNo, status] properties: id: {$ref: '#/components/schemas/Id'} resourceNo: {type: string} status: {type: string} version: {type: integer, minimum: 0} CreateSettlementPaymentRequest: type: object required: [transactionDate, amount, currency, method, voucherFileIds, expectedVersion] description: 仅用于 PAYABLE 结算单人工付款;amount 必须大于 0 且不得超过未付余额,File 校验必须 fail-closed。 properties: transactionDate: {type: string, format: date} amount: {$ref: '#/components/schemas/PositiveMoney'} currency: {type: string, enum: [CNY]} method: {type: string, enum: [BANK_TRANSFER, CASH, OTHER]} referenceNo: {type: string} voucherFileIds: type: array minItems: 1 uniqueItems: true items: {$ref: '#/components/schemas/Id'} expectedVersion: {type: integer, minimum: 0} remark: {type: string, maxLength: 500} SettlementActionRequest: type: object additionalProperties: false properties: action: {type: string, enum: [VOID, REOPEN]} reason: {type: string, minLength: 1, maxLength: 500} expectedVersion: {type: integer, minimum: 0} required: [action, reason, expectedVersion] ErrorEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message] properties: code: {type: string} message: {type: string} FeeSourceEventResultEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/FeeSourceEventResult'} AccountPageEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data, page] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/AccountSummary'}} page: {$ref: '#/components/schemas/PageMeta'} AccountDetailEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/AccountDetail'} LedgerPageEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data, page] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/LedgerEntry'}} page: {$ref: '#/components/schemas/PageMeta'} FeeSourcePageEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data, page] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/FeeSource'}} page: {$ref: '#/components/schemas/PageMeta'} FeeSourceDetailEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/FeeSourceDetail'} ReconciliationPageEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data, page] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/ReconciliationSummary'}} page: {$ref: '#/components/schemas/PageMeta'} ReconciliationDetailEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/ReconciliationDetail'} SettlementPageEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data, page] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/SettlementSummary'}} page: {$ref: '#/components/schemas/PageMeta'} SettlementDetailEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/SettlementDetail'} CustomerAccountReadEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/CustomerAccountRead'} CustomerAccountSummaryEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/CustomerAccountSummary'} FeePoolReadEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/FeePoolItemRead'}} StatementListReadEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/ReconciliationSummary'}} StatementDetailReadEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/StatementDetailRead'} ReceivableSettlementListReadEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/ReceivableSettlementRead'}} PayableSettlementListReadEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/PayableSettlementRead'}} ClientReceiptListReadEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/ClientReceiptRead'}} PlatformReceiptListReadEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {type: array, items: {$ref: '#/components/schemas/PlatformReceiptRead'}} ResourceResultEnvelope: allOf: - $ref: '#/components/schemas/TraceMeta' - type: object required: [code, message, data] properties: code: {type: string, example: '200'} message: {type: string} data: {$ref: '#/components/schemas/ResourceResult'} responses: AccountPageResponse: description: 客户账户派生汇总分页。 content: {application/json: {schema: {$ref: '#/components/schemas/AccountPageEnvelope'}}} AccountDetailResponse: description: 客户账户派生详情。 content: {application/json: {schema: {$ref: '#/components/schemas/AccountDetailEnvelope'}}} LedgerPageResponse: description: 客户财务派生流水分页。 content: {application/json: {schema: {$ref: '#/components/schemas/LedgerPageEnvelope'}}} FeeSourcePageResponse: description: 费用来源分页。 content: {application/json: {schema: {$ref: '#/components/schemas/FeeSourcePageEnvelope'}}} FeeSourceDetailResponse: description: 费用来源详情。 content: {application/json: {schema: {$ref: '#/components/schemas/FeeSourceDetailEnvelope'}}} ReconciliationPageResponse: description: 客户对账单分页。 content: {application/json: {schema: {$ref: '#/components/schemas/ReconciliationPageEnvelope'}}} ReconciliationDetailResponse: description: 客户对账单详情。 content: {application/json: {schema: {$ref: '#/components/schemas/ReconciliationDetailEnvelope'}}} SettlementPageResponse: description: 结算单分页。 content: {application/json: {schema: {$ref: '#/components/schemas/SettlementPageEnvelope'}}} SettlementDetailResponse: description: 结算单详情。 content: {application/json: {schema: {$ref: '#/components/schemas/SettlementDetailEnvelope'}}} CustomerAccountReadResponse: description: 当前固定 DTO 客户账户及流水。 content: {application/json: {schema: {$ref: '#/components/schemas/CustomerAccountReadEnvelope'}}} CustomerAccountSummaryResponse: description: 客户正式结算口径财务汇总。 content: {application/json: {schema: {$ref: '#/components/schemas/CustomerAccountSummaryEnvelope'}}} FeePoolReadResponse: description: 当前固定 DTO 客户应收应付费用池。 content: {application/json: {schema: {$ref: '#/components/schemas/FeePoolReadEnvelope'}}} StatementListReadResponse: description: 客户对账单业务摘要列表,包含期间、金额、来源数量和流程时间。 content: {application/json: {schema: {$ref: '#/components/schemas/StatementListReadEnvelope'}}} StatementDetailReadResponse: description: 当前固定 DTO 客户对账单详情。 content: {application/json: {schema: {$ref: '#/components/schemas/StatementDetailReadEnvelope'}}} ReceivableSettlementListReadResponse: description: 当前固定 DTO 应收结算单列表。 content: {application/json: {schema: {$ref: '#/components/schemas/ReceivableSettlementListReadEnvelope'}}} PayableSettlementListReadResponse: description: 当前固定 DTO 应付结算单列表。 content: {application/json: {schema: {$ref: '#/components/schemas/PayableSettlementListReadEnvelope'}}} ClientReceiptListReadResponse: description: 客户专用收款 DTO 列表,不含凭证和内部字段。 content: {application/json: {schema: {$ref: '#/components/schemas/ClientReceiptListReadEnvelope'}}} PlatformReceiptListReadResponse: description: 平台专用收款 DTO 列表,包含凭证引用和账单分配。 content: {application/json: {schema: {$ref: '#/components/schemas/PlatformReceiptListReadEnvelope'}}} ResourceResultResponse: description: 写操作资源结果。 content: {application/json: {schema: {$ref: '#/components/schemas/ResourceResultEnvelope'}}} BusinessError: description: 稳定业务错误。 content: {application/json: {schema: {$ref: '#/components/schemas/ErrorEnvelope'}}}