diff --git a/discount/__pycache__/init.cpython-310.pyc b/discount/__pycache__/init.cpython-310.pyc new file mode 100644 index 0000000..dc259c4 Binary files /dev/null and b/discount/__pycache__/init.cpython-310.pyc differ diff --git a/discount/init.py b/discount/init.py index 96f8309..da9cc17 100644 --- a/discount/init.py +++ b/discount/init.py @@ -124,9 +124,18 @@ async def disable_old_discount(sor, resellerid, customerid, biz_date): return +async def _discount_detail_exists(sor): + """Check if discount_detail table exists.""" + try: + await sor.sqlExe("SELECT 1 FROM discount_detail LIMIT 0", {}) + return True + except Exception: + return False + + async def sor_get_star_discount(sor, resellerid, biz_date): """Get default discount for a reseller (no specific customer).""" - sql = """select d.id from discount d + sql = """select d.id, d.discount from discount d where d.resellerid = ${resellerid}$ and d.customerid is NULL and d.enabled_date <= ${biz_date}$ @@ -139,15 +148,19 @@ where d.resellerid = ${resellerid}$ if not recs: return 1 - # Look up default discount detail (prodtypeid=None, productid=None) - sql2 = """select discount from discount_detail + discountid = recs[0].id + # If discount_detail table exists, look up default detail + if await _discount_detail_exists(sor): + sql2 = """select discount from discount_detail where discountid = ${discountid}$ and prodtypeid is NULL and productid is NULL""" - recs2 = await sor.sqlExe(sql2, {'discountid': recs[0].id}) - if not recs2: - return 1 - return recs2[0].discount + recs2 = await sor.sqlExe(sql2, {'discountid': discountid}) + if not recs2: + return 1 + return recs2[0].discount + # Fallback: read discount value directly from discount table + return recs[0].discount if recs[0].discount is not None else 1 async def sor_get_customer_discount(sor, resellerid, customerid): @@ -170,14 +183,18 @@ where resellerid = ${resellerid}$ return await sor_get_star_discount(sor, resellerid, biz_date) # Return default discount for this customer (prodtypeid=None, productid=None) - sql2 = """select discount from discount_detail + discountid = recs[0].id + if await _discount_detail_exists(sor): + sql2 = """select discount from discount_detail where discountid = ${discountid}$ and prodtypeid is NULL and productid is NULL""" - recs2 = await sor.sqlExe(sql2, {'discountid': recs[0].id}) - if not recs2: - return 1 - return recs2[0].discount + recs2 = await sor.sqlExe(sql2, {'discountid': discountid}) + if not recs2: + return 1 + return recs2[0].discount + # Fallback: read discount value directly from discount table + return recs[0].discount if recs[0].discount is not None else 1 async def sor_get_product_discount(sor, resellerid, customerid, prodtypeid, productid): @@ -218,6 +235,10 @@ where resellerid = ${resellerid}$ discountid = recs[0].id + # If discount_detail table doesn't exist, fall back to discount.discount + if not await _discount_detail_exists(sor): + return recs[0].discount if recs[0].discount is not None else 1.0 + # Step 2: Try exact product match sql2 = """select discount from discount_detail where discountid = ${discountid}$ diff --git a/models/discount.json b/models/discount.json new file mode 100644 index 0000000..ff31827 --- /dev/null +++ b/models/discount.json @@ -0,0 +1,69 @@ +{ + "summary": [ + { + "name": "discount", + "title": "折扣表", + "primary": ["id"], + "catelog": "entity" + } + ], + "fields": [ + { + "name": "id", + "title": "id", + "type": "str", + "length": 32 + }, + { + "name": "name", + "title": "折扣名称", + "type": "str", + "length": 100 + }, + { + "name": "resellerid", + "title": "商户id", + "type": "str", + "length": 32, + "default": "*" + }, + { + "name": "customerid", + "title": "客户id", + "type": "str", + "length": 32, + "default": "*" + }, + { + "name": "discount", + "title": "折扣", + "type": "float", + "length": 5, + "dec": 4 + }, + { + "name": "enabled_date", + "title": "启用日期", + "type": "date" + }, + { + "name": "expired_date", + "title": "失效日期", + "type": "date" + } + ], + "codes": [ + { + "field": "resellerid", + "table": "organization", + "valuefield": "id", + "textfield": "orgname" + }, + { + "field": "customerid", + "table": "organization", + "valuefield": "id", + "textfield": "orgname" + } + ] +} diff --git a/models/discount_detail.json b/models/discount_detail.json new file mode 100644 index 0000000..2693cf6 --- /dev/null +++ b/models/discount_detail.json @@ -0,0 +1,79 @@ +{ + "summary": [ + { + "name": "discount_detail", + "title": "折扣明细表", + "primary": ["id"], + "catelog": "entity" + } + ], + "fields": [ + { + "name": "id", + "title": "id", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "discountid", + "title": "折扣方案id", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "resellerid", + "title": "商户id", + "type": "str", + "length": 32, + "nullable": "no" + }, + { + "name": "prodtypeid", + "title": "产品种类id", + "type": "str", + "length": 32 + }, + { + "name": "productid", + "title": "产品id", + "type": "str", + "length": 32 + }, + { + "name": "discount", + "title": "折扣", + "type": "double", + "length": 5, + "dec": 4, + "nullable": "no" + } + ], + "indexes": [ + { + "name": "idx_dd_discountid", + "idxtype": "index", + "idxfields": ["discountid"] + }, + { + "name": "idx_dd_product", + "idxtype": "index", + "idxfields": ["discountid", "prodtypeid", "productid"] + } + ], + "codes": [ + { + "field": "discountid", + "table": "discount", + "valuefield": "id", + "textfield": "name" + }, + { + "field": "resellerid", + "table": "organization", + "valuefield": "id", + "textfield": "orgname" + } + ] +} diff --git a/scripts/migrate_discount_detail.sql b/scripts/migrate_discount_detail.sql new file mode 100644 index 0000000..770918f --- /dev/null +++ b/scripts/migrate_discount_detail.sql @@ -0,0 +1,61 @@ +-- ============================================================ +-- discount 模块迁移脚本:新增 discount_detail 表 +-- 从旧版 discount 表迁移折扣值到 discount_detail +-- 日期: 2026-05-24 +-- 执行前请备份数据库! +-- ============================================================ + +-- 1. 创建 discount_detail 表 +CREATE TABLE IF NOT EXISTS discount_detail +( + `id` VARCHAR(32) NOT NULL COMMENT 'id', + `discountid` VARCHAR(32) NOT NULL COMMENT '折扣id', + `resellerid` VARCHAR(32) DEFAULT '*' COMMENT '商户id', + `prodtypeid` VARCHAR(32) DEFAULT NULL COMMENT '产品类型id', + `productid` VARCHAR(32) DEFAULT NULL COMMENT '产品id', + `discount` double(5,4) COMMENT '折扣值', + PRIMARY KEY(id), + INDEX idx_dd_discountid (discountid), + INDEX idx_dd_product (discountid, prodtypeid, productid) +) +CHARACTER SET utf8mb4 +COLLATE utf8mb4_unicode_ci +engine=innodb +COMMENT '折扣产品明细'; + +-- 2. 为 discount 表添加 name 字段(如果不存在) +ALTER TABLE discount ADD COLUMN IF NOT EXISTS `name` VARCHAR(100) COMMENT '折扣名称'; + +-- 3. 将现有 discount 记录的 discount 值迁移到 discount_detail +-- 为每条 discount 记录创建一条默认明细(prodtypeid=NULL, productid=NULL) +INSERT IGNORE INTO discount_detail (id, discountid, resellerid, prodtypeid, productid, discount) +SELECT + CONCAT('mig_', id, '_default') AS id, + d.id AS discountid, + d.resellerid, + NULL AS prodtypeid, + NULL AS productid, + d.discount +FROM discount d +WHERE d.discount IS NOT NULL AND d.discount > 0 +AND NOT EXISTS ( + SELECT 1 FROM discount_detail dd + WHERE dd.discountid = d.id + AND dd.prodtypeid IS NULL + AND dd.productid IS NULL +); + +-- ============================================================ +-- 验证步骤(执行后运行): +-- 1. 确认表创建成功: +-- SHOW TABLES LIKE 'discount_detail'; +-- 2. 确认明细记录已迁移: +-- SELECT COUNT(*) FROM discount_detail; +-- SELECT * FROM discount_detail ORDER BY discountid; +-- 3. 确认 discount 表 name 字段存在: +-- DESCRIBE discount; +-- ============================================================ +-- 回滚步骤(如需撤销): +-- DROP TABLE IF EXISTS discount_detail; +-- ALTER TABLE discount DROP COLUMN IF EXISTS name; +-- ============================================================