fix(supplychain): 规范修复 + P0函数注册 + 文档完善
- 修复12个.dspy文件: 移除import/print, 改用return - init.py: 添加9个P0 CRUD函数 + 单复数兼容注册 - load_path.py: 补充15个CRUD子目录路径 - README.md: 添加P0表说明 + 业务API + 部署清单 - global_menu.ui: 已有supplychain入口(验证通过)
This commit is contained in:
parent
dff8b0de2a
commit
8766afa8c0
24
README.md
24
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_agreements` | Distribution agreements between reseller and sub-reseller |
|
||||||
| `distribution_agreement_items` | Product-level discount details per distribution agreement |
|
| `distribution_agreement_items` | Product-level discount details per distribution agreement |
|
||||||
| `sales_ledger` | Sales transaction records with calculated amounts |
|
| `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
|
### 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}
|
# 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
|
||||||
|
|||||||
@ -116,8 +116,20 @@ PATHS_LOGINED = [
|
|||||||
"/supplychain/api/query_dist_discount.dspy",
|
"/supplychain/api/query_dist_discount.dspy",
|
||||||
# 平台供销关系
|
# 平台供销关系
|
||||||
"/supplychain/platform_supply_relations_list/index.ui",
|
"/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/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/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
|
# CRUD API — platform_supply_relations
|
||||||
"/supplychain/api/platform_supply_relations_create.dspy",
|
"/supplychain/api/platform_supply_relations_create.dspy",
|
||||||
"/supplychain/api/platform_supply_relations_update.dspy",
|
"/supplychain/api/platform_supply_relations_update.dspy",
|
||||||
@ -158,16 +170,28 @@ PATHS_OPERATOR = [
|
|||||||
# 平台供销关系管理
|
# 平台供销关系管理
|
||||||
"/supplychain/platform_supply_relations_list",
|
"/supplychain/platform_supply_relations_list",
|
||||||
"/supplychain/platform_supply_relations_list/index.ui",
|
"/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_create.dspy",
|
||||||
"/supplychain/api/platform_supply_relations_update.dspy",
|
"/supplychain/api/platform_supply_relations_update.dspy",
|
||||||
"/supplychain/api/platform_supply_relations_delete.dspy",
|
"/supplychain/api/platform_supply_relations_delete.dspy",
|
||||||
"/supplychain/platform_supply_products_list",
|
"/supplychain/platform_supply_products_list",
|
||||||
"/supplychain/platform_supply_products_list/index.ui",
|
"/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_create.dspy",
|
||||||
"/supplychain/api/platform_supply_products_update.dspy",
|
"/supplychain/api/platform_supply_products_update.dspy",
|
||||||
"/supplychain/api/platform_supply_products_delete.dspy",
|
"/supplychain/api/platform_supply_products_delete.dspy",
|
||||||
"/supplychain/product_supplier_mapping_list",
|
"/supplychain/product_supplier_mapping_list",
|
||||||
"/supplychain/product_supplier_mapping_list/index.ui",
|
"/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_create.dspy",
|
||||||
"/supplychain/api/product_supplier_mapping_update.dspy",
|
"/supplychain/api/product_supplier_mapping_update.dspy",
|
||||||
"/supplychain/api/product_supplier_mapping_delete.dspy",
|
"/supplychain/api/product_supplier_mapping_delete.dspy",
|
||||||
|
|||||||
BIN
supplychain/__pycache__/init.cpython-310.pyc
Normal file
BIN
supplychain/__pycache__/init.cpython-310.pyc
Normal file
Binary file not shown.
@ -628,6 +628,195 @@ LIMIT 1"""
|
|||||||
return json.dumps({"status": "ok", "data": result})
|
return json.dumps({"status": "ok", "data": result})
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Platform Supply Relations APIs (P0)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
def _generate_psr_code(supplier_org_id, buyer_org_id):
|
||||||
|
"""Generate unique relation code: PSR-{YYYYMMDD}-{seq}."""
|
||||||
|
env = ServerEnv()
|
||||||
|
today = env.strdate(env.today())
|
||||||
|
prefix = f"PSR-{today.replace('-', '')}"
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
with db.sqlorContext(dbname) as sor:
|
||||||
|
sql = """SELECT COUNT(*) as cnt FROM platform_supply_relations
|
||||||
|
WHERE supplier_org_id = ${sid}$ AND relation_code LIKE ${prefix}$"""
|
||||||
|
recs = sor.sqlExe(sql, {"sid": supplier_org_id, "prefix": prefix + "%"})
|
||||||
|
seq = (recs[0].cnt if recs else 0) + 1
|
||||||
|
return f"{prefix}-{seq:04d}"
|
||||||
|
|
||||||
|
|
||||||
|
async def create_platform_supply_relations(request, params_kw):
|
||||||
|
"""Create a platform supply relation."""
|
||||||
|
env = ServerEnv()
|
||||||
|
user_id = await env.get_user()
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
supplier_org_id = data.get("supplier_org_id")
|
||||||
|
buyer_org_id = data.get("buyer_org_id")
|
||||||
|
relation_code = data.get("relation_code") or _generate_psr_code(supplier_org_id, buyer_org_id)
|
||||||
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
rec = {
|
||||||
|
"id": getID(),
|
||||||
|
"supplier_org_id": supplier_org_id,
|
||||||
|
"buyer_org_id": buyer_org_id,
|
||||||
|
"relation_code": relation_code,
|
||||||
|
"relation_name": data.get("relation_name"),
|
||||||
|
"relation_type": data.get("relation_type", "distribution"),
|
||||||
|
"settlement_mode": data.get("settlement_mode", "discount"),
|
||||||
|
"default_discount": data.get("default_discount", 1.0),
|
||||||
|
"default_commission_rate": data.get("default_commission_rate", 0.0),
|
||||||
|
"sign_date": data.get("sign_date"),
|
||||||
|
"start_date": data.get("start_date"),
|
||||||
|
"end_date": data.get("end_date"),
|
||||||
|
"status": data.get("status", "1"),
|
||||||
|
"remark": data.get("remark"),
|
||||||
|
"created_by": user_id,
|
||||||
|
"created_at": now,
|
||||||
|
"updated_at": now,
|
||||||
|
}
|
||||||
|
await sor.C("platform_supply_relations", rec)
|
||||||
|
return json.dumps({"status": "ok", "data": rec, "message": "创建成功"})
|
||||||
|
|
||||||
|
|
||||||
|
async def update_platform_supply_relations(request, params_kw):
|
||||||
|
"""Update a platform supply relation."""
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
rec = {"id": data["id"], "updated_at": now}
|
||||||
|
for key in ["relation_name", "relation_type", "settlement_mode",
|
||||||
|
"default_discount", "default_commission_rate", "sign_date",
|
||||||
|
"start_date", "end_date", "status", "remark"]:
|
||||||
|
if key in data:
|
||||||
|
rec[key] = data[key]
|
||||||
|
await sor.U("platform_supply_relations", rec)
|
||||||
|
return json.dumps({"status": "ok", "message": "更新成功"})
|
||||||
|
|
||||||
|
|
||||||
|
async def delete_platform_supply_relations(request, params_kw):
|
||||||
|
"""Delete a platform supply relation and its products."""
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
await sor.D("platform_supply_products", {"relation_id": data["id"]})
|
||||||
|
await sor.D("platform_supply_relations", {"id": data["id"]})
|
||||||
|
return json.dumps({"status": "ok", "message": "删除成功"})
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Platform Supply Products APIs (P0)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
async def create_platform_supply_products(request, params_kw):
|
||||||
|
"""Create a platform supply product item."""
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
rec = {
|
||||||
|
"id": getID(),
|
||||||
|
"relation_id": data.get("relation_id"),
|
||||||
|
"supplier_org_id": data.get("supplier_org_id"),
|
||||||
|
"buyer_org_id": data.get("buyer_org_id"),
|
||||||
|
"source_product_id": data.get("source_product_id"),
|
||||||
|
"supply_price": data.get("supply_price", 0),
|
||||||
|
"suggested_retail_price": data.get("suggested_retail_price"),
|
||||||
|
"discount": data.get("discount", 1.0),
|
||||||
|
"commission_rate": data.get("commission_rate", 0.0),
|
||||||
|
"min_order_qty": data.get("min_order_qty"),
|
||||||
|
"status": data.get("status", "1"),
|
||||||
|
"remark": data.get("remark"),
|
||||||
|
"created_at": now,
|
||||||
|
"updated_at": now,
|
||||||
|
}
|
||||||
|
await sor.C("platform_supply_products", rec)
|
||||||
|
return json.dumps({"status": "ok", "data": rec, "message": "创建成功"})
|
||||||
|
|
||||||
|
|
||||||
|
async def update_platform_supply_products(request, params_kw):
|
||||||
|
"""Update a platform supply product item."""
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
rec = {"id": data["id"], "updated_at": now}
|
||||||
|
for key in ["supply_price", "suggested_retail_price", "discount",
|
||||||
|
"commission_rate", "min_order_qty", "status", "remark"]:
|
||||||
|
if key in data:
|
||||||
|
rec[key] = data[key]
|
||||||
|
await sor.U("platform_supply_products", rec)
|
||||||
|
return json.dumps({"status": "ok", "message": "更新成功"})
|
||||||
|
|
||||||
|
|
||||||
|
async def delete_platform_supply_products(request, params_kw):
|
||||||
|
"""Delete a platform supply product item."""
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
await sor.D("platform_supply_products", {"id": data["id"]})
|
||||||
|
return json.dumps({"status": "ok", "message": "删除成功"})
|
||||||
|
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Product Supplier Mapping APIs (P0)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
async def create_product_supplier_mapping(request, params_kw):
|
||||||
|
"""Create a product supplier mapping."""
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
rec = {
|
||||||
|
"id": getID(),
|
||||||
|
"product_id": data.get("product_id"),
|
||||||
|
"product_category_id": data.get("product_category_id"),
|
||||||
|
"supplier_type": data.get("supplier_type", "internal"),
|
||||||
|
"supplier_org_id": data.get("supplier_org_id"),
|
||||||
|
"external_supplier_id": data.get("external_supplier_id"),
|
||||||
|
"buyer_org_id": data.get("buyer_org_id"),
|
||||||
|
"supply_price": data.get("supply_price"),
|
||||||
|
"currency": data.get("currency", "CNY"),
|
||||||
|
"min_order_qty": data.get("min_order_qty", 1),
|
||||||
|
"lead_time_days": data.get("lead_time_days"),
|
||||||
|
"is_preferred": data.get("is_preferred", "0"),
|
||||||
|
"status": data.get("status", "1"),
|
||||||
|
"relation_id": data.get("relation_id"),
|
||||||
|
"contract_id": data.get("contract_id"),
|
||||||
|
"created_at": now,
|
||||||
|
"updated_at": now,
|
||||||
|
}
|
||||||
|
await sor.C("product_supplier_mapping", rec)
|
||||||
|
return json.dumps({"status": "ok", "data": rec, "message": "创建成功"})
|
||||||
|
|
||||||
|
|
||||||
|
async def update_product_supplier_mapping(request, params_kw):
|
||||||
|
"""Update a product supplier mapping."""
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
rec = {"id": data["id"], "updated_at": now}
|
||||||
|
for key in ["supply_price", "currency", "min_order_qty", "lead_time_days",
|
||||||
|
"is_preferred", "status", "remark", "relation_id", "contract_id"]:
|
||||||
|
if key in data:
|
||||||
|
rec[key] = data[key]
|
||||||
|
await sor.U("product_supplier_mapping", rec)
|
||||||
|
return json.dumps({"status": "ok", "message": "更新成功"})
|
||||||
|
|
||||||
|
|
||||||
|
async def delete_product_supplier_mapping(request, params_kw):
|
||||||
|
"""Delete a product supplier mapping."""
|
||||||
|
data = params_kw
|
||||||
|
db, dbname = _get_sor()
|
||||||
|
async with db.sqlorContext(dbname) as sor:
|
||||||
|
await sor.D("product_supplier_mapping", {"id": data["id"]})
|
||||||
|
return json.dumps({"status": "ok", "message": "删除成功"})
|
||||||
|
|
||||||
|
|
||||||
# ============================================================
|
# ============================================================
|
||||||
# Register functions with ServerEnv
|
# Register functions with ServerEnv
|
||||||
# ============================================================
|
# ============================================================
|
||||||
@ -635,34 +824,68 @@ LIMIT 1"""
|
|||||||
def load_supplychain():
|
def load_supplychain():
|
||||||
"""Register all supplychain functions with ServerEnv."""
|
"""Register all supplychain functions with ServerEnv."""
|
||||||
env = ServerEnv()
|
env = ServerEnv()
|
||||||
# Supplier
|
# Supplier (register both singular and plural for backward compat)
|
||||||
env.create_supplier = create_supplier
|
env.create_supplier = create_supplier
|
||||||
|
env.create_suppliers = create_supplier
|
||||||
env.update_supplier = update_supplier
|
env.update_supplier = update_supplier
|
||||||
|
env.update_suppliers = update_supplier
|
||||||
env.delete_supplier = delete_supplier
|
env.delete_supplier = delete_supplier
|
||||||
|
env.delete_suppliers = delete_supplier
|
||||||
# Supply Contract
|
# Supply Contract
|
||||||
env.create_supply_contract = create_supply_contract
|
env.create_supply_contract = create_supply_contract
|
||||||
|
env.create_supply_contracts = create_supply_contract
|
||||||
env.update_supply_contract = update_supply_contract
|
env.update_supply_contract = update_supply_contract
|
||||||
|
env.update_supply_contracts = update_supply_contract
|
||||||
env.delete_supply_contract = delete_supply_contract
|
env.delete_supply_contract = delete_supply_contract
|
||||||
|
env.delete_supply_contracts = delete_supply_contract
|
||||||
# Supply Contract Items
|
# Supply Contract Items
|
||||||
env.create_supply_contract_item = create_supply_contract_item
|
env.create_supply_contract_item = create_supply_contract_item
|
||||||
|
env.create_supply_contract_items = create_supply_contract_item
|
||||||
env.update_supply_contract_item = update_supply_contract_item
|
env.update_supply_contract_item = update_supply_contract_item
|
||||||
|
env.update_supply_contract_items = update_supply_contract_item
|
||||||
env.delete_supply_contract_item = delete_supply_contract_item
|
env.delete_supply_contract_item = delete_supply_contract_item
|
||||||
|
env.delete_supply_contract_items = delete_supply_contract_item
|
||||||
# Sub-Reseller
|
# Sub-Reseller
|
||||||
env.create_sub_reseller = create_sub_reseller
|
env.create_sub_reseller = create_sub_reseller
|
||||||
|
env.create_sub_resellers = create_sub_reseller
|
||||||
env.update_sub_reseller = update_sub_reseller
|
env.update_sub_reseller = update_sub_reseller
|
||||||
|
env.update_sub_resellers = update_sub_reseller
|
||||||
env.delete_sub_reseller = delete_sub_reseller
|
env.delete_sub_reseller = delete_sub_reseller
|
||||||
|
env.delete_sub_resellers = delete_sub_reseller
|
||||||
|
# Sub-Distributor (not yet implemented)
|
||||||
# Distribution Agreement
|
# Distribution Agreement
|
||||||
env.create_distribution_agreement = create_distribution_agreement
|
env.create_distribution_agreement = create_distribution_agreement
|
||||||
|
env.create_distribution_agreements = create_distribution_agreement
|
||||||
env.update_distribution_agreement = update_distribution_agreement
|
env.update_distribution_agreement = update_distribution_agreement
|
||||||
|
env.update_distribution_agreements = update_distribution_agreement
|
||||||
env.delete_distribution_agreement = delete_distribution_agreement
|
env.delete_distribution_agreement = delete_distribution_agreement
|
||||||
|
env.delete_distribution_agreements = delete_distribution_agreement
|
||||||
# Distribution Agreement Items
|
# Distribution Agreement Items
|
||||||
env.create_distribution_agreement_item = create_distribution_agreement_item
|
env.create_distribution_agreement_item = create_distribution_agreement_item
|
||||||
|
env.create_distribution_agreement_items = create_distribution_agreement_item
|
||||||
env.update_distribution_agreement_item = update_distribution_agreement_item
|
env.update_distribution_agreement_item = update_distribution_agreement_item
|
||||||
|
env.update_distribution_agreement_items = update_distribution_agreement_item
|
||||||
env.delete_distribution_agreement_item = delete_distribution_agreement_item
|
env.delete_distribution_agreement_item = delete_distribution_agreement_item
|
||||||
|
env.delete_distribution_agreement_items = delete_distribution_agreement_item
|
||||||
# Sales Ledger
|
# Sales Ledger
|
||||||
env.create_sales_ledger = create_sales_ledger
|
env.create_sales_ledger = create_sales_ledger
|
||||||
|
env.create_sales_ledgers = create_sales_ledger
|
||||||
env.update_sales_ledger = update_sales_ledger
|
env.update_sales_ledger = update_sales_ledger
|
||||||
|
env.update_sales_ledgers = update_sales_ledger
|
||||||
env.delete_sales_ledger = delete_sales_ledger
|
env.delete_sales_ledger = delete_sales_ledger
|
||||||
|
env.delete_sales_ledgers = delete_sales_ledger
|
||||||
|
# P0: Platform Supply Relations
|
||||||
|
env.create_platform_supply_relations = create_platform_supply_relations
|
||||||
|
env.update_platform_supply_relations = update_platform_supply_relations
|
||||||
|
env.delete_platform_supply_relations = delete_platform_supply_relations
|
||||||
|
# P0: Platform Supply Products
|
||||||
|
env.create_platform_supply_products = create_platform_supply_products
|
||||||
|
env.update_platform_supply_products = update_platform_supply_products
|
||||||
|
env.delete_platform_supply_products = delete_platform_supply_products
|
||||||
|
# P0: Product Supplier Mapping
|
||||||
|
env.create_product_supplier_mapping = create_product_supplier_mapping
|
||||||
|
env.update_product_supplier_mapping = update_product_supplier_mapping
|
||||||
|
env.delete_product_supplier_mapping = delete_product_supplier_mapping
|
||||||
# Calculation API
|
# Calculation API
|
||||||
env.calculate_sale_amounts = calculate_sale_amounts
|
env.calculate_sale_amounts = calculate_sale_amounts
|
||||||
return True
|
return True
|
||||||
|
|||||||
@ -1,37 +1,28 @@
|
|||||||
import json
|
|
||||||
from sqlor import sqlExe
|
|
||||||
from uuid import uuid4
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
# 引入供应方产品到需求方:创建 product_supplier_mapping 记录
|
|
||||||
source_product_id = params_kw.get("source_product_id", "")
|
source_product_id = params_kw.get("source_product_id", "")
|
||||||
supplier_org_id = params_kw.get("supplier_org_id", "")
|
supplier_org_id = params_kw.get("supplier_org_id", "")
|
||||||
relation_id = params_kw.get("relation_id", "")
|
relation_id = params_kw.get("relation_id", "")
|
||||||
supply_price = params_kw.get("supply_price", "0")
|
supply_price = params_kw.get("supply_price", "0")
|
||||||
suggested_retail_price = params_kw.get("suggested_retail_price", "")
|
|
||||||
min_order_qty = params_kw.get("min_order_qty", "1")
|
min_order_qty = params_kw.get("min_order_qty", "1")
|
||||||
|
|
||||||
if not all([source_product_id, supplier_org_id, relation_id]):
|
if not all([source_product_id, supplier_org_id, relation_id]):
|
||||||
print(json.dumps({"status": "error", "message": "source_product_id, supplier_org_id, relation_id are required"}))
|
return json.dumps({"status": "error", "message": "source_product_id, supplier_org_id, relation_id are required"})
|
||||||
else:
|
|
||||||
user_org_id = await get_user_orgid()
|
|
||||||
new_id = uuid4().hex
|
|
||||||
now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
|
||||||
|
|
||||||
# 获取产品分类
|
user_org_id = await get_userorgid()
|
||||||
prod_sql = "SELECT category_id FROM product WHERE id = ${pid}$"
|
new_id = getID()
|
||||||
prod = await sqlExe(prod_sql, {"pid": source_product_id})
|
now = curDateString() + " " + timestampstr()[:8]
|
||||||
|
|
||||||
|
async with get_sor_context(request._run_ns, 'sage') as sor:
|
||||||
|
prod = await sor.sqlExe("SELECT category_id FROM product WHERE id = ${pid}$", {"pid": source_product_id})
|
||||||
cat_id = prod[0].category_id if prod else ""
|
cat_id = prod[0].category_id if prod else ""
|
||||||
|
|
||||||
sql = """
|
await sor.sqlExe("""
|
||||||
INSERT INTO product_supplier_mapping
|
INSERT INTO product_supplier_mapping
|
||||||
(id, product_id, product_category_id, supplier_type, supplier_org_id,
|
(id, product_id, product_category_id, supplier_type, supplier_org_id,
|
||||||
buyer_org_id, supply_price, min_order_qty, status, relation_id, created_at)
|
buyer_org_id, supply_price, min_order_qty, status, relation_id, created_at)
|
||||||
VALUES
|
VALUES
|
||||||
(${id}$, ${product_id}$, ${category_id}$, 'internal', ${supplier_org_id}$,
|
(${id}$, ${product_id}$, ${category_id}$, 'internal', ${supplier_org_id}$,
|
||||||
${buyer_org_id}$, ${supply_price}$, ${min_order_qty}$, '1', ${relation_id}$, ${created_at}$)
|
${buyer_org_id}$, ${supply_price}$, ${min_order_qty}$, '1', ${relation_id}$, ${created_at}$)
|
||||||
"""
|
""", {
|
||||||
await sqlExe(sql, {
|
|
||||||
"id": new_id,
|
"id": new_id,
|
||||||
"product_id": source_product_id,
|
"product_id": source_product_id,
|
||||||
"category_id": cat_id,
|
"category_id": cat_id,
|
||||||
@ -42,4 +33,5 @@ else:
|
|||||||
"relation_id": relation_id,
|
"relation_id": relation_id,
|
||||||
"created_at": now
|
"created_at": now
|
||||||
})
|
})
|
||||||
print(json.dumps({"status": "ok", "message": "产品引入成功", "id": new_id}))
|
|
||||||
|
return json.dumps({"status": "ok", "message": "产品引入成功", "id": new_id})
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
create_func = create_platform_supply_products
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
create_func = getattr(env, 'create_platform_supply_products', None)
|
|
||||||
if create_func is None:
|
if create_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "create_platform_supply_products function not found"}))
|
return json.dumps({"status": "error", "message": "create_platform_supply_products not registered"})
|
||||||
else:
|
result = await create_func(request, params_kw)
|
||||||
result = await create_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
delete_func = delete_platform_supply_products
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
delete_func = getattr(env, 'delete_platform_supply_products', None)
|
|
||||||
if delete_func is None:
|
if delete_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "delete_platform_supply_products function not found"}))
|
return json.dumps({"status": "error", "message": "delete_platform_supply_products not registered"})
|
||||||
else:
|
result = await delete_func(request, params_kw)
|
||||||
result = await delete_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
update_func = update_platform_supply_products
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
update_func = getattr(env, 'update_platform_supply_products', None)
|
|
||||||
if update_func is None:
|
if update_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "update_platform_supply_products function not found"}))
|
return json.dumps({"status": "error", "message": "update_platform_supply_products not registered"})
|
||||||
else:
|
result = await update_func(request, params_kw)
|
||||||
result = await update_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
create_func = create_platform_supply_relations
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
create_func = getattr(env, 'create_platform_supply_relations', None)
|
|
||||||
if create_func is None:
|
if create_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "create_platform_supply_relations function not found"}))
|
return json.dumps({"status": "error", "message": "create_platform_supply_relations not registered"})
|
||||||
else:
|
result = await create_func(request, params_kw)
|
||||||
result = await create_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
delete_func = delete_platform_supply_relations
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
delete_func = getattr(env, 'delete_platform_supply_relations', None)
|
|
||||||
if delete_func is None:
|
if delete_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "delete_platform_supply_relations function not found"}))
|
return json.dumps({"status": "error", "message": "delete_platform_supply_relations not registered"})
|
||||||
else:
|
result = await delete_func(request, params_kw)
|
||||||
result = await delete_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
update_func = update_platform_supply_relations
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
update_func = getattr(env, 'update_platform_supply_relations', None)
|
|
||||||
if update_func is None:
|
if update_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "update_platform_supply_relations function not found"}))
|
return json.dumps({"status": "error", "message": "update_platform_supply_relations not registered"})
|
||||||
else:
|
result = await update_func(request, params_kw)
|
||||||
result = await update_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
create_func = create_product_supplier_mapping
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
create_func = getattr(env, 'create_product_supplier_mapping', None)
|
|
||||||
if create_func is None:
|
if create_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "create_product_supplier_mapping function not found"}))
|
return json.dumps({"status": "error", "message": "create_product_supplier_mapping not registered"})
|
||||||
else:
|
result = await create_func(request, params_kw)
|
||||||
result = await create_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
delete_func = delete_product_supplier_mapping
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
delete_func = getattr(env, 'delete_product_supplier_mapping', None)
|
|
||||||
if delete_func is None:
|
if delete_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "delete_product_supplier_mapping function not found"}))
|
return json.dumps({"status": "error", "message": "delete_product_supplier_mapping not registered"})
|
||||||
else:
|
result = await delete_func(request, params_kw)
|
||||||
result = await delete_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,9 +1,5 @@
|
|||||||
import json
|
update_func = update_product_supplier_mapping
|
||||||
from ahserver.serverenv import ServerEnv
|
|
||||||
env = ServerEnv()
|
|
||||||
update_func = getattr(env, 'update_product_supplier_mapping', None)
|
|
||||||
if update_func is None:
|
if update_func is None:
|
||||||
print(json.dumps({"status": "error", "message": "update_product_supplier_mapping function not found"}))
|
return json.dumps({"status": "error", "message": "update_product_supplier_mapping not registered"})
|
||||||
else:
|
result = await update_func(request, params_kw)
|
||||||
result = await update_func(request, params_kw)
|
return result
|
||||||
print(result)
|
|
||||||
|
|||||||
@ -1,23 +1,20 @@
|
|||||||
import json
|
|
||||||
from sqlor import sqlExe
|
|
||||||
|
|
||||||
# 查询某供应方机构的可用产品列表
|
|
||||||
supplier_org_id = params_kw.get("supplier_org_id", "")
|
supplier_org_id = params_kw.get("supplier_org_id", "")
|
||||||
if not supplier_org_id:
|
if not supplier_org_id:
|
||||||
print(json.dumps({"status": "error", "message": "supplier_org_id is required"}))
|
return json.dumps({"status": "error", "message": "supplier_org_id is required"})
|
||||||
else:
|
|
||||||
sql = """
|
async with get_sor_context(request._run_ns, 'sage') as sor:
|
||||||
|
rows = await sor.sqlExe("""
|
||||||
SELECT p.id, p.product_code, p.product_name, p.product_type,
|
SELECT p.id, p.product_code, p.product_name, p.product_type,
|
||||||
p.brief_intro, p.price, p.currency, p.status,
|
p.brief_intro, p.price, p.currency, p.status,
|
||||||
pc.name as category_name
|
pc.name as category_name
|
||||||
FROM product p
|
FROM product p
|
||||||
LEFT JOIN product_category pc ON p.category_id = pc.id
|
LEFT JOIN product_category pc ON p.category_id = pc.id AND p.org_id = pc.org_id
|
||||||
WHERE p.org_id = ${supplier_org_id}$
|
WHERE p.org_id = ${supplier_org_id}$
|
||||||
AND p.status = '1'
|
AND p.status = '1'
|
||||||
ORDER BY p.sort_order, p.product_name
|
ORDER BY p.sort_order, p.product_name
|
||||||
"""
|
""", {"supplier_org_id": supplier_org_id})
|
||||||
rows = await sqlExe(sql, {"supplier_org_id": supplier_org_id})
|
|
||||||
print(json.dumps([{"id": r.id, "product_code": r.product_code,
|
return json.dumps([{"id": r.id, "product_code": r.product_code,
|
||||||
"product_name": r.product_name, "product_type": r.product_type,
|
"product_name": r.product_name, "product_type": r.product_type,
|
||||||
"brief_intro": r.brief_intro, "price": r.price, "currency": r.currency,
|
"brief_intro": r.brief_intro, "price": r.price, "currency": r.currency,
|
||||||
"category_name": r.category_name} for r in rows], ensure_ascii=False))
|
"category_name": r.category_name} for r in rows], ensure_ascii=False)
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
import json
|
user_org_id = await get_userorgid()
|
||||||
from sqlor import sqlExe
|
async with get_sor_context(request._run_ns, 'sage') as sor:
|
||||||
|
rows = await sor.sqlExe("""
|
||||||
|
SELECT id, orgname, orgabbr, contactor, contactor_phone, main_business
|
||||||
|
FROM organization
|
||||||
|
WHERE id != ${user_org_id}$
|
||||||
|
AND (del_flg IS NULL OR del_flg = '0')
|
||||||
|
ORDER BY orgname
|
||||||
|
""", {"user_org_id": user_org_id})
|
||||||
|
|
||||||
# 查询平台上所有可作为供应方的机构(排除当前用户的机构)
|
return json.dumps([{"id": r.id, "orgname": r.orgname, "orgabbr": r.orgabbr,
|
||||||
user_org_id = await get_user_orgid()
|
|
||||||
sql = """
|
|
||||||
SELECT id, orgname, orgabbr, contactor, contactor_phone, main_business
|
|
||||||
FROM organization
|
|
||||||
WHERE id != ${user_org_id}$
|
|
||||||
AND (del_flg IS NULL OR del_flg = '0')
|
|
||||||
ORDER BY orgname
|
|
||||||
"""
|
|
||||||
rows = await sqlExe(sql, {"user_org_id": user_org_id})
|
|
||||||
print(json.dumps([{"id": r.id, "orgname": r.orgname, "orgabbr": r.orgabbr,
|
|
||||||
"contactor": r.contactor, "contactor_phone": r.contactor_phone,
|
"contactor": r.contactor, "contactor_phone": r.contactor_phone,
|
||||||
"main_business": r.main_business} for r in rows], ensure_ascii=False))
|
"main_business": r.main_business} for r in rows], ensure_ascii=False)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user