Odoo 19 → 20preview

Odoo 19 to 20 Website & eCommerce migration: a guide for custom modules

A large release for Website and eCommerce where several public-facing controller routes have been removed or reshaped, so most of the risk for custom modules sits in the cart, delivery, donation and checkout flows rather than in the data model.

3,793 verified changesWebsite & eCommerceverified on Odoo 20
Preview. Odoo 20 is pre-release; this guide is built from Odoo's development branch and will be refreshed at the official release.
3,793
verified changes
212
models affected
54
modules affected

Change breakdown

Changed method619
Changed template617
Changed view / record339
Added method325
Added template222
Removed method216
Removed template191
Added view / record173

Removed and renamed items are what a custom module feels first — they break references at load time. Added and internally-changed items rarely touch existing code.

Where the changes land

website1,246
website_sale1,017
website_slides248
website_blog202
website_forum193
website_event108
website_event_track82
website_sale_stock60

Changes reach 54 modules in all — but they cluster. website carries the most (1,246 changes), so it's the first place to look if you extend it.

Odoo 19 to 20 Website & eCommerce migration: a guide for custom modules

A large release for Website and eCommerce where several public-facing controller routes have been removed or reshaped, so most of the risk for custom modules sits in the cart, delivery, donation and checkout flows rather than in the data model.

Start by mapping where your module hooks into the storefront: any JavaScript that calls Odoo's shop endpoints, any controller you subclass, and any template you inherit. This release moves a good deal of the cart and checkout plumbing around, so the fastest way to find your exposure is to grep your addon for the old route paths and for the controller methods you override, then work outward from there. Because much of the churn is in HTTP/JSON routes rather than in fields, a broken frontend is more likely to show up as a silent 404 than as a load error, so test the buying journey end to end.

This guide tracks the Odoo 20 development branch, which is still pre-release, and it will be refreshed at general availability once the APIs settle. The areas most likely to bite are the cart quantity and clearing flow, the delivery pickup-location lookups, and the donation payment path — all of which had their public routes removed and reorganised.

What needs the closest look

Reading the cart quantity from its own endpoint is gone

Removed method — Cart.cart_quantity

The dedicated route that returned the number of items in the cart (with a session fallback) has been removed. If your frontend polls this endpoint or you override it to tweak the badge count, move to the current cart update flow that returns quantities as part of its response instead of calling this separately.

Present in Odoo 19, removed in 20:

@route(
    route='/shop/cart/quantity',
    type='jsonrpc',
    auth='public',
    methods=['POST'],
    website=True
)
def cart_quantity(self):
    if 'website_sale_cart_quantity' not in request.session:
        return request.cart.cart_quantity
    return request.session['website_sale_cart_quantity']

The empty-the-cart route no longer exists

Removed method — Cart.clear_cart

The route that unlinked every order line to clear the cart is gone. Any custom 'clear cart' button or automation that hit this path needs to be repointed at the current cart handling, and if you overrode it to add cleanup logic, that logic needs a new home.

Present in Odoo 19, removed in 20:

@route(
    route='/shop/cart/clear',
    type='jsonrpc',
    auth='public',
    website=True
)
def clear_cart(self):
    request.cart.order_line.unlink()

Looking up pickup locations has moved

Removed method — Delivery.website_sale_get_pickup_locations

The public route that fetched nearby pickup points from a zip code (using GeoIP or the delivery address country) has been removed. If your delivery integration calls this endpoint or extends it to add carriers, you'll need to hook into the reworked pickup-location handling rather than this route.

Removed in Odoo 20 — it was defined as:

@route('/website_sale/get_pickup_locations', type='jsonrpc', auth='public', website=True)
def website_sale_get_pickup_locations(self, zip_code=None, **kwargs):

Setting the chosen pickup location has moved

Removed method — Delivery.website_sale_set_pickup_location

Its companion route that stored the customer's selected pickup point on the order is also gone. Custom delivery modules that persist extra data when a location is chosen should move that behaviour to the new mechanism that pairs with the lookup change above.

Removed in Odoo 20 — it was defined as:

@route('/website_sale/set_pickup_location', type='jsonrpc', auth='public', website=True)
def website_sale_set_pickup_location(self, pickup_location_data):

The donation payment page route is removed

Removed method — PaymentPortal.donation_pay

The controller that rendered the donation form (a donation-flavoured variant of the standard payment page, carrying donation options and prefilled amount descriptions) no longer exists. If your module links to /donation/pay or customises the donation form, rework it against the current payment flow, as donation handling is no longer a bespoke route.

Removed in Odoo 20 — it was defined as:

@http.route('/donation/pay', type='http', methods=['GET', 'POST'], auth='public', website=True, sitemap=False, list_as_website_content=_lt("Donation Payment"))
def donation_pay(self, **kwargs):

The donation transaction endpoint is gone

Removed method — PaymentPortal.donation_transaction

The route that validated a minimum donation amount and created the transaction (including public-partner handling) has been removed alongside the donation page. Any custom validation or partner logic you layered on this needs to be reimplemented within the standard transaction path.

Removed in Odoo 20 — it was defined as:

@http.route('/donation/transaction/<minimum_amount>', type='jsonrpc', auth='public', website=True, sitemap=False)
def donation_transaction(self, amount, currency_id, partner_id, access_token, minimum_amount=0, **kwargs):

The 'website info' sitemap generator was dropped

Removed method — Website.sitemap_website_info

The helper that conditionally added the /website/info page to the sitemap (only when those views were active) has been removed. If you relied on that page appearing in the sitemap or extended its generator, you'll need to register your own sitemap entry.

Removed in Odoo 20 — it was defined as:

def sitemap_website_info(env, rule, qs):

Also worth checking

Checkout and product pages. Several eCommerce helpers on the sale controllers have been dropped and are worth a look if you extended checkout. The express-checkout path lost its separate tax-computation helper for the shipping address, so if you adjusted taxes during express checkout, follow that logic into the current flow. The old product-page route and the image-clearing helper on the sale controller are gone, as is the check that decided whether to show the product configurator — if you gated the configurator or cleaned up product images through these, revisit those overrides. Kit-based availability also changed: the helper that reported unavailable quantities coming from MRP kits has been removed, which matters if your module surfaces stock messages for kit products.

Backend dashboard and installs. On the website backend, the access-rights check and the module-install tracking helpers have been removed, so any customisation of the dashboard's create-permission logic or its 'installing modules' progress needs rechecking.

Other apps built on Website. A scattering of app-specific controllers lost helper methods: partner-assignment lost its partner detail method, the forum lost its URL-title helper, and recruitment lost the check that spotted a recent duplicate application — relevant only if you extended those specific pages. On the model side, account.payment no longer carries the is_donation flag (in line with the donation rework above), and on blog.post both the post_date field and the custom copy_data have been removed, so any code that read a blog post's publish date through that field or relied on its duplication behaviour must be updated. The social helper on the website model has also gone.

Beyond these, roughly 2314 smaller internal changes exist — compute helpers and body-only edits — only relevant if you override Odoo's private helpers.

Your migration checklist

  1. Grep your module for the removed route paths (/shop/cart/quantity, /shop/cart/clear, /website_sale/get_pickup_locations, /website_sale/set_pickup_location, /donation/pay, /donation/transaction) in both Python and JavaScript, and repoint or reimplement each caller.
  2. Review any controller you subclass in Website/eCommerce for the removed methods, especially around cart, delivery pickup, donation and express checkout, and move your added logic into the current flows.
  3. Update model references: remove or replace uses of account.payment.is_donation and blog.post.post_date, and rework anything relying on blog.post.copy_data.
  4. Re-test the full buying journey (add to cart, update quantity, clear cart, choose pickup location, checkout) and the donation flow in a staging build, watching for silent 404s.
  5. If you customised the website backend dashboard or app-specific pages (forum, recruitment, partner assign), verify those still load after the helper removals.
  6. Re-run this pass at Odoo 20 GA, since these are pre-release APIs and some routes may settle differently.

Related guides

Is your module ready for Odoo 20?
Scan it free — every breaking change above, found in your actual code, with AI fixes verified on a real Odoo server.
Scan your module →