main #116
18
b/.mcp.json
Normal file
18
b/.mcp.json
Normal file
@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -75,7 +75,7 @@ async def affirmbz_order(ns={}):
|
|||||||
await sor.U('customer_goods', {'id': resource_find_id, 'del_flg': '1'})
|
await sor.U('customer_goods', {'id': resource_find_id, 'del_flg': '1'})
|
||||||
|
|
||||||
# 处理续费逻辑
|
# 处理续费逻辑
|
||||||
elif order_type == 'RENEW':
|
elif order_type == 'RENEW' or order_type == 'DILATATION':
|
||||||
# 找到资源并更新时间
|
# 找到资源并更新时间
|
||||||
resource_find_sql = """select id from customer_goods where FIND_IN_SET('%s', resourceid) and del_flg = '0';""" % j['resourceids']
|
resource_find_sql = """select id from customer_goods where FIND_IN_SET('%s', resourceid) and del_flg = '0';""" % j['resourceids']
|
||||||
resource_find_li = await sor.sqlExe(resource_find_sql, {})
|
resource_find_li = await sor.sqlExe(resource_find_sql, {})
|
||||||
@ -488,6 +488,8 @@ async def get_baidu_orderlist(ns={}):
|
|||||||
business_op = 'BUY'
|
business_op = 'BUY'
|
||||||
elif order_type == 'RENEW':
|
elif order_type == 'RENEW':
|
||||||
business_op = 'RENEW'
|
business_op = 'RENEW'
|
||||||
|
elif order_type == 'DILATATION':
|
||||||
|
business_op = 'DILATATION'
|
||||||
elif order_type == 'REFUND':
|
elif order_type == 'REFUND':
|
||||||
business_op = 'BUY_REVERSE'
|
business_op = 'BUY_REVERSE'
|
||||||
else:
|
else:
|
||||||
@ -498,6 +500,8 @@ async def get_baidu_orderlist(ns={}):
|
|||||||
'reason': '支付形式目前仅包含购买,续费,退订'
|
'reason': '支付形式目前仅包含购买,续费,退订'
|
||||||
}
|
}
|
||||||
await user_action_record(ns_record)
|
await user_action_record(ns_record)
|
||||||
|
# 取消订单
|
||||||
|
await baidu_order_cancel({'baidu_id': baidu_users[0]['baidu_id'], 'order_id': ns.get('order_id')})
|
||||||
return {
|
return {
|
||||||
'status': False,
|
'status': False,
|
||||||
'msg': '线上暂不支持, 请联系售后'
|
'msg': '线上暂不支持, 请联系售后'
|
||||||
@ -605,8 +609,11 @@ async def get_baidu_orderlist(ns={}):
|
|||||||
with open('baidu_error.log', 'a') as f:
|
with open('baidu_error.log', 'a') as f:
|
||||||
f.write('保存配置configurations失败' + str(e) + '\n')
|
f.write('保存配置configurations失败' + str(e) + '\n')
|
||||||
|
|
||||||
|
if order_type == 'DILATATION':
|
||||||
|
# 暂时不确定升降配是否需要重新计算日期
|
||||||
|
pass
|
||||||
# 如果是续费订单 由于没有返回日期, 重新计算日期
|
# 如果是续费订单 由于没有返回日期, 重新计算日期
|
||||||
if order_type == 'RENEW':
|
elif order_type == 'RENEW':
|
||||||
history_time_sql = "select resourcestarttime, resourceendtime from order_goods where FIND_IN_SET('%s', resourceids) order by resourceendtime desc;" % \
|
history_time_sql = "select resourcestarttime, resourceendtime from order_goods where FIND_IN_SET('%s', resourceids) order by resourceendtime desc;" % \
|
||||||
nss['resourceids']
|
nss['resourceids']
|
||||||
history_time = await sor.sqlExe(history_time_sql, {})
|
history_time = await sor.sqlExe(history_time_sql, {})
|
||||||
|
|||||||
@ -75,7 +75,6 @@ SALEMODE_LABEL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
INCOME_SUBJECTS = ('折扣收入', '底价收入')
|
INCOME_SUBJECTS = ('折扣收入', '底价收入')
|
||||||
PARENT_SETTLE_SUBJECT = '分销商存放资金'
|
|
||||||
SUPPLIER_SETTLE_PREFIX = '待结转'
|
SUPPLIER_SETTLE_PREFIX = '待结转'
|
||||||
|
|
||||||
_SALEMODE_SQL_OWN = """
|
_SALEMODE_SQL_OWN = """
|
||||||
@ -116,6 +115,15 @@ def _round_money(v):
|
|||||||
return round(float(v), 2)
|
return round(float(v), 2)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_reverse_op(business_op):
|
||||||
|
"""退订/红冲类操作(BUY_REVERSE 等 *_REVERSE)。
|
||||||
|
|
||||||
|
数据中退订账单的 bill_detail 方向与正常单一致(均为贷),仅靠 business_op 区分。
|
||||||
|
退订口径:销售额、利润取反(减少);上游结算/应付供应商仍正向累加(增加)。
|
||||||
|
"""
|
||||||
|
return str(business_op or '').upper().endswith('_REVERSE')
|
||||||
|
|
||||||
|
|
||||||
def _salemode_label(code):
|
def _salemode_label(code):
|
||||||
if code is None:
|
if code is None:
|
||||||
return None
|
return None
|
||||||
@ -194,9 +202,12 @@ async def _org_name(sor, orgid):
|
|||||||
|
|
||||||
|
|
||||||
async def _is_business_owner(sor, orgid):
|
async def _is_business_owner(sor, orgid):
|
||||||
|
# 业主机构 parentid 为空串(非 NULL),org_type='0';两者都视为顶级机构。
|
||||||
rows = await sor.sqlExe(
|
rows = await sor.sqlExe(
|
||||||
"SELECT id FROM organization WHERE id=${id}$ AND parentid IS NULL AND del_flg='0'",
|
"""SELECT id FROM organization
|
||||||
{'id': orgid},
|
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
|
return len(rows) > 0
|
||||||
|
|
||||||
@ -324,8 +335,14 @@ async def _protocol_snapshot(sor, accounting_orgid, customerid, providerid, prod
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _estimate_finance(catalog_amount, protocol, is_owner):
|
def _estimate_finance(catalog_amount, protocol, is_reverse=False):
|
||||||
"""未记账:估算本级利润与本级应付(不含代付费单独字段)。"""
|
"""未记账:估算本级利润与本级应付(本级成本)。
|
||||||
|
|
||||||
|
与已记账口径一致,本级应付取「本级作为采购方(bid)的协议」即 own_*,
|
||||||
|
对业主机构与分销商统一(own_discount 即上级给本级的折扣/底价)。
|
||||||
|
|
||||||
|
退订(is_reverse):利润取反(减少);上游结算仍正向(增加)。
|
||||||
|
"""
|
||||||
catalog_amount = float(catalog_amount or 0)
|
catalog_amount = float(catalog_amount or 0)
|
||||||
qty = protocol.get('quantity') or 1
|
qty = protocol.get('quantity') or 1
|
||||||
profit = None
|
profit = None
|
||||||
@ -335,29 +352,23 @@ def _estimate_finance(catalog_amount, protocol, is_owner):
|
|||||||
cust_mode = protocol.get('customer_salemode')
|
cust_mode = protocol.get('customer_salemode')
|
||||||
own_disc = protocol.get('own_discount')
|
own_disc = protocol.get('own_discount')
|
||||||
cust_disc = protocol.get('customer_discount')
|
cust_disc = protocol.get('customer_discount')
|
||||||
reseller_disc = protocol.get('reseller_discount')
|
|
||||||
|
|
||||||
if own_mode == '0' or cust_mode == '0':
|
if own_mode == '0' or cust_mode == '0':
|
||||||
if own_disc is not None and cust_disc is not None:
|
if own_disc is not None and cust_disc is not None:
|
||||||
profit = catalog_amount * (float(cust_disc) - float(own_disc))
|
profit = catalog_amount * (float(cust_disc) - float(own_disc))
|
||||||
if is_owner:
|
if own_disc is not None:
|
||||||
if own_disc is not None:
|
settle_upstream = catalog_amount * float(own_disc)
|
||||||
settle_upstream = catalog_amount * float(own_disc)
|
|
||||||
elif reseller_disc is not None:
|
|
||||||
settle_upstream = catalog_amount * float(reseller_disc)
|
|
||||||
|
|
||||||
elif own_mode == '2' or cust_mode == '2':
|
elif own_mode == '2' or cust_mode == '2':
|
||||||
own_price = protocol.get('own_floor_unit_price')
|
own_price = protocol.get('own_floor_unit_price')
|
||||||
cust_price = protocol.get('customer_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:
|
if own_price is not None and cust_price is not None:
|
||||||
profit = (float(cust_price) - float(own_price)) * qty
|
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
|
settle_upstream = float(own_price) * qty
|
||||||
elif not is_owner and reseller_price is not None:
|
|
||||||
settle_upstream = float(reseller_price) * qty
|
if is_reverse and profit is not None:
|
||||||
elif not is_owner and cust_price is not None:
|
profit = -profit
|
||||||
settle_upstream = float(cust_price) * qty
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'profit_amount': _round_money(profit),
|
'profit_amount': _round_money(profit),
|
||||||
@ -379,8 +390,15 @@ async def _bill_detail_rows(sor, billid):
|
|||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_owner, parent_orgid):
|
async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_reverse=False):
|
||||||
"""已记账:从 bill_detail 取本级利润与本级应付。"""
|
"""已记账:从 bill_detail 取本级利润与本级应付。
|
||||||
|
|
||||||
|
统一口径(业主机构与分销商一致):
|
||||||
|
- profit_amount = 本级账本「折扣收入/底价收入」贷方合计
|
||||||
|
- settle_upstream = 本级账本「待结转*销售收入」贷方合计(本级成本/本级应付上级)
|
||||||
|
|
||||||
|
退订(is_reverse):利润取反(减少);上游结算仍正向累加(增加)。
|
||||||
|
"""
|
||||||
rows = await _bill_detail_rows(sor, billid)
|
rows = await _bill_detail_rows(sor, billid)
|
||||||
profit = 0.0
|
profit = 0.0
|
||||||
settle_upstream = 0.0
|
settle_upstream = 0.0
|
||||||
@ -400,25 +418,14 @@ async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_owner, par
|
|||||||
subj = r['subjectname'] or ''
|
subj = r['subjectname'] or ''
|
||||||
direction = r['accounting_dir']
|
direction = r['accounting_dir']
|
||||||
|
|
||||||
if book == accounting_orgid and subj in INCOME_SUBJECTS and direction == '贷':
|
if book == accounting_orgid and direction == '贷':
|
||||||
profit += amt
|
if subj in INCOME_SUBJECTS:
|
||||||
|
profit += amt
|
||||||
|
elif subj.startswith(SUPPLIER_SETTLE_PREFIX):
|
||||||
|
settle_upstream += amt
|
||||||
|
|
||||||
if is_owner:
|
if is_reverse:
|
||||||
if (
|
profit = -profit
|
||||||
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
|
|
||||||
):
|
|
||||||
settle_upstream += amt
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'profit_amount': _round_money(profit),
|
'profit_amount': _round_money(profit),
|
||||||
@ -438,20 +445,21 @@ async def _build_report_row(sor, row, accounting_orgid, is_owner):
|
|||||||
catalog_amount = _round_money(_row_get(row, 'catalog_amount'))
|
catalog_amount = _round_money(_row_get(row, 'catalog_amount'))
|
||||||
customer_pay = _round_money(_row_get(row, 'customer_pay_amount'))
|
customer_pay = _round_money(_row_get(row, 'customer_pay_amount'))
|
||||||
customer_parentid = _row_get(row, 'customer_parentid')
|
customer_parentid = _row_get(row, 'customer_parentid')
|
||||||
|
is_reverse = _is_reverse_op(_row_get(row, 'business_op'))
|
||||||
|
if is_reverse and customer_pay is not None:
|
||||||
|
# 退订:客户实付(销售额)取负,使汇总相应减少
|
||||||
|
customer_pay = _round_money(-customer_pay)
|
||||||
|
|
||||||
protocol = await _protocol_snapshot(
|
protocol = await _protocol_snapshot(
|
||||||
sor, accounting_orgid, customerid, providerid, productid, bill_date, quantity,
|
sor, accounting_orgid, customerid, providerid, productid, bill_date, quantity,
|
||||||
)
|
)
|
||||||
parent_orgid = protocol['parent_orgid']
|
|
||||||
settle_meta = await _settle_upstream_meta(sor, accounting_orgid, providerid)
|
settle_meta = await _settle_upstream_meta(sor, accounting_orgid, providerid)
|
||||||
|
|
||||||
bill_state = _row_get(row, 'bill_state')
|
bill_state = _row_get(row, 'bill_state')
|
||||||
if str(bill_state) == '1':
|
if str(bill_state) == '1':
|
||||||
amounts = await _finance_from_bill_detail(
|
amounts = await _finance_from_bill_detail(sor, bill_id, accounting_orgid, is_reverse)
|
||||||
sor, bill_id, accounting_orgid, is_owner, parent_orgid,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
amounts = _estimate_finance(catalog_amount, protocol, is_owner)
|
amounts = _estimate_finance(catalog_amount, protocol, is_reverse)
|
||||||
amounts['bill_detail_legs'] = []
|
amounts['bill_detail_legs'] = []
|
||||||
|
|
||||||
product_name = _row_get(row, 'product_name')
|
product_name = _row_get(row, 'product_name')
|
||||||
@ -652,17 +660,21 @@ def _customer_segment(customer_parentid, accounting_orgid, reseller_id_set):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_orgid):
|
async def _bill_finance_amounts(sor, row, accounting_orgid):
|
||||||
"""单笔:销售额、本级利润、本级应付上级/供应商。"""
|
"""单笔:销售额、本级利润、本级应付上级/供应商。
|
||||||
|
|
||||||
|
退订(BUY_REVERSE 等):销售额、利润取负(减少);应付上级仍正向(增加)。
|
||||||
|
"""
|
||||||
sales = float(_row_get(row, 'customer_pay_amount') or 0)
|
sales = float(_row_get(row, 'customer_pay_amount') or 0)
|
||||||
bill_id = _row_get(row, 'bill_id')
|
bill_id = _row_get(row, 'bill_id')
|
||||||
bill_state = _row_get(row, 'bill_state')
|
bill_state = _row_get(row, 'bill_state')
|
||||||
quantity = int(_row_get(row, 'quantity') or 1)
|
quantity = int(_row_get(row, 'quantity') or 1)
|
||||||
|
is_reverse = _is_reverse_op(_row_get(row, 'business_op'))
|
||||||
|
if is_reverse:
|
||||||
|
sales = -sales
|
||||||
|
|
||||||
if str(bill_state) == '1':
|
if str(bill_state) == '1':
|
||||||
fin = await _finance_from_bill_detail(
|
fin = await _finance_from_bill_detail(sor, bill_id, accounting_orgid, is_reverse)
|
||||||
sor, bill_id, accounting_orgid, is_owner, parent_orgid,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
catalog = float(_row_get(row, 'catalog_amount') or 0)
|
catalog = float(_row_get(row, 'catalog_amount') or 0)
|
||||||
protocol = await _protocol_snapshot(
|
protocol = await _protocol_snapshot(
|
||||||
@ -674,7 +686,7 @@ async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_org
|
|||||||
_row_get(row, 'bill_date'),
|
_row_get(row, 'bill_date'),
|
||||||
quantity,
|
quantity,
|
||||||
)
|
)
|
||||||
fin = _estimate_finance(catalog, protocol, is_owner)
|
fin = _estimate_finance(catalog, protocol, is_reverse)
|
||||||
|
|
||||||
profit = float(fin.get('profit_amount') or 0)
|
profit = float(fin.get('profit_amount') or 0)
|
||||||
settle = float(fin.get('settle_upstream_amount') or 0)
|
settle = float(fin.get('settle_upstream_amount') or 0)
|
||||||
@ -786,7 +798,7 @@ async def _fetch_bill_row_via_R(sor, bill_id):
|
|||||||
'customer_pay_amount': b.get('amount'),
|
'customer_pay_amount': b.get('amount'),
|
||||||
'quantity': b.get('quantity'),
|
'quantity': b.get('quantity'),
|
||||||
'order_date': o.get('order_date'),
|
'order_date': o.get('order_date'),
|
||||||
'business_op': o.get('business_op'),
|
'business_op': b.get('business_op') or o.get('business_op'),
|
||||||
'servicename': o.get('servicename'),
|
'servicename': o.get('servicename'),
|
||||||
'customer_name': cust.get('orgname'),
|
'customer_name': cust.get('orgname'),
|
||||||
'customer_parentid': cust.get('parentid'),
|
'customer_parentid': cust.get('parentid'),
|
||||||
@ -878,9 +890,9 @@ async def finance_order_report(ns=None):
|
|||||||
userid, start_date, end_date, customerid, productid, order_id, bill_state
|
userid, start_date, end_date, customerid, productid, order_id, bill_state
|
||||||
current_page (默认1), page_size (默认20, 最大100)
|
current_page (默认1), page_size (默认20, 最大100)
|
||||||
|
|
||||||
返回 finance.settle_upstream_*:
|
返回 finance.settle_upstream_*(统一口径,取本级账本「待结转*销售收入」贷方):
|
||||||
- 本机构:应付供应商(待结转* 贷方,仅本机构账本)
|
- 本机构:应付供应商
|
||||||
- 分销商:应付直接上级(上级账本「分销商存放资金」借方,participant=本级)
|
- 分销商:应付直接上级机构(金额=本级成本,与本级账本待结转一致)
|
||||||
"""
|
"""
|
||||||
ns = ns or {}
|
ns = ns or {}
|
||||||
accounting_orgid = ns.get('accounting_orgid')
|
accounting_orgid = ns.get('accounting_orgid')
|
||||||
@ -1053,7 +1065,7 @@ async def finance_billing_overview(ns=None):
|
|||||||
口径(与订单明细接口一致):
|
口径(与订单明细接口一致):
|
||||||
sales_total = 客户实付合计 bill.amount
|
sales_total = 客户实付合计 bill.amount
|
||||||
profit_total = 本级账本折扣收入+底价收入(bill_detail)或协议估算
|
profit_total = 本级账本折扣收入+底价收入(bill_detail)或协议估算
|
||||||
settle_upstream_total= 本机构→供应商待结转;分销→上级账本分销商存放资金借方
|
settle_upstream_total= 本级账本「待结转*销售收入」贷方合计(本级成本/应付上级,业主与分销统一)
|
||||||
|
|
||||||
分段:
|
分段:
|
||||||
direct_customers 直属客户(cust.parentid = accounting_orgid)
|
direct_customers 直属客户(cust.parentid = accounting_orgid)
|
||||||
@ -1084,7 +1096,6 @@ async def finance_billing_overview(ns=None):
|
|||||||
sor, accounting_orgid, include_sub,
|
sor, accounting_orgid, include_sub,
|
||||||
)
|
)
|
||||||
is_owner = await _is_business_owner(sor, accounting_orgid)
|
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]
|
conditions = ["b.del_flg = '0'", "o.del_flg = '0'", scope_sql]
|
||||||
params = dict(scope_params)
|
params = dict(scope_params)
|
||||||
@ -1128,7 +1139,7 @@ async def finance_billing_overview(ns=None):
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
sales, profit, settle, _src = await _bill_finance_amounts(
|
sales, profit, settle, _src = await _bill_finance_amounts(
|
||||||
sor, row, accounting_orgid, is_owner, parent_orgid,
|
sor, row, accounting_orgid,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
errors.append({
|
errors.append({
|
||||||
@ -1230,11 +1241,10 @@ async def finance_billing_overview(ns=None):
|
|||||||
|
|
||||||
# _report = params_kw.get('report') or params_kw.get('api') or 'order_list'
|
# _report = params_kw.get('report') or params_kw.get('api') or 'order_list'
|
||||||
_report = None
|
_report = None
|
||||||
if _report in ('overview', 'billing_overview', 'finance_billing_overview'):
|
# if _report in ('overview', 'billing_overview', 'finance_billing_overview'):
|
||||||
ret = await finance_billing_overview(params_kw)
|
# ret = await finance_billing_overview(params_kw)
|
||||||
elif _report in ('detail', 'order_detail'):
|
# elif _report in ('detail', 'order_detail'):
|
||||||
ret = await finance_order_report_detail(params_kw)
|
# ret = await finance_order_report_detail(params_kw)
|
||||||
else:
|
# else:
|
||||||
ret = await finance_order_report(params_kw)
|
ret = await finance_order_report(params_kw)
|
||||||
return ret
|
|
||||||
return ret
|
return ret
|
||||||
@ -75,7 +75,6 @@ SALEMODE_LABEL = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
INCOME_SUBJECTS = ('折扣收入', '底价收入')
|
INCOME_SUBJECTS = ('折扣收入', '底价收入')
|
||||||
PARENT_SETTLE_SUBJECT = '分销商存放资金'
|
|
||||||
SUPPLIER_SETTLE_PREFIX = '待结转'
|
SUPPLIER_SETTLE_PREFIX = '待结转'
|
||||||
|
|
||||||
_SALEMODE_SQL_OWN = """
|
_SALEMODE_SQL_OWN = """
|
||||||
@ -116,6 +115,15 @@ def _round_money(v):
|
|||||||
return round(float(v), 2)
|
return round(float(v), 2)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_reverse_op(business_op):
|
||||||
|
"""退订/红冲类操作(BUY_REVERSE 等 *_REVERSE)。
|
||||||
|
|
||||||
|
数据中退订账单的 bill_detail 方向与正常单一致(均为贷),仅靠 business_op 区分。
|
||||||
|
退订口径:销售额、利润取反(减少);上游结算/应付供应商仍正向累加(增加)。
|
||||||
|
"""
|
||||||
|
return str(business_op or '').upper().endswith('_REVERSE')
|
||||||
|
|
||||||
|
|
||||||
def _salemode_label(code):
|
def _salemode_label(code):
|
||||||
if code is None:
|
if code is None:
|
||||||
return None
|
return None
|
||||||
@ -194,9 +202,12 @@ async def _org_name(sor, orgid):
|
|||||||
|
|
||||||
|
|
||||||
async def _is_business_owner(sor, orgid):
|
async def _is_business_owner(sor, orgid):
|
||||||
|
# 业主机构 parentid 为空串(非 NULL),org_type='0';两者都视为顶级机构。
|
||||||
rows = await sor.sqlExe(
|
rows = await sor.sqlExe(
|
||||||
"SELECT id FROM organization WHERE id=${id}$ AND parentid IS NULL AND del_flg='0'",
|
"""SELECT id FROM organization
|
||||||
{'id': orgid},
|
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
|
return len(rows) > 0
|
||||||
|
|
||||||
@ -324,8 +335,14 @@ async def _protocol_snapshot(sor, accounting_orgid, customerid, providerid, prod
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def _estimate_finance(catalog_amount, protocol, is_owner):
|
def _estimate_finance(catalog_amount, protocol, is_reverse=False):
|
||||||
"""未记账:估算本级利润与本级应付(不含代付费单独字段)。"""
|
"""未记账:估算本级利润与本级应付(本级成本)。
|
||||||
|
|
||||||
|
与已记账口径一致,本级应付取「本级作为采购方(bid)的协议」即 own_*,
|
||||||
|
对业主机构与分销商统一(own_discount 即上级给本级的折扣/底价)。
|
||||||
|
|
||||||
|
退订(is_reverse):利润取反(减少);上游结算仍正向(增加)。
|
||||||
|
"""
|
||||||
catalog_amount = float(catalog_amount or 0)
|
catalog_amount = float(catalog_amount or 0)
|
||||||
qty = protocol.get('quantity') or 1
|
qty = protocol.get('quantity') or 1
|
||||||
profit = None
|
profit = None
|
||||||
@ -335,29 +352,23 @@ def _estimate_finance(catalog_amount, protocol, is_owner):
|
|||||||
cust_mode = protocol.get('customer_salemode')
|
cust_mode = protocol.get('customer_salemode')
|
||||||
own_disc = protocol.get('own_discount')
|
own_disc = protocol.get('own_discount')
|
||||||
cust_disc = protocol.get('customer_discount')
|
cust_disc = protocol.get('customer_discount')
|
||||||
reseller_disc = protocol.get('reseller_discount')
|
|
||||||
|
|
||||||
if own_mode == '0' or cust_mode == '0':
|
if own_mode == '0' or cust_mode == '0':
|
||||||
if own_disc is not None and cust_disc is not None:
|
if own_disc is not None and cust_disc is not None:
|
||||||
profit = catalog_amount * (float(cust_disc) - float(own_disc))
|
profit = catalog_amount * (float(cust_disc) - float(own_disc))
|
||||||
if is_owner:
|
if own_disc is not None:
|
||||||
if own_disc is not None:
|
settle_upstream = catalog_amount * float(own_disc)
|
||||||
settle_upstream = catalog_amount * float(own_disc)
|
|
||||||
elif reseller_disc is not None:
|
|
||||||
settle_upstream = catalog_amount * float(reseller_disc)
|
|
||||||
|
|
||||||
elif own_mode == '2' or cust_mode == '2':
|
elif own_mode == '2' or cust_mode == '2':
|
||||||
own_price = protocol.get('own_floor_unit_price')
|
own_price = protocol.get('own_floor_unit_price')
|
||||||
cust_price = protocol.get('customer_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:
|
if own_price is not None and cust_price is not None:
|
||||||
profit = (float(cust_price) - float(own_price)) * qty
|
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
|
settle_upstream = float(own_price) * qty
|
||||||
elif not is_owner and reseller_price is not None:
|
|
||||||
settle_upstream = float(reseller_price) * qty
|
if is_reverse and profit is not None:
|
||||||
elif not is_owner and cust_price is not None:
|
profit = -profit
|
||||||
settle_upstream = float(cust_price) * qty
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'profit_amount': _round_money(profit),
|
'profit_amount': _round_money(profit),
|
||||||
@ -379,8 +390,15 @@ async def _bill_detail_rows(sor, billid):
|
|||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_owner, parent_orgid):
|
async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_reverse=False):
|
||||||
"""已记账:从 bill_detail 取本级利润与本级应付。"""
|
"""已记账:从 bill_detail 取本级利润与本级应付。
|
||||||
|
|
||||||
|
统一口径(业主机构与分销商一致):
|
||||||
|
- profit_amount = 本级账本「折扣收入/底价收入」贷方合计
|
||||||
|
- settle_upstream = 本级账本「待结转*销售收入」贷方合计(本级成本/本级应付上级)
|
||||||
|
|
||||||
|
退订(is_reverse):利润取反(减少);上游结算仍正向累加(增加)。
|
||||||
|
"""
|
||||||
rows = await _bill_detail_rows(sor, billid)
|
rows = await _bill_detail_rows(sor, billid)
|
||||||
profit = 0.0
|
profit = 0.0
|
||||||
settle_upstream = 0.0
|
settle_upstream = 0.0
|
||||||
@ -400,25 +418,14 @@ async def _finance_from_bill_detail(sor, billid, accounting_orgid, is_owner, par
|
|||||||
subj = r['subjectname'] or ''
|
subj = r['subjectname'] or ''
|
||||||
direction = r['accounting_dir']
|
direction = r['accounting_dir']
|
||||||
|
|
||||||
if book == accounting_orgid and subj in INCOME_SUBJECTS and direction == '贷':
|
if book == accounting_orgid and direction == '贷':
|
||||||
profit += amt
|
if subj in INCOME_SUBJECTS:
|
||||||
|
profit += amt
|
||||||
|
elif subj.startswith(SUPPLIER_SETTLE_PREFIX):
|
||||||
|
settle_upstream += amt
|
||||||
|
|
||||||
if is_owner:
|
if is_reverse:
|
||||||
if (
|
profit = -profit
|
||||||
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
|
|
||||||
):
|
|
||||||
settle_upstream += amt
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'profit_amount': _round_money(profit),
|
'profit_amount': _round_money(profit),
|
||||||
@ -438,20 +445,21 @@ async def _build_report_row(sor, row, accounting_orgid, is_owner):
|
|||||||
catalog_amount = _round_money(_row_get(row, 'catalog_amount'))
|
catalog_amount = _round_money(_row_get(row, 'catalog_amount'))
|
||||||
customer_pay = _round_money(_row_get(row, 'customer_pay_amount'))
|
customer_pay = _round_money(_row_get(row, 'customer_pay_amount'))
|
||||||
customer_parentid = _row_get(row, 'customer_parentid')
|
customer_parentid = _row_get(row, 'customer_parentid')
|
||||||
|
is_reverse = _is_reverse_op(_row_get(row, 'business_op'))
|
||||||
|
if is_reverse and customer_pay is not None:
|
||||||
|
# 退订:客户实付(销售额)取负,使汇总相应减少
|
||||||
|
customer_pay = _round_money(-customer_pay)
|
||||||
|
|
||||||
protocol = await _protocol_snapshot(
|
protocol = await _protocol_snapshot(
|
||||||
sor, accounting_orgid, customerid, providerid, productid, bill_date, quantity,
|
sor, accounting_orgid, customerid, providerid, productid, bill_date, quantity,
|
||||||
)
|
)
|
||||||
parent_orgid = protocol['parent_orgid']
|
|
||||||
settle_meta = await _settle_upstream_meta(sor, accounting_orgid, providerid)
|
settle_meta = await _settle_upstream_meta(sor, accounting_orgid, providerid)
|
||||||
|
|
||||||
bill_state = _row_get(row, 'bill_state')
|
bill_state = _row_get(row, 'bill_state')
|
||||||
if str(bill_state) == '1':
|
if str(bill_state) == '1':
|
||||||
amounts = await _finance_from_bill_detail(
|
amounts = await _finance_from_bill_detail(sor, bill_id, accounting_orgid, is_reverse)
|
||||||
sor, bill_id, accounting_orgid, is_owner, parent_orgid,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
amounts = _estimate_finance(catalog_amount, protocol, is_owner)
|
amounts = _estimate_finance(catalog_amount, protocol, is_reverse)
|
||||||
amounts['bill_detail_legs'] = []
|
amounts['bill_detail_legs'] = []
|
||||||
|
|
||||||
product_name = _row_get(row, 'product_name')
|
product_name = _row_get(row, 'product_name')
|
||||||
@ -652,17 +660,21 @@ def _customer_segment(customer_parentid, accounting_orgid, reseller_id_set):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_orgid):
|
async def _bill_finance_amounts(sor, row, accounting_orgid):
|
||||||
"""单笔:销售额、本级利润、本级应付上级/供应商。"""
|
"""单笔:销售额、本级利润、本级应付上级/供应商。
|
||||||
|
|
||||||
|
退订(BUY_REVERSE 等):销售额、利润取负(减少);应付上级仍正向(增加)。
|
||||||
|
"""
|
||||||
sales = float(_row_get(row, 'customer_pay_amount') or 0)
|
sales = float(_row_get(row, 'customer_pay_amount') or 0)
|
||||||
bill_id = _row_get(row, 'bill_id')
|
bill_id = _row_get(row, 'bill_id')
|
||||||
bill_state = _row_get(row, 'bill_state')
|
bill_state = _row_get(row, 'bill_state')
|
||||||
quantity = int(_row_get(row, 'quantity') or 1)
|
quantity = int(_row_get(row, 'quantity') or 1)
|
||||||
|
is_reverse = _is_reverse_op(_row_get(row, 'business_op'))
|
||||||
|
if is_reverse:
|
||||||
|
sales = -sales
|
||||||
|
|
||||||
if str(bill_state) == '1':
|
if str(bill_state) == '1':
|
||||||
fin = await _finance_from_bill_detail(
|
fin = await _finance_from_bill_detail(sor, bill_id, accounting_orgid, is_reverse)
|
||||||
sor, bill_id, accounting_orgid, is_owner, parent_orgid,
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
catalog = float(_row_get(row, 'catalog_amount') or 0)
|
catalog = float(_row_get(row, 'catalog_amount') or 0)
|
||||||
protocol = await _protocol_snapshot(
|
protocol = await _protocol_snapshot(
|
||||||
@ -674,7 +686,7 @@ async def _bill_finance_amounts(sor, row, accounting_orgid, is_owner, parent_org
|
|||||||
_row_get(row, 'bill_date'),
|
_row_get(row, 'bill_date'),
|
||||||
quantity,
|
quantity,
|
||||||
)
|
)
|
||||||
fin = _estimate_finance(catalog, protocol, is_owner)
|
fin = _estimate_finance(catalog, protocol, is_reverse)
|
||||||
|
|
||||||
profit = float(fin.get('profit_amount') or 0)
|
profit = float(fin.get('profit_amount') or 0)
|
||||||
settle = float(fin.get('settle_upstream_amount') or 0)
|
settle = float(fin.get('settle_upstream_amount') or 0)
|
||||||
@ -786,7 +798,7 @@ async def _fetch_bill_row_via_R(sor, bill_id):
|
|||||||
'customer_pay_amount': b.get('amount'),
|
'customer_pay_amount': b.get('amount'),
|
||||||
'quantity': b.get('quantity'),
|
'quantity': b.get('quantity'),
|
||||||
'order_date': o.get('order_date'),
|
'order_date': o.get('order_date'),
|
||||||
'business_op': o.get('business_op'),
|
'business_op': b.get('business_op') or o.get('business_op'),
|
||||||
'servicename': o.get('servicename'),
|
'servicename': o.get('servicename'),
|
||||||
'customer_name': cust.get('orgname'),
|
'customer_name': cust.get('orgname'),
|
||||||
'customer_parentid': cust.get('parentid'),
|
'customer_parentid': cust.get('parentid'),
|
||||||
@ -878,9 +890,9 @@ async def finance_order_report(ns=None):
|
|||||||
userid, start_date, end_date, customerid, productid, order_id, bill_state
|
userid, start_date, end_date, customerid, productid, order_id, bill_state
|
||||||
current_page (默认1), page_size (默认20, 最大100)
|
current_page (默认1), page_size (默认20, 最大100)
|
||||||
|
|
||||||
返回 finance.settle_upstream_*:
|
返回 finance.settle_upstream_*(统一口径,取本级账本「待结转*销售收入」贷方):
|
||||||
- 本机构:应付供应商(待结转* 贷方,仅本机构账本)
|
- 本机构:应付供应商
|
||||||
- 分销商:应付直接上级(上级账本「分销商存放资金」借方,participant=本级)
|
- 分销商:应付直接上级机构(金额=本级成本,与本级账本待结转一致)
|
||||||
"""
|
"""
|
||||||
ns = ns or {}
|
ns = ns or {}
|
||||||
accounting_orgid = ns.get('accounting_orgid')
|
accounting_orgid = ns.get('accounting_orgid')
|
||||||
@ -1053,7 +1065,7 @@ async def finance_billing_overview(ns=None):
|
|||||||
口径(与订单明细接口一致):
|
口径(与订单明细接口一致):
|
||||||
sales_total = 客户实付合计 bill.amount
|
sales_total = 客户实付合计 bill.amount
|
||||||
profit_total = 本级账本折扣收入+底价收入(bill_detail)或协议估算
|
profit_total = 本级账本折扣收入+底价收入(bill_detail)或协议估算
|
||||||
settle_upstream_total= 本机构→供应商待结转;分销→上级账本分销商存放资金借方
|
settle_upstream_total= 本级账本「待结转*销售收入」贷方合计(本级成本/应付上级,业主与分销统一)
|
||||||
|
|
||||||
分段:
|
分段:
|
||||||
direct_customers 直属客户(cust.parentid = accounting_orgid)
|
direct_customers 直属客户(cust.parentid = accounting_orgid)
|
||||||
@ -1084,7 +1096,6 @@ async def finance_billing_overview(ns=None):
|
|||||||
sor, accounting_orgid, include_sub,
|
sor, accounting_orgid, include_sub,
|
||||||
)
|
)
|
||||||
is_owner = await _is_business_owner(sor, accounting_orgid)
|
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]
|
conditions = ["b.del_flg = '0'", "o.del_flg = '0'", scope_sql]
|
||||||
params = dict(scope_params)
|
params = dict(scope_params)
|
||||||
@ -1128,7 +1139,7 @@ async def finance_billing_overview(ns=None):
|
|||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
sales, profit, settle, _src = await _bill_finance_amounts(
|
sales, profit, settle, _src = await _bill_finance_amounts(
|
||||||
sor, row, accounting_orgid, is_owner, parent_orgid,
|
sor, row, accounting_orgid,
|
||||||
)
|
)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
errors.append({
|
errors.append({
|
||||||
|
|||||||
@ -178,7 +178,7 @@ async def getbz_order(ns={}):
|
|||||||
'BUY': '购买',
|
'BUY': '购买',
|
||||||
'RENEW': '续费',
|
'RENEW': '续费',
|
||||||
'BUY_REVERSE': '退款',
|
'BUY_REVERSE': '退款',
|
||||||
# 'UPGRADE': '升级'
|
'DILATATION': '升降配'
|
||||||
}
|
}
|
||||||
item['business_op_text'] = business_op_mapping.get(item['business_op'], item['business_op'])
|
item['business_op_text'] = business_op_mapping.get(item['business_op'], item['business_op'])
|
||||||
|
|
||||||
|
|||||||
@ -95,7 +95,7 @@ def _normalize_usage_row(row, bill_amount_map=None):
|
|||||||
'prompt_tokens': int(usage.get('prompt_tokens') or 0),
|
'prompt_tokens': int(usage.get('prompt_tokens') or 0),
|
||||||
'completion_tokens': int(usage.get('completion_tokens') or 0),
|
'completion_tokens': int(usage.get('completion_tokens') or 0),
|
||||||
'total_tokens': int(usage.get('total_tokens') or 0),
|
'total_tokens': int(usage.get('total_tokens') or 0),
|
||||||
'amount': round(amount, 8),
|
'amount': round(amount, 4),
|
||||||
'bill_status': row.get('bill_status'),
|
'bill_status': row.get('bill_status'),
|
||||||
'orderid': orderid,
|
'orderid': orderid,
|
||||||
'usage_time': row.get('created_at'),
|
'usage_time': row.get('created_at'),
|
||||||
@ -224,7 +224,7 @@ def _aggregate_admin_summary(items, user_map, org_map):
|
|||||||
bucket['prompt_tokens'] += item.get('prompt_tokens') or 0
|
bucket['prompt_tokens'] += item.get('prompt_tokens') or 0
|
||||||
bucket['completion_tokens'] += item.get('completion_tokens') or 0
|
bucket['completion_tokens'] += item.get('completion_tokens') or 0
|
||||||
bucket['total_tokens'] += item.get('total_tokens') or 0
|
bucket['total_tokens'] += item.get('total_tokens') or 0
|
||||||
bucket['amount'] = round(bucket['amount'] + float(item.get('amount') or 0), 8)
|
bucket['amount'] = round(bucket['amount'] + float(item.get('amount') or 0), 4)
|
||||||
bucket['request_count'] += 1
|
bucket['request_count'] += 1
|
||||||
usage_time = item.get('usage_time')
|
usage_time = item.get('usage_time')
|
||||||
if usage_time:
|
if usage_time:
|
||||||
@ -267,7 +267,7 @@ def _aggregate_items(items, group_by=None):
|
|||||||
bucket['prompt_tokens'] += item.get('prompt_tokens') or 0
|
bucket['prompt_tokens'] += item.get('prompt_tokens') or 0
|
||||||
bucket['completion_tokens'] += item.get('completion_tokens') or 0
|
bucket['completion_tokens'] += item.get('completion_tokens') or 0
|
||||||
bucket['total_tokens'] += item.get('total_tokens') or 0
|
bucket['total_tokens'] += item.get('total_tokens') or 0
|
||||||
bucket['amount'] = round(bucket['amount'] + float(item.get('amount') or 0), 8)
|
bucket['amount'] = round(bucket['amount'] + float(item.get('amount') or 0), 4)
|
||||||
bucket['request_count'] += 1
|
bucket['request_count'] += 1
|
||||||
|
|
||||||
return sorted(buckets.values(), key=lambda x: x['period'], reverse=True)
|
return sorted(buckets.values(), key=lambda x: x['period'], reverse=True)
|
||||||
@ -279,7 +279,7 @@ def _summarize(items):
|
|||||||
'prompt_tokens': sum(i.get('prompt_tokens') or 0 for i in items),
|
'prompt_tokens': sum(i.get('prompt_tokens') or 0 for i in items),
|
||||||
'completion_tokens': sum(i.get('completion_tokens') or 0 for i in items),
|
'completion_tokens': sum(i.get('completion_tokens') or 0 for i in items),
|
||||||
'total_tokens': sum(i.get('total_tokens') or 0 for i in items),
|
'total_tokens': sum(i.get('total_tokens') or 0 for i in items),
|
||||||
'amount': round(sum(float(i.get('amount') or 0) for i in items), 8),
|
'amount': round(sum(float(i.get('amount') or 0) for i in items), 4),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -129,19 +129,19 @@ export const reqModelInfoConfig = (params = {}) => {
|
|||||||
const isFormData = params instanceof FormData
|
const isFormData = params instanceof FormData
|
||||||
return request({
|
return request({
|
||||||
url: '/cntoai/model_management_add.dspy',
|
url: '/cntoai/model_management_add.dspy',
|
||||||
method: isFormData ? 'post' : 'get',
|
method: 'post',
|
||||||
params: isFormData ? undefined : params,
|
params: isFormData ? undefined : params,
|
||||||
data: isFormData ? params : undefined,
|
data: isFormData ? params : undefined,
|
||||||
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : undefined
|
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : undefined
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 模型信息配置编辑(编辑时需要额外传 id)
|
// 模型信息配置编辑
|
||||||
export const reqModelInfoConfigEdit = (params = {}) => {
|
export const reqModelInfoConfigEdit = (params = {}) => {
|
||||||
const isFormData = params instanceof FormData
|
const isFormData = params instanceof FormData
|
||||||
return request({
|
return request({
|
||||||
url: '/cntoai/model_management_update.dspy',
|
url: '/cntoai/model_management_update.dspy',
|
||||||
method: isFormData ? 'post' : 'get',
|
method: 'post',
|
||||||
params: isFormData ? undefined : params,
|
params: isFormData ? undefined : params,
|
||||||
data: isFormData ? params : undefined,
|
data: isFormData ? params : undefined,
|
||||||
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : undefined
|
headers: isFormData ? { 'Content-Type': 'multipart/form-data' } : undefined
|
||||||
|
|||||||
@ -10,10 +10,10 @@
|
|||||||
<p>核算机构:<b>{{ displayValue(billingData.accounting_orgname) }}</b></p>
|
<p>核算机构:<b>{{ displayValue(billingData.accounting_orgname) }}</b></p>
|
||||||
<p>机构编号:{{ displayValue(billingData.accounting_orgid) }}</p>
|
<p>机构编号:{{ displayValue(billingData.accounting_orgid) }}</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="view-info">
|
<!-- <div class="view-info">
|
||||||
<strong>管理员视图</strong>
|
<strong>管理员视图</strong>
|
||||||
<small>生成于 2026/5/29 17:00:06</small>
|
<small>生成于 2026/5/29 17:00:06</small>
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="summary-grid">
|
<div class="summary-grid">
|
||||||
|
|||||||
@ -18,9 +18,9 @@
|
|||||||
<span>数据截断:<b>{{ financialOverview.truncated ? '是' : '否' }}</b></span>
|
<span>数据截断:<b>{{ financialOverview.truncated ? '是' : '否' }}</b></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="view-meta">
|
<!-- <div class="view-meta">
|
||||||
查看计费统计
|
查看计费统计
|
||||||
</div>
|
</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="summary-grid">
|
<div class="summary-grid">
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -84,11 +84,11 @@
|
|||||||
|
|
||||||
<el-table v-loading="loading" :data="usageList" class="usage-table" style="width: 100%">
|
<el-table v-loading="loading" :data="usageList" class="usage-table" style="width: 100%">
|
||||||
<el-table-column prop="model" label="模型名称" min-width="180" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="model" label="模型名称" min-width="180" show-overflow-tooltip></el-table-column>
|
||||||
<el-table-column prop="request_count" label="调用次数" width="120"></el-table-column>
|
<!-- <el-table-column prop="request_count" label="调用次数" width="120"></el-table-column> -->
|
||||||
<el-table-column prop="prompt_tokens" label="输入Token" min-width="140"></el-table-column>
|
<el-table-column prop="prompt_tokens" label="输入Token" min-width="140"></el-table-column>
|
||||||
<el-table-column prop="completion_tokens" label="输出Token" min-width="140"></el-table-column>
|
<el-table-column prop="completion_tokens" label="输出Token" min-width="140"></el-table-column>
|
||||||
<el-table-column prop="total_tokens" label="总Token" min-width="140"></el-table-column>
|
<el-table-column prop="total_tokens" label="总Token" min-width="140"></el-table-column>
|
||||||
<el-table-column prop="amount" label="预估费用" width="130">
|
<el-table-column prop="amount" label="费用" width="130">
|
||||||
<template slot-scope="scope">¥ {{ formatAmount(scope.row.amount) }}</template>
|
<template slot-scope="scope">¥ {{ formatAmount(scope.row.amount) }}</template>
|
||||||
</el-table-column>
|
</el-table-column>
|
||||||
<el-table-column prop="usage_time" label="使用时间" min-width="170" show-overflow-tooltip></el-table-column>
|
<el-table-column prop="usage_time" label="使用时间" min-width="170" show-overflow-tooltip></el-table-column>
|
||||||
@ -131,7 +131,7 @@ export default {
|
|||||||
statCards: [
|
statCards: [
|
||||||
{ label: '总消耗 Token', value: '0', desc: '当前筛选范围', type: 'primary', icon: 'el-icon-coin' },
|
{ label: '总消耗 Token', value: '0', desc: '当前筛选范围', type: 'primary', icon: 'el-icon-coin' },
|
||||||
{ label: '调用次数', value: '0', desc: '当前筛选范围', type: 'success', icon: 'el-icon-s-promotion' },
|
{ label: '调用次数', value: '0', desc: '当前筛选范围', type: 'success', icon: 'el-icon-s-promotion' },
|
||||||
{ label: '预估费用', value: '¥ 0.00', desc: '按当前单价估算', type: 'warning', icon: 'el-icon-wallet' },
|
{ label: ' 费用', value: '¥ 0.00', desc: '按当前单价估算', type: 'warning', icon: 'el-icon-wallet' },
|
||||||
{ label: '输入/输出 Token', value: '0 / 0', desc: 'Prompt / Completion', type: 'purple', icon: 'el-icon-pie-chart' }
|
{ label: '输入/输出 Token', value: '0 / 0', desc: 'Prompt / Completion', type: 'purple', icon: 'el-icon-pie-chart' }
|
||||||
],
|
],
|
||||||
usageList: [],
|
usageList: [],
|
||||||
@ -165,11 +165,27 @@ export default {
|
|||||||
return this.rangeLabel
|
return this.rangeLabel
|
||||||
},
|
},
|
||||||
modelUsageRank() {
|
modelUsageRank() {
|
||||||
const maxTokens = Math.max(...this.usageList.map(item => Number(item.total_tokens || 0)), 0)
|
const modelMap = this.usageList.reduce((map, item) => {
|
||||||
return this.usageList
|
const model = item.model || item.model_name || item.display_name || '-'
|
||||||
|
const totalTokens = Number(item.total_tokens || 0) || Number(item.prompt_tokens || 0) + Number(item.completion_tokens || 0)
|
||||||
|
if (!map[model]) {
|
||||||
|
map[model] = {
|
||||||
|
model,
|
||||||
|
total_tokens: 0,
|
||||||
|
request_count: 0,
|
||||||
|
amount: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
map[model].total_tokens += totalTokens
|
||||||
|
map[model].request_count += Number(item.request_count || 0)
|
||||||
|
map[model].amount += Number(item.amount || 0)
|
||||||
|
return map
|
||||||
|
}, {})
|
||||||
|
const rankSource = Object.values(modelMap)
|
||||||
|
const maxTokens = Math.max(...rankSource.map(item => Number(item.total_tokens || 0)), 0)
|
||||||
|
return rankSource
|
||||||
.map(item => ({
|
.map(item => ({
|
||||||
model: item.model,
|
...item,
|
||||||
total_tokens: Number(item.total_tokens || 0),
|
|
||||||
percent: maxTokens ? Math.round((Number(item.total_tokens || 0) / maxTokens) * 100) : 0
|
percent: maxTokens ? Math.round((Number(item.total_tokens || 0) / maxTokens) * 100) : 0
|
||||||
}))
|
}))
|
||||||
.sort((a, b) => b.total_tokens - a.total_tokens)
|
.sort((a, b) => b.total_tokens - a.total_tokens)
|
||||||
@ -328,7 +344,14 @@ export default {
|
|||||||
},
|
},
|
||||||
formatter: params => {
|
formatter: params => {
|
||||||
const item = params && params[0]
|
const item = params && params[0]
|
||||||
return item ? `${item.name}<br/>${this.formatNumber(item.value)} Token` : ''
|
if (!item) return ''
|
||||||
|
const rankItem = rankList[item.dataIndex] || {}
|
||||||
|
return [
|
||||||
|
item.name,
|
||||||
|
`${this.formatNumber(item.value)} Token`,
|
||||||
|
`调用次数:${this.formatNumber(rankItem.request_count)}`,
|
||||||
|
`预估费用:¥ ${this.formatAmount(rankItem.amount)}`
|
||||||
|
].join('<br/>')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
xAxis: {
|
xAxis: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user