|
|
# -*- coding: utf-8 -*-
# Author: Nicolas Bessi. Copyright Camptocamp SA # Copyright (C) # 2014: Agile Business Group (<http://www.agilebg.com>) # 2015: Grupo ESOC <www.grupoesoc.es> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as # published by the Free Software Foundation, either version 3 of the # License, or (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Affero General Public License for more details. # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging from openerp import api, fields, models from . import exceptions
_logger = logging.getLogger(__name__)
class ResPartner(models.Model): """Adds last name and first name; name becomes a stored function field.""" _inherit = 'res.partner'
firstname = fields.Char("First name") lastname = fields.Char("Last name") name = fields.Char( compute="_compute_name", inverse="_inverse_name_after_cleaning_whitespace", required=False, store=True)
@api.model def create(self, vals): """Add inverted names at creation if unavailable.""" if "name" in vals: inverted = self._get_inverse_name( vals.get("name"), vals.get("is_company", self.default_get(["is_company"])["is_company"]))
for key, value in inverted.iteritems(): if not vals.get(key): vals[key] = value
return super(ResPartner, self).create(vals)
@api.model def default_get(self, fields_list): """Invert name when getting default values.""" result = super(ResPartner, self).default_get(fields_list)
inverted = self._get_inverse_name( result.get("name", ""), result.get("is_company", False))
for field in inverted.keys(): if field in fields_list: result[field] = inverted.get(field)
return result
@api.model def _get_computed_name(self, lastname, firstname): """Compute the 'name' field according to splitted data.
You can override this method to change the order of lastname and firstname the computed name"""
return u" ".join((p for p in (lastname, firstname) if p))
@api.one @api.depends("firstname", "lastname") def _compute_name(self): """Write the 'name' field according to splitted data.""" self.name = self._get_computed_name(self.lastname, self.firstname)
@api.one def _inverse_name_after_cleaning_whitespace(self): """Clean whitespace in :attr:`~.name` and split it.
Removes leading, trailing and duplicated whitespace.
The splitting logic is stored separately in :meth:`~._inverse_name`, so submodules can extend that method and get whitespace cleaning for free. """
# Remove unneeded whitespace clean = u" ".join(self.name.split(None)) if self.name else self.name
# Clean name avoiding infinite recursion if self.name != clean: self.name = clean
# Save name in the real fields else: self._inverse_name()
@api.model def _get_inverse_name(self, name, is_company=False): """Compute the inverted name.
- If the partner is a company, save it in the lastname. - Otherwise, make a guess.
This method can be easily overriden by other submodules. You can also override this method to change the order of name's attributes
When this method is called, :attr:`~.name` already has unified and trimmed whitespace. """
# Company name goes to the lastname if is_company or not name: parts = [name or False, False] # Guess name splitting else: parts = name.split(" ", 1) while len(parts) < 2: parts.append(False) return {"lastname": parts[0], "firstname": parts[1]}
@api.one def _inverse_name(self): """Try to revert the effect of :meth:`._compute_name`.""" parts = self._get_inverse_name(self.name, self.is_company) self.lastname, self.firstname = parts["lastname"], parts["firstname"]
@api.one @api.constrains("firstname", "lastname") def _check_name(self): """Ensure at least one name is set.""" if not (self.firstname or self.lastname): raise exceptions.EmptyNamesError(self)
@api.one @api.onchange("firstname", "lastname") def _onchange_subnames(self): """Avoid recursion when the user changes one of these fields.
This forces to skip the :attr:`~.name` inversion when the user is setting it in a not-inverted way. """
# Modify self's context without creating a new Environment. # See https://github.com/odoo/odoo/issues/7472#issuecomment-119503916. self.env.context = self.with_context(skip_onchange=True).env.context
@api.one @api.onchange("name") def _onchange_name(self): """Ensure :attr:`~.name` is inverted in the UI.""" if self.env.context.get("skip_onchange"): # Do not skip next onchange self.env.context = ( self.with_context(skip_onchange=False).env.context) else: self._inverse_name_after_cleaning_whitespace()
@api.model def _install_partner_firstname(self): """Save names correctly in the database.
Before installing the module, field ``name`` contains all full names. When installing it, this method parses those names and saves them correctly into the database. This can be called later too if needed. """
# Find records with empty firstname and lastname records = self.search([("firstname", "=", False), ("lastname", "=", False)])
# Force calculations there records._inverse_name() _logger.info("%d partners updated installing module.", len(records))
|