The separate /eskaera/<slug>/payment step is gone. Members review the summary, choose home delivery and pick a payment method on the checkout, in one screen; the old URL redirects there so bookmarks and sessions that were mid-flow do not hit a 404. The checkout now renders the member's draft sale.order instead of the localStorage cart. That is what fixes the products appearing "out of nowhere" between the two pages: the summary was a snapshot of localStorage taken at page load, and `_autoLoadDraftOnInit` then pulled the draft back into localStorage without re-rendering. Deleting a product in the shop removed it from the cart but left the line on the draft, so the autoload resurrected it, the confirm button sent it back, and it only became visible one page later. The checkout no longer auto-loads the draft — it renders it, and what it shows is what the payment form charges. "Proceed to Checkout" pushes the cart to that draft before navigating. Saving is idempotent: `_merge_or_replace_draft` reuses the cycle's draft and, through the new `_draft_matches_lines`, rewrites `order_line` only when the lines actually differ — replacing them unlinks and recreates every one of them, which is pure churn when nothing changed. The home delivery checkbox goes through the new /eskaera/set-home-delivery so the delivery line moves on the order itself. Writing only to localStorage would have changed the summary and left the amount alone, which with online payment on is the amount being charged. Also fixes the confirmation notice nobody ever saw: saving answered with the payment step URL and the frontend followed it immediately, destroying the toast in the same tick. Saving no longer navigates; the caller decides whether it is staying or moving on. Along the way: checkout_labels.js and the eskaera_checkout_summary / eskaera_payment templates are removed, superseded by the server-rendered summary and checkout, and the stale sessionStorage delivery preference no longer overrides the checkbox the order just rendered. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
16 KiB
16 KiB
Changelog - Website Sale Aplicoop
[18.0.1.16.0] - 2026-08-17
Changed
- Payment moved into the checkout: the separate
/eskaera/<slug>/paymentstep is gone. Members review the summary, pick home delivery and choose a payment method on/eskaera/<slug>/checkout, in one screen. The old URL redirects there so bookmarks and in-flight sessions keep working. - The checkout summary is server-side: it renders the draft
sale.orderinstead of the localStorage cart, so what is shown is what gets charged. "Proceed to Checkout" pushes the cart to that draft before navigating, reusing the cycle's draft and rewriting its lines only when they differ. - The home delivery checkbox on the checkout writes to the order through
/eskaera/set-home-delivery, so the total and the payment amount follow it.
Fixed
- The confirmation notice after saving a draft was destroyed by the immediate redirect to the payment step, so members saw nothing at all. Saving no longer navigates.
- Products the member had deleted reappeared between the checkout and the payment page. The checkout auto-loaded the draft into localStorage after the summary had already rendered, resurrecting deleted lines, which were then sent back on confirm. The checkout no longer auto-loads the draft — it renders it.
Removed
checkout_labels.jsand theeskaera_checkout_summary/eskaera_paymenttemplates, superseded by the server-rendered summary and checkout.
[18.0.1.13.0] - 2026-08-11
Added
- Readable URLs for group orders:
group.ordergains aslugfield and the public pages move from/eskaera/<id>to/eskaera/<slug>(e.g./eskaera/escola-fructuos). The slug is generated from the order name on creation, is editable on the form (empty it to regenerate it from the name), is unique, and rejects values that would collide with the shop's own routes (labels,save-order, …) or with a plain number. A post-migration script fills the slug of the orders that already existed.
Changed
/eskaera/<id>and/eskaera/<id>/checkoutare kept as redirects to their slug URL, so links already shared with members keep working. The AJAX endpoints (/eskaera/<id>/load-page,/eskaera/save-order, …) stay numeric.- The frontend reads the order id from the
data-order-idattribute only; it can no longer be recovered from the URL, which now carries the slug.
[18.0.1.12.0] - 2026-08-06
Removed
- Standard cart restriction extracted to
website_sale_disable_cart: the cart UI removal (header cart link, add-to-cart buttons) and the/shop/cart*route redirects no longer live in this module, so installing Aplicoop leaves the standardwebsite_saleshop untouched. Sites that want the previous behaviour must installwebsite_sale_disable_cartand set its Cart Redirect URL to/eskaera. The new module also fixes the route paths (Odoo 18 uses/shop/cart/quantity, not/shop/cart_quantity), covers the 5 header styles that were missing (boxed, sidebar, sales two/three/four — the header cart link was still visible on those) and overrides the standard endpoints instead of registering duplicate ones. Upgrade order matters: update this module first (so its old templates are dropped) and installwebsite_sale_disable_cartin a second Odoo run — both sets of templates use the same XPaths and obsolete records are only cleaned up at the end of a run, so a single combined run fails.
[18.0.1.11.0] - 2026-07-15
Added
- Non-weekly cycle automation: one-time (special/promotional), biweekly and monthly group orders now follow the same cron confirmation flow as weekly orders (confirm linked sale orders + batch their pickings once the cycle cutoff passes).
- Biweekly/monthly recurrence: these periods keep the weekday scheme
(
cutoff_day/pickup_day) but on a recurrence grid anchored atstart_date(creation date as fallback): cutoffs advance every 14 days / 1 month (snapped tocutoff_day), with automatic catch-up if the cron was down. Previously they behaved as weekly. - One-time orders: their single cycle is driven by
end_date(cutoff_date = end_date); once it passes, the cron confirms, batches and closes the group order automatically.
Changed
end_datekeeps its "permanent if empty" meaning for all recurring periods; it only closes the cycle for one-time orders.- Draft-cart lookup window on the website is now period-aware (7/14 days, 1 month, or the full order lifetime for one-time orders) instead of always 6 days.
[18.0.1.9.0] - 2026-05-20
Added
- Category sequence: New
sequencefield onproduct.categoryfor controlling product display order on the web shop. Migration adds the column with default 10. - Stock availability check on history orders: When loading a historical order, products are validated against current stock (
virtual_available). Out-of-stock items are flagged before adding to cart.
Changed
- Cart disabled / redirected to /eskaera: Standard
website_salecart is fully hidden — header cart icon removed, add-to-cart buttons removed from standard shop,/cartand/shoproutes redirect to/eskaera. Customers interact exclusively through the group order flow. - Product card UI overhaul: Improved responsive layout, placeholder image for products without photo, better accessibility markup, and professional styling for mobile.
- Stock check uses
virtual_available: Replacesqty_availableso forecasted quantity (including incoming moves) is considered.
Fixed
- Lint fixes: exception chaining (
raise ... from exc), unused imports/vars,disable attribute-string-redundantannotations.
[18.0.1.8.0] - 2026-04-08
Added
- Clear cart button: New button in the sidebar to empty the current group order cart in one click (
eskaera_clear_cartroute).
Changed
- Portal access restricted to consumer group: Portal users can only see group orders belonging to their consumer group. Security rule
rule_group_order_company_readupdated withuser.shareguard. - Controller filtering by consumer group:
eskaera_listandeskaera_shoproutes filter orders by the logged-in user's consumer group, not just by company.
Fixed
- Stale cart invalidation: carts linked to closed/cancelled group orders are cleared on next access.
- Home delivery draft flow: fixed state transition for home delivery orders.
- Auto-confirm
sale.orderon cutoff day: fixed off-by-one (>vs>=) in cutoff guard so orders on the cutoff day are correctly confirmed. - Pickup dates frozen after cron confirm: cron no longer overwrites pickup dates on already-confirmed orders.
- Cron hardened against missing/invalid group order configurations.
- Cart layout: moved cart sidebar before product grid.
- i18n: added missing ES/EU translations for checkout, cart labels, Save Draft button, and weekday strings. Removed legacy
week_drafttranslation keys.
[18.0.1.7.0] - 2026-03-06
Added
- Automatic batch picking creation: After the cutoff cron confirms sale orders, picking batches are automatically created grouped by consumer group and pickup date.
- Consumer group propagation:
consumer_group_idis now propagated directly from thegroup.orderto linkedsale.orderrecords, eliminating manual assignment. - Out-of-stock blocking: Add-to-cart button is hard-disabled for out-of-stock products.
allow_out_of_stock_orderflag on product is respected.
Changed
- Cron auto-confirm sale orders: Daily cron (
_cron_confirm_group_orders) now confirms linked sale orders on the cutoff date instead of requiring manual action. - Order card meta extracted: Order card metadata (dates, state badge) moved to a reusable
_eskaera_order_card_metatemplate for cleaner rendering. - Delivery toggle (reparto/envío a domicilio) wired directly from the cart sidebar.
- Pricing alignment: theoretical price and displayed price reconciled for orders with home delivery.
Fixed
- Fixed broken
aplicoopShop→groupOrderShopJS class reference. - Ensured add-to-cart event listeners are re-attached after infinite scroll loads new products.
- i18n: translated weekday names (ES/EU).
[18.0.1.6.0] - 2026-02-22
Added
- Category Blacklist Feature: Category-based exclusion system for group orders
- New field:
excluded_category_ids(Many2many to product.category) - Recursive exclusion: Excludes products in selected categories AND all subcategories
- Blacklist has absolute priority over all inclusion sources
- Helper method:
get_all_excluded_descendants()for recursive category tree traversal - Comprehensive test suite in
test_product_discovery.py(TestCategoryBlacklist class with 9 tests)
- New field:
Changed
-
Product Discovery Logic: Extended to filter by category blacklist
_get_products_for_group_order()now appliesexcluded_category_idsfilter recursively- Products in excluded categories and their subcategories are filtered out
_compute_available_products_count()now depends onexcluded_category_ids- Detailed logging for excluded categories and affected products
-
UI Updates: "Productos Excluidos" section now includes three blacklist types:
excluded_supplier_ids: Blacklist suppliersexcluded_category_ids: Blacklist categories (recursive)excluded_product_ids: Blacklist specific products
Technical Details
- New M2M relation:
group_order_excluded_category_rel - Recursive logic: Walks category tree to find all descendants
- Filter logic:
products.filtered(lambda p: p.categ_id not in all_excluded_categories) - Works in combination with product and supplier blacklists (all filters apply)
Use Case
- Admin wants to exclude all products in a category and its subcategories
- Example: Exclude "Fresh Produce" → automatically excludes "Fruits", "Vegetables", etc.
- Add parent category to inclusion → add problematic subcategory to exclusion
- Result: Fine-grained control over product catalog with minimal configuration
[18.0.1.5.0] - 2026-02-22
Added
- Supplier Blacklist Feature: New exclusion system by supplier for group orders
- New field:
excluded_supplier_ids(Many2many to res.partner) - Filters products by
main_seller_id(from product_main_seller addon) - Blacklist has absolute priority over all inclusion sources
- Products whose main supplier is blacklisted never appear
- Comprehensive test suite in
test_product_discovery.py(TestSupplierBlacklist class with 9 tests)
- New field:
Changed
-
Product Discovery Logic: Extended to filter by supplier blacklist
_get_products_for_group_order()now appliesexcluded_supplier_idsfilter- Products with
main_seller_idin excluded_supplier_ids are filtered out _compute_available_products_count()now depends onexcluded_supplier_ids- Detailed logging for excluded suppliers and affected products
-
UI Updates: "Productos Excluidos" section now includes both:
excluded_supplier_ids: Blacklist suppliersexcluded_product_ids: Blacklist specific products
Technical Details
- New M2M relation:
group_order_excluded_supplier_rel - Filter logic:
products.filtered(lambda p: p.product_tmpl_id.main_seller_id not in excluded_supplier_ids) - Works in combination with product blacklist (both filters apply)
- Uses
main_seller_idfrom product_main_seller addon (NOT default_supplier_id)
Use Case
- Admin wants to exclude all products from a specific supplier (e.g., temporary unavailability)
- Add category with 100 products → add problematic supplier to excluded_supplier_ids
- Result: All products from that supplier are excluded, even if directly included
- Combined workflow: Category inclusion + supplier exclusion + individual product exclusion
[18.0.1.4.0] - 2026-02-22
Added
- Product Blacklist Feature: New exclusion system for group orders
- New field:
excluded_product_ids(Many2many to product.product) - Blacklist has absolute priority over all inclusion sources (product_ids, category_ids, supplier_ids)
- Model method: Updated
_get_products_for_group_order()with blacklist filter - Comprehensive test suite in
test_product_discovery.py(TestProductBlacklist class)
- New field:
Changed
-
UI Improvements: Renamed "Associations" section to "Catálogo de Productos" for better user clarity
- New subsection: "Productos Incluidos" (whitelist: suppliers, categories, direct products)
- New subsection: "Productos Excluidos" (blacklist: explicit exclusions)
- Updated help texts for all inclusion fields
- Complete Spanish and Euskera translations
-
Product Discovery Logic:
_get_products_for_group_order()now appliesexcluded_product_idsfilter at the end- Products in blacklist never appear, regardless of inclusion source
_compute_available_products_count()now depends onexcluded_product_ids- Detailed logging for excluded product count
Technical Details
- New M2M relation:
group_order_excluded_product_rel(separate from whitelist relations) - Blacklist filter uses set subtraction:
products = products - order.excluded_product_ids - All tests validate absolute priority: direct products, category products, supplier products, and multi-source products all respect blacklist
Use Case
- Admin selects a category with 100 products → adds to category_ids
- Admin identifies 5 unwanted products → adds to excluded_product_ids
- Result: 95 products available in the order
- Workflow: Bulk inclusion via categories/suppliers + fine-grained exclusion via blacklist
[18.0.1.3.0] - 2026-02-16
Added
-
Lazy Loading Feature: Configurable product pagination for significantly faster page loads
- New Settings:
Enable Lazy Loading,Products Per Page - New endpoint:
GET /eskaera/<order_id>/load-page?page=N - JavaScript method:
_attachLoadMoreListener() - Model method:
group_order._get_products_paginated()
- New Settings:
-
Configuration Parameters:
website_sale_aplicoop.lazy_loading_enabled(Boolean, default: True)website_sale_aplicoop.products_per_page(Integer, default: 20)
-
Frontend Components:
- New template:
eskaera_shop_products(reusable for initial page + AJAX) - Load More button with pagination controls
- Spinner during AJAX load ("Loading..." state)
- Event listener re-attachment for dynamically loaded products
- New template:
-
Documentation:
- Complete lazy loading guide:
docs/LAZY_LOADING.md - Configuration examples
- Troubleshooting section
- Performance metrics
- Complete lazy loading guide:
Changed
-
Template
eskaera_shop:- Products grid now has
id="products-grid" - Calls reusable
eskaera_shop_productstemplate - Conditional "Load More" button display
- Products grid now has
-
JavaScript
website_sale.js:_attachEventListeners()now calls_attachLoadMoreListener()- Re-attaches listeners after AJAX loads new products
-
README.md:
- Added lazy loading feature to features list
- Added version 18.0.1.3.0 to changelog
Performance Impact
- Initial page load: 10-20s → 500-800ms (20x faster)
- Product DOM size: 1000 elements → 20 elements (initial)
- Subsequent page loads: 200-400ms via AJAX
- Price calculation: Only for visible products (reduced from 1000+ to 20)
Technical Details
- Zero-impact if lazy loading disabled
- Transparent pagination (no URL changes)
- Maintains cart synchronization
- Compatible with existing search/filter
- No changes to pricing logic or validation
[18.0.1.2.0] - 2026-02-02
Added
- Improved UI elements in cart and checkout
Fixed
- Pickup date calculation (was adding extra week)
- Delivery date display on order pages
Changed
- Cart styling: 2x text size, larger icons
- Checkout button: Enhanced visibility
[18.0.1.0.0] - 2024-12-20
Added
- Initial release of Website Sale Aplicoop
- Group order management system
- Multi-language support (ES, PT, GL, CA, EU, FR, IT)
- Member management and tracking
- Order state machine (draft → confirmed → collected → invoiced → completed)
- Separate shopping carts per group order
- Cutoff and pickup date validation
- Integration with OCA ecosystem (pricing, taxes, etc.)