# Copyright 2026 Criptomart # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl). from odoo import fields, http from odoo.http import request from odoo.tools.translate import _ from odoo.addons.website_membership.controllers.main import ( WebsiteMembership as BaseWebsiteMembership, ) class WebsiteMembership(BaseWebsiteMembership): @http.route() def members( self, membership_id=None, country_name=None, country_id=0, page=1, **post ): request.env = request.env( context=dict(request.env.context, include_associate_members=True) ) response = super().members( membership_id=membership_id, country_name=country_name, country_id=country_id, page=page, **post, ) self._add_associate_members(response, membership_id, country_id, page, post) return response def _add_associate_members( self, response, membership_id, country_id, page, post ): values = response.qcontext memberships_partner_ids = values.get("memberships_partner_ids", {}) if not memberships_partner_ids: return post_name = post.get("search") or post.get("name", "") host_keys = {} for key, ids in memberships_partner_ids.items(): for partner_id in ids: host_keys.setdefault(partner_id, []).append(key) host_ids = set(host_keys.keys()) hosts = { pid: partner for pid, partner in values.get("partners", {}).items() if pid in host_ids } associates = ( request.env["membership.membership_line"] .sudo() ._get_associate_partners( tuple(host_ids), country_id=country_id, post_name=post_name ) ) new_memberships_partner_ids = self._filter_displayed_hosts( memberships_partner_ids, hosts, country_id, post_name ) for associate in associates: keys = host_keys.get(associate.associate_member.id) if not keys: continue for key in keys: if associate.id not in new_memberships_partner_ids[key]: new_memberships_partner_ids[key].append(associate.id) values["memberships_partner_ids"] = { key: ids for key, ids in new_memberships_partner_ids.items() if ids } displayed_ids = set( pid for ids in values["memberships_partner_ids"].values() for pid in ids ) values["partners"] = { p.id: p for p in request.env["res.partner"] .sudo() .browse(list(displayed_ids)) } all_host_ids, all_free_host_ids, all_associates = ( self._get_all_visible_ids(membership_id, country_id, post_name) ) self._recompute_countries( values, all_host_ids, all_free_host_ids, all_associates, country_id ) self._update_google_map(values, country_id, post_name) self._update_pager( values, membership_id, country_id, page, post, all_host_ids, all_free_host_ids, ) def _filter_displayed_hosts( self, memberships_partner_ids, hosts, country_id, post_name ): return { key: [ pid for pid in ids if pid not in hosts or self._partner_matches_filters(hosts[pid], country_id, post_name) ] for key, ids in memberships_partner_ids.items() } def _partner_matches_filters(self, partner, country_id, post_name): if country_id and partner.country_id.id != country_id: return False if post_name and not self._partner_matches_search(partner, post_name): return False return True def _partner_matches_search(self, partner, post_name): term = post_name.lower() if term in (partner.name or "").lower(): return True if term in (partner.website_description or "").lower(): return True return False def _get_all_visible_ids(self, membership_id, country_id, post_name): free_selected = membership_id in (None, "free") if membership_id == "free": all_host_ids = set() else: all_host_ids = self._get_all_host_ids( membership_id, country_id, post_name ) all_free_host_ids = ( self._get_all_free_host_ids(country_id, post_name) if free_selected else set() ) all_associates = ( request.env["membership.membership_line"] .sudo() ._get_associate_partners( tuple(all_host_ids | all_free_host_ids), country_id=country_id, post_name=post_name, ) ) return all_host_ids, all_free_host_ids, all_associates def _get_all_host_ids(self, membership_id, country_id, post_name): Product = request.env["product.product"] MembershipLine = request.env["membership.membership_line"] today = fields.Date.today() products = Product.sudo().search([("membership", "=", True)]) domain = [ ("partner.website_published", "=", True), ("state", "=", "paid"), ("date_to", ">=", today), ("date_from", "<=", today), ("membership_id", "in", products.ids), ] if membership_id and membership_id != "free": domain.append(("membership_id", "=", int(membership_id))) if post_name: domain += [ "|", ("partner.name", "ilike", post_name), ("partner.website_description", "ilike", post_name), ] if country_id: domain.append(("partner.country_id", "=", country_id)) lines = MembershipLine.sudo().search(domain) return set(lines.partner.ids) def _get_all_free_host_ids(self, country_id, post_name): domain = [ ("membership_state", "=", "free"), ("website_published", "=", True), ] if post_name: domain += [ "|", ("name", "ilike", post_name), ("website_description", "ilike", post_name), ] if country_id: domain.append(("country_id", "=", country_id)) return set(request.env["res.partner"].sudo().search(domain).ids) def _recompute_countries( self, values, all_host_ids, all_free_host_ids, all_associates, country_id ): visible_ids = all_host_ids | all_free_host_ids | set(all_associates.ids) values["countries"] = self._build_countries(visible_ids, country_id) def _build_countries(self, visible_ids, country_id): Partner = request.env["res.partner"] Country = request.env["res.country"] current_country = None countries = Partner.sudo().read_group( [("id", "in", list(visible_ids))], ["__count"], groupby="country_id", ) countries_total = sum( country_dict["country_id_count"] for country_dict in countries ) if country_id: current_country = Country.browse(country_id).read(["id", "name"])[0] if not any( x["country_id"] and x["country_id"][0] == country_id for x in countries ): countries.append( { "country_id_count": 0, "country_id": (country_id, current_country["name"]), } ) countries = [d for d in countries if d["country_id"]] countries.sort(key=lambda d: d["country_id"][1]) countries.insert( 0, { "country_id_count": countries_total, "country_id": (0, _("All Countries")), }, ) return countries def _update_google_map(self, values, country_id, post_name): map_ids_str = values.get("google_map_partner_ids", "") if not map_ids_str: return map_ids = [int(pid) for pid in map_ids_str.split(",") if pid] if not map_ids: return partners = request.env["res.partner"].sudo().browse(map_ids) if country_id: partners = partners.filtered( lambda p: p.country_id.id == country_id ) if post_name: partners = partners.filtered( lambda p: self._partner_matches_search(p, post_name) ) values["google_map_partner_ids"] = ",".join( str(pid) for pid in partners.ids ) def _update_pager( self, values, membership_id, country_id, page, post, all_host_ids, all_free_host_ids, ): post_name = post.get("search") or post.get("name", "") if membership_id == "free": displayed_host_ids = set() else: host_records = request.env["res.partner"].sudo().browse( list(all_host_ids) ) displayed_host_ids = { host.id for host in host_records if self._partner_matches_filters(host, country_id, post_name) } count_members = len(displayed_host_ids) + len(all_free_host_ids) limit = self._references_per_page base_url = "/members%s%s" % ( "/association/%s" % membership_id if membership_id else "", "/country/%s" % country_id if country_id else "", ) values["pager"] = request.website.pager( url=base_url, total=count_members, page=page, step=limit, scope=7, url_args=post, ) values["search_count"] = count_members