from netforce.model import Model, fields, get_model from netforce.utils import get_data_path from netforce.access import get_active_company, get_active_user, set_active_user class LaborCost(Model): _name="clinic.labor.cost" _string="Labor Cost" _multi_company=True _name_field="cycle_item_id" _key=['cycle_item_id'] def _get_store(self,ids,context={}): res={} for obj in self.browse(ids): item=obj.cycle_item_id res[obj.id]={ 'date': item.date, 'cycle_id': item.cycle_id.id, 'department_id': item.department_id.id, 'branch_id': item.branch_id.id, } return res def _get_all(self,ids,context={}): res={} for obj in self.browse(ids): hd_cases=[hdcase for hdcase in obj.cycle_item_id.hd_cases if hdcase.state in ('waiting_payment','paid')] or [] total_case=len(hd_cases) total_a,total_b=0,0 total=0.0 for fline in obj.formulars: total+=fline.amount or 0 total_a+=fline.var_a or 0 total_b+=fline.var_b or 0 var_ptx=total_case*(obj.var_k or 0) var_fml1='PTxK=%sx%s'%(total_a,total_b) total_bstr=total_b < 0 and "+%s"%(abs(total_b)) or "-%s"%total_b var_x=0.0 if total_a: var_x=eval('(%s%s)/%s'%(var_ptx,total_bstr,total_a)) total_nqty=0 total_formular=0 for line in obj.formulars: total_nqty+=line.qty or 0 total_formular+=line.amount or 0 total_ncost=0.0 for line in obj.nurse_lines: #total_ncost+=line.amount or 0.0 total_ncost+=line.rate or 0.0 total_dcost=0.0 total_dqty=0.0 for line in obj.doctor_lines: total_dcost+=line.amount or 0.0 total_dqty+=line.qty or 0.0 total_stcost=0.0 for line in obj.staff_lines: total_stcost+=line.amount or 0.0 total_ncost=round(total_ncost,0) total_dcost=round(total_dcost,0) total_stcost=round(total_stcost,0) total_formular=round(total_formular,0) total=total_ncost+total_dcost+total_stcost res[obj.id]={ 'var_pt': total_case, 'var_ptx': total_case*(obj.var_k or 0), 'var_fml1': '%s'%(var_fml1), 'var_fml2': '%s=%sx%s'%(var_ptx,total_a,total_b), 'var_fml3': '(%s%s)/%s'%(var_ptx,total_bstr,total_a), 'var_x': round(var_x,2), 'total': total, 'total_formular': total_formular, 'total_ncost': total_ncost, 'total_nqty': total_nqty, 'total_dcost': total_dcost, 'total_dqty': total_dqty, 'total_stcost': total_stcost, } return res _fields={ "cycle_item_id": fields.Many2One("clinic.cycle.item","Cycle Item",required=True), 'var_k': fields.Float("K"), 'var_pt': fields.Integer("PT", function="_get_all",function_multi=True), 'var_ptx': fields.Char("PT x K:", function="_get_all",function_multi=True), 'var_fml1': fields.Char("Step 1:",function="_get_all",function_multi=True), 'var_fml2': fields.Char("Step 2:",function="_get_all",function_multi=True), 'var_fml3': fields.Char("X:",function="_get_all",function_multi=True), 'var_x': fields.Char("X:",function="_get_all",function_multi=True), 'total': fields.Float("Total (Baht)",function="_get_all",function_multi=True), 'total_formular': fields.Float("Total",function="_get_all",function_multi=True), 'total_ncost': fields.Float("Nurse Cost",function="_get_all",function_multi=True), 'total_nqty': fields.Float("Nurse Cost",function="_get_all",function_multi=True), 'total_dcost': fields.Float("Doctor Cost",function="_get_all",function_multi=True), 'total_dqty': fields.Float("Doctor Cost",function="_get_all",function_multi=True), 'total_stcost': fields.Float("Staff Cost",function="_get_all",function_multi=True), 'manual': fields.Boolean("Manual"), "formulars": fields.One2Many("clinic.labor.cost.formular", "labor_cost_id", "Formulars"), "nurse_lines": fields.One2Many("clinic.labor.cost.line", "labor_cost_id", "Nurse Lines",domain=[['type','=','nurse']]), "doctor_lines": fields.One2Many("clinic.labor.cost.line", "labor_cost_id", "Doctor Lines",domain=[['type','=','doctor']]), "staff_lines": fields.One2Many("clinic.labor.cost.line", "labor_cost_id", "staff Lines",domain=[['type','=','staff']]), 'company_id': fields.Many2One("company","Company"), 'date': fields.Date('Date',function="_get_store",function_multi=True,store=True,search=True), 'cycle_id': fields.Many2One('clinic.cycle',"Cycle", function="_get_store",function_multi=True,store=True,search=True), 'department_id': fields.Many2One('clinic.department',"Department", function="_get_store",function_multi=True,store=True,search=True), 'branch_id': fields.Many2One('clinic.branch',"Branch", function="_get_store",function_multi=True,store=True,search=True), 'cost_per_case': fields.Float("Cost Per Case"), # for doctor } def _get_cost_per_case(self,context={}): st=get_model("clinic.setting").browse(1) return st.cost_per_case or 0 _defaults={ 'company_id': lambda *a: get_active_company(), 'cost_per_case': _get_cost_per_case, } def compute(self,ids,context={}): obj=self.browse(ids)[0] user_id=get_active_user() set_active_user(1) if not obj.manual: for fline in obj.formulars: fline.delete() levels={} for level_id in get_model('clinic.staff.level').search([['type','=','nurse']]): vals={ level_id: { 'total': 0, } } levels.update(vals) item=obj.cycle_item_id for line in item.lines: nurse=line.nurse_id level=line.level_id or nurse.level_id if not level: raise Exception("Please specify level for %s"%nurse.name) levels[level.id]['total']+=1 st_levels={} st=get_model("clinic.setting").browse(1) for line in st.levels: level=line.level_id st_levels[level.id]={ 'var_a': line.var_a or 0, 'var_b': line.var_b or 0, 'op': line.op or "", 'formular': line.formular or "", } formulars=[] total_a,total_b=0,0 for level_id, value in levels.items(): qty=value['total'] st_level=st_levels.get(level_id,None) a,b=0,0 state="fail" if st_level: state="success" var_a=float(st_level['var_a'] or "0") var_b=float(st_level['var_b'] or "0") fml_org=st_level['formular'] a=qty*var_a a_str='%sX'%(a) total_a+=a op=st_level['op'] sign=op=='-' and -1 or 1 op_str=sign==1 and op or "" b=(qty*var_b)*sign b_str=(str(b) if b else "") total_b+=b else: # XXX prevent to show all level if not configuration from setting continue fml=''.join([a_str, op_str, b_str]) formulars.append(('create',{ 'level_id': level_id, 'var_a': a, 'var_b': b, 'qty': qty, 'formular_org': fml_org, 'formular': fml if qty else "0", 'state': state, })) if not obj.manual: var_pt=len([hdcase for hdcase in item.hd_cases if hdcase.state in ("waiting_payment", "paid")]) var_ptx=var_pt*(obj.var_k or 0) total_bstr=total_b < 0 and "+%s"%(abs(total_b)) or "-%s"%total_b var_x=0 if total_a: exp='(%s%s)/%s'%(var_ptx,total_bstr,total_a) var_x=eval(exp) for fline in formulars: vals=fline[1] fml=vals['formular'].replace("X","*%s") vals['amount']=0 if vals['var_a'] or vals['var_b']: vals['amount']=eval(fml%var_x) else: # update qty (a) formulars=[] for fline in obj.formulars: level=fline.level_id qty=fline.qty or 0 st_level=st_levels.get(level.id,None) a,b=0,0 state="fail" if st_level: state="success" var_a=float(st_level['var_a'] or "0") var_b=float(st_level['var_b'] or "0") fml_org=st_level['formular'] a=qty*var_a a_str='%sX'%(a) op=st_level['op'] sign=op=='-' and -1 or 1 op_str=sign==1 and op or "" b=(qty*var_b)*sign b_str=(str(b) if b else "") else: print("not found in setting ", level.id) fml=''.join([a_str, op_str, b_str]) formulars.append(('write',[fline.id],{ 'level_id': level.id, 'var_a': a, 'var_b': b, 'qty': qty, 'formular': fml if qty else "0", 'formular_org': fml_org, 'state': state, })) obj.write({ 'formulars': formulars, }) levels={} if obj.manual: for fline in obj.formulars: fml=(fline.formular or "").replace("X","*%s") if fline.var_a or fline.var_b: amt=eval(fml%obj.var_x) else: amt=0 fline.write({ 'amount': amt, }) level=fline.level_id levels[level.id]={ 'amount': amt or 0.0, 'qty': fline.qty or 0, 'level_id': level.id, } else: for fline in formulars: vals=fline[1] level_id=vals['level_id'] levels[level_id]={ 'amount': vals['amount'] or 0.0, 'qty': vals['qty'] or 0, 'level_id': level_id, } item=obj.cycle_item_id lines=[] # cost's nurses for line in item.lines: nurse=line.nurse_id level=line.level_id or nurse.level_id vals=levels.get(level.id) rate,amt,qty=0.0,0.0,0 level_id=level.id if vals: level_id=vals['level_id'] amt=vals['amount'] qty=vals['qty'] if qty: rate=amt/qty lines.append(('create',{ 'cycle_id': item.cycle_id.id, 'staff_id': nurse.id, 'level_id': level_id, 'categ_id': nurse.categ_id.id, 'rate': rate, 'type': 'nurse', 'qty': 1, })) # cost's doctor st=get_model('clinic.setting').browse(1) cost_per_case=obj.cost_per_case or st.cost_per_case or 0 staff_total={} dwalkin=None for staff in get_model("clinic.staff").search_browse([['number','=','walkin'],['type','=','doctor']]): dwalkin=staff for hd_case in item.hd_cases: if hd_case.state not in ('waiting_payment','paid'): continue staffs=hd_case.staffs doctor_id=hd_case.doctor_id if not doctor_id and dwalkin: if not staff_total.get(dwalkin.id): staff_total[dwalkin.id]={ 'base': 0, 'type': dwalkin.type, 'categ_id': dwalkin.categ_id.id, 'level_id': dwalkin.level_id.id, 'qty': 0, } base=cost_per_case staff_total[dwalkin.id]['base']=base staff_total[dwalkin.id]['qty']+=1 else: for ps in staffs: staff=ps.staff_id or dwalkin if not staff: continue base=staff.base if not base: base=cost_per_case if not staff_total.get(staff.id): staff_total[staff.id]={ 'base': 0, 'type': staff.type, 'categ_id': staff.categ_id.id, 'level_id': staff.level_id.id, 'qty': 0, } if staff.type!='doctor': base=0 staff_total[staff.id]['description']=hd_case.number staff_total[staff.id]['base']=base staff_total[staff.id]['qty']+=1 for doctor_id, value in staff_total.items(): base=value['base'] type=value['type'] qty=value['qty'] level_id=value['level_id'] categ_id=value['categ_id'] lines.append(('create',{ 'cycle_id': item.cycle_id.id, 'staff_id': doctor_id, 'level_id': level_id, 'categ_id': categ_id, 'rate': base, 'qty': qty, 'type': type, 'description': value.get('description',"") })) # clear cost line for line in obj.nurse_lines: line.delete() for line in obj.doctor_lines: line.delete() # group staff and cycle date glines={} for line in lines: mode,vals=line cycle_id=vals['cycle_id'] staff_id=vals['staff_id'] rate=vals['rate'] or 0 qty=vals['qty'] or 0 categ_id=vals['categ_id'] amount=qty*rate key=(cycle_id,staff_id) if not key in glines.keys(): glines[key]={ 'amount': amount, 'level_id': vals['level_id'], 'rate': rate, 'qty': qty, 'type': vals['type'], 'description': vals.get("description",""), 'categ_id': categ_id, } continue glines[key]['amount']+=amount glines[key]['qty']+=qty nurse_lines=[] doctor_lines=[] for key,vals in glines.items(): cycle_id,staff_id=key line={ 'cycle_id': cycle_id, 'staff_id': staff_id, 'date': item.date, } line.update(vals) st_type=vals['type'] if st_type=='doctor': doctor_lines.append(('create',line)) else: nurse_lines.append(('create',line)) obj.write({ 'doctor_lines': doctor_lines, 'nurse_lines': nurse_lines, }) set_active_user(user_id) return { 'next': { 'name': 'clinic_labor_cost', 'mode': 'form', 'active_id': obj.id, }, 'flash':'Compute successfully', } def onchange_cost_line(self,context={}): data=context['data'] path=context['path'] line=get_data_path(data,path,parent=True) qty=line.get("qty",0) rate=line.get("rate",0.0) amt=qty*rate line['amount']=amt data=self.update_amt(context) return data def update_amt(self,context): total=0.0 data=context['data'] for line in data['doctor_lines']: qty=line['qty'] or 0 rate=line['rate'] or 0.0 amt=qty*rate total+=amt data['total_dcost']=total for line in data['nurse_lines']: #qty=line['qty'] or 0 #rate=line['rate'] or 0.0 #amt=qty*rate amt=line['amount'] or 0.0 total+=amt data['total_ncost']=total data['total']=total return data def create(self,vals,**kw): id=super().create(vals,**kw) self.function_store([id]) return id def write(self,ids,vals,**kw): super().write(ids,vals,**kw) self.function_store(ids) LaborCost.register()