81 lines
6.0 KiB
Markdown
81 lines
6.0 KiB
Markdown
# dealerhub · P0 改造实施报告(对标竞品差距清单)
|
||
|
||
> **依据**:`docs/差距分析与改造清单.md` P0 六项 + `docs/P0改造实施计划.md`。
|
||
> **结果**:六项全部落地,专项新增 38 个测试,全量回归 **141 passed**(原 103 + 新增 38),`manage.py check` 0 issues。
|
||
|
||
## ✅ #1 批次/效期管理(食品饮料线地基)
|
||
|
||
- `catalog.Product`:新增 `is_batch_managed` / `shelf_life_days`;入库未传到期日时按生产日期+保质期自动推算
|
||
- `inventory.StockBatch`:批次账(warehouse×product×batch_no 唯一),与总账 Stock 并行维护
|
||
- `inventory/services.inbound`:批次商品必须带批次号(缺参报错);`outbound` 自动 **FEFO 分摊**(近效期优先,空到期日最后,先入先出兜底),分摊明细写入 `StockMovement.batch_detail`
|
||
- 采购穿透:`PurchaseBillLine` 支持批次号/生产日期/到期日,过账写入批次账
|
||
- 近效期预警:`notify` 新增 `batch_expiry` 规则(threshold=提前天数),按批次+当日去重,挂入 `run_all_alert_checks`
|
||
- API:`GET /api/v1/inventory/batches/`(只读,支持 product/warehouse/in_stock 过滤)
|
||
- 测试 9 例:批次必填、聚合一致、FEFO 跨批分摊、不足拒绝、预警去重、采购端到端、非批次回归
|
||
|
||
## ✅ #2 多单位换算(整件散包基础)
|
||
|
||
- 新模型 `catalog.UnitConversion(product, unit, rate)`:1 录入单位 = rate × 基本单位
|
||
- `catalog/services.to_base`:换算服务,缺换算率抛 `UnitConversionNotFound`
|
||
- sales/purchase 四个行模型新增 `source_unit/source_quantity`(可空,老调用零影响);`quantity` 恒存基本单位
|
||
- 语义:带录入单位时 `unit_price` 按**录入单位**计价,`amount = source_quantity × price`;不传价时默认价 × rate
|
||
- 测试:2 箱×24=48 出库、缺换算率报错、按箱默认价 5×24=120、老式行回归
|
||
|
||
## ✅ #3 开单自动取价
|
||
|
||
- 新模型 `partner.CustomerProductPrice`(客户×商品专属价)
|
||
- `partner/services.quote_price` 四级优先:**客户专属价 → 价格等级折扣 → 最近成交价 → 默认售价**;同时返回 last/min/max 历史成交参考(智慧记同款体验)
|
||
- `create_sales_bill` 行不传价自动取价;API `GET /api/v1/partner/price-quote/`(批量,供前端预填)
|
||
- 测试:四级优先级、历史价统计、开单自动填充、报价 API
|
||
|
||
## ✅ #4 最低售价 + 抹零
|
||
|
||
- `Product.min_sale_price`:低于即抛 `BelowMinPrice`,行传 `allow_below_min=True` 视为审批放行
|
||
- `SalesBill.round_off`:`create_sales_bill(round_to=1|0.1|0.01)` 向下取整抹零,净额入 `total_amount`,应收按净额生成;"抹零 X 元"自动追加 remark
|
||
- `core/services` 抽出共享行解析(单位/价格/最低价/抹零),sales 与 purchase 语义一致
|
||
- 测试:拒绝/放行、元/角/分三档抹零矩阵、应收净额一致性
|
||
|
||
## ✅ #5 信用额度落地(此前字段存在但从不校验)
|
||
|
||
- `partner/services.credit_usage`:客户 open/partial 应收净占用;`check_credit` 服务
|
||
- `confirm_sales_bill` 过账前强制校验:超限抛 `CreditLimitExceeded`(事务回滚,库存/应收/状态零变化);`force=True` 放行并写预警通知;占用 ≥90% 提前预警
|
||
- API:`GET /api/v1/partner/credit-usage/<customer_id>/`(前端额度进度条数据源)
|
||
- 测试:通过/拒绝回滚/force+通知/90%预警/无限额跳过/抹零净额口径
|
||
|
||
## ✅ #6 账龄分析 + 对账单 + 公开分享
|
||
|
||
- `finance/services.receivable_aging`:0-30/31-60/61-90/91-180/181-365/365+ 六桶,支持 as_of 与单客户
|
||
- `customer_statement`:期初(含"区间内核销旧账"的口径修正)→ 区间应收(借)/收款核销(贷) → 期末,逐行滚动余额
|
||
- 分享:`finance.StatementShare`(UUID token + 过期 + 吊销);受保护 `POST/GET /api/v1/finance/statements/share/`;公开 `GET /api/v1/open/statements/<token>/`(AllowAny,不依赖租户头,过期/吊销 404)
|
||
- 测试:六桶金额、已结清剔除、单客户过滤、期初/期末平衡、匿名访问、过期 404、吊销 404
|
||
|
||
## 📁 新增/变更文件
|
||
|
||
```
|
||
backend/
|
||
├── apps/core/services.py [新] 行解析/取价/最低价/抹零 共享服务
|
||
├── apps/catalog/services.py [新] to_base 单位换算
|
||
├── apps/catalog/models.py Product 批次字段/min_sale_price + UnitConversion
|
||
├── apps/inventory/models.py StockBatch + StockMovement.batch_detail
|
||
├── apps/inventory/services.py 批次入库 + FEFO 出库
|
||
├── apps/partner/models.py CustomerProductPrice
|
||
├── apps/partner/services.py [新] quote_price / credit_usage / check_credit
|
||
├── apps/partner/views.py·urls.py price-quote / credit-usage API
|
||
├── apps/sales/services.py 取价/换算/最低价/抹零/信用额度 全接入
|
||
├── apps/purchase/services.py·models.py 批次穿透 + 行单位字段
|
||
├── apps/finance/services.py receivable_aging / customer_statement
|
||
├── apps/finance/models.py StatementShare
|
||
├── apps/finance/views.py·urls.py 账龄/对账单/分享 API + 公开端点
|
||
├── config/urls.py /api/v1/open/statements/<token>/ 公开路由
|
||
├── apps/notify/models.py·services.py batch_expiry 规则 + 扫描
|
||
├── migrations ×7 app [新]
|
||
└── tests/test_p0_batch.py·test_p0_unit_price.py·test_p0_credit.py·test_p0_aging_statement.py [新] 38 例
|
||
```
|
||
|
||
## 🔜 后续(未在本次范围)
|
||
|
||
- 前端 12 页对应改造(开单页自动取价/单位选择/抹零、客户页额度进度条、账龄报表页、对账单分享按钮)
|
||
- P1:AI 应收风险预警(notify 规则底座已就绪)、AI 开单
|
||
- P2:套餐计费/官网/演示账套(见《差距分析与改造清单》P2)
|
||
- 线上(192.168.5.7)镜像重建与部署
|