diff --git a/models/product.json b/models/product.json index d9ecca5..5314e7a 100644 --- a/models/product.json +++ b/models/product.json @@ -121,13 +121,13 @@ { "name": "created_at", "title": "创建时间", - "type": "datetime", + "type": "timestamp", "nullable": "no" }, { "name": "updated_at", "title": "更新时间", - "type": "datetime", + "type": "timestamp", "nullable": "no" } ], @@ -202,4 +202,4 @@ "cond": "parentid='product_type'" } ] -} \ No newline at end of file +} diff --git a/models/product_category.json b/models/product_category.json index def11da..c86dd84 100644 --- a/models/product_category.json +++ b/models/product_category.json @@ -90,13 +90,13 @@ { "name": "created_at", "title": "创建时间", - "type": "datetime", + "type": "timestamp", "nullable": "no" }, { "name": "updated_at", "title": "更新时间", - "type": "datetime", + "type": "timestamp", "nullable": "no" } ], @@ -156,4 +156,4 @@ "cond": "parentid='product_type'" } ] -} \ No newline at end of file +} diff --git a/models/product_resource.json b/models/product_resource.json index 8d53c6d..e40a198 100644 --- a/models/product_resource.json +++ b/models/product_resource.json @@ -3,28 +3,115 @@ { "name": "product_resource", "title": "产品资源绑定表", - "primary": ["id"], + "primary": [ + "id" + ], "catelog": "relation" } ], "fields": [ - {"name": "id", "title": "主键ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "product_id", "title": "产品ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "resource_type", "title": "资源类型", "type": "str", "length": 32, "nullable": "no"}, - {"name": "resource_ref_id", "title": "资源引用ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "resource_ref_name", "title": "资源显示名", "type": "str", "length": 255}, - {"name": "quota", "title": "配额量", "type": "double", "length": 15, "dec": 4, "default": "0"}, - {"name": "quota_unit", "title": "配额单位", "type": "str", "length": 32}, - {"name": "priority", "title": "优先级", "type": "int", "default": "1"}, - {"name": "overflow_product_id", "title": "超额后转用产品ID", "type": "str", "length": 32}, - {"name": "status", "title": "状态", "type": "char", "length": 1, "default": "1"}, - {"name": "created_at", "title": "创建时间", "type": "datetime", "nullable": "no"}, - {"name": "updated_at", "title": "更新时间", "type": "datetime"} + { + "name": "id", + "title": "主键ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "product_id", + "title": "产品ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "resource_type", + "title": "资源类型", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "resource_ref_id", + "title": "资源引用ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "resource_ref_name", + "title": "资源显示名", + "type": "str", + "length": 255 + }, + { + "name": "quota", + "title": "配额量", + "type": "double", + "length": 15, + "dec": 4, + "default": "0" + }, + { + "name": "quota_unit", + "title": "配额单位", + "type": "str", + "length": 32 + }, + { + "name": "priority", + "title": "优先级", + "type": "int", + "default": "1" + }, + { + "name": "overflow_product_id", + "title": "超额后转用产品ID", + "type": "str", + "length": 32 + }, + { + "name": "status", + "title": "状态", + "type": "char", + "length": 1, + "default": "1" + }, + { + "name": "created_at", + "title": "创建时间", + "type": "timestamp", + "nullable": "no" + }, + { + "name": "updated_at", + "title": "更新时间", + "type": "datetime" + } ], "indexes": [ - {"name": "idx_pr_product", "idxtype": "index", "idxfields": ["product_id"]}, - {"name": "idx_pr_resource", "idxtype": "index", "idxfields": ["resource_type", "resource_ref_id"]}, - {"name": "idx_pr_status", "idxtype": "index", "idxfields": ["status"]} + { + "name": "idx_pr_product", + "idxtype": "index", + "idxfields": [ + "product_id" + ] + }, + { + "name": "idx_pr_resource", + "idxtype": "index", + "idxfields": [ + "resource_type", + "resource_ref_id" + ] + }, + { + "name": "idx_pr_status", + "idxtype": "index", + "idxfields": [ + "status" + ] + } ], "codes": [ { diff --git a/models/product_resource_supplier.json b/models/product_resource_supplier.json index 7d7d3f5..86ca1cf 100644 --- a/models/product_resource_supplier.json +++ b/models/product_resource_supplier.json @@ -3,23 +3,83 @@ { "name": "product_resource_supplier", "title": "产品资源供应商关联表", - "primary": ["id"], + "primary": [ + "id" + ], "catelog": "relation" } ], "fields": [ - {"name": "id", "title": "主键ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "product_resource_id", "title": "产品资源绑定ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "supplier_org_id", "title": "供应商机构ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "priority", "title": "优先级", "type": "int", "default": "1"}, - {"name": "weight", "title": "权重", "type": "int", "default": "100"}, - {"name": "status", "title": "状态", "type": "char", "length": 1, "default": "1"}, - {"name": "created_at", "title": "创建时间", "type": "datetime", "nullable": "no"} + { + "name": "id", + "title": "主键ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "product_resource_id", + "title": "产品资源绑定ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "supplier_org_id", + "title": "供应商机构ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "priority", + "title": "优先级", + "type": "int", + "default": "1" + }, + { + "name": "weight", + "title": "权重", + "type": "int", + "default": "100" + }, + { + "name": "status", + "title": "状态", + "type": "char", + "length": 1, + "default": "1" + }, + { + "name": "created_at", + "title": "创建时间", + "type": "timestamp", + "nullable": "no" + } ], "indexes": [ - {"name": "idx_prs_resource", "idxtype": "index", "idxfields": ["product_resource_id"]}, - {"name": "idx_prs_supplier", "idxtype": "index", "idxfields": ["supplier_org_id"]}, - {"name": "idx_prs_unique", "idxtype": "unique", "idxfields": ["product_resource_id", "supplier_org_id"]} + { + "name": "idx_prs_resource", + "idxtype": "index", + "idxfields": [ + "product_resource_id" + ] + }, + { + "name": "idx_prs_supplier", + "idxtype": "index", + "idxfields": [ + "supplier_org_id" + ] + }, + { + "name": "idx_prs_unique", + "idxtype": "unique", + "idxfields": [ + "product_resource_id", + "supplier_org_id" + ] + } ], "codes": [ { diff --git a/models/product_subscription.json b/models/product_subscription.json index f9abb99..8071b02 100644 --- a/models/product_subscription.json +++ b/models/product_subscription.json @@ -3,34 +3,163 @@ { "name": "product_subscription", "title": "客户订购表", - "primary": ["id"], + "primary": [ + "id" + ], "catelog": "relation" } ], "fields": [ - {"name": "id", "title": "主键ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "product_id", "title": "产品ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "user_id", "title": "客户用户ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "user_org_id", "title": "客户机构ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "subscription_type", "title": "订购类型", "type": "char", "length": 1, "nullable": "no"}, - {"name": "status", "title": "状态", "type": "char", "length": 1, "nullable": "no", "default": "1"}, - {"name": "start_date", "title": "生效日期", "type": "date", "nullable": "no"}, - {"name": "end_date", "title": "到期日期", "type": "date", "nullable": "no"}, - {"name": "quota_total", "title": "总配额", "type": "double", "length": 15, "dec": 4, "default": "0"}, - {"name": "quota_used", "title": "已使用量", "type": "double", "length": 15, "dec": 4, "default": "0"}, - {"name": "quota_unit", "title": "配额单位", "type": "str", "length": 32}, - {"name": "overflow_mode", "title": "超额模式", "type": "char", "length": 1, "default": "1"}, - {"name": "overflow_rate", "title": "超额单价", "type": "double", "length": 15, "dec": 6, "default": "0"}, - {"name": "purchase_price", "title": "购买价格", "type": "double", "length": 15, "dec": 2, "default": "0"}, - {"name": "purchase_currency", "title": "货币", "type": "char", "length": 8, "default": "CNY"}, - {"name": "created_at", "title": "创建时间", "type": "datetime", "nullable": "no"}, - {"name": "updated_at", "title": "更新时间", "type": "datetime"} + { + "name": "id", + "title": "主键ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "product_id", + "title": "产品ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "user_id", + "title": "客户用户ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "user_org_id", + "title": "客户机构ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "subscription_type", + "title": "订购类型", + "type": "char", + "length": 1, + "nullable": "no" + }, + { + "name": "status", + "title": "状态", + "type": "char", + "length": 1, + "nullable": "no", + "default": "1" + }, + { + "name": "start_date", + "title": "生效日期", + "type": "date", + "nullable": "no" + }, + { + "name": "end_date", + "title": "到期日期", + "type": "date", + "nullable": "no" + }, + { + "name": "quota_total", + "title": "总配额", + "type": "double", + "length": 15, + "dec": 4, + "default": "0" + }, + { + "name": "quota_used", + "title": "已使用量", + "type": "double", + "length": 15, + "dec": 4, + "default": "0" + }, + { + "name": "quota_unit", + "title": "配额单位", + "type": "str", + "length": 32 + }, + { + "name": "overflow_mode", + "title": "超额模式", + "type": "char", + "length": 1, + "default": "1" + }, + { + "name": "overflow_rate", + "title": "超额单价", + "type": "double", + "length": 15, + "dec": 6, + "default": "0" + }, + { + "name": "purchase_price", + "title": "购买价格", + "type": "double", + "length": 15, + "dec": 2, + "default": "0" + }, + { + "name": "purchase_currency", + "title": "货币", + "type": "char", + "length": 8, + "default": "CNY" + }, + { + "name": "created_at", + "title": "创建时间", + "type": "timestamp", + "nullable": "no" + }, + { + "name": "updated_at", + "title": "更新时间", + "type": "datetime" + } ], "indexes": [ - {"name": "idx_ps_product", "idxtype": "index", "idxfields": ["product_id"]}, - {"name": "idx_ps_user", "idxtype": "index", "idxfields": ["user_id", "user_org_id"]}, - {"name": "idx_ps_status", "idxtype": "index", "idxfields": ["status"]}, - {"name": "idx_ps_dates", "idxtype": "index", "idxfields": ["start_date", "end_date"]} + { + "name": "idx_ps_product", + "idxtype": "index", + "idxfields": [ + "product_id" + ] + }, + { + "name": "idx_ps_user", + "idxtype": "index", + "idxfields": [ + "user_id", + "user_org_id" + ] + }, + { + "name": "idx_ps_status", + "idxtype": "index", + "idxfields": [ + "status" + ] + }, + { + "name": "idx_ps_dates", + "idxtype": "index", + "idxfields": [ + "start_date", + "end_date" + ] + } ], "codes": [ { diff --git a/models/product_type_config.json b/models/product_type_config.json index 4b27a00..85e7325 100644 --- a/models/product_type_config.json +++ b/models/product_type_config.json @@ -66,13 +66,13 @@ { "name": "created_at", "title": "创建时间", - "type": "datetime", + "type": "timestamp", "nullable": "no" }, { "name": "updated_at", "title": "更新时间", - "type": "datetime", + "type": "timestamp", "nullable": "no" } ], @@ -119,4 +119,4 @@ "cond": "parentid='enabled_flg'" } ] -} \ No newline at end of file +} diff --git a/models/product_usage_log.json b/models/product_usage_log.json index 338ca70..5517ae1 100644 --- a/models/product_usage_log.json +++ b/models/product_usage_log.json @@ -3,38 +3,186 @@ { "name": "product_usage_log", "title": "产品消费记录表", - "primary": ["id"], + "primary": [ + "id" + ], "catelog": "relation" } ], "fields": [ - {"name": "id", "title": "主键ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "product_id", "title": "产品ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "subscription_id", "title": "订购ID", "type": "str", "length": 32}, - {"name": "user_id", "title": "消费者用户ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "user_org_id", "title": "消费者机构ID", "type": "str", "length": 32, "nullable": "no"}, - {"name": "product_resource_id", "title": "产品资源绑定ID", "type": "str", "length": 32}, - {"name": "supplier_org_id", "title": "供应商机构ID", "type": "str", "length": 32}, - {"name": "resource_type", "title": "资源类型", "type": "str", "length": 32}, - {"name": "resource_ref_id", "title": "资源引用ID", "type": "str", "length": 32}, - {"name": "used_amount", "title": "消耗量", "type": "double", "length": 15, "dec": 4, "nullable": "no"}, - {"name": "used_unit", "title": "消耗单位", "type": "str", "length": 32}, - {"name": "unit_cost", "title": "单位成本", "type": "double", "length": 15, "dec": 8, "default": "0"}, - {"name": "total_cost", "title": "总成本", "type": "double", "length": 15, "dec": 6, "default": "0"}, - {"name": "sell_price", "title": "客户售价", "type": "double", "length": 15, "dec": 6, "default": "0"}, - {"name": "billing_mode", "title": "计费模式", "type": "char", "length": 1, "nullable": "no"}, - {"name": "source_ref_table", "title": "来源表", "type": "str", "length": 64}, - {"name": "source_ref_id", "title": "来源记录ID", "type": "str", "length": 32}, - {"name": "use_time", "title": "消费时间", "type": "datetime", "nullable": "no"}, - {"name": "created_at", "title": "创建时间", "type": "datetime", "nullable": "no"} + { + "name": "id", + "title": "主键ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "product_id", + "title": "产品ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "subscription_id", + "title": "订购ID", + "type": "str", + "length": 32 + }, + { + "name": "user_id", + "title": "消费者用户ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "user_org_id", + "title": "消费者机构ID", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "product_resource_id", + "title": "产品资源绑定ID", + "type": "str", + "length": 32 + }, + { + "name": "supplier_org_id", + "title": "供应商机构ID", + "type": "str", + "length": 32 + }, + { + "name": "resource_type", + "title": "资源类型", + "type": "str", + "length": 32 + }, + { + "name": "resource_ref_id", + "title": "资源引用ID", + "type": "str", + "length": 32 + }, + { + "name": "used_amount", + "title": "消耗量", + "type": "double", + "length": 15, + "dec": 4, + "nullable": "no" + }, + { + "name": "used_unit", + "title": "消耗单位", + "type": "str", + "length": 32 + }, + { + "name": "unit_cost", + "title": "单位成本", + "type": "double", + "length": 15, + "dec": 8, + "default": "0" + }, + { + "name": "total_cost", + "title": "总成本", + "type": "double", + "length": 15, + "dec": 6, + "default": "0" + }, + { + "name": "sell_price", + "title": "客户售价", + "type": "double", + "length": 15, + "dec": 6, + "default": "0" + }, + { + "name": "billing_mode", + "title": "计费模式", + "type": "char", + "length": 1, + "nullable": "no" + }, + { + "name": "source_ref_table", + "title": "来源表", + "type": "str", + "length": 64 + }, + { + "name": "source_ref_id", + "title": "来源记录ID", + "type": "str", + "length": 32 + }, + { + "name": "use_time", + "title": "消费时间", + "type": "datetime", + "nullable": "no" + }, + { + "name": "created_at", + "title": "创建时间", + "type": "timestamp", + "nullable": "no" + } ], "indexes": [ - {"name": "idx_pul_product", "idxtype": "index", "idxfields": ["product_id"]}, - {"name": "idx_pul_subscription", "idxtype": "index", "idxfields": ["subscription_id"]}, - {"name": "idx_pul_user", "idxtype": "index", "idxfields": ["user_id", "user_org_id"]}, - {"name": "idx_pul_supplier", "idxtype": "index", "idxfields": ["supplier_org_id"]}, - {"name": "idx_pul_time", "idxtype": "index", "idxfields": ["use_time"]}, - {"name": "idx_pul_source", "idxtype": "index", "idxfields": ["source_ref_table", "source_ref_id"]} + { + "name": "idx_pul_product", + "idxtype": "index", + "idxfields": [ + "product_id" + ] + }, + { + "name": "idx_pul_subscription", + "idxtype": "index", + "idxfields": [ + "subscription_id" + ] + }, + { + "name": "idx_pul_user", + "idxtype": "index", + "idxfields": [ + "user_id", + "user_org_id" + ] + }, + { + "name": "idx_pul_supplier", + "idxtype": "index", + "idxfields": [ + "supplier_org_id" + ] + }, + { + "name": "idx_pul_time", + "idxtype": "index", + "idxfields": [ + "use_time" + ] + }, + { + "name": "idx_pul_source", + "idxtype": "index", + "idxfields": [ + "source_ref_table", + "source_ref_id" + ] + } ], "codes": [ { diff --git a/product_management/core.py b/product_management/core.py index 837a427..c28523b 100644 --- a/product_management/core.py +++ b/product_management/core.py @@ -178,7 +178,6 @@ class ProductManager: """Get product detail for current org (reseller). Returns product_info + category_info + operator_config + extra_parsed. - No physical table routing - all data comes from product table + extra_json. """ if not org_id: org_id = self._get_current_org_id() @@ -471,9 +470,10 @@ class ProductManager: if existing: config_id = existing[0]['id'] await sor.U('product_type_config', { + 'id': config_id, 'config_json': config_json, 'updated_at': now - }, {'id': config_id, 'org_id': org_id}) + }) return {'success': True, 'id': config_id, 'message': 'Config updated'} else: config_id = getID() @@ -511,7 +511,7 @@ class ProductManager: return {'success': False, 'message': 'Product not found'} rid = getID() - await sor.I('product_resource', { + await sor.C('product_resource', { 'id': rid, 'product_id': product_id, 'resource_type': resource_type, @@ -598,7 +598,7 @@ class ProductManager: sid = getID() try: - await sor.I('product_resource_supplier', { + await sor.C('product_resource_supplier', { 'id': sid, 'product_resource_id': product_resource_id, 'supplier_org_id': supplier_org_id, @@ -636,14 +636,14 @@ class ProductManager: dbname = self._get_dbname() async with DBPools().sqlorContext(dbname) as sor: - data = {} + data = {'id': prs_id} if priority is not None: data['priority'] = int(priority) if weight is not None: data['weight'] = int(weight) - if not data: + if len(data) <= 1: return {'success': False, 'message': 'No fields to update'} - await sor.U('product_resource_supplier', data, {'id': prs_id}) + await sor.U('product_resource_supplier', data) return {'success': True} async def set_overflow_product(self, product_resource_id, overflow_product_id, org_id=None): @@ -655,9 +655,10 @@ class ProductManager: async with DBPools().sqlorContext(dbname) as sor: await sor.U('product_resource', { + 'id': product_resource_id, 'overflow_product_id': overflow_product_id or '', 'updated_at': now - }, {'id': product_resource_id}) + }) return {'success': True} # ─── Subscriptions ─── @@ -708,7 +709,7 @@ class ProductManager: elif product.get('product_type') in ('llm_model', 'compute'): sub_type = '2' - await sor.I('product_subscription', { + await sor.C('product_subscription', { 'id': sub_id, 'product_id': product_id, 'user_id': user_id, @@ -793,8 +794,9 @@ class ProductManager: async with DBPools().sqlorContext(dbname) as sor: await sor.U('product_subscription', { + 'id': subscription_id, 'status': '3', 'updated_at': now - }, {'id': subscription_id}) + }) return {'success': True} async def expire_subscriptions(self): @@ -816,17 +818,7 @@ class ProductManager: async def product_use(self, product_id, user_id, user_org_id, used_amount, used_unit, resource_ref_id=None, source_ref_table=None, source_ref_id=None): - """Core consumption engine: route supplier, calc cost, log usage. - - Flow: - 1. Validate product - 2. Check subscription (for monthly products) - 3. Route to supplier (by priority/weight) - 4. Calculate cost from supplier_resource_price - 5. Calculate sell price - 6. Write product_usage_log - 7. Update subscription quota - """ + """Core consumption engine: route supplier, calc cost, log usage.""" dbname = self._get_dbname() now = time.strftime('%Y-%m-%d %H:%M:%S') today = datetime.date.today().isoformat() @@ -873,17 +865,19 @@ class ProductManager: remaining_quota = remaining - used_amount # Update quota await sor.U('product_subscription', { + 'id': subscription_id, 'quota_used': quota_used + used_amount, 'updated_at': now - }, {'id': subscription_id}) + }) else: # Overflow: use up remaining, rest is overage if remaining > 0: await sor.U('product_subscription', { + 'id': subscription_id, 'quota_used': quota_total, 'status': '4', 'updated_at': now - }, {'id': subscription_id}) + }) billing_mode = '2' overage = used_amount - remaining else: @@ -961,7 +955,7 @@ class ProductManager: # Step 5: Write usage log log_id = getID() - await sor.I('product_usage_log', { + await sor.C('product_usage_log', { 'id': log_id, 'product_id': product_id, 'subscription_id': subscription_id or '', diff --git a/wwwroot/api/product_category_update.dspy b/wwwroot/api/product_category_update.dspy index 0995d6e..19d84ea 100644 --- a/wwwroot/api/product_category_update.dspy +++ b/wwwroot/api/product_category_update.dspy @@ -1,12 +1,8 @@ -#!/usr/bin/env python3 -import json, time - result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid', 'type': 'error'}} try: user_id = await get_user() org_id = (await get_userorgid()) or '0' - now = time.strftime('%Y-%m-%d %H:%M:%S') dbname = get_module_dbname('product_management') data = dict(params_kw) @@ -23,15 +19,16 @@ try: if not check: raise ValueError('无权操作该记录') - data['updated_at'] = now + data['updated_at'] = timestampstr() + data['id'] = record_id if data.get('has_product') == '0': data['product_type'] = '' data['product_type_title'] = '' - fields = {k: v for k, v in data.items() if v is not None and v != '' or k in ('product_type', 'product_type_title', 'parent_id')} + fields = {k: v for k, v in data.items() if v is not None and v != '' or k in ('product_type', 'product_type_title', 'parent_id', 'id')} async with DBPools().sqlorContext(dbname) as sor: - await sor.U('product_category', fields, {'id': record_id, 'org_id': org_id}) + await sor.U('product_category', fields) result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '类别更新成功', 'type': 'success'}} diff --git a/wwwroot/api/product_resource_supplier_update.dspy b/wwwroot/api/product_resource_supplier_update.dspy index 185008a..959cbe5 100644 --- a/wwwroot/api/product_resource_supplier_update.dspy +++ b/wwwroot/api/product_resource_supplier_update.dspy @@ -6,9 +6,11 @@ try: record_id = data.pop('id', None) if not record_id: raise ValueError('Missing id') + data['updated_at'] = timestampstr() + data['id'] = record_id async with DBPools().sqlorContext(dbname) as sor: - await sor.U('product_resource_supplier', data, {'id': record_id}) + await sor.U('product_resource_supplier', data) result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '供应商关联更新成功', 'type': 'success'}} except Exception as e: diff --git a/wwwroot/api/product_resource_update.dspy b/wwwroot/api/product_resource_update.dspy index 2e6cc3d..0c3a540 100644 --- a/wwwroot/api/product_resource_update.dspy +++ b/wwwroot/api/product_resource_update.dspy @@ -7,9 +7,10 @@ try: if not record_id: raise ValueError('Missing id') data['updated_at'] = timestampstr() + data['id'] = record_id async with DBPools().sqlorContext(dbname) as sor: - await sor.U('product_resource', data, {'id': record_id}) + await sor.U('product_resource', data) result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '资源绑定更新成功', 'type': 'success'}} except Exception as e: diff --git a/wwwroot/api/product_subscription_update.dspy b/wwwroot/api/product_subscription_update.dspy index 6b927cd..9eae4cb 100644 --- a/wwwroot/api/product_subscription_update.dspy +++ b/wwwroot/api/product_subscription_update.dspy @@ -7,9 +7,10 @@ try: if not record_id: raise ValueError('Missing id') data['updated_at'] = timestampstr() + data['id'] = record_id async with DBPools().sqlorContext(dbname) as sor: - await sor.U('product_subscription', data, {'id': record_id}) + await sor.U('product_subscription', data) result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '订购更新成功', 'type': 'success'}} except Exception as e: diff --git a/wwwroot/api/product_type_config_update.dspy b/wwwroot/api/product_type_config_update.dspy index 4131aeb..810e1f9 100644 --- a/wwwroot/api/product_type_config_update.dspy +++ b/wwwroot/api/product_type_config_update.dspy @@ -1,12 +1,8 @@ -#!/usr/bin/env python3 -import json, time - result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid', 'type': 'error'}} try: user_id = await get_user() org_id = (await get_userorgid()) or '0' - now = time.strftime('%Y-%m-%d %H:%M:%S') dbname = get_module_dbname('product_management') data = dict(params_kw) @@ -22,10 +18,11 @@ try: if not check: raise ValueError('无权操作该记录') - data['updated_at'] = now + data['updated_at'] = timestampstr() + data['id'] = record_id async with DBPools().sqlorContext(dbname) as sor: - await sor.U('product_type_config', data, {'id': record_id, 'org_id': org_id}) + await sor.U('product_type_config', data) result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '配置更新成功', 'type': 'success'}} diff --git a/wwwroot/api/product_update.dspy b/wwwroot/api/product_update.dspy index 60b8a78..a988641 100644 --- a/wwwroot/api/product_update.dspy +++ b/wwwroot/api/product_update.dspy @@ -1,12 +1,8 @@ -#!/usr/bin/env python3 -import json, time - result = {'widgettype': 'Message', 'options': {'title': 'Error', 'message': 'Invalid', 'type': 'error'}} try: user_id = await get_user() org_id = (await get_userorgid()) or '0' - now = time.strftime('%Y-%m-%d %H:%M:%S') dbname = get_module_dbname('product_management') data = dict(params_kw) @@ -14,7 +10,7 @@ try: if not record_id: raise ValueError('Missing id') - # Verify belongs to org + # Verify belongs to org + auto-fill product_type if category changed async with DBPools().sqlorContext(dbname) as sor: check = await sor.sqlExe( "SELECT id FROM product WHERE id = ${id}$ AND org_id = ${org_id}$", @@ -23,19 +19,19 @@ try: if not check: raise ValueError('无权操作该记录') - data['updated_at'] = now + if data.get('category_id') and not data.get('product_type'): + cat_check = await sor.sqlExe( + "SELECT product_type FROM product_category WHERE id = ${category_id}$ AND org_id = ${org_id}$", + {'category_id': data['category_id'], 'org_id': org_id} + ) + if cat_check: + data['product_type'] = cat_check[0].get('product_type', '') - # If category changed, update product_type - if data.get('category_id') and not data.get('product_type'): - cat_check = await sor.sqlExe( - "SELECT product_type FROM product_category WHERE id = ${category_id}$ AND org_id = ${org_id}$", - {'category_id': data['category_id'], 'org_id': org_id} - ) - if cat_check: - data['product_type'] = cat_check[0].get('product_type', '') + data['updated_at'] = timestampstr() + data['id'] = record_id async with DBPools().sqlorContext(dbname) as sor: - await sor.U('product', data, {'id': record_id, 'org_id': org_id}) + await sor.U('product', data) result = {'widgettype': 'Message', 'options': {'title': 'Success', 'message': '产品更新成功', 'type': 'success'}}