1. 项目概览 OVERVIEW
本项目围绕 OVES 集团在 Odoo.SH (enterprise.omnivoltaic.com) 的 ERP 实例展开系统性分析,涵盖架构审计、数据质量检查、POS 部署规划三个维度。
核心工作流
- MCP 连接与代理绕过 — 修复 Cloudflare/HTTP_PROXY 问题,建立稳定 XML-RPC 通道
- SA 架构发现与图谱模型 — 分析 228 个服务账户、1,026 个成员、28 个关联模型
- 实施记分卡 — 对比 dirac-odoo ADR 设计意图 vs 实际实现
- 序列号追踪分析 — 各公司序列号启用状态、数据质量问题
- OVT (Oves Togo) 审计 — 数据质量审计 + 法语报告
- HM (浩迈) 深度分析 — 零成本产品、产品类型检查、POS 部署规划
- 产品类型重大修正 — 纠正 consu=实物 vs combo=组合 的术语错误
2. 连接与 MCP 配置 TECH
| 项目 | 详情 |
| 连接方式 | XML-RPC (JSON-RPC 被 Cloudflare 拦截返回 403) |
| 认证方式 | 密码认证 (API Key 在 XML-RPC 下无效) |
| MCP 版本 | odoo_mcp v0.3.0 |
| Python 路径 | Python 3.12 (system) + odoo_mcp 安装 |
| 写权限 | ODOO_MCP_ENABLE_WRITES=1 (默认关闭) |
⚠️ 关键修复:HTTP_PROXY 代理绕过
系统环境变量 HTTP_PROXY=http://127.0.0.1:10808/ 导致 odoo_mcp 的 RedirectTransport 尝试通过代理隧道连接 Odoo.sh,返回 301 Moved Permanently。
解决方案:在 mcp.json 的 env 配置中添加 "HTTP_PROXY": "", "HTTPS_PROXY": "", "NO_PROXY": "*"。
数据清单
| 数据集 | 数量 |
| 联系人 (res.partner) | 2,103 |
| 产品 (product.product) | 3,547 |
| 销售订单 (sale.order) | 1,364 |
| 调拨单 (stock.picking) | 1,276 |
| 批次/序列号 (stock.lot) | 936 |
| 凭证 (account.move) | 6,378 |
3. 服务账户 (SA) 架构 ARCHITECTURE
SA 系统是一个在 Odoo 原生用户/公司系统之上构建的 分层 RBAC + 多租户治理系统,核心设计理念是图谱模型:
- 节点 (Nodes) = Odoo 基础模型(res.partner, sale.order, product.product...)
- 边 (Edges) =
ov.sa_* 关联模型(通过 FK 连接节点)
- 原则:永不修改底层 Odoo 模型,通过关联表建立连接
核心模型
| 模型 | 记录数 | 字段数 | 说明 |
| ov.serviced_account | 228 | 49 | 服务账户树 (133 active + 95 inactive, 196 EXTC + 32 OVAC) |
| ov.membership | 1,026 | 17 | 人员 ↔ SA 关联 (214 staff + 138 agent, 1,012 active) |
| ov.sa_* (28 个) | 不等 | ~13/个 | 业务对象 ↔ SA 关联模型(sale_order, purchase, invoice, product...) |
| ov.actor_sa_* (27 个) | 不等 | ~13/个 | 参与者级别的关联模型(96% 覆盖率) |
| ov.asset, ov.outlet, ov.bop.* | 不等 | ~41 | 领域模型(受管资产、服务站点、属性清单) |
📐 SA 图谱模型架构
每个 ov.sa_* 关联模型包含:account_id → SA、[object]_id → 业务对象、association_kind(绑定/可见/负责)、date_from/to(时效性)、assigned_by_id(审计)、state(状态)。
association_kind 字段是最重要的设计元素——它定义了"边"的语义(所有权 vs 可见性 vs 责任),比 Odoo 原生 ir.rule 仅有的"可见/不可见"更富表现力。
4. 实施记分卡 AUDIT
对比 dirac-odoo ADR 设计意图 vs 实际 Odoo 实现的合规性检查。
| ADR | 通过率 | 裁决 |
| 0001 V1 SA 构造模型 | 45% (5/11) | 字段重命名漂移;assigned_by_id 缺失 |
| 0002 ov.* 命名空间 | 38% (3/8) | ❌ 基础模型泄漏 FOUND |
| 0003 V3 关联模型 | 67% (6/9) | 命名不一致;缺失 actor 变体 |
| 0004 Fleet/Item 关联 | 40% (2/5) | 尚未实现(可能是未来工作) |
| V3 默认状态 | 100% (7/7) | ✅ V3 已正确作为默认模式 |
| 总体 | ~80% | 关键问题:基础模型泄漏 |
🔴 P0 — 基础模型泄漏 (ADR 0002 违规)
| 基础模型 | 泄漏字段 | 引用 |
sale.order | x_outlet_id | ov.outlet |
product.product | bop_sheet_id | ov.bop.sheet |
product.template | bop_sheet_id | ov.bop.sheet |
hr.employee | outlet_ids | ov.outlet |
影响:违反了"永不修改底层 Odoo 模型"的核心设计原则。
行动:从基础模型移除这些字段,创建正确的
ov.sa_* 关联模型。
🟡 关键警告
- ov.membership.assigned_by_id 缺失 — ADR 指定的审计字段未实现(仅有 Odoo 标准 create_uid)
- 字段命名不一致 —
ov.sa_applet_config 使用 sa_id,其他 27 个模型使用 account_id
- ov.actor_sa_applet_config 缺失 — 二层模式覆盖率 96% 而非 100%
- assigned_by_id 指向 res.partner — 而非更合适的 res.users
5. 序列号追踪分析 INVENTORY
| 公司 | 序列号追踪产品数 |
| Shared(无公司) | 15 |
| Test Company | 8 |
| Oves Shenzhen (HM) | 2 |
| OV Kenya (Test) | 1 |
⚠️ 数据质量问题
部分序列号追踪产品现有库存的 lot_id=None 且 qty > 1:
E-VCU-C: qty=238 (lot=None) · 12345: qty=31 (lot=None) · E-Mob-Bat30Ah: qty=6 (lot=None)
这些产品可能是在已有库存后才开启序列号追踪的。需要做库存调整,把 >1 的库存拆成独立序列号。
📌 序列号追踪机制(Odoo 18+)
批次和序列号追踪共用一个数据库模型 stock.lot。区别仅在于 product.product.tracking 字段:
- lot:每批允许多数量 · serial:必须 qty=1
工作流:收货 → 强制录入序列号 → 发货 → 强制选择具体序列号
6. OVT (Oves Togo) 审计 AUDIT
🔴 4 大关键问题
- 产品未分类 — 大部分产品没有归属产品分类 (product.category)
- 72.6% 产品零成本 — standard_price=0 或 null,导致 COGS 失真
- 1,506 张草稿发票 — 大量发票停留在 draft 状态未处理
- 全部产品为 consu 类型 — 但 Odoo 18 的 consu=实物,这是正确的
销售分析 (CFA 货币)
| 类别 | 笔数 | 收入 (CFA) | ≈USD |
| 已完成 SO (B2C 个人) | 45 | 472,180 | ~$787 |
| 已完成 SO (B2B 公司) | 14 | 332,770 | ~$555 |
| 报价单 (draft/sent) | 212 | 316,900 | ~$528 |
⚠️ 团队经验不足——需关注
OVT 团队在财务和运营方面缺乏经验,报告已用法语生成:AUDIT_OVT_RAPPORT.html
7. HM (浩迈) 深度分析 HM
零成本产品
| 范围 | standard_price=0 | standard_price>0 |
| HM 专属产品 | 152 | 994 |
| Shared(无公司) | 1,137 | — |
152 个 HM 专属产品 standard_price=0 但 list_price=1.00——很可能是从未设定成本的占位产品。COGS=0 导致毛利虚高 100%。
产品类型分布 已修正!
| 内部值 | 中文界面 | 英文标签 | HM 数量 | 正确性 |
consu | 实物 | Goods | 4,581 | ✅ 正确 |
service | 服务 | Service | 25 | 部分需确认 |
combo | 组合 | Combo | 0 | ✅ — |
追踪方式分布
| 追踪方式 | 数量 |
| 无追踪 (none) | 4,476 |
| 批次 (lot) | 115 |
| 唯一序列号 (serial) | 15 |
⚡ 8. 重大错误修正:产品类型术语 LESSON LEARNED
❌ 我犯的错误
在早期分析中,我把 Odoo 18 的
consu 错误地翻译为"组合"(combo),并告诉用户 HM 的 4,581 个产品都是"组合类型,应该改为实物"。
这是完全错误的。事实上:
consu 在 Odoo 18 的英文标签是 "Goods",中文翻译为 "实物"
combo 才是 "组合"(捆绑包)
- HM 产品本来就是 "实物"——完全正确,不需要任何修改
Odoo 18 产品类型——精确映射
| 内部值 | 英文 | 中文界面 | 含义 |
consu | Goods | 实物 ✅ | 实物商品,可库存/序列号追踪/POS |
service | Service | 服务 | 非实物服务 |
combo | Combo | 组合 | 捆绑组合包 |
📌 版本差异解析
Odoo v16 之前:类型为 consumable(消耗品)、product(可存储)、service(服务)
Odoo 18:重构为 consu(Goods/实物)、service(服务)、combo(组合)
注意:Odoo 18 的 consu = 旧版的 product(storable),不是旧版的 consumable!
✅ 已创建修复技能
已将上述映射规则编码为 WorkBuddy 技能 odoo-product-types,存放在 ~/.workbuddy/skills/odoo-product-types/,确保今后不再犯同样错误。
9. POS 部署规划 RETAIL
当前状态
| 公司 | POS 模块 | POS 订单 | POS 配置 | 支付方式 |
| OV Togo (CFA) | 已安装 | 0 | ❌ 无 | ❌ 无 |
| OV Kenya (KES) | 已安装 | 0 | ❌ 无 | ❌ 无 M-Pesa |
| HM Shenzhen (CNY) | 已安装 | 0 | ❌ 无 | ❌ 无微信 |
HM POS 部署清单
| # | 阶段 | 行动项 | 状态 |
| P0 | 前置 | 确认 HM 会计科目 ID | 待确认 |
| P0 | 前置 | 确认零售毛利率 % | 待确认 |
| 1 | 支付 | 创建微信支付 + 现金 CNY | 可自动化 |
| 2 | 产品 | 创建零售价格表 (CNY) | 可自动化 |
| 3 | POS 配置 | 创建 HM 门店 (Daiyun/Buji/Longhua) | 可自动化 |
| 4 | 权限 | 分配 POS 用户权限 | 需手动 |
| 5 | 仓库 | 3 个 POS 门店各自独立仓库 | 可自动化 |
| 6 | 测试 | 跑 1 笔 POS 交易验证流程 | 需现场操作 |
| 6 | 测试 | 序列号扫描 (退货保修使用) | 实物类型已支持 |
| 7 | 培训 | 收银员手册 + 现场培训 | 可自动化编写手册 |
完整部署清单文件:HM_POS_部署清单.md
🔗 SA 治理架构与 POS 的集成
ov.sa_pos_order 模型已存在于 Odoo 实例中(28 个 SA 关联模型之一)。它天然建立了 POS 订单 → SA 的治理连接。
建议的"PoS Applet"概念:通过 ov.sa_pos_config、ov.sa_pos_order、ov.sa_pos_payment 三个关联模型,实现 POS 层面的权限治理和可见性控制。
10. 交付物清单 DELIVERABLES
文档
| 文件 | 说明 |
docs/odoo-extension-architecture.md | SA 图谱模型架构参考文档 |
SERIAL_TRACKING_REPORT.html | 序列号追踪状态 HTML 报告 |
AUDIT_OVT_RAPPORT.html | OVT 数据质量审计 (法语) |
IMPLEMENTATION_SCORECARD.md | 实现记分卡 (ADR 对比) |
HM_POS_部署清单.md | HM POS 部署完整清单 |
docs/learning-guides/odoo-learning-guide.md | Odoo 学习指南 |
docs/migration-plan/odoo-sh-to-on-premises-migration-plan.md | Odoo.sh → 本地部署迁移计划 |
WorkBuddy 技能
| 技能名 | 位置 | 用途 |
mcp-canonical-setup | ~/.workbuddy/skills/ | MCP 标准化配置流程 |
odoo-model-inspector | ~/.workbuddy/skills/ | Odoo 自定义模型系统检查 |
odoo-product-types | ~/.workbuddy/skills/ | Odoo 18 产品类型映射规则 |
脚本 (Python XML-RPC)
| 脚本 | 用途 |
verify_sa_fk.py | 验证所有 28 个 ov.sa_* 模型 FK 到 ov.serviced_account |
check_serial_tracking.py | 查询各公司序列号启用状态 |
query_hm_zero_cost_v2.py | HM 零成本产品分析 |
audit_ovt.py | OVT 数据质量审计 |
query_pos_models.py | POS 模型清单 |
check_hm_pos.py | HM POS 状态检查 |
check_hm_pricelist.py | HM 价格表检查 |
📝 11. 经验教训 LEARNINGS
- 永远检查 Odoo 版本 — 不同版本的字段定义、类型选项可能完全不同。Odoo 18 的 product type 与 v16 以前有重大差异。
- proxy 环境变量 — 本机有 HTTP_PROXY 设置,所有外部连接必须显式绕过,否则返回 301/403 错误。
- 多币种 — 11 家公司使用 7 种不同货币,直接读取 list_price 会得到错误数据(如 OVT 的 CFA 被误读为 USD)。
- 自动检查要二次验证 — 查找 FK 时不能只匹配字段名(如
sa_id),还要检查字段的 relation 属性。
- "HM" 有歧义 — 系统中 HM 匹配两个公司:ID 13 (虚拟 Beryl) 和 ID 17 (真·浩迈)。始终确认公司 ID。
- consu ≠ 消耗品 — Odoo 18 的 consu = Goods(实物) = 旧版的 product(storable)。这是最重要的教训。
- ir.translation 在 Odoo 18 中已重命名 — 不能用旧版的方式查翻译。
⚠️ 本报告由 WorkBuddy AI 基于 Odoo.SH 实例的 XML-RPC 实时查询生成。所有数据来源于 enterprise.omnivoltaic.com (Odoo 18.0+e Enterprise)。报告仅作为内部技术参考,不构成任何业务决策建议。