import time from datetime import datetime, timedelta from netforce.model import Model, fields, get_model from netforce.utils import get_data_path, get_file_path from netforce.access import get_active_user,set_active_user, get_active_company from . import utils class HDCase(Model): _name="clinic.hd.case" _string="HD Case" _audit_log=True _name_field="number" _multi_company=True def _get_duration(self,ids,context={}): res={} fmt="%Y-%m-%d %H:%M:%S" for obj in self.browse(ids): diff=datetime.strptime(obj.time_stop,fmt)-datetime.strptime(obj.time_start,fmt) total_time=round(diff.seconds/3600,2) res[obj.id]=total_time return res def _get_pay_amount(self,ids,context={}): res={} for obj in self.browse(ids): res[obj.id]=obj.amount return res def _get_all(self,ids,context={}): vals={} for obj in self.browse(ids): total_amt=0 rmb_amt=0 due_amt=0 for line in obj.lines: if line.reimbursable=='yes': rmb_amt+=line.amount or 0.0 else: due_amt+=line.amount or 0.0 total_amt+=line.amount or 0.0 for line in obj.payment_lines: due_amt-=line.amount or 0.0 vals[obj.id]={ "total_amount": total_amt, "due_amount": due_amt, 'rmb_amount': rmb_amt, 'hd_case_id': obj.id, } return vals def _get_patient_type(self,ids,context={}): res={} for obj in self.browse(ids): patient=obj.patient_id res[obj.id]=patient.type_id.id return res def _get_store(self,ids,context={}): res={} for obj in self.browse(ids): include=False type_code=obj.patient_id.type_id.code if obj.patient_id.type_id.hct_include: include=True staff_id=None for sline in obj.staffs: staff=sline.staff_id if staff and sline.priop=='personal': staff_id=staff.id break res[obj.id]={ 'hct_include': include, 'type_code': type_code, 'doctor_id2': staff_id, } return res def _get_expense(self,ids,context={}): res={} user_id=get_active_user() set_active_user(1) reimbursable_ctx=context.get('reimbursable') no=0 for obj in self.browse(ids): if not obj.doctor_id: print('obj.date ', obj.date) no+=1 dlz_use=0 dlz_max=0 dlz_name=[] dlz_id=None for dlz in obj.dialyzers: dz=dlz.dialyzer_id dlz_id=dz.id prod=dz.product_id name="" if prod: name=prod.description or "" dlz_name.append(name) dlz_use+=dlz.use_time or 0 dlz_max+=dlz.max_use_time or 0 dlz_name=','.join([dlz for dlz in dlz_name]) epo_names=[] mdc_names=[] iron_names=[] fee=0 lab=0 misc=0 dlz_price=0 srv=0 mdc=0 for line in obj.lines: amt=line.amount or 0 prod=line.product_id prod_name=prod.description or prod.name or "" categ=line.product_categ_id if categ and prod: sign=1 if line.reimbursable=='yes': sign=-1 if categ.parent_id: if categ.parent_id.code=='MDC': if reimbursable_ctx: if reimbursable_ctx==line.reimbursable: mdc+=amt mdc_names.append(prod_name or "") else: mdc+=amt mdc_names.append(prod_name or "") if categ.code=='EPO': epo_names.append(prod_name.title()) elif categ.code=='IVR': iron_names.append(prod_name.title()) elif categ.code=='FEE': fee+=amt*sign elif categ.code=='DLZ': dlz_price+=amt elif categ.code=='SRV': srv+=amt elif categ.code=="LAB": if reimbursable_ctx: if reimbursable_ctx==line.reimbursable: lab+=amt else: lab+=amt else: if reimbursable_ctx: if reimbursable_ctx==line.reimbursable: misc+=amt else: misc+=amt res[obj.id]={ 'epo': ','.join([n for n in epo_names]), 'mdc_name': ','.join([n for n in mdc_names]), 'iron_name': ','.join([n for n in iron_names]), 'fee': fee, 'lab': lab, 'misc': misc, 'mdc': mdc, 'srv': srv, 'dlz_id': dlz_id, 'dlz_price': dlz_price, 'dlz_name': dlz_name, 'dlz_use': dlz_use, 'dlz_max': dlz_max, } set_active_user(user_id) return res def _get_req_fee(self,ids,context={}): res={} for obj in self.browse(ids): total_amt=0 rmb_amt=0 for line in obj.lines: amt=line.amount or 0 if line.reimbursable=='yes': rmb_amt+=amt total_amt+=amt pm_amt=0 for pline in obj.payment_lines: pm_amt+=pline.amount or 0 due_amt=total_amt-pm_amt-rmb_amt paid=0 if due_amt>0: paid=1 res[obj.id]=paid return res def _get_hct_msg(self,ids,context={}): res={} for obj in self.browse(ids): msg="" hct=obj.hct or 0 if(hct<=36): msg="สามารถเบิกค่ายาสูงสุดไม่เกิน 1,125บาท ต่อ สัปดาห์" elif(hct>36 and hct<=39): msg="สามารถเบิกค่ายาสูงสุดไม่เกิน 750บาท ต่อ สัปดาห์" elif(hct> 39): msg="ไม่สามารถเบิกค่ายาฉีดได้ทุกตัว" res[obj.id]=msg return res _fields={ "number": fields.Char("Number",required=True,search=True), "epo": fields.Char("EPO",function="_get_expense",function_multi=True), "fee": fields.Float("Fee",function="_get_expense",function_multi=True), "lab": fields.Float("Fee",function="_get_expense",function_multi=True), "misc": fields.Float("Fee",function="_get_expense",function_multi=True), "dlz_name": fields.Float("DZ",function="_get_expense",function_multi=True), "dlz_price": fields.Float("DZ",function="_get_expense",function_multi=True), "dlz_use": fields.Float("DZ Use",function="_get_expense",function_multi=True), "dlz_max": fields.Float("DZ Max",function="_get_expense",function_multi=True), "dlz_id": fields.Integer("DZ ID",function="_get_expense",function_multi=True), "mdc": fields.Float("MDC",function="_get_expense",function_multi=True), "srv": fields.Float("Service",function="_get_expense",function_multi=True), "mdc_name": fields.Float("MDC Name",function="_get_expense",function_multi=True), "iron_name": fields.Float("Iron Name",function="_get_expense",function_multi=True), 'sickbed_id': fields.Many2One("clinic.sickbed",'Sickbed'), "ref": fields.Char("Ref",search=True), "time_start": fields.DateTime("Start Time",required=True), "time_stop": fields.DateTime("Finish Time",required=True), "date": fields.Date("Date",required=True,search=True), "patient_id": fields.Many2One("clinic.patient","Patient",domain=[['state','=','admit']],required=True,search=True), "patient_type_id": fields.Many2One("clinic.patient.type", "Type"), "nurse_id": fields.Many2One("clinic.staff","Approve By", domain=[['type','=','nurse']]), "department_id": fields.Many2One("clinic.department", "Department",search=True), "wt_start": fields.Float("Start Wt (kg.)"), "wt_stop": fields.Float("Finish Wt (kg.)"), "bp_start": fields.Char("Start BP"), "bp_stop": fields.Char("Finish BP"), "membrane_type": fields.Selection([("unsub","Unsub cellul"),("sub","Sub cellul"),("synthetic","Synthetic")],"Membrane Type"), "hd_acc": fields.Selection([("o","OPD"),("i","IPD")],"HD Acc"), "hd_mode": fields.Selection([("chronic","Chronic"),("acute","Acute")],"HD Mode"), "vascular_acc": fields.Many2One("clinic.vascular.access","Vascular Ac."), "bid_flow_rate": fields.Integer("BFR (ml/min)"), "ultrafittration": fields.Float("Ultrafiltration (kg.)"), "hct": fields.Integer("Hct"), "hct_msg" : fields.Char("",function="_get_hct_msg",store=True), 'hct_include': fields.Boolean("HCT Include", function="_get_store", function_multi=True,store=True), 'type_code': fields.Char("Product Code", function="_get_store", function_multi=True,store=True), 'doctor_id2': fields.Many2One("clinic.staff","Doctor2", function="_get_store", function_multi=True,store=True), "state": fields.Selection([("draft","Draft"),('waiting_treatment','Waiting Treatment'),("in_progress","In Progress"),("completed","Finish Treatment"),('paid','Paid'),("waiting_payment","Waiting Payment"),("discountinued","Discountinued"),("cancelled","Cancelled")],"Status",required=True), "staffs": fields.One2Many("clinic.hd.case.staff","hd_case_id","Staffs"), "comments": fields.One2Many("message","related_id","Comments"), "company_id": fields.Many2One("company","Company"), "dialyzers": fields.One2Many("clinic.hd.case.dialyzer","hd_case_id","Dialyzers"), "lines": fields.One2Many("clinic.hd.case.line","hd_case_id","Lines"), "invoices": fields.One2Many("account.invoice","related_id","Invoices"), "pickings": fields.One2Many("stock.picking","related_id","Pickings"), "payments": fields.One2Many("account.payment","related_id","Payments"), "payment_lines": fields.One2Many("clinic.payment","hd_case_id","Payment Lines"), "expenes": fields.One2Many("clinic.hd.case.expense","hd_case_id","Expenses"), 'visit_id': fields.Many2One("clinic.visit", "Visit"), 'duration': fields.Integer("Duration (Hours)",function="_get_duration"), "total_amount": fields.Float("Total",function="_get_all",readonly=True,function_multi=True), "rmb_amount": fields.Float("Reimbursable",function="_get_all",readonly=True,function_multi=True), "due_amount": fields.Float("Due Amount",function="_get_all",readonly=True,function_multi=True), 'fee_partner_id': fields.Many2One("partner","Contact Fee"), 'note': fields.Text("Note"), 'complication': fields.Text("Complication"), "cycle_id": fields.Many2One("clinic.cycle","Cycle"), 'cycle_item_id': fields.Many2One("clinic.cycle.item","Cycle Item (Nurses)"), # on_delete="cascade" -> will rm visit from cycle item 'pay_amount': fields.Float("Amount",function="_get_pay_amount"), 'pay_date': fields.Date("Pay Date"), 'pay_account_id': fields.Many2One("account.account","Account"), 'payment_id': fields.Many2One("account.payment","Payment"), # for print 'dlz_id': fields.Many2One("clinic.dialyzer","Dialyzer"), # for link "total_doctor": fields.Integer("Total Doctor",function="get_staff",function_multi=True), "total_nurse": fields.Integer("Total Nurse",function="get_staff",function_multi=True), 'doctor_id': fields.Many2One("clinic.staff","Doctor",domain=[['type','=','doctor']],function="get_staff",function_multi=True), 'nu': fields.Char("N/U"), "invoice_policy": fields.Selection([("fee","Only Fee"),("fee_mdc","Fee & Medicine")],"Government pay for:"), "invoice_option": fields.Selection([("fee_mdc_plus","Combine Fee & Medicine"),("fee_mdc_split","Split Fee & Medicine")],"Invoice:"), 'req_fee': fields.Integer("Request Expense",function="_get_req_fee"), 'hd_case_id': fields.Many2One("clinic.hd.case","HD",function="_get_all",function_multi=True), # XXX 'company_id': fields.Many2One("company","Company"), 'branch_id': fields.Many2One("clinic.branch","Branch"), } def _get_number(self,context={}): while 1: seq_id=get_model("sequence").find_sequence(type="clinic_hdcase") num=get_model("sequence").get_next_number(seq_id,context=context) if not num: return None user_id=get_active_user() set_active_user(1) res=self.search([["number","=",num]]) set_active_user(user_id) if not res: return num get_model("sequence").increment_number(seq_id,context=context) def _get_number_invoice_noclaim(self,context={}): while 1: seq_id=get_model("sequence").find_sequence(type="clinic_invoice_noclaim",name=None,context=context) num=get_model("sequence").get_next_number(seq_id,context=context) if not num: return None user_id=get_active_user() set_active_user(1) res=get_model('account.invoice').search([["number","=",num]]) set_active_user(user_id) if not res: return num get_model("sequence").increment_number(seq_id,context=context) _defaults={ "state": "draft", "date": lambda *a: time.strftime("%Y-%m-%d"), "time_start": lambda *a: time.strftime("%Y-%m-%d %H:%M:%S"), "time_stop": lambda *a: time.strftime("%Y-%m-%d %H:%M:%S"), 'number': '/', "company_id": lambda *a: get_active_company(), 'hd_acc': 'o', 'hd_mode': 'chronic', 'hct_msg': "สามารถเบิกค่ายาสูงสุดไม่เกิน 1,125บาท ต่อ สัปดาห์", 'invoice_option': 'fee', 'invoice_policy': 'fee', 'req_fee': 0, 'hct_include': False, } _order="date desc,number desc" def onchange_dialyzer(self,context={}): data=context["data"] path=context["path"] line=get_data_path(data,path,parent=True) dialyzer_id=line.get("dialyzer_id") if not dialyzer_id: return {} dialyzer=get_model("clinic.dialyzer").browse(dialyzer_id) use_time=dialyzer.use_time or 0 max_time=dialyzer.max_use_time or 0 if use_time > max_time: dialyzer.write({ 'state': 'expire', }) raise Exception("%s is expired"%dialyzer.number) use_time+=1 line["description"]=dialyzer.name or dialyzer.product_id.name or "" line["use_time"]=use_time line["max_use_time"]=dialyzer.max_use_time line["dialyzer_type"]=dialyzer.dialyzer_type data['dlz_id']=dialyzer.id return data def onchange_cycle(self,context={}): data=context['data'] cycle_id=data['cycle_id'] cycle=get_model("clinic.cycle").browse(cycle_id) date=data['time_start'][0:10] data['time_start']='%s %s'%(date, cycle.time_start) data['time_stop']='%s %s'%(date, cycle.time_stop) fmt="%Y-%m-%d %H:%M" diff=datetime.strptime(data['time_stop'],fmt)-datetime.strptime(data['time_start'],fmt) total_time=round(diff.seconds/3600,2) data['duration']=total_time #XXX get nurse team return data def empty_line(self,lines=[]): empty=True for line in lines: if line: empty=False break return empty def onchange_patient(self,context={}): data=context['data'] patient_id=data['patient_id'] if patient_id: patient=get_model('clinic.patient').browse(patient_id) department=patient.department_id branch=patient.branch_id cycle=patient.cycle_id partner=patient.type_id.contact_id if partner: data['fee_partner_id']=partner.id else: data['fee_partner_id']=None data['department_id']=department.id data['branch_id']=branch.id data['cycle_id']=cycle.id data['patient_type_id']=patient.type_id.id data['type_code']=patient.type_id.code if patient.type_id.hct_include: data['hct_include']=True else: data['hct_include']=False data['dialyzers']=[] doctor=patient.doctor_id data['staffs']=[] # XXX data['staffs'].append({ 'staff_id': doctor.id, 'type': 'doctor', 'priop': 'personal', }) if data['patient_type_id']: st=get_model("clinic.setting").browse(1) data['lines']=[] for pline in st.products: if data['patient_type_id']==pline.patient_type_id.id: data['lines'].append({ 'product_categ_id': pline.product_categ_id.id, 'product_id': pline.product_id.id, 'description': pline.description or "", 'uom_id': pline.uom_id.id, 'qty': pline.qty or 0, 'price': pline.price or 0, 'amount': pline.amount or 0, }) return data def onchange_line(self,context={}): data=context['data'] path=context['path'] line=get_data_path(data,path,parent=True) qty=line['qty'] or 0 price=line['price'] or 0.0 line['amount']=qty*price data=self.update_amount(context) #bug show button return data def onchange_product(self,context={}): data=context['data'] path=context['path'] line=get_data_path(data,path,parent=True) product_id=line.get('product_id') prod=get_model("product").browse(product_id) if not prod: return data if prod.can_sell: line['reimbursable']='no' else: line['reimbursable']='yes' line['uom_id']=prod.uom_id.id line['description']=prod.name line['product_categ_id']=prod.categ_id.id qty=1 price=prod.sale_price or 0.0 amt=qty*price line['qty']=qty line['price']=price line['amount']=amt data=self.update_amount(context) return data def onchange_pay(self,context={}): data=context['data'] pay_amount=data['pay_amount'] or 0 amount=data['amount'] or 0 if pay_amount > amount: data['pay_amount']=0 return data def update_amount(self,context={}): data=context['data'] due_amt=0.0 rmb_amt=0.0 for line in data['lines']: amt=line.get('amount', 0.0) reimbursable=line.get('reimbursable','no') if reimbursable=='yes': rmb_amt+=amt else: due_amt+=amt data['rmb_amount']=rmb_amt data['due_amount']=due_amt data['total_amount']=due_amt+rmb_amt data['req_fee']=0 if due_amt: data['req_fee']=1 return data def make_payment(self,ids,context={}): obj=self.browse(ids)[0] if not obj.total_amount: return remaining_amt=0.0 for line in obj.lines: remaining_amt+=line.amount or 0.0 for line in obj.payment_lines: remaining_amt-=line.amount or 0.0 partner=obj.patient_id.partner_id if not partner: raise Exception("Not partner") st=get_model('clinic.setting').browse(1) cash_account_id=st.cash_account_id.id income_account_id=st.income_account_id.id if not cash_account_id: raise Exception("No Cash Account") if not income_account_id: raise Exception("No Income Account") pay_amount=obj.pay_amount bill_no=context.get("bill_no", "") if context.get("amount",0): pay_amount=context['amount'] or 0.0 company_id=get_active_company() vals={ "partner_id": partner.id, "company_id": company_id, "type": "in", "pay_type": "direct", 'date': time.strftime("%Y-%m-%d"), "account_id": cash_account_id, 'related_id': "clinic.hd.case,%s"%obj.id, 'ref': bill_no or obj.number or "", 'direct_lines': [], } patient=obj.patient_id ptype=patient.type_id shop_type=st.shop_type_id if not shop_type: raise Exception("No Patient Type -> Clinic Settings-> RD Shop -> Patient Type") ptype=shop_type prod_acc=st.get_product_account track_id=obj.branch_id.track_id.id for line in obj.lines: if line.reimbursable=='no': if line.amount < 1: continue prod=line.product_id acc=prod_acc(prod.id,ptype.id,'cash') account_id=acc.get("ar_credit_id",None) ar_debit_id=acc.get("ar_debit_id",None) if not account_id: raise Exception("No Income Credit Account for product [%s] %s"%(prod.code, prod.name)) if not ar_debit_id: raise Exception("No Ar Debit Account for product [%s] %s"%(prod.code, prod.name)) desc=line.description or "" if prod: desc="[%s] %s"%(prod.code, line.description or "") vals['direct_lines'].append(('create',{ "description": desc, "qty": line.qty, "unit_price": line.price or 0, "amount": line.amount or 0, 'account_id': account_id, 'track_id': track_id, })) context={ 'type': 'in', 'branch_id': obj.branch_id.id, } payment_id=get_model("account.payment").create(vals,context=context) obj.write({ 'payment_lines': [('create',{ 'payment_id': payment_id, 'amount': pay_amount, })], }) payment=get_model('account.payment').browse(payment_id) payment.post() if payment.move_id: for mline in payment.move_id.lines: mline.write({ 'partner_id': partner.id, }) return { 'next': { 'name': 'clinic_hd_case', 'mode': 'form', 'active_id': obj.id, }, 'flash': 'Pay OK', } def cancelled(self,ids,context={}): obj=self.browse(ids)[0] if obj.sickbed_id: obj.sickbed_id.write({ 'available': True, }) obj.write({"state":"cancelled"}) def make_invoices(self,ids,context={}): setting=get_model("settings").browse(1,context) currency_id=setting.currency_id.id if not currency_id: raise Exception("Currency not found in account settings") company_id=get_active_company() uom=get_model("uom").search_browse([['name','ilike','%Unit%']]) if not uom: raise Exception("Unit not found in uom") obj=self.browse(ids[0]) if obj.invoices: for inv in obj.invoices: inv.void() due_date=obj.date[0:10] # cash, credit is_credit=context.get('is_credit') or False context['type']='out' context['inv_type']='invoice' rmb_lines=[] #yes normb_lines=[] #no cst=get_model('clinic.setting').browse(1) prod_acc=cst.get_product_account track_id=obj.branch_id.track_id.id for line in obj.lines: if line.state!='draft': continue if line.amount < 1: continue #XXX prod=line.product_id print("#1.find in line") account_id=line.account_id.id ar_debit_id=line.ar_debit_id.id if not account_id or not ar_debit_id: print("#2.find in ratchawat setting") if line.reimbursable=='yes': acc=prod_acc(prod.id,obj.patient_type_id.id) else: stype=cst.shop_type_id # Pay them self if not stype: raise Exception("No Patient Type : Clinic Setting -> RD Shop") if is_credit: acc=prod_acc(prod.id,stype.id,'credit') else: acc=prod_acc(prod.id,stype.id,'cash') account_id=acc.get("ar_credit_id",None) ar_debit_id=acc.get("ar_debit_id",None) if not account_id: raise Exception("No Income Credit Account for product [%s] %s"%(prod.code, prod.name)) if not ar_debit_id: raise Exception("No Ar Debit Account for product [%s] %s"%(prod.code, prod.name)) if line.reimbursable=='yes': rmb_lines.append(('create',{ "product_id": prod.id, "description": line.description or "", "qty": line.qty, "uom_id": line.uom_id.id, "unit_price": line.price or 0, "amount": line.amount or 0, 'account_id': account_id, 'ar_debit_id': ar_debit_id, 'track_id': track_id, })) else: normb_lines.append(('create',{ "product_id": prod.id, "description": line.description or "", "qty": line.qty, "uom_id": line.uom_id.id, "unit_price": line.price or 0, "amount": line.amount or 0, 'account_id': account_id, 'ar_debit_id': ar_debit_id, 'track_id': track_id, })) patient=obj.patient_id patient_partner=patient.partner_id if rmb_lines: ptype=patient.type_id partner=ptype.contact_id if not partner: raise Exception("No contact for patient type %s"%obj.ptype.name) vals={ "type": "out", "inv_type": "invoice", "tax_type": "tax_in", 'date': obj.date, 'due_date': due_date, "ref": '%s (%s)'%(patient.name or '',patient.number or ''), 'department_id': obj.department_id.id, "related_id": "clinic.hd.case,%s"%obj.id, "currency_id": currency_id, "company_id": company_id, "lines": [], "company_id": company_id, 'hdcase_credit': False, } vals["partner_id"]=partner.id vals['lines']=rmb_lines if patient_partner: vals['patient_partner_id']=patient_partner.id, #XXX if obj.branch_id: context['branch_id']=obj.branch_id.id get_model("account.invoice").create(vals,context=context) if normb_lines and is_credit: partner=patient.partner_id if not partner: raise Exception("No contact for this patient %s"%obj.partner.name) context['branch_id']=obj.branch_id.id number=self._get_number_invoice_noclaim(context=context) vals={ 'number': number, "type": "out", "inv_type": "invoice", "tax_type": "tax_in", 'due_date': due_date, "ref": obj.number, "related_id": "clinic.hd.case,%s"%obj.id, "currency_id": currency_id, "company_id": company_id, "lines": [], "company_id": company_id, 'partner_id':partner.id, 'hdcase_credit': True, } vals['lines']=normb_lines if patient_partner: vals['patient_partner_id']=patient_partner.id, get_model("account.invoice").create(vals,context) # create alway obj.make_pickings() # prevent douplicate create invoice & picking for line in obj.lines: line.write({ 'state': 'done', }) def make_pickings(self,ids,context={}): obj=self.browse(ids[0]) # no picking if not obj.lines: return patient=obj.patient_id partner=patient.partner_id if not partner: raise Exception("Contact not for this patient") ship_address_id=None for address in partner.addresses: if address.type=="shipping": ship_address_id=address.id break if not ship_address_id: patient.simple_address() #raise Exception("contact %s dont'have address with type shipping"%partner.name) # default journal cust_loc_id=None wh_loc_id=None # find location # 1. from department -> branch -> stock journal -> from, to department=obj.department_id if department: stock_journal=department.pick_out_journal_id if stock_journal: wh_loc_id=stock_journal.location_from_id.id cust_loc_id=stock_journal.location_to_id.id print("get location from stock journal %s "%(stock_journal.name)) pick_vals={ "type": "out", 'journal_id': stock_journal.id, "ref": obj.number, "related_id": "clinic.hd.case,%s"%obj.id, "partner_id": obj.patient_id.partner_id.id, "ship_address_id": ship_address_id, "state": "draft", "lines": [], } if not cust_loc_id: res=get_model("stock.location").search([["type","=","customer"]]) if not res: raise Exception("Customer location not found") cust_loc_id=res[0] #XXX no_lines=context.get('no_line') or False if no_lines: return prod_ids=context.get('prod_ids') or [] prod_exist_ids=[] for line in obj.lines: if line.state!='draft': continue if line.qty < 1: continue prod=line.product_id if prod.type != 'stock': continue # check orginal product prod_code=prod.code.split("-")[0] if patient.type_id.main_product: if len(prod_code)>1: prods=get_model('product').search_browse(['code','=',prod_code]) if not prods: raise Exception("Can not create good issue: product code %s is not found!"%prod_code) prod=prods[0] if prod_ids and prod.id not in prod_ids or prod.id in prod_exist_ids: continue prod_exist_ids.append(prod.id) #XXX dpt_prods=get_model('clinic.department.product').get_location(obj.department_id.id,prod.id) if dpt_prods: print("get location from menu department products") wh_loc_id=dpt_prods.get('wh_loc_id') cust_loc_id=dpt_prods.get('cust_loc_id') #pick_vals['journal_id']=dpt_prods.get('journal_id') if not wh_loc_id: wh_loc_id=prod.location_id.id if wh_loc_id: res=get_model("stock.location").search([["type","=","internal"]]) if not res: raise Exception("Warehouse not found") wh_loc_id=res[0] line_vals={ "product_id": prod.id, "qty": line.qty, "uom_id": prod.uom_id.id, "location_from_id": wh_loc_id, "location_to_id": cust_loc_id, } pick_vals["lines"].append(("create",line_vals)) if not pick_vals["lines"]: return { "flash": "Nothing left to deliver", } picking_obj=get_model("stock.picking") context={ 'pick_type': 'out', 'journal_id': pick_vals['journal_id'], } pick_id=picking_obj.create(pick_vals,context=context) pick=picking_obj.browse(pick_id) pick.set_done([pick_id]) def post_invoices(self,ids,context={}): obj=self.browse(ids[0]) for inv in obj.invoices: if inv.amount_total<1: continue inv.post() print("Post!") def do_treatment(self,ids,context={}): obj=self.browse(ids)[0] #TODO should find dlz when confirm visit if not obj.dialyzers: raise Exception("Please input dialyzer!") vals={ 'state': 'in_progress', } if obj.number=='/': context['branch_id']=obj.branch_id.id number=self._get_number(context=context) vals['number']=number # update start time st=get_model("clinic.setting").browse(1) if st.real_time: timenow=time.strftime("%H:%M:%S") date=obj.date vals['time_start']='%s %s'%(date,timenow) vals['time_stop']='%s %s'%(date,timenow) obj.write(vals) def discontinue(self,ids,context={}): obj=self.browse(ids)[0] # TODO pop to note obj.write({"state":"cancelled"}) def update_usetime(self,ids,context={}): for obj in self.browse(ids): is_decrease=context.get('is_decrease') for dlz_line in obj.dialyzers: dlz=dlz_line.dialyzer_id membrane_type=dlz_line.membrane_type or 'unsub' dialyzer_type=dlz_line.dialyzer_type or 'low' use_time=dlz_line.use_time or 0 max_use_time=dlz_line.max_use_time or 0 desc=dlz_line.description or '' #TODO when we to draft after approve hdcase it will update the wrong use time #if use_time > (dlz.use_time or 0): #continue if is_decrease: use_time-=1 vals={ 'membrane_type': membrane_type, 'dialyzer_type': dialyzer_type, 'use_time': use_time, 'max_use_time': max_use_time, 'note': desc, } if use_time==max_use_time: vals.update({ 'use_time': use_time, 'state': 'expire', }) elif use_time > max_use_time: raise Exception("Dialyzer is expired!") dlz.write(vals) return True def create_cycle_item(self,ids,context={}): for obj in self.browse(ids): cycle_item=get_model("clinic.cycle.item") datenow=obj.time_start[0:10] if not datenow: datenow=time.strftime('%Y-%m-%d') cycle_id=obj.cycle_id.id branch_id=obj.branch_id.id department_id=obj.department_id.id dom=[] if datenow: dom.append(['date','=',datenow]) if cycle_id: dom.append(['cycle_id','=',cycle_id]) if branch_id: dom.append(['branch_id','=',branch_id]) if department_id: dom.append(['department_id','=',department_id]) cycle_item_ids=cycle_item.search(dom) cycle_item_id=None if cycle_item_ids: cycle_item_id=cycle_item_ids[0] else: cycle_item_id=cycle_item.create({ 'date': obj.date, 'cycle_id': cycle_id, 'branch_id': branch_id, 'department_id': department_id, }) obj.write({ 'cycle_item_id': cycle_item_id, }) return True def do_expense(self,ids,context={}): # not longer use 2015-02-28 for obj in self.browse(ids): # clear old expense for exp in obj.expenes: exp.delete() exp_lines=[] fee=0.0 mdc=0.0 srv=0.0 other=0.0 for line in obj.lines: amt=line.amount or 0.0 if line.reimbursable=='no': amt=0 categ=line.product_categ_id if categ.code=='FEE': fee+=amt elif categ.code=='EPO': mdc+=amt elif categ.code=='SRV': srv+=amt else: other+=amt exp_lines.append(('create',{ 'date': obj.date, 'patient_id': obj.patient_id.id, 'hd_case_id': obj.id, 'fee_amt': fee, 'mdc_amt': mdc, 'srv_amt': srv, 'state': 'waiting_matching', })) obj.write({ 'expenes': exp_lines, }) def complete(self,ids,context={}): obj=self.browse(ids)[0] obj.make_invoices(context=context) obj.post_invoices(context=context) obj.create_cycle_item() #obj.do_expense(context=context) vals={ "state":"waiting_payment", # for government } st=get_model("clinic.setting").browse(1) if st.real_time: timenow=time.strftime("%H:%M:%S") date=obj.date vals['time_stop']='%s %s'%(date,timenow) obj.write(vals) if context.get("called"): return obj.id return { 'next': { 'name': 'clinic_hd_case', 'mode': 'form', 'active_id': obj.id, }, 'flash': '%s is completed'%obj.number, } def delete(self,ids,context={}): for obj in self.browse(ids): if obj.state != 'draft': raise Exception("Can not delete HD Case %s because state is not draft"%obj.number) super().delete(ids) def onchange_hct(self,context={}): data=context['data'] if not data.get("hct"): data['hct']=0 hct=data["hct"] msg="" # XXX do not hard code if(hct<=36): msg="สามารถเบิกค่ายาสูงสุดไม่เกิน 1,125บาท ต่อ สัปดาห์" elif(hct>36 and hct<=39): msg="สามารถเบิกค่ายาสูงสุดไม่เกิน 750บาท ต่อ สัปดาห์" elif(hct> 39): msg="ไม่สามารถเบิกค่ายาฉีดได้ทุกตัว" data['hct_msg']=msg return data def undo(self,ids,context={}): obj=self.browse(ids)[0] context['is_decrease']=True obj.update_usetime(context=context) for line in obj.lines: line.write({ 'state': 'draft', }) for inv in obj.invoices: inv.write({ 'state': 'draft', }) if inv.move_id: inv.move_id.to_draft() inv.move_id.delete() inv.delete() for pick in obj.pickings: pick.write({ 'state': 'draft', }) pick.delete() for payment in obj.payments: payment.to_draft() payment.delete() for pm_line in obj.payment_lines: pm_line.delete() for exp in obj.expenes: exp.delete() state=context.get("state","in_progress") #force state obj.write({ 'state': state, }) # update sickbed if obj.sickbed_id: obj.sickbed_id.write({ 'available': False, }) return { 'next': { 'name': 'clinic_hd_case', 'mode': 'form', 'active_id': obj.id, }, 'flash': '%s has been undo'%obj.number, } def view_payment(self,ids,context={}): print("clinic_view_payment") return { 'next': { 'name': 'payment', 'mode': 'form', 'active_id': ids[0], }, } def request_fee(self,ids,context={}): obj=self.browse(ids)[0] obj.update_usetime() obj.complete() # send some message to anyboby: patient return { 'next': { 'name': 'clinic_hd_case', 'mode': 'form', 'active_id': obj.id, } } def pay(self,ids,context={}): return { 'next': { 'name': 'clinic_payment', 'refer_id': ids[0], #XXX } } def done(self,ids,context={}): obj=self.browse(ids)[0] count=0 for sline in obj.staffs: if sline.staff_id: count+=1 if not count: raise Exception("Please define doctor for patient %s"%obj.patient_id.name) obj.update_usetime() #FIXME allow user to write sickbed status user_id=get_active_user() set_active_user(1) nurse_id=None for st in get_model("clinic.staff").search_browse([['user_id','=',user_id]]): nurse_id=st.id obj.write({ 'state': 'completed', 'nurse_id': nurse_id, }) obj.sickbed_id.write({ 'available': True, }) set_active_user(user_id) return { 'next': { 'name': 'clinic_hd_case', 'mode': 'form', 'active_id': obj.id, }, 'flash': 'Finish treatment!', } def get_report_payment_data(self,context={}): if not context.get('payment_id'): return {} payment_id=context.get("payment_id") if not payment_id: return {} payment=get_model("account.payment").browse(int(payment_id)) comp_id=get_active_company() comp=get_model('company').browse(comp_id) hdcase=payment.related_id if hdcase: context['branch_id']=hdcase.branch_id.id st=get_model('settings').browse(1,context=context) cst=get_model('clinic.setting').browse(1) cust=payment.partner_id cust_name=cust.name or '' cust_addr='' if cust.addresses: cust_addr=cust.addresses[0].address_text if 'your' in cust_addr: cust_addr='' if cust.walkin_cust: cust_name=payment.ref or '' no=1 sub_total=0 amount_total=0 lines=[] def get_prod(desc): product=None if desc: i1=desc.index('[') i2=desc.index(']') code=desc[i1+1:i2] for prod in get_model("product").search_browse([['code','=',code]]): product=prod return product for line in payment.lines: amt=line.amount or 0 desc=line.description or '' uom_name="" prod=get_prod(desc) if prod: uom_name=prod.uom_id.name lines.append({ 'no': no, 'product_name': '', 'description': desc, 'uom_name': uom_name, 'qty': line.qty or 0, 'price': line.unit_price or 0, 'amount': amt, }) sub_total+=amt no+=1 amount_total=sub_total is_draft=payment.state=='draft' and True or False is_cheque=False pay_type=payment.pay_type or '' 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 "" add=st.default_address_id data={ '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': payment.number or '', 'ref': payment.ref, 'date': payment.date, 'datenow': payment.date or time.strftime("%d/%m/%Y"), 'dateprint': payment.date or time.strftime("%d/%m/%Y %H:%M:%S"), 'cust_name': cust_name, 'cust_addr': cust_addr, 'user_name': user.name or "", 'note': payment.memo 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, 'pay_type': pay_type, 'state': payment.state or "", } if pay_type=='direct': data['pay_type']='Cash' else: data['pay_type']='Credit' if st.logo: data['logo']=get_file_path(st.logo) if cst.signature: data['signature']=get_file_path(cst.signature) return data def get_payment_data(self,ids,context={}): settings=get_model('settings').browse(1) pages=[] for obj in self.browse(ids): if not obj.payments: raise Exception("Receipt not found!") for payment in obj.payments: context['payment_id']=payment.id data=self.get_report_payment_data(context=context) limit_item=9 if data['state']=='draft': limit_item=10 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 new_dialyzer(self,ids,context={}): obj=self.browse(ids)[0] is_wiz=context.get("is_wiz") dlz_vals={} if is_wiz: pop_id=context.get('pop_id') if pop_id: pop=get_model("clinic.hd.case.popup.dlz").browse(pop_id) prod=pop.product_id dlz_vals={ 'product_id': prod.id, 'name': prod.name or "", 'note': pop.note or '', 'use_time': 0, 'max_use_time': pop.max_use_time, 'dialyzer_type': pop.dialyzer_type, 'exp_date': pop.exp_date, 'department_id': obj.department_id.id, 'patient_id': obj.patient_id.id, 'visit_id': obj.visit_id.id, "membrane_type": pop.membrane_type, } else: dlz_vals=get_model("clinic.dialyzer").default_get(context=context) dlz_vals['patient_id']=obj.patient_id.id dlz_vals['company_id']=dlz_vals['company_id'][0] product_name=dlz_vals['product_id'][1] dlz_vals['product_id']=dlz_vals['product_id'][0] dlz_id=get_model('clinic.dialyzer').create(dlz_vals) dialyzer=get_model("clinic.dialyzer").browse(dlz_id) dialyzer.validate() vals={ 'dlz_id': dlz_id, 'dialyzers': [], } vals['dialyzers'].append(('create',{ 'dialyzer_id': dlz_id, 'description': dialyzer.name or product_name, 'use_time': 1, 'max_use_time': dialyzer.max_use_time, 'dialyzer_type': dialyzer.dialyzer_type, 'membrane_type': dialyzer.membrane_type, })) obj.write(vals) if context.get('called'): return obj.id return { 'next': { 'name': 'clinic_hd_case', 'mode': 'form', 'active_id': obj.id, }, 'flash': 'Create new dialyzer successfully', } def to_draft(self,ids,context={}): obj=self.browse(ids)[0] context['state']='draft' obj.undo(context=context) def get_staff(self,ids,context={}): res={} for obj in self.browse(ids): doctor=0 nurse=0 doctor_id=None for ps in obj.staffs: if ps.type=="doctor": if ps.priop=='personal': doctor_id=ps.staff_id.id doctor+= 1 else: nurse+=1 if not doctor_id: for ps in obj.staffs: if ps.type=="doctor": doctor_id=ps.staff_id.id res[obj.id]={ 'total_doctor': doctor, 'total_nurse': nurse, 'doctor_id': doctor_id, } return res def get_staff_line(self,vals,patient_id=None): if not patient_id: return vals # staff patient=get_model("clinic.patient").browse(patient_id) if not vals.get('staffs'): vals['staffs']=[] doctor=patient.doctor_id if doctor: vals['staffs'].append(('create',{ 'staff_id': doctor.id, 'type': 'doctor', 'priop': 'personal', })) # fee st=get_model("clinic.setting").browse(1) if st.auto_gen: return vals if not vals.get('lines'): vals['lines']=[] for st_prod in st.products: ptype=st_prod.patient_type_id prod=st_prod.product_id prod_acc=st.get_product_account(prod.id,ptype.id) # get product account if patient.type_id.id==ptype.id: price=st_prod.price or 0 qty=st_prod.qty or 0 amt=st_prod.amount categ=st_prod.product_categ_id account_id=prod_acc.get("ar_credit_id",None) ar_debit_id=prod_acc.get("ar_debit_id",None) if not amt: amt=qty*price line_vals={ 'product_categ_id': categ.id, 'uom_id': st_prod.uom_id.id, 'description': st_prod.description, 'price': price, 'qty': qty, 'reimbursable': st_prod.reimbursable, 'amount': amt, 'account_id': account_id, 'ar_debit_id': ar_debit_id, } if prod: line_vals.update({ 'product_id': prod.id, }) #if not line_vals['account_id']: #line_vals['account_id']=prod.sale_account_id.id #if not line_vals['account_id']: #raise Exception("Please contact accountant: product [%s] %s"%(prod.code, prod.name)) vals['lines'].append(('create',line_vals)) # XXX need to get default partner=patient.type_id.contact_id if partner: vals['fee_partner_id']=partner.id if not partner: raise Exception("Not found contact %s at menu: Patiens -> Type"%patient.type_id.name) return vals def get_invoice_policy(self,vals={},patient_id=None): if patient_id: patient=get_model("clinic.patient").browse(patient_id) st=get_model("clinic.setting").browse(1) for pl in st.invoice_policies: policy=pl.invoice_policy patient_type=pl.patient_type_id opt=pl.invoice_option if patient.type_id.id==patient_type.id: vals['invoice_policy']=policy vals['invoice_option']=opt break return vals def get_hct(self,vals,patient_id): fmt="%Y-%m-%d" datenow=datetime.strptime(vals['time_start'][0:10],fmt) wd=datenow.weekday() date_week=[datenow.strftime(fmt)] count=1 res='' for i in list(range(0,wd)): if i < wd: res=(datenow-timedelta(days=count)).strftime(fmt) else: res=(datenow+timedelta(days=count)).strftime(fmt) date_week.append(res) count+=1 count=1 for i in list(range(wd,6)): if i < wd: res=(datenow-timedelta(days=count)).strftime(fmt) else: res=(datenow+timedelta(days=count)).strftime(fmt) date_week.append(res) count+=1 print("day week", date_week) # search hct from monday to sunday dom=[] dom.append(['patient_id','=',patient_id]) dom.append(['date', 'in',date_week]) # 1. get date between weekend # 2. if date out of dat gen set 0 else copy previous hct for hdcase in self.search_browse(dom): vals['hct']=hdcase.hct or 0 #break return vals def create(self,vals,**kw): patient_id=vals['patient_id'] if 'vascular_acc' in vals.keys(): patient=get_model("clinic.patient").browse(patient_id) patient.write({ 'vascular_acc': vals['vascular_acc'] }) vals=self.get_staff_line(vals,patient_id) vals=self.get_hct(vals,patient_id) new_id=super().create(vals,**kw) self.function_store([new_id]) return new_id def check_hct(self,obj): if obj.hct_include and obj.state=='in_progress': if not obj.hct: raise Exception("Please define HCT") else: if len(str(obj.hct))<=1: raise Exception("HCT should be more that 9") def write(self,ids,vals,**kw): obj=self.browse(ids)[0] # update vascular access if 'vascular_acc' in vals.keys(): patient_id=obj.patient_id.id if 'patient_id' in vals.keys(): patient_id=vals['patient_id'] patient=get_model("clinic.patient").browse(patient_id) patient.write({ 'vascular_acc': vals['vascular_acc'] }) if 'sickbed_id' in vals.keys(): user_id=get_active_user() set_active_user(1) if vals['sickbed_id']!=obj.sickbed_id.id and obj.state!='draft': if obj.sickbed_id: obj.sickbed_id.write({ 'available': True, }) sb=get_model("clinic.sickbed").browse(vals['sickbed_id']) sb.write({ 'state': 'not_available', }) set_active_user(user_id) if 'lines' in vals.keys(): if not vals['lines']: print("lines is empty will update it now...") patient_id=obj.patient_id.id vals=self.get_staff_line(vals,patient_id) self.function_store(ids) super().write(ids,vals,**kw) obj=self.browse(ids)[0] # prevent duplicate doctor print('obj.state ', obj.state) if obj.state in ('waiting_payment', 'paid'): st={} for lstaff in obj.staffs: staff=lstaff.staff_id if not st.get(staff.id): st[staff.id]=1 else: raise Exception("Douplicate %s"%staff.name) if not st: raise Exception("Please define doctor!") self.check_hct(obj) def approve(self,ids,context={}): obj=self.browse(ids)[0] obj.write({ 'state': 'completed', }) return { 'next': { 'name': 'clinic_hd_case', 'mode': 'form', 'active_id': obj.id, }, 'flash': '%s has been approval'%obj.number, } def onchange_datestart(self,context={}): data=context['data'] data['date']=data['time_start'][0:10] data['time_stop']='%s %s'%(data['date'],data['time_stop'][11:]) return data def onchange_cycle_item(self,context={}): data=context['data'] item=get_model("clinic.cycle.item").browse(data['cycle_item_id']) cycle=item.cycle_id date=item.date time_start='%s %s'%(date,cycle.time_start) time_stop='%s %s'%(date,cycle.time_stop) data['cycle_id']=cycle.id data['date']=date data['time_start']=time_start data['time_stop']=time_stop data['duration']=cycle.duration return data def onchange_weight(self,context={}): data=context['data'] wt_stop=data['wt_stop'] or 0 wt_start=data['wt_start'] or 0 data['ultrafittration']=wt_stop-wt_start return data def new_shop(self,ids,context={}): return { 'next': { 'hd_case_call': True, 'refer_id': ids[0], 'name': 'clinic_popup_shop', } } def drop_dlz(self,ids,context={}): obj=self.browse(ids)[0] for dline in obj.dialyzers: use_time=dline.use_time or 0 dlz=dline.dialyzer_id if dlz.state=='drop': raise Exception("%s is drop!"%dlz.number) dlz.write({ 'use_time': use_time, }) dlz.drop(context=context) return { 'next': { 'name': 'clinic_hd_case', 'mode': 'form', 'active_id': obj.id, }, 'flash': '%s is droped'%dlz.number, } def onchange_staff(self,context={}): data=context['data'] path=context['path'] line=get_data_path(data,path,parent=True) if not line.get('priop'): line['priop']='personal' return data HDCase.register()