Files
dealerhub/backend/PROGRESS_P0_GAPS.md

81 lines
6.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)镜像重建与部署