200 lines
No EOL
8.5 KiB
Python
200 lines
No EOL
8.5 KiB
Python
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
|
|
|
|
import werkzeug.datastructures
|
|
|
|
from odoo.fields import Date
|
|
|
|
from odoo.addons.website_membership_signup_required.controllers.main import (
|
|
AuthSignupHomeMembership as AuthSignupHome,
|
|
)
|
|
from odoo.addons.website_membership_signup_required.controllers.website_sale import (
|
|
WebsiteSaleMembershipSignup,
|
|
)
|
|
from odoo.addons.website.tools import MockRequest
|
|
from odoo.tests import TransactionCase, tagged
|
|
|
|
|
|
@tagged("post_install", "-at_install")
|
|
class TestMembershipSignup(TransactionCase):
|
|
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
super().setUpClass()
|
|
cls.website = cls.env.ref("website.default_website")
|
|
cls.website.auth_signup_uninvited = "b2b"
|
|
today = Date.to_date(Date.today())
|
|
cls.membership_product = cls.env["product.product"].create({
|
|
"name": "Membership Card",
|
|
"membership": True,
|
|
"list_price": 50.0,
|
|
"membership_date_from": today.replace(month=1, day=1),
|
|
"membership_date_to": today.replace(month=12, day=31),
|
|
})
|
|
cls.regular_product = cls.env["product.product"].create({
|
|
"name": "Regular Mug",
|
|
"membership": False,
|
|
"list_price": 10.0,
|
|
})
|
|
cls.no_user_partner = cls.env["res.partner"].create({
|
|
"firstname": "Backend",
|
|
"lastname": "Partner",
|
|
})
|
|
|
|
# -- RF-07 / RF-default ------------------------------------------------
|
|
|
|
def test_01_website_default_flag(self):
|
|
new_website = self.env["website"].create({"name": "Aux site"})
|
|
self.assertTrue(new_website.membership_signup_required)
|
|
|
|
# -- RF-01 helper -------------------------------------------------------
|
|
|
|
def test_02_is_required_membership_product_anonymous(self):
|
|
self.assertTrue(
|
|
self.website._membership_signup_required_for(
|
|
self.membership_product.id, is_public=True
|
|
)
|
|
)
|
|
|
|
# -- RF-05 -------------------------------------------------------------
|
|
|
|
def test_03_is_required_non_membership_product(self):
|
|
self.assertFalse(
|
|
self.website._membership_signup_required_for(
|
|
self.regular_product.id, is_public=True
|
|
)
|
|
)
|
|
|
|
# -- RF-06 -------------------------------------------------------------
|
|
|
|
def test_04_is_required_authenticated_user(self):
|
|
self.assertFalse(
|
|
self.website._membership_signup_required_for(
|
|
self.membership_product.id, is_public=False
|
|
)
|
|
)
|
|
|
|
# -- RF-07 -------------------------------------------------------------
|
|
|
|
def test_05_is_required_disabled_on_website(self):
|
|
self.website.membership_signup_required = False
|
|
self.assertFalse(
|
|
self.website._membership_signup_required_for(
|
|
self.membership_product.id, is_public=True
|
|
)
|
|
)
|
|
|
|
# -- RF-03 -------------------------------------------------------------
|
|
|
|
def test_06_signup_scope_override_with_marker(self):
|
|
Users = self.env["res.users"]
|
|
# No marker -> delegates to super (b2b because of setUpClass).
|
|
with MockRequest(self.env, website=self.website) as mock_request:
|
|
mock_request.httprequest.args = werkzeug.datastructures.MultiDict()
|
|
self.assertEqual(Users._get_signup_invitation_scope(), "b2b")
|
|
# Query param marker -> b2c.
|
|
with MockRequest(self.env, website=self.website) as mock_request:
|
|
mock_request.httprequest.args = werkzeug.datastructures.MultiDict(
|
|
{"membership_signup": "1"}
|
|
)
|
|
self.assertEqual(Users._get_signup_invitation_scope(), "b2c")
|
|
# Session flag marker -> b2c.
|
|
with MockRequest(self.env, website=self.website) as mock_request:
|
|
mock_request.httprequest.args = werkzeug.datastructures.MultiDict()
|
|
mock_request.session["membership_signup_active"] = True
|
|
self.assertEqual(Users._get_signup_invitation_scope(), "b2c")
|
|
# Marker removed again -> back to b2b.
|
|
with MockRequest(self.env, website=self.website) as mock_request:
|
|
mock_request.httprequest.args = werkzeug.datastructures.MultiDict()
|
|
self.assertEqual(Users._get_signup_invitation_scope(), "b2b")
|
|
|
|
# -- RF-09 -------------------------------------------------------------
|
|
|
|
def test_07_prepare_signup_values_firstname_lastname(self):
|
|
controller = AuthSignupHome()
|
|
qcontext = {
|
|
"login": "joohn.doe@example.com",
|
|
"password": "verystrongpwd",
|
|
"confirm_password": "verystrongpwd",
|
|
"firstname": "John",
|
|
"lastname": "Doe",
|
|
}
|
|
with MockRequest(self.env, website=self.website):
|
|
values = controller._prepare_signup_values(qcontext)
|
|
self.assertEqual(values.get("firstname"), "John")
|
|
self.assertEqual(values.get("lastname"), "Doe")
|
|
# partner_firstname: `name` is composed (lastname + firstname, or
|
|
# firstname + lastname depending on _get_names_order) and added by
|
|
# our override so that the core signup check (no name or partner)
|
|
# passes. partner_firstname's `res.partner.create` will later drop
|
|
# this composed `name` and recompute it from the split fields.
|
|
self.assertIn("name", values)
|
|
self.assertIn("John", values["name"])
|
|
self.assertIn("Doe", values["name"])
|
|
|
|
# -- RF-08 -------------------------------------------------------------
|
|
|
|
def test_08_backend_sale_order_with_membership_product_without_user(self):
|
|
order = self.env["sale.order"].create({
|
|
"partner_id": self.no_user_partner.id,
|
|
"order_line": [(0, 0, {
|
|
"product_id": self.membership_product.id,
|
|
"product_uom_qty": 1.0,
|
|
})],
|
|
})
|
|
self.assertTrue(order)
|
|
self.assertEqual(order.order_line.product_id, self.membership_product)
|
|
# Confirming the SO drives membership creation (core `membership`).
|
|
order.action_confirm()
|
|
self.assertEqual(order.state, "sale")
|
|
|
|
# -- Phone not mandatory at checkout (EMES) ----------------------------
|
|
|
|
def test_09_phone_not_mandatory_address_fields(self):
|
|
"""`phone` must not be part of the mandatory checkout fields, for
|
|
any address (billing or delivery) and any flow on the EMES website.
|
|
The core default (`website_sale/controllers/main.py:
|
|
_get_mandatory_address_fields`) includes 'phone'; our override drops
|
|
it. The frontend `address.js` then no longer marks the input
|
|
`:required` nor shows the asterisk, and the server-side
|
|
`_check_billing_address` / `_check_delivery_address` no longer
|
|
reject empty phones.
|
|
"""
|
|
country = self.env.ref("base.es")
|
|
ctrl = WebsiteSaleMembershipSignup()
|
|
fields = ctrl._get_mandatory_address_fields(country)
|
|
self.assertNotIn("phone", fields)
|
|
# Default mandatory fields still present.
|
|
self.assertIn("name", fields)
|
|
self.assertIn("street", fields)
|
|
self.assertIn("city", fields)
|
|
self.assertIn("country_id", fields)
|
|
|
|
def test_10_phone_not_in_portal_mandatory_fields(self):
|
|
"""`phone` must also be dropped from the portal-side mandatory
|
|
field list (`portal/controllers/portal.py:_get_mandatory_fields`
|
|
returns `["name", "phone", "email", "street", "city",
|
|
"country_id"]`). `website_sale`'s
|
|
`_get_mandatory_billing_address_fields` UNIONS that set with the
|
|
address set from `_get_mandatory_address_fields`, so even with the
|
|
address override alone, 'phone' would come back via the portal
|
|
path for billing. Hence this second override.
|
|
"""
|
|
ctrl = WebsiteSaleMembershipSignup()
|
|
fields = ctrl._get_mandatory_fields()
|
|
self.assertNotIn("phone", fields)
|
|
# Other portal mandatory fields still present.
|
|
self.assertIn("name", fields)
|
|
self.assertIn("email", fields)
|
|
self.assertIn("country_id", fields)
|
|
|
|
def test_11_phone_not_in_mandatory_billing_address_fields(self):
|
|
"""End-to-end check of the billing set: the union of
|
|
`_get_mandatory_address_fields` + `_get_mandatory_fields` (which is
|
|
what `_get_mandatory_billing_address_fields` returns) must NOT
|
|
contain 'phone'.
|
|
"""
|
|
country = self.env.ref("base.es")
|
|
ctrl = WebsiteSaleMembershipSignup()
|
|
billing_fields = ctrl._get_mandatory_billing_address_fields(country)
|
|
self.assertNotIn("phone", billing_fields)
|
|
self.assertIn("email", billing_fields) |