clinic/netforce_clinic/models/labor_cost.py

425 lines
15 KiB
Python
Raw Normal View History

2014-12-08 11:35:39 +00:00
from netforce.model import Model, fields, get_model
2014-12-08 14:54:25 +00:00
from netforce.utils import get_data_path
from netforce.access import get_active_company, get_active_user, set_active_user
2014-12-08 11:35:39 +00:00
class LaborCost(Model):
_name="clinic.labor.cost"
_string="Labor Cost"
2014-12-09 04:24:41 +00:00
_multi_company=True
2014-12-08 11:35:39 +00:00
_name_field="cycle_item_id"
_key=['cycle_item_id']
2015-01-22 14:40:10 +00:00
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
2014-12-08 11:35:39 +00:00
def _get_all(self,ids,context={}):
res={}
for obj in self.browse(ids):
hd_cases=obj.cycle_item_id.hd_cases or []
total_case=len(hd_cases)
total_a,total_b=0,0
total=0.0
2014-12-08 14:54:25 +00:00
for fline in obj.formulars:
total+=fline.amount or 0
total_a+=fline.var_a or 0
total_b+=fline.var_b or 0
2014-12-08 11:35:39 +00:00
var_ptx=total_case*(obj.var_k or 0)
2015-02-12 08:52:35 +00:00
var_fml1='PTxK=%sx%s'%(total_a,total_b)
2014-12-08 11:35:39 +00:00
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))
2014-12-08 14:54:25 +00:00
2014-12-09 07:29:30 +00:00
total_ncost=0.0
for line in obj.nurse_lines:
total_ncost+=line.amount or 0.0
total_dcost=0.0
for line in obj.doctor_lines:
total_dcost+=line.amount or 0.0
total_stcost=0.0
for line in obj.staff_lines:
total_stcost+=line.amount or 0.0
2015-01-19 15:40:24 +00:00
#XXX
total=total_ncost+total_dcost+total_stcost
2014-12-08 11:35:39 +00:00
res[obj.id]={
'var_pt': total_case,
'var_ptx': total_case*(obj.var_k or 0),
'var_fml1': '%s'%(var_fml1),
2015-02-12 08:52:35 +00:00
'var_fml2': '%s=%sx%s'%(var_ptx,total_a,total_b),
2014-12-08 11:35:39 +00:00
'var_fml3': '(%s%s)/%s'%(var_ptx,total_bstr,total_a),
'var_x': round(var_x,2),
'total': total,
2014-12-09 07:29:30 +00:00
'total_ncost': total_ncost,
'total_dcost': total_dcost,
'total_stcost': total_stcost,
2014-12-08 11:35:39 +00:00
}
2014-12-08 14:54:25 +00:00
2014-12-08 11:35:39 +00:00
return res
_fields={
2015-01-19 13:34:43 +00:00
"cycle_item_id": fields.Many2One("clinic.cycle.item","Cycle Item",required=True,search=True),
2014-12-08 11:35:39 +00:00
'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),
2015-01-19 15:40:24 +00:00
'total': fields.Float("Total (Baht)",function="_get_all",function_multi=True),
'total_ncost': fields.Float("Nurse Cost",function="_get_all",function_multi=True),
'total_dcost': fields.Float("Doctor Cost",function="_get_all",function_multi=True),
'total_stcost': fields.Float("Staff Cost",function="_get_all",function_multi=True),
2014-12-08 11:35:39 +00:00
'manual': fields.Boolean("Manual"),
"formulars": fields.One2Many("clinic.labor.cost.formular", "labor_cost_id", "Formulars"),
2014-12-09 07:29:30 +00:00
"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']]),
2014-12-09 04:24:41 +00:00
'company_id': fields.Many2One("company","Company"),
2015-01-22 14:40:10 +00:00
'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),
2014-12-08 11:35:39 +00:00
}
2014-12-09 04:24:41 +00:00
_defaults={
'company_id': lambda *a: get_active_company(),
}
2014-12-08 11:35:39 +00:00
def compute(self,ids,context={}):
obj=self.browse(ids)[0]
user_id=get_active_user()
set_active_user(1)
2014-12-08 11:35:39 +00:00
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
2015-01-18 10:31:54 +00:00
for line in item.lines:
level=line.level_id
nurse=line.nurse_id
2014-12-08 11:35:39 +00:00
if not level:
2015-01-18 10:31:54 +00:00
raise Exception("Please specify level for %s"%nurse.name)
2014-12-08 11:35:39 +00:00
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(item.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 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,
})
2014-12-08 14:54:25 +00:00
levels={}
2014-12-08 11:35:39 +00:00
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,
})
2014-12-08 14:54:25 +00:00
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,
}
#TODO UPDATE COST : like cycle daily
item=obj.cycle_item_id
lines=[]
# cost's nurses
2015-01-18 10:31:54 +00:00
for line in item.lines:
nurse=line.nurse_id
level=line.level_id
2014-12-08 14:54:25 +00:00
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,
2015-02-08 08:48:08 +00:00
'categ_id': nurse.categ_id.id,
2014-12-08 14:54:25 +00:00
'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 item.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,
2014-12-09 07:29:30 +00:00
'type': staff.type,
2015-02-08 08:48:08 +00:00
'categ_id': staff.categ_id.id,
2014-12-08 14:54:25 +00:00
'level_id': staff.level_id.id,
'qty': 0,
}
2014-12-09 07:29:30 +00:00
if staff.type!='doctor':
base=0
staff_total[staff.id]['description']=hd_case.number
2014-12-08 14:54:25 +00:00
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']
2015-02-08 08:48:08 +00:00
categ_id=value['categ_id']
2014-12-08 14:54:25 +00:00
lines.append(('create',{
'cycle_id': item.cycle_id.id,
'staff_id': doctor_id,
'level_id': level_id,
2015-02-08 08:48:08 +00:00
'categ_id': categ_id,
2014-12-08 14:54:25 +00:00
'rate': base,
'qty': qty,
'type': type,
2014-12-09 07:29:30 +00:00
'description': value.get('description',"")
2014-12-08 14:54:25 +00:00
}))
# clear cost line
2014-12-09 07:29:30 +00:00
for line in obj.nurse_lines:
line.delete()
for line in obj.doctor_lines:
2014-12-08 14:54:25 +00:00
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
2015-02-08 08:48:08 +00:00
categ_id=vals['categ_id']
2014-12-08 14:54:25 +00:00
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,
2014-12-09 07:29:30 +00:00
'type': vals['type'],
'description': vals.get("description",""),
2015-02-08 08:48:08 +00:00
'categ_id': categ_id,
2014-12-08 14:54:25 +00:00
}
continue
glines[key]['amount']+=amount
glines[key]['qty']+=qty
2014-12-09 07:29:30 +00:00
nurse_lines=[]
doctor_lines=[]
2014-12-08 14:54:25 +00:00
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)
2014-12-09 07:29:30 +00:00
st_type=vals['type']
if st_type=='doctor':
doctor_lines.append(('create',line))
else:
nurse_lines.append(('create',line))
2014-12-08 14:54:25 +00:00
obj.write({
2014-12-09 07:29:30 +00:00
'doctor_lines': doctor_lines,
'nurse_lines': nurse_lines,
2014-12-08 14:54:25 +00:00
})
set_active_user(user_id)
2014-12-08 11:35:39 +00:00
return {
'next': {
'name': 'clinic_labor_cost',
'mode': 'form',
'active_id': obj.id,
},
'flash':'Compute successfully',
}
2014-12-08 14:54:25 +00:00
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']
2015-01-30 11:15:13 +00:00
for line in data['doctor_lines']:
2014-12-08 14:54:25 +00:00
qty=line['qty'] or 0
rate=line['rate'] or 0.0
amt=qty*rate
total+=amt
2015-01-30 11:15:13 +00:00
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
2014-12-08 14:54:25 +00:00
return data
2015-01-22 14:40:10 +00:00
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)
2014-12-08 11:35:39 +00:00
LaborCost.register()