From 6faf88b224008eeb6c60e18455b78a0d5f72dc30 Mon Sep 17 00:00:00 2001 From: yumoqing Date: Wed, 16 Jul 2025 14:32:14 +0800 Subject: [PATCH] first commit --- README.md | 2 + accounting/__init__.py | 0 accounting/accounting_config.py | 236 ++++++++++++++++++++ accounting/accountingnode.py | 87 ++++++++ accounting/alipay_recharge.py | 55 +++++ accounting/argsconvert.py | 95 ++++++++ accounting/bill.py | 123 +++++++++++ accounting/bizaccount.py | 262 +++++++++++++++++++++++ accounting/bzdate.py | 53 +++++ accounting/const.py | 44 ++++ accounting/consume.py | 63 ++++++ accounting/dayend_balance.py | 18 ++ accounting/excep.py | 121 +++++++++++ accounting/getaccount.py | 156 ++++++++++++++ accounting/getdbname.py | 7 + accounting/init.py | 23 ++ accounting/ledger.py | 28 +++ accounting/openaccount.py | 101 +++++++++ accounting/order_to_bill.py | 56 +++++ accounting/recharge.py | 87 ++++++++ accounting/settle.py | 56 +++++ accounting/settledate.py | 28 +++ accounting/version.py | 2 + app/acc.py | 29 +++ docs/平台类系统记账子系统.docx | Bin 0 -> 18286 bytes json/acc_balance.json | 17 ++ json/acc_detail.json | 17 ++ json/account.json | 34 +++ json/account_config.json | 16 ++ json/accounting_config.json | 14 ++ json/accounting_log.json | 17 ++ json/build.sh | 3 + json/subject.json | 25 +++ models/acc_balance.xlsx | Bin 0 -> 14912 bytes models/acc_detail.xlsx | Bin 0 -> 17498 bytes models/account.xlsx | Bin 0 -> 16315 bytes models/account_config.xlsx | Bin 0 -> 16885 bytes models/accounting_config.xlsx | Bin 0 -> 16401 bytes models/accounting_log.xlsx | Bin 0 -> 18307 bytes models/bill.xlsx | Bin 0 -> 16012 bytes models/bill_detail.xlsx | Bin 0 -> 17673 bytes models/ledger.xlsx | Bin 0 -> 17348 bytes models/subject.xlsx | Bin 0 -> 16876 bytes requirements.txt | 2 + script/roleperm.sh | 8 + setup.py | 52 +++++ test/open_account.py | 31 +++ test/recharge.py | 47 ++++ test/run_test.py | 12 ++ test/test_rf.py | 45 ++++ 50 files changed, 2072 insertions(+) create mode 100644 README.md create mode 100644 accounting/__init__.py create mode 100644 accounting/accounting_config.py create mode 100644 accounting/accountingnode.py create mode 100644 accounting/alipay_recharge.py create mode 100644 accounting/argsconvert.py create mode 100644 accounting/bill.py create mode 100644 accounting/bizaccount.py create mode 100644 accounting/bzdate.py create mode 100644 accounting/const.py create mode 100644 accounting/consume.py create mode 100644 accounting/dayend_balance.py create mode 100644 accounting/excep.py create mode 100644 accounting/getaccount.py create mode 100644 accounting/getdbname.py create mode 100644 accounting/init.py create mode 100644 accounting/ledger.py create mode 100644 accounting/openaccount.py create mode 100644 accounting/order_to_bill.py create mode 100644 accounting/recharge.py create mode 100644 accounting/settle.py create mode 100644 accounting/settledate.py create mode 100644 accounting/version.py create mode 100644 app/acc.py create mode 100644 docs/平台类系统记账子系统.docx create mode 100644 json/acc_balance.json create mode 100644 json/acc_detail.json create mode 100644 json/account.json create mode 100644 json/account_config.json create mode 100644 json/accounting_config.json create mode 100644 json/accounting_log.json create mode 100755 json/build.sh create mode 100644 json/subject.json create mode 100644 models/acc_balance.xlsx create mode 100644 models/acc_detail.xlsx create mode 100644 models/account.xlsx create mode 100644 models/account_config.xlsx create mode 100644 models/accounting_config.xlsx create mode 100644 models/accounting_log.xlsx create mode 100644 models/bill.xlsx create mode 100644 models/bill_detail.xlsx create mode 100644 models/ledger.xlsx create mode 100644 models/subject.xlsx create mode 100644 requirements.txt create mode 100755 script/roleperm.sh create mode 100755 setup.py create mode 100644 test/open_account.py create mode 100644 test/recharge.py create mode 100644 test/run_test.py create mode 100644 test/test_rf.py diff --git a/README.md b/README.md new file mode 100644 index 0000000..cf8c8de --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# accounting + diff --git a/accounting/__init__.py b/accounting/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/accounting/accounting_config.py b/accounting/accounting_config.py new file mode 100644 index 0000000..a98ac82 --- /dev/null +++ b/accounting/accounting_config.py @@ -0,0 +1,236 @@ +import asyncio +import re +from .const import * +from .accountingnode import get_parent_orgid +from .excep import * +from .getaccount import get_account, getAccountByName +from appPublic.uniqueID import getID +from appPublic.log import debug, exception +from sqlor.dbpools import DBPools +from appPublic.timeUtils import curDateString +# from .argsconvert import ArgsConvert +from appPublic.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 Accounting: + """ + 需要caller功能: + caller中要有分录中的变量 + get_accounting_orgid(leg) 获得记账机构 + get_account(leg,accounting_orgid) 获得记账账号(通过科目,机构类型,账务机构确定一个唯一的账号) + """ + def __init__(self, caller): + self.caller = caller + 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 = 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 + + async def setup_accounting_legs(self): + global accounting_config + action = self.action.split('_')[0] + await get_accounting_config(self.sor) + self.accounting_legs = [r.copy() for r in accounting_config + if r.action == action ] + debug(f'{self.accounting_legs=}') + rev = self.action.endswith('_REVERSE') + for l in self.accounting_legs: + if rev: + l['acc_dir'] = DEBT if l['accounting_dir'] == CREDIT else CREDIT + else: + l['acc_dir'] = l['accounting_dir'] + ac = ArgsConvert('${', '}$') + try: + amtstr = ac.convert(l['amt_pattern'], + self.variable.copy() + ) + debug(f'{l["amt_pattern"]=}, {amtstr=}, {self.variable=}') + if isinstance(amtstr, str): + l['amount'] = eval(amtstr) + else: + l['amount'] = amtstr + + except Exception as e: + exception(f"{e=}, {l['amt_pattern']}, {self.variable=}") + raise e + + if l['amount'] is None: + debug(f'amount is None:{l["amt_pattern"]}, {self.variable=},{self.caller.bill=}') + raise AccountingAmountIsNone(self.caller.billid) + + def check_accounting_balance(self, legs): + debt_balance = 0.0 + credit_balance = 0.0 + for l in legs: + if l['acc_dir'] == DEBT: + debt_balance += l['amount'] + else: + credit_balance += l['amount'] + if abs(credit_balance - debt_balance) >= 0.01: + e = Exception('accounting legs not balance') + exception(f'{legs=}, {e=}') + raise e + + async def do_accounting(self, sor): + self.sor = sor + + await self.setup_accounting_legs() + debug(f'do_accounting() ...{self.accounting_legs=}') + self.check_accounting_balance(self.accounting_legs) + for leg in self.accounting_legs: + accounting_orgid = await self.caller.get_orgid_by_trans_role(sor, leg.accounting_orgtype) + orgid = await self.caller.get_orgid_by_trans_role(sor, leg.orgtype) + org1id = None if leg.org1type is None else \ + await self.caller.get_orgid_by_trans_role(sor, 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) + + 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'] == 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): + # print(f'leg_accounting(), {accid=}, {leg=}') + if leg['amount'] < 0.0001: + return + 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' : leg['accounting_orgid'], + 'billid' : self.billid, + 'description' : self.summary, + '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':self.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':self.summary, + 'amount':leg['amount'], + 'balance':leg['new_balance'], + 'acclogid':logid + } + await sor.C('acc_detail', ns.copy()) + diff --git a/accounting/accountingnode.py b/accounting/accountingnode.py new file mode 100644 index 0000000..d36abb4 --- /dev/null +++ b/accounting/accountingnode.py @@ -0,0 +1,87 @@ +from .const import * +from appPublic.log import debug +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_orgtypes(sor, orgid): + sql = "select orgtypeid from orgtypes where orgid = ${orgid}$" + recs = await sor.sqlExe(sql, {'orgid':orgid}) + return [r.orgtypeid for r in recs] + +async def get_accounting_nodes(sor, customerid): + """ + gt all accounting organization for transactes customer orgid + """ + mytypes = await get_orgtypes(sor, customerid) + is_c = False + for t in mytypes: + if t in ['customer', 'agencycustomer', 'personalcustomer']: + is_c = True + break + + if not is_c: + debug(f'{customerid=} is not a customer organzition') + return [] + + sql = """select a.id from organization a, organization b +where b.parentid = a.id + and b.id = ${customerid}$ + """ + recs = await sor.sqlExe(sql, {'customerid':customerid}) + if len(recs) == 0: + debug(f'{customerid=} not found is organziation table') + return ['0'] + return [] + ret = await get_ancestor_orgs(sor, recs[0]['id']) + ret.append(recs[0]['id']) + return ret + + + diff --git a/accounting/alipay_recharge.py b/accounting/alipay_recharge.py new file mode 100644 index 0000000..76d277a --- /dev/null +++ b/accounting/alipay_recharge.py @@ -0,0 +1,55 @@ + +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 + diff --git a/accounting/argsconvert.py b/accounting/argsconvert.py new file mode 100644 index 0000000..1f9dd05 --- /dev/null +++ b/accounting/argsconvert.py @@ -0,0 +1,95 @@ +# -*- 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) diff --git a/accounting/bill.py b/accounting/bill.py new file mode 100644 index 0000000..c4fb83c --- /dev/null +++ b/accounting/bill.py @@ -0,0 +1,123 @@ +from appPublic.uniqueID import getID +from appPublic.dictObject import DictObject +from sqlor.dbpools import DBPools +from ahserver.serverenv import get_serverenv +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, Accounting +# from .settle import SettleAccounting + +async def write_bill(sor, customerid, userid, orderid, business_op, amount): + bill = DictObject() + bill.customerid = customerid + bill.id = getID() + bill.userid = userid + bill.orderid = orderid + bill.business_op = business_op + bill.amount = amount + get_business_date = get_serverenv('get_business_date') + bill.bill_date = await get_business_date(sor) + bill_state = '0' + await sor.C('bill', bill.copy()) + return bill + +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 + diff --git a/accounting/bizaccount.py b/accounting/bizaccount.py new file mode 100644 index 0000000..69154ea --- /dev/null +++ b/accounting/bizaccount.py @@ -0,0 +1,262 @@ +import asyncio +import re +from .const import * +from .accountingnode import get_parent_orgid +from .excep import * +from .getaccount import get_account, getAccountByName +from appPublic.uniqueID import getID +from appPublic.log import debug, exception +from sqlor.dbpools import DBPools +from appPublic.timeUtils import curDateString +# from .argsconvert import ArgsConvert +from appPublic.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 BizAccounting: + """ + def __init__(self, curdate, accountset): + accountset:with accounting attribute and a sub accountsets + accountset: + action:with action can find the accounting_config + participal: found the account to be accounting + async def prepare(sor): + find all the accounting_legs + merge multiple accounting for one account to one + check if account overdraw + sort accounting_legs by account id + + async def do_accounting(sor) + wrtie bill, billdetail + writ accounting_log + write acc_detail + write acc_balance + """ + def __init__(self, curdate, biz_order, accountset, amount_threahold=0.0001): + self.accounting_config = None + self.curdate = curdate + self.biz_order = biz_order + self.accountset = accountset + self.amount_threahold = amount_threahold + self.timestamp = timestampstr() + + async def do_accounting(self, sor): + legs = self.get_accounting_legs(sor) + legs = [l for l in legs if l['amount'] >= self.amount_threahold] + self.check_accounting_balance(legs) + bill = await write_bill(sor, self.biz_order.customerid, + self.biz_order.userid, + self.biz_order.id, + self.biz_order.business_op, + self.biz_order.amount) + await self.write_billdetail(sor) + self.merge_legs(legs) + self.accounting_legs = legs + for leg in legs: + await self.leg_accounting(sor, leg) + + async def get_orgid_by_trans_role(self, role, accountset): + return accountset.get(role) + + async def get_accounting_legs(self, sor): + leg = self.get_accountset_legs(sor, self.accountset) + if self.accountset.subsets: + for aset in self.accountset.subsets: + legs1 = self.get_accountset_legs(sor, aset) + leg += legs1 + return legs + + async def get_accountset_legs(self, sor, accountset): + global accounting_config + action = accountset.action.split('_')[0] + await get_accounting_config(sor) + legs = [r.copy() for r in accounting_config + if r.action == action ] + debug(f'{legs=}') + rev = accountset.action.endswith('_REVERSE') + for l in legs: + if rev: + l['acc_dir'] = DEBT if l['accounting_dir'] == CREDIT else CREDIT + else: + l['acc_dir'] = l['accounting_dir'] + ac = ArgsConvert('${', '}$') + try: + amtstr = ac.convert(l['amt_pattern'], + accountset.copy() + ) + debug(f'{l["amt_pattern"]=}, {amtstr=}, {accountset=}') + if isinstance(amtstr, str): + l['amount'] = eval(amtstr) + else: + l['amount'] = amtstr + + except Exception as e: + exception(f"{e=}, {l['amt_pattern']}, {accountset=}") + raise e + + if l['amount'] is None: + debug(f'amount is None:{l["amt_pattern"]}, {accountset=}') + raise AccountingAmountIsNone(self.caller.billid) + accounting_orgid = await self.get_orgid_by_trans_role(l.accounting_orgtype) + orgid = await self.get_orgid_by_trans_role(l.orgtype) + org1id = None if l.org1type is None else \ + await self.get_orgid_by_trans_role(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['acc'] = acc + legs = sorted(legs, key=lambda x: x['acc']) + return legs + + def merge_two_legs(self, l1, l2): + if l1['acc_dir'] == l2['acc_dir']: + l = l1 + l['amount'] = l1['amount'] + l2['amount'] + return l + l = l1 if l1['amount'] > l2['amount'] else l2 + l['amount'] = abs(l1['amount'] - l2['amount']) + return l + + def merge_legs(self, legs): + mlegs = [] + cnt = len(legs) + cleg = None + for i, leg in enumerate(legs): + if leg['acc'].id == cleg['acc'].id: + cleg = self.merge_two_legs(cleg, leg) + else: + mlegs.append(cleg) + cleg = leg + mleg.append(cleg) + return mleg + + def check_accounting_balance(self, legs): + debt_balance = 0.0 + credit_balance = 0.0 + for l in legs: + if l['acc_dir'] == DEBT: + debt_balance += l['amount'] + else: + credit_balance += l['amount'] + if abs(credit_balance - debt_balance) >= self.threahold: + e = Exception('accounting legs not balance') + exception(f'{legs=}, {e=}') + raise e + + async def write_billdetail(self, sor, legs): + for leg in legs: + ns = { + 'id':getID(), + 'accounting_orgid' : leg['accounting_orgid'], + 'billid' : self.billid, + 'description' : self.summary, + 'participantid' : leg['orgid'], + 'participanttype' : leg['orgtype'], + 'subjectname' : leg['subjectname'], + 'accounting_dir': leg['accounting_dir'], + 'amount' : leg['amount'] + } + await sor.C('bill_detail', 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, leg): + accid = leg['acc'].id + 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 + logid = getID() + ns = { + 'id':logid, + 'accountid':accid, + 'acc_date':self.curdte, + 'acc_timestamp':self.timestamp, + 'acc_dir':leg['acc_dir'], + 'summary':self.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':self.summary, + 'amount':leg['amount'], + 'balance':leg['new_balance'], + 'acclogid':logid + } + await sor.C('acc_detail', ns.copy()) diff --git a/accounting/bzdate.py b/accounting/bzdate.py new file mode 100644 index 0000000..13e0f02 --- /dev/null +++ b/accounting/bzdate.py @@ -0,0 +1,53 @@ +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 + + diff --git a/accounting/const.py b/accounting/const.py new file mode 100644 index 0000000..37a1ab0 --- /dev/null +++ b/accounting/const.py @@ -0,0 +1,44 @@ +from appPublic.registerfunction import RegisterFunction + +def DBNAME(): + rf = RegisterFunction() + f = rf.get('get_module_database') + if f is None: + e = Exception('function "get_module_database" not registed') + exception(f'{e}') + raise e + return f('accounting') + +RESELLER_ORG = '1' +OWNER_OGR = '0' +CORP_CUSTOMER = '2' +PERSONAL = '3' +PROVIDER = '4' + +PARTY_OWNER = '平台' +PARTY_CUSTOMER = '客户' +PARTY_RESELLER = '分销商' +PARTY_PROVIDER = '供应商' + +DEBT = '0' +CREDIT = '1' + +ACTNAME_BUY = 'consume' +ACTNAME_RECHARGE = 'recharge' +ACTNAME_RECHARGE_ALIPAY = 'rechange_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' diff --git a/accounting/consume.py b/accounting/consume.py new file mode 100644 index 0000000..a048228 --- /dev/null +++ b/accounting/consume.py @@ -0,0 +1,63 @@ +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 ConsumeAccounting: + def __init__(self, cnsume_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()) + diff --git a/accounting/dayend_balance.py b/accounting/dayend_balance.py new file mode 100644 index 0000000..9e785ef --- /dev/null +++ b/accounting/dayend_balance.py @@ -0,0 +1,18 @@ +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) + diff --git a/accounting/excep.py b/accounting/excep.py new file mode 100644 index 0000000..b0cb95f --- /dev/null +++ b/accounting/excep.py @@ -0,0 +1,121 @@ +################### +#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) + + diff --git a/accounting/getaccount.py b/accounting/getaccount.py new file mode 100644 index 0000000..52ad42b --- /dev/null +++ b/accounting/getaccount.py @@ -0,0 +1,156 @@ +from appPublic.log import debug, exception +from sqlor.dbpools import DBPools +from ahserver.serverenv import ServerEnv, get_serverenv +from .const import * +from accounting.accountingnode import get_parent_orgid + +async def get_account(sor, accounting_orgid, orgid, subjectid, org1id=None): + ss = "org1id is NULL" + if org1id: + ss = "org1id = ${org1id}$" + + sql = """select * from account + where + subjectid = ${subjectid}$ and + accounting_orgid = ${accounting_orgid}$ and + orgid = ${orgid}$ and + """ + ss + ns = { + "accounting_orgid":accounting_orgid, + "orgid":orgid, + "org1id":org1id, + "subjectid":subjectid + } + recs = await sor.sqlExe(sql, { + "accounting_orgid":accounting_orgid, + "orgid":orgid, + "org1id":org1id, + "subjectid":subjectid + }) + if len(recs) == 0: + debug(f'{sql=}, {ns=}') + return None + return recs[0] + +async def get_account_by_subjectname(sor, accounting_orgid, orgid, subjectname, org1id=None): + ss = "a.org1id is NULL" + if org1id: + ss = "a.org1id = ${org1id}$" + + sql = """select * from account a, subject b + where + a.subjectid = b.id and + b.name = ${subjectname}$ and + a.accounting_orgid = ${accounting_orgid}$ and + a.orgid = ${orgid}$ and + """ + ss + recs = await sor.sqlExe(sql, { + "accounting_orgid":accounting_orgid, + "orgid":orgid, + "org1id":org1id, + "subjectname":subjectname + }); + if len(recs) == 0: + return None + for rec in recs: + if a.org1id == org1id: + return rec['id'] + return None + +async def getAccountByName(sor, accounting_orgid, orgid, name, org1id): + 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 + for rec in recs: + if rec.org1id == org1id: + return rec['id'] + return None + +async def getTransPayMode(): + pass + +async def getCustomerBalance(sor, customerid): + name = '客户资金账户' + get_owner_orgid = get_serverenv('get_owner_orgid') + if get_owner_orgid is None: + debug('get_owner_orgid function is not a serverenv function') + return None + debug(f'{get_owner_orgid=}') + orgid = await get_owner_orgid(sor, customerid) + if orgid is None: + debug(f"{customerid=}'s parent organization not found") + return None + + balance = await getAccountBalance(sor, orgid, customerid, name, None) + if balance is None: + debug(f'accid is None, {orgid=}, {customerid=}, {name=}') + return None + return balance + +async def getAccountBalance(sor, accounting_orgid, orgid, subjectname, org1id): + accid = await getAccountByName(sor, accounting_orgid, + orgid, + subjectname,org1id) + if accid is None: + debug(f'accid is None, {accounting_orgid=}, {orgid=}, {subjectname=}') + return None + return await getAccountBalanceByAccid(sor, accid) + +async def get_account_total_amount(sor, accid, accounting_dir, from_date, to_date): + sql = """select sun(amount) as amount from acc_detail +where accountid =${accountid}$ + and acc_date >= ${from_date}$ + and acc_date < ${to_date}$ + and acc_dir = ${accounting_dir}$ +""" + ns = { + 'accountid':accid, + 'accounting_dir':accounting_dir, + 'from_date':from_date, + 'to_date':to_date + } + recs = await sor.sqlExe(sql, ns.copy()) + if len(recs)==0: + e = Exception(f'get_account_total_amount() error, {ns=}') + exception('{e=}') + raise e + return recs[0].amount + + +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: + debug(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 diff --git a/accounting/getdbname.py b/accounting/getdbname.py new file mode 100644 index 0000000..5d2fcf5 --- /dev/null +++ b/accounting/getdbname.py @@ -0,0 +1,7 @@ +from ahserver.serverenv import get_serverenv + +def get_dbname(): + f = get_serverenv('get_module_dbname') + if f is None: + raise Exception('get_module_dbname() not found') + return f('accounting') diff --git a/accounting/init.py b/accounting/init.py new file mode 100644 index 0000000..c2fc277 --- /dev/null +++ b/accounting/init.py @@ -0,0 +1,23 @@ +from appPublic.registerfunction import RegisterFunction +from appPublic.dictObject import DictObject +from appPublic.log import debug, exception, error +from ahserver.serverenv import ServerEnv +from accounting.accounting_config import Accounting +from accounting.bill import write_bill +from accounting.openaccount import openOwnerAccounts, openProviderAccounts, openResellerAccounts, openCustomerAccounts +from accounting.getaccount import getAccountBalance, getCustomerBalance, getAccountByName, get_account_total_amount +from accounting.bizaccount import BizAccounting + +def load_accounting(): + g = ServerEnv() + g.Accounting = Accounting + g.write_bill = write_bill + g.openOwnerAccounts = openOwnerAccounts + g.openProviderAccounts = openProviderAccounts + g.openResellerAccounts = openResellerAccounts + g.openCustomerAccounts = openCustomerAccounts + g.getAccountBalance = getAccountBalance + g.getCustomerBalance = getCustomerBalance + g.getAccountByName = getAccountByName + g.get_account_total_amount = get_account_total_amount + g.BizAccounting = BizAccounting diff --git a/accounting/ledger.py b/accounting/ledger.py new file mode 100644 index 0000000..121401e --- /dev/null +++ b/accounting/ledger.py @@ -0,0 +1,28 @@ +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()) + diff --git a/accounting/openaccount.py b/accounting/openaccount.py new file mode 100644 index 0000000..3c0efcb --- /dev/null +++ b/accounting/openaccount.py @@ -0,0 +1,101 @@ +from sqlor.dbpools import DBPools +from .const import * +from appPublic.uniqueID import getID +from appPublic.registerfunction import RegisterFunction, rfexe +from appPublic.log import debug, exception +from datetime import datetime +from accounting.getaccount import get_account + +async def openAccount(sor, accounting_orgid, orgid, account_config, org1id=None): + acc = await get_account(sor, accounting_orgid, orgid, + account_config['subjectid'], org1id=org1id) + if acc: + debug(f'{acc=} opened') + return + + ns = { + 'id':getID(), + 'accounting_orgid':accounting_orgid, + 'orgid':orgid, + 'subjectid':account_config['subjectid'], + 'balance_at':account_config['balance_side'], + 'max_detailno':0 + } + if org1id: + ns['org1id'] = org1id; + debug(f'openAccount(), {ns=}') + await sor.C('account', ns.copy()) + debug(f'{ns=} opened') + +async def openPartyAccounts(sor, accounting_orgid, orgid, party_type, org1id=None, party1_type=None): + addon_cond = " and a.party1type is NULL " + ns = {'partytype':party_type} + if party1_type: + addon_cond = " and a.party1type = ${party1type}$ " + ns['party1type'] = party1_type + + sql = """select a.*, b.id as subjectid, b.name as subjectname,b.balance_side from account_config a, subject b +where a.subjectid = b.id """ \ + + addon_cond + """ + and a.partytype=${partytype}$ """ + recs = await sor.sqlExe(sql, ns) + # print(f'select account_config {recs=}', party_type) + debug(f'{sql=}, {orgid=}, {party_type=}') + for r in recs: + debug(f'{r=}') + await openAccount(sor, accounting_orgid, orgid, r, org1id=org1id) + +async def openResellerAccounts(sor, accounting_orgid, orgid): + return await openPartyAccounts(sor, accounting_orgid, orgid, PARTY_RESELLER) + +async def openCustomerAccounts(sor, accounting_orgid, orgid): + return await openPartyAccounts(sor, accounting_orgid, orgid, PARTY_CUSTOMER) + +async def openOwnerAccounts(sor, accounting_orgid): + orgid = accounting_orgid + return await openPartyAccounts(sor, accounting_orgid, orgid, PARTY_OWNER) + +async def openProviderAccounts(sor, accounting_orgid, orgid): + return await openPartyAccounts(sor, accounting_orgid, orgid, PARTY_PROVIDER) + +async def openAllCustomerAccounts(sor, accounting_orgid): + rf = RegisterFunction() + f = rf.get('get_customers_by_orgid') + if f is None: + exception(f'get_customers_by_orgid function not registed, {accounting_orgid=}') + raise Exception('get_customers_by_orgid not registed') + recs = await f(sor, accounting_orgid) + print(f'{recs=}') + for r in recs: + await openCustomerAccounts(sor, accounting_orgid, r['id']) + +async def openAllResellerAccounts(sor, accounting_orgid): + rf = RegisterFunction() + f = rf.get('get_resellers_by_orgid') + if f is None: + exception(f'get_resellers_by_orgid function not registed, {accounting_orgid=}') + raise Exception('get_resellers_by_orgid not registed') + recs = await f(sor, accounting_orgid) + print(f'{recs=}') + for r in recs: + await openResellerAccounts(sor, accounting_orgid, r['id']) + +async def openAllProviderAccounts(sor, accounting_orgid): + rf = RegisterFunction() + f = rf.get('get_providers_by_orgid') + if f is None: + exception(f'get_providers_by_orgid function not registed, {accounting_orgid=}') + raise Exception('get_providers_by_orgid not registed') + recs = await f(sor, accounting_orgid) + print(f'{recs=}') + for r in recs: + await openProviderAccounts(sor, accounting_orgid, r['id']) + +async def openRetailRelationshipAccounts(sor, accounting_orgid, providerid, resellerid): + await openPartyAccounts(sor, accounting_orgid, providerid, PARTY_PROVIDER, + org1id=resellerid, + party1_type=PARTY_RESELLER) + await openPartyAccounts(sor, accounting_orgid, resellerid, PARTY_RESELLER, + org1id=providerid, + party1_type=PARTY_PROVIDER) + diff --git a/accounting/order_to_bill.py b/accounting/order_to_bill.py new file mode 100644 index 0000000..560dc9d --- /dev/null +++ b/accounting/order_to_bill.py @@ -0,0 +1,56 @@ +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) diff --git a/accounting/recharge.py b/accounting/recharge.py new file mode 100644 index 0000000..31d2954 --- /dev/null +++ b/accounting/recharge.py @@ -0,0 +1,87 @@ + +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 .getdbname import get_dbname +from .accounting_config import get_accounting_config, Accounting +from .const import * +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 = recharge_log['orderid'] + self.curdate = recharge_log['transdate'] + 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.variable = { + "交易金额":100, + "充值费率":0.003, + } + 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 get_account(self, leg): + if leg.orgtype == '平台': + 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) + + ao = Accounting(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()) + +async def recharge_accounting(sor, customerid, action, orderid, transdate, recharge_amt): + """ + summary:recharge channe(handly, wechat, alipay) + """ + recharge_log = { + "customerid":customerid, + "transdate":transdate, + "orderid":orderid, + "recharge_amt":recharge_amt, + "action":action, + } + ra = RechargeAccounting(recharge_log) + if sor: + r = await ra.accounting(sor) + return True + + db = DBPools() + dbname = get_dbname() + async with db.sqlorContext(dbname) as sor: + r = await ra.accounting(sor) + return True + diff --git a/accounting/settle.py b/accounting/settle.py new file mode 100644 index 0000000..a4af45e --- /dev/null +++ b/accounting/settle.py @@ -0,0 +1,56 @@ +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()) diff --git a/accounting/settledate.py b/accounting/settledate.py new file mode 100644 index 0000000..4844ad7 --- /dev/null +++ b/accounting/settledate.py @@ -0,0 +1,28 @@ +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) + diff --git a/accounting/version.py b/accounting/version.py new file mode 100644 index 0000000..2247efc --- /dev/null +++ b/accounting/version.py @@ -0,0 +1,2 @@ +__version__ = '0.1.0' + diff --git a/app/acc.py b/app/acc.py new file mode 100644 index 0000000..efe84c0 --- /dev/null +++ b/app/acc.py @@ -0,0 +1,29 @@ +import json +import os +from time import time + +from appPublic.worker import awaitify +from appPublic.jsonConfig import getConfig +from ahserver.serverenv import ServerEnv +from appPublic.registerfunction import RegisterFunction +from ahserver.webapp import webapp +from accounting.openaccount import openAllResellerAccounts +from accounting.openaccount import openAllCustomerAccounts +from accounting.openaccount import openAllProviderAccounts +from accounting.openaccount import openRetailRelationshipAccounts +from accounting.openaccount import openOwnerAccounts +from accounting.recharge import recharge_accounting +from accounting.getaccount import getAccountBalance, getCustomerBalance +from accounting.init import load_accounting + +def get_db(module=''): + return 'test' + +def init_func(): + rf = RegisterFunction() + rf.register('get_module_dbname', get_db) + load_accounting() + +if __name__ == '__main__': + webapp(init_func) + diff --git a/docs/平台类系统记账子系统.docx b/docs/平台类系统记账子系统.docx new file mode 100644 index 0000000000000000000000000000000000000000..8c1cacc4607679316e69f8d3b2e249f951a27cc0 GIT binary patch literal 18286 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 z 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 Kn=1Cl)&B#{>kTsi literal 0 HcmV?d00001 diff --git a/json/acc_balance.json b/json/acc_balance.json new file mode 100644 index 0000000..a6d3fab --- /dev/null +++ b/json/acc_balance.json @@ -0,0 +1,17 @@ +{ + "models_dir": "${HOME}$/py/rbac/models", + "output_dir": "${HOME}$/py/sage/wwwroot/account", + "dbname": "sage", + "tblname": "acc_balance", + "title":"科目", + "params": { + "sortby":"name", + "browserfields": { + "exclouded": ["id"], + "cwidth": {} + }, + "editexclouded": [ + "id" + ] + } +} diff --git a/json/acc_detail.json b/json/acc_detail.json new file mode 100644 index 0000000..1bab98e --- /dev/null +++ b/json/acc_detail.json @@ -0,0 +1,17 @@ +{ + "models_dir": "${HOME}$/py/rbac/models", + "output_dir": "${HOME}$/py/sage/wwwroot/acc_detail", + "dbname": "sage", + "tblname": "acc_detail", + "title":"科目", + "params": { + "sortby":"name", + "browserfields": { + "exclouded": ["id"], + "cwidth": {} + }, + "editexclouded": [ + "id" + ] + } +} diff --git a/json/account.json b/json/account.json new file mode 100644 index 0000000..71a9a53 --- /dev/null +++ b/json/account.json @@ -0,0 +1,34 @@ +{ + "models_dir": "${HOME}$/py/rbac/models", + "output_dir": "${HOME}$/py/sage/wwwroot/account", + "dbname": "sage", + "tblname": "account", + "title":"科目", + "params": { + "sortby":"name", + "browserfields": { + "exclouded": ["id"], + "cwidth": {} + }, + "editexclouded": [ + "id" + ], + "subtables":[ + { + "field":"accountid", + "title":"账户余额", + "subtable":"acc_balance" + }, + { + "field":"accountid", + "title":"账户明细", + "subtable":"acc_detail" + }, + { + "field":"accountid", + "title":"账户日志", + "subtable":"accounting_log" + } + ] + } +} diff --git a/json/account_config.json b/json/account_config.json new file mode 100644 index 0000000..fa5d29c --- /dev/null +++ b/json/account_config.json @@ -0,0 +1,16 @@ +{ + "models_dir": "${HOME}$/py/accounting/models", + "output_dir": "${HOME}$/py/sage/wwwroot/account_config", + "dbname": "sage", + "tblname": "account_config", + "title":"账户设置", + "params": { + "browserfields": { + "exclouded": ["id"], + "cwidth": {} + }, + "editexclouded": [ + "id" + ] + } +} diff --git a/json/accounting_config.json b/json/accounting_config.json new file mode 100644 index 0000000..ed13af3 --- /dev/null +++ b/json/accounting_config.json @@ -0,0 +1,14 @@ +{ + "tblname": "accounting_config", + "title":"账务设置", + "params": { + "sortby":["action","accounting_dir"], + "browserfields": { + "exclouded": ["id"], + "cwidth": {} + }, + "editexclouded": [ + "id" + ] + } +} diff --git a/json/accounting_log.json b/json/accounting_log.json new file mode 100644 index 0000000..3d5441f --- /dev/null +++ b/json/accounting_log.json @@ -0,0 +1,17 @@ +{ + "models_dir": "${HOME}$/py/rbac/models", + "output_dir": "${HOME}$/py/sage/wwwroot/accounting_log", + "dbname": "sage", + "tblname": "accounting_log", + "title":"科目", + "params": { + "sortby":"name", + "browserfields": { + "exclouded": ["id"], + "cwidth": {} + }, + "editexclouded": [ + "id" + ] + } +} diff --git a/json/build.sh b/json/build.sh new file mode 100755 index 0000000..2c4a9d1 --- /dev/null +++ b/json/build.sh @@ -0,0 +1,3 @@ +#!/usr/bin/bash + +xls2ui -m ../models -o ../wwwroot accounting *.json diff --git a/json/subject.json b/json/subject.json new file mode 100644 index 0000000..71a7c41 --- /dev/null +++ b/json/subject.json @@ -0,0 +1,25 @@ +{ + "models_dir": "${HOME}$/py/rbac/models", + "output_dir": "${HOME}$/py/sage/wwwroot/subject", + "dbname": "sage", + "tblname": "subject", + "title":"科目", + "params": { + "sortby":"name", + "browserfields": { + "exclouded": ["id"], + "cwidth": {} + }, + "editexclouded": [ + "id" + ], + "subtables":[ + { + "field":"subjectid", + "title":"账户设置", + "url":"../account_config", + "subtable":"account_config" + } + ] + } +} diff --git a/models/acc_balance.xlsx b/models/acc_balance.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..8b4cd3a2a39c6821556da17346c383d1caa6cfe4 GIT binary patch literal 14912 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 z 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 literal 0 HcmV?d00001 diff --git a/models/acc_detail.xlsx b/models/acc_detail.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..a3731f7339ba792454f50bf1f717f33f2851262c GIT binary patch literal 17498 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 BWcdI9 literal 0 HcmV?d00001 diff --git a/models/account_config.xlsx b/models/account_config.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ef5b18e41ec4f0f61a4010ba70da898a979df3f6 GIT binary patch literal 16885 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 DWCG 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 literal 0 HcmV?d00001 diff --git a/models/bill.xlsx b/models/bill.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..6ba50f1d9d1f43b32cbd15552fd6bacb1f94fbe4 GIT binary patch literal 16012 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
7RQ51`viBQnd9 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 KmD%(CJo|qE@Be%N literal 0 HcmV?d00001 diff --git a/models/ledger.xlsx b/models/ledger.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..955d4bf5b794c45a9f619c21aa481c43fee05f53 GIT binary patch literal 17348 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 literal 0 HcmV?d00001 diff --git a/models/subject.xlsx b/models/subject.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..5406d6d4b42cdb5aa704d821236f1599a5923017 GIT binary patch literal 16876 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 literal 0 HcmV?d00001 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..05a1a48 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +# git+https://git.kaiyuancloud.cn/yumoqing/rbac + diff --git a/script/roleperm.sh b/script/roleperm.sh new file mode 100755 index 0000000..1923f6e --- /dev/null +++ b/script/roleperm.sh @@ -0,0 +1,8 @@ +#!/usr/bin/bash + +python ~/py/rbac/script/roleperm.py sage accounting owner superuser account_config accounting_config subject +python ~/py/rbac/script/roleperm.py sage accounting reseller operator account acc_detail acc_balance accounting_log bill bill_detail ledger +python ~/py/rbac/script/roleperm.py sage accounting reseller sale account acc_detail acc_balance accounting_log bill bill_detail ledger +python ~/py/rbac/script/roleperm.py sage accounting reseller accountant account acc_detail acc_balance accounting_log bill bill_detail ledger +python ~/py/rbac/script/roleperm.py sage accounting customer customer account acc_detail acc_balance accounting_log bill bill_detail ledger + diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..2f9af9e --- /dev/null +++ b/setup.py @@ -0,0 +1,52 @@ +# -*- coding: utf-8 -*- + +from accounting.version import __version__ +try: + from setuptools import setup +except ImportError: + from distutils.core import setup +required = [] +with open('requirements.txt', 'r') as f: + ls = f.read() + required = ls.split('\n') + +with open('accounting/version.py', 'r') as f: + x = f.read() + y = x[x.index("'")+1:] + z = y[:y.index("'")] + version = z +with open("README.md", "r") as fh: + long_description = fh.read() + +name = "accounting" +description = "accounting" +author = "yumoqing" +email = "yumoqing@gmail.com" + +package_data = {} + +setup( + name="accounting", + version=version, + + # uncomment the following lines if you fill them out in release.py + description=description, + author=author, + author_email=email, + platforms='any', + install_requires=required , + packages=[ + "accounting" + ], + package_data=package_data, + keywords = [ + ], + url="https://github.com/yumoqing/accounting", + long_description=long_description, + long_description_content_type="text/markdown", + classifiers = [ + 'Operating System :: OS Independent', + 'Programming Language :: Python :: 3', + 'License :: OSI Approved :: MIT License', + ], +) diff --git a/test/open_account.py b/test/open_account.py new file mode 100644 index 0000000..4e7ecf0 --- /dev/null +++ b/test/open_account.py @@ -0,0 +1,31 @@ +from run_test import run +from appPublic.log import debug +from sqlor.dbpools import DBPools +from accounting.openaccount import openAllCustomerAccounts, \ + openOwnerAccounts, openAllProviderAccounts, openAllResellerAccounts + +import test_rf + +async def OpenAccount(): + orgid = '_VaV5trl8faujgr7xaE3D' + db = DBPools() + async with db.sqlorContext('sage') as sor: + try: + await openAllCustomerAccounts(sor, orgid) + except Exception as e: + debug(f'{e}') + try: + await openOwnerAccounts(sor, orgid) + except Exception as e: + debug(f'{e}') + try: + await openAllProviderAccounts(sor, orgid) + except Exception as e: + debug(f'{e}') + try: + await openAllResellerAccounts(sor, orgid) + except Exception as e: + debug(f'{e}') + +if __name__ == '__main__': + run(OpenAccount) diff --git a/test/recharge.py b/test/recharge.py new file mode 100644 index 0000000..3e5213c --- /dev/null +++ b/test/recharge.py @@ -0,0 +1,47 @@ +import asyncio +from sqlor.dbpools import DBPools +from appPublic.jsonConfig import getConfig +from appPublic.dictObject import DictObject +from accounting.recharge import recharge_accounting + +async def test1(): + db = DBPools() + dbname = 'sage' + async with db.sqlorContext(dbname) as sor: + await recharge_accounting(sor, '4twr0MGHMZ4aFHYzQ9Lxh', 'RECHARGE', 'oEdlkg4SfX6JH5xQnCHW', '2025-01-10', 100) + +async def test2(): + rl = DictObject() + rl.customerid = '4zXVMkBCEaTmR0xwneUBX' + rl.recharge_date = '2024-09-21' + rl.recharge_amt = 100 + rl.action = 'RECHARGE_REVERSE' + rl.orderid = '1' + rl.recharge_channel = 'alipay' + ra = RechargeAccounting(rl) + db = DBPools() + async with db.sqlorContext('sage') as sor: + await ra.accounting(sor) + +async def test(): + await test1() + await test2() + +if __name__ == '__main__': + DBPools({ + "sage":{ + "driver":"aiomysql", + "async_mode":True, + "coding":"utf8", + "maxconn":100, + "dbname":"sage", + "kwargs":{ + "user":"test", + "db":"sage", + "password":"QUZVcXg5V1p1STMybG5Ia6mX9D0v7+g=", + "host":"localhost" + } + } + }) + asyncio.get_event_loop().run_until_complete(test1()) + diff --git a/test/run_test.py b/test/run_test.py new file mode 100644 index 0000000..b72908d --- /dev/null +++ b/test/run_test.py @@ -0,0 +1,12 @@ +import os +import asyncio + +from sqlor.dbpools import DBPools +from appPublic.jsonConfig import getConfig + +def run(test_coro): + os.chdir('/Users/ymq/py/sage') + conf = getConfig() + DBPools(conf.databases) + asyncio.get_event_loop().run_until_complete(test_coro()) + diff --git a/test/test_rf.py b/test/test_rf.py new file mode 100644 index 0000000..bd9e058 --- /dev/null +++ b/test/test_rf.py @@ -0,0 +1,45 @@ +from appPublic.registerfunction import RegisterFunction + +rf = RegisterFunction() + +def get_module_database(module_name): + return 'sage' + +rf.register('get_module_database', get_module_database) + +async def get_providers_by_orgid(sor, accounting_orgid): + sql = """select * from organization a, orgtypes b +where a.parentid = ${accounting_orgid}$ and + b.orgtypeid = 'provider' and + a.id = b.orgid """ + recs = await sor.sqlExe(sql, {'accounting_orgid':accounting_orgid}) + return recs + +rf.register('get_providers_by_orgid', get_providers_by_orgid) + +async def get_resellers_by_orgid(sor, accounting_orgid): + sql = """select * from organization a, orgtypes b +where a.parentid=${accounting_orgid}$ and + a.id = b.orgid and + b.orgtypeid = 'reseller'""" + recs = await sor.sqlExe(sql, {'accounting_orgid':accounting_orgid}) + return recs + +rf.register('get_resellers_by_orgid', get_resellers_by_orgid) + +async def get_customers_by_orgid(sor, accounting_orgid): + sql = """select * from organization a, + (select orgid, count(*) cnt + from orgtypes + where orgtypeid in ('customer', 'personalcustomer', 'agencycustomer') + group by orgid + ) b +where a.parentid=${accounting_orgid}$ and + a.id = b.orgid and + b.cnt > 0 + """ + recs = await sor.sqlExe(sql, {'accounting_orgid':accounting_orgid}) + return recs + +rf.register('get_customers_by_orgid', get_customers_by_orgid) +