diff --git a/netforce_clinic/layouts/clinic_cust_invoice_form.xml b/netforce_clinic/layouts/clinic_cust_invoice_form.xml
index f185557..fcc409b 100644
--- a/netforce_clinic/layouts/clinic_cust_invoice_form.xml
+++ b/netforce_clinic/layouts/clinic_cust_invoice_form.xml
@@ -3,4 +3,8 @@
+
+
+
+
diff --git a/netforce_clinic/layouts/fin_account_settings.xml b/netforce_clinic/layouts/fin_account_settings.xml
index e6ae90d..498c3bd 100644
--- a/netforce_clinic/layouts/fin_account_settings.xml
+++ b/netforce_clinic/layouts/fin_account_settings.xml
@@ -1,5 +1,7 @@
+
diff --git a/netforce_clinic/migrations/__init__.py b/netforce_clinic/migrations/__init__.py
index 204e2c6..bde4b2c 100644
--- a/netforce_clinic/migrations/__init__.py
+++ b/netforce_clinic/migrations/__init__.py
@@ -1,7 +1,3 @@
from . import clinic_setting
-from . import update_account_tracking
-#from . import print_labor_cost
-#from . import hdcase
-#from . import remove_conv_bal
-#from . import import_acc
-#from . import update_labor_cost_line
+#from . import conv_bal
+from . import repost_invoice
diff --git a/netforce_clinic/migrations/conv_bal.py b/netforce_clinic/migrations/conv_bal.py
new file mode 100644
index 0000000..64cf82d
--- /dev/null
+++ b/netforce_clinic/migrations/conv_bal.py
@@ -0,0 +1,55 @@
+from netforce.model import get_model
+from netforce import migration
+from netforce.access import set_active_user, set_active_company
+
+class Migration(migration.Migration):
+ _name="clinic.conv.bal"
+ _version="2.10.0"
+
+ def migrate(self):
+ set_active_user(1)
+ set_active_company(1)
+ #for mv in get_model("account.move").search_browse([['number','ilike', 'OPEN']]):
+ #mv.to_draft()
+ #mv.delete()
+ cbv_id=24
+ cbv=get_model("conv.bal").browse(cbv_id)
+ cbv.write({
+ 'date_fmt': '%Y-%m-%d',
+ 'file': 'tb.csv',
+ })
+ print("import acc file (step 1) running ...")
+ get_model("conv.bal").import_acc_file([cbv.id],context={})
+ get_model("conv.bal").import_acc([cbv.id],context={})
+
+ cbv.write({
+ 'date_fmt': '%d/%m/%Y',
+ 'file': 'ar.csv',
+ })
+ print("import sale file (step 2)running ...")
+ get_model("conv.bal").import_sale_file([cbv.id],context={})
+ get_model("conv.bal").import_sale([cbv.id],context={})
+
+ print("import purch file (step 3) running ...")
+ cbv.write({
+ 'file': 'ap.csv',
+ 'date_fmt': '%d/%m/%Y',
+ })
+ get_model("conv.bal").import_purch_file([cbv.id],context={})
+ get_model("conv.bal").import_purch([cbv.id],context={})
+
+ cbv.write({
+ 'date_fmt': '%Y-%m-%d',
+ })
+
+ print(">> next 3")
+ print("create_open_entry...")
+ cbv.create_open_entry()
+ print("create_sale_invoices...")
+ cbv.create_sale_invoices()
+ print("create_purch_invoices...")
+ cbv.create_purch_invoices()
+ print("Done!")
+ return True
+
+Migration.register()
diff --git a/netforce_clinic/migrations/import_acc.py b/netforce_clinic/migrations/import_acc.py
deleted file mode 100644
index 95a15a9..0000000
--- a/netforce_clinic/migrations/import_acc.py
+++ /dev/null
@@ -1,41 +0,0 @@
-from netforce.model import get_model
-from netforce import migration
-from netforce.access import set_active_user, get_active_user, set_active_company
-
-class Migration(migration.Migration):
- _name="import.acc"
- _version="2.11.0"
-
- def migrate(self):
- set_active_company(1)
- cbv_id=24
- cbv=get_model("conv.bal").browse(cbv_id)
- #cbv.write({
- #'file': 'tb.csv',
- #})
- #print("import acc file (step 1) running ...")
- #get_model("conv.bal").import_acc([cbv.id],context={})
-
- #cbv.write({
- #'file': 'ar.csv',
- #})
- #print("import sale file (step 2)running ...")
- #get_model("conv.bal").import_sale_file([cbv.id],context={})
-
- #print("import purch file (step 3) running ...")
- #cbv.write({
- #'file': 'ap.csv',
- #})
- #get_model("conv.bal").import_purch([cbv.id],context={})
- #print("create invoice from setep 1 to 3 is running...")
- #print("create_open_entry...")
- #print('Done!')
- #cbv.create_open_entry()
- #print("create_sale_invoices...")
- #cbv.create_sale_invoices()
- #print("create_purch_invoices...")
- #cbv.create_purch_invoices()
- print("Done!")
- return True
-
-Migration.register()
diff --git a/netforce_clinic/migrations/repost_invoice.py b/netforce_clinic/migrations/repost_invoice.py
new file mode 100644
index 0000000..401fb53
--- /dev/null
+++ b/netforce_clinic/migrations/repost_invoice.py
@@ -0,0 +1,39 @@
+from netforce.model import get_model
+from netforce import migration
+from netforce.access import set_active_user, set_active_company
+
+class Migration(migration.Migration):
+ _name="clinic.repos.invoice"
+ _version="2.10.0"
+
+ def migrate(self):
+ set_active_user(1)
+ set_active_company(1)
+ for hdcase_line in get_model('clinic.hd.case.line').search_browse([['description','=',None]]):
+ prod=hdcase_line.product_id
+ if prod:
+ hdcase_line.write({
+ 'description': prod.name,
+ })
+
+ for hdcase in get_model('clinic.hd.case').search_browse([]):
+ for inv in hdcase.invoices:
+ if inv.state=='waiting_payment':
+ print('hdcase:repost ---> ', inv.number)
+ inv.to_draft()
+ inv.write({
+ 'hdcase_reconcile': True,
+ })
+ inv.post()
+ for shop in get_model('clinic.shop').search_browse([]):
+ for inv in shop.invoices:
+ print('shop:repost ---> ', inv.number)
+ inv.to_draft()
+ inv.write({
+ 'hdcase_reconcile': True,
+ })
+ inv.post()
+ print("Done!")
+ return True
+
+Migration.register()
diff --git a/netforce_clinic/models/__init__.py b/netforce_clinic/models/__init__.py
index cb004e0..9e9cc5f 100644
--- a/netforce_clinic/models/__init__.py
+++ b/netforce_clinic/models/__init__.py
@@ -140,3 +140,6 @@ from . import share_location
from . import report_cycle_setting
from . import print_labor_cost
from . import print_labor_cost_line
+from . import conv_bal
+from . import conv_sale_invoice
+from . import account_move_line
diff --git a/netforce_clinic/models/account_invoice.py b/netforce_clinic/models/account_invoice.py
index 44d1c39..817f7dd 100644
--- a/netforce_clinic/models/account_invoice.py
+++ b/netforce_clinic/models/account_invoice.py
@@ -9,6 +9,7 @@ class AccountInvoice(Model):
'department_id': fields.Many2One("clinic.department","Department",search=True),
'patient_partner_id': fields.Many2One("partner","Patient",search=True),
'hdcase_credit': fields.Boolean("HD Case Credit"),
+ 'hdcase_reconcile': fields.Boolean("HD Case Reconcile"),
}
def _get_number(self,context={}):
@@ -240,15 +241,19 @@ class AccountInvoice(Model):
line["credit"]=-amt
is_match=False
- if settings.acc_prod_match and obj.type=='out':
+ if obj.hdcase_reconcile 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']
+ if not desc:
+ print("skip no description ", obj.number)
+ continue
ar_debit_id=None
#ar_credit_id=None
+ # search from patient_type
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')
@@ -256,8 +261,16 @@ class AccountInvoice(Model):
ar_debit_id=acc.get("ar_debit_id")
if ar_debit_id:
break
+
+ # search from patient
if not ar_debit_id:
- raise Exception("Missing AR Debit Account for product %s"%(desc))
+ for pt in get_model('clinic.patient').search_browse([['partner_id','=',partner.id]]):
+ acc=prod_acc(prod_id,pt.type_id.id,'credit')
+ 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), partner.id, partner.name)
line_vals={
"description": desc,
"account_id": ar_debit_id,
diff --git a/netforce_clinic/models/account_move_line.py b/netforce_clinic/models/account_move_line.py
new file mode 100644
index 0000000..96c24a6
--- /dev/null
+++ b/netforce_clinic/models/account_move_line.py
@@ -0,0 +1,7 @@
+from netforce.model import Model
+
+class AccountMoveLine(Model):
+ _inherit="account.move.line"
+
+
+AccountMoveLine.register()
diff --git a/netforce_clinic/models/account_payment.py b/netforce_clinic/models/account_payment.py
index e8f1172..6fd9236 100644
--- a/netforce_clinic/models/account_payment.py
+++ b/netforce_clinic/models/account_payment.py
@@ -1,3 +1,6 @@
+from pprint import pprint
+
+
from netforce.model import Model, fields, get_model
class AccountPayment(Model):
@@ -58,9 +61,447 @@ class AccountPayment(Model):
}
}
+ def clinic_post(self,ids,context={}):
+ print("account_payment.post")
+ obj=self.browse(ids)[0]
+ settings=get_model("settings").browse(1)
+ 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 or 1)
+ obj.write({"currency_rate":currency_rate})
+ if obj.pay_type=="direct":
+ desc=obj.memo or obj.ref or obj.partner_id.name or obj.number # XXX: as in myob?
+ elif obj.pay_type=="invoice":
+ desc=obj.memo or "Payment; %s"%obj.partner_id.name # XXX: as in myob?
+ elif obj.pay_type=="prepay":
+ desc="Prepayment: %s"%obj.partner_id.name
+ elif obj.pay_type=="overpay":
+ desc="Overpayment: %s"%obj.partner_id.name
+ elif obj.pay_type=="refund":
+ desc="Refund: %s"%obj.partner_id.name
+ elif obj.pay_type=="claim":
+ desc="Expense claim payment"
+ elif obj.pay_type=="adjust":
+ desc="Adjustment"
+ else:
+ desc="Payment: %s"%obj.partner_id.name
+ if obj.type=="in":
+ journal_id=settings.pay_in_journal_id.id
+ if not journal_id:
+ raise Exception("Receipts journal not found")
+ elif obj.type=="out":
+ journal_id=settings.pay_out_journal_id.id
+ if not journal_id:
+ raise Exception("Disbursements journal not found")
+ if not obj.number:
+ raise Exception("Missing payment number")
+ move_vals={
+ "journal_id": journal_id,
+ "number": obj.number,
+ "date": obj.date,
+ "narration": desc,
+ "related_id": "account.payment,%s"%obj.id,
+ "company_id": obj.company_id.id,
+ }
+ move_id=get_model("account.move").create(move_vals)
+ lines=[]
+ track_id=None
+ for line in obj.lines: # XXX
+ if line.track_id:
+ if track_id:
+ track_id=None
+ break
+ else:
+ track_id=line.track_id.id
+ amt=get_model("currency").convert(obj.amount_payment,obj.currency_id.id,settings.currency_id.id,rate=currency_rate)
+ if obj.type=="out":
+ amt=-amt
+ line_vals={
+ "move_id": move_id,
+ "account_id": obj.account_id.id,
+ "description": desc,
+ "track_id": track_id,
+ "debit": amt>0 and amt or 0,
+ "credit": amt<0 and -amt or 0,
+ }
+ if obj.account_id.currency_id.id!=settings.currency_id.id:
+ if obj.account_id.currency_id.id!=obj.currency_id.id:
+ raise Exception("Invalid account currency for this payment: %s"%obj.account_id.code)
+ line_vals["amount_cur"]=obj.amount_payment if obj.type=="in" else -obj.amount_payment
+ get_model("account.move.line").create(line_vals)
+ taxes={}
+ reconcile_ids=[]
+ total_over=0
+ for line in obj.lines:
+ if line.type in ("direct","prepay"):
+ cur_amt=get_model("currency").convert(line.amount,obj.currency_id.id,settings.currency_id.id,rate=currency_rate)
+ tax=line.tax_id
+ if tax 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="direct_payment")
+ for comp_id,tax_amt in tax_comps.items():
+ if comp_id in taxes:
+ tax_vals=taxes[comp_id]
+ tax_vals["amount_base"]+=base_amt
+ tax_vals["amount_tax"]+=tax_amt
+ else:
+ tax_vals={
+ "tax_comp_id": comp_id,
+ "amount_base": base_amt,
+ "amount_tax": tax_amt,
+ }
+ taxes[comp_id]=tax_vals
+ else:
+ base_amt=cur_amt
+ if obj.type=="out":
+ amt=base_amt
+ else:
+ amt=-base_amt
+ line_vals={
+ "move_id": move_id,
+ "description": line.description or desc,
+ "account_id": line.account_id.id,
+ "debit": amt>0 and amt or 0,
+ "credit": amt<0 and -amt or 0,
+ "track_id": line.track_id.id,
+ "track2_id": line.track2_id.id,
+ }
+ print("direct")
+ pprint(line_vals)
+ get_model("account.move.line").create(line_vals)
+ elif line.type in ("invoice","refund"):
+ inv=line.invoice_id
+ inv_taxes={}
+ if inv.inv_type in ("invoice","credit","debit"):
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": inv.account_id.id,
+ "due_date": inv.due_date,
+ "partner_id": inv.partner_id.id,
+ }
+ if line.amount_currency>inv.amount_due:
+ pay_amt=inv.amount_due
+ over_amt=line.amount_currency-inv.amount_due
+ total_over+=get_model("currency").convert(over_amt,inv.currency_id.id,settings.currency_id.id,rate=inv.currency_rate)
+ else:
+ pay_amt=line.amount_currency
+ pay_ratio=pay_amt/inv.amount_total
+ inv_amt=inv.amount_total*pay_ratio
+ cur_inv_amt=get_model("currency").convert(inv_amt,inv.currency_id.id,settings.currency_id.id,rate=inv.currency_rate)
+ if obj.type=="out":
+ amt=cur_inv_amt
+ else:
+ amt=-cur_inv_amt
+ if amt>0:
+ line_vals["debit"]=amt
+ else:
+ line_vals["credit"]=-amt
+ if inv.account_id.currency_id.id!=settings.currency_id.id:
+ if obj.type=="out":
+ line_vals["amount_cur"]=inv_amt
+ else:
+ line_vals["amount_cur"]=-inv_amt
+ print("invoice")
+ pprint(line_vals)
+ pay_line_id=get_model("account.move.line").create(line_vals)
+ if inv.reconcile_move_line_id:
+ inv_line_id=inv.reconcile_move_line_id.id
+ elif inv.move_id: # XXX
+ inv_line_id=inv.move_id.lines[0].id
+ else:
+ inv_line_id=None
+ if inv_line_id:
+ #customize
+ reconcile_ids.append([pay_line_id,inv_line_id])
+ for invline in inv.lines:
+ tax=invline.tax_id
+ if tax and inv.tax_type!="no_tax": # XXX: simplify this
+ cur_line_amt_inv=get_model("currency").convert(invline.amount*pay_ratio,inv.currency_id.id,settings.currency_id.id,rate=inv.currency_rate)
+ base_amt=get_model("account.tax.rate").compute_base(tax.id,cur_line_amt_inv,tax_type=inv.tax_type)
+ tax_comps=get_model("account.tax.rate").compute_taxes(tax.id,base_amt,when="invoice_payment_inv")
+ for comp_id,tax_amt in tax_comps.items():
+ if comp_id in inv_taxes:
+ tax_vals=inv_taxes[comp_id]
+ tax_vals["amount_base"]+=base_amt
+ tax_vals["amount_tax"]+=tax_amt
+ else:
+ tax_vals={
+ "tax_comp_id": comp_id,
+ "amount_base": base_amt,
+ "amount_tax": tax_amt,
+ }
+ inv_taxes[comp_id]=tax_vals
+ cur_line_amt_pmt=get_model("currency").convert(invline.amount*pay_ratio,inv.currency_id.id,settings.currency_id.id,rate=inv.currency_rate) # XXX: check this
+ base_amt=get_model("account.tax.rate").compute_base(tax.id,cur_line_amt_pmt,tax_type=inv.tax_type)
+ tax_comps=get_model("account.tax.rate").compute_taxes(tax.id,base_amt,when="invoice_payment_pmt")
+ for comp_id,tax_amt in tax_comps.items():
+ if comp_id in inv_taxes:
+ tax_vals=inv_taxes[comp_id]
+ tax_vals["amount_base"]+=base_amt
+ tax_vals["amount_tax"]+=tax_amt
+ else:
+ tax_vals={
+ "tax_comp_id": comp_id,
+ "amount_base": base_amt,
+ "amount_tax": tax_amt,
+ }
+ inv_taxes[comp_id]=tax_vals
+ elif inv.inv_type=="overpay":
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": inv.account_id.id,
+ "partner_id": inv.partner_id.id,
+ }
+ amt=line.amount
+ if obj.type=="out":
+ line_vals["debit"]=amt
+ else:
+ line_vals["credit"]=amt
+ print("overpay")
+ pprint(line_vals)
+ get_model("account.move.line").create(line_vals)
+ elif inv.inv_type=="prepay":
+ for oline in inv.lines:
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": oline.account_id.id,
+ }
+ amt=oline.amount*line.amount/inv.amount_total # XXX: currency
+ tax=oline.tax_id
+ if tax:
+ base_amt=get_model("account.tax.rate").compute_base(tax.id,amt,tax_type=inv.tax_type)
+ else:
+ base_amt=amt
+ if obj.type=="out":
+ line_vals["debit"]=base_amt
+ else:
+ line_vals["credit"]=base_amt
+ print("prepay")
+ pprint(line_vals)
+ get_model("account.move.line").create(line_vals)
+ if tax and inv.tax_type!="no_tax":
+ tax_comps=get_model("account.tax.rate").compute_taxes(tax.id,base_amt,when="invoice") # XXX
+ for comp_id,tax_amt in tax_comps.items():
+ if comp_id in inv_taxes:
+ tax_vals=inv_taxes[comp_id]
+ tax_vals["amount_base"]+=base_amt
+ tax_vals["amount_tax"]+=tax_amt
+ else:
+ tax_vals={
+ "tax_comp_id": comp_id,
+ "amount_base": base_amt,
+ "amount_tax": tax_amt,
+ }
+ inv_taxes[comp_id]=tax_vals
+ for comp_id,inv_tax_vals in inv_taxes.items():
+ comp=get_model("account.tax.component").browse(comp_id)
+ if comp.type in ("vat","vat_defer"):
+ acc_id=comp.account_id.id
+ if not acc_id:
+ raise Exception("Missing account for tax component %s"%comp.name)
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": acc_id,
+ "tax_comp_id": comp_id,
+ "tax_base": inv_tax_vals["amount_base"],
+ "partner_id": obj.partner_id.id,
+ "invoice_id": inv.id,
+ }
+ if comp.type=="vat":
+ if inv.type=="out":
+ if line.tax_no:
+ tax_no=line.tax_no
+ else:
+ tax_no=get_model("account.invoice").gen_tax_no(context={"date":obj.date})
+ line.write({"tax_no":tax_no})
+ line_vals["tax_no"]=tax_no
+ elif inv.type=="in":
+ line_vals["tax_no"]=line.tax_no
+ amt=inv_tax_vals["amount_tax"]
+ if obj.type=="in":
+ amt=-amt
+ if amt>0:
+ line_vals["debit"]=amt
+ else:
+ line_vals["credit"]=-amt
+ print("tax")
+ pprint(line_vals)
+ get_model("account.move.line").create(line_vals)
+ elif comp.type=="wht":
+ if comp_id in taxes:
+ tax_vals=taxes[comp_id]
+ tax_vals["amount_base"]+=inv_tax_vals["amount_base"]
+ tax_vals["amount_tax"]+=inv_tax_vals["amount_tax"]
+ else:
+ taxes[comp_id]=inv_tax_vals.copy()
+ elif line.type=="claim":
+ expense=line.expense_id
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": settings.unpaid_claim_id.id,
+ }
+ amt=line.amount
+ if obj.type=="out":
+ line_vals["debit"]=amt
+ else:
+ line_vals["credit"]=amt
+ print("claim")
+ pprint(line_vals)
+ get_model("account.move.line").create(line_vals)
+ elif line.type=="adjust":
+ cur_amt=get_model("currency").convert(line.amount,obj.currency_id.id,settings.currency_id.id,rate=currency_rate)
+ tax_base=get_model("currency").convert(line.tax_base or 0,obj.currency_id.id,settings.currency_id.id,rate=currency_rate)
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": line.account_id.id,
+ "tax_comp_id": line.tax_comp_id.id,
+ "tax_base": tax_base,
+ "track_id": line.track_id.id,
+ "partner_id": obj.partner_id.id,
+ }
+ if obj.type=="in":
+ cur_amt=-cur_amt
+ if cur_amt>0:
+ line_vals["debit"]=cur_amt
+ else:
+ line_vals["credit"]=-cur_amt
+ print("adjust")
+ pprint(line_vals)
+ get_model("account.move.line").create(line_vals)
+ if total_over>0.01:
+ partner=obj.partner_id
+ if obj.type=="in":
+ 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=="out":
+ account_id=partner.account_payable_id.id or settings.account_payable_id.id
+ if not account_id:
+ raise Exception("Account payable not found")
+ line_vals={
+ "move_id": move_id,
+ "description": context.get("overpay_description",""),
+ "account_id": account_id,
+ "track_id": line.track_id.id,
+ "partner_id": obj.partner_id.id,
+ }
+ if obj.type=="out":
+ line_vals["debit"]=total_over
+ else:
+ line_vals["credit"]=total_over
+ print("overpay")
+ pprint(line_vals)
+ get_model("account.move.line").create(line_vals)
+ inv_line_vals={
+ "description": context.get("overpay_description",""),
+ "account_id": account_id,
+ "amount": total_over,
+ }
+ inv_vals={
+ "type": obj.type=="in" and "out" or "in",
+ "inv_type": "overpay",
+ "partner_id": obj.partner_id.id,
+ "date": obj.date,
+ "tax_type": "no_tax",
+ "lines": [("create",inv_line_vals)],
+ "state": "waiting_payment",
+ "payment_id": obj.id,
+ "account_id": account_id,
+ }
+ inv_id=get_model("account.invoice").create(inv_vals)
+ wht_no=get_model("account.payment").gen_wht_no(context={"date":obj.date})
+ for comp_id,tax_vals in sorted(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)
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": acc_id,
+ "tax_comp_id": comp_id,
+ "tax_base": tax_vals["amount_base"],
+ "partner_id": obj.partner_id.id,
+ }
+ if comp.type=="vat":
+ if obj.type=="in":
+ if obj.tax_no:
+ tax_no=obj.tax_no
+ else:
+ tax_no=get_model("account.invoice").gen_tax_no(context={"date":obj.date})
+ obj.write({"tax_no":tax_no})
+ line_vals["tax_no"]=tax_no
+ elif obj.type=="out":
+ line_vals["tax_no"]=obj.tax_no
+ elif comp.type=="wht":
+ if obj.type=="out":
+ # 1 Payment should have same wht_no
+ #wht_no=get_model("account.payment").gen_wht_no(context={"date":obj.date})
+ line_vals["tax_no"]=wht_no
+ amt=tax_vals["amount_tax"]
+ if obj.type=="in":
+ amt=-amt
+ if amt>0:
+ line_vals["debit"]=amt
+ else:
+ line_vals["credit"]=-amt
+ print("tax")
+ pprint(line_vals)
+ get_model("account.move.line").create(line_vals)
+ amt=0
+ move=get_model("account.move").browse(move_id)
+ for line in move.lines:
+ amt+=line.credit-line.debit
+ if amt>0.001:
+ if not settings.currency_loss_id:
+ raise Exception("Missing currency loss account")
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": settings.currency_loss_id.id,
+ "debit": amt,
+ "credit": 0,
+ }
+ get_model("account.move.line").create(line_vals)
+ elif amt<-0.001:
+ if not settings.currency_gain_id:
+ raise Exception("Missing currency gain account")
+ line_vals={
+ "move_id": move_id,
+ "description": desc,
+ "account_id": settings.currency_loss_id.id,
+ "debit": 0,
+ "credit": -amt,
+ }
+ get_model("account.move.line").create(line_vals)
+ get_model("account.move").post([move_id])
+ obj.write({"move_id":move_id,"state":"posted"})
+ #Cutomize
+ for rec_lines in reconcile_ids:
+ get_model("account.move.line").reconcile(rec_lines)
+ obj.create_prepay_invoice()
+
def post(self,ids,context={}):
obj=self.browse(ids)[0]
res=None
+ if obj.hdcase_reconcile:
+ obj.clinic_post()
if obj.rd_cust:
res={}
print("RD Customize")
diff --git a/netforce_clinic/models/conv_bal.py b/netforce_clinic/models/conv_bal.py
new file mode 100644
index 0000000..6023d6e
--- /dev/null
+++ b/netforce_clinic/models/conv_bal.py
@@ -0,0 +1,184 @@
+import csv
+import datetime
+from io import StringIO
+
+from netforce.model import Model, fields, get_model
+from netforce.utils import get_file_path
+
+class ConvBal(Model):
+ _inherit="conv.bal"
+
+ def create_sale_invoices(self,ids,context={}):
+ obj=self.browse(ids)[0]
+ desc="Conversion balance %s"%obj.date
+ for inv in obj.sale_invoices:
+ vals={
+ "type": "out",
+ "inv_type": inv.amount_due>=0 and "invoice" or "credit",
+ "partner_id": inv.contact_id.id,
+ "date": inv.date,
+ "due_date": inv.due_date,
+ "number": inv.number,
+ "ref": inv.ref,
+ "memo": desc,
+ "lines": [],
+ "state": "waiting_payment",
+ "account_id": inv.account_id.id,
+ "reconcile_move_line_id": inv.move_line_id.id,
+ "currency_id": inv.account_id.currency_id.id,
+ "currency_rate": inv.amount_due/inv.amount_cur if inv.amount_cur else None,
+ "department_id": inv.department_id.id,
+ }
+ line_vals={
+ "description": desc,
+ "amount": abs(inv.amount_cur or inv.amount_due),
+ "track_id": inv.track_id.id,
+ }
+ vals["lines"].append(("create",line_vals))
+ res=get_model("account.invoice").search([["number","=",inv.number]])
+ if res:
+ inv2_id=res[0]
+ inv2=get_model("account.invoice").browse(inv2_id)
+ #ratchawat
+ inv2.write({
+ 'lines': vals['lines'],
+ })
+ #if abs(inv2.amount_total)-abs(inv.amount_due)>0.001: # XXX
+ #raise Exception("Failed to update invoice %s: different amount"%inv.number)
+ if inv2.state=="draft":
+ raise Exception("Failed to update invoice %s: invalid state"%inv.number)
+ inv2.write({
+ "move_id": obj.move_id.id,
+ "reconcile_move_line_id": inv.move_line_id.id,
+ })
+ else:
+ get_model("account.invoice").create(vals)
+
+ def import_sale_file(self,ids,context):
+ obj=self.browse(ids)[0]
+ path=get_file_path(obj.file)
+ data=open(path).read()
+ rd=csv.reader(StringIO(data))
+ headers=next(rd)
+ headers=[h.strip() for h in headers]
+ del_ids=get_model("conv.sale.invoice").search([["conv_id","=",obj.id]])
+ get_model("conv.sale.invoice").delete(del_ids)
+ for row in rd:
+ #print("row",row)
+ row+="," #XXX append blank column for Amount Cur
+ line=dict(zip(headers,row))
+ #print("line",line)
+ track_id=None
+ department_id=None
+ department_name=line.get("Department")
+ if department_name:
+ for dpt in get_model("clinic.department").search_browse([['name','=',department_name]]):
+ department_id=dpt.id
+ track_id=dpt.branch_id.track_id.id
+ if not line.get("Number"):
+ continue
+ number=line["Number"].strip()
+ if not number:
+ continue
+
+ ##XXX remove invoice
+ #for inv in get_model('account.invoice').search_browse([['number','=', number]]):
+ #print('number --> ', number)
+ #inv.to_draft()
+ #inv.delete()
+ #continue
+
+ ref=line["Reference"].strip()
+ contact_name=line["Contact"].strip()
+ res=get_model("partner").search([["name","=",contact_name]])
+ if not res:
+ raise Exception("Contact not found: '%s'"%contact_name)
+ contact_id=res[0]
+ date=datetime.datetime.strptime(line["Date"].strip(),obj.date_fmt).strftime("%Y-%m-%d")
+ due_date=datetime.datetime.strptime(line["Due Date"].strip(),obj.date_fmt).strftime("%Y-%m-%d")
+ amount_due=float(line["Amount Due"].strip().replace(",","") or 0)
+ acc_code=line["Account"].strip()
+ amount_cur=float(line["Amount Cur"].strip().replace(",","") or 0)
+ acc_codes=acc_code.split(",")
+ amts=[] #XXX
+ for m in line['Memo'].split(","):
+ amt=m.split(":")[1]
+ amt=amt.strip()
+ if amt:
+ amt=float(amt)
+ amts.append(amt)
+ if len(acc_codes) > 1:
+ count=0
+ print("*"*80)
+ for acc_code in acc_codes:
+ acc_code=acc_code.strip()
+ res=get_model("account.account").search([["code","=",acc_code]])
+ if not res:
+ raise Exception("Account code not found: %s"%acc_code)
+ acc_id=res[0]
+ amount_due=amts[count]
+ vals={
+ "conv_id": obj.id,
+ "number": number,
+ "ref": ref,
+ "contact_id": contact_id,
+ "date": date,
+ "due_date": due_date,
+ "amount_due": amount_due,
+ "account_id": acc_id,
+ "amount_cur": amount_due, #XXX
+ 'track_id': track_id,
+ 'department_id': department_id,
+ }
+ get_model("conv.sale.invoice").create(vals)
+ count+=1
+ elif len(amts) >= 1 and len(acc_codes)<=1:
+ acc_code=acc_codes[0].strip()
+ res=get_model("account.account").search([["code","=",acc_code]])
+ if not res:
+ raise Exception("Account code not found: %s"%acc_code)
+ acc_id=res[0]
+ for amt in amts:
+ amount_due=amt
+ vals={
+ "conv_id": obj.id,
+ "number": number,
+ "ref": ref,
+ "contact_id": contact_id,
+ "date": date,
+ "due_date": due_date,
+ "amount_due": amount_due,
+ "account_id": acc_id,
+ "amount_cur": amount_due, #XXX
+ 'track_id': track_id,
+ 'department_id': department_id,
+ }
+ get_model("conv.sale.invoice").create(vals)
+ else:
+ res=get_model("account.account").search([["code","=",acc_code]])
+ if not res:
+ raise Exception("Account code not found: %s"%acc_code)
+ acc_id=res[0]
+ vals={
+ "conv_id": obj.id,
+ "number": number,
+ "ref": ref,
+ "contact_id": contact_id,
+ "date": date,
+ "due_date": due_date,
+ "amount_due": amount_due,
+ "account_id": acc_id,
+ "amount_cur": amount_cur,
+ 'track_id': track_id,
+ 'department_id': department_id,
+ }
+ get_model("conv.sale.invoice").create(vals)
+ return {
+ "next": {
+ "name": "conv_bal",
+ "active_id": obj.id,
+ "view_xml": "conv_bal2",
+ }
+ }
+
+ConvBal.register()
diff --git a/netforce_clinic/models/conv_sale_invoice.py b/netforce_clinic/models/conv_sale_invoice.py
new file mode 100644
index 0000000..4ecfb59
--- /dev/null
+++ b/netforce_clinic/models/conv_sale_invoice.py
@@ -0,0 +1,12 @@
+from netforce.model import Model, fields
+
+class ConvSaleInvoice(Model):
+ _inherit="conv.sale.invoice"
+ _transient=True
+ _fields={
+ "department_id": fields.Many2One("clinic.department","Department"),
+ "track_id": fields.Many2One("account.track.categ","Track1"),
+ }
+
+
+ConvSaleInvoice.register()
diff --git a/netforce_clinic/models/hd_case.py b/netforce_clinic/models/hd_case.py
index 0b3c44d..10cd6f1 100644
--- a/netforce_clinic/models/hd_case.py
+++ b/netforce_clinic/models/hd_case.py
@@ -681,6 +681,7 @@ class HDCase(Model):
"lines": [],
"company_id": company_id,
'hdcase_credit': False,
+ 'hdcase_reconcile': True,
}
vals["partner_id"]=partner.id
vals['lines']=rmb_lines
@@ -711,6 +712,7 @@ class HDCase(Model):
"company_id": company_id,
'partner_id':partner.id,
'hdcase_credit': True,
+ 'hdcase_reconcile': True,
}
vals['lines']=normb_lines
if patient_partner:
diff --git a/netforce_clinic/models/shop.py b/netforce_clinic/models/shop.py
index 028d799..41467df 100644
--- a/netforce_clinic/models/shop.py
+++ b/netforce_clinic/models/shop.py
@@ -333,6 +333,7 @@ class Shop(Model):
"currency_id": currency_id,
"company_id": company_id,
'partner_id': partner.id,
+ 'hdcase_reconcile': True,
"lines": [],
}
track_id=obj.branch_id.track_id.id