from pprint import pprint from netforce.model import Model, fields, get_model class AccountPayment(Model): _inherit="account.payment" _fields={ 'rd_cust': fields.Boolean("RD Customize"), 'number': fields.Char("Number",required=True,search=True), } def _get_number(self,context={}): type=context.get("type") if type=="in": seq_type="pay_in" elif type=="out": seq_type="pay_out" else: return seq_id=get_model("sequence").find_sequence(type=seq_type,context=context) # force to use 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, } def run_report(self,ids,context={}): obj=self.browse(ids)[0] hd_case_id=obj.related_id.id hd_case=get_model("clinic.hd.case").browse(hd_case_id) # TODO # set payment_id on hd case # send to action print form payment hd_case.write({ 'payment_id': obj.id, }) return { 'next': { 'name': 'report_clinic_payment_form', 'refer_id': hd_case_id, 'payment_id': obj.id, }, } def import_payment(self,ids,context={}): if not ids: raise Exception("Please save payment before import") return { 'next': { 'name': 'clinic_import_uc', 'refer_id': ids[0], #XXX } } 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") desc="Recieved %s"%obj.partner_id.name for ivline in obj.invoice_lines: invoice=ivline.invoice_id partner_id=invoice.partner_id.id for mline in invoice.move_id.lines: if mline.debit>0: amt=mline.debit or 0 account_id=mline.account_id.id if not res.get(account_id): res[account_id]={ 'credit': 0, 'debit': 0, 'description': desc, 'partner_id': partner_id } res[account_id]['credit']+=amt settings=get_model("settings").browse(1) if obj.type=="in": journal_id=obj.journal_id.id or settings.pay_in_journal_id.id if not journal_id: raise Exception("Receipts journal not found") elif obj.type=="out": journal_id=obj.journal_id.id or 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) 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 lines1=[] lines1.append(('create',{ "move_id": move_id, "account_id": obj.account_id.id, "description": desc, "track_id": track_id, 'debit': 0, 'credit':0, })) lines2=[] for account_id, rvals in res.items(): amt=rvals['credit'] or 0 lines1[0][1]['debit']+=amt #XXX lines2.append(('create',{ "move_id": move_id, "account_id": account_id, "description": rvals['description'], 'partner_id': rvals['partner_id'], 'debit': rvals['debit'], 'credit': rvals['credit'], "track_id": track_id, })) if obj.type=="in": rate_type="sell" else: rate_type="buy" adjust_lines=[] adjust_amt=0 for jline in obj.adjust_lines: cur_amt=get_model("currency").convert(line.amount,obj.currency_id.id,settings.currency_id.id,date=obj.date,rate_type=rate_type) tax_base=get_model("currency").convert(line.tax_base or 0,obj.currency_id.id,settings.currency_id.id,date=obj.date,rate_type=rate_type) cur_amt=abs(cur_amt) adjust_lines.append(('create',{ "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, "credit":0, "debit": cur_amt, })) #XXX adjust_amt+=cur_amt lines1[0][1]['debit']-=cur_amt lines=lines1+adjust_lines+lines2 #debit, debit, credit move=get_model("account.move").browse(move_id) move.write({ 'lines': lines, }) move.post() obj.write({ 'move_id': move.id, 'state': 'posted', }) print("Done!") else: res=super().post(ids,context=context) return res AccountPayment.register()