diff --git a/b/.mcp.json b/b/.mcp.json new file mode 100644 index 0000000..c823eab --- /dev/null +++ b/b/.mcp.json @@ -0,0 +1,18 @@ +{ + "mcpServers": { + "mysql": { + "command": "npx", + "args": ["-y", "mcp-mysql-multi-db"], + "env": { // <-- 就是这里!env 是一个对象 + "MYSQL_HOST": "localhost", + "MYSQL_PORT": "3306", + "MYSQL_USER": "root", + "MYSQL_PASSWORD": "lima2018", + "MYSQL_DATABASE": "kprod", + // 👇 要执行 INSERT/UPDATE 等写操作,就在这里添加下面两行 + // "ALLOW_DML": "true", + // "ALLOW_DDL": "true" + } + } + } +} \ No newline at end of file diff --git a/b/bill/finance_order_report.dspy b/b/bill/finance_order_report.dspy index d9ede32..426f023 100644 --- a/b/bill/finance_order_report.dspy +++ b/b/bill/finance_order_report.dspy @@ -75,7 +75,6 @@ SALEMODE_LABEL = { } INCOME_SUBJECTS = ('折扣收入', '底价收入') -PARENT_SETTLE_SUBJECT = '分销商存放资金' SUPPLIER_SETTLE_PREFIX = '待结转' _SALEMODE_SQL_OWN = """ @@ -194,9 +193,12 @@ async def _org_name(sor, orgid): async def _is_business_owner(sor, orgid): + # 业主机构 parentid 为空串(非 NULL),org_type='0';两者都视为顶级机构。 rows = await sor.sqlExe( - "SELECT id FROM organization WHERE id=${id}$ AND parentid IS NULL AND del_flg='0'", - {'id': orgid}, + """SELECT id FROM organization + WHERE id=${id}$ AND del_flg='0' + AND ((parentid IS NULL OR parentid='') OR org_type=${owner_type}$)""", + {'id': orgid, 'owner_type': OWNER_OGR}, ) return len(rows) > 0 @@ -324,8 +326,12 @@ async def _protocol_snapshot(sor, accounting_orgid, customerid, providerid, prod } -def _estimate_finance(catalog_amount, protocol, is_owner): - """未记账:估算本级利润与本级应付(不含代付费单独字段)。""" +def _estimate_finance(catalog_amount, protocol): + """未记账:估算本级利润与本级应付(本级成本)。 + + 与已记账口径一致,本级应付取「本级作为采购方(bid)的协议」即 own_*, + 对业主机构与分销商统一(own_discount 即上级给本级的折扣/底价)。 + """ catalog_amount = float(catalog_amount or 0) qty = protocol.get('quantity') or 1 profit = None @@ -335,29 +341,20 @@ def _estimate_finance(catalog_amount, protocol, is_owner): cust_mode = protocol.get('customer_salemode') own_disc = protocol.get('own_discount') cust_disc = protocol.get('customer_discount') - reseller_disc = protocol.get('reseller_discount') if own_mode == '0' or cust_mode == '0': if own_disc is not None and cust_disc is not None: profit = catalog_amount * (float(cust_disc) - float(own_disc)) - if is_owner: - if own_disc is not None: - settle_upstream = catalog_amount * float(own_disc) - elif reseller_disc is not None: - settle_upstream = catalog_amount * float(reseller_disc) + if own_disc is not None: + settle_upstream = catalog_amount * float(own_disc) elif own_mode == '2' or cust_mode == '2': own_price = protocol.get('own_floor_unit_price') cust_price = protocol.get('customer_floor_unit_price') - reseller_price = protocol.get('reseller_floor_unit_price') if own_price is not None and cust_price is not None: profit = (float(cust_price) - float(own_price)) * qty - if is_owner and own_price is not None: + if own_price is not None: settle_upstream = float(own_price) * qty - elif not is_owner and reseller_price is not None: - settle_upstream = float(reseller_price) * qty - elif not is_owner and cust_price is not None: - settle_upstream = float(cust_price) * qty return { 'profit_amount': _round_money(profit), @@ -379,8 +376,13 @@ async def _bill_detail_rows(sor, billid): )) -async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_owner, parent_orgid): - """已记账:从 bill_detail 取本级利润与本级应付。""" +async def _finance_from_bill_detail(sor, billid, accounting_orgid): + """已记账:从 bill_detail 取本级利润与本级应付。 + + 统一口径(业主机构与分销商一致): + - profit_amount = 本级账本「折扣收入/底价收入」贷方合计 + - settle_upstream = 本级账本「待结转*销售收入」贷方合计(本级成本/本级应付上级) + """ rows = await _bill_detail_rows(sor, billid) profit = 0.0 settle_upstream = 0.0 @@ -400,24 +402,10 @@ async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_owner, par subj = r['subjectname'] or '' direction = r['accounting_dir'] - if book == accounting_orgid and subj in INCOME_SUBJECTS and direction == '贷': - profit += amt - - if is_owner: - if ( - book == accounting_orgid - and subj.startswith(SUPPLIER_SETTLE_PREFIX) - and direction == '贷' - ): - settle_upstream += amt - else: - if ( - parent_orgid - and book == parent_orgid - and subj == PARENT_SETTLE_SUBJECT - and direction == '借' - and r.get('participantid') == accounting_orgid - ): + if book == accounting_orgid and direction == '贷': + if subj in INCOME_SUBJECTS: + profit += amt + elif subj.startswith(SUPPLIER_SETTLE_PREFIX): settle_upstream += amt return { @@ -442,16 +430,13 @@ async def _build_report_row(sor, row, accounting_orgid, is_owner): protocol = await _protocol_snapshot( sor, accounting_orgid, customerid, providerid, productid, bill_date, quantity, ) - parent_orgid = protocol['parent_orgid'] settle_meta = await _settle_upstream_meta(sor, accounting_orgid, providerid) bill_state = _row_get(row, 'bill_state') if str(bill_state) == '1': - amounts = await _finance_from_bill_detail( - sor, bill_id, accounting_orgid, is_owner, parent_orgid, - ) + amounts = await _finance_from_bill_detail(sor, bill_id, accounting_orgid) else: - amounts = _estimate_finance(catalog_amount, protocol, is_owner) + amounts = _estimate_finance(catalog_amount, protocol) amounts['bill_detail_legs'] = [] product_name = _row_get(row, 'product_name') @@ -652,7 +637,7 @@ def _customer_segment(customer_parentid, accounting_orgid, reseller_id_set): return None -async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_orgid): +async def _bill_finance_amounts(sor, row, accounting_orgid): """单笔:销售额、本级利润、本级应付上级/供应商。""" sales = float(_row_get(row, 'customer_pay_amount') or 0) bill_id = _row_get(row, 'bill_id') @@ -660,9 +645,7 @@ async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_org quantity = int(_row_get(row, 'quantity') or 1) if str(bill_state) == '1': - fin = await _finance_from_bill_detail( - sor, bill_id, accounting_orgid, is_owner, parent_orgid, - ) + fin = await _finance_from_bill_detail(sor, bill_id, accounting_orgid) else: catalog = float(_row_get(row, 'catalog_amount') or 0) protocol = await _protocol_snapshot( @@ -674,7 +657,7 @@ async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_org _row_get(row, 'bill_date'), quantity, ) - fin = _estimate_finance(catalog, protocol, is_owner) + fin = _estimate_finance(catalog, protocol) profit = float(fin.get('profit_amount') or 0) settle = float(fin.get('settle_upstream_amount') or 0) @@ -878,9 +861,9 @@ async def finance_order_report(ns=None): userid, start_date, end_date, customerid, productid, order_id, bill_state current_page (默认1), page_size (默认20, 最大100) - 返回 finance.settle_upstream_*: - - 本机构:应付供应商(待结转* 贷方,仅本机构账本) - - 分销商:应付直接上级(上级账本「分销商存放资金」借方,participant=本级) + 返回 finance.settle_upstream_*(统一口径,取本级账本「待结转*销售收入」贷方): + - 本机构:应付供应商 + - 分销商:应付直接上级机构(金额=本级成本,与本级账本待结转一致) """ ns = ns or {} accounting_orgid = ns.get('accounting_orgid') @@ -1053,7 +1036,7 @@ async def finance_billing_overview(ns=None): 口径(与订单明细接口一致): sales_total = 客户实付合计 bill.amount profit_total = 本级账本折扣收入+底价收入(bill_detail)或协议估算 - settle_upstream_total= 本机构→供应商待结转;分销→上级账本分销商存放资金借方 + settle_upstream_total= 本级账本「待结转*销售收入」贷方合计(本级成本/应付上级,业主与分销统一) 分段: direct_customers 直属客户(cust.parentid = accounting_orgid) @@ -1084,7 +1067,6 @@ async def finance_billing_overview(ns=None): sor, accounting_orgid, include_sub, ) is_owner = await _is_business_owner(sor, accounting_orgid) - parent_orgid = await get_parent_orgid(sor, accounting_orgid) conditions = ["b.del_flg = '0'", "o.del_flg = '0'", scope_sql] params = dict(scope_params) @@ -1128,7 +1110,7 @@ async def finance_billing_overview(ns=None): continue try: sales, profit, settle, _src = await _bill_finance_amounts( - sor, row, accounting_orgid, is_owner, parent_orgid, + sor, row, accounting_orgid, ) except Exception as exc: errors.append({ @@ -1230,11 +1212,10 @@ async def finance_billing_overview(ns=None): # _report = params_kw.get('report') or params_kw.get('api') or 'order_list' _report = None -if _report in ('overview', 'billing_overview', 'finance_billing_overview'): - ret = await finance_billing_overview(params_kw) -elif _report in ('detail', 'order_detail'): - ret = await finance_order_report_detail(params_kw) -else: - ret = await finance_order_report(params_kw) +# if _report in ('overview', 'billing_overview', 'finance_billing_overview'): +# ret = await finance_billing_overview(params_kw) +# elif _report in ('detail', 'order_detail'): +# ret = await finance_order_report_detail(params_kw) +# else: +ret = await finance_order_report(params_kw) return ret -return ret \ No newline at end of file diff --git a/b/bill/finance_order_report_overview.dspy b/b/bill/finance_order_report_overview.dspy index 43af926..2049911 100644 --- a/b/bill/finance_order_report_overview.dspy +++ b/b/bill/finance_order_report_overview.dspy @@ -75,7 +75,6 @@ SALEMODE_LABEL = { } INCOME_SUBJECTS = ('折扣收入', '底价收入') -PARENT_SETTLE_SUBJECT = '分销商存放资金' SUPPLIER_SETTLE_PREFIX = '待结转' _SALEMODE_SQL_OWN = """ @@ -194,9 +193,12 @@ async def _org_name(sor, orgid): async def _is_business_owner(sor, orgid): + # 业主机构 parentid 为空串(非 NULL),org_type='0';两者都视为顶级机构。 rows = await sor.sqlExe( - "SELECT id FROM organization WHERE id=${id}$ AND parentid IS NULL AND del_flg='0'", - {'id': orgid}, + """SELECT id FROM organization + WHERE id=${id}$ AND del_flg='0' + AND ((parentid IS NULL OR parentid='') OR org_type=${owner_type}$)""", + {'id': orgid, 'owner_type': OWNER_OGR}, ) return len(rows) > 0 @@ -324,8 +326,12 @@ async def _protocol_snapshot(sor, accounting_orgid, customerid, providerid, prod } -def _estimate_finance(catalog_amount, protocol, is_owner): - """未记账:估算本级利润与本级应付(不含代付费单独字段)。""" +def _estimate_finance(catalog_amount, protocol): + """未记账:估算本级利润与本级应付(本级成本)。 + + 与已记账口径一致,本级应付取「本级作为采购方(bid)的协议」即 own_*, + 对业主机构与分销商统一(own_discount 即上级给本级的折扣/底价)。 + """ catalog_amount = float(catalog_amount or 0) qty = protocol.get('quantity') or 1 profit = None @@ -335,29 +341,20 @@ def _estimate_finance(catalog_amount, protocol, is_owner): cust_mode = protocol.get('customer_salemode') own_disc = protocol.get('own_discount') cust_disc = protocol.get('customer_discount') - reseller_disc = protocol.get('reseller_discount') if own_mode == '0' or cust_mode == '0': if own_disc is not None and cust_disc is not None: profit = catalog_amount * (float(cust_disc) - float(own_disc)) - if is_owner: - if own_disc is not None: - settle_upstream = catalog_amount * float(own_disc) - elif reseller_disc is not None: - settle_upstream = catalog_amount * float(reseller_disc) + if own_disc is not None: + settle_upstream = catalog_amount * float(own_disc) elif own_mode == '2' or cust_mode == '2': own_price = protocol.get('own_floor_unit_price') cust_price = protocol.get('customer_floor_unit_price') - reseller_price = protocol.get('reseller_floor_unit_price') if own_price is not None and cust_price is not None: profit = (float(cust_price) - float(own_price)) * qty - if is_owner and own_price is not None: + if own_price is not None: settle_upstream = float(own_price) * qty - elif not is_owner and reseller_price is not None: - settle_upstream = float(reseller_price) * qty - elif not is_owner and cust_price is not None: - settle_upstream = float(cust_price) * qty return { 'profit_amount': _round_money(profit), @@ -379,8 +376,13 @@ async def _bill_detail_rows(sor, billid): )) -async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_owner, parent_orgid): - """已记账:从 bill_detail 取本级利润与本级应付。""" +async def _finance_from_bill_detail(sor, billid, accounting_orgid): + """已记账:从 bill_detail 取本级利润与本级应付。 + + 统一口径(业主机构与分销商一致): + - profit_amount = 本级账本「折扣收入/底价收入」贷方合计 + - settle_upstream = 本级账本「待结转*销售收入」贷方合计(本级成本/本级应付上级) + """ rows = await _bill_detail_rows(sor, billid) profit = 0.0 settle_upstream = 0.0 @@ -400,24 +402,10 @@ async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_owner, par subj = r['subjectname'] or '' direction = r['accounting_dir'] - if book == accounting_orgid and subj in INCOME_SUBJECTS and direction == '贷': - profit += amt - - if is_owner: - if ( - book == accounting_orgid - and subj.startswith(SUPPLIER_SETTLE_PREFIX) - and direction == '贷' - ): - settle_upstream += amt - else: - if ( - parent_orgid - and book == parent_orgid - and subj == PARENT_SETTLE_SUBJECT - and direction == '借' - and r.get('participantid') == accounting_orgid - ): + if book == accounting_orgid and direction == '贷': + if subj in INCOME_SUBJECTS: + profit += amt + elif subj.startswith(SUPPLIER_SETTLE_PREFIX): settle_upstream += amt return { @@ -442,16 +430,13 @@ async def _build_report_row(sor, row, accounting_orgid, is_owner): protocol = await _protocol_snapshot( sor, accounting_orgid, customerid, providerid, productid, bill_date, quantity, ) - parent_orgid = protocol['parent_orgid'] settle_meta = await _settle_upstream_meta(sor, accounting_orgid, providerid) bill_state = _row_get(row, 'bill_state') if str(bill_state) == '1': - amounts = await _finance_from_bill_detail( - sor, bill_id, accounting_orgid, is_owner, parent_orgid, - ) + amounts = await _finance_from_bill_detail(sor, bill_id, accounting_orgid) else: - amounts = _estimate_finance(catalog_amount, protocol, is_owner) + amounts = _estimate_finance(catalog_amount, protocol) amounts['bill_detail_legs'] = [] product_name = _row_get(row, 'product_name') @@ -652,7 +637,7 @@ def _customer_segment(customer_parentid, accounting_orgid, reseller_id_set): return None -async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_orgid): +async def _bill_finance_amounts(sor, row, accounting_orgid): """单笔:销售额、本级利润、本级应付上级/供应商。""" sales = float(_row_get(row, 'customer_pay_amount') or 0) bill_id = _row_get(row, 'bill_id') @@ -660,9 +645,7 @@ async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_org quantity = int(_row_get(row, 'quantity') or 1) if str(bill_state) == '1': - fin = await _finance_from_bill_detail( - sor, bill_id, accounting_orgid, is_owner, parent_orgid, - ) + fin = await _finance_from_bill_detail(sor, bill_id, accounting_orgid) else: catalog = float(_row_get(row, 'catalog_amount') or 0) protocol = await _protocol_snapshot( @@ -674,7 +657,7 @@ async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_org _row_get(row, 'bill_date'), quantity, ) - fin = _estimate_finance(catalog, protocol, is_owner) + fin = _estimate_finance(catalog, protocol) profit = float(fin.get('profit_amount') or 0) settle = float(fin.get('settle_upstream_amount') or 0) @@ -878,9 +861,9 @@ async def finance_order_report(ns=None): userid, start_date, end_date, customerid, productid, order_id, bill_state current_page (默认1), page_size (默认20, 最大100) - 返回 finance.settle_upstream_*: - - 本机构:应付供应商(待结转* 贷方,仅本机构账本) - - 分销商:应付直接上级(上级账本「分销商存放资金」借方,participant=本级) + 返回 finance.settle_upstream_*(统一口径,取本级账本「待结转*销售收入」贷方): + - 本机构:应付供应商 + - 分销商:应付直接上级机构(金额=本级成本,与本级账本待结转一致) """ ns = ns or {} accounting_orgid = ns.get('accounting_orgid') @@ -1053,7 +1036,7 @@ async def finance_billing_overview(ns=None): 口径(与订单明细接口一致): sales_total = 客户实付合计 bill.amount profit_total = 本级账本折扣收入+底价收入(bill_detail)或协议估算 - settle_upstream_total= 本机构→供应商待结转;分销→上级账本分销商存放资金借方 + settle_upstream_total= 本级账本「待结转*销售收入」贷方合计(本级成本/应付上级,业主与分销统一) 分段: direct_customers 直属客户(cust.parentid = accounting_orgid) @@ -1084,7 +1067,6 @@ async def finance_billing_overview(ns=None): sor, accounting_orgid, include_sub, ) is_owner = await _is_business_owner(sor, accounting_orgid) - parent_orgid = await get_parent_orgid(sor, accounting_orgid) conditions = ["b.del_flg = '0'", "o.del_flg = '0'", scope_sql] params = dict(scope_params) @@ -1128,7 +1110,7 @@ async def finance_billing_overview(ns=None): continue try: sales, profit, settle, _src = await _bill_finance_amounts( - sor, row, accounting_orgid, is_owner, parent_orgid, + sor, row, accounting_orgid, ) except Exception as exc: errors.append({