Thursday, August 28, 2025
21 changes · saas-18.4
Enhancements to existing features
Point-of-sale receipts now show loyalty points earned from the purchase and the customer’s current points balance. This makes loyalty rewards clearer for customers at checkout and helps staff answer reward-related questions more easily.
Original PR description
Before this commit: =================== - The receipt screen did not display any details about loyalty points won or the current loyalty point balance. After this commit: ================== - Loyalty point details (points earned and balance) are now displayed on the receipt screen. Task: 5022234 | saas-18.3 and above | This PR | |--------|--------| | <img width="391" height="844" alt="image" src="https://github.com/user-attachments/assets/c0ca55c0-cd46-468c-bb16-b19da5daa742" /> | <img width="391" height="844" alt="image" src="https://github.com/user-attachments/assets/1dd6d398-693b-4ab7-a598-520d6f8d8c56" /> | Forward-Port-Of: odoo/odoo#223396
Resolved issues and error corrections
This fixes a case where unbuilding a completed manufacturing order could be incorrectly blocked if component products were later changed to require lot or serial tracking. Businesses can now reverse eligible manufacturing orders without unnecessary errors, while existing lot tracking rules remain in place for components that were tracked at the time of production.
Original PR description
**Description of the issue/feature this PR addresses:** This PR fixes a regression when using the _Unbuild_ feature on a previously completed `mrp.production` whose components did not originally…
Features or functions removed from Odoo
Employee version records no longer keep separate calculated start and end dates, reducing confusion over which dates teams should rely on. The system now uses helper logic to determine the relevant dates consistently across HR, leave, calendar, and work entry processes.
Original PR description
There are currently 5 dates used in a version : - date_version: date at which the version starts to be effective - contract_date_start: start date of the contract - date_start (computed): maximum between the start of contract and the start of version - contract_date_end: end date of the contract - date_end (computed): minimum between the end of contract and the start of next version - 1 day This can create a lot of confusion between which fields should be really used, thus the decision was taken to remove the computed dates and create helper methods in their stead.
**Description of the issue/feature this PR addresses:** This PR fixes a regression when using the _Unbuild_ feature on a previously completed `mrp.production` whose components did not originally require tracking (no lot/serial), but have been updated later to require it. When unbuilding such a product, `stock.move.line._action_done` currently raises a UserError requiring a lot/serial number, because the component moves created by `mrp.unbuild`: - do not have a picking_type_id, - are not inventory moves, - are not scrap moves, - and lack lot/serial information. However, in this context, the lot requirement is misleading, as the original `mrp.production` did not generate tracked components. It is valid to restore untracked components even if they are now tracked. **Current behavior before PR:** - Create an `mrp.production` for a product with untracked components. - Complete the production. - Later, enable lot tracking on one or more of the original components. - Attempt to unbuild the production. - ❌ Error is raised: “You need to supply a Lot/Serial Number for product…” **Desired behavior after PR is merged:** - The unbuild operation proceeds without error. - The untracked components are restored correctly. - Behavior remains unchanged for tracked components that did require lot info during the original MO. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#222612 Forward-Port-Of: odoo/odoo#217282
This fixes an error that could occur when a live chat guest was connected to more than one discussion channel and then changed their display name. Users can now update guest names without interrupting the chat experience or causing a system traceback.
Original PR description
Guests linked to more than one discuss channel cause a traceback when their name is updated. Steps to reproduce the error: - Install ``website_livechat`` module with demo data - Login in as…
Guests linked to more than one discuss channel cause a traceback when their name is updated. Steps to reproduce the error: - Install ``website_livechat`` module with demo data - Login in as ``Mitchell Admin`` in one tab - Open Incognito Tab, start a conversation via the ``livechat`` button twice. - Switch back to Mitchell Admin Tab > Open that latest discuss channel > Invite People > Copy Link > paste the link into the same incognito tab - Edit the guest name (top-right corner) Traceback: ``AssertionError: channel should be empty or should be a single record: discuss.channel(5, 7)`` When the guest starts two separate conversations, two discuss.channel records are created. https://github.com/odoo/odoo/blob/f4bd509a8c828596db5aacd42099224ad9f54007/addons/mail/models/discuss/mail_guest.py#L81 During the guest name update, ``self.channel_ids`` contains multiple channels. This triggers an error from the below line. https://github.com/odoo/odoo/blob/f4bd509a8c828596db5aacd42099224ad9f54007/addons/mail/tools/discuss.py#L298-L300 sentry-6803396766 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Creating a discussion channel with guest members no longer fails when saving. This prevents an error that blocked users from setting up channels involving guests, making collaboration setup smoother.
Original PR description
Currently, an error occurs when creating a channel that includes guest members. Steps to Reproduce: - Install the `mail` module. - Go to `Channels > New`. - Fill in the `channel name` and `Under…
Currently, an error occurs when creating a channel that includes guest members. Steps to Reproduce: - Install the `mail` module. - Go to `Channels > New`. - Fill in the `channel name` and `Under Members`, add a member with a `guest`, and `save`. `KeyError: 'partner_id'` This error occurs when a user creates a channel and adds a guest in the Members section. This error occurs after [this commit]( https://github.com/odoo/odoo/commit/ad612321bcafe6dfdaabf3aa37f26af364185a69), where the partner_id and guest_id fields dynamically become readonly [1], so that if only the guest is entered, the partner becomes readonly, and when the record is created, the partner_id key does not exist, and raises the error [2]. This commit ensures that the partner_id is accessed only if it is present in the record. [1]- https://github.com/odoo/odoo/blob/5bddf9bfb634d09d3264e4fe4734d75f1083775a/addons/mail/views/discuss_channel_views.xml#L87-L88 [2]- https://github.com/odoo/odoo/blob/5bddf9bfb634d09d3264e4fe4734d75f1083775a/addons/mail/models/discuss/discuss_channel.py#L235 sentry-6791956423 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#222211
This fixes an error that could occur when a sales order form included multiple linked invoices and a user made a change that refreshed the form. Users can now edit those sales orders without seeing a blocking traceback, improving reliability for customized workflows.
Original PR description
**Step to reproduce** - create a SO - link 2+ invoices to it - using studio, add invoice_ids to the SO Form - trigger a onchange (ex. change the product from SOL) - we receive a traceback…
**Step to reproduce** - create a SO - link 2+ invoices to it - using studio, add invoice_ids to the SO Form - trigger a onchange (ex. change the product from SOL) - we receive a traceback **Traceback:** ```ValueError: Expected singleton: account.move(<NewId origin=35>, <NewId origin=31>, <NewId origin=32>, <NewId origin=33>, <NewId origin=34>)``` **Issue:** - from `onchange` triggers chain,`_compute_duplicated_ref_ids` is invoked calling `_fetch_duplicate_reference` for the related moves (invoice_ids) such that as they are in create/edit mode - at this time `convert_to_write(moves[field_name], moves)` fails as moves has more than 1 record and `recordset[field]` is not valid syntax in such case https://github.com/odoo/odoo/blob/3966753eb5a8534c8b5b8a16e626f5250c9013cf/addons/account/models/account_move.py#L1868-L1884 - hence, we receive valueError, expecting a singleton **Fix;** - we adapt the method to accept multiple moves which may be in create/edit mode opw-4959528 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#223513
Updating a product’s on-hand quantity after requesting an inventory count with an accounting date now works correctly. The accounting date is recorded in the stock move reference, preventing the previous save error and keeping inventory valuation context available.
Original PR description
Problem: When trying to update a product’s quantity after requesting a count with an accounting date set, you get an error. This error occurs because the name field was removed from the stock move model. Purpose: To have the accounted on date information set on the stock move’s reference field instead of the name field. Steps to Reproduce on Runbot: 1. Navigate to Inventory > Operations > Physical Inventory. 2. Select a product in the list view and click on Request a Count. 3. Set the Accounting Date in the wizard. 4. Navigate to the product and try to update the on-hand quantity. 5. Once you save the updated on-hand quantity you will receive an error. opw-5009967 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Point of Sale product searches now return both product variants and regular products that match the same search terms. This prevents cashiers from missing the intended item when a variant name overlaps with another product name, improving checkout accuracy.
Original PR description
If you have a product template with variant, ex: Telephone case, variant name : Iphone 15 SE, Samsung Galaxy, Nokia 1999 When doing a search with more then 2 letters you will only find the Telephone…
If you have a product template with variant, ex: Telephone case, variant name : Iphone 15 SE, Samsung Galaxy, Nokia 1999 When doing a search with more then 2 letters you will only find the Telephone case, searh exemple: Iphone 15 SE, Galaxy, Samsung. ** Step to reproduce ** - Create a product called "Telephone case" and add a variant named samsung galaxy S24 ultra - Create a product called "Samsung galaxy" - Enable both products for point of sale - Go to the point of sale app and open a shop that sells both of those products. - Do a search for the product Samsung galaxy - Issue : Only the product "Telephone case" will appear. ** Cause of the issue ** Doing a search will call getProductsBySearchWord: https://github.com/odoo/odoo/blob/5a1fff2cc61bd8676049879039defa3fb2a3f13d/addons/point_of_sale/static/src/app/services/pos_store.js#L2401-L2407 During the product.exactMatch(words) we will get a hit since we will have a name of the product variant: https://github.com/odoo/odoo/blob/5a1fff2cc61bd8676049879039defa3fb2a3f13d/addons/point_of_sale/static/src/app/models/product_template.js#L265-L278 And the call for the function will finish there since the searchword lenght > 2 and we have a hit. ** Origin of the issue ** The variant search was implemented in "exactMatch()" which block more search if it find a result. https://github.com/odoo/odoo/commit/05abd586d7adcceed3dae0943526e6357b28dbb4 opw-4864976 Forward-Port-Of: odoo/odoo#217484
Fixes a website editor crash that could happen when saving links in mega menus using the Cards template. The update ensures only real text color styles are treated as colors, preventing formatting classes from triggering an endless error loop.
Original PR description
Steps to Reproduce: - Open the website. - Create a mega menu. - Enter edit mode. - Change the mega menu template to “Cards”. - Click on any option available in the mega menu. - A link popover will…
Steps to Reproduce: - Open the website. - Create a mega menu. - Enter edit mode. - Change the mega menu template to “Cards”. - Click on any option available in the mega menu. - A link popover will open. - Click the Edit link button in the popover. - Click the Apply button to save the link. - A traceback occurs. Description of the issue: The error occurs because the text-wrap class is applied to the link. When the `hasColor` method is triggered, it checks whether **a.nav-link** has a text color class. However, `TEXT_CLASSES_REGEX` incorrectly matches **text-wrap** as a color class. As a result, the removeColor method attempts to remove it and triggers `_applyColor` to remove the color, but in `_applyColor` method it does not find any color to remove on selected text. As a result, the `removeColor` process enters an infinite loop, which eventually leads to a traceback. Solution: Update `TEXT_CLASSES_REGEX` so that it only matches valid text color classes and excludes formatting classes such as text-wrap, text-center, etc.
Saudi Arabia point-of-sale receipt QR codes now show the local KSA time instead of UTC. This keeps the scanned QR code time aligned with the printed receipt and supports ZATCA e-invoicing expectations.
Original PR description
**Problem:** If you have an SA company, and try to scan the QR code generated on the receipt, the time will be the UTC time instead of the KSA time, as we are in SA. **Steps to reproduce:** - Change your company to SA and install l10n_sa_pos - Make a purchase with a customer from SA - Scan the QR code from the receipt using an app such as E-invoice QR reader - The invoice date will be the UTC time, or 3 hours less than it should **Why the fix:** Before this fix, the time was always displayed as UTC. It could have been correct if it also displayed a 'Z' in the end, to indicate that it is not local KSA time. We now directly change it using the KSA time, to respect the ZATCA guidelines. The time is now the same on the printed invoice and in the app when scanning the QR code. opw-4769521 Forward-Port-Of: odoo/odoo#223348 Forward-Port-Of: odoo/odoo#216640
Manufacturing orders created from sales demand now remain in draft when their bill of materials has no components or operations. This prevents empty orders from being confirmed too early, giving users time to add the needed production details before proceeding.
Original PR description
Issue Before This Commit: ============================ Currently, if a BOM has `no components or operations` and is triggered via `MTSO`, the generated Manufacturing Order (MO) is automatically set to a `confirmed` state. This behaviour is inconsistent and not meaningful, as there's nothing to produce or track. Steps to Reproduce: ============================ - Install the `mrp and sale` module. - Enable MTSO route. - Create a product with a BOM that has `no components or operations`. - Create a sale order for that product. MO is created in a `confirmed` state. With This Commit: ============================ This commit ensures that MOs triggered via `MTO(Already worked) or MTSO` are created in draft state if their BOM has no components and no operations. This allows the user to manually add required details before confirming the MO. supporting custom use cases. TaskID:- 4920195 Forward-Port-Of: odoo/odoo#221844
The Spanish SME balance sheet no longer double-counts certain current financial investment accounts. This ensures investment totals match the underlying accounting entries, improving accuracy for Spanish financial reporting.
Original PR description
**Issue**: * Amounts were exactly doubled in 'Current financial investments' (line 12500) in the Spanish Balance Sheet - SMEs report as account codes 551 and 5525 were incorrectly included in…
**Issue**: * Amounts were exactly doubled in 'Current financial investments' (line 12500) in the Spanish Balance Sheet - SMEs report as account codes 551 and 5525 were incorrectly included in balance_pymes_line_12500_sub_balances formula **Root Cause**: * Account codes 551 and 5525 were included in BOTH: 1. Line 12500 sub_balances (unfiltered account_codes expression) 2. Line 12500 sub_debits (domain expression with sum_if_pos filter) * This double-counting within the same line caused financial investment amounts to appear twice in the balance sheet **How to Reproduce**: 1. Create Spanish company with 'es_pymes' chart of accounts 2. Post journal entries to accounts 551 or 5525 (current financial investments) 3. Generate 'Balance Sheet - SMEs (ES)' report 4. Observe amounts in line 'V. Current financial investments' are exactly doubled compared to account balances 5. Click on the doubled amount - shows underlying transactions sum to half the amount **Fix**: * Removed account codes 551 and 5525 from balance_pymes_line_12500_sub_balances * These accounts are properly handled by the sub_debits expression * Each account is now counted only once within the line opw-4983300 Forward-Port-Of: odoo/enterprise#93052
This fixes an issue that prevented event badges from printing through the badge printer in Point of Sale. Event staff can now print attendee badges from the POS as expected, avoiding manual workarounds during check-in or sales flows.
Original PR description
Due to an oversight in odoo/enterprise#83021, printing badges using the badge printer from POS was not working. This commit fixes the issue by restoring the `badge_format` field to the list of fields loaded in the POS.
UK tax report submissions to HMRC now include the correct obligation ID instead of leaving it undefined. This helps ensure reports are sent successfully and reduces filing errors for UK businesses using Odoo.
Original PR description
Issue: Prior to this commit, when sending a tax report to HMRC, the obligation ID was undefined Fix: sending the appropriate obligation ID opw-4965620
Italian VAT XML exports now correctly split quarterly submissions into three reporting sections instead of combining everything into one. The export file name and VAT threshold handling are also corrected, helping businesses submit compliant files with less manual adjustment.
Original PR description
Description of the issue this commit addresses: The XML export should contain three "Modulo" sections when the report is submitted quarterly but currently only ever sends one big chunk of data. Also the name of the exported file is wrong. --- Desired behavior after this commit merged: The exported file adapts to whether it is submitted monthly or quarterly and the name of the file issue is addressed. --- Community PR: https://github.com/odoo/odoo/pull/216887 task-4826511 Forward-Port-Of: odoo/enterprise#93181 Forward-Port-Of: odoo/enterprise#86642
This fix prevents exempt Brazilian ICMS taxes from being added as extra invoice amounts when Avalara marks them as not accounting-relevant. Businesses get more accurate invoice totals while still keeping a visible record of the exempt tax in the document chatter.
Original PR description
### Steps to reproduce: - Install l10n_br_edi, switch to Brazilian company - Set up Avalara - Create an invoice with the tax "ICMS Exemption Incl." which is included in price - Click "Generate taxes"…
### Steps to reproduce:
- Install l10n_br_edi, switch to Brazilian company
- Set up Avalara
- Create an invoice with the tax "ICMS Exemption Incl." which is included in price
- Click "Generate taxes" to compute the taxes with Avalara
- In "Journal Items" we can see a line for "ICMS Exemption Incl.", its value appear as excluded
### Cause:
The result from Avalara included a value for this tax:
```
'tax': 1.44,
'taxImpact': {
'accounting': 'none',
'impactOnFinalPrice': 'Included',
'impactOnNetAmount': 'Included',
},
```
But the untaxed amount is computed without this tax. Odoo keeps the untaxed amount from the response and add a line for the tax. As a result the tax is added to the amounts like an excluded tax would.
### Solution:
In the response from Avalara, we don't want to create a line for the tax `icmsDeson` when there is `'accounting': 'none'`.
We also log this tax in the chatter to keep a trace of it.
opw-4964315
Forward-Port-Of: odoo/enterprise#91940Fixed an issue where project budget indicators could show green even when an expense budget was exceeded. This helps users quickly identify overspending from the project dashboard and avoid missing budget overruns.
Original PR description
**Step to reproduce:** - install "project_account_budget" - go to accounting > accounting > Analytic Budget - create a budget of type expense,say test budget - select analytic account `Asustek - Wood…
**Step to reproduce:**
- install "project_account_budget"
- go to accounting > accounting > Analytic Budget
- create a budget of type expense,say test budget
- select analytic account `Asustek - Wood Corner`
- set budget amount => 500. open the budget
- create a new project 'test project"> open setting > Analytic Page
- add `Asustek - Wood Corner` analytic account in project field
- create a PO with amount > 500
- in analytic distribution column, add `Asustek - Wood Corner` in project column
- confirm PO and create Bill
- Go to `test project` settings > Dashboard smart button
**Observation:**
- For exceeding expense budget, we have green color in budget section
- It should be red
**Cause:**
The conditional class for budget progress was incorrectly evaluated due to missing parentheses around the `and` condition.
In expressions like:
`(true and (1 == 1 ? 'a' : 'c')) or (1 == 1 ? 'b' : 'd') → 'a'` ✅
`true and 1 == 1 ? 'a' : 'c' or 1 == 1 ? 'b' : 'd' → 'b'` ❌
Without parenthesis, the `or` clause is evaluated unexpectedly, even when the `and` branch is intended to take precedence.
This commit wraps the `and` condition in parentheses to ensure the correct evaluation order and consistent class assignment.
Budget:
<img width="1203" height="291" alt="budget 4968162" src="https://github.com/user-attachments/assets/2d8223d5-0344-4ad0-b33c-2598ea167f2d" />
Before fix:
<img width="623" height="195" alt="before fix 4968162" src="https://github.com/user-attachments/assets/4ac749bf-fa93-4835-963a-5dfbdd05559d" />
After fix:
<img width="643" height="225" alt="after fix 4968162 " src="https://github.com/user-attachments/assets/4fd228f9-e32f-48d9-b6ef-55251b21d601" />
opw-4968162
Forward-Port-Of: odoo/enterprise#91617Fixed an issue where tax return XML generation could omit data for some companies when company names were ordered in a certain way. The report now preserves the intended active company during generation, helping ensure accurate multi-company tax filings.
Original PR description
Error: When generating a tax return, there is a circumstance that will cause certain companies to be omitted from the xml computation. This happens when a child company is earlier alphabetically than the parent company. The company ids are ordered alphabetically for display purposes on the tax return view, however when writing this value into the `allowed_company_ids` context value, the first id in the list will override the current company environment variable during xml generation. To fix this the active company is passed into the context to ensure that it is not overwritten. OPW-4964467 Forward-Port-Of: odoo/enterprise#91667
The Luxembourg annual VAT declaration now includes 0% custom tax rates in the exported XML, preventing ECDF rejection when those fields are required. Employee average fields are also treated as decimal values, improving accuracy for Section V reporting.
Original PR description
**PROBLEM** 1. In Annexes D and E you can declare custom tax rate. If the custom rate is 0%, this percentage will not be exported into the xml. When submitting the xml to the ECDF, the submission…
**PROBLEM** 1. In Annexes D and E you can declare custom tax rate. If the custom rate is 0%, this percentage will not be exported into the xml. When submitting the xml to the ECDF, the submission will be rejected because the xml doesn't state how much % is the custom tax rate. 2. In Section V, code 110, 108 and 109 should be decimal since they are averages. **STEP TO REPRODUCE** 1. install the l10n_lu module and select the demo lu company. 2. In accouting app, goes to the annual tax report (Accounting/Reporting/Tax Report, select Annual VAT Declaration). 3. Goes to Appendix D or E, and fill code 128, 136, 144, and 162, and leave the custom rate(%) above each of them at 0%. 4. Export to xml (using the little cog thingy). 5. Notice the code 396, 394 149, and 153 doesn't appear in the xml. **CAUSE** 1. Field containing zero are filtered out the xml by default, which is the case of the custom rate (%) fields. 2. Average number of employee during the year is declared in the report data file to be of the integer type. **FIX** 1. Adding custom rate fields to the mandatory fields. 2. Changing type of average employee fields to float. opw-4978365 Forward-Port-Of: odoo/enterprise#91938
Bank reconciliation can now match outstanding payments even when the imported bank memo differs slightly from the original payment reference. This helps reduce missed matches from payment providers such as Stripe while preserving reliable reconciliation behavior.
Original PR description
Commit 4c23de148eb3689842a48df81a5ced772c214861 introduced another query to look for outstanding payments to match in the bank reco widget, aiming to reduce the number of wrong matches found by the algorithm. Doing so, limiting the match between account.payment initiated in odoo and their matching bank transaction imported (through stripe for example), on an exact match of the memo seemed like a good idea. But for obscure reasons, the memo we're sending is not guaranteed to be found back, depending on the payment provider and the import flow. Also, for backward compatibility, it now appears important to allow the match to be on a part of the memo, like we used to do. So we're back on a solution that splits the memo using ' - '. Forward-Port-Of: odoo/enterprise#93237
This update removes remaining references to old start and end date fields on HR version records across payroll, contracts, time off, documents, and country-specific payroll flows. It keeps those areas aligned with the newer HR data model, reducing the risk of outdated date logic affecting payslips, work entries, leave handling, and reporting.
Original PR description
Changes to files that used the now removed start_date and end_date fields from version