Monday, January 12, 2026
25 changes · saas-19.1
Enhancements to existing features
This update modifies the chart of accounts for Odoo's Vietnamese localization to align with new accounting regulations (Circular 99/2025). These changes are necessary to ensure compliance with current Vietnamese tax laws, taking effect in January 2026. This update impacts financial reporting for Vietnamese businesses using the Odoo system.
Original PR description
Update the COA for the vietnamese localization, which is based on the circular 200/2014 by the new one based on the circular 99/2025. This new COA applies starting in Jan. 2026 task-5357470 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#243078 Forward-Port-Of: odoo/odoo#238983
This update modifies the chart of accounts for Odoo's Vietnamese localization to align with recent accounting regulations (Circular 99/2025). This change is necessary to ensure compliance with updated Vietnamese accounting standards, effective January 2026. It impacts financial reporting within the Vietnamese Odoo implementation.
Original PR description
Update the COA for the vietnamese localization, which is based on the circular 200/2014 by the new one based on the circular 99/2025. This new COA applies starting in Jan. 2026 task-5357470 Forward-Port-Of: odoo/enterprise#103823 Forward-Port-Of: odoo/enterprise#102843
This update enhances the way Odoo fetches invoices from Nilvera. Previously, only recent documents were retrieved, but now the system supports pagination and resuming interrupted downloads, ensuring all invoices are fetched in the correct order and without duplication. This improves data accuracy and efficiency.
Original PR description
Nilvera returns documents in pages of 30 items and, when no date range is provided, only returns documents created within the last week. As a result, _l10n_tr_nilvera_get_documents only processed the first page of recent documents. This commit introduces a full pagination and incremental-fetching mechanism: - Provide explicit StartDate and EndDate parameters. - Store the last successfully fetched CreatedDate per company in an ir.config_parameter to allow resuming after interruptions. - Fetch pages in ascending CreationDateTime order. This ensures all documents are fetched, in order, without duplication and without reprocessing previously downloaded data. task-5186428 Forward-Port-Of: odoo/odoo#239536
This update optimizes the calculation of work time in Odoo's payroll system. Previously, the same calculation was performed repeatedly, leading to slower processing times. This change eliminates redundant calculations, resulting in a performance improvement.
Original PR description
Before the work time was calculated inside a for loop of worked_days, because this function can be called and is usually called by all worked_day_line_ids of a payslip, the same calculation is done multiple times.
This update streamlines the process for importing product data across key Odoo modules like Sales, Purchase, and Inventory. The product import template and download button have been updated, ensuring a smoother experience for users updating their product information.
Original PR description
This commit updates the product import template and the button to download it. The change impacts all products 'import data' views such as the ones in Sales, Purchase, Inventory and Accounting. part of task-4874693 task-4925525
This update enhances the ‘Looking for Help’ sidebar by displaying the live chat conversation description alongside the visitor’s name. This allows support agents to quickly understand the context of conversations, leading to faster and more efficient customer support. The change improves agent workflow and customer experience.
Original PR description
*= im_livechat **Purpose of this PR:** Before this PR, the discuss sidebar only showed the visitor’s name, making it difficult to know the context of a conversation without opening it. This PR displays the livechat conversation description in the sidebar so agents can quickly understand the context of a conversation. Before/After: <img width="321" height="120" alt="image" src="https://github.com/user-attachments/assets/b3ce2a84-96cf-49e7-9c31-2c078f3859d5" /> <img width="330" height="125" alt="image" src="https://github.com/user-attachments/assets/d4a9aa0a-d827-4b43-ba72-0fa8e2d45eb4" /> task-5404924
Resolved issues and error corrections
This update strengthens the security of our Point of Sale (POS) system by ensuring that data is accessed securely. Previously, unauthorized access attempts could cause errors and crashes. Now, the system checks permissions before reading POS data, preventing disruptions and improving stability.
Original PR description
**: pos_hr Before this commit: --- - POS data was read directly from records without validating read access. - This could raise `AccessError` when the user lacked permissions, breaking POS data loading. After this commit: --- - Check read access on records before calling `read`. - Prevent POS crashes caused by unauthorized model reads. runbot-231708 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#226421
This update corrects a bug that caused automatic balancing lines to be added to journal entries for company-paid expenses. The fix ensures that tax calculations are handled correctly when creating these expense reports, preventing inaccurate accounting entries. This improves the reliability of expense tracking for company-paid expenses.
Original PR description
Changing the analytic account on the journal entry generated by a company-paid expense creates an unwanted auto-balancing line. ## Steps to reproduce 1. Create an expense paid by the company. 2.…
Changing the analytic account on the journal entry generated by a company-paid expense creates an unwanted auto-balancing line. ## Steps to reproduce 1. Create an expense paid by the company. 2. Confirm and generate the expense report. 3. Reset the expense’s journal entry to draft and add an analytic account on the first line. → An auto-balancing line is added to the entry, and the remaining lines are incorrectly debited. ## Cause For company-paid expenses, the generated journal entry represents a *payment* rather than an *invoice*. In `_prepare_product_base_line_for_taxes_computation`, this causes the method to use `product_line_amount_currency` as the price unit, which excludes taxes. However, in `hr_expense`, the same method always defines `special_mode['total_included'] = False`. This combination leads `_get_tax_details` to call `_eval_tax_amount_price_included` instead of `_eval_tax_amount_price_excluded`, reapplying the tax on the lines. As a result, the move becomes unbalanced and Odoo generates an auto-balancing line to compensate. ## Solution Keep the special mode as *total excluded* for payments generated by company-paid expenses, since their tax and product lines are already handled separately in the corresponding `account.move`. **opw-5166707** --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#243052 Forward-Port-Of: odoo/odoo#233841
This update fixes an issue where the barcode app on mobile devices displayed stock locations in a list view, which wasn't ideal for small screens. The change prioritizes a more user-friendly kanban view for mobile, ensuring product information is easily accessible on smaller devices.
Original PR description
Issue ===== On mobile, we should prioritize kanban views over list views because kanban views are usually more suitable for small device screen. That said, when a product's barcode is scanned in the Barcode app main menu, we show this product's stock locations but we do that with a list view, no matter if the user is on a big screen or a small screen. How to reproduce ================ On mobile device: - Enable location and have a product with a barcode and with quantities in two different locations; - Open Barcode app; - Scan the product's barcode => The product's stock locations are displayed in a list view, which is not very pratical on small device. Fix === The action key `mobile_view_mode` was not set, with this key, we can define what view type we want to prioritize for mobile device. [opw-5180783](https://www.odoo.com/odoo/project/49/tasks/5180783) Forward-Port-Of: odoo/enterprise#101957 Forward-Port-Of: odoo/enterprise#101336
This update fixes a potential issue where invoices generated from sales orders didn't always align with the correct fiscal partner information. Now, invoices use the invoice partner's details, ensuring consistent fiscal calculations across sales orders and their corresponding invoices. This improves accuracy and avoids discrepancies in financial reporting.
Original PR description
## Before this commit Fiscal position on Sale Orders was computed based on `partner_id` and `partner_shipping_id`. However, during invoice creation from a Sale Order, We uses `partner_invoice_id` as the invoice’s `partner_id`. This mismatch caused fiscal inconsistencies between the Sale Order and the generated Invoice in certain edge cases. ## After this commit Fiscal position is now computed using `partner_invoice_id` to ensure that both the Sale Order and its Invoice use the same fiscal partner reference. This aligns fiscal determination across documents and avoids inconsistencies in scenarios where the invoice partner differs from the order’s main or shipping partner. opw-5367523 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#239806
This update resolves issues that could lead to data inconsistencies when uninstalling the 'mail' module. Specifically, it ensures that model and field definitions are properly cleaned up during uninstallation and adds warnings to alert developers to potential problems with deleted records.
Original PR description
This fixes two overrides of `unlink()` that break when module `mail` is being uninstalled. It also fixes the uninstalling system to comply to the spec of the `ondelete` decorator. ### Add warnings…
This fixes two overrides of `unlink()` that break when module `mail` is being uninstalled.
It also fixes the uninstalling system to comply to the spec of the `ondelete` decorator.
### Add warnings when some model/field could not be deleted
The uninstallation process tries to delete all the records created by the modules being uninstalled. It uses a best-effort strategy, i.e., it skips the records that cannot be deleted, whatever the reason. But some records are very likely to cause problems, namely `ir.model` and `ir.model.fields` records, because skipping them implies not cleaning up their corresponding table's schema.
For instance, if a column is not dropped, reinstalling the corresponding module will possibly cause inconsistencies, because
- the column contains old values for existing records, which won't be recomputed (if the field is computed);
- the column contains NULLs for records created between the uninstallation and the reinstallation of the module.
We therefore add a warning in those cases, in order to detect and fix those potential issues as soon as possible.
### Make ondelete decorator work as documented
A method decorated with `@api.ondelete(at_uninstall=False)` should be called except when the method's module is being uninstalled. Currently the method is skipped when *any* module is uninstalled.
The fix consists in adding the set of modules being uninstalled in the attribute `registry.uninstalling_modules`, which may be used to detect uninstallation and determine which modules are being uninstalled.
### Replace MODULE_UNINSTALL_FLAG by new conventional flag 'force_delete'
We turn constant `MODULE_UNINSTALL_FLAG` into an explicit conventional flag, and rename it `force_delete` for the sake of simplicity. The idea is to decouple the flag from uninstallation. The caller simply uses
```py
records.with_context(force_delete=True).unlink()
```
to bypass some deletion hooks, which typically prevent deletion by raising some exception, in order to avoid data inconsistencies. On the callee's side, one has to explicitly detect the flag and skip the checks, like in:
```py
@api.ondelete(at_uninstall=False)
def _prevent_deleting_confirmed(self):
if self.env.context.get('force_delete'):
return
if any(record.state == 'confirm' for record in self):
raise UserError(_("You cannot delete confirmed records!"))
```
Note that the uninstallation process uses the convention by automatically adding `force_delete=True` in the `context` for deleting records.
### Fix issue module mail uninstallation
Two overrides of `unlink()` on models `ir.model` and `ir.model.fields` fail when uninstalling module "mail", because their code relies on some columns and those columns have been dropped already. This causes some table and column to remain after uninstallation. When reinstalling module "mail", errors like follows are logged:
```
column "mail_message_id" of relation "mail_tracking_value" contains null values
```
The fix consists in turning the overrides in proper "ondelete" methods, which are skipped when module "mail" is uninstalled.
https://github.com/odoo/enterprise/pull/103651This update resolves an issue where pressing "Enter" in a form containing a Kanban-displayed x2many field would cause the system to crash. The fix ensures the Kanban renderer handles optional properties correctly, preventing errors and improving form stability. This ensures a smoother user experience when working with related records.
Original PR description
Be in a form view containing an x2many field displayed as a kanban view. Press "Enter". Before this commit, it crashed, because the kanban renderer tried to access it's `quickCreateState` props which was undefined. The props is indeed optional, so we must be careful when reading/using it. Issue introduced by https://github.com/odoo/odoo/pull/228632 Spotted by task~5441808 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a bug impacting how absences are tracked within the HR Attendance module. The fix ensures accurate recording and reporting of employee absences, improving the reliability of attendance data. This change primarily affects the HR Attendance and HR Holidays Attendance modules.
Original PR description
Task: 5470030 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#242567
This update prevents users from creating new POS sessions when multiple online payment methods are linked to a single POS configuration. Previously, a workaround involving deleting payment methods was required. Now, a constraint ensures only one online payment method can be associated with a POS config, improving session stability.
Original PR description
Task: [#5420237](https://www.odoo.com/odoo/project/1737/tasks/5420237) --- There is a constraint on the `pos.config` model that prevents opening a POS session when multiple online payment methods are…
Task: [#5420237](https://www.odoo.com/odoo/project/1737/tasks/5420237) --- There is a constraint on the `pos.config` model that prevents opening a POS session when multiple online payment methods are configured for the same POS config. However, from the `pos.payment.method` model, it is still possible to add multiple online payment methods to a single POS config, which then prevents opening a session. In addition, if a session is already open, it is no longer possible to resolve the situation: * From `pos.payment.method`: the POS session must be closed before removing the POS config from an online payment method. * From `pos.config`: the payment methods field is read-only when there is an open session. We had to delete one of the online payment methods from the database directly to be able to open the POS session again. To prevent this inconsistent state, a constraint is added on `pos.payment.method` to ensure that each POS config has at most one online payment method. Forward-Port-Of: odoo/odoo#240343
This update addresses several issues impacting the accuracy of the social balance sheet calculations for Belgian payroll. Specifically, the system now correctly handles employees without certificates, avoids double-counting, and prevents incorrect gender checks on payslipless employees. These fixes ensure more reliable reporting for HR and accounting teams.
Original PR description
Forward-Port-Of: odoo/enterprise#103786
This update resolves an issue with how hourly wages are calculated, ensuring greater accuracy for payroll processing, particularly for employees with variable working schedules. The changes also eliminate a technical dependency issue that previously caused unexpected validation errors when managing offers.
Original PR description
- All percentage fields now use self.env.remove_to_compute to break circular dependencies, so UIs no longer need the ad-hoc skip_percentage_calc context. - _l10n_in_get_montly_wage now derives monthly hours from the version’s or its company’s resource calendar via hours/week previously it was static to 22 days. - fix raises validation when opening offer after changing working schedule it raise validation error which isn't expected behaviour. task-5421228 Forward-Port-Of: odoo/enterprise#102488
This update fixes a technical issue that caused users to see confusing tracebacks when errors occurred during the ZATCA onboarding process. Now, users receive clear, user-friendly alerts with the actual error message returned by ZATCA, improving the onboarding experience and ensuring compliance.
Original PR description
Whenever an error occurs during the ZATCA onboarding steps—such as providing a company name that exceeds 127 bytes in binary representation (for example, 64 Arabic characters without whitespace…
Whenever an error occurs during the ZATCA onboarding steps—such as providing a company name that exceeds 127 bytes in binary representation (for example, 64 Arabic characters without whitespace result in exactly 127 bytes; see refs [1] and [2])—the system returns a traceback to the user instead of a clear and user-friendly error message. Error: `TypeError: argument should be a bytes-like object or ASCII string, not 'NoneType' This is due to the check-in `_l10n_sa_request_production_csid` for an 'error' key, not present in the response when an OTP is invalid because in these cases, the `_l10n_sa_call_api` returns the response_data directly. This fix improves the behaviour by displaying a user-friendly alert message with the error returned by ZATCA, instead of a traceback. This ensures a better experience and compliance with CCSID onboarding flows. [1]: https://zatca1.discourse.group/t/organization-name-is-too-long-issue-csr/7571 [2]: https://zatca1.discourse.group/t/organisation-name-with-restriction-of-64-characters/960 sentry-7169834710 Forward-Port-Of: odoo/odoo#242810
This update corrects a bug where the FAIA XML reports generated for l10n_lu companies with products having multiple taxes were missing a crucial element, `TaxBase`. This change ensures compliance with Luxembourg tax reporting requirements and prevents potential reporting errors. The fix impacts the generation of General Ledger → FAIA XML reports.
Original PR description
### Issue: The `TaxBase` element was missing in the generated FAIA XML, although it is required when a product line has multiple taxes ### Steps to reproduce: - Use a l10n_lu company - Create an invoice with a product line that has two taxes - Download the General Ledger → FAIA XML report - Observe that `TaxBase` is not included before the TaxBaseDescription element ### Specs & reference: FAIA v2.01 (full) XSD files: https://pfi.public.lu/dam-assets/backup/FAIA/FAIA/XSD_Files.zip opw-5360519 Forward-Port-Of: odoo/enterprise#103862 Forward-Port-Of: odoo/enterprise#101178
This update fixes an issue where cancelling a backorder MO also incorrectly cancelled related 'post -> stock' pickings in multi-step production routes. The change ensures that pickings are only cancelled if no MOs have been completed, preventing unnecessary disruption to inventory management. This improves the reliability of the production process.
Original PR description
Issue ----- For multi step routes, cancelling the backorder MO also cancels the (post -> stock) picking for the produced quantity. Steps to reproduce ----- - Activate routes - Go to the main warehouse and activate 3 step production - Creation of a MO for 100 units - Validate the pre production picking - Produce 40 units and create a backorder for remaining quantity - Cancel the backorder > The "post -> stock" picking is cancelled as well Cause ----- The picking is in "ready" state, so it gets cancelled by https://github.com/odoo/odoo/blob/083d53c688a0d18a1f4594b9fcbbfa738aa5e86d/addons/mrp/models/mrp_production.py#L1743-L1744 Desired behaviour ----- > Only cancel related MO pickings (pre prod/post prod) if no MO (or MOs) done yet. Don't cancel related MO pickings if any MO validated. ----- Ticket: opw-5405024 Forward-Port-Of: odoo/odoo#242969 Forward-Port-Of: odoo/odoo#239865
This update resolves an issue that previously prevented users from creating attendance records when the 'Planning' work entry source was selected. The fix corrects errors related to date and time calculations during attendance creation, ensuring accurate attendance tracking when using the planning feature. This improves the reliability of the attendance management process.
Original PR description
Currently, an error occurs when user creates an attendance with Planning as the Work Entry Source. **Steps to…
Currently, an error occurs when user creates an attendance with Planning as the Work Entry Source. **Steps to Reproduce([Video](https://drive.google.com/file/d/1vGIZswZ-0D_ISAKn8LltYlGgQ7gzI6oA/view)):** - Install the `hr_work_entry_planning_attendance` module. - Go to `Employees` and create a `new employee` or open an `existing one`. - In the `Payroll` section, set `Work Entry Source` to `Planning`. - Go to `Planning` and create a planning slot for this employee `(if it does not exist)` with `Allocated Time` set to less than 100%. - Go to `Attendance` and create `an attendance for this employee` within the planning slot start and end dates. **Error 1:** `AttributeError: 'method_descriptor' object has no attribute 'min'` **Error 2:** `TypeError: Intervals.__init__() takes from 1 to 2 positional arguments but 4 were given` **Cause:** When the Work Entry Source is set to Planning and an attendance is created for that employee, the system updates overtime (if any) and retrieves the scheduled working time from the planning slot. If the planning slot has less than 100% allocated time, it is split day by day, keeping only a portion of each day’s working hours based on the allocation percentage. While creating a datetime at the very start or end of a day, an error occurs due to incorrect access of the min or max attribute from datetime. Another issue occurs when creating intervals using the start and end dates: an error is raised because separate start and stop arguments are passed instead of a list of interval tuples. **Fix:** This commit ensures that the correct datetime.min.time() / datetime.max.time() values are used and that intervals are provided in a list-of-tuples format. [1]- https://github.com/odoo/enterprise/blob/ee8919530ef5835d539b3ade47fa450f736b22a3/hr_work_entry_planning_attendance/models/hr_employee.py#L56-L57 [2]- https://github.com/odoo/enterprise/blob/ee8919530ef5835d539b3ade47fa450f736b22a3/hr_work_entry_planning_attendance/models/hr_employee.py#L60 **No Task ID** Forward-Port-Of: odoo/enterprise#103662
This update fixes an issue where the Helpdesk return wizard incorrectly defaulted to internal 'PICK' operations instead of the correct 'OUT' operation for multi-step deliveries. The fix ensures the wizard now selects the final, customer-facing 'OUT' operation, streamlining the return process and improving data accuracy.
Original PR description
Steps to reproduce: - 1. Configure a warehouse for multi-step delivery (e.g., Pick + Ship). 2. Create a Sales Order for a product and fully process the delivery, including all steps. 3. Create a…
Steps to reproduce: - 1. Configure a warehouse for multi-step delivery (e.g., Pick + Ship). 2. Create a Sales Order for a product and fully process the delivery, including all steps. 3. Create a Helpdesk ticket for that customer. 4. From the ticket, click the "Return" button to open the wizard and select the sales order. Issue: - The return wizard incorrectly defaults to the first operation in the delivery chain (e.g., the internal 'PICK' operation) instead of the final, customer-facing 'OUT' operation. Cause: - Since picking is ordered by 'priority, scheduled_date asc, id desc', records are sorted by scheduled_date, this often resulted in selecting an internal 'PICK' operation instead of the final 'OUT' operation, making a more specific filter necessary. Fix: - The code now explicitly filters for pickings with the type code 'outgoing' and sets it as the default delivery order. task-4948134 Forward-Port-Of: odoo/enterprise#103883 Forward-Port-Of: odoo/enterprise#93154
This update resolves an issue where changing a commission plan's effective dates would erase associated targets and forecasts. Now, the system correctly checks if new dates are within the plan's range and removes outdated targets, ensuring accurate reporting and planning. This improves the reliability of commission calculations.
Original PR description
Before this commit, changing the Effective Period of a Commission Plan was erasing all the targets and forecast linked to that plan. After this commit, this is no longer the case as we compare if the new targets are within the range and delete the out-of-period targets. task-5469817 Forward-Port-Of: odoo/enterprise#103363
This update fixes an issue where users could hide a channel during an active call. The change prevents this action from appearing, ensuring channels remain visible and accessible throughout ongoing conversations. This improves the user experience and prevents disruption during calls.
Original PR description
Purpose: When a call is active in a channel, the “Hide until new message” action is still available, which does not make sense since the channel should remain visible throughout the call. This commit hides the “Hide until new message” action from the action list when an active call is ongoing, preventing users from hiding the channel mid-call. task-5469844
This update fixes a display issue where the customer order total incorrectly showed prices excluding taxes. The change ensures that the customer display always shows the total price including taxes, aligning with the main PoS product display. It also provides a more detailed breakdown of prices – subtotal and taxes – for better transparency.
Original PR description
Steps to reproduce ------------------ 1. In PoS settings, set the "Tax Display" to "Tax-Excluded Price" 2. Enable customer display 3. Open a PoS session, and open the customer display simultaneously…
Steps to reproduce ------------------ 1. In PoS settings, set the "Tax Display" to "Tax-Excluded Price" 2. Enable customer display 3. Open a PoS session, and open the customer display simultaneously 4. Add products, notice that the total in PoS is price included as expected. However, the total in cusromer display is tax excluded, so customer thinks he will be pay less. Why it happens ---------------- In the refactors done in 9538698f13d5763b4, we mistakenly set the order.amount (i.e. total amount) to follow the config "Tax Display". However, that price should always be tax incl. In this PR, we now use the `currencyDisplayPriceIncl` getter, instead of the config dependent `currencyDisplayPrice`. Additional enhancements ------------------------- In additional to total price, we also display the taxes amount not. And In case of "Tax-Excluded" price config, also display the subtotal (total price excluded). **That follows exactly the UI of the main cart in the products page**. So now we have ---------------- Tax included: <img width="558" height="659" alt="image" src="https://github.com/user-attachments/assets/51415c5c-2234-48dd-a974-572a6b090714" /> Tax excluded: <img width="550" height="661" alt="image" src="https://github.com/user-attachments/assets/2c664716-49ab-44eb-bb30-ad42206bc849" /> opw-5401560 Forward-Port-Of: odoo/odoo#239250
This update corrects a calculation error in the Belgian payroll module (l10n_be_hr_payroll) related to the 3000 deduction. The change ensures that the deduction amount accurately reflects the latest tax regulations up to the year 2026, improving payroll accuracy for Belgian users. This is a critical fix to ensure compliance with local tax laws.
Original PR description
Forward-Port-Of: odoo/enterprise#103891 Forward-Port-Of: odoo/enterprise#103824