feat: multi-currency billing — llmusage currency fields + real-time exchange
This commit is contained in:
parent
cf16d60893
commit
43e8b40774
@ -21,15 +21,43 @@ async def llm_charging(ppid, llmusage):
|
|||||||
e = Exception(f'{ppid=}, {usages=}{llmusage.id=} env.buffered_charging() return None')
|
e = Exception(f'{ppid=}, {usages=}{llmusage.id=} env.buffered_charging() return None')
|
||||||
exception(f'{e}')
|
exception(f'{e}')
|
||||||
raise e
|
raise e
|
||||||
return None
|
|
||||||
amount = 0
|
amount = 0
|
||||||
for p in prices:
|
for p in prices:
|
||||||
amount += p.amount
|
amount += p.amount
|
||||||
discount = await env.get_customer_discount(llmusage.ownerid,
|
discount = await env.get_customer_discount(llmusage.ownerid,
|
||||||
llmusage.userorgid)
|
llmusage.userorgid)
|
||||||
|
# Get pricing program currency (provider's settlement currency)
|
||||||
|
cost_currency = 'CNY'
|
||||||
|
try:
|
||||||
|
pp = await env.get_ppid_pricing(ppid)
|
||||||
|
if pp and hasattr(pp, 'pp') and hasattr(pp.pp, 'currency'):
|
||||||
|
cost_currency = pp.pp.currency or 'CNY'
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Get user's billing currency
|
||||||
|
user_currency = 'CNY'
|
||||||
|
try:
|
||||||
|
user_currency = await env.get_user_currency(llmusage.userorgid)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Convert cost to user currency at real-time rate
|
||||||
|
cost_in_user_currency = amount
|
||||||
|
if cost_currency != user_currency:
|
||||||
|
rate = await env.get_exchange_rate(cost_currency, user_currency, 'buy_rate')
|
||||||
|
cost_in_user_currency = round(amount * rate, 2)
|
||||||
|
|
||||||
|
# Convert both to base currency (CNY) for reporting
|
||||||
|
amount_base = await env.convert_to_base(cost_in_user_currency, user_currency, 'sell_rate')
|
||||||
|
|
||||||
return DictObject(**{
|
return DictObject(**{
|
||||||
'original_amount': amount,
|
'original_amount': amount,
|
||||||
'amount': amount * discount,
|
'amount': cost_in_user_currency * discount,
|
||||||
|
'cost_currency': cost_currency,
|
||||||
|
'amount_currency': user_currency,
|
||||||
|
'amount_base': amount_base * discount,
|
||||||
|
'cost_base': await env.convert_to_base(amount, cost_currency, 'buy_rate'),
|
||||||
})
|
})
|
||||||
|
|
||||||
async def checkCustomerBalance(llmid, userid, userorgid, catelogid=None):
|
async def checkCustomerBalance(llmid, userid, userorgid, catelogid=None):
|
||||||
@ -95,6 +123,10 @@ async def llm_accounting(llmusage):
|
|||||||
providerid = llm.providerid
|
providerid = llm.providerid
|
||||||
trans_amount = llmusage.amount
|
trans_amount = llmusage.amount
|
||||||
trans_cost = llmusage.cost
|
trans_cost = llmusage.cost
|
||||||
|
amount_currency = getattr(llmusage, 'amount_currency', 'CNY')
|
||||||
|
cost_currency = getattr(llmusage, 'cost_currency', 'CNY')
|
||||||
|
amount_base = getattr(llmusage, 'amount_base', trans_amount)
|
||||||
|
cost_base = getattr(llmusage, 'cost_base', trans_cost)
|
||||||
async with get_sor_context(env, 'llmage') as sor:
|
async with get_sor_context(env, 'llmage') as sor:
|
||||||
biz_date = await env.get_business_date(sor)
|
biz_date = await env.get_business_date(sor)
|
||||||
timestamp = env.timestampstr()
|
timestamp = env.timestampstr()
|
||||||
@ -116,7 +148,8 @@ async def llm_accounting(llmusage):
|
|||||||
"orderid": orderid,
|
"orderid": orderid,
|
||||||
"productid": llmid,
|
"productid": llmid,
|
||||||
"product_cnt": 1,
|
"product_cnt": 1,
|
||||||
"trans_amount": trans_amount
|
"trans_amount": trans_amount,
|
||||||
|
"currency": amount_currency,
|
||||||
}
|
}
|
||||||
await sor.C('biz_orderdetail', orderdetail)
|
await sor.C('biz_orderdetail', orderdetail)
|
||||||
ais = []
|
ais = []
|
||||||
@ -130,8 +163,12 @@ async def llm_accounting(llmusage):
|
|||||||
ai0.timestamp = timestamp
|
ai0.timestamp = timestamp
|
||||||
ai0.productid = llmid
|
ai0.productid = llmid
|
||||||
ai0.transamt = trans_amount
|
ai0.transamt = trans_amount
|
||||||
|
ai0.currency = amount_currency
|
||||||
|
ai0.base_amount = amount_base
|
||||||
ai0.variable = {
|
ai0.variable = {
|
||||||
"交易金额": trans_amount,
|
"交易金额": trans_amount,
|
||||||
|
"交易币种": amount_currency,
|
||||||
|
"折本位币": amount_base,
|
||||||
"交易手续费": 0
|
"交易手续费": 0
|
||||||
}
|
}
|
||||||
ais.append(ai0)
|
ais.append(ai0)
|
||||||
@ -145,6 +182,8 @@ async def llm_accounting(llmusage):
|
|||||||
ai1.providerid = providerid
|
ai1.providerid = providerid
|
||||||
ai1.productid = llmid
|
ai1.productid = llmid
|
||||||
ai1.transamt = trans_cost
|
ai1.transamt = trans_cost
|
||||||
|
ai1.currency = cost_currency
|
||||||
|
ai1.base_amount = cost_base
|
||||||
ai1.variable = {
|
ai1.variable = {
|
||||||
"采购成本": trans_cost
|
"采购成本": trans_cost
|
||||||
}
|
}
|
||||||
@ -200,6 +239,10 @@ where a.llmid = b.id
|
|||||||
ns = {
|
ns = {
|
||||||
'id': r.id,
|
'id': r.id,
|
||||||
'amount': r.amount,
|
'amount': r.amount,
|
||||||
|
'amount_currency': getattr(d, 'amount_currency', 'CNY'),
|
||||||
|
'amount_base': getattr(d, 'amount_base', r.amount),
|
||||||
|
'cost_currency': getattr(d, 'cost_currency', 'CNY'),
|
||||||
|
'cost_base': getattr(d, 'cost_base', 0),
|
||||||
'usage': json.dumps(r.usage, ensure_ascii=False, indent=4)
|
'usage': json.dumps(r.usage, ensure_ascii=False, indent=4)
|
||||||
}
|
}
|
||||||
await sor.U('llmusage', ns)
|
await sor.U('llmusage', ns)
|
||||||
|
|||||||
@ -87,6 +87,21 @@
|
|||||||
"length": 18,
|
"length": 18,
|
||||||
"dec": 2
|
"dec": 2
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "amount_currency",
|
||||||
|
"title": "计费币种",
|
||||||
|
"type": "str",
|
||||||
|
"length": 3,
|
||||||
|
"default": "CNY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "amount_base",
|
||||||
|
"title": "折本位币金额",
|
||||||
|
"type": "float",
|
||||||
|
"length": 20,
|
||||||
|
"dec": 2,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "cost",
|
"name": "cost",
|
||||||
"title": "交易成本",
|
"title": "交易成本",
|
||||||
@ -94,6 +109,21 @@
|
|||||||
"length": 18,
|
"length": 18,
|
||||||
"dec": 2
|
"dec": 2
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "cost_currency",
|
||||||
|
"title": "成本币种",
|
||||||
|
"type": "str",
|
||||||
|
"length": 3,
|
||||||
|
"default": "CNY"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cost_base",
|
||||||
|
"title": "折本位币成本",
|
||||||
|
"type": "float",
|
||||||
|
"length": 20,
|
||||||
|
"dec": 2,
|
||||||
|
"default": 0
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "userorgid",
|
"name": "userorgid",
|
||||||
"title": "user_orgname",
|
"title": "user_orgname",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user