clinic/netforce_clinic/models/account_payment.py

616 lines
27 KiB
Python

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()