Skip to content

[20.0][MIG] website_sale_product_item_cart_custom_qty - #1375

Open
JrAdhoc wants to merge 22 commits into
OCA:20.0from
adhoc-dev:20.0-t-76692-jr
Open

JrAdhoc wants to merge 22 commits into
OCA:20.0from
adhoc-dev:20.0-t-76692-jr

Conversation

@JrAdhoc

@JrAdhoc JrAdhoc commented Oct 23, 2026 •

Copy link
Copy Markdown
Contributor

Migration of website_sale_product_item_cart_custom_qty to 20.0.

Why it is not a straight port

In 19.0 the product tile was a <form>: the add to cart button carried
a-submit, the product travelled in hidden inputs, and the
input[name="add_qty"] this module inserts travelled with them. In 20.0 the
tile is an <article> (website_sale/templates/product_tile_templates.xml),
the button carries the product in data attributes, and the
website_sale.add_to_cart interaction posts it through the cart service. That
interaction reads the quantity from an input[name="add_qty"] inside the
closest .js_product:

const productEl = button.closest('.js_product');
const productPageData = productEl ? {
    quantity: parseFloat(productEl.querySelector('input[name="add_qty"]')?.value) || 1,
    ...
} : {};

.js_product only exists on the product page, so on the shop the selector
rendered fine and every product was added one at a time.

How the quantity reaches the cart

Through _getOptionalParams(), the hook AddToCart documents for exactly
this, reading the input from the tile of the clicked button — and only when
the core did not already read a quantity from a .js_product, so the product
page keeps the value it computed.

The product container is deliberately left alone: other modules look for
their own fields inside the one the core resolves, and
website_sale_renting reads .o_website_sale_daterange_picker there, which
on the shop page is a single element outside the tiles. Pointing the
container at the tile would have silently dropped the rental dates.

Minimum quantity

20.0 added product.template.minimum_quantity, and the server raises the
line to it (sale_order._get_remaining_minimum_qty()). A tile hardcoded to
data-min="1" would show 1 and add 5, so the selector now starts at the
product's minimum and clamps to it.

"Always display qty buttons"

That option needed a second rule to keep working. 19.0 hid the tile actions
with visibility: hidden on the row, which the module's override on that row
undid; 20.0 fades each .btn inside the row instead
(product_tile.scss, .o_wsale_products_opt_actions_onhover), so with the
option on the row showed and the buttons did not: the tile displayed the
quantity box alone, without +/- and without the cart button, until the mouse
hovered it. The override now reaches the buttons.

The +/- buttons

js_add_cart_json, the core handler they relied on, is gone in 20.0, and the
one that replaced it (website_sale.product_page) binds
.css_quantity > button under .o_wsale_product_page, so it never reaches
the catalog. They get their own interaction, ProductTileQuantity, with the
same clamping (and the same change event) as the core's
incOrDecQuantity. A quantity typed by hand is clamped too, which the tile
never did before.

They also become <button> elements instead of <a href="#"> — there is no
form left to submit — and are named after the core ones (minus_button),
which is what tells decrement from increment. The icons move to Material
Symbols (<i class="oi" data-icon="remove"/>), since 20.0 no longer serves
the Font Awesome stylesheet.

Tests

The tour follows the buttons (a[title='Add one'] → button[title='Add one']);
everything else it asserts still exists in 20.0.

The tour itself could not be run locally — the image at hand has no Chrome and
the test skips — so it is on CI. What was verified by hand on a 20.0 database
with the module installed, driving the browser through the tour's own
selectors: hover, +, add to cart, the cart badge at 2, the cart line at
quantity 2 and deleting it, with no JS errors. Also checked: the arithmetic
(1 → + → + → 3 → − → 2, never below data-min), and a product with variants,
where the tile quantity reaches the configurator and ends up in the cart. A 41-second recording of the whole
walkthrough was made for our internal review.

Notes for reviewers

  • The third template (products_item, which removes d-flex gap-2 from
    o_wsale_product_btn) is left untouched. Those classes are not on that div
    in 20.0 — but they were not in 19.0 either, so the template was already
    inert before this migration and cleaning it up felt out of scope here.
  • The .pot is not updated by hand; the bot regenerates it after the merge.

CarlosRoca13 and others added 21 commits October 23, 2026 11:10
…add to cart custom quantity from product item
Currently translated at 100.0% (2 of 2 strings)

Translation: e-commerce-15.0/e-commerce-15.0-website_sale_product_item_cart_custom_qty
Translate-URL: https://translation.odoo-community.org/projects/e-commerce-15-0/e-commerce-15-0-website_sale_product_item_cart_custom_qty/it/
Currently translated at 100.0% (2 of 2 strings)

Translation: e-commerce-15.0/e-commerce-15.0-website_sale_product_item_cart_custom_qty
Translate-URL: https://translation.odoo-community.org/projects/e-commerce-15-0/e-commerce-15-0-website_sale_product_item_cart_custom_qty/es/
Add a setting in /shop page > customize: Always display qty buttons
Qty and add to cart buttons are always visible (not only on rollover)
To improve the visualization, move the buttons below the image so that they do not overlap it, now it occupies about 20% of the image height.
Currently translated at 100.0% (2 of 2 strings)

Translation: e-commerce-18.0/e-commerce-18.0-website_sale_product_item_cart_custom_qty
Translate-URL: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-website_sale_product_item_cart_custom_qty/es/
Currently translated at 100.0% (2 of 2 strings)

Translation: e-commerce-18.0/e-commerce-18.0-website_sale_product_item_cart_custom_qty
Translate-URL: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-website_sale_product_item_cart_custom_qty/it/
Currently translated at 100.0% (2 of 2 strings)

Translation: e-commerce-18.0/e-commerce-18.0-website_sale_product_item_cart_custom_qty
Translate-URL: https://translation.odoo-community.org/projects/e-commerce-18-0/e-commerce-18-0-website_sale_product_item_cart_custom_qty/sl/
@OCA-git-bot OCA-git-bot added mod:website_sale_product_item_cart_custom_qty Module website_sale_product_item_cart_custom_qty series:20.0 labels Oct 23, 2026
@JrAdhoc JrAdhoc mentioned this pull request Oct 23, 2026
50 tasks
Odoo 20 turned the product tile into an <article>: it is no longer a form
with hidden inputs that the add to cart button submitted, so the quantity
this module adds to the tile stopped travelling with it. The button now
carries the product in data attributes, and the `website_sale.add_to_cart`
interaction sends it through the cart service, taking the quantity from an
`input[name="add_qty"]` inside the closest `.js_product` -- an element the
tile does not have.

The quantity reaches that interaction through `_getOptionalParams()`, the
hook the core provides for it, read from the tile of the clicked button and
only when the core did not already read one from a `.js_product`. The
container is left alone: other modules look for their own fields inside the
one the core resolves, and `website_sale_renting` reads the rental daterange
picker there, which on the shop page lives outside the tile.

The +/- buttons need an interaction of their own as well: `js_add_cart_json`,
the core handler they relied on, is gone in 20.0, and the remaining one
(`website_sale.product_page`) binds `.css_quantity > button` on the product
page only. They are now <button> elements named after the core ones
(`minus_button`, `plus_button`), with the Material Symbols icons that
replaced Font Awesome in 20.0, and the tour follows them. A typed quantity is
clamped on change, which the tile never did.

The selector also honours `minimum_quantity`, a `product.template` field 20.0
added: the server raises the quantity of the line to the product's minimum
(`sale_order._get_remaining_minimum_qty()`), so a tile starting at 1 for a
product with a minimum of 5 showed one quantity and added another.

The "Always display qty buttons" option needed a second rule to keep working.
In 19.0 the theme hid the tile actions with `visibility: hidden` on the row,
which the module's `opacity`/`visibility` override on that row undid; 20.0
fades each `.btn` inside the row instead, so the row showed and the buttons
did not -- the tile ended up displaying the quantity box alone, without the
+/- buttons or the cart button, until the mouse hovered it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

mod:website_sale_product_item_cart_custom_qty Module website_sale_product_item_cart_custom_qty series:20.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.