add website_membership_associate

This commit is contained in:
Luis 2026-07-28 09:29:14 +02:00
parent 40d7cc8772
commit 31d53c428c
12 changed files with 837 additions and 0 deletions

View file

@ -0,0 +1,293 @@
# 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