class ProductTemplate(orm.Model): _inherit = 'product.template' _columns = { 'date_start': fields.date("Start date"), 'date_end': fields.date("End Date"), 'period': fields.selection([('week', 'Week'), ('month', 'Month'), ('year', 'Year')], 'Time Period'), 'analysis_type': fields.selection([('average', 'Average'), ('end_of_period', 'End of period')], 'Type of analysis'), 'stock_graphic': fields.binary("Graph") } _defaults = { 'date_start': lambda *a: (datetime.now() - relativedelta(months=6)).strftime('%Y-%m-%d'), 'date_end': lambda *a: datetime.now().strftime('%Y-%m-%d'), 'period': 'month', 'analysis_type': 'average' }
class custom_calendar_event(osv.osv): _name = "calendar.event" _inherit = 'calendar.event' @api.depends('x_categ_id','x_partner_id') def _compute_categ_id_char(self): self.x_categ_id_char = self.x_categ_id.name if self.x_categ_id_char and self.x_partner_id.display_name and self.x_partner_id.phone: self.name = self.x_categ_id_char+' : '+self.x_partner_id.display_name+', '+self.x_partner_id.phone elif self.x_categ_id_char and self.x_partner_id.display_name: self.name = self.x_categ_id_char+' : '+self.x_partner_id.display_name elif self.x_partner_id.display_name: self.name = self.x_partner_id.display_name elif self.x_categ_id_char: self.name = self.x_categ_id_char else: _columns = { 'x_domicile': fields.boolean('A domicile'), 'x_partner_id': fields.many2one('res.partner', 'Attendee', default=''), 'x_categ_id': fields.many2one('calendar.event.type', 'Tags'), 'x_categ_id_char': fields.char(compute='_compute_categ_id_char', default=''), 'x_event_is_billed': fields.boolean('is_billed'), 'x_event_is_printed': fields.boolean('is_printed'), # related field res.partner # ------------------------- 'x_event_display_name' : fields.related('x_partner_id', 'display_name', type="char"), 'x_event_name' : fields.related('x_partner_id', 'name', type="char"), 'x_event_phone' : fields.related('x_partner_id', 'phone', type="char", default=''), 'x_event_patient_prenom': fields.related('x_partner_id', 'x_patient_prenom', type="char"), 'x_event_patient_sexe': fields.related('x_partner_id', 'x_patient_sexe', type="selection", selection=SEXE_SELECTION), 'x_event_patient_cafat': fields.related('x_partner_id', 'x_patient_cafat', type="char"), 'x_event_dob': fields.date(related='x_partner_id.dob'), 'x_event_age' : fields.integer(related='x_partner_id.age'), 'x_event_src_avatar' : fields.binary(related='x_partner_id.x_src_avatar'), 'x_event_medecin_traitant': fields.char(related='x_partner_id.x_medecin_traitant'), ########## MEDICAL INFO ??? # 'x_event_groupe_sang': fields.related('x_partner_id', 'x_groupe_sang', type="selection", selection=GRP_SANG_SELECTION), # 'x_event_taille': fields.float(related='x_partner_id.x_taille'), # 'x_event_poids': fields.float(related='x_partner_id.x_poids'), # 'x_event_IMC': fields.float(related='x_partner_id.x_IMC'), ########## # related field calendar_event_type # ------------------------- 'x_event_codeActe': fields.char(related='x_categ_id.x_code_acte', size=8), 'x_event_priceActe': fields.float(related='x_categ_id.x_price_acte', digits=(4,0)), # ------------------------- } _default = { 'x_domicile': False, }
class uis_papl_apl(models.Model): _name ='uis.papl.apl' name = fields.Char() full_name=fields.Char() inv_num = fields.Char() bld_year =fields.Char(string="Building year") startexp_date = fields.Date(string="Start operations date") line_len=fields.Float(digits=(3,2)) line_len_calc=fields.Float(digits=(6,2), compute='_apl_get_len') prol_max_len=fields.Float(digits=(2,2), compute='_apl_get_len') prol_med_len=fields.Float(digits=(2,2), compute='_apl_get_len') prol_min_len=fields.Float(digits=(2,2), compute='_apl_get_len') pillar_id=fields.One2many('uis.papl.pillar','apl_id', string ="Pillars") tap_ids=fields.One2many('uis.papl.tap', 'apl_id', string="Taps") sup_substation_id=fields.Many2one('uis.papl.substation', string="Supply Substation") scheme_image=fields.binary(string="Scheme", compute='_get_scheme_image')
class demo_xls_report_file(osv.osv_memory): _name = 'demo.xls.report.file' _description = 'PDF Reports for showing all disconnection,reconnection' _columns = { 'file': fields.binary('File'), 'file_name': fields.char('File Name', size=64), 'name': fields.many2one('xls.report', 'Name'), 'partner_id': fields.many2one('res.partner', 'Customer') } def default_get(self, cr, uid, fields, context=None): if context is None: context = {} res = super(demo_xls_report_file, self).default_get(cr, uid, fields, context=context) res.update({'file_name': 'Report.xls'}) if context.get('file'): res.update({'file': context['file']}) return res
class upload_images(osv.osv): _name = 'upload_images.tutorial' _description = 'Tutorial image uploading' def _get_image(self, cr, uid, ids, name, args, context=None): result = dict.fromkeys(ids, False) for obj in self.browse(cr, uid, ids, context=context): result[obj.id] = tools.image_get_resized_images(obj.image) return result def _set_image(self, cr, uid, id, name, value, args, context=None): return self.write(cr, uid, [id], {'image': tools.image_resize_image_big(value)}, context=context) _columns = { 'name': fields.char('Name', required=True, translate=True), 'image': fields.binary("Image", help="This field holds the image used as image for our customers, limited to 1024x1024px."), 'image_medium': fields.function(_get_image, fnct_inv=_set_image, string="Image (auto-resized to 128x128):", type="binary", multi="_get_image", store={ 'upload_images.tutorial': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), },help="Medium-sized image of the category. It is automatically "\ "resized as a 128x128px image, with aspect ratio preserved. "\ "Use this field in form views or some kanban views."), 'image_small': fields.function(_get_image, fnct_inv=_set_image, string="Image (auto-resized to 64x64):", type="binary", multi="_get_image", store={ 'upload_images.tutorial': (lambda self, cr, uid, ids, c={}: ids, ['image'], 10), }, help="Small-sized image of the category. It is automatically "\ "resized as a 64x64px image, with aspect ratio preserved. "\ "Use this field anywhere a small image is required."), }
class ccg_travel_order_total_export(osv.osv_memory): # orm.TransientModel _name = 'ccg.travel.order.total.export' _columns = { 'data': fields.binary('File', readonly=True), 'name': fields.char('Filename', size=255, readonly=True), 'state': fields.selection(( ('create', 'create'), ('get', 'get'), ), default='create'), 'delimiter': fields.selection(( (',', ', (comma)'), (';', '; (semicolon)'), ('\t', '(tab)'), ), default=';'), 'quotation': fields.selection(( ('"', '"'), ("'", "'"), ('none', '(none)'), ), default='none'), 'encoding': fields.selection((('utf-8', 'utf-8'), ('utf-8-sig', 'utf-8 with BOM'), ("windows-1250", "windows-1250")), default='utf-8'), 'decimal': fields.selection((('.', '. (dot)'), (',', ', (comma)')), default=','), } _travel_order_name = '' def get_currency_code(self, cr, uid, currency_name, context=None): obj = self.pool.get('currency.mapping') ids = obj.search(cr, uid, [('currency_name', '=', currency_name)], context=context) currency_codes = obj.browse(cr, uid, ids, context=context) if currency_codes: return currency_codes[0].total_id else: return False def get_expense_id(self, cr, uid, ccg_product_id, context=None): obj = self.pool.get('expense.mapping') ids = obj.search(cr, uid, [('product_id', '=', ccg_product_id)], context=context) expenses = obj.browse(cr, uid, ids, context=context) if expenses: return expenses[0].total_id else: return False def get_transportation_type(self, cr, uid, crm_transportation_id, context=None): obj = self.pool.get('transportation.mapping') ids = obj.search(cr, uid, [('transportation_id', '=', crm_transportation_id)], context=context) transportations = obj.browse(cr, uid, ids, context=context) if transportations: return transportations[0].total_id else: return False def get_employee_id(self, cr, uid, company_id, ccg_employee_id, context=None): obj = self.pool.get('employee.mapping') ids = obj.search(cr, uid, [('company_id', '=', company_id), ('employee_id', '=', ccg_employee_id)], context=context) employees = obj.browse(cr, uid, ids, context=context) if employees: return employees[0].total_id else: return False def get_responsible_person_id(self, cr, uid, company_id, context=None): obj = self.pool.get('responsible.person.mapping') ids = obj.search(cr, uid, [('company_id', '=', company_id)], context=context) responsible_persons = obj.browse(cr, uid, ids, context=context) if responsible_persons: return responsible_persons[0].total_id else: return False def _quotation(self): return self.form['quotation'] def _delimiter(self): return self.form['delimiter'] def _encoding(self): return self.form['encoding'] def _decimal(self): return self.form['decimal'] def _quoted(self, text): q = self._quotation() if q == 'none': return str(text) else: return '{1}{0}{1}'.format(text, q) def _trim(self, text): if text: s = text.replace('\n', ' ').replace(';', '.') return s else: return "" def _reformat_date(self, date): dd = date[8:10] mm = date[5:7] yyyy = date[0:4] return '{}.{}.{}'.format(dd, mm, yyyy) def _reformat_datetime(self, datetime_str, sec=False): fmt_in = '%Y-%m-%d %H:%M:%S' fmt_out = '%d.%m.%Y %H:%M:%S' t = datetime.strptime(datetime_str, fmt_in) localtime = timezone('UTC').localize(t).astimezone( timezone("Europe/Zagreb")) return localtime.strftime(fmt_out) def _document(self, cr, uid, travel_order, context=None): line = [] # header - Vrijednost 1 obavezna u svakom retku line.append(self._quoted('1')) # datum_naloga (+) if travel_order.document_date: document_date = self._reformat_date(travel_order.document_date) document_datetime = '{} {}'.format(document_date, travel_order.create_date[-8:]) line.append(document_datetime) else: raise Warning( _("Missing or invalid document date in travel order {} ({})!". format(self._travel_order_name, travel_order.employee_id.name))) # datum_isplate (+) if travel_order.date_liquidation: date_liquidation = self._reformat_date( travel_order.date_liquidation) line.append(date_liquidation) else: raise Warning( _("Missing or invalid date liquidation in travel order {} ({})!" .format(self._travel_order_name, travel_order.employee_id.name))) # sifra_zaposlenika_putnika employee_id = self.get_employee_id(cr, uid, travel_order.company_id.id, travel_order.employee_id.id) if employee_id: line.append(self._quoted(employee_id)) else: raise Warning( _("Missing or invalid employee in travel order {}!".format( self._travel_order_name))) # sifra_zaposlenika_odobritelja responsible_person_id = self.get_responsible_person_id( cr, uid, travel_order.company_id.id) if responsible_person_id: line.append(self._quoted(responsible_person_id)) else: raise Warning( _("Missing or invalid responsible person in travel order {} ({})!" .format(self._travel_order_name, travel_order.employee_id.name))) # datum_i_vrijeme_odlaska date_from = self._reformat_datetime(travel_order.date_from) line.append(self._quoted(date_from)) # datum_i_vrijeme_povratka date_to = self._reformat_datetime(travel_order.date_to) line.append(self._quoted(date_to)) # pbr_mjesto_polaska departure_city_zip = travel_order.company_id.zip line.append(self._quoted(departure_city_zip)) # pbr_mjesto_odrediste (*) # city_destination = travel_order.dest_city.split(',') # line.append(city_destination[0]) if travel_order.partner_ids: destination_partner = travel_order.partner_ids[0] if destination_partner.zip: destination_city_zip = destination_partner.zip else: destination_city_zip = '' else: destination_city_zip = '' line.append(self._quoted(destination_city_zip)) # opis_putovanja purpose = travel_order.purpose[:200] if travel_order.purpose else "" if not purpose: raise Warning( _("Missing purpose of travel order {} ({})!".format( self._travel_order_name, travel_order.employee_id.name))) else: line.append(self._trim(purpose)) # tip_prijevozno_sredstvo depart_transportation_type = self.get_transportation_type( cr, uid, travel_order.depart_transportation[0].id) if depart_transportation_type: line.append(self._quoted(depart_transportation_type)) else: raise Warning( _("Missing or invalid transportation type in travel order {} ({})!" .format(self._travel_order_name, travel_order.employee_id.name))) # marka_i_regbr_vozila if travel_order.depart_vehicle_ids: vehicle_registration = travel_order.depart_vehicle_ids[0].name else: vehicle_registration = '' line.append(vehicle_registration) # pocetno_stanje_brojila if travel_order.itinerary_ids: odometer_start = travel_order.itinerary_ids[0].odometer_start else: odometer_start = '0' line.append(self._quoted(odometer_start)) # odobreni_predujam advance_payment = travel_order.advance_payment line.append(self._quoted(locale.str(advance_payment))) # valuta_za_predujam if travel_order.currency_id: advance_currency_code = self.get_currency_code( cr, uid, travel_order.currency_id.name) else: advance_currency_code = '' if advance_currency_code: line.append(self._quoted(advance_currency_code)) else: raise Warning( _("Missing or invalid currency for advance payment in travel order {} ({})!" .format(self._travel_order_name, travel_order.employee_id.name))) # putno_izvjesce report = travel_order.other_data if not report: raise Warning( _("Missing travel order report (Other Data) in travel order {} ({})!" .format(self._travel_order_name, travel_order.employee_id.name))) else: line.append(self._trim(report)) csv_row = self._delimiter().join(line) return csv_row def _allowances(self, cr, uid, allowances, travel_order, context=None): lines = [] for allowance in allowances: line = [] # Header - Vrijednost 2 obavezna u svakom retku line.append(self._quoted('2')) # sifra_drzave country_code = get_country_code(allowance.country_id.code) if country_code: line.append(self._quoted(country_code)) else: raise Warning( _("Missing or invalid currency for advance payment in travel order {} ({})!" .format(self._travel_order_name, travel_order.employee_id.name))) # datum_i_vrijeme_izlaska # TODO convert datetime fron UTC to local time!!! date_to = allowance.date_to line.append(self._reformat_datetime(date_to)) data = self._delimiter().join(line) lines.append(data) csv_rows = '\n'.join(lines) return (csv_rows) def _expenses(self, cr, uid, expenses, travel_order, context=None): lines = [] for expense in expenses: line = [] # header - Vrijednost 3 obavezna u svakom retku line.append(self._quoted('3')) # vrsta_putnog_troska expense_type = self.get_expense_id(cr, uid, expense.product_id.id) if expense_type: line.append(self._quoted(expense_type)) else: raise Warning( _("Missing or invalid expense type for '{}' in travel order {} ({})!" .format(expense.name, self._travel_order_name, travel_order.employee_id.name))) # oznaka_placeno paid = 1 if expense.journal_id.type == 'bank' else 0 line.append(self._quoted(paid)) # nije plaćeno # tip_isplate_joppd line.append(self._quoted('0')) #ostalo # opis_troska line.append(self._quoted(expense.name)) # kolicina qty = expense.unit_quantity line.append(self._quoted(locale.str(qty))) # cijena price = expense.unit_amount line.append(self._quoted(locale.str(price))) # valuta currency_name = expense.currency_id.name currency_code = self.get_currency_code(cr, uid, expense.currency_id.name) if currency_code: line.append(self._quoted(currency_code)) else: raise Warning( _("Missing or invalid currency for expense '{}' in travel order {} ({})!" .format(expense.name, self._travel_order_name, travel_order.employee_id.name))) # tecaj currency_rate = expense.lcy_rate line.append(self._quoted(locale.str(currency_rate))) # oznaka_pdv line.append(self._quoted('')) data = self._delimiter().join(line) lines.append(data) csv_rows = '\n'.join(lines) return (csv_rows) def _itinerary_expenses(self, cr, uid, itinerary_lines, travel_order, context=None): lines = [] for itinerary in itinerary_lines: line = [] # header - Vrijednost 3 obavezna u svakom retku line.append(self._quoted('3')) # vrsta_putnog_troska = 1 (kilomterina) line.append(self._quoted('1')) # oznaka_placeno line.append(self._quoted(0)) # nije unaprijed plaćeno # tip_isplate_joppd - za privatni auto = 4 Isplata u gotovini, za službeni = 0 - nije plaćeno if itinerary.vehicle_id.type == 'private': line.append( self._quoted('4')) # kilometrina se isplaćuje u gotovini else: # službeni line.append(self._quoted('0')) # kilometrina se ne isplaćuje # opis_troska description = 'Kilometrina' line.append(self._quoted(description)) # kolicina qty = itinerary.distance line.append(self._quoted(locale.str(qty))) # cijena # print itinerary.vehicle_type.lower(), itinerary.vehicle_id.name, itinerary.vehicle_id.type if itinerary.vehicle_id.type == 'private': price = 2.0 #HRK/km else: price = 0.0 line.append(self._quoted(locale.str(price))) # valuta currency_name = 'HRK' currency_code = self.get_currency_code(cr, uid, currency_name) line.append(self._quoted(currency_code)) # tecaj currency_rate = 1.0 line.append(self._quoted(locale.str(currency_rate))) # oznaka_pdv line.append(self._quoted('')) data = self._delimiter().join(line) lines.append(data) csv_rows = '\n'.join(lines) return (csv_rows) def _daily_allowance_expenses(self, cr, uid, daily_allowance_lines, travel_order, context=None): lines = [] for allowance in daily_allowance_lines: if allowance.num_of_allowances: line = [] # header - Vrijednost 3 obavezna u svakom retku line.append(self._quoted('3')) # vrsta_putnog_troska if allowance.currency_id.name == 'HRK': expense_type = self._quoted('2') description = 'Domaća dnevnica' else: expense_type = self._quoted('3') description = 'Inozemna dnevnica' line.append(expense_type) # oznaka_placeno line.append(self._quoted(0)) # nije plaćeno # tip_isplate_joppd line.append(self._quoted('4')) # dnevnice # opis_troska line.append(self._quoted(description)) # kolicina qty = allowance.num_of_allowances line.append(self._quoted(locale.str(qty))) # cijena # price = allowance.allowance_amount_total price = allowance.allowance_unit_amount line.append(self._quoted(locale.str(price))) # valuta currency_name = allowance.currency_id.name currency_code = self.get_currency_code(cr, uid, currency_name) line.append(self._quoted(currency_code)) # tecaj currency_rate = allowance.lcy_rate line.append(self._quoted(locale.str(currency_rate))) # oznaka_pdv line.append(self._quoted('')) data = self._delimiter().join(line) lines.append(data) csv_rows = '\n'.join(lines) return (csv_rows) def _csv_lines(self, cr, uid, travel_orders, context=None): csv = [] self._set_decimal_point(self._decimal()) for to in travel_orders: self._travel_order_name = to.name # hr.travel.order document_csv = self._document(cr, uid, to, context) csv.append(document_csv) # daily.allowance.lines if to.daily_allowance_ids: allowances_csv = self._allowances(cr, uid, to.daily_allowance_ids, to, context) csv.append(allowances_csv) # hr.expense.line if to.expense_line_ids: expenses_csv = self._expenses(cr, uid, to.expense_line_ids, to, context) csv.append(expenses_csv) # append itinerrary to expenses hr.travel.opder.itinerary.lines if to.itinerary_ids: itinerary_csv = self._itinerary_expenses( cr, uid, to.itinerary_ids, to, context) csv.append(itinerary_csv) # append daily allowances to expenses daily.allowance.lines if to.daily_allowance_ids: allowance_csv = self._daily_allowance_expenses( cr, uid, to.daily_allowance_ids, to, context) csv.append(allowance_csv) self._set_decimal_point() # reset decimal point to default return csv def _set_decimal_point(self, frm=''): if frm == '.': locale.setlocale(locale.LC_NUMERIC, 'en_US.utf8') elif frm == ',': locale.setlocale(locale.LC_NUMERIC, 'hr_HR.utf8') else: locale.setlocale(locale.LC_ALL, '') # reset to system default def generate_csv(self, cr, uid, ids, context=None): if context is None: context = {} self.form = self.read(cr, uid, ids)[0] active_model = context.get('active_model', None) active_ids = context.get('active_ids', []) sorted_ids = self.pool.get(active_model).search( cr, uid, [('id', 'in', active_ids)], order='name', context=context) travel_orders = self.pool.get(active_model).browse(cr, uid, sorted_ids, context=context) csv_lines = self._csv_lines(cr, uid, travel_orders, context) data = '\n'.join(csv_lines) if len(active_ids) == 1: # ima datoteke se sastoji od broja putnog naloga filename = 'travel_order_{}.csv'.format( travel_orders.name.replace('/', '_')) else: # ako ima više putnih naloga, ime datoteke ima ukupni broj putnih naloga filename = 'travel_order_{}.csv'.format(len(active_ids)) self.write( cr, uid, ids, { 'data': base64.encodestring(data.encode(self._encoding())), 'name': filename, 'state': 'get' }, context=context) # ovaj dictionary sadrži podatke kao i record 'action_export_opportunity_for_ds_wizard' u xml-u # tako da po povratku iz ove metode opet otvori takav prozor return { 'context': context, 'view_type': 'form', 'view_mode': 'form', 'res_model': 'ccg.travel.order.total.export', 'res_id': ids[0], 'view_id': False, 'type': 'ir.actions.act_window', 'target': 'new', 'name': 'Export for TOTAL', }
class crm_lead_export_for_ds(osv.osv_memory): # orm.TransientModel _name = 'crm.lead.export.for.ds' _columns = { 'data' : fields.binary('File', readonly=True), 'name' : fields.char('Filename', size=32, readonly=True), 'state' : fields.selection((('choose', 'choose'), ('get', 'get'),)), 'delimiter' : fields.selection(((',', ', (comma)'), (';', '; (semicolon)'), ('\t', '(tab)'),), default=','), 'quotation' : fields.selection((('"', '"'), ("'", "'"), ('none', '(none)'),), default='"'), 'encoding' : fields.selection((('utf-8', 'utf-8'), ('utf-8-sig', 'utf-8 with BOM'), ("windows-1250", "windows-1250")), default='utf-8'), 'decimal' : fields.selection((('.', '(dot)'), (',', ', (comma)')), default='.'), } _ds_fields = ['CustomerName', #A 'DSSiteID', #B 'PartnerCustomerID', #C 'CustomerDUNSNumber', #D 'CustomerVATNumber', #E 'CustomerRegistrationID', #F 'CustomerAddress1', #G 'CustomerAddress2', #H 'CustomerCity', #I 'CustomerCountry',#J 'CustomerStatePrefecture', #K 'CustomerZipPostcode', #L 'CustomerWebsiteHomepageURL', #M 'CustomerContactSalutation', #N 'CustomerContactFirstName', #O 'CustomerContactLastName', #P 'CustomerContactJobTitle', #Q 'CustomerContactTel', #R 'CustomerContactEmail', #S 'PartnerSalesRepFirstName', #T 'PartnerSalesRepLastName', # U 'PartnerSalesRepEmail', #V 'OpportunityLeadName', #W 'OpportunityLeadDescription', #X 'PartnerOpportunityID', #Y 'DSLeadID', #Z # 'CoMarketingYN', # not in specification 'COMETCampaignCode', #AA 'CampaignName', #AB 'SalesStage', #AC 'ForecastCategory', #AD 'DomainofInterest', #AE 'LeadSource', #AF 'NextMilestone', #AG 'NextMilestoneDate', #AH 'CloseDate', #AI 'ReasonLost', #AJ 'ReasonWon', #AK 'ReasonWonLostComment', #AL 'IfLostWhoWon', #AM 'OfferName', # AN 'RevenueAmount', #AO 'RevenueCurrency', #AP 'RevenueType', #AQ ] _field_mappings = { # 0-table, 1-field, 2-alias, 3-string, 4-active, 5-required 'CustomerName' : ('res_partner', 'name', 'partner_name', 'Customer', True, True ), 'DSSiteID' : ('res_partner', 'site_id', 'site_id', 'DSSiteID', True, False ), 'HeadOfficeID' : ('res_partner', 'head_office_id', 'head_office_id', 'HeadOfficeID', False, False ), 'CustomerAddress1' : ('res_partner', 'street', 'street', 'Address Street', True, True ), 'CustomerAddress2' : ('res_partner', 'street2', 'street2', 'Address Street2', True, False ), 'CustomerCity' : ('res_partner', 'city', 'city', 'City', True, True ), 'CustomerCountry' : ('res_country', 'name', 'country', 'Country', True, True ), 'CustomerZipPostcode' : ('res_partner', 'zip', 'zip', 'ZIP', True, True ), 'CustomerVATNumber' : ('res_partner', 'vat', 'vat', 'VAT', True, True ), 'OfferName' : ('ccg_offer_name', 'name', 'offer_name', 'Offer name', True, True ), 'RevenueAmount' : ('crm_lead', 'ds_expected_revenue', 'planned_revenue', 'Expected revenue for DS', True, True ), 'RevenueCurrency' : ('', "'EUR'", 'currency', 'Currency', True, True ), 'PartnerOpportunityID' : ('crm_lead', 'lead_ref_no', 'opportunity_id', 'Opportunity ID', True, True ), 'CCGSalesStage' : ('crm_case_stage', 'name', 'ccg_sales_stage', 'CCG Sales stage', True, True ), 'SalesStage' : ('', "''", 'sales_stage', 'Sales stage', True, True ), 'ForecastCategory' : ('', "''", 'forecast_category', 'Forecast category', True, True ), 'CloseDate' : ('crm_lead', 'date_deadline', 'close_date', 'Expected closing date', True, True ), 'RevenueType' : ('crm_lead', 'revenue_type', 'revenue_type', 'Revenue type', True, True ), 'CustomerContactName' : ('partner_contact', 'name', 'contact_name', "Customer's Contact Person Name", False, False), 'CustomerContactFirstName' : ('', "''", 'contact_first_name', "Customer's Contact Person First Name", True, True ), 'CustomerContactLastName' : ('', "''", 'contact_last_name', "Customer's Contact Person Last Name", True, True ), 'CustomerContactEmail' : ('partner_contact', 'email', 'contact_email', "Customer's Contact Email", True, True ), 'DSLeadID' : ('crm_lead', 'ds_lead_id', 'ds_lead_id', 'DS Lead ID', True, False ), 'COMETCampaignCode' : ('crm_lead', 'comet_campaign_code', 'comet_campaign_code', 'COMET Campaign Code', True, False ), 'CampaignName' : ('crm_lead', 'campaign_name', 'campaign_name', 'Campaign Name', True, False ), 'NextMilestone' : ('crm_lead', 'next_milestone', 'next_milestone', 'Next Milestone', True, False ), 'PartnerSalesRepName' : ('sales', 'name', 'partner_sales_name', "Partner's Salesman", False, False), 'PartnerSalesRepFirstName' : ('', "''", 'partner_sales_first_name', "Partner's Salesman First Name", True, True ), 'PartnerSalesRepLastName' : ('', "''", 'partner_sales_last_name', "Partner's Salesman Last Name", True, True ), 'PartnerSalesRepEmail' : ('sales', 'email', 'partner_sales_email', "Partner's Salesman Email", True, True ), 'OpportunityLeadName' : ('',"crm_lead.name || ' [' || crm_lead.lead_ref_no || ']'",'opportunity_name', "Opportunity name", True, True ), 'Management Assessment' : ('crm_lead','management_assessment','management_assessment','management assessment', False, False ), 'ReasonLost' : ('crm_lost_reason','name','lost_reason','Lost Reason', True, False ), } """ DS Sales stages Closed/Lost Closed/Won 1-Sales Lead 2-Validate Opportunity 3-Establish Value 4-Reach Agreement """ """ DS Forecast categories: Upside Commit Safe Won Lost """ _stage_mapping = { 'New': ('1-Sales Lead', 'Upside'), 'Validation' : ('2-Validate Opportunity', 'Upside'), 'Establish value' : ('3-Establish Value', 'Upside'), 'Negotiation' : ('3-Establish Value', 'Commit'), 'Reach Agreement': ('4-Reach Agreement', 'Safe'), 'Won' : ('Closed/Won', 'Won'), 'Lost' : ('Closed/Lost', 'Lost'), 'Sleeping' : ('2-Validate Opportunity', 'Upside'), } def default_get(self, cr, uid, fields, context=None): res = super(crm_lead_export_for_ds, self).default_get(cr, uid, fields, context=context) res['state'] = 'choose' return res def map_stage(self, cr, uid, row, context=None): sales_stage = row['ccg_sales_stage'] new_stage = self._stage_mapping[sales_stage][0] if not new_stage: raise Warning(_("Cannot export opportunity which is in state '{}'!".format(sales_stage))) forecast_category = row['ccg_sales_stage'] new_forecast_category = self._stage_mapping[forecast_category][1] row.update({'sales_stage':new_stage, 'forecast_category':new_forecast_category}) return row def split_contact_name(self, cr, uid, row, context=None): contact_name = row['contact_name'] if contact_name: names = contact_name.split() first_name = names[0] last_name = " ".join([ln for ln in names[1:] if ln]) else: opportunity_id = row['opportunity_id'] field_label = self._field_mappings['CustomerContactName'][3] raise osv.except_osv(_('Export Error!'), _('Missing field "{}" in opportunity "{}"!'.format(field_label, opportunity_id))) row.update({'contact_first_name':first_name, 'contact_last_name':last_name}) return row def split_salesman_name(self, cr, uid, row, context=None): partner_sales_name = row['partner_sales_name'] if partner_sales_name: names = partner_sales_name.split() first_name = names[0] last_name = " ".join([ln for ln in names[1:] if ln]) else: opportunity_id = row['opportunity_id'] field_label = self._field_mappings['PartnerSalesRepName'][3] raise osv.except_osv(_('Export Error!'), _('Missing field "{}" in opportunity "{}"!'.format(field_label, opportunity_id))) row.update({'partner_sales_first_name':first_name, 'partner_sales_last_name':last_name}) return row def management_assessment_into_next_milestone(self, cr, uid, row, context=None): print row next_milestone = row['next_milestone'] or '' management_assessment = row['management_assessment'] if row['ccg_sales_stage']=='Negotiation' else '' value = ' - '.join([l for l in [ management_assessment, next_milestone] if l]) row.update({'next_milestone': value}) print row return row def _quotation(self): return self.form['quotation'] def _delimiter(self): return self.form['delimiter'] def _encoding(self): return self.form['encoding'] def _decimal(self): return self.form['decimal'] def _quoted(self, text): q = self._quotation() not_null_text = text if text else '' if q=='none': return str(not_null_text) else: return '{1}{0}{1}'.format(not_null_text, q) def _get_opportunity_fields(self, cr, uid, context=None): ids = context.get('active_ids', []) fields = [] for key in self._field_mappings.keys(): value = self._field_mappings[key] table = value[0] field = value[1] alias = value[2] or field if table: fields.append('{}.{} as {}'.format(table, field, alias)) else: fields.append('{} as {}'.format(field, alias)) sql = ''' SELECT {} FROM crm_lead LEFT JOIN res_partner ON (crm_lead.partner_id=res_partner.id) LEFT JOIN crm_case_stage ON (crm_lead.stage_id = crm_case_stage.id) LEFT JOIN res_country ON (res_partner.country_id = res_country.id) LEFT JOIN ccg_offer_name ON (crm_lead.offer_name_id = ccg_offer_name.id) LEFT JOIN res_partner partner_contact ON (crm_lead.contact_name_id=partner_contact.id) LEFT JOIN res_users users ON (res_partner.user_id=users.id) LEFT JOIN res_partner sales ON (users.partner_id=sales.id) LEFT JOIN crm_lost_reason ON (crm_lead.lost_reason_id = crm_lost_reason.id) WHERE crm_lead.id in ({}) '''.format(','.join([f for f in fields ]), ','.join([str(i) for i in ids])) print sql cr.execute(sql) return cr.dictfetchall() def _csv_lines(self, cr, uid, context=None): data = self._get_opportunity_fields(cr, uid, context) lines = [] for row_original in data: line = [] opportunity_id = row_original['opportunity_id'] row = self.map_stage(cr, uid, row_original, context) row = self.split_contact_name(cr, uid, row, context) row = self.split_salesman_name(cr, uid, row, context) row = self.management_assessment_into_next_milestone(cr, uid, row, context) print row for ds_field_name in self._ds_fields: value = self._field_mappings.get(ds_field_name, False) field_value_strnig = '' if value: if value[4]: # is active crm_field_name = value[2] or value[1] field_value = row[crm_field_name] print crm_field_name, ':', field_value required = value[5] field_label = value[3] if not field_value: if required: raise osv.except_osv(_('Export Error!'), _('Missing field "{}" in opportunity "{}"!'.format(field_label, opportunity_id))) # else: # raise Warning (_('Warning!'), _('Field "{}" in opportunity "{}" is missing but needed in some situations!'.format(field_label, opportunity_id))) if crm_field_name == 'close_date': field_value = '{}.{}.{}'.format(field_value[8:10],field_value[5:7],field_value[0:4]) field_value_strnig = self._quoted(field_value) line.append(field_value_strnig) csv_line = self._delimiter().join(line) lines.append(csv_line) if len(lines) > 1: csv_file_name ='opportunities.csv' else: csv_file_name = 'opportunity_{}.csv'.format(opportunity_id) return '\n'.join(lines), csv_file_name def generate_csv(self, cr, uid, ids, context=None): if context is None: context = {} self.form = self.read(cr, uid, ids)[0] # header = self._delimiter().join([k for k in self._ds_fields if self._field_mappings[k][4]]) header = self._delimiter().join(self._ds_fields) lines, filename = self._csv_lines(cr, uid, context) if header and lines: data = header + '\n' + lines self.write(cr, uid, ids, {'data': base64.encodestring(data.encode(self._encoding())), 'name':filename, 'state':'get'}, context=context) # ovaj dictionary sadrži podatke kao i record 'action_export_opportunity_for_ds_wizard' u xml-u # tako da po povratku iz ove metode opet otvori takav prozor return { 'context': context, 'view_type': 'form', 'view_mode': 'form', 'res_model': 'crm.lead.export.for.ds', 'res_id': ids[0], 'view_id': False, 'type': 'ir.actions.act_window', 'target': 'new', 'name' : 'Export for DS portal', }
class crm_logika_export(osv.osv_memory): # orm.TransientModel _name = 'crm.logika.export' _columns = { 'data': fields.binary('File', readonly=True), 'name': fields.char('Filename', size=255, readonly=True), 'state': fields.selection(( ('create', 'create'), ('get', 'get'), ), default='create'), 'delimiter': fields.selection(( (',', ', (comma)'), (';', '; (semicolon)'), ('\t', '(tab)'), ), default=';'), 'quotation': fields.selection(( ('"', '"'), ("'", "'"), ('none', '(none)'), ), default='none'), 'encoding': fields.selection((('utf-8', 'utf-8'), ('utf-8-sig', 'utf-8 with BOM'), ("windows-1250", "windows-1250")), default='utf-8'), 'decimal': fields.selection((('.', '. (dot)'), (',', ', (comma)')), default=','), } def _quotation(self): return self.form['quotation'] def _delimiter(self): return self.form['delimiter'] def _encoding(self): return self.form['encoding'] def _decimal(self): return self.form['decimal'] def _quoted(self, text): q = self._quotation() if q == 'none': return str(text) else: return '{1}{0}{1}'.format(text, q) def _reformat_date(self, date): dd = date[8:10] mm = date[5:7] yyyy = date[0:4] return '{}.{}.{}'.format(dd, mm, yyyy) def _document(self, cr, uid, id, context=None): active_model = context.get('active_model', None) active_id = id invoice_obj = self.pool.get(active_model).browse(cr, uid, id, context=context) invoice = invoice_obj.browse(active_id) # A: Header - Vrijednost 1 obavezna u svakom retku invoice_data = [self._quoted('1')] # B: Alt. broj - Alternativni broj računa (broj za Total se generira automatski) invoice_number = invoice.internal_invoice_number invoice_data.append(self._quoted(invoice_number)) # C: Datum - Datum računa invoice_data.append( self._quoted(self._reformat_date(invoice.date_invoice))) # D: Datum isporuke - Datum isporuke tj- datum otpreme # invoice_data.append(self._quoted(self._reformat_date(invoice.date_delivery))) # neće se više koristiti invoice_data.append(self._quoted('')) # šalje se prazno polje # E: Rok plaćanja - Rok plaćanja u danima date_format = '%Y-%m-%d' dd = datetime.strptime(invoice.date_due, date_format) di = datetime.strptime(invoice.date_invoice, date_format) date_delta = dd - di if date_delta.days < 0: raise Warning( _("Wrong date in invoice {0}. Due date ({1:%d.%m.%Y}) is prior to the invoice date ({2:%d.%m.%Y})" .format(invoice_number, dd, di))) invoice_data.append(self._quoted(date_delta.days)) # F: Valuta - Šifra valute za račun (191 = HRK itd.) currency_code = { 'EUR': '978', 'HRK': '191', 'USD': '840' }.get(invoice.currency_id.name) invoice_data.append(self._quoted(currency_code)) # G: Tečaj - Tečaj računa (za HRK upisati iznos 1) invoice_data.append(self._quoted(locale.str(invoice.lcy_rate))) # H: Uvodni tekst - Uvodni tekst računa (1000 znakova) invoice_data.append(self._quoted('Invoice description')) # I: Šifra_prodavača - Ne koristimo invoice_data.append(self._quoted('')) # J: Tip računa - 1 = redovni, 2 = avansni invoice_type = 2 if invoice.advance_payment else 1 invoice_data.append(self._quoted(invoice_type)) data = self._delimiter().join(invoice_data) partner_id = invoice.partner_id lines = invoice.invoice_line return (data, invoice_number, invoice.partner_id, lines) def _partner(self, cr, uid, partner, context=None): fields = [] # A: Header - Vrijednost 2 obavezna u svakom retku partner_data = [self._quoted('2')] # B: OIB - OIB partnera prema koje će se pronaći šifra partnera partner_data.append(self._quoted(partner.vat.replace('HR', ''))) # C: Naziv partnera - Naziv partnera (opcionalno) partner_data.append(self._quoted(partner.name)) # D: Poštanski broj - Poštanski broj mjesta partnera (opcionalno) partner_data.append(self._quoted(partner.zip)) # E: Naziv mjesta - Naziv mjesta partnera (opcionalno) partner_data.append(self._quoted(partner.city)) # F: Šifra države - Šifra države partnera (opcionalno) partner_data.append(self._quoted('')) # G: Adresa - Adresa i kućni broj partnera (opcionalno) partner_data.append(self._quoted(partner.street)) data = self._delimiter().join(partner_data) return (data, partner.name) def _items(self, cr, uid, lines, context=None): data = [] for line in lines: # A: Header - Vrijednost 3 obavezna u svakom retku line_data = [self._quoted('3')] # B: Kataloški broj - Kataloški broj artikla - KONTO PRODUKTA će biti šifra!!! line_data.append(self._quoted(line.account_id.code[4:])) # C: Količina - Prodana količina artikla line_data.append(self._quoted(locale.str(line.quantity))) # D: Oznaka stope PDV - 0 = 0%, 2 = 10%, 4 = 25%, 5 = 5% tax_percent = line.invoice_line_tax_id[0].amount * 100 tax_code = { 0: '0', 10: '2', 25: '4', 5: '5' }.get(tax_percent, '-1') line_data.append(self._quoted(tax_code)) # E: Oznaka oslobođ. PDV - Ako nema oslobođenja PDV ostaviti prazno line_data.append(self._quoted('')) # F: Cijena - Veleprodajna cijena prodanog artikla line_data.append(self._quoted(locale.str(line.price_unit))) # G: Rabat - Odobreni rabat line_data.append(self._quoted(locale.str(line.discount))) # H: Opis artikla - Dodatni opis za ovu stavku ako postoji (ako je prefix # opis pregazi naziv iz baze artikala) line_data.append(self._quoted('#' + line.product_id.name)) line_csv = self._delimiter().join(line_data) data.append(line_csv) return '\n'.join(data) def _csv_lines(self, cr, uid, ids, context=None): csv = [] for id in ids: (invoice_data, invoice_number, partner_id, lines) = self._document(cr, uid, id, context) csv.append(invoice_data) (partner_data, partner_name) = self._partner(cr, uid, partner_id, context) csv.append(partner_data) csv.append(self._items(cr, uid, lines, context)) return (csv, invoice_number, partner_name) def _set_decimal_point(self, frm=''): if frm == '.': locale.setlocale(locale.LC_NUMERIC, 'en_US.utf8') elif frm == ',': locale.setlocale(locale.LC_NUMERIC, 'hr_HR.utf8') else: locale.setlocale(locale.LC_ALL, '') # reset to system default def _sort_ids_by_invoice_number(self, cr, uid, ids, context=None): active_model = context.get('active_model', None) sorted_ids = self.pool.get(active_model).search( cr, uid, [('id', 'in', ids)], order='internal_invoice_number', context=context) return sorted_ids def generate_csv(self, cr, uid, ids, context=None): if context is None: context = {} self.form = self.read(cr, uid, ids)[0] active_ids = context.get('active_ids', []) sorted_ids = self._sort_ids_by_invoice_number(cr, uid, active_ids, context=context) self._set_decimal_point(self._decimal()) (csv, invoice, partner) = self._csv_lines(cr, uid, sorted_ids, context) self._set_decimal_point() # reset decimal point to default data = '\n'.join(csv) if len(active_ids) == 1: # ima datoteke se sastoji od broja računa i prvih 10 slova partnera filename = 'invoice_{}_{}.csv'.format( invoice, partner.replace('.', '_').replace(' ', '_')[:10]) else: # ako ima više računa, ime datoteke ima ukupni broj računa filename = 'invoices_{}.csv'.format(len(active_ids)) self.write( cr, uid, ids, { 'data': base64.encodestring(data.encode(self._encoding())), 'name': filename, 'state': 'get' }, context=context) # ovaj dictionary sadrži podatke kao i record 'action_export_opportunity_for_ds_wizard' u xml-u # tako da po povratku iz ove metode opet otvori takav prozor return { 'context': context, 'view_type': 'form', 'view_mode': 'form', 'res_model': 'crm.logika.export', 'res_id': ids[0], 'view_id': False, 'type': 'ir.actions.act_window', 'target': 'new', 'name': 'Export for TOTAL', }
class custom_res_partner(osv.osv): _name = "res.partner" _inherit = 'res.partner' def _x_opportunity_meeting_count(self, cr, uid, ids, field_name, arg, context=None): res = dict( map( lambda x: (x, { 'x_opportunity_count': 0, 'x_meeting_count': 0 }), ids)) # the user may not have access rights for opportunities or meetings try: for partner in self.browse(cr, uid, ids, context): if partner.is_company: operator = 'child_of' else: operator = '=' opp_ids = self.pool['crm.lead'].search( cr, uid, [('partner_id', operator, partner.id), ('type', '=', 'opportunity'), ('probability', '<', '100')], context=context) res[partner.id] = { 'x_opportunity_count': len(opp_ids), 'x_meeting_count': len(partner.x_meeting_ids), } except: pass return res ########## MEDICAL INFO ??? # @api.one # @api.depends('x_poids','x_taille') # def _compute_IMC(self): # if self.x_taille == 0: # self.x_IMC = '0' # else: # self.x_IMC = self.x_poids / ((self.x_taille / 100) * (self.x_taille / 100)) ########## @api.one @api.depends('name', 'x_patient_prenom') def _compute_display_name(self): if self.x_patient_prenom == '': names = [self.name] else: names = [self.name, self.x_patient_prenom] self.display_name = ' '.join(filter(None, names)) _columns = { 'partner_id' : fields.many2one('res.partner','Customer', default=lambda self: self.env.user.partner_id), 'display_name' : fields.char(string='Name', compute='_compute_display_name'), 'x_patient_prenom': fields.char('Prénom', size=16), 'x_patient_sexe': fields.selection(SEXE_SELECTION, string='Sexe'), 'x_convention_type': fields.selection(CONVENTION_SELECTION, string='Protection'), 'x_patient_cafat': fields.char(string='Numéro assuré', size=8, help='Numéro CAFAT du patient'), 'x_is_pro': fields.boolean('is_pro_bool', help="Check if the contact is a professional, otherwise it is a patient"), 'x_compte_type': fields.selection(selection=[('patient', 'Patient'), ('pro', 'Pro')], string='Type compte'), 'dob': fields.date('Date de naissance'), 'age' : fields.integer('Age'), 'x_src_avatar' : fields.binary("x_src_avatar", attachment=True, help="This field holds the image used as avatar for this contact, limited to 1024x1024px"), 'x_medecin_traitant': fields.char('Médecin traitant', size=32), ########## MEDICAL INFO ??? # 'x_groupe_sang': fields.selection(GRP_SANG_SELECTION, string='Groupe sang.'), # 'x_taille': fields.float('Taille (cm)',digits=(4,6)), # 'x_poids': fields.float('Poids (kg)',digits=(4,6)), # 'x_IMC': fields.float(string='IMC', compute='_compute_IMC',digits=(4,6)), ########## # Reprise de CRM 'x_opportunity_ids': fields.one2many('crm.lead', 'partner_id',\ 'Opportunities', domain=[('type', '=', 'opportunity')]), 'x_meeting_ids': fields.one2many('calendar.event', 'x_partner_id', 'Meetings'), 'x_opportunity_count': fields.function(_x_opportunity_meeting_count, string="Opportunity", type='integer', multi='opp_meet'), 'x_meeting_count': fields.function(_x_opportunity_meeting_count, string="# Meetings", type='integer', multi='opp_meet'), } def redirect_partner_form(self, cr, uid, partner_id, context=None): search_view = self.pool.get('ir.model.data').get_object_reference( cr, uid, 'base', 'view_res_partner_filter') _order = 'name, x_patient_prenom' _default = { 'x_patient_sexe': 'masculin', 'x_patient_cafat': '', 'x_is_pro': False, 'x_compte_type': 'pro', 'x_medecin_traitant': ' ', 'x_groupe_sang': '', ########## MEDICAL INFO ??? # 'x_taille': '0,1', # 'x_poids': '0,1', ########## } _sql_constraints = [] ############# Changement Praticien <-> Patient ############# @api.multi def _on_change_compte_type(self, x_compte_type): return {'value': {'x_is_pro': x_compte_type == 'pro'}} ############# Changement de date de naissance ############# @api.onchange('dob') def _onchange_getage_id(self, cr, uid, ids, dob, context=None): current_date = datetime.now() current_year = current_date.year birth_date = parser.parse(dob) current_age = current_year - birth_date.year val = {'age': current_age} return {'value': val} ############# Donne l'image a utiliser comme avatar ############# ############# MODIFY ??? !!! @api.model def _get_default_avatar(self, vals): if getattr(threading.currentThread(), 'testing', False) or self.env.context.get('install_mode'): return False # ------------------ CABINET if self.is_company == True: img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'company_image.png') elif self.x_compte_type == 'pro': if self.x_patient_sexe == 'feminin': img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_medecin_femme.png') else: img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_medecin_homme.png') # ------------------ PATIENTS #----------------------- Adultes elif self.age > 18: if self.x_patient_sexe == 'feminin': img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_femme.png') else: img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_homme.png') #----------------------- Enfants elif self.age > 2: if self.x_patient_sexe == 'feminin': img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_fille.png') else: img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_garcon.png') #----------------------- Bebes elif self.age <= 2: if self.x_patient_sexe == 'feminin': img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_bebe_f.png') else: img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_bebe_g.png') #----------------------- Default else: img_path = openerp.modules.get_module_resource( 'AlloDoc', 'static/src/img', 'avatar_default.png') with open(img_path, 'rb') as f: x_src_avatar = f.read() # return img_avatar return tools.image_resize_image_big(x_src_avatar.encode('base64')) def name_get(self, cr, uid, ids, context=None): if context is None: context = {} if isinstance(ids, (int, long)): ids = [ids] res = [] for record in self.browse(cr, uid, ids, context=context): name = record.display_name or '' if record.parent_id and not record.is_company: if not name and record.type in [ 'invoice', 'delivery', 'other' ]: name = dict( self.fields_get( cr, uid, ['type'], context=context)['type']['selection'])[record.type] name = "%s, %s" % (record.parent_name, name) if context.get('show_address_only'): name = self._display_address(cr, uid, record, without_company=True, context=context) if context.get('show_address'): name = name + "\n" + self._display_address( cr, uid, record, without_company=True, context=context) name = name.replace('\n\n', '\n') name = name.replace('\n\n', '\n') if context.get('show_email') and record.email: name = "%s <%s>" % (name, record.email) if context.get('html_format'): name = name.replace('\n', '<br/>') res.append((record.id, name)) return res # Need to write these lines twice to get result I excepted... # if not, at save, avatar is not updated with value filled in form (_get_default_avatar), # but with values previously stored in DB @api.multi def write(self, vals): vals['x_src_avatar'] = self._get_default_avatar(vals) result = super(custom_res_partner, self).write(vals) vals['x_src_avatar'] = self._get_default_avatar(vals) result = super(custom_res_partner, self).write(vals) return result