import json from appPublic.uniqueID import getID from datetime import datetime async def main(request, params_kw): """ 产品销售时调用此API计算供销记账金额。 输入参数: productid: 产品ID prodtypeid: 产品分类ID (可选) quantity: 销售数量 unit_price: 销售单价 sub_distributor_id: 二级分销商ID (可选, 如果是直接销售则为空) sale_date: 销售日期 (可选, 默认今天) source_type: 来源类型 (1=手动, 2=API调用) source_id: 来源记录ID (可选) 计算逻辑: 1. 查找有效的供销合同及对应产品折扣 2. 查找有效的分销协议及对应产品折扣 (如果有二级分销商) 3. 计算: 进货金额 = 单价 * 数量 * 进货折扣 4. 计算: 分销金额 = 单价 * 数量 * 分销折扣 5. 计算: 利润金额 = 分销金额 - 进货金额 6. 创建记账记录 返回: 记账记录数据 """ user_id = await get_user() user_orgid = await get_userorgid() dbname = get_module_dbname('supplychain') # Parse input data = params_kw.get("data", "{}") if isinstance(data, str): data = json.loads(data) productid = data.get("productid") prodtypeid = data.get("prodtypeid") quantity = float(data.get("quantity", 0)) unit_price = float(data.get("unit_price", 0)) sub_distributor_id = data.get("sub_distributor_id") sale_date = data.get("sale_date", datetime.now().strftime("%Y-%m-%d")) source_type = data.get("source_type", "2") source_id = data.get("source_id") remark = data.get("remark", "") if not productid or quantity <= 0 or unit_price <= 0: return json.dumps({"status": "error", "message": "缺少必要参数: productid, quantity, unit_price"}) config = getConfig(".") DBPools(config.databases) total_amount = quantity * unit_price async with db.sqlorContext(dbname) as sor: # Step 1: Find active supply contract with product discount # Priority: exact product > product type > default contract discount supply_contract_id = None supply_contract_item_id = None supplier_id = None supply_discount = 1.0 supply_amount = total_amount # Find supply contract items matching this product if prodtypeid: sql_sci = """SELECT sci.id, sci.contract_id, sci.discount, sci.settlement_price, sc.supplier_id FROM supply_contract_items sci JOIN supply_contracts sc ON sci.contract_id = sc.id WHERE sci.resellerid = ${resellerid}$ AND sc.status = '1' AND sc.start_date <= ${sale_date}$ AND (sc.end_date IS NULL OR sc.end_date >= ${sale_date}$) AND sci.productid = ${productid}$ ORDER BY sci.created_at DESC LIMIT 1""" ns_sci = {"resellerid": user_orgid, "sale_date": sale_date, "productid": productid} sci_recs = await sor.sqlExe(sql_sci, ns_sci) if not prodtypeid or not sci_recs: sql_sci = """SELECT sci.id, sci.contract_id, sci.discount, sci.settlement_price, sc.supplier_id FROM supply_contract_items sci JOIN supply_contracts sc ON sci.contract_id = sc.id WHERE sci.resellerid = ${resellerid}$ AND sc.status = '1' AND sc.start_date <= ${sale_date}$ AND (sc.end_date IS NULL OR sc.end_date >= ${sale_date}$) AND sci.prodtypeid = ${prodtypeid}$ ORDER BY sci.created_at DESC LIMIT 1""" ns_sci = {"resellerid": user_orgid, "sale_date": sale_date, "prodtypeid": prodtypeid} sci_recs = await sor.sqlExe(sql_sci, ns_sci) if sci_recs: supply_contract_item_id = sci_recs[0].id supply_contract_id = sci_recs[0].contract_id supplier_id = sci_recs[0].supplier_id supply_discount = float(sci_recs[0].discount) if sci_recs[0].discount else 1.0 if sci_recs[0].settlement_price: supply_amount = float(sci_recs[0].settlement_price) * quantity else: supply_amount = total_amount * supply_discount else: # Fallback: find any active supply contract with default discount sql_sc = """SELECT id, supplier_id, default_discount FROM supply_contracts WHERE resellerid = ${resellerid}$ AND status = '1' AND start_date <= ${sale_date}$ AND (end_date IS NULL OR end_date >= ${sale_date}$) ORDER BY created_at DESC LIMIT 1""" sc_recs = await sor.sqlExe(sql_sc, {"resellerid": user_orgid, "sale_date": sale_date}) if sc_recs: supply_contract_id = sc_recs[0].id supplier_id = sc_recs[0].supplier_id supply_discount = float(sc_recs[0].default_discount) if sc_recs[0].default_discount else 1.0 supply_amount = total_amount * supply_discount # Step 2: Find active distribution agreement with product discount (if sub_distributor) distribution_agreement_id = None distribution_agreement_item_id = None dist_discount = 1.0 dist_amount = total_amount if sub_distributor_id: # Find distribution agreement items matching this product sql_dai = """SELECT dai.id, dai.agreement_id, dai.discount, dai.settlement_price FROM distribution_agreement_items dai JOIN distribution_agreements da ON dai.agreement_id = da.id WHERE dai.resellerid = ${resellerid}$ AND da.sub_distributor_id = ${sub_distributor_id}$ AND da.status = '1' AND da.start_date <= ${sale_date}$ AND (da.end_date IS NULL OR da.end_date >= ${sale_date}$) AND dai.productid = ${productid}$ ORDER BY dai.created_at DESC LIMIT 1""" ns_dai = {"resellerid": user_orgid, "sub_distributor_id": sub_distributor_id, "sale_date": sale_date, "productid": productid} dai_recs = await sor.sqlExe(sql_dai, ns_dai) if not dai_recs and prodtypeid: sql_dai = """SELECT dai.id, dai.agreement_id, dai.discount, dai.settlement_price FROM distribution_agreement_items dai JOIN distribution_agreements da ON dai.agreement_id = da.id WHERE dai.resellerid = ${resellerid}$ AND da.sub_distributor_id = ${sub_distributor_id}$ AND da.status = '1' AND da.start_date <= ${sale_date}$ AND (da.end_date IS NULL OR da.end_date >= ${sale_date}$) AND dai.prodtypeid = ${prodtypeid}$ ORDER BY dai.created_at DESC LIMIT 1""" ns_dai["productid"] = None dai_recs = await sor.sqlExe(sql_dai, ns_dai) if dai_recs: distribution_agreement_item_id = dai_recs[0].id distribution_agreement_id = dai_recs[0].agreement_id dist_discount = float(dai_recs[0].discount) if dai_recs[0].discount else 1.0 if dai_recs[0].settlement_price: dist_amount = float(dai_recs[0].settlement_price) * quantity else: dist_amount = total_amount * dist_discount else: # Fallback: find active distribution agreement with default discount sql_da = """SELECT id, default_discount FROM distribution_agreements WHERE resellerid = ${resellerid}$ AND sub_distributor_id = ${sub_distributor_id}$ AND status = '1' AND start_date <= ${sale_date}$ AND (end_date IS NULL OR end_date >= ${sale_date}$) ORDER BY created_at DESC LIMIT 1""" da_recs = await sor.sqlExe(sql_da, {"resellerid": user_orgid, "sub_distributor_id": sub_distributor_id, "sale_date": sale_date}) if da_recs: distribution_agreement_id = da_recs[0].id dist_discount = float(da_recs[0].default_discount) if da_recs[0].default_discount else 1.0 dist_amount = total_amount * dist_discount # Step 3: Calculate profit profit_amount = dist_amount - supply_amount # Step 4: Create accounting record accounting_id = getID() record = { "id": accounting_id, "resellerid": user_orgid, "supply_contract_id": supply_contract_id, "supply_contract_item_id": supply_contract_item_id, "distribution_agreement_id": distribution_agreement_id, "distribution_agreement_item_id": distribution_agreement_item_id, "sub_distributor_id": sub_distributor_id, "supplier_id": supplier_id, "prodtypeid": prodtypeid, "productid": productid, "quantity": quantity, "unit_price": unit_price, "supply_discount": supply_discount, "supply_amount": supply_amount, "dist_discount": dist_discount, "dist_amount": dist_amount, "profit_amount": profit_amount, "sale_date": sale_date, "source_type": source_type, "source_id": source_id, "remark": remark, "created_by": user_id, "created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S") } await sor.C("supplychain_accounting", record) result = { "status": "ok", "data": record, "summary": { "total_amount": total_amount, "supply_amount": supply_amount, "dist_amount": dist_amount, "profit_amount": profit_amount, "supply_discount": supply_discount, "dist_discount": dist_discount } } return json.dumps(result)