[ADD] website_sale_aplicoop: online payment per group order

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>
This commit is contained in:
GitHub Copilot 2026-08-16 21:59:35 +02:00
parent a67181ab42
commit 6ba554c91b
21 changed files with 1993 additions and 37 deletions

View file

@ -2362,3 +2362,169 @@ msgid ""
msgstr ""
"<span class=\"badge text-bg-success\"><i class=\"fa fa-truck\" aria-"
"hidden=\"true\"/> Lliurament a domicili</span>"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_order_lines_summary
msgid "<span class=\"total-label\">Total</span>:"
msgstr "<span class=\"total-label\">Total</span>:"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment
msgid "<span>Back to Checkout</span>"
msgstr "<span>Torna al checkout</span>"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment_confirmation
msgid "<span>Back to Orders</span>"
msgstr "<span>Torna a les comandes</span>"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment_confirmation
msgid "<span>Order</span>"
msgstr "<span>Comanda</span>"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment
msgid "<span>Payment in progress</span>"
msgstr "<span>Pagament en curs</span>"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment
msgid "<span>Reference</span>:"
msgstr "<span>Referència</span>:"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment_confirmation
msgid "<span>Thank you, your order is confirmed</span>"
msgstr "<span>Gràcies, la teva comanda està confirmada</span>"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment_confirmation
msgid "<span>View my order</span>"
msgstr "<span>Veure la meva comanda</span>"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment_confirmation
msgid "<span>Your payment is being processed</span>"
msgstr "<span>El teu pagament s'està processant</span>"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_shop
msgid "<strong>You already placed an order for this cycle.</strong>"
msgstr "<strong>Ja has fet una comanda per a aquest cicle.</strong>"
#. module: website_sale_aplicoop
#. odoo-python
#: code:addons/website_sale_aplicoop/controllers/website_sale.py:0
#: code:addons/website_sale_aplicoop/models/js_translations.py:0
msgid "Confirm and pay"
msgstr "Confirma i paga"
#. module: website_sale_aplicoop
#. odoo-python
#: code:addons/website_sale_aplicoop/models/js_translations.py:0
msgid "Confirm the order and go to payment"
msgstr "Confirma la comanda i ves al pagament"
#. module: website_sale_aplicoop
#: model:ir.model.fields,help:website_sale_aplicoop.field_group_order__online_payment
msgid ""
"Let members pay their order online when they place it. Payment providers are"
" configured globally (Settings > Payment Providers); this only decides "
"whether this group order offers them. When enabled, paying is the only way "
"to place an order from the checkout page."
msgstr ""
"Permet que els socis paguin la seva comanda en línia en fer-la. Els "
"proveïdors de pagament es configuren globalment (Configuració > Proveïdors "
"de pagament); això només decideix si aquesta comanda de grup els ofereix. "
"Amb l'opció activa, pagar és l'única manera de fer la comanda des de la "
"pàgina de checkout."
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.view_group_order_form
msgid ""
"Members must pay online to place their order in this cycle. The\n"
" available methods come from the payment providers published on the\n"
" website (Settings &gt; Payment Providers); this order does not\n"
" configure any of them."
msgstr ""
"Els socis han de pagar en línia per fer la seva comanda en aquest cicle. Les"
" formes de pagament disponibles surten dels proveïdors publicats al lloc web"
" (Configuració > Proveïdors de pagament); aquesta comanda no en configura "
"cap."
#. module: website_sale_aplicoop
#: model:ir.model.fields,field_description:website_sale_aplicoop.field_group_order__online_payment
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.view_group_order_form
msgid "Online Payment"
msgstr "Pagament en línia"
#. module: website_sale_aplicoop
#. odoo-python
#: code:addons/website_sale_aplicoop/models/js_translations.py:0
msgid "Online payment is not available right now. Please contact your group."
msgstr ""
"El pagament en línia no està disponible ara mateix. Contacta amb el teu "
"grup."
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment_confirmation
msgid "Order Confirmed:"
msgstr "Comanda confirmada:"
#. module: website_sale_aplicoop
#. odoo-python
#: code:addons/website_sale_aplicoop/controllers/website_sale.py:0
#: code:addons/website_sale_aplicoop/models/js_translations.py:0
msgid "Order ready for payment"
msgstr "Comanda a punt per pagar"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment
msgid "Pay Order:"
msgstr "Paga la comanda:"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment
msgid "Payment Method"
msgstr "Forma de pagament"
#. module: website_sale_aplicoop
#: model:ir.model,name:website_sale_aplicoop.model_payment_transaction
msgid "Payment Transaction"
msgstr "Transacció de pagament"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment_confirmation
msgid "Pickup"
msgstr "Recollida"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_shop
msgid "View my order"
msgstr "Veure la meva comanda"
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment
msgid ""
"We are still waiting for your payment to be confirmed. Please do not pay "
"again."
msgstr ""
"Encara estem esperant la confirmació del teu pagament. No tornis a pagar."
#. module: website_sale_aplicoop
#. odoo-python
#: code:addons/website_sale_aplicoop/controllers/website_sale.py:0
#: code:addons/website_sale_aplicoop/models/js_translations.py:0
msgid "You already placed an order for this cycle."
msgstr "Ja has fet una comanda per a aquest cicle."
#. module: website_sale_aplicoop
#: model_terms:ir.ui.view,arch_db:website_sale_aplicoop.eskaera_payment_confirmation
msgid ""
"Your order will be confirmed as soon as we receive the payment. You can "
"follow it from your orders page."
msgstr ""
"La teva comanda es confirmarà tan bon punt rebem el pagament. La pots seguir"
" des de la pàgina de comandes."