bugfix
This commit is contained in:
parent
f44799eb36
commit
13e7ae95d6
@ -1,5 +1,6 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import re
|
import re
|
||||||
|
from operator import itemgetter
|
||||||
from .const import *
|
from .const import *
|
||||||
from .accountingnode import get_parent_orgid
|
from .accountingnode import get_parent_orgid
|
||||||
from .excep import *
|
from .excep import *
|
||||||
@ -37,10 +38,12 @@ class Accounting:
|
|||||||
get_account(leg,accounting_orgid) 获得记账账号(通过科目,机构类型,账务机构确定一个唯一的账号)
|
get_account(leg,accounting_orgid) 获得记账账号(通过科目,机构类型,账务机构确定一个唯一的账号)
|
||||||
"""
|
"""
|
||||||
def __init__(self, caller):
|
def __init__(self, caller):
|
||||||
|
if isinstance(caller, list):
|
||||||
|
self.callers = caller
|
||||||
|
caller = self.callers[0]
|
||||||
self.caller = caller
|
self.caller = caller
|
||||||
self.curdate = caller.curdate
|
self.curdate = caller.curdate
|
||||||
self.realtimesettled = False
|
self.realtimesettled = False
|
||||||
self.curdte = caller.curdate
|
|
||||||
self.timestamp = caller.timestamp
|
self.timestamp = caller.timestamp
|
||||||
self.billid = caller.billid
|
self.billid = caller.billid
|
||||||
self.action = caller.action
|
self.action = caller.action
|
||||||
@ -53,15 +56,42 @@ class Accounting:
|
|||||||
self.reseller_salemode = None
|
self.reseller_salemode = None
|
||||||
self.variable = caller.variable
|
self.variable = caller.variable
|
||||||
|
|
||||||
|
async def setup_all_accounting_legs(self):
|
||||||
|
self.accounting_legs = []
|
||||||
|
for caller in self.callers:
|
||||||
|
self.caller = caller
|
||||||
|
self.curdate = caller.curdate
|
||||||
|
self.realtimesettled = False
|
||||||
|
self.timestamp = caller.timestamp
|
||||||
|
self.billid = caller.billid
|
||||||
|
self.action = caller.action
|
||||||
|
self.summary = f'{self.caller.orderid}:{self.caller.billid}'
|
||||||
|
self.providerid = caller.providerid
|
||||||
|
self.productid = caller.productid
|
||||||
|
self.resellerid = caller.resellerid
|
||||||
|
self.customerid = caller.customerid
|
||||||
|
self.own_salemode = None
|
||||||
|
self.reseller_salemode = None
|
||||||
|
self.variable = caller.variable
|
||||||
|
self.setup_accounting_legs()
|
||||||
|
legs = sorted(
|
||||||
|
self.accounting_legs,
|
||||||
|
key=lambda x: (
|
||||||
|
x.get('accounting_orgid','0'),
|
||||||
|
x.get('accid', '0'),
|
||||||
|
0 if x.get('acc_dir', '0') == x.get('balance_at', '0') else 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.accounting_legs = legs
|
||||||
|
|
||||||
async def setup_accounting_legs(self):
|
async def setup_accounting_legs(self):
|
||||||
global accounting_config
|
|
||||||
action = self.action.split('_')[0]
|
action = self.action.split('_')[0]
|
||||||
await get_accounting_config(self.sor)
|
acfg = get_accounting_config(self.sor)
|
||||||
self.accounting_legs = [r.copy() for r in accounting_config
|
legs = [r.copy() for r in acfg
|
||||||
if r.action == action ]
|
if r.action == action ]
|
||||||
debug(f'{self.accounting_legs=}')
|
debug(f'{legs=}')
|
||||||
rev = self.action.endswith('_REVERSE')
|
rev = self.action.endswith('_REVERSE')
|
||||||
for l in self.accounting_legs:
|
for l in legs:
|
||||||
if rev:
|
if rev:
|
||||||
l['acc_dir'] = DEBT if l['accounting_dir'] == CREDIT else CREDIT
|
l['acc_dir'] = DEBT if l['accounting_dir'] == CREDIT else CREDIT
|
||||||
else:
|
else:
|
||||||
@ -84,39 +114,55 @@ class Accounting:
|
|||||||
if l['amount'] is None:
|
if l['amount'] is None:
|
||||||
debug(f'amount is None:{l["amt_pattern"]}, {self.variable=},{self.caller.bill=}')
|
debug(f'amount is None:{l["amt_pattern"]}, {self.variable=},{self.caller.bill=}')
|
||||||
raise AccountingAmountIsNone(self.caller.billid)
|
raise AccountingAmountIsNone(self.caller.billid)
|
||||||
|
accounting_orgid = await self.caller.get_orgid_by_trans_role(sor, l, l.accounting_orgtype)
|
||||||
|
orgid = await self.caller.get_orgid_by_trans_role(sor, l, l.orgtype)
|
||||||
|
org1id = None if l.org1type is None else \
|
||||||
|
await self.caller.get_orgid_by_trans_role(sor, l, l.org1type)
|
||||||
|
acc = await get_account(sor, accounting_orgid, orgid, l.subjectid, org1id=org1id)
|
||||||
|
if acc is None:
|
||||||
|
debug(f'can not get accountid {accounting_orgid=}, {orgid=},{l.subjectid=}, {org1id=}')
|
||||||
|
raise AccountIdNone(accounting_orgid, orgid, l['subjectid'])
|
||||||
|
l['accounting_orgid'] = accounting_orgid
|
||||||
|
l['orgid'] = orgid
|
||||||
|
l['org1id'] = org1id
|
||||||
|
l['accid'] = acc.id
|
||||||
|
l['balance_at'] = acc.balance_at
|
||||||
|
l['acc'] = acc
|
||||||
|
self.accounting_legs += legs
|
||||||
|
|
||||||
def check_accounting_balance(self, legs):
|
def check_accounting_balance(self, legs):
|
||||||
debt_balance = 0.0
|
debt_balance = 0.0
|
||||||
credit_balance = 0.0
|
credit_balance = 0.0
|
||||||
|
curacc = None
|
||||||
|
acc_balance = 0.00
|
||||||
for l in legs:
|
for l in legs:
|
||||||
|
if l['accid'] != curacc:
|
||||||
|
curacc = l['accid']
|
||||||
|
acc_balance = l['acc'].balance
|
||||||
|
if l['acc_dir'] != l['balance_at']:
|
||||||
|
acc_balance -= l['amount']
|
||||||
|
else:
|
||||||
|
acc_balance += l['amount']
|
||||||
|
if acc_balance < 0.000000:
|
||||||
|
e = AccountOverDraw(curacc, acc['balance'], leg['amount'])
|
||||||
|
exception(f'{e},{legs=}')
|
||||||
|
raise e
|
||||||
|
l['new_balance'] = acc_balance
|
||||||
if l['acc_dir'] == DEBT:
|
if l['acc_dir'] == DEBT:
|
||||||
debt_balance += l['amount']
|
debt_balance += l['amount']
|
||||||
else:
|
else:
|
||||||
credit_balance += l['amount']
|
credit_balance += l['amount']
|
||||||
if abs(credit_balance - debt_balance) >= 0.01:
|
if abs(credit_balance - debt_balance) >= 0.00001:
|
||||||
e = Exception('accounting legs not balance')
|
e = Exception('accounting legs not balance')
|
||||||
exception(f'{legs=}, {e=}')
|
exception(f'{legs=}, {e=}')
|
||||||
raise e
|
raise e
|
||||||
|
|
||||||
async def do_accounting(self, sor):
|
async def do_accounting(self, sor):
|
||||||
self.sor = sor
|
self.sor = sor
|
||||||
|
|
||||||
await self.setup_accounting_legs()
|
await self.setup_accounting_legs()
|
||||||
debug(f'do_accounting() ...{self.accounting_legs=}')
|
debug(f'do_accounting() ...{self.accounting_legs=}')
|
||||||
self.check_accounting_balance(self.accounting_legs)
|
self.check_accounting_balance(self.accounting_legs)
|
||||||
for leg in self.accounting_legs:
|
for leg in self.accounting_legs:
|
||||||
accounting_orgid = await self.caller.get_orgid_by_trans_role(sor, leg, leg.accounting_orgtype)
|
|
||||||
orgid = await self.caller.get_orgid_by_trans_role(sor, leg, leg.orgtype)
|
|
||||||
org1id = None if leg.org1type is None else \
|
|
||||||
await self.caller.get_orgid_by_trans_role(sor, leg, leg.org1type)
|
|
||||||
acc = await get_account(sor, accounting_orgid, orgid, leg.subjectid, org1id=org1id)
|
|
||||||
if acc is None:
|
|
||||||
debug(f'can not get accountid {accounting_orgid=}, {orgid=},{leg.subjectid=}, {org1id=}')
|
|
||||||
raise AccountIdNone(accounting_orgid, orgid, leg['subjectid'])
|
|
||||||
leg['accounting_orgid'] = accounting_orgid
|
|
||||||
leg['orgid'] = orgid
|
|
||||||
leg['org1id'] = org1id
|
|
||||||
leg['acc'] = acc
|
|
||||||
await self.leg_accounting(sor, acc.id, leg)
|
await self.leg_accounting(sor, acc.id, leg)
|
||||||
|
|
||||||
async def write_settle_log(self):
|
async def write_settle_log(self):
|
||||||
@ -137,52 +183,10 @@ class Accounting:
|
|||||||
sor = self.sor
|
sor = self.sor
|
||||||
await sor.C('settle_log', ns)
|
await sor.C('settle_log', ns)
|
||||||
|
|
||||||
async def overdraw_check(self, sor, accid, leg, tryAgain=True):
|
|
||||||
if accid is None:
|
|
||||||
raise AccountIdNone()
|
|
||||||
|
|
||||||
sql0 = "select max(acc_date) as acc_date from acc_balance where accountid=${accid}$"
|
|
||||||
recs = await sor.sqlExe(sql0, {'accid':accid})
|
|
||||||
acc_date = recs[0]['acc_date']
|
|
||||||
bal = {}
|
|
||||||
if acc_date is not None:
|
|
||||||
if acc_date > self.curdate:
|
|
||||||
raise FutureAccountingExist(accid, self.curdate, acc_date)
|
|
||||||
ns={'accid':accid, 'acc_date':acc_date}
|
|
||||||
r = await sor.sqlExe("""select * from acc_balance
|
|
||||||
where accountid=${accid}$
|
|
||||||
and acc_date = ${acc_date}$""", ns.copy())
|
|
||||||
if len(r) > 0:
|
|
||||||
bal = r[0]
|
|
||||||
|
|
||||||
accs = await sor.R('account', {'id':accid})
|
|
||||||
if len(accs) == 0:
|
|
||||||
raise AccountNoFound(accid)
|
|
||||||
|
|
||||||
acc = accs[0]
|
|
||||||
acc['acc_date'] = self.curdate
|
|
||||||
acc['balance'] = bal.get('balance', 0)
|
|
||||||
|
|
||||||
if acc.get('balance') is None:
|
|
||||||
acc['balance'] = 0
|
|
||||||
if acc['balance_at'] == DEBT and leg['acc_dir'] == CREDIT \
|
|
||||||
or acc['balance_at'] == CREDIT and leg['acc_dir'] == DEBT:
|
|
||||||
if int(acc['balance']*10000) - int(leg['amount']*10000) < 0:
|
|
||||||
if tryAgain:
|
|
||||||
await asyncio.sleep(1.5);
|
|
||||||
return await self.overdraw_check(sor, accid, leg, tryAgain=False)
|
|
||||||
else:
|
|
||||||
print(f"{acc['balance_at']=}, {leg=}")
|
|
||||||
raise AccountOverDraw(accid, acc['balance'], leg['amount'])
|
|
||||||
leg['new_balance'] = acc['balance'] - leg['amount']
|
|
||||||
else:
|
|
||||||
leg['new_balance'] = acc['balance'] + leg['amount']
|
|
||||||
|
|
||||||
async def leg_accounting(self, sor, accid, leg):
|
async def leg_accounting(self, sor, accid, leg):
|
||||||
# print(f'leg_accounting(), {accid=}, {leg=}')
|
# print(f'leg_accounting(), {accid=}, {leg=}')
|
||||||
if leg['amount'] < 0.0001:
|
if leg['amount'] < 0.00001:
|
||||||
return
|
return
|
||||||
await self.overdraw_check(sor, accid, leg)
|
|
||||||
subjects = await sor.R('subject', {'id': leg['subjectid']})
|
subjects = await sor.R('subject', {'id': leg['subjectid']})
|
||||||
if len(subjects) > 0:
|
if len(subjects) > 0:
|
||||||
leg['subjectname'] = subjects[0].name
|
leg['subjectname'] = subjects[0].name
|
||||||
|
|||||||
@ -5,15 +5,19 @@ from .const import *
|
|||||||
from accounting.accountingnode import get_parent_orgid
|
from accounting.accountingnode import get_parent_orgid
|
||||||
|
|
||||||
async def get_account(sor, accounting_orgid, orgid, subjectid, org1id=None):
|
async def get_account(sor, accounting_orgid, orgid, subjectid, org1id=None):
|
||||||
ss = "org1id is NULL"
|
ss = "a.org1id is NULL"
|
||||||
if org1id:
|
if org1id:
|
||||||
ss = "org1id = ${org1id}$"
|
ss = "a.org1id = ${org1id}$"
|
||||||
|
|
||||||
sql = """select * from account
|
sql = """select
|
||||||
where
|
a.*,
|
||||||
subjectid = ${subjectid}$ and
|
case when c.balance is null then 0.00 else c.balance end as balance
|
||||||
accounting_orgid = ${accounting_orgid}$ and
|
from account a left join acc_balance b
|
||||||
orgid = ${orgid}$ and
|
on a.id = b.accountid
|
||||||
|
where
|
||||||
|
a.subjectid = ${subjectid}$ and
|
||||||
|
a.accounting_orgid = ${accounting_orgid}$ and
|
||||||
|
a.orgid = ${orgid}$ and
|
||||||
""" + ss
|
""" + ss
|
||||||
ns = {
|
ns = {
|
||||||
"accounting_orgid":accounting_orgid,
|
"accounting_orgid":accounting_orgid,
|
||||||
|
|||||||
@ -16,12 +16,22 @@ async def all_my_accounts(request):
|
|||||||
userid = await env.get_user()
|
userid = await env.get_user()
|
||||||
userorgid = await env.get_userorgid()
|
userorgid = await env.get_userorgid()
|
||||||
async with get_sor_context(request._run_ns, 'accounting') as sor:
|
async with get_sor_context(request._run_ns, 'accounting') as sor:
|
||||||
sql = """select b.id, a.name, b.balance_at, c.balance from
|
sql = """select
|
||||||
subject a, account b,
|
b.id,
|
||||||
(select a.* from acc_balance a, (select accountid, max(acc_date) max_date from acc_balance group by accountid) b where a.accountid=b.accountid and a.acc_date=b.max_date) c
|
a.name,
|
||||||
where c.accountid = b.id
|
b.balance_at,
|
||||||
and b.subjectid = a.id
|
case when c.balance is null then 0.00 else c.balance end as balance
|
||||||
and b.orgid = ${orgid}$
|
from
|
||||||
|
subject a,
|
||||||
|
account b left join
|
||||||
|
(
|
||||||
|
select a.*
|
||||||
|
from acc_balance a,
|
||||||
|
(select accountid, max(acc_date) max_date from acc_balance group by accountid) b
|
||||||
|
where a.accountid=b.accountid and a.acc_date=b.max_date
|
||||||
|
) c on c.accountid = b.id
|
||||||
|
where b.subjectid = a.id
|
||||||
|
and b.orgid = ${orgid}$
|
||||||
"""
|
"""
|
||||||
ns = {'orgid': userorgid}
|
ns = {'orgid': userorgid}
|
||||||
recs = await sor.sqlExe(sql, ns)
|
recs = await sor.sqlExe(sql, ns)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user