[FIX] website_sale_aplicoop: Move template logic to controller for QWeb compatibility

This fixes the persistent 'TypeError: NoneType object is not callable' error
by moving all complex conditional logic out of the template and into the
Python controller.

QWeb has strict parsing limitations - it fails on:
- Complex nested conditionals in t-set
- Chained 'or' operators in t-attf-* attributes
- Deep object attribute chains (uom_id.category_id.name)

Solution: Pre-process all display values in controller via _prepare_product_display_info()
which creates product_display_info dict with safe values ready for template.

Template now uses simple dict.get() calls without any conditional logic.
This commit is contained in:
snt 2026-02-16 23:28:36 +01:00
parent e29d7e41d4
commit 5721687488
2 changed files with 55 additions and 10 deletions

View file

@ -388,6 +388,40 @@ class AplicoopWebsiteSale(WebsiteSale):
)
return False
def _prepare_product_display_info(self, product, product_price_info):
"""Prepare all display information for a product in a QWeb-safe way.
This function pre-processes all values that might be None or require
conditional logic, so the template can use simple variable references
without complex expressions that confuse QWeb's parser.
Args:
product: product.template record
product_price_info: dict with 'price', 'list_price', etc.
Returns:
dict with all pre-processed display values ready for template
"""
# Safety: Get price, ensure it's a float
price_data = product_price_info.get(product.id, {})
price = (
price_data.get("price", product.list_price)
if price_data
else product.list_price
)
price_safe = float(price) if price else 0.0
# Safety: Get UoM category name
uom_category_name = ""
if product.uom_id:
if product.uom_id.category_id:
uom_category_name = product.uom_id.category_id.name or ""
return {
"display_price": price_safe,
"safe_uom_category": uom_category_name,
}
def _validate_confirm_request(self, data):
"""Validate all requirements for confirm order request.
@ -1029,6 +1063,15 @@ class AplicoopWebsiteSale(WebsiteSale):
"tax_included": False,
}
# Prepare display info for each product (QWeb-safe: all values pre-processed)
# This ensures the template can use simple variable references without complex conditionals
product_display_info = {}
for product in products:
display_info = self._prepare_product_display_info(
product, product_price_info
)
product_display_info[product.id] = display_info
# Calculate available tags with product count (only show tags that are actually used and visible)
# Build a dict: {tag_id: {'id': tag_id, 'name': tag_name, 'count': num_products}}
available_tags_dict = {}
@ -1099,6 +1142,7 @@ class AplicoopWebsiteSale(WebsiteSale):
"day_names": self._get_day_names(env=request.env),
"product_supplier_info": product_supplier_info,
"product_price_info": product_price_info,
"product_display_info": product_display_info,
"labels": labels,
"labels_json": json.dumps(labels, ensure_ascii=False),
"lazy_loading_enabled": lazy_loading_enabled,
@ -1225,6 +1269,14 @@ class AplicoopWebsiteSale(WebsiteSale):
"published_tags": published_tags,
}
# Prepare display info for each product (QWeb-safe: all values pre-processed)
product_display_info = {}
for product in products_page:
display_info = self._prepare_product_display_info(
product, product_price_info
)
product_display_info[product.id] = display_info
# Get labels
labels = self.get_checkout_labels()
@ -1236,6 +1288,7 @@ class AplicoopWebsiteSale(WebsiteSale):
"filtered_product_tags": filtered_products,
"product_supplier_info": product_supplier_info,
"product_price_info": product_price_info,
"product_display_info": product_display_info,
"labels": labels,
"has_next": has_next,
"next_page": page + 1,

View file

@ -1161,17 +1161,9 @@
</small>
</p>
</t>
<t
t-set="price_info"
t-value="product_price_info.get(product.id, {})"
/>
<t
t-set="display_price_value"
t-value="price_info.get('price')"
/>
<t
t-set="display_price"
t-value="display_price_value or product.list_price or 0.0"
t-value="product_display_info.get(product.id, {}).get('display_price', 0.0)"
/>
<t
t-set="base_price"
@ -1217,7 +1209,7 @@
</div>
<t
t-set="safe_uom_category"
t-value="product.uom_id.category_id.name if (product.uom_id and product.uom_id.category_id) else ''"
t-value="product_display_info.get(product.id, {}).get('safe_uom_category', '')"
/>
<form
class="add-to-cart-form"