generate invoice depend on account receivable

fix_acc
watcha.h 2015-08-18 17:06:58 +07:00
parent 9227cb7237
commit c33f4cf1d3
4 changed files with 268 additions and 46 deletions

View File

@ -4,6 +4,6 @@
<field name="patient_partner_id" span="2"/> <field name="patient_partner_id" span="2"/>
</field> </field>
<field name="memo" position="after"> <field name="memo" position="after">
<field name="account_id" span="2"/> <field name="account_id" string="Account Receivable" span="2"/>
</field> </field>
</inherit> </inherit>

View File

@ -57,6 +57,7 @@
<field name="description"/> <field name="description"/>
</list> </list>
</field> </field>
<field name="note"/>
</group> </group>
</tab> </tab>
<tab string="Expense"> <tab string="Expense">
@ -110,12 +111,9 @@
<group span="3" columns="1"> <group span="3" columns="1">
</group> </group>
</tab> </tab>
<tab string="Note"> <tab string="Approval">
<field name="note" nolabel="1"/>
</tab>
<tab string="Other">
<field name="nurse_id" span="4"/> <field name="nurse_id" span="4"/>
<field name="fee_partner_id" span="4" domain="[['type','=','org']]"/> <!--<field name="fee_partner_id" span="4" domain="[['type','=','org']]"/>-->
</tab> </tab>
</tabs> </tabs>
<foot> <foot>

View File

@ -76,4 +76,208 @@ class AccountInvoice(Model):
} }
get_model("account.fixed.asset").create(vals) 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
#XXX ratchawat
if not obj.patient_partner_id:
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
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,
}
#XXX ratchawat: get receive account from invoice directly
if obj.patient_partner_id:
line_vals['account_id']=obj.account_id.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() AccountInvoice.register()

View File

@ -635,7 +635,7 @@ class HDCase(Model):
else: else:
acc=prod_acc(prod.id,stype.id,'cash') acc=prod_acc(prod.id,stype.id,'cash')
account_id=acc.get("ar_credit_id",None) account_id=acc.get("ar_credit_id",None)
ar_debit_id=acc.get("ar_debit_id",None) ar_debit_id=acc.get("ar_debit_id",None) # account receiveable
if not account_id: if not account_id:
raise Exception("No Income Credit Account for product [%s] %s"%(prod.code, prod.name)) raise Exception("No Income Credit Account for product [%s] %s"%(prod.code, prod.name))
if not ar_debit_id: if not ar_debit_id:
@ -668,58 +668,78 @@ class HDCase(Model):
patient=obj.patient_id patient=obj.patient_id
patient_partner=patient.partner_id patient_partner=patient.partner_id
def group_invoice_line(invoice_lines):
invoice_vals={}
for mode,invoice_line in invoice_lines:
ar_debit_id=invoice_line['ar_debit_id']
if not invoice_vals.get(ar_debit_id):
invoice_vals[ar_debit_id]=[]
del invoice_line['ar_debit_id']
invoice_vals[ar_debit_id].append((mode,invoice_line))
return invoice_vals
if rmb_lines: if rmb_lines:
ptype=patient.type_id ptype=patient.type_id
partner=ptype.contact_id partner=ptype.contact_id
if not partner: if not partner:
raise Exception("No contact for patient type %s"%obj.ptype.name) raise Exception("No contact for patient type %s"%obj.ptype.name)
vals={ #vals['lines']=rmb_lines
"type": "out", # reset account receiveable
"inv_type": "invoice", # group invoice line by account receiveable
"tax_type": "tax_in", invoices=group_invoice_line(rmb_lines)
'date': obj.date,
'due_date': due_date,
"ref": '%s (%s)'%(patient.name or '',patient.number or ''),
'department_id': obj.department_id.id,
"related_id": "clinic.hd.case,%s"%obj.id,
"currency_id": currency_id,
"company_id": company_id,
"lines": [],
"company_id": company_id,
}
vals["partner_id"]=partner.id
vals['lines']=rmb_lines
if patient_partner:
vals['patient_partner_id']=patient_partner.id,
if obj.branch_id: if obj.branch_id:
context['branch_id']=obj.branch_id.id context['branch_id']=obj.branch_id.id
get_model("account.invoice").create(vals,context=context) for account_receiveable_id, lines in invoices.items():
vals={
"type": "out",
"inv_type": "invoice",
"tax_type": "tax_in",
'date': obj.date,
'due_date': due_date,
"ref": '%s (%s)'%(patient.name or '',patient.number or ''),
'department_id': obj.department_id.id,
"related_id": "clinic.hd.case,%s"%obj.id,
"currency_id": currency_id,
"company_id": company_id,
"lines": [],
"company_id": company_id,
"partner_id": partner.id,
'patient_partner_id':patient_partner.id,
'account_id':account_receiveable_id ,
'lines':lines,
}
inv_id=get_model("account.invoice").create(vals,context=context)
inv=get_model("account.invoice").browse(inv_id)
# click button Credit from popup of button Pay
if normb_lines and is_credit: if normb_lines and is_credit:
partner=patient.partner_id partner=patient.partner_id
if not partner: if not partner:
raise Exception("No contact for this patient %s"%obj.partner.name) raise Exception("No contact for this patient %s"%obj.partner.name)
context['branch_id']=obj.branch_id.id context['branch_id']=obj.branch_id.id
number=self._get_number_invoice_noclaim(context=context)
vals={ invoices=group_invoice_line(normb_lines)
'number': number, for account_receiveable_id, lines in invoices.items():
"type": "out", number=self._get_number_invoice_noclaim(context=context)
"inv_type": "invoice", vals={
"tax_type": "tax_in", 'number': number,
'due_date': due_date, "type": "out",
"ref": '%s (%s)'%(patient.name or '',patient.number or ''), "inv_type": "invoice",
"related_id": "clinic.hd.case,%s"%obj.id, "tax_type": "tax_in",
"currency_id": currency_id, 'due_date': due_date,
"company_id": company_id, "ref": '%s (%s)'%(patient.name or '',patient.number or ''),
"lines": [], "related_id": "clinic.hd.case,%s"%obj.id,
"company_id": company_id, "currency_id": currency_id,
'partner_id':partner.id, "company_id": company_id,
} "lines": [],
vals['lines']=normb_lines "company_id": company_id,
if patient_partner: 'partner_id':partner.id,
vals['patient_partner_id']=patient_partner.id, 'patient_partner_id':patient_partner.id,
get_model("account.invoice").create(vals,context) 'account_id': account_receiveable_id,
}
vals['lines']=lines
get_model("account.invoice").create(vals,context)
obj.make_pickings() obj.make_pickings()
# prevent douplicate create invoice & picking # prevent douplicate create invoice & picking