diff --git a/netforce_clinic/layouts/fin_account_settings.xml b/netforce_clinic/layouts/fin_account_settings.xml
new file mode 100644
index 0000000..e6ae90d
--- /dev/null
+++ b/netforce_clinic/layouts/fin_account_settings.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/netforce_clinic/models/account_invoice.py b/netforce_clinic/models/account_invoice.py
index 77bb01a..44d1c39 100644
--- a/netforce_clinic/models/account_invoice.py
+++ b/netforce_clinic/models/account_invoice.py
@@ -1,3 +1,5 @@
+import time
+
from netforce.model import Model, fields, get_model
class AccountInvoice(Model):
@@ -75,4 +77,237 @@ class AccountInvoice(Model):
}
get_model("account.fixed.asset").create(vals)
+ def post(self,ids,context={}):
+ t0=time.time()
+ settings=get_model("settings").browse(1)
+ for obj in self.browse(ids):
+ obj.check_related()
+ if abs(obj.amount_total)<0.001:
+ raise Exception("Invoice total is zero")
+ partner=obj.partner_id
+ if obj.type=="out":
+ account_id=partner.account_receivable_id.id or settings.account_receivable_id.id
+ if not account_id:
+ raise Exception("Account receivable not found")
+ elif obj.type=="in":
+ account_id=partner.account_payable_id.id or settings.account_payable_id.id
+ if not account_id:
+ raise Exception("Account payable not found")
+ sign=obj.type=="out" and 1 or -1
+ if obj.inv_type=="credit":
+ sign*=-1
+ obj.write({"account_id": account_id})
+ if obj.type=="out":
+ desc="Sale; "+partner.name
+ elif obj.type=="in":
+ desc="Purchase; "+partner.name
+ if obj.type=="out":
+ journal_id=settings.sale_journal_id.id
+ if not journal_id:
+ raise Exception("Sales journal not found")
+ elif obj.type=="in":
+ journal_id=settings.purchase_journal_id.id
+ if not journal_id:
+ raise Exception("Purchases journal not found")
+ if obj.currency_rate:
+ currency_rate=obj.currency_rate
+ else:
+ if obj.currency_id.id==settings.currency_id.id:
+ currency_rate=1.0
+ else:
+ rate_from=obj.currency_id.get_rate(date=obj.date)
+ if not rate_from:
+ raise Exception("Missing currency rate for %s"%obj.currency_id.code)
+ rate_to=settings.currency_id.get_rate(date=obj.date)
+ if not rate_to:
+ raise Exception("Missing currency rate for %s"%settings.currency_id.code)
+ currency_rate=rate_from/rate_to
+ obj.write({"currency_rate":currency_rate})
+ move_vals={
+ "journal_id": journal_id,
+ "number": obj.number,
+ "date": obj.date,
+ "ref": obj.ref,
+ "narration": desc,
+ "related_id": "account.invoice,%s"%obj.id,
+ "company_id": obj.company_id.id,
+ }
+ lines=[]
+ taxes={}
+ tax_nos=[]
+ t01=time.time()
+ total_amt=0.0
+ total_base=0.0
+ total_tax=0.0
+ for line in obj.lines:
+ cur_amt=get_model("currency").convert(line.amount,obj.currency_id.id,settings.currency_id.id,rate=currency_rate)
+ total_amt+=cur_amt
+ tax_id=line.tax_id
+ if tax_id and obj.tax_type!="no_tax":
+ base_amt=get_model("account.tax.rate").compute_base(tax_id,cur_amt,tax_type=obj.tax_type)
+ tax_comps=get_model("account.tax.rate").compute_taxes(tax_id,base_amt,when="invoice")
+ for comp_id,tax_amt in tax_comps.items():
+ tax_vals=taxes.setdefault(comp_id,{"tax_amt":0,"base_amt":0})
+ tax_vals["tax_amt"]+=tax_amt
+ tax_vals["base_amt"]+=base_amt
+ total_tax+=tax_amt
+ else:
+ base_amt=cur_amt
+ total_base+=base_amt
+ acc_id=line.account_id.id
+ if not acc_id:
+ raise Exception("Missing line account for invoice line '%s'"%line.description)
+ amt=base_amt*sign
+ line_vals={
+ "description": line.description,
+ "account_id": acc_id,
+ "credit": amt>0 and amt or 0,
+ "debit": amt<0 and -amt or 0,
+ "track_id": line.track_id.id,
+ "track2_id": line.track2_id.id,
+ "partner_id": partner.id,
+ }
+ lines.append(line_vals)
+ for comp_id,tax_vals in taxes.items():
+ comp=get_model("account.tax.component").browse(comp_id)
+ acc_id=comp.account_id.id
+ if not acc_id:
+ raise Exception("Missing account for tax component %s"%comp.name)
+ amt=tax_vals["tax_amt"]*sign
+ line_vals={
+ "description": desc,
+ "account_id": acc_id,
+ "credit": amt>0 and amt or 0,
+ "debit": amt<0 and -amt or 0,
+ "tax_comp_id": comp_id,
+ "tax_base": tax_vals["base_amt"],
+ "partner_id": partner.id,
+ "invoice_id": obj.id,
+ }
+ if comp.type in ("vat","vat_exempt"):
+ if obj.type=="out":
+ if obj.tax_no:
+ tax_no=obj.tax_no
+ else:
+ tax_no=self.gen_tax_no(exclude=tax_nos,context={"date":obj.date})
+ tax_nos.append(tax_no)
+ obj.write({"tax_no":tax_no})
+ line_vals["tax_no"]=tax_no
+ elif obj.type=="in":
+ line_vals["tax_no"]=obj.tax_no
+ lines.append(line_vals)
+ if obj.tax_type=="tax_in":
+ rounding=total_amt-(total_base+total_tax)
+ if abs(rounding)>0.00499: # XXX
+ amt=rounding*sign
+ if not settings.rounding_account_id.id:
+ raise Exception("Missing rounding account in financial settings")
+ line_vals={
+ "description": desc,
+ "account_id": settings.rounding_account_id.id,
+ "credit": amt>0 and amt or 0,
+ "debit": amt<0 and -amt or 0,
+ "partner_id": partner.id,
+ "invoice_id": obj.id,
+ }
+ lines.append(line_vals)
+ t02=time.time()
+ dt01=(t02-t01)*1000
+ print("post dt01",dt01)
+ groups={}
+ keys=["description","account_id","track_id","tax_comp_id","partner_id","invoice_id","reconcile_id"]
+ for line in lines:
+ key_val=tuple(line.get(k) for k in keys)
+ if key_val in groups:
+ group=groups[key_val]
+ group["debit"]+=line["debit"]
+ group["credit"]+=line["credit"]
+ if line.get("tax_base"):
+ if "tax_base" not in group:
+ group["tax_base"]=0
+ group["tax_base"]+=line["tax_base"]
+ else:
+ groups[key_val]=line.copy()
+ group_lines=sorted(groups.values(),key=lambda l: (l["debit"],l["credit"]))
+ for line in group_lines:
+ amt=line["debit"]-line["credit"]
+ amt=get_model("currency").round(settings.currency_id.id,amt)
+ if amt>=0:
+ line["debit"]=amt
+ line["credit"]=0
+ else:
+ line["debit"]=0
+ line["credit"]=-amt
+
+ is_match=False
+ if settings.acc_prod_match and obj.type=='out':
+ print("#POST: clinic customize")
+ cst=get_model('clinic.setting').browse(1)
+ prod_acc=cst.get_product_account
+ move_vals["lines"]=[]
+ for line in group_lines:
+ desc=line['description']
+ ar_debit_id=None
+ #ar_credit_id=None
+ for prod_id in get_model('product').search([['name','=',desc]]):
+ for ptype_id in get_model("clinic.patient.type").search([['contact_id','=',partner.id]]):
+ acc=prod_acc(prod_id,ptype_id,'credit')
+ #ar_credit_id=acc.get("ar_credit_id")
+ ar_debit_id=acc.get("ar_debit_id")
+ if ar_debit_id:
+ break
+ if not ar_debit_id:
+ raise Exception("Missing AR Debit Account for product %s"%(desc))
+ line_vals={
+ "description": desc,
+ "account_id": ar_debit_id,
+ "debit": line['credit'],
+ "credit": 0,
+ "due_date": obj.due_date,
+ "partner_id": partner.id,
+ 'track_id': line['track_id'],
+ }
+ move_vals["lines"]+=[("create",line_vals)]
+ move_vals["lines"]+=[("create",vals) for vals in group_lines]
+ is_match=True
+ if not is_match:
+ print("#POST: standard account")
+ amt=0
+ for line in group_lines:
+ amt-=line["debit"]-line["credit"]
+ line_vals={
+ "description": desc,
+ "account_id": account_id,
+ "debit": amt>0 and amt or 0,
+ "credit": amt<0 and -amt or 0,
+ "due_date": obj.due_date,
+ "partner_id": partner.id,
+ }
+ acc=get_model("account.account").browse(account_id)
+ if acc.currency_id.id!=settings.currency_id.id:
+ if acc.currency_id.id!=obj.currency_id.id:
+ raise Exception("Invalid account currency for this invoice: %s"%acc.code)
+ line_vals["amount_cur"]=obj.amount_total*sign
+ move_vals["lines"]=[("create",line_vals)]
+ move_vals["lines"]+=[("create",vals) for vals in group_lines]
+
+ t03=time.time()
+ dt02=(t03-t02)*1000
+ print("post dt02",dt02)
+ move_id=get_model("account.move").create(move_vals)
+ t04=time.time()
+ dt03=(t04-t03)*1000
+ print("post dt03",dt03)
+ get_model("account.move").post([move_id])
+ t05=time.time()
+ dt04=(t05-t04)*1000
+ print("post dt04",dt04)
+ obj.write({"move_id":move_id,"state":"waiting_payment"})
+ t06=time.time()
+ dt05=(t06-t05)*1000
+ print("post dt05",dt05)
+ t1=time.time()
+ dt=(t1-t0)*1000
+ print("invoice.post <<< %d ms"%dt)
+
AccountInvoice.register()
diff --git a/netforce_clinic/models/fin_setting.py b/netforce_clinic/models/fin_setting.py
index dba9c55..3c9e9a4 100644
--- a/netforce_clinic/models/fin_setting.py
+++ b/netforce_clinic/models/fin_setting.py
@@ -8,6 +8,7 @@ class Settings(Model):
"income_account_id": fields.Many2One("account.account","Income Account"),
"ap_nurse_id": fields.Many2One("account.account","Account Payment Nurse"),
"ap_doctor_id": fields.Many2One("account.account","Account Payment Doctor"),
+ 'acc_prod_match': fields.Boolean("Account Product Matching"),
}
def get_default_address(self,ids,context={}):
diff --git a/netforce_clinic/models/hd_case.py b/netforce_clinic/models/hd_case.py
index 82f00a1..787d705 100644
--- a/netforce_clinic/models/hd_case.py
+++ b/netforce_clinic/models/hd_case.py
@@ -104,6 +104,7 @@ class HDCase(Model):
dlz_name=','.join([dlz for dlz in dlz_name])
epo_names=[]
mdc_names=[]
+ iron_names=[]
fee=0
lab=0
misc=0
@@ -113,6 +114,7 @@ class HDCase(Model):
for line in obj.lines:
amt=line.amount or 0
prod=line.product_id
+ prod_name=prod.description or prod.name or ""
categ=line.product_categ_id
if categ and prod:
sign=1
@@ -120,24 +122,17 @@ class HDCase(Model):
sign=-1
if categ.parent_id:
if categ.parent_id.code=='MDC':
- name=prod.description or prod.name or ""
- ##name=name.split("-")
- #name=name.replace("-SSO","")
- #name=name.title()
- #name=name[0].title()
if reimbursable_ctx:
if reimbursable_ctx==line.reimbursable:
mdc+=amt
- mdc_names.append(name or "")
+ mdc_names.append(prod_name or "")
else:
mdc+=amt
mdc_names.append(name or "")
if categ.code=='EPO':
- name=prod.description or prod.name or ""
- #name=name.split("-")
- #if name:
- #name=name[0].title()
- epo_names.append(name.title())
+ epo_names.append(prod_name.title())
+ elif categ.code=='IVR':
+ iron_names.append(prod_name.title())
elif categ.code=='FEE':
fee+=amt*sign
elif categ.code=='DLZ':
@@ -158,12 +153,13 @@ class HDCase(Model):
misc+=amt
res[obj.id]={
'epo': ','.join([n for n in epo_names]),
+ 'mdc_name': ','.join([n for n in mdc_names]),
+ 'iron_name': ','.join([n for n in iron_names]),
'fee': fee,
'lab': lab,
'misc': misc,
'mdc': mdc,
'srv': srv,
- 'mdc_name': ','.join([n for n in mdc_names]),
'dlz_id': dlz_id,
'dlz_price': dlz_price,
'dlz_name': dlz_name,
@@ -558,7 +554,6 @@ class HDCase(Model):
}
payment_id=get_model("account.payment").create(vals,context=context)
obj.write({
- #'state': 'paid',
'payment_lines': [('create',{
'payment_id': payment_id,
'amount': pay_amount,
diff --git a/netforce_clinic/models/hd_case_payment.py b/netforce_clinic/models/hd_case_payment.py
index 402a7c3..d226259 100644
--- a/netforce_clinic/models/hd_case_payment.py
+++ b/netforce_clinic/models/hd_case_payment.py
@@ -45,7 +45,7 @@ class HDCasePayment(Model):
hd_case.post_invoices()
if obj.pay_amount:
hd_case.make_payment(context=context)
- hd_case.do_expense()
+ #hd_case.do_expense()
inv_remain_amount=0
for inv in hd_case.invoices:
@@ -82,7 +82,7 @@ class HDCasePayment(Model):
hd_case.make_invoices(context=context)
hd_case.post_invoices()
hd_case.create_cycle_item()
- hd_case.do_expense()
+ #hd_case.do_expense()
hd_case.write({
'state': 'waiting_payment',
'req_fee': 0, # force to hide button pay!
diff --git a/netforce_clinic/models/report_cycle_item.py b/netforce_clinic/models/report_cycle_item.py
index 98dc708..d66dfc2 100644
--- a/netforce_clinic/models/report_cycle_item.py
+++ b/netforce_clinic/models/report_cycle_item.py
@@ -247,12 +247,14 @@ class ReportCycleItem(Model):
epo_items=[{'name': k, 'qty': v} for k,v in epos.items() if k ]
nlines.append({
'sub': 'show',
+ 'is_sub': True,
'sub_txt': 'รวม',
'row_color': '#dfdfdf',
'no': count,
'fee': sub_fee,
'mdc': sub_mdc,
'epo_items': epo_items,
+ 'epo_txt': ', '.join(['%s = %s'%(k,v) for k,v in epos.items() if k])
})
for epo_item in epo_items:
if not total_epos.get(epo_item['name']):
@@ -285,6 +287,9 @@ class ReportCycleItem(Model):
})
index+=1
vscl_txt=' '.join(['%s = %s'%(x['description'],x['qty']) for x in vscl_lines])
+ total_epo_txt=''
+ for t_epo in total_epo_items:
+ total_epo_txt+='%s = %s '%(t_epo['name'], t_epo['qty'])
data={
'company_name': company_name or "",
'lines': nlines,
@@ -301,6 +306,7 @@ class ReportCycleItem(Model):
'total_pt': total_pt,
'total_epo': sum([x['qty'] for x in total_epo_items]),
'total_epo_items': total_epo_items,
+ 'total_epo_txt': total_epo_txt,
}
return data
diff --git a/netforce_clinic/reports/report_cycle_item.xlsx b/netforce_clinic/reports/report_cycle_item.xlsx
index 9b6dd22..d867e67 100644
Binary files a/netforce_clinic/reports/report_cycle_item.xlsx and b/netforce_clinic/reports/report_cycle_item.xlsx differ
diff --git a/netforce_clinic/templates/report_cycle_item.hbs b/netforce_clinic/templates/report_cycle_item.hbs
index 26d0de7..7e902e5 100644
--- a/netforce_clinic/templates/report_cycle_item.hbs
+++ b/netforce_clinic/templates/report_cycle_item.hbs
@@ -13,7 +13,8 @@
ชื่อ-สกุล |
แพทย์ |
สิทธ์ |
- ยาฉีด |
+ EPO |
+ Iron |
HCT |
DZ |
N/U |
@@ -38,18 +39,19 @@
{{dname}} |
{{tname}} |
{{mdc_name}} |
+ {{iron_name}} |
{{hct}} |
{{dlz_name}} |
{{dlz_use}} |
{{nfirst_name}} |
{{else}}
{{#ifeq sub "show"}}
- ผู้ป่วย | ยาฉีด |
+ รวม |
|
{{no}} |
-
+ |
{{#each epo_items}}
- {{name}} : {{qty}}
+ {{name}} = {{qty}}
{{/each}}
|
{{else}}
@@ -61,6 +63,7 @@
{{dname}} |
{{tname}} |
{{mdc_name}} |
+ {{iron_name}} |
{{hct}} |
{{dlz_name}} |
{{dlz_use}} |
@@ -73,7 +76,7 @@
ผู้ป่วยทั้งหมด |
|
{{total_pt}} |
-
+ |
{{#each ptype_lines}}
{{name}} : {{qty}}
@@ -87,10 +90,10 @@
|
- ยาฉีดทั้งหมด |
+ ยาทั้งหมด |
|
{{total_epo}} |
-
+ |
{{#each total_epo_items}}
{{name}} = {{qty}}
|