From 3a572053379877583d2a17d19b8f94a2b270df6a Mon Sep 17 00:00:00 2001 From: yumoqing Date: Sun, 24 May 2026 22:31:42 +0800 Subject: [PATCH] =?UTF-8?q?fix(discount):=20=E5=85=BC=E5=AE=B9discount=5Fd?= =?UTF-8?q?etail=E8=A1=A8=E4=B8=8D=E5=AD=98=E5=9C=A8=E7=9A=84=E6=83=85?= =?UTF-8?q?=E5=86=B5=EF=BC=8Cfallback=E5=88=B0discount.discount=E5=AD=97?= =?UTF-8?q?=E6=AE=B5=20+=20=E6=96=B0=E5=A2=9Ediscount=5Fdetail=E8=A1=A8?= =?UTF-8?q?=E5=AE=9A=E4=B9=89=E5=92=8C=E8=BF=81=E7=A7=BB=E8=84=9A=E6=9C=AC?= =?UTF-8?q?=20+=20=E4=BF=AE=E5=A4=8Ddiscount.json=E4=B8=ADfloat=E7=B1=BB?= =?UTF-8?q?=E5=9E=8B=E7=BC=BA=E5=B0=91dec=E5=AD=97=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- discount/__pycache__/init.cpython-310.pyc | Bin 0 -> 8941 bytes discount/init.py | 45 ++++++++---- models/discount.json | 69 +++++++++++++++++++ models/discount_detail.json | 79 ++++++++++++++++++++++ scripts/migrate_discount_detail.sql | 61 +++++++++++++++++ 5 files changed, 242 insertions(+), 12 deletions(-) create mode 100644 discount/__pycache__/init.cpython-310.pyc create mode 100644 models/discount.json create mode 100644 models/discount_detail.json create mode 100644 scripts/migrate_discount_detail.sql diff --git a/discount/__pycache__/init.cpython-310.pyc b/discount/__pycache__/init.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dc259c4a75af0be0acce87836172ac420deedf35 GIT binary patch literal 8941 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 Vm8`?o5$mc|vF4DUwya9wKLPk*r4#@F literal 0 HcmV?d00001 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; +-- ============================================================