import time from calendar import monthrange from netforce.model import Model, fields, get_model from netforce.utils import get_file_path, get_data_path from netforce.access import get_active_company, get_active_user from . import utils class MatchingPayment(Model): _name="clinic.matching.payment" _string="Payment Matching" def _get_store(self,ids,context={}): res={} for obj in self.browse(ids): partner=obj.patient_type_id.contact_id res[obj.id]={ 'partner_id': partner.id, } return res def _get_all(self,ids,context={}): res={} for obj in self.browse(ids): total_match=0 total_fee=0 total_srv=0 total_epo=0 otype=obj.type or "all" lines=obj.lines if otype=='match': lines=obj.match_lines elif otype=='unmatch': lines=obj.unmatch_lines for line in lines: total_fee+=line.fee or 0 total_srv+=line.srv or 0 total_epo+=line.epo or 0 state=line.state or '' if state=='match': total_match+=1 res[obj.id]={ 'total': len(lines), 'total_match': total_match, 'total_unmatch': len(lines)-total_match, 'total_fee': total_fee, 'total_srv': total_srv, 'total_epo': total_epo, } return res _fields={ 'name': fields.Char("Name"), "date": fields.Date("Month"), "date_from": fields.Date("From", required=True), "date_to": fields.Date("To", required=True), 'file': fields.File("File"), 'patient_type_id': fields.Many2One("clinic.patient.type","Patient Type",required=True), 'partner_id': fields.Many2One("partner","Contact", function="_get_store", function_multi=True, store=True), 'pcode': fields.Char("Code",required=True), 'hcode_id': fields.Many2One("clinic.hospital","HCode"), 'lines': fields.One2Many("clinic.matching.payment.line","match_id", "Lines"), 'match_lines': fields.One2Many("clinic.matching.payment.line","match_id", "Lines",domain=[['state','=','match']]), 'unmatch_lines': fields.One2Many("clinic.matching.payment.line","match_id", "Lines",domain=[['state','=','unmatch']]), 'note': fields.Text("Note"), 'total': fields.Integer("Total",function="_get_all",function_multi=True), 'total_match': fields.Integer("Match",function="_get_all",function_multi=True), 'total_unmatch': fields.Integer("Unmatch",function="_get_all",function_multi=True), 'total_fee': fields.Float("FEE",function="_get_all",function_multi=True), 'total_srv': fields.Float("Service",function="_get_all",function_multi=True), 'total_epo': fields.Float("EPO",function="_get_all",function_multi=True), 'state': fields.Selection([['draft','Draft'],['approved','Approved']],'State'), 'type': fields.Selection([['all','All'],['match','Match'],['unmatch','Not Match']],'Type'), 'user_id': fields.Many2One("base.user","Approver"), 'department_id': fields.Many2One("clinic.department","Department"), 'branch_id': fields.Many2One("clinic.branch","Branch"), } def _get_ptype(self,context={}): tids=get_model('clinic.patient.type').search([['default','=',True]]) tid=None if tids: tid=tids[0] return tid def _get_pcode(self,context={}): types=get_model('clinic.patient.type').search_browse([['default','=',True]]) if types: return types[0].code def _get_date_from(self,context={}): year,month=time.strftime("%Y-%m").split("-") return '%s-%s-01'%(year,month) def _get_date_to(self,context={}): year,month,day=time.strftime("%Y-%m-%d").split("-") weekday, total_day=monthrange(int(year), int(month)) return "%s-%s-%s"%(year,month,total_day) def _get_name(self,ids,context={}): return time.strftime("%Y/%m") _defaults={ 'date': lambda *a: time.strftime("%Y-%m-%d"), 'name': _get_name, 'date_from': _get_date_from, 'date_to': _get_date_to, 'patient_type_id': _get_ptype, 'pcode': _get_pcode, 'state': 'draft', 'user_id': lambda *a: get_active_user(), 'type': 'all', } _order="date desc" def get_line(self,ids,context={}): obj=self.browse(ids)[0] if not obj.file: raise Exception("File not found!") fname=obj.file if obj.pcode=='SSO': hcode=obj.hcode_id.code or "" if not hcode: raise Exception("Wrong HCode") try: n,sf=fname.split(".") except Exception as e: print("ERROR: wrong file ", e) if sf not in ('xls','xlsx'): raise Exception("File should be xls or xlsx") fpath=get_file_path(fname) lines=utils.read_excel(fpath,show_datetime=True) elif obj.pcode=='UC': fpath=get_file_path(fname) node='HDBills' lines=utils.read_xml(fpath,node=node) hcode=fname.split("_")[0] else: raise Exception("Type %s is not support"%obj.pcode or "") if not lines: raise Exception("No data to match") return lines def match(self,ids,context={}): obj=self.browse(ids)[0] lines=obj.get_line() print("total lines: ", len(lines)) patient_type=obj.patient_type_id if not patient_type: raise Exception("Not found patient type") contact=patient_type.contact_id if not contact: raise Exception("Contact not found") st=get_model("clinic.setting").browse(1) st_pt=st.get_patient_hn() patient_hn=st_pt['hns'] patient_names=st_pt['names'] matches1={} matches2={} matches3={} matches_uc={} dom=[] dom.append(['date',">=",obj.date_from]) dom.append(['date',"<=",obj.date_to]) dom.append(['partner_id',"=",contact.id]) dom.append(['state','=', 'waiting_payment']) invoices=get_model('account.invoice').search_browse(dom) print("total invoices: ", len(invoices)) for invoice in invoices: pname,hn,card_no='', '', '' pname2=pname hn='' if invoice.related_id: hdcase=invoice.related_id patient=hdcase.patient_id pname='%s%s'%(patient.first_name or "",patient.last_name or "") #XXX partner name should be the same patient name if patient_names.get(pname): pname=patient_names[pname] pname2='%s %s'%(patient.first_name or "",patient.last_name or "") card_no=patient.card_no or "" hn=patient.hn_no or "" elif invoice.ref: pname=invoice.ref or '' if patient_names.get(pname): pname=patient_names[pname] pname2=pname pname=pname.replace(" ","") # remove space for pt in get_model("clinic.patient").search_browse([['name_check','=',pname]]): hn=pt.hn_no or "" else: pass hn=hn[0:7] #XXX fee,epo,srv=0, 0, 0 due_amount=0 for inv_line in invoice.lines: amount=inv_line.amount or 0 prod=inv_line.product_id categ_code='' categ=prod.categ_id if categ: categ_code=categ.code if categ_code=='FEE': fee+=amount elif categ_code=='SRV': srv+=amount elif categ_code=='EPO': epo+=amount else: due_amount+=amount vals={ 'invoice_id': invoice.id, 'fee': fee, 'epo': epo, 'srv': srv, 'name': pname2, } due_amount+=fee+epo+srv #XXX date=invoice.date req_vals=[date,due_amount] key1=':'.join([str(v) for v in [hn]+req_vals]) key2=':'.join([str(v) for v in [card_no]+req_vals]) key3=':'.join([str(v) for v in [pname]+req_vals]) # name no space key_uc=':'.join([str(v) for v in [hn,date,due_amount]]) # becareful!!! if not matches1.get(key1): matches1[key1]=vals if not matches2.get(key2): matches2[key2]=vals if not matches3.get(key3): matches3[key3]=vals if not matches_uc.get(key_uc): matches_uc[key_uc]=vals nf_hcode='' if obj.hcode_id: nf_hcode=obj.hcode_id.code records=[] if obj.pcode=='SSO': for line in lines: hcode=line.get('hcode18') if not hcode: hcode='0' hcode=int(hcode) hcode=str(hcode) if nf_hcode==hcode: epo=line.get('epoadm29') or 0 fee=line.get('amount23') or 0 srv=line.get('allow37') or 0 date_treatment=line.get("dttran") name=line.get("name14") name_nospace=name.replace(" ","") card_no=int(line.get('pid')) date=date_treatment[0:10] time=date_treatment[11:] #XXX if not time: print("wrong format") continue due_amount=fee+epo+srv req_vals=[date,due_amount] hn=line.get('hn') hn=''.join([x for x in hn if x.isdigit()]) key1=':'.join([str(v) for v in [hn]+req_vals]) key2=':'.join([str(v) for v in [card_no]+req_vals]) key3=':'.join([str(v) for v in [name_nospace]+req_vals]) record={ 'date':date, 'patient_name': name, 'pid': card_no, 'hn': hn, 'fee': fee, 'srv': srv, 'epo': epo, 'invoice_id': None, 'state': 'unmatch', } if matches1.get(key1): print("found ", key1) record.update({ 'invoice_id': matches1[key1]['invoice_id'], 'state': 'match', }) elif matches2.get(key2): print("found ", key2) record.update({ 'invoice_id': matches2[key2]['invoice_id'], 'state': 'match', }) elif matches3.get(key3): print("found ", key3) record.update({ 'invoice_id': matches3[key3]['invoice_id'], 'state': 'match', }) else: # from ratchawat account settting phn=patient_hn.get(hn) if phn: key1=':'.join([str(v) for v in [phn['hn']]+req_vals]) ss="not found" if matches1.get(key1): ss="found" record.update({ 'invoice_id': matches1[key1]['invoice_id'], 'state': 'match', }) print(ss, ' account mathing ', key1) ## unmatch records.append(record) elif obj.pcode=='UC': records=[] for line in lines: #{'amount': '1500.0000', #'cstat': None, #'dttran': '2014-09-27T10:00:00', #'epostat': 'E', #'hdflag': 'COU', #'hdrate': '1500.0000', #'hn': '98511252', #'hreg': 'NHSO1', #'invno': '437941480', #'paid': '0.0000', #'paychk': '1', #'reimbpay': '0.0000', #'rid': '2190', #'station': '01'} date,time=(line['dttran'] or "").split("T") fee=0 if line.get('amount'): fee=float(line['amount']) hn=line['hn'] hn=hn.replace(" ", "") key_uc='' req_vals=[date,fee] if date and time: key_uc=':'.join([str(v) for v in [line['hn']]+req_vals]) pname='' pid='' for pt in get_model("clinic.patient").search_browse([['hn_no','=',hn]]): pname=pt.name or "" pid=pt.card_no or "" record={ 'date':date, 'name': pname, 'pid': pid, 'hn': hn, 'fee': fee, 'srv': 0, 'epo': 0, 'invoice_id': None, 'state': 'unmatch', } if matches_uc.get(key_uc): record.update({ 'invoice_id': matches1[key_uc]['invoice_id'], 'state': 'match', }) else: hn=hn.replace("-", "") hn=hn.replace("/", "") phn=patient_hn.get(hn) if phn: # match with name key3=':'.join([str(v) for v in [phn['name']]+req_vals]) ss="not found" mvals=matches3.get(key3) if mvals: ss="found" record.update({ 'invoice_id': mvals['invoice_id'], 'name': mvals['name'], 'state': 'match', }) print(ss, ' account mathing ', key_uc) records.append(record) if obj.hcode_id and not records: raise Exception("Nothing to match! for %s"%(obj.hcode_id.name or "")) if not records: raise Exception("Nothing to match! Please verify your file and your filter condition.") return records def onchange_date(self,context={}): data=context['data'] date=data['date'] year,month,day=date.split("-") weekday, total_day=monthrange(int(year), int(month)) data['date_from']="%s-%s-01"%(year,month) data['date_to']="%s-%s-%s"%(year,month,total_day) data['name']='%s/%s'%(year,month) return data def onchange_ptype(self,context={}): data=context['data'] type_id=data['patient_type_id'] if type_id: t=get_model('clinic.patient.type').browse(type_id) data['pcode']=t.code or "" return data def do_import(self,ids,context={}): st=get_model("clinic.setting").browse(1) if not st.import_account_id: raise Exception("Import account not found (Ratchawat Setting -> Accounting)") obj=self.browse(ids)[0] partner=obj.patient_type_id.contact_id company_id=get_active_company() vals={ "partner_id": partner.id, "company_id": company_id, "type": "in", "pay_type": "invoice", 'date': time.strftime("%Y-%m-%d"), "account_id": st.import_account_id.id, 'invoice_lines': [], 'rd_cust': True, #XXX } for line in obj.lines: inv=line.invoice_id if inv: vals['invoice_lines'].append(('create',{ 'invoice_id': inv.id, 'amount': inv.amount_due or 0, })) if inv.related_id: hdcase=inv.related_id if hdcase: hdcase.write({ 'state': 'paid', }) if not vals['invoice_lines']: raise Exception("Nothing to import") payment_id=get_model("account.payment").create(vals,context={"type":"in"}) return { 'next': { 'name': 'payment', 'mode': 'form', 'active_id': payment_id, }, 'flash': 'Create Payment successfully', } def do_match(self,ids,context={}): obj=self.browse(ids)[0] records=obj.match() lines=[] if obj.pcode=='SSO': for record in records: state=record['state'] or '' vals={ 'date': record['date'], 'hn': record['hn'], 'pid': record['pid'], 'name': record['patient_name'], 'epo': record['epo'], 'srv': record['srv'], 'fee': record['fee'], 'invoice_id': record['invoice_id'], 'state': state, } lines.append(('create', vals)) elif obj.pcode=='UC': for record in records: state=record['state'] or '' vals={ 'date': record['date'], 'hn': record['hn'], 'pid': record['pid'], 'name': record['name'], 'fee': record['fee'], 'invoice_id': record['invoice_id'], 'state': state, } lines.append(('create', vals)) for line in obj.lines: line.delete() obj.write({ 'lines': lines, }) def update_id(self,ids,context={}): obj=self.browse(ids)[0] lines=obj.get_line() pts={} for line in lines: pid=line.get("pid") name=line.get("name14") hn=line.get("hn") if not pts.get(name): pts[name]=pid for pt in get_model('clinic.patient').search_browse([]): pid=pts.get(pt.name) if pid: if pt.card_no: pid=''.join([str(x) for x in pt.card_no if x.isnumeric()]) print(pt.name, 'pid ', pid) else: pid=int(pid) print("pid ", pid) pt.write({ 'card_no': pid, }) print("Done!") def get_report_data(self,ids,context={}): lines=[] if ids: obj=self.browse(ids)[0] lines=obj.match() data={ 'lines': lines, } return data def onchange_invoice(self,context={}): data=context['data'] path=context['path'] line=get_data_path(data,path,parent=True) if line.get("invoice_id"): line['state']='match' else: line['state']='' return data def clear_line(self,ids,context={}): obj=self.browse(ids)[0] line_ids=[line.id for line in obj.lines] get_model("clinic.matching.payment.line").delete(line_ids) print("Cleared %s"%(line_ids)) def approve(self,ids,context={}): obj=self.browse(ids)[0] obj.write({ 'state': 'approved', }) return { 'next': { 'name': 'clinic_matching_payment', 'mode': 'form', 'active_id': obj.id, }, 'flash': '%s has been approved'%obj.name, } def to_draft(self,ids,context={}): for obj in self.browse(ids): obj.write({ 'state': 'draft', }) def create(self,vals,**kw): new_id=super().create(vals,**kw) self.function_store([new_id]) return new_id def write(self,ids,vals,**kw): super().write(ids,vals,**kw) self.function_store(ids) def get_data_match(self,context={}): ref_id=int(context.get("refer_id","0")) obj=self.browse(ref_id) inv_match_ids=[] for line in obj.lines: invoice=line.invoice_id if invoice and line.state=='match': inv_match_ids.append(invoice.id) dom=[ ['partner_id','=',obj.partner_id.id], ['date', '>=', obj.date_from], ['date', '<=', obj.date_to], ['state','=','waiting_payment'], ] lines=[] no=1 for invoice in get_model('account.invoice').search_browse(dom): if invoice.id not in inv_match_ids: continue vals={ 'no': no, 'date': invoice.date, 'number': invoice.number, 'ref': invoice.ref, 'amount_due': invoice.amount_due or 0, } lines.append(vals) no+=1 data={ 'ptype': obj.patient_type_id.name or "", 'title': 'Invoice Match', 'lines': lines, 'date_from': obj.date_from, 'date_to': obj.date_to, } return data def get_data_unmatch(self,context={}): ref_id=int(context.get("refer_id","0")) obj=self.browse(ref_id) inv_match_ids=[] for line in obj.lines: invoice=line.invoice_id if invoice and line.state=='match': inv_match_ids.append(invoice.id) dom=[ ['partner_id','=',obj.partner_id.id], ['date', '>=', obj.date_from], ['date', '<=', obj.date_to], ['state','=','waiting_payment'], ] lines=[] no=1 for invoice in get_model('account.invoice').search_browse(dom): if invoice.id in inv_match_ids: continue vals={ 'no': no, 'date': invoice.date, 'number': invoice.number, 'ref': invoice.ref, 'amount_due': invoice.amount_due or 0, } lines.append(vals) no+=1 data={ 'ptype': obj.patient_type_id.name or "", 'title': 'Invoice Unmatch', 'lines': lines, 'date_from': obj.date_from, 'date_to': obj.date_to, } return data def print_invoice_unmatch(self,ids,context={}): obj=self.browse(ids)[0] return { 'next':{ 'name': 'clinic_matching_payment', 'mode': 'form', 'active_id': obj.id, }, } def print_invoice_match(self,ids,context={}): obj=self.browse(ids)[0] return { 'next':{ 'name': 'clinic_matching_payment', 'mode': 'form', 'active_id': obj.id, }, } MatchingPayment.register()