addons-cm/website_sale_aplicoop/views/website_templates.xml

690 lines
52 KiB
XML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?xml version='1.0' encoding='utf-8'?>
<odoo>
<data>
<template id="eskaera_page" name="Eskaera Page">
<t t-call="website.layout">
<div id="wrap" class="eskaera-page oe_structure oe_empty" data-name="Eskaera Orders">
<div class="container">
<div class="row">
<div class="col-lg-12">
<h1>Available Orders</h1>
<p class="text-muted" role="status">Browse and select an order to view its products.</p>
</div>
</div>
<div class="row mt-4">
<div class="col-lg-12">
<div class="oe_structure oe_empty" data-name="Before Orders" />
<t t-if="active_orders">
<div class="eskaera-orders eskaera-orders-grid">
<t t-foreach="active_orders" t-as="order">
<div class="eskaera-order-card-wrapper">
<div class="eskaera-order-card">
<div class="card-body">
<div class="position-absolute order-badge-position">
<span class="badge bg-primary d-flex align-items-center gap-2 order-badge-custom">
<i class="fa fa-shopping-bag" />
<strong>
<t t-esc="order.available_products_count" />
</strong>
</span>
</div>
<a t-attf-href="/eskaera/{{ order.id }}" class="eskaera-order-card-link" t-attf-aria-label="View products for order {{ order.name }}">
<div class="card-header-top d-flex gap-2 align-items-center order-header-margin">
<t t-set="image_to_show" t-value="order.image or (order.group_ids[0].image_1920 if order.group_ids else False)" />
<t t-if="image_to_show">
<img t-att-src="image_data_uri(image_to_show)" alt="Order image" class="order-thumbnail-sm" />
</t>
<div class="flex-grow-1">
<h5 class="card-title mb-1">
<t t-esc="order.name" />
</h5>
<t t-if="order.description">
<p class="text-muted small mb-0 order-desc-text">
<t t-esc="(order.description[:150] + '...') if len(order.description) &gt; 200 else order.description" />
</p>
</t>
</div>
</div>
</a>
<div class="card-meta-compact mt-3">
<table class="meta-table">
<tbody>
<tr class="meta-row">
<td class="meta-label-cell" t-if="order.type">
<span>Order Type</span>
</td>
<td class="meta-value-cell">
<t t-if="order.type">
<t t-esc="dict(order.fields_get('type', ['selection'])['type']['selection']).get(order.type, order.type)" />
</t>
</td>
</tr>
<tr class="meta-row">
<td class="meta-label-cell" t-if="order.period">
<span>Order Period</span>
</td>
<td class="meta-value-cell">
<t t-if="order.period">
<t t-esc="dict(order.fields_get('period', ['selection'])['period']['selection']).get(order.period, order.period)" />
</t>
</td>
</tr>
<tr class="meta-row">
<td class="meta-label-cell" t-if="order.cutoff_day">
<span>Cutoff Day</span>
</td>
<td class="meta-value-cell">
<t t-if="order.cutoff_day">
<t t-esc="day_names[int(order.cutoff_day) % 7]" /> - <t t-esc="order.cutoff_date.strftime('%d/%m')" />
</t>
</td>
</tr>
<tr class="meta-row">
<td class="meta-label-cell" t-if="order.pickup_day and order.pickup_date">
<span>Pickup Day</span>
</td>
<td class="meta-value-cell">
<t t-if="order.pickup_day and order.pickup_date">
<t t-esc="day_names[int(order.pickup_day) % 7]" /> - <t t-esc="order.pickup_date.strftime('%d/%m')" />
</t>
</td>
</tr>
<tr class="meta-row">
<td class="meta-label-cell" t-if="order.end_date">
<span>Open until</span>
</td>
<td class="meta-value-cell">
<t t-if="order.end_date">
<t t-esc="order.end_date.strftime('%d/%m/%Y')" />
</t>
</td>
</tr>
<tr class="meta-row">
<td class="meta-label-cell">
<span>Home Delivery</span>
</td>
<td class="meta-value-cell">
<t t-if="order.home_delivery">
<span class="badge bg-success">Yes</span>
</t>
<t t-else="">
<span class="badge bg-warning">No</span>
</t>
</td>
</tr>
<tr class="meta-row">
<td class="meta-label-cell" t-if="order.delivery_date and order.home_delivery">
<span>Delivery</span>
</td>
<td class="meta-value-cell">
<t t-if="order.delivery_date and order.home_delivery">
<t t-esc="day_names[order.delivery_date.weekday()]" /> - <t t-esc="order.delivery_date.strftime('%d/%m')" />
</t>
</td>
</tr>
</tbody>
</table>
</div>
<a t-attf-href="/eskaera/{{ order.id }}" class="btn btn-primary btn-sm" aria-label="Browse products for {{ order.name }}">
<i class="fa fa-shopping-bag" aria-hidden="true" t-translation="off" />
<span>Browse Products</span>
</a>
</div>
</div>
</div>
</t>
</div>
</t>
<t t-else="">
<div class="eskaera-empty-state">
<div class="alert alert-info" role="status" aria-live="polite">
<p>No group orders available this week.</p>
</div>
</div>
</t>
<div class="oe_structure oe_empty mt-4" data-name="After Orders" />
</div>
</div>
</div>
</div>
<script type="text/javascript">
(function() {
'use strict';
// console.log('[eskaera_page] Loading translated labels for category selector');
// Fetch translated labels from endpoint
fetch('/eskaera/labels', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-CSRFToken': odoo.csrf_token || ''
}
})
.then(response =&gt; response.json())
.then(labels =&gt; {
//console.log('[eskaera_page] Labels received:', labels);
// Update category selector first option text
var categorySelect = document.getElementById('realtime-category-select');
if (categorySelect &amp;&amp; categorySelect.options[0] &amp;&amp; labels &amp;&amp; labels.all_categories) {
categorySelect.options[0].text = labels.all_categories;
// console.log('[eskaera_page] Updated category selector to:', labels.all_categories);
} else {
console.log('[eskaera_page] Could not update category selector');
console.log(' categorySelect:', !!categorySelect);
console.log(' categorySelect.options[0]:', categorySelect ? !!categorySelect.options[0] : false);
console.log(' labels:', !!labels);
console.log(' labels.all_categories:', labels ? labels.all_categories : 'N/A');
}
})
.catch(error =&gt; {
console.error('[eskaera_page] Error fetching labels:', error);
});
})();
</script>
</t>
</template>
<template id="confirm_message_snippet" name="Confirm Message Snippet">
<t t-esc="_('Thank you! Your order has been confirmed.')" />
</template>
<template id="confirm_pickup_label_snippet" name="Confirm Pickup Label Snippet">
<t t-esc="_('Pickup Day')" />
</template>
<template id="order_header" name="Order Header">
<div t-att-class="header_class or 'eskaera-order-header'">
<div class="d-flex gap-5 align-items-center mb-4">
<t t-set="image_to_show" t-value="group_order.image or (group_order.group_ids[0].image_1920 if group_order.group_ids else False)" />
<t t-if="image_to_show">
<img t-att-src="image_data_uri(image_to_show)" alt="Order image" class="order-thumbnail-md" />
</t>
<div class="flex-grow-1">
<h1 class="mb-2">
<t t-esc="header_title or group_order.name" />
</h1>
<t t-if="group_order.description">
<p class="text-muted mb-0 order-desc-full">
<t t-esc="group_order.description" />
</p>
</t>
</div>
</div>
</div>
</template>
<template id="eskaera_shop" name="Eskaera Shop">
<t t-call="website.layout">
<div id="wrap" class="eskaera-shop-page oe_structure oe_empty" data-name="Eskaera Shop" t-attf-data-delivery-product-id="{{ delivery_product_id or '' }}" t-attf-data-delivery-product-name="{{ delivery_product_name or '' }}" t-attf-data-delivery-product-price="{{ delivery_product_price or '' }}" t-attf-data-home-delivery-enabled="{{ 'true' if group_order.home_delivery else 'false' }}">
<div class="container">
<div class="row mb-4">
<div class="col-lg-12">
<t t-call="website_sale_aplicoop.order_header">
<t t-set="header_class" t-value="'eskaera-order-header'" />
</t>
<div class="eskaera-order-header">
<div class="order-info-grid">
<div class="info-item">
<span t-att-class="'info-label'">Consumer Groups</span>
<span class="info-value">
<t t-esc="', '.join(group_order.group_ids.mapped('name'))" />
</span>
</div>
<t t-if="group_order.cutoff_day">
<div class="info-item">
<span t-att-class="'info-label'">Cutoff Day</span>
<span class="info-value">
<t t-esc="day_names[int(group_order.cutoff_day) % 7]" /> (<t t-esc="group_order.cutoff_date.strftime('%d/%m/%Y')" />)</span>
</div>
</t>
<t t-if="group_order.pickup_day">
<div class="info-item">
<span t-att-class="'info-label'">Store Pickup Day</span>
<span class="info-value">
<t t-esc="day_names[int(group_order.pickup_day) % 7]" /> (<t t-esc="group_order.pickup_date.strftime('%d/%m/%Y')" />)</span>
</div>
</t>
<t t-if="group_order.delivery_date and group_order.home_delivery">
<div class="info-item">
<span t-att-class="'info-label'">Home Delivery Day</span>
<span class="info-value">
<t t-esc="day_names[group_order.delivery_date.weekday()]" /> (<t t-esc="group_order.delivery_date.strftime('%d/%m/%Y')" />)</span>
</div>
</t>
<t t-if="group_order.start_date">
<div class="info-item">
<span t-att-class="'info-label'">Open From</span>
<span class="info-value">
<t t-esc="group_order.start_date.strftime('%d/%m/%Y')" />
</span>
</div>
</t>
<t t-if="group_order.end_date">
<div class="info-item">
<span t-att-class="'info-label'">Open Until</span>
<span class="info-value">
<t t-esc="group_order.end_date.strftime('%d/%m/%Y')" />
</span>
</div>
</t>
</div>
</div>
</div>
</div>
<div class="mb-3" id="realtimeSearch-filters">
<div class="row g-2">
<div class="col-md-7">
<div style="position: relative;">
<input type="text" id="realtime-search-input" class="form-control realtime-search-box search-input-styled" placeholder="Search products..." autocomplete="off" style="padding-right: 40px;" />
<button type="button" id="clear-search-btn" class="btn btn-link" style="position: absolute; right: 5px; top: 50%; transform: translateY(-50%); padding: 0; width: 30px; height: 30px; display: none; color: #6c757d; text-decoration: none; font-size: 1.5rem; line-height: 1;" aria-label="Clear search" title="Clear search">
×
</button>
</div>
</div>
<div class="col-md-5">
<select name="category" id="realtime-category-select" class="form-select">
<option value="">Browse Product Categories</option>
<t t-call="website_sale_aplicoop.category_hierarchy_options">
<t t-set="categories" t-value="category_hierarchy" />
<t t-set="depth" t-value="0" />
</t>
</select>
</div>
</div>
<t t-if="available_tags">
<div class="row mt-3">
<div class="col-12">
<div id="tag-filter-container" class="tag-filter-badges">
<t t-foreach="available_tags" t-as="tag">
<t t-if="tag['color']">
<button type="button" class="badge tag-filter-badge" t-att-data-tag-id="tag['id']" t-att-data-tag-name="tag['name']" t-att-data-tag-color="tag['color']" t-attf-style="background-color: {{ tag['color'] }} !important; border-color: {{ tag['color'] }} !important; color: #ffffff !important;" data-toggle="tag-filter">
<span t-esc="tag['name']" /> (<span class="tag-count" t-esc="tag['count']" />)
</button>
</t>
<t t-else="">
<button type="button" class="badge tag-filter-badge tag-use-theme-color" t-att-data-tag-id="tag['id']" t-att-data-tag-name="tag['name']" data-tag-color="" data-toggle="tag-filter">
<span t-esc="tag['name']" /> (<span class="tag-count" t-esc="tag['count']" />)
</button>
</t>
</t>
</div>
</div>
</div>
</t>
</div>
<div class="row g-2">
<div class="col-lg-9">
<div class="oe_structure oe_empty" data-name="Before Products Filter" />
<t t-if="products">
<div class="products-grid" id="products-grid">
<t t-call="website_sale_aplicoop.eskaera_shop_products" />
</div>
<div id="eskaera-config" t-attf-data-order-id="{{ group_order.id }}" t-attf-data-search="{{ search_query }}" t-attf-data-category="{{ selected_category }}" t-attf-data-per-page="{{ per_page }}" t-attf-data-current-page="{{ current_page }}" t-attf-data-has-next="{{ 'true' if has_next else 'false' }}" class="d-none">
</div>
<t t-if="lazy_loading_enabled and has_next">
<div id="infinite-scroll-container" class="row mt-4">
<div class="col-12 text-center">
<div id="loading-spinner" class="d-none" style="padding: 20px;">
<div class="spinner-border text-primary" role="status">
<span class="visually-hidden">Loading...</span>
</div>
<p class="mt-2">Loading more products...</p>
</div>
<button id="load-more-btn" class="btn btn-primary btn-lg d-none" t-attf-data-page="{{ current_page + 1 }}" t-attf-data-order-id="{{ group_order.id }}" t-attf-data-search="{{ search_query }}" t-attf-data-category="{{ selected_category }}" t-attf-data-per-page="{{ per_page }}" aria-label="Load more products" style="display: none;">
<i class="fa fa-download me-2" />Load More Products
</button>
</div>
</div>
</t>
</t>
<t t-else="">
<div class="alert alert-warning" role="status" aria-live="polite">
<p>No products available in this order.</p>
</div>
</t>
<div class="oe_structure oe_empty mt-4" data-name="After Products" />
</div>
<div class="col-lg-3">
<div class="card sticky-top cart-sticky-position" aria-label="Cart Summary">
<div class="card-header d-flex justify-content-between align-items-center gap-1">
<h6 class="mb-0 cart-title-sm" id="cart-title">My Cart</h6>
<div class="btn-group cart-btn-group gap-0" role="group">
<button type="button" class="btn btn-primary cart-btn-compact" id="save-cart-btn" t-attf-data-order-id="{{ group_order.id }}" data-bs-title="Save Cart" data-bs-toggle="tooltip">
<i class="fa fa-save cart-icon-size" />
</button>
<t t-if="group_order.home_delivery and delivery_product_id">
<button type="button" class="btn btn-outline-warning cart-btn-compact" id="home-delivery-btn" aria-label="Toggle home delivery" data-bs-title="Home Delivery" data-bs-toggle="tooltip">
<i class="fa fa-truck cart-icon-size" aria-hidden="true" />
</button>
</t>
<a t-attf-href="/eskaera/{{ group_order.id }}/checkout" class="btn btn-success cart-btn-compact" aria-label="Proceed to checkout" data-bs-title="Proceed to Checkout" data-bs-toggle="tooltip">
<i class="fa fa-check cart-icon-size" aria-hidden="true" />
</a>
</div>
</div>
<div class="card-body cart-body-lg" id="cart-items-container" t-attf-data-order-id="{{ group_order.id }}" aria-labelledby="cart-title" aria-live="polite" aria-relevant="additions removals">
<p class="text-muted">This order's cart is empty</p>
</div>
<div class="card-footer bg-white text-center">
<a t-attf-href="/eskaera/{{ group_order.id }}/checkout" class="btn btn-success checkout-btn-lg" data-bs-title="Proceed to Checkout" data-bs-toggle="tooltip">
Proceed to Checkout
</a>
</div>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
(function() {
'use strict';
function initializeTooltips() {
console.log('[TOOLTIP] Initializing tooltips using native title attribute...');
var tooltipElements = document.querySelectorAll('[data-bs-toggle="tooltip"]');
console.log('[TOOLTIP] Found', tooltipElements.length, 'tooltip elements');
var successCount = 0;
tooltipElements.forEach(function(element) {
var title = element.getAttribute('data-bs-title');
if (title) {
// Set native title attribute for browser-native tooltip
element.setAttribute('title', title);
successCount++;
console.log('[TOOLTIP] ✅ Set title for', element.id || element.className, ':', title);
} else {
console.warn('[TOOLTIP] ⚠️ No data-bs-title found for element:', element.id || element.className);
}
});
console.log('[TOOLTIP] Tooltip initialization complete:', successCount, 'elements updated');
}
// Initialize when DOM is ready
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initializeTooltips);
} else {
// DOM is already loaded
initializeTooltips();
}
})();
</script>
</t>
</template>
<template id="eskaera_checkout_summary" name="Checkout Order Summary">
<div class="checkout-summary-container">
<table class="table table-hover checkout-summary-table" id="checkout-summary-table">
<thead class="table-dark">
<tr>
<th class="col-name">Product</th>
<th class="col-qty text-center">Quantity</th>
<th class="col-price text-right">Price</th>
<th class="col-subtotal text-right">Subtotal</th>
</tr>
</thead>
<tbody id="checkout-summary-tbody">
<tr id="checkout-empty-row" class="empty-message">
<td colspan="4" class="text-center text-muted py-4">
<i class="fa fa-inbox fa-2x mb-2" />
<p>This order's cart is empty</p>
</td>
</tr>
</tbody>
</table>
<div class="checkout-total-section">
<div class="total-row">
<span class="total-label">Total</span>:
<span class="total-amount" id="checkout-total-amount">0.00</span>
<span class="currency"></span>
</div>
</div>
</div>
</template>
<template id="eskaera_checkout" name="Eskaera Checkout">
<t t-call="website.layout">
<div id="wrap" class="eskaera-checkout-page oe_structure oe_empty" data-name="Eskaera Checkout" t-attf-data-delivery-product-id="{{ delivery_product_id }}" t-attf-data-delivery-product-name="{{ delivery_product_name }}" t-attf-data-delivery-product-price="{{ delivery_product_price }}" t-attf-data-home-delivery-enabled="{{ 'true' if group_order.home_delivery else 'false' }}" t-attf-data-pickup-day="{{ group_order.pickup_day }}" t-attf-data-pickup-date="{{ group_order.pickup_date.strftime('%d/%m/%Y') if group_order.pickup_date else '' }}" t-attf-data-delivery-notice="{{ (group_order.delivery_notice or '').replace(chr(10), ' ').replace(chr(13), ' ') }}">
<div class="container mt-5">
<div class="row">
<div class="col-lg-10 offset-lg-1">
<div class="mb-4">
<t t-call="website_sale_aplicoop.order_header">
<t t-set="header_class" t-value="'checkout-header'" />
<t t-set="header_title">Confirm Order: <t t-esc="group_order.name" />
</t>
</t>
</div>
<div class="order-info-card card border-0 shadow-sm mb-4">
<div class="card-body">
<div class="row mb-4">
<div class="col-md-4">
<div class="info-item">
<label t-att-class="'info-label'">Cutoff Day</label>
<t t-if="group_order.cutoff_day and group_order.cutoff_date">
<span class="info-value">
<t t-esc="day_names[int(group_order.cutoff_day) % 7]" />
<span class="info-date">(<t t-esc="group_order.cutoff_date.strftime('%d/%m/%Y')" />)</span>
</span>
</t>
<t t-else="1">
<span t-att-class="'text-muted small'">Not configured</span>
</t>
</div>
</div>
<div class="col-md-4">
<div class="info-item">
<t t-if="group_order.pickup_day and group_order.pickup_date">
<label t-att-class="'info-label'">Store Pickup Day</label>
<span class="info-value" t-attf-data-pickup-date="{{ group_order.pickup_date }}" t-attf-data-delivery-date="{{ group_order.delivery_date }}">
<t t-esc="day_names[int(group_order.pickup_day) % 7]" />
<span class="info-date">(<t t-esc="group_order.pickup_date.strftime('%d/%m/%Y')" />)</span>
</span>
</t>
</div>
</div>
<div class="col-md-4">
<div class="info-item">
<t t-if="group_order.delivery_date and group_order.home_delivery">
<label t-att-class="'info-label'">Home Delivery Day</label>
<span class="info-value">
<t t-esc="day_names[group_order.delivery_date.weekday()]" />
<span class="info-date">(<t t-esc="group_order.delivery_date.strftime('%d/%m/%Y')" />)</span>
</span>
</t>
</div>
</div>
</div>
<hr class="my-2" />
</div>
</div>
<h4 class="summary-heading mb-3">Order Summary</h4>
<div class="oe_structure oe_empty mb-3" data-name="Before Summary" />
<div id="checkout-summary" class="mb-5">
<t t-call="website_sale_aplicoop.eskaera_checkout_summary">
<t t-set="labels" t-value="{}" />
</t>
</div>
<div class="oe_structure oe_empty mb-4" data-name="After Summary" />
<div class="card border-0 shadow-sm mb-4">
<div class="card-body">
<div class="form-check">
<input type="checkbox" class="form-check-input" id="home-delivery-checkbox" name="home_delivery" />
<label class="form-check-label fw-bold" for="home-delivery-checkbox">Home Delivery</label>
</div>
<div id="delivery-info-alert" class="alert alert-info mt-3 d-none">
<p class="mb-2">
<i class="fa fa-truck" aria-hidden="true" t-translation="off" />
<t t-if="group_order.delivery_date and group_order.home_delivery">
<strong>Delivery Information:</strong> Your order will be delivered at
<t t-esc="day_names[(int(group_order.pickup_day) + 1) % 7]" />
<t t-esc="group_order.delivery_date.strftime('%d/%m/%Y')" />
<t t-if="group_order.delivery_notice">
<br />
<t t-esc="group_order.delivery_notice" />
</t>
</t>
</p>
</div>
</div>
</div>
<div class="checkout-actions d-grid gap-3" id="checkout-form-labels">
<button class="btn btn-success btn-lg" id="confirm-order-btn" t-attf-data-order-id="{{ group_order.id }}" data-confirmed-label="Order saved as draft" data-pickup-label="Pickup Day" aria-label="Save order as draft" data-bs-title="Save Draft" data-bs-toggle="tooltip">
<i class="fa fa-save" aria-hidden="true" t-translation="off" />
<span>Save Draft</span>
</button>
<a t-attf-href="/eskaera/{{ group_order.id }}" class="btn btn-outline-secondary btn-lg" aria-label="Back to cart page" data-bs-title="Back to Cart" data-bs-toggle="tooltip">
<i class="fa fa-arrow-left" aria-hidden="true" t-translation="off" />
<span>Back to Cart</span>
</a>
</div>
</div>
</div>
</div>
<script type="text/javascript">
(function() {
'use strict';
// Initialize groupOrderShop.labels from server-rendered labels
if (!window.groupOrderShop) {
window.groupOrderShop = {};
}
window.groupOrderShop.labels = <t t-raw="labels_json" />;
console.log('[LABELS] Initialized from server:', window.groupOrderShop.labels);
})();
</script>
<script type="text/javascript">
// Auto-load cart from localStorage when accessing checkout directly
(function() {
'use strict';
// Get order ID from button
var confirmBtn = document.getElementById('confirm-order-btn');
if (!confirmBtn) return;
var orderId = confirmBtn.getAttribute('data-order-id');
var cartKey = 'eskaera_' + orderId + '_cart';
// Check if there's a saved cart and load it
var savedCart = localStorage.getItem(cartKey);
if (savedCart) {
try {
var cart = JSON.parse(savedCart);
console.log('[CHECKOUT AUTO-LOAD] Cart found in localStorage:', cart);
// Simulate cart loading by triggering a custom event
// The checkout_labels.js will listen for cart data
var event = new CustomEvent('cartLoaded', { detail: { cart: cart } });
document.dispatchEvent(event);
} catch (e) {
console.error('[CHECKOUT AUTO-LOAD] Error parsing cart:', e);
}
} else {
console.log('[CHECKOUT AUTO-LOAD] No cart found in localStorage');
}
})();
</script>
</div>
</t>
</template>
<template id="category_hierarchy_options" name="Category Hierarchy Options">
<t t-foreach="categories" t-as="cat">
<t t-set="padding_px" t-value="depth * 20" />
<t t-set="prefix">
<t t-foreach="range(depth)" t-as="i"></t>
</t>
<option t-att-value="str(cat['id'])" t-attf-style="padding-left: {{ padding_px }}px;">
<t t-esc="prefix" />
<t t-esc="cat['name']" />
</option>
<t t-if="cat['children']">
<t t-call="website_sale_aplicoop.category_hierarchy_options">
<t t-set="categories" t-value="cat['children']" />
<t t-set="depth" t-value="depth + 1" />
</t>
</t>
</t>
</template>
<template id="eskaera_shop_products" name="Eskaera Shop Products">
<t t-foreach="products" t-as="product">
<div class="product-card-wrapper product-card" t-attf-data-product-name="{{ product.name }}" t-attf-data-category-id="{{ product.categ_id.id if product.categ_id else '' }}" t-attf-data-product-tags="{{ ','.join(str(t.id) for t in product.product_tag_ids) if product.product_tag_ids else '' }}">
<div class="card h-100">
<t t-if="product.image_128">
<img t-attf-src="data:image/png;base64,{{ product.image_128.decode() }}" class="card-img-top product-img-cover" t-attf-alt="{{ product.name }}" />
</t>
<t t-else="">
<div class="card-img-top bg-light d-flex align-items-center justify-content-center product-img-placeholder">
<i class="fa fa-image fa-3x text-muted" />
</div>
</t>
<t t-if="product.dynamic_ribbon_id">
<t t-set="ribbon" t-value="product.dynamic_ribbon_id" />
<span t-attf-class="o_ribbon {{ ribbon._get_position_class() }} z-1" t-attf-style="color: {{ ribbon.text_color }}; background-color: {{ ribbon.bg_color }};" t-esc="ribbon.name" />
</t>
<div class="card-body d-flex flex-column">
<h6 class="card-title" t-esc="product.name" />
<t t-if="product.product_tag_ids">
<div class="product-tags mb-2">
<t t-foreach="filtered_product_tags.get(product.id, {}).get('published_tags', product.product_tag_ids)" t-as="tag">
<t t-if="tag.color">
<span class="badge badge-km" t-attf-style="background-color: {{ tag.color }} !important; border-color: {{ tag.color }} !important; color: #ffffff !important;" t-esc="tag.name" />
</t>
<t t-else="">
<span class="badge badge-km tag-use-theme-color" t-esc="tag.name" />
</t>
</t>
</div>
</t>
<t t-if="product_supplier_info.get(product.id)">
<p class="product-supplier mb-2">
<small>
<t t-esc="product_supplier_info[product.id]" />
</small>
</p>
</t>
<t t-if="product.origin_text">
<p class="product-origin mb-2">
<small>
<i class="fa fa-map-marker" aria-hidden="true" />
<t t-out="product.origin_text" />
</small>
</p>
</t>
<t t-set="price_info" t-value="product_price_info.get(product.id, {})" />
<t t-set="display_price" t-value="product_display_info.get(product.id, {}).get('display_price', 0.0)" />
<t t-set="base_price" t-value="price_info.get('list_price', product.list_price)" />
<h6 class="card-text product-price-display">
<span class="product-price-main">
<t t-esc="'%.2f' % display_price" />
</span>
<t t-if="price_info.get('has_discounted_price', False)">
<small class="text-muted text-decoration-line-through ms-1">
<t t-esc="'%.2f' % base_price" />
</small>
</t>
</h6>
<t t-if="product.base_unit_price and product.base_unit_name">
<p class="product-unit-price text-muted" style="font-size: 0.85rem; margin-top: 0.25rem; margin-bottom: 0;">
<t t-esc="'%.2f' % product.base_unit_price" /> € / <t t-esc="product.base_unit_name" />
</p>
</t>
</div>
<t t-set="safe_uom_category" t-value="product_display_info.get(product.id, {}).get('safe_uom_category', '')" />
<t t-set="quantity_step" t-value="product_display_info.get(product.id, {}).get('quantity_step', 1)" />
<t t-set="order_id_safe" t-value="group_order.id if group_order else ''" />
<form class="add-to-cart-form" t-attf-data-order-id="{{ order_id_safe }}" t-attf-data-product-id="{{ product.id }}" t-attf-data-product-name="{{ product.name }}" t-attf-data-product-price="{{ display_price }}" t-attf-data-uom-category="{{ safe_uom_category }}" t-attf-data-quantity-step="{{ quantity_step }}">
<div class="qty-control">
<label t-attf-for="qty_{{ product.id }}" class="sr-only">Quantity of <t t-esc="product.name" />
</label>
<button class="qty-decrease" type="button" t-attf-data-product-id="{{ product.id }}" aria-label="Decrease quantity">
<i class="fa fa-minus" />
</button>
<input type="number" t-attf-id="qty_{{ product.id }}" class="product-qty" name="quantity" t-attf-value="1" t-attf-min="{{ quantity_step }}" t-attf-step="{{ quantity_step }}" />
<button class="qty-increase" type="button" t-attf-data-product-id="{{ product.id }}" aria-label="Increase quantity">
<i class="fa fa-plus" />
</button>
<button t-attf-class="add-to-cart-btn {{ 'btn-disabled' if product.is_out_of_stock else '' }}" type="button" t-att-disabled="product.is_out_of_stock or None" t-attf-aria-label="{{ 'Out of stock' if product.is_out_of_stock else 'Add %s to cart' % product.name }}" t-attf-title="{{ 'Out of stock' if product.is_out_of_stock else 'Add %s to cart' % product.name }}">
<i t-attf-class="fa {{ 'fa-ban' if product.is_out_of_stock else 'fa-shopping-cart' }}" aria-hidden="true" />
</button>
</div>
</form>
</div>
</div>
</t>
</template>
</data>
</odoo>