diff --git a/academic_sale_subscription/__manifest__.py b/academic_sale_subscription/__manifest__.py index 00bdd815..5288dcda 100644 --- a/academic_sale_subscription/__manifest__.py +++ b/academic_sale_subscription/__manifest__.py @@ -30,6 +30,7 @@ "data/mail_template.xml", "wizard/academic_order_wizard_views.xml", "wizard/update_payment_responsible_wizard_views.xml", + "wizard/update_payment_responsible_partner_wizard_views.xml", "views/sale_order_template_views.xml", "views/sale_subscription_plan_views.xml", "views/sale_order_views.xml", diff --git a/academic_sale_subscription/i18n/es.po b/academic_sale_subscription/i18n/es.po index 74a52fc7..053c4770 100644 --- a/academic_sale_subscription/i18n/es.po +++ b/academic_sale_subscription/i18n/es.po @@ -1257,8 +1257,9 @@ msgstr "" #. module: academic_sale_subscription #: model:ir.actions.act_window,name:academic_sale_subscription.action_update_payment_responsible #: model:ir.model,name:academic_sale_subscription.model_update_payment_responsible_wizard +#: model_terms:ir.ui.view,arch_db:academic_sale_subscription.view_update_payment_responsible_partner_wizard msgid "Update Payment Responsible" -msgstr "" +msgstr "Actualizar Responsable de Pago" #. module: academic_sale_subscription #: model:ir.model,name:academic_sale_subscription.model_update_payment_responsible_line @@ -1445,11 +1446,170 @@ msgstr "" #~ msgid "Download Certificate" #~ msgstr "Descargar Certificado" -#~ msgid "" -#~ "The debt free certificate for is not " -#~ "available because some of the payment responsible persons have pending " -#~ "debt." -#~ msgstr "" -#~ "El certificado de libre deuda para no " -#~ "está disponible porque alguno de los responsables de pago tiene deuda " -#~ "pendiente." +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/models/res_partner_link.py:0 +msgid "" +"Cannot remove \"Payment Responsible\" role from contact %s because student %s " +"has pending invoices." +msgstr "" +"No se puede quitar el rol de \"Responsable de Pago\" del contacto %s " +"porque el estudiante %s tiene facturas pendientes de pago." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/models/res_partner_link.py:0 +msgid "" +"Cannot remove \"Payment Responsible\" role from contact %s because student %s " +"has active subscriptions." +msgstr "" +"No se puede quitar el rol de \"Responsable de Pago\" del contacto %s " +"porque el estudiante %s tiene suscripciones activas." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/models/res_partner_link.py:0 +msgid "" +"Cannot %s from contact %s because student %s has pending invoices." +msgstr "" +"No se puede %s del contacto %s porque el estudiante %s tiene facturas pendientes de pago." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/models/res_partner_link.py:0 +msgid "" +"Cannot %s from contact %s because student %s has active subscriptions." +msgstr "" +"No se puede %s del contacto %s porque el estudiante %s tiene suscripciones activas." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/models/res_partner_link.py:0 +msgid "This link does not have the Payment Responsible role." +msgstr "Este enlace no tiene el rol de Responsable de Pago." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "No partner selected." +msgstr "No se seleccionó ningún contacto." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "Partner %s does not have the Payment Responsible role." +msgstr "El contacto %s no tiene el rol de Responsable de Pago." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "%d pending invoices" +msgstr "%d facturas pendientes" + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "%d pending invoices (without registered payments)" +msgstr "%d facturas pendientes (sin pagos registrados)" + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "%d active sales/subscriptions" +msgstr "%d ventas/suscripciones activas" + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "This action will update the payment responsible for: %s" +msgstr "Esta acción actualizará el responsable de pago para: %s" + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "No records found to update." +msgstr "No se encontraron registros para actualizar." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "Please select a new payment responsible." +msgstr "Por favor seleccione un nuevo responsable de pago." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "New payment responsible must be different from current one." +msgstr "El nuevo responsable de pago debe ser diferente al actual." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "%d invoices updated" +msgstr "%d facturas actualizadas" + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "%d sales/subscriptions updated" +msgstr "%d ventas/suscripciones actualizadas" + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "Payment responsible successfully updated for: %s" +msgstr "Responsable de pago actualizado exitosamente para: %s" + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "No records were updated." +msgstr "No se actualizaron registros." + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "Success" +msgstr "Éxito" + +#. module: academic_sale_subscription +#. odoo-python +#: code:addons/academic_sale_subscription/wizard/update_payment_responsible_partner_wizard.py:0 +msgid "Payment responsible roles updated" +msgstr "Roles de responsable de pago actualizados" + +#. module: academic_sale_subscription +#: model_terms:ir.ui.view,arch_db:academic_sale_subscription.view_academic_partner_form +#: code:addons/academic_sale_subscription/models/res_partner_link.py:0 +msgid "Change Payment Responsible" +msgstr "Cambiar Responsable de Pago" + +#. module: academic_sale_subscription +#: model_terms:ir.ui.view,arch_db:academic_sale_subscription.view_academic_partner_form +msgid "Payment responsible will be changed for active sales and pending debts" +msgstr "Se cambiará el responsable de pago de las ventas activas y deudas pendientes" + +#. module: academic_sale_subscription +#: model:ir.model,name:academic_sale_subscription.model_update_payment_responsible_partner_wizard +msgid "Update Payment Responsible from Partner" +msgstr "Actualizar Responsable de Pago desde Contacto" + +#. module: academic_sale_subscription +#: model:ir.model.fields,field_description:academic_sale_subscription.field_update_payment_responsible_partner_wizard__current_partner_id +msgid "Current Payment Responsible" +msgstr "Responsable de Pago Actual" + +#. module: academic_sale_subscription +#: model:ir.model.fields,field_description:academic_sale_subscription.field_update_payment_responsible_partner_wizard__new_partner_id +msgid "New Payment Responsible" +msgstr "Nuevo Responsable de Pago" + +#. module: academic_sale_subscription +#: model:ir.model.fields,field_description:academic_sale_subscription.field_update_payment_responsible_partner_wizard__sale_count +msgid "Active Sales/Subscriptions" +msgstr "Ventas/Suscripciones Activas" + +#. module: academic_sale_subscription +#: model:ir.model.fields,field_description:academic_sale_subscription.field_update_payment_responsible_partner_wizard__sale_ids +msgid "Sales/Subscriptions to Update" +msgstr "Ventas/Suscripciones a Actualizar" diff --git a/academic_sale_subscription/models/__init__.py b/academic_sale_subscription/models/__init__.py index 02373016..34ade1c3 100644 --- a/academic_sale_subscription/models/__init__.py +++ b/academic_sale_subscription/models/__init__.py @@ -14,3 +14,4 @@ from . import mail_thread from . import sale_order_close_reason from . import payment_transaction +from . import res_partner_link diff --git a/academic_sale_subscription/models/res_partner_link.py b/academic_sale_subscription/models/res_partner_link.py new file mode 100644 index 00000000..880a8419 --- /dev/null +++ b/academic_sale_subscription/models/res_partner_link.py @@ -0,0 +1,145 @@ +############################################################################## +# For copyright and license notices, see __manifest__.py file in module root +# directory +############################################################################## +from odoo import Command, _, models +from odoo.exceptions import ValidationError + + +class ResPartnerLink(models.Model): + _inherit = "res.partner.link" + + def _get_affected_students(self, link): + """Get list of students affected by this link.""" + if link.student_id.partner_type == "student": + return [link.student_id] + elif link.student_id.partner_type == "family": + return link.student_id.student_ids.filtered(lambda s: s.partner_type == "student") + return [] + + def _check_payment_responsible_restrictions(self, links): + """Check if payment responsible role can be removed/deleted.""" + if not links: + return + + paying_role = self.env.ref("academic.paying_role") + + for link in links: + if paying_role not in link.role_ids: + continue + + students_to_check = self._get_affected_students(link) + if not students_to_check: + continue + + pending_invoices = self.env["account.move"].search( + [ + ("student_id", "in", [s.id for s in students_to_check]), + ("move_type", "in", ["out_invoice", "out_refund"]), + ("state", "=", "posted"), + ("amount_residual", ">", 0), + ], + limit=1, + ) + + if pending_invoices: + student_with_debt = pending_invoices.student_id + raise ValidationError( + _( + 'Cannot remove "Payment Responsible" role from contact %s ' + "because student %s has pending invoices." + ) + % (link.partner_id.name, student_with_debt.name) + ) + + active_subscriptions = self.env["sale.order"].search( + [ + ("partner_invoice_id", "=", link.partner_id.id), + ("subscription_state", "=", "3_progress"), + ("partner_id", "in", [s.id for s in students_to_check]), + ], + limit=1, + ) + + if active_subscriptions: + student_with_subscription = active_subscriptions.student_id + raise ValidationError( + _( + 'Cannot remove "Payment Responsible" role from contact %s ' + "because student %s has active subscriptions." + ) + % (link.partner_id.name, student_with_subscription.name) + ) + + def _process_role_commands(self, old_roles, role_commands): + """Process Many2many commands to determine resulting roles.""" + new_roles = old_roles + + if not isinstance(role_commands, list): + return new_roles + + ResPartnerRole = self.env["res.partner.role"] + + for command in role_commands: + if command[0] == Command.SET: + new_roles = ResPartnerRole.browse(command[2]) + elif command[0] == Command.LINK: + new_roles |= ResPartnerRole.browse(command[1]) + elif command[0] == Command.UNLINK: + new_roles -= ResPartnerRole.browse(command[1]) + elif command[0] == Command.CLEAR: + new_roles = ResPartnerRole + elif command[0] == Command.DELETE: + new_roles -= ResPartnerRole.browse(command[1]) + + return new_roles + + def write(self, vals): + if "role_ids" in vals: + paying_role = self.env.ref("academic.paying_role") + links_to_check = [] + + for link in self: + if paying_role not in link.role_ids: + continue + + new_roles = self._process_role_commands(link.role_ids, vals["role_ids"]) + if paying_role not in new_roles: + links_to_check.append(link) + + if links_to_check: + self._check_payment_responsible_restrictions(links_to_check) + + return super().write(vals) + + def unlink(self): + paying_role = self.env.ref("academic.paying_role") + links_with_paying_role = self.filtered(lambda l: paying_role in l.role_ids) + + if links_with_paying_role: + self._check_payment_responsible_restrictions(links_with_paying_role) + + return super().unlink() + + def action_change_payment_responsible(self): + paying_role = self.env.ref("academic.paying_role") + if paying_role not in self.role_ids: + return { + "type": "ir.actions.client", + "tag": "display_notification", + "params": { + "title": _("Warning"), + "message": _("This link does not have the Payment Responsible role."), + "type": "warning", + "sticky": False, + }, + } + + return { + "type": "ir.actions.act_window", + "name": _("Change Payment Responsible"), + "res_model": "update.payment.responsible.partner.wizard", + "view_mode": "form", + "target": "new", + "context": {"active_id": self.partner_id.id}, + } diff --git a/academic_sale_subscription/security/ir.model.access.csv b/academic_sale_subscription/security/ir.model.access.csv index 8c67bd03..37bb97b7 100644 --- a/academic_sale_subscription/security/ir.model.access.csv +++ b/academic_sale_subscription/security/ir.model.access.csv @@ -3,3 +3,4 @@ access_academic_order_wizard,academic.order.wizard,academic_sale_subscription.mo access_academic_order_wizard_line,academic.order.wizard.line,academic_sale_subscription.model_academic_order_wizard_line,academic.group_user,1,1,1,1 access_update_payment_responsible_wizard,update.payment.responsible.wizard,academic_sale_subscription.model_update_payment_responsible_wizard,academic.group_user,1,1,1,1 access_update_payment_responsible_line,update.payment.responsible.line,academic_sale_subscription.model_update_payment_responsible_line,academic.group_user,1,1,1,1 +access_update_payment_responsible_partner_wizard,update.payment.responsible.partner.wizard,academic_sale_subscription.model_update_payment_responsible_partner_wizard,academic.group_user,1,1,1,1 diff --git a/academic_sale_subscription/views/res_partner_views.xml b/academic_sale_subscription/views/res_partner_views.xml index 62f5f910..ac2d34fb 100644 --- a/academic_sale_subscription/views/res_partner_views.xml +++ b/academic_sale_subscription/views/res_partner_views.xml @@ -65,4 +65,20 @@ + + + academic.partner.form + res.partner + + + +