Daily updates from Odoo
Wednesday, May 13, 2026
104 changes
15 changes
New functionality added to Odoo
This update introduces ECPay, a new payment provider specifically designed for transactions in Taiwan. ECPay supports various payment methods including credit cards, bank transfers, and increasingly popular local options like convenience stores and mobile wallets, expanding our payment options for Taiwanese customers.
Original PR description
This change integrates a new payment provider: ECPay for payments in Taiwan. Supported Payment methods of the provider: - card: credit/debit card - bank transfer - wechat pay - [NEW] Convenience Stores (eg. 7/11, OK Mart etc.) - [NEW] Mobile Wallet (eg. iPASS Money, Jkopay etc.) - [NEW] TWQR Note: - Tokenization and Refund is not implemented in this commit. Task-5168802 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#235069
Enhancements to existing features
This update enhances the system's partner suggestion feature by prioritizing partners who have recently communicated within a discussion thread. The system now considers message recency when ranking suggestions, making it more likely that you'll see individuals you've interacted with most recently. This improves efficiency and connection within the platform.
Original PR description
backport of https://github.com/odoo/odoo/pull/262708 This commit adds a compare criteria to the `partnerCompareRegistry` used to sort partner suggestions. With this new criteria, partners that have recently authored a message in the thread will be ranked higher in the suggestion list, with the internal ordering depending on message recency. task-5932229 Forward-Port-Of: odoo/odoo#263783
Resolved issues and error corrections
This update resolves an issue where rapid actions triggered duplicate entries being created in the database for account return checks. The fix prevents multiple simultaneous processes from attempting to create the same record, ensuring data integrity. This improves the stability and efficiency of the account reporting feature.
Original PR description
Issue -------------- When refreshing checks on account returns (e.g. from rapid successive clicks or component re-renders), multiple concurrent RPC calls to `refresh_checks` were being dispatched to…
Issue
--------------
When refreshing checks on account returns (e.g. from rapid successive clicks or component re-renders), multiple concurrent RPC calls to `refresh_checks` were being dispatched to the server. This created a race condition that resulted in duplicate `account.return.check` records being generated in the database.
steps to reproduce demonstrated in video: https://drive.google.com/file/d/1-A0ZHdYGdv-UL0dqClqK6Kos_iVXoZai/view?usp=sharing
When this happen the `runAllReturnChecks` method fires parallel RPC calls to [`refresh_checks`](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1974-L1992) on the server. In the case of instant multiple RPC calls, parallel threads are dispatched which causes the data preparation stage to run simultaneously.
Because both threads run in parallel, Thread 2 runs its [preparation and existing ](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1986-L1987 )check mechanism before Thread 1 has reached the actual `create()` function [trigger](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1998-L1999). Consequently, Thread 2's existence check fails to find the record (since Thread 1 hasn't committed it to the database yet), and it considers the record eligible for creation—even though the exact same record is already prepared for creation by Thread 1. This race condition leads to duplicate `account.return.check` records.
Logs to demonstrate the thread execution:
--------
```python
2026-04-16 08:30:51,493 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.000 0.002
2026-04-16 08:30:51,662 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "POST /web/dataset/call_kw/account.report/dispatch_report_action#account.report.dispatch_report_action HTTP/1.0" 200 - 17 0.006 0.012
2026-04-16 08:30:51,847 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "POST /web/dataset/call_kw/account.return/get_views#account.return.get_views HTTP/1.0" 200 - 26 0.009 0.025
2026-04-16 08:30:52,099 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:52] "POST /web/dataset/call_kw/account.return/web_read_group#account.return.web_read_group HTTP/1.0" 200 - 95 0.029 0.064
2026-04-16 08:30:52,320 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:52] "POST /web/dataset/call_kw/account.return/get_next_returns_ids#account.return.get_next_returns_ids HTTP/1.0" 200 - 2 0.001 0.004
THREAD NAME: odoo.service.http.request.137360481711808 Thread ID: 137360481711808
REFRESH CHECK START:--------------------------------------------
Thread ID: 137360481711808 -------------DATA PREPARING STAGE------------
Thread ID: 137360481711808
Thread ID: 137360481711808 RECORD EXISTING CHECK: None
2026-04-16 08:30:53,842 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:53] "GET /odoo/tax-report/tax-return?debug=1 HTTP/1.0" 200 - 29 0.020 0.021
2026-04-16 08:30:54,066 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/webclient/load_menus HTTP/1.0" 200 - 4 0.002 0.009
2026-04-16 08:30:54,351 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/manifest.webmanifest HTTP/1.0" 200 - 6 0.003 0.005
2026-04-16 08:30:54,493 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/webclient/translations?hash=bb5aa713d587cc7dd07b13d1d7efc2c525517e99&lang=en_US HTTP/1.0" 200 - 1 0.000 0.002
2026-04-16 08:30:54,586 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/bundle/web_tour.interactive?lang=en_US&debug=1 HTTP/1.0" 200 - 1 0.001 0.003
2026-04-16 08:30:54,640 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/action/load_breadcrumbs HTTP/1.0" 200 - 7 0.003 0.006
2026-04-16 08:30:54,710 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/ir.http/lazy_session_info#ir.http.lazy_session_info HTTP/1.0" 200 - 2 0.001 0.004
2026-04-16 08:30:54,753 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /bus/websocket_worker_bundle?v=19.0-2 HTTP/1.0" 304 - 3 0.004 0.006
2026-04-16 08:30:54,766 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/image?model=res.users&field=avatar_128&id=2 HTTP/1.0" 304 - 9 0.012 0.013
2026-04-16 08:30:54,777 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /mail/data HTTP/1.0" 200 - 34 0.034 0.020
2026-04-16 08:30:54,824 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/account.return/get_views#account.return.get_views HTTP/1.0" 200 - 3 0.001 0.010
2026-04-16 08:30:54,934 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/account.return/web_read_group#account.return.web_read_group HTTP/1.0" 200 - 88 0.029 0.051
2026-04-16 08:30:55,107 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:55] "POST /web/dataset/call_kw/account.return/get_next_returns_ids#account.return.get_next_returns_ids HTTP/1.0" 200 - 2 0.001 0.005
THREAD NAME: odoo.service.http.request.137360513177280 Thread ID: 137360513177280
REFRESH CHECK START:--------------------------------------------
Thread ID: 137360513177280 -------------DATA PREPARING STAGE------------
Thread ID: 137360513177280
Thread ID: 137360513177280 RECORD EXISTING CHECK: None
2026-04-16 08:30:55,589 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:55] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.001 0.006
2026-04-16 08:30:56,702 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:56] "GET /web/service-worker.js HTTP/1.0" 200 - 1 0.000 0.003
2026-04-16 08:30:58,893 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:58] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.006 0.023
2026-04-16 08:31:05,296 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:31:05] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.001 0.002
Thread ID: 137360481711808 DATA to_create: 168
Thread ID: 137360481711808 done process create
2026-04-16 08:31:10,132 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:31:10] "POST /web/dataset/call_kw/account.return/refresh_checks#account.return.refresh_checks HTTP/1.0" 200 - 513 11.611 6.039
Thread ID: 137360513177280 DATA to_create: 168
Thread ID: 137360513177280 done process create
```
- OPW: 5917459
Forward-Port-Of: odoo/enterprise#114045This update refines how Odoo automatically matches bank statements to invoices and payments. Previously, it prioritized the closest date, which wasn't always accurate. Now, it only matches if there's one prior statement candidate, ensuring more reliable reconciliation and reducing potential errors in financial reporting.
Original PR description
Before this pr, we decided that when there was multiple candidates, we would take the one closer to the date of the statement line but it is not always what we want. We decided to change that so that it would match only if there is one candidate prior the date of the statement line. Exemple: Invoice 1 the 10/06 and invoice 2 the 20/06 → Payment the 05/06 → no matching (0 before) → Payment the 15/06 → match with invoice 1 (only 1 before) → Payment the 25/06 → no matching (More than 1 invoice open before) task-6143809 Forward-Port-Of: odoo/enterprise#115888 Forward-Port-Of: odoo/enterprise#115284
This update fixes an issue where loyalty point transactions in POS orders were only recorded as a net difference, not the individual earned and spent amounts. The change ensures that the loyalty history accurately reflects the complete transaction, providing a more precise record of customer loyalty activity. This improves reporting and data accuracy for managing customer rewards.
Original PR description
When a loyalty card both earned and spent points in the same POS order, the history entry only reflected the net difference instead of the gross amounts. The root cause was that the JS payload sent only a single `points` field representing the net change. Fix by tracking `points_earned` and `points_spent` separately in `couponData` and sending them to the server. opw-6041420 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262314 Forward-Port-Of: odoo/odoo#256022
This update fixes a recurring issue where Odoo would repeatedly retry sending eTIMS transactions, leading to an error (924). The change improves reliability by intelligently handling network interruptions and ensuring that invoice numbers are not duplicated, preventing delays and data inconsistencies. This ensures smoother eTIMS processing for Kenyan customers.
Original PR description
When the network drops after eTIMS processes a transaction but before Odoo receives the confirmation, Odoo would retry with the same invoice number, causing eTIMS error 924 (Invoice number already…
When the network drops after eTIMS processes a transaction but before Odoo receives the confirmation, Odoo would retry with the same invoice number, causing eTIMS error 924 (Invoice number already exists). For POS orders, the old code decremented the sequence on any error (including timeout), so the next retry consumed the same invcNo. If eTIMS had already recorded the original send, the retry was rejected with 924. Fix by introducing a fetch-first strategy: on retry, if a pending invcNo is found in l10n_ke_order_json, call selectInvoiceDetails before sending. If eTIMS already has the invoice, recover the receipt data directly without resending. If eTIMS does not have it, resend with the same invcNo safely. On timeout errors, the sequence is no longer decremented so the invcNo is preserved in l10n_ke_order_json for the next idempotent retry. For customer invoices, the existing fetch-first logic only bailed out on TIM (timeout) errors, falling through on CON (connection) errors and retrying blindly. Additionally, if saveTrnsSalesOsdc returned 924, there was no recovery path and the invoice number would be cleared. Fix by also bailing on CON in the fetch block, and adding an explicit 924 handler that calls selectInvoiceDetails to recover the existing receipt instead of failing. opw-6105693 Forward-Port-Of: odoo/enterprise#115649
This update fixes a bug that occurred when users tried to reschedule marketing activities, specifically within automated campaigns. The change prevents errors related to missing parent information, ensuring campaigns run smoothly and reliably. This improves the stability of our marketing automation features.
Original PR description
**Steps to reproduce:** - Create a new marketing campaign with two activities - Set them to occur some number of days after the beginning - Save the campaign and start it - Modify one of the…
**Steps to reproduce:** - Create a new marketing campaign with two activities - Set them to occur some number of days after the beginning - Save the campaign and start it - Modify one of the activities to occur some number of days after the other activity and save - Modify the child activity by changing the number of days after its parent that it should run and save - An error will be thrown **Issue:** The trace related to the child activity has no parent when trying to reschedule it in `_update_schedule_date`. This causes an issue when trying to get the first mailing_trace_ids using index 0 in this line: `base_dt_str = trace.parent_id.schedule_date or trace.parent_id.mailing_trace_ids[0].write_date or trace.participant_id.create_date` **Fix:** Prevent the activity hierarchy to be modified on started campaigns. We also change the indexing to avoid further out of range issue and properly default on the participant create value. Trying to match existing traces to their parents has too many edge cases when trying to avoid duplicates, and might often need to reset the whole trace chain to work properly. This approach avoids user mistakes on running campaigns, but if a user tries to launch a test (even on draft campaign) he won't be able to modify the hierarchy further without deleting/recreating some activities/traces. So we should ignore this for test traces, but it could impact the behavior between test and actual executions. opw-5362978 Forward-Port-Of: odoo/enterprise#107556
This update optimizes the PDF generation process for Odoo's SA (Saudi Arabia) edition, addressing a significant performance bottleneck. Previously, PDF creation was delaying checkout, but ZATCA now only requires XML and QR codes. This change dramatically speeds up the checkout process for SA users.
Original PR description
For SA companies, wkhtmltopdf PDF generation was accounting for ~47% of the sync_from_ui response time (~3.1s out of ~6.5s total), blocking the cashier at every order. The PDF is not needed during checkout: ZATCA requires only the signed XML and returns the QR code. The PDF can be generated on demand when the invoice is first viewed or downloaded. opw-6019994 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261417 Forward-Port-Of: odoo/odoo#253641
This update resolves an error that occurred when calculating overtime deductions for employees with specific filing statuses (other than 'single' or 'jointly'). The fix ensures the system correctly handles different filing status values, preventing a crash. This improves the accuracy of overtime calculations for a wider range of employee scenarios.
Original PR description
Issue: ---------------------------------------- When having an employee with `l10n_us_filing_status` not in `['single', 'jointly']` and evaluating the rule parameter…
Issue: ---------------------------------------- When having an employee with `l10n_us_filing_status` not in `['single', 'jointly']` and evaluating the rule parameter `l10n_us_qualified_overtime_deduction_cap` an error occurs. Cause: ---------------------------------------- `l10n_us_filing_status` can have 5 values: `['single', 'jointly', 'separately', 'head', 'survivor']` But only `['single', 'jointly']` are defined for `l10n_us_qualified_overtime_deduction_cap` ([src](https://github.com/odoo/enterprise/blob/2d2056766441157dc45ebc37b677841c44e5c513/l10n_us_hr_payroll/data/hr_rule_parameters_data.xml#L48)). When running the rule "Qualified Overtime", the custom Python crashes because we read a key that is not there: https://github.com/odoo/enterprise/blob/2d2056766441157dc45ebc37b677841c44e5c513/l10n_us_hr_payroll/data/hr_salary_rule_data.xml#L56 Solution: ---------------------------------------- In the custom Python condition, we first check if the key is there. The custom Python computation also tries to read the key, but it is run only if the condition is validated. So we don't need to change it. Also fixed indentation of test 069. opw-6129657 Forward-Port-Of: odoo/enterprise#116913 Forward-Port-Of: odoo/enterprise#115754
This update resolves an issue where Swedish characters in import files were being incorrectly interpreted, resulting in misformatted account data. The fix ensures that account names are imported accurately, specifically addressing the 'vriga imm anl tillg' error for account 1090. This improves data integrity for Swedish businesses using the Odoo Enterprise system.
Original PR description
Issue: Non-ASCII charatcter from sie file were lost on import. Steps to reproduce: - in a Swedish company - import the SIE4 exemple file from sie website: https://sie.se/wp-content/uploads/2024/01/SIE4-Exempelfil-Sample-file-1.zip Current behavior: - The account 1090 is imported as "vriga imm anl tillg" instead of "Övriga imm anl tillg" Expected behavior: - The account 1090 is imported as "Övriga imm anl tillg" Cause: CP437 uses 8 bits to represent data. Ö is \x99. However, file was imported using either UTF-8 or ISO-8859-1, where Ö is \xC396 and \x99 doesn't link to anything. This commit update the test file as it was save in cp437 but read as UTF-8. opw-6167408 Forward-Port-Of: odoo/enterprise#116722
This update resolves an issue where users couldn't send messages from opportunities when a company partner was assigned. The previous system incorrectly checked for a direct match between the user and the assigned partner, failing when the user was a child contact. This change uses a more robust 'child_of' filter to ensure proper access, allowing messages to be sent correctly from company partners.
Original PR description
Steps to reproduce: 1) Create a partner contact form 2) Create a child contact for this partner, and grant it portal access 3) Create a customer contact form 4) Create an opportunity for the customer, with the previously created partner as "assigned partner" 5) Connect on the portal account of the partner 6) Send a message from an opportunity When a company partner is assigned to an opportunity (instead of a specific contact person), posting a message in the chatter raised a 404 NotFound error. _mail_get_operation_for_mail_message_operation was using a strict equality check (partner_assigned_id == user.partner_id), which fails when the assigned partner is the company and the user is a child contact under it. Replace the equality check with a child_of domain filter on commercial_partner_id, consistent with the logic already used in _assert_portal_write_access. Forward-Port-Of: odoo/odoo#259973 Forward-Port-Of: odoo/odoo#252854
This update resolves several errors that could occur when Odoo processes NOTI files for Belgian payroll. These errors were preventing accurate tax calculations and reporting for businesses using the l10n_be_hr_payroll module. The fix ensures more reliable and accurate payroll processing for Belgian users.
Original PR description
Forward-Port-Of: odoo/enterprise#116871
This update fixes a bug in the Belgium Payroll DMFA report that incorrectly displayed 'Days Per Week' as 5 when employees worked fewer than 5 days. The fix ensures the report accurately reflects the employee's actual working schedule, improving the accuracy of tax reporting.
Original PR description
## Issue When generating a DMFA report with a working schedule with more or less than 5 days a week, the *Days Per Week* value in the report is still appearing as 5. ## Steps to reproduce 1. Install…
## Issue
When generating a DMFA report with a working schedule with more or less than 5 days a week, the *Days Per Week* value in the report is still appearing as 5.
## Steps to reproduce
1. Install *Belgium - Payroll* (`l10n_be_hr_payroll`)
2. In Payroll's Settings:
- set *ONSS Registration Number* to `0830123456`
- set *DMFA Employer Class* to `083`
- create a *Work Address DMFA code* (any name, any numeral code, but set the *Working Address* to the Belgian company used for the rest of the steps)
3. In Employees' Settings, set the *Company Working Hours* to a new Working Schedule, with 9 hours/day, 4 days/week. E.g from Monday to Thursday included:
- Work from 8:00 to 12:00
- Lunch from 12:00 to 13:00
- Work from 13:00 to 18:00
4. Create an Employee E for the Belgian company:
- In the *Payroll* tab, set the start date of the contract to 01/01/2026.
- In the *Personal* tab, set the *NISS Number* to `85073003328`
5. Create the payslip for January 2026 for the Employee E.
6. In Payroll > Reporting > Belgium > DMFA, create a new DMFA for the first quarter of 2026 and generate the PDF report
7. **In the generated PDF report, the _Days per Week_ line is set to 5.**
## Cause
The number of days was calculated by multiplying `5` with the `work_time_rate` of the related calendar. This is inaccurate in the case of a company where employees are only expected to work 4 days a week.
opw-6103934
Forward-Port-Of: odoo/enterprise#116963
Forward-Port-Of: odoo/enterprise#113804This update fixes a display issue where the number of ECOs listed on a Bill of Materials (BoM) was incorrect. The fix ensures that the count accurately reflects the ECOs directly associated with the current BoM version, resolving a misleading display for users. This improves the accuracy of BoM information and simplifies understanding of related changes.
Original PR description
Steps to Reproduce (Fresh Database): -------------------------------------- 1. Install `Manufacturing` (mrp) and `PLM` (mrp_plm) modules 2. Create a product > New -- Name: "Test Product" > Save 3.…
Steps to Reproduce (Fresh Database):
--------------------------------------
1. Install `Manufacturing` (mrp) and `PLM` (mrp_plm) modules
2. Create a product > New -- Name: "Test Product" > Save
3. Create BoM v1
- Go to Manufacturing > Products > Bills of Materials > New --Product: Test Product
- Add component: any
4. Create and apply ECO 1 on BoM v1
- Go to PLM > ECOs > New-- Product: Test Product | Apply on: Bill of Materials
- BoM: Test Product (v1) > Confirm > Apply Changes
- This creates BoM v2 (previous_bom_id = BoM v1)
5. Create and apply ECO 2 on BoM v2
- Same as step 4 but select BoM v2
- This creates BoM v3 (previous_bom_id = BoM v2)
6. Create a separate unrelated BoM for the same product
- Go to Manufacturing > Bills of Materials > New
- Product: Test Product | Component: "Component B" > Save
7. Create ECO 3 on the separate BoM
- Go to PLM > ECOs > New - Product: Test Product | Apply on: Bill of Materials
- BoM: select the separate BoM from step 6 > Confirm
Observed Bug:
-------------
- Open BoM v3 > ECO(s) stat button shows count = 2
- Click the button > opens 3 records (ECO 3 incorrectly included)
Explain:-
----------
The ECO stat button on the BoM form was showing a mismatched count vs
the actual records opened when clicking it. This happened because
[button_mrp_eco](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/mrp_plm/models/mrp_bom.py#L56) was using all keys from [_get_previous_boms](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/mrp_plm/models/mrp_bom.py#L67)() as the
domain, which includes BoMs from unrelated lineages of the same product
template, while [_compute_eco_data](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/mrp_plm/models/mrp_bom.py#L20) only counts ECOs belonging to the
current BoM's version lineage.
Fixed by filtering the domain to only include BoM IDs whose lineage set
contains the current BoM ID, making the opened records consistent with
the displayed count.
Before Fix
<img width="1901" height="875" alt="image" src="https://github.com/user-attachments/assets/3208aed5-ebd3-47a3-a457-a7d61b7743cb" />
```
In [24]: labo = self.env['mrp.bom'].browse(710)
In [25]: previous_boms_mapping = labo._get_previous_boms()
In [26]: Test = ['&', ('bom_id', 'in', list(previous_boms_mapping.keys())), ('type', '=', 'bom')]
In [27]: Test
Out[27]:
['&',
('bom_id',
'in',
[710,
1991,
2049,
1913,
1840,
1823,
1676,
1759,
1794,
1651,
1604,
1544,
1537,
1527,
1506,
1460,
1265,
1259,
1196,
1221,
1223,
1060,
1029,
960,
858,
850,
791,
739,
723,
698]),
('type', '=', 'bom')]
```
With My Fix
<img width="1824" height="947" alt="image" src="https://github.com/user-attachments/assets/0d68fdbc-7e42-4ce4-a326-2fb030ba1d06" />
```
In [15]: labo = self.env['mrp.bom'].browse(710)
In [16]: previous_boms_mapping = labo._get_previous_boms()
In [17]: previous_boms_mapping
Out[17]:
{710: {710},
1991: set(),
2049: set(),
1913: set(),
1840: set(),
1823: set(),
1676: set(),
1759: set(),
1794: set(),
1651: set(),
1604: set(),
1544: set(),
1537: set(),
1527: set(),
1506: set(),
1460: set(),
1265: set(),
1259: set(),
1196: set(),
1221: set(),
1223: set(),
1060: set(),
1029: set(),
960: set(),
858: set(),
850: set(),
791: set(),
739: set(),
723: set(),
698: {710}}
In [18]: relevant_bom_ids = [
...: bom_id
...: for bom_id, current_bom_set in previous_boms_mapping.items()
...: if labo.id in current_bom_set
...: ]
In [19]: relevant_bom_ids
Out[19]: [710, 698]
```
Task-6065020
Forward-Port-Of: odoo/enterprise#114039This update resolves an issue where users were experiencing errors when opening account records. The fix ensures that payment IDs returned in a key calculation are filtered based on user access rights, preventing unauthorized access and improving stability. This change was made to align with existing security practices.
Original PR description
the computed fields _compute_reconciled_payment_ids return payment ids with a sql request that by pass the access rule. This lead in an error while opening some account.move as for https://github.com/odoo/enterprise/pull/99410 invoice_ids in sale.order the result return by the sql query should be filtered according to the access right. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261595
16 changes
New functionality added to Odoo
This update introduces ECPay, a new payment provider specifically designed to support transactions in Taiwan. ECPay allows customers to pay via credit/debit cards, bank transfers, popular mobile wallets, convenience stores (like 7-Eleven), and QR codes, expanding payment options for Taiwanese users.
Original PR description
This change integrates a new payment provider: ECPay for payments in Taiwan. Supported Payment methods of the provider: - card: credit/debit card - bank transfer - wechat pay - [NEW] Convenience Stores (eg. 7/11, OK Mart etc.) - [NEW] Mobile Wallet (eg. iPASS Money, Jkopay etc.) - [NEW] TWQR Note: - Tokenization and Refund is not implemented in this commit. Task-5168802 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#235069
Resolved issues and error corrections
This update resolves an issue where rapid actions triggered duplicate account return checks, leading to unnecessary database entries. The fix ensures that only one check is created, improving system performance and data integrity. This was caused by a race condition in how the system processed multiple requests.
Original PR description
Issue -------------- When refreshing checks on account returns (e.g. from rapid successive clicks or component re-renders), multiple concurrent RPC calls to `refresh_checks` were being dispatched to…
Issue
--------------
When refreshing checks on account returns (e.g. from rapid successive clicks or component re-renders), multiple concurrent RPC calls to `refresh_checks` were being dispatched to the server. This created a race condition that resulted in duplicate `account.return.check` records being generated in the database.
steps to reproduce demonstrated in video: https://drive.google.com/file/d/1-A0ZHdYGdv-UL0dqClqK6Kos_iVXoZai/view?usp=sharing
When this happen the `runAllReturnChecks` method fires parallel RPC calls to [`refresh_checks`](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1974-L1992) on the server. In the case of instant multiple RPC calls, parallel threads are dispatched which causes the data preparation stage to run simultaneously.
Because both threads run in parallel, Thread 2 runs its [preparation and existing ](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1986-L1987 )check mechanism before Thread 1 has reached the actual `create()` function [trigger](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1998-L1999). Consequently, Thread 2's existence check fails to find the record (since Thread 1 hasn't committed it to the database yet), and it considers the record eligible for creation—even though the exact same record is already prepared for creation by Thread 1. This race condition leads to duplicate `account.return.check` records.
Logs to demonstrate the thread execution:
--------
```python
2026-04-16 08:30:51,493 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.000 0.002
2026-04-16 08:30:51,662 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "POST /web/dataset/call_kw/account.report/dispatch_report_action#account.report.dispatch_report_action HTTP/1.0" 200 - 17 0.006 0.012
2026-04-16 08:30:51,847 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "POST /web/dataset/call_kw/account.return/get_views#account.return.get_views HTTP/1.0" 200 - 26 0.009 0.025
2026-04-16 08:30:52,099 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:52] "POST /web/dataset/call_kw/account.return/web_read_group#account.return.web_read_group HTTP/1.0" 200 - 95 0.029 0.064
2026-04-16 08:30:52,320 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:52] "POST /web/dataset/call_kw/account.return/get_next_returns_ids#account.return.get_next_returns_ids HTTP/1.0" 200 - 2 0.001 0.004
THREAD NAME: odoo.service.http.request.137360481711808 Thread ID: 137360481711808
REFRESH CHECK START:--------------------------------------------
Thread ID: 137360481711808 -------------DATA PREPARING STAGE------------
Thread ID: 137360481711808
Thread ID: 137360481711808 RECORD EXISTING CHECK: None
2026-04-16 08:30:53,842 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:53] "GET /odoo/tax-report/tax-return?debug=1 HTTP/1.0" 200 - 29 0.020 0.021
2026-04-16 08:30:54,066 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/webclient/load_menus HTTP/1.0" 200 - 4 0.002 0.009
2026-04-16 08:30:54,351 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/manifest.webmanifest HTTP/1.0" 200 - 6 0.003 0.005
2026-04-16 08:30:54,493 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/webclient/translations?hash=bb5aa713d587cc7dd07b13d1d7efc2c525517e99&lang=en_US HTTP/1.0" 200 - 1 0.000 0.002
2026-04-16 08:30:54,586 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/bundle/web_tour.interactive?lang=en_US&debug=1 HTTP/1.0" 200 - 1 0.001 0.003
2026-04-16 08:30:54,640 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/action/load_breadcrumbs HTTP/1.0" 200 - 7 0.003 0.006
2026-04-16 08:30:54,710 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/ir.http/lazy_session_info#ir.http.lazy_session_info HTTP/1.0" 200 - 2 0.001 0.004
2026-04-16 08:30:54,753 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /bus/websocket_worker_bundle?v=19.0-2 HTTP/1.0" 304 - 3 0.004 0.006
2026-04-16 08:30:54,766 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/image?model=res.users&field=avatar_128&id=2 HTTP/1.0" 304 - 9 0.012 0.013
2026-04-16 08:30:54,777 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /mail/data HTTP/1.0" 200 - 34 0.034 0.020
2026-04-16 08:30:54,824 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/account.return/get_views#account.return.get_views HTTP/1.0" 200 - 3 0.001 0.010
2026-04-16 08:30:54,934 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/account.return/web_read_group#account.return.web_read_group HTTP/1.0" 200 - 88 0.029 0.051
2026-04-16 08:30:55,107 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:55] "POST /web/dataset/call_kw/account.return/get_next_returns_ids#account.return.get_next_returns_ids HTTP/1.0" 200 - 2 0.001 0.005
THREAD NAME: odoo.service.http.request.137360513177280 Thread ID: 137360513177280
REFRESH CHECK START:--------------------------------------------
Thread ID: 137360513177280 -------------DATA PREPARING STAGE------------
Thread ID: 137360513177280
Thread ID: 137360513177280 RECORD EXISTING CHECK: None
2026-04-16 08:30:55,589 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:55] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.001 0.006
2026-04-16 08:30:56,702 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:56] "GET /web/service-worker.js HTTP/1.0" 200 - 1 0.000 0.003
2026-04-16 08:30:58,893 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:58] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.006 0.023
2026-04-16 08:31:05,296 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:31:05] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.001 0.002
Thread ID: 137360481711808 DATA to_create: 168
Thread ID: 137360481711808 done process create
2026-04-16 08:31:10,132 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:31:10] "POST /web/dataset/call_kw/account.return/refresh_checks#account.return.refresh_checks HTTP/1.0" 200 - 513 11.611 6.039
Thread ID: 137360513177280 DATA to_create: 168
Thread ID: 137360513177280 done process create
```
- OPW: 5917459
Forward-Port-Of: odoo/enterprise#114045This update enhances the logging of technical errors related to Saudi VAT (ZATCA) compliance within the odoo system. Previously, these errors were hidden from users to maintain a clean interface, but this made troubleshooting difficult. Now, server logs will record these errors with a specific prefix, allowing our team to quickly identify and resolve issues.
Original PR description
Log suppressed technical validation failures in server logs with a stable ZATCA_ERROR prefix while keeping user-facing errors unchanged. task-6110313 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261536
This update refines how Odoo automatically matches bank statements to invoices and payments. Previously, it prioritized the closest date, which wasn't always accurate. Now, it only matches if there's one prior statement candidate, ensuring more reliable reconciliation and reducing potential errors in financial reporting.
Original PR description
Before this pr, we decided that when there was multiple candidates, we would take the one closer to the date of the statement line but it is not always what we want. We decided to change that so that it would match only if there is one candidate prior the date of the statement line. Exemple: Invoice 1 the 10/06 and invoice 2 the 20/06 → Payment the 05/06 → no matching (0 before) → Payment the 15/06 → match with invoice 1 (only 1 before) → Payment the 25/06 → no matching (More than 1 invoice open before) task-6143809 Forward-Port-Of: odoo/enterprise#115888 Forward-Port-Of: odoo/enterprise#115284
This update fixes a previous issue where employee export reports were unavailable. It reintroduces the ability to generate these reports by updating the user interface and ensuring compatibility across installed modules. This ensures users can continue to generate necessary reports.
Original PR description
During the work entry apocalypse, the gantt view that was used to do the exports for Partena, Acerta etc was removed. With it, we lost the ability to trigger those reports, which we want to…
During the work entry apocalypse, the gantt view that was used to do the exports for Partena, Acerta etc was removed. With it, we lost the ability to trigger those reports, which we want to reintroduce here. To do so we create a dropdown element in the cog menu registry, which starts out empty but is populated with the various reports based on which modules are isntalled, by inheriting and adding the relative dropdown items. At the same time, currently the cogmenu of the employee when hr_presence is installed is being overridden to use HrPresenceCogMenu which adds a Dropdown of its own that includes actions related to employee presence. Therefore, we need to refactor this dropdown becuase depending on the module installation order the HrPresenceCogMenu might override the addition of the ExportCogMenu and overriding the CogMenu is not the correct way to add elements to it in general. I have been able to move the logic of the PresenceCogMenu to the registry but the actions don't have the correct context and give errors because the records are not passed. Also there are some problems with the ActionMenu (the one that shows up if you select employees from the lsit view. Task: 5985900
This update reintroduces the ability to export HR reports that were previously unavailable. The changes address an issue where export functionality was removed and now utilize a more robust method for adding export options based on installed modules. This ensures consistent reporting across different HR modules.
Original PR description
During the work entry apocalypse, the gantt view that was used to do the exports for Partena, Acerta etc was removed. With it, we lost the ability to trigger those reports, which we want to…
During the work entry apocalypse, the gantt view that was used to do the exports for Partena, Acerta etc was removed. With it, we lost the ability to trigger those reports, which we want to reintroduce here. To do so we create a dropdown element in the cog menu registry, which starts out empty but is populated with the various reports based on which modules are isntalled, by inheriting and adding the relative dropdown items. At the same time, currently the cogmenu of the employee when hr_presence is installed is being overridden to use HrPresenceCogMenu which adds a Dropdown of its own that includes actions related to employee presence. Therefore, we need to refactor this dropdown becuase depending on the module installation order the HrPresenceCogMenu might override the addition of the ExportCogMenu and overriding the CogMenu is not the correct way to add elements to it in general. I have been able to move the logic of the PresenceCogMenu to the registry but the actions don't have the correct context and give errors because the records are not passed. Also there are some problems with the ActionMenu (the one that shows up if you select employees from the lsit view. Task: 5985900
This update fixes an issue where scanning a packaging barcode (like '6' for a 6-pack) intermittently added quantities to the wrong line in the stock picking process. The fix ensures the barcode scan correctly identifies and updates the intended packaging unit, resolving quantity discrepancies.
Original PR description
Issue ----- When there are 2 lines for a single product and different packaging uoms, scanning a packaging barcode alternates between lines. Steps to reproduce ----- - Enable packagings - Create a…
Issue ----- When there are 2 lines for a single product and different packaging uoms, scanning a packaging barcode alternates between lines. Steps to reproduce ----- - Enable packagings - Create a product AAA - barcode 1 - Create a packaging 6-Pack - 6 units - barcode for AAA set to 6 - Create a PO - one line for 30 units of AAA - one line for 5 6-Pack of AAA - Confirm PO and open picking in barcode - Scan "6" multiple times > Quantity increases on both lines, alternating for each scan Cause ----- Both lines can be found as matching lines when doing https://github.com/odoo/enterprise/blob/d279632db25713dd639a51385cad197dfdbd2bdc/stock_barcode/static/src/models/barcode_model.js#L1426 The reason it alternates between the lines is because we set the currently selected line first in the array - and since both lines match, the `foundLine` returned ends up being the non-selected line. https://github.com/odoo/enterprise/blob/d279632db25713dd639a51385cad197dfdbd2bdc/stock_barcode/static/src/models/barcode_model.js#L1823-L1832 We can avoid this y refining the `break` condition of the loop to also match the packaging uom. ----- Ticket: opw-6034572 Forward-Port-Of: odoo/enterprise#112578
This update fixes a recurring issue where Odoo would retry eTIMS transactions, leading to errors (specifically 924) because it was using the same invoice number repeatedly. The fix ensures Odoo intelligently recovers existing invoice data when possible, improving the reliability of eTIMS processing for Kenyan VAT invoices. This prevents delays and ensures accurate data transmission.
Original PR description
When the network drops after eTIMS processes a transaction but before Odoo receives the confirmation, Odoo would retry with the same invoice number, causing eTIMS error 924 (Invoice number already…
When the network drops after eTIMS processes a transaction but before Odoo receives the confirmation, Odoo would retry with the same invoice number, causing eTIMS error 924 (Invoice number already exists). For POS orders, the old code decremented the sequence on any error (including timeout), so the next retry consumed the same invcNo. If eTIMS had already recorded the original send, the retry was rejected with 924. Fix by introducing a fetch-first strategy: on retry, if a pending invcNo is found in l10n_ke_order_json, call selectInvoiceDetails before sending. If eTIMS already has the invoice, recover the receipt data directly without resending. If eTIMS does not have it, resend with the same invcNo safely. On timeout errors, the sequence is no longer decremented so the invcNo is preserved in l10n_ke_order_json for the next idempotent retry. For customer invoices, the existing fetch-first logic only bailed out on TIM (timeout) errors, falling through on CON (connection) errors and retrying blindly. Additionally, if saveTrnsSalesOsdc returned 924, there was no recovery path and the invoice number would be cleared. Fix by also bailing on CON in the fetch block, and adding an explicit 924 handler that calls selectInvoiceDetails to recover the existing receipt instead of failing. opw-6105693 Forward-Port-Of: odoo/enterprise#115649
This update fixes a bug that occurred when users tried to reschedule marketing activities, specifically within automated campaigns. The change prevents errors related to missing parent information, ensuring campaign scheduling works reliably. It also avoids potential user confusion by limiting modification options for test campaigns.
Original PR description
**Steps to reproduce:** - Create a new marketing campaign with two activities - Set them to occur some number of days after the beginning - Save the campaign and start it - Modify one of the…
**Steps to reproduce:** - Create a new marketing campaign with two activities - Set them to occur some number of days after the beginning - Save the campaign and start it - Modify one of the activities to occur some number of days after the other activity and save - Modify the child activity by changing the number of days after its parent that it should run and save - An error will be thrown **Issue:** The trace related to the child activity has no parent when trying to reschedule it in `_update_schedule_date`. This causes an issue when trying to get the first mailing_trace_ids using index 0 in this line: `base_dt_str = trace.parent_id.schedule_date or trace.parent_id.mailing_trace_ids[0].write_date or trace.participant_id.create_date` **Fix:** Prevent the activity hierarchy to be modified on started campaigns. We also change the indexing to avoid further out of range issue and properly default on the participant create value. Trying to match existing traces to their parents has too many edge cases when trying to avoid duplicates, and might often need to reset the whole trace chain to work properly. This approach avoids user mistakes on running campaigns, but if a user tries to launch a test (even on draft campaign) he won't be able to modify the hierarchy further without deleting/recreating some activities/traces. So we should ignore this for test traces, but it could impact the behavior between test and actual executions. opw-5362978 Forward-Port-Of: odoo/enterprise#107556
This update resolves several errors that occurred when the system processed NOTI files for Belgian payroll. The fix ensures accurate calculations and reporting related to ONSS declarations, improving the reliability of payroll data. This prevents potential discrepancies and ensures compliance with Belgian tax regulations.
Original PR description
Forward-Port-Of: odoo/enterprise#116871
This update resolves an issue where users were experiencing errors when opening account records. The fix ensures that payment IDs returned in a key calculation are filtered based on user access rights, preventing unauthorized access to sensitive financial data. This improves data security and stability.
Original PR description
the computed fields _compute_reconciled_payment_ids return payment ids with a sql request that by pass the access rule. This lead in an error while opening some account.move as for https://github.com/odoo/enterprise/pull/99410 invoice_ids in sale.order the result return by the sql query should be filtered according to the access right. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261595
This update fixes a confusion point in the split bill screen for point-of-sale, allowing users to clearly see the different price variations for product variants. Previously, it was difficult to identify which price corresponded to each variant option when splitting an order. This enhancement ensures accurate order processing and reduces potential errors.
Original PR description
Currently, when using the split bill screen you cannot differentiate variants. That's problematic when each variant is assigned to an extra price and you have to determine which price corresponds to each variant. Steps to reproduce: ------------------- * Go to the product and search for the Bacon Burger * Assign a different extra price for each variant option * Open Restaurant * Order the bacon burger multiple times, one for each possible variant * Split the order > Observation: On the split screen you see multiple lines of bacon burger each with a different price but if you don't know all the extra price possible it's impossible to know which orderline corresponds to each variant. Why the fix: ------------ Attributes are only shown in display mode, we also show them in split mode. opw-6041713 Forward-Port-Of: odoo/odoo#262489 Forward-Port-Of: odoo/odoo#257265
This update fixes a reporting issue where employees with flexible schedules and overlapping shifts were incorrectly shown with double the planned hours. The fix ensures that the attendance analysis accurately reflects the duration of planned shifts, regardless of overlap, preventing inflated reporting figures.
Original PR description
__ ## Short functional explanation of the error When for an employee with a Flexible schedule, we set a shift overlapping on two days. The attendance report displays twice the worked hours. ##…
__ ## Short functional explanation of the error When for an employee with a Flexible schedule, we set a shift overlapping on two days. The attendance report displays twice the worked hours. ## Reproduction Steps 1. Create an employee with a flexible schedule and with Work Entry Source set at Planning. 2. Go to Planning. Create a Planning Slot for this employee from 9 pm to 5 am, then Send and Publish it. 3. Click on the Reporting tab > Planning / Attendance Analysis. ### Expected behavior The total for this Month for this employee under the Planned Time field should be equal to 8 hours, which is the duration of the planning slot. ### Unexpected behavior The total for this Month for this employee under the Planned Time field is equal to 16 hours. ## Origin of the issue This report is a view, for which the SQL is defined starting this line: https://github.com/odoo/enterprise/blob/7362f1c5be7f496bdab660ed8fad37a6dd283616/planning_attendance/report/planning_attendance_analysis_report.py#L27 the issue stems from here: https://github.com/odoo/enterprise/blob/7362f1c5be7f496bdab660ed8fad37a6dd283616/planning_attendance/report/planning_attendance_analysis_report.py#L56 where we don't select distinct the planning entries based on their ID. As our shift overlaps 2 days, there will be only one entry for this shift in the `planning_slot`, but because of that, it will be duplicated. __ opw-6146052 Forward-Port-Of: odoo/enterprise#115447
This update resolves several issues related to timesheet timers, specifically preventing incorrect timer displays and simultaneous timer activation. The fix reverts changes that were causing the timer to reset incorrectly or run in the background, ensuring accurate time tracking within projects.
Original PR description
## Issues When starting a timer from a task within a project, the timer appears in two locations: the page header, and the task's *Timesheets* tab. The latter does not behave as expected: when…
## Issues When starting a timer from a task within a project, the timer appears in two locations: the page header, and the task's *Timesheets* tab. The latter does not behave as expected: when opening the *Timesheets* tab, the timer resets to 00:00, and if the timer was started more than a minute earlier, it begins counting down (00:00, then -00:59, and so on). (**I1**) A second issue (**I2**), introduced at the same time, is that two timers can run simultaneously if the database is reloaded while a timer is active. A third issue (**I3**) happens after starting and stopping a timer from the Project app: the timer seems to still be running in the Timesheet app. ## Steps to reproduce 1. Install *Timesheets* (`timesheet_grid`) 2. Create a Project P and a Task T 3. Start the timer for Task T, wait a few seconds, then open the *Timesheets* tab 4. **The timer from the _Timesheets_ tab does not match the one on top of the page** 5. Wait for the timer in the header to reach 00:01:00, then open the *Timesheets* tab again 6. **The timer is going backward** For the second issue (**I2**), after executing the steps above: 7. Do not stop the timer, but stop the database and start it again 8. Create a new Project P2 and a Task T2 9. Start the timer for Task T2 10. **The timer in the header blinks between the timer from T1 and the newly started timer for T2**  For the third issue (**I3**): 1. In the project app, (create a project and a task and) start then stop a timer. Log the time 2. Open the timesheet app 3. **A timer is running** ## Cause The issues are introduced by the following commit: https://github.com/odoo/enterprise/commit/f4c7115fdf. The commit aimed to resolve an issue in which timers for sample data would start automatically, and the *Stop* button would throw an error. The issue was addressed by updating the condition that defines the `timerRunning` variable, which controls whether the *Stop* button in the Timesheets app is displayed. https://github.com/odoo/enterprise/blob/ac186aa71cd7e1b80b307ea12c7eaca246afd649/timesheet_grid/static/src/components/timesheet_display_timer/timesheet_display_timer.js#L57-L64 Issue **I1** is a side effect of this change in the Project app, where the `timerRunning` variable is evaluated to `true`, causing the timer to be displayed when it should not. The multiple timers running simultaneously (**I2**) stems from the `timerRunning` variable being initiated to false by default in the props. https://github.com/odoo/enterprise/blob/64f813dab727d76286c1ff6c80c08cb6a6737b49/timesheet_grid/static/src/components/timesheet_display_timer/timesheet_display_timer.js#L47-L50 The *Stop* button appearing after logging a task (**I3**) stems from the condition of the patch using `is_timer_running` over `timer_start`. https://github.com/odoo/enterprise/blob/64f813dab727d76286c1ff6c80c08cb6a6737b49/timesheet_grid/static/src/hooks/sample_server_patch.js#L9-L15 ## Fix This commit reverts the problematic segments from the previous commit. opw-5870756 opw-5879176 opw-5961764 Forward-Port-Of: odoo/enterprise#107014
This update prevents a critical error that occurred when creating quality checks from quality points. The issue arose when a product wasn't specified, leading to a system error. This fix ensures quality checks can be created successfully under all circumstances, improving data integrity and preventing disruptions to the quality control process.
Original PR description
When creating a quality check from a quality point, a traceback occurs if no product is set. Steps to reproduce the error: - Install ``quality_control`` module with demo data - Go to Quality > Quality Control > Control Points > Create a new Control point > Set Control per: Quantity, Partial Test: 99 > Save - Click on Quality Checks smart button > Click on New Traceback: ```py ValueError: Expected singleton: uom.uom() ``` https://github.com/odoo/enterprise/blob/4fa1c0c13308bd8de06646543391f8cbcf28d05e/quality_control/models/quality.py#L369 During creation of a quality check, ``product_id`` is not set. The compute method ``_compute_qty_to_test`` accesses ``product_id.uom_id``, which leads to the above traceback. sentry-7440188763
This update fixes a calculation error in employee timesheets, ensuring accurate tracking of working hours across contract versions. The fix updates how the system determines the valid working schedule for each employee, resolving a discrepancy where hours were incorrectly calculated.
Original PR description
Steps to reproduce: ------------------------------------ 1. Install Timesheets Module with demo data 2. Create a new Employee with: * Payroll Page > Contract > Start from 1st March * Payroll Page >…
Steps to reproduce:
------------------------------------
1. Install Timesheets Module with demo data
2. Create a new Employee with:
* Payroll Page > Contract > Start from 1st March
* Payroll Page > Working hours set to 'Standard 40 hours/week'
3. Go to Timesheets > All Timesheets
4. Add Timesheet for any task as follows:
* Select a date in a past week (e.g., 14th April)
* Hours: 8 hours
* Select the newly created employee
5. Go to Timesheets > All Timesheets:
* Filter by the new employee
* Navigate to the same past week
* Observe the remaining hours for the employee (e.g, -32:00)
6. Open the newly created employee form:
* Click on '+' to create a new contract version
* Set the version date before the timesheet date (e.g., 12th April)
* Change Working Hours to Standard 38 hours/week.
7. Repeat Step 5
Observation:
------------------------------------
The Remaining Hours shows -32:00, meaning the system still uses the 40 hours/week schedule instead of the updated one. The expected value should be -30:00 based on the 38 hours/week schedule.
Issue:
------------------------------------
The method `_get_contracts_valid_periods` determines which working calendar applies for which time period. It uses `contract.contract_date_start` and `contract.contract_date_end` to build calendar validity intervals, but these are the contract employment dates (shared across all versions of the same contract), NOT the version-specific effective dates.
Both versions share the same `contract_date_start`, so both claim the entire period as valid. The 40h calendar produces larger work intervals that win when combined via Intervals union, so the old 40h schedule is used instead of the current 38h one.
Solution:
------------------------------------
Replace `contract.contract_date_start` / `contract.contract_date_end` with `contract.date_start` / `contract.date_end`
These dates represent each version's effective validity period, computed from `date_version` and bounded by the next version's start date. Using these ensures each calendar is only valid during the period its version was actually in effect correctly splitting the working hours at version boundaries.
opw-6142137
Forward-Port-Of: odoo/odoo#264114
Forward-Port-Of: odoo/odoo#26061414 changes
New functionality added to Odoo
This update introduces ECPay, a new payment provider specifically designed for transactions in Taiwan. ECPay supports various payment methods including credit cards, bank transfers, and increasingly popular options like convenience stores, mobile wallets, and QR codes, expanding Odoo's payment capabilities within the Taiwanese market.
Original PR description
This change integrates a new payment provider: ECPay for payments in Taiwan. Supported Payment methods of the provider: - card: credit/debit card - bank transfer - wechat pay - [NEW] Convenience Stores (eg. 7/11, OK Mart etc.) - [NEW] Mobile Wallet (eg. iPASS Money, Jkopay etc.) - [NEW] TWQR Note: - Tokenization and Refund is not implemented in this commit. Task-5168802 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#235069
Resolved issues and error corrections
This update resolves an issue where rapid actions triggered duplicate account return check records being created in the database. The fix prevents multiple simultaneous processes from attempting to create the same record, ensuring data integrity and preventing unnecessary database load. This improves system performance and stability.
Original PR description
Issue -------------- When refreshing checks on account returns (e.g. from rapid successive clicks or component re-renders), multiple concurrent RPC calls to `refresh_checks` were being dispatched to…
Issue
--------------
When refreshing checks on account returns (e.g. from rapid successive clicks or component re-renders), multiple concurrent RPC calls to `refresh_checks` were being dispatched to the server. This created a race condition that resulted in duplicate `account.return.check` records being generated in the database.
steps to reproduce demonstrated in video: https://drive.google.com/file/d/1-A0ZHdYGdv-UL0dqClqK6Kos_iVXoZai/view?usp=sharing
When this happen the `runAllReturnChecks` method fires parallel RPC calls to [`refresh_checks`](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1974-L1992) on the server. In the case of instant multiple RPC calls, parallel threads are dispatched which causes the data preparation stage to run simultaneously.
Because both threads run in parallel, Thread 2 runs its [preparation and existing ](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1986-L1987 )check mechanism before Thread 1 has reached the actual `create()` function [trigger](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1998-L1999). Consequently, Thread 2's existence check fails to find the record (since Thread 1 hasn't committed it to the database yet), and it considers the record eligible for creation—even though the exact same record is already prepared for creation by Thread 1. This race condition leads to duplicate `account.return.check` records.
Logs to demonstrate the thread execution:
--------
```python
2026-04-16 08:30:51,493 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.000 0.002
2026-04-16 08:30:51,662 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "POST /web/dataset/call_kw/account.report/dispatch_report_action#account.report.dispatch_report_action HTTP/1.0" 200 - 17 0.006 0.012
2026-04-16 08:30:51,847 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "POST /web/dataset/call_kw/account.return/get_views#account.return.get_views HTTP/1.0" 200 - 26 0.009 0.025
2026-04-16 08:30:52,099 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:52] "POST /web/dataset/call_kw/account.return/web_read_group#account.return.web_read_group HTTP/1.0" 200 - 95 0.029 0.064
2026-04-16 08:30:52,320 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:52] "POST /web/dataset/call_kw/account.return/get_next_returns_ids#account.return.get_next_returns_ids HTTP/1.0" 200 - 2 0.001 0.004
THREAD NAME: odoo.service.http.request.137360481711808 Thread ID: 137360481711808
REFRESH CHECK START:--------------------------------------------
Thread ID: 137360481711808 -------------DATA PREPARING STAGE------------
Thread ID: 137360481711808
Thread ID: 137360481711808 RECORD EXISTING CHECK: None
2026-04-16 08:30:53,842 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:53] "GET /odoo/tax-report/tax-return?debug=1 HTTP/1.0" 200 - 29 0.020 0.021
2026-04-16 08:30:54,066 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/webclient/load_menus HTTP/1.0" 200 - 4 0.002 0.009
2026-04-16 08:30:54,351 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/manifest.webmanifest HTTP/1.0" 200 - 6 0.003 0.005
2026-04-16 08:30:54,493 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/webclient/translations?hash=bb5aa713d587cc7dd07b13d1d7efc2c525517e99&lang=en_US HTTP/1.0" 200 - 1 0.000 0.002
2026-04-16 08:30:54,586 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/bundle/web_tour.interactive?lang=en_US&debug=1 HTTP/1.0" 200 - 1 0.001 0.003
2026-04-16 08:30:54,640 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/action/load_breadcrumbs HTTP/1.0" 200 - 7 0.003 0.006
2026-04-16 08:30:54,710 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/ir.http/lazy_session_info#ir.http.lazy_session_info HTTP/1.0" 200 - 2 0.001 0.004
2026-04-16 08:30:54,753 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /bus/websocket_worker_bundle?v=19.0-2 HTTP/1.0" 304 - 3 0.004 0.006
2026-04-16 08:30:54,766 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/image?model=res.users&field=avatar_128&id=2 HTTP/1.0" 304 - 9 0.012 0.013
2026-04-16 08:30:54,777 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /mail/data HTTP/1.0" 200 - 34 0.034 0.020
2026-04-16 08:30:54,824 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/account.return/get_views#account.return.get_views HTTP/1.0" 200 - 3 0.001 0.010
2026-04-16 08:30:54,934 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/account.return/web_read_group#account.return.web_read_group HTTP/1.0" 200 - 88 0.029 0.051
2026-04-16 08:30:55,107 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:55] "POST /web/dataset/call_kw/account.return/get_next_returns_ids#account.return.get_next_returns_ids HTTP/1.0" 200 - 2 0.001 0.005
THREAD NAME: odoo.service.http.request.137360513177280 Thread ID: 137360513177280
REFRESH CHECK START:--------------------------------------------
Thread ID: 137360513177280 -------------DATA PREPARING STAGE------------
Thread ID: 137360513177280
Thread ID: 137360513177280 RECORD EXISTING CHECK: None
2026-04-16 08:30:55,589 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:55] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.001 0.006
2026-04-16 08:30:56,702 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:56] "GET /web/service-worker.js HTTP/1.0" 200 - 1 0.000 0.003
2026-04-16 08:30:58,893 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:58] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.006 0.023
2026-04-16 08:31:05,296 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:31:05] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.001 0.002
Thread ID: 137360481711808 DATA to_create: 168
Thread ID: 137360481711808 done process create
2026-04-16 08:31:10,132 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:31:10] "POST /web/dataset/call_kw/account.return/refresh_checks#account.return.refresh_checks HTTP/1.0" 200 - 513 11.611 6.039
Thread ID: 137360513177280 DATA to_create: 168
Thread ID: 137360513177280 done process create
```
- OPW: 5917459
Forward-Port-Of: odoo/enterprise#114045This update enhances the logging of technical errors related to Saudi VAT (ZATCA) compliance within the Odoo system. Previously, these errors were hidden from users to maintain a clean interface, but this made troubleshooting difficult. Now, server logs will record these errors with a specific prefix, allowing our team to quickly identify and resolve issues.
Original PR description
Log suppressed technical validation failures in server logs with a stable ZATCA_ERROR prefix while keeping user-facing errors unchanged. task-6110313 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#261536
This fix resolves an issue where generating closing entries in the Inventory Valuation view incorrectly calculated values when multiple companies were selected. The update ensures that the generated account move lines accurately reflect the inventory valuation based on the selected main company, preventing incorrect balances.
Original PR description
**Problem:** In view Inventory valuation, generate entry doesn't work when multiple companies are selected. In the view only the main company matters. That means that even if multiple companies are…
**Problem:** In view Inventory valuation, generate entry doesn't work when multiple companies are selected. In the view only the main company matters. That means that even if multiple companies are selected, only the stock variation lines related to the main company selected are displayed (which is expected). But if you then click on 'generate entry' the account move lines created will have wrong values (not matching the values appearing in the view) **Steps to reproduce:** - create 2 new companies (to have clean accounting) - create a warehouse for both companies - for both comp, in settings for the 'fiscal localization' set Package : Generic Chart of account, if not already set (to have account journals). From company 1 : - create a storable prod with avco perpetual category - confirm PO for 2 @ 10, receive - bill only 1 @ 10 From company 2: - make sure the category is also perpetual average from this other company - confirm PO for 2 @ 50, receive, don't bill Notice how from the 'Inventory Valuation' view, rightfully, only the main company matters (no matter what other comp are selected): - If main comp is comp 1 there is stock variation lines for amount of 10 (which is expected because we have 20 in stock and only 10 in stock valuation account) - If main comp is comp 2 there is stock variation lines for amount of 100 (which is expected because we have 100 in stock and only 0 in stock valuation account) With comp 1 and 2 selected and comp 1 as main company: - click on 'Generate Entry' **Current behavior:** - both line have a balance of 110 **Expected behavior:** - they should have a balance of 10 as we saw on the 'inventory valuation' view **Cause of the issue:** To generate the data from the 'inventory valuation' view, inside _get_report_data() we call stock_value() and stock_accounting_value() to compare values from inventory and value from accounting. https://github.com/odoo/odoo/blob/dd84309df7fd39e9e97ed02d135d25b211085135/addons/stock_account/report/stock_valuation_report.py#L36-L37 stock_value() sums total_value() of each product in the valued accounts https://github.com/odoo/odoo/blob/dd84309df7fd39e9e97ed02d135d25b211085135/addons/stock_account/models/res_company.py#L90-L94 Whereas stock_acounting_value(), sums the balance of each account move line of each valuation account https://github.com/odoo/odoo/blob/dd84309df7fd39e9e97ed02d135d25b211085135/addons/stock_account/models/res_company.py#L112-L114 All of this is related to the main company because we call _get_report_data() with context 'allowed_company_ids' set to only the main company https://github.com/odoo/odoo/blob/dd84309df7fd39e9e97ed02d135d25b211085135/addons/stock_account/report/stock_valuation_report.py#L13 But when we click on generate entry, _get_stock_valuation_account_vals() is called with no context modification to 'allowed_company_ids' so when we call stock_value(), https://github.com/odoo/odoo/blob/dd84309df7fd39e9e97ed02d135d25b211085135/addons/stock_account/models/res_company.py#L238-L239 total_value will be based on both company https://github.com/odoo/odoo/blob/dd84309df7fd39e9e97ed02d135d25b211085135/addons/stock_account/models/res_company.py#L92 Note that stock_accounting_value() is still rightfully based only on main company because we use self.id in the domain https://github.com/odoo/odoo/blob/dd84309df7fd39e9e97ed02d135d25b211085135/addons/stock_account/models/res_company.py#L105-L108 opw-6168699 Forward-Port-Of: odoo/odoo#262776
This update fixes a display issue where the number of ECOs listed on a Bill of Materials (BoM) was incorrect. The fix ensures that the count accurately reflects the ECOs directly associated with the current BoM version, resolving a visual discrepancy and improving data accuracy. This impacts users reviewing BoM details and associated ECOs.
Original PR description
Steps to Reproduce (Fresh Database): -------------------------------------- 1. Install `Manufacturing` (mrp) and `PLM` (mrp_plm) modules 2. Create a product > New -- Name: "Test Product" > Save 3.…
Steps to Reproduce (Fresh Database):
--------------------------------------
1. Install `Manufacturing` (mrp) and `PLM` (mrp_plm) modules
2. Create a product > New -- Name: "Test Product" > Save
3. Create BoM v1
- Go to Manufacturing > Products > Bills of Materials > New --Product: Test Product
- Add component: any
4. Create and apply ECO 1 on BoM v1
- Go to PLM > ECOs > New-- Product: Test Product | Apply on: Bill of Materials
- BoM: Test Product (v1) > Confirm > Apply Changes
- This creates BoM v2 (previous_bom_id = BoM v1)
5. Create and apply ECO 2 on BoM v2
- Same as step 4 but select BoM v2
- This creates BoM v3 (previous_bom_id = BoM v2)
6. Create a separate unrelated BoM for the same product
- Go to Manufacturing > Bills of Materials > New
- Product: Test Product | Component: "Component B" > Save
7. Create ECO 3 on the separate BoM
- Go to PLM > ECOs > New - Product: Test Product | Apply on: Bill of Materials
- BoM: select the separate BoM from step 6 > Confirm
Observed Bug:
-------------
- Open BoM v3 > ECO(s) stat button shows count = 2
- Click the button > opens 3 records (ECO 3 incorrectly included)
Explain:-
----------
The ECO stat button on the BoM form was showing a mismatched count vs
the actual records opened when clicking it. This happened because
[button_mrp_eco](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/mrp_plm/models/mrp_bom.py#L56) was using all keys from [_get_previous_boms](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/mrp_plm/models/mrp_bom.py#L67)() as the
domain, which includes BoMs from unrelated lineages of the same product
template, while [_compute_eco_data](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/mrp_plm/models/mrp_bom.py#L20) only counts ECOs belonging to the
current BoM's version lineage.
Fixed by filtering the domain to only include BoM IDs whose lineage set
contains the current BoM ID, making the opened records consistent with
the displayed count.
Before Fix
<img width="1901" height="875" alt="image" src="https://github.com/user-attachments/assets/3208aed5-ebd3-47a3-a457-a7d61b7743cb" />
```
In [24]: labo = self.env['mrp.bom'].browse(710)
In [25]: previous_boms_mapping = labo._get_previous_boms()
In [26]: Test = ['&', ('bom_id', 'in', list(previous_boms_mapping.keys())), ('type', '=', 'bom')]
In [27]: Test
Out[27]:
['&',
('bom_id',
'in',
[710,
1991,
2049,
1913,
1840,
1823,
1676,
1759,
1794,
1651,
1604,
1544,
1537,
1527,
1506,
1460,
1265,
1259,
1196,
1221,
1223,
1060,
1029,
960,
858,
850,
791,
739,
723,
698]),
('type', '=', 'bom')]
```
With My Fix
<img width="1824" height="947" alt="image" src="https://github.com/user-attachments/assets/0d68fdbc-7e42-4ce4-a326-2fb030ba1d06" />
```
In [15]: labo = self.env['mrp.bom'].browse(710)
In [16]: previous_boms_mapping = labo._get_previous_boms()
In [17]: previous_boms_mapping
Out[17]:
{710: {710},
1991: set(),
2049: set(),
1913: set(),
1840: set(),
1823: set(),
1676: set(),
1759: set(),
1794: set(),
1651: set(),
1604: set(),
1544: set(),
1537: set(),
1527: set(),
1506: set(),
1460: set(),
1265: set(),
1259: set(),
1196: set(),
1221: set(),
1223: set(),
1060: set(),
1029: set(),
960: set(),
858: set(),
850: set(),
791: set(),
739: set(),
723: set(),
698: {710}}
In [18]: relevant_bom_ids = [
...: bom_id
...: for bom_id, current_bom_set in previous_boms_mapping.items()
...: if labo.id in current_bom_set
...: ]
In [19]: relevant_bom_ids
Out[19]: [710, 698]
```
Task-6065020
Forward-Port-Of: odoo/enterprise#114039This update resolves an issue where the Point of Sale (POS) wouldn't open correctly when reloading in offline mode. The fix ensures data is properly handled during offline reloads, and updated tests confirm the POS can now be reloaded successfully while offline. This improves the user experience and reliability of the POS system.
Original PR description
Currently when reloading the POS while offline the POS does not open despite all data being stored in IndexedDB. This is because some of the data fetching functions were not properly handling the offline case. Modified tests to ensure that the POS can be reloaded while offline. Also modified the tour offline_util so it handles page refresh. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#260590
This update fixes a bug that occurred when users tried to reschedule marketing activities within a campaign. The change prevents errors related to activity hierarchy updates, ensuring campaigns run smoothly and reliably. It also simplifies the process to avoid user mistakes when testing campaigns.
Original PR description
**Steps to reproduce:** - Create a new marketing campaign with two activities - Set them to occur some number of days after the beginning - Save the campaign and start it - Modify one of the…
**Steps to reproduce:** - Create a new marketing campaign with two activities - Set them to occur some number of days after the beginning - Save the campaign and start it - Modify one of the activities to occur some number of days after the other activity and save - Modify the child activity by changing the number of days after its parent that it should run and save - An error will be thrown **Issue:** The trace related to the child activity has no parent when trying to reschedule it in `_update_schedule_date`. This causes an issue when trying to get the first mailing_trace_ids using index 0 in this line: `base_dt_str = trace.parent_id.schedule_date or trace.parent_id.mailing_trace_ids[0].write_date or trace.participant_id.create_date` **Fix:** Prevent the activity hierarchy to be modified on started campaigns. We also change the indexing to avoid further out of range issue and properly default on the participant create value. Trying to match existing traces to their parents has too many edge cases when trying to avoid duplicates, and might often need to reset the whole trace chain to work properly. This approach avoids user mistakes on running campaigns, but if a user tries to launch a test (even on draft campaign) he won't be able to modify the hierarchy further without deleting/recreating some activities/traces. So we should ignore this for test traces, but it could impact the behavior between test and actual executions. opw-5362978 Forward-Port-Of: odoo/enterprise#107556
This update corrects a bug in the payroll calculation for Colorado-based employees. Previously, the system incorrectly generated a positive CO State Income Tax amount. This fix aligns with established payroll tax rules, ensuring accurate withholding and preventing potential refund issues.
Original PR description
## Issue When generating a payslip for an employee of a company located in Colorado, the *CO State Income Tax* could end up positive. ## Steps to reproduce 1. Install *United States - Payroll*…
## Issue
When generating a payslip for an employee of a company located in Colorado, the *CO State Income Tax* could end up positive.
## Steps to reproduce
1. Install *United States - Payroll* (`l10n_us_hr_payroll`)
2. Set the current company's State to Colorado
3. Create an employee and a contract
- Wage: $0
- (Set the contract's status to *Running*)
- (In the payroll tab) State Withholding Allowance: $1000
4. Create a Payslip for the employee
- Structure: *"United States: Regular Pay"*
5. Compute Sheet
6. **In the _Salary Computation_ tab, the _CO State Income Tax_ line has a positive value**
## Justification
This fix is similar to the one applied for the AL(abama) state income tax by https://github.com/odoo/enterprise/commit/f0eeb55f1e3cf965c6a409675813d4a699e5fca6. That modification was justified by CAS (PO of US localizations for Payroll) in opw-5137280:
> *"Payroll taxes are always funds withheld from employee's paychecks, if there is a positive value it means the tax is a refund, not a withholding. Refunds happen when individuals file their income."*
## Note to reviewer
The test [`test_069_al_state_tax_0_income`](https://github.com/odoo/enterprise/blob/219d2a797ee2099c9d77c2defc9c9c5e1d504ffe/test_l10n_us_hr_payroll_account/tests/test_salary_rules.py#L957-L989) (added by the aforementioned commit https://github.com/odoo/enterprise/commit/f0eeb55f1e3cf965c6a409675813d4a699e5fca6) is wrongly indented and thus never executed. The test passes with the dedicated fix, and fails without it, as expected. Let me know if you want me to indent it correctly (in this commit or in an additional one).
opw-5999856
Forward-Port-Of: odoo/enterprise#116653
Forward-Port-Of: odoo/enterprise#112724This update clarifies the extra pricing applied when customers select combo items in the self-order system. Previously, customers were confused about additional costs, leading to inquiries about 'too much' charges. This change ensures transparent pricing and avoids customer confusion, improving the overall ordering experience.
Original PR description
The display for the extra price during the combo selection was not very clear. The customer were not aware of the additional cost that were applied when choosing some elements that were not included but extra. This led to customer asking cashier if there was a problem because they were paying "too much" when the computation was actually correct but not clear enough. task-id: 6142095 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#260705
This update resolves an issue where creating two overtime shifts on the same Saturday (ending at midnight) would trigger an error. The fix addresses a timing discrepancy in how overtime start and end times are calculated, preventing the 'Expected singleton' error. This ensures overtime is correctly recorded for employees with overlapping shifts.
Original PR description
__ ## Short functional explanation of the error When we create 2 shifts for the same day for an employee, on a non-working day for their schedule. When trying to create the second one after setting…
__ ## Short functional explanation of the error When we create 2 shifts for the same day for an employee, on a non-working day for their schedule. When trying to create the second one after setting the end date to midnight, we get the error: `ValueError: Expected singleton: hr.attendance.overtime.line(2, 3)` ## Reproduction Steps 1. Create an Employee. In the Payroll tab, Make sure they have an active contract. Set their Working Hours to a fixed schedule, where they have saturdays as non-working days. In the Settings tab, set an Overtime Ruleset. 2. Click on the overtime ruleset. Then, for each rule, under Action, set the Work Entry Type To Use as Overtime Hours. 3. Go to Attendances. In Configuration > Settings, under Extra Hours, set the Extra Hours Validation as Approved By Manager. 4. Create an attendance for your Employee on a Saturday, from 12h to 18h. 5. Create a second attendance for your Employee on that same Saturday, from 18h to 00h00. Try to Save. Note: the timezone of your computer, the working schedule and the employee should be set at Brussels time. ### Expected behavior The Overtime is registered. ### Unexpected behavior An error occurs: `ValueError: Expected singleton: hr.attendance.overtime.line(2, 3)` ## Origin of the issue The end time of the overtime is defined as follows: https://github.com/odoo/enterprise/blob/47faff7d6c9da5572e3bad3ff5a55b40c2ba81ac/hr_work_entry_attendance/models/hr_version.py#L54-L56 However, in the case where our shift ends after the computed end of the day (in our case, the end time of the shift is 00:00:00 and the end of the day is set at 23:59:59), it creates some problems. The end time of the overtime is set 1 second too early. Later we compute the start time of the overtime as follows: https://github.com/odoo/enterprise/blob/47faff7d6c9da5572e3bad3ff5a55b40c2ba81ac/hr_work_entry_attendance/models/hr_version.py#L57 Thus, the time start of the overtime is also set one second too early. As our second shift starts right after the first one, after the execution of this code, we will get a second shift that starts before the end of the first one. Then, we add these values in a list: https://github.com/odoo/enterprise/blob/47faff7d6c9da5572e3bad3ff5a55b40c2ba81ac/hr_work_entry_attendance/models/hr_version.py#L59 which will contain overlapping timeframes, and with which we create an Interval: https://github.com/odoo/enterprise/blob/47faff7d6c9da5572e3bad3ff5a55b40c2ba81ac/hr_work_entry_attendance/models/hr_version.py#L60 But when we create an Interval with overlapping timeframes, we obtain only one interval as the timeframes are merged. https://github.com/odoo/enterprise/blob/47faff7d6c9da5572e3bad3ff5a55b40c2ba81ac/hr_work_entry_attendance/models/hr_version.py#L173 As a result, `overtime_intervals` will contain only one time frame with 2 different corresponding overtimes, which causes a singleton error when reaching: https://github.com/odoo/enterprise/blob/47faff7d6c9da5572e3bad3ff5a55b40c2ba81ac/hr_work_entry_attendance/models/hr_version.py#L179 __ opw-6096454 Forward-Port-Of: odoo/enterprise#114147
This update resolves several errors that occurred when Odoo processed NOTI files for Belgian payroll tax declarations. The fix ensures accurate and reliable transmission of payroll data, preventing potential issues with tax reporting and compliance. This improves the stability and accuracy of the Odoo Enterprise system for our Belgian clients.
Original PR description
Forward-Port-Of: odoo/enterprise#116871
This update corrects a calculation error in the employee timesheet system. Previously, the system incorrectly applied the standard 40-hour work week even after changing the employee's contract to 38 hours. This fix ensures accurate timesheet hour tracking based on the employee's current contract version.
Original PR description
Steps to reproduce: ------------------------------------ 1. Install Timesheets Module with demo data 2. Create a new Employee with: * Payroll Page > Contract > Start from 1st March * Payroll Page >…
Steps to reproduce:
------------------------------------
1. Install Timesheets Module with demo data
2. Create a new Employee with:
* Payroll Page > Contract > Start from 1st March
* Payroll Page > Working hours set to 'Standard 40 hours/week'
3. Go to Timesheets > All Timesheets
4. Add Timesheet for any task as follows:
* Select a date in a past week (e.g., 14th April)
* Hours: 8 hours
* Select the newly created employee
5. Go to Timesheets > All Timesheets:
* Filter by the new employee
* Navigate to the same past week
* Observe the remaining hours for the employee (e.g, -32:00)
6. Open the newly created employee form:
* Click on '+' to create a new contract version
* Set the version date before the timesheet date (e.g., 12th April)
* Change Working Hours to Standard 38 hours/week.
7. Repeat Step 5
Observation:
------------------------------------
The Remaining Hours shows -32:00, meaning the system still uses the 40 hours/week schedule instead of the updated one. The expected value should be -30:00 based on the 38 hours/week schedule.
Issue:
------------------------------------
The method `_get_contracts_valid_periods` determines which working calendar applies for which time period. It uses `contract.contract_date_start` and `contract.contract_date_end` to build calendar validity intervals, but these are the contract employment dates (shared across all versions of the same contract), NOT the version-specific effective dates.
Both versions share the same `contract_date_start`, so both claim the entire period as valid. The 40h calendar produces larger work intervals that win when combined via Intervals union, so the old 40h schedule is used instead of the current 38h one.
Solution:
------------------------------------
Replace `contract.contract_date_start` / `contract.contract_date_end` with `contract.date_start` / `contract.date_end`
These dates represent each version's effective validity period, computed from `date_version` and bounded by the next version's start date. Using these ensures each calendar is only valid during the period its version was actually in effect correctly splitting the working hours at version boundaries.
opw-6142137
Forward-Port-Of: odoo/odoo#260614This update fixes an issue where the reprint button on preparation printers was only visible on the device that initially sent the order. By moving data to a shared session variable, the reprint button is now consistently available on all devices within the same order session, streamlining order preparation.
Original PR description
When sending an order to a preparation printer, the reprint button was invisible on any device other than the one that originally sent the order. This happened because `lastPrints` was stored in the order's `uiState`, which is local to each device. Moving it to `last_order_preparation_change` — which is shared across devices in the same session — fixes the issue. The reprint button is now visible and functional on all devices sharing the same session. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6196913
This update resolves a crash in the website editor that occurred when an event was set as the homepage. The issue stemmed from a missing match case in the event ID retrieval process. By adding a default return value, the editor now correctly identifies event IDs, ensuring a stable experience for users managing homepage events.
Original PR description
**Description of the issue/feature this PR addresses:** The `WebsiteEvent._getEventObjectId` method lacks a specific match case for the root directory, causing event ID retrieval to fail on the…
**Description of the issue/feature this PR addresses:** The `WebsiteEvent._getEventObjectId` method lacks a specific match case for the root directory, causing event ID retrieval to fail on the homepage. In order to resolve this, I've implemented a default return of 0 when the URL pattern matching fails [following the pattern established by later revisions of this code](https://github.com/odoo/odoo/blob/2199f71070ce3e9a4717eb6b750c14485406f7aa/addons/website_event/static/src/website_builder/event_page_option_plugin.js#L67). **Steps to reproduce bug:** 1. Create an event website 2. Create an event and visit it 3. On the page click Site > Properties 4. Enable `Is Homepage` 5. Return to the homepage of the application and open the editor https://drive.google.com/file/d/1OpCUAp4LJKqkoStciWeJEGVVlR3qpw1R/view?usp=drive_link **Current behavior before PR:** https://drive.google.com/file/d/1c7ACqaQx03mePzJSV_RoPn8mlLWSMa1I/view?usp=drive_link **Desired behavior after PR is merged:** https://drive.google.com/file/d/1L3Ne9h6-yB3v7VbXipjly9OrDSkZvDOu/view?usp=drive_link opw-6101680 Forward-Port-Of: odoo/odoo#262886 Forward-Port-Of: odoo/odoo#258502
3 changes
Resolved issues and error corrections
This update resolves issues preventing Odoo's Norwegian VAT XML exports from passing government validation checks. The changes ensure accurate decimal formatting, correct mathematical calculations, and the inclusion of required legal notes, allowing businesses to file their VAT returns correctly and avoid delays. This fix directly addresses compliance requirements with Skatteetaten.
Original PR description
Before commit: The Norwegian VAT XML export fails Skatteetaten validation due to incorrect decimal formatting, mathematical rounding mismatches between base and tax amounts, missing mandatory legal…
Before commit: The Norwegian VAT XML export fails Skatteetaten validation due to incorrect decimal formatting, mathematical rounding mismatches between base and tax amounts, missing mandatory legal notes, and invalid KID number formats. Fix: To strictly follow Skatteetaten validation rules for the Norway VAT XML, the following changes were implemented: - Ensured standard rates drop the decimal (e.g, `25.0` to `25`), and formatted fractional rates like `11.11` to `11,11` in XML. - Rounded down the `tax_amount` to align precisely with government mathematical expectations. - `base_amount` converted into absolute value to ensuring the calculation (`base * rate = tax`) resolves perfectly. - Add the mandatory `<merknad>` explaining the reverse charge method for codes 81, 83, 86, 88, and 91. - Clean the `company_kid` by safely stripping the 'NO' prefix, and 'MVA' suffix. Expect: The generated XML payload now adheres perfectly to Skatteetaten's strict structural and mathematical rules, allowing the VAT return to pass government validations successfully. Related Community PR: https://github.com/odoo/odoo/pull/258390 Task-6033027 Forward-Port-Of: odoo/enterprise#116962 Forward-Port-Of: odoo/enterprise#110792
This update resolves a bug where undoing a template conversion left the project's documents folder in an inconsistent state, preventing further template creation. The fix ensures the original documents folder is properly restored and cleaned up during the undo process, improving workflow reliability.
Original PR description
Steps to Reproduce: --- 1. Create a project with documents. 2. Convert it into a template. 3. Click on "Undo". 4. Try to convert the project into a template again. Issue: --- After undoing the template conversion, the project's original documents folder remained archived while the template's documents folder stayed active. This inconsistent state prevented subsequent template creation from the same project. Current behaviour: --- A UserError is raised: "You cannot duplicate document(s) in the Trash." Expected behaviour: --- Undoing template conversion should properly restore original project's documents folder and clean up template's documents folder. Fix: --- - Archive original project's documents folder during template creation - Implement documents folder unarchival during undo operations task-4916027
This update resolves an issue that caused invoices with combo products lacking taxes to generate errors when sent to Peru's UBL system. The fix ensures that combo product invoice lines without taxes are properly validated, preventing the traceback and allowing invoices to be successfully processed. This improves the reliability of the Peru UBL integration.
Original PR description
A traceback occurs when sending an invoice to Peru UBL if a combo product invoice line does not have any taxes applied. Steps to reproduce the error: - Install ``l10n_pe_edi`` module with demo data -…
A traceback occurs when sending an invoice to Peru UBL if a combo product invoice line does not have any taxes applied. Steps to reproduce the error: - Install ``l10n_pe_edi`` module with demo data - Switch to PE Company - Create an invoice > Add a Office Combo product > unset the taxes > Confirm - Process now https://github.com/odoo/enterprise/blob/d7f71a68fbd5ff9c7cd52f96e1616671a6b8d77c/l10n_pe_edi/models/account_edi_xml_ubl_pe.py#L549-L552 Here, the ``grouping_key`` becomes ``None`` when no taxes are present on the invoice line. Normally, invoices without taxes are restricted at [1], but combo products are excluded from this validation at [2]. As a result, combo product lines without taxes bypass the restriction and trigger a traceback. [1]: https://github.com/odoo/enterprise/blob/d7f71a68fbd5ff9c7cd52f96e1616671a6b8d77c/l10n_pe_edi/models/account_edi_format.py#L928-L929 [2]: https://github.com/odoo/odoo/blob/42b8852df9b323984364c41a13cf27d19fbe04a7/addons/account/models/account_move_line.py#L3433-L3434 sentry-7430552834
6 changes
Resolved issues and error corrections
This update corrects a display issue where certain quality point types were incorrectly shown regardless of the selected operations. The fix ensures these types are only visible when a manufacturing operation is selected and a work order operation is defined, improving data accuracy and usability.
Original PR description
**Steps to reproduce:** - Install `quality_control` and `mrp` modules with demo data - Go to Quality → Quality Points → Create(New) - In the `Type` field, observe that options such as 'Print Label',…
**Steps to reproduce:**
- Install `quality_control` and `mrp` modules with demo data
- Go to Quality → Quality Points → Create(New)
- In the `Type` field, observe that options such as
'Print Label', 'Register Production', etc. appear
regardless of the selected `Operations`
**Issue**:
Types like `print_label`, `register_production`,
`register_byproducts`, and `register_consumed_materials`
are displayed even when the Operations is not
Manufacturing and when no work order operation is defined.
**Expected behavior**:
These `types` should only be available when:
- `Operations` Type = Manufacturing
- `work order operation` is set
**Cause**:
The custom search logic for the `allow_registration` boolean field
relied on receiving a direct `True` or `False` value.
https://github.com/odoo/enterprise/blob/de3682c7f50b68c19d3a3429fa3768c447074f50/mrp_workorder/models/quality.py#L104
Before `saas-18.3`, the `value` passed to the domain search method was
a plain boolean(True/False).
https://github.com/odoo/enterprise/blob/de3682c7f50b68c19d3a3429fa3768c447074f50/mrp_workorder/models/quality.py#L21-L24
Starting from `saas-18.3`, the value is passed as
`OrderedSet([True])`. while the operator received is `in`
or `not in`.
Because the value always arrives `OrderedSet([True])`,
the condition checking the `value` is always
evaluated as truthy. As a result, the code never reaches the
else branch of the logic, which causes the incorrect domain
behavior.
The issue is caused by how Odoo optimizes boolean domains.
When we pass:
('allow_registration', '=', False)
the value correctly reaches the base domain logic as
`allow_registration = False`.
But during domain processing at:
https://github.com/odoo/odoo/blob/347c46f8ecff7ae97c2a686bf5750374b6c3e2d3/odoo/orm/domains.py#L967
it optimize it to:
('allow_registration', 'in', [False])
Then `_optimize()` is called, which again calls
`_optimize_step()`:
https://github.com/odoo/odoo/blob/347c46f8ecff7ae97c2a686bf5750374b6c3e2d3/odoo/orm/domains.py#L459
Inside `_optimize_step()` at:
https://github.com/odoo/odoo/blob/347c46f8ecff7ae97c2a686bf5750374b6c3e2d3/odoo/orm/domains.py#L971
it is further simplified to:n ('allow_registration', 'not in', [True])
Similarly, when we pass: ('allow_registration', '=', True)
it becomes: ('allow_registration', 'in', [True])
This is expected behavior.
The custom search method for `allow_registration`
was not handling these optimized forms correctly,
which caused Issue.
**FIX:**
- Use the domain `operator (in / not in)` to determine the intended
boolean condition instead of relying on the received value(OrderedSet([True])).
- This is correct because Odoo normalizes boolean domains to only two
forms during optimization: in [True] and not in [True]. Therefore,
the operator reliably indicates whether the condition expects
True or False, allowing the search method to handle the domain
correctly.
---
opw-5915197This update fixes an issue where returned subcontracted products were incorrectly routed to the subcontractor's location instead of the user's stock. When returning products 'for exchange', the system now correctly directs returned items to the subcontractor's location and new deliveries to the user's stock, ensuring accurate inventory tracking. This improves the efficiency of subcontracting operations.
Original PR description
## Issue When making a request for quotation for a subcontracted product and returning the delivery "for exchange", the new incoming delivery does not have the correct destination. Instead of having…
## Issue
When making a request for quotation for a subcontracted product and returning the delivery "for exchange", the new incoming delivery does not have the correct destination. Instead of having the stock of the user, the destination of the new incoming delivery is the same as its source: the subcontracting location.
<img width="1254" height="257" alt="5479900" src="https://github.com/user-attachments/assets/c7e6d392-8328-4a03-a71e-466e768f448b" />
## Steps to reproduce
1. Install MRP Subcontracting (`mrp_subcontracting`) and Purchase (`purchase`)
2. In Settings, enable *Subcontracting*
3. Create a Product P and a subcontracting BoM with Subcontractor S
4. Create a Request for Quotation
- Vendor: Subcontractor S
- Product: Product P (any quantity > 0)
5. Confirm the RFQ, receive the PO, validate the picking
6. On the validated picking, click *Return*, set the quantity of products to return, and click *Return for Exchange*
- This creates two new pickings, one to return the product(s) we received, and one to receive new products
7. Validate the two new pickings
8. **In Inventory > Reporting > Moves History, the very last `stock.move.line` has the same location in the *From* (`location_id`) and the *To* (`location_dest_id`) columns**
## Cause
The `location_dest_id` of the new `stock.move` is updated in `StockReturnPickingLine._prepare_move_default_values`.
https://github.com/odoo/odoo/blob/fb534f1eadcb8ef74e2ee6fd5b68872dddb978e3/addons/mrp_subcontracting/wizard/stock_picking_return.py#L20-L25
The condition added by https://github.com/odoo/odoo/commit/5404b426aac9 sets the destination of all returned subcontracted moves to the subcontractor location. This is incorrect when using "return for exchange", as in this case, the return move is directed towards the user's stock. In fact, when using "return for exchange", the following pickings are created:
| id | name | return_id | |
|:--:|--------------|:---------:|---|
| 1 | WH/IN/00001 | | Initial RFQ delivery |
| 2 | WH/OUT/00001 | 1 | Return of the initial RFQ delivery |
| 3 | WH/IN/00002 | 2 | New products delivery to replace the initial delivery. The stock.move.line of this stock.picking has a wrong `location_dest_id` |
## Fix
In the context of return for exchanges, the returned item must be directed to the *Subcontracting Location* while the new item must be directed to the *Stock*. In the `_prepare_move_default_values`, we should only set the `location_dest_it` to the subcontractor location for outgoing pickings.
opw-5479900This update resolves an issue where users accessing bank reconciliation within a child company were encountering access errors. The fix involves using 'sudo' to ensure the correct currency ID is retrieved, allowing proper bank reconciliation functionality within the child company environment. This improves usability for users working with multiple company structures.
Original PR description
The bug is easy to reproduce, but niche. 1. Have a company set up with a child company 2. Have a non admin user with administration rights for accounting 3. Create a bank statement in a journal with no set currency_id and fully reconcile it 4. While only in the child company, try to access the bank reconciliation widget -> access error The error occurs because of how journal_currency_id is computed on the bank rec widget. The fallback value for the currency is derived from the journal_id.company_id.currency_id which is inaccessible from the child company. To circumvent this, we just add sudo() to the call. Forward-Port-Of: odoo/enterprise#117005
This update ensures Odoo's audit trail feature in India (l10n_in) remains active, complying with Ministry of Corporate Affairs regulations. Previously, the audit trail could be disabled, but this change permanently enforces its maintenance to meet legal requirements. This ensures data integrity and reduces potential compliance risks.
Original PR description
After the refactor introduced in https://github.com/odoo/odoo/commit/f280f762b6417fa1a0b09649ffbdecafcc7e7579, The audit trail feature was split into two modes: a lightweight general-purpose mode and a force-restricted mode for specific localizations (e.g., Germany), where deactivation is not allowed once enabled. In India, as per the requirements of the Ministry of Corporate Affairs, the audit trail must be maintained and cannot be disabled once activated. This commit extends the force-restricted audit trail mode to the Indian localization (l10n_in) to ensure compliance with statutory requirements. task-6182002
This update fixes an issue where tax calculations were incorrect after removing a tax line on a sales order or invoice. The fix ensures that dependent taxes (those affected by the base amount) are properly recalculated, preventing inaccurate tax amounts. This improves the reliability of financial reporting.
Original PR description
**Steps to reproduce:** * Install the *Accounting* module with French localization (*l10n_fr_account*). * Create a *Sales Tax* with: * A new tax group (e.g., 'Codifab'). * Enable *Affect Base of…
**Steps to reproduce:** * Install the *Accounting* module with French localization (*l10n_fr_account*). * Create a *Sales Tax* with: * A new tax group (e.g., 'Codifab'). * Enable *Affect Base of Subsequent Taxes*. * Create a *Sales Order*: * Add the first tax (with *Affect Base of Subsequent Taxes*). * Then add the second tax (eg VAT tax). * Confirm the *Sales Order*. * Create a *Down Payment Invoice* (percentage-based). * Open the generated invoice and: * Remove the first tax (the one affecting the base). **Observed behavior:** * The amount of the second tax group does not update after removing the first tax, leading to incorrect tax computation. **Cause:** * In `_import_base_line_extra_tax_data`, the condition: `all(str(tax.id) in extra_tax_data['manual_tax_amounts'] for tax in sorted_taxes)` only ensured partial matching of taxes. * This allowed reuse of stale `manual_tax_amounts` when taxes were removed or modified, causing incorrect base values for dependent taxes (e.g., *Affect Base of Subsequent Taxes*). **Fix:** * Update the condition to enforce an exact match between current taxes and cached `manual_tax_amounts` by checking both size and membership. * Prevent reuse of outdated tax data when taxes change, ensuring proper recomputation of dependent taxes. * Align Python logic with the JS implementation for consistency between `account_tax.py` and `account_tax.js`. opw-6063970
This update resolves an issue that prevented the final invoice from being correctly sent to ZATCA when down payments had been reversed. The fix ensures that the system properly handles both reversed and non-reversed down payment invoices, preventing a critical error. This improves the reliability of ZATCA invoice generation for SA companies.
Original PR description
Sending the final invoice of a sale order to ZATCA crashed with `ValueError: Expected singleton: account.move(a, b)` when the sale order had multiple down-payment references. Steps to reproduce: 1.…
Sending the final invoice of a sale order to ZATCA crashed with `ValueError: Expected singleton: account.move(a, b)` when the sale order had multiple down-payment references. Steps to reproduce: 1. Configure a SA company and setup ZATCA 2. Create a sale order and confirm it 3. Deliver the product line. 3. From the sale order, create a down-payment invoice (fixed amount, e.g. 115) and post it (DP1). 4. On DP1, click "Credit Note" and choose "Full refund and new draft invoice"; validate. DP1 becomes `reversed` and a new draft down-payment DP2 is created. Post DP2. 5. From the sale order, create the final regular invoice and post it. 6. Send the final invoice to ZATCA (or generate its XML) -> `ValueError: Expected singleton: account.move(a, b)`. Root cause: _l10n_sa_get_line_prepayment_vals looks up the related down-payment move through the down-payment sale order line shared with the product line. The filter matched any out_invoice with _is_downpayment() == True, so the reversed DP1 and the active DP2 both ended up in the recordset, and reading .name raised the singleton error. Prefer non-reversed down-payment moves when available, but fall back to reversed ones if no alternative exists (e.g. when generating a credit note of the final invoice after the original down-payment was itself reversed). opw-6116265 Forward-Port-Of: odoo/odoo#260980 Forward-Port-Of: odoo/odoo#259384
1 change
Resolved issues and error corrections
This update fixes an issue where discount lines in VAT reports were incorrectly calculated. The previous system incorrectly converted negative discount values to positive, leading to inflated report totals. The fix ensures accurate reporting by only flipping the sign of account balances when credits are issued.
Original PR description
Step to reproduce: - install l10n_cz_reports_2025 and switch to cz company - create a invoice, with cz company ( as partner), of 100. - when adding products, add "Transaction code" (optional fields) to "Goods" - Add discount line, set to -10, add "Transaction code" in this line too. - confirm it Observation: - invoice is 90$ - open vies summary report for this year - value turn out to 110 Cause: - commit [1](https://github.com/odoo/enterprise/commit/892268c44b1bbc838a9f03ef36a079bfff625ca6) converts every balance to +ve and only negate it, in case of refund - in case of discount lines, price is -ve, ABS() turn it to +ve and value comes out to be wrong Fix: - instead of applying ABS() directly, we flip the signs only for out_* moves, in short when a account is credited, its balance is < 0 then we flip its sign opw- 5979262 Forward-Port-Of: odoo/enterprise#116990 Forward-Port-Of: odoo/enterprise#113087
29 changes
New functionality added to Odoo
This update introduces a new report (IR56M) to comply with Hong Kong's payroll regulations for non-employee workers (freelancers, contractors). It also includes adjustments to Chart of Accounts to align with local requirements. This ensures accurate reporting for HK businesses.
Original PR description
task-[5050335](https://www.odoo.com/odoo/my-tasks/5050335) odoo/odoo#263768 odoo/enterprise#116875 odoo/upgrade#10186 --- Preceeding PR Status: #116875 I named named `Taxable Salary` so it aligns with this upcoming change https://github.com/odoo/enterprise/pull/113135 @vin-odoo lmk what this should be tq ### Approach From my observations, all the other ir56 report templates name the variables accordingly to the XML template. I agree with this approach--keeping template dumb and the mapping logic in the python code. This will apply to the case for `AmtOfType2` which is equivalent to `AmtOfCommFee` in B,F,G ### Todo - [ ] squash commits - [ ] commit msg/desc - [ ] rename CE/EE to master- so upgrades work
Enhancements to existing features
This update restricts the 'Flexible Employment' (FLX) category option in the Belgian payroll module for Odoo Enterprise, aligning with specific Belgian labor regulations. It now requires a compatible Joint Committee (CP) and NACE company code to be selected, ensuring compliance and accurate reporting. This change improves data integrity and reduces potential errors related to FLX category selection.
Original PR description
[IMP] l10n_be_hr_payroll: restrict dimona flx category FLX in employee_type is selectable only for certain CPs (Joint Committees) and NACE codes of the company Ref list link:…
[IMP] l10n_be_hr_payroll: restrict dimona flx category
FLX in employee_type is selectable only for certain CPs (Joint Committees) and NACE codes of the company
Ref list link: https://emploi.belgique.be/fr/themes/contrats-de-travail/contrats-de-travail-particuliers/contrat-de-travail-flexi-job#toc_heading_3
1 - I created a new allowed_employee_types_ids M2M field to determine which employee types will be shown in the selection box (or flex will be shown or not)
1.1 - If the egov3 code of the joint committee is one of the determined codes in the ref link, the flex type is shown.
1.2 - Sometimes egov3 code of joint committee and NACE code of the company need to be combined
2 - In hr_version, joint committee field in UI was reseting after changing employee type to Flex or changing type from Flex to False, now it remains unchanged
3 - In employee form view, allowed_employee_types_ids is added as a domain to employee_type_id to show flex type or not
task - 6131721This update automatically calculates and displays the subscription duration on customer quotes (both PDF and Portal views) when a template has a defined duration. Previously, the duration wasn't visible until a subscription started, leading to a poor customer experience. The changes also improve the reliability of subscription synchronization.
Original PR description
**Why** Currently, when a quotation template has a duration, the end date is only computed and set when the subscription starts. As a result: - The duration is not visible to the customer on the PDF quote. - The duration is not visible to the customer on the Portal. - If a user manually defines a start date on the quote, the end date is not computed automatically. **What** - Made `end_date` a computed field depending on `start_date`. If the start date is set and the template has a fixed duration, the end date is now computed automatically. - Updated the Portal quote view to display the template's duration (Duration + Unit) if no start date is defined yet. - Updated the PDF quote report to display the template's duration if no start date is defined yet. - Refactored confirmation hook to maintain recurrence synchronization safely without redundant loops. **task**: 5969513
This update simplifies the process of canceling old invoices in Mexico's EDI system. When a new invoice replaces an existing one, the system now automatically cancels the original invoice, eliminating the need for manual intervention. This improves efficiency and reduces potential errors related to invoice management.
Original PR description
Triggers the EDI document cancellation method for the substituted invoice when the substitute document is signed, removing the requirement for the user to go back and click cancel again as well as bypassing calling a wizard with no options for the user to select from. task-5927581 Forward-Port-Of: odoo/enterprise#116959 Forward-Port-Of: odoo/enterprise#107541
This update improves how expenses are tracked within Odoo Enterprise by allowing for more detailed configuration. Previously, a generic 'EXPENSE' rule limited expense tracking, but now businesses can define specific input types for product categories, ensuring expenses are handled accurately according to local regulations and business needs.
This update enhances document creation by standardizing chatter messages, providing clear details like author, source, and document name. This improves traceability and reduces user confusion when managing documents, leading to a better overall experience.
Original PR description
Currently, when documents are created, their chatter messages are inconsistent, lack important details, or simply do not exist. This creates confusion and wastes users' time when trying to trace a document's origin. To solve this problem and improve the user experience, this PR introduces a standardized chatter message format that cleanly captures all essential information. Displayed information: - Document Author - Original document name - Document source (e.g., user upload, email, PEPPOL, or an Odoo app) - Notes section (hidden if empty; used to display the related record when saving an attachment from the chatter) Implementation notes: - adapted the tests of `account_invoice_extract` to account for new creation message. - Enabled logs for documents generated from emails. - A recent commit completely rewrote the "Add" document operation but left the old implementation intact. This PR removes that obsolete code. task-5498838
This update aligns the data cleaning views with standard Odoo list views, resolving inconsistencies in mass editing actions. By moving key actions like 'validate,' 'archive,' and 'unarchive' to the header, the user experience is now more intuitive and consistent with other Odoo workflows.
Original PR description
In the deduplication, and field cleaning views, mass selection did not behave consistently with standard Odoo list views and displayed redundant action buttons. This commit moves the validate, archive (discard), and unarchive (undiscard) actions from view buttons to header buttons so they behave like standard mass-edit actions in Odoo and provide a more consistent UX. task-6112028
This update enhances Odoo's support for Mexican import/export regulations (IMMEX) to align with CFDI 4.0 standards. Specifically, the 'External Trade' field now supports additional trade type codes, and defaults are set based on customer information for improved accuracy. This ensures proper tax reporting for Mexican businesses.
Original PR description
IMMEX is a program created by the Mexican government which enables companies to import goods into Mexico without paying taxes because they will be exported back in a short time. The "External Trade"(`l10n_mx_edi_external_trade_type`) field now includes values 01, 02, 03, and 04 to comply with CFDI 4.0. - Default value is "01 - Does not apply". - The field in `account.move` now defaults based on `res.partner` value. Populate 'External Trade' field in demo records: - Azure Interior: [02] - Definitive - Escuela Kemper Urgate: [04] - Definitive without alienation For `account.move` and `sale.order`, when the partner is a foreign customer, the "CFDI to public" (`l10n_mx_edi_cfdi_to_public`) field is automatically enabled. target: master task: 4819749
This update integrates the EC Sales List into the standard account returns process, streamlining the handling of returns related to online sales. The system now directly associates return information with the account return record, improving data accuracy and reporting. A new safeguard prevents incorrect return status resets when returns have been accepted by Digipoort.
Original PR description
This commit introduces the EC Sales List into the standard account returns flow and refactors the SBR status service to attach its messages directly to the account return instead of the closing entry. Specific changes include: * EC Sales List Integration: The EC Sales List report is now configured to auto-generate. * Status Service Refactoring: The `closing_entry_id` field on the `l10n_nl_reports.sbr.status.service` model has been replaced by `account_return_id`. * Message Processing Updates: The `_process_messages_and_statuses` method is updated to accept a consolidated `message_data` dictionary and apply it directly to the account return. * State Safeguards: A new safeguard (`action_reset_2_states`) prevents the resetting of an EC Sales return if it has already been accepted by Digipoort.
This update fixes inconsistencies in string sorting across different languages, ensuring accurate ordering for users in various locales. The new `localeCompare` function provides a locale-sensitive sorting method, addressing issues with default string comparisons and improving overall user experience.
Original PR description
Alphabetical order differs from one language to another. For example, in Estonian, Z comes after S and before T. This means that the order of strings displayed to the end users needs to be adapted…
Alphabetical order differs from one language to another. For example, in Estonian, Z comes after S and before T. This means that the order of strings displayed to the end users needs to be adapted depending on the current locale. This commit introduces the `localeCompare` utility function, which allows comparing two strings in a locale-sensitive way. ### What's wrong with the default behavior of `Array.prototype.sort`? `Array.prototype.sort` compares strings according to the UTF-16 code unit values of their characters. This results in behaviors that may not be what the end user expects. For example, "Zebra" is sorted before "apple", as uppercase letters come before lowercase letters in the ASCII table. "Élise" is not grouped with "Elise", and two same accented letters with different normalization forms aren't considered to be equivalent. ### Why not just use `String.prototype.localeCompare`? - Our `localeCompare` uses `user.lang` by default, which the string method doesn't - Our `localeCompare` comes with sensible defaults, such as sorting numbers based on their numerical value rather than their position in the ASCII table (i.e. "User 9" should come before "User 10000") - Our `localeCompare` always reuses the same instance of `Intl.Collator`, sparing the theoretical cost of instantiating it every time. Community: https://github.com/odoo/odoo/pull/264047
Resolved issues and error corrections
This update addresses a critical issue where Odoo transactions could leave incorrect tax records with Avalara. By committing Avalara's actions after the initial Odoo transaction, we prevent 'ghost' invoices and ensure accurate tax reporting. Accountants will now receive alerts if issues arise, allowing for quick resolution.
Original PR description
Some flows post an invoice and then perform additional work that may fail or at least delay the database commit (e.g. `_cron_post_process()` on `payment.transaction`). This extra work can raise…
Some flows post an invoice and then perform additional work that may fail or at least delay the database commit (e.g. `_cron_post_process()` on `payment.transaction`). This extra work can raise standard Odoo exceptions, and even without them, concurrent transactions or database deadlocks are possible. The invoice is committed on Avalara's side within `_post()`, so a later rollback of the Odoo transaction leaves a committed ghost invoice on Avalara's side. Accountants need to find these and manually void them to stop Avalara from filing incorrect tax returns. To avoid this, we move the Avalara commit into a postcommit hook. Since `account_external_tax` already calls `_get_external_taxes()` just before `_post()` to calculate taxes, the postcommit call is unlikely to fail. If it does, we log an activity on the invoice to notify the user, who will then need to resolve it manually (either by cancelling on the Odoo side and retrying, or by recreating the entry directly in the Avalara portal). opw-6192702
This update simplifies a confusing error message related to GST registrations, specifically for businesses using multiple GST numbers within the same organization. The new message clearly prompts users to verify the connection between their GST username and number, reducing support requests and improving the user experience. This change enhances the reliability of the system for businesses managing multiple tax registrations.
Original PR description
Users operating with multiple GST registrations (GST-wise branches/companies) could encounter a misleading error when the GST username belonged to a different GST number within the same organization. Previously, the system raised an error directly received from the server: [AUTH4041] Invalid Parameter state-cd in request header This message was confusing and led to unnecessary support tickets and false reports, as the issue was actually a mismatch between GST username and number. The error message has been updated to be more explicit and user-friendly: Please confirm that <gst_username> is associated with <gst_number>. Additionally, refactored duplicated logic by extracting the common code into a single helper function and reusing it across all occurrences. task-6041510 Forward-Port-Of: odoo/enterprise#111115
This update resolves an issue where rapid actions triggered duplicate account return check records being created in the database. The fix prevents multiple simultaneous processes from attempting to create the same record, ensuring data integrity. This improves the stability and efficiency of the account reporting feature.
Original PR description
Issue -------------- When refreshing checks on account returns (e.g. from rapid successive clicks or component re-renders), multiple concurrent RPC calls to `refresh_checks` were being dispatched to…
Issue
--------------
When refreshing checks on account returns (e.g. from rapid successive clicks or component re-renders), multiple concurrent RPC calls to `refresh_checks` were being dispatched to the server. This created a race condition that resulted in duplicate `account.return.check` records being generated in the database.
steps to reproduce demonstrated in video: https://drive.google.com/file/d/1-A0ZHdYGdv-UL0dqClqK6Kos_iVXoZai/view?usp=sharing
When this happen the `runAllReturnChecks` method fires parallel RPC calls to [`refresh_checks`](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1974-L1992) on the server. In the case of instant multiple RPC calls, parallel threads are dispatched which causes the data preparation stage to run simultaneously.
Because both threads run in parallel, Thread 2 runs its [preparation and existing ](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1986-L1987 )check mechanism before Thread 1 has reached the actual `create()` function [trigger](https://github.com/odoo/enterprise/blob/55bfd499660d3eda0abfc9e8ed8c9a2befbd394b/account_reports/models/account_return.py#L1998-L1999). Consequently, Thread 2's existence check fails to find the record (since Thread 1 hasn't committed it to the database yet), and it considers the record eligible for creation—even though the exact same record is already prepared for creation by Thread 1. This race condition leads to duplicate `account.return.check` records.
Logs to demonstrate the thread execution:
--------
```python
2026-04-16 08:30:51,493 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.000 0.002
2026-04-16 08:30:51,662 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "POST /web/dataset/call_kw/account.report/dispatch_report_action#account.report.dispatch_report_action HTTP/1.0" 200 - 17 0.006 0.012
2026-04-16 08:30:51,847 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:51] "POST /web/dataset/call_kw/account.return/get_views#account.return.get_views HTTP/1.0" 200 - 26 0.009 0.025
2026-04-16 08:30:52,099 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:52] "POST /web/dataset/call_kw/account.return/web_read_group#account.return.web_read_group HTTP/1.0" 200 - 95 0.029 0.064
2026-04-16 08:30:52,320 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:52] "POST /web/dataset/call_kw/account.return/get_next_returns_ids#account.return.get_next_returns_ids HTTP/1.0" 200 - 2 0.001 0.004
THREAD NAME: odoo.service.http.request.137360481711808 Thread ID: 137360481711808
REFRESH CHECK START:--------------------------------------------
Thread ID: 137360481711808 -------------DATA PREPARING STAGE------------
Thread ID: 137360481711808
Thread ID: 137360481711808 RECORD EXISTING CHECK: None
2026-04-16 08:30:53,842 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:53] "GET /odoo/tax-report/tax-return?debug=1 HTTP/1.0" 200 - 29 0.020 0.021
2026-04-16 08:30:54,066 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/webclient/load_menus HTTP/1.0" 200 - 4 0.002 0.009
2026-04-16 08:30:54,351 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/manifest.webmanifest HTTP/1.0" 200 - 6 0.003 0.005
2026-04-16 08:30:54,493 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/webclient/translations?hash=bb5aa713d587cc7dd07b13d1d7efc2c525517e99&lang=en_US HTTP/1.0" 200 - 1 0.000 0.002
2026-04-16 08:30:54,586 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/bundle/web_tour.interactive?lang=en_US&debug=1 HTTP/1.0" 200 - 1 0.001 0.003
2026-04-16 08:30:54,640 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/action/load_breadcrumbs HTTP/1.0" 200 - 7 0.003 0.006
2026-04-16 08:30:54,710 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/ir.http/lazy_session_info#ir.http.lazy_session_info HTTP/1.0" 200 - 2 0.001 0.004
2026-04-16 08:30:54,753 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /bus/websocket_worker_bundle?v=19.0-2 HTTP/1.0" 304 - 3 0.004 0.006
2026-04-16 08:30:54,766 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "GET /web/image?model=res.users&field=avatar_128&id=2 HTTP/1.0" 304 - 9 0.012 0.013
2026-04-16 08:30:54,777 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /mail/data HTTP/1.0" 200 - 34 0.034 0.020
2026-04-16 08:30:54,824 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/account.return/get_views#account.return.get_views HTTP/1.0" 200 - 3 0.001 0.010
2026-04-16 08:30:54,934 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:54] "POST /web/dataset/call_kw/account.return/web_read_group#account.return.web_read_group HTTP/1.0" 200 - 88 0.029 0.051
2026-04-16 08:30:55,107 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:55] "POST /web/dataset/call_kw/account.return/get_next_returns_ids#account.return.get_next_returns_ids HTTP/1.0" 200 - 2 0.001 0.005
THREAD NAME: odoo.service.http.request.137360513177280 Thread ID: 137360513177280
REFRESH CHECK START:--------------------------------------------
Thread ID: 137360513177280 -------------DATA PREPARING STAGE------------
Thread ID: 137360513177280
Thread ID: 137360513177280 RECORD EXISTING CHECK: None
2026-04-16 08:30:55,589 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:55] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.001 0.006
2026-04-16 08:30:56,702 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:56] "GET /web/service-worker.js HTTP/1.0" 200 - 1 0.000 0.003
2026-04-16 08:30:58,893 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:30:58] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.006 0.023
2026-04-16 08:31:05,296 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:31:05] "GET /websocket?version=19.0-2 HTTP/1.0" 400 - 1 0.001 0.002
Thread ID: 137360481711808 DATA to_create: 168
Thread ID: 137360481711808 done process create
2026-04-16 08:31:10,132 14 INFO bsra_4165887_upg werkzeug: 202.131.97.106 - - [16/Apr/2026 08:31:10] "POST /web/dataset/call_kw/account.return/refresh_checks#account.return.refresh_checks HTTP/1.0" 200 - 513 11.611 6.039
Thread ID: 137360513177280 DATA to_create: 168
Thread ID: 137360513177280 done process create
```
- OPW: 5917459
Forward-Port-Of: odoo/enterprise#114045This update resolves an error that prevented users from marking payslips as paid when the 'Include Unpaid' option was selected. The change ensures that the system correctly processes unpaid payslips, preventing a technical error and improving the reliability of the payroll reporting feature. This fix addresses a potential disruption to payroll processing.
Original PR description
Currently, an error occurs when a user attempts to mark a payslip as paid. **Steps to Reproduce:** - Install the `hr_payroll` module without demo data. - Go to `Payslips` and click on `New…
Currently, an error occurs when a user attempts to mark a payslip as paid. **Steps to Reproduce:** - Install the `hr_payroll` module without demo data. - Go to `Payslips` and click on `New Off-cycle`. - Create a record > `Compute` > `Validate`, and Pay. - In the wizard, enable `Include Unpaid` and select `CSV` mode. - Click `Mark as Paid`. **Error:** `UnboundLocalError: cannot access local variable 'rows' where it is not associated with a value` The error occurs when a user tries to mark a payslip as paid with Include Unpaid enabled. When the wizard is created from here [1], the default unpaid payslips are empty. In this case, the system assigns an empty set of payslips to process [2].and the rows variable is not defined because there are no payslips to work on, which raises the error [3]. This commit ensures that when the wizard is created, the matched unpaid payslips are passed to the wizard. If the Include Unpaid option is enabled, the unpaid payslips are assigned for processing, similar to [4]. The unpaid payslips cannot be empty, as they always include the currently processed payslip. Also, the rows are redefined for each payslip case and updated accordingly. Therefore, this commit ensures that the rows are created at the end from grouped payments. [1] https://github.com/odoo/enterprise/blob/a784d118e076724b02e5c59d9ce5d1815c42b0bf/hr_payroll/models/hr_payslip.py#L792-L809 [2] https://github.com/odoo/enterprise/blob/e971fca0d09e564ae9029f3d7e166e078c44dcbb/hr_payroll/wizard/hr_payroll_payment_report_wizard.py#L56 [3] https://github.com/odoo/enterprise/blob/e971fca0d09e564ae9029f3d7e166e078c44dcbb/hr_payroll/wizard/hr_payroll_payment_report_wizard.py#L97 [4]: https://github.com/odoo/enterprise/blob/a784d118e076724b02e5c59d9ce5d1815c42b0bf/hr_payroll/models/hr_payslip_run.py#L274-L288 sentry-7436885639 Forward-Port-Of: odoo/enterprise#116787 Forward-Port-Of: odoo/enterprise#115090
This update refines how Odoo automatically matches bank statements to invoices. Previously, it prioritized the closest date, which wasn't always accurate. Now, it only matches if there's a single bank statement prior to the statement line's date, ensuring more reliable reconciliation.
Original PR description
Before this pr, we decided that when there was multiple candidates, we would take the one closer to the date of the statement line but it is not always what we want. We decided to change that so that it would match only if there is one candidate prior the date of the statement line. Exemple: Invoice 1 the 10/06 and invoice 2 the 20/06 → Payment the 05/06 → no matching (0 before) → Payment the 15/06 → match with invoice 1 (only 1 before) → Payment the 25/06 → no matching (More than 1 invoice open before) task-6143809 Forward-Port-Of: odoo/enterprise#115888 Forward-Port-Of: odoo/enterprise#115284
This update resolves an issue where setting a maximum package weight in Sendcloud caused rate calculations to fail. The fix ensures that shipments are correctly split into packages based on weight limits, preventing errors when requesting shipping rates. This improves the accuracy of shipping cost estimations.
Original PR description
Issue ----- Putting a max weight on a package type causes getting a rate with Sendcloud to fail. Steps to reproduce ----- - Setup Mondial Relay using Sendcloud - Set a default package type with max…
Issue ----- Putting a max weight on a package type causes getting a rate with Sendcloud to fail. Steps to reproduce ----- - Setup Mondial Relay using Sendcloud - Set a default package type with max weight 2kg - Create a product with a 500g weight - Create a SO with the product - Add delivery - Sendcloud Mondial Relay - Get rate > Impossible to get a rate Cause ----- When retrieving the shipping method to use when retrieving a rate, we use the real weight of the order. https://github.com/odoo/enterprise/blob/cca1433f5a064673b8e007530e20e8a9fe72949b/delivery_sendcloud/models/sendcloud_service.py#L67 https://github.com/odoo/enterprise/blob/cca1433f5a064673b8e007530e20e8a9fe72949b/delivery_sendcloud/models/sendcloud_service.py#L81 However, when making the rate call, we use the value returned by `_split_shipping` https://github.com/odoo/enterprise/blob/cca1433f5a064673b8e007530e20e8a9fe72949b/delivery_sendcloud/models/sendcloud_service.py#L91 which is equal to the maximum weight of the package. This is blocking in some cases, like if - the real weight is 750g - the package max is 2kg - Sendcloud returns a shipping method for [500g;1kg] Asking a rate for this method & a 2kg package will fail (rightfully so). Solution ----- The shipment should be split into packages before retrieving the shipping methods. Otherwise the problem might be the other way around where we retrieve a shipping method for the whole order, only to split it into multiple packages because they don't fit in one. Also, the `shipping_weight` returned by `_split_shipping` should only be different from the order's total weight if it is higher than the maximum deliverable weight. ----- Ticket: opw-5947199 Forward-Port-Of: odoo/enterprise#116909 Forward-Port-Of: odoo/enterprise#108315
This update fixes a recurring issue where Odoo would repeatedly retry sending eTIMS transactions, leading to an error (924). The change improves reliability by intelligently handling network interruptions and ensuring that invoice numbers are correctly tracked, preventing duplicate attempts and improving data accuracy for Kenyan e-invoicing.
Original PR description
When the network drops after eTIMS processes a transaction but before Odoo receives the confirmation, Odoo would retry with the same invoice number, causing eTIMS error 924 (Invoice number already…
When the network drops after eTIMS processes a transaction but before Odoo receives the confirmation, Odoo would retry with the same invoice number, causing eTIMS error 924 (Invoice number already exists). For POS orders, the old code decremented the sequence on any error (including timeout), so the next retry consumed the same invcNo. If eTIMS had already recorded the original send, the retry was rejected with 924. Fix by introducing a fetch-first strategy: on retry, if a pending invcNo is found in l10n_ke_order_json, call selectInvoiceDetails before sending. If eTIMS already has the invoice, recover the receipt data directly without resending. If eTIMS does not have it, resend with the same invcNo safely. On timeout errors, the sequence is no longer decremented so the invcNo is preserved in l10n_ke_order_json for the next idempotent retry. For customer invoices, the existing fetch-first logic only bailed out on TIM (timeout) errors, falling through on CON (connection) errors and retrying blindly. Additionally, if saveTrnsSalesOsdc returned 924, there was no recovery path and the invoice number would be cleared. Fix by also bailing on CON in the fetch block, and adding an explicit 924 handler that calls selectInvoiceDetails to recover the existing receipt instead of failing. opw-6105693 Forward-Port-Of: odoo/enterprise#115649
This update resolves an issue where the table number on the kitchen display was being cut off when the order title exceeded a certain length. This prevented kitchen staff from quickly identifying the correct table, leading to potential delays. The change has been reverted to ensure the table number is always fully visible.
Original PR description
**Steps to reproduce:** - Download the German language - Set the restaurant to QR + Ordering - Set the Service at Table, pay after each order - Set the language to German - Go to the Self and order…
**Steps to reproduce:** - Download the German language - Set the restaurant to QR + Ordering - Set the Service at Table, pay after each order - Set the language to German - Go to the Self and order something while the language is German - Chose table 12 - Go to the kitchen display - The title is truncated, meaning we can't see the table number **Why the fix:** If the title is more than 150px it will be truncated and "..." will replace the table number. This has been introduced in ed5b010dc7b5c11bbbc8513c1edb0ec4f58778c1 but not being able to see the table number might be bad as some people would need to spend time trying to figure out which table the order is for, instead of just having to look at the kitchen display. We now revert this change to break to a new line in the case where the card title is too long, so we can always see the table number. Before: <img width="317" height="156" alt="image" src="https://github.com/user-attachments/assets/25e76026-bdad-4639-9dfc-0d75ffa8d8c8" /> Afer: <img width="329" height="174" alt="image" src="https://github.com/user-attachments/assets/f387dd5f-96d3-4148-bc76-215393c76e67" /> opw-6096111 Forward-Port-Of: odoo/enterprise#116594 Forward-Port-Of: odoo/enterprise#114859
This update resolves an issue where the barcode scanning feature wasn't accurately updating inventory quantities when scanning pack-in-pack items. The fix ensures that quantities are correctly recorded during inventory counts, improving the reliability of stock tracking. This resolves a problem preventing accurate inventory updates.
Original PR description
### Steps to reproduce: - In the settings enable "Packages" - Create a storable product A and put 1 unit in a package P in stock - Inventory > Products > Packages > open your package P - Set a parent…
### Steps to reproduce: - In the settings enable "Packages" - Create a storable product A and put 1 unit in a package P in stock - Inventory > Products > Packages > open your package P - Set a parent package PP as container - Inventory > Operations > Adjustments > Physical Inventory - Select you product line for A > Request a count (from the control panel button) - Enable Show Expected Quantity and confirm - Go to the barcode app > Count Inventory (1) - scan your parent package PP #### > traceback: Uncaught Promise > Cannot create property 'inventory_quantity' on boolean 'false' ### Cause of the issue: When the Package scan is processed, we loop over all quants related to it: https://github.com/odoo/enterprise/blob/30a28e28f8dd27cf2c88df65e5ff47eab59360c7/stock_barcode/static/src/models/barcode_quant_model.js#L566-L569 https://github.com/odoo/enterprise/blob/30a28e28f8dd27cf2c88df65e5ff47eab59360c7/stock_barcode/static/src/models/barcode_quant_model.js#L602-L617 And for each of these we try to find an existing line representing the quant to update or we do create a new line. Now, the issue, is that the subpackages of the quant are not provided to find the quant candidate line to update. As such, no line is found we enter the else clause and try to createa a NewLine: https://github.com/odoo/enterprise/blob/30a28e28f8dd27cf2c88df65e5ff47eab59360c7/stock_barcode/static/src/models/barcode_quant_model.js#L617-L627 This time however, the appropriate subpackage (the one of the quant) is provided to the arguments. And, since the line representing this quant is already existing, the `_createNewLine` will return False: https://github.com/odoo/enterprise/blob/30a28e28f8dd27cf2c88df65e5ff47eab59360c7/stock_barcode/static/src/models/barcode_quant_model.js#L393-L399 https://github.com/odoo/enterprise/blob/30a28e28f8dd27cf2c88df65e5ff47eab59360c7/stock_barcode/static/src/models/barcode_quant_model.js#L423 This leads to a traceback at the end of the else close since `false.inventory_quantity` doe not make sense (Cannot create property 'inventory_quantity' on boolean 'false') https://github.com/odoo/enterprise/blob/30a28e28f8dd27cf2c88df65e5ff47eab59360c7/stock_barcode/static/src/models/barcode_quant_model.js#L626-L627 Fix: We adapt the `_processPackage` of the `BarcodeQuantModel` to mimic the existing 'update' behavior on the `BarcodePickingModel`: https://github.com/odoo/enterprise/blob/30a28e28f8dd27cf2c88df65e5ff47eab59360c7/stock_barcode/static/src/models/barcode_picking_model.js#L2110-L2133 Note that UOM converstion should not be required since quants are already uniformly expressed in the product uom: https://github.com/odoo/odoo/blob/30b4edace6b0859cb1b1ba4f7f2ea80ba5398e3d/addons/stock/models/stock_quant.py#L52-L54 opw-5864591 Forward-Port-Of: odoo/enterprise#116715
This update fixes a bug that occurred when users tried to reschedule marketing activities, specifically within automated campaigns. The change prevents errors related to missing parent information, ensuring campaign scheduling functions reliably. This improves campaign stability and reduces potential disruptions for users.
Original PR description
**Steps to reproduce:** - Create a new marketing campaign with two activities - Set them to occur some number of days after the beginning - Save the campaign and start it - Modify one of the…
**Steps to reproduce:** - Create a new marketing campaign with two activities - Set them to occur some number of days after the beginning - Save the campaign and start it - Modify one of the activities to occur some number of days after the other activity and save - Modify the child activity by changing the number of days after its parent that it should run and save - An error will be thrown **Issue:** The trace related to the child activity has no parent when trying to reschedule it in `_update_schedule_date`. This causes an issue when trying to get the first mailing_trace_ids using index 0 in this line: `base_dt_str = trace.parent_id.schedule_date or trace.parent_id.mailing_trace_ids[0].write_date or trace.participant_id.create_date` **Fix:** Prevent the activity hierarchy to be modified on started campaigns. We also change the indexing to avoid further out of range issue and properly default on the participant create value. Trying to match existing traces to their parents has too many edge cases when trying to avoid duplicates, and might often need to reset the whole trace chain to work properly. This approach avoids user mistakes on running campaigns, but if a user tries to launch a test (even on draft campaign) he won't be able to modify the hierarchy further without deleting/recreating some activities/traces. So we should ignore this for test traces, but it could impact the behavior between test and actual executions. opw-5362978 Forward-Port-Of: odoo/enterprise#107556
This update resolves several issues within the AI Fields module, primarily related to error messages and how the AI agent retrieves and displays web sources. The fixes ensure more reliable AI functionality and prevent misleading error notifications for users.
Original PR description
This commit fixes the following bugs: - In 99f76c1, tools.py was moved from ai_fields module instead ai_fields_tools in the ai module. However, the 'odoo.addons.ai_fields.tools.UnresolvedQuery' error which is caught in _computeAiField method wasn't changed to reflect the new file path which made the error appear to the user instead of just being a toaster message. - When performing web_grounding, the URL citations are replaced by [WEB_SOURCE:<id>] to prevent LLM hallucinating sources during the agentic_loop. These placeholders are replaced again by the actual URLs before sending the responseback to the user. However, this wasn't done in the case of _get_direct_response when the web_grounding completion option was set to True and was only done if the custom web_search tool was used. This caused these placeholders to appear in AI Fields. task-6209766
This update resolves inaccuracies in the data used for calculating Belgian HR payroll through Prisma. Specifically, it addresses missing codes related to leave types (LEAVE280, LEAVE115, LEAVE231) and ensures accurate calculations for various work accident and occupational disease scenarios. This ensures payroll calculations align with Belgian regulations.
Original PR description
Issue: ---------------------------------------- Some prisma codes are wrong. Solution: ---------------------------------------- Change the data files. There are some subtilities that were not implemented: - LEAVE280: 0304 (if less than a year) and 0345 (if more) - LEAVE115: 0820 (Work accident) and 0830 (Occupational Disease) opw-6090081 Forward-Port-Of: odoo/enterprise#116808 Forward-Port-Of: odoo/enterprise#112949
This update streamlines the work order planning process by reordering and renaming menus for better usability. Specifically, the 'Plan MO' button has been added, and the Gantt chart now filters employee displays based on assigned work orders, resolving a previous issue of showing all employees. The update also restores previously removed views for enhanced planning options.
Original PR description
Some ui fixes for the new workorder planning Task: 6143389 Forward-Port-Of: odoo/enterprise#115477
This update resolves an issue where the CUFE (Contribution Fiscal Electronica) information wasn't appearing on invoices generated as PDFs for the CO_DIAN localization. The fix reordered the invoice PDF layout, ensuring this critical data is now correctly included. This ensures accurate reporting and compliance for CO_DIAN customers.
Original PR description
**STEP TO REPRODUCE** 1. Setup DIAN. 2. Create an invoice. 3. Send it to dian. 4. Notice the cufe doesn't appear on the pdf. This fix moves the CUFE div before the informations div. Before the fix, it was placed at the top of the xml which appears to not render starting from 19.2. opw-6182706 Forward-Port-Of: odoo/enterprise#116245
This update resolves an error that occurred when calculating overtime deductions for employees with specific filing statuses (beyond 'single' or 'jointly'). The fix ensures the system correctly handles a wider range of filing status values, preventing a crash. This improves the accuracy of overtime calculations for affected employees.
Original PR description
Issue: ---------------------------------------- When having an employee with `l10n_us_filing_status` not in `['single', 'jointly']` and evaluating the rule parameter…
Issue: ---------------------------------------- When having an employee with `l10n_us_filing_status` not in `['single', 'jointly']` and evaluating the rule parameter `l10n_us_qualified_overtime_deduction_cap` an error occurs. Cause: ---------------------------------------- `l10n_us_filing_status` can have 5 values: `['single', 'jointly', 'separately', 'head', 'survivor']` But only `['single', 'jointly']` are defined for `l10n_us_qualified_overtime_deduction_cap` ([src](https://github.com/odoo/enterprise/blob/2d2056766441157dc45ebc37b677841c44e5c513/l10n_us_hr_payroll/data/hr_rule_parameters_data.xml#L48)). When running the rule "Qualified Overtime", the custom Python crashes because we read a key that is not there: https://github.com/odoo/enterprise/blob/2d2056766441157dc45ebc37b677841c44e5c513/l10n_us_hr_payroll/data/hr_salary_rule_data.xml#L56 Solution: ---------------------------------------- In the custom Python condition, we first check if the key is there. The custom Python computation also tries to read the key, but it is run only if the condition is validated. So we don't need to change it. Also fixed indentation of test 069. opw-6129657 Forward-Port-Of: odoo/enterprise#116913 Forward-Port-Of: odoo/enterprise#115754
This update resolves several errors that could occur when the system processes NOTI files for Belgian payroll. The fix ensures accurate and reliable calculation of social security contributions, minimizing potential discrepancies and compliance issues. This improves the overall stability and accuracy of the HR payroll module.
Original PR description
Forward-Port-Of: odoo/enterprise#116871
This update resolves a problem preventing accurate delivery status updates from Amazon through the Shiprocket integration. The team added specific carrier sub-category names (like Xpressbees) to the Amazon carrier mapping, which is essential for the integration to function correctly in India. This ensures reliable tracking of orders on Amazon.
Original PR description
Fixing Amazon delivery status update failure via Shiprocket integration. See also: - Community PR: https://github.com/odoo/odoo/pull/262751 OPW:5959762
This update fixes an issue where Swedish financial data files were not importing correctly, resulting in incorrect account names. The fix ensures the data is interpreted using the correct CP437 encoding, accurately displaying Swedish characters like 'Ö' in imported financial records.
Original PR description
Issue: Non-ASCII charatcter from sie file were lost on import. Steps to reproduce: - in a Swedish company - import the SIE4 exemple file from sie website: https://sie.se/wp-content/uploads/2024/01/SIE4-Exempelfil-Sample-file-1.zip Current behavior: - The account 1090 is imported as "vriga imm anl tillg" instead of "Övriga imm anl tillg" Expected behavior: - The account 1090 is imported as "Övriga imm anl tillg" Cause: CP437 uses 8 bits to represent data. Ö is \x99. However, file was imported using either UTF-8 or ISO-8859-1, where Ö is \xC396 and \x99 doesn't link to anything. This commit update the test file as it was save in cp437 but read as UTF-8. opw-6167408 Forward-Port-Of: odoo/enterprise#117032 Forward-Port-Of: odoo/enterprise#116722
Code cleanup and technical improvements
This update replaces partner data with user data within member-related flows across several Odoo Enterprise modules. This change enhances data accuracy and simplifies user management, aligning with best practices for user identification and access control. It impacts modules like Frontdesk, WhatsApp, and AI Livechat.
Original PR description
\* = ai_livechat, frontdesk, whatsapp Enterprise counter-part. task-5946571 https://github.com/odoo/odoo/pull/249517
5 changes
Resolved issues and error corrections
This update fixes an issue where the remaining balance wasn't accurately displayed when multiple foreign currency transactions were selected in the accounting dashboard. The change ensures that the correct balance is always shown, regardless of how many transactions are selected, improving accuracy and reliability of financial reporting.
Original PR description
Steps to reproduce: - company currency EUR - Copy the bank journal and define the USD as a currency - Create and confirm two invoices for Customer A for a total amount X - Go to the Accounting Dashboard and select the new journal - Create a new transaction of an amount Y > X - Select 1 of the invoices - Select the second one Issue: When selecting one transaction line, the correct balance is displayed. When selecting multiple lines in the foreign currency journal, the balance changes to “/” instead of showing the actual balance. opw-6168097
This update resolves issues preventing Odoo's Norwegian VAT XML reports from passing validation by Skatteetaten. The changes ensure correct decimal formatting, mathematical calculations, and required legal notes are included in the XML, allowing businesses to accurately file their VAT returns. This addresses a critical compliance requirement.
Original PR description
Before commit: The Norwegian VAT XML export fails Skatteetaten validation due to incorrect decimal formatting, mathematical rounding mismatches between base and tax amounts, missing mandatory legal…
Before commit: The Norwegian VAT XML export fails Skatteetaten validation due to incorrect decimal formatting, mathematical rounding mismatches between base and tax amounts, missing mandatory legal notes, and invalid KID number formats. Fix: To strictly follow Skatteetaten validation rules for the Norway VAT XML, the following changes were implemented: - Ensured standard rates drop the decimal (e.g, `25.0` to `25`), and formatted fractional rates like `11.11` to `11,11` in XML. - Rounded down the `tax_amount` to align precisely with government mathematical expectations. - `base_amount` converted into absolute value to ensuring the calculation (`base * rate = tax`) resolves perfectly. - Add the mandatory `<merknad>` explaining the reverse charge method for codes 81, 83, 86, 88, and 91. - Clean the `company_kid` by safely stripping the 'NO' prefix, and 'MVA' suffix. Expect: The generated XML payload now adheres perfectly to Skatteetaten's strict structural and mathematical rules, allowing the VAT return to pass government validations successfully. Related Community PR: https://github.com/odoo/odoo/pull/258390 Task-6033027 Forward-Port-Of: odoo/enterprise#116962 Forward-Port-Of: odoo/enterprise#110792
This update resolves an issue where fiscal categories and related products weren't consistently loaded when using the self-order blackbox feature. Now, these essential product details are automatically loaded, ensuring accurate order processing and reporting within the self-order environment.
Original PR description
Before this commit, the fiscal category and the products work in and work out weren't necessarily automatically loaded when using the self with a blackbox, it is now the case.
This update resolves an error that occurred when users removed the Source Entity Id Type in the Super Contributions reporting module. The fix ensures that the system correctly handles this removal, preventing a computation error and maintaining data integrity. This improves the reliability of the Australian Super Contributions reporting.
Original PR description
Currently an error occurs when the user removes the Source Entity Id Type on Super Contributions. **Steps to Reproduce:** - Install `l10n_au_hr_payroll_account` with demo data. - Switch to an…
Currently an error occurs when the user removes the Source Entity Id Type on Super Contributions. **Steps to Reproduce:** - Install `l10n_au_hr_payroll_account` with demo data. - Switch to an `Australian` company. - Go to `Payroll` > `Reporting` > `Australia` > `Super Contributions`. - Open an existing record or create a new one. - Remove the `Source Entity Id Type` value and click anywhere. `ValueError: Compute method failed to assign l10n_au.super.stream(<NewId origin=1>,).source_entity_id` After [change] in the selection field behavior, when the user removes the Source Entity Id Type, the compute method is triggered to compute the Source Entity ID. However, the condition in the compute method is not match, so no value is assigned. As a result, the method fails and raises an error. This commit ensures that if the condition is not match, the Source Entity ID is explicitly set to False. [1]- https://github.com/odoo/enterprise/blob/9d523d7aabffda277e1ef734caf2b0e434545dca/l10n_au_hr_payroll_account/models/l10n_au_super_stream.py#L61-L65 [change]: https://github.com/odoo/odoo/pull/214422/changes/8d2a42ac419fdf7943a0c11beb8c5de6c6f85bef
This update fixes an issue where importing a product with a changed subscription type could bypass a necessary warning. Previously, the system processed the import without alerting the user that they were attempting to modify a product already sold as a subscription. Now, a warning is raised to prevent unintended changes to subscription settings.
Original PR description
__ ## Short functional explanation of the error When we have a subscription product that has already been sold. If we try to import a product with the same ID but where we change the subscription…
__ ## Short functional explanation of the error When we have a subscription product that has already been sold. If we try to import a product with the same ID but where we change the subscription type of the product, the import is executed without issue. However, this leads to undesired behavior: when we go to the product page and try to manually change the subscription type (set it back to subscription), the change is not applied as a warning is raised. ## Reproduction Steps Make sure you have debug mode enabled. 1. Create a product, and check the Subscription box. 2. Click on Orders and create a Quotation with this product, then confirm. 3. Go to Products > Products. Select the list view and search for the product you just created. Select it, and click Actions > Export. 4. Check the import compatible field. Select the fields to export: name, id and recurring_invoice. Upon exporting, a file is downloaded. 5. Access that file and change the recurring_invoice to FAUX or FALSE if your computer is in English. Save the changes. 6. Unselect the product and click on the cog, top right > Import. Click on Upload Data File and select the file that you have downloaded upon exporting, then import. ### Expected behavior A user warning is raised: we shouldn't be able to change the subscription type of the product when it has already been sold. ### Unexpected behavior The import is processed normally. Then, when we access the product page, and try to check the Subscriptions box again, a warning is raised. ## Origin of the issue Nothing prevents the import from occurring in that case. __ opw-6143789 Forward-Port-Of: odoo/enterprise#117046 Forward-Port-Of: odoo/enterprise#115046
10 changes
Resolved issues and error corrections
This update optimizes a key query in our Point of Sale system, resulting in significantly faster report generation. By adding the journal to the search criteria, the system now leverages an existing database index, dramatically reducing the time it takes to retrieve account move information. This improves the overall performance and responsiveness of the POS system.
Original PR description
Currently the query to get the closing difference account move is done by searching for the reference of the move, which is not very efficient. This commit optimizes this query by adding the journal…
Currently the query to get the closing difference account move is done by searching for the reference of the move, which is not very efficient. This commit optimizes this query by adding the journal to the search criteria, which allows us to benefit from the index on the journal_id field. Here is an example of the before after on a database with 39 million account_move records. Meanwhile only 10-20K account_move are linked to specific journals used in POS payment methods. All measures are performed with a warmed up cache [Explain Before](https://explain.dalibo.com/plan/h8edf56c09d7dfd7) ### Benchmark: <table> <thead> <tr> <th># of am</th> <th>Before</th> <th>After</th> </tr> </thead> <tbody> <tr> <td>38982635</td> <td>~17s</td> <td>~22ms</td> </tr> </tbody> </table> [Explain After](https://explain.dalibo.com/plan/be2397f176a6b29d) --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#262148
This update strengthens the signup process by ensuring all email addresses entered during registration are validated. Previously, users could enter any string, creating a potential security risk. The change enforces email format validation and adds autocomplete attributes to the signup form for a better user experience.
Original PR description
**Problem**
Before this commit, the email address typed in the signup form was not validated. Consequently, the user could use whatever string as email address.
**How to reproduce**
1. Activate "free sign up" ("Settings"->"Website"->"Customer Account")
2. While being signed off, navigate to "/web/signup"
3. No validation is enforced on the email field
**Fix**
The email field is correclty marked as "required", but its type was set as "text" instead of "email". This commit fixes the problem by changing the type to "email".
task-6094631
Forward-Port-Of: odoo/odoo#258967This update ensures that when stock valuation moves are created from purchase orders, the correct analytic account from the PO is automatically applied to the corresponding account move lines. Previously, these moves didn't inherit the analytic distribution from the PO, leading to incorrect accounting. This change aligns the behavior with how analytic distributions are handled for invoices.
Original PR description
**Problem:** account move created by stock valuation layer does not take analytic account from PO **Steps to reproduce:** - make sure you have at least one analytic account - create a storable…
**Problem:** account move created by stock valuation layer does not take analytic account from PO **Steps to reproduce:** - make sure you have at least one analytic account - create a storable product with categ standard automated - set a positive cost - create a PO for 1 quantity - on the PO line of the product, in the analytic distribution column (might need to be unfiltered) set an analytic account - confirm PO and validate receipt - click on the valuation smart button and on the book widget of the stock valuation layer **Current behavior:** the account move lines have no analytic distribution **Expected behavior:** The account move lines should inherit the analytic account from the purchase order line like it's the case for the bill. For the analytic distribution of the Bill, the selection is : 1) take analytic distribution from PO if one 2) if not, take from distribution model if there is one 3) empty Currently for the account move lines of the svl the selection is: 1) take from distribution model if there is one 2) empty But we should use same selection as for the bill **Cause of the issue:** When setting the analytic distribution we first try to use the one from PO/SO by calling _related_analytic_distribution() https://github.com/odoo/odoo/blob/4cc1e6884be673523f768d5ec471a1ffa19c5fb4/addons/account/models/account_move_line.py#L1157 But since the account move lines have no purchase_line_id no analytic distribution will be returned https://github.com/odoo/odoo/blob/4cc1e6884be673523f768d5ec471a1ffa19c5fb4/addons/purchase/models/account_invoice.py#L540-L545 opw-6022695
This update enables customers to cancel Stripe payments directly through the payment terminal, both on the standard POS and self-order kiosks. Previously, cancellation was only possible through the POS interface, creating a frustrating experience for users. This change improves customer satisfaction and streamlines the payment process.
Original PR description
Before this commit, when making a payment on a Stripe terminal, the only way to cancel the payment was from the POS interface. In the self order kiosk, it was impossible to cancel the payment. After this commit, a cancel button will appear on the payment terminal for both POS and kiosk Stripe payments. task-6166789 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves an issue where the French Intrastat export was incorrectly omitting quantity data for products with supplementary units. The fix ensures that accurate quantity information is included in the DEBWEB2 XML file, improving the reliability of Intrastat reporting for French businesses. This prevents data discrepancies and ensures compliance.
Original PR description
Steps to reproduce 1. In a French company with Intrastat enabled, set up a product whose commodity code has a CN supplementary unit (e.g. 8802 30 00, "p/st") and set…
Steps to reproduce
1. In a French company with Intrastat enabled, set up a product whose commodity code has a CN supplementary unit (e.g. 8802 30 00, "p/st") and set `intrastat_supplementary_unit_amount` on it.
2. Post EU customer invoices for that product.
3. Export the DEBWEB2 XML from the Intrastat report.
Issue
The FR export collapses engine rows a second time in `_group_items`, because the DEBWEB2 format groups more aggressively than the SQL. The aggregator only declares `value` and `weight`: https://github.com/odoo/enterprise/blob/6ae5d3df6e9305416e4d6f74259cd01753025f42/l10n_fr_intrastat/models/account_intrastat_report.py#L308-L313 Items are then rebuilt as `dict(zip(grouping_key, key_tuple)) | grouped_item_values`. `SU_code` survives (it is in the grouping key), but the numeric `supplementary_units` is in neither side and is silently dropped as soon as two engine rows merge. The template then skips the element because of its `t-if="item.get('supplementary_units')"` guard: https://github.com/odoo/enterprise/blob/6ae5d3df6e9305416e4d6f74259cd01753025f42/l10n_fr_intrastat/data/intrastat_export.xml#L61
opw-6139657This update resolves an issue where Point of Sale orders would fail if a product used an archived Unit of Measure. Now, archived UOMs are automatically loaded into the POS, ensuring orders can be processed without errors and improving the reliability of the POS system. This change prevents order processing failures and enhances the user experience.
Original PR description
If a product uses an archived UOM and an order is then created in the POS with this product, an error would occur because it could result in trying to use a UOM that wasn't loaded in the POS since it was archived. To fix this issue, we now load archived UOMs in the POS. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6197465
This update resolves a bug that caused reconciliation errors when dealing with kit components in Odoo. The issue stemmed from how valuation layers were being handled, leading to duplicate reconciliation attempts. The fix ensures accurate reconciliation of inventory movements for kits and their components, improving accounting accuracy.
Original PR description
Steps to reproduce ----- - Modules: Sale, Purchase, Mrp, Accounting - Enable automatic accounting & anglo-saxon valuation - Create an AVCO Product category (AVCO automatic valuation) - Create a Kit…
Steps to reproduce
-----
- Modules: Sale, Purchase, Mrp, Accounting
- Enable automatic accounting & anglo-saxon valuation
- Create an AVCO Product category (AVCO automatic valuation)
- Create a Kit product storable & AVCO
- Kit bom
- Comp as a component (storable & AVCO)
- Settings > Decimal Accuracy > Product Price > set to 4 digits
- Purchase 3 units of Comp at 3.3333 piece & validate reception
- Make 2 sales for 1 unit of Comp each & validate both deliveries
- Create a SO for 1 Kit and 1 Comp & confirm
- Create & confirm invoice
- Go to the delivery, force quantity on the component and try to validate delivery
> Error message: "You are trying to reconcile some entries that are already reconciled."
/!\ Fun(?) fact: this error doesn't occur if the order of the moves is inverted.
Cause
-----
When the purchase delivery is validated, a stock valuation layer is created for 3 units with a value of 10. As they are sold individually, these 3 units generate a valuation layer for 3.33 per unit summing to 9.99.
When we validate the last delivery, the 0.01 difference is detected and an adjustment is made on the valuation layer in `_prepare_out_svl_vals`.
However this adjustment is made for the product when the invoice line concerns the kit. As a result, the first reconciliation fails and the line is added to the list to be reconciled later.
Then, when handling the line for COMP2, it will successfully reconcile the lines while it is still in the pool to be reconciled, resulting in an error when attempting to reconcile it later.
This is caused by `_stock_account_anglo_saxon_reconcile_valuation` where the `product_stock_moves` only contains the kit move when called with the kit product as argument, but it contains both moves when called with the component itself as argument. This leads to the same AML being reconciled twice.
https://github.com/odoo/odoo/blob/f0b9f4c234cd0101f5cb259e58620e1cf65bb2b7/addons/stock_account/models/account_move.py#L222-L225
-----
Ticket:
opw-5722072
Forward-Port-Of: odoo/odoo#258013This update resolves an issue causing the FatturaPA import in the l10n_it_edi module to fail when the related account module isn't installed. The fix duplicates key helper functions from another Odoo module to ensure compatibility and stability of the import process. This prevents crashes and ensures correct FatturaPA invoice processing.
Original PR description
The FatturaPA import in `l10n_it_edi/models/account_move.py` calls `self.env['account.edi.common']` for the partner and the bank account. That model belongs to `account_edi_ubl_cii`, which `l10n_it_edi` does not depend on. Without that module installed, the import dies with a `KeyError`. It is not correct to add that dependency. PR #254505 (`63926d9d`) introduced the two calls and removed the search-only lookups that lived there before. ### Fix Copied `account.edi.common._import_partner` to `_l10n_it_edi_import_partner` Copied `account.edi.common._import_partner_bank` to `_l10n_it_edi_import_partner_bank` Fixes: https://github.com/odoo/odoo/issues/264306
A bug in the Point of Sale system was causing automatic database maintenance to delete critical sequences, leading to temporary system unavailability. This fix ensures that the system correctly identifies and protects these sequences, preventing future disruptions to the POS functionality. The change improves system stability and reliability for our Point of Sale users.
Original PR description
The `_gc_session_sequences` method searches for sequences using Odoo's `=like` operator, which maps to SQL LIKE where `_` is a single-character wildcard. The prefix `pos.order_` (added by `pos_self_order`) therefore matched the `pos.order.line` sequence, which has no integer suffix and was never added to `keep_codes`, causing the autovacuum to delete it silently. This made POS unusable until the sequence was recreated manually. Fix by filtering the search results with `str.startswith` to retain only sequences whose code literally begins with the prefix, discarding any false positives introduced by the SQL wildcard. opw-6215331 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a technical issue impacting invoice accuracy for Mexican VAT (SAT) compliance. Specifically, it corrects rounding errors that occurred when invoices with many items had a small negative line, leading to discounts being hidden due to currency precision. This ensures invoices pass SAT validation and avoid potential compliance problems.
Original PR description
…any lines Fix SAT validation errors CFDI40111 and CFDI40108 that occur when invoices with many lines contain a small negative line, causing per-line discounts to be hidden due to currency precision. opw-6187014
1 change
Resolved issues and error corrections
This update corrects a bug where previously validated manual transactions could incorrectly be matched with new transactions. The fix ensures that manual operations are no longer suggested for matching with subsequent transactions, improving the accuracy of reconciliation processes. This resolves a potential issue with financial reporting.
Original PR description
Currently, after validating a transaction with a manual operation, the aml resulting from the manual operation can still be selected and matched with other transactions. Steps to reproduce: - Create a transaction for 500 dollars - Create a manual counterpart line for the bank statement line with label "test123" and validate - Create another transaction of -1000 dollars and label "test123" Issue: The manual counterpart line matched before is being suggested against the new transaction. The perfect match reconciliation model will reconcile the manual counterpart line with the new bank statement line. Adding test for community branch opw-6045050