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