diff --git a/accounting/accounting_config.py b/accounting/accounting_config.py
index b4b34b6..39eed08 100644
--- a/accounting/accounting_config.py
+++ b/accounting/accounting_config.py
@@ -5,7 +5,7 @@ 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
+from appPublic.log import debug, exception
 from sqlor.dbpools import DBPools
 from appPublic.timeUtils import curDateString
 # from .argsconvert import ArgsConvert
@@ -25,17 +25,13 @@ async def get_accounting_config(sor):
 	return None
 
 class Accounting:
-	/*
+	"""
 	需要caller功能:
 	caller中要有分录中的变量
 	get_accounting_orgid(leg) 获得记账机构
 	get_account(leg,accounting_orgid)	获得记账账号(通过科目,机构类型,账务机构确定一个唯一的账号)
-	*/
-	def __init__(self, caller, 
-					accounting_orgid, 
-					customerid,
-					resellerid=None
-	): 
+	"""
+	def __init__(self, caller):
 		self.caller = caller
 		self.curdate = caller.curdate
 		self.realtimesettled = False
@@ -43,16 +39,14 @@ class Accounting:
 		self.timestamp = caller.timestamp
 		self.billid = caller.billid
 		self.action = caller.action
-		self.billid = getID()
 		self.summary = f'{self.caller.orderid}:{self.caller.billid}'
 		self.providerid = caller.providerid
 		self.productid = caller.productid
-		self.accounting_orgid = accounting_orgid
-		self.resellerid = resellerid
-		self.customerid = customerid
+		self.resellerid = caller.resellerid
+		self.customerid = caller.customerid
 		self.own_salemode = None
 		self.reseller_salemode = None
-		self.variable = self.caller.varable
+		self.variable = caller.variable
 
 	async def setup_accounting_legs(self):
 		global accounting_config
@@ -68,14 +62,18 @@ class Accounting:
 			else:
 				l['acc_dir'] = l['accounting_dir']
 			ac = ArgsConvert('${', '}$')
-			debug(f'{l["id"]},{l["amt_pattern"]=}')
 			try:
 				amtstr = ac.convert(l['amt_pattern'],
 							self.variable.copy()
 				)
-				l['amount'] = eval(amtstr)
+				debug(f'{l["amt_pattern"]=}, {amtstr=}, {self.variable=}')
+				if isinstance(amtstr, str):
+					l['amount'] = eval(amtstr)
+				else:
+					l['amount'] = amtstr
+ 
 			except Exception as e:
-				print(l['amt_pattern'], l['id'], self.variable)
+				exception(f'{e=}, {l['amt_pattern']}, {self.variable=}')
 				raise e
 
 			if l['amount'] is None:
@@ -87,9 +85,9 @@ class Accounting:
 		credit_balance = 0.0
 		for l in legs:
 			if l['acc_dir'] == DEBT:
-				debt_balance += legs['amount']
+				debt_balance += l['amount']
 			else:
-				credit_balance += legs['amount']
+				credit_balance += l['amount']
 		if abs(credit_balance - debt_balance) >= 0.01:
 			e = Exception('accounting legs not balance')
 			exception(f'{legs=}, {e=}')
@@ -102,14 +100,18 @@ class Accounting:
 		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_accounting_orgid(sor, leg.accounting_orgtype)
-			orgid = await self.caller.get_accounting_orgid(sor, leg.orgtype)
+			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_account_orgid(sor, leg.org1type)
+						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('can not get accountid {accounting_orgid=}, {leg=}')
-				raise AccountIdNone(self.accounting_orgid, orgid, leg['subjectname'])
+				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):
@@ -197,9 +199,9 @@ where accountid=${accid}$
 		# summary = self.summary
 		ns = {
 			'id':getID(),
-			'accounting_orgid' : self.accounting_orgid,
+			'accounting_orgid' : leg['accounting_orgid'],
 			'billid' : self.billid,
-			'description' : self.specstr,
+			'description' : self.summary,
 			'participantid' : leg['orgid'],
 			'participanttype' : leg['orgtype'],
 			'subjectname' : leg['subjectname'],
@@ -214,7 +216,7 @@ where accountid=${accid}$
 			'acc_date':self.curdte,
 			'acc_timestamp':self.timestamp,
 			'acc_dir':leg['acc_dir'],
-			'summary':leg['summary'],
+			'summary':self.summary,
 			'amount':leg['amount'],
 			'billid':self.billid
 		}
@@ -225,7 +227,7 @@ where accountid=${accid}$
 			'acc_date':self.curdate,
 			'acc_timestamp':self.timestamp,
 			'acc_dir':leg['acc_dir'],
-			'summary':leg['summary'],
+			'summary':self.summary,
 			'amount':leg['amount'],
 			'balance':leg['new_balance'],
 			'acclogid':logid
diff --git a/accounting/bill.py b/accounting/bill.py
index 150cb31..c4fb83c 100644
--- a/accounting/bill.py
+++ b/accounting/bill.py
@@ -1,13 +1,14 @@
 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, AccountingOrgs
-from .businessdate import get_business_date
+from .accounting_config import get_accounting_config, Accounting
 # from .settle import SettleAccounting
 
 async def write_bill(sor, customerid, userid, orderid, business_op, amount):
@@ -18,6 +19,7 @@ async def write_bill(sor, customerid, userid, orderid, business_op, amount):
 	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())
diff --git a/accounting/getaccount.py b/accounting/getaccount.py
index b118d65..52ad42b 100644
--- a/accounting/getaccount.py
+++ b/accounting/getaccount.py
@@ -1,4 +1,6 @@
+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
 
@@ -13,12 +15,41 @@ async def get_account(sor, accounting_orgid, orgid, subjectid, org1id=None):
 	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:
@@ -26,31 +57,6 @@ async def get_account(sor, accounting_orgid, orgid, subjectid, org1id=None):
 			return rec['id']
 	return None
 
-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
@@ -65,33 +71,28 @@ where a.subjectid = b.id and
 	if len(recs) == 0:
 		return None
 	for rec in recs:
-		if a.org1id == org1id:
+		if rec.org1id == org1id:
 			return rec['id']
 	return None
 
 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)
+	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:
-		print(f"{customerid=}'s parent organization not found")
+		debug(f"{customerid=}'s parent organization not found")
 		return None
 
-	balance = await getAccountBalance(sor, orgid, customerid, name)
+	balance = await getAccountBalance(sor, orgid, customerid, name, None)
 	if balance is None:
-		print(f'accid is None, {orgid=}, {customerid=}, {name=}')
+		debug(f'accid is None, {orgid=}, {customerid=}, {name=}')
 		return None
 	return balance
 
@@ -100,14 +101,35 @@ async def getAccountBalance(sor, accounting_orgid, orgid, subjectname, org1id):
 										orgid, 
 										subjectname,org1id)
 	if accid is None:
-		print(f'accid is None, {accounting_orgid=}, {orgid=}, {subjectname=}')
+		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:
-		print(f'acc_balance is None, {accid=}')
+		debug(f'acc_balance is None, {accid=}')
 		return 0
 	return balances[0]['balance']
 
diff --git a/accounting/init.py b/accounting/init.py
index 9ab0772..c32923c 100644
--- a/accounting/init.py
+++ b/accounting/init.py
@@ -1,18 +1,21 @@
 from appPublic.registerfunction import RegisterFunction
-from appPublic.dictOBject import DictObject
+from appPublic.dictObject import DictObject
 from appPublic.log import debug, exception, error
 from ahserver.serverenv import ServerEnv
-from accounting.accounting_config import AccountingOrgs
+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
 
 def load_accounting():
 	g = ServerEnv()
-	g.recharge_accounting = recharge_accounting
-	g.pay_accounting = pay_accounting
-	g.settle_accounting = settle_accounting
-	g.open_customer_account = open_customer_account
-	g.open_reseller_account = open_reseller_account
-	g.open_provider_account = open_provider_account
-	g.open_owner_account = open_owner_account
-	g.get_customer_balance = get_customer_balance
+	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
diff --git a/accounting/openaccount.py b/accounting/openaccount.py
index 4f035fc..3c0efcb 100644
--- a/accounting/openaccount.py
+++ b/accounting/openaccount.py
@@ -4,8 +4,15 @@ 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,
@@ -18,7 +25,7 @@ async def openAccount(sor, accounting_orgid, orgid, account_config, org1id=None)
 		ns['org1id'] = org1id;
 	debug(f'openAccount(), {ns=}')
 	await sor.C('account', ns.copy())
-	print(ns, 'opened')
+	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 "
@@ -27,7 +34,7 @@ async def openPartyAccounts(sor, accounting_orgid, orgid, party_type, org1id=Non
 		addon_cond = " and a.party1type = ${party1type}$ "
 		ns['party1type'] = party1_type
 
-	sql = """select a.*, b.id as subjectid, b.balance_side from account_config a, subject b
+	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}$ """
@@ -38,24 +45,18 @@ where a.subjectid = b.id """ \
 		debug(f'{r=}')
 		await openAccount(sor, accounting_orgid, orgid, r, org1id=org1id)
 
-async def _openPartyAccounts(accounting_orgid, orgid, party_type):
-	db = DBPools()
-	dbname = await rfexe('get_module_dbname', 'accounting')
-	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)
+	return await openPartyAccounts(sor, accounting_orgid, orgid, PARTY_RESELLER)
 
 async def openCustomerAccounts(sor, accounting_orgid, orgid):
-	return await _openPartyAccounts(accounting_orgid, orgid, PARTY_CUSTOMER)
+	return await openPartyAccounts(sor, accounting_orgid, orgid, PARTY_CUSTOMER)
 
 async def openOwnerAccounts(sor, accounting_orgid):
 	orgid = accounting_orgid
-	return await _openPartyAccounts(accounting_orgid, orgid, PARTY_OWNER)
+	return await openPartyAccounts(sor, accounting_orgid, orgid, PARTY_OWNER)
 
 async def openProviderAccounts(sor, accounting_orgid, orgid):
-	return await _openPartyAccounts(accounting_orgid, orgid, PARTY_PROVIDER)
+	return await openPartyAccounts(sor, accounting_orgid, orgid, PARTY_PROVIDER)
 
 async def openAllCustomerAccounts(sor, accounting_orgid):
 	rf = RegisterFunction()
@@ -91,13 +92,10 @@ async def openAllProviderAccounts(sor, accounting_orgid):
 		await openProviderAccounts(sor, accounting_orgid, r['id'])
 
 async def openRetailRelationshipAccounts(sor, accounting_orgid, providerid, resellerid):
-	db = DBPools()
-	dbname = await rfexe('get_module_dbname', 'accounting')
-	async with db.sqlorContext(dbname) as sor:
-		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)
+	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/json/accounting_config.json b/json/accounting_config.json
index c01137a..5818e6f 100644
--- a/json/accounting_config.json
+++ b/json/accounting_config.json
@@ -1,7 +1,4 @@
 {
-    "models_dir": "${HOME}$/py/accounting/models",
-    "output_dir": "${HOME}$/py/sage/wwwroot/accounting_config",
-    "dbname": "sage",
     "tblname": "accounting_config",
 	"title":"账务设置",
     "params": {
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/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
+