import time from netforce.model import Model, fields, get_model from netforce.access import get_active_company, get_active_user from netforce.utils import get_data_path class CycleItem(Model): _name="clinic.cycle.item" _string="Cycle Item" _name_field="name" def _get_all(self,ids,context={}): res={} for obj in self.browse(ids): cycle=obj.cycle_id cycle_name='' if cycle: cycle_name=cycle.name name="%s-%s"%(cycle_name,obj.date) total_case=len(obj.hd_cases) total_a,total_b=0,0 total=0.0 for line in obj.lines: total+=line.amount or 0 total_a+=line.var_a total_b+=line.var_b 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)) res[obj.id]={ 'name': name, '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, } return res _fields={ 'name': fields.Char("Name", function="_get_all",function_multi=True), 'date': fields.Date("Date",search=True), 'cycle_id': fields.Many2One("clinic.cycle", "Cycle",search=True), 'cycle_daily_id': fields.Many2One("clinic.cycle.daily", "Cycle Daily",search=True), 'lines': fields.One2Many("clinic.cycle.item.line","item_id", "Lines"), 'visits': fields.One2Many("clinic.visit","cycle_item_id", "Visits"), 'hd_cases': fields.One2Many("clinic.hd.case","cycle_item_id", "HD Cases"), 'nurses': fields.One2Many("clinic.cycle.item.nurse",'cycle_item_id','Nurses'), 'sequence': fields.Char("Sequence"), # for sort item 'company_id': fields.Many2One("company", "Company"), "state": fields.Selection([("draft","Draft"),("done","Done")],"Status",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",function="_get_all",function_multi=True), 'manual': fields.Boolean("Manual"), 'user_id': fields.Many2One("base.user","User"), } def _get_vark(self,context={}): st=get_model("clinic.setting").browse(1) return st.var_k or 0 _defaults={ 'state': 'draft', 'company_id': lambda *a: get_active_company(), 'date': lambda *a: time.strftime("%Y-%m-%d"), 'user_id': lambda *a: get_active_user(), 'var_k': _get_vark, } _order="date desc" _sql_constraints=[ ("cycle_item_uniq","unique (cycle_id,date,company_id)","Cycle item should be unique"), ] def get_cycle_daily(self,date): dom=[] print("get ", date) dom.append(['date','=',date]) cd_ids=get_model('clinic.cycle.daily').search(dom) cd_id=None if cd_ids: cd_id=cd_ids[0] else: cd_id=get_model('clinic.cycle.daily').create({ 'date':date, 'name':date, }) return cd_id def create(self, vals,**kw): date=vals['date'] cycle_id=vals['cycle_id'] vals['cycle_daily_id']=self.get_cycle_daily(date) cycle=get_model("clinic.cycle").browse(cycle_id) vals['sequence']='%s-%s'%(date,cycle.sequence) #date-sequence obj_id=super().create(vals,**kw) return obj_id def write(self,ids,vals,**kw): obj=self.browse(ids)[0] cycle=obj.cycle_id date=vals.get('date') and vals.get('date') or obj.date vals['cycle_daily_id']=self.get_cycle_daily(date) vals['sequence']='%s-%s'%(obj.date,cycle.sequence) #date-sequence super().write(ids,vals,**kw) def validate(self,ids,context={}): obj=self.browse(ids)[0] levels={} for line in obj.lines: level=line.level_id levels[level.id]={ 'amount': line.amount or 0, 'qty': line.qty, 'level_id': level.id, } lines=[] # cost's nurses for nr in obj.nurses: nurse=nr.nurse_id level=nr.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': obj.cycle_id.id, 'staff_id': nurse.id, 'level_id': level_id, 'rate': rate, 'type': 'nurse', 'qty': 1, })) # cost's doctor st=get_model('clinic.setting').browse(1) cost_per_case=st.cost_per_case or 0 staff_total={} for hd_case in obj.hd_cases: staffs=hd_case.staffs for ps in staffs: staff=ps.staff_id 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, 'level_id': staff.level_id.id, 'type': ps.type, 'qty': 0, } 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'] lines.append(('create',{ 'cycle_id': obj.cycle_id.id, 'staff_id': doctor_id, 'level_id': level_id, 'rate': base, 'qty': qty, 'type': type, })) cycle_daily=obj.cycle_daily_id # clear cost line for line in cycle_daily.lines: cycle=line.cycle_id if obj.cycle_id.id==cycle.id: # only own cycle 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'] #amount=vals['amount'] or 0 rate=vals['rate'] or 0 qty=vals['qty'] or 0 amount=qty*rate key=(cycle_id,staff_id) if not key in glines.keys(): glines[key]={ 'amount': amount, 'type': vals['type'], 'level_id': vals['level_id'], 'rate': rate, 'qty': qty, } continue glines[key]['amount']+=amount glines[key]['qty']+=qty lines=[] for key,vals in glines.items(): cycle_id,staff_id=key line={ 'cycle_id': cycle_id, 'staff_id': staff_id, 'date': obj.date, } line.update(vals) lines.append(('create',line)) # call from outside if context.get('called'): return lines cycle_daily.write({ 'lines': lines, }) obj.write({ 'state': 'done', }) return { 'next': { 'name': 'clinic_cycle_daily', 'mode': 'form', 'active_id': cycle_daily.id, }, 'flash': 'Cycle Item has been validated, please see the detail of cost below.', } def to_draft(self,ids,context={}): obj=self.browse(ids)[0] obj.write({ 'state': 'draft', }) def compute(self,ids,context={}): obj=self.browse(ids)[0] if not obj.manual: for line in obj.lines: line.delete() levels={} for level_id in get_model('clinic.staff.level').search([['type','=','nurse']]): vals={ level_id: { 'total': 0, } } levels.update(vals) for ns in obj.nurses: level=ns.level_id if not level: raise Exception("Please specify level for %s"%ns.nurse_id.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 "", } lines=[] 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]) lines.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(obj.hd_cases) 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: var_x=eval('(%s%s)/%s'%(var_ptx,total_bstr,total_a)) for line in lines: vals=line[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) lines=[] for line in obj.lines: level=line.level_id qty=line.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]) lines.append(('write',[line.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({ 'lines': lines, }) if obj.manual: for line in obj.lines: fml=(line.formular or "").replace("X","*%s") if line.var_a or line.var_b: amt=eval(fml%obj.var_x) else: amt=0 line.write({ 'amount': amt, }) return { 'next': { 'name': 'clinic_cycle_item', 'mode': 'form', 'active_id': obj.id, }, 'flash':'Compute successfully', } def onchange_nurse(self,context={}): data=context["data"] path=context["path"] line=get_data_path(data,path,parent=True) nurse_id=line['nurse_id'] nurse=get_model('clinic.staff').browse(nurse_id) line['level_id']=nurse.level_id.id return data def view_schedule(self,ids,context={}): obj=self.browse(ids)[0] date=obj.date schd_ids=get_model('clinic.schedule').search([['date','=',date]]) schedule_id=None if schd_ids: schedule_id=schd_ids[0] return { 'next': { 'name': 'clinic_schedule', 'mode': 'form', 'active_id': schedule_id, } } def view_cycle_daily(self,ids,context={}): obj=self.browse(ids)[0] if not obj.cycle_daily_id: raise Exception("Please validate cycle item") return { 'next': { 'name': 'clinic_cycle_daily', 'mode': 'form', 'active_id': obj.cycle_daily_id.id, } } def load_nurse_from_schedule(self,ids,context={}): obj=self.browse(ids)[0] #TODO check cycle number & date from schedule schedules=get_model("clinic.schedule").search_browse([['date','=',obj.date]]) nurses=[] for schedule in schedules: for line in schedule.lines: cycle=line.cycle_id if obj.cycle_id.id==cycle.id: nurse=line.nurse_id level=line.level_id nurses.append(('create',{ 'nurse_id': nurse.id, 'level_id': level.id, })) for nurse in obj.nurses: nurse.delete() obj.write({ 'nurses': nurses, }) return { 'next': { 'name': 'clinic_cycle_item', 'mode': 'form', 'active_id': obj.id, }, 'flash': 'Load nurse from schedule to cycle item successfully', } CycleItem.register()