# -*- coding: utf-8 -*- # # Copyright 2016 Fabien Bourgeois # # 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 . """ GOLEM Members """ import logging from odoo import models, fields, api, _ from odoo.exceptions import UserError _LOGGER = logging.getLogger(__name__) class ResPartner(models.Model): """ GOLEM Member partner adaptations """ _inherit = 'res.partner' @api.model def _get_default_nationality_id(self): return self.env.ref('base.main_company').country_id nationality_id = fields.Many2one('res.country', 'Nationality', default=_get_default_nationality_id) country_id = fields.Many2one(default=_get_default_nationality_id) # Gender overwriting : no need for 'other' choice gender = fields.Selection([('male', _('Male')), ('female', _('Female'))]) member_id = fields.One2many('golem.member', 'partner_id', 'GOLEM Member', readonly=True) is_member = fields.Boolean('Is member', compute='_compute_is_member') member_number = fields.Char('Member number', related='member_id.number') @api.depends('member_id') def _compute_is_member(self): """ Computes is member """ for partner in self: partner.is_member = len(partner.member_id) > 0 @api.multi def view_member(self): """ Go to member form """ self.ensure_one() if self[0].member_id: return {'type': 'ir.actions.act_window', 'res_model': 'golem.member', 'view_mode': 'form', 'res_id': self[0].member_id.id} @api.multi def create_golem_member(self): """ Member creation from partner form """ self.ensure_one() gm_obj = self.env['golem.member'] gm_obj.create({'partner_id': self[0].id}) class GolemMember(models.Model): """ GOLEM Member model """ _name = 'golem.member' _description = 'GOLEM Member' _inherit = 'mail.thread' _inherits = {'res.partner': 'partner_id'} _sql_constraints = [('golem_member_number_manual_uniq', 'UNIQUE (number_manual)', _('This member number has already been used.'))] partner_id = fields.Many2one('res.partner', required=True, index=True, ondelete='cascade') @api.model def _default_season(self): """ Get default season """ domain = [('is_default', '=', True)] return self.env['golem.season'].search(domain, limit=1) number_name = fields.Char('Member computed name', compute='_compute_number_name') number = fields.Char('Member number', store=True, readonly=True) number_manual = fields.Char('Manual number', size=50, index=True, help='Manual number overwriting automatic ' 'numbering') pictures_agreement = fields.Boolean('Pictures agreement?') opt_out_sms = fields.Boolean('Out of SMS campaigns?', help='If this field has been checked, it ' 'tells that the user refuses to receive SMS') season_ids = fields.Many2many('golem.season', string='Seasons', required=True, default=_default_season, ondelete='restrict') is_current = fields.Boolean('Current user?', default=False, readonly=True, store=True, compute='compute_is_current') is_number_manual = fields.Boolean('Is number manual?', store=False, compute='_compute_is_number_manual') image_permission = fields.Boolean('Image permission?', default=True) currency_id = fields.Many2one('res.currency', compute='_get_company_currency', string="Currency") @api.one def _get_company_currency(self): if self.company_id: self.currency_id = self.sudo().company_id.currency_id else: self.currency_id = self.env.user.company_id.currency_id @api.onchange('country_id') def _onchange_country_id(self): member = self[0] if member.country_id: return { 'domain': {'state_id': [('country_id', '=', member.country_id.id)]} } else: return {'domain': {'state_id': []}} @api.depends('number', 'name') def _compute_number_name(self): """ Computes a name composed with number and name """ for member in self: if member.name: member.number_name = u'{} - {}'.format(member.number, member.name) else: member.number_name = u'' @api.multi @api.depends('season_ids') def compute_is_current(self): """ Computes is current according to seasons """ default_s = self._default_season() for member in self: member.is_current = default_s in member.season_ids @api.multi @api.depends('number') def _compute_is_number_manual(self): conf = self.env['ir.config_parameter'] is_num_man = (conf.get_param('golem_numberconfig_isautomatic') == '0') self.write({'is_number_manual': is_num_man}) @api.multi def generate_number_perseason(self): """ Number generation in case of per season configuration """ res = None conf = self.env['ir.config_parameter'] member_number_obj = self.env['golem.member.number'] for member in self: for season in member.season_ids: domain = ['&', ('member_id', '=', member.id), ('season_id', '=', season.id)] member_num = member_number_obj.search(domain) if not member_num: season.write({'member_counter': season.member_counter}) pkey = 'golem_numberconfig_prefix' pfx = conf.get_param(pkey, '') number = u'{}{}'.format(pfx, unicode(season.member_counter)) data = {'member_id': member.id, 'season_id': season.id, 'number': number} member_num = member_number_obj.create(data) season.member_counter += 1 if season.is_default: res = member_num.number return res @api.multi def generate_number_global(self): """ Number generation in case of global configuration """ self.ensure_one() conf = self.env['ir.config_parameter'] domain = ['&', ('member_id', '=', self[0].id), ('season_id', '=', None)] member_number_obj = self.env['golem.member.number'] member_num = member_number_obj.search(domain) if not member_num: last = int(conf.get_param('golem_number_counter', 1)) pfx = conf.get_param('golem_numberconfig_prefix', '') number = pfx + str(last) data = {'member_id': self[0].id, 'season_id': None, 'number': number} member_num = member_number_obj.create(data) last += 1 conf.set_param('golem_number_counter', str(last)) else: member_num = member_num[0] return member_num.number @api.multi def generate_number(self): """ Computes number according to pre-existing number and chosen seasons """ conf = self.env['ir.config_parameter'] isauto = conf.get_param('golem_numberconfig_isautomatic') == '1' isperseason = conf.get_param('golem_numberconfig_isperseason') == '1' isfornew = conf.get_param('golem_numberconfig_isfornewmembersonly') == '1' for member in self: if not isauto or (isfornew and member.number_manual): member.number = member.number_manual else: if isperseason: member.number = member.generate_number_perseason() else: member.number = member.generate_number_global() @api.model def create(self, values): """ Number generation after creation """ new_member = super(GolemMember, self).create(values) new_member.generate_number() return new_member @api.multi def write(self, values): """ Number generation after updates """ res = super(GolemMember, self).write(values) if 'season_ids' in values or 'number_manual' in values: self.generate_number() return res class GolemMemberNumber(models.Model): """ GOLEM Member Numbers """ _name = 'golem.member.number' _description = 'GOLEM Member Numbers' name = fields.Char('Name', compute='_compute_name') member_id = fields.Many2one('golem.member', string='Member', index=True, required=True, ondelete='cascade', auto_join=True) season_id = fields.Many2one('golem.season', string='Season', index=True, auto_join=True) number = fields.Char('Number', index=True, readonly=True) @api.multi @api.depends('season_id') def _compute_name(self): for number in self: number.name = number.season_id.name class GolemNumberConfig(models.TransientModel): """ Configuration for number computing """ _name = 'golem.member.numberconfig' _description = 'Configuration for number computing' @api.model def _default_is_automatic(self): conf = self.env['ir.config_parameter'] return conf.get_param('golem_numberconfig_isautomatic', '1') @api.model def _default_is_per_season(self): conf = self.env['ir.config_parameter'] return conf.get_param('golem_numberconfig_isperseason', '0') @api.model def _default_prefix(self): conf = self.env['ir.config_parameter'] return conf.get_param('golem_numberconfig_prefix', '') is_automatic = fields.Selection([('1', _('Yes')), ('0', _('No'))], string='Computed automatically?', default=_default_is_automatic) is_per_season = fields.Selection([('1', _('Yes')), ('0', _('No'))], string='Per season number?', default=_default_is_per_season) prefix = fields.Char('Optional prefix', default=_default_prefix) number_from = fields.Integer('First number', default=1, help='Number starting from, default to 1') @api.multi def apply_config(self): """ Apply new configuration """ self.ensure_one() conf = self.env['ir.config_parameter'] conf.set_param('golem_numberconfig_isautomatic', self.is_automatic) conf.set_param('golem_numberconfig_isperseason', self.is_per_season) conf.set_param('golem_numberconfig_prefix', self.prefix or '') if self.number_from: _LOGGER.warning('New number_from %s', self.number_from) conf.set_param('golem_number_counter', unicode(self.number_from)) self.env['golem.season'].search([]).write({ 'member_counter': self.number_from }) @api.multi def apply_nocompute(self): """ Apply new configuration only for new members (keep old numbers) """ self.ensure_one() self.apply_config() conf = self.env['ir.config_parameter'] conf.set_param('golem_numberconfig_isfornewmembersonly', '1') @api.multi def apply_recompute(self): """ Recomputes all member numbers according to new configuration """ self.ensure_one() self.apply_config() conf = self.env['ir.config_parameter'] conf.set_param('golem_numberconfig_isfornewmembersonly', '0') self.env['golem.member.number'].search([]).unlink() self.env['golem.season'].search([]).write({ 'member_counter': int(self.number_from) }) self.env['golem.member'].search([]).generate_number() class MergePartnerAutomatic(models.TransientModel): """ Merge Partner Automatic adaptations """ _inherit = 'base.partner.merge.automatic.wizard' @api.multi def action_merge(self): """ Merge adaptations : warn if there is a member """ for merge in self: for partner in merge.partner_ids: if partner.member_id: emsg = _('GOLEM Members merge has not been implemented yet. ' 'Please only merge partners, not members, or delete ' 'GOLEM Members manually before merging.') raise UserError(emsg) return super(MergePartnerAutomatic, self).action_merge()