diff --git a/__manifest__.py b/__manifest__.py index 6473c94ae0f68e13e81e26b86567ba6e46273d6c..5de3ca10ccec0ded5d1f0b6687e419a0148a30ae 100755 --- a/__manifest__.py +++ b/__manifest__.py @@ -19,5 +19,6 @@ "views/scop_bordereau_cg.xml", "views/scop_cotisation_cg.xml", "views/union_regionale.xml", + "wizard/scop_cotisation_cg_wizard.xml", ] } diff --git a/views/scop_cotisation_cg.xml b/views/scop_cotisation_cg.xml index 85544510aba06f114c43ce06f06216cdfd86f8f1..afef3bd4c42e0b51c9ba9f4b0e2116be6abbfc4e 100644 --- a/views/scop_cotisation_cg.xml +++ b/views/scop_cotisation_cg.xml @@ -30,7 +30,8 @@ <form string="Cotisations"> <header> <button name="cotiz_view" type="object" string="Accéder aux appels de cotisations"/> - <button string="Calculer les cotisations" type="object" name="cotiz_generate" class="oe_highlight" states="new,ongoing"/> + <button name="cotiz_generate" type="object" string="Calculer les cotisatisons de renouvellement" class="oe_highlight" states="new,ongoing"/> + <button name="cotiz_generate_wizard" type="object" string="Calculer les cotisatisons des nouveaux adhérents" class="oe_highlight" states="new,ongoing"/> <field name="state" widget="statusbar" clickable="False"/> </header> <sheet> diff --git a/wizard/__init__.py b/wizard/__init__.py index 19819ada1414c6c1a760bcb3f85287c244b64e07..240a8250fa859454a1e1e6dbbe7a87ca4357d8d3 100644 --- a/wizard/__init__.py +++ b/wizard/__init__.py @@ -2,3 +2,4 @@ # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). from . import account_invoice_refund +from . import scop_cotisation_cg_wizard diff --git a/wizard/scop_cotisation_cg_wizard.py b/wizard/scop_cotisation_cg_wizard.py new file mode 100644 index 0000000000000000000000000000000000000000..02c165df408ada6651c18bf90383326761229e66 --- /dev/null +++ b/wizard/scop_cotisation_cg_wizard.py @@ -0,0 +1,244 @@ +# © 2021 Le Filament (<http://www.le-filament.com>) +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). + +import logging +import threading + +from odoo import api, fields, models, exceptions, registry + +_logger = logging.getLogger(__name__) + + +class ScopCotisationWizard(models.TransientModel): + _name = 'scop.cotisation.cg.wizard' + _description = "Wizard: Génération des cotisations nouveaux adhérents" + + year = fields.Char( + string='Année', + required=True) + cotisation_cg_id = fields.Many2one( + comodel_name='scop.cotisation.cg', + string='Base de cotisation') + nb_quarter = fields.Selection( + string='Nombre de trimestres de cotisation', + selection=[('1', '1'), + ('2', '2'), + ('3', '3'), + ('4', '4')], + default='4', + required=True) + type = fields.Selection([ + ('all', 'Toutes les coop nouvelles adhérentes'), + ('selected', 'Sélectionner des coop')], + string='Type de création', + default='all' + ) + partner_ids = fields.Many2many( + comodel_name='res.partner', + string='Coopératives' + ) + + # ------------------------------------------------------ + # Button function + # ------------------------------------------------------ + @api.onchange('type') + def onchange_domain_partner_ids(self): + if self.type == 'selected': + # TODO : Vérifier la bonne utilisation du contexte ? + # Mieux utiliser cotisaion_cg_id ? + invoiced_members = self.env['scop.cotisation.cg'].search([ + ('year', '=', self.year)]).invoice_ids.mapped('partner_id') + + return {'domain': {'partner_ids': [ + ('is_company', '=', True), + ('id', 'not in', invoiced_members.mapped('id')) + ]}} + + # ------------------------------------------------------ + # Button function + # ------------------------------------------------------ + @api.multi + def cotiz_generate_new_adherents(self): + if not self.env.user.company_id.is_contribution_cg: + raise exceptions.UserError( + "La gestion des cotisations CGScop n'est pas configurée.") + + if self.type == 'selected': + members = self.partner_ids + else: + members = self.cotisation_cg_id.get_new_members() + + invoiced_members = self.cotisation_cg_id. \ + invoice_ids.mapped('partner_id') + + members_to_invoice = members - invoiced_members + + if len(members_to_invoice) > 0: + message = ( + "<h3>Appels de cotisation " + str(self.year) + + "</h3> <hr/>" + + "<br/>Cotisations nouveaux adhérents à générer : " + + str(len(members_to_invoice)) + + "<p>Les appels de cotisation sont en cours de " + "création...</p> " + ) + message_id = self.env['message.wizard'].create( + {'message': message}) + + # Création de la task + cotiz_cg_task = self.env['scop.cotisation.task'].create({ + 'year': self.year, + 'cotiz_to_create': len(members_to_invoice), + 'message': "En cours de création", + 'status': 'in_process' + }) + cotiz_cg_task.env.cr.commit() + # Lancement du calcul en arrière plan + threaded_cotiz = threading.Thread( + target=self._process_cotiz_generate, + args=(members_to_invoice, cotiz_cg_task, self.nb_quarter)) + threaded_cotiz.start() + else: + message = ("<p class='text-center'>Tous les appels de cotisations " + "pour les nouveaux adhérents connus ont déjà été " + "créés !</p>") + message_id = self.env['message.wizard'].create( + {'message': message}) + + return { + 'name': 'Génération des appels de cotisation nouveaux adhérents', + 'type': 'ir.actions.act_window', + 'view_mode': 'form', + 'res_model': 'message.wizard', + 'res_id': message_id.id, + 'target': 'new' + } + + # ------------------------------------------------------ + # Threading task + # ------------------------------------------------------ + def _process_cotiz_generate(self, partner_ids, + cotiz_cg_task, nb_quarter): + """ + Process de génération des cotiz Aura en background + """ + cotiz_created = 0 + cotiz_to_create = len(partner_ids) + + with api.Environment.manage(): + with registry(self.env.cr.dbname).cursor() as new_cr: + # Def new env + new_env = api.Environment( + new_cr, self.env.uid, self.env.context + ) + + # Def new var in new env + task = cotiz_cg_task.with_env(new_env) + new_self = self.with_env(new_env) + + # Definition of specific params + Cotiz_cg = new_self.cotisation_cg_id + # CG + product_cg_id = Cotiz_cg.company_id.contribution_cg_id + type_cotisation_cg = new_self.env.ref( + 'cgscop_partner.riga_14397').id + # Fede + product_fede_id = Cotiz_cg.company_id.contribution_fede_id + type_cotisation_fede = new_self.env.ref( + 'cgscop_partner.riga_14398').id + # UR HDF + product_hdf_id = Cotiz_cg.company_id.contribution_hdf_id + ur_hdf = new_self.env.ref('cgscop_partner.riga_14232').id + # UR Med + product_med_id = Cotiz_cg.company_id.contribution_med_id + ur_med = new_self.env.ref('cgscop_partner.riga_14238').id + # + type_cotisation_ur = new_self.env.ref( + 'cgscop_partner.riga_14399').id + + # Creation of cotiz invoice for each member + for member_id in partner_ids: + member = member_id.with_env(new_env) + + try: + liasse_id = Cotiz_cg.get_liasse(member) + # Bordereau + bordereau_id = Cotiz_cg.create_bordereau(member) + + # Invoice cotiz CG + amount_cg = Cotiz_cg.get_cotiz_cg(member, liasse_id) + invoice_cotiz_cg = Cotiz_cg.create_contribution( + product_cg_id, member, liasse_id, amount_cg) + invoice_cotiz_cg.write({ + 'type_contribution_id': type_cotisation_cg, + 'cotisation_cg_id': Cotiz_cg.id, + 'bordereau_id': bordereau_id.id, + 'amount_cg_calculated': amount_cg + }) + invoice_cotiz_cg.env.cr.commit() + + # Invoice cotiz Fede + if member.is_federation_com: + amount_fede = Cotiz_cg.get_cotiz_fede( + member, liasse_id) + invoice_cotiz_fede = Cotiz_cg.create_contribution( + product_fede_id, member, liasse_id, + amount_fede) + invoice_cotiz_fede.write({ + 'type_contribution_id': type_cotisation_fede, + 'cotisation_cg_id': Cotiz_cg.id, + 'bordereau_id': bordereau_id.id, + 'amount_cg_calculated': amount_fede + }) + invoice_cotiz_fede.env.cr.commit() + + # Invoice cotiz UR HDF + if member.ur_id.id == ur_hdf: + amount_hdf = Cotiz_cg.get_cotiz_hdf( + member, liasse_id) + invoice_cotiz_hdf = Cotiz_cg.create_contribution( + product_hdf_id, member, liasse_id, + amount_hdf) + invoice_cotiz_hdf.write({ + 'type_contribution_id': type_cotisation_ur, + 'cotisation_cg_id': Cotiz_cg.id, + 'bordereau_id': bordereau_id.id, + 'amount_cg_calculated': amount_hdf + }) + invoice_cotiz_hdf.env.cr.commit() + + # Invoice cotiz UR Med + if member.ur_id.id == ur_med: + amount_med = Cotiz_cg.get_cotiz_med( + member, liasse_id) + invoice_cotiz_med = Cotiz_cg.create_contribution( + product_med_id, member, liasse_id, amount_med) + invoice_cotiz_med.write({ + 'type_contribution_id': type_cotisation_ur, + 'cotisation_cg_id': Cotiz_cg.id, + 'bordereau_id': bordereau_id.id, + 'amount_cg_calculated': amount_med + }) + invoice_cotiz_med.env.cr.commit() + + cotiz_created += 1 + task.write({ + 'cotiz_created': cotiz_created, + }) + if cotiz_created == cotiz_to_create: + task.write({ + 'message': "Tous les appels de cotisaions ont" + " été créés", + 'status': "done" + }) + task.env.cr.commit() + except Exception as e: + _logger.exception(str(e)) + task.write({ + 'cotiz_created': cotiz_created, + 'message': "%d / %d ont été créés" % ( + cotiz_created, cotiz_to_create), + 'is_error': True, + 'status': "done" + }) + task.env.cr.commit() diff --git a/wizard/scop_cotisation_cg_wizard.xml b/wizard/scop_cotisation_cg_wizard.xml new file mode 100644 index 0000000000000000000000000000000000000000..f38b644550083d06a5a110b9f3a3c0f03061ddf3 --- /dev/null +++ b/wizard/scop_cotisation_cg_wizard.xml @@ -0,0 +1,37 @@ +<?xml version="1.0"?> +<!-- Copyright 2021 Le Filament + License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). --> + +<odoo> + <data> + + <record model="ir.ui.view" id="scop_cotisation_cg_wizard_form_view"> + <field name="name">scop.cotisation.cg.wizard.form</field> + <field name="model">scop.cotisation.cg.wizard</field> + <field name="arch" type="xml"> + <form string="Générer les cotisation pour les nouveaux adhérents"> + <group> + <field name="year" required="1" invisible="1"/> + <field name="nb_quarter" required="1"/> + <field name="type" widget="radio"/> + <field name="partner_ids" attrs="{'invisible': [('type', '=', 'all')]}" widget="many2many_tags" options="{'no_create': True, 'no_open': True}"/> + </group> + <footer> + <button name="cotiz_generate_new_adherents" type="object" + string="Générer les cotisations" class="oe_highlight"/> + <button special="cancel" string="Cancel"/> + </footer> + </form> + </field> + </record> + + <record model="ir.actions.act_window" id="action_genere_cotisation_cg_new_adherents"> + <field name="name">Générer les cotisations nouveaux adhérents</field> + <field name="res_model">scop.cotisation.cg.wizard</field> + <field name="view_mode">form</field> + <field name="view_id" ref="scop_cotisation_cg_wizard_form_view"/> + <field name="target">new</field> + </record> + + </data> +</odoo>