clinic/netforce_clinic/models/account_invoice.py

484 lines
20 KiB
Python
Raw Permalink Normal View History

2015-08-08 15:34:21 +00:00
import time
2015-02-03 08:37:43 +00:00
from netforce.model import Model, fields, get_model
2015-08-25 15:40:48 +00:00
from netforce.utils import get_file_path
from netforce.access import get_active_company, get_active_user
from . import utils
2014-10-27 14:17:22 +00:00
2014-12-14 11:15:14 +00:00
class AccountInvoice(Model):
_inherit="account.invoice"
2015-08-24 09:45:12 +00:00
def _get_patient(self,ids,context={}):
res={}
for obj in self.browse(ids):
pt_id=None
pt_type_id=None
2015-08-24 09:45:12 +00:00
if obj.patient_partner_id:
for pt in get_model('clinic.patient').search_browse([['partner_id','=',obj.patient_partner_id.id]]):
pt_id=pt.id
pt_type_id=pt.type_id.id
res[obj.id]={
'patient_id': pt_id,
'patient_type_id': pt_type_id,
}
2015-08-24 09:45:12 +00:00
return res
2014-12-14 11:15:14 +00:00
_fields={
'clinic_expense_id': fields.Many2One("clinic.hd.case.expense","Expense"),
2015-01-20 13:58:38 +00:00
'department_id': fields.Many2One("clinic.department","Department",search=True),
2015-08-24 09:45:12 +00:00
'patient_partner_id': fields.Many2One("partner","Partner Patient",search=True),
'patient_id': fields.Many2One("clinic.patient","Patient",function="_get_patient", function_multi=True,store=True,search=True),
'patient_type_id': fields.Many2One("clinic.patient.type","Patient Type",function="_get_patient", function_multi=True,store=True,search=True),
2016-03-08 11:07:50 +00:00
'create_invoice_id': fields.Many2One("create.invoice.payment","Create Invoice Payment"),
2014-12-14 11:15:14 +00:00
}
2015-03-18 01:39:03 +00:00
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,
}
2015-02-03 08:37:43 +00:00
# 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)
2015-03-04 07:19:53 +00:00
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)
2015-08-24 09:45:12 +00:00
2015-08-25 15:40:48 +00:00
def get_invoice_data(self,ids,context={}):
settings=get_model('settings').browse(1)
pages=[]
for obj in self.browse(ids):
context['refer_id']=obj.id
data=self.get_invoice_page(context=context)
limit_item=10
if data['state']=='draft':
limit_item-=3
for i in range(len(data['lines']),limit_item):
data['lines'].append({
'no': '',
'product_name': '',
'description': '',
'uom_name': '',
'qty': None,
'price': None,
'amount': None,
})
pages.append(data)
if pages:
pages[-1]["is_last_page"]=True
return {
"pages": pages,
"logo": get_file_path(settings.logo),
}
def get_invoice_page(self,context={}):
if not context.get('refer_id'):
return {}
inv_id=int(context['refer_id'])
inv=self.browse(inv_id)
comp_id=get_active_company()
comp=get_model('company').browse(comp_id)
cust=inv.partner_id
cust_tax_no=cust.tax_no or ''
cust_name=cust.name or ''
cust_addr=''
if cust.addresses:
cust_addr=cust.addresses[0].address_text
if 'your' in cust_addr:
cust_addr=''
2015-08-26 03:09:34 +00:00
dpt=inv.department_id
branch_id=None
if dpt:
branch_id=dpt.branch_id.id
elif inv.patient_partner_id:
for pt in get_model('clinic.patient').search_read([['partner_id','=',inv.patient_partner_id.id]],['branch_id']):
if pt.get("branch_id"):
branch_id=pt['branch_id'][0]
context['branch_id']=branch_id
st=get_model('settings').browse(1,context=context)
cst=get_model('clinic.setting').browse(1)
2015-08-25 15:40:48 +00:00
no=1
sub_total=0
amount_total=0
lines=[]
for line in inv.lines:
amt=line.amount or 0
prod=line.product_id
lines.append({
'no': no,
'product_name': prod.name or '',
'description': line.description or '',
'uom_name': prod.uom_id.name or '',
'qty': line.qty or 0,
'price': line.price or 0,
'amount': amt,
})
sub_total+=amt
no+=1
amount_total=sub_total
is_draft=inv.state=='draft' and True or False
is_cheque=False
user_id=get_active_user()
user=get_model("base.user").browse(user_id)
comp_name=comp.name or ""
if st.default_address_id.company:
comp_name=st.default_address_id.company or ""
payment_terms=''
currency_code=''
due_date=inv.due_date
number=inv.number or ""
ref=inv.ref or ""
payment_terms=inv.payment_terms or ""
currency_code=inv.currency_id.code or ""
due_date=inv.due_date
add=st.default_address_id
hdcase=inv.related_id
patient=hdcase.patient_id
2015-08-25 15:40:48 +00:00
data={
'partner_name': cust_name,
'partner_address': cust_addr,
'partner_tax_no': cust_tax_no,
'due_date': due_date,
'currency_code': currency_code,
'payment_terms': payment_terms,
'comp_name': comp_name,
'add_address': add.address or '',
'add_address2': add.address2 or '',
'add_province_name': add.province_id.name or '',
'add_district_name': add.district_id.name or '',
'add_subdistrict_name': add.subdistrict_id.name or '',
'add_city': add.city or '',
'add_postal_code': add.postal_code or '',
'add_phone': add.phone or '',
'add_fax': add.fax or '',
'tax_no': st.tax_no or '',
'number': number,
'ref': ref,
'date': inv.date,
'datenow': inv.date or time.strftime("%d/%m/%Y"),
'dateprint': inv.date or time.strftime("%d/%m/%Y %H:%M:%S"),
'note': inv.note or '',
'lines':lines,
'amount_subtotal': sub_total,
'amount_total': amount_total,
'total_text': utils.num2word(amount_total),
'is_cheque': is_cheque,
'is_draft': is_draft,
'user_name': user.name or "",
'patient_name': patient.name or "",
2015-08-25 15:40:48 +00:00
'state': inv.state or "",
}
data['pay_type']='Credit'
if st.logo:
data['logo']=get_file_path(st.logo)
if cst.signature:
data['signature']=get_file_path(cst.signature)
data['auth_signature']=get_file_path(cst.signature)
2015-08-25 15:40:48 +00:00
return data
2017-11-24 08:28:42 +00:00
def pay_invoice(self, ids, context={}):
paid_inv=[]
for obj in self.browse(ids):
if obj.state!='waiting_payment':
continue
rel=obj.related_id
if rel and rel._model=='clinic.hd.case':
clinic_setting=get_model("clinic.setting").browse(1)
if not clinic_setting.hdcase_payment_account_id:
raise Exception("Missing HDCase Payment Account in setting!")
inv_pm_id=get_model("invoice.payment").create({
'date': time.strftime("%Y-%m-%d"),
'invoice_id': obj.id,
'account_id': clinic_setting.hdcase_payment_account_id.id,
'ref': rel.number,
'amount': obj.amount_due,
})
inv_pm=get_model("invoice.payment").browse(inv_pm_id)
inv_pm.add_payment(context)
for pm_line in obj.payments:
pm=pm_line.payment_id
pm.write({
'related_id': "clinic.hd.case,%s"%rel.id,
})
paid_inv.append(obj.number)
if not paid_inv:
raise Exception("Nothing to paid!")
return {
'flash': 'Invoice: %s has been paid'%(','.join(paid_inv)),
}
2018-01-24 05:07:43 +00:00
def hdcase_to_draft(self, ids, context={}):
for payment_line in get_model("account.payment.line").search_browse([['invoice_id','in',ids]]):
payment=payment_line.payment_id
rel=payment.related_id
if rel._model=='clinic.hd.case':
payment.to_draft()
payment.delete()
for inv in self.browse(ids):
inv.to_draft()
inv.approve()
2017-11-24 08:28:42 +00:00
2014-12-14 11:15:14 +00:00
AccountInvoice.register()