Members can now pay their eskaera at checkout, through the standard Odoo
payment machinery. Enabled per group order with a new `online_payment`
boolean, off by default: an order without it behaves exactly as before,
members save a draft and the cutoff cron confirms them in bulk.
The flow mirrors website_sale's: the checkout button becomes "Confirm and
pay", saving the cart redirects to a new /eskaera/<slug>/payment step that
renders `payment.form` from `sale`'s `_get_payment_values`, and the standard
/my/orders/<id>/transaction route takes it from there. This addon ships no
provider and configures none; the co-op publishes whichever it wants.
`website_sale`'s `_get_shop_payment_values` is deliberately not reused: it
runs `_get_shop_payment_errors`, which blocks on shippable products without a
delivery method — exactly an eskaera order, collected at the co-op with no
carrier. For the same reason the transaction route stays the portal one,
which does not call `_check_cart_is_ready_to_be_paid()`.
Payment confirms the order, which has three consequences handled here:
* `payment.transaction._check_amount_and_confirm_order` now confirms group
orders with `from_orderpoint=True`, the way the cutoff cron already does.
Without it a product with a broken replenishment route raises inside
`_post_process`, and `/payment/status/poll` rolls back and re-raises: the
member sees a payment error over a `done` transaction and the retry cron
fails forever.
* `_confirm_linked_sale_orders` also sweeps the cycle's already confirmed
orders into the picking batch, scoped by `pickup_date`. Its early return on
"no drafts" ran before any batching, so a fully prepaid cycle produced no
batch at all. `_cron_batch_paid_orders_of_closed_cycles` covers the same
hole for cycles closed by hand.
* A duplicate-order guard answers 409 on save-order, add-to-cart and
load-draft, and shows a notice on the shop, so a member whose order is
already placed cannot build and pay for a second one.
The payment policy lives in the model rather than the controller: there are
three sale.order creation paths and two are live, so `_compute_require_payment`
and `_compute_prepayment_percent` are extended instead of patching five vals
dicts. Orders are also created under the group order's company, which is what
filters the payment providers.
Along the way: eskaera drafts were invisible in /my/orders. The portal rule is
`message_partner_ids child_of` and sale.order only subscribes the customer on
send or confirm, never on a draft create, so the `_prepare_orders_domain`
override that includes drafts never had any effect. Fixed with an explicit
`message_subscribe`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Quantity control layout: changed from wrapping flex to deliberate two-row
grid so the add-to-cart button sits full-width underneath the stepper,
avoiding accidental line breaks and giving the primary action more pulsing
area. Also removed the /Kg suffix's redundant font rules.
Order card delivery row: reordered to badge-then-date (visually centred),
removed the "Delivery" label, and swapped bg-primary to text-bg-primary for
proper contrast on the home-delivery badge (3.13:1 minimum).
Tooltip translations: moved hardcoded static tooltips from data-bs-title
(untranslatable) to title (QWeb-translatable). Handled the edge case of
"Save Cart" and "Back to Cart" which had translations but no model_terms
reference in the POT, causing the merge to discard them — added the view
reference so translations now apply.
Load-from-history page: added accessibility: a visible status message
("Loading your order…"), a <noscript> fallback with link to the group
order, lang and viewport meta tags, and localised strings for all three
languages. Gave the page a minimal inline style block since it does not
inherit the token system (no website.layout).
Translations: 11 new entries (es/eu/ca) for new/reworded UI strings, plus
two code catalogue entries (products found, Close) that needed the
#. odoo-python comment for _() resolution. Documented the silent-failure
pattern in docs/TRANSLATIONS.md: the POT merge, untranslatable attributes,
and missing code comments.
Tests: 246 passing. Pre-commit: clean.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
One-time, biweekly and monthly group orders now follow the same cron
confirmation flow as weekly ones (confirm sale orders + batch pickings
when the cycle cutoff passes):
- Biweekly/monthly keep the cutoff_day/pickup_day weekday scheme on a
recurrence grid anchored at start_date (creation date as fallback):
cutoffs advance +14 days / +1 month snapped to cutoff_day, with
catch-up after cron downtime. Previously they behaved as weekly.
- One-time orders (specials/promotions) are driven by end_date
(cutoff_date = end_date); once passed, the cron confirms, batches
and closes the group order.
- end_date keeps its "empty = permanent" meaning for recurring orders.
- Website draft-cart lookup window is now period-aware instead of
assuming a 6-day weekly cycle.
- New cron tests for once/biweekly/monthly cycles; i18n es/eu updated.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add hardcoded fallback translations for es/eu when PO-based translation
returns the source string unchanged. Expand labels dict with all keys
needed by the frontend. Fix JSON response parsing in template
(data.result || data). Add js_translations keys. Add pot file for
stock_picking_batch_custom.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Añade botón 'Clear Cart' (fa-trash) en el header y footer del sidebar
del carrito en la página de lista de productos.
Cambios:
- views/website_templates.xml: botón clear-cart-btn en card-header y
clear-cart-btn-footer en card-footer del sidebar
- controllers/website_sale.py: nuevo endpoint POST /eskaera/clear-cart
que cancela el sale.order borrador del usuario si existe
- static/src/js/website_sale.js: método _clearCart(), listeners para
ambos botones (header + footer)
- models/js_translations.py: nuevas cadenas clear_cart, clear_cart_confirm,
cart_cleared, draft_cancelled
- i18n/es.po, i18n/eu.po: traducciones ES y EU de los nuevos labels
- Add comprehensive test suite for excluded_category_ids
- 9 tests covering: single category, recursive subcategories,
parent exclusion, direct product override, unrelated categories,
empty blacklist, multiple exclusions, combined blacklists,
available_products_count validation
- Update UI to show excluded_category_ids in 'Productos Excluidos'
- Bump version to 18.0.1.6.0
- Update CHANGELOG with category blacklist documentation
Technical notes:
- Category blacklist was already implemented in model/logic
- This commit adds missing tests and documentation
- Recursive exclusion via get_all_excluded_descendants()
- Blacklist has absolute priority over all inclusion sources
- Add excluded_supplier_ids field for supplier exclusion
- Filter products by main_seller_id (from product_main_seller addon)
- Blacklist has absolute priority over all inclusion sources
- Products with blacklisted main supplier never appear in orders
- Update _get_products_for_group_order() with supplier blacklist logic
- Add excluded_supplier_ids to 'Productos Excluidos' section in form view
- Add comprehensive test suite (TestSupplierBlacklist class with 9 tests):
* Test exclusion by main_seller_id
* Test multiple supplier exclusion
* Test products without main seller not affected
* Test blacklist with direct product inclusion
* Test blacklist priority over supplier inclusion
* Test combined product and supplier blacklist
* Test available_products_count with supplier blacklist
- Add Spanish and Euskera translations
- Update available_products_count computation to include excluded_supplier_ids
- Version bump to 18.0.1.5.0
Use case: Exclude all products from specific supplier (e.g., temporary unavailability)
Example: Category with 100 products, exclude supplier X → all products from X excluded
Workflow: Bulk inclusion via categories + supplier-level exclusion + product-level exclusion
- Add excluded_product_ids field for explicit product exclusion
- Blacklist has absolute priority over all inclusion sources (product_ids, category_ids, supplier_ids)
- Update _get_products_for_group_order() with blacklist filter logic
- Rename 'Associations' section to 'Catálogo de Productos' with subsections:
* Productos Incluidos (whitelist: suppliers, categories, direct products)
* Productos Excluidos (blacklist: explicit exclusions)
- Add comprehensive test suite (TestProductBlacklist class with 7 tests)
- Add Spanish and Euskera translations
- Update available_products_count computation to include excluded_product_ids
- Version bump to 18.0.1.4.0
Use case: Bulk inclusion via categories/suppliers + fine-grained exclusion via blacklist
Example: Select a category with 100 products, exclude 5 unwanted → 95 available