fix(discount): 折扣模型纠正——三类折扣各归其位,不取 min

- 客户折扣(discount 模块 get_min_product_discount) → amount 售价
- 供应商折扣(supplychain 模块 calculate_sale_amounts) → cost 平台进货成本
- 分销商折扣不进本函数(分销场景单独用 calculate_sale_amounts 的 distribution_amount)
- 供应商 id 来源:product.providerid,空则查 product_supplier_mapping 首选供应商

之前"取 min 三类折扣"是错的:用户折扣不能采用供应商折扣,两者独立。
This commit is contained in:
ymq 2026-08-26 16:52:44 +08:00
parent 4ed6d15a59
commit 7852583739

View File

@ -1389,12 +1389,16 @@ class ProductManager:
async def calculate_product_cost(self, product_id=None, product_code=None, async def calculate_product_cost(self, product_id=None, product_code=None,
usage_data=None, user_org_id=None): usage_data=None, user_org_id=None):
"""计算消费费用:资源真实定价 × 产品级折扣。 """计算消费费用:资源真实定价 + 客户折扣(售价) + 供应商折扣(成本)。
折扣精确到 product_id(discount_detail.productid),三类折扣取最优惠: 三类折扣各自独立、归属不同环节,不取 min:
- 客户折扣:get_min_product_discount(product_id, resellerid, customerid) - 客户折扣 discount 模块 get_min_product_discount → amount(客户应付售价)
- 分销商折扣:get_min_distributor_discount(product_id, resellerid, distributorid) - 供应商折扣 supplychain 模块 calculate_sale_amounts → cost(平台进货成本)
- 供应商折扣:get_min_supplier_discount(product_id, resellerid, supplierid) - 分销商折扣 分销场景单独用(calculate_sale_amounts 的 distribution_amount),
不进本函数。
返回:original_amount(资源真实定价)、amount(售价=原价×客户折扣)、
cost(成本=原价×供应商折扣)、discount(客户折扣率)
""" """
iface, product, err = await self._get_product_interface( iface, product, err = await self._get_product_interface(
product_id, product_code) product_id, product_code)
@ -1423,51 +1427,59 @@ class ProductManager:
original_amount = float(result.get('original_amount', original_amount = float(result.get('original_amount',
result.get('amount', 0) or 0)) result.get('amount', 0) or 0))
# 2. 产品级折扣:精确到 product_id,取最优惠(min)
env = ServerEnv() env = ServerEnv()
resellerid = product.get('org_id') or '0' resellerid = product.get('org_id') or '0'
pid = product.get('id') or '' pid = product.get('id') or ''
final_discount = 1.0
# 2a. 客户折扣(customerid 精确 + '*'/NULL 通配) # 2. 客户折扣(discount 模块,售价侧)→ amount
discount = 1.0
if user_org_id: if user_org_id:
try: try:
d = await env.get_min_product_discount(pid, resellerid, user_org_id) d = await env.get_min_product_discount(pid, resellerid, user_org_id)
if d not in (None, '', 0): if d not in (None, '', 0):
final_discount = min(final_discount, float(d)) discount = float(d)
except Exception: except Exception:
pass pass
amount = original_amount * discount
# 2b. 分销商折扣(客户归属的分销商,discount_customer_bind) # 3. 供应商折扣(supplychain 模块,成本侧)→ cost
# 供应商折扣是平台进货折扣,与客户折扣独立,不取 min。
cost = original_amount
try: try:
dbname = self._get_dbname() supplier_id = product.get('providerid') or ''
async with DBPools().sqlorContext(dbname) as sor: if not supplier_id:
binds = await sor.R('discount_customer_bind', # 从 supplychain 的产品→供应商映射查首选供应商
{'customerid': user_org_id}) dbname = self._get_dbname()
if binds: async with DBPools().sqlorContext(dbname) as sor:
distributorid = getattr(binds[0], 'resellerid', '') or '' maps = await sor.R('product_supplier_mapping',
if distributorid: {'product_id': pid})
d = await env.get_min_distributor_discount( if maps:
pid, resellerid, distributorid) pref = [m for m in maps
if d not in (None, '', 0): if str(getattr(m, 'is_preferred', '')) == '1'] or maps
final_discount = min(final_discount, float(d)) supplier_id = (getattr(pref[0], 'external_supplier_id', '')
or getattr(pref[0], 'supplier_org_id', '')
or '')
if supplier_id:
sc = await env.calculate_sale_amounts(None, {
'resellerid': resellerid,
'supplier_id': supplier_id,
'productid': pid,
'prodtypeid': product.get('category_id') or '',
'quantity': 1,
'unit_price': original_amount,
})
if sc:
sc_data = json.loads(sc) if isinstance(sc, str) else sc
sc_data = sc_data.get('data', {}) if isinstance(sc_data, dict) else {}
supply_discount = float(sc_data.get('supply_discount', 1.0) or 1.0)
cost = original_amount * supply_discount
except Exception: except Exception:
pass cost = original_amount
# 2c. 供应商折扣(product.providerid)
supplierid = product.get('providerid') or ''
if supplierid:
try:
d = await env.get_min_supplier_discount(pid, resellerid, supplierid)
if d not in (None, '', 0):
final_discount = min(final_discount, float(d))
except Exception:
pass
amount = original_amount * final_discount
result['amount'] = round(amount, 6) result['amount'] = round(amount, 6)
result['original_amount'] = round(original_amount, 6) result['original_amount'] = round(original_amount, 6)
result['discount'] = final_discount result['cost'] = round(cost, 6)
result['discount'] = discount
return result return result
async def llm_id_to_product_id(self, llm_id): async def llm_id_to_product_id(self, llm_id):