diff --git a/addons/account/data/invoice_action_data.xml b/addons/account/data/invoice_action_data.xml index 37cd08e6837..458302fd233 100644 --- a/addons/account/data/invoice_action_data.xml +++ b/addons/account/data/invoice_action_data.xml @@ -21,7 +21,7 @@ % set access_url = access_action['type'] == 'ir.actions.act_url' and access_action['url'] or '/report/pdf/account.report_invoice/' + str(object.id)

Dear -% if object.partner_id.company_type == 'company' and object.child_ids: +% if object.partner_id.is_company and object.child_ids: ${object.partner_id.child_ids[0].name} % else : ${object.partner_id.name} diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py index 7a82962f6ec..ff79875cd28 100644 --- a/addons/account/models/account_invoice.py +++ b/addons/account/models/account_invoice.py @@ -452,8 +452,8 @@ class AccountInvoice(models.Model): res_dom = [('res_id', '=', 'res.partner,%s' % partner_id)] rec_prop = prop.search(rec_dom + res_dom) or prop.search(rec_dom) pay_prop = prop.search(pay_dom + res_dom) or prop.search(pay_dom) - rec_account = rec_prop.get_by_record(rec_prop) - pay_account = pay_prop.get_by_record(pay_prop) + rec_account = rec_prop.get_by_record() + pay_account = pay_prop.get_by_record() if not rec_account and not pay_account: action = self.env.ref('account.action_account_config') msg = _('Cannot find a chart of accounts for this company, You should configure it. \nPlease go to Account Configuration.') diff --git a/addons/account/views/report_overdue.xml b/addons/account/views/report_overdue.xml index d92a5c8c67d..668cdc790b3 100644 --- a/addons/account/views/report_overdue.xml +++ b/addons/account/views/report_overdue.xml @@ -6,7 +6,7 @@


- +

diff --git a/addons/base_setup/res_config.py b/addons/base_setup/res_config.py index 86378f86430..fa017effdab 100644 --- a/addons/base_setup/res_config.py +++ b/addons/base_setup/res_config.py @@ -42,7 +42,7 @@ class base_config_settings(osv.osv_memory): 'target': 'current', } - def get_default_company_share_partner(self, cr, uid, ids, fields, context=None): + def get_default_company_share_partner(self, cr, uid, fields, context=None): partner_rule = self.pool['ir.model.data'].xmlid_to_object(cr, uid, 'base.res_partner_rule', context=context) return { 'company_share_partner': not bool(partner_rule.active) diff --git a/addons/crm/crm_lead.py b/addons/crm/crm_lead.py index 18c5fa637f6..252a0c77a96 100644 --- a/addons/crm/crm_lead.py +++ b/addons/crm/crm_lead.py @@ -9,7 +9,7 @@ from werkzeug import url_encode from openerp import SUPERUSER_ID from openerp import tools, api -from openerp.addons.base.res.res_partner import format_address +from openerp.addons.base.res.res_partner import FormatAddress from openerp.addons.crm import crm_stage from openerp.osv import fields, osv from openerp.tools.translate import _ @@ -51,7 +51,7 @@ CRM_LEAD_FIELDS_TO_MERGE = ['name', 'partner_name'] -class crm_lead(format_address, osv.osv): +class crm_lead(FormatAddress, osv.osv): """ CRM Lead Case """ _name = "crm.lead" _description = "Lead/Opportunity" diff --git a/addons/crm/res_config.py b/addons/crm/res_config.py index c5622dbb9bd..fa12c752a45 100644 --- a/addons/crm/res_config.py +++ b/addons/crm/res_config.py @@ -43,7 +43,7 @@ class crm_configuration(osv.TransientModel): alias_id = alias_ids and alias_ids[0] or False return alias_id - def get_default_generate_sales_team_alias(self, cr, uid, ids, context=None): + def get_default_generate_sales_team_alias(self, cr, uid, fields, context=None): return {'generate_sales_team_alias': self.pool['ir.values'].get_default( cr, uid, 'sales.config.settings', 'generate_sales_team_alias')} @@ -51,7 +51,7 @@ class crm_configuration(osv.TransientModel): config_value = self.browse(cr, uid, ids, context=context).generate_sales_team_alias self.pool['ir.values'].set_default(cr, uid, 'sales.config.settings', 'generate_sales_team_alias', config_value) - def get_default_alias_prefix(self, cr, uid, ids, context=None): + def get_default_alias_prefix(self, cr, uid, fields, context=None): alias_name = False alias_id = self._find_default_lead_alias_id(cr, uid, context=context) if alias_id: diff --git a/addons/google_calendar/res_config.py b/addons/google_calendar/res_config.py index e890a04bad9..412f66122cd 100644 --- a/addons/google_calendar/res_config.py +++ b/addons/google_calendar/res_config.py @@ -10,16 +10,15 @@ class calendar_config_settings(osv.TransientModel): 'server_uri': fields.char('URI for tuto') } - def set_calset(self,cr,uid,ids,context=None) : + def set_calset(self, cr, uid, ids, context=None) : params = self.pool['ir.config_parameter'] - myself = self.browse(cr,uid,ids[0],context=context) + myself = self.browse(cr, uid, ids[0], context=context) params.set_param(cr, uid, 'google_calendar_client_id', (myself.cal_client_id or '').strip(), groups=['base.group_system'], context=None) params.set_param(cr, uid, 'google_calendar_client_secret', (myself.cal_client_secret or '').strip(), groups=['base.group_system'], context=None) - def get_default_all(self,cr,uid,ids,context=None): + def get_default_all(self, cr, uid, fields, context=None): params = self.pool.get('ir.config_parameter') - cal_client_id = params.get_param(cr, uid, 'google_calendar_client_id',default='',context=context) cal_client_secret = params.get_param(cr, uid, 'google_calendar_client_secret',default='',context=context) server_uri= "%s/google_account/authentication" % params.get_param(cr, uid, 'web.base.url',default="http://yourcompany.odoo.com",context=context) diff --git a/addons/hr_equipment/models/res_config.py b/addons/hr_equipment/models/res_config.py index f3acb8d1b93..a029e45eab7 100644 --- a/addons/hr_equipment/models/res_config.py +++ b/addons/hr_equipment/models/res_config.py @@ -11,8 +11,8 @@ class HrEquipmentConfigSettings(models.TransientModel): equipment_alias_prefix = fields.Char('Use the following alias to report internal equipment issue') alias_domain = fields.Char("Alias Domain") - @api.multi - def get_default_alias_equipment(self): + @api.model + def get_default_alias_equipment(self, fields): alias_name = False alias_id = self.env.ref('hr_equipment.mail_alias_equipment') if alias_id: @@ -29,8 +29,8 @@ class HrEquipmentConfigSettings(models.TransientModel): alias_id.write({'alias_name': record.equipment_alias_prefix}) return True - @api.multi - def get_default_alias_domain(self): + @api.model + def get_default_alias_domain(self, fields): alias_domain = self.env['ir.config_parameter'].get_param("mail.catchall.domain") if not alias_domain: domain = self.env["ir.config_parameter"].get_param("web.base.url") diff --git a/addons/mail/models/res_config.py b/addons/mail/models/res_config.py index c0b36437222..d413f03f0e5 100644 --- a/addons/mail/models/res_config.py +++ b/addons/mail/models/res_config.py @@ -15,15 +15,15 @@ class BaseConfiguration(models.TransientModel): alias_domain = fields.Char('Alias Domain', help="If you have setup a catch-all email domain redirected to " "the Odoo server, enter the domain name here.") - @api.multi - def get_default_fail_counter(self): + @api.model + def get_default_fail_counter(self, fields): previous_date = datetime.datetime.now() - datetime.timedelta(days=30) return { 'fail_counter': self.env['mail.mail'].sudo().search_count([('date', '>=', previous_date.strftime(tools.DEFAULT_SERVER_DATETIME_FORMAT)), ('state', '=', 'exception')]), } - @api.multi - def get_default_alias_domain(self): + @api.model + def get_default_alias_domain(self, fields): alias_domain = self.env["ir.config_parameter"].get_param("mail.catchall.domain", default=None) if alias_domain is None: domain = self.env["ir.config_parameter"].get_param("web.base.url") diff --git a/addons/purchase/data/mail_template_data.xml b/addons/purchase/data/mail_template_data.xml index e8324d89540..c913586dace 100644 --- a/addons/purchase/data/mail_template_data.xml +++ b/addons/purchase/data/mail_template_data.xml @@ -15,7 +15,7 @@ ${object.partner_id.lang} Dear -% if object.partner_id.company_type == 'company' and object.child_ids: +% if object.partner_id.is_company and object.child_ids: ${object.partner_id.child_ids[0].name} % else : ${object.partner_id.name} @@ -51,7 +51,7 @@ from ${object.company_id.name}. ${object.partner_id.lang} Dear -% if object.partner_id.company_type == 'company' and object.child_ids: +% if object.partner_id.is_company and object.child_ids: ${object.partner_id.child_ids[0].name} % else : ${object.partner_id.name} diff --git a/addons/sale/data/mail_template_data.xml b/addons/sale/data/mail_template_data.xml index f6a9421e8ad..474a5d83c5f 100644 --- a/addons/sale/data/mail_template_data.xml +++ b/addons/sale/data/mail_template_data.xml @@ -21,7 +21,7 @@ % set access_url = is_online and access_action['url'] or '/report/pdf/sale.report_saleorder/' + str(object.id)

Dear -% if object.partner_id.company_type == 'company' and object.child_ids: +% if object.partner_id.is_company and object.child_ids: ${object.partner_id.child_ids[0].name} % else : ${object.partner_id.name} diff --git a/openerp/addons/base/res/__init__.py b/openerp/addons/base/res/__init__.py index 94cafaff28a..a43bcf80462 100644 --- a/openerp/addons/base/res/__init__.py +++ b/openerp/addons/base/res/__init__.py @@ -11,5 +11,4 @@ import res_font import res_company import res_users import res_request -import res_lang import ir_property diff --git a/openerp/addons/base/res/ir_property.py b/openerp/addons/base/res/ir_property.py index 813ed437d02..60cc18698f7 100644 --- a/openerp/addons/base/res/ir_property.py +++ b/openerp/addons/base/res/ir_property.py @@ -2,16 +2,9 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from operator import itemgetter -import time -from openerp import models, api -from openerp.osv import osv, orm, fields -from openerp.tools.misc import attrgetter -from openerp.exceptions import UserError - -# ------------------------------------------------------------------------- -# Properties -# ------------------------------------------------------------------------- +from odoo import api, fields, models, _ +from odoo.exceptions import UserError TYPE2FIELD = { 'char': 'value_text', @@ -26,44 +19,37 @@ TYPE2FIELD = { 'selection': 'value_text', } -class ir_property(osv.osv): + +class Property(models.Model): _name = 'ir.property' - _columns = { - 'name': fields.char('Name', select=1), + name = fields.Char(index=True) + res_id = fields.Char(string='Resource', index=True, help="If not set, acts as a default value for new resources",) + company_id = fields.Many2one('res.company', string='Company', index=True) + fields_id = fields.Many2one('ir.model.fields', string='Field', ondelete='cascade', required=True, index=True) + value_float = fields.Float(string='Value') + value_integer = fields.Integer(string='Value') + value_text = fields.Text(string='Value') # will contain (char, text) + value_binary = fields.Binary(string='Value') + value_reference = fields.Char(string='Value') + value_datetime = fields.Datetime(string='Value') + type = fields.Selection([('char', 'Char'), + ('float', 'Float'), + ('boolean', 'Boolean'), + ('integer', 'Integer'), + ('text', 'Text'), + ('binary', 'Binary'), + ('many2one', 'Many2One'), + ('date', 'Date'), + ('datetime', 'DateTime'), + ('selection', 'Selection'), + ], + required=True, + default='many2one', + index=True) - 'res_id': fields.char('Resource', help="If not set, acts as a default value for new resources", select=1), - 'company_id': fields.many2one('res.company', 'Company', select=1), - 'fields_id': fields.many2one('ir.model.fields', 'Field', ondelete='cascade', required=True, select=1), - - 'value_float' : fields.float('Value'), - 'value_integer' : fields.integer('Value'), - 'value_text' : fields.text('Value'), # will contain (char, text) - 'value_binary' : fields.binary('Value'), - 'value_reference': fields.char('Value'), - 'value_datetime' : fields.datetime('Value'), - - 'type' : fields.selection([('char', 'Char'), - ('float', 'Float'), - ('boolean', 'Boolean'), - ('integer', 'Integer'), - ('text', 'Text'), - ('binary', 'Binary'), - ('many2one', 'Many2One'), - ('date', 'Date'), - ('datetime', 'DateTime'), - ('selection', 'Selection'), - ], - 'Type', - required=True, - select=1), - } - - _defaults = { - 'type': 'many2one', - } - - def _update_values(self, cr, uid, ids, values): + @api.multi + def _update_values(self, values): value = values.pop('value', None) if not value: return values @@ -71,8 +57,8 @@ class ir_property(osv.osv): prop = None type_ = values.get('type') if not type_: - if ids: - prop = self.browse(cr, uid, ids[0]) + if self: + prop = self[0] type_ = prop.type else: type_ = self._defaults['type'] @@ -82,7 +68,7 @@ class ir_property(osv.osv): raise UserError(_('Invalid type')) if field == 'value_reference': - if isinstance(value, orm.BaseModel): + if isinstance(value, models.BaseModel): value = '%s,%d' % (value._name, value.id) elif isinstance(value, (int, long)): field_id = values.get('fields_id') @@ -91,68 +77,69 @@ class ir_property(osv.osv): raise ValueError() field_id = prop.fields_id else: - field_id = self.pool.get('ir.model.fields').browse(cr, uid, field_id) + field_id = self.env['ir.model.fields'].browse(field_id) value = '%s,%d' % (field_id.relation, value) values[field] = value return values - def write(self, cr, uid, ids, values, context=None): - return super(ir_property, self).write(cr, uid, ids, self._update_values(cr, uid, ids, values), context=context) + @api.multi + def write(self, values): + return super(Property, self).write(self._update_values(values)) - def create(self, cr, uid, values, context=None): - return super(ir_property, self).create(cr, uid, self._update_values(cr, uid, None, values), context=context) + @api.model + def create(self, values): + return super(Property, self).create(self._update_values(values)) + @api.v7 def get_by_record(self, cr, uid, record, context=None): - if record.type in ('char', 'text', 'selection'): - return record.value_text - elif record.type == 'float': - return record.value_float - elif record.type == 'boolean': - return bool(record.value_integer) - elif record.type == 'integer': - return record.value_integer - elif record.type == 'binary': - return record.value_binary - elif record.type == 'many2one': - if not record.value_reference: + return Property.get_by_record(self.browse(cr, uid, record.id, context=context)) + + @api.v8 + def get_by_record(self): + self.ensure_one() + if self.type in ('char', 'text', 'selection'): + return self.value_text + elif self.type == 'float': + return self.value_float + elif self.type == 'boolean': + return bool(self.value_integer) + elif self.type == 'integer': + return self.value_integer + elif self.type == 'binary': + return self.value_binary + elif self.type == 'many2one': + if not self.value_reference: return False - model, resource_id = record.value_reference.split(',') - value = self.pool[model].browse(cr, uid, int(resource_id), context=context) - return value.exists() - elif record.type == 'datetime': - return record.value_datetime - elif record.type == 'date': - if not record.value_datetime: + model, resource_id = self.value_reference.split(',') + return self.env[model].browse(int(resource_id)).exists() + elif self.type == 'datetime': + return self.value_datetime + elif self.type == 'date': + if not self.value_datetime: return False - return time.strftime('%Y-%m-%d', time.strptime(record.value_datetime, '%Y-%m-%d %H:%M:%S')) + return fields.Date.to_string(fields.Datetime.from_string(self.value_datetime)) return False - def get(self, cr, uid, name, model, res_id=False, context=None): - domain = self._get_domain(cr, uid, name, model, context=context) + @api.model + def get(self, name, model, res_id=False): + domain = self._get_domain(name, model) if domain is not None: domain = [('res_id', '=', res_id)] + domain #make the search with company_id asc to make sure that properties specific to a company are given first - nid = self.search(cr, uid, domain, limit=1, order='company_id asc', context=context) - if not nid: return False - record = self.browse(cr, uid, nid[0], context=context) - return self.get_by_record(cr, uid, record, context=context) + prop = self.search(domain, limit=1, order='company_id') + if prop: + return prop.get_by_record() return False - def _get_domain(self, cr, uid, prop_name, model, context=None): - context = context or {} - cr.execute('select id from ir_model_fields where name=%s and model=%s', (prop_name, model)) - res = cr.fetchone() + def _get_domain(self, prop_name, model): + self._cr.execute("SELECT id FROM ir_model_fields WHERE name=%s AND model=%s", (prop_name, model)) + res = self._cr.fetchone() if not res: return None - - cid = context.get('force_company') - if not cid: - company = self.pool.get('res.company') - cid = company._company_default_get(cr, uid, model, res[0], context=context) - - return [('fields_id', '=', res[0]), ('company_id', 'in', [cid, False])] + company_id = self._context.get('force_company') or self.env['res.company']._company_default_get(model, res[0]).id + return [('fields_id', '=', res[0]), ('company_id', 'in', [company_id, False])] @api.model def get_multi(self, name, model, ids): @@ -179,7 +166,7 @@ class ir_property(osv.osv): # for a given res_id, take the first property only id = refs.pop(prop.res_id, None) if id is not None: - result[id] = self.get_by_record(prop) + result[id] = prop.get_by_record() # set the default value to the ids that are not in result default_value = result.pop(False, False) @@ -223,7 +210,7 @@ class ir_property(osv.osv): value = clean(values[id]) if value == default_value: prop.unlink() - elif value != clean(prop.get_by_record(prop)): + elif value != clean(prop.get_by_record()): prop.write({'value': value}) # create new properties for records that do not have one yet diff --git a/openerp/addons/base/res/res_bank.py b/openerp/addons/base/res/res_bank.py index 31af80d893c..1a9e0aed12a 100644 --- a/openerp/addons/base/res/res_bank.py +++ b/openerp/addons/base/res/res_bank.py @@ -2,15 +2,16 @@ import re -from openerp import api, fields, models, _ -from openerp.osv import expression -from openerp.exceptions import UserError +from odoo import api, fields, models +from odoo.osv import expression + def sanitize_account_number(acc_number): if acc_number: return re.sub(r'\W+', '', acc_number).upper() return False + class Bank(models.Model): _description = 'Bank' _name = 'res.bank' @@ -49,6 +50,7 @@ class Bank(models.Model): banks = self.search(domain + args, limit=limit) return banks.name_get() + class ResPartnerBank(models.Model): _name = 'res.partner.bank' _rec_name = 'acc_number' @@ -70,15 +72,15 @@ class ResPartnerBank(models.Model): ('unique_number', 'unique(sanitized_acc_number)', 'Account Number must be unique'), ] - @api.one @api.depends('acc_number') def _compute_sanitized_acc_number(self): - self.sanitized_acc_number = sanitize_account_number(self.acc_number) + for bank in self: + bank.sanitized_acc_number = sanitize_account_number(bank.acc_number) - @api.one - @api.depends('acc_type') + @api.multi def _compute_acc_type(self): - self.acc_type = 'bank' + for bank in self: + bank.acc_type = 'bank' @api.model def search(self, args, offset=0, limit=None, order=None, count=False): diff --git a/openerp/addons/base/res/res_company.py b/openerp/addons/base/res/res_company.py index 8372acc55d4..602e3c9d0aa 100644 --- a/openerp/addons/base/res/res_company.py +++ b/openerp/addons/base/res/res_company.py @@ -3,224 +3,15 @@ import os import re -import openerp -from openerp import SUPERUSER_ID, tools, api -from openerp.osv import fields, osv -from openerp.tools.translate import _ -from openerp.tools.safe_eval import safe_eval as eval -from openerp.tools import image_resize_image - -class res_company(osv.osv): +from odoo import api, fields, models, tools, _ +from odoo.exceptions import ValidationError + + +class Company(models.Model): _name = "res.company" _description = 'Companies' _order = 'name' - - def _get_address_data(self, cr, uid, ids, field_names, arg, context=None): - """ Read the 'address' functional fields. """ - result = {} - part_obj = self.pool.get('res.partner') - for company in self.browse(cr, uid, ids, context=context): - result[company.id] = {}.fromkeys(field_names, False) - if company.partner_id: - address_data = part_obj.address_get(cr, openerp.SUPERUSER_ID, [company.partner_id.id], adr_pref=['contact']) - if address_data['contact']: - address = part_obj.read(cr, openerp.SUPERUSER_ID, [address_data['contact']], field_names, context=context)[0] - for field in field_names: - result[company.id][field] = address[field] or False - return result - - def _set_address_data(self, cr, uid, company_id, name, value, arg, context=None): - """ Write the 'address' functional fields. """ - company = self.browse(cr, uid, company_id, context=context) - if company.partner_id: - part_obj = self.pool.get('res.partner') - address_data = part_obj.address_get(cr, uid, [company.partner_id.id], adr_pref=['contact']) - address = address_data['contact'] - if address: - part_obj.write(cr, uid, [address], {name: value or False}, context=context) - else: - part_obj.create(cr, uid, {name: value or False, 'parent_id': company.partner_id.id}, context=context) - return True - - def _get_logo_web(self, cr, uid, ids, _field_name, _args, context=None): - result = dict.fromkeys(ids, False) - for record in self.browse(cr, uid, ids, context=context): - size = (180, None) - result[record.id] = image_resize_image(record.partner_id.image, size) - return result - - def _get_companies_from_partner(self, cr, uid, ids, context=None): - return self.pool['res.company'].search(cr, uid, [('partner_id', 'in', ids)], context=context) - - _columns = { - 'name': fields.related('partner_id', 'name', string='Company Name', size=128, required=True, store=True, type='char'), - 'parent_id': fields.many2one('res.company', 'Parent Company', select=True), - 'child_ids': fields.one2many('res.company', 'parent_id', 'Child Companies'), - 'partner_id': fields.many2one('res.partner', 'Partner', required=True), - 'rml_header': fields.text('RML Header', required=True), - 'rml_header1': fields.char('Company Tagline', help="Appears by default on the top right corner of your printed documents (report header)."), - 'rml_header2': fields.text('RML Internal Header', required=True), - 'rml_header3': fields.text('RML Internal Header for Landscape Reports', required=True), - 'rml_footer': fields.text('Report Footer', help="Footer text displayed at the bottom of all reports."), - 'rml_footer_readonly': fields.related('rml_footer', type='text', string='Report Footer', readonly=True), - 'custom_footer': fields.boolean('Custom Footer', help="Check this to define the report footer manually. Otherwise it will be filled in automatically."), - 'font': fields.many2one('res.font', string="Font", domain=[('mode', 'in', ('Normal', 'Regular', 'all', 'Book'))], - help="Set the font into the report header, it will be used as default font in the RML reports of the user company"), - 'logo': fields.related('partner_id', 'image', string="Logo", type="binary"), - # logo_web: do not store in attachments, since the image is retrieved in SQL for - # performance reasons (see addons/web/controllers/main.py, Binary.company_logo) - 'logo_web': fields.function(_get_logo_web, string="Logo Web", type="binary", store={ - 'res.company': (lambda s, c, u, i, x: i, ['partner_id'], 10), - 'res.partner': (_get_companies_from_partner, ['image'], 10), - }), - 'currency_id': fields.many2one('res.currency', 'Currency', required=True), - 'user_ids': fields.many2many('res.users', 'res_company_users_rel', 'cid', 'user_id', 'Accepted Users'), - 'account_no':fields.char('Account No.'), - 'street': fields.function(_get_address_data, fnct_inv=_set_address_data, size=128, type='char', string="Street", multi='address'), - 'street2': fields.function(_get_address_data, fnct_inv=_set_address_data, size=128, type='char', string="Street2", multi='address'), - 'zip': fields.function(_get_address_data, fnct_inv=_set_address_data, size=24, type='char', string="Zip", multi='address'), - 'city': fields.function(_get_address_data, fnct_inv=_set_address_data, size=24, type='char', string="City", multi='address'), - 'state_id': fields.function(_get_address_data, fnct_inv=_set_address_data, type='many2one', relation='res.country.state', string="Fed. State", multi='address'), - 'country_id': fields.function(_get_address_data, fnct_inv=_set_address_data, type='many2one', relation='res.country', string="Country", multi='address'), - 'email': fields.related('partner_id', 'email', size=64, type='char', string="Email", store=True), - 'phone': fields.related('partner_id', 'phone', size=64, type='char', string="Phone", store=True), - 'fax': fields.function(_get_address_data, fnct_inv=_set_address_data, size=64, type='char', string="Fax", multi='address'), - 'website': fields.related('partner_id', 'website', string="Website", type="char", size=64), - 'vat': fields.related('partner_id', 'vat', string="Tax ID", type="char", size=32), - 'company_registry': fields.char('Company Registry', size=64), - 'rml_paper_format': fields.selection([('a4', 'A4'), ('us_letter', 'US Letter')], "Paper Format", required=True, oldname='paper_format'), - } - _sql_constraints = [ - ('name_uniq', 'unique (name)', 'The company name must be unique !') - ] - - @api.onchange('custom_footer', 'phone', 'fax', 'email', 'website', 'vat', 'company_registry') - def onchange_footer(self): - if not self.custom_footer: - # first line (notice that missing elements are filtered out before the join) - res = ' | '.join(filter(bool, [ - self.phone and '%s: %s' % (_('Phone'), self.phone), - self.fax and '%s: %s' % (_('Fax'), self.fax), - self.email and '%s: %s' % (_('Email'), self.email), - self.website and '%s: %s' % (_('Website'), self.website), - self.vat and '%s: %s' % (_('TIN'), self.vat), - self.company_registry and '%s: %s' % (_('Reg'), self.company_registry), - ])) - self.rml_footer_readonly = res - self.rml_footer = res - - def onchange_state(self, cr, uid, ids, state_id, context=None): - if state_id: - return {'value':{'country_id': self.pool.get('res.country.state').browse(cr, uid, state_id, context).country_id.id }} - return {} - - def onchange_font_name(self, cr, uid, ids, font, rml_header, rml_header2, rml_header3, context=None): - """ To change default header style of all and drawstring. """ - - def _change_header(header,font): - """ Replace default fontname use in header and setfont tag """ - - default_para = re.sub('fontName.?=.?".*"', 'fontName="%s"'% font, header) - return re.sub('("%s"\g<3>'% font, default_para) - - if not font: - return True - fontname = self.pool.get('res.font').browse(cr, uid, font, context=context).name - return {'value':{ - 'rml_header': _change_header(rml_header, fontname), - 'rml_header2':_change_header(rml_header2, fontname), - 'rml_header3':_change_header(rml_header3, fontname) - }} - - def on_change_country(self, cr, uid, ids, country_id, context=None): - res = {'domain': {'state_id': []}} - currency_id = self._get_euro(cr, uid, context=context) - if country_id: - currency_id = self.pool.get('res.country').browse(cr, uid, country_id, context=context).currency_id.id - res['domain'] = {'state_id': [('country_id','=',country_id)]} - res['value'] = {'currency_id': currency_id} - return res - - def name_search(self, cr, uid, name='', args=None, operator='ilike', context=None, limit=100): - context = dict(context or {}) - if context.pop('user_preference', None): - # We browse as superuser. Otherwise, the user would be able to - # select only the currently visible companies (according to rules, - # which are probably to allow to see the child companies) even if - # she belongs to some other companies. - user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid, context=context) - cmp_ids = list(set([user.company_id.id] + [cmp.id for cmp in user.company_ids])) - uid = SUPERUSER_ID - args = (args or []) + [('id', 'in', cmp_ids)] - return super(res_company, self).name_search(cr, uid, name=name, args=args, operator=operator, context=context, limit=limit) - - @api.returns('self') - def _company_default_get(self, cr, uid, object=False, field=False, context=None): - """ - Returns the default company (the user's company) - The 'object' and 'field' arguments are ignored but left here for - backward compatibility and potential override. - """ - return self.pool['res.users']._get_company(cr, uid, context=context) - - @tools.ormcache('uid', 'company') - def _get_company_children(self, cr, uid=None, company=None): - if not company: - return [] - ids = self.search(cr, uid, [('parent_id','child_of',[company])]) - return ids - - def _get_partner_hierarchy(self, cr, uid, company_id, context=None): - if company_id: - parent_id = self.browse(cr, uid, company_id)['parent_id'] - if parent_id: - return self._get_partner_hierarchy(cr, uid, parent_id.id, context) - else: - return self._get_partner_descendance(cr, uid, company_id, [], context) - return [] - - def _get_partner_descendance(self, cr, uid, company_id, descendance, context=None): - descendance.append(self.browse(cr, uid, company_id).partner_id.id) - for child_id in self._get_company_children(cr, uid, company_id): - if child_id != company_id: - descendance = self._get_partner_descendance(cr, uid, child_id, descendance) - return descendance - - # - # This function restart the cache on the _get_company_children method - # - def cache_restart(self, cr): - self._get_company_children.clear_cache(self) - - def create(self, cr, uid, vals, context=None): - if not vals.get('name', False) or vals.get('partner_id', False): - self.cache_restart(cr) - return super(res_company, self).create(cr, uid, vals, context=context) - obj_partner = self.pool.get('res.partner') - partner_id = obj_partner.create(cr, uid, {'name': vals['name'], 'is_company':True, 'image': vals.get('logo', False), 'customer': False}, context=context) - vals.update({'partner_id': partner_id}) - self.cache_restart(cr) - company_id = super(res_company, self).create(cr, uid, vals, context=context) - obj_partner.write(cr, uid, [partner_id], {'company_id': company_id}, context=context) - return company_id - - def write(self, cr, uid, ids, values, context=None): - self.cache_restart(cr) - return super(res_company, self).write(cr, uid, ids, values, context=context) - - def _get_euro(self, cr, uid, context=None): - rate_obj = self.pool.get('res.currency.rate') - rate_id = rate_obj.search(cr, uid, [('rate', '=', 1)], context=context) - return rate_id and rate_obj.browse(cr, uid, rate_id[0], context=context).currency_id.id or False - - def _get_logo(self, cr, uid, ids): - return open(os.path.join( tools.config['root_path'], 'addons', 'base', 'res', 'res_company_logo.png'), 'rb') .read().encode('base64') - - def _get_font(self, cr, uid, ids): - font_obj = self.pool.get('res.font') - res = font_obj.search(cr, uid, [('family', '=', 'Helvetica'), ('mode', '=', 'all')], limit=1) - return res and res[0] or False _header = """

@@ -247,19 +38,8 @@ class res_company(osv.osv):
""" _header2 = _header % (539, 772, "1.0cm", "28.3cm", "11.1cm", "28.3cm", "1.0cm 28.1cm 20.1cm 28.1cm") - _header3 = _header % (786, 525, 25, 555, 440, 555, "25 550 818 550") - def _get_header(self,cr,uid,ids): - try : - header_file = tools.file_open(os.path.join('base', 'report', 'corporate_rml_header.rml')) - try: - return header_file.read() - finally: - header_file.close() - except: - return self._header_a4 - _header_main = """
@@ -311,24 +91,249 @@ class res_company(osv.osv): _header_a4 = _header_main % ('21.7cm', '27.7cm', '27.7cm', '27.7cm', '27.8cm', '27.3cm', '25.3cm', '25.0cm', '25.0cm', '24.6cm', '24.6cm', '24.5cm', '24.5cm') _header_letter = _header_main % ('20cm', '26.0cm', '26.0cm', '26.0cm', '26.1cm', '25.6cm', '23.6cm', '23.3cm', '23.3cm', '22.9cm', '22.9cm', '22.8cm', '22.8cm') - def onchange_rml_paper_format(self, cr, uid, ids, rml_paper_format, context=None): - if rml_paper_format == 'us_letter': - return {'value': {'rml_header': self._header_letter}} - return {'value': {'rml_header': self._header_a4}} + def _get_header(self): + try: + header_file = tools.file_open(os.path.join( + 'base', 'report', 'corporate_rml_header.rml')) + try: + return header_file.read() + finally: + header_file.close() + except: + return self._header_a4 - def act_discover_fonts(self, cr, uid, ids, context=None): - return self.pool.get("res.font").font_scan(cr, uid, context=context) + def _get_font(self): + return self.env['res.font'].search([('family', '=', 'Helvetica'), ('mode', '=', 'all')], limit=1) - _defaults = { - 'currency_id': _get_euro, - 'rml_paper_format': 'a4', - 'rml_header':_get_header, - 'rml_header2': _header2, - 'rml_header3': _header3, - 'logo':_get_logo, - 'font':_get_font, - } + def _get_logo(self): + return open(os.path.join(tools.config['root_path'], 'addons', 'base', 'res', 'res_company_logo.png'), 'rb') .read().encode('base64') - _constraints = [ - (osv.osv._check_recursion, 'Error! You can not create recursive companies.', ['parent_id']) + @api.model + def _get_euro(self): + return self.env['res.currency.rate'].search([('rate', '=', 1)], limit=1).currency_id + + name = fields.Char(related='partner_id.name', string='Company Name', required=True, store=True) + parent_id = fields.Many2one('res.company', string='Parent Company', index=True) + child_ids = fields.One2many('res.company', 'parent_id', string='Child Companies') + partner_id = fields.Many2one('res.partner', string='Partner', required=True) + rml_header = fields.Text(required=True, default=_get_header) + rml_header1 = fields.Char(string='Company Tagline', help="Appears by default on the top right corner of your printed documents (report header).") + rml_header2 = fields.Text(string='RML Internal Header', required=True, default=_header2) + rml_header3 = fields.Text(string='RML Internal Header for Landscape Reports', required=True, default=_header3) + rml_footer = fields.Text(string='Report Footer', help="Footer text displayed at the bottom of all reports.") + rml_footer_readonly = fields.Text(related='rml_footer', string='Report Footer', readonly=True) + custom_footer = fields.Boolean(help="Check this to define the report footer manually. Otherwise it will be filled in automatically.") + font = fields.Many2one('res.font', string="Font", default=lambda self: self._get_font(), + domain=[('mode', 'in', ('Normal', 'Regular', 'all', 'Book'))], + help="Set the font into the report header, it will be used as default font in the RML reports of the user company") + logo = fields.Binary(related='partner_id.image', default=_get_logo) + # logo_web: do not store in attachments, since the image is retrieved in SQL for + # performance reasons (see addons/web/controllers/main.py, Binary.company_logo) + logo_web = fields.Binary(compute='_compute_logo_web', store=True) + currency_id = fields.Many2one('res.currency', string='Currency', required=True, default=lambda self: self._get_euro()) + user_ids = fields.Many2many('res.users', 'res_company_users_rel', 'cid', 'user_id', string='Accepted Users') + account_no = fields.Char(string='Account No.') + street = fields.Char(compute='_compute_address', inverse='_inverse_street') + street2 = fields.Char(compute='_compute_address', inverse='_inverse_street2') + zip = fields.Char(compute='_compute_address', inverse='_inverse_zip') + city = fields.Char(compute='_compute_address', inverse='_inverse_city') + state_id = fields.Many2one('res.country.state', compute='_compute_address', inverse='_inverse_state', string="Fed. State") + bank_ids = fields.One2many('res.partner.bank', 'company_id', string='Bank Accounts', help='Bank accounts related to this company') + country_id = fields.Many2one('res.country', compute='_compute_address', inverse='_inverse_country', string="Country") + email = fields.Char(related='partner_id.email', store=True) + phone = fields.Char(related='partner_id.phone', store=True) + fax = fields.Char(compute='_compute_address', inverse='_inverse_fax') + website = fields.Char(related='partner_id.website') + vat = fields.Char(related='partner_id.vat', string="Tax ID") + company_registry = fields.Char() + rml_paper_format = fields.Selection([('a4', 'A4'), ('us_letter', 'US Letter')], string="Paper Format", required=True, default='a4', oldname='paper_format') + + _sql_constraints = [ + ('name_uniq', 'unique (name)', 'The company name must be unique !') ] + + # TODO @api.depends(): currently now way to formulate the dependency on the + # partner's contact address + def _compute_address(self): + for company in self.filtered(lambda company: company.partner_id): + address_data = company.partner_id.sudo().address_get(adr_pref=['contact']) + if address_data['contact']: + partner = company.partner_id.browse(address_data['contact']) + company.street = partner.street + company.street2 = partner.street2 + company.city = partner.city + company.zip = partner.zip + company.state_id = partner.state_id + company.country_id = partner.country_id + company.fax = partner.fax + + def _inverse_street(self): + for company in self: + company.partner_id.street = company.street + + def _inverse_street2(self): + for company in self: + company.partner_id.street2 = company.street2 + + def _inverse_zip(self): + for company in self: + company.partner_id.zip = company.zip + + def _inverse_city(self): + for company in self: + company.partner_id.city = company.city + + def _inverse_state(self): + for company in self: + company.partner_id.state_id = company.state_id + + def _inverse_country(self): + for company in self: + company.partner_id.country_id = company.country_id + + def _inverse_fax(self): + for company in self: + company.partner_id.fax = company.fax + + @api.depends('partner_id', 'partner_id.image') + def _compute_logo_web(self): + for company in self: + company.logo_web = tools.image_resize_image(company.partner_id.image, (180, None)) + + @api.onchange('custom_footer', 'phone', 'fax', 'email', 'website', 'vat', 'company_registry') + def onchange_footer(self): + if not self.custom_footer: + # first line (notice that missing elements are filtered out before the join) + res = ' | '.join(filter(bool, [ + self.phone and '%s: %s' % (_('Phone'), self.phone), + self.fax and '%s: %s' % (_('Fax'), self.fax), + self.email and '%s: %s' % (_('Email'), self.email), + self.website and '%s: %s' % (_('Website'), self.website), + self.vat and '%s: %s' % (_('TIN'), self.vat), + self.company_registry and '%s: %s' % (_('Reg'), self.company_registry), + ])) + self.rml_footer_readonly = res + self.rml_footer = res + + @api.onchange('state_id') + def _onchange_state(self): + self.country_id = self.state_id.country_id + + @api.onchange('font') + def _onchange_font_name(self): + """ To change default header style of all and drawstring. """ + def _change_header(header, font): + """ Replace default fontname use in header and setfont tag """ + default_para = re.sub(r'fontName.?=.?".*"', 'fontName="%s"' % font, header) + return re.sub(r'("%s"\g<3>' % font, default_para) + + if self.font: + fontname = self.font.name + self.rml_header = _change_header(self.rml_header, fontname) + self.rml_header2 = _change_header(self.rml_header2, fontname) + self.rml_header3 = _change_header(self.rml_header3, fontname) + + @api.multi + def on_change_country(self, country_id): + # This function is called from account/models/chart_template.py, hence decorated with `multi`. + self.ensure_one() + currency_id = self._get_euro() + if country_id: + currency_id = self.env['res.country'].browse(country_id).currency_id.id + return {'value': {'currency_id': currency_id}} + + @api.onchange('country_id') + def _onchange_country_id_wrapper(self): + res = {'domain': {'state_id': []}} + if self.country_id: + res['domain']['state_id'] = [('country_id', '=', self.country_id.id)] + values = self.on_change_country(self.country_id.id)['value'] + for fname, value in values.iteritems(): + setattr(self, fname, value) + return res + + @api.model + def name_search(self, name='', args=None, operator='ilike', limit=100): + context = dict(self.env.context) + newself = self + if context.pop('user_preference', None): + # We browse as superuser. Otherwise, the user would be able to + # select only the currently visible companies (according to rules, + # which are probably to allow to see the child companies) even if + # she belongs to some other companies. + companies = self.env.user.company_id + self.env.user.company_ids + args = (args or []) + [('id', 'in', companies.ids)] + newself = newself.sudo() + return super(Company, newself.with_context(context)).name_search(name=name, args=args, operator=operator, limit=limit) + + @api.model + @api.returns('self', lambda value: value.id) + def _company_default_get(self, object=False, field=False): + """ Returns the default company (usually the user's company). + The 'object' and 'field' arguments are ignored but left here for + backward compatibility and potential override. + """ + return self.env['res.users']._get_company() + + @api.model + @tools.ormcache('self.env.uid', 'company') + def _get_company_children(self, company=None): + if not company: + return [] + return self.search([('parent_id', 'child_of', [company])]).ids + + @api.multi + def _get_partner_hierarchy(self): + self.ensure_one() + parent = self.parent_id + if parent: + return parent._get_partner_hierarchy() + else: + return self._get_partner_descendance([]) + + @api.multi + def _get_partner_descendance(self, descendance): + self.ensure_one() + descendance.append(self.partner_id.id) + for child_id in self._get_company_children(self.id): + if child_id != self.id: + descendance = self.browse(child_id)._get_partner_descendance(descendance) + return descendance + + # deprecated, use clear_caches() instead + def cache_restart(self): + self.clear_caches() + + @api.model + def create(self, vals): + if not vals.get('name') or vals.get('partner_id'): + self.clear_caches() + return super(Company, self).create(vals) + partner = self.env['res.partner'].create({'name': vals['name'], 'is_company': True, 'image': vals.get('logo'), 'customer': False}) + vals['partner_id'] = partner.id + self.clear_caches() + company = super(Company, self).create(vals) + partner.write({'company_id': company.id}) + return company + + @api.multi + def write(self, values): + self.clear_caches() + return super(Company, self).write(values) + + @api.onchange('rml_paper_format') + def _onchange_rml_paper_format(self): + if self.rml_paper_format == 'us_letter': + self.rml_header = self._header_letter + else: + self.rml_header = self._header_a4 + + @api.multi + def act_discover_fonts(self): + self.ensure_one() + return self.env["res.font"].font_scan() + + @api.constrains('parent_id') + def _check_parent_id(self): + if not self._check_recursion(): + raise ValidationError(_('Error ! You cannot create recursive companies.')) diff --git a/openerp/addons/base/res/res_company_view.xml b/openerp/addons/base/res/res_company_view.xml index 76180b9b6d4..17bc2a00c0f 100644 --- a/openerp/addons/base/res/res_company_view.xml +++ b/openerp/addons/base/res/res_company_view.xml @@ -30,9 +30,9 @@ - + - +
@@ -65,10 +65,10 @@