From 8766afa8c026b4e48c2a34a3bdc751bcf4d34815 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Fri, 5 Jun 2026 22:34:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(supplychain):=20=E8=A7=84=E8=8C=83=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D=20+=20P0=E5=87=BD=E6=95=B0=E6=B3=A8=E5=86=8C=20+=20?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=AE=8C=E5=96=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 修复12个.dspy文件: 移除import/print, 改用return - init.py: 添加9个P0 CRUD函数 + 单复数兼容注册 - load_path.py: 补充15个CRUD子目录路径 - README.md: 添加P0表说明 + 业务API + 部署清单 - global_menu.ui: 已有supplychain入口(验证通过) --- README.md | 24 ++ scripts/load_path.py | 24 ++ supplychain/__pycache__/init.cpython-310.pyc | Bin 0 -> 20289 bytes supplychain/init.py | 225 +++++++++++++++++- wwwroot/api/import_supplier_product.dspy | 30 +-- .../api/platform_supply_products_create.dspy | 12 +- .../api/platform_supply_products_delete.dspy | 12 +- .../api/platform_supply_products_update.dspy | 12 +- .../api/platform_supply_relations_create.dspy | 12 +- .../api/platform_supply_relations_delete.dspy | 12 +- .../api/platform_supply_relations_update.dspy | 12 +- .../api/product_supplier_mapping_create.dspy | 12 +- .../api/product_supplier_mapping_delete.dspy | 12 +- .../api/product_supplier_mapping_update.dspy | 12 +- wwwroot/api/query_platform_products.dspy | 25 +- wwwroot/api/query_platform_suppliers.dspy | 25 +- 16 files changed, 341 insertions(+), 120 deletions(-) create mode 100644 supplychain/__pycache__/init.cpython-310.pyc diff --git a/README.md b/README.md index 07bb3fa..cb7c1ac 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,22 @@ Manages the complete supply chain workflow for reseller/distributor organization | `distribution_agreements` | Distribution agreements between reseller and sub-reseller | | `distribution_agreement_items` | Product-level discount details per distribution agreement | | `sales_ledger` | Sales transaction records with calculated amounts | +| `platform_supply_relations` | Platform-level org-to-org supply relationships (P0) | +| `platform_supply_products` | Product details within platform supply relations (P0) | +| `product_supplier_mapping` | Unified product-to-supplier mapping across internal/external (P0) | + +### P0 Platform Supply Chain (2026-06) + +Enables supply chain relationships between organizations on the Sage platform: + +- **platform_supply_relations**: Links two organizations (supplier ↔ buyer) with cooperation type (distribution/agency/direct-supply), settlement mode (discount/commission/fixed), and contract period +- **platform_supply_products**: Product-level pricing within a supply relation — supply price, retail price, discount, commission rate, min order qty +- **product_supplier_mapping**: Unified view mapping any product to its supplier(s), whether internal (platform org) or external (suppliers table), with preferred supplier flag + +Key business APIs: +- `query_platform_suppliers.dspy` — List platform orgs available as suppliers (excludes current user's org) +- `query_platform_products.dspy` — List active products owned by a supplier org +- `import_supplier_product.dspy` — Import a supplier's product into buyer's mapping (creates product_supplier_mapping record) ### Discount Calculation Logic @@ -165,3 +181,11 @@ result = await env.calculate_sale_amounts(request, { }) # Returns: {contract_id, agreement_id, total_amount, supply_discount, supply_amount, distribution_discount, distribution_amount, profit_amount} ``` + +## Deployment Checklist + +1. Execute DDL: `models/mysql.ddl.sql` — creates 3 new tables (platform_supply_relations, platform_supply_products, product_supplier_mapping) +2. Init appcodes: Run `init/data.json` inserts for 6 appcode groups +3. Build CRUD UI: `bash build.sh` +4. Register RBAC: `~/repos/sage/py3/bin/python scripts/load_path.py` (or central load_path.py) +5. Restart Sage diff --git a/scripts/load_path.py b/scripts/load_path.py index 6a823fc..3bdde7f 100755 --- a/scripts/load_path.py +++ b/scripts/load_path.py @@ -116,8 +116,20 @@ PATHS_LOGINED = [ "/supplychain/api/query_dist_discount.dspy", # 平台供销关系 "/supplychain/platform_supply_relations_list/index.ui", + "/supplychain/platform_supply_relations_list/get_platform_supply_relations.dspy", + "/supplychain/platform_supply_relations_list/add_platform_supply_relations.dspy", + "/supplychain/platform_supply_relations_list/update_platform_supply_relations.dspy", + "/supplychain/platform_supply_relations_list/delete_platform_supply_relations.dspy", "/supplychain/platform_supply_products_list/index.ui", + "/supplychain/platform_supply_products_list/get_platform_supply_products.dspy", + "/supplychain/platform_supply_products_list/add_platform_supply_products.dspy", + "/supplychain/platform_supply_products_list/update_platform_supply_products.dspy", + "/supplychain/platform_supply_products_list/delete_platform_supply_products.dspy", "/supplychain/product_supplier_mapping_list/index.ui", + "/supplychain/product_supplier_mapping_list/get_product_supplier_mapping.dspy", + "/supplychain/product_supplier_mapping_list/add_product_supplier_mapping.dspy", + "/supplychain/product_supplier_mapping_list/update_product_supplier_mapping.dspy", + "/supplychain/product_supplier_mapping_list/delete_product_supplier_mapping.dspy", # CRUD API — platform_supply_relations "/supplychain/api/platform_supply_relations_create.dspy", "/supplychain/api/platform_supply_relations_update.dspy", @@ -158,16 +170,28 @@ PATHS_OPERATOR = [ # 平台供销关系管理 "/supplychain/platform_supply_relations_list", "/supplychain/platform_supply_relations_list/index.ui", + "/supplychain/platform_supply_relations_list/get_platform_supply_relations.dspy", + "/supplychain/platform_supply_relations_list/add_platform_supply_relations.dspy", + "/supplychain/platform_supply_relations_list/update_platform_supply_relations.dspy", + "/supplychain/platform_supply_relations_list/delete_platform_supply_relations.dspy", "/supplychain/api/platform_supply_relations_create.dspy", "/supplychain/api/platform_supply_relations_update.dspy", "/supplychain/api/platform_supply_relations_delete.dspy", "/supplychain/platform_supply_products_list", "/supplychain/platform_supply_products_list/index.ui", + "/supplychain/platform_supply_products_list/get_platform_supply_products.dspy", + "/supplychain/platform_supply_products_list/add_platform_supply_products.dspy", + "/supplychain/platform_supply_products_list/update_platform_supply_products.dspy", + "/supplychain/platform_supply_products_list/delete_platform_supply_products.dspy", "/supplychain/api/platform_supply_products_create.dspy", "/supplychain/api/platform_supply_products_update.dspy", "/supplychain/api/platform_supply_products_delete.dspy", "/supplychain/product_supplier_mapping_list", "/supplychain/product_supplier_mapping_list/index.ui", + "/supplychain/product_supplier_mapping_list/get_product_supplier_mapping.dspy", + "/supplychain/product_supplier_mapping_list/add_product_supplier_mapping.dspy", + "/supplychain/product_supplier_mapping_list/update_product_supplier_mapping.dspy", + "/supplychain/product_supplier_mapping_list/delete_product_supplier_mapping.dspy", "/supplychain/api/product_supplier_mapping_create.dspy", "/supplychain/api/product_supplier_mapping_update.dspy", "/supplychain/api/product_supplier_mapping_delete.dspy", diff --git a/supplychain/__pycache__/init.cpython-310.pyc b/supplychain/__pycache__/init.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5dc0ef3ad6b1ba1b47b4ae367d28378aa4f82350 GIT binary patch literal 20289 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