diff --git a/__manifest__.py b/__manifest__.py index cc195d5ec9789b51f6661ed54a0434fb6ca1fcec..55560f631b518bd2a6cd94fc4028674e60bb74aa 100644 --- a/__manifest__.py +++ b/__manifest__.py @@ -2,11 +2,11 @@ "name": "Solagro Website Event Partner", "summary": "Crée une relation entre les réponses aux questions et les contacts " "authentifiés", - "author": "Le Filament", + "author": "Le Filament, Odoo Community Association (OCA)", "website": "https://le-filament.com", "version": "16.0.1.0.1", "license": "AGPL-3", - "depends": ["website_event"], + "depends": ["website_event", "partner_firstname"], "data": [ "security/ir.model.access.csv", # datas diff --git a/controllers/website_event.py b/controllers/website_event.py index b9acfedc842970cd255521664c37fe3991f0e75f..7e9e0a355491e0663d782a4fd0accb48c1ac087b 100644 --- a/controllers/website_event.py +++ b/controllers/website_event.py @@ -1,11 +1,12 @@ # Copyright 2024 Le Filament (<http://www.le-filament.com>) # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). -from odoo import _ +from odoo import _, http from odoo.exceptions import ValidationError from odoo.http import request from odoo.tools import str2bool +from odoo.addons.website_event.controllers.main import WebsiteEventController from odoo.addons.website_event_questions.controllers.main import WebsiteEvent @@ -16,11 +17,12 @@ class WebsiteEventPartnerQuestion(WebsiteEvent): registrations = super()._process_attendees_form(event, form_details) fields_to_update = {} for key, value in form_details.items(): + # questions contact if key.startswith("question_contact-"): - _dummy, question = key.split("-") + _dummy, question_str = key.split("-") # ruff: noqa: B023 question_id = event.sudo().partner_question_ids.filtered( - lambda q: q.id == int(question) + lambda q: q.id == int(question_str) ) if not question_id: raise ValidationError(_("Answer not in event.")) @@ -41,6 +43,7 @@ class WebsiteEventPartnerQuestion(WebsiteEvent): else: fields_to_update[ir_field_id.name] = value + # multi question if key.startswith("question_contact_multi-"): _dummy, question, _answer = key.split("-") # ruff: noqa: B023 @@ -54,6 +57,72 @@ class WebsiteEventPartnerQuestion(WebsiteEvent): fields_to_update[field_name][0][2].append(int(value)) else: fields_to_update[field_name] = [(6, 0, [int(value)])] + + # when seeing lastname, search firstname + # to complete name of registered participant + if key.endswith("-lastname"): + lastname = value + counter_str, _lastname = key.split("-") + counter = int(counter_str) - 1 + firstname = form_details.get(counter_str + "-firstname", "") + name = request.env["res.partner"]._get_computed_name( + lastname, firstname + ) + registrations[counter]["name"] = name + request.env.user.partner_id.update(fields_to_update) return registrations + + +class WebsiteEventControllerSolagro(WebsiteEventController): + # overload route to add more precompletion info on default_first_attendee + # copy-paste by lack of extensibility + # everything is the same except default_first_attendee firstname and lastname + # fields + @http.route( + ['/event/<model("event.event"):event>/registration/new'], + type="json", + auth="public", + methods=["POST"], + website=True, + ) + def registration_new(self, event, **post): + tickets = self._process_tickets_form(event, post) + availability_check = True + if event.seats_limited: + ordered_seats = 0 + for ticket in tickets: + ordered_seats += ticket["quantity"] + if event.seats_available < ordered_seats: + availability_check = False + if not tickets: + return False + default_first_attendee = {} + if not request.env.user._is_public(): + default_first_attendee = { + "name": request.env.user.name, + "firstname": request.env.user.firstname, + "lastname": request.env.user.lastname, + "email": request.env.user.email, + "phone": request.env.user.mobile or request.env.user.phone, + } + else: + visitor = request.env["website.visitor"]._get_visitor_from_request() + if visitor.email: + default_first_attendee = { + "name": visitor.name, + "firstname": visitor.partner_id.firstname, + "lastname": visitor.partner_id.lastname, + "email": visitor.email, + "phone": visitor.mobile, + } + return request.env["ir.ui.view"]._render_template( + "website_event.registration_attendee_details", + { + "tickets": tickets, + "event": event, + "availability_check": availability_check, + "default_first_attendee": default_first_attendee, + }, + ) diff --git a/i18n/fr.po b/i18n/fr.po index 2f46898980ef6e4bb2d50dd416e0c34ff34924f4..eb4cc6f5eaaabccf91beeffaa608bc46aad09989 100644 --- a/i18n/fr.po +++ b/i18n/fr.po @@ -6,8 +6,8 @@ msgid "" msgstr "" "Project-Id-Version: Odoo Server 16.0\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-08-14 12:36+0000\n" -"PO-Revision-Date: 2024-08-14 12:36+0000\n" +"POT-Creation-Date: 2025-03-11 10:23+0000\n" +"PO-Revision-Date: 2025-03-11 10:23+0000\n" "Last-Translator: \n" "Language-Team: \n" "MIME-Version: 1.0\n" @@ -92,6 +92,16 @@ msgstr "Question liée à un contact sur un évènement" msgid "Fields for partner related questions on Events" msgstr "Champs pour questions liées à un contact sur les évènements" +#. module: solagro_website_event_partner +#: model_terms:ir.ui.view,arch_db:solagro_website_event_partner.registration_attendee_partner_question_details +msgid "Firstname *" +msgstr "Prénom *" + +#. module: solagro_website_event_partner +#: model:ir.model,name:solagro_website_event_partner.model_ir_http +msgid "HTTP Routing" +msgstr "Routage HTTP" + #. module: solagro_website_event_partner #: model:ir.model.fields,field_description:solagro_website_event_partner.field_event_partner_fields__id #: model:ir.model.fields,field_description:solagro_website_event_partner.field_event_partner_question__id @@ -116,6 +126,11 @@ msgstr "Dernière modification par" msgid "Last Updated on" msgstr "Date de dernière modification :" +#. module: solagro_website_event_partner +#: model_terms:ir.ui.view,arch_db:solagro_website_event_partner.registration_attendee_partner_question_details +msgid "Lastname *" +msgstr "Nom *" + #. module: solagro_website_event_partner #: model:ir.model.fields,field_description:solagro_website_event_partner.field_event_partner_fields__ir_field_id msgid "Model Field" @@ -140,7 +155,9 @@ msgstr "Questions liées à un contact" #: code:addons/solagro_website_event_partner/models/event_partner_question.py:0 #, python-format msgid "Question cannot be linked to both an Event and an Event Type." -msgstr "Une question ne peut pas être liée à la fois à un évènement et un modèle d'évènement." +msgstr "" +"Une question ne peut pas être liée à la fois à un évènement et un modèle " +"d'évènement." #. module: solagro_website_event_partner #: model:ir.model.fields,field_description:solagro_website_event_partner.field_event_partner_question__sequence @@ -153,7 +170,9 @@ msgstr "Séquence" #: model:ir.model.constraint,message:solagro_website_event_partner.constraint_event_partner_question__uniq_event_partner_question #, python-format msgid "This field is present more than once in event questions." -msgstr "Ce champ est présent plusieurs fois dans les questions liées à un contact de l'évènement." +msgstr "" +"Ce champ est présent plusieurs fois dans les questions liées à un contact de" +" l'évènement." #. module: solagro_website_event_partner #. odoo-python @@ -161,7 +180,9 @@ msgstr "Ce champ est présent plusieurs fois dans les questions liées à un con #: model:ir.model.constraint,message:solagro_website_event_partner.constraint_event_partner_question__uniq_event_type_partner_question #, python-format msgid "This field is present more than once in event type questions." -msgstr "Ce champ est présent plusieurs fois dans les questions liées à un contact du modèle d'évènement." +msgstr "" +"Ce champ est présent plusieurs fois dans les questions liées à un contact du" +" modèle d'évènement." #. module: solagro_website_event_partner #: model:ir.model.fields,field_description:solagro_website_event_partner.field_event_partner_question__title @@ -173,3 +194,12 @@ msgstr "Titre" msgid "Yes" msgstr "Oui" +#. module: solagro_website_event_partner +#: model_terms:ir.ui.view,arch_db:solagro_website_event_partner.registration_attendee_partner_question_details +msgid "i.e. Doe" +msgstr "par ex. Nguyen" + +#. module: solagro_website_event_partner +#: model_terms:ir.ui.view,arch_db:solagro_website_event_partner.registration_attendee_partner_question_details +msgid "i.e. John" +msgstr "par ex. Julie" diff --git a/models/__init__.py b/models/__init__.py index 559a5b06144cc8afab6279d9597ce1fc957d6caf..f167e2042d7490057514fba2275fe5cb0ba16ed6 100644 --- a/models/__init__.py +++ b/models/__init__.py @@ -3,3 +3,4 @@ from . import event_type from . import event_partner_fields from . import event_partner_question from . import res_company +from . import ir_http diff --git a/models/ir_http.py b/models/ir_http.py new file mode 100644 index 0000000000000000000000000000000000000000..09dcd9437af19b49bc073f5c62b9f9da92e2446b --- /dev/null +++ b/models/ir_http.py @@ -0,0 +1,10 @@ +from odoo import models + + +class IrHttp(models.AbstractModel): + _inherit = "ir.http" + + @classmethod + def _get_translation_frontend_modules_name(cls): + modules = super()._get_translation_frontend_modules_name() + return modules + ["solagro_website_event_partner"] diff --git a/templates/event_registration_template.xml b/templates/event_registration_template.xml index a9e6e13903cd4bb2bb91cdabaf19d42a6cd38d86..ce620696d00ec2632a75f8f0abeb33ed20ea03a4 100644 --- a/templates/event_registration_template.xml +++ b/templates/event_registration_template.xml @@ -35,7 +35,9 @@ t-attf-name="question_contact-#{question.id}" class="form-control" t-att-required="is_mandatory_answer" - ><t t-out="partner_id[field_id.name]" /></textarea> + > + <t t-out="partner_id[field_id.name]" /> + </textarea> </t> <!-- Date --> <t t-if="field_id.ttype == 'date'"> @@ -161,7 +163,8 @@ <label t-attf-for="question_contact_multi-#{question.id}-#{answer.id}" class="form-check-label fw-normal" - ><span t-out="answer.name" /> + > + <span t-out="answer.name" /> </label> </div> </t> @@ -177,6 +180,46 @@ name="Registration Attendee Contact detail" priority="101" > + + + <!-- replaces name by firstname / lastname --> + <xpath expr="//input[@t-attf-name='#{counter}-name']/.." position="replace"> + <div class="col-lg my-2 field-firstname"> + <label for="name">Firstname *</label> + <input + type="text" + t-attf-name="#{counter}-firstname" + t-att-value="default_first_attendee.get('firstname', '') if counter == 1 else ''" + id="firstname" + class="form-control" + placeholder="i.e. John" + required="required" + /> + </div> + <div class="col-lg my-2 field-lastname"> + <label for="name">Lastname *</label> + <input + type="text" + t-attf-name="#{counter}-lastname" + t-att-value="default_first_attendee.get('lastname', '') if counter == 1 else ''" + id="lastname" + class="form-control" + placeholder="i.e. Doe" + required="required" + /> + </div> + </xpath> + + <!-- customize email validation --> + <xpath expr="//input[@t-attf-name='#{counter}-email']" position="attributes"> + <!-- regexp prise sur https://developer.mozilla.org/fr/docs/Web/HTML/Element/input/email#validation_simple --> + <!-- mais avec un '+' plutôt qu'un '*' à la fin, comme demandé par solagro --> + <!-- et échappée correctement --> + <attribute + name="pattern" + >^[a-zA-Z0-9.!#$%&'*+\/=?^_`\{\|\}~\-]+@[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9\-]{0,61}[a-zA-Z0-9])?)+$</attribute> + </xpath> + <!-- Phone is only displayed if user not connected or if we are not registering the first contact @@ -211,8 +254,11 @@ </div> </t> </xpath> + + </template> + <template id="registration_attendee_details_questions_solagro" inherit_id="website_event_questions.registration_attendee_details_questions"