import time from netforce.model import Model, fields, get_model class AccountInvoice(Model): _inherit="account.invoice" _fields={ 'clinic_expense_id': fields.Many2One("clinic.hd.case.expense","Expense"), '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"), } def _get_number(self,context={}): defaults=context.get("defaults") if defaults: # XXX type=defaults.get("type") inv_type=defaults.get("inv_type") else: type=context.get("type") inv_type=context.get("inv_type") seq_type=None if type=="out": if inv_type in ("invoice","prepay"): seq_type="cust_invoice" elif inv_type=="credit": seq_type="cust_credit" elif inv_type=="debit": seq_type="cust_debit" elif type=="in": if inv_type in ("invoice","prepay"): seq_type="supp_invoice" elif inv_type=="credit": seq_type="supp_credit" elif inv_type=="debit": seq_type="supp_debit" if not seq_type: return seq_id=get_model("sequence").find_sequence(type=seq_type,context=context) if not seq_id: return None while 1: num=get_model("sequence").get_next_number(seq_id,context=context) res=self.search([["number","=",num]]) if not res: return num get_model("sequence").increment_number(seq_id,context=context) _defaults={ "number": _get_number, } # override this function to push tracking def create_fixed_assets(self,ids,context={}): for obj in self.browse(ids): if obj.fixed_assets: raise Exception("Fixed assets already created for invoice %s"%obj.number) for line in obj.lines: acc=line.account_id if acc.type!="fixed_asset": continue ass_type=acc.fixed_asset_type_id if not ass_type: continue vals={ "name": line.description, "type_id": ass_type.id, "date_purchase": obj.date, "price_purchase": line.amount, # XXX: should be tax-ex "fixed_asset_account_id": acc.id, "dep_rate": ass_type.dep_rate, "dep_method": ass_type.dep_method, "accum_dep_account_id": ass_type.accum_dep_account_id.id, "dep_exp_account_id": ass_type.dep_exp_account_id.id, "invoice_id": obj.id, 'track_id': line.track_id.id, } 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()