# Copyright 2026 Criptomart # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). from odoo import fields from odoo.tests import HttpCase, tagged from odoo.addons.membership.tests.common import TestMembershipCommon @tagged("post_install", "-at_install") class TestWebsiteMembershipAssociate(HttpCase, TestMembershipCommon): @classmethod def setUpClass(cls): super().setUpClass() cls.website = cls.env.ref("website.default_website") cls.country_us = cls.env.ref("base.us") cls.country_be = cls.env.ref("base.be") cls.membership_1.write({"website_published": True}) cls.partner_1.write( { "website_published": True, "is_company": True, "country_id": cls.country_us.id, } ) invoice = cls.partner_1.create_membership_invoice(cls.membership_1, 75.0) invoice.action_post() cls.env["account.payment.register"].with_context( active_model="account.move", active_ids=invoice.ids ).create( { "amount": 86.25, "payment_method_line_id": cls.inbound_payment_method_line.id, } )._create_payments() cls.partner_1._compute_membership_state() cls.associate = cls.env["res.partner"].create( { "name": "Associate Paid", "associate_member": cls.partner_1.id, "website_published": True, "is_company": True, "country_id": cls.country_be.id, "website_description": "Sustainable farming", } ) cls.partner_2.write( { "website_published": True, "is_company": True, "country_id": cls.country_us.id, } ) cls.associate_free = cls.env["res.partner"].create( { "name": "Associate Free", "associate_member": cls.partner_2.id, "website_published": True, "is_company": True, "country_id": cls.country_us.id, } ) def test_host_membership_state_is_paid(self): self.assertEqual(self.partner_1.membership_state, "paid") def test_members_page_lists_host_and_associate(self): response = self.url_open("/members") self.assertEqual(response.status_code, 200) self.assertIn(self.partner_1.name, response.text) self.assertIn(self.associate.name, response.text) def test_membership_filter_includes_associate(self): response = self.url_open("/members/association/%d" % self.membership_1.id) self.assertEqual(response.status_code, 200) self.assertIn(self.partner_1.name, response.text) self.assertIn(self.associate.name, response.text) def test_free_membership_filter_includes_associate(self): response = self.url_open("/members/association/free") self.assertEqual(response.status_code, 200) self.assertIn(self.partner_2.name, response.text) self.assertIn(self.associate_free.name, response.text) def test_country_filter_counts_associate(self): response = self.url_open("/members/country/%d" % self.country_be.id) self.assertEqual(response.status_code, 200) self.assertIn(self.associate.name, response.text) self.assertNotIn(self.partner_1.name, response.text) self.assertNotIn(self.partner_2.name, response.text) self.assertNotIn(self.associate_free.name, response.text) def test_search_finds_associate(self): response = self.url_open("/members?search=Sustainable+farming") self.assertEqual(response.status_code, 200) self.assertIn(self.associate.name, response.text) self.assertNotIn(self.partner_1.name, response.text) def test_published_companies_map_includes_associate(self): host_line = self.partner_1.member_lines[0] companies = host_line._get_published_companies(limit=2000) self.assertIn(self.partner_1.id, companies) self.assertIn(self.associate.id, companies) @tagged("post_install", "-at_install") class TestWebsiteMembershipAssociatePagination(HttpCase, TestMembershipCommon): @classmethod def setUpClass(cls): super().setUpClass() cls.website = cls.env.ref("website.default_website") cls.country_es = cls.env.ref("base.es") cls.membership_1.write({"website_published": True}) host_vals = [ { "name": "Host Page %d" % i, "website_published": True, "is_company": True, "country_id": cls.country_es.id, } for i in range(20) ] cls.paginated_hosts = cls.env["res.partner"].create(host_vals) invoices = cls.paginated_hosts.create_membership_invoice( cls.membership_1, 75.0 ) invoices.action_post() cls.env["account.payment.register"].with_context( active_model="account.move", active_ids=invoices.ids ).create( { "amount": sum(invoices.mapped("amount_total")), "payment_method_line_id": cls.inbound_payment_method_line.id, } )._create_payments() cls.paginated_hosts._compute_membership_state() associate_vals = [ { "name": "Associate Page %d" % i, "associate_member": cls.paginated_hosts[i].id, "website_published": True, "is_company": True, "country_id": cls.country_es.id, } for i in range(20) ] cls.paginated_associates = cls.env["res.partner"].create(associate_vals) def test_pagination_hosts_plus_associates(self): response = self.url_open("/members/association/%d" % self.membership_1.id) self.assertEqual(response.status_code, 200) # Page 1 contains all 20 hosts plus their 20 associates. self.assertIn("Host Page 0", response.text) self.assertIn("Host Page 19", response.text) self.assertIn("Associate Page 0", response.text) self.assertIn("Associate Page 19", response.text) # No pagination placeholder from a second page is expected. self.assertNotIn("Host Page 20", response.text) self.assertNotIn("Associate Page 20", response.text) @tagged("post_install", "-at_install") class TestMembershipLineAssociate(TestMembershipCommon): @classmethod def setUpClass(cls): super().setUpClass() cls.country_us = cls.env.ref("base.us") cls.country_be = cls.env.ref("base.be") cls.membership_1.write({"website_published": True}) cls.partner_1.write( { "website_published": True, "is_company": True, "country_id": cls.country_us.id, "website_description": "Host description", } ) invoice = cls.partner_1.create_membership_invoice(cls.membership_1, 75.0) invoice.action_post() cls.env["account.payment.register"].with_context( active_model="account.move", active_ids=invoice.ids ).create( { "amount": invoice.amount_total, "payment_method_line_id": cls.inbound_payment_method_line.id, } )._create_payments() cls.partner_1._compute_membership_state() cls.associate = cls.env["res.partner"].create( { "name": "Associate Paid", "associate_member": cls.partner_1.id, "website_published": True, "is_company": True, "country_id": cls.country_be.id, "website_description": "Sustainable farming", } ) def _base_domain(self): today = fields.Date.today() return [ ("partner.website_published", "=", True), ("state", "=", "paid"), ("date_to", ">=", today), ("date_from", "<=", today), ("membership_id", "in", self.membership_1.ids), ] def test_search_excludes_host_when_only_associate_matches_without_context(self): domain = self._base_domain() domain += [ "|", ("partner.name", "ilike", "Sustainable farming"), ("partner.website_description", "ilike", "Sustainable farming"), ] lines = self.env["membership.membership_line"].search(domain) self.assertNotIn(self.partner_1.id, lines.partner.ids) def test_search_includes_host_when_associate_name_matches(self): domain = self._base_domain() domain += [ "|", ("partner.name", "ilike", "Sustainable farming"), ("partner.website_description", "ilike", "Sustainable farming"), ] lines = ( self.env["membership.membership_line"] .with_context(include_associate_members=True) .search(domain) ) self.assertIn(self.partner_1.id, lines.partner.ids) def test_search_includes_host_when_associate_country_matches(self): domain = self._base_domain() domain.append(("partner.country_id", "=", self.country_be.id)) lines = ( self.env["membership.membership_line"] .with_context(include_associate_members=True) .search(domain) ) self.assertIn(self.partner_1.id, lines.partner.ids) def test_get_associate_partners_filters_by_country(self): MembershipLine = self.env["membership.membership_line"] match = MembershipLine._get_associate_partners( (self.partner_1.id,), country_id=self.country_be.id ) self.assertEqual(match, self.associate) no_match = MembershipLine._get_associate_partners( (self.partner_1.id,), country_id=self.country_us.id ) self.assertFalse(no_match) def test_get_associate_partners_filters_by_search(self): MembershipLine = self.env["membership.membership_line"] match = MembershipLine._get_associate_partners( (self.partner_1.id,), post_name="Sustainable" ) self.assertEqual(match, self.associate) no_match = MembershipLine._get_associate_partners( (self.partner_1.id,), post_name="Nonexistent" ) self.assertFalse(no_match) def test_published_companies_includes_associate(self): host_line = self.partner_1.member_lines[0] companies = host_line._get_published_companies(limit=2000) self.assertIn(self.partner_1.id, companies) self.assertIn(self.associate.id, companies)