# PROGRESS_AGI_ITERATION_7 · D2 业务员 H5 + P2-2 部署清单 > 跑法口径:后端 `pytest` 全量(`tests/` + `apps/core/tests`),前端 `npm run build` + `npm test`。 > - 后端 SQLite:**510 passed / 4 skipped**(4 skipped 均为 PG 专用并发用例) > - 后端 PG 5433 `-m postgres`:**4 passed** > - 前端:`npm run build` ✅ 5.64s;`npm test` ✅ 11 pass / 0 fail > - `manage.py check` 0 issues;`makemigrations --check` No changes > - D2 移动模拟:`backend/scripts/verify_salesman_h5.py` 全 10 步通过,0 console errors > - P2-2:`docker compose config` exit 0 + `docs/DEPLOY_CHECKLIST.md` 落地;镜像构建/上线因无凭证未做,不虚报 > - P3-1:按规格跳过,未建模 ## 一、P2-3 D2 业务员移动开单 H5(`PROGRESS_BATCH_D.md:236` + `NEXT_PLAN.md` §P2-3) 规格原文:复用 `Storefront.vue` 外壳 + `SalesBills` 取价/单位/抹零组件, 换业务员角色(外勤开单/查欠款/收款登记),Chrome 移动模拟全流程走通。 ### 交付 - 新建 `frontend/src/pages/Salesman.vue`(约 550 行,`dist/assets/Salesman-*.js` 16.26 kB): - 外壳:复用 Storefront 的 `sf-wrap` 移动布局(max-width 560px + 480px 断点纵排), 登录用后台用户 JWT(`POST /auth/token/`,与 PC 同一套账号),公开路由 `/#/salesman`。 - 外勤开单:客户/仓库下拉 + 商品搜索 + 单位下拉 + 数量; 取价走 `GET /partner/price-quote/`(客户专属价→等级价→上次成交价→默认价, 与 SalesBills 同源,source 标签同文案);单位换算走 `GET /catalog/products//units/` + `utils/transaction.js` 的 `unitRate/lineAmount` (与 SalesBills 同口径);税率/税额行内显示(价内拆分,与 D4 同公式); 抹零(不抹/抹分/抹角/抹元)+ 应收合计;保存走 `POST /sales/bills/create-bill/` 后自动 `POST /sales/bills//confirm/`(402 超限弹强制过账确认,与 SalesBills 同流程)。 - 查欠款:`GET /finance/receivables/` 只留 open/partial(前端过滤,BaseTenantViewSet 无精确 customer 过滤器,不伪造后端参数),显示单号/客户/日期/共欠/已收/未结余额 + 状态标签 + 未结合计。 - 收款登记:`POST /finance/receipts/`(客户/单号必填/日期/金额>0/方式/备注), 单号必填是实测结论(Receipt.bill_no 无自生成,漏填 400),表单 rules 与 `Receivables.vue` 登记 dialog 同约束。 - 路由:`frontend/src/router/index.js` 加 `/salesman` + `PUBLIC_ROUTES` 加 `salesman` (P0-3 同类坑:不加则匿名被踢回 login)。 ### 验证(干净库实跑,非残留数据) `backend/scripts/verify_salesman_h5.py`(Playwright Chromium,Pixel 5 移动模拟 393×851 + touch + 移动 UA),dev 后端 :18099 + vite :15173(临时 verify 配置代理 /api): ``` [pre] customer=C001 warehouse=WH01 product=B001 token=ok [1] login ok (mobile viewport 393x851) [2] customer: OK:C001 张三便利店 / warehouse: OK:WH01 主仓库 [3] add-to-order ok (qty=2) [4] round_to: OK:抹角(0.1)/ submit+confirm clicked [5] debt tab: 未结 ¥31.00(1 单)RC202609120001 … 未收 [6] receipt customer OK / submit clicked [7] console errors: 0 [8] latest bill: XS202609120001 state=confirmed total=31.0000 [9] receipt SMH50002 ok amount=50.0000 [10] open receivables: 1, first balance=31.0000 ALL SALESMAN-H5 CHECKS PASSED ``` 验证后残留(XS202609120001/SMH50002/RC202609120001)已删,`default` 租户恢复 0 单据。 为验证造的最小数据保留(alice/alice12345 + B001/C001/WH01/1000 库存),属可用 fixture。 ### 踩坑 1. 密码框无 placeholder(只有前两个 input 有),用 `.sm-login input` 序号定位。 2. 移动视口下 `li[role=option]`(非 `.el-select-dropdown .el-option`)且常判不可见, Playwright click(连 force)会被 visible 挡 → 一律用 JS `offsetParent` 过滤可见项后 `.click()`。 3. 收款 tab 切换用 `#tab-receipt/#pane-receipt` 稳定选择器,不用 role 或 is-active。 4. 填单号前先 `Escape` 关残留 popper,否则输入框被浮层挡住无法 fill。 ## 二、P2-2 部署 readiness(`NEXT_PLAN.md` §P2-2) - `docs/DEPLOY_CHECKLIST.md`(新建):本地校验表(7 项全 ✅ exit 0/实测值)+ 上线 gate(环境变量/构建/迁移/collectstatic/DEBUG/PG/HTTPS/日志轮转/备份/冒烟)+ 诚实记录(未构建镜像、未上线、无备份脚本,均不虚报)。 - 附带真缺口修复:`backend/config/settings/prod.py` 拒绝 `DJANGO_ALLOWED_HOSTS` 含 `*`。 根因:`base.py:read_env` 把 dev `.env`(`DJANGO_ALLOWED_HOSTS=*`)写进 `os.environ`, prod 空值门读到 `*` 静默通过。验证:不传变量 → `ImproperlyConfigured(通配符)`; `=example.com` → check 0 issues。全仓 grep `settings.prod` 零命中,无测试依赖。 - 本地校验实测:`docker compose config` exit 0(插值全展开); prod `check` 0 issues;`collectstatic` 216 files;prod 基线 (DEBUG=False / dealerhub INFO / PG pool 2/10/10 / HSTS 30 天+include+preload / Secure Cookie / proxy https / DENY)逐项打印确认。 ## 三、P3-1 跳过声明 按 `NEXT_PLAN.md` §P3-1 与 `PROGRESS_BATCH_D.md:238` 定调"按客户驱动,不提前做": 本轮未建 `Serial`/辅助属性/套装拆件,未动 inventory/catalog 模型, `makemigrations --check` No changes 即为预期状态。 ## 四、最终验证数字(本轮实跑) ``` backend pytest tests/(SQLite): 496 passed / 4 skipped backend pytest 全量(含 core/tests): 510 passed / 4 skipped backend PG -m postgres: 4 passed frontend npm run build: ✓ 5.64s(含 Salesman-*.js 16.26 kB) frontend npm test: 11 pass / 0 fail manage.py check: 0 issues;makemigrations --check: No changes D2 verify_salesman_h5.py: ALL PASSED(0 console errors) ``` ## 五、变更文件清单 ``` frontend/src/pages/Salesman.vue [新] D2 业务员 H5 三职一页 frontend/src/router/index.js [改] +/salesman 路由 + PUBLIC_ROUTES backend/scripts/verify_salesman_h5.py [新] D2 移动模拟全流程脚本(10 步断言) backend/config/settings/prod.py [改] ALLOWED_HOSTS 拒绝通配符 * docs/DEPLOY_CHECKLIST.md [新] P2-2 readiness gate 清单 frontend/dist/ [重建] ``` ## 六、遗留 - 镜像构建 + 上线 192.168.5.7:无 Docker 目标机/服务器凭证,停在清单 + 本地校验。 - 日志轮转/备份:运维侧动作,仓库无实现(清单已如实标注)。 - D2 欠款页用前端过滤(open/partial + 按客户),数据量大时应补后端 `customer/status` 精确过滤;当前为 H5 外勤场景可接受范围。