import time from netforce.model import Model, fields, get_model from netforce.access import get_active_user, set_active_user, get_active_company from netforce.utils import get_data_path, get_file_path from . import utils class Shop(Model): _name="clinic.shop" _string="Shop" _name_field="number" _multi_company=True def _get_all(self,ids,context={}): res={} st=get_model("clinic.setting").browse(1) shop_categs=[x.id for x in st.shop_categs] for obj in self.browse(ids): total=0 for line in obj.lines: amt=line.amount or 0 total+=amt res[obj.id]={ 'total': total, 'shop_categs': shop_categs, } return res _fields={ "number": fields.Char("Number",required=True,search=True), "ref": fields.Char("Ref",search=True), 'date': fields.Date("Date",search=True), 'patient_id': fields.Many2One('clinic.patient','Patient',search=True), 'contact_id': fields.Many2One('partner','Contact',search=True), 'department_id': fields.Many2One("clinic.department","Department",search=True), 'branch_id': fields.Many2One("clinic.branch","Branch",search=True), 'lines': fields.One2Many('clinic.shop.line','shop_id','Lines'), 'total': fields.Float("Total",function="_get_all",function_multi=True), 'user_id': fields.Many2One("base.user","Pharmacist"), 'state': fields.Selection([['draft','Draft'],['waiting_payment','Waiting Payment'],['paid','Paid']],'State'), "pickings": fields.One2Many("stock.picking","related_id","Pickings"), "invoices": fields.One2Many("account.invoice","related_id","Invoices"), "payments": fields.One2Many("account.payment","related_id","Payments"), 'dom_str': fields.Char("Dom Str"), 'shop_categs': fields.Many2Many("product.categ","Categs",function="_get_all",function_multi=True,store=True), "related_id": fields.Reference([["sale.order","Sales Order"],["purchase.order","Purchase Order"],["project","Project"],["job","Service Order"],["service.contract","Service Contract"]],"Related To"), 'company_id': fields.Many2One("company","Company"), "pay_type": fields.Selection([("cash","Cash"),("credit","Credit")],"Pay Type"), "pay_by": fields.Selection([("cash","Cash"),("cheque","Cheque")],"Pay By"), 'pay_date': fields.Date("Pay Date"), 'bank_name': fields.Char("Bank"), 'bank_branch': fields.Char("Bank Branch"), 'cheque_no': fields.Char("Cheque No."), 'hd_case_call': fields.Boolean("HD Case Call"), 'note': fields.Text("Note"), } def _get_branch(self,context={}): b_ids=get_model('clinic.branch').search([]) if b_ids: return b_ids[0] def _get_department(self,context={}): dpt_ids=get_model('clinic.department').search([]) if dpt_ids: return dpt_ids[0] def _get_shop_categs(self,context={}): st=get_model("clinic.setting").browse(1) shop_categs=[x.id for x in st.shop_categs] return shop_categs def _get_related(self,context={}): related_id=None if context.get('refer_id'): related_id="clinic.hd.case,%s"%context.get("refer_id") return related_id def _get_patient(self,context={}): patient_id=None if context.get('refer_id'): refer_id=context.get("refer_id") hd_case=get_model("clinic.hd.case").browse(refer_id) patient_id=hd_case.patient_id.id return patient_id def _get_contact(self,context={}): partner_id=None if context.get('refer_id'): refer_id=context.get("refer_id") hd_case=get_model("clinic.hd.case").browse(refer_id) patient=hd_case.patient_id partner=patient.partner_id partner_id=partner.id return partner_id def _get_hdcase_call(self,context={}): res=False if context.get('hd_case_call'): res=True return res def _get_number(self,context={}): while 1: seq_id=get_model("sequence").find_sequence(name="Clinic RD Shop") 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) _defaults={ 'number': '/', 'date': lambda *a: time.strftime("%Y-%m-%d"), 'user_id': lambda *a: get_active_user(), 'company_id': lambda *a: get_active_company(), 'branch_id': _get_branch, 'department_id': _get_department, 'state': 'draft', 'shop_categs': _get_shop_categs, 'related_id': _get_related, 'patient_id': _get_patient, 'contact_id': _get_contact, 'pay_type': 'cash', 'hd_case_call': _get_hdcase_call, } def update_all(self,context={}): data=context['data'] data['total']=0 for line in data['lines']: data['total']+=line['amount'] or 0 return data def onchange_line(self,context={}): data=context['data'] path=context['path'] line=get_data_path(data,path,parent=True) line['amount']=(line['qty'] or 0)*(line['price'] or 0) data=self.update_all(context=context) return data def onchange_product(self,context={}): data=context['data'] path=context['path'] line=get_data_path(data,path,parent=True) prod_id=line['product_id'] prod=get_model('product').browse(prod_id) line['uom_id']=prod.uom_id.id line['description']=prod.name or '' line['price']=prod.sale_price or 0 if not line.get('qty'): line['qty']=1 line['amount']=line['price']*line['qty'] data=self.update_all(context) return data def onchange_categ(self,context={}): data=context['data'] path=context['path'] line=get_data_path(data,path,parent=True) line['product_id']=None return data def onchange_patient(self,context={}): data=context['data'] patient_id=data['patient_id'] patient=get_model("clinic.patient").browse(patient_id) dpt=patient.department_id branch=patient.branch_id contact=patient.partner_id data['department_id']=dpt.id data['branch_id']=branch.id data['contact_id']=contact.id return data def onchange_contact(self,context={}): data=context['data'] contact_id=data['contact_id'] data['patient_id']=None data['department_id']=None data['branch_id']=None print("contact_id ", contact_id) for patient in get_model("clinic.patient").search_browse([['partner_id','=',contact_id]]): dpt=patient.department_id branch=patient.branch_id data['department_id']=dpt.id data['branch_id']=branch.id data['patient_id']=patient.id 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) def pay_credit(self,ids,context={}): obj=self.browse(ids)[0] active_id=obj.id action="clinic_shop" if obj.hd_case_call: active_id=obj.related_id.id action="clinic_hd_case" st=get_model("clinic.setting").browse(1) if not st.shop_type_id: raise Exception("Please defind Shop Type on menu Clinic Settings -> RD Shop") if obj.number=="/": obj.write({ 'number': self._get_number(), }) obj.make_invoices() return { 'next': { 'name': action, 'mode': 'form', 'active_id': active_id, }, 'flash': 'Pay Successfully', } def pay_cash(self,ids,context={}): obj=self.browse(ids)[0] active_id=obj.id action="clinic_shop" if obj.hd_case_call: active_id=obj.related_id.id action="clinic_hd_case" st=get_model("clinic.setting").browse(1) if not st.shop_type_id: raise Exception("Please defind Shop Type on menu Clinic Settings -> RD Shop") if obj.number=="/": obj.write({ 'number': self._get_number(), }) obj.make_payment() return { 'next': { 'name': action, 'mode': 'form', 'active_id': active_id, }, 'flash': 'Pay Successfully', } def make_invoices(self,ids,context={}): setting=get_model("settings").browse(1,context) cst=get_model("clinic.setting").browse(1) shop_type=cst.shop_type_id 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[1:10] # XXX context['type']='out' context['inv_type']='invoice' cst=get_model('clinic.setting').browse(1) prod_acc=cst.get_product_account partner=obj.contact_id vals={ "type": "out", "inv_type": "invoice", "tax_type": "tax_in", 'due_date': due_date, "ref": obj.number or "", 'department_id': obj.department_id.id, "related_id": "clinic.shop,%s"%obj.id, "currency_id": currency_id, "company_id": company_id, 'partner_id': partner.id, "lines": [], } for line in obj.lines: if line.amount < 1: continue prod=line.product_id acc=prod_acc(prod.id,shop_type.id,'credit') 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)) vals['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, })) inv_id=get_model("account.invoice").create(vals,context) inv=get_model("account.invoice").browse(inv_id) inv.post() obj.make_pickings() obj.write({ 'state': 'paid', 'pay_type': 'credit', }) def make_pickings(self,ids,context={}): obj=self.browse(ids[0]) partner=obj.contact_id # no picking if not obj.lines: return ship_address_id=None for address in partner.addresses: if address.type=="shipping": ship_address_id=address.id break if not ship_address_id: raise Exception("No shipping address for contact %s"%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 pick_vals={ "type": "out", 'journal_id': stock_journal.id, "ref": obj.number, "related_id": "clinic.shop,%s"%obj.id, "partner_id": partner.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] for line in obj.lines: if line.qty < 1: continue prod=line.product_id if prod.type != 'stock': continue if not wh_loc_id: wh_loc_id=prod.location_id.id if not 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") pick_id=picking_obj.create(pick_vals,context={"pick_type": "out"}) pick=picking_obj.browse(pick_id) pick.set_done([pick_id]) def make_payment(self,ids,context={}): obj=self.browse(ids)[0] partner=obj.contact_id cst=get_model('clinic.setting').browse(1) shop_type=cst.shop_type_id cash_account_id=cst.cash_account_id.id income_account_id=cst.income_account_id.id if not cash_account_id: raise Exception("No Cash Account") if not income_account_id: raise Exception("No Income Account") 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.shop,%s"%obj.id, 'ref': obj.number, 'direct_lines': [], } prod_acc=cst.get_product_account for line in obj.lines: prod=line.product_id acc=prod_acc(prod.id,shop_type.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="[%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, })) payment_id=get_model("account.payment").create(vals,context={"type":"in"}) payment=get_model('account.payment').browse(payment_id) payment.post() obj.make_pickings() obj.write({ 'state': 'paid', 'pay_type': 'cash', }) def to_draft(self,ids,context={}): for obj in self.browse(ids): for payment in obj.payments: payment.to_draft() payment.delete() 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 picking in obj.pickings: picking.to_draft() picking.delete() obj.write({ 'state': 'draft', }) if obj: return { 'next': { 'name': { 'next': 'clinic_shop', 'mode': 'form', 'active_id': obj.id, }, 'flash': '%s has been set to draft'%obj.number or "", } } def view_payment(self,ids,context={}): return { 'next': { 'name': 'payment', 'mode': 'form', 'active_id': ids[0], }, } def get_bill(self,context={}): if not context.get('refer_id'): return {} shop_id=int(context['refer_id']) shop=self.browse(shop_id) comp_id=get_active_company() comp=get_model('company').browse(comp_id) st=get_model('settings').browse(1) addresses=st.addresses comp_addr='' if addresses: comp_addr=addresses[0].address_text cust=shop.contact_id cust_name=cust.name or '' cust_addr='' if cust.addresses: cust_addr=cust.addresses[0].address_text if cust.walkin_cust: cust_name=shop.ref or '' no=1 sub_total=0 amount_total=0 lines=[] for line in shop.lines: amt=line.amount or 0 prod=line.product_id lines.append({ 'no': no, 'product_name': prod.name or '', 'description': line.description or '', 'uom_name': line.uom_id.name or '', 'qty': line.qty or 0, 'price': line.price or 0, 'amount': amt, }) sub_total+=amt no+=1 amount_total=sub_total #XXX is_draft=shop.state=='draft' and True or False is_cheque=False pay_type=shop.pay_type or '' data={ 'comp_name': comp.name or '', 'comp_addr': comp_addr or '', 'tax_no': st.tax_no or '', 'number': shop.number or '', 'ref': shop.ref, 'date': shop.date, 'cust_name': cust_name, 'cust_addr': cust_addr, 'note': shop.note 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, } blank_dot='' if pay_type=='cash': data['pay_type']='Cash' if shop.cheque_no: data['is_cheque']=True data['bank_name']=shop.bank_name or blank_dot data['branch_name']=shop.branch_name or blank_dot data['cheque_no']=shop.cheque_no or blank_dot data['cheque_date']=shop.pay_date or blank_dot else: data['pay_type']='Credit' if st.logo: data['logo']=get_file_path(st.logo) return data def get_data(self,ids,context={}): settings=get_model('settings').browse(1) pages=[] for obj in get_model('clinic.shop').browse(ids): context['refer_id']=obj.id data=get_model('clinic.shop').get_bill(context=context) pages.append(data) if pages: pages[-1]["is_last_page"]=True return { "pages": pages, "logo": get_file_path(settings.logo), } def print_bill(self,ids,context={}): return { 'next': { 'refer_id': ids[0], 'name': 'clinic_cust_print', } } def pay(self,ids,context={}): res={} obj=self.browse(ids)[0] if not obj.lines: raise Exception("No item") if obj.pay_type=='cash': res=obj.pay_cash() else: res=obj.pay_credit() return res Shop.register()