diff --git a/website_membership_signup_required/models/__init__.py b/website_membership_signup_required/models/__init__.py index 8606c32..c77ee6b 100644 --- a/website_membership_signup_required/models/__init__.py +++ b/website_membership_signup_required/models/__init__.py @@ -2,4 +2,5 @@ from . import website from . import res_config_settings +from . import res_partner from . import res_users \ No newline at end of file diff --git a/website_membership_signup_required/models/res_partner.py b/website_membership_signup_required/models/res_partner.py new file mode 100644 index 0000000..84e1c2d --- /dev/null +++ b/website_membership_signup_required/models/res_partner.py @@ -0,0 +1,32 @@ +# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). + +from odoo import api, models + + +class ResPartner(models.Model): + _inherit = "res.partner" + + @api.model + def _signup_retrieve_info(self, token): + """Extend the core's token-based signup info with `firstname` and + `lastname` so the signup form (extended by this module to collect + them separately via `partner_firstname`) can be pre-filled and + shown readonly when the visitor follows an invitation link. + + The core (`auth_signup/models/res_partner.py:_signup_retrieve_info`) + only returns `name`, `login` and `email`. Our signup template + replaced the single `name` input with `firstname` / `lastname` + inputs, so without this override those inputs would be empty (and + readonly, because `only_passwords` is True for token flows) when + an invited partner already has the split fields populated. + + We keep `name` in the returned dict (the core's contract) and add + the two split fields so the controller's `setdefault` populates + the qcontext transparently. + """ + res = super()._signup_retrieve_info(token) + partner = self._get_partner_from_token(token) + if partner: + res["firstname"] = partner.firstname or "" + res["lastname"] = partner.lastname or "" + return res \ No newline at end of file diff --git a/website_membership_signup_required/tests/test_membership_signup.py b/website_membership_signup_required/tests/test_membership_signup.py index 6caa1ef..0216cb5 100644 --- a/website_membership_signup_required/tests/test_membership_signup.py +++ b/website_membership_signup_required/tests/test_membership_signup.py @@ -227,4 +227,52 @@ class TestMembershipSignup(TransactionCase): ctrl = WebsiteSaleMembershipSignup() billing_fields = ctrl._get_mandatory_billing_address_fields(country) self.assertNotIn("phone", billing_fields) - self.assertIn("email", billing_fields) \ No newline at end of file + self.assertIn("email", billing_fields) + + # -- Token-based signup: pre-fill firstname / lastname ----------------- + + def test_12_signup_retrieve_info_returns_firstname_lastname(self): + """When a partner is invited via token (the email-invitation flow), + the core's `_signup_retrieve_info` only returns `name`. Our + `res.partner` override adds `firstname` / `lastname` so the signup + form (extended by this module to collect them separately) is + pre-filled when the invited partner already has the split fields + (which is the case with `partner_firstname` installed). + + The invited partner must NOT have a user yet, otherwise the token + payload check (`user_ids`) won't match. + """ + partner = self.env["res.partner"].create({ + "firstname": "Invited", + "lastname": "Researcher", + "email": "invited.researcher@example.com", + "signup_type": "signup", + }) + self.assertFalse(partner.user_ids, "test precondition: no user yet") + token = partner._generate_signup_token() + info = self.env["res.partner"]._signup_retrieve_info(token) + self.assertEqual(info.get("firstname"), "Invited") + self.assertEqual(info.get("lastname"), "Researcher") + self.assertEqual(info.get("name"), partner.name) + self.assertEqual(info.get("email"), "invited.researcher@example.com") + + def test_13_signup_retrieve_info_legacy_partner_without_split(self): + """A partner created without `firstname`/`lastname` (legacy, only + `name`) should not crash the override. `firstname`/`lastname` come + back as '' (falsy), `name` as the legacy value, and the token flow + still works — the form will show empty readonly inputs for the split + fields, which is the best we can do without re-splitting. + """ + partner = self.env["res.partner"].create({ + "name": "Legacy Researcher", + "email": "legacy@example.com", + "signup_type": "signup", + }) + # partner_firstname's post_create hook may or may not have split + # `name` automatically; we just check the override does not crash + # and returns the contract keys. + token = partner._generate_signup_token() + info = self.env["res.partner"]._signup_retrieve_info(token) + self.assertIn("firstname", info) + self.assertIn("lastname", info) + self.assertEqual(info.get("name"), partner.name) \ No newline at end of file