Repository navigation
Conversation
…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/
JrAdhoc
force-pushed
the
20.0-t-76692-jr
branch
from
October 23, 2026 15:03
2210610 to
36d63b2
Compare
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.
JrAdhoc
force-pushed
the
20.0-t-76692-jr
branch
from
October 23, 2026 19:22
36d63b2 to
042e088
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Migration of
website_sale_product_item_cart_custom_qtyto 20.0.Why it is not a straight port
In 19.0 the product tile was a
<form>: the add to cart button carrieda-submit, the product travelled in hidden inputs, and theinput[name="add_qty"]this module inserts travelled with them. In 20.0 thetile is an
<article>(website_sale/templates/product_tile_templates.xml),the button carries the product in data attributes, and the
website_sale.add_to_cartinteraction posts it through the cart service. Thatinteraction reads the quantity from an
input[name="add_qty"]inside theclosest
.js_product:.js_productonly exists on the product page, so on the shop the selectorrendered fine and every product was added one at a time.
How the quantity reaches the cart
Through
_getOptionalParams(), the hookAddToCartdocuments for exactlythis, 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 productpage 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_rentingreads.o_website_sale_daterange_pickerthere, whichon 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 theline to it (
sale_order._get_remaining_minimum_qty()). A tile hardcoded todata-min="1"would show 1 and add 5, so the selector now starts at theproduct'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: hiddenon the row, which the module's override on that rowundid; 20.0 fades each
.btninside the row instead(
product_tile.scss,.o_wsale_products_opt_actions_onhover), so with theoption 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 theone that replaced it (
website_sale.product_page) binds.css_quantity > buttonunder.o_wsale_product_page, so it never reachesthe catalog. They get their own interaction,
ProductTileQuantity, with thesame clamping (and the same
changeevent) as the core'sincOrDecQuantity. A quantity typed by hand is clamped too, which the tilenever did before.
They also become
<button>elements instead of<a href="#">— there is noform 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 servesthe 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 atquantity 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
products_item, which removesd-flex gap-2fromo_wsale_product_btn) is left untouched. Those classes are not on that divin 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.
.potis not updated by hand; the bot regenerates it after the merge.