Compare commits
No commits in common. "cecb0d9e735769946de3f518f9054ac3a041057b" and "b8485b8100ffee6f0a691f48e34574b66ea0d4cc" have entirely different histories.
cecb0d9e73
...
b8485b8100
@ -1,433 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
import re
|
|
||||||
from .const import *
|
|
||||||
from .accountingnode import get_parent_orgid
|
|
||||||
from .excep import *
|
|
||||||
from .getaccount import getAccountByName
|
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
from appPublic.timeUtils import curDateString
|
|
||||||
from .argsconvert import ArgsConvert
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
accounting_config = None
|
|
||||||
|
|
||||||
async def get_accounting_config(sor):
|
|
||||||
global accounting_config
|
|
||||||
if accounting_config:
|
|
||||||
return accounting_config
|
|
||||||
recs = await sor.R('accounting_config', {})
|
|
||||||
if len(recs) > 0:
|
|
||||||
accounting_config = recs
|
|
||||||
return accounting_config
|
|
||||||
return None
|
|
||||||
|
|
||||||
class AccountingOrgs:
|
|
||||||
def __init__(self, caller,
|
|
||||||
accounting_orgid,
|
|
||||||
customerid,
|
|
||||||
dbname=DBNAME,
|
|
||||||
resellerid=None
|
|
||||||
):
|
|
||||||
self.caller = caller
|
|
||||||
self.dbname = dbname
|
|
||||||
self.curdate = caller.curdate
|
|
||||||
self.realtimesettled = False
|
|
||||||
self.curdte = caller.curdate
|
|
||||||
self.timestamp = caller.timestamp
|
|
||||||
self.billid = caller.billid
|
|
||||||
self.action = caller.action
|
|
||||||
# self.summary = self.action
|
|
||||||
self.providerid = caller.providerid
|
|
||||||
self.productid = caller.productid
|
|
||||||
self.accounting_orgid = accounting_orgid
|
|
||||||
self.resellerid = resellerid
|
|
||||||
self.customerid = customerid
|
|
||||||
self.own_salemode = None
|
|
||||||
self.reseller_salemode = None
|
|
||||||
self.variable = {
|
|
||||||
'交易金额':self.caller.transamount
|
|
||||||
}
|
|
||||||
self.salemode_sql0 = """
|
|
||||||
select a.*, b.providerid, b.productid, b.discount, b.price
|
|
||||||
from saleprotocol a, product_salemode b
|
|
||||||
where a.id = b.protocolid
|
|
||||||
and a.bid_orgid=${bid_orgid}$
|
|
||||||
and (b.productid=${productid}$ or b.productid = '*')
|
|
||||||
and b.providerid = ${providerid}$
|
|
||||||
and a.start_date <= ${curdate}$
|
|
||||||
and a.end_date > ${curdate}$
|
|
||||||
order by productid desc
|
|
||||||
"""
|
|
||||||
self.salemode_sql = """
|
|
||||||
select a.*, b.providerid, b.productid, b.discount, b.price
|
|
||||||
from saleprotocol a, product_salemode b
|
|
||||||
where a.id = b.protocolid
|
|
||||||
and a.offer_orgid=${offer_orgid}$
|
|
||||||
and b.providerid = ${providerid}$
|
|
||||||
and a.bid_orgid=${bid_orgid}$
|
|
||||||
and (b.productid=${productid}$ or b.productid = '*')
|
|
||||||
and a.start_date <= ${curdate}$
|
|
||||||
and a.end_date > ${curdate}$
|
|
||||||
order by productid desc
|
|
||||||
"""
|
|
||||||
|
|
||||||
async def is_business_owner(self):
|
|
||||||
sor = self.sor
|
|
||||||
recs = await sor.sqlExe("select * from organization where id=${orgid}$ and parentid is null",
|
|
||||||
{'orgid':self.accounting_orgid})
|
|
||||||
if len(recs) > 0:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
async def check_add_realtime_settle_legs(self):
|
|
||||||
sor = self.sor
|
|
||||||
if self.settle_mode == '0':
|
|
||||||
await self.add_online_settle_legs()
|
|
||||||
print('settle legs added ....')
|
|
||||||
else:
|
|
||||||
print(f'{self.providerid=}')
|
|
||||||
|
|
||||||
async def add_online_settle_legs(self):
|
|
||||||
specstr = ACTNAME_SETTLE + '-' + self.own_salemode + '-实时'
|
|
||||||
ls = [r.copy() for r in accounting_config if r['specstr'] == specstr ]
|
|
||||||
for l in ls:
|
|
||||||
if self.action.endswith('_REVERSE'):
|
|
||||||
l['summary'] = 'SETTLE_REVERSE'
|
|
||||||
else:
|
|
||||||
l['summary'] = 'SETTLE'
|
|
||||||
|
|
||||||
self.accounting_legs += ls
|
|
||||||
self.realtimesettled = True
|
|
||||||
|
|
||||||
async def setup_accounting_legs(self):
|
|
||||||
global accounting_config
|
|
||||||
specstr = await self.get_act_specstr()
|
|
||||||
self.specstr = specstr
|
|
||||||
await get_accounting_config(self.sor)
|
|
||||||
aorgtype = '客户所在机构'
|
|
||||||
if self.resellerid:
|
|
||||||
aorgtype = '分销商机构'
|
|
||||||
if self.specstr.startswith(ACTNAME_SETTLE):
|
|
||||||
self.accounting_legs = [r.copy() for r in accounting_config
|
|
||||||
if r['specstr'] == specstr ]
|
|
||||||
else:
|
|
||||||
self.accounting_legs = [r.copy() for r in accounting_config
|
|
||||||
if r['specstr'] == specstr
|
|
||||||
and r['accounting_orgtype'] == aorgtype]
|
|
||||||
for l in self.accounting_legs:
|
|
||||||
l['summary'] = self.action
|
|
||||||
|
|
||||||
if self.specstr.startswith(ACTNAME_BUY):
|
|
||||||
await self.check_add_realtime_settle_legs()
|
|
||||||
else:
|
|
||||||
print(f'{self.specstr} is notstartswith {ACTNAME_BUY}')
|
|
||||||
|
|
||||||
print(f'setup_accounting_legs():{self.specstr}')
|
|
||||||
rev = self.action.endswith('_REVERSE')
|
|
||||||
for l in self.accounting_legs:
|
|
||||||
if rev:
|
|
||||||
l['acc_dir'] = '0' if l['accounting_dir'] == CREDIT else '1'
|
|
||||||
else:
|
|
||||||
l['acc_dir'] = '0' if l['accounting_dir'] == DEBT else '1'
|
|
||||||
ac = ArgsConvert('${', '}$')
|
|
||||||
print(f'{l["id"]},{l["amt_pattern"]=}')
|
|
||||||
try:
|
|
||||||
l['amount'] = eval(await ac.convert(
|
|
||||||
l['amt_pattern'],
|
|
||||||
self.variable.copy(),
|
|
||||||
default=self.localamount))
|
|
||||||
except Exception as e:
|
|
||||||
print(l['amt_pattern'], l['id'], self.variable)
|
|
||||||
raise e
|
|
||||||
|
|
||||||
if l['amount'] is None:
|
|
||||||
print(f'amount is None:{l["amt_pattern"]}, {self.variable=},{self.caller.bill=}')
|
|
||||||
raise AccountingAmountIsNone(self.caller.billid)
|
|
||||||
|
|
||||||
async def setup_bill_variable(self):
|
|
||||||
"""
|
|
||||||
'本方折扣'
|
|
||||||
'客户折扣'
|
|
||||||
'分销商折扣'
|
|
||||||
'进价'
|
|
||||||
'客户售价'
|
|
||||||
'分销商售价'
|
|
||||||
"""
|
|
||||||
sor = self.sor
|
|
||||||
recs = await sor.sqlExe(self.salemode_sql0, {
|
|
||||||
'bid_orgid':self.accounting_orgid,
|
|
||||||
'providerid':self.providerid,
|
|
||||||
'productid':self.productid,
|
|
||||||
'curdate':self.curdate})
|
|
||||||
if len(recs) == 0:
|
|
||||||
raise ProductBidProtocolNotDefined(None, self.accounting_orgid,
|
|
||||||
self.providerid,
|
|
||||||
self.productid,
|
|
||||||
self.curdate
|
|
||||||
)
|
|
||||||
rec = recs[0]
|
|
||||||
self.settle_mode = rec['settle_mode']
|
|
||||||
self.quantity = self.caller.bill['quantity']
|
|
||||||
salemode=rec['salemode']
|
|
||||||
if salemode == '0':
|
|
||||||
self.variable['本方折扣'] = rec['discount']
|
|
||||||
elif salemode == '2':
|
|
||||||
self.variable['进价'] = rec['price'] * self.quantity
|
|
||||||
|
|
||||||
recs = await sor.sqlExe(self.salemode_sql, {
|
|
||||||
'offer_orgid':self.accounting_orgid,
|
|
||||||
'bid_orgid':self.customerid,
|
|
||||||
'providerid':self.providerid,
|
|
||||||
'productid':self.productid,
|
|
||||||
'curdate':self.curdate})
|
|
||||||
if len(recs) == 0:
|
|
||||||
recs = await sor.sqlExe(self.salemode_sql, {
|
|
||||||
'offer_orgid':self.accounting_orgid,
|
|
||||||
'bid_orgid':'*',
|
|
||||||
'providerid':self.providerid,
|
|
||||||
'productid':self.productid,
|
|
||||||
'curdate':self.curdate})
|
|
||||||
print(f'get customer price or discount, {recs=}')
|
|
||||||
if len(recs) == 0:
|
|
||||||
raise ProductBidProtocolNotDefined(None, self.customerid,
|
|
||||||
self.providerid,
|
|
||||||
self.productid,
|
|
||||||
self.curdate
|
|
||||||
)
|
|
||||||
rec = recs[0]
|
|
||||||
salemode=rec['salemode']
|
|
||||||
if salemode == '0':
|
|
||||||
self.variable['客户折扣'] = rec['discount']
|
|
||||||
elif salemode == '2':
|
|
||||||
self.variable['客户售价'] = rec['price'] * self.quantity
|
|
||||||
|
|
||||||
if self.resellerid:
|
|
||||||
recs = await sor.sqlExe(self.salemode_sql, {
|
|
||||||
'offer_orgid':self.accounting_orgid,
|
|
||||||
'bid_orgid':self.resellerid,
|
|
||||||
'providerid':self.providerid,
|
|
||||||
'productid':self.productid,
|
|
||||||
'curdate':self.curdate})
|
|
||||||
if len(recs) == 0:
|
|
||||||
raise ProductBidProtocolNotDefined(None, self.resellerid,
|
|
||||||
self.providerid,
|
|
||||||
self.productid,
|
|
||||||
self.curdate
|
|
||||||
)
|
|
||||||
rec = recs[0]
|
|
||||||
salemode=rec['salemode']
|
|
||||||
if salemode == '0':
|
|
||||||
self.variable['分销商折扣'] = rec['discount']
|
|
||||||
elif salemode == '2':
|
|
||||||
self.variable['分销商售价'] = rec['price'] * self.quantity
|
|
||||||
|
|
||||||
async def localamount(self, name):
|
|
||||||
a = name.split('-')
|
|
||||||
if len(a) == 3:
|
|
||||||
for l in self.accounting_legs:
|
|
||||||
if a[0] == l['accounting_dir'] and \
|
|
||||||
a[1] == l['orgtype'] and \
|
|
||||||
a[2] == l['subjectname']:
|
|
||||||
return l['amount']
|
|
||||||
if name[0] == '#':
|
|
||||||
i = int(name[1:])
|
|
||||||
return self.accounting_legs[i]['amount']
|
|
||||||
|
|
||||||
print(f'{name} not found')
|
|
||||||
|
|
||||||
async def do_accounting(self, sor):
|
|
||||||
self.sor = sor
|
|
||||||
|
|
||||||
await self.setup_accounting_legs()
|
|
||||||
print('do_accounting() ...', self.accounting_legs)
|
|
||||||
for leg in self.accounting_legs:
|
|
||||||
orgid = self.accounting_orgid
|
|
||||||
if leg['orgtype'] == '客户':
|
|
||||||
orgid = self.customerid
|
|
||||||
elif leg['orgtype'] == '分销商':
|
|
||||||
orgid = self.resellerid
|
|
||||||
elif leg['orgtype'] == '供应商':
|
|
||||||
orgid = self.providerid
|
|
||||||
accid = await getAccountByName(sor,
|
|
||||||
self.accounting_orgid,
|
|
||||||
orgid,
|
|
||||||
leg['subjectname'])
|
|
||||||
if accid is None:
|
|
||||||
print('can not get accountid', self.accounting_orgid, orgid, leg['subjectname'], leg['id'])
|
|
||||||
raise AccountIdNone(self.accounting_orgid, orgid, leg['subjectname'])
|
|
||||||
leg['orgid'] = orgid
|
|
||||||
await self.leg_accounting(sor, accid, leg)
|
|
||||||
if self.realtimesettled:
|
|
||||||
x = await self.is_business_owner()
|
|
||||||
if x:
|
|
||||||
await self.write_settle_log()
|
|
||||||
|
|
||||||
async def write_settle_log(self):
|
|
||||||
sale_mode = {
|
|
||||||
SALEMODE_DISCOUNT:'0',
|
|
||||||
SALEMODE_REBATE:'1',
|
|
||||||
SALEMODE_FLOORPRICE:'2'
|
|
||||||
}
|
|
||||||
ns = {
|
|
||||||
'id':getID(),
|
|
||||||
'accounting_orgid':self.accounting_orgid,
|
|
||||||
'providerid':self.providerid,
|
|
||||||
'sale_mode':sale_mode.get(self.own_salemode),
|
|
||||||
'settle_date':self.curdate,
|
|
||||||
'settle_amt':self.accounting_legs[-1]['amount']
|
|
||||||
}
|
|
||||||
|
|
||||||
sor = self.sor
|
|
||||||
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'] == '0' and leg['acc_dir'] == '1' \
|
|
||||||
or acc['balance_at'] == '1' and leg['acc_dir'] == '0':
|
|
||||||
if int(acc['balance']*100) - int(leg['amount']*100) < 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):
|
|
||||||
# print(f'leg_accounting(), {accid=}, {leg=}')
|
|
||||||
await self.overdraw_check(sor, accid, leg)
|
|
||||||
# write acc_balance
|
|
||||||
sql = """select * from acc_balance
|
|
||||||
where accountid=${accid}$
|
|
||||||
and acc_date = ${curdate}$"""
|
|
||||||
recs = await sor.sqlExe(sql, {'accid':accid, 'curdate':self.curdate})
|
|
||||||
if len(recs) == 0:
|
|
||||||
ns = {
|
|
||||||
'id':getID(),
|
|
||||||
'accountid':accid,
|
|
||||||
'acc_date':self.curdate,
|
|
||||||
'balance':leg['new_balance']
|
|
||||||
}
|
|
||||||
await sor.C('acc_balance', ns.copy())
|
|
||||||
else:
|
|
||||||
ns = recs[0]
|
|
||||||
ns['balance'] = leg['new_balance']
|
|
||||||
await sor.U('acc_balance', ns.copy())
|
|
||||||
|
|
||||||
# summary = self.summary
|
|
||||||
ns = {
|
|
||||||
'id':getID(),
|
|
||||||
'accounting_orgid' : self.accounting_orgid,
|
|
||||||
'billid' : self.billid,
|
|
||||||
'description' : self.specstr,
|
|
||||||
'participantid' : leg['orgid'],
|
|
||||||
'participanttype' : leg['orgtype'],
|
|
||||||
'subjectname' : leg['subjectname'],
|
|
||||||
'accounting_dir': leg['accounting_dir'],
|
|
||||||
'amount' : leg['amount']
|
|
||||||
}
|
|
||||||
await sor.C('bill_detail', ns)
|
|
||||||
logid = getID()
|
|
||||||
ns = {
|
|
||||||
'id':logid,
|
|
||||||
'accountid':accid,
|
|
||||||
'acc_date':self.curdte,
|
|
||||||
'acc_timestamp':self.timestamp,
|
|
||||||
'acc_dir':leg['acc_dir'],
|
|
||||||
'summary':leg['summary'],
|
|
||||||
'amount':leg['amount'],
|
|
||||||
'billid':self.billid
|
|
||||||
}
|
|
||||||
await sor.C('accounting_log', ns.copy())
|
|
||||||
ns = {
|
|
||||||
'id':getID(),
|
|
||||||
'accountid':accid,
|
|
||||||
'acc_date':self.curdate,
|
|
||||||
'acc_timestamp':self.timestamp,
|
|
||||||
'acc_dir':leg['acc_dir'],
|
|
||||||
'summary':leg['summary'],
|
|
||||||
'amount':leg['amount'],
|
|
||||||
'balance':leg['new_balance'],
|
|
||||||
'acclogid':logid
|
|
||||||
}
|
|
||||||
await sor.C('acc_detail', ns.copy())
|
|
||||||
|
|
||||||
async def get_reseller_salemode(self, orgid):
|
|
||||||
sor = self.sor
|
|
||||||
recs = await sor.sqlExe(self.salemode_sql0,
|
|
||||||
{
|
|
||||||
'bid_orgid':orgid,
|
|
||||||
'providerid':self.providerid,
|
|
||||||
'productid':self.productid,
|
|
||||||
'curdate':self.curdate
|
|
||||||
})
|
|
||||||
if len(recs) == 0:
|
|
||||||
return None
|
|
||||||
return recs[0]['salemode']
|
|
||||||
|
|
||||||
async def get_act_specstr(self):
|
|
||||||
sor = self.sor
|
|
||||||
if self.action in [ ACTION_RECHARGE, ACTION_RECHARGE_REVERSE ]:
|
|
||||||
return ACTNAME_RECHARGE
|
|
||||||
|
|
||||||
if self.action in [ ACTION_SETTLE, ACTION_SETTLE_REVERSE ]:
|
|
||||||
spec = ACTNAME_SETTLE
|
|
||||||
if self.caller.sale_mode == '0':
|
|
||||||
spec = f'{ACTNAME_SETTLE}-{SALEMODE_DISCOUNT}'
|
|
||||||
elif self.caller.sale_mode == '1':
|
|
||||||
spec = f'{ACTNAME_SETTLE}-{SALEMODE_REBATE}'
|
|
||||||
else:
|
|
||||||
spec = f'{ACTNAME_SETTLE}-{SALEMODE_FLOORPRICE}'
|
|
||||||
return spec
|
|
||||||
|
|
||||||
|
|
||||||
ret = ACTNAME_BUY
|
|
||||||
for id in [self.accounting_orgid, self.resellerid]:
|
|
||||||
if id is None:
|
|
||||||
break
|
|
||||||
salemode = await self.get_reseller_salemode(id)
|
|
||||||
if salemode == '0':
|
|
||||||
sale_mode = SALEMODE_DISCOUNT
|
|
||||||
elif salemode == '1':
|
|
||||||
sale_mode = SALEMODE_REBATE
|
|
||||||
else:
|
|
||||||
sale_mode = SALEMODE_FLOORPRICE
|
|
||||||
|
|
||||||
ret += '-' + sale_mode
|
|
||||||
if id == self.accounting_orgid:
|
|
||||||
self.own_salemode = sale_mode
|
|
||||||
else:
|
|
||||||
self.reseller_salemode = sale_mode
|
|
||||||
await self.setup_bill_variable()
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
|||||||
from .const import *
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
|
|
||||||
async def get_parent_orgid(sor, orgid):
|
|
||||||
sql = """select a.id from organization a, organization b
|
|
||||||
where b.parentid = a.id
|
|
||||||
and b.id = ${orgid}$"""
|
|
||||||
recs = await sor.sqlExe(sql, {'orgid':orgid})
|
|
||||||
if len(recs) == 0:
|
|
||||||
return None
|
|
||||||
return recs[0]['id']
|
|
||||||
|
|
||||||
async def get_offer_orgid(sor, bid_orgid, providerid, productid, curdate):
|
|
||||||
sql = """select a.offer_orgid from saleprotocol a, product_salemode b
|
|
||||||
where a.id = b.protocolid
|
|
||||||
and a.bid_orgid = ${bid_orgid}$
|
|
||||||
and b.providerid = ${providerid}$
|
|
||||||
and b.productid in (${productid}$, '*')
|
|
||||||
and a.start_date <= ${curdate}$
|
|
||||||
and a.end_date > ${curdate}$
|
|
||||||
"""
|
|
||||||
recs = await sor.sqlExe(sql, {
|
|
||||||
'bid_orgid':bid_orgid,
|
|
||||||
'providerid':providerid,
|
|
||||||
'productid':productid,
|
|
||||||
'curdate':curdate
|
|
||||||
})
|
|
||||||
if len(recs) == 0:
|
|
||||||
return None
|
|
||||||
rec = recs[0]
|
|
||||||
return rec['offer_orgid']
|
|
||||||
|
|
||||||
async def get_offer_orgs(sor, bid_orgid, providerid, productid, curdate):
|
|
||||||
offer_orgid = await get_offer_orgid(sor, bid_orgid, providerid,
|
|
||||||
productid, curdate)
|
|
||||||
if offer_orgid is None or offer_orgid == providerid:
|
|
||||||
return []
|
|
||||||
myids = [offer_orgid]
|
|
||||||
orgs = await get_offer_orgs(sor, offer_orgid,
|
|
||||||
providerid,
|
|
||||||
productid,
|
|
||||||
curdate)
|
|
||||||
return orgs + myids
|
|
||||||
|
|
||||||
async def get_ancestor_orgs(sor, orgid):
|
|
||||||
id = await get_parent_orgid(sor, orgid)
|
|
||||||
if not id:
|
|
||||||
return []
|
|
||||||
ret = await get_ancestor_orgs(sor, id)
|
|
||||||
return ret + [id]
|
|
||||||
|
|
||||||
async def get_accounting_nodes(sor, customerid):
|
|
||||||
"""
|
|
||||||
gt all accounting organization for transactes customer orgid
|
|
||||||
"""
|
|
||||||
sql = """select a.id from organization a, organization b
|
|
||||||
where b.parentid = a.id
|
|
||||||
and b.id = ${customerid}$
|
|
||||||
and b.org_type in ('2','3')"""
|
|
||||||
recs = await sor.sqlExe(sql, {'customerid':customerid})
|
|
||||||
if len(recs) == 0:
|
|
||||||
return []
|
|
||||||
ret = await get_ancestor_orgs(sor, recs[0]['id'])
|
|
||||||
ret.append(recs[0]['id'])
|
|
||||||
return ret
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,55 +0,0 @@
|
|||||||
|
|
||||||
from datetime import datetime
|
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
from appPublic.timeUtils import curDateString
|
|
||||||
from appPublic.argsConvert import ArgsConvert
|
|
||||||
from .accounting_config import get_accounting_config, AccountingOrgs
|
|
||||||
from .const import *
|
|
||||||
from .accountingnode import get_accounting_nodes
|
|
||||||
from .excep import *
|
|
||||||
from .getaccount import getAccountByName
|
|
||||||
from .businessdate import get_business_date
|
|
||||||
from .recharge import RechargeAccounting
|
|
||||||
|
|
||||||
class AlipayAccountingOrgs(AccountingOrgs):
|
|
||||||
def __init__(self, caller,
|
|
||||||
accounting_orgid,
|
|
||||||
customerid,
|
|
||||||
resellerid=None):
|
|
||||||
|
|
||||||
super(AlipayAccountingOrgs, self). __init__(caller,
|
|
||||||
accounting_orgid,
|
|
||||||
customerid,
|
|
||||||
resellerid=resellerid)
|
|
||||||
self.variable['手续费'] = self.caller.fee_amt
|
|
||||||
|
|
||||||
async def get_act_specstr(self):
|
|
||||||
return ACTNAME_RECHARGE_ALIPAY
|
|
||||||
|
|
||||||
class AlipayRechargeAccounting(RechargeAccounting):
|
|
||||||
def __init__(self, recharge_log):
|
|
||||||
super(AlipayRechargeAccounting, self).__init__(recharge_log)
|
|
||||||
self.fee_amt = recharge_log['fee_amt']
|
|
||||||
|
|
||||||
async def accounting(self, sor):
|
|
||||||
self.sor = sor
|
|
||||||
bz_date = await get_business_date(sor=sor)
|
|
||||||
if bz_date != self.curdate:
|
|
||||||
raise AccountingDateNotInBusinessDate(self.curdate, bz_date)
|
|
||||||
|
|
||||||
nodes = await get_accounting_nodes(sor, self.customerid)
|
|
||||||
lst = len(nodes) - 1
|
|
||||||
self.accountingOrgs = []
|
|
||||||
for i, n in enumerate(nodes):
|
|
||||||
if i < lst:
|
|
||||||
ao = AlipayAccountingOrgs(self, nodes[i], self.customerid,
|
|
||||||
resellerid=nodes[i+1])
|
|
||||||
else:
|
|
||||||
ao = AlipayAccountingOrgs(self, nodes[i], self.customerid)
|
|
||||||
self.accountingOrgs.append(ao)
|
|
||||||
await self.write_bill(sor)
|
|
||||||
[await ao.do_accounting(sor) for ao in self.accountingOrgs ]
|
|
||||||
print(f'recharge ok for {self.bill}, {nodes=}')
|
|
||||||
return True
|
|
||||||
|
|
@ -1,95 +0,0 @@
|
|||||||
# -*- coding:utf8 -*-
|
|
||||||
import re
|
|
||||||
class ConvertException(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class ArgsConvert(object):
|
|
||||||
def __init__(self,preString,subfixString,coding='utf-8'):
|
|
||||||
self.preString = preString
|
|
||||||
self.subfixString = subfixString
|
|
||||||
self.coding=coding
|
|
||||||
sl1 = [ u'\\' + c for c in self.preString ]
|
|
||||||
sl2 = [ u'\\' + c for c in self.subfixString ]
|
|
||||||
ps = u''.join(sl1)
|
|
||||||
ss = u''.join(sl2)
|
|
||||||
re1 = ps + r"[_a-zA-Z_\u4e00-\u9fa5][a-zA-Z_0-9\u4e00-\u9fa5\,\.\'\{\}\[\]\(\)\-\+\*\/]*" + ss
|
|
||||||
self.re1 = re1
|
|
||||||
# print( self.re1,len(self.re1),len(re1),type(self.re1))
|
|
||||||
|
|
||||||
async def convert(self,obj,namespace,default=''):
|
|
||||||
""" obj can be a string,[],or dictionary """
|
|
||||||
if type(obj) == type(b''):
|
|
||||||
return await self.convertBytes(obj,namespace,default)
|
|
||||||
if type(obj) == type(''):
|
|
||||||
return await self.convertString(obj,namespace,default)
|
|
||||||
if type(obj) == type([]):
|
|
||||||
ret = []
|
|
||||||
for o in obj:
|
|
||||||
ret.append(await self.convert(o,namespace,default))
|
|
||||||
return ret
|
|
||||||
if type(obj) == type({}):
|
|
||||||
ret = {}
|
|
||||||
for k in obj.keys():
|
|
||||||
ret.update({k:await self.convert(obj.get(k),namespace,default)})
|
|
||||||
return ret
|
|
||||||
# print( type(obj),"not converted")
|
|
||||||
return obj
|
|
||||||
|
|
||||||
def findAllVariables(self,src):
|
|
||||||
r = []
|
|
||||||
for ph in re.findall(self.re1,src):
|
|
||||||
dl = self.getVarName(ph)
|
|
||||||
r.append(dl)
|
|
||||||
return r
|
|
||||||
|
|
||||||
def getVarName(self,vs):
|
|
||||||
return vs[len(self.preString):-len(self.subfixString)]
|
|
||||||
|
|
||||||
async def getVarValue(self,var,namespace,default):
|
|
||||||
v = default
|
|
||||||
try:
|
|
||||||
v = eval(var,namespace)
|
|
||||||
except Exception as e:
|
|
||||||
v = namespace.get(var, None)
|
|
||||||
if v:
|
|
||||||
return v
|
|
||||||
if callable(default):
|
|
||||||
return await default(var)
|
|
||||||
return default
|
|
||||||
return v
|
|
||||||
|
|
||||||
async def convertString(self,s,namespace,default):
|
|
||||||
args = re.findall(self.re1,s)
|
|
||||||
for arg in args:
|
|
||||||
dl = s.split(arg)
|
|
||||||
var = self.getVarName(arg)
|
|
||||||
v = await self.getVarValue(var,namespace,default)
|
|
||||||
if type(v) != type(u''):
|
|
||||||
v = str(v)
|
|
||||||
s = v.join(dl)
|
|
||||||
return s
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
from appPublic.asynciorun import run
|
|
||||||
async def main():
|
|
||||||
ns = {
|
|
||||||
'a':12,
|
|
||||||
'b':'of',
|
|
||||||
'c':'abc',
|
|
||||||
u'是':'is',
|
|
||||||
'd':{
|
|
||||||
'a':'doc',
|
|
||||||
'b':'gg',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
AC = ArgsConvert('%{','}%')
|
|
||||||
s1 = "%{a}% is a number,%{d['b']}% is %{是}% undefined,%{c}% is %{d['a']+'(rr)'}% string"
|
|
||||||
arglist=['this is a descrciption %{b}% selling book',123,'ereg%{a}%,%{c}%']
|
|
||||||
argdict={
|
|
||||||
'my':arglist,
|
|
||||||
'b':s1
|
|
||||||
}
|
|
||||||
print(s1,'<=>',await AC.convert(s1,ns))
|
|
||||||
print(argdict,'<=>',await AC.convert(argdict,ns))
|
|
||||||
|
|
||||||
run(main)
|
|
@ -1,108 +0,0 @@
|
|||||||
from appPublic.uniqueID import getID
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
from appPublic.argsConvert import ArgsConvert
|
|
||||||
import datetime
|
|
||||||
from .const import *
|
|
||||||
from .accountingnode import get_offer_orgs, get_parent_orgid
|
|
||||||
from .excep import *
|
|
||||||
from .getaccount import getAccountByName
|
|
||||||
from .accounting_config import get_accounting_config, AccountingOrgs
|
|
||||||
from .businessdate import get_business_date
|
|
||||||
# from .settle import SettleAccounting
|
|
||||||
|
|
||||||
class BillAccounting:
|
|
||||||
def __init__(self, bill):
|
|
||||||
self.curdate = bill['bill_date']
|
|
||||||
self.timestamp = bill['bill_timestamp']
|
|
||||||
self.bill = bill
|
|
||||||
self.productid = bill['productid']
|
|
||||||
self.providerid = bill['providerid']
|
|
||||||
self.customerid = bill['customerid']
|
|
||||||
self.billid = bill['id']
|
|
||||||
self.action = bill['business_op']
|
|
||||||
self.accountingOrgs = []
|
|
||||||
self.transamount = bill['provider_amt']
|
|
||||||
self.amount = bill['amount']
|
|
||||||
self.discount_recs = {
|
|
||||||
}
|
|
||||||
|
|
||||||
async def get_accounting_nodes(self):
|
|
||||||
sor = self.sor
|
|
||||||
orgid = await get_parent_orgid(sor, self.customerid)
|
|
||||||
orgids = await get_offer_orgs(sor, orgid,
|
|
||||||
self.providerid,
|
|
||||||
self.productid,
|
|
||||||
self.curdate)
|
|
||||||
if orgids is None:
|
|
||||||
return [orgid]
|
|
||||||
return orgids + [orgid]
|
|
||||||
|
|
||||||
async def accounting(self, sor):
|
|
||||||
self.sor = sor
|
|
||||||
bz_date = await get_business_date(sor=sor)
|
|
||||||
if bz_date != self.curdate:
|
|
||||||
raise AccountingDateNotInBusinessDate(self.curdate, bz_date)
|
|
||||||
await self.prepare_accounting()
|
|
||||||
await self.do_accounting()
|
|
||||||
await sor.U('bill', {'id':self.billid, 'bill_state':'1'})
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def do_accounting(self):
|
|
||||||
for ao in self.accountingOrgs:
|
|
||||||
await ao.do_accounting(self.sor)
|
|
||||||
|
|
||||||
async def prepare_accounting(self):
|
|
||||||
nodes = await self.get_accounting_nodes()
|
|
||||||
print(f'accounting ndoes:{nodes}')
|
|
||||||
lst = len(nodes) - 1
|
|
||||||
for i, n in enumerate(nodes):
|
|
||||||
if i < lst:
|
|
||||||
ao = AccountingOrgs(self, nodes[i], self.customerid, resellerid=nodes[i+1])
|
|
||||||
else:
|
|
||||||
ao = AccountingOrgs(self, nodes[i], self.customerid)
|
|
||||||
self.accountingOrgs.append(ao)
|
|
||||||
|
|
||||||
async def get_customer_discount(self, customerid, productid):
|
|
||||||
k = customerid
|
|
||||||
rec = self.discount_recs.get(k, None)
|
|
||||||
if rec:
|
|
||||||
return rec
|
|
||||||
sor = self.sor
|
|
||||||
sql = """select * from cp_discount
|
|
||||||
where customerid=${id}$
|
|
||||||
and productid=${productid}$
|
|
||||||
and start_date <= ${today}$
|
|
||||||
and ${today}$ < end_date"""
|
|
||||||
ns = {
|
|
||||||
'id':customerid,
|
|
||||||
'today':self.curdate,
|
|
||||||
'productid':productid
|
|
||||||
}
|
|
||||||
recs = await sor.sqlExe(sql, ns)
|
|
||||||
if len(recs) > 0:
|
|
||||||
self.discount_recs[k] = recs[0]
|
|
||||||
return recs[0]
|
|
||||||
return None
|
|
||||||
|
|
||||||
async def get_reseller_discount(self, resellerid, productid):
|
|
||||||
k = resellerid
|
|
||||||
rec = self.discount_recs.get(k, None)
|
|
||||||
if rec:
|
|
||||||
return rec
|
|
||||||
sor = self.sor
|
|
||||||
sql = """select * from rp_discount
|
|
||||||
where resellerid=${id}$
|
|
||||||
and productid=${productid}$
|
|
||||||
and start_date <= ${today}$
|
|
||||||
and ${today}$ < end_date"""
|
|
||||||
ns = {
|
|
||||||
'id':resellerid,
|
|
||||||
'today':self.curdate,
|
|
||||||
'productid':productid
|
|
||||||
}
|
|
||||||
recs = await sor.sqlExe(sql, ns)
|
|
||||||
if len(recs) > 0:
|
|
||||||
self.discount_recs[k] = recs[0]
|
|
||||||
return recs[0]
|
|
||||||
return None
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
|||||||
from sqlor.dbpools import DBPools
|
|
||||||
from appPublic.timeUtils import strdate_add
|
|
||||||
from .excep import BusinessDateParamsError
|
|
||||||
from .const import *
|
|
||||||
async def get_business_date(sor=None):
|
|
||||||
async def _f(sor):
|
|
||||||
sql = "select * from params where pname = 'business_date'"
|
|
||||||
recs = await sor.sqlExe(sql, {})
|
|
||||||
if len(recs) > 0:
|
|
||||||
return recs[0]['pvalue']
|
|
||||||
raise BusinessDateParamsError
|
|
||||||
|
|
||||||
if sor:
|
|
||||||
return await _f(sor)
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext(DBNAME) as sor:
|
|
||||||
return await _f(sor)
|
|
||||||
|
|
||||||
async def new_business_date(sor=None):
|
|
||||||
async def _f(sor):
|
|
||||||
dat = await get_business_date(sor)
|
|
||||||
new_dat = strdate_add(dat, days=1)
|
|
||||||
sql = "update params set pvalue=${new_dat}$ where pname='business_date'"
|
|
||||||
await sor.sqlExe(sql, {'new_dat':new_dat})
|
|
||||||
|
|
||||||
if sor:
|
|
||||||
return await _f(sor)
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext(DBNAME) as sor:
|
|
||||||
return await _f(sor)
|
|
||||||
|
|
||||||
async def previous_business_date(sor=None):
|
|
||||||
dat = await get_business_date(sor=sor)
|
|
||||||
return strdate_add(dat, days=-1)
|
|
||||||
|
|
||||||
async def next_business_date(sor=None):
|
|
||||||
dat = await get_business_date(sor=sor)
|
|
||||||
return strdate_add(dat, days=1)
|
|
||||||
|
|
@ -1,53 +0,0 @@
|
|||||||
from datetime import date, timedelta
|
|
||||||
"""
|
|
||||||
Patterns =
|
|
||||||
'D'
|
|
||||||
'W[0-6]'
|
|
||||||
'M[00-31]'
|
|
||||||
'S[1-3]-[00-31]'
|
|
||||||
'Y[01-12]-[00-31]'
|
|
||||||
}
|
|
||||||
"""
|
|
||||||
|
|
||||||
def str2date(sd):
|
|
||||||
a = [ int(i) for i in sd.split('-') ]
|
|
||||||
return date(*a)
|
|
||||||
|
|
||||||
def is_monthend(dt):
|
|
||||||
if isinstance(dt, str):
|
|
||||||
dt = str2date(dt)
|
|
||||||
nxt_day = dt + timedelta(days=1)
|
|
||||||
if dt.month != nxt_day.month:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
def is_match_pattern(pattern, strdate):
|
|
||||||
if pattern == 'D':
|
|
||||||
return True
|
|
||||||
dt = ste2date(strdate)
|
|
||||||
if pattern.startswith('W'):
|
|
||||||
w = (int(pattern[1]) + 1) % 7
|
|
||||||
|
|
||||||
if dt.weekday() == w:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
if pattern.startswith('M'):
|
|
||||||
day = int(pattern[1:])
|
|
||||||
if day == 0 and is_monthend(dt):
|
|
||||||
return True
|
|
||||||
if day == dt.day:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
if pattern.startswith('S'):
|
|
||||||
m,d = [ int(i) for i in pattern[1:].split('-') ]
|
|
||||||
m %= 4
|
|
||||||
if m == dt.month and d == dt.day:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
if pattern.startswith('Y'):
|
|
||||||
m,d = [ int(i) for i in pattern[1:].split('-') ]
|
|
||||||
if m == dt.month and d == dt.day:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
@ -1,34 +0,0 @@
|
|||||||
DBNAME = 'kboss'
|
|
||||||
RESELLER_ORG = '1'
|
|
||||||
OWNER_OGR = '0'
|
|
||||||
CORP_CUSTOMER = '2'
|
|
||||||
PERSONAL = '3'
|
|
||||||
PROVIDER = '4'
|
|
||||||
|
|
||||||
PARTY_OWNER = '本机构'
|
|
||||||
PARTY_CUSTOMER = '客户'
|
|
||||||
PARTY_RESELLER = '分销商'
|
|
||||||
PARTY_PROVIDER = '供应商'
|
|
||||||
|
|
||||||
DEBT = '借'
|
|
||||||
CREDIT = '贷'
|
|
||||||
|
|
||||||
ACTNAME_BUY = '付费'
|
|
||||||
ACTNAME_RECHARGE = '充值'
|
|
||||||
ACTNAME_RECHARGE_ALIPAY = '支付宝充值'
|
|
||||||
ACTNAME_SETTLE = '结算'
|
|
||||||
|
|
||||||
SALEMODE_DISCOUNT = '折扣'
|
|
||||||
SALEMODE_REBATE = '代付费'
|
|
||||||
SALEMODE_FLOORPRICE = '底价'
|
|
||||||
|
|
||||||
ACTION_RECHARGE_ALIPAY = 'RECHARGE_ALIPAY'
|
|
||||||
ACTION_RECHARGE_ALIPAY_REVERSE = 'RECHARGE_ALIPAY_REVERSE'
|
|
||||||
ACTION_RECHARGE = 'RECHARGE'
|
|
||||||
ACTION_RECHARGE_REVERSE = 'RECHARGE_REVERSE'
|
|
||||||
ACTION_BUY = 'BUY'
|
|
||||||
ACTION_REVERSE_BUY = 'BUY_REVERSE'
|
|
||||||
ACTION_RENEW = 'RENEW'
|
|
||||||
ACTION_RENEW_REVERSE = 'RENEW_REVERSE'
|
|
||||||
ACTION_SETTLE = 'SETTLE'
|
|
||||||
ACTION_SETTLE_REVERSE = 'SETTLE_REVERSE'
|
|
@ -1,18 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
from accounting.businessdate import previous_business_date
|
|
||||||
from accounting.const import *
|
|
||||||
|
|
||||||
async def dayend_balance():
|
|
||||||
dat = await previous_business_date()
|
|
||||||
ts = datetime.now()
|
|
||||||
sql = """select a.* from (select accountid, max(acc_date) as acc_date, balance from acc_balance where accountid is not null group by accountid) a where acc_date < ${acc_date}$"""
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext(DBNAME) as sor:
|
|
||||||
recs = await sor.sqlExe(sql, {'acc_date':dat})
|
|
||||||
for r in recs:
|
|
||||||
r['id'] = getID()
|
|
||||||
r['acc_date'] = dat
|
|
||||||
await sor.C('acc_balance', r)
|
|
||||||
|
|
@ -1,121 +0,0 @@
|
|||||||
###################
|
|
||||||
#exceptions for accounting
|
|
||||||
####################
|
|
||||||
class AccountIdNone(Exception):
|
|
||||||
def __init__(self, accounting_orgid, orgid, subjectname):
|
|
||||||
self.accounting_orgid = accounting_orgid
|
|
||||||
self.orgid = orgid
|
|
||||||
self.subjectname = subjectname
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'AccountIdNone({self.accounting_orgid=}, {self.orgid=}, {self.subjectname=}'
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class AccountingAmountIsNone(Exception):
|
|
||||||
def __init__(self, billid):
|
|
||||||
self.billid = billid
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'AccountingAmountIsNone({self.billid=}) accounting amount is None'
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class AccountOverDraw(Exception):
|
|
||||||
def __init__(self, accid, balance, transamt):
|
|
||||||
self.accid = accid
|
|
||||||
self.balance = balance
|
|
||||||
self.transamt = transamt
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'AccountOverDraw({self.accid=},{self.balance=}, {self.transamt=}) overdraw'
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class AccountNoFound(Exception):
|
|
||||||
def __init__(self, accid):
|
|
||||||
self.accid = accid
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'Account({self.accid}) not found'
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class OrderNotFound(Exception):
|
|
||||||
def __init__(self, orderid):
|
|
||||||
self.orderid = orderid
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'Order({self.orderid}) not found'
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
class BusinessDateParamsError(Exception):
|
|
||||||
pass
|
|
||||||
|
|
||||||
class AccountingDateNotInBusinessDate(Exception):
|
|
||||||
def __init__(self, accounting_date, business_date):
|
|
||||||
self.accounting_date = accounting_date
|
|
||||||
self.business_date = business_date
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'Accounting date({self.accounting_date}) not in business_date({self.business_date})'
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class FutureAccountingExist(Exception):
|
|
||||||
def __init__(self, accid, accounting_date, future_date):
|
|
||||||
self.accid = accid
|
|
||||||
self.accounting_date = accounting_date
|
|
||||||
self.future_date = future_date
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'Account(id={self.accid}) in acc_balance exist future({self.future_date}) accounting record, curdate={self.accounting_date}'
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class GetCustomerPriceError(Exception):
|
|
||||||
def __init__(self, accounting_orgid, orgid, productid):
|
|
||||||
self.accounting_orgid = accounting_orgid
|
|
||||||
self.orgid = orgid
|
|
||||||
self.productid = productid
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'GetCustomerPriceError({self.accounting_orgid=}, {self.orgid=}, {self.productid=})'
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class ProductProtocolNotDefined(Exception):
|
|
||||||
def __init__(self, offer_orgid, bid_orgid, providerid, productid, curdate):
|
|
||||||
self.bid_orgid = bid_orgid
|
|
||||||
self.offer_orgid = offer_orgid
|
|
||||||
self.providerid = providerid
|
|
||||||
self.productid = productid
|
|
||||||
self.curdate = curdate
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'ProductProtocolNotDefined({self.offer_orgid=},{self.bid_orgid=},{self.providerid=},{self.productid=},{self.curdate=})'
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
class ProductBidProtocolNotDefined(Exception):
|
|
||||||
def __init__(self, offer_orgid, bid_orgid, providerid, productid, curdate):
|
|
||||||
self.bid_orgid = bid_orgid
|
|
||||||
self.offer_orgid = offer_orgid
|
|
||||||
self.providerid = providerid
|
|
||||||
self.productid = productid
|
|
||||||
self.curdate = curdate
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return f'ProductProtocolNotDefined({self.offer_orgid=},{self.bid_orgid=},{self.providerid=},{self.productid=},{self.curdate=})'
|
|
||||||
|
|
||||||
def __expr__(self):
|
|
||||||
return str(self)
|
|
||||||
|
|
||||||
|
|
@ -1,82 +0,0 @@
|
|||||||
from sqlor.dbpools import DBPools
|
|
||||||
from .const import *
|
|
||||||
from accounting.accountingnode import get_parent_orgid
|
|
||||||
|
|
||||||
async def getAccountByName(sor, accounting_orgid, orgid, name):
|
|
||||||
sql = """select a.* from account a, subject b
|
|
||||||
where a.subjectid = b.id and
|
|
||||||
a.accounting_orgid = ${accounting_orgid}$ and
|
|
||||||
a.orgid = ${orgid}$ and
|
|
||||||
b.name = ${name}$"""
|
|
||||||
recs = await sor.sqlExe(sql, {
|
|
||||||
"accounting_orgid":accounting_orgid,
|
|
||||||
"orgid":orgid,
|
|
||||||
"name":name
|
|
||||||
});
|
|
||||||
if len(recs) == 0:
|
|
||||||
return None
|
|
||||||
return recs[0]['id']
|
|
||||||
|
|
||||||
async def getTransPayMode():
|
|
||||||
pass
|
|
||||||
|
|
||||||
async def getParentOrganization(sor, childid):
|
|
||||||
sql="select a.* from organization a, organization b where b.parentid=a.id and b.id = ${childid}$"
|
|
||||||
ns = {
|
|
||||||
"childid":childid
|
|
||||||
}
|
|
||||||
recs = await sor.sqlExe(sql, ns)
|
|
||||||
if len(recs) == 0:
|
|
||||||
return None
|
|
||||||
return recs[0]
|
|
||||||
|
|
||||||
async def getCustomerBalance(sor, customerid):
|
|
||||||
name = '业务账'
|
|
||||||
orgid = await get_parent_orgid(sor, customerid)
|
|
||||||
if orgid is None:
|
|
||||||
print(f"{customerid=}'s parent organization not found")
|
|
||||||
return None
|
|
||||||
|
|
||||||
balance = await getAccountBalance(sor, orgid, customerid, name)
|
|
||||||
if balance is None:
|
|
||||||
print(f'accid is None, {orgid=}, {customerid=}, {name=}')
|
|
||||||
return None
|
|
||||||
return balance
|
|
||||||
|
|
||||||
async def getAccountBalance(sor, accounting_orgid, orgid, subjectname):
|
|
||||||
accid = await getAccountByName(sor, accounting_orgid,
|
|
||||||
orgid,
|
|
||||||
subjectname)
|
|
||||||
if accid is None:
|
|
||||||
print(f'accid is None, {accounting_orgid=}, {orgid=}, {subjectname=}')
|
|
||||||
return None
|
|
||||||
return await getAccountBalanceByAccid(sor, accid)
|
|
||||||
|
|
||||||
async def getAccountBalanceByAccid(sor, accid):
|
|
||||||
balances = await sor.sqlExe("""select * from acc_balance where accountid=${accid}$ order by acc_date desc""", {'accid':accid})
|
|
||||||
if len(balances) == 0:
|
|
||||||
print(f'acc_balance is None, {accid=}')
|
|
||||||
return 0
|
|
||||||
return balances[0]['balance']
|
|
||||||
|
|
||||||
async def get_account_info(sor, accid):
|
|
||||||
sql = '''
|
|
||||||
select b.orgname as accounting_org,
|
|
||||||
case when a.accounting_orgid = a.orgid then '本机构'
|
|
||||||
when c.org_type in ('0', '1') then '分销商'
|
|
||||||
when c.org_type = '2' then '供应商'
|
|
||||||
else '客户' end as acctype,
|
|
||||||
c.orgname,
|
|
||||||
d.name
|
|
||||||
from account a, organization b, organization c, subject d
|
|
||||||
where a.accounting_orgid = b.id
|
|
||||||
and a.orgid = c.id
|
|
||||||
and a.subjectid = d.id
|
|
||||||
and a.id = ${accid}$'''
|
|
||||||
recs = await sor.sqlExe(sql, {'accid':accid})
|
|
||||||
if len(recs) == 0:
|
|
||||||
|
|
||||||
return None
|
|
||||||
r = recs[0]
|
|
||||||
r['balance'] = await getAccountBalanceByAccid(sor, accid)
|
|
||||||
return r
|
|
@ -1,28 +0,0 @@
|
|||||||
from datetime import datetime
|
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
from appPublic.timeUtils import strdate_add
|
|
||||||
from accounting.businessdate import get_business_date
|
|
||||||
|
|
||||||
async def accounting_ledger(sor):
|
|
||||||
rd = await get_business_date(sor)
|
|
||||||
d = strdate_add(rd, days=-1)
|
|
||||||
print(f'{rd=}, {d=}')
|
|
||||||
ts = datetime.now()
|
|
||||||
sql = """
|
|
||||||
select a.accounting_orgid,
|
|
||||||
a.subjectid,
|
|
||||||
sum(case a.balance_at when '1' then b.balance else 0 end) as c_balance,
|
|
||||||
sum(case a.balance_at when '0' then b.balance else 0 end) as d_balance
|
|
||||||
from account a, acc_balance b
|
|
||||||
where a.id = b.accountid
|
|
||||||
and b.acc_date = ${acc_date}$
|
|
||||||
group by a.accounting_orgid, a.subjectid
|
|
||||||
"""
|
|
||||||
recs = await sor.sqlExe(sql, {'acc_date':d})
|
|
||||||
await sor.sqlExe('delete from ledger where acc_date=${acc_date}$',
|
|
||||||
{'acc_date':d})
|
|
||||||
for r in recs:
|
|
||||||
r['id'] = getID()
|
|
||||||
r['acc_date'] = d
|
|
||||||
await sor.C('ledger', r.copy())
|
|
||||||
|
|
@ -1,71 +0,0 @@
|
|||||||
from sqlor.dbpools import DBPools
|
|
||||||
from .const import *
|
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
async def openAccount(sor, accounting_orgid, orgid, account_config):
|
|
||||||
ns = {
|
|
||||||
'id':getID(),
|
|
||||||
'accounting_orgid':accounting_orgid,
|
|
||||||
'orgid':orgid,
|
|
||||||
'subjectid':account_config['subjectid'],
|
|
||||||
'balance_at':account_config['balance_side'],
|
|
||||||
'max_detailno':0
|
|
||||||
}
|
|
||||||
await sor.C('account', ns.copy())
|
|
||||||
print(ns, 'opened')
|
|
||||||
|
|
||||||
async def openPartyAccounts(sor, accounting_orgid, orgid, party_type):
|
|
||||||
sql = """select a.*, b.id as subjectid, b.balance_side from account_config a, subject b
|
|
||||||
where a.subjectname = b.name
|
|
||||||
and a.partytype=${partytype}$ """
|
|
||||||
recs = await sor.sqlExe(sql, {'partytype':party_type})
|
|
||||||
print(f'select account_config {recs=}', party_type)
|
|
||||||
for r in recs:
|
|
||||||
await openAccount(sor, accounting_orgid, orgid, r)
|
|
||||||
|
|
||||||
async def _openPartyAccounts(accounting_orgid, orgid, party_type):
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext(DBNAME) as sor:
|
|
||||||
await openPartyAccounts(sor, accounting_orgid, orgid, party_type)
|
|
||||||
|
|
||||||
async def openResellerAccounts(sor, accounting_orgid, orgid):
|
|
||||||
return await _openPartyAccounts(accounting_orgid, orgid, PARTY_RESELLER)
|
|
||||||
|
|
||||||
async def openCustomerAccounts(sor, accounting_orgid, orgid):
|
|
||||||
return await _openPartyAccounts(accounting_orgid, orgid, PARTY_CUSTOMER)
|
|
||||||
|
|
||||||
async def openOwnerAccounts(sor, accounting_orgid):
|
|
||||||
orgid = accounting_orgid
|
|
||||||
return await _openPartyAccounts(accounting_orgid, orgid, PARTY_OWNER)
|
|
||||||
|
|
||||||
async def openProviderAccounts(sor, accounting_orgid, orgid):
|
|
||||||
return await _openPartyAccounts(accounting_orgid, orgid, PARTY_PROVIDER)
|
|
||||||
|
|
||||||
async def openAllCustomerAccounts(sor, accounting_orgid):
|
|
||||||
sql = """select * from organization
|
|
||||||
where parentid=${accounting_orgid}$ and
|
|
||||||
org_type in ('2', '3' )"""
|
|
||||||
recs = await sor.sqlExe(sql, {'accounting_orgid':accounting_orgid})
|
|
||||||
print(f'{recs=}')
|
|
||||||
for r in recs:
|
|
||||||
await openCustomerAccounts(sor, accounting_orgid, r['id'])
|
|
||||||
|
|
||||||
async def openAllResellerAccounts(sor, accounting_orgid):
|
|
||||||
sql = """select * from organization
|
|
||||||
where parentid=${accounting_orgid}$ and
|
|
||||||
org_type = '1'"""
|
|
||||||
recs = await sor.sqlExe(sql, {'accounting_orgid':accounting_orgid})
|
|
||||||
print(f'{recs=}')
|
|
||||||
for r in recs:
|
|
||||||
await openResellerAccounts(sor, accounting_orgid, r['id'])
|
|
||||||
|
|
||||||
async def openAllProviderAccounts(sor, accounting_orgid):
|
|
||||||
sql = """select * from organization
|
|
||||||
where org_type = '4'"""
|
|
||||||
recs = await sor.sqlExe(sql, {'accounting_orgid':accounting_orgid})
|
|
||||||
print(f'{recs=}')
|
|
||||||
for r in recs:
|
|
||||||
await openProviderAccounts(sor, accounting_orgid, r['id'])
|
|
||||||
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
from .const import *
|
|
||||||
from datetime import datetime
|
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
|
|
||||||
async def _order2bill(sor, orderid):
|
|
||||||
sql = """select
|
|
||||||
og.orderid,
|
|
||||||
og.id as ordergoodsid,
|
|
||||||
o.customerid,
|
|
||||||
o.order_date,
|
|
||||||
o.business_op,
|
|
||||||
o.provider_orderid,
|
|
||||||
og.productid,
|
|
||||||
og.quantity,
|
|
||||||
og.providerid,
|
|
||||||
og.list_price,
|
|
||||||
og.discount,
|
|
||||||
og.price,
|
|
||||||
og.amount
|
|
||||||
from bz_order o, order_goods og
|
|
||||||
where o.id = og.orderid
|
|
||||||
and o.id = ${id}$
|
|
||||||
and o.order_status = '0'
|
|
||||||
"""
|
|
||||||
recs = await sor.sqlExe(sql, {'id':orderid})
|
|
||||||
if len(recs) == 0:
|
|
||||||
return
|
|
||||||
for r in recs:
|
|
||||||
ns = {
|
|
||||||
'id':getID(),
|
|
||||||
'customerid':r['customerid'],
|
|
||||||
'ordergoodsid':r['ordergoodsid'],
|
|
||||||
'orderid':r['orderid'],
|
|
||||||
'business_op':r['business_op'],
|
|
||||||
'provider_amt':r['list_price'] * r['quantity'],
|
|
||||||
'quantity':r['quantity'],
|
|
||||||
'amount':r['amount'],
|
|
||||||
'bill_date':r['order_date'],
|
|
||||||
'bill_timestamp':datetime.now(),
|
|
||||||
'bill_state':'0',
|
|
||||||
'productid':r['productid'],
|
|
||||||
'providerid':r['providerid'],
|
|
||||||
'provider_billid':None,
|
|
||||||
'resourceid':None
|
|
||||||
}
|
|
||||||
await sor.C('bill', ns)
|
|
||||||
await sor.U('bz_order', {'id':orderid, 'order_status':'1'})
|
|
||||||
|
|
||||||
async def order2bill(orderid, sor=None):
|
|
||||||
if sor is None:
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext(DBNAME) as sor:
|
|
||||||
await _order2bill(sor, orderid)
|
|
||||||
else:
|
|
||||||
await _order2bill(sor, orderid)
|
|
@ -1,64 +0,0 @@
|
|||||||
|
|
||||||
from datetime import datetime
|
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
from appPublic.timeUtils import curDateString
|
|
||||||
from appPublic.argsConvert import ArgsConvert
|
|
||||||
from .accounting_config import get_accounting_config, AccountingOrgs
|
|
||||||
from .const import *
|
|
||||||
from .accountingnode import get_accounting_nodes
|
|
||||||
from .excep import *
|
|
||||||
from .getaccount import getAccountByName
|
|
||||||
from .businessdate import get_business_date
|
|
||||||
|
|
||||||
class RechargeAccounting:
|
|
||||||
def __init__(self, recharge_log):
|
|
||||||
self.db = DBPools()
|
|
||||||
self.recharge_log = recharge_log
|
|
||||||
self.customerid = recharge_log['customerid']
|
|
||||||
self.orderid = None
|
|
||||||
self.curdate = recharge_log['recharge_date']
|
|
||||||
self.transamount = recharge_log['recharge_amt']
|
|
||||||
self.timestamp = datetime.now()
|
|
||||||
self.productid = None
|
|
||||||
self.providerid = None
|
|
||||||
self.action = recharge_log['action']
|
|
||||||
self.summary = self.action
|
|
||||||
self.billid = getID()
|
|
||||||
self.bill = {
|
|
||||||
'id':self.billid,
|
|
||||||
'customerid':self.recharge_log['customerid'],
|
|
||||||
'resellerid':None,
|
|
||||||
'orderid':None,
|
|
||||||
'business_op':self.recharge_log['action'],
|
|
||||||
'amount':self.recharge_log['recharge_amt'],
|
|
||||||
'bill_date':self.curdate,
|
|
||||||
'bill_timestamp':self.timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
async def accounting(self, sor):
|
|
||||||
self.sor = sor
|
|
||||||
bz_date = await get_business_date(sor=sor)
|
|
||||||
if bz_date != self.curdate:
|
|
||||||
raise AccountingDateNotInBusinessDate(self.curdate, bz_date)
|
|
||||||
|
|
||||||
nodes = await get_accounting_nodes(sor, self.customerid)
|
|
||||||
lst = len(nodes) - 1
|
|
||||||
self.accountingOrgs = []
|
|
||||||
for i, n in enumerate(nodes):
|
|
||||||
if i < lst:
|
|
||||||
ao = AccountingOrgs(self, nodes[i], self.customerid,
|
|
||||||
resellerid=nodes[i+1])
|
|
||||||
else:
|
|
||||||
ao = AccountingOrgs(self, nodes[i], self.customerid)
|
|
||||||
self.accountingOrgs.append(ao)
|
|
||||||
await self.write_bill(sor)
|
|
||||||
[await ao.do_accounting(sor) for ao in self.accountingOrgs ]
|
|
||||||
print(f'recharge ok for {self.bill}, {nodes=}')
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def write_bill(self, sor):
|
|
||||||
await sor.C('bill', self.bill.copy())
|
|
||||||
# await sor.C('recharge_log', self.recharge_log.copy())
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
|||||||
from .const import *
|
|
||||||
from .accountingnode import get_accounting_nodes
|
|
||||||
from .excep import *
|
|
||||||
from .getaccount import getAccountByName
|
|
||||||
from appPublic.uniqueID import getID
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
from appPublic.timeUtils import curDateString
|
|
||||||
from appPublic.argsConvert import ArgsConvert
|
|
||||||
from .accounting_config import get_accounting_config, AccountingOrgs
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
def get_subjectid(salemode):
|
|
||||||
d = {
|
|
||||||
'0':'acc009',
|
|
||||||
'1':'acc010',
|
|
||||||
'2':'acc011'
|
|
||||||
}
|
|
||||||
return d.get(salemode)
|
|
||||||
|
|
||||||
class SettleAccounting:
|
|
||||||
def __init__(self, settle_log):
|
|
||||||
self.accounting_orgid = settle_log['accounting_orgid']
|
|
||||||
self.settle_log = settle_log
|
|
||||||
self.providerid = settle_log['providerid']
|
|
||||||
self.orderid = None
|
|
||||||
self.sale_mode = settle_log['sale_mode']
|
|
||||||
self.curdate = settle_log['settle_date']
|
|
||||||
self.transamount = settle_log['settle_amt']
|
|
||||||
self.timestamp = datetime.now()
|
|
||||||
self.productid = None
|
|
||||||
self.action = settle_log['business_op']
|
|
||||||
self.summary = self.action
|
|
||||||
self.settleid = getID()
|
|
||||||
self.billid = getID()
|
|
||||||
self.bill = {
|
|
||||||
'id':self.billid,
|
|
||||||
'business_op':self.action,
|
|
||||||
'amount':self.transamount,
|
|
||||||
'bill_date':self.curdate,
|
|
||||||
'bill_timestamp':self.timestamp
|
|
||||||
}
|
|
||||||
|
|
||||||
async def accounting(self, sor):
|
|
||||||
ao = AccountingOrgs(self, self.accounting_orgid, None)
|
|
||||||
await self.write_settle_log(sor)
|
|
||||||
await self.write_bill(sor)
|
|
||||||
await ao.do_accounting(sor)
|
|
||||||
return True
|
|
||||||
|
|
||||||
async def write_settle_log(self, sor):
|
|
||||||
ns = self.settle_log.copy()
|
|
||||||
ns['id'] = self.settleid
|
|
||||||
await sor.C('settle_log', ns)
|
|
||||||
|
|
||||||
async def write_bill(self, sor):
|
|
||||||
await sor.C('bill', self.bill.copy())
|
|
@ -1,28 +0,0 @@
|
|||||||
from appPublic.timeUtils import is_match_pattern
|
|
||||||
from sqlor.sor import SQLor
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
from accounting.const import *
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def is_provider_settle_date(strdate:str,
|
|
||||||
providerid:str,
|
|
||||||
sor:SQLor=None) -> bool:
|
|
||||||
async def f(sor:SQLor, strdate:str, providerid:str):
|
|
||||||
sql = """select * from provider where orgid=${providerid}$"""
|
|
||||||
recs = await sor.sqlExe(sql, {'providerid':providerid})
|
|
||||||
if len(recs) == 0:
|
|
||||||
return False
|
|
||||||
pattern = recs[0]['settle_datep']
|
|
||||||
if pattern is None:
|
|
||||||
return False
|
|
||||||
return is_match_pattern(pattern, strdate)
|
|
||||||
|
|
||||||
if sor:
|
|
||||||
return await f(sor, strdate, providerid)
|
|
||||||
db = DBPools()
|
|
||||||
async with db.sqlorContext(DBNAME) as sor:
|
|
||||||
return await f(sor, strdate, providerid)
|
|
||||||
|
|
@ -1,30 +0,0 @@
|
|||||||
import asyncio
|
|
||||||
from datetime import date
|
|
||||||
from sqlor.dbpools import DBPools
|
|
||||||
from appPublic.jsonConfig import getConfig
|
|
||||||
from appPublic.timeUtils import curDateString
|
|
||||||
from accounting.accounting_config import Accounting
|
|
||||||
async def main():
|
|
||||||
db = DBPools()
|
|
||||||
orders = []
|
|
||||||
dat = date.today() #curDateString()
|
|
||||||
async with db.sqlorContext('kboss') as sor:
|
|
||||||
sql = "select * from bz_order where order_date=${dat}$"
|
|
||||||
orders = await sor.sqlExe(sql, {'dat':dat})
|
|
||||||
|
|
||||||
print(dat, orders)
|
|
||||||
ai = [ Accounting(o) for o in orders ]
|
|
||||||
print(ai)
|
|
||||||
[ await a.accounting() for a in ai ]
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
p = '.'
|
|
||||||
if len(sys.argv) > 1:
|
|
||||||
p = sys.argv[1]
|
|
||||||
config = getConfig(p, {'woridir':p})
|
|
||||||
DBPools(config.databases)
|
|
||||||
loop = asyncio.new_event_loop()
|
|
||||||
asyncio.set_event_loop(loop)
|
|
||||||
loop.run_until_complete(main())
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
|||||||
__version__ = '0.1.0'
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user