财务ERP - 进销存模块(采购与台账)详细开发流程文档
财务ERP - 进销存模块(采购与台账)详细开发流程文档
文档说明
本文档为20260618进销存模块梳理后的详细开发流程文档,面向开发团队,明确开发的顺序、依赖、任务拆解、开发步骤及验收标准。重点覆盖采购模块与财务模块的互通,以及台账管理的完整实现。
重要说明:本文档仅包含业务需求、流程设计、接口契约和验收标准,不包含具体代码实现。请根据现有系统架构自行设计代码结构,避免与现有代码产生冲突。
版本历史
| 版本 | 日期 | 修改内容 | 作者 |
|---|---|---|---|
| v1.0 | 2026-06-25 | 初稿,基于20260618需求梳理 | 架构组 |
1. 模块依赖关系与开发顺序
1.1 模块依赖图
┌─────────────────────────────────────────────────────────────────────────────┐
│ 开发依赖关系(自上而下) │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────┐ │
│ │ 基础配置模块 │ ◄── 第1周:无依赖,可优先开发 │
│ │ - 采购账户配置 │ │
│ │ - 供应商收款账户 │ │
│ │ - 进销存全局配置 │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ 采购订单(会计版) │ ◄── 第2周:依赖基础配置 + ERP供应商/SKU数据 │
│ │ - 订单创建/查询 │ │
│ │ - 付款/退款/入库 │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ ◄── 第3周:依赖采购订单数据 │
│ │ 采购账户台账 │ │
│ │ - 台账列表查询 │ │
│ │ - 台账付款 │ │
│ │ - 批量对账单上传 │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ ◄── 第4周:依赖采购订单 + 税局API │
│ │ 发票台账 │ │
│ │ - 发票同步 │ │
│ │ - 发票入账 │ │
│ │ - 供应商台账查询 │ │
│ └──────────┬──────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────┐ ◄── 第5周:依赖库存变动数据 │
│ │ 库存台账 │ │
│ │ - 移动加权平均计算 │ │
│ │ - 汇总账/明细账 │ │
│ │ - 勾稽校验 │ │
│ └─────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
1.2 开发顺序总览
| 阶段 | 周期 | 模块 | 产出物 | 依赖 |
|---|---|---|---|---|
| 阶段一 | 第1周 | 基础配置模块 | 采购账户CRUD、供应商收款账户管理、配置校验逻辑 | 现有科目表、辅助核算表 |
| 阶段二 | 第2-3周 | 采购订单(会计版) | 订单创建、付款、退款、入库、状态管理、凭证生成 | 阶段一 + ERP供应商/SKU数据 |
| 阶段三 | 第3-4周 | 采购账户台账 | 台账列表、台账付款、批量上传对账单、图表统计 | 阶段二 |
| 阶段四 | 第4-5周 | 发票台账与供应商台账 | 发票同步、发票入账、供应商汇总查询、未开票导出 | 阶段二 + 税局API |
| 阶段五 | 第5-6周 | 库存台账(本地仓库) | 移动加权平均计算、汇总账、明细账、勾稽校验 | 阶段二 + 阶段四 |
| 阶段六 | 第6周 | 联调与测试 | 端到端流程测试、性能测试、Bug修复 | 全部模块 |
2. 数据库设计(新增表)
2.1 新增表清单
| 表名 | 说明 | 关联模块 |
|---|---|---|
fin_purchase_account |
采购账户表 | 基础配置 |
fin_supplier_bank |
供应商收款账户表 | 基础配置 |
fin_purchase_order |
采购订单表(会计版) | 采购订单 |
fin_purchase_payment |
采购付款明细表 | 采购订单/台账 |
fin_invoice |
发票台账表 | 发票台账 |
fin_warehouse_stock |
库存余额表 | 库存台账 |
fin_inventory_transaction |
库存变动明细表 | 库存台账 |
2.2 表结构设计要点
2.2.1 采购账户表 fin_purchase_account
| 字段 | 类型 | 说明 | 校验规则 |
|---|---|---|---|
id |
bigint unsigned | 主键 | 自增 |
groupid |
bigint unsigned | 租户ID | 必填,索引 |
account_name |
varchar(100) | 账户名称 | 必填,唯一(同租户下) |
account_type |
tinyint | 1-现金,2-账期 | 必填,默认1 |
related_subject_id |
bigint unsigned | 对应会计科目ID | 必填,关联fin_accounting_subjects |
config_json |
json | 完整配置 | 见下方结构 |
is_enabled |
tinyint | 是否启用 | 默认1 |
created_time |
datetime | 创建时间 | 自动 |
updated_time |
datetime | 更新时间 | 自动 |
config_json 结构:
{
"feeTypes": [
{ "code": "GOODS", "name": "货款", "isSupplierRelated": true },
{ "code": "FREIGHT", "name": "运费", "isSupplierRelated": true },
{ "code": "SERVICE", "name": "跨境直采手续费", "isSupplierRelated": false }
],
"paySubjectMapping": {
"GOODS": { "debitSubjectId": 101, "creditSubjectId": 201 },
"FREIGHT": { "debitSubjectId": 102, "creditSubjectId": 201 }
},
"refundMapping": {
"GOODS": { "debitSubjectId": 201, "creditSubjectId": 101 }
},
"creditPayAccounts": [
{ "cashAccountId": 1, "subjectMapping": { "debit": 301, "credit": 201 } }
]
}
2.2.2 供应商收款账户表 fin_supplier_bank
| 字段 | 类型 | 说明 | 校验规则 |
|---|---|---|---|
id |
bigint unsigned | 主键 | 自增 |
groupid |
bigint unsigned | 租户ID | 必填 |
supplier_id |
bigint unsigned | 供应商ID | 必填,索引 |
bank_name |
varchar(100) | 开户银行 | 可选 |
account_name |
varchar(100) | 收款账户名称 | 必填 |
account_no |
varchar(50) | 收款账号 | 必填 |
is_default |
tinyint | 是否默认 | 默认0,同供应商仅一个默认 |
is_enabled |
tinyint | 是否启用 | 默认1 |
created_time |
datetime | 创建时间 | 自动 |
2.2.3 采购订单表 fin_purchase_order
| 字段 | 类型 | 说明 | 校验规则 |
|---|---|---|---|
id |
bigint unsigned | 主键 | 自增 |
groupid |
bigint unsigned | 租户ID | 必填,索引 |
supplier_id |
bigint unsigned | 供应商ID | 必填,关联t_erp_supplier |
purchase_account_id |
bigint unsigned | 采购账户ID | 必填 |
sku |
varchar(50) | SKU编码 | 必填 |
warehouse_code |
varchar(50) | 入库仓库编码 | 必填 |
order_qty |
decimal(12,2) | 订单数量 | >0 |
unit_price |
decimal(18,4) | 采购单价 | ≥0 |
total_amount |
decimal(18,2) | 订单金额 | = order_qty × unit_price |
paid_amount |
decimal(18,2) | 累计已付 | ≥0,≤total_amount |
inventory_value |
decimal(18,2) | 库存价值 | ≥0 |
invoiced_amount |
decimal(18,2) | 已开票金额 | ≥0,≤total_amount |
status_order |
tinyint | 1-草稿,2-已确认,3-已完成,4-已取消 | 默认1 |
status_pay |
tinyint | 1-未付款,2-部分付款,3-已付款,4-退款中,5-已退款 | 默认1 |
status_inv |
tinyint | 1-未开票,2-部分开票,3-已开票 | 默认1 |
status_stock |
tinyint | 1-未收货,2-部分收货,3-已收货 | 默认1 |
2.2.4 采购付款明细表 fin_purchase_payment
| 字段 | 类型 | 说明 |
|---|---|---|
id |
bigint unsigned | 主键 |
purchase_order_id |
bigint unsigned | 关联采购订单 |
purchase_account_id |
bigint unsigned | 使用的采购账户 |
voucher_id |
bigint unsigned | 生成的凭证ID |
fee_type |
varchar(50) | 费用类型(货款/运费/手续费) |
is_supplier_related |
tinyint | 是否归属供应商款项 |
amount |
decimal(18,2) | 支付金额 |
payment_date |
date | 付款日期 |
is_refund |
tinyint | 是否退款 |
refund_original_id |
bigint unsigned | 退款对应的原付款明细ID |
status |
tinyint | 0-正常,1-已退款 |
2.2.5 发票台账表 fin_invoice
| 字段 | 类型 | 说明 |
|---|---|---|
id |
bigint unsigned | 主键 |
invoice_no |
varchar(100) | 数电发票号码(唯一) |
invoice_type |
varchar(20) | 数电专票/普票/传统 |
groupid |
bigint unsigned | 入账账套ID |
supplier_id |
bigint unsigned | 匹配的供应商ID |
seller_name |
varchar(200) | 销方名称 |
seller_tax_no |
varchar(50) | 销方税号 |
invoice_date |
date | 开票日期 |
amount_with_tax |
decimal(18,2) | 价税合计 |
amount_without_tax |
decimal(18,2) | 不含税金额 |
tax_amount |
decimal(18,2) | 税额 |
status |
varchar(20) | NORMAL/CANCELLED/RED_ALL/RED_PART/ABNORMAL |
posting_status |
tinyint | 0-未入账,1-已入账 |
voucher_id |
bigint unsigned | 入账凭证ID |
2.2.6 库存余额表 fin_warehouse_stock
| 字段 | 类型 | 说明 |
|---|---|---|
id |
bigint unsigned | 主键 |
groupid |
bigint unsigned | 租户ID |
sku |
varchar(50) | SKU编码 |
warehouse_code |
varchar(50) | 仓库编码 |
warehouse_type |
tinyint | 1-本地,2-FBA |
current_qty |
decimal(12,2) | 当前数量 |
current_amount |
decimal(18,2) | 当前金额 |
unit_cost |
decimal(18,4) | 移动平均单价 |
period |
varchar(6) | 会计期间(YYYYMM) |
2.2.7 库存变动明细表 fin_inventory_transaction
| 字段 | 类型 | 说明 |
|---|---|---|
id |
bigint unsigned | 主键 |
groupid |
bigint unsigned | 租户ID |
sku |
varchar(50) | SKU编码 |
warehouse_code |
varchar(50) | 仓库编码 |
trans_date |
date | 变动日期 |
trans_type |
varchar(50) | PURCHASE_IN/SALE_OUT/TRANSFER_IN/ADJUST |
source_doc_id |
varchar(100) | 来源单据号 |
qty_change |
decimal(12,2) | 正为入库,负为出库 |
amount_change |
decimal(18,2) | 金额变动 |
unit_cost |
decimal(18,4) | 发生时单价 |
voucher_id |
bigint unsigned | 关联凭证ID |
3. 服务层开发任务(按顺序执行)
3.1 阶段一:基础配置模块(第1周)
3.1.1 任务清单
| 序号 | 任务 | 服务类 | 方法/职责 | 验收标准 |
|---|---|---|---|---|
| 1 | 采购账户CRUD | PurchaseAccountService |
创建、更新、删除、查询列表 | 可正常增删改查,配置JSON正确序列化 |
| 2 | 采购账户配置校验 | PurchaseAccountValidator |
校验费用类型、科目映射完整性 | 配置不完整时拒绝保存并提示 |
| 3 | 供应商收款账户管理 | SupplierBankService |
保存、更新、设置默认、查询 | 支持多账户、默认账户唯一 |
| 4 | 进销存全局配置 | InventoryConfigService |
获取配置、更新配置 | 支持配置成本方法(仅移动加权) |
3.1.2 开发步骤
- 创建实体类:映射新增表,使用MyBatis-Plus注解,JSON字段配置TypeHandler
- 创建Mapper接口:继承BaseMapper,定义必要的自定义查询方法
- 实现Service层: - 创建:校验参数完整性、唯一性,保存配置JSON - 更新:校验是否被引用,合并配置 - 删除:软删除或校验无引用后删除 - 列表:支持按账套、类型筛选
- 实现Controller层:定义REST接口,参数校验,统一响应格式
- 单元测试:覆盖CRUD各场景
3.1.3 接口契约
创建采购账户
POST /api/finance/purchase/account/create- 请求体:
{
"groupid": 1001,
"accountName": "公户现金",
"accountType": 1,
"relatedSubjectId": 2384,
"configJson": { ... }
}
- 响应:
{ "code": 200, "data": { "id": 1 } }
查询采购账户列表
GET /api/finance/purchase/account/list?groupid=1001&type=1- 响应:账户列表JSON
3.1.4 测试用例
| 测试场景 | 预期结果 |
|---|---|
| 创建现金类账户,配置完整 | 保存成功 |
| 创建账期类账户,未配置cashAccount列表 | 校验失败,提示配置不完整 |
| 删除正在使用的账户 | 返回错误,提示账户已被引用 |
| 设置默认收款账户 | 该账户is_default=1,其他同供应商账户=0 |
3.2 阶段二:采购订单(会计版)(第2-3周)
3.2.1 任务清单
| 序号 | 任务 | 服务类 | 方法/职责 | 验收标准 |
|---|---|---|---|---|
| 1 | 采购订单创建 | PurchaseOrderService |
创建订单,初始状态为草稿 | 订单保存,状态正确 |
| 2 | 采购订单确认 | PurchaseOrderService |
确认订单,状态变为已确认 | 仅草稿状态可确认 |
| 3 | 采购订单付款 | PurchasePaymentService |
付款,生成凭证,更新状态 | 凭证生成正确,状态更新 |
| 4 | 采购订单退款 | PurchasePaymentService |
退款,生成红字凭证,更新状态 | 凭证方向相反,状态更新 |
| 5 | 采购入库 | PurchaseOrderService |
入库,更新库存,生成凭证 | 库存更新,凭证生成 |
| 6 | 采购退货 | PurchaseOrderService |
退货,更新库存,生成凭证 | 库存回退,凭证生成 |
| 7 | 订单列表查询 | PurchaseOrderService |
分页查询,多维度筛选 | 筛选条件生效,状态展示正确 |
3.2.2 订单状态机设计
订单状态(status_order)流转:
1-草稿→ 确认 →2-已确认→ 付款+入库完成 →3-已完成1-草稿→4-已取消(仅草稿可取消)2-已确认→ 任何状态 →3-已完成(所有子状态均为完成)
付款状态(status_pay)流转:
1-未付款→ 付款金额>0且<总额 →2-部分付款1-未付款或2-部分付款→ 付款金额=总额 →3-已付款3-已付款→ 发起退款 →4-退款中→ 退款完成 →5-已退款
库存状态(status_stock)流转:
1-未收货→ 入库数量>0且<订单数量 →2-部分收货1-未收货或2-部分收货→ 入库数量=订单数量 →3-已收货
发票状态(status_inv)流转:
1-未开票→ 开票金额>0且<总额 →2-部分开票1-未开票或2-部分开票→ 开票金额=总额 →3-已开票
3.2.3 凭证生成规则
场景A:现金类账户付款
- 付款凭证: - 借:预付账款-ERP采购供应商(供应商辅助核算) - 贷:对应现金科目(如银行存款-浦发)
- 在途库存凭证(同时生成): - 借:在途库存_XX本地仓库(存货辅助核算) - 贷:预付账款-ERP在途发票
场景B:账期类账户付款
- 付款凭证: - 借:预付账款-ERP采购供应商(供应商辅助核算) - 贷:应付账款_XXX(账期账户对应科目)
- 在途库存凭证(同时生成): - 借:在途库存_XX本地仓库(存货辅助核算) - 贷:预付账款-ERP在途发票
场景C:入库
- 借:库存商品_XX本地仓库(存货辅助核算)
- 贷:在途库存_XX本地仓库
场景D:发票入账
- 借:预付账款-ERP在途发票
- 贷:预付账款-ERP采购供应商(供应商辅助核算)
3.2.4 接口契约
采购订单付款
POST /api/finance/purchase/order/pay- 请求体:
{
"orderId": 1001,
"accountId": 5,
"feeType": "GOODS",
"amount": 10000.00,
"paymentDate": "2026-06-25"
}
- 响应:
{ "code": 200, "data": { "voucherId": 123, "status": "PAID" } }
采购入库
POST /api/finance/purchase/order/receive- 请求体:
{
"orderId": 1001,
"qty": 100,
"receiveDate": "2026-06-25"
}
- 响应:
{ "code": 200, "data": { "voucherId": 124, "newUnitCost": 95.50 } }
3.2.5 异常场景处理
| 异常场景 | 错误码 | 提示信息 |
|---|---|---|
| 付款金额超过未付金额 | 4001 | "付款金额超过未付金额" |
| 订单已付款完成 | 4002 | "订单已付款完成,不可重复付款" |
| 订单状态不可付款 | 4003 | "当前订单状态不可付款" |
| 入库数量超过订单数量 | 4004 | "入库数量超过订单未入库数量" |
| 采购账户科目映射缺失 | 5001 | "采购账户科目映射不完整,请联系管理员" |
3.2.6 测试用例
| 测试场景 | 预期结果 |
|---|---|
| 创建订单,初始状态 | status_order=1(草稿),所有子状态均为1 |
| 现金付款,全额 | 生成2张凭证(付款+在途),status_pay=3(已付款) |
| 账期付款,全额 | 生成2张凭证(应付+在途),status_pay=3,现金未扣 |
| 部分付款 | status_pay=2(部分付款),待付金额正确 |
| 入库数量等于订单数量 | status_stock=3(已收货) |
| 部分入库 | status_stock=2(部分收货) |
| 全额退款 | 生成红字凭证,status_pay=5(已退款) |
3.3 阶段三:采购账户台账(第3-4周)
3.3.1 任务清单
| 序号 | 任务 | 服务类 | 方法/职责 | 验收标准 |
|---|---|---|---|---|
| 1 | 台账列表查询 | LedgerQueryService |
分页查询,汇总行计算 | 数据准确,汇总正确 |
| 2 | 台账付款(批量) | LedgerPaymentService |
勾选多条,生成凭证,更新状态 | 凭证生成,状态更新 |
| 3 | 对账单上传 | LedgerBatchService |
解析Excel,预览确认,批量付款 | 解析成功,预览准确 |
| 4 | 退款处理 | LedgerPaymentService |
生成红字凭证,更新台账 | 凭证正确,台账更新 |
| 5 | 图表统计 | LedgerStatisticsService |
返回日期X轴+金额Y轴数据 | 图表数据正确 |
3.3.2 台账列表查询字段
| 字段组 | 包含字段 | 计算逻辑 |
|---|---|---|
| 订单信息 | 账簿、采购账户、采购订单号、SKU、供应商、收款账号 | 直接从订单表关联查询 |
| 付款状态 | 订单金额、请款金额、已付金额、待付金额 | 请款=归属供应商的费用类型金额合计;已付=累计付款;待付=请款-已付 |
| 库存状态 | 库存价值、已入库价值、待入库价值 | 库存价值=采购订单的inventory_value;已入库=SUM(入库变动金额);待入库=库存价值-已入库 |
| 发票状态 | 应开票金额、已开票金额、待开票金额 | 应开票=归属供应商的请款金额;已开票=sum(invoiced_amount);待开票=应开票-已开票 |
重要限制:
- 非供应商款项(如跨境直采手续费)不计入请款金额
- 退款金额按原方向反冲,减少请款金额
3.3.3 台账付款核心约束
- 同账户约束:一次付款操作,所有选中的记录必须使用同一个账期采购账户
- 账户类型约束:仅账期类型账户支持台账付款
- 现金账户约束:选中的现金账户必须在账期账户的
creditPayAccounts配置中 - 金额约束:付款金额不超过各订单待付金额之和
- 尾差处理:按比例分摊,差额归入最后一条记录
3.3.4 Excel批量上传模板
| 列名 | 类型 | 说明 | 校验规则 |
|---|---|---|---|
| 采购订单号 | 文本 | 订单唯一标识 | 必填,存在于系统 |
| SKU | 文本 | SKU编码 | 必填,与订单匹配 |
| 应付金额 | 数字 | 订单应付金额 | 必填,≥0 |
| 本次付款金额 | 数字 | 本次实际支付 | 必填,>0,≤应付-已付 |
| 费用类型 | 文本 | 货款/运费/其他 | 必填,在配置中 |
上传流程:
- 用户下载模板
- 填写后上传
- 系统解析并校验
- 返回预览数据(含校验结果)
- 用户确认后提交
- 批量生成付款记录和凭证
3.3.5 接口契约
台账列表查询
GET /api/finance/ledger/purchase/page- 参数:
groupid,accountId,startDate,endDate,payStatus,page,size - 响应:分页数据 + 汇总行(订单金额、已付金额、待付金额汇总)
台账付款
POST /api/finance/ledger/purchase/ledger-pay- 请求体:
{
"orderIds": [1001, 1002, 1003],
"cashAccountId": 5,
"paymentDate": "2026-06-25"
}
- 响应:
{ "code": 200, "data": { "voucherIds": [123, 124, 125], "totalAmount": 50000 } }
上传对账单
POST /api/finance/ledger/purchase/upload-pay- 请求:
multipart/form-data,file字段 - 响应:预览数据
3.3.6 测试用例
| 测试场景 | 预期结果 |
|---|---|
| 查询台账列表,带筛选条件 | 返回正确数据,汇总行金额正确 |
| 勾选3条账期记录,台账付款 | 生成3张凭证,订单待付金额归零 |
| 上传对账单Excel | 解析成功,预览显示待付款明细 |
| 确认上传的对账单 | 批量生成凭证,更新订单状态 |
| 部分退款 | 生成红字凭证,订单状态变为退款中/已退款 |
3.4 阶段四:发票台账与供应商台账(第4-5周)
3.4.1 任务清单
| 序号 | 任务 | 服务类 | 方法/职责 | 验收标准 |
|---|---|---|---|---|
| 1 | 发票同步(税局API) | InvoiceSyncService |
拉取发票数据,写入fin_invoice | 去重,匹配供应商 |
| 2 | 发票台账查询 | InvoiceQueryService |
多维度筛选,显示入账状态 | 筛选条件生效 |
| 3 | 发票入账 | InvoicePostingService |
生成凭证,更新发票和订单状态 | 凭证生成,状态更新 |
| 4 | 供应商台账查询 | SupplierLedgerService |
按供应商汇总各金额字段 | 汇总数据正确 |
| 5 | 未开票明细导出 | SupplierLedgerService |
导出Excel | 格式正确,数据完整 |
3.4.2 发票同步流程
- 触发方式: - 定时任务:每日凌晨2点自动执行 - 手动触发:用户在页面点击"同步"按钮
- 数据来源:税局电子发票API(或金蝶接口)
- 处理逻辑:
- 按日期范围拉取发票列表
- 按发票号码去重(已存在则跳过)
- 按销方税号匹配内部供应商(
t_erp_supplier) - 匹配成功则记录supplier_id,否则留空 - 写入fin_invoice,状态为"正常",入账状态为"未入账" - 异常处理:单条失败不影响整体,记录日志
3.4.3 发票入账流程
- 入口:发票台账页面勾选未入账发票 → 点击"入账"
- 或:供应商台账页面勾选待开票记录 → 选择发票 → 提交入账
- 处理逻辑:
- 校验发票未入账
- 校验供应商与订单供应商一致
- 获取该供应商下待开票订单列表
- 按订单待开票金额比例分摊发票金额
- 生成凭证(借:预付账款-ERP在途发票,贷:预付账款-ERP采购供应商)
- 更新发票:
posting_status=1,关联voucher_id- 更新订单:invoiced_amount增加,status_inv重新计算
3.4.4 供应商台账查询字段
| 字段 | 计算逻辑 |
|---|---|
| 供应商名称 | 从t_erp_supplier关联 |
| 应付金额 | SUM(归属供应商的请款金额) |
| 已付金额 | SUM(已付款金额,仅归属供应商部分) |
| 待付金额 | 应付金额 - 已付金额 |
| 库存价值 | SUM(inventory_value) |
| 应开票金额 | SUM(归属供应商的请款金额) |
| 已开票金额 | SUM(invoiced_amount) |
| 待开票金额 | 应开票金额 - 已开票金额 |
3.4.5 接口契约
发票同步
POST /api/finance/ledger/invoice/sync- 请求体(可选):
{
"groupid": 1001,
"startDate": "2026-06-01",
"endDate": "2026-06-25"
}
- 响应:
{ "code": 200, "data": { "success": 50, "failed": 2 } }
发票入账
POST /api/finance/ledger/invoice/post- 请求体:
{
"invoiceIds": [101, 102],
"orderIds": [1001, 1002, 1003],
"voucherDate": "2026-06-25"
}
- 响应:
{ "code": 200, "data": { "voucherId": 200 } }
供应商台账查询
GET /api/finance/ledger/supplier/page- 参数:
groupid,supplierIds,page,size - 响应:分页数据
导出未开票明细
GET /api/finance/ledger/supplier/export-uninvoiced- 参数:
groupid,supplierId - 响应:Excel文件流
3.4.6 测试用例
| 测试场景 | 预期结果 |
|---|---|
| 手动触发发票同步 | 拉取到新发票,写入fin_invoice,匹配供应商 |
| 发票入账(全额匹配) | 生成凭证,订单待开票金额归零 |
| 发票入账(部分匹配) | 分摊到多条订单,待开票金额减少 |
| 供应商台账查询 | 汇总数据正确,与订单明细一致 |
| 导出未开票明细 | Excel包含未开票订单及金额 |
3.5 阶段五:库存台账(本地仓库)(第5-6周)
3.5.1 任务清单
| 序号 | 任务 | 服务类 | 方法/职责 | 验收标准 |
|---|---|---|---|---|
| 1 | 移动加权平均计算 | MovingAverageCostCalculator |
计算新单价、出库成本 | 计算精确,保留4位小数 |
| 2 | 采购入库更新库存 | InventoryService |
更新余额表、插入变动明细、生成凭证 | 余额正确,明细完整 |
| 3 | 销售出库更新库存 | InventoryService |
更新余额表、插入变动明细、生成凭证 | 余额正确,明细完整 |
| 4 | 库存汇总账查询 | InventoryQueryService |
按期间展示期初/入库/出库/期末 | 数据准确 |
| 5 | 库存明细账查询 | InventoryQueryService |
逐笔变动明细,联查凭证 | 明细完整,可联查 |
| 6 | 勾稽校验 | InventoryCheckService |
对比库存余额与科目余额 | 提示差异明细 |
3.5.2 移动加权平均核算规则
核心公式:
新移动单价 = (当前结存金额 + 本次入库金额) / (当前结存数量 + 本次入库数量)
出库成本 = 出库数量 × 当前移动单价
重要规则:
- 只有采购入库(
PURCHASE_IN)、盘盈入库(ADJUST_IN)会改变移动单价 - 销售出库(
SALE_OUT)、调拨出库(TRANSFER_OUT)不改变单价,仅减少数量 - 库存余额不通过"单价×数量"反算,采用滚动加减法: - 新余额 = 旧余额 + 入库金额 - 出库成本
- 单价保留4位小数,金额保留2位小数
- 尾差处理:出库时先乘后减,避免单价反算误差
期间核算:
- 按月汇总,每月初从上月期末结转
- 同一SKU在同一仓库同一期间仅有一条库存余额记录
3.5.3 库存变动类型
| 类型编码 | 说明 | 数量方向 | 是否影响单价 | 来源 |
|---|---|---|---|---|
PURCHASE_IN |
采购入库 | 正 | 是 | 采购订单收货 |
SALE_OUT |
销售出库 | 负 | 否 | 销售订单发货 |
TRANSFER_IN |
调拨入库 | 正 | 否(沿用原单价) | 仓库调拨 |
TRANSFER_OUT |
调拨出库 | 负 | 否 | 仓库调拨 |
ADJUST_IN |
盘盈入库 | 正 | 是 | 盘点调整 |
ADJUST_OUT |
盘亏出库 | 负 | 否 | 盘点调整 |
3.5.4 汇总账查询结构
| 列 | 说明 |
|---|---|
| 期间 | YYYYMM |
| 账簿 | groupid对应账套名称 |
| SKU | SKU编码 |
| 仓库 | 仓库编码 |
| 期初数量 | 上期期末数量 |
| 期初金额 | 上期期末金额 |
| 本期入库数量 | SUM(入库变动数量) |
| 本期入库金额 | SUM(入库变动金额) |
| 本期出库数量 | SUM(出库变动数量绝对值) |
| 本期出库金额 | SUM(出库变动金额绝对值) |
| 期末数量 | 期初数量 + 入库数量 - 出库数量 |
| 期末金额 | 期初金额 + 入库金额 - 出库金额 |
| 期末单价 | 期末金额 / 期末数量 |
3.5.5 明细账查询结构
| 列 | 说明 |
|---|---|
| 日期 | 变动日期 |
| SKU | SKU编码 |
| 仓库 | 仓库编码 |
| 变动类型 | PURCHASE_IN/SALE_OUT等 |
| 数量 | 正为入库,负为出库 |
| 单价 | 发生时使用的单价 |
| 金额 | 数量 × 单价 |
| 来源单据号 | 采购订单号/销售订单号等 |
| 凭证号 | 关联凭证编号 |
3.5.6 勾稽校验逻辑
校验目标:库存台账的期末金额与总账中"库存商品"科目余额一致
校验步骤:
- 查询指定期间内所有SKU的期末库存金额合计
- 查询总账中"库存商品"科目(及所有子科目)的期末余额
- 对比两者差异
- 若差异不为零,列出差异明细(按SKU或按仓库)
差异处理建议:
- 差异 < 100元:可接受,记录为"微小差异"
- 差异 ≥ 100元:需要生成调整凭证
3.5.7 接口契约
库存汇总账查询
GET /api/finance/ledger/stock/summary- 参数:
groupid,period(YYYYMM),sku(可选模糊搜索),warehouseCode(可选) - 响应:分页数据
库存明细账查询
GET /api/finance/ledger/stock/detail- 参数:
groupid,sku,warehouseCode,startDate,endDate - 响应:分页明细数据
勾稽校验
GET /api/finance/ledger/stock/check- 参数:
groupid,period - 响应:
{
"stockAmount": 1000000.00,
"ledgerAmount": 1000050.00,
"diff": -50.00,
"status": "BALANCED", // 或 "DIFF"
"details": [] // 差异明细
}
3.5.8 测试用例
| 测试场景 | 预期结果 |
|---|---|
| 采购入库,库存为空 | 新增库存余额记录,单价=入库金额/数量 |
| 采购入库,库存已有 | 更新余额,重新计算移动单价 |
| 销售出库 | 按当前单价计算成本,减少库存 |
| 盘点调整 | 调整后单价重新计算 |
| 勾稽校验,无差异 | 返回BALANCED状态 |
| 勾稽校验,有差异 | 返回DIFF状态,列出差异明细 |
4. 联调与测试(第6周)
4.1 端到端流程测试
| 测试场景 | 操作步骤 | 验证点 |
|---|---|---|
| 完整采购流程(现金) | 创建订单→付款→入库→发票入账 | 凭证正确,台账更新,状态流转正确 |
| 完整采购流程(账期) | 创建订单→账期付款→台账付款→入库→发票入账 | 凭证正确,台账更新,状态流转正确 |
| 部分付款+部分入库 | 创建订单→部分付款→部分入库→余款付款→余货入库 | 状态正确,金额正确 |
| 退款流程(已付款未入库) | 创建订单→全额付款→全额退款 | 红字凭证,状态变为已退款 |
| 退款流程(已付款已入库) | 创建订单→付款→入库→退货→退款 | 退货凭证,退款凭证,库存回退 |
| 批量对账单上传 | 上传Excel→预览→确认 | 批量生成凭证和付款明细 |
| 月末结账 | 调汇→结转损益→结账 | 期间关闭,不可修改 |
4.2 性能测试
| 测试项 | 数据量 | 性能要求 |
|---|---|---|
| 台账列表查询 | 10万条订单 | 响应时间 ≤ 3秒 |
| 发票同步 | 单次1万条 | 处理时间 ≤ 5分钟 |
| 库存汇总账 | 1万条SKU记录 | 响应时间 ≤ 5秒 |
| 批量对账单上传 | 500条记录 | 处理时间 ≤ 30秒 |
| 移动加权平均计算 | 单次1000条变动 | 计算时间 ≤ 5秒 |
4.3 数据一致性测试
| 测试项 | 验证方法 |
|---|---|
| 采购订单金额 = 付款明细合计 | 查询统计对比 |
| 订单库存价值 = 入库明细合计 | 查询统计对比 |
| 订单已开票金额 = 发票入账金额合计 | 查询统计对比 |
| 库存余额 = 期初 + 入库 - 出库 | 滚动计算校验 |
| 库存余额对应总账科目余额 | 勾稽校验接口 |
5. 数据迁移方案(第6周)
5.1 迁移范围
- 历史采购订单(从ERP采购单表)
- 历史库存数据(从现有库存表)
- 历史发票数据(从金蝶/税局)
5.2 迁移顺序
- 采购账户:手动创建历史使用的采购账户
- 采购订单:按时间分批迁移,每批1000条
- 付款明细:从ERP付款记录中提取
- 库存余额:从当前库存表初始化
- 发票台账:从税局API拉取历史发票
5.3 迁移校验
- 迁移完成后,运行勾稽校验
- 对比迁移前后的总额数据,误差 < 100元为通过
6. 风险与应对
| 风险 | 影响 | 应对措施 |
|---|---|---|
| 税局API不稳定 | 发票同步失败 | 支持手动导入Excel,保留重试机制 |
| 历史数据量过大 | 迁移耗时长 | 分批迁移,错峰执行 |
| 科目配置复杂 | 凭证生成错误 | 提供配置校验工具,预置常用模板 |
| 多账套数据隔离 | 权限混乱 | 所有查询强制带groupid,使用多租户拦截器 |
| 移动加权计算精度 | 尾差累积 | 保留4位小数,定期勾稽校验 |
7. 里程碑与交付物
| 里程碑 | 时间 | 交付物 |
|---|---|---|
| M1:基础配置上线 | 第1周末 | 采购账户CRUD、供应商收款账户管理 |
| M2:采购订单上线 | 第3周末 | 采购订单创建、付款、退款、入库、凭证生成 |
| M3:台账模块上线 | 第4周末 | 采购账户台账、台账付款、批量对账单 |
| M4:发票模块上线 | 第5周末 | 发票同步、发票入账、供应商台账 |
| M5:库存模块上线 | 第6周中 | 库存汇总账、明细账、勾稽校验 |
| M6:全量联调上线 | 第6周末 | 端到端测试通过,数据迁移完成 |
8. 附录:术语表
| 术语 | 说明 |
|---|---|
| 账期账户 | 采购时先挂账,后续通过台账付款实际支付的账户类型 |
| 现金账户 | 采购时直接扣款的账户类型,如银行账户、连连账户 |
| 台账付款 | 账期账户的还款操作,在台账页面批量处理 |
| 归属供应商款项 | 计入供应商应付/已付的金额(如货款、运费),不含手续费等 |
| 非供应商款项 | 不计入供应商应付的金额(如跨境直采手续费) |
| 移动加权平均 | 每笔入库后重新计算库存单价的成本核算方法 |
| 在途库存 | 已付款但尚未入库的存货,在途库存_XX本地仓库科目 |
| 预付账款-ERP采购供应商 | 用于记录已付款但未取得发票的供应商款项 |
| 预付账款-ERP在途发票 | 用于记录已取得发票但未入库的库存 |