diff --git a/__manifest__.py b/__manifest__.py index 3c94d6b7fcf96213a024f4a877635154552a8f02..09e96df5398bb489d9cb21320540f9bbce31175a 100755 --- a/__manifest__.py +++ b/__manifest__.py @@ -25,6 +25,8 @@ "views/res_config_settings.xml", "views/scop_bordereau_cg.xml", "views/scop_cotisation_cg.xml", + "views/scop_cotisation_simulation.xml", + "views/scop_liasse_fiscale.xml", "wizard/export_journal_wizard_view.xml", "wizard/scop_cotisation_cg_wizard.xml", "wizard/scop_bordereau_update_confirm_view.xml", diff --git a/models/__init__.py b/models/__init__.py index c7c3521d1bd6b94ce2b5b45f226de0f61ae76f0e..14a36e45970b8b7d70501ae26d038f07fc6e1863 100755 --- a/models/__init__.py +++ b/models/__init__.py @@ -5,4 +5,6 @@ from . import account_invoice from . import res_company from . import res_config_settings from . import scop_bordereau_cg +from . import scop_cotisation_simulation from . import scop_cotisation_cg +from . import scop_liasse_fiscale diff --git a/models/scop_cotisation_cg.py b/models/scop_cotisation_cg.py index 0c8811a8d755eb063f3230ce2f8ba288b02cb172..3e3410e97a63e607e5047b6614a45c005c3651ac 100644 --- a/models/scop_cotisation_cg.py +++ b/models/scop_cotisation_cg.py @@ -1,9 +1,12 @@ # © 2021 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). +import base64 import json import logging import threading +import xlsxwriter +from io import BytesIO from odoo import models, fields, api, exceptions, registry @@ -20,6 +23,11 @@ class ScopCotisation(models.Model): compute='_compute_name', store=True) + simul_ids = fields.One2many( + comodel_name='scop.cotisation.cg.simulation', + inverse_name='cotisation_id', + string='Simulations') + invoice_ids = fields.One2many( comodel_name='account.invoice', inverse_name='cotisation_cg_id', @@ -36,31 +44,12 @@ class ScopCotisation(models.Model): state = fields.Selection([ ('new', 'Brouillon'), - ('ongoing', 'Instruction'), + ('ongoing', 'En cours'), ('end', 'Clôturé')], string="Statut", default='new', compute='_compute_state', store=True, track_visibility='onchange',) - amount_cg = fields.Monetary( - string="Montant CG Scop", currency_field='company_currency_id', - compute='_compute_amount_cotiz_cg') - amount_fede_com = fields.Monetary( - string="Montant Fédé de la Com", currency_field='company_currency_id', - compute='_compute_amount_cotiz_cg') - amount_fede_cae = fields.Monetary( - string="Montant Fédé CAE", currency_field='company_currency_id', - compute='_compute_amount_cotiz_cg') - amount_ur_hdf = fields.Monetary( - string="Montant UR HDF", currency_field='company_currency_id', - compute='_compute_amount_cotiz_cg') - amount_ur_med = fields.Monetary( - string="Montant UR Pyrénées", currency_field='company_currency_id', - compute='_compute_amount_cotiz_cg') - amount_total = fields.Monetary( - string="Montant total", compute="_compute_amount_total", - currency_field='company_currency_id') - invoice_count = fields.Integer( string='Appels de cotisations émis', compute='_compute_real') @@ -108,48 +97,6 @@ class ScopCotisation(models.Model): cotiz.year, dict(self._fields['state'].selection).get(cotiz.state)) - @api.multi - def _compute_amount_cotiz_cg(self): - for cotiz in self: - type_contribution_cg = cotiz.env.ref('cgscop_partner.riga_14397') - cotiz_cg = cotiz.invoice_ids.filtered( - lambda i: i.type_contribution_id == type_contribution_cg) - - type_contribution_fede_com = cotiz.env.ref( - 'cgscop_partner.riga_14398') - cotiz_fede_com = cotiz.invoice_ids.filtered( - lambda i: i.type_contribution_id == type_contribution_fede_com) - - type_contribution_fede_cae = cotiz.env.ref( - 'cgscop_partner.cotiz_fede_cae') - cotiz_fede_cae = cotiz.invoice_ids.filtered( - lambda i: i.type_contribution_id == type_contribution_fede_cae) - - type_contribution_ur = cotiz.env.ref('cgscop_partner.riga_14399') - cotiz_ur = cotiz.invoice_ids.filtered( - lambda i: i.type_contribution_id == type_contribution_ur) - - ur_hdf = cotiz.env.ref('cgscop_partner.riga_14232') - cotiz_hdf = cotiz_ur.filtered(lambda i: i.partner_ur_id == ur_hdf) - - ur_med = cotiz.env.ref('cgscop_partner.riga_14243') - cotiz_med = cotiz_ur.filtered(lambda i: i.partner_ur_id == ur_med) - - cotiz.amount_cg = sum(cotiz_cg.mapped("amount_total")) - cotiz.amount_fede_com = sum(cotiz_fede_com.mapped("amount_total")) - cotiz.amount_fede_cae = sum(cotiz_fede_cae.mapped("amount_total")) - cotiz.amount_ur_hdf = sum(cotiz_hdf.mapped("amount_total")) - cotiz.amount_ur_med = sum(cotiz_med.mapped("amount_total")) - - @api.multi - def _compute_amount_total(self): - for cotiz in self: - cotiz.amount_total = (cotiz.amount_cg + - cotiz.amount_fede_com + - cotiz.amount_fede_cae + - cotiz.amount_ur_hdf + - cotiz.amount_ur_med) - @api.multi def _compute_amount_called(self): for cotiz in self: @@ -237,6 +184,10 @@ class ScopCotisation(models.Model): raise exceptions.UserError( "La cotisation CG Scop n'est pas configurée.") + if not self.trimester_1 or not self.trimester_2 or not self.trimester_3 or not self.trimester_4: + raise exceptions.UserError( + "Les trimestres doivent être configurés pour lancer les cotisations.") + # List of members already invoiced member_invoiced = self.invoice_ids.mapped('partner_id') @@ -252,8 +203,6 @@ class ScopCotisation(models.Model): "</h3> <hr/>" + "Nombre d'adhérents renouvelés : " + str(self.member_count) + - # "<br/>Nombre de nouveaux adhérents : " + - # str(self.new_member_count) + "<br/>Bordereaux déjà générées non vides : " + str(self.invoiced_member_count) + "<br/>Bordereaux à générer : " + @@ -293,6 +242,10 @@ class ScopCotisation(models.Model): } def cotiz_generate_wizard(self): + if not self.trimester_1 or not self.trimester_2 or not self.trimester_3 or not self.trimester_4: + raise exceptions.UserError( + "Les trimestres doivent être configurés pour lancer les cotisations.") + wizard = self.env['scop.cotisation.cg.wizard'].create({ 'year': self.year, 'cotisation_cg_id': self.id, @@ -439,6 +392,226 @@ class ScopCotisation(models.Model): 'target': 'new' } + def add_simul(self): + """ + Ajoute une simulation à la base de cotisation pour l'année donnée. + Cette simulation est sous la forme d'un fichier Excel avec le détail + des cotisations par coopératives. + + @return: object scop.cotisation.cg.simulation + """ + # Get context + type_simul = self.env.context.get('type_simul') + + # Get contribution type + type_cotisation_cg = self.env.ref('cgscop_partner.riga_14397') + + # Get product type + InvoiceLine = self.env['account.invoice.line'] + product_cg_id = self.company_id.contribution_cg_id + product_com_id = self.company_id.contribution_fede_com_id + product_cae_id = self.company_id.contribution_fede_cae_id + product_hdf_id = self.company_id.contribution_hdf_id + product_med_id = self.company_id.contribution_med_id + + # List of members + members = self.get_members() + + header = [ + 'N° Adhérent', + 'Union Régionale', + 'Forme Coopérative', + 'Organisme', + 'Type de cotisation', + 'Cotisation ' + str(self.year), + 'Cotisation ' + str(self.year - 1), + 'Assiette', + 'Montant Assiette', + 'Année Liasse', + 'CA sens CG Scop', + 'VABDF sens CG Scop', + 'Salaires sens CG Scop', + 'Résultat', + 'Dernier effectif connu', + 'Moyen de paiement' + ] + + # Init variables + datas = [] + total_cg = total_hdf = total_com = total_med = total_cae = 0 + count_member = 0 + + for m in self.web_progress_iter(members, msg="cotisations calculées"): + liasse = self.get_liasse(m) + line_ids = InvoiceLine.search([ + ('partner_id', '=', m.id), + ('invoice_id.state', 'not in', ('draft', 'cancel')), + ('invoice_id.year', '=', self.year - 1) + ]) + + # Calcul Cotisation CG Scop + net_results = liasse.L2053_HN \ + if liasse.L2053_HN > 0 else liasse.L2051_DI + contrib_cg = self.round_to_closest_multiple( + liasse.contribution_cg, 4) if liasse else 300 + contribution_amount = contrib_cg + contribution_name = type_cotisation_cg.name + + # Calcul cotisation N-1 + contribution_last_year = sum(line_ids.filtered( + lambda l: l.product_id == product_cg_id).mapped('price_subtotal_signed')) + + # Construction Tableau + datas_contrib = [ + m.member_number, + m.ur_id.name, + m.cooperative_form_id.name, + m.name, + contribution_name, + contribution_amount, + contribution_last_year, + liasse.contribution_base_type.upper() if liasse else 'CA', + liasse.contribution_base_amount, + liasse.year, + liasse.revenue_cg, + liasse.av_cg, + liasse.wage_cg, + net_results, + m.staff_last, + m.customer_payment_mode_id.name if m.customer_payment_mode_id else 'Virement/Chèque', + ] + + # Ajout ligne CG Scop + datas.append(datas_contrib) + + if type_simul == 'all': + # Ajout ligne UR HDF + ur_hdf = self.env.ref('cgscop_partner.riga_14232') + if m.ur_id == ur_hdf: + # Calcul cotisation + contrib_hdf = self.round_to_closest_multiple( + liasse.contribution_hdf, 4) if liasse else 40 + # Calcul cotisation N-1 + contribution_last_year = sum(line_ids.filtered( + lambda l: l.product_id == product_hdf_id).mapped('price_subtotal_signed')) + datas_contrib[4] = 'Cotisation UR HDF' + datas_contrib[5] = contrib_hdf + datas_contrib[6] = contribution_last_year + datas.append(datas_contrib) + total_hdf += contrib_hdf + + # Ajout ligne UR Med + ur_med = self.env.ref('cgscop_partner.riga_14243') + if m.ur_id == ur_med: + # Calcul cotisation + contrib_med = self.round_to_closest_multiple( + liasse.contribution_med, 4) if liasse else 0 + # Calcul cotisation N-1 + contribution_last_year = sum(line_ids.filtered( + lambda l: l.product_id == product_med_id).mapped('price_subtotal_signed')) + datas_contrib[4] = 'Cotisation UR Méditerranée' + datas_contrib[5] = contrib_med + datas_contrib[6] = contribution_last_year + datas.append(datas_contrib) + total_med += contrib_med + + # Ajout ligne Fédération Com + if m.is_federation_com: + # Calcul cotisation + if liasse: + contrib_fede_com = self.round_to_closest_multiple( + liasse.contribution_com, 4) + else: + staff_id = self.get_last_staff_id(liasse.partner_id) + if staff_id.staff_average > 0: + contrib_fede_com = staff_id.staff_average * 108 + else: + contrib_fede_com = staff_id.staff_count * 108 + if contrib_fede_com < 108: + contrib_fede_com = 108 + # Calcul cotisation N-1 + contribution_last_year = sum(line_ids.filtered( + lambda l: l.product_id == product_com_id).mapped('price_subtotal_signed')) + datas_contrib[4] = 'Cotisation Fédération de la Com' + datas_contrib[5] = contrib_fede_com + datas_contrib[6] = contribution_last_year + datas.append(datas_contrib) + total_com += contrib_fede_com + + # Ajout ligne Fédération CAE + if m.is_federation_cae: + contrib_fede_cae = 100 + # Calcul cotisation N-1 + contribution_last_year = sum(line_ids.filtered( + lambda l: l.product_id == product_cae_id).mapped('price_subtotal_signed')) + datas_contrib[4] = 'Cotisation Fédération des CAE' + datas_contrib[5] = contrib_fede_cae + datas_contrib[6] = contribution_last_year + datas.append(datas_contrib) + total_cae += contrib_fede_cae + + count_member += 1 + total_cg += contrib_cg + + # Génération du ficher Excel + file_name = 'Simulation cotisations ' + str(self.year) + '.xlsx' + output = BytesIO() + workbook = xlsxwriter.Workbook(output, {'in_memory': True}) + worksheet1 = workbook.add_worksheet('Données brutes') + + # Intégration Header + format_header = workbook.add_format( + {'bg_color': '#eeeeee', 'font_color': '#333333', 'bold': True}) + for col, h in enumerate(header): + worksheet1.write(0, col, h, format_header) + + # Intégration datas + format_monetary = workbook.add_format( + {'num_format': '#,##0 [$€-407]'}) + for row, contrib in enumerate(datas): + for col, value in enumerate(contrib): + worksheet1.write(row + 1, col, value) + + # Format columns + worksheet1.set_column(0, 0, 10, None) + worksheet1.set_column(1, 1, 30, None) + worksheet1.set_column(2, 2, 15, None) + worksheet1.set_column(3, 3, 50, None) + worksheet1.set_column(4, 4, 25, None) + worksheet1.set_column(5, 6, 20, format_monetary) + worksheet1.set_column(8, 13, 20, format_monetary) + worksheet1.set_column(14, 14, 15, None) + worksheet1.set_column(15, 15, 20, None) + + # Enregistrement du fichier dans la base + workbook.close() + output.seek(0) + mem_bytes = output.read() + file_base64 = base64.b64encode(mem_bytes) + + simul_id = self.simul_ids.create({ + 'cotisation_id': self.id, + 'file': file_base64, + 'filename': file_name, + 'type_simul': type_simul, + 'total_member': count_member, + 'total_cg': total_cg, + 'total_hdf': total_hdf, + 'total_com': total_com, + 'total_cae': total_cae, + 'total_med': total_med, + }) + + return { + 'name': 'Simulation cotisation', + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'scop.cotisation.cg.simulation', + 'res_id': simul_id.id, + 'target': 'new', + 'flags': {'mode': 'readonly', 'default_buttons': False} + } + # ------------------------------------------------------ # Global functions # ------------------------------------------------------ @@ -593,6 +766,19 @@ class ScopCotisation(models.Model): # Calcul des cotisations # ------------------------------------------------------ def get_cotiz_cg(self, partner, bordereau): + """ + Appelle la fonction de calcul de la cotisation CG Scop + à partir des variables du bordereau + """ + + type_assiette = bordereau.type_assiette_retenu + ca = self.check_dureeExercice( + bordereau.ca_retenu, bordereau.dureeExercice) + va = self.check_dureeExercice( + bordereau.va_cg_retenu, bordereau.dureeExercice) + return self.calc_cotiz_cg(partner, ca, va, type_assiette) + + def calc_cotiz_cg(self, partner, ca, va, type_assiette): """ Calcule la cotisation de la CG Scop : - VA = VA saisie ou VA au sens CGSCOP si pas de VA renseignée @@ -607,11 +793,6 @@ class ScopCotisation(models.Model): @return float : cotisation """ values = self.get_values_for_cotiz_cg(partner) - type_assiette = bordereau.type_assiette_retenu - ca = self.check_dureeExercice( - bordereau.ca_retenu, bordereau.dureeExercice) - va = self.check_dureeExercice( - bordereau.va_cg_retenu, bordereau.dureeExercice) if type_assiette == 'ca': rate = self.get_rate_ca(partner) cotiz = ca * rate diff --git a/models/scop_cotisation_simulation.py b/models/scop_cotisation_simulation.py new file mode 100644 index 0000000000000000000000000000000000000000..03d1e9d535bd59b1a766065420e71b4644e8602a --- /dev/null +++ b/models/scop_cotisation_simulation.py @@ -0,0 +1,32 @@ +# © 2021 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import json +import logging +import threading + +from odoo import models, fields, api, exceptions, registry + +_logger = logging.getLogger(__name__) + + +class ScopCotisation(models.Model): + _name = "scop.cotisation.cg.simulation" + _description = "Simulation cotisations CG" + + cotisation_id = fields.Many2one( + comodel_name='scop.cotisation.cg', + ) + + file = fields.Binary('Fichier') + filename = fields.Char() + type_simul = fields.Selection( + selection=[('all', 'Toutes les cotisation'), ('cgscop', 'Cotisations CG Scop')], + string='Type de simulation' + ) + total_member = fields.Integer('Nombre Adhérents') + total_cg = fields.Float('Total CG Scop') + total_hdf = fields.Float('Total UR HDF') + total_med = fields.Float('Total UR Med') + total_com = fields.Float('Total Fédération Com') + total_cae = fields.Float('Total Fédération CAE') diff --git a/models/scop_liasse_fiscale.py b/models/scop_liasse_fiscale.py new file mode 100644 index 0000000000000000000000000000000000000000..24e6d72f302f82ab58cd1ed1fd0da291368e1e92 --- /dev/null +++ b/models/scop_liasse_fiscale.py @@ -0,0 +1,301 @@ +# © 2021 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +from odoo import models, fields, api + + +class ScopLiasseFiscale(models.Model): + _inherit = "scop.liasse.fiscale" + + contribution_cg = fields.Float( + string='Cotisation CG Scop', + compute='_compute_contribution_cg', + store=True) + contribution_base_type = fields.Selection( + string='Type Assiette de cotisation', + selection=[('ca', 'CA'), + ('va', 'VA'), ], + compute='_compute_contribution_cg', + store=True) + contribution_base_amount = fields.Integer( + string='Montant Assiette de cotisation', + compute='_compute_contribution_cg', + store=True) + contribution_hdf = fields.Float( + string='Cotisation UR HDF', + compute='_compute_contribution_hdf', + store=True) + contribution_med = fields.Float( + string='Cotisation UR Méditerranée', + compute='_compute_contribution_med', + store=True) + contribution_com = fields.Float( + string='Cotisation Fédération Com', + compute='_compute_contribution_com', + store=True) + + # ------------------------------------------------------ + # Compute fields + # ------------------------------------------------------ + @api.depends('av_lf', 'av_cg', 'revenue_cg') + @api.multi + def _compute_contribution_cg(self): + """ + Calcule la cotisation de la CG Scop : + - VA = VA saisie ou VA au sens CGSCOP si pas de VA renseignée + - 0,3% du CA ou 0,7% de la VA + - 300 € pour CA compris entre 0 et 100 K€ + - 600 € pour CA compris entre 100 et 200 K€ + - Max = 375 K€ + + @return float : cotisation + """ + for liasse in self: + # Calcul VA + va = liasse.av_lf if liasse.av_lf > 0 else liasse.av_cg + ca = liasse.revenue_cg + if liasse.dureeExercice and liasse.dureeExercice not in (0, 12): + va = va * (12 / liasse.dureeExercice) + ca = ca * (12 / liasse.dureeExercice) + + # Calcul Type Assiette + if ca > 0 and va > 0: + if ca <= va * 7 / 3: + contribution_base_type = 'ca' + contribution_base_amount = ca + else: + contribution_base_type = 'va' + contribution_base_amount = va + else: + if va > 0: + contribution_base_type = 'va' + contribution_base_amount = va + else: + contribution_base_type = 'ca' + contribution_base_amount = ca + + liasse.contribution_base_type = contribution_base_type + liasse.contribution_base_amount = contribution_base_amount + + # Calcul valeurs plancher + values = self.get_values_for_cotiz_cg(liasse.partner_id) + + # Calcul Cotisation CG Scop + if contribution_base_type == 'ca': + rate = self.get_rate_ca(liasse.partner_id) + contribution = ca * rate + else: + rate = self.get_rate_va(liasse.partner_id) + contribution = va * rate + + if contribution < values['plancher1']: + liasse.contribution_cg = values['plancher1'] + elif contribution < values['plancher2']: + liasse.contribution_cg = values['plancher2'] + elif contribution >= values['plancher3']: + if contribution_base_type == 'ca': + contribution = (25000000 * rate) + (ca - 25000000) * (rate / 2) + else: + cotiz = (10714286 * rate) + (va - 10714286) * (rate / 2) + if contribution <= values['plafond']: + liasse.contribution_cg = cotiz + else: + liasse.contribution_cg = values['plafond'] + else: + liasse.contribution_cg = contribution + + @api.depends('wage_cg') + @api.multi + def _compute_contribution_hdf(self): + """ + Calcule la cotisation de l'UR HDF pour 1 partenaire : + - 0,1 % de la masse salariale annuelle brute prévisionnelle + ou figurant sur la liasse fiscale. + + @return float : cotisation + """ + ur_hdf = self.env.ref('cgscop_partner.riga_14232') + for liasse in self: + if liasse.partner_id.ur_id == ur_hdf: + rate = 0.001 + plancher = 40 + if liasse.dureeExercice and liasse.dureeExercice not in (0, 12): + wage_cg = liasse.wage_cg * (12/liasse.dureeExercice) + else: + wage_cg = liasse.wage_cg + if wage_cg > 0: + contribution_hdf = wage_cg * rate + else: + contribution_hdf = 0 + + if contribution_hdf > plancher: + liasse.contribution_hdf = contribution_hdf + else: + liasse.contribution_hdf = plancher + + @api.depends('av_lf', 'av_cg') + @api.multi + def _compute_contribution_com(self): + """ + Calcule la cotisation de la fédération de la com pour 1 partenaire + - Assiette annuelle : VA saisie ou VA au sens CGSCOP + - Taux : 0.0032 + - Calcul : Valeur Ajoutée * 0.0032 + - Pour les nouvelles coopératives (pas de comptes annuels) : + 108 € par salarié (effectif moyen s’il est saisi, à défaut + effectif), soit 27 € par salarié et par trimestre. + - Plancher annuel : 108 € + - Plafond annuel : 18 428 € + + @return float : cotisation + """ + plancher = 108 + plafond = 18428 + rate = 0.0032 + for liasse in self: + if liasse.partner_id.is_federation_com: + # Calcul VA + va = liasse.av_lf if liasse.av_lf > 0 else liasse.av_cg + + # Calcul VA proratisée + if liasse.dureeExercice and liasse.dureeExercice not in (0, 12): + va = va * (12 / liasse.dureeExercice) + else: + va = va + + # Calcul effectifs + staff_id = self.get_last_staff_id(liasse.partner_id) + if staff_id: + staff_average = staff_id.staff_average + staff_count = staff_id.staff_count + else: + staff_average = 0 + staff_count = 0 + + # Calcul cotisation + if va != 0: + contribution_com = va * rate + else: + if staff_average > 0: + contribution_com = staff_average * plancher + else: + contribution_com = staff_count * plancher + if plancher <= contribution_com <= plafond: + liasse.contribution_com = contribution_com + elif contribution_com < plancher: + liasse.contribution_com = plancher + else: + liasse.contribution_com = plafond + + @api.depends('contribution_cg', 'L2053_HN') + @api.multi + def _compute_contribution_med(self): + """ + Calcule la cotisation de l'UR Med pour 1 liasse : + - Assiette : Assiette de la cotisation CGSCOP + - Taux d’appel : 1/3 du taux + - Calcul intermédiaire : Assiette * taux + (soit 1/3 de la cotisation CGSCOP sans plancher) + - Complément de cotisation : 1% du résultat net si positif + - Abattement pour sociétariat : + Taux de sociétariat = nombre de salariés sociétaires / + nombre de salariés + Abattement 20 % si >= 50 % + Abattement 30 % si >= 80 % + - Calcul cotisations : + [(Assiette*taux) + (résultat net *0.01)]* (1 ou 0.8 ou 0.7) + + @return float : cotisation + """ + ur_med = self.env.ref('cgscop_partner.riga_14243') + for liasse in self: + if liasse.partner_id.ur_id == ur_med: + # Assiette CG + assiette_rate = 1/3 + assiette = liasse.contribution_cg + + # Résultat net + net_results_rate = 0.01 + net_results = liasse.L2053_HN if liasse.L2053_HN > 0 else liasse.L2051_DI + if liasse.dureeExercice and liasse.dureeExercice not in (0, 12): + net_results = net_results * (12/liasse.dureeExercice) + + # Effectifs + staff_id = self.get_last_staff_id(liasse.partner_id) + if staff_id: + staff_shareholder_count = staff_id.staff_shareholder_count + staff_count = staff_id.staff_count + else: + staff_shareholder_count = staff_count = 0 + + # Taux d'abattement pour sociétariat + if staff_count > 0: + societariat_rate = staff_shareholder_count / staff_count + else: + societariat_rate = 0 + + if 0.5 <= societariat_rate < 0.8: + abatt_rate = 1 - 0.2 + elif societariat_rate >= 0.8: + abatt_rate = 1 - 0.3 + else: + abatt_rate = 1 - 0 + + # Calcul Cotisation + contribution_med = ((assiette * assiette_rate) + + (net_results * net_results_rate)) * abatt_rate + final_contribution_med = contribution_med if contribution_med >= 0 else 0 + liasse.contribution_med = final_contribution_med + + # ------------------------------------------------------ + # Business Function + # ------------------------------------------------------ + def get_values_for_cotiz_cg(self, partner): + # Calcul des Taux SCOP en fonction du type + plancher1 = 300 + plancher2 = 600 + plancher3 = 75000 + plafond = 375000 + if partner.cooperative_form_id in ( + self.env.ref('cgscop_partner.form_coop47'), + self.env.ref('cgscop_partner.form_lamaneur')): + plancher1 = 1 / 3 * plancher1 + plancher2 = 1 / 3 * plancher2 + plancher3 = 1 / 3 * plancher3 + plafond = 1 / 3 * plafond + + return { + 'plancher1': plancher1, + 'plancher2': plancher2, + 'plancher3': plancher3, + 'plafond': plafond, + } + + def get_rate_ca(self, partner): + # Calcul des Taux SCOP en fonction du type + if partner.cooperative_form_id in ( + self.env.ref('cgscop_partner.form_coop47'), + self.env.ref('cgscop_partner.form_lamaneur')): + rate_ca = 0.002 + else: + rate_ca = 0.003 + return rate_ca + + def get_rate_va(self, partner): + # Calcul des Taux SCOP en fonction du type + if partner.cooperative_form_id in ( + self.env.ref('cgscop_partner.form_coop47'), + self.env.ref('cgscop_partner.form_lamaneur')): + rate_va = 0.0047 + else: + rate_va = 0.007 + return rate_va + + def get_last_staff_id(self, partner): + """ + Return last known staff_id line + :param partner: + :return: + """ + staff_id = partner.staff_ids.sorted(key=lambda l: l.effective_date) + return staff_id[-1] if len(staff_id) > 1 else staff_id \ No newline at end of file diff --git a/security/ir.model.access.csv b/security/ir.model.access.csv index eb297e129b283e04a98adc2c4776d4c16daa6df1..68bfdfbe3ce217b57d6aa7c62b09d3b8bf20a629 100755 --- a/security/ir.model.access.csv +++ b/security/ir.model.access.csv @@ -1,4 +1,6 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink +access_scop_cotisation_simulation,access_scop_cotisation_simulation,model_scop_cotisation_cg_simulation,account.group_account_manager,1,1,1,1 +admin_access_scop_cotisation_simulation,admin_access_scop_cotisation_simulation,model_scop_cotisation_cg_simulation,cgscop_partner.group_cg_administrator,1,1,1,1 access_scop_cotisation_cg,access_scop_cotisation_cg,model_scop_cotisation_cg,account.group_account_manager,1,1,1,0 admin_access_scop_cotisation_cg,admin_access_scop_cotisation_cg,model_scop_cotisation_cg,cgscop_partner.group_cg_administrator,1,1,1,1 access_scop_bordereau,access_scop_bordereau,model_scop_bordereau,account.group_account_manager,1,1,1,1 diff --git a/views/scop_cotisation_cg.xml b/views/scop_cotisation_cg.xml index 239e050abdf06d5a01513c22927fdaaee6fada2f..354cd086444c317c963ca3455e8818dd7a32a27a 100644 --- a/views/scop_cotisation_cg.xml +++ b/views/scop_cotisation_cg.xml @@ -14,7 +14,6 @@ <field name="year"/> <field name="name"/> <field name="create_date"/> - <field name="amount_cg"/> <field name="state"/> <field name="member_count"/> <field name="write_date"/> @@ -42,7 +41,7 @@ <group> <group name="contribution" string="Cotisations"> <field name="year"/> - <field name="date_cotisation" attrs="{'readonly': [('state', '!=', 'new')]}"/> + <field name="date_cotisation" attrs="{'readonly': [('state', '!=', 'new')], 'required': [('state', '!=', 'new')]}"/> <field name="create_date"/> <field name="write_date"/> <field name="payment_term_id"/> @@ -50,28 +49,32 @@ <group name="count_contribution" string="Adhérents"> <field name="member_count" readonly="1"/> <field name="new_member_count" readonly="1"/> - <field name="invoiced_member_count" readonly="1" string="Bordereaux générés non vides"/> <field name="invoice_count" readonly="1"/> <field name="invoice_valid_count" readonly="1"/> </group> </group> <group> - <group name="simulation" string="Simulation"> - <field name="amount_cg" readonly="1" widget="monetary"/> - <field name="amount_fede_com" readonly="1" widget="monetary"/> - <field name="amount_fede_cae" readonly="1" widget="monetary"/> - <field name="amount_ur_hdf" readonly="1" widget="monetary"/> - <field name="amount_ur_med" readonly="1" widget="monetary"/> - <hr/> - <field name="amount_total" readonly="1" widget="monetary"/> - </group> <group name="schedule" string="Échéancier"> - <field name="trimester_1" required="1"/> - <field name="trimester_2" required="1"/> - <field name="trimester_3" required="1"/> - <field name="trimester_4" required="1"/> + <field name="trimester_1" attrs="{'required': [('state', '!=', 'new')]}"/> + <field name="trimester_2" attrs="{'required': [('state', '!=', 'new')]}"/> + <field name="trimester_3" attrs="{'required': [('state', '!=', 'new')]}"/> + <field name="trimester_4" attrs="{'required': [('state', '!=', 'new')]}"/> </group> </group> + <notebook> + <page name="simulation" string="Simulations"> + <h5>Ajouter une simulation :</h5> + <hr/> + <button name="add_simul" class="btn btn-outline-info" style="margin-right: 20px; width: 250px;" + type="object" string="Globale : CG, UR et Fédération" + attrs="{'invisible': [('state', '!=', 'new')]}" context="{'type_simul': 'all'}"/> + + <button name="add_simul" class="btn btn-outline-info" style="width: 250px;" + type="object" string="CG Scop uniquement" + attrs="{'invisible': [('state', '!=', 'new')]}" context="{'type_simul': 'cgscop'}"/> + <field name="simul_ids"/> + </page> + </notebook> </sheet> </form> </field> @@ -88,10 +91,8 @@ <field name="state"/> <field name="member_count"/> <field name="new_member_count"/> - <field name="invoiced_member_count"/> <field name="percent_cotiz_paid"/> <field name="graph_values"/> - <field name="amount_total"/> <field name="amount_called"/> <field name="amount_paid"/> <field name="amount_residual"/> @@ -106,7 +107,6 @@ <p class="text-muted"> Nombre d'adhérents renouvelés : <field name="member_count"/> <br /> Nombre de nouveaux adhérents : <field name="new_member_count"/> <br /> - Nombre d'adhérents facturés : <field name="invoiced_member_count"/> </p> </t> </div> @@ -122,10 +122,6 @@ <div class="col-6"> <table class="table table-bordered"> <tbody> - <tr> - <td>Montant théorique</td> - <td><field name="amount_total"/> €</td> - </tr> <tr> <td>Montant appelé</td> <td><field name="amount_called"/> €</td> diff --git a/views/scop_cotisation_simulation.xml b/views/scop_cotisation_simulation.xml new file mode 100644 index 0000000000000000000000000000000000000000..7e5f1753174d46b2f947feedd8ec4f4d9f89505b --- /dev/null +++ b/views/scop_cotisation_simulation.xml @@ -0,0 +1,65 @@ +<?xml version="1.0"?> +<!-- Copyright 2019 Le Filament + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> + +<odoo> + <data> + + <!-- Tree view --> + <record id="view_scop_cotisation_cg_simulation_tree" model="ir.ui.view"> + <field name="name">scop.cotisation.cg.simulation.tree</field> + <field name="model">scop.cotisation.cg.simulation</field> + <field name="arch" type="xml"> + <tree string="Simulations" create="0" edit="0"> + <field name="create_date" string="Date de création"/> + <field name="type_simul"/> + <field name="file" string="Fichier"/> + <field name="total_member"/> + <field name="total_cg"/> + <field name="total_hdf"/> + <field name="total_med"/> + <field name="total_com"/> + <field name="total_cae"/> + </tree> + </field> + </record> + + <!-- Form view --> + <record id="view_scop_cotisation_cg_simulation_form" model="ir.ui.view"> + <field name="name">scop.cotisation.cg.simulation.form</field> + <field name="model">scop.cotisation.cg.simulation</field> + <field name="arch" type="xml"> + <form> + <sheet> + <group> + <group string="Fichier simulation"> + <field name="create_date" string="Date de création"/> + <field name="type_simul" readonly="1"/> + <field name="file" filename="filename" readonly="1"/> + <field name="filename" invisible="1"/> + </group> + <group string="Données globales"> + <field name="total_member" readonly="1"/> + <field name="total_cg" readonly="1"/> + <field name="total_hdf" readonly="1"/> + <field name="total_med" readonly="1"/> + <field name="total_com" readonly="1"/> + <field name="total_cae" readonly="1"/> + </group> + </group> + </sheet> + </form> + </field> + </record> + + + <record id="view_scop_cotisation_cg_simulation_action" model="ir.actions.act_window"> + <field name="name">Simulation Cotisation</field> + <field name="type">ir.actions.act_window</field> + <field name="res_model">scop.cotisation.cg.simulation</field> + <field name="view_mode">form</field> + </record> + + + </data> +</odoo> diff --git a/views/scop_liasse_fiscale.xml b/views/scop_liasse_fiscale.xml new file mode 100644 index 0000000000000000000000000000000000000000..2f5260ea5c31affedcb7e9f3ff0faad1a6a7b363 --- /dev/null +++ b/views/scop_liasse_fiscale.xml @@ -0,0 +1,36 @@ +<?xml version="1.0"?> +<!-- Copyright 2021 Le Filament + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> + +<odoo> + <data> + + <!-- Form view --> + <record id="view_scop_liasse_fiscale_simulation_form" model="ir.ui.view"> + <field name="name">scop.liasse.fiscale.contribution.form</field> + <field name="model">scop.liasse.fiscale</field> + <field name="inherit_id" ref="cgscop_liste_ministere.scop_liasse_fiscale_form_view_prio"/> + <field name="arch" type="xml"> + <xpath expr="//form" position="inside"> + <hr/> + <div class="alert alert-info" role="alert"> + <strong><u>Cotisations théoriques</u></strong><br/> + Cette section donne les montants théoriques des diverses cotisations en fonction des valeurs de la liasse fiscale. + </div> + <group name="simulation"> + <group> + <field name="contribution_base_type" string="Type Assiette"/> + <field name="contribution_base_amount" string="Montant Assiette"/> + <field name="contribution_cg" string="Cotisation CG Scop"/> + </group> + <group> + <field name="contribution_hdf" string="Cotisation HDF"/> + <field name="contribution_med" string="Cotisation Méditerranée"/> + <field name="contribution_com" string="Cotisation Fédération Com"/> + </group> + </group> + </xpath> + </field> + </record> + </data> +</odoo>