Group order pages were published under their database id (`/eskaera/1`), which says nothing to the member opening the link. `group.order` gains a `slug` field and the public pages move to `/eskaera/<slug>` (e.g. `/eskaera/escola-fructuos`). The slug is generated from the order name on creation, is unique, and can be edited under the name on the form; emptying it regenerates it from the current name. Values that would make the order unreachable are rejected: a plain number (the legacy numeric URLs win that match) and the static routes served under `/eskaera/` (`labels`, `save-order`, `i18n`, ...). `/eskaera/<id>` and `/eskaera/<id>/checkout` are kept as redirects to their slug URL, so the links already shared with members keep working. The AJAX endpoints (`load-page`, `save-order`, `confirm`, ...) stay numeric: they never show up in the address bar. Consequently the frontend now reads the order id from the `data-order-id` attribute only, as the URL no longer carries it. The post-migration script fills the slug of the orders that already existed. Renaming the `/eskaera` prefix itself (`/escolas` for a schools deployment) needs no code: a *308 Redirect / Rewrite* rule per public route in Website > Configuration > Redirects serves the pages on the new prefix, rewrites the links in the templates and redirects the old URLs, per website. Documented in `readme/CONFIGURE.rst`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
15 KiB
15 KiB
Changelog - Website Sale Aplicoop
[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.)