addons-cm/website_sale_aplicoop/__manifest__.py
GitHub Copilot 6ba554c91b [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>
2026-08-16 21:59:35 +02:00

94 lines
3.3 KiB
Python

# Copyright 2025 - Today Criptomart
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl)
{ # noqa: B018
"name": "Website Sale - Aplicoop",
"version": "18.0.1.14.0",
"category": "Website/Sale",
"summary": "Modern replacement of legacy Aplicoop - Collaborative consumption group orders",
"author": "Odoo Community Association (OCA), Criptomart",
"maintainers": ["Criptomart"],
"website": "https://git.criptomart.net/criptomart/addons-cm",
"license": "AGPL-3",
"depends": [
"website_sale",
"website_sale_stock",
"payment",
"product",
"sale",
"stock",
"stock_picking_batch",
"account",
"product_get_price_helper",
"l10n_es_partner",
],
"data": [
# Datos: Grupos propios
"data/groups.xml",
# Datos: Menús del website
"data/website_menus.xml",
# Datos: Cron jobs
"data/cron.xml",
# Datos: Product ribbons for stock levels
"data/product_ribbon_data.xml",
# Vistas de seguridad
"security/ir.model.access.csv",
"security/record_rules.xml",
# Vistas
"views/group_order_views.xml",
"views/product_category_views.xml",
"views/res_partner_views.xml",
"views/res_config_settings_views.xml",
"views/website_templates.xml",
"views/product_template_views.xml",
"views/sale_order_views.xml",
"views/stock_picking_views.xml",
"views/portal_templates.xml",
"views/load_from_history_templates.xml",
],
"demo": [
# Demo: Account Taxes (must be loaded first)
"demo/account_tax_demo.xml",
# Demo: Partners (Groups and Members)
"demo/res_partner_demo.xml",
# Demo: Suppliers
"demo/res_partner_suppliers_demo.xml",
# Demo: Products and Categories
"demo/product_demo.xml",
# Demo: Group Orders
"demo/group_order_demo.xml",
# Demo: Sale Orders
"demo/sale_order_demo.xml",
],
"i18n": [
"i18n/es.po",
"i18n/eu_ES.po",
],
"external_dependencies": {
"python": [],
},
"assets": {
"web.assets_frontend": [
"website_sale_aplicoop/static/src/css/website_sale.css",
# i18n and helpers must load first
"website_sale_aplicoop/static/src/js/i18n_manager.js",
"website_sale_aplicoop/static/src/js/i18n_helpers.js",
# Core shop functionality
"website_sale_aplicoop/static/src/js/website_sale.js",
"website_sale_aplicoop/static/src/js/checkout_labels.js",
"website_sale_aplicoop/static/src/js/home_delivery.js",
"website_sale_aplicoop/static/src/js/checkout_summary.js",
"website_sale_aplicoop/static/src/js/eskaera_payment.js",
# Search and pagination
"website_sale_aplicoop/static/src/js/infinite_scroll.js",
"website_sale_aplicoop/static/src/js/realtime_search.js",
],
"web.assets_tests": [
"website_sale_aplicoop/static/tests/test_suite.js",
"website_sale_aplicoop/static/tests/test_cart_functions.js",
"website_sale_aplicoop/static/tests/test_tooltips_labels.js",
"website_sale_aplicoop/static/tests/test_realtime_search.js",
],
},
"application": True,
}