# Part of Odoo. See LICENSE file for full copyright and licensing details. from odoo import api, models, fields, _ from odoo.exceptions import UserError, ValidationError import re avs_code_pattern = r'^[0-9]{3}\.[0-9]{3}$' class L10nChSocialInsurance(models.Model): _name = 'l10n.ch.social.insurance' _description = 'Swiss: Social Insurances (AVS, AC)' @api.model def _get_default_avs_line_ids(self): vals = [ (0, 0, { 'date_from': fields.Date.today().replace(month=1, day=1), 'employer_rate': 5.3, 'employee_rate': 5.3, 'admin_fees': 1.2, }) ] return vals @api.model def _get_default_ac_line_ids(self): vals = [ (0, 0, { 'date_from': fields.Date.today().replace(month=1, day=1), 'employer_rate': 1.1, 'employee_rate': 1.1, 'employee_additional_rate': 0, 'employer_additional_rate': 0, }) ] return vals @api.model def _get_default_l10n_ch_avs_rente_ids(self): vals = [ (0, 0, { 'date_from': fields.Date.today().replace(month=1, day=1), 'amount': 1400 }) ] return vals @api.model def _get_default_l10n_ch_avs_ac_threshold_ids(self): vals = [ (0, 0, { 'date_from': fields.Date.today().replace(month=1, day=1), 'amount': 148200 }) ] return vals @api.model def _get_default_l10n_ch_avs_acc_threshold_ids(self): vals = [ (0, 0, { 'date_from': fields.Date.today().replace(month=1, day=1), 'amount': 0 }) ] return vals name = fields.Char(required=True) member_number = fields.Char() member_subnumber = fields.Char() # https://www.swissdec.ch/fileadmin/user_upload/_Datenempfaenger/Empfaengerliste.pdf insurance_code = fields.Char(required=True) avs_line_ids = fields.One2many('l10n.ch.social.insurance.avs.line', 'insurance_id', default=_get_default_avs_line_ids) ac_line_ids = fields.One2many('l10n.ch.social.insurance.ac.line', 'insurance_id', default=_get_default_ac_line_ids) l10n_ch_avs_rente_ids = fields.One2many('l10n.ch.social.insurance.avs.retirement.rente', 'insurance_id', default=_get_default_l10n_ch_avs_rente_ids) l10n_ch_avs_ac_threshold_ids = fields.One2many('l10n.ch.social.insurance.avs.ac.threshold', 'insurance_id', default=_get_default_l10n_ch_avs_ac_threshold_ids) l10n_ch_avs_acc_threshold_ids = fields.One2many('l10n.ch.social.insurance.avs.acc.threshold', 'insurance_id', default=_get_default_l10n_ch_avs_acc_threshold_ids) age_start = fields.Integer(string="Start of the obligation to contribute to the AVS", default=18, required=True) age_stop_male = fields.Integer(string="Start of retirement age for men", default=65, required=True) age_stop_female = fields.Integer(string="Start of retirement age for women", default=64, required=True) laa_insurance_id = fields.Many2one("l10n.ch.accident.insurance", string="Company LAA Insurance") laa_insurance_from = fields.Date(string="LAA: Valid as of") lpp_insurance_id = fields.Many2one("l10n.ch.lpp.insurance", string="Company LPP Insurance") lpp_insurance_from = fields.Date(string="LPP: Valid as of") active = fields.Boolean(default=True) company_id = fields.Many2one("res.company", default=lambda self: self.env.company) no_laa_reason = fields.Char(help="If your company doesn't have a main LAA insurance, state the reason here.") no_lpp_reason = fields.Char(help="If your company doesn't have a main LPP insurance, state the reason here.") @api.constrains('insurance_code') def _check_insurance_code(self): """ Format XXX.XXX with the first bloc greater than 0 """ for record in self: if record.insurance_code: if re.fullmatch(avs_code_pattern, record.insurance_code): if record.insurance_code.split(".")[0] == "000": raise ValidationError(_("AVS Insurance code is not plausible.")) else: raise ValidationError(_("AVS Insurance code is not plausible.")) def _get_avs_rates(self, target): if not self: return 0, 0, 0 for line in self.avs_line_ids: if line.date_from <= target and (not line.date_to or target <= line.date_to): return line.employee_rate, line.employer_rate, line.admin_fees raise UserError(_('No AVS rates found for date %s', target)) def _get_ac_rates(self, target): if not self: return 0, 0 for line in self.ac_line_ids: if line.date_from <= target and (not line.date_to or target <= line.date_to): return line.employee_rate, line.employer_rate raise UserError(_('No AC rates found for date %s', target)) def _get_additional_ac_rates(self, target): if not self: return 0, 0 for line in self.ac_line_ids: if line.date_from <= target and (not line.date_to or target <= line.date_to): return line.employee_additional_rate, line.employer_additional_rate raise UserError(_('No AC rates found for date %s', target)) def _get_retirement_rente(self, target): if not self: return 0.0 for line in self.l10n_ch_avs_rente_ids: if line.date_from <= target and (not line.date_to or target <= line.date_to): return line.amount raise UserError(_('No retirement exoneration amounts found for date date %s', target)) def _get_ac_threshold(self, target): if not self: return 0.0 for line in self.l10n_ch_avs_ac_threshold_ids: if line.date_from <= target and (not line.date_to or target <= line.date_to): return line.amount raise UserError(_('No AC threshold rates found for date %s', target)) def _get_acc_threshold(self, target): if not self: return 0.0 for line in self.l10n_ch_avs_acc_threshold_ids: if line.date_from <= target and (not line.date_to or target <= line.date_to): return line.amount raise UserError(_('No ACC threshold rates found for date %s', target)) class L10nChSocialInsuranceAvsLine(models.Model): _name = 'l10n.ch.social.insurance.avs.line' _description = 'Swiss: Social Insurances - AVS Line' date_from = fields.Date(string="From", required=True) date_to = fields.Date(string="To") insurance_id = fields.Many2one('l10n.ch.social.insurance') employee_rate = fields.Float(string="Employee Rate (%)", digits='Payroll Rate', default=5.3) employer_rate = fields.Float(string="Company Rate (%)", digits='Payroll Rate', default=5.3) admin_fees = fields.Float(string="Administrative Costs (%)", digits='Payroll Rate', default=1.2) class L10nChSocialInsuranceAcLine(models.Model): _name = 'l10n.ch.social.insurance.ac.line' _description = 'Swiss: Social Insurances - AC Line' date_from = fields.Date(string="From", required=True) date_to = fields.Date(string="To") insurance_id = fields.Many2one('l10n.ch.social.insurance') employee_rate = fields.Float(string="Employee Rate (%)", digits='Payroll Rate', default=1.1) employer_rate = fields.Float(string="Company Rate (%)", digits='Payroll Rate', default=1.1) employee_additional_rate = fields.Float(string="Employee Additional Rate (%)", digits='Payroll Rate', default=0) employer_additional_rate = fields.Float(string="Company Additional Rate (%)", digits='Payroll Rate', default=0) class L10nChSocialInsuranceAvsRetirementRente(models.Model): _name = 'l10n.ch.social.insurance.avs.retirement.rente' _description = 'Swiss: Retired Employees Exoneration' date_from = fields.Date(string="From", required=True) date_to = fields.Date(string="To") insurance_id = fields.Many2one('l10n.ch.social.insurance') amount = fields.Float(string="Amount", default=1400) class L10nChSocialInsuranceAvsAcThreshold(models.Model): _name = 'l10n.ch.social.insurance.avs.ac.threshold' _description = 'Swiss: AC: Rate Threshold' date_from = fields.Date(string="From", required=True) date_to = fields.Date(string="To") insurance_id = fields.Many2one('l10n.ch.social.insurance') amount = fields.Float(string="Amount", default=148200) class L10nChSocialInsuranceAvsAccThreshold(models.Model): _name = 'l10n.ch.social.insurance.avs.acc.threshold' _description = 'Swiss: ACC: Rate Threshold' date_from = fields.Date(string="From", required=True) date_to = fields.Date(string="To") insurance_id = fields.Many2one('l10n.ch.social.insurance') amount = fields.Float(string="Amount", default=370500)