From 19f127a43c3c67201d7fadac6528827ee7a02cb4 Mon Sep 17 00:00:00 2001 From: Emanuel Cino Date: Mon, 16 May 2022 12:38:37 +0200 Subject: [PATCH 1/5] CO-3200 FIX various group visit process bugs --- website_event_compassion/controllers/events_controller.py | 8 +++----- website_event_compassion/controllers/group_visit.py | 4 ++-- website_event_compassion/forms/agreement_step2_forms.py | 7 ++++++- website_event_compassion/forms/group_visit_payment.py | 4 ++++ website_event_compassion/models/account_invoice.py | 2 +- .../models/partner_communication_job.py | 7 +++---- 6 files changed, 19 insertions(+), 13 deletions(-) diff --git a/website_event_compassion/controllers/events_controller.py b/website_event_compassion/controllers/events_controller.py index fd3b32f1d..9a5bd5c1d 100644 --- a/website_event_compassion/controllers/events_controller.py +++ b/website_event_compassion/controllers/events_controller.py @@ -286,10 +286,10 @@ def down_payment_validate(self, invoice_id=None, **post): """ failure_template = "website_event_compassion.donation_failure" error_intro = _( - "Thank you for your efforts in the Compassion trip registration " "process." + "Thank you for your efforts in the Compassion trip registration process." ) try: - invoice = request.env["account.invoice"].browse(int(invoice_id)) + invoice = request.env["account.invoice"].browse(int(invoice_id)).sudo() invoice.exists().ensure_one() tx = invoice.get_portal_last_transaction() except ValueError: @@ -329,9 +329,7 @@ def down_payment_validate(self, invoice_id=None, **post): "the departure. Until then, don't hesitate to contact us if " "you have any question." ) - return super().compassion_payment_validate( - tx, template, failure_template, **post - ) + return request.render(template, post) def get_donation_success_template(self, event): """ diff --git a/website_event_compassion/controllers/group_visit.py b/website_event_compassion/controllers/group_visit.py index 73f7ff411..7562a2002 100644 --- a/website_event_compassion/controllers/group_visit.py +++ b/website_event_compassion/controllers/group_visit.py @@ -105,7 +105,7 @@ def group_visit_payment(self, reg_uid, **kwargs): def get_payment_form(self, reg_uid, form_model, **kwargs): kwargs["form_model_key"] = form_model - values = self._get_group_visit_page_values(reg_uid, "account.invoice", **kwargs) + values = self._get_group_visit_page_values(reg_uid, "cms.form.event.group.visit.payment", **kwargs) if not isinstance(values, dict): # values can be a redirect in case of error return values @@ -221,7 +221,7 @@ def _get_group_visit_page_values(self, reg_uid, form_model=None, **kwargs): :param kwargs: calling args :return: dict of values for template rendering """ - registration = request.env["event.registration"].search( + registration = request.env["event.registration"].sudo().search( [("uuid", "=", reg_uid)] ) if not registration: diff --git a/website_event_compassion/forms/agreement_step2_forms.py b/website_event_compassion/forms/agreement_step2_forms.py index 7bf8213f4..de6b1255a 100644 --- a/website_event_compassion/forms/agreement_step2_forms.py +++ b/website_event_compassion/forms/agreement_step2_forms.py @@ -31,6 +31,11 @@ def form_widgets(self): res["form_id"] = "cms_form_compassion.form.widget.hidden" return res + def form_init(self, request, main_object=None, **kw): + if main_object: + main_object = main_object.sudo() + return super().form_init(request, main_object, **kw) + def form_cancel_url(self, main_object=None): """URL to redirect to after click on "cancel" button.""" main_object = main_object or self.main_object @@ -266,7 +271,7 @@ def _form_validate_passport_expiration_date(self, value, **req_values): valid = True old = False try: - date = datetime.strptime(value, "%d.%m.%Y") + date = fields.Datetime.from_string(value) limit_date = ( self.main_object.compassion_event_id.end_date + relativedelta(months=6) diff --git a/website_event_compassion/forms/group_visit_payment.py b/website_event_compassion/forms/group_visit_payment.py index 8bad9f8b4..98dc860af 100644 --- a/website_event_compassion/forms/group_visit_payment.py +++ b/website_event_compassion/forms/group_visit_payment.py @@ -97,3 +97,7 @@ def generate_invoice(self): } ) return group_visit_invoice + + def _form_create(self, values): + # Do nothing here + return True diff --git a/website_event_compassion/models/account_invoice.py b/website_event_compassion/models/account_invoice.py index 087de697f..c0876c2f4 100644 --- a/website_event_compassion/models/account_invoice.py +++ b/website_event_compassion/models/account_invoice.py @@ -24,7 +24,7 @@ def modify_open_invoice(self, vals): self.action_invoice_cancel() self.action_invoice_draft() self.write(vals) - for invoice in self.filtered(lambda i: i.partner_id.state == "active"): + for invoice in self: invoice.action_invoice_open() return True diff --git a/website_event_compassion/models/partner_communication_job.py b/website_event_compassion/models/partner_communication_job.py index 564a6a24c..3ea7f686d 100644 --- a/website_event_compassion/models/partner_communication_job.py +++ b/website_event_compassion/models/partner_communication_job.py @@ -68,10 +68,9 @@ def get_trip_payment_attachment(self): "communication": event_name, } report_name = "report_compassion.bvr_fund" + report = self.env.ref("report_compassion.report_bvr_fund") pdf_data = base64.b64encode( - self.env["report"] - .with_context(must_skip_send_to_printer=True) - .render_qweb_pdf(registration.partner_id.ids, report_name, - data=report_vals) + report.with_context(must_skip_send_to_printer=True) + .render_qweb_pdf(registration.partner_id.ids, data=report_vals)[0] ) return {event_name + ".pdf": [report_name, pdf_data]} From 882739ea5b5fd1e9e4cea3ce2103a126628a5ed8 Mon Sep 17 00:00:00 2001 From: Emanuel Cino Date: Tue, 17 May 2022 15:30:28 +0200 Subject: [PATCH 2/5] FIX Thank you quote translation --- partner_compassion/models/advocate_details.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/partner_compassion/models/advocate_details.py b/partner_compassion/models/advocate_details.py index 8891b268b..5b048ba55 100644 --- a/partner_compassion/models/advocate_details.py +++ b/partner_compassion/models/advocate_details.py @@ -125,8 +125,7 @@ def _compute_thank_you_quote(self): "image_data": details.partner_id.with_context(bin_size=False) .image.decode("utf-8"), "text": details.quote.strip() or "", - "attribution": _("Quote from %s %s" - % (firstname, lastname)) + "attribution": _("Quote from %s %s") % (firstname, lastname) if details.quote.strip() else "", } From 2fe45540b8d7e31a1a6bed5ff51917fe2b6538fe Mon Sep 17 00:00:00 2001 From: Emanuel Cino Date: Thu, 19 May 2022 10:01:14 +0200 Subject: [PATCH 3/5] Use commercial partner for tax receipt generation cron --- partner_communication_switzerland/models/res_partner.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/partner_communication_switzerland/models/res_partner.py b/partner_communication_switzerland/models/res_partner.py index f1c991820..bab6a49cb 100644 --- a/partner_communication_switzerland/models/res_partner.py +++ b/partner_communication_switzerland/models/res_partner.py @@ -253,7 +253,7 @@ def generate_tax_receipts(self): ("partner_id.tax_certificate", "!=", "no"), ] ) - config = self.env.ref("partner_communication_switzerland." "tax_receipt_config") + config = self.env.ref("partner_communication_switzerland.tax_receipt_config") existing_comm = self.env["partner.communication.job"].search( [ ("config_id", "=", config.id), @@ -261,7 +261,7 @@ def generate_tax_receipts(self): ("date", ">", end_date), ] ) - partners = invoice_lines.mapped("partner_id") - existing_comm.mapped( + partners = invoice_lines.mapped("partner_id.commercial_partner_id") - existing_comm.mapped( "partner_id" ) total = len(partners) From 468ba6d0bc7988a2480c8b9e68ca3c7f1b1ee0f5 Mon Sep 17 00:00:00 2001 From: Emanuel Cino Date: Thu, 19 May 2022 12:10:16 +0200 Subject: [PATCH 4/5] FIX zoom registration confirmation for people declining it. --- .../models/res_partner_zoom_attendee.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/partner_communication_switzerland/models/res_partner_zoom_attendee.py b/partner_communication_switzerland/models/res_partner_zoom_attendee.py index e35406bbc..ab59a827c 100644 --- a/partner_communication_switzerland/models/res_partner_zoom_attendee.py +++ b/partner_communication_switzerland/models/res_partner_zoom_attendee.py @@ -124,6 +124,6 @@ def send_communication(self, config_name): def form_completion_callback(self): self.ensure_one() if datetime.now() >= ( - self.zoom_session_id.date_send_link or self.zoom_session_id.date_start): + self.zoom_session_id.date_send_link or self.zoom_session_id.date_start) and self.state != "declined": return self.send_communication(ZoomCommunication.LINK) return self.send_communication(ZoomCommunication.REGISTRATION) From 17672b82388542bc158bf230c3a3726a5e518aa0 Mon Sep 17 00:00:00 2001 From: Guillaume Date: Thu, 19 May 2022 15:16:37 +0200 Subject: [PATCH 5/5] CS-736: address duplication in Odoo (#1525) * improve duplicate partners check refactor the checks and add another one based on lastname, street and zip * update check name * add some doc in comments * add some doc --- .../models/partner_compassion.py | 134 +++++++++++------- 1 file changed, 79 insertions(+), 55 deletions(-) diff --git a/partner_compassion/models/partner_compassion.py b/partner_compassion/models/partner_compassion.py index 0d60c3d63..ed1f3e3d9 100644 --- a/partner_compassion/models/partner_compassion.py +++ b/partner_compassion/models/partner_compassion.py @@ -369,25 +369,9 @@ def _compute_prim_sec_segments(self): ########################################################################## @api.model def create(self, vals): - """ - Lookup for duplicate partners and notify. - """ - email = vals.get("email") - if email: - vals["email"] = email.strip() - duplicate = self.search( - [ - "|", - "&", - ("email", "=", vals.get("email")), - ("email", "!=", False), - "&", - "&", - ("firstname", "ilike", vals.get("firstname")), - ("lastname", "ilike", vals.get("lastname")), - ("zip", "=", vals.get("zip")), - ] - ) + duplicate_domain = self._check_duplicates_domain(vals, skip_props_check=True) + duplicate = self.search(duplicate_domain) + duplicate_ids = [(4, itm.id) for itm in duplicate] vals.update({"partner_duplicate_ids": duplicate_ids}) vals["ref"] = self.env["ir.sequence"].get("partner.ref") @@ -517,47 +501,87 @@ def _check_qorder(self, word): raise return True + def _check_duplicates_domain(self, vals=None, skip_props_check=False): + """ + Generates a search domain to find duplicates for this partner based on various filters + :param dict vals: a dictionnary containing values used by the filters, inferred from self if not provided + :param bool skip_props_checks: whether you want to skip verifying that each variable's filter are set, thus running them all anyway + """ + if not vals: + vals = { + "email": self.email, + "firstname": self.firstname, + "lastname": self.lastname, + "zip": self.zip, + "street": self.street, + } + + # define set of checks for duplicates and required fields + checks = [ + # Email check + (vals.get('email'), [ + '&', + ('email', '=', vals.get('email')), + ('email', '!=', False) + ]), + # zip and name check + (vals.get('firstname') and vals.get('lastname') and vals.get('zip'), [ + "&", + "&", + ("firstname", "ilike", vals.get('firstname')), + ("lastname", "ilike", vals.get('lastname')), + ("zip", "=", vals.get('zip')), + ]), + # name and address check + (vals.get('lastname') and vals.get('street') and vals.get('zip'), [ + "&", + "&", + ("lastname", "ilike", vals.get('lastname')), + ("zip", "=", vals.get('zip')), + ("street", "ilike", vals.get('street')) + ]) + ] + + # This step builds a domain query based on the checks that + # passed, prepending the list with a "|" operator for all item + # once its size is > 1 + search_filters = [] + for check in checks: + if skip_props_check or check[0]: + if len(search_filters) > 0: + search_filters.insert(0, "|") + search_filters.extend(check[1]) + return search_filters + ########################################################################## # ONCHANGE METHODS # ########################################################################## @api.onchange("lastname", "firstname", "zip", "email") def _onchange_partner(self): - if ( - (self.lastname and self.firstname and self.zip) or self.email - ) and self.contact_type != "attached": - partner_duplicates = self.search( - [ - ("id", "!=", self._origin.id), - "|", - "&", - ("email", "=", self.email), - ("email", "!=", False), - "&", - "&", - ("firstname", "ilike", self.firstname), - ("lastname", "ilike", self.lastname), - ("zip", "=", self.zip), - ] - ) - if partner_duplicates: - self.partner_duplicate_ids = partner_duplicates - # Commit the found duplicates - with api.Environment.manage(): - with registry(self.env.cr.dbname).cursor() as new_cr: - new_env = api.Environment(new_cr, self.env.uid, {}) - self._origin.with_env(new_env).write( - {"partner_duplicate_ids": [(6, 0, partner_duplicates.ids)]} - ) - return { - "warning": { - "title": _("Possible existing partners found"), - "message": _( - "The partner you want to add may " - 'already exist. Please use the "' - 'Check duplicates" button to review it.' - ), - }, - } + duplicates_domain = self._check_duplicates_domain(skip_props_check=False) + if self.contact_type == "attached" or not duplicates_domain: + return + + partner_duplicates = self.search([("id", "!=", self._origin.id)] + duplicates_domain) + if partner_duplicates: + self.partner_duplicate_ids = partner_duplicates + # Commit the found duplicates + with api.Environment.manage(): + with registry(self.env.cr.dbname).cursor() as new_cr: + new_env = api.Environment(new_cr, self.env.uid, {}) + self._origin.with_env(new_env).write( + {"partner_duplicate_ids": [(6, 0, partner_duplicates.ids)]} + ) + return { + "warning": { + "title": _("Possible existing partners found"), + "message": _( + "The partner you want to add may " + 'already exist. Please use the "' + 'Check duplicates" button to review it.' + ), + }, + } ########################################################################## # PUBLIC METHODS #