Daily updates from Odoo
Wednesday, August 5, 2026
51 changes · saas-19.1
New functionality added to Odoo
Adds support for Romania’s Declarația 390 EC Sales report, enabling Romanian businesses to prepare the required monthly EU cross-border transaction declaration in Odoo. The new module generates the ANAF-required XML export and collects declarant details needed for electronic filing, while also improving audit results for EC Sales reports using tax tags.
Original PR description
This commit introduces a new module, 'Romania - EC Sales D390 Report'. For the support of Declarația 390 report as an EC List report for Romania in stable versions. Romanian localization has…
This commit introduces a new module, 'Romania - EC Sales D390 Report'.
For the support of Declarația 390 report as an EC List report for Romania in
stable versions.
Romanian localization has different requirements for the
EC Sales List report. So the generic EC Sales List does not work in the case of
Romania.
LEGAL REQUIREMENTS:
- Romanian tax authority accepts the Declarația 390 (Form 390) report for
cross-border transactions within the European Union.
- This declaration is filed on a monthly basis.
- The declaration must be submitted electronically to ANAF by the 25th of the
month following the month in which the transactions occurred. For example,
the declaration for transactions made in July must be filed by August 25th.
- The declaration must include all the intra-community transactions. These
transactions include:
1. Intra-Community acquisition of Goods
2. Intra-Community acquisition of Services
3. Intra-Community triangular trades
4. Intra-Community supplies of Goods
5. Intra-Community supplies of Services
REQUIRED FORMAT:
- Declarația 390 must be submitted electronically in a specific XML format.
The structure of this XML file is defined by ANAF.
- To facilitate compliance, ANAF provides a free software application called
'DUKIntegrator'. This tool allows businesses to:
1. Validate the generated XML file against the official schema to ensure it is
correctly formatted.
2. Generate the final PDF file with the XML attachment, which is the official
format for submission.
TECHNICAL DETAILS:
- Implemented the tax returns for the D390 EC Sales List report filing.
- Implemented XML export file generator, which creates the whole D390 XML report
with the required schema format.
- The D390 report needs to have the declarant's details in the report, the
attributes like 'nume_declar(Middle Name)', 'prenume_declar(First Name)',
'functie_declar(Job Position)' and 'adresa(Fiscal Domicile Address)'.
For collecting these details, we've created a wizard that will be on the
return validation action. Along with these details, we ask the user if the
current return is the corrected/rectified one, with the 'corrective_declaration'
field in this wizard. This wizard will then store these details in the
respective return. And in the XML export file generator, we are retrieving
these details from the return to show in the report.
REFERENCES:
- Drive link for official XML report schema, report structure, 'DUKIntegrator'
software and XML report attribute explanation in English: (
https://drive.google.com/drive/folders/1uzROZAM5Vuiv0HlBXw-vU28x5a9sVOpb)
- Official ANAF sources for D390 report: (
https://static.anaf.ro/static/10/Anaf/Declaratii_R/390.html)
- Official ANAF website for Electronic Declaration: (
https://www.anaf.ro/anaf/internet/ANAF/servicii_online/declaratii_electronice)Enhancements to existing features
Large SEPA direct debit batches now validate more quickly by reducing repeated system work during mandate checks and customer pre-notification emails. This improves processing reliability for high-volume payment runs, including cases that previously risked timing out.
Original PR description
- Replace the `id:recordset` aggregation in `_get_expiry_date_per_mandate()` with `date:max` to compute the latest payment date directly in SQL. - Render `email_from` for all payments in batch and cache the computed authors by sender email to avoid repeated partner lookups during SDD pre-notification. This reduces ORM/cache overhead when validating large SEPA batches containing thousands of payments. Measured on a production-sized database: | metric | before | after | factor | |--------|-------:|------:|-------:| | `_get_expiry_date_per_mandate` (500 payments) | 564 ms | 111 ms | ~5x | | `_send_after_validation` notification (500 payments) | 92.9 s | 55.7 s | ~1.7x | | `_get_expiry_date_per_mandate` (1000 payments) | 890 ms | 178 ms | ~5x | | `_send_after_validation` notification (1000 payments) | timed out (>159 s) | 108.9 s | completed | OPW-6377340 Forward-Port-Of: odoo/enterprise#126429 Forward-Port-Of: odoo/enterprise#125439
This update backports expanded test coverage and supporting tools for Marketing Automation, including checks for message failures, bounces, campaign enrollment, and scheduled synchronization behavior. It helps reduce the risk of regressions in automated campaigns, especially when participant synchronization or message delivery encounters errors.
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Add new tests for synchronization cron behavior, notably in case of failure. Forward-Port-Of: odoo/enterprise#126334
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: -
Original PR description
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites…
Before this commit, expect.waitForSteps and expect.waitForErrors gave 2 seconds, less than the 3 seconds of the DOM waits sitting next to them, on the same page and the same RPCs. Over 340 call sites in addons tests reach waitForSteps and not one of them passes an explicit timeout, so 2 seconds is what every step wait gets. The problem is that the RPC chain a step wait sits on takes longer than that on a loaded machine. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds. Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the steps are in, so it only delays the report of a test that was going to fail anyway. This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test. Companion of https://github.com/odoo/odoo/pull/279983 to fix https://runbot.odoo.com/odoo/error/944188 kind of issues. Forward-Port-Of: odoo/odoo#279984
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951
Original PR description
The feature was never merged on IAP/Internal's side and we now have a new task to move the setting up of the auto-refill from the local db to the IAP server, so the feature is no longer relevant on the client side. Task-6397951
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
Original PR description
Backport various tests added in Odoo 19.4+ in order to better spot potential regressions. Forward-Port-Of: odoo/odoo#279677
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and /discuss/channel/messages. Measured from openDiscuss resolving to the message being in the DOM: - 250 to 460ms on an idle machine; - 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a busy runbot looks like, 3 of the 10 over 2 seconds; - 1474 to 6912ms with the CPU throttl
Original PR description
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and…
Before this commit, contains() and its variants gave the client 3 seconds, and the bus helpers 2 seconds. The problem is that the first wait after openDiscuss pays for the whole mount, /mail/data and /discuss/channel/messages. Measured from openDiscuss resolving to the message being in the DOM:
- 250 to 460ms on an idle machine;
- 867 to 5258ms over 10 runs with the CPU throttled 4x, which is what a
busy runbot looks like, 3 of the 10 over 2 seconds;
- 1474 to 6912ms with the CPU throttled 6x, 5 of 6 over 3 seconds.
"Reactions are ordered by id" fails 1 run in 60 at 4x for that reason.
Note that a longer timeout costs nothing on a green build: the timer is cleared as soon as the element is there, so it only delays the report of a test that was going to fail anyway.
This commit raises both to 10 seconds, the delay a tour step already gets in macro.js. test_js.py runs the presets with timeout=15000, so hoot fails the test itself at 15 seconds and 10 leaves room for the rest of the test.
This should also close most of the open runbot errors shaped like:
Failed to find x of "..." (Timeout of 3 seconds). Found 0 instead.
The element does show up in those, just after the wait gave up.
https://runbot.odoo.com/odoo/error/944188
web companion https://github.com/odoo/odoo/pull/279984
Forward-Port-Of: odoo/odoo#280400
Forward-Port-Of: odoo/odoo#279983Comply with new provincial fiscal transparency regulations (CABA, Entre Ríos, Chubut, and other provinces still not defined) that mandate detailing Perception IIBB taxes on B2C invoices (Factura/Invoice B): - Some jurisdictions mandate a new description for IIBB perception taxes on the invoice, - We need to put the IIBB perception taxes in the special "Fiscal Transparency Regime" table, and exclude them from the standard tax table, task-6367087 Forward-Port-Of: odoo/odoo#278729 Forwar
Original PR description
Comply with new provincial fiscal transparency regulations (CABA, Entre Ríos, Chubut, and other provinces still not defined) that mandate detailing Perception IIBB taxes on B2C invoices (Factura/Invoice B): - Some jurisdictions mandate a new description for IIBB perception taxes on the invoice, - We need to put the IIBB perception taxes in the special "Fiscal Transparency Regime" table, and exclude them from the standard tax table, task-6367087 Forward-Port-Of: odoo/odoo#278729 Forward-Port-Of: odoo/odoo#277673
Resolved issues and error corrections
Date and datetime fields now disappear from the pivot setup popup once all available time options have already been used. This prevents users from adding duplicates, avoiding confusing drag-and-drop behavior and keeping spreadsheet pivot configuration consistent.
Original PR description
Current behavior before PR: - Date and datetime fields remained visible even when all their granularities were already added to the pivot. - Users could add the same field with the same granularity multiple times, creating duplicate IDs and causing unexpected drag and drop behavior. Desired behavior after PR is merged: - Hide date and datetime fields from the popup once all available granularities have already been added to the pivot. - This prevents duplicate field IDs and keeps the popup behavior consistent with spreadsheet pivots during drag-and-drop. Task: [6295794](https://www.odoo.com/odoo/project/2328/tasks/6295794) Forward-Port-Of: odoo/enterprise#123280
Cancelled Mexican CFDI invoices now keep showing their required fiscal information when reprinted, including QR codes, digital stamps, and fiscal folios. This ensures businesses can provide legally relevant invoice copies even after cancellation.
Original PR description
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR…
### Issue before this commit: When an invoice's CFDI cancellation request is confirmed (state moves from sent to cancel), reprinting the invoice PDF no longer displays the fiscal information (QR code, digital stamps, fiscal folio/UUID, etc.), even though the signed CFDI attachment is still present on the invoice. ### Steps to reproduce the issue: 1. Download Accounting and l10n_mx 2. Create an invoice and send it to CFDI 3. Select 'Request for cancel' 4. Wait and click retry button in the CFDI tab until the invoice is marked as cancelled 5. Print the invoice again 6. See PDF does not show fiscal information (QR, fiscal folio, etc.) ### Cause of the issue: https://github.com/odoo/enterprise/blob/f6c94d4ca3ef4211a5ab00bf0b39f6a7675c8f79/l10n_mx_edi/models/account_move.py#L904-L909 Once the CFDI is cancelled, the computed field switches to 'cancel', so the condition fails and the method falls back to the generic account.report_invoice_document template, which has no knowledge of CFDI fiscal fields. ### Reason to introduce the fix: A cancelled CFDI invoice is still a legally relevant fiscal document in Mexico and must be reprintable with its fiscal data intact (to prove it was issued and later cancelled). The fix extends the condition to also cover the 'cancel' state, ensuring the CFDI-specific report template is used whenever a valid attachment exists, regardless of whether the CFDI is currently signed or cancelled. opw-6393656 Forward-Port-Of: odoo/enterprise#126466
Peruvian electronic invoices now calculate prepaid amounts consistently when down payments include withholding tax. This prevents mismatched XML totals and avoids references to cancelled down payment invoices, reducing rejection risk during electronic invoicing.
Original PR description
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with…
### Issue: When an invoice has a down payment on a line with a withholding tax, the `PrepaidPayment/PaidAmount` in the UBL XML included the withholding tax amount, causing a mismatch with `LegalMonetaryTotal/PrepaidAmount` which correctly excludes it ### Cause: `PrepaidPayment/PaidAmount` was set directly from `prepayment_move.amount_total`, which includes all taxes `LegalMonetaryTotal/PrepaidAmount` uses `_aggregate_base_line_tax_details` to exclude withholding taxes, but this was not applied to the `PrepaidPayment` node ### Fix: Using `prepayment_move.amount_total` directly includes all taxes and does not match the rounding logic of `LegalMonetaryTotal` Instead, `_aggregate_base_line_tax_details` is used with the same `total_grouping_function` as `LegalMonetaryTotal`, ensuring both nodes use the same rounding logic and exclude withholding taxes Reversed down payment moves are also excluded from `AdditionalDocumentReference` to avoid referencing cancelled invoices ### Steps to reproduce: - Install `l10n_pe_edi` and `sale_management` with demo data - Switch to the PE company - Create and confirm a Sale Order (Customer: PE Company, Product: Any, Unit Price: 200, Taxes: VAT 18% and 3% IGV Withholding) - Create, confirm and pay a Down Payment Invoice (Fixed: 28.92) - Go back to the SO and create the Regular Invoice - Confirm it and click Process Now - Open the EDI Document tab and download the XML Before the fix, the sum of `PrepaidPayment/PaidAmount` did not match `LegalMonetaryTotal/PrepaidAmount` opw-6273903 Forward-Port-Of: odoo/enterprise#121733
The self-ordering test flow now matches the current behavior where takeaway is selected automatically when it is the only option. This keeps validation reliable without changing the customer-facing ordering experience.
Original PR description
In this commit: - The takeaway preset is now automatically selected when it is the only available option. Remove the explicit "Takeaway" selection step from the tour to match the updated behavior. Task:6217791 Community PR : https://github.com/odoo/odoo/pull/274301 Forward-Port-Of: odoo/enterprise#122979
International shipments through Sendcloud DPD can now include the customer's tax number in the customs details required by the carrier. This prevents validation errors caused by missing or translated VAT information and adds fallbacks for required customs fields.
Original PR description
### This is a revision of #119399 which had to be reverted. Original issue ----- Deliveries cannot be validated using DPD with Sendcloud, users get an error. Steps to reproduce ----- - Set up…
### This is a revision of #119399 which had to be reverted. Original issue ----- Deliveries cannot be validated using DPD with Sendcloud, users get an error. Steps to reproduce ----- - Set up Sendcloud DPD - Create a SO - Interntional customer - Some VAT number - Some product - Add sendcloud delivery - Confirm SO - Validate the linked picking > Error: “The receiver VAT number is missing; please provide it to continue” Issue's cause ----- Tax numbers should be included in the `customs_information` field of the request as per the API https://sendcloud.dev/api/v2/parcels/create-a-parcel-or-parcels#body-one-of-0-parcel-customs-information-tax-numbers For the `vat_label` field, we have to force the language to English in the context because the field is translated by default, but sendcloud only accepts the english names (eg French "TVA" is not accepted, expected value is "VAT"). https://github.com/odoo/odoo/blob/d1d1610332a1596d026fb0a42ec236d1a79c71cc/odoo/addons/base/models/res_country.py#L75 Revert cause ----- The vat_label field is marked for translation (translate=True) https://github.com/odoo/odoo/blob/d1d1610332a1596d026fb0a42ec236d1a79c71cc/odoo/addons/base/models/res_country.py#L75 So if the user has the DB in french for example, we are sending "TVA" instead of "VAT" in the name field. Other issues ----- - We need to provide an actual fallback for `customs_invoice_nr`. As it stands, if we create a new delivery it cannot be validated because Sendcloud doesn't accept for the field to be empty. - Same for `name`, we need to provide an actual fallback. ----- Ticket: opw-6250860 Forward-Port-Of: odoo/enterprise#124245
AI chat now stays usable when users navigate to areas such as Shopfloor where view switcher information is not available. This prevents an error when sending a message, reducing interruption for users who keep the AI chat open while moving between apps.
Original PR description
### Issue When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.…
### Issue
When AI chat is used in views where `config.viewSwitcherEntries` is not initialized, sending a message raises a `TypeError` because the code attempts to call `.map()` on an undefined value.
### Steps to Reproduce
[Video](https://drive.google.com/file/d/1i7kWDnmv4mebGtf1to12BNHCG5omBTXl/view?usp=sharing)
1. Click the **Ask AI** button.
2. Open the AI chat.
3. Keep it open and navigate to the **Shopfloor** app.
4. Send a message in the AI chat.
### Error
```text
TypeError: Cannot read properties of undefined (reading 'map')
at WithSearch.getCurrentViewInfo
```
### Fix
Safely handle cases where `config.viewSwitcherEntries` is undefined by using optional chaining and falling back to an empty array.
**Before**
```js
result.available_view_types = config.viewSwitcherEntries.map((v) => v.type);
```
**After**
```js
result.available_view_types =
config.viewSwitcherEntries?.map((v) => v.type) || [];
```
opw-6414684
Forward-Port-Of: odoo/enterprise#125821Users can now duplicate several maintenance requests at the same time without the system showing an error. This makes bulk maintenance work smoother and avoids interruptions when managing manufacturing-related maintenance requests.
Original PR description
Currently, when a user attempts to duplicate multiple maintenance requests simultaneously, the system throws a ValueError (Expected singleton). This PR fixes that. ### How to reproduce the issue: - Install `mrp_maintenance` module; - Open maintenance request list view; - Select multiple records and try to duplicate them using the Action button; - It will throw a traceback stating a singleton error. ### Expected behavior after PR is merged: Now multiple maintenance requests will be copied without raising any errors. Forward-Port-Of: odoo/enterprise#124255
Bank reconciliation now keeps the right settings even when users open the page directly from a bookmark or copied URL. This ensures matching rules can still reconcile transactions automatically and synchronized bank journals no longer show an upload option that should be hidden.
Original PR description
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized…
### Issue: When accessing the Bank Reconciliation view directly via URL or bookmark, auto-matching with reconciliation models may not trigger and the upload button may be visible on synchronized journals ### Cause: `_action_open_bank_reconciliation_widget` injects two context keys: - `auto_statement_processing`: triggers auto-reconciliation on statement creation - `bank_statements_source`: hides the upload button for synchronized journals When the view is accessed directly, these keys are not present, causing the UI to ignore them `auto_statement_processing` is now set directly in the user context via `onWillRender`/`onWillDestroy` in `BankRecKanbanController` `bank_statements_source` requires an ORM call to fetch the journal's value and is resolved via `fetchBankStatementsSourceInto` on startup Notes: The fix for `bank_statements_source` was added opportunistically while addressing `auto_statement_processing` Steps to reproduce: - Install `accountant` with demo data - Duplicate the Bank Journal and set Bank Feeds to Online Synchronization - Open the Accounting Dashboard and open the Bank (copy) - Create a transaction (Label: Test, any amount) and click Add & Close - In the 3 dots menu, choose Manage Models - Create a Reconciliation Model (Label contains: Test, Lines: any account, default values) - Click Automate - Go back to the Bank Reconciliation page and verify: -- The transaction is reconciled automatically -- No Upload button is displayed - Create a new transaction, it should be reconciled automatically - Copy the URL and open it in a new tab - Create a new transaction Before the fix, the transaction is not reconciled and the Upload button is present opw-6391107 Forward-Port-Of: odoo/enterprise#126359
This fixes a test issue where cash basis report checks depended on a specific generated account code. The tests now use the configured outstanding receipts account, preventing false failures when account codes vary between databases.
Original PR description
Description of the issue this commit addresses: Commit 63f5646cfd75 made the tests use the default outstanding account but hard-coded code 101403. In an all-module database, generated account codes depend on existing accounts, so Outstanding Receipts may use code 101404 and make otherwise correct report assertions fail. --- Desired behavior after this commit is merged: This commit derives the expected report line name from the configured outstanding receipts account, making the assertions independent of its generated code. --- runbot-[231581](https://runbot.odoo.com/odoo/error/231581) Forward-Port-Of: odoo/enterprise#125652
Timesheet assistant suggestions now use the intended event duration instead of estimating time from start and end times. This prevents planning shifts with breaks or differing allocated hours from suggesting the wrong timesheet duration, while keeping calendar event suggestions accurate.
Original PR description
*_: project_timesheet_forecast, timesheet_grid, timesheet_grid_calendar Previously, the timesheet assistant derived suggested entry durations from an event's start and stop datetimes. This worked for calendar events but produced incorrect suggestions for planning shifts whenever the allocated working hours differed from the overall scheduled time window. This commit introduces an explicit ``duration`` field in assistant events and updates all providers to supply it. Planning slots now use their allocated hours as the event duration, while calendar events expose their existing duration value. The assistant now consistently relies on this field instead of computing the duration from the event time range. As a result, suggested timesheet durations accurately reflect the intended working time for both planning shifts and calendar events. task-6366593
Updated incorrect Italian wording in the Balance Sheet reports so users see the proper field names when using the Italian language. This improves clarity and reduces confusion for accounting teams reviewing Italian financial statements.
Original PR description
### Steps to reproduce the issue: 1. Download Accounting and l10n_it 2. Install and switch to italian language 3. Go to Balance Sheets and select Balance Sheet (IT) 4. Some words are not correct [Here]( https://docs.google.com/spreadsheets/d/1-w83oAHTxDRIi-W_VSJiscNclw-yijzQUHOgMnTq7jE/edit?gid=0#gid=0) the wrong fields with their correct translations. opw-6424609 Forward-Port-Of: odoo/enterprise#126253
The Helpdesk Knowledge website feature now declares the dependency it needs to install correctly in special installation scenarios. This prevents setup failures when auto-installation is skipped, improving reliability for deployments and upgrades.
Original PR description
Trying to install website_helpdesk_knowledge with the flag --skip-auto-install would fail due to website_helpdesk_knowledge/views/helpdesk_views.xml referencing `is_published` which is only defined in `website` https://github.com/odoo/odoo/blob/4d60d5693f3d0253a28dd38412125b2fc6d6b41f/addons/website/models/mixins.py#L184 Reproduciton steps: odoo/odoo-bin --addons-path odoo/addons,odoo/odoo/addons,enterprise,design-themes -d oes_runbot --stop-after-init --log-level=test --max-cron-threads=0 -i website_helpdesk_knowledge --skip-auto-install Adding `website_knowledge` pulls in the relevant dependencies resulting in the field being found and valid Affects **18.0** and **19.0**, **nothing in between** Forward-Port-Of: odoo/enterprise#126260
Employee unavailable time is now shown consistently across Attendance and Time Off planning views. Days outside an employee’s contract, including employees without contracts, are correctly greyed out, while flexible schedules are handled more accurately.
Original PR description
purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days,…
purpose:
1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application.
Fix:
1:
- implemented `_get_employee_unavailable_intervals` in employee model to be used in both time off and attendance.
- more optimized than the old implementation in time off as it calls `_work_intervals_batch` once per calendar instead of calling it for each contract in `_unavailable_intervals_batch`
- greys out "out of contract" periods
- for flexible and fully flexible employees, the whole period is considered available except leave periods
- made `_get_calendar_periods` use version date start instead of contract date start and corrected a bug in tz conversion 2:
- made `_get_unusual_days` return True for all the days outside of contracts for the employee instead of not returning anything for them or getting values from the working schedule of the employee (means that they will be greyed out in the callendar view) and added a test for it
task-id: 5473055
Forward-Port-Of: odoo/enterprise#113253Fixes an issue in the Barcode app where selecting items from a delivery containing both packaged and unpackaged products could leave two lines selected at once. This helps warehouse users avoid confusion and reduces the risk of processing the wrong delivery line.
Original PR description
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty…
**Steps to reproduce:** - Enable "Move Entire Packages" setting on deliveries - Make a product A, that has a package P1, on hand qty of 1 - Make product B that don't have a package, but on hand qty of 1 - Make a delivery that has both of those products, requested qty of 1 for both - Mark it as todo - Go to the barcode app, select the delivery - Select the line with product B - Select the line with product A --> The line with product B is not unselected **Why the fix:** When we have a mix of packaged products and products without a package on the same operation, they are handled separately. The products without a package are handled in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L388-L392 that calls https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1277-L1284 But as you can see, there are no mention of the selected package line, which is stored in **this.lastScanned.packageId**. As we do not touch this variable, the selected package line stays selected. The same is true for the other way around, when we select a package line we call https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L394-L398 This function does not care for the **selectedLineVirtualId** which represents the selected line without a package. To avoid this and make it so that only one line is selected even if they have different package, we now set the corresponding value to false to unselect the other line in all situation. This is basically how it's done in https://github.com/odoo/enterprise/blob/98c79af3fb6cb354f46fd2f58e642a72a9271443/stock_barcode/static/src/models/barcode_model.js#L1202-L1208 to unselect every line regardless of packages. opw-6266203 Forward-Port-Of: odoo/enterprise#125703 Forward-Port-Of: odoo/enterprise#122038
This fix ensures that surcharge fees are added to point-of-sale orders before the payment is completed. It prevents affected Tyro transactions from being validated without the required surcharge line, improving order accuracy and checkout reliability.
Original PR description
Currently when completing a Tyro payment with a surcharge fee in some cases there is a race condition preventing the surcharge line to be added to the pos order before its validation This PR fixes that issue opw-6402191 Forward-Port-Of: odoo/enterprise#125852
Customer balances in Point of Sale now show the correct amount when the company and PoS use different currencies. This prevents pay-later orders from being converted twice, so staff see accurate customer dues at checkout.
Original PR description
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any…
Steps to reproduce: - set the company currency to XCG - set the PoS sales journal currency and the PoS pricelist currency to USD - configure a XCG <-> USD rate - create a customer without any outstanding balance - open the PoS, create an order of USD 100 and validate it with the Customer Account (Pay Later) payment method - open the Customers screen and look at the Total Due of that customer Issue: The Total Due shows about USD 55.56, i.e. the amount converted once too many, instead of the expected USD 100. Cause: get_total_due() sums two amounts that are not expressed in the same currency before converting them. partner.total_due comes from the accounting entries, it is the sum of account.move.line.amount_residual and is therefore in company currency, while total_settled is the sum of pos.payment.amount of the still open sessions, which is in the currency of the order, so the PoS one. The addition is done first and the result is then converted from the company currency to the PoS one, so the pay later payments end up converted a second time. opw-6403320 Forward-Port-Of: odoo/enterprise#126402 Forward-Port-Of: odoo/enterprise#125798
This update ensures the Ecuador electronic invoicing module installs with the payment dependency it needs. It prevents automated installation tests from failing when optional modules are skipped, improving release stability without changing day-to-day user behavior.
Original PR description
Runbot test would fail when running with `--skip-auto-install` due to the file l10n_ec_edi/views/withhold_portal_templates.xml referencing something that didn't exist as `account_payment` wasn't installed. Element `<xpath expr="//div[@name='invoice_paid_badge']">` cannot be located in parent view Reproduction step: odoo/odoo-bin --addons-path odoo/addons,odoo/odoo/addons,enterprise,design-themes -d oes_test --stop-after-init --log-level=test --max-cron-threads=0 -i l10n_ec_edi --skip-auto-install runbot-[237864](https://runbot.odoo.com/odoo/error/237864)
Confirmed manufacturing orders now correctly reflect changes made to their bill of materials when users choose to update them. This prevents outdated or removed operations from remaining on production orders and helps manufacturing teams work from accurate instructions.
Original PR description
Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation…
Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation on anything else than the company, name or workcenter - Go back to the MO, click the "Update Bom" button > The second operation is not unlinked and the first operation is not updated Cause of the issue: The `action_update_bom` updates the move raws and operations of the MO via the `_link_bom`: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L1214-L1218 For draft MO's all the work of these updates is done via the compute methods and by deleting all the records unrelevant to the new bom: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2603-L2626 And, in that case all the workorders that are not linked to an operation of the bom are expected to be deleted. However, when the MO is not in draft, the update of operations is expected to be performed here: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2647-L2664 However, since the operation of the bom has been deleted, the workorder that is expected to be deleted is not linked to any operation and hence does not satisfy the condition to be deleted: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2663-L2664 Concerning the non update of operations, it happens because the MO's operation are only updated on the three fields: `company_id`, `workcenter_id`, `name`: https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2647-L2664 https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2628-L2629 However, many other cahnges can and are actually relevant. Note: Prior to commit 80e6ed658fb43584bc2fad673ca40d9af6cf0ab6 operations were archived on boms rather than deleted: https://github.com/odoo/odoo/blob/4a5270218fe6fd7d30edb6d684b3340dc7423bab/addons/mrp/views/mrp_routing_views.xml#L53-L55 As such they would still be linked to an operation (but unrelated to the present values of the bom) and hence would fall into the condition of being unlinked from the MO. Since the bom operations are no longer archived there is no way to determine if an operation used to be linked to a bom and we therefore need to chose between deleting all operations unrelated to the present bom or to keep them all (when the MO has been confirmed). Community: https://github.com/odoo/odoo/pull/269747 opw-6285878 opw-6261738 Forward-Port-Of: odoo/enterprise#120709
Replacing a Sign document now keeps multiple signature fields correctly linked to the same signer. This prevents duplicate signer entries and helps ensure signing workflows remain accurate after a document is replaced.
Original PR description
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields,…
### Description of the issue/feature this PR addresses: This PR fixes an issue in the Sign module where replacing a document breaks the link between a signer and their multiple signature fields, causing Odoo to erroneously generate separate signers for each individual field. ### Current behavior before PR: When a document with multiple signature fields assigned to the same person is replaced, the _copy_sign_items_to function duplicates the sign.item records. During this duplication process, Odoo duplicates the old responsible_ids, creating copies with new ids. These new copies overwrite the old responsible_ids, ensuring that the newly created sign_items have entirely new responsible_ids. Because a shared responsible_id is the primary key Odoo uses to group multiple signature items under a single signer, this change in ID causes the system to lose the grouping. As a result, Odoo treats each copied field as belonging to a completely new, separate signer. _Note_: Because of the limitation mentioned before, any responsible_id that is passed through the copy function, and thereby the copy_data function, is overwritten with new ids. The only work-around then is to update the responsible_id value attached to the new_sign_item after the copy_data function has completed and the new_sign_item has been created. ### Desired behavior after PR is merged: The original responsible_id is explicitly carried over and assigned to the newly copied sign.item immediately after the copy operation completes. This ensures the copied signature fields retain their original role IDs and grouping, keeping them correctly assigned to the single original signer. opw-6354334 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#123628
This fix reverts a module dependency change in the Helpdesk Knowledge website integration because dependency changes are not allowed in stable releases. It helps keep the stable version predictable and reduces the risk of unintended installation or upgrade behavior.
Original PR description
Changes to depends are not allowed in stable Merge through saas-19.1 https://github.com/odoo/enterprise/pull/126260 Forward-Port-Of: odoo/enterprise#126892
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative.
Original PR description
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with…
**PROBLEM** When using fixed tax not affecting the base on line with discount, the xml generated is invalid and refused by peppol. **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create an invoice with the following line: - qty: 2, price_unit: 100, discount: 10%, taxes: 21% + fixed tax 1€ - qty: -2, price_unit: 0, taxes: fixed tax 1€ 3. Generate an xml, and try validating it on peppol. 4. The validation fails with the error: [BR-27]-The Item net price (BT-146) shall NOT be negative. **CAUSE** Fixed tax not affecting the base of other tax are dispatched into new base lines and then merged into one line per fixed tax. The new base lines they are dispatched to are created as a copy of the line they originated from. It means we copy the discount from the original lines. The fixed tax amount is the unit price of each new base lines. When reducing the base lines into one line, we take the unit prices of the line, and apply the discount to the unit price. But, since the unit price is the fixed tax amount, and fixed tax are not affected by discounts, we shouldn't apply discount. **PROBLEM 2** fixed division by 0 traceback when the aggregation of invoice lines is 0 **STEP TO REPRODUCE** 1. Install l10n_be. 2. Create the following invoice: - qty: 1, unit_price: 100, tax:0% + fixed tax 1€, set an analytic distribution account - qty: -1, unit_price: 50, tax:0% + fixed tax 1€, set the same analytic distribution account 3. Send the invoice to peppol. 4. A division by 0 should occur. opw-6388219 Forward-Port-Of: odoo/odoo#276945
Before this commit: The info, 'You can choose how you want us to send your invoices, and with which electronic format.' was never visible because `invoice_edi_format` is always None. After this commit: Update condition from `invoice_edi_format` to `invoice_edi_formats` to make condition correct and will display info if there are multiple invoice_sending_methods and at-least one edi format. Forward-Port-Of: odoo/odoo#278870
Original PR description
Before this commit: The info, 'You can choose how you want us to send your invoices, and with which electronic format.' was never visible because `invoice_edi_format` is always None. After this commit: Update condition from `invoice_edi_format` to `invoice_edi_formats` to make condition correct and will display info if there are multiple invoice_sending_methods and at-least one edi format. Forward-Port-Of: odoo/odoo#278870
## Issue When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO. ## Steps to reproduce 1. Install *Sales Timesheet* (`sale_timesheet`) 2. Create a Product P - Product Type: Service - Create on Order: Task - Project: Any project - Invoicing Policy: Based on Timesheets 3. Create a SO - Any Customer - Product P (any quantity) - Confi
Original PR description
## Issue When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO. ## Steps…
## Issue
When generating an invoice for a service product with an invoicing policy based on timesheets, the amount of hours invoiced is wrong if there exists a credit note linked to that SO.
## Steps to reproduce
1. Install *Sales Timesheet* (`sale_timesheet`)
2. Create a Product P
- Product Type: Service
- Create on Order: Task
- Project: Any project
- Invoicing Policy: Based on Timesheets
3. Create a SO
- Any Customer
- Product P (any quantity)
- Confirm the SO
4. In the created task, add a timesheet entry
- Date: Today
- Time Spent: 10:00 (10 hours)
5. Create and confirm the invoice for the SO
6. Create a Credit Note from the invoice, set the quantity to 4 hours, and confirm it
7. From the created task, add a second timesheet entry
- Date: Any future date (e.g., today + 7)
- Time Spent: 15:00 (15 hours)
8. Create a second invoice, but set a Timesheets Period that only covers the second timesheet entry
9. **The quantity on the newly created invoice is 9 hours, even though we're clearly trying to invoice the 15 hours from the second timesheet entry.**
## Cause
The second invoice is impacted by the credit note generated from the first one. When generating that second invoice, the [`_recompute_qty_to_invoice`](https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L149) method incorrectly computes the amount to invoice by taking into account `account.analytic.line` from outside the provided range.
The delivered quantity is correctly calculated by taking into account the provided range (through the `start_date` and `end_date` added to the domain passed to `_get_delivered_quantity_by_analytic`:
https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L176-L180
But then, for each `sale.order.line`, we look at the related `account.analytic.line` without taking into account the provided dates, which leads to lines outside of the range impacting the invoice.
https://github.com/odoo/odoo/blob/0512ebd4c8cc277fdb4fbe0f57619a0bd61192c2/addons/sale_timesheet/models/sale_order_line.py#L182-L193
In the example described in the *Steps to reproduce*, we start with a (correct) amount delivered of 15.0, we find two `invoice_lines_to_calculate` (the invoice of 10 hours, and the credit note of 4 hours), which leads to the quantity to invoice being set to `15 - (-4 + 10) = 9`. This seems like an odd behavior as it:
- doesn't invoice all the hours within the provided range (15 hours within the range, and we're only invoicing 9)
- doesn't invoice **all** the hours left to be invoiced (6 hours are already invoiced, 25 should be in total, and we're invoicing 9)
opw-6373870
Forward-Port-Of: odoo/odoo#277727Issue: Every change of the selected order makes the PoS call `pos.config.update_customer_display`, which publishes the order on the bus for the customer display paired with this browser. The device uuid identifying that pairing is only generated when the customer display dialog is opened, so a PoS whose customer display was never opened sends `device_uuid: null` and the server publishes on `UPDATE_CUSTOMER_DISPLAY-null`, a channel nobody can listen to. Steps to reproduce: Open a PoS session
Original PR description
Issue: Every change of the selected order makes the PoS call `pos.config.update_customer_display`, which publishes the order on the bus for the customer display paired with this browser. The device…
Issue: Every change of the selected order makes the PoS call `pos.config.update_customer_display`, which publishes the order on the bus for the customer display paired with this browser. The device uuid identifying that pairing is only generated when the customer display dialog is opened, so a PoS whose customer display was never opened sends `device_uuid: null` and the server publishes on `UPDATE_CUSTOMER_DISPLAY-null`, a channel nobody can listen to. Steps to reproduce: Open a PoS session, never open the customer display, and add a product to an order. Current behaviour: An rpc is sent for each change of the order, and each of them ends up as a bus notification that no customer display can ever receive. Expected behaviour: Nothing is sent as long as no customer display was ever opened. Solution: Skip the rpc while no device uuid exists. A customer display opened in the same browser as the PoS is served by the BroadcastChannel, which is unaffected. task-6408513 Forward-Port-Of: odoo/odoo#277687
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email marketing as dedicated servers. In doing so, it missed the fact that while in *Email Marketing > Settings*, the "Dedicated Server" picker now correctly ignores personal OMS entries, the selection widget for `mail_server_id` in `view_mail_mass_mailing_form` still let's you manually select a OMS with a
Original PR description
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email…
The bugfix introduced in https://github.com/odoo/odoo/commit/01d11a770f89c391f7c6a2c46a3d770d10afb428 made it so that "personal" outgoing mail servers are blocked/ignored from being used in email marketing as dedicated servers.
In doing so, it missed the fact that while in *Email Marketing > Settings*, the "Dedicated Server" picker now correctly ignores personal OMS entries, the selection widget for `mail_server_id` in `view_mail_mass_mailing_form` still let's you manually select a OMS with an owner set. As there is not warning or an explicit error, this can lead to accidental miss configurations on an email marketing campaign, where the selected OMS will be actually ignored by the backend.
To align the changes introduced by the bugfix, we add a search domain to the selection field, so that only OMS with `('owner_user_id', '=', False)` will be presented as a choice.
OPW-6388562
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#278595In this commit: - When only one preset remains available after filtering table identifier in self-order mode, automatically select it and skip the preset selection page. - This avoids showing a location selection page when there is no actual choice available to the customer. Task:6217791 Enterprise PR : https://github.com/odoo/enterprise/pull/122979 Forward-Port-Of: odoo/odoo#274301
Original PR description
In this commit: - When only one preset remains available after filtering table identifier in self-order mode, automatically select it and skip the preset selection page. - This avoids showing a location selection page when there is no actual choice available to the customer. Task:6217791 Enterprise PR : https://github.com/odoo/enterprise/pull/122979 Forward-Port-Of: odoo/odoo#274301
Repro steps: 1) Create an invoice 2) Activate auto post (monthly for example) 3) Confirm the invoice, a new draft invoice will be created 4) Reset to draft 5) Confirm again Problem: A second draft would be created, and next period, 2 invoices would be confirmed Fix: This commit deletes the next auto post recurrence of an invoice, if that next recurrence is in draft, and the invoice is being set to draft. It also prevents creating a recurrence at a date if there is already an exi
Original PR description
Repro steps: 1) Create an invoice 2) Activate auto post (monthly for example) 3) Confirm the invoice, a new draft invoice will be created 4) Reset to draft 5) Confirm again Problem: A second draft would be created, and next period, 2 invoices would be confirmed Fix: This commit deletes the next auto post recurrence of an invoice, if that next recurrence is in draft, and the invoice is being set to draft. It also prevents creating a recurrence at a date if there is already an existing recurrent move on that date. task-6311219 Forward-Port-Of: odoo/odoo#279159
Description of the issue/feature this PR addresses: Mail server ports are identifiers rather than quantities. The incoming and outgoing mail server views use the unsupported `format` option, so locale-based integer formatting remains enabled. Steps to reproduce: 1. Enable developer mode. 2. Go to Settings > Technical > Email > Outgoing Mail Servers. 3. Create a server and set SMTP Port to `8069`. 4. Move focus away from the field. 5. The same issue occurs on an Incomin
Original PR description
Description of the issue/feature this PR addresses: Mail server ports are identifiers rather than quantities. The incoming and outgoing mail server views use the unsupported `format` option, so…
Description of the issue/feature this PR addresses: Mail server ports are identifiers rather than quantities. The incoming and outgoing mail server views use the unsupported `format` option, so locale-based integer formatting remains enabled. Steps to reproduce: 1. Enable developer mode. 2. Go to Settings > Technical > Email > Outgoing Mail Servers. 3. Create a server and set SMTP Port to `8069`. 4. Move focus away from the field. 5. The same issue occurs on an Incoming Mail Server with a port such as `10143`. Current behavior before PR: Ports are displayed with thousands separators, e.g. `8,069` and `10,143`. Desired behavior after PR is merged: Mail server ports remain unformatted, e.g. `8069` and `10143`. Fixes #275937 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr "As a recent Computer Engineering graduate, I made my first open-source contribution to Odoo." :) Forward-Port-Of: odoo/odoo#278329
A user with own sales permissions won't be able to change the task partner when that task has a timesheet configured. Description of the issue/feature this PR addresses: - With a user with bare sales permissions (own sales) go to a task with timesheets and a sale order linked to it - Try to change the Customer for the task and save Current behavior before PR: <img width="1148" height="308" alt="image" src="https://github.com/user-attachments/assets/f0ccd25c-757b-455f-be36-68599de18c
Original PR description
A user with own sales permissions won't be able to change the task partner when that task has a timesheet configured. Description of the issue/feature this PR addresses: - With a user with bare sales permissions (own sales) go to a task with timesheets and a sale order linked to it - Try to change the Customer for the task and save Current behavior before PR: <img width="1148" height="308" alt="image" src="https://github.com/user-attachments/assets/f0ccd25c-757b-455f-be36-68599de18cd3" /> Desired behavior after PR is merged: No access error cc @moduon MT-15215 OPW-6364376 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273916
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the "+" button to make a new hr version record for this employee. 4) Set the date to be the first of the last month. 5) In the Attendance app -> New -> Select the new employee. 6) Select the check in and out dates to be from last month, edit the times such that the time worked is between 7 and 8 h
Original PR description
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the…
Steps to reproduce: 1) Install hr_holidays & hr_attendance. 2) Enable "Display Extra Hours" & "Absence Management" in the Attendance app settings. 3) Make a new employee, in the form view click the "+" button to make a new hr version record for this employee. 4) Set the date to be the first of the last month. 5) In the Attendance app -> New -> Select the new employee. 6) Select the check in and out dates to be from last month, edit the times such that the time worked is between 7 and 8 hours (ex 9:00am to 4:55pm). 7) In the Attendance app -> Reporting -> Attendances -> the test employee should have a negative value for "Worked Extra Hours" 8) Create a new time off type, enable "Deduct Extra Hours" & disable "Requires Allocation" use hours as the Unit of measure. 9) Open the time off smart button menu from the test employee's form view. Issue) The value seen in the report from step 7 is not the same as what the user sees in the dashboard. Notes) This issue can occur when an employee scheduled to work for 8 hours a day only clocks in for 7:55 hours leading to a negative extra time. The back-end has the correct value stored and sends it to the browser. The issue occurs because the JavaScript function that converts the decimal number of hours into a string (9.5 -> "9:30") does not work with negative input. This PR resolves that issue. opw-6417543 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280085 Forward-Port-Of: odoo/odoo#260367
Original PR description
**PROBLEM** Before this PR, there was no way to handle invoices sent to clients depending from a JST/LGU (local government unit). This PR add support for it. opw-6095581 Forward-Port-Of: odoo/odoo#280085 Forward-Port-Of: odoo/odoo#260367
Currently, a transfer is marked as 'Printed' only when the 'Picking Operations' report is printed using the Print button in the 'ready' state. If the same report is printed from the actions (gear) menu, the transfer is not marked as printed. This PR ensures that printing the 'Picking Operations' report from the actions menu also marks the transfer as 'Printed'. **Steps to reproduce:** - Install the stock module. - Open the Transfers list view. - Add custom group for 'Printed'. - Open a
Original PR description
Currently, a transfer is marked as 'Printed' only when the 'Picking Operations' report is printed using the Print button in the 'ready' state. If the same report is printed from the actions (gear)…
Currently, a transfer is marked as 'Printed' only when the 'Picking Operations' report is printed using the Print button in the 'ready' state. If the same report is printed from the actions (gear) menu, the transfer is not marked as printed. This PR ensures that printing the 'Picking Operations' report from the actions menu also marks the transfer as 'Printed'. **Steps to reproduce:** - Install the stock module. - Open the Transfers list view. - Add custom group for 'Printed'. - Open a transfer in the 'ready' state and print the 'Picking Operations' report using the Print button. Notice that the transfer is marked as 'Printed'. - Open another transfer in the 'ready' state and print the 'Picking Operations' report from the actions menu. - Observe that the transfer is not marked as Printed. The same issue occurs when printing it from list view. **Expected behavior:** A transfer in the 'ready' state should be marked as Printed whenever the 'Picking Operations' report is printed, regardless of whether it is triggered from the 'Print' button or the actions menu. close #235129 Forward-Port-Of: odoo/odoo#276582
Before this commit, turning the camera on during a call could leave the camera off in every member's UI, including the local user's own tile, while the video was already being sent. This happens because toggleVideo awaits network.updateUpload before updateAndBroadcast, and updateUpload waits on the ready promise of every peer. A single member whose handshake never completes holds isCameraOn and isScreenSharingOn for everyone. This commit fixes the issue by broadcasting the state first and
Original PR description
Before this commit, turning the camera on during a call could leave the camera off in every member's UI, including the local user's own tile, while the video was already being sent. This happens because toggleVideo awaits network.updateUpload before updateAndBroadcast, and updateUpload waits on the ready promise of every peer. A single member whose handshake never completes holds isCameraOn and isScreenSharingOn for everyone. This commit fixes the issue by broadcasting the state first and awaiting the upload after. Note that updateUpload sends its info snapshot to the peers synchronously, so they still learn the new track. Back-port of https://github.com/odoo/odoo/pull/279106 Forward-Port-Of: odoo/odoo#280301 Forward-Port-Of: odoo/odoo#280014
By default event notifications are configured with positive integers to state how many minutes/hours/days they should be triggered before an event starts. This works fine in within Odoo. But in an ICS file a TRIGGER with such positive integer means it starts after the event. For example ICS file generated by Odoo contains TRIGGER;related=START:PT15M but it should be negative: TRIGGER;related=START:-PT15M (note the minus) in order to trigger before the event. See [here](https://icalendar.org/iCal
Original PR description
By default event notifications are configured with positive integers to state how many minutes/hours/days they should be triggered before an event starts. This works fine in within Odoo. But in an ICS file a TRIGGER with such positive integer means it starts after the event. For example ICS file generated by Odoo contains TRIGGER;related=START:PT15M but it should be negative: TRIGGER;related=START:-PT15M (note the minus) in order to trigger before the event. See [here](https://icalendar.org/iCalendar-RFC-5545/3-8-6-3-trigger.html) for reference. Current behavior before PR: The reminder is triggered AFTER the event start Desired behavior after PR is merged: The reminder is triggered BEFORE the event start Closes #245052. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#274744
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a by
Original PR description
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of…
Steps to reproduce 1. Go to Manufacturing > Configuration > Settings and enable By-Products 2. Go to Inventory > Configuration > Locations, find the location with type Production and set the Cost of Production account 3. Go to Inventory > Configuration > Product Categories and set the costing method to Standard Price and Inventory Valuation to Perpetual (at invoicing) 4. Set the finished product and byproduct as Storable with a non-zero Cost 5. Create a BoM with a component and a byproduct with a Cost Share % assigned 6. Create and complete a manufacturing order 7. Check the journal entries of the MO: the byproduct entry shows $0 Issue Standard-cost byproduct moves have no price_unit set in either code path of _cal_price, so their journal entries always show $0. When the finished product is standard cost, _cal_price returns early at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L66-L68 without iterating byproducts at all, so no price_unit is ever set on them. When the finished product is FIFO/AVCO, the byproduct loop at https://github.com/odoo/odoo/blob/55221db559cda1c61229eecf8493f5fbaee5cd50/addons/mrp_account/models/mrp_production.py#L83-L84 only sets price_unit for FIFO/AVCO byproducts. Standard byproducts are skipped, giving them $0 even though their cost_share was already deducted from the finished product, making value disappear from inventory entirely. For standard-cost products the MO has no influence on their value — they always use the standard_price from the product form, regardless of cost_share. Solution In the early-return branch, iterate byproducts: standard ones get standard_price, FIFO/AVCO ones get total_cost * cost_share. In the FIFO/AVCO branch, add the same standard_price fallback so standard byproducts are no longer left at $0 when their cost_share is set. opw-6020065 Forward-Port-Of: odoo/odoo#257472
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with p
Original PR description
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and…
A user with role Inventory/User cannot validate the dropship of a product with an Average Cost (AVCO) Costing Method Steps to reproduce: 1. Install sale_management, stock_dropshipping and stock_landed_costs module 2. Go to Sales > Configuration > Categories and change Furniture / Office's Costing Method to Average Cost (AVCO) 3. Go to Settings > Users and set Marc Demo's role on Purchase to User 3. Log in as Marc Demo 4. Create and confirm a quotation for customer Acme Corporation with product Large Cabinet (Dropship route and AVCO costing method) 5. Go to the related purchase order and confirm it 6. Go to the related dropship and validate it 7. An access error is raised Issue: Validating a dropship recomputes the cost of the product and reads `stock.valuation.adjustment.lines` https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/models/stock_move.py#L11 But only Inventory/Administrator have read access to these records https://github.com/odoo/odoo/blob/cb7b3de6cea07464bcadd1325f52533d34ce09bc/addons/stock_landed_costs/security/ir.model.access.csv#L4 Solution: Call `_get_landed_cost` with `.sudo()` in order to update the cost even though the user has no landed costs access opw-6366844 Forward-Port-Of: odoo/odoo#276285
purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application. Fix: 1: - implemente
Original PR description
purpose: 1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days,…
purpose:
1- We should have a consistent way to compute `_gantt_unavailability` of employees in time off and attendance. Currently, some cases have inconsistent behavior such as out of contract days, flexible and fully flexibe employees. 2- In time off calendar view, if the employee does not have a contract at all, the current working schedule will appear in the calendar and it will not be greyed out. This is inconsistent with the behavior of the attendance application.
Fix:
1:
- implemented `_get_employee_unavailable_intervals` in employee model to be used in both time off and attendance.
- more optimized than the old implementation in time off as it calls `_work_intervals_batch` once per calendar instead of calling it for each contract in `_unavailable_intervals_batch`
- greys out "out of contract" periods
- for flexible and fully flexible employees, the whole period is considered available except leave periods
- made `_get_calendar_periods` use version date start instead of contract date start and corrected a bug in tz conversion 2:
- made `_get_unusual_days` return True for all the days outside of contracts for the employee instead of not returning anything for them or getting values from the working schedule of the employee (means that they will be greyed out in the callendar view) and added a test for it
task-id: 5473055
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#258038Problem: The `product_label_section_and_note_field` widget ignores the `no_open` option in list views. The `m2oProps` getter overrides the framework's native `p.canOpen` property, hardcoding the clickable state based purely on readonly status. Purpose: Ensure the widget respects standard framework options by the `p.canOpen` with the business logic, restoring the ability to disable record navigation. Steps to Reproduce on Runbot: - Go to Purchase app and open a quotation. - Open Odoo St
Original PR description
Problem: The `product_label_section_and_note_field` widget ignores the `no_open` option in list views. The `m2oProps` getter overrides the framework's native `p.canOpen` property, hardcoding the clickable state based purely on readonly status. Purpose: Ensure the widget respects standard framework options by the `p.canOpen` with the business logic, restoring the ability to disable record navigation. Steps to Reproduce on Runbot: - Go to Purchase app and open a quotation. - Open Odoo Studio. - Click on the product table and select "Edit list view". - Click on the product column. - On the sidebar, go to properties and activate "Disable opening". - Close Studio and click the product name on a line. - The form view action is triggered. opw-6422065 Forward-Port-Of: odoo/odoo#279221
Previously, we did not prevent FRCTC from registering through Peppol, even though FRCTC is not supported in Peppol. French companies could attempt to register in Peppol with FRCTC, which caused many errors. task-6421930 Forward-Port-Of: odoo/odoo#278782
Original PR description
Previously, we did not prevent FRCTC from registering through Peppol, even though FRCTC is not supported in Peppol. French companies could attempt to register in Peppol with FRCTC, which caused many errors. task-6421930 Forward-Port-Of: odoo/odoo#278782
Before this commit, this test was failing non-deterministically on on some machines: ``` show banner for new message after thread was read from another device ``` With the following error: ``` Error: Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))" (Timeout of 3 seconds). Found 0 instead. ``` This happens because while the message list has 20 messages, each message is 1-line long. That means on many monitors the bottom of conversation is visible and thus it c
Original PR description
Before this commit, this test was failing non-deterministically on on some machines:
```
show banner for new message after thread was read from another device
```
With the following error:
```
Error: Failed to find 1 of ".o-mail-Thread-banner:has(:text('1 new message'))" (Timeout of 3 seconds). Found 0 instead.
```
This happens because while the message list has 20 messages, each message is 1-line long. That means on many monitors the bottom of conversation is visible and thus it can mark as read automatically the conversation. When this happens the banner is removed, thus the last step would fail.
This commit fixes the issue by making each message body bigger, so that this is very unlikely to see the bottom of message list, therefore avoiding the auto-mark as read from reaching the bottom of conversation.
Forward-Port-Of: odoo/odoo#280103**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it. - Remove any amount of recipients then send the mail. - You will see that the recipients are added back and the mail is sent to them. **Behavior:** Currently whenever a user clicks on an attachment
Original PR description
**Steps to reproduce:** - Go to any view where you can send mails (eg sale orders) - Send a first mail to multiple recipients so they are added automatically on the next mail. - Open a new mail,…
**Steps to reproduce:**
- Go to any view where you can send mails (eg sale orders)
- Send a first mail to multiple recipients so they are added automatically on the next mail.
- Open a new mail, confirm that the recipients are present, add a selectable attachment (eg a PDF), then click on it.
- Remove any amount of recipients then send the mail.
- You will see that the recipients are added back and the mail is sent to them.
**Behavior:**
Currently whenever a user clicks on an attachment in a mail composer, the systems considers that the user might be trying
to leave the page and will trigger an `urgentSave()`, and further down the line a `web_save()`.
The behavior when a web_save() is triggered is to create a record if there isnt currently one, and otherwise to write the modified values onto the record, using commands.
The recipients for the mail are added by default, which is represented by a list of `[4, id]`add commands, that will be written on the record created in the first `web_save`, however this list is not correctly emptied after the first `_save()`.
If the list is present within `this._changes` then it is correctly cleared, but in the case where no changes were made, the within `this._values['partner_ids']` still contains the commands.
So when we later assign `this.data = { ...this._values };`, `this.data['partner_ids']` now contains our uncleared list of commands.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1222-L1230
And when we compute changes['partner_ids'] in our next iteration, we find ourselves with our command list again.
https://github.com/odoo/odoo/blob/f3e407c6a58abd2ddba42f26fcbd1928da63cb63/addons/web/static/src/model/relational_model/record.js#L1317-L1322
So when we then try to remove a recipient tag, the new delete command `[3, id]`
just gets canceled out with the already present add command.
And the `write()` in `web_save()` only writes add commands of already present partners, which doesn't do anything.
----
This commit adds a line to ensure commands inside `_values` are cleared
opw-6304713
Forward-Port-Of: odoo/odoo#278876### Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation on anything else than the company, name or workcenter - Go back to the MO, click the "Update Bom" button > The second operation is not unlinked and the first operation is not updated ### Cause of the issue: The `action_update_bom` updates the move raws and operations of the MO via t
Original PR description
### Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first…
### Steps to reproduce: - Create a product with a bom and 2 operations - Create an MO for 1 unit of that product - Confirm the MO - On the bom, delete the second operation and modify the first operation on anything else than the company, name or workcenter - Go back to the MO, click the "Update Bom" button > The second operation is not unlinked and the first operation is not updated ### Cause of the issue: The `action_update_bom` updates the move raws and operations of the MO via the `_link_bom`: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L1214-L1218 For draft MO's all the work of these updates is done via the compute methods and by deleting all the records unrelevant to the new bom: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2603-L2626 And, in that case all the workorders that are not linked to an operation of the bom are expected to be deleted. However, when the MO is not in draft, the update of operations is expected to be performed here: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2647-L2664 However, since the operation of the bom has been deleted, the workorder that is expected to be deleted is not linked to any operation and hence does not satisfy the condition to be deleted: https://github.com/odoo/odoo/blob/f66614193cce18f5a3298d03ce7e5f29d54f07e9/addons/mrp/models/mrp_production.py#L2663-L2664 Concerning the non update of operations, it happens because the MO's operation are only updated on the three fields: `company_id`, `workcenter_id`, `name`: https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2647-L2664 https://github.com/odoo/odoo/blob/31df5033e31c193b4576ef37dfbc5fc683817bc5/addons/mrp/models/mrp_production.py#L2628-L2629 However, many other changes can and are actually relevant. ### Note: Prior to commit 80e6ed658fb43584bc2fad673ca40d9af6cf0ab6 operations were archived on boms rather than deleted: https://github.com/odoo/odoo/blob/4a5270218fe6fd7d30edb6d684b3340dc7423bab/addons/mrp/views/mrp_routing_views.xml#L53-L55 As such they would still be linked to an operation (but unrelated to the present values of the bom) and hence would fall into the condition of being unlinked from the MO. Since the bom operations are no longer archived there is no way to determine if an operation used to be linked to a bom and we therefore need to chose between deleting all operations unrelated to the present bom or to keep them all (when the MO has been confirmed). Starting from saas-19.1, the fix conflict with commit https://github.com/odoo/odoo/commit/5c4cf2e0fcc3ed5bef77380bb65f356c56b5dac4 That is, the `action_update_bom`, now replan's workorders: https://github.com/odoo/odoo/blob/3412253211daf13d50755fdce7edd9ed9c4400df/addons/mrp/models/mrp_production.py#L1207-L1217 However, the `_link_bom` now unlinks the obsolete and re-creates the still valid workorders (possibly unplanned). In particular, both the computation of `is_planned` and of the new `duration_expected` might differ from the expected checked in the `action_update_bom`. Note that to ensure everything goes as planned, we need to unlink the obsolete workorders before creating the new workorders which would be incorrectly replanned. Other than that, the check on the `duration_expected` in the `action_update_bom` needs to be updated accordingly. Enterprise: https://github.com/odoo/enterprise/pull/120709 opw-6285878 opw-6261738 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#269747
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#276595 Forward-Port-Of: odoo/odoo#268284
Original PR description
Microsoft issues a new refresh token on every access token refresh (rolling 90-day sliding window). The previous code discarded it, causing users to be forced to re-authenticate every 90 days once the original token expired. Closes #253543 Forward-Port-Of: odoo/odoo#276595 Forward-Port-Of: odoo/odoo#268284