Daily updates from Odoo
Wednesday, June 3, 2026
44 changes · saas-19.2
New functionality added to Odoo
This update enhances the Odoo Enterprise payroll system by allowing for more flexible adjustments to individual payslip lines. This change improves the accuracy and customization of payroll calculations for employees. The update modifies related models and views to support these new editing capabilities.
This update integrates with Cashmatic, a company providing self-service cash machines, through a new HTTP API connection. This allows Point of Sale (POS) systems to communicate with these machines for automated cash counting and dispensing, streamlining transactions. It's a key addition to support modern payment options.
Original PR description
Cashmatic is a company providing self-service cash machines, which can automatically count cash and dispense change. This commit adds basic support for Cashmatic cash machines via an HTTP REST API connection. Task-5887125 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#253585
Resolved issues and error corrections
This update resolves an issue where dropshipping orders incorrectly displayed a negative delivered quantity. The change introduced a new functionality for returns that inadvertently caused this error. The fix ensures accurate delivery quantity calculations by preventing negative values when dropshipping isn't involved.
Original PR description
Currently, an error occurs when the user receives a dropship order instead of delivering it directly to the customer. As a result, the sale order shows a negative delivered quantity. ## Steps to…
Currently, an error occurs when the user receives a dropship order instead of delivering it directly to the customer. As a result, the sale order shows a negative delivered quantity. ## Steps to replicate: - Install Sales, Inventory, and Purchase. - Enable Dropshipping from Inventory settings. - Create a test product with the Dropship route enabled and set a vendor for it in the Purchase tab. - Create and confirm a quotation for a customer. - Go to Purchase > `Deliver To:` and set it to `My Company: Receipts.` - Confirm the Purchase Order and validate the receipt. - Go back to the Sale Order. ## Observed Behavior: The delivered quantity is -1, which is incorrect because the customer has not returned any products, nor has the user created a sale order line with a negative quantity (which would indicate a return). ## Root cause: When computing the delivered quantity at [1], the function `_get_outgoing_incoming_moves` [2] is called to retrieve the incoming and outgoing stock moves associated with the sale order lines. Inside this function, moves are filtered and categorized as incoming or outgoing. At [3], the condition is satisfied because the default value of `to_refund` is `True`, so the move is added to `incoming_move_ids`. Later, during the computation at [1], the code iterates through the incoming moves and subtracts their quantities from the delivered quantity. Since the initial delivered quantity is 0, including such a move in `incoming_move_ids` causes the delivered quantity to become -1. <h3> Why did this behavior not occur in lower versions?:</h3> This issue was introduced by [commit], which added the functionality for users to return products that are not listed in the purchase order. As a result, their quantities appear as negative received quantities on the purchase order. Before this change (in saas-18.2), the field `move.to_refund` had a default value of `False`. Because of this, the condition at [3] was not satisfied, and the move was not included in `incoming_move_ids`. Therefore, it was not subtracted when iterating through incoming moves, and the delivered quantity did not become negative. Starting from 18.3, the default value of `to_refund` was changed to `True`. This causes the condition at [3] to be satisfied, the move to be included in `incoming_move_ids`, and its quantity to be subtracted during the computation, resulting in a delivered quantity of -1. [1]- https://github.com/odoo/odoo/blob/1256875226436a854558a1334ffdc886fa4767a8/addons/sale_stock/models/sale_order_line.py#L193-L209 [2]- https://github.com/odoo/odoo/blob/1256875226436a854558a1334ffdc886fa4767a8/addons/sale_stock/models/sale_order_line.py#L316-L353 [3]- https://github.com/odoo/odoo/blob/1256875226436a854558a1334ffdc886fa4767a8/addons/sale_stock/models/sale_order_line.py#L346-L351 ## Solution: We can make the condition stricter by ensuring that only incoming moves that are actual returns are counted as negative in the quantity delivered on a sale order. Specifically, if an incoming move has no corresponding originating return move and the customer has not created a sale order line with a negative quantity (which could also indicate a return), it should not be considered when calculating the delivered quantity. [commit]: https://github.com/odoo/odoo/pull/209110/changes/c1c86182e4b28e929bf56e79f57f33aaa13e67f1 opw-5933594 Forward-Port-Of: odoo/odoo#267531 Forward-Port-Of: odoo/odoo#252383
This update fixes an issue where users couldn't reliably select formatted text within a table cell. The fix simplifies the selection process by directly verifying cell boundaries, ensuring consistent and accurate cell selection across the HTML editor. This enhances the user experience when working with tables.
Original PR description
### Steps to reproduce: - create a table (e.g. /table) - type something in any cell and select that cell. - apply formatting through toolbar (bold, italic, etc.) - now select that single cell through…
### Steps to reproduce: - create a table (e.g. /table) - type something in any cell and select that cell. - apply formatting through toolbar (bold, italic, etc.) - now select that single cell through mouse. - observe that it is not selected ### Description of the issue/feature this PR addresses: - The single-cell selection logic relied on getTargetedNodes(), which collects descendants of the selection’s common ancestor. When selecting text inside inline formatting tag (e.g. `<i>`), the text node became the common ancestor, so the parent `<i>` tag was excluded from selectedNodes. As a result, check ensuring all cell elements were selected failed, preventing from being selected. ### Desired behavior after PR is merged: - Cell selection was simplified using areNodeContentsFullySelected(startTd) directly instead of manually matching targeted descendants. This relies on DOM Range to verify whether the cell boundaries are fully selected. task-6207941 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266208 Forward-Port-Of: odoo/odoo#263742
This update optimizes the styling of the Odoo Enterprise home menu by replacing inefficient CSS selectors with CSS variables. This change improves page loading speed and overall performance, leading to a smoother user experience. The update addresses a performance issue related to hover and active states.
Original PR description
Avoid selectors after `:hover` and `:active`, as they can impact performance. CSS variables are now used instead. Replace hex color values with "0 0 0" RGB syntax to ensure compatibility with CSS variable usage. Forward-Port-Of: odoo/enterprise#119082
This update resolves a bug that caused the 'Missing required fields' error when sending WhatsApp messages. The fix removes a dependency on automatic data pre-filling, ensuring the required fields are only checked when WhatsApp is enabled. This improves the user experience for sending messages via WhatsApp.
Original PR description
**Steps to reproduce** --- 1. Configure a follow-up level with a WhatsApp template with required variables. 2. On a contact open Send and Print. 3. Uncheck WhatsApp (keep Email checked) and click…
**Steps to reproduce** --- 1. Configure a follow-up level with a WhatsApp template with required variables. 2. On a contact open Send and Print. 3. Uncheck WhatsApp (keep Email checked) and click Send. **Issue** --- The wizard raises "Missing required fields" even though the WhatsApp section is hidden. The free-text inputs in the WhatsApp group of the manual reminder wizard are declared with `required="number_of_free_text >= N"` see https://github.com/odoo/enterprise/blob/17231450e90cc7465370b5fe0a138b7f93dde91c/whatsapp_account_followup/wizard/followup_manual_reminder_views.xml#L23-L33 The surrounding group hides them with `invisible="not whatsapp"`, so as soon as a WhatsApp template is loaded on the wizard the fields are required regardless of the WhatsApp toggle. This was masked until https://github.com/odoo/enterprise/commit/47369f696acd5c7e236e527deef890639017f2f1 removed the `_compute_free_text` prefill on `whatsapp.composer`: the free-text fields used to be auto-populated with each variable's demo value, so the required check was trivially satisfied. With the prefill gone the fields start empty and the latent constraint fires whenever WhatsApp is unchecked. Ticket [link](https://www.odoo.com/odoo/project.task/6227911) opw-6227911
This update resolves a technical issue preventing Viva payments in the POS kiosk. The Viva payment system requires a unique identifier for the cash register, and previously, this wasn't consistently provided. Now, the system automatically generates a valid 'cashRegisterId' based on the cashier's name, ensuring Viva payments process correctly.
Original PR description
When validating a payment in POS Kiosk with Viva payment method we get a Viva.com error Viva’s card-terminal API validates the JSON body with Pydantic and requires a non-empty ``cashRegisterId``. Steps to reproduce: ------------------- * Open POS in kiosk * Make an order and pay with Viva > Observation: Viva returns a validation error: ``cashRegisterId`` is missing or required in the request body (Pydantic ``missing`` on ``body.cashRegisterId``). Why the fix: ------------ Compute ``cashRegisterId`` in the POS client as cashier name, then ``pos.config.name`` so the value is always a non-empty string sent to ``viva_wallet_send_payment_request``. opw-6091223 Forward-Port-Of: odoo/odoo#267280 Forward-Port-Of: odoo/odoo#258605
This update resolves an issue where clicking on binary data within a list view would also open the associated record. We've implemented a change to prevent this automatic opening, ensuring users only download the desired file content. Unit tests have been added to guarantee this fix.
Original PR description
If a list view contains a field (column) with binary widget, on click it will download the content of the field. This is the intended behavior but at the same time it will, by default, open the record of which it is part, which is strange since the user only wants to download the content. With this PR we make use of .stop on the t-on-click to detach the execution of the function from the opening of the record. We also add unit tests for this. Task: 6260266 Forward-Port-Of: odoo/odoo#267197
This update fixes an issue where timesheet forms weren't loading correctly after refreshing a page. Now, when you view a timesheet entry, the correct, detailed form view is displayed, ensuring accurate data access. This improves the user experience for timesheet management.
Original PR description
…m view * Go to Timesheets > My Timesheets > switch to Grid view. * Hover over a cell with a timesheet entry and click the magnifier (search) icon. * The list opens; click a record to open its form view. * Observe the URL: `/odoo/timesheets/account.analytic.line/<id>`. * Refresh the page (F5). Before this commit, the generic form view was shown instead of the timesheet-specific form view. This occurred because, when reloading a page with a dynamic action and a resId, a generic view layout [false, "form"] was requested instead of the action-defined view. Now, the dynamic action is properly restored on refresh, ensuring the correct specific view is loaded for the form. opw-6133602 Forward-Port-Of: odoo/odoo#266369 Forward-Port-Of: odoo/odoo#265552
This update optimizes how Odoo recalculates styles in large tables, like the Accounting > Balances Sheets. By using a more targeted approach, the system now responds faster during window resizing, scrolling, and sorting, leading to a smoother user experience. This change improves overall performance and responsiveness.
Original PR description
Avoid using the :has() selector and use a specific class on the body instead to replicate the same behavior. This reduces work during the "Recalculate Style" phase (for example when hovering rows in large tables such as the Accounting > Balances Sheets). It lowers recalculation time during window resizes, heavy scrolling, and table sorting by preventing broad selector matches and limiting style checks to elements with the specific class. Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267602 Forward-Port-Of: odoo/odoo#267170
This update resolves an issue where the Documents app incorrectly displayed a duplicate PDF preview when receiving XML attachments via email. The fix ensures that the preview accurately shows the PDF content, addressing a visual inconsistency. This improvement enhances the user experience when accessing documents from email.
Original PR description
**Steps to reproduce:** - Install documents_account - Set up alias to catch incoming mails - Receive a mail with xml attachement which can be previewed as pdf - Go to Documents app - Click on the…
**Steps to reproduce:** - Install documents_account - Set up alias to catch incoming mails - Receive a mail with xml attachement which can be previewed as pdf - Go to Documents app - Click on the document preview - Preview is split in two iframes, both with the same content (pdf) **Issue:** Due to the `isPdf` patch the attachment can match multiple types for the preview (pdf and text) as both getter return `true`. ``` <iframe t-if="state.file.isPdf" ... <iframe t-if="state.file.isText" ... ``` It also seems that xml received by mail are imported as text, which is why the issue doesn't happen when manually uploading the same xml file. **Fix:** Ensure that if the document is matching `isPdf`, it doesn't trigger the second iframe with `isText`. Also it seems fixed in 19.0 as the text iframe is replaced by this xpath: `<xpath expr="//iframe[@t-if='state.file.isText']" position="replace">` which was added for https://github.com/odoo/enterprise/commit/de614ee5e9a087d49939c65c0118ae6164c7b31b related patch: https://github.com/odoo/enterprise/commit/ffcdd2275c8bf564e15151ccbcaf3965ed968450 opw-6018536 Forward-Port-Of: odoo/enterprise#118041 Forward-Port-Of: odoo/enterprise#112041
This update fixes a bug in the helpdesk rating dashboard. Previously, ratings created late in the day weren't accurately reflected in searches. The change now uses the current date and time for searching, ensuring all recent ratings are included in the dashboard view.
Original PR description
Before this commit, the ratings created the current date at 23h will not been taken into account in helpdesk rating dashboard. This commit uses datetime.now() instead of date.today() to search the ratings in the last 7 seven days. runbot-error-230905 Forward-Port-Of: odoo/enterprise#119035
This update fixes an issue where automation rules for sales orders weren't correctly assigning users to newly created activities. The change uses a more robust method to handle relationships between records, ensuring that the intended user is always associated with the activity. This improves the reliability of automated workflows.
Original PR description
Steps to reproduce: ------------------------------------ 1. Install `base_automation` and the Sales module 2. Create an automation rule for a sale order as follows: * Trigger: State set to Sale order…
Steps to reproduce:
------------------------------------
1. Install `base_automation` and the Sales module
2. Create an automation rule for a sale order as follows:
* Trigger: State set to Sale order
* Add a Create Activity action
* Change User Type to Dynamic
* Set User Field to Customer > Users
3. Create and confirm a sale order with Admin as the customer
Observation:
------------------------------------
The activity is created in Chatter, but it was not assigned to any user
Issue:
------------------------------------
The condition `self.activity_user_field_name in record` uses the `__contains__` check which only looks for direct fields on the record's model. A dotted path like 'partner_id.user_id' is not a field name on the record itself, so the check evaluated to `False`, skipping the user assignment entirely https://github.com/odoo/odoo/blob/2bafcebfaba01e46856d6eb2a440ede95b9c0a4a/addons/mail/models/ir_actions_server.py#L378-L379
Solution:
------------------------------------
Use `record.mapped()` as a fallback when the field name is not directly present on the record. `mapped()` natively supports dotted paths by traversing the relational chain (e.g. record -> partner_id -> user_id)
opw-6191715
Related Enterprise PR: https://github.com/odoo/enterprise/pull/118921
Forward-Port-Of: odoo/odoo#263530This update resolves a situation where users would receive warnings related to the Italian EDI (SdI) functionality even when it wasn't applicable. Now, the system only displays these warnings when the company is actually configured for Italian EDI processing, ensuring a cleaner user experience.
Original PR description
We shouldn't show warnings for `l10n_it_edi` if it's not possible to use it, even if the partner has its preferred EDI method set as `it_edi_xml`. Ticket [link](https://www.odoo.com/odoo/project.task/5985570) opw-5985570 Forward-Port-Of: odoo/odoo#267019
This update resolves an issue where changes made within nested editable areas of the description field weren't consistently saved. The fix replaces a specific event listener with one that correctly triggers a save when the focus leaves the editable area, ensuring all updates are recorded accurately. This improves the reliability of description updates.
Original PR description
Problem: When the selection is inside a `contenteditable="true"` element that is not the root editable, focusing away does not trigger a save. Cause: When the DOM contains a nested contenteditable…
Problem:
When the selection is inside a `contenteditable="true"` element that is not the root editable, focusing away does not trigger a save.
Cause:
When the DOM contains a nested contenteditable structure like:
```html
<div class="odoo-editor-editable" contenteditable="true">
abc
<div contenteditable="false">
ac
<div contenteditable="true">a</div>
</div>
</div>
```
With the selection inside the inner `contenteditable="true"`, the `blur` event is not triggered on `.odoo-editor-editable` when focusing away, because the active element is the inner div and `blur` does not bubble.
Solution:
Replace the `blur` listener with `focusout`, which bubbles from the inner `contenteditable="true"` up to `.odoo-editor-editable`, allowing `onBlur` to be called correctly.
Steps to reproduce:
- Open Project > Task.
- Add a `/column` block in the description.
- Focus inside any column and write some text.
- Click away to change tab.
- Reopen the description tab.
- The latest changes inside the columns were not saved.
opw-6227922
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#266367This update fixes an issue where manually added analytic distributions on purchase orders were lost when the line's account was changed. Now, when a purchase order line's account is modified, the associated analytic distribution remains intact, ensuring accurate tracking of costs. This prevents data inconsistencies and simplifies reporting.
Original PR description
__ ## Short functional explanation of the error When confirming a Purchase Order holding lines with an analytic distribution that has been manually added, and creating a vendor bill out of this PO…
__ ## Short functional explanation of the error When confirming a Purchase Order holding lines with an analytic distribution that has been manually added, and creating a vendor bill out of this PO using the Auto-Complete field. When we change the account of that line, the line loses the manually added Analytic Distribution. ## Reproduction Steps 1. Go to Accounting. Click on the tab Configuration; under the Analytic Accounting section, click on Analytic Distribution Models. 2. Create an Analytic Distribution Model for a product. 3. Go to Purchase. Create a new PO, set a Vendor and select the product you created the Analytic Distribution Model for. On the right side of the form, click on the view menu and check Analytic Distribution to make it appear. 4. Click on the Analytic Distribution of the product and add a new one; for example, select Administrative in the Departments section. 5. Confirm order. 6. Go to Accounting and click on the Vendors tab > Bills. Create a new bill, and in the field Auto-Complete, select the PO you just created. 7. Change the account of the line. ### Expected behavior Only the account should be changed on the line. ### Unexpected behavior The manually added Analytic Distribution has disappeared. ## Origin of the issue When we change the `account_id` field, the compute method `_compute_analytic_distribution` is triggered. This method retrieves the related distributions of the line: https://github.com/odoo/odoo/blob/af32885ec5f07d492f3b8e8fff1785996a739f72/addons/account/models/account_move_line.py#L1154 which, in the context of Purchase, calls this method: https://github.com/odoo/odoo/blob/af32885ec5f07d492f3b8e8fff1785996a739f72/addons/purchase/models/account_invoice.py#L540-L545 We retrieve the distribution of the related line using `self.purchase_line_id.analytic_distribution`. However, this code isn't triggered when the move line has an analytic distribution, even though the related line `purchase_line_id` might have one! Therefore, we need to execute that code whether or not our move line has an analytic distribution. Note: the same behavior is to avoid when creating invoices for quotations. __ opw-6062466 Forward-Port-Of: odoo/odoo#267274 Forward-Port-Of: odoo/odoo#258380
This update resolves an issue where currency amounts in Arabic RTL (right-to-left) views were incorrectly formatted, appearing with the minus sign positioned to the left of the currency symbol. The fix ensures that currency amounts are displayed correctly, aligning with standard left-to-right formatting in Arabic locales. This improves the user experience for Arabic-speaking users.
Original PR description
Steps to reproduce 1. Create a company with Egypt localization, currency EGP 2. On a bank journal, set Outstanding Receipt and Outstanding Payment accounts 3. Register a customer payment so the…
Steps to reproduce 1. Create a company with Egypt localization, currency EGP 2. On a bank journal, set Outstanding Receipt and Outstanding Payment accounts 3. Register a customer payment so the journal dashboard shows the Payments row with a negative amount 4. Switch the user language to Arabic 5. Open the Accounting dashboard Issue The Payments amount renders as "LE 5,000.00-" instead of "-5,000.00 LE". formatCurrency returns the string "-5,000.00 LE". In an Arabic page the leading "-" has no intrinsic direction, so the browser attaches it to the surrounding right-to-left Arabic text and visually moves it past the symbol. Sibling rows on the same dashboard render correctly because they already wrap the amount in dir="ltr", see https://github.com/odoo/odoo/blob/d0424f2ffcf99ee59befe288150f1643b3fa0112/addons/account/views/account_journal_dashboard_view.xml#L252 opw-6183749 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267582 Forward-Port-Of: odoo/odoo#266742
This update resolves a visual issue in the Gantt holiday view, specifically a problematic background color in dark mode. It also corrects a previous issue where the selection of holidays was incorrectly counting records instead of the number of selected cells, ensuring accurate holiday management.
Original PR description
- changed selected value in the view to be number of selected cells instead of number of selected records - fixed a visual bug in dark mode where the create popup has ugly background task-id: 6124765
This update corrects a recent change that unintentionally removed a styling class from all dynamic website snippets. The previous fix, intended for mono-record snippets, was too broad. This commit restores the correct styling for all dynamic snippets, ensuring consistent layout and appearance on the website.
Original PR description
Before [1], the `s_dynamic_snippet_row` class was added to all dynamic snippets using the `website.s_dynamic_snippet.grid` template and defining `columnClasses` values. In [1], a fix was introduced to prevent adding this class on mono-record snippets, as it was breaking the layout when used inside small containers (`o_container_small`). However, the condition introduced by that fix is too broad and currently removes the class from all dynamic snippets. This commit fixes the condition so that `s_dynamic_snippet_row` is only excluded from mono-record snippets, restoring the intended layout for other dynamic snippets. [1]: https://github.com/odoo/odoo/commit/fe2279f760adc6a53ba2242961f3873a5d3215dd Forward-Port-Of: odoo/odoo#265362 Forward-Port-Of: odoo/odoo#264407
This update fixes a limitation in how analytics data is managed for assets. It now allows users to simultaneously edit multiple analytics distribution values within the asset form, mirroring the functionality available for journal items. This streamlines the process of updating and analyzing asset performance data.
Original PR description
This commit fixes the multi-edit of analytics distribution field in assets form view. The multi-edit option was added to the analytics distribution widget, same as in the journal items. task-6218188 Forward-Port-Of: odoo/enterprise#119054 Forward-Port-Of: odoo/enterprise#118042
This update fixes an issue where multiple lines of text were being converted into separate code or quote blocks instead of a single block. The fix ensures that selecting multiple lines and changing the block type results in a unified code or quote block, improving the editor's functionality and consistency.
Original PR description
Steps to reproduce: - Write multiple lines of text. - Select all lines. - Change block type from Normal to Code (or Quote) via the toolbar. Description of the issue: - Notice that each line is now a separate code block (or quote). Cause: - The `setBlock` method currently converts each selected block individually into the target block type, creating multiple blocks when multiple lines are selected. Solution: - For code and quote blocks, `setBlock` now converts only the first selected block into the target type and merges the content of the other selected blocks into it, ensuring a single code/quote block. task-6068930 Forward-Port-Of: odoo/odoo#258331
This update resolves an issue where large product weights (over 150kg) in the e-commerce system caused errors when calculating shipping rates through Sendcloud. The fix ensures that the system accurately determines if multiple packages are needed and correctly processes orders with heavy items, improving order fulfillment reliability.
Original PR description
Issue ----- Traceback when trying to get a rate through the e-commerce if the order has to be split into multiple packages due to weight being too high. Steps to reproduce ----- - Setup Sendcloud…
Issue ----- Traceback when trying to get a rate through the e-commerce if the order has to be split into multiple packages due to weight being too high. Steps to reproduce ----- - Setup Sendcloud delivery method - make it available in e-commerce - Create a 150kg product and publish it - Go to e-commerce - Add the product to cart - Checkout the cart > Traceback Cause ----- We retrieve the order's weight through the context. https://github.com/odoo/enterprise/blob/d9a9339e1f30f1e5cc37ebb88949451a6652f83b/delivery_sendcloud/models/delivery_carrier.py#L108 If the call to `_get_shipping_rate` returns that the delivery requires multiple packages, we go into https://github.com/odoo/enterprise/blob/d9a9339e1f30f1e5cc37ebb88949451a6652f83b/delivery_sendcloud/models/delivery_carrier.py#L126-L128 If `order_weight` was not present in the context, this will cause an error in `sendcloud_convert_weight` since it expects a numerical value but receives the `None` fallback. This context key is only present when going through `choose.delivery.carrier` (so not in the e-commerce flow). https://github.com/odoo/odoo/blob/058e640e6687ed3f709dc846f0fa7a1f45226849/addons/delivery/wizard/choose_delivery_carrier.py#L69 ----- Ticket: opw-6210398 Forward-Port-Of: odoo/enterprise#119048 Forward-Port-Of: odoo/enterprise#117028
This update resolves a technical error that occurred when PL companies attempted to pay non-VAT PL suppliers with invoices exceeding 15,000 PLN. The fix prevents unnecessary verification processes, ensuring smoother payment processing for these suppliers. This improves the reliability of the bank verification system.
Original PR description
[FIX] l10n_pl_bank_verification: PL Supplier no VAT When a PL supplier has no VAT and a PL company tries to pay him a bill above 15.000 PLN, there is a traceback. The reason is that there was no check for partner with no VAT, a verification was created every time the field was compute. Forward-Port-Of: odoo/odoo#266878
This update strengthens Odoo.com's subscription verification process by adding a check for duplicated SAAS databases that have been neutralized. Previously, test databases could incorrectly pass subscription checks, leading to potential issues. This change ensures accurate subscription validation for all Odoo.com users.
Original PR description
Odoo.com does not create a distinction between a production and duplicated SAAS database. This allows test databases to pass the check for subscription. This commit adds an additional check for duplicated SAAS databases with a neutralised status. task-6249752 Forward-Port-Of: odoo/enterprise#118281
This update resolves an issue where importing Peppol XML invoices through newly created purchase journals (using only the Invoicing app) fails due to a missing default account. The fix automatically assigns a default account, mirroring the behavior for bank/cash journals, ensuring successful invoice imports.
Original PR description
When a user installs only the Invoicing app and creates a new purchase journal, no default_account_id is set on the journal. The Invoicing app does not expose account configuration, so the user…
When a user installs only the Invoicing app and creates a new purchase journal, no default_account_id is set on the journal. The Invoicing app does not expose account configuration, so the user cannot fix this manually. As a result, importing a Peppol XML invoice through that journal fails with a database constraint error because the generated account.move.line has a null account_id. https://github.com/odoo/odoo/blob/16245530f0e3e9be21c8b96baaecd3a679420cac/addons/account/models/account_journal.py#L776-L805 This already auto-creates accounts for bank/cash journals, but does nothing for sale/purchase journals. Steps to reproduce: - Install the Invoicing app (no full Accounting) - Create a new purchase journal with type 'purchase' - Go to Vendors -> Bills and Upload a Peppol XML file - Error importing attachment as invoice (decoder=_import_invoice_ubl_cii) Ticket [link](https://www.odoo.com/odoo/action-4043/6014363) opw-6014363 Forward-Port-Of: odoo/odoo#267552 Forward-Port-Of: odoo/odoo#252859
This update corrects a formatting problem in invoices generated when 'Hide composition' is enabled. Previously, columns after the description were misaligned, causing a visually incorrect invoice PDF. This fix ensures invoices are displayed correctly for German companies using the l10n_din5008 module.
Original PR description
| Before | After | |--------|--------| | <img width="1573" height="830" alt="image" src="https://github.com/user-attachments/assets/1960b51b-5c3e-4560-bd09-a20adfe2b381" /> | <img width="1573" height="830" alt="image" src="https://github.com/user-attachments/assets/565d0238-a295-44b7-bdaa-e7c6dd1200cf" /> | Steps to reproduce ================== - Install l10n_din5008,l10n_de - Use a german company - Go to settings - Enable "Show Position Column in Reports" - Go to Invoicing > Sales > New - Add a new section - Click on the three dots - Check "Hide composition" - Add a new line with a product - Confirm the Journal Entry - Print the Invoice PDF => Every column after the description is offset by one opw-5427590 Forward-Port-Of: odoo/odoo#261527
This pull request resolves an error preventing CFDI (Mexican tax) documents from being generated correctly when an employee has an IMSS disability. The fix adds the required 'Incapacidades' node to the XML, accurately reflecting disability time off and ensuring compliance with Mexican law. This prevents validation failures and ensures accurate tax reporting.
Original PR description
Several error are logged in the chatter when signing a payslip that includes an IMSS disability time off. Steps to reproduce: * Install l10n_mx_hr_payroll_account modules * Switch to "INNOVACION…
Several error are logged in the chatter when signing a payslip that includes an IMSS disability time off.
Steps to reproduce:
* Install l10n_mx_hr_payroll_account modules
* Switch to "INNOVACION VALOR Y DESARROLLO SA SA" company
* Go to Employees and open Cesar Osbaldo Cruz Solorzano
* Click on "Time Off" smart button and create a new time off with "Disability due to illness (IMSS)" type for "02/01/2026"(Any date).
* Go to Payroll > Payslips > Payslips and create a new pay run
* Select Salary Structure 'Mexico: Regular Pay', Pay Schedule 'Monthly' and the Period '01/01/2026 -> 01/31/2026'
* Click on Continue, select Cesar and click on Select
* Open the payslip, click on "Validate" and "Ok"
* Mark as paid, open the "Journal Entry" from the smart button and click on "Post".
* Back to the payslip, and click on "Generate CFDI" button.
* An error is added to the chatter.
### Missing node to declare disabilities
Original message
```py
An error occurred while signing the CFDI document with the government:
Code : NOM111 Message : Error no clasificado. Extra Info : El nodo
"Incapacidades" se debera informar si se incluye en percepciones la
clave 014 "Subsidios por Incapacidad" o bien en deducciones la clave 006
"Descuento por incapacidad".
```
Translated message
```py
An error occurred while signing the CFDI document with the government:
Code: NOM111 Message: Unclassified error. Extra Info: The "Incapacidades"
(Disabilities) node must be reported if the perception key 014
"Subsidios por Incapacidad" (Disability Subsidies) is included, or if
the deduction key 006 "Descuento por incapacidad" (Disability Deduction)
is included.
```
Legal Context:
According to Mexican law, IMSS disabilities must be declared in a specific XML node.
There are two primary scenarios for reporting these amounts:
* Deduction (Type 006): The employer does not pay for these days, as the IMSS is responsible for the payment to the employee.
This is the most common scenario.
* Perception (Type 014): The employer pays for these days as a superior benefit. For example, by law, the IMSS does not pay for the first 3 days of a disability due to illness, and employers are not obligated to cover them either. However, companies offering superior benefits may choose to pay these days as a "Disability Subsidy."
Solution:
The chosen approach is to configure the Deduction node.
For the `l10n_mx_regular_pay_imss_disabilities` rule, the `l10n_mx_concept` has been set to `l10n_mx_concept_d6` (D06 - Disability Deduction). This ensures the required node is added.
### Missing "ImporteMonetario" attribute
Original message
```
An error occurred while signing the CFDI document with the government:
Code : NOM95 Message : El atributo Deduccion:Importe no es igual a la
suma de los nodos Incapacidad:ImporteMonetario, ya que la clave
expresada en Nomina.Deducciones.Deduccion.TipoDeduccion es "006".
```
Translated message
```
An error occurred while signing the CFDI document with the government:
Code: NOM95 Message: The attribute "Deduccion:Importe" does not match
the sum of the "Incapacidad:ImporteMonetario" nodes, as the key
expressed in "Nomina.Deducciones.Deduccion.TipoDeduccion" is "006".
```
Problem:
The "Incapacidades" node requires the "ImporteMonetario" attribute, which should represent the sum of the monetary value associated with the disabilities.
Solution:
Add the "ImporteMonetario" attribute and calculate its value using `l10n_mx_daily_salary`.
### Invalid "DiasIncapacidad" format
```py
An error occurred while signing the CFDI document with the government:
Code : 301 Message : XML mal formado Extra Info : Element
'{[http://www.sat.gob.mx/nomina12}Incapacidad](http://www.sat.gob.mx/nomina12%7DIncapacidad)', attribute
'DiasIncapacidad': '4.0' is not a valid value of the local atomic type.
```
Problem:
Altough the defaultdict where the values are sum up, `number_of_days` is
a float field, and when we get back the value, it is a float, adding for
example 4.0 instead of 4, which is not a valid value.
Solution:
Cast the value to int.
### Duplicate deduction on disabilities
```py
Wrong python code defined for:
- Employee: Cesar Osbaldo Cruz Solorzano
- Version: False
- Payslip: Salary Slip - Cesar Osbaldo Cruz Solorzano - 05/01/2026 - 05/15/2026
- Salary rule: ISR (Income Tax) (ISR)
- Error: TypeError('cannot unpack non-iterable NoneType object') while
evaluating
"
def find_rates(x, rates):
for low, high, fix, rate in rates:
if low <= x <= high:
return low, high, fix, rate
gross = categories['GROSS']
result = 0
if gross:
isr_table = payslip._rule_parameter('l10n_mx_isr_tables')[version.schedule_pay]
low, high, fix, rate = find_rates(gross, isr_table)
result = -((gross - low) * rate + fix)
period_factor = payslip._rule_parameter('l10n_mx_schedule_table')[version.schedule_pay]
if period_factor >= 15:
period_factor = (period_factor / 30) * (365 / 12)
min_wage = payslip._rule_parameter('l10n_mx_daily_min_wage') * period_factor
if gross <= min_wage:
result_qty = 0.0
"
```
Problem:
The IMSS disability amount is being deducted twice:
1. During "Worked Days" calculation, the IMSS disability is already not considered because the work entries belong to the "Unpaid Work Entry Types" of "Mexico: Regular Pay" structure.
2. During "Salary Computation", the `IMSS_DISABLE` salary rule deducts another time because it is in the `TAXABLE_ALW` category, and this one is deducted in the `NET` rule.
When the disability covers more than half of the period (e.g., 20 days in a monthly schedule), the double deduction causes the NET to become negative. This prevents the ISR rule from finding a correct stage in the tax tables, leading to a traceback.
Example: For a monthly wage of 30,000.0 and 5 disability days:
- The total amount in "Worked Days" is 25,000.0 (disabilities already deducted).
- The IMSS_DISABLE rule calculates -5,000.0, and when the NET rule is calculated, the disabilities are deducted again. Total NET becomes 16,843.84 instead of the expected 20,834.85.
Solution:
Change the rule category to `INTERMEDIARY_COMPUTATION` and avoid the double deduction when the `NET` is calculated, as it is already considered in the "Worked Days".
### Incorrect values in the XML
The signing process completes without errors, but some amounts in the generated XML are incorrect.
Problem:
The introduction of the Deduction 006 (Disability) directly impacts the calculation of the SubTotal and Total attributes in the Comprobante node.
For a monthly payslip with a wage of 30,000.00 (daily salary of 1,000.00) and 5 disability days (work risk), the values are calculated incorrectly as follows:
Attribute | Calculation | Actual Value | Correct Value
---------------------|----------------------------------|--------------|--------------
Comprobante:SubTotal | Sum of Perceptions (P01) | 25000.00 | 30000.00 (1)
Comprobante:Total | SubTotal - Total Deductions (2) | 15803.74 | 20803.74
(1) Must include the 5,000.00 from disabilities to balance the deduction.
(2) Total Deductions = D06 (5,000.00) + ISR (3,451.65) + IMSS (744.61) = 9,196.26.
The Total is currently undercalculated because the 5,000.00 is being
deducted from the SubTotal that already had those 5,000.00 excluded.
Solution:
Since the `SubTotal` is derived from Perceptions, and the "(P01)
Salaries, Wages, Stripes, and Day Labor" amount is driven by the
`GROSS_WITHOUT_HOLIDAY` rule, the disability amount must be added. This
balances the Deduction 006, ensuring `SubTotal` is correct.
### Absenteeism and Disabilities
By law, the calculation of IMSS contributions depends on these two types of unpaid days:
* Disabilities: Refers to medical leave issued by the Institute (IMSS).
* Absenteeism: Refers to unjustified leave; apply for periods of fewer than 8 days.
Source: [Artículo 31](https://www.imss.gob.mx/sites/all/statics/pdf/leyes/LSS.pdf)
Translated text:
Article 31. When wages are not paid due to the employee's absence from work, but the employment relationship persists, the monthly contribution shall be adjusted according to the following rules:
I. If the employee's absences are for periods of fewer than eight consecutive or non-consecutive days, contributions shall be calculated and paid for such periods only for the sickness and maternity insurance...
If the employee's absences are for periods of eight consecutive days or more, the employer shall be released from the payment of employer-employee contributions...
IV. In the case of absences covered by medical disabilities issued by the Institute, it shall not be mandatory to cover the employer-employee contributions, except regarding the retirement branch.
The following table summarizes the contribution requirements based on the type of absence:
Insurance Branch (RAMA) | Section I (Absenteeism) | Section IV (Disability)
--------------------------------|-------------------------|------------------------
Sickness and Maternity | Paid | Not Paid
Disability and Life | Not Paid | Not Paid
Severance and Old Age | Not Paid | Not Paid
Work Risk | Not Paid | Not Paid
Daycare and Social Benefits | Not Paid | Not Paid
INFONAVIT | Not Paid | Paid
Retirement | Not Paid | Paid
The type of unpaid day to be considered depends on the specific insurance branch being calculated within the employer-employee contributions.
### Add test for cfdi with disabilities.
target: 19.0
task-6066160
Forward-Port-Of: odoo/enterprise#116819This update ensures that file uploads initiated through the link popover are immediately canceled when the user discards the popover. Previously, uploads continued in the background even after the discard button was pressed, leading to potential data inconsistencies. This change improves the user experience by preventing unexpected uploads.
Original PR description
**Current behavior before PR:** Steps to reproduce the issue: - Go to Todo, In the network tab switch to "Slow 4G" so that file upload can take few seconds to upload. - Upload a file using link popover. - While the file upload is in progress, hit the discard button of the link popover. - Notice that the upload continues in the background and when it completes successfully, link is inserted. **Desired behavior after PR is merged:** Discarding the link popover during file upload should cancel the upload request and prevent inserting the link. task-6199113 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267611 Forward-Port-Of: odoo/odoo#263463
This update fixes an issue where the project template dropdown in demo mode had a cluttered appearance, making it difficult to read. The fix removed a styling element that caused text to overlap, ensuring a clean and consistent display for all users.
Original PR description
Steps to reproduce: == Login as demo/onboarding user Open Project app Click on New Observe the template dropdown list Issue: == The template dropdown items are rendered with collapsed row height and poor vertical spacing in demo mode, making the list hard to read. Cause: == The template dropdown items utilized the `pe-0` utility class, which removed the padding at the end of the element. For non-admin users this caused the template name to touch the right edge of the container. Fix: == Removed the `pe-0` from the `DropdownItem` to restore standard right-side padding, and ensure consistent and readable row heights for both Admin and Demo users. task-5338191 Forward-Port-Of: odoo/enterprise#104440
This update resolves an issue where time off requests with the 'Both' approval type didn't send notifications to the designated responsible parties (e.g., Time Off Officer). The fix ensures that notifications are correctly sent, streamlining the approval process and preventing delays. This improves the reliability of the HR leave management system.
Original PR description
…cer') no fallback for responsible_ids
Issue:
When ('both','By Employee's Approver and Time Off Officer') is selected on a new HR Leave Type it does not fall back to the responsible_ids or “Notify HR”.
Steps:
1) Setup a neutralized outgoing mail server
2) install hr_holidays
3) make a new hr.leave.Type (Approval) with ('both','By Employee's Approver and Time Off Officer') and select a 'Notified Time Off Officer'(responsible_ids) 4) select an emplyee with a reelated user and remove the coach, manager, and responsible 'Time Off'. 5) save
6) Sign in as the employee, make a time off request under the new Type 7) No email
Fix:
Add a conditional with the lowest priority to fall back to responsible_ids
opw-6101637
Forward-Port-Of: odoo/odoo#265075
Forward-Port-Of: odoo/odoo#261853This update fixes an issue where purchase bills were created in the company's default currency, regardless of the original purchase order's currency. Now, bills automatically inherit the currency from the corresponding purchase order, ensuring accurate financial reporting and reducing potential discrepancies. This improves the reliability of our accounting processes.
Original PR description
**Steps to reproduce:** - create a storable product - confirm a PO in another currency than the main for this product - click on the "bill matching" smart button - select only the purchase order line from your PO - click on match **Current behavior:** this creates on Bill in the main currency **Expected behavior:** the currency should be inherited from the POL **Cause of the issue:** Inside action_match_lines() if there is no amls selected we call _action_create_bill_from_po_lines(). https://github.com/odoo/odoo/blob/e3b0ca11d99b2ef819cdad68b169112cd73668b6/addons/purchase/models/purchase_bill_line_match.py#L157 Inside this method, there's currently no mechanism to take the currency from the POL when we create the bill. **fix:** If multiple different other currencies we take the main currency of the company opw-6131314 Forward-Port-Of: odoo/odoo#266013
This update ensures that duplicated website pages accurately reflect the most current content, regardless of the user's language setting. Previously, duplication didn't account for 'delayed translations,' leading to outdated versions. Now, the system correctly uses the latest translation data for duplicated pages.
Original PR description
**Steps to Reproduce:** 1. Configure the website default language different from the user’s current language. 2. Go to Website → Site → Pages. 3. Duplicate an existing page. 4. Edit the duplicated…
**Steps to Reproduce:**
1. Configure the website default language different from the user’s current language.
2. Go to Website → Site → Pages.
3. Duplicate an existing page.
4. Edit the duplicated page and save the changes.
5. Duplicate the edited page again.
6. Observe that the newly duplicated page is generated from the original page content instead of the updated duplicated page.
**Issue:**
When duplicating a website page, the website default language was not passed in the context. As a result, the duplication was performed using the active user language.
The root cause is that `copy()` does not simply duplicate the existing `arch_db` translation dictionary. Instead, it copies the field value in the current language and then rebuilds all translations through `copy_translations()`.
This behavior becomes problematic when `delayed translations` are involved. After a page is modified in a non-default language, the latest changes may be stored in a delayed translation entry (`_{lang}`) while the regular translation value remains unchanged. During the copy process, these delayed translation entries are intentionally discarded because they are considered temporary data and are not treated as valid language translations.
As a result, when the page is duplicated from a non-default language, `copy()` rebuilds the translations using an outdated translation value instead of the most recent content stored in the delayed translation. The newly
duplicated page therefore does not accurately reflect the current state of the source page.
**Solution:**
The fix enables `check_translation=True` during page duplication so that the copy operation uses the latest translation state, including delayed translations when available. This ensures duplicated pages are generated
from the most recent version of the source page and keeps translated content consistent across languages.
**opw-5914281**
Forward-Port-Of: odoo/odoo#264656A recent test within the HR Holidays module failed due to an error in how it checked for recordsets with multiple records. This commit corrected the code to avoid this issue, preventing test failures when other modules are installed. This ensures the HR Holidays tests run reliably.
Original PR description
Before this commit, the line https://github.com/odoo/odoo/blob/saas-19.1/addons/hr_holidays/tests/test_holidays_mail.py#L69 used `.id` on a many to many recordset which failed when the recordset had multiple records. This test led to an error when installing other modules with demo data like `test_l10n_be_hr_payroll_account` and the test was run with demo data. This commit uses the `in` operator instead of `==` and avoids `employee_ids.id` to avoid the error. Runbot error: https://runbot.odoo.com/odoo/error/241106 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266677
This update fixes an issue where the cursor position was incorrect after moving content within the HTML editor. Now, when moving a table or paragraph, the cursor automatically adjusts to the beginning of the moved item, preserving the user's selection if it was within the moved content.
Original PR description
#### Description of the issue/feature this PR addresses: - MoveNode restores the cursor at the container end position - After moving a table, the cursor ends outside the table body #### Desired behavior after PR is merged: - Preserve the selection if it was inside the moved node - Otherwise place the cursor at the start of the moved node #### Steps to reproduce: - Create a table in the editor - Move the table using Movenode - Drop the table and check the cursor position - The cursor ends outside the moved table body - Select some text in a paragraph - Move that paragraph using Movenode - The selection is placed at the end of the moved node task-6215743 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267549 Forward-Port-Of: odoo/odoo#264264
This update corrects a flaw in how Odoo tracks device status (supported/unsupported). Previously, changes weren't consistently reflected in the database when a device switched between states. Now, device status changes are tracked separately, ensuring accurate database updates and preventing issues with device recognition.
Original PR description
When a device is marked unsupported (e.g. FDM after power outage) and becomes supported with the same identifier (e.g. FDM after the client restarts it after the power outage), the changed was not taken into account because we used to track changes in a set of supported + unsupported. We now track changes in supported and unsupported separately to make sure the db is informed of the changes.
This update resolves an issue where users without employee access rights couldn't search for timesheet versions. The change removes a restriction on accessing version fields, ensuring broader search functionality while maintaining security through a previously implemented bypass mechanism. This improves usability for all users.
Original PR description
Issue: ---------------------------------------- When searching for a field from `hr.version` without any rights on Employees, we get an access error. Steps to reproduce:…
Issue: ---------------------------------------- When searching for a field from `hr.version` without any rights on Employees, we get an access error. Steps to reproduce: ---------------------------------------- - Timesheet > To Validate > All timesheet - Filter on Employee > Department (is set for example) - An error pops up Cause: ---------------------------------------- The field `department_id` of `hr.employee` belongs to `hr.version` and is accessible through the `_inherits` and the field `version_id`. When doing the search above, during the optimization of the domain, we end up trying to read `department_id` on `hr.employee.version_id`. But the field `hr.employee.version_id` is not accessible to users without Employee access rights. They only have rights on the field `hr.employee.current_version_id`. This occurs from version saas-19.1 because the access check was added in this version. ([commit](https://github.com/odoo/odoo/commit/aa58663a271e24a1fcb3f59e6bddfac50054703c)) Solution: ---------------------------------------- We remove the group restriction on `version_id`. The group restrictions are done with the fields of `hr.version`. As `version_id` is only a computed field from `current_version_id` which has `bypass_search_access=True`, this should not expose any field that wasn't already. `bypass_search_access=True` was added on `current_version_id` for the same reason. ([src](https://github.com/odoo/odoo/commit/94bb4a29189400d6bd0c2ca97eba271601262e1b)) opw-6149198 opw-6251866 Forward-Port-Of: odoo/odoo#264953
This update fixes an issue where the duration of calendar events created via drag-and-drop wasn't accurately reflected in the full event form. Previously, the duration was stuck with the initial drag value. Now, the full form correctly displays the updated duration based on the user's final time selection, ensuring accurate event scheduling.
Original PR description
When creating a calendar event by dragging on the calendar view, modifying the end time in the quick-create popover, and then clicking "More Options", the duration shown in the full form is the…
When creating a calendar event by dragging on the calendar view, modifying the end time in the quick-create popover, and then clicking "More Options", the duration shown in the full form is the original drag value instead of the value implied by the user's updated stop. calendar's makeContextDefaults seeds default_start, default_stop, default_duration, and default_allday from the drag extent. In the quick-create popover, changing stop triggers _compute_duration on that record so its duration becomes correct. On "More Options", goToFullEvent extracts a whitelist of fields from the quick-create record as default_X and merges them with the original drag context. https://github.com/odoo/odoo/blob/c82341c503ac/addons/calendar/static/src/views/calendar_form/calendar_quick_create.js#L9-L19 duration is missing from that whitelist, so the merged context still carries the stale default_duration from the drag. In the full form, that default is applied to the duration field and _compute_duration does not run because a default was provided for a stored, writable field. Adding duration to the whitelist forwards the quick-create's recomputed value as default_duration so the full form opens with the correct duration. Steps to reproduce: 1. Open Calendar, drag to create a 2-hour event (e.g. 10:00-12:00) 2. In the quick-create popover, change the end time to 14:00 3. Click "More Options" 4. Check the Duration field in the full form => Duration shows the original drag value (02:00) instead of 04:00 opw-6087449 Forward-Port-Of: odoo/odoo#257294
This update fixes an issue where group allocations with past start dates incorrectly showed zero accrual amounts. The change ensures that accrual calculations are properly triggered when group allocations are created, regardless of the start date, ensuring accurate time-off tracking. This improves the reliability of the group allocation feature.
Original PR description
Problem ------------------ When creating group allocations, when the allocation type is accrual and the start date is set in the past, the newly created allocations have the accrual amounts at 0. To…
Problem ------------------ When creating group allocations, when the allocation type is accrual and the start date is set in the past, the newly created allocations have the accrual amounts at 0. To reproduce: 1. Create an accrual plan with an easily measurable milestone (e.g. 1 day every day) 2. From the allocations view -> New Group Allocation 3. Enter the following values: Grant -> By Employee Employees -> select your employee Time Off Type -> Paid Time Off (doesn't matter too much) Allocation Type -> Based on Accrual Plan Validity Period -> any date a few days in the past (Personally I tested with 1/1/2025 and no end date) Allocation -> Keep at 0 Allocate Time Off 4. Go to the newly created allocation The allocation amount is 0. Reason ---------------------- When creating group allocations, the `hr.leave.allocation.generate.multi.wizard` calls the `_process_accrual_plans()` method to compute the accruals, but when the allocations are created, the nextcall and lastcall fields are set, so the accruals are not computed and the scheduled action also does nothing until the nextcall date. The onchange method manually sets the nextcall date to False so the accruals are processed. Solution ------------------ Created a method to get the fields that need to be set to calculate the initial accrual amounts from the start date, which is called both in the onchange and to batch write in the wizard before accrual plans are processed. The wizard checks the duration values before overwriting the number_of_days field, since user manually setting the amount should overwrite the calculations. task-4938695 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#267305 Forward-Port-Of: odoo/odoo#265783
This update ensures that mass mailing background colors remain consistent across emails, even after website color palettes are updated. Previously, changes to primary colors would cause emails to display the new color, but this fix removes the conflicting class, guaranteeing the designed color is always used. This improves email consistency and brand alignment.
Original PR description
When a mass mailing block uses a `bg-o-color-N` theme color class, the mailing's `body_arch` stores the class and `convert_inline` correctly inlines the resolved color into `body_html`, matching the…
When a mass mailing block uses a `bg-o-color-N` theme color class, the mailing's `body_arch` stores the class and `convert_inline` correctly inlines the resolved color into `body_html`, matching the website palette at save time. The class also stays on the element in `body_html`. The stylesheet rule that gives `bg-o-color-N` its color is declared with `!important`. When the website palette is later rebuilt (any change to the primary colors), the new `bg-o-color-N` rule wins over the inline color whenever `body_html` is rendered. So an already-sent mailing reopened in the backend shows the new palette's color instead of the one that was picked, and resaving the mailing bakes that new color into `body_html`. `classToStyle` already does the right thing for the property value. What was missing is dropping the class itself from `body_html` once its style has been inlined, so no future `!important` palette rule can override the inline color. `body_arch` keeps the class, so the editor preview stays theme-aware while editing, but `body_html` is now stable across palette rebuilds. Steps to reproduce: 1. Open Email Marketing and create a new mailing using the Welcome Message template 2. Select a content block, open Customize, set the background to the 5th theme color 3. Save the mailing 4. Open the Website editor and change the 5th primary color to a different value 5. Reopen the saved mailing in the backend => the block's rendered background follows the new website color instead of the one picked at design time Ticket [link](https://www.odoo.com/odoo/project.task/5892350) opw-5892350 Forward-Port-Of: odoo/odoo#267570 Forward-Port-Of: odoo/odoo#253934
This update fixes a bug preventing the 'NABN' document type from being used for GT vendor credit notes. Previously, this option was restricted to regular vendor bills. Now, users can correctly select 'NABN' when reversing a GT credit note, ensuring accurate electronic payment processing according to local regulations.
Original PR description
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Navigate to Invoicing > Vendors > Bills. - Create a new vendor bill. - Observe that `GT Document Type`…
**Steps to reproduce:** - Install the `l10n_gt_edi` module and switch to a `GT Company`. - Navigate to Invoicing > Vendors > Bills. - Create a new vendor bill. - Observe that `GT Document Type` includes `NABN - Nota de Pago Electrónica` option. - `Confirm` the bill. - Click `Credit Note`, add a reason, and click `Reverse`. - Observe the available options in the `GT Document Type` field. **Observation:** The `NABN - Nota de Pago Electrónica` option is not available for vendor credit notes (`in_refund`), even though `NABN` is a GT-specific credit note document type. **Root Cause:** At [1], `NABN` is added for vendor bills (`in_invoice`, `in_receipt`) instead of vendor credit notes (`in_refund`). **Fix:** This commit ensures users can correctly select `NABN - Nota de Pago Electrónica` on GT vendor credit notes. [1]: https://github.com/odoo/enterprise/blob/c7fa8c9c6f6830f5702fab4f6efaf3ac33f7fe72/l10n_gt_edi/models/account_move.py#L159-L160 opw-6252256 Forward-Port-Of: odoo/enterprise#119215 Forward-Port-Of: odoo/enterprise#118711
This update fixes a previous limitation where channel owners without system admin privileges couldn't promote members to admin roles. The change ensures that channel owners can now correctly assign admin access, improving channel management capabilities. This resolves a usability issue for channel administrators.
Original PR description
`canSetAdmin` was checking the target member role instead of the current user's role. Because of that, a channel owner who was not a system admin could not promote another member to admin. task-6250058 Forward-Port-Of: odoo/odoo#266615
This update fixes an issue where EDI invoices were incorrectly assigned to individual contacts due to shared VAT numbers. The change prioritizes main companies and active vendors during matching, ensuring invoices are routed to the correct business entity. This improves data accuracy and reduces manual intervention in invoice processing.
Original PR description
### Description of the issue/feature this PR addresses: **Issue:** When processing incoming EDI/Peppol invoices, multiple contacts (parent companies, joint ventures, child contacts) frequently share…
### Description of the issue/feature this PR addresses: **Issue:** When processing incoming EDI/Peppol invoices, multiple contacts (parent companies, joint ventures, child contacts) frequently share the same VAT number. Because the parser's tie-breaker relies primarily on VAT, invoices are often incorrectly assigned to individual child contacts or newly created joint ventures rather than the correct vendor. **Solution:** Prepend is_company DESC, supplier_rank DESC to the SQL search order in the _import_retrieve_customer fallback domain. This ensures that the matching logic explicitly prioritizes business entities over individual contacts, and active vendors over other records. ### Current behavior before PR: When searching by VAT with limit=1, the parser uses order='company_id, parent_id DESC, id DESC'. If a parent company and a child contact share a VAT, the query frequently returns the child contact or a newer joint venture due to the id DESC fallback. ### Desired behavior after PR is merged: The parser will correctly prioritize main companies over individual contacts when VAT numbers are shared. If multiple companies share the same VAT, the most active vendor will be selected. opw-6174628 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#266224
This update fixes a technical issue in Odoo related to Python 3.14's garbage collection. Specifically, it prevented a runtime error that occurred when copying data structures using an `OrderedSet`. The change utilizes a more reliable copying method to avoid conflicts with the garbage collector, ensuring data integrity.
Original PR description
In Python 3.14, iterating over weak references (like `transaction.envs`) can trigger a `RuntimeError: dictionary changed size during iteration`. This happens mostly because the Garbage Collector can remove a weakref while `OrderedSet.copy()` is rebuilding the set via `dict.fromkeys()`. Instead of re-initializing the set by iterating over its elements, we now directly use the dictionary's native `.copy()` method. This atomic operation prevents the GC from modifying the size of the underlying `_map` during the copy. Forward-Port-Of: odoo/odoo#267947
Features or functions removed from Odoo
This update removes a reference to 'Peppol' from the French Payroll (l10n_fr_pdp) module. This change simplifies the configuration process and aligns with current regulatory requirements for French businesses. It ensures clarity and avoids potential confusion for users.
Original PR description
task-None Forward-Port-Of: odoo/odoo#267650