import re import time from netforce.model import Model, fields, get_model from netforce.access import get_active_company 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): name="%s-%s"%(obj.cycle_id.name,obj.date) hd_total=len([hd_case for hd_case in obj.hd_cases if hd_case.state=='completed']) # XXX pt=(hd_total or 0.0) k=(obj.var_k or 0.0) pt_k=pt*k x=(pt_k + 1275)/13.5 total=0.0 for line in obj.nurse_lines: total+=(line.amount or 0.0) total2=0.0 for line in obj.doctor_lines: total2+=(line.amount or 0.0) res[obj.id]={ 'name': name, 'var_x': x, 'total_pt': hd_total, 'total_amount': hd_total*k, 'total': total, 'total2': total2, 'total_balance': (hd_total*k)-total, } return res _fields={ 'name': fields.Char("Name", function="_get_all",function_multi=True), # need to field related in journal 'company_id': fields.Many2One("company", "Company"), 'cycle_id': fields.Many2One("clinic.cycle", "Cycle",search=True), 'date': fields.Date("Date",search=True), 'var_k': fields.Float("K"), 'var_x': fields.Float("X", function="_get_all",function_multi=True), 'total_pt': fields.Float("PT", function="_get_all",function_multi=True), 'total_amount': fields.Float("PT*K", function="_get_all",function_multi=True), 'total_balance': fields.Float("Total Balance", function="_get_all",function_multi=True), 'total': fields.Float("Total", function="_get_all",function_multi=True), 'total2': fields.Float("Total", function="_get_all",function_multi=True), "state": fields.Selection([("draft","Draft"),("done","Done")],"Status",required=True), 'hd_cases': fields.One2Many("clinic.hd.case","cycle_item_id", "HD Cases"), 'nurse_lines': fields.One2Many('clinic.cycle.item.line', 'cycle_item_id', 'Nurse Lines',domain=[['type','=','nurse']]), 'doctor_lines': fields.One2Many('clinic.cycle.item.line', 'cycle_item_id', 'Doctor Lines',domain=[['type','=','doctor']]), 'var_doctor': fields.Float("K Doctor"), } _defaults={ 'state': 'draft', 'company_id': lambda *a: get_active_company(), 'date': lambda *a: time.strftime("%Y-%m-%d"), 'var_k': 450, 'var_doctor': 450, } def compute(self,ids,context={}): # XXX should compute after hd case done for obj in self.browse(ids): vals={ 'nurse_lines': [], 'doctor_lines': [], } nurse_dict={} doctor_dict={} for hd_case in obj.hd_cases: if hd_case.state=='completed': nurse_code=hd_case.nurse_id.categ_id.code or "" if not nurse_dict.get(nurse_code): nurse_dict[nurse_code]=0 nurse_dict[nurse_code]+=1 doctor_categ=hd_case.doctor_id.categ_id or "" if not doctor_categ: continue doctor_name=hd_case.doctor_id.name or "" key=(doctor_categ,doctor_name) if not doctor_dict.get(key): doctor_dict[key]=0 doctor_dict[key]+=1 for line in obj.nurse_lines: line.delete() for line in obj.doctor_lines: line.delete() for k, v in doctor_dict.items(): categ=k[0] name=k[1] qty=v vals['doctor_lines'].append(('create',{ 'personal_categ': categ.id, 'description': name, 'type': 'doctor', 'formular': categ.formular, 'qty': qty, 'rate': obj.var_doctor or 0.0, 'amount': qty*obj.var_doctor, })) print(nurse_dict) for personal_categ in get_model("clinic.personal.categ").search_browse([]): if personal_categ.type=='nurse': formular=personal_categ.formular or "" rate=0 try: var_x="%s"%(round(obj.var_x,2)) formulared=formular.replace("x",var_x) rate=eval(formulared) except: rate=0 qty=nurse_dict.get(personal_categ.code,0) vals['nurse_lines'].append(('create',{ 'personal_categ': personal_categ.id, 'type': 'nurse', 'formular': formular, 'qty': qty, 'rate': rate, 'amount': qty*rate, })) print("qty * rate ", qty, ' ', rate) # x=(pt*k+n2*100+n3*250-n4*25-n5*25+n6*75)/(n1+n2+n3+0.5*(n4+n5+n6)) obj.write(vals) return { 'next': { 'name': 'clinic_cycle_item', 'mode': 'form', 'active_id': obj.id, }, 'flash': 'Compute OK', } def reduce_formular(self,line_strs=None): def get_lines(line_str): return line_strs.replace("\n","").replace(" ","").split(",") line2=[] m='/(\d+)' for line in get_lines(line_strs): res=re.findall(m,line) if res: x1=res[0] line=line.replace("/%s"%x1,"") line=line.replace("(","") line=line.replace(")","") p1='x' res=re.findall(p1,line) if res: line=line.replace("x",'x/%s'%x1) p2='[-,+,*]\d+' res=re.findall(p2,line) if res: for r in res: x2=float(r)/float(x1) x2=x2> 0 and '+%s'%x2 or x2 line=line.replace(r,str(x2)) if line: line2.append(line) return line2 def match_value(self,items): for qty, f in items: p1='x' res=re.findall(p1,f) if res: f=f.replace("x",'%sx'%qty) p2='([-,+,*])(\d+)' res=re.findall(p2,f) #XXX if res: #print('res ', res) sym=res[0][0] v=res[0][1] sym_v=''.join([sym,str(int(v)*int(qty))]) old_v=''.join([sym,str(int(v))]) #print('-'*50) #print(f) #print(old_v, " ", sym_v) f=f.replace('%s'%str(old_v),'%s'%str(sym_v)) #print(f) #print('-'*50) print(f) def onchange_line(self,context={}): data=context['data'] path=context["path"] line=get_data_path(data,path,parent=True) #pt=data['pt'] or 0.0 #k=data['var_k'] or 0.0 #x=(pt*k+n2*100+n3*250-n4*25-n5*25+n6*75)/(n1+n2+n3+0.5*(n4+n5+n6)) #qty=line.get("qty") #rate=line.get("rate") total=0.0 items=[] values=[] for line in data['nurse_lines']: formular=line['formular'] values.append(line['qty']) items.append(formular) qty=line['qty'] rate=line['rate'] line['amount']=qty*rate total+=line['amount'] formulars=self.reduce_formular(','.join(items)) res=self.match_value(list(zip(values,formulars))) data['total']=total data['total_amount']=data['total_pt']*(data['var_k'] or 0) data['total_balance']=data['total_amount']-data['total'] return data def create_payment(self,ids,context={}): obj=self.browse(ids)[0] settings=get_model("settings").browse(1) account_id=settings.ap_nurse_id.id if not account_id: raise Exception("No Account payment for Nurse") vals={ "company_id": obj.company_id.id, "type": "out", "pay_type": "direct", "date": obj.date or time.strftime("%Y-%m-%d"), "account_id": account_id, 'related_id': "clinic.cycle.item,%s"%obj.id, 'direct_lines': [], } for line in obj.nurse_lines: if not line.amount: continue vals['direct_lines'].append(('create',{ 'description': 'Payment; %s'%line.personal_categ.name, 'account_id': account_id, 'qty': 1, 'unit_price': line.amount, 'amount': line.amount, })) account_id=settings.ap_doctor_id.id if not account_id: raise Exception("No Account payment for Doctor") for line in obj.doctor_lines: if not line.amount: continue vals['direct_lines'].append(('create',{ 'description': 'Payment; %s'%line.description, 'account_id': account_id, 'qty': line.qty, 'unit_price': line.amount, 'amount': line.amount, })) payment_id=get_model("account.payment").create(vals,context={"type":"out"}) #get_model("account.payment").browse(payment_id).post() obj.write({ 'state': 'done', }) if context.get('called'): return obj.id return { 'next': { 'name': 'payment', 'mode': 'form', 'active_id': payment_id, }, 'flash': 'Create journal successfully', } def to_draft(self,ids,context={}): obj=self.browse(ids)[0] related_id="clinic.cycle.item,%s"%obj.id for payment in get_model("account.payment").search_browse([['related_id','=',related_id]]): payment.to_draft() payment.delete() obj.write({ 'state': 'draft', }) if context.get('called'): return obj.id return { 'next': { 'name': 'clinic_cycle_item', 'mode': 'form', 'active_id': obj.id, }, 'flash': 'Cycle item is set to draft', } def to_drafts(self,ids,context={}): for obj in self.browse(ids): context['called']=True obj.to_draft(context=context) return { 'next': { 'name': 'clinic_cycle_item', 'mode': 'list', }, 'flash': 'Cycle item is set to draft', } def view_payment(self,ids,context={}): obj=self.browse(ids)[0] related_id="clinic.cycle.item,%s"%obj.id payment_ids=get_model("account.payment").search([['related_id','=',related_id]]) if payment_ids: payment_id=payment_ids[0] return { 'next': { 'name': 'payment', 'mode': 'form', 'active_id': payment_id, }, } def pay(self,ids,context={}): context['called']=True for obj in self.browse(ids): obj.create_payment(context) return { 'next': { 'name': 'clinic_cycle_item', 'mode': 'list', }, 'flash': 'Paid', } CycleItem.register()