Daily updates from Odoo
Friday, July 3, 2026
160 changes
19 changes
Resolved issues and error corrections
When warehouse staff use the barcode app and click “put in pack,” Odoo now shows the package type selection prompt when the delivery settings require it. This prevents users from missing required packaging details and keeps barcode workflows aligned with standard delivery operations.
Original PR description
### Steps to reproduce: - In the settings enable: Packages - On the operation type `Delivery Order` set "Set Package Type" - Create and confirm a delivery for 1 unit of a product P + reserve it - Got…
### Steps to reproduce: - In the settings enable: Packages - On the operation type `Delivery Order` set "Set Package Type" - Create and confirm a delivery for 1 unit of a product P + reserve it - Got to the barcode app to process the delivery - Scan your product and click "put in pack" #### > The put in pack wizard allowing you to set a package type on the new package does not pop up. ### Cause of the issue: As a general rule of thumb the wizard is suppose to be displayed when the option is enabled and when a package/package type is not already provided to the call: https://github.com/odoo/odoo/blob/5dbc448d336c7ff22803ae91d5014eb6d0a07234/addons/stock/models/stock_package.py#L332-L341 https://github.com/odoo/odoo/blob/5dbc448d336c7ff22803ae91d5014eb6d0a07234/addons/stock/models/stock_move_line.py#L1236-L1238 However an override was added to the barcode module so that the wizard is never displayed when the action is launched from the barcode app: https://github.com/odoo/enterprise/blob/673d449f38cd3eff27c44270c8f7edf91d0ecd02/stock_barcode/models/stock_move_line.py#L193-L196 The idea behind this override was that you could provide the package type id via scans and hence that is was not necessary. However, if you click directly on the put in pack button, the wizard still make sense and should therefore be displayed under the same conditions. opw-6325092 Forward-Port-Of: odoo/enterprise#122308
This update corrects a bug where loyalty reward descriptions weren't consistently translating across multiple languages. Previously, changes to a discount's description only updated the current language, leaving other languages unchanged. Now, all languages will reflect the updated description, ensuring accurate and consistent messaging for customers.
Original PR description
### Steps to Reproduce 1. Activate any other language (ex. FR) 2. Create a new Discount code in Discount & Loyalty 3. Change your user language preference to FR, open the newly created loyalty…
### Steps to Reproduce 1. Activate any other language (ex. FR) 2. Create a new Discount code in Discount & Loyalty 3. Change your user language preference to FR, open the newly created loyalty reward, and change the Description on Order to Test Discount for both languages 4. Navigate to the backend Product Variants menu and observe how its name did not translate in English ### Description of the issue/feature this PR addresses: **Issue:** When you edit a translation for a loyalty.reward description in a multi-language setup, the product name (`discount_line_product_id.name`) fails to receive the complete translation in all languages. It only updates the current language. **Solution:** Override the 'update_field_translations' method on the loyalty.reward model. When changes are saved for the 'description' field on the discount code, intercept the payload and mirror directly at the discount product's `name` field. ### Current behavior before PR: Updating the reward description only updates the current language and all other languages do not change. ### Desired behavior after PR is merged: For all languages in which changes are made in a discount code's description, the discount line product name will reflect the same changes. opw-6314760 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273821 Forward-Port-Of: odoo/odoo#271680
A recent change in Cloudflare functionality disrupted how turnstile callbacks were handled in the website module. To ensure turnstile functionality continues to work correctly, the team reverted to a previous implementation that doesn't rely on specific external widget details. This resolves a technical issue impacting turnstile performance.
Original PR description
Callbacks were changed to use a single shared callback instead of a bunch of callbacks that captured a specific container. Cloudlfare since introduced a change that breaks this change by not making "this" available inside callbacks. We thus go back to the previous implementation that did not rely on implementation details of the external widget. related: 5aa5cf62a9d3f2b0c862b0aab337b22367843fa6 Forward-Port-Of: odoo/odoo#273538 Forward-Port-Of: odoo/odoo#273336
This update corrects a calculation error in the Swiss tax report (l10n_ch). Previously, negative values in certain report lines resulted in incorrect subtractions. The fix ensures that these lines display positive values, guaranteeing accurate tax report totals. This improves the reliability of financial reporting for Swiss clients.
Original PR description
### Issue: In 19.0, the values of lines 415 and 420 in the Swiss tax report are negative, causing line 479 to add them instead of subtracting Line 479 formula: `tax_ch_400 + tax_ch_405 + tax_ch_410 -…
### Issue: In 19.0, the values of lines 415 and 420 in the Swiss tax report are negative, causing line 479 to add them instead of subtracting Line 479 formula: `tax_ch_400 + tax_ch_405 + tax_ch_410 - tax_ch_415 - tax_ch_420` For the subtraction to be correct, 415 and 420 must be positive ### Cause: In 18.0, each tax grid had two variants (`+415`/`-415`) allowing the user to control the sign manually The double negative (`-*-`) incidentally produced positive values in the report In 19.0, the unified tax grid merges them into a single tax grid (`415`) with automatic sign handling 415 and 420 are correction lines that must appear positive in the report so that 479 subtracts them correctly The formulas were not updated to reflect this change ### Steps to reproduce: - Install `l10n_ch_reports` and `accountant` - Switch to `CH Company` - Create and confirm a Bill (Amount: 100, Tax: 8.1%) - Create and post a Journal Entry: - Account: 1170 Input Tax (VAT), Credit: 2, Tax Grids: 415 and 420 - Account: 1021 Bank, Debit: 2 - Open the Tax Report for this month Before the fix, lines 415 and 420 are negative and line 479 adds them instead of subtracting opw-6311126 Forward-Port-Of: odoo/odoo#272385
This update fixes an issue where sales from European companies to Northern Ireland (XI) were incorrectly calculating intra-community taxes. The change adds a check to ensure these service sales are treated as third-country transactions, aligning with tax regulations. This ensures accurate financial reporting.
Original PR description
…stomers The services sales done from a European company to a Northern Ireland (XI) company should not contain intra-community taxes but should be treated as third country (non-EU) transactions. We solve it by adding a check in the EC Sales List return that is only visible when a wrong record occurs. task-6007931 Forward-Port-Of: odoo/enterprise#122535 Forward-Port-Of: odoo/enterprise#121487
This update fixes an issue where GS1-compliant product barcodes were incorrectly interpreted. When the 'Default GS1 Nomenclature' setting is enabled, scanning a valid GS1 barcode now correctly adds the product to the delivery, resolving a discrepancy in quantity tracking. This ensures accurate inventory management based on GS1 standards.
Original PR description
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings…
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings enable "Default GS1 Nomenclature" - Create a storable product P with the barcode 3701762412212 - Create and confirm a delivery for 2 units of P and set the qty to 2 - Go to the barcode app and open your delivery - Scan 3701762412212 > The line of P is now selected with a quantity of 1/2 - Scan 3701762412212 #### > A new line is created for 1762411 units ### Cause of the issue: According to the GS1 nomenclature, the barcode 3701762412212 matches the scan of a quantity of "1762412" units of the lot name "2". As the scan of the of the product match a pattern for the GS1 nomenclature before matching a product, its barcode data is expected to be reset by these lines: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1320-L1324 In order to bypass the GS1 parser and to add 1 unit of the product. This is what happen on the first scan. However, performing the first scan also selects the associated line and, hence on the second scan the lines just above this check do set the product to match the product of the current line: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1294-L1320 In particular, we do not bypass the result provided by the GS1 parser and add `1762412` units of the product. opw-6175621 Forward-Port-Of: odoo/enterprise#122256 Forward-Port-Of: odoo/enterprise#120035
This update fixes an issue where changing an invoice's price caused incorrect payment states. Now, when an invoice's amount changes, all payments associated with it correctly transition to 'In Process', ensuring accurate reconciliation and reporting. This improves the reliability of financial data.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273563 Forward-Port-Of: odoo/odoo#269510
This update fixes an issue where group payments weren't correctly updated when invoices were changed, leading to reconciliation problems. The update ensures that all payments, including group payments, transition to 'In Process' when a statement line is unreconciled, resolving a conflict during batch payment validation.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 Forward-Port-Of: odoo/enterprise#122585 Forward-Port-Of: odoo/enterprise#120210
This update fixes an issue where bank reconciliation calculations were inaccurate when dealing with foreign currencies. The system now correctly converts amounts from the journal currency to the company currency during reconciliation, ensuring accurate balance calculations and preventing constraint errors. This improves the reliability of bank reconciliation processes.
Original PR description
### Issue: When a bank journal uses a foreign currency, reconciliation model lines with `Amount Type: From Label` (regex) could raise a constraint error or produce incorrect balances on the journal…
### Issue: When a bank journal uses a foreign currency, reconciliation model lines with `Amount Type: From Label` (regex) could raise a constraint error or produce incorrect balances on the journal entry ### Cause: The `balance` of the generated move line was set to the raw value extracted by the regex, without converting it from the journal currency to the company currency This violated the sign constraint between `balance` and `amount_currency` when the exchange rate caused a mismatch, raising a `_check_amount_currency_balance_sign` error The `amount_currency` was already correctly set Only the `balance` conversion was missing ### Steps to reproduce: - Install `accountant` - Enable a foreign currency (e.g. EUR) with two rates: yesterday: ratio < 1 (e.g. 0.5), today: ratio > 1 (e.g. 2.0) - Create a Bank journal in EUR - Open Bank Reconciliation for that journal - Add two transactions (one dated yesterday, one today) (Ref: "test BANK:0001690,00EUR EXP:00033,80", amount: 1656.20) - Create a reconciliation model (3 dots > Manage Models) (name: From Label): -- Account: 101401 Bank, Amount: BANK:0*(\d+),(\d+) -- Account: 600000 Expenses, Amount: EXP:0*(\d+),(\d+) - Apply the model on both transactions Before the fix, one raised an error due to the constraint violation - From the list view, open the Journal Entry for the other transaction Before the fix, `balance` was not converted to company currency opw-6292839 Forward-Port-Of: odoo/enterprise#121114
This update ensures that products added to the point-of-sale system, regardless of how they're added (via card or barcode scan), automatically assign themselves to the correct course. Previously, barcode scanning didn't trigger this feature. This enhancement streamlines the ordering process and improves accuracy.
Original PR description
..., point_of_sale --- When adding a product by clicking on its card with auto course allocation enabled, the product is correctly placed inside its course. However, when adding a product by scanning its barcode, the auto course allocation was not applied. This commit fixes the issue by extracting the auto course allocation logic into a separate function and calling it in both cases: clicking on the card and scanning the barcode. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6197864 Forward-Port-Of: odoo/odoo#264029
This update fixes an error in how timesheet revenue is calculated for prepaid services, specifically when using days as the unit of measure. The previous calculation was inaccurate due to rounding, leading to incorrect revenue reporting. This change ensures accurate revenue recognition for prepaid orders, reflecting discounts and the correct number of days worked.
Original PR description
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at…
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at 800/day 3. Register 1 hour on the generated task 4. Open Timesheets > Reporting, add the "Timesheet Revenues" measure Issue `timesheet_revenues` in `timesheets.analysis.report` was computed per analytic line as `(SOL.price_subtotal / SOL.qty_delivered) * (unit_amount * sol_uom.factor / ts_uom.factor)` (https://github.com/odoo/odoo/blob/16f170619d9cc5fd86529a3f17e349da37607f73/addons/sale_timesheet/report/timesheets_analysis_report.py#L42-L44). `SOL.qty_delivered` is a stored float rounded to the day UoM precision (0.01d). For 1 hour timesheeted, qty_delivered = 1/8 = 0.125d rounds to 0.13d, so the formula yields (1600 / 0.13) × (1/8) = 1538.46 instead of the correct 100. Because `qty_delivered` is recomputed each time a timesheet is added, all existing rows shift their revenue figure with every new entry. Additionally, using `price_subtotal / qty_delivered` as the per-unit rate ignores any line discount: the rate derived from a discounted subtotal divided by a delivered quantity that differs from the ordered quantity is not the effective price per day. For prepaid lines, the effective per-unit rate is `price_subtotal / product_uom_qty` — the ordered quantity is stable and the subtotal already reflects any discount — multiplied by the timesheet hours converted to the SO line UoM. opw-6150555 Forward-Port-Of: odoo/odoo#272910 Forward-Port-Of: odoo/odoo#262524
This update corrects a functionality issue in the Philippine accounting module (l10n_ph) by allowing purchase withholding taxes to be used as withhold taxes on vendor bills. This ensures accurate tax withholding calculations and compliance with Philippine regulations, streamlining the billing process for businesses operating in the Philippines.
Original PR description
Set is_withholding_tax to True on purchase withholding taxes to allow them to be used as withhold taxes on vendor bills. task-6319767
This update fixes an issue where withholding tax reports (2306/2307) were inaccurate when invoices were paid via payment instead of direct bill payment. The change ensures tax lines are correctly associated with payments, resolving incorrect income calculations and ensuring accurate reporting for this payment method.
Original PR description
Withholding taxes flagged as withhold-at-payment book their tax line on the payment's move instead of the vendor bill. This broke the 2306/2307 report two ways: the income payment base came out with the wrong sign, since bill and payment entries store it oppositely, and the per-move scoping only looked at the bill's own move, so bills paid this way had nothing to show. Normalize the base sign using the tax line's sign instead of the base's own, and extend the scoping to also match lines booked on a payment registered against the bill. task-6319767
This update resolves an issue where payruns were incorrectly selecting the main company instead of the branch company, leading to errors. The fix ensures that the correct branch company is selected during payrun creation, improving payroll accuracy. This change also addresses a similar problem in the Hong Kong localization.
Original PR description
[FIX] hr_payroll: fix correct company selection in payrun (branch case) Bug reproduc: 1 - Select 19.3 or master -> Open a branch to belgium company -> create an employee in that branch 2 - In your…
[FIX] hr_payroll: fix correct company selection in payrun (branch case)
Bug reproduc:
1 - Select 19.3 or master -> Open a branch to belgium company -> create an employee in that branch
2 - In your env, select both belgium and its branch, payroll->payrun->select branch as a company.
3 - Continue till the end of payrun creation, you will get warning (blocked) due to wrong company selection, main belg company is selected instead of branch
Bug cause:
1 - In selectEmployees function of hr_payslip_run_form, in the raw_record the company_id is passed as integer.
2 - In buildRawRecord function of hr_version_list_controller, we are assigning company_id as raw_record's company_ids id, but company id was already integer, company_id.id is undefined
3 - Since undefined is passed to the company_id, it uses the self.env.company_id as a default in the creation of hr payrun that cause to the error.
Bug fix:
1 - In the buildRawRecord function of hr_version_list_controller, I just assigned the company_id because it is already integer and all problem is solved.
task - 6326117
Forward-Port-Of: odoo/enterprise#121505This change reverses recent updates that allowed employees to directly edit personal information like marital status within the system. Management requested this revert due to concerns about potential inaccuracies impacting payroll and compliance, specifically regarding tax deductions and benefits. HR will now maintain all payroll-related data to ensure accuracy and adherence to regulations.
Original PR description
This reverts the recent changes that exposed the "Family" and "Personal Info" sections (such as Marital Status) in the employee's "My Preferences" menu. While the initial addition was intended to improve employee self-service, management requested this revert because allowing employees to directly edit these fields poses a risk to payroll accuracy and compliance. Data points like marital status or family dependents directly impact tax deductions and benefit enrollments. To ensure data integrity, any modifications to payroll-affecting information must remain the exclusive duty of the HR team, who can require and verify the proper legal documentation before updating the system. task-6304031 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#270203
This update reverts a recent change that allowed employees to directly edit sensitive payroll information like marital status. This change was removed due to concerns about potential inaccuracies impacting tax calculations and compliance. HR now retains exclusive control over updating payroll data to ensure accuracy and legal requirements are met.
Original PR description
This reverts the recent changes that exposed the "Family" and "Personal Info" sections (such as Marital Status) in the employee's "My Preferences" menu. While the initial addition was intended to improve employee self-service, management requested this revert because allowing employees to directly edit these fields poses a risk to payroll accuracy and compliance. Data points like marital status or family dependents directly impact tax deductions and benefit enrollments. To ensure data integrity, any modifications to payroll-affecting information must remain the exclusive duty of the HR team, who can require and verify the proper legal documentation before updating the system. task-6304031 Forward-Port-Of: odoo/enterprise#120646
This update removes the ability to create new journals directly from the point-of-sale payment method form. The accounting team requested this change to ensure journals are created only within the dedicated accounting application, improving process control and data integrity. The fix addresses a potential security and workflow issue.
Original PR description
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos…
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos payment method * Select the journal field * Select "Search more" > See two creation buttons Why the fix: ------------ One button is the standard "On search more" button which can be hidden using options such as no_create, no_create_edit, ... The second button is defined on the list view for journals and since the search more uses the list view it shows the button as well. Currently we can do that with a context key to ensure that on the "real" list view it's still visible. Why do we want to hide those buttons? Asked the R&D accounting team, it should not be allowed to create journals on the fly. You should only be able to create them inside accounting app. Before the fix: ------------------- <img width="700" height="417" alt="image" src="https://github.com/user-attachments/assets/6b67a45b-6e52-4e02-a827-1aca5d8417ec" /> <img width="1507" height="887" alt="image" src="https://github.com/user-attachments/assets/077bc3ab-bc6e-42a1-85e6-adf778000b92" /> After the fix: ----------------- <img width="707" height="474" alt="image" src="https://github.com/user-attachments/assets/da2a43e3-01c0-44c5-b529-e73f21825150" /> <img width="1457" height="870" alt="image" src="https://github.com/user-attachments/assets/b658b95f-5bc3-4b7a-9e7c-8b182cab48a0" /> opw-6131231 Forward-Port-Of: odoo/odoo#269716
This update resolves an issue where deleting a customized product line in the PoS would cause the preparation display to crash. The fix ensures the display remains stable by gracefully handling the deletion of order lines and their associated custom values, preventing a blank screen and maintaining order visibility for kitchen staff.
Original PR description
When an order is sent to the preparation display and one of its products has an attribute with a custom (free text) value, completely deleting that line in the PoS makes the whole preparation display…
When an order is sent to the preparation display and one of its products has an attribute with a custom (free text) value, completely deleting that line in the PoS makes the whole preparation display crash and show a blank white screen, so the kitchen can no longer see any order. Steps to reproduce: ------------------- * Configure a PoS product with an attribute whose variant that has a custom (free text) value. * In the PoS, add the product, select that attribute value and send the order to the preparation display. * Back in the PoS, completely delete that order line (do not just set its quantity to 0) and send the order to the preparation display again. > Observation: The preparation display crashes and only a white screen is shown. The browser console reports "TypeError: Cannot read properties of undefined (reading 'id')". Why the fix: ------------ Completely deleting the line deletes the source pos.order.line, so the preparation line that is still displayed no longer resolves its `pos_order_line_id`. While building the attributes to display, the orderline component dereferenced `.id` on that (now undefined) relation, as well as on the related custom value records, which threw and brought down the whole preparation display instead of only that line. We now guard those relations: when the originating order line is gone, the unresolvable custom value is simply dropped and the attribute is still shown, keeping the preparation display alive. opw-6282607 Forward-Port-Of: odoo/enterprise#121194
This update resolves an issue preventing users from creating rental orders. The fix grants the necessary access to manage rental orders and associated stock lots, ensuring a smooth rental order creation process. This improvement allows users to properly initiate and fulfill rental agreements.
Original PR description
Issue: --- It's not possible to create rental orders without stock.lot access. Steps to reproduce: 1- Change demo user access: - All inventory accesses: No 2- Enable `Rental Transfers`. 3- Login Demo user. 4- Create a rental order. You will get access error. Cause and Fix: --- `stock.lot` model is in only accessed by `group_stock_user`. As a result fields such as `reserved_lot_ids` will be problematic when we don't have stock access. We initially tried to fix the issue by limiting the problematic fields to group stock user. However that limits the user from rental pickup. Instead we are giving the required access to group rental picking user. opw-6281154 Forward-Port-Of: odoo/enterprise#120670
19 changes
Enhancements to existing features
The timesheet timer now opens with a likely project already selected based on the employee's recent timesheets, while still prioritizing the project or task currently being viewed. It also avoids preselecting archived or template records, reducing manual selection and preventing invalid time entries.
Original PR description
When opening the timesheet systray, the timer is now prefilled with the project to which the employee's three most recent timesheets are all linked, since they are most likely to keep logging time on it. The currently viewed project or task takes precedence over the favorite project, and viewing a project form now prefills the timer as well, just like task views already do. task-6290859 Forward-Port-Of: odoo/enterprise#120028
This update enhances the expense dashboard by ensuring managers can accurately view the total expenses of their team members. Previously, the dashboard's filters didn't align with the status of expenses ('To Submit', 'Waiting Approval', 'Waiting Reimbursement'). Now, managers will see consolidated expense totals, providing better visibility and control.
Original PR description
For the expense dashboard with the states 'To Submit', 'Waiting Approval' and 'Waiting Reimbursement', make these states compliants with the current filters of the list view. It means, for example, that a manager can see the total amounts of the people he manages. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273398 Forward-Port-Of: odoo/odoo#270234
Resolved issues and error corrections
Audit reports exported to PDF now include images that users inserted with the file command. This prevents missing visual evidence or context in downloaded reports and makes the PDF match the report content more accurately.
Original PR description
Currently, when a user uses the `/file` command to insert an image into an audit report and exports the report to PDF, the image is omitted from the generated PDF. To improve the support of those blocks, we will pre-process the document and replace the embedded files that correspond to images with standard image elements before PDF generation. This will ensure that images are correctly rendered and displayed within the document's text flow in the exported PDF. Task [link](https://www.odoo.com/odoo/project.task/5115280) task-5115280 Forward-Port-Of: odoo/enterprise#122699 Forward-Port-Of: odoo/enterprise#121673
This update fixes a bug where loyalty reward descriptions weren't consistently translating across multiple languages. Now, when you change the description of a discount code in one language, it automatically updates in all other languages, ensuring accurate and localized messaging for our customers. This improves the overall user experience and consistency of our loyalty program.
Original PR description
### Steps to Reproduce 1. Activate any other language (ex. FR) 2. Create a new Discount code in Discount & Loyalty 3. Change your user language preference to FR, open the newly created loyalty…
### Steps to Reproduce 1. Activate any other language (ex. FR) 2. Create a new Discount code in Discount & Loyalty 3. Change your user language preference to FR, open the newly created loyalty reward, and change the Description on Order to Test Discount for both languages 4. Navigate to the backend Product Variants menu and observe how its name did not translate in English ### Description of the issue/feature this PR addresses: **Issue:** When you edit a translation for a loyalty.reward description in a multi-language setup, the product name (`discount_line_product_id.name`) fails to receive the complete translation in all languages. It only updates the current language. **Solution:** Override the 'update_field_translations' method on the loyalty.reward model. When changes are saved for the 'description' field on the discount code, intercept the payload and mirror directly at the discount product's `name` field. ### Current behavior before PR: Updating the reward description only updates the current language and all other languages do not change. ### Desired behavior after PR is merged: For all languages in which changes are made in a discount code's description, the discount line product name will reflect the same changes. opw-6314760 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#271680
This update corrects a bug where global discounts were incorrectly applied in Point of Sale for users with Dutch (or similar) localization settings. The fix ensures that discount percentages, formatted with a comma as the decimal separator, are correctly calculated and applied, preventing unintended full discounts.
Original PR description
When using Dutch (or similar locales where the decimal separator is a comma), a configured global discount percentage with decimals is misapplied in POS. For example, a default discount of 8,33% is…
When using Dutch (or similar locales where the decimal separator is a comma), a configured global discount percentage with decimals is misapplied in POS. For example, a default discount of 8,33% is shown in the discount popup as 8.33% and, when confirmed without editing, applies a 100% discount on the order instead of 8,33%. Steps to reproduce: ------------------- * Activate Belgian localization for accounting * Set the user language to Dutch (Netherlands) or Dutch (Belgium) * In Point of Sale settings, enable global discounts and set the default discount percentage to 8,33% * Open a POS session, add a product to the cart, and click Discount * Confirm the popup without changing the value > Observation: The popup displays 8.33% (with a dot). After confirmation, the order receives a full discount instead of 8,33%. Why the fix: ------------ The discount popup initialized its value with `String(discount_pc)`, which always uses a dot as decimal separator. POS then parses the input with locale-aware rules where `.` is the thousands separator, so "8.33" is read as 833 and capped to 100%. Format the default discount percentage with `formatFloat` so the popup starts with the correct localized value (e.g. "8,33"). opw-6334367 Forward-Port-Of: odoo/odoo#273022
This update resolves issues where emojis inserted from the suggestion list didn't correctly remove the previous search text and caused cursor placement problems after emoji replacement on mobile devices. The changes ensure emojis are inserted properly and cursor positioning is accurate, improving the user experience.
Original PR description
**Issue 1:** Step to reproduce: - Type ':wave' to open suggestion list - Now click on any emoji from the suggestion list Description of the issue: - The selected emoji gets inserted, but the…
**Issue 1:** Step to reproduce: - Type ':wave' to open suggestion list - Now click on any emoji from the suggestion list Description of the issue: - The selected emoji gets inserted, but the `searchNode` `:wave` does not get removed and remains beside the inserted emoji Cause: - When the user clicks an emoji from the suggestion list, focus shifts to the suggestion list item. As a result, `selection.extend()` is unable to properly select the searchNode in the editable area. Because the `searchNode` is not selected, `deleteSelection()` fails to remove it before inserting the emoji. Solution: - Added the `user-select-none` class to the suggestion list to prevent selection/focus shift on emoji click, ensuring the searchNode is properly selected and replaced by the selected emoji **Issue 2:** Steps to reproduce: - Open a To-do on a mobile device. - Type `:p` to create an emoji. - Press Backspace. Issue: - When using the SwiftKey keyboard, pressing Backspace after an emoji can result in an incorrect cursor position. Cause: - When Backspace is pressed, a selection snapshot is cached during the `keydown` event. - Later, `deleteBackward` converts the emoji back to its corresponding expression (:p) by triggering an undo operation, but the cached selection does not get updated. As a result, the previously cached selection is reused, causing the cursor to be placed incorrectly. Solution: - After performing the undo, update the cached selection to match the new cursor position. - This ensures that the latest selection is used instead of the outdated selection captured during `keydown`. **Issue 3:** Steps to reproduce: - Open a To-do on a mobile device. - Type `:p` to create an emoji. - Press Backspace. Issue: - Pressing Backspace on an emoji does not revert it to its matching expression (`:p`). Cause: - On mobile devices, `event.key` can be undefined in keydown. As a result, `deleteBackward` is triggered through the `beforeinput` event, which correctly reverts the emoji to its matching expression. However, after that, the `input` event is triggered and converts the expression back into the emoji again, making it appear as if the emoji was not reverted. Solution: - When the event type is `deleteContentBackward`, skip converting the expression back into an emoji and return early. task-6201173 Forward-Port-Of: odoo/odoo#263777
This update corrects a calculation error in the Swiss tax report (l10n_ch). Previously, negative values in specific report lines resulted in incorrect subtractions. The fix ensures these lines display positive values, guaranteeing accurate tax report totals. This improves the reliability of Swiss tax reporting within the Odoo system.
Original PR description
### Issue: In 19.0, the values of lines 415 and 420 in the Swiss tax report are negative, causing line 479 to add them instead of subtracting Line 479 formula: `tax_ch_400 + tax_ch_405 + tax_ch_410 -…
### Issue: In 19.0, the values of lines 415 and 420 in the Swiss tax report are negative, causing line 479 to add them instead of subtracting Line 479 formula: `tax_ch_400 + tax_ch_405 + tax_ch_410 - tax_ch_415 - tax_ch_420` For the subtraction to be correct, 415 and 420 must be positive ### Cause: In 18.0, each tax grid had two variants (`+415`/`-415`) allowing the user to control the sign manually The double negative (`-*-`) incidentally produced positive values in the report In 19.0, the unified tax grid merges them into a single tax grid (`415`) with automatic sign handling 415 and 420 are correction lines that must appear positive in the report so that 479 subtracts them correctly The formulas were not updated to reflect this change ### Steps to reproduce: - Install `l10n_ch_reports` and `accountant` - Switch to `CH Company` - Create and confirm a Bill (Amount: 100, Tax: 8.1%) - Create and post a Journal Entry: - Account: 1170 Input Tax (VAT), Credit: 2, Tax Grids: 415 and 420 - Account: 1021 Bank, Debit: 2 - Open the Tax Report for this month Before the fix, lines 415 and 420 are negative and line 479 adds them instead of subtracting opw-6311126 Forward-Port-Of: odoo/odoo#272385
This update corrects a bug in gift card redemption within Point of Sale (PoS). When the default tax setting was 'tax included,' the system incorrectly deducted the full gift card value. The fix ensures accurate tax calculations and consistent totals, preventing under-deduction and maintaining correct tax line displays.
Original PR description
We had a bug when redeeming a gift card when the default taxe of the company was tax_included. Steps to reproduce: ------------------- * Set default 15% tax to bo Tax Included * In PoS, sell a gift card * Use that gift card in a new order > Observation: Deducted amount is 43.48, that's 50 without taxes Why the fix: ------------ We now compute the gift card reward line from a tax-aware amount and choose the unit price based on whether the discount product’s tax is price-included, ensuring we deduct the full intended value while displaying the correct tax. This prevents under-deduction (untaxed base only) and avoids re-adding tax on top, keeping totals and tax lines consistent. opw-5441106 Forward-Port-Of: odoo/odoo#244735
This update resolves an issue preventing users from creating rental orders. The fix grants necessary access to rental picking users, allowing them to successfully create and manage rental orders. This ensures a smoother experience for users utilizing the rental order functionality.
Original PR description
Issue: --- It's not possible to create rental orders without stock.lot access. Steps to reproduce: 1- Change demo user access: - All inventory accesses: No 2- Enable `Rental Transfers`. 3- Login Demo user. 4- Create a rental order. You will get access error. Cause and Fix: --- `stock.lot` model is in only accessed by `group_stock_user`. As a result fields such as `reserved_lot_ids` will be problematic when we don't have stock access. We initially tried to fix the issue by limiting the problematic fields to group stock user. However that limits the user from rental pickup. Instead we are giving the required access to group rental picking user. opw-6281154 Forward-Port-Of: odoo/enterprise#120670
This update fixes an issue where bank reconciliation calculations were inaccurate when dealing with foreign currencies. The system now correctly converts amounts from the journal currency to the company currency, ensuring accurate balance calculations and preventing errors during reconciliation processes. This improves the reliability of financial reporting.
Original PR description
### Issue: When a bank journal uses a foreign currency, reconciliation model lines with `Amount Type: From Label` (regex) could raise a constraint error or produce incorrect balances on the journal…
### Issue: When a bank journal uses a foreign currency, reconciliation model lines with `Amount Type: From Label` (regex) could raise a constraint error or produce incorrect balances on the journal entry ### Cause: The `balance` of the generated move line was set to the raw value extracted by the regex, without converting it from the journal currency to the company currency This violated the sign constraint between `balance` and `amount_currency` when the exchange rate caused a mismatch, raising a `_check_amount_currency_balance_sign` error The `amount_currency` was already correctly set Only the `balance` conversion was missing ### Steps to reproduce: - Install `accountant` - Enable a foreign currency (e.g. EUR) with two rates: yesterday: ratio < 1 (e.g. 0.5), today: ratio > 1 (e.g. 2.0) - Create a Bank journal in EUR - Open Bank Reconciliation for that journal - Add two transactions (one dated yesterday, one today) (Ref: "test BANK:0001690,00EUR EXP:00033,80", amount: 1656.20) - Create a reconciliation model (3 dots > Manage Models) (name: From Label): -- Account: 101401 Bank, Amount: BANK:0*(\d+),(\d+) -- Account: 600000 Expenses, Amount: EXP:0*(\d+),(\d+) - Apply the model on both transactions Before the fix, one raised an error due to the constraint violation - From the list view, open the Journal Entry for the other transaction Before the fix, `balance` was not converted to company currency opw-6292839 Forward-Port-Of: odoo/enterprise#121114
A recent issue in the mass mailing functionality caused crashes when opening emails after they were sent. This fix addresses a problem where evaluating inline QWeb nodes with nested structures resulted in errors. The update ensures mass mailings display correctly without causing unexpected crashes.
Original PR description
Prior to this commit, if a `<t>` node had children, the function evaluating if they should be displayed inline or not would crash. How to reproduce: - send a mass_mailing with qweb instructions: a `t-if` node containing a `t-out` - open the mass_mailing after it was sent (in readonly) Issue: - crash when opening the mass mailing (in Email Marketing) task-6250450 Forward-Port-Of: odoo/odoo#273446 Forward-Port-Of: odoo/odoo#266663
This update fixes an issue where GS1-compliant product barcodes were incorrectly interpreted, leading to inaccurate quantity updates during scanning. Enabling the 'Default GS1 Nomenclature' setting now ensures that GS1 barcodes are correctly processed as product scans, resolving a potential data discrepancy in inventory management. This improves the reliability of barcode scanning for stock tracking.
Original PR description
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings…
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings enable "Default GS1 Nomenclature" - Create a storable product P with the barcode 3701762412212 - Create and confirm a delivery for 2 units of P and set the qty to 2 - Go to the barcode app and open your delivery - Scan 3701762412212 > The line of P is now selected with a quantity of 1/2 - Scan 3701762412212 #### > A new line is created for 1762411 units ### Cause of the issue: According to the GS1 nomenclature, the barcode 3701762412212 matches the scan of a quantity of "1762412" units of the lot name "2". As the scan of the of the product match a pattern for the GS1 nomenclature before matching a product, its barcode data is expected to be reset by these lines: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1320-L1324 In order to bypass the GS1 parser and to add 1 unit of the product. This is what happen on the first scan. However, performing the first scan also selects the associated line and, hence on the second scan the lines just above this check do set the product to match the product of the current line: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1294-L1320 In particular, we do not bypass the result provided by the GS1 parser and add `1762412` units of the product. opw-6175621 Forward-Port-Of: odoo/enterprise#122256 Forward-Port-Of: odoo/enterprise#120035
This update ensures that automatic course allocation works consistently for all product additions, regardless of whether a user clicks on a product card or scans its barcode. Previously, scanning barcodes didn't trigger the automatic course assignment, leading to manual adjustments. This fix streamlines the ordering process for restaurant staff.
Original PR description
..., point_of_sale --- When adding a product by clicking on its card with auto course allocation enabled, the product is correctly placed inside its course. However, when adding a product by scanning its barcode, the auto course allocation was not applied. This commit fixes the issue by extracting the auto course allocation logic into a separate function and calling it in both cases: clicking on the card and scanning the barcode. --- Task: https://www.odoo.com/odoo/project/1737/tasks/6197864 Forward-Port-Of: odoo/odoo#264029
This update fixes an error in how timesheet revenue is calculated for prepaid services, ensuring accurate reporting. The previous calculation incorrectly accounted for day UoM precision, leading to inflated revenue figures. The fix now uses the correct per-unit rate, reflecting discounts and ensuring accurate revenue reporting for prepaid orders.
Original PR description
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at…
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at 800/day 3. Register 1 hour on the generated task 4. Open Timesheets > Reporting, add the "Timesheet Revenues" measure Issue `timesheet_revenues` in `timesheets.analysis.report` was computed per analytic line as `(SOL.price_subtotal / SOL.qty_delivered) * (unit_amount * sol_uom.factor / ts_uom.factor)` (https://github.com/odoo/odoo/blob/16f170619d9cc5fd86529a3f17e349da37607f73/addons/sale_timesheet/report/timesheets_analysis_report.py#L42-L44). `SOL.qty_delivered` is a stored float rounded to the day UoM precision (0.01d). For 1 hour timesheeted, qty_delivered = 1/8 = 0.125d rounds to 0.13d, so the formula yields (1600 / 0.13) × (1/8) = 1538.46 instead of the correct 100. Because `qty_delivered` is recomputed each time a timesheet is added, all existing rows shift their revenue figure with every new entry. Additionally, using `price_subtotal / qty_delivered` as the per-unit rate ignores any line discount: the rate derived from a discounted subtotal divided by a delivered quantity that differs from the ordered quantity is not the effective price per day. For prepaid lines, the effective per-unit rate is `price_subtotal / product_uom_qty` — the ordered quantity is stable and the subtotal already reflects any discount — multiplied by the timesheet hours converted to the SO line UoM. opw-6150555 Forward-Port-Of: odoo/odoo#272910 Forward-Port-Of: odoo/odoo#262524
This update fixes an issue where the Auto Plan feature incorrectly assigned resources to slots, regardless of the role assigned to the slot. The fix ensures that resources are only assigned based on their role, preventing misallocation and improving planning accuracy. This ensures resources are assigned to the correct roles for optimal scheduling.
Original PR description
## Issue When using the *Auto Plan* feature on a planning slot with a Role and a Project set, a resource which operated on the same project will be chosen if available, without taking into account…
## Issue
When using the *Auto Plan* feature on a planning slot with a Role and a Project set, a resource which operated on the same project will be chosen if available, without taking into account the Role set on the slot.
## Steps to reproduce
1. Install Project Planning (`project_forecast`)
2. In Planning > Configuration > Roles, create two planning roles A and B
- Role A: Assign a resource R
- Role B: No resource
3. Open Planning (Schedule by Resource), and go back a few weeks (to prevent overlaps with potential demo data)
4. Create two new slots:
1. Set Role B and a random Project P, then click Auto Plan: there should be no available resource (because we didn't set any resource for Role B)
2. Set Role A and the same Project P, then click Auto Plan: it should assign the resource R assigned to Role A
5. After assigning a resource to the slot for Role A, edit the Open Shift for Role B again and click Auto Plan: **it assigns the same resource R, even though that resource is not assigned to Role B.**
## Cause
The `_get_open_shifts_resources` override in `project_forecast` looks for resources that were assigned to slots related to the same project. It does not filter resources based on the requested role.
https://github.com/odoo/enterprise/blob/885edbc270a86ab76e0a6eff4acb5767c0fe29d1/project_forecast/models/planning_slot.py#L104-L116
This means that resources that are not part of the requested role can be assigned to the slot, as long as the resource operated on another slot for the same project.
opw-6325744
Forward-Port-Of: odoo/enterprise#122352
Forward-Port-Of: odoo/enterprise#122035This update resolves an issue where editing lot IDs in tracked stock moves led to incorrect quantity updates. The fix ensures that lot assignments accurately reflect stock levels and reservations, maintaining consistency when managing lot-tracked products. This improves the reliability of stock tracking and order fulfillment.
Original PR description
### Issue: Editing the `lot_ids` of a move of a `lot` tracked product from the picking form view leads to wildly unexpected results. This happens only with tracking by `lot` not by serial. ###…
### Issue:
Editing the `lot_ids` of a move of a `lot` tracked product from the picking form view leads to wildly unexpected results. This happens only with tracking by `lot` not by serial.
### Concrete Issue 1:
1. In the settings Enable "Lots and serial numbers", "Storage Locations"
2. Create a storable product P tracked by lots
3. Create and confirm a delivery for 5 units of P
4. Set the quantity of the move to 5 from the Form picking view > save
5. Create and set 2 lots: LOT1, LOT2 on the serial numbers field
6. Save
#### > The quantity of the move has been updated to 2, only the first lot is set and it has been for this quantity of 2
### Concrete Issues 2 and 3:
1. In the settings Enable "Lots and serial numbers", "Storage Locations"
2. Create a storable product P tracked by lots
3. Update the onhand quantity of P:
- 1 units of LOT001 in Shelf1
- 2 units of LOT001 in Shelf2
- 2 units of LOT002 in Stock
4. Create and confirm a delivery for 5 units of P
5. Remove LOT002 from the Serial numbers in the Form picking view > save
#### > The quantity of the move is updated to 1 (only the 1 unit of LOT001 from Shelf2 is kept)
5'. Remove LOT002 and put it back
#### > The quantity is updated from 5 to 2 if you save, only LOT001 is kept.
### Cause of the issue:
The `_onchange_lot_ids` and `_set_lot_ids` methods have been tailored to work appropriately only with `serial` tracking, updating the quantities considering a 1 to 1 quantity, lot matching:
https://github.com/odoo/odoo/blob/c9715982134220aa8fa525d0cf6a8d47eaeb6ed6/addons/stock/models/stock_move.py#L623-L645
However, for lot tracked product the situation is much more subtle to handle.
### Behavior after the fix:
Editing the `lot_ids` on tracked products should adapt the reservation following these rules:
- Existing move lines with a valid lot or lot name should be kept unchanged.
- Removing a lot should delete its related move lines and adjust the move quantity accordingly.
- Each newly assigned lot must be linked to at least one move line of the move.
If the move is expected to bypass reservation (e.g. receipts, final move of a production,...):
- Assignment should be performed, in priority, on an existing free move line.
- If no suitable free move line exists, a new move line should be created with the largest possible quantity that does not cause the total assigned quantity to exceed the move demand.
- If such a quantity cannot be assigned, the new move line should be created with a quantity of 1 in the product.uom_id.
If the move is expected to be reserved (e.g. internal transfer, deliveries,...):
- Each new lot should be assigned from an existing quants with the maximum available quantity to satisfy at best the remaining demand.
- If no available quantity can be assigned from existing quants, the lot should be assigned a minimum quantity of 1 in product.uom_id.
### Additional note on the fix:
Since move that do bypass reservation use a different detailed operation view relying on lot_names form move line rather than lot_id from existing quants it is important to set both the `lot_name` as well as the `lot_id` on move lines for the changes to be visible in the detailed operations view.
### Note:
The current fix populated records on which the `label_production_view_pdf` report was tested (by the test_report) highlighting a template error:
https://github.com/odoo/odoo/blob/a73428187112b3948a11810abae2a3c82c9c7bcd/addons/mrp/report/mrp_production_templates.xml#L187
The value provided to the t-field being something else than a field but rather an or close between two fields.
opw-6173914
opw-5881661
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#272253
Forward-Port-Of: odoo/odoo#263037This update speeds up partner searches within the Point of Sale (POS) system. Previously, searching through a large number of partners was slow due to rendering all filtered results. Now, the system limits the displayed results to 200 and adjusts the search input's delay to reduce unnecessary calls, resulting in a smoother and faster user experience.
Original PR description
Before this commit, when high number of partners were loaded in the POS, searching for a partner was slow. The main issue was that all of the filtered partners based on the search query were being rendered, while in reality, if a query returns lots of results, the search query is not refined enough and the user is likely to type more characters to narrow down the search. So in this commit, we limit the number of rendered partners to 200, which is a reasonable number of results to display and does not cause performance issues. Moreover, the debounce time of the search input has been increased from 100ms to 500ms to further reduce the number of times the search function is called while the user is typing. opw-6215958 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#268658 Forward-Port-Of: odoo/odoo#264300
This update removes the ability to create new journals directly from the point-of-sale payment method form. The change, requested by the accounting team, ensures that journal creation is restricted to the accounting application, improving data integrity and process control. This prevents accidental or unauthorized journal creation during POS transactions.
Original PR description
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos…
Currently on the pos payment method form, if you click "Select more" on the journal field, you will see two buttons 'New' & 'Create New'. Steps to reproduce: ------------------- * Open any pos payment method * Select the journal field * Select "Search more" > See two creation buttons Why the fix: ------------ One button is the standard "On search more" button which can be hidden using options such as no_create, no_create_edit, ... The second button is defined on the list view for journals and since the search more uses the list view it shows the button as well. Currently we can do that with a context key to ensure that on the "real" list view it's still visible. Why do we want to hide those buttons? Asked the R&D accounting team, it should not be allowed to create journals on the fly. You should only be able to create them inside accounting app. Before the fix: ------------------- <img width="700" height="417" alt="image" src="https://github.com/user-attachments/assets/6b67a45b-6e52-4e02-a827-1aca5d8417ec" /> <img width="1507" height="887" alt="image" src="https://github.com/user-attachments/assets/077bc3ab-bc6e-42a1-85e6-adf778000b92" /> After the fix: ----------------- <img width="707" height="474" alt="image" src="https://github.com/user-attachments/assets/da2a43e3-01c0-44c5-b529-e73f21825150" /> <img width="1457" height="870" alt="image" src="https://github.com/user-attachments/assets/b658b95f-5bc3-4b7a-9e7c-8b182cab48a0" /> opw-6131231 Forward-Port-Of: odoo/odoo#269716
This update resolves a performance issue in the previous memory profiler, which significantly impacted Odoo's speed. The team switched to a new approach using psutil for tracking memory allocations, reducing overhead and improving responsiveness. This change provides a more accurate and efficient way to identify memory usage within Odoo.
Original PR description
The previous memory profiler was causing a lot of performance issues. This is because tracemalloc tracks the allocations that happens at the python interpreter level by attaching to the cpython…
The previous memory profiler was causing a lot of performance issues. This is because tracemalloc tracks the allocations that happens at the python interpreter level by attaching to the cpython allocators. This first meant each allocation that happens through python has to go through a callstack while holding the GIL and preventing the thread and other threads from operating. This callstack does multiple things, first is walking the allocation back from the current frame up until the specified frame depth at the start of collection. The other is updating the internal object that keeps track of the allocations and what cause them up until now which degrades the performance even more when the allocator keeps running for a long time. Increasing the frame depth also means the partitioning becomes even more fragmented in the internal object and leads to higher memory usage. This in turns means lower performance as well. The issue becomes more evident when the overhead of tracemalloc blocks any execution even turning it off because the gil cannot be released until the full allocation execution happens. Currently this would happen on long enough requests or a high enough depth. Two PRs were made to try to address this issue. 1- https://github.com/odoo/odoo/pull/251950 : This PR tries the solution of having a lower frame depth but matching the frames based on a window of frames so that we can reconstruct an approximation of the flamegraph, for example: matching window of 2 frames 1 - > 2 - > 3 - > 4 2 - > 3 - > 4 - > 5 would mean that we would match frames 2 and 3 in both stack traces and append the first frame to the second callstack which would look like 1 - > 2 - > 3 - > 4 - > 5 Neverthless this was deemed to have too big of an assumption in the building heuristic. 2- https://github.com/odoo/odoo/pull/253120: This PR was supposed to be introducing memray as a profiler. Memray is the best tool for this usecase. First because it attaches on the native system allocation calls, and uses a file to append to on allocations. This solves both of the issues that we had in the beginning but the issue with memray is that it's an external tool that was deemed unnecessary to add. The final solution is this PR: The PR assumes a heuristic that in worker mode, a single worker handles one thread which mean that the process memory can be fully attributed to the request. The heuristic is also based that on a high enough sampling rate, the delta can be fully attributed to the current frame. This is a close enough approximation to know where to look but not what is the actual memory usage by line. Forward-Port-Of: odoo/odoo#273158 Forward-Port-Of: odoo/odoo#253604
10 changes
Resolved issues and error corrections
The Work Order employee planning view now only loads employees for the active company. This prevents access errors in multi-company setups and lets manufacturing planners open the schedule reliably.
Original PR description
Issue ----- When there are employees in different companies, opening the Work Order planning view causes an access error. Steps to reproduce ----- - Create 2 companies - Create an employee in each company - Go to Manufacturing > Planning > Employee Planning > Acces error Cause ----- The error happens in `_gantt_unavailability` when trying to browse the employee list https://github.com/odoo/enterprise/blob/5ddef3263d4d9788b894ea465fb183e53d4c9e89/mrp_workorder/models/mrp_workorder.py#L696 This function is called by `get_gantt_view` when loading the page. The list of ids come from https://github.com/odoo/enterprise/blob/5ddef3263d4d9788b894ea465fb183e53d4c9e89/mrp_workorder/models/mrp_workorder.py#L639 We can provide a domain to restrict the search to the current company instead. ----- Ticket: opw-6302105
This update fixes a bug where employees with the 'Judicially Separated' marital status were incorrectly receiving zero tax deductions. The update now accurately calculates withholding taxes and special social contributions for this status, ensuring accurate payroll processing. This resolves a potential overpayment of taxes.
Original PR description
**Steps to Reproduce:** 1. Create a new employee. 2. Set their marital status to "Judicially Separated". 3. Generate a payslip. **Reason:** - The "Judicially Separated" marital status was not explicitly included in the conditions for calculating withholding taxes or special social contributions. As a result, employees with this status bypassed the calculations entirely, receiving a rate of 0 for both and a significantly larger reduction on master which also appears to be incorrect. **Solution:** - Included the 'separated' status in isolated tax and CSSS logic. Task-6321245 Forward-Port-Of: odoo/enterprise#122193 Forward-Port-Of: odoo/enterprise#121457
This update ensures that short URLs generated by the Email Marketing module consistently use the correct base URL (`web.base.url`) regardless of the context. Previously, these URLs were incorrectly using company-specific domains, leading to unexpected behavior in automated processes like mass mailing queues. This fix corrects a critical issue that impacts URL accuracy across all operations.
Original PR description
The [`_compute_short_url_host`](https://github.com/odoo/odoo/blob/a81fa8699c89385d2cccb260ada07255c6ea1275/addons/website_links/models/link_tracker.py#L20-L24) override builds link.tracker short URLs…
The [`_compute_short_url_host`](https://github.com/odoo/odoo/blob/a81fa8699c89385d2cccb260ada07255c6ea1275/addons/website_links/models/link_tracker.py#L20-L24) override builds link.tracker short URLs from `website.get_current_website()` and the current company's website domain. It was introduced by https://github.com/odoo/odoo/commit/f13ecb15af7f0bdc67e37dfb41e8bac77f5a541a for a multi-company backend flow (users switching companies to post social marketing links), but it runs for every compute, including CRON contexts with no HTTP request such as the mass-mailing queue. Without a request, `get_current_website()` picks an arbitrary website (the first in the database) and `self.env.company` resolves to the user's main company, so the short URL uses that company's website domain instead of `web.base.url`. Fall back to `super()._compute_short_url_host()` (which uses `web.base.url`) when no website is resolvable from the request, session, or context. Backend flows with a real request still hit the company-aware branch. Steps to reproduce: 1. Install Email Marketing and Website. 2. Settings > Companies: create a second company B. Settings > Websites: ensure website A points to company A with domain A, and create website B for company B with domain B. 3. Settings > Technical > Parameters > System Parameters: set `web.base.url` to a third domain C, and add `web.base.url.freeze` = `True`. 4. On company A, Email Marketing: create a mailing with body `<a href="http://example.com">test</a>` and a recipient list, then click Send. 5. Settings > Technical > Automation > Scheduled Actions > "Mass Mailing: Process queue" > Run Manually. 6. Email Marketing > Configuration > Link Tracker: open the tracker generated for the mailing. => The Tracked URL uses domain A. => The Tracked URL uses domain C. Ticket [link](https://www.odoo.com/odoo/project.task/6038590) opw-6038590 Forward-Port-Of: odoo/odoo#259200
This fix resolves an issue where editing lot IDs on tracked products in the picking form caused unexpected quantity updates. The update ensures that lot assignments correctly adjust reservations, maintaining accurate stock levels and quantities, particularly when managing lot-tracked inventory. This improves the reliability of stock movements and reduces potential discrepancies.
Original PR description
### Issue: Editing the `lot_ids` of a move of a `lot` tracked product from the picking form view leads to wildly unexpected results. This happens only with tracking by `lot` not by serial. ###…
### Issue:
Editing the `lot_ids` of a move of a `lot` tracked product from the picking form view leads to wildly unexpected results. This happens only with tracking by `lot` not by serial.
### Concrete Issue 1:
1. In the settings Enable "Lots and serial numbers", "Storage Locations"
2. Create a storable product P tracked by lots
3. Create and confirm a delivery for 5 units of P
4. Set the quantity of the move to 5 from the Form picking view > save
5. Create and set 2 lots: LOT1, LOT2 on the serial numbers field
6. Save
#### > The quantity of the move has been updated to 2, only the first lot is set and it has been for this quantity of 2
### Concrete Issues 2 and 3:
1. In the settings Enable "Lots and serial numbers", "Storage Locations"
2. Create a storable product P tracked by lots
3. Update the onhand quantity of P:
- 1 units of LOT001 in Shelf1
- 2 units of LOT001 in Shelf2
- 2 units of LOT002 in Stock
4. Create and confirm a delivery for 5 units of P
5. Remove LOT002 from the Serial numbers in the Form picking view > save
#### > The quantity of the move is updated to 1 (only the 1 unit of LOT001 from Shelf2 is kept)
5'. Remove LOT002 and put it back
#### > The quantity is updated from 5 to 2 if you save, only LOT001 is kept.
### Cause of the issue:
The `_onchange_lot_ids` and `_set_lot_ids` methods have been tailored to work appropriately only with `serial` tracking, updating the quantities considering a 1 to 1 quantity, lot matching:
https://github.com/odoo/odoo/blob/c9715982134220aa8fa525d0cf6a8d47eaeb6ed6/addons/stock/models/stock_move.py#L623-L645
However, for lot tracked product the situation is much more subtle to handle.
### Behavior after the fix:
Editing the `lot_ids` on tracked products should adapt the reservation following these rules:
- Existing move lines with a valid lot or lot name should be kept unchanged.
- Removing a lot should delete its related move lines and adjust the move quantity accordingly.
- Each newly assigned lot must be linked to at least one move line of the move.
If the move is expected to bypass reservation (e.g. receipts, final move of a production,...):
- Assignment should be performed, in priority, on an existing free move line.
- If no suitable free move line exists, a new move line should be created with the largest possible quantity that does not cause the total assigned quantity to exceed the move demand.
- If such a quantity cannot be assigned, the new move line should be created with a quantity of 1 in the product.uom_id.
If the move is expected to be reserved (e.g. internal transfer, deliveries,...):
- Each new lot should be assigned from an existing quants with the maximum available quantity to satisfy at best the remaining demand.
- If no available quantity can be assigned from existing quants, the lot should be assigned a minimum quantity of 1 in product.uom_id.
### Additional note on the fix:
Since move that do bypass reservation use a different detailed operation view relying on lot_names form move line rather than lot_id from existing quants it is important to set both the `lot_name` as well as the `lot_id` on move lines for the changes to be visible in the detailed operations view.
### Note:
The current fix populated records on which the `label_production_view_pdf` report was tested (by the test_report) highlighting a template error:
https://github.com/odoo/odoo/blob/a73428187112b3948a11810abae2a3c82c9c7bcd/addons/mrp/report/mrp_production_templates.xml#L187
The value provided to the t-field being something else than a field but rather an or close between two fields.
opw-6173914
opw-5881661
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#263037This update corrects a bug in the Point of Sale system where global discount percentages with comma decimal separators (like in Dutch) were incorrectly applied. The fix ensures that discounts are calculated accurately based on the user's locale, preventing orders from being discounted to 100% instead of the intended percentage. This improves the reliability of the POS discount functionality.
Original PR description
When using Dutch (or similar locales where the decimal separator is a comma), a configured global discount percentage with decimals is misapplied in POS. For example, a default discount of 8,33% is…
When using Dutch (or similar locales where the decimal separator is a comma), a configured global discount percentage with decimals is misapplied in POS. For example, a default discount of 8,33% is shown in the discount popup as 8.33% and, when confirmed without editing, applies a 100% discount on the order instead of 8,33%. Steps to reproduce: ------------------- * Activate Belgian localization for accounting * Set the user language to Dutch (Netherlands) or Dutch (Belgium) * In Point of Sale settings, enable global discounts and set the default discount percentage to 8,33% * Open a POS session, add a product to the cart, and click Discount * Confirm the popup without changing the value > Observation: The popup displays 8.33% (with a dot). After confirmation, the order receives a full discount instead of 8,33%. Why the fix: ------------ The discount popup initialized its value with `String(discount_pc)`, which always uses a dot as decimal separator. POS then parses the input with locale-aware rules where `.` is the thousands separator, so "8.33" is read as 833 and capped to 100%. Format the default discount percentage with `formatFloat` so the popup starts with the correct localized value (e.g. "8,33"). opw-6334367 Forward-Port-Of: odoo/odoo#273022
This update corrects a bug in gift card redemption within Point of Sale (PoS). Previously, when the default tax setting was 'tax included,' gift card deductions were inaccurate. The fix ensures the correct value is deducted and displayed, maintaining accurate tax totals and preventing miscalculations.
Original PR description
We had a bug when redeeming a gift card when the default taxe of the company was tax_included. Steps to reproduce: ------------------- * Set default 15% tax to bo Tax Included * In PoS, sell a gift card * Use that gift card in a new order > Observation: Deducted amount is 43.48, that's 50 without taxes Why the fix: ------------ We now compute the gift card reward line from a tax-aware amount and choose the unit price based on whether the discount product’s tax is price-included, ensuring we deduct the full intended value while displaying the correct tax. This prevents under-deduction (untaxed base only) and avoids re-adding tax on top, keeping totals and tax lines consistent. opw-5441106 Forward-Port-Of: odoo/odoo#244735
This update ensures that invoice PDFs automatically translate the recipient's address (like VAT numbers) into the customer's preferred language. Previously, the system wasn't correctly applying language settings to PDF reports. This improves the user experience and compliance with local regulations.
Original PR description
We currently set the recipient address before we rebrowse the related records. It is therefore not translated into the recipient's language.
Steps to reproduce on Runbot:
1. Set the language of the user to English.
2. Install the l10n_es localization with demo data.
3. Switch to the ES company.
4. Create an invoice for a customer with a VAT number.
5. Set the language of that customer to Spanish.
6. Print the PDF.
The sender address `vat_label` is correctly translated to "NIF", but the `vat_label` of the recipient address remains in English: "VAT".
Ticket [link](https://www.odoo.com/odoo/project.task/6193141)
opw-6193141This update resolves a problem that could cause installation of the Spanish VAT module (`l10n_es_edi_verifactu`) to fail due to excessive memory usage. The issue stemmed from complex calculations within the module, specifically related to existing invoices. This fix ensures smoother and more reliable installation, particularly for databases with existing data.
Original PR description
### Description: When trying to install the module `l10n_es_edi_verifactu` on a database that already has moves, it is possible to encounter a timeout or a memory error. This is caused by the compute `l10n_es_edi_verifactu_state` and `l10n_es_edi_verifactu_clave_regimen`, both compute linked to the new model `l10n_es_edi_verifactu.document`. ### Reference: opw-6293590 Forward-Port-Of: odoo/odoo#271550
This update fixes an issue where shifts spanning multiple days were incorrectly adding an extra minute to their allocated time. The change ensures that shift durations align precisely with the template, resolving inaccuracies in planning reports. This improves the accuracy of employee scheduling and reporting.
Original PR description
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift…
**Problem:** On a round-the-clock (0h-24h) working schedule, shifts created from a shift template that spans more than one day get one extra minute added to their allocated time: an 8-hour shift shows 08:01. **Steps to reproduce:** 1. Create a working schedule with a 00:00 -> 24:00 attendance for every day (24h/day, "Full Day"). 2. Assign an employee to that schedule. 3. Create a multi-day-span shift template (e.g. 16:00 -> 00:00, 2 days). 4. Plan a shift for that employee using the template. 5. Observe the Allocated Time shows one minute more than expected (08:01). **Current behavior:** Allocated Time is one minute too long (e.g. 08:01 instead of 08:00), which throws off the customer's planning reports. **Expected behavior:** Allocated Time matches the template duration exactly (08:00). **Cause of the issue:** In `_calculate_start_end_dates`, the end of a multi-day-span shift is computed with `resource.calendar_id.plan_days(...)`. On a 0h-24h calendar each day ends at `time.max` (23:59:59.999999), so `plan_days` returns an end datetime carrying those stale seconds. The following `end.replace(hour=..., minute=...)` overwrites only the hour and minute, leaving `second=59, microsecond=999999`. The slot is therefore ~1 minute longer than intended, and `allocated_hours` rounds that up to 08:01. **Fix:** Resetting seconds and microseconds when rebuilding the end datetime keeps the slot aligned to the template's whole-minute boundary, regardless of how the underlying calendar represents the end of day. The hour/minute already come from the template, so the leftover sub-minute precision from `plan_days` is never meaningful and is what produces the drift. opw-6265238 Forward-Port-Of: odoo/enterprise#121964 Forward-Port-Of: odoo/enterprise#120219
This update fixes a formatting issue in the Mexican tax reporting XML generated by the accounting module. The report now adheres to the specific requirements of the Mexican tax authority (SAT), ensuring accurate and compliant reporting. This ensures seamless integration with Mexican tax regulations.
Original PR description
**Steps to reproduce:** - Install the `l10n_mx_reports` module and switch to a Mexican company. - Navigate to Accounting > Reporting > Trial Balance. - From the dropdown menu, click `SAT (XML)`. -…
**Steps to reproduce:** - Install the `l10n_mx_reports` module and switch to a Mexican company. - Navigate to Accounting > Reporting > Trial Balance. - From the dropdown menu, click `SAT (XML)`. - Open the generated XML file and inspect the `<BCE:Ctas>` nodes. **Observation:** - The generated XML uses the following attribute order: `Debe > NumCta > Haber > SaldoFin > SaldoIni` - However, the SAT-recommended structure is: `NumCta > SaldoIni > Debe > Haber > SaldoFin` **Root Cause:** At [1], the attributes of the `<BCE:Ctas>` node are defined in an order that differs from the SAT-recommended structure. While the XML remains valid, the generated report does not match the layout recommended by the Mexican government specification. **Fix:** This commit reorders the `<BCE:Ctas>` attributes to follow the SAT-recommended structure, aligning the generated XML with the behavior introduced at [2] for `saas-19.3`. backport-of: https://github.com/odoo/enterprise/pull/115374 [1]: https://github.com/odoo/enterprise/blob/cb9c19272309d793379fa4d23145162f72fa5552/l10n_mx_reports/data/templates/cfdibalance.xml#L15-L20 [2]: https://github.com/odoo/enterprise/blob/acf0929a88ec788aecd44f6b4c647e468dc0a319/l10n_mx_reports/data/templates/cfdibalance.xml#L17-L22 opw-6297711 Forward-Port-Of: odoo/enterprise#122469 Forward-Port-Of: odoo/enterprise#121440
4 changes
Resolved issues and error corrections
Warehouse staff can now scan a package as the destination package during picking even when that package already contains other products. This prevents an incorrect error from blocking normal barcode workflows when extra products are not allowed for the operation.
Original PR description
### Steps to reproduce: - In the settings Enable: Multi-steps Routes, Packages - Put your warehouse in delivery in 2-steps - On the Pick operation type in the barcode tab disable: "Allow extra…
### Steps to reproduce: - In the settings Enable: Multi-steps Routes, Packages - Put your warehouse in delivery in 2-steps - On the Pick operation type in the barcode tab disable: "Allow extra products" - Create two storable products P1 and P2 - On P2 > On hand > Update Quantity > New - Create a new line in WH/Output with a package POOK for 1 unit - Create a new internal transfer for 1 unit of P1 using the pick operation type so that the picking goes WH/Stock -> WH/Output - Set the quantity of the move to 1 unit and go to the barcode app - Open the Pick > Scan WH-STOCK > Scan P1 > Scan POOK #### > An error is raised: This package contains extra products and extra products are not allowed on this operation. #### Expected behavior: The package should be set as result package. ### Cause of the issue: In the `_processPackage`, a check that is done to ensure that the package scan will not add extraproduct to the picking if this operation is not allowed: https://github.com/odoo/enterprise/blob/5e4c8ecb0c644e21755570ed59cd8f6e9f618c8a/stock_barcode/static/src/models/barcode_picking_model.js#L2024-L2035 Unfortunately, this check is done just before a possible usage of the package as package dest. And, in that case, since we do not try to add any product to the picking the check is irrelevant anyway. opw-6303969 Forward-Port-Of: odoo/enterprise#121789
This update corrects a calculation error in the Swiss tax report (l10n_ch). Previously, negative values in certain report lines resulted in incorrect subtractions. The fix ensures these lines display positive values, guaranteeing accurate tax report totals. This improves the reliability of Swiss tax reporting within the Odoo system.
Original PR description
### Issue: In 19.0, the values of lines 415 and 420 in the Swiss tax report are negative, causing line 479 to add them instead of subtracting Line 479 formula: `tax_ch_400 + tax_ch_405 + tax_ch_410 -…
### Issue: In 19.0, the values of lines 415 and 420 in the Swiss tax report are negative, causing line 479 to add them instead of subtracting Line 479 formula: `tax_ch_400 + tax_ch_405 + tax_ch_410 - tax_ch_415 - tax_ch_420` For the subtraction to be correct, 415 and 420 must be positive ### Cause: In 18.0, each tax grid had two variants (`+415`/`-415`) allowing the user to control the sign manually The double negative (`-*-`) incidentally produced positive values in the report In 19.0, the unified tax grid merges them into a single tax grid (`415`) with automatic sign handling 415 and 420 are correction lines that must appear positive in the report so that 479 subtracts them correctly The formulas were not updated to reflect this change ### Steps to reproduce: - Install `l10n_ch_reports` and `accountant` - Switch to `CH Company` - Create and confirm a Bill (Amount: 100, Tax: 8.1%) - Create and post a Journal Entry: - Account: 1170 Input Tax (VAT), Credit: 2, Tax Grids: 415 and 420 - Account: 1021 Bank, Debit: 2 - Open the Tax Report for this month Before the fix, lines 415 and 420 are negative and line 479 adds them instead of subtracting opw-6311126 Forward-Port-Of: odoo/odoo#272385
This update resolves a problem where the logout button triggered duplicate requests, causing CSRF errors. It now ensures only one logout request is sent, improving website stability. Additionally, a test automation fix now automatically enables the 'Free sign up' setting, simplifying test execution and reducing manual intervention.
Original PR description
### Commit 1: [FIX] website: prevent CSRF error by blocking duplicate form submission Before this commit: Clicking the logout button from the website preview triggered two simultaneous logout…
### Commit 1:
[FIX] website: prevent CSRF error by blocking duplicate form submission
Before this commit: Clicking the logout button from the website
preview triggered two simultaneous logout requests:
1. The browser performed the default form submission with a valid
`csrf_token`, destroying the session afterward.
2. During the same click event, `setupClickListener()` intercepted
the click using `closest('[action]')`, found the parent
`/web/session/logout` form, and triggered a second POST request
using `odoo.csrf_token`.
Since the session was already destroyed by the first request, the
second request resulted in a "CSRF validation failed" error.
This commit prevents the default form submission before triggering
the manual POST request, ensuring that only one request is sent.
Runbot-940403
--------------------------------------------------------------------------------------------------------------------------------
### Commit 2:
[FIX] website: enable free sign up setting in test_auth_forms_warning
Steps to reproduce:
1. Install any website related module (e.g. `website`, `website_event`).
2. Keep the default configuration and do not manually enable
'Free sign up' in Settings.
3. Run `test_auth_forms_warning`.
Before this commit: The test did not programmatically enable the
'Free sign up' setting. As a result, it failed unless a developer
manually navigated to the setting and enabled it beforehand.
After this commit: This commit explicitly enables the "Free sign up"
configuration during test execution, allowing public access to the
`/web/signup` page and ensuring the test passes without any manual
setup.
runbot-940394
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-prThis update fixes a critical issue where server reloads triggered by file changes could cause the Odoo process to crash. The fix prevents multiple signals from interrupting the server's restart process, ensuring stability and preventing service interruptions during development and deployment. This improves the reliability of the Odoo server.
Original PR description
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP`…
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP` into `KeyboardInterrupt`, which `ThreadedServer.run()`'s wait-loop catches. The catch is too narrow — a reload `SIGHUP` can kill the process through **three** windows that all sit outside the wait-loop's `try/except`, so the exception escapes `run()`/`main()`. Under Docker's default `restart: no`, PID 1 dies and the container stays down. ### The three windows 1. **Teardown duplicate (exit 130).** One file change can emit several FS events; the FSWatcher's `if not odoo.phoenix:` dedup races across threads and fires more than one `SIGHUP`. The first begins the phoenix teardown; the second lands during `stop()` / `watcher.stop()` / `_reexec()` and `KeyboardInterrupt` escapes. 2. **Exec-gap (exit 129).** `os.execve()` resets caught signal handlers to their default disposition (`SIGHUP` terminates) but preserves `SIG_IGN`; a `SIGHUP` arriving after the exec but before the re-exec'd process re-installs its handler kills the process outright. 3. **Startup (exit 130).** In the re-exec'd process, a `SIGHUP` anywhere in the startup section that precedes the wait-loop — `start()`, `preload_registries()` **and** `cron_spawn()` — escapes `run()`. ### Reproducer (deterministic) Boot a `ThreadedServer` (`--workers 0`) on any initialised db, then signal PID 1 a few times in quick succession: ```bash docker exec <container> sh -c 'i=0; while [ $i -lt 8 ]; do kill -HUP 1; sleep 0.1; i=$((i+1)); done' ``` Unpatched the process exits 130 or 129. Patched it stays up after one clean phoenix reload. Verified live on 17.0 and 18.0: stock `server.py` dies; the patched `server.py` survives sustained bursts (20/20 across repeated reload cycles on each version); `SIGINT`/`SIGTERM` still exit 0. ### Fix Minimal, in `signal_handler` + `run()` + `_reexec()`; `SIGINT`/`SIGTERM` untouched; one new instance attribute, no new module globals: - **Teardown duplicate:** ignore a `SIGHUP` once `quit_signals_received` is set (a restart/shutdown is already pending; the re-exec reloads fresh code). - **Startup:** a per-instance `in_preload` flag marks the entire startup section (`start()` + `preload_registries()` + `cron_spawn()`); a `SIGHUP` there sets the phoenix flag + counter and returns instead of raising, so the wait-loop exits right after startup and runs the normal restart. - **Exec-gap:** `signal.signal(signal.SIGHUP, signal.SIG_IGN)` just before `os.execve` so a `SIGHUP` in the gap is dropped rather than terminating the process. ### Related - #21209 (merged) — introduced the phoenix flag; did not guard these windows. - #206898 (merged), #207930 (open) — PreforkServer reload. ### CLA Covered by Codeforward B.V.'s corporate CLA; #269240 adds me to its contributor list (pending merge). Forward-Port-Of: odoo/odoo#269247
2 changes
Resolved issues and error corrections
This update fixes a bug where users weren't consistently warned about adding recurring products without a subscription plan. The change ensures that all order entry methods – manual and catalog view – now correctly validate this combination, preventing incorrect orders and improving data integrity. This enhances the reliability of subscription order creation.
Original PR description
Steps to reproduce: --------------------------------------- 1. Install Subscription Module 2. Create and Confirm SO with no recurring plan and a non-recurring product 3. Add a recurring product >…
Steps to reproduce: --------------------------------------- 1. Install Subscription Module 2. Create and Confirm SO with no recurring plan and a non-recurring product 3. Add a recurring product > Save SO > Observe the User Error 4. Now add the same recurring product through Catalog View Observation: --------------------------------------- No User Error raised stating 'You cannot save a sale order with recurring product and no subscription plan.' Issue: --------------------------------------- When you manually add a line and click 'Save', the constraint (`_constraint_subscription_plan`) is triggered and raised `UserError` https://github.com/odoo/enterprise/blob/434d88960abb5e424fdc1106fc93935d328bff78/sale_subscription/models/sale_order.py#L176-L177 When you add a product via the catalog view, it calls `_update_order_line_info` which directly creates/updates order lines, Which do not trigger the python constraint. https://github.com/odoo/odoo/blob/ef9772bba1515bdaf5410c3af5a3e395f562d513/addons/sale/models/sale_order.py#L1926-L1933 Solution: --------------------------------------- Two private helpers are introduced: * `_is_exempt_from_subscription_plan_check`: single source of truth for all exempt states (draft, cancelled, upsell, and legacy upgrade orders). * `_check_recurring_plan_mismatch`: raises a `UserError` when the order has or will have a recurring product but no subscription plan, reusing the exemption helper so both call sites stay in sync. `_constraint_subscription_plan` is refactored to delegate to these helpers, and `_update_order_line_info` is overridden to call `_check_recurring_plan_mismatch` before the catalog update is applied, ensuring consistent validation across both entry points. opw-6194865 Forward-Port-Of: odoo/enterprise#121886 Forward-Port-Of: odoo/enterprise#117879
This update fixes an issue where users weren't receiving notifications when a sign request was completed after they'd set their notification preference to 'Handle in Odoo'. The fix ensures that users receive timely updates, improving workflow efficiency and transparency around signed documents. This resolves a previous bug impacting the Sign module.
Original PR description
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign*…
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign* (`sign`) 2. Sets the current user's notification preference to "Handle in Odoo" (`inbox`) 3. Create a sign request and send it to Marc Demo 4. As Marc Demo, sign the request 5. **The user who sent the sign request did not receive a notification to notify them that the request was signed.** ## Fix This is a partial backport of both https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda (saas-18.2) and a related fix https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 (19.0). Before the first commit, users would not receive inbox notification when sign requests would be completed. ## Note to reviewer The issue only occurs in 18.0, as it is fixed by https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda in 18.2, but we can backport the fix from https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 from 18.2 to 18.4 if desired. opw-6251702 Forward-Port-Of: odoo/enterprise#122519 Forward-Port-Of: odoo/enterprise#120740
4 changes
Resolved issues and error corrections
This update fixes an issue where users weren't receiving notifications when a sign request was completed after they selected 'Handle in Odoo' (inbox) for notifications. The change ensures that the sender receives a notification, improving transparency and workflow efficiency for sign requests. This was a bug impacting the sign process.
Original PR description
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign*…
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign* (`sign`) 2. Sets the current user's notification preference to "Handle in Odoo" (`inbox`) 3. Create a sign request and send it to Marc Demo 4. As Marc Demo, sign the request 5. **The user who sent the sign request did not receive a notification to notify them that the request was signed.** ## Fix This is a partial backport of both https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda (saas-18.2) and a related fix https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 (19.0). Before the first commit, users would not receive inbox notification when sign requests would be completed. ## Note to reviewer The issue only occurs in 18.0, as it is fixed by https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda in 18.2, but we can backport the fix from https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 from 18.2 to 18.4 if desired. opw-6251702 Forward-Port-Of: odoo/enterprise#122519 Forward-Port-Of: odoo/enterprise#120740
This update resolves an issue where server reloads triggered by file changes could cause the application to crash. The fix prevents a series of signals from interrupting the server's restart process, ensuring stability and preventing service interruptions during updates. This improves the reliability of the Odoo server.
Original PR description
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP`…
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP` into `KeyboardInterrupt`, which `ThreadedServer.run()`'s wait-loop catches. The catch is too narrow — a reload `SIGHUP` can kill the process through **three** windows that all sit outside the wait-loop's `try/except`, so the exception escapes `run()`/`main()`. Under Docker's default `restart: no`, PID 1 dies and the container stays down. ### The three windows 1. **Teardown duplicate (exit 130).** One file change can emit several FS events; the FSWatcher's `if not odoo.phoenix:` dedup races across threads and fires more than one `SIGHUP`. The first begins the phoenix teardown; the second lands during `stop()` / `watcher.stop()` / `_reexec()` and `KeyboardInterrupt` escapes. 2. **Exec-gap (exit 129).** `os.execve()` resets caught signal handlers to their default disposition (`SIGHUP` terminates) but preserves `SIG_IGN`; a `SIGHUP` arriving after the exec but before the re-exec'd process re-installs its handler kills the process outright. 3. **Startup (exit 130).** In the re-exec'd process, a `SIGHUP` anywhere in the startup section that precedes the wait-loop — `start()`, `preload_registries()` **and** `cron_spawn()` — escapes `run()`. ### Reproducer (deterministic) Boot a `ThreadedServer` (`--workers 0`) on any initialised db, then signal PID 1 a few times in quick succession: ```bash docker exec <container> sh -c 'i=0; while [ $i -lt 8 ]; do kill -HUP 1; sleep 0.1; i=$((i+1)); done' ``` Unpatched the process exits 130 or 129. Patched it stays up after one clean phoenix reload. Verified live on 17.0 and 18.0: stock `server.py` dies; the patched `server.py` survives sustained bursts (20/20 across repeated reload cycles on each version); `SIGINT`/`SIGTERM` still exit 0. ### Fix Minimal, in `signal_handler` + `run()` + `_reexec()`; `SIGINT`/`SIGTERM` untouched; one new instance attribute, no new module globals: - **Teardown duplicate:** ignore a `SIGHUP` once `quit_signals_received` is set (a restart/shutdown is already pending; the re-exec reloads fresh code). - **Startup:** a per-instance `in_preload` flag marks the entire startup section (`start()` + `preload_registries()` + `cron_spawn()`); a `SIGHUP` there sets the phoenix flag + counter and returns instead of raising, so the wait-loop exits right after startup and runs the normal restart. - **Exec-gap:** `signal.signal(signal.SIGHUP, signal.SIG_IGN)` just before `os.execve` so a `SIGHUP` in the gap is dropped rather than terminating the process. ### Related - #21209 (merged) — introduced the phoenix flag; did not guard these windows. - #206898 (merged), #207930 (open) — PreforkServer reload. ### CLA Covered by Codeforward B.V.'s corporate CLA; #269240 adds me to its contributor list (pending merge). Forward-Port-Of: odoo/odoo#269247
This update resolves an issue preventing users from modifying a product's Bill of Materials (BOM) type when sales orders are already linked across multiple companies. Previously, the system prevented changes to ensure data integrity. Now, users can safely adjust BOM types, maintaining accurate sales order fulfillment and inventory management within a multi-company environment.
Original PR description
### Steps to reproduce: - Have two companies: company1 and company2 - Create a producct P available in both company1 and company2 - with company1, create a kit bom for a product P - with company2,…
### Steps to reproduce: - Have two companies: company1 and company2 - Create a producct P available in both company1 and company2 - with company1, create a kit bom for a product P - with company2, create and confirm a sale order for 1 unit of P - with company1, change the bom type of P from kit to manufature #### > UserError: As long as there are some sale order lines that must be delivered/invoiced and are related to these bills of materials, you can not remove them. ### Cause of the issue: Changing the bom type from a kit (phantom type) to a non kit will launch a call of the `_ensure_bom_is_free` in order to ensure data integrity if the kit bom was used by a relevant sale order line: https://github.com/odoo/odoo/blob/f4c76be062bec47b68ee42505d7d42fed31ac0f2/addons/sale_mrp/models/mrp_bom.py#L15-L18 https://github.com/odoo/odoo/blob/f4c76be062bec47b68ee42505d7d42fed31ac0f2/addons/sale_mrp/models/mrp_bom.py#L24-L42 However, this check does not take the company of the bom into account and in the present flow, the company of the bom is different from the company of the supposedly problematic sol. opw-6290304 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#273486 Forward-Port-Of: odoo/odoo#271119
This update fixes an error in how timesheet revenue is calculated for prepaid services, ensuring accurate reporting. The previous calculation incorrectly accounted for day UoM rounding, leading to inflated revenue figures. This change now uses the correct per-unit rate, reflecting discounts and ensuring accurate revenue reporting for prepaid orders.
Original PR description
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at…
Steps to reproduce 1. Create a service product: Invoicing Policy = Prepaid/Fixed Price, Track Service = Timesheets, Unit of Measure = Days 2. Confirm a Sales Order with 2 days of that product at 800/day 3. Register 1 hour on the generated task 4. Open Timesheets > Reporting, add the "Timesheet Revenues" measure Issue `timesheet_revenues` in `timesheets.analysis.report` was computed per analytic line as `(SOL.price_subtotal / SOL.qty_delivered) * (unit_amount * sol_uom.factor / ts_uom.factor)` (https://github.com/odoo/odoo/blob/16f170619d9cc5fd86529a3f17e349da37607f73/addons/sale_timesheet/report/timesheets_analysis_report.py#L42-L44). `SOL.qty_delivered` is a stored float rounded to the day UoM precision (0.01d). For 1 hour timesheeted, qty_delivered = 1/8 = 0.125d rounds to 0.13d, so the formula yields (1600 / 0.13) × (1/8) = 1538.46 instead of the correct 100. Because `qty_delivered` is recomputed each time a timesheet is added, all existing rows shift their revenue figure with every new entry. Additionally, using `price_subtotal / qty_delivered` as the per-unit rate ignores any line discount: the rate derived from a discounted subtotal divided by a delivered quantity that differs from the ordered quantity is not the effective price per day. For prepaid lines, the effective per-unit rate is `price_subtotal / product_uom_qty` — the ordered quantity is stable and the subtotal already reflects any discount — multiplied by the timesheet hours converted to the SO line UoM. opw-6150555 Forward-Port-Of: odoo/odoo#272910 Forward-Port-Of: odoo/odoo#262524
22 changes
New functionality added to Odoo
Odoo can now use official daily exchange rates from the Central Bank of Azerbaijan for automatic currency updates. This helps businesses using AZN keep multi-currency accounting and tax transactions aligned with official rates, including currencies quoted in larger nominal units.
Original PR description
This commit adds the Central Bank of Azerbaijan (CBA) as a supported service provider for automatic currency rate updates. Purpose: To ensure multi-currency accounting entries and taxable transactions are accurately translated into the national currency (AZN) using the official exchange rate defined by the CBA for the transaction day. Functionality: -Enables fetching official daily exchange rates directly from CBA via XML. -Automatically handles rates defined for different nominal quantities (e.g., rates quoted per 100 units instead of 1 unit). task-6112867
Enhancements to existing features
Senders using Sign Now for documents with multiple signers can now choose whether each remaining person signs immediately or receives their signing link by email. This makes in-person signing sessions more flexible and clearly confirms that the request will finish once emailed recipients complete their part.
Original PR description
When signing locally for multiple signers, the sender can now choose, for each remaining signer, to sign on the spot or send them the link by email. Once every signer has been handled, a confirmation dialog lets the sender know the request will complete as the emailed signers sign on their side. task-6234594
VoIP demo mode now only allows administrators to place demo calls, helping prevent unintended use by regular users. The VoIP dashboard is also simplified by removing a production filter that was not useful in live environments.
Original PR description
1. Only allow voip admin to make demo calls in demo mode 2. remove the default is_producion filter in dashboard since it's useless in production. Task-6304061
French fiscal declaration exports now run additional validation before submission. This helps ensure required company, debtor, writer, and partner information is complete and that ambiguous report choices are resolved before the file is sent.
Original PR description
while exporting liasse fiscale, no chceks were done before the export and there were no account returns checks before sending it, this commit add account return checks to the liasse fiscale: -writer and debtor have the necessary informations on their record -partners mentionned in the reports have the necessary fields completed on their records -for some line, we have to choose between some values task-6127270 Forward-Port-Of: odoo/enterprise#115812
This update improves Japanese tax reporting within Odoo Enterprise by incorporating the two distinct types of Japanese Consumption Tax Returns (JCT) – Accumulation and Deduction. This change aligns Odoo with updated Japanese tax regulations, ensuring accurate reporting and compliance.
Original PR description
Replace the single generic Japanese return type with the two JCT return types, Accumulation and Deduction, pointing at the new sectioned reports in l10n_jp. task-4490922
This update enhances the visual clarity of the attendance Gantt chart by addressing issues with negative overtime values and adjusting the color scheme. The changes improve the user experience and make it easier to understand employee attendance data.
Original PR description
Improve the readability of the progress bar: - no negative values for overtimes - adapt colors task-6341209
This update enhances the report editor by introducing tabs, similar to the website editor, for easier switching between different report creation modes. The changes also incorporate new Owl 3 features, streamlining the report editor's functionality and improving the overall user experience. This simplifies report design and development workflows.
Original PR description
This commit introduces tabs (like in the website editor) for switching between different modes in the report editor. It also updates and improves part of the report_editor codebase to take advantage of new Owl 3 features.
Resolved issues and error corrections
Payroll run creation now keeps the selected branch company instead of falling back to the main company. This prevents blocking warnings and supports accurate payroll processing for branch employees, including Hong Kong payroll flows.
Original PR description
[FIX] hr_payroll: fix correct company selection in payrun (branch case) Bug reproduc: 1 - Select 19.3 or master -> Open a branch to belgium company -> create an employee in that branch 2 - In your…
[FIX] hr_payroll: fix correct company selection in payrun (branch case)
Bug reproduc:
1 - Select 19.3 or master -> Open a branch to belgium company -> create an employee in that branch
2 - In your env, select both belgium and its branch, payroll->payrun->select branch as a company.
3 - Continue till the end of payrun creation, you will get warning (blocked) due to wrong company selection, main belg company is selected instead of branch
Bug cause:
1 - In selectEmployees function of hr_payslip_run_form, in the raw_record the company_id is passed as integer.
2 - In buildRawRecord function of hr_version_list_controller, we are assigning company_id as raw_record's company_ids id, but company id was already integer, company_id.id is undefined
3 - Since undefined is passed to the company_id, it uses the self.env.company_id as a default in the creation of hr payrun that cause to the error.
Bug fix:
1 - In the buildRawRecord function of hr_version_list_controller, I just assigned the company_id because it is already integer and all problem is solved.
task - 6326117
Forward-Port-Of: odoo/enterprise#122538
Forward-Port-Of: odoo/enterprise#121505Belgian payroll now handles cases where a student minimum wage salary scale cannot be found without causing the calculation to fail. This helps payroll teams avoid unexpected errors and keeps wage checks running reliably.
Original PR description
When computing _get_student_min_wage and the specific salary scale is not found, it returns None and then fails in the tuple compression as None is not an interable. task-6318004 Forward-Port-Of: odoo/enterprise#122500 Forward-Port-Of: odoo/enterprise#121392
Fixes a point of sale issue where deleting an order line with a custom product attribute could make the kitchen preparation display go blank. The display now stays available and continues showing the order information it can safely resolve, reducing disruption for kitchen staff.
Original PR description
When an order is sent to the preparation display and one of its products has an attribute with a custom (free text) value, completely deleting that line in the PoS makes the whole preparation display…
When an order is sent to the preparation display and one of its products has an attribute with a custom (free text) value, completely deleting that line in the PoS makes the whole preparation display crash and show a blank white screen, so the kitchen can no longer see any order. Steps to reproduce: ------------------- * Configure a PoS product with an attribute whose variant that has a custom (free text) value. * In the PoS, add the product, select that attribute value and send the order to the preparation display. * Back in the PoS, completely delete that order line (do not just set its quantity to 0) and send the order to the preparation display again. > Observation: The preparation display crashes and only a white screen is shown. The browser console reports "TypeError: Cannot read properties of undefined (reading 'id')". Why the fix: ------------ Completely deleting the line deletes the source pos.order.line, so the preparation line that is still displayed no longer resolves its `pos_order_line_id`. While building the attributes to display, the orderline component dereferenced `.id` on that (now undefined) relation, as well as on the related custom value records, which threw and brought down the whole preparation display instead of only that line. We now guard those relations: when the originating order line is gone, the unresolvable custom value is simply dropped and the attribute is still shown, keeping the preparation display alive. opw-6282607 Forward-Port-Of: odoo/enterprise#122691 Forward-Port-Of: odoo/enterprise#121194
This update resolves issues with knowledge tours and web_studio's Powerbox functionality. By inserting a forward slash into the DOM and adjusting event handling, the system now correctly simulates Powerbox opening, ensuring tours function as expected and web_studio's editing features are reliable.
Original PR description
#### Description of the issue: - Since the search powerbox plugin now checks for the actual existence of `/` in the DOM, some knowledge tours were failing because only the input event was dispatched without inserting `/`. - In web_studio, `insertText` was not positioning the selection correctly after insertion and was not dispatching beforeinput event before the DOM insertion. #### After this commit: - Adapt the `openPowerbox` utility in knowledge to insert `/` in the DOM before opening the powerbox. - Dispatch `beforeinput` before DOM insertion and `input` after it in web_studio, and move the selection after the inserted text. Community PR-https://github.com/odoo/odoo/pull/266284 task-6243724 Forward-Port-Of: odoo/enterprise#118310
This update fixes an issue where customer names weren't being correctly displayed in Odoo bookings created through Reserve with Google. Now, when booking through Google, the customer's full name (first and last) is used instead of just their email address, improving the user experience and contact information accuracy.
Original PR description
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to…
When a customer books through Reserve with Google, the createBooking payload carries the booker given_name and family_name next to the email, but the handler passed only the normalized email to _mail_find_partner_from_emails. The new res.partner was therefore created with its name falling back to the email, see https://github.com/odoo/odoo/blob/aa7b5921191a0ff53ef1cc32af99fe458c45c0da/addons/mail/models/res_partner.py#L177 That name then flows into the calendar.event name, the attendee common_name and the contact details, all showing the email instead of the customer name. The module has read neither field since it was added in https://github.com/odoo/enterprise/commit/2e855b910173b56e8501d0ebe9ee6f83ac5845bc. Build the booker name from given_name and family_name and pass it with the email through formataddr in google_reserve_booking_create, so a newly created partner is named after the customer. A partner matched on an existing email keeps its current name. Steps to reproduce: 1. Enable Reserve with Google on an appointment type. 2. Book a slot from Google Maps with given name John and family name Doe. 3. Open the created booking and its contact in Odoo. => the contact name is the email instead of John Doe Ticket [link](https://www.odoo.com/odoo/project/49/tasks/6232318) opw-6232318 Forward-Port-Of: odoo/enterprise#120604
This update fixes an issue where the withholding tax return was incorrectly combining balances with regular tax returns. The change ensures the withholding tax return accurately calculates the independent balance due, resolving a discrepancy in reported tax liabilities for Italian companies. This improves the accuracy of tax reporting.
Original PR description
Steps to reproduce: - setup an Italian company - make an invoice (for example in May) with a withholding tax and make a transaction to pay it - generate tax returns (opening date in June so that it generates from May) - validate regular tax return for May - validate withholding tax return for May -> The withholding tax return shows an amount to pay with a balance that is a combination of both the regular tax return and the withholding one, while it should be independent of the regular one. task-6116304 Forward-Port-Of: odoo/enterprise#121254 Forward-Port-Of: odoo/enterprise#119375
This update resolves an issue where downloading the ETA payroll form generated an error due to incorrect file formatting. Additionally, a warning about missing employee data (like Social Insurance Number) was fixed by adding a dependency to automatically recompute warnings when the data changes. These improvements ensure accurate payroll reporting and data integrity.
Original PR description
Issue 1: Steps to Reproduce: -> Create Payslip for Employee -> Once payslip is validated, Click Pay, and for Mode Choose ETA Form 2 -> Download and open the File it throws Formatting error Cause: The Excel workbook was base64-encoded before being written to the binary field, which expects raw bytes. Fix: Save raw binary data directly and update the test case to load it using `io.BytesIO` on binary field content Issue 2: Steps to Reproduce: -> Create a payslip for an employee missing (like EG Social Insurance Number) -> A warning is raised that field is missing. -> Even if the field is filled, the warning does not disappear. Cause: There is no compute dependency to recompute warnings when value changed. Fix: Added dependency in `_issues_dependencies` so it recomputes when value changes. task-**6292194** Forward-Port-Of: odoo/enterprise#122474 Forward-Port-Of: odoo/enterprise#120544
This update fixes an issue where sales from European companies to Northern Ireland (XI) were incorrectly calculating intra-community taxes. The change adds a check to ensure these transactions are treated as third-country sales, aligning with tax regulations. This ensures accurate financial reporting.
Original PR description
…stomers The services sales done from a European company to a Northern Ireland (XI) company should not contain intra-community taxes but should be treated as third country (non-EU) transactions. We solve it by adding a check in the EC Sales List return that is only visible when a wrong record occurs. task-6007931 Forward-Port-Of: odoo/enterprise#122535 Forward-Port-Of: odoo/enterprise#121487
This update fixes an issue where GS1-compliant barcodes were not correctly interpreted as product scans. When enabled, the system now accurately processes these barcodes, ensuring correct quantity updates during scanning, improving inventory accuracy.
Original PR description
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings…
In certain cases the barcode of a product could be a valid standalone GS1 sequence. In that case it needs to be be correctly interpreted as a product scan. ### Steps to reproduce: - In the settings enable "Default GS1 Nomenclature" - Create a storable product P with the barcode 3701762412212 - Create and confirm a delivery for 2 units of P and set the qty to 2 - Go to the barcode app and open your delivery - Scan 3701762412212 > The line of P is now selected with a quantity of 1/2 - Scan 3701762412212 #### > A new line is created for 1762411 units ### Cause of the issue: According to the GS1 nomenclature, the barcode 3701762412212 matches the scan of a quantity of "1762412" units of the lot name "2". As the scan of the of the product match a pattern for the GS1 nomenclature before matching a product, its barcode data is expected to be reset by these lines: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1320-L1324 In order to bypass the GS1 parser and to add 1 unit of the product. This is what happen on the first scan. However, performing the first scan also selects the associated line and, hence on the second scan the lines just above this check do set the product to match the product of the current line: https://github.com/odoo/enterprise/blob/7cceddaf086d849b8e2121e1023ef3479397534f/stock_barcode/static/src/models/barcode_model.js#L1294-L1320 In particular, we do not bypass the result provided by the GS1 parser and add `1762412` units of the product. opw-6175621 Forward-Port-Of: odoo/enterprise#122256 Forward-Port-Of: odoo/enterprise#120035
This update fixes an issue where bank reconciliation calculations were incorrect when dealing with foreign currencies. The system now properly converts amounts from the journal currency to the company currency, ensuring accurate balance calculations and preventing constraint errors. This improves the reliability of bank reconciliation processes.
Original PR description
### Issue: When a bank journal uses a foreign currency, reconciliation model lines with `Amount Type: From Label` (regex) could raise a constraint error or produce incorrect balances on the journal…
### Issue: When a bank journal uses a foreign currency, reconciliation model lines with `Amount Type: From Label` (regex) could raise a constraint error or produce incorrect balances on the journal entry ### Cause: The `balance` of the generated move line was set to the raw value extracted by the regex, without converting it from the journal currency to the company currency This violated the sign constraint between `balance` and `amount_currency` when the exchange rate caused a mismatch, raising a `_check_amount_currency_balance_sign` error The `amount_currency` was already correctly set Only the `balance` conversion was missing ### Steps to reproduce: - Install `accountant` - Enable a foreign currency (e.g. EUR) with two rates: yesterday: ratio < 1 (e.g. 0.5), today: ratio > 1 (e.g. 2.0) - Create a Bank journal in EUR - Open Bank Reconciliation for that journal - Add two transactions (one dated yesterday, one today) (Ref: "test BANK:0001690,00EUR EXP:00033,80", amount: 1656.20) - Create a reconciliation model (3 dots > Manage Models) (name: From Label): -- Account: 101401 Bank, Amount: BANK:0*(\d+),(\d+) -- Account: 600000 Expenses, Amount: EXP:0*(\d+),(\d+) - Apply the model on both transactions Before the fix, one raised an error due to the constraint violation - From the list view, open the Journal Entry for the other transaction Before the fix, `balance` was not converted to company currency opw-6292839 Forward-Port-Of: odoo/enterprise#121114
This update fixes an issue where group payments weren't correctly updated when invoices were modified, leading to reconciliation problems. The change ensures that all payments, including group payments, transition to 'In Process' state when a statement line is unreconciled, resolving a discrepancy in payment status.
Original PR description
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A *…
**Steps to reproduce:** - Install Accounting - Create an invoice: * Customer: Partner A * Total: 30.00 - Confirm the invoice - Create a second invoice for the same customer: * Customer: Partner A * Total; 10.00 - Confirm the invoice - From the invoice list, select both invoice - Create payment: * Journal: Bank * Group Payments: [checked] * Group Payments: [checked] * Amount: 40.00 - Create a third invoice for another customer: * Customer: Partner B * Total: 25.00 - Confirm the invoice - Register payment from the invoice - Create a fourth invoice for another customer: * Customer: Partner C * Total; 40.00 - Confirm the invoice - Register payment from the invoice - From the payment list, select all 3 payments and create batch payment - Validate the batch payment - From Accounting dashboard, open Bank journal - Create a new bank statement line of 105.00 - Match it with the batch payment At that point, the statement line is reconciled with the 4 invoices and the 3 payments are marked as paid. - Go to the fourth invoice - Reset it to draft - Change the price - Save When the amount of the invoice is changed, the statement line is unreconciled and all the payments should change state from "Paid" to "In Process". **Issue:** All the single payments have their state correctly changed to "In Process", except for the group payment for the 2 first invoices, which leads to undesired values when trying to reconcile the statement line with the batch payment again. **Cause:** When the statement is unreconciled, all the partial reconcile records are deleted and the state of the linked payments are updated to "In Process". The payments are retrieved by checking if there are linked to an account move present in the partial reconcile record and if the amount of the payment matches the amount of the partial reconcile record. In case of a group payment, there are 2 partial reconcile records for each invoice linked to the payment. Therefore, in that case, the amount doesn't match the amount of the payment because it matches the amount of one of the invoice. opw-6141089 Forward-Port-Of: odoo/enterprise#122585 Forward-Port-Of: odoo/enterprise#120210
This update fixes an issue where users would lose the project, description, and task information they entered in the Timesheets systray when closing it. The previous fix was an unnecessary precaution, and this update removes it, ensuring data is saved correctly.
Original PR description
## Issue When using the Timesheets systray, if we set a project after clicking the *Save* or *Reset* button, the project is not saved after closing the systray. ## Steps to reproduce 1. Install…
## Issue When using the Timesheets systray, if we set a project after clicking the *Save* or *Reset* button, the project is not saved after closing the systray. ## Steps to reproduce 1. Install *Timesheets* (`timesheet_grid`) 2. Open the Timesheets systray 3. Click *Reset* and set a description, a project and/or a task, then close the systray 4. Open the systray again 5. **The description/project/task set in step 3 do(es) not appear anymore.** ## Cause Commit https://github.com/odoo/enterprise/commit/b9b7f8a0acf7a1c545c6613cf8bbc29871632e26 introduced the `preventUnmountSave` attribute. The attribute is set to `true` after saving and discarding an entry. When the systray is unMounted, the manual values (e.g., description, project and task) are not saved if the attribute is set to `true`: https://github.com/odoo/enterprise/blob/7cd8dd008eb88d6c12f3e65fb8d311058290a301/timesheet_grid/static/src/components/timesheet_timer_inline_form/timesheet_timer_inline_form.js#L171-L174 ## Fix After discussing with the author of the previous commit, it appears this was done to prevent an issue with values stored in cache, but that issue does not seem to occur anymore, which leads to believe that the attribute is not required anymore. opw-6284016 Forward-Port-Of: odoo/enterprise#122332 Forward-Port-Of: odoo/enterprise#121605
This update reverts a recent change that allowed employees to directly edit personal information within Odoo. Management requested this change to prevent potential inaccuracies in payroll calculations and ensure compliance with tax regulations. HR team oversight will now be required for any updates to this sensitive data.
Original PR description
This reverts the recent changes that exposed the "Family" and "Personal Info" sections (such as Marital Status) in the employee's "My Preferences" menu. While the initial addition was intended to improve employee self-service, management requested this revert because allowing employees to directly edit these fields poses a risk to payroll accuracy and compliance. Data points like marital status or family dependents directly impact tax deductions and benefit enrollments. To ensure data integrity, any modifications to payroll-affecting information must remain the exclusive duty of the HR team, who can require and verify the proper legal documentation before updating the system. task-6304031
This update resolves an issue where signed documents were incorrectly placed in separate folders, leading to duplicate entries and confusion. Now, signed documents from both the Documents and HR apps appear only in their respective folders (Employee/Payroll), and no extra documents are created upon completion. This ensures data consistency and simplifies document management.
Original PR description
Before: - Documents flow: after signing, the signed copy was placed in the Sign folder instead of the same folder as the original document. - HR flow: after signing a sign.request linked to an HR…
Before: - Documents flow: after signing, the signed copy was placed in the Sign folder instead of the same folder as the original document. - HR flow: after signing a sign.request linked to an HR record (e.g. hr.employee, hr.version), the signed document appeared twice, once in the Employee/Payroll folder and again in the Sign folder. - [_sign()](https://github.com/odoo/enterprise/blob/19.0/sign/models/sign_request.py#L505) attaches a copy of the signed document to the linked record, but the missing `no_document=True` was mistakenly creating an extra document - Import from Documents flow: after signing via "Import from Documents" in the Sign app, the signed copy was placed in the original document folder instead of the Sign folder. After: - Documents flow: the signed document is now placed in the same folder as the original document. - HR flow: the signed document is created only once, in the Employee/Payroll folder. No copy is made in the Sign folder. - No extra documents are created in the background when a sign request linked to a record is completed. - Import from Documents flow: the signed document is now placed in the Sign folder. Impact: - Signed documents from the Documents app stay in the same folder. - Signed HR contracts appear only in the Employee/Payroll folder. - No duplicate documents are created on completion. Task: 6176315
This update fixes an error in calculating holiday attest annual taxable income for employees on long-term sick leave (over 30 days). Previously, the calculation was incorrect due to a reliance on zero-valued payslips. Now, the system uses the employee's monthly wage to ensure accurate taxable income calculations, aligning with Belgian tax regulations.
Original PR description
Problem ---------------------- When an employee takes a long sick leave (more than 30 days), the basic wage on the payslip is set to 0, leading to the holiday attest annual taxable income to be…
Problem ---------------------- When an employee takes a long sick leave (more than 30 days), the basic wage on the payslip is set to 0, leading to the holiday attest annual taxable income to be calculated as 0 * 12, which is incorrect. Reason ------------------- The calculation for the holiday attest uses the last payslip for the employee, and if the employee had leave type LEAVE214, the last payslip has the basic wage set to zero, so the taxable wage that is used in the annual taxable wage calculation is wrong. The monthly wage should be used as the basic wage in the payslip to get the correct computation. Solution ------------------- The GROSS (taxable income) line that is used is computed as (basic wage - ONSS total + BIK), but the basic wage was 0. This commit checks whether the basic wage is 0 and if the time off type was longterm sick leave, and simulates a payslip using the monthly wage from the contract as basic wage to get the accurate computation for the taxable income. task-6237717 Forward-Port-Of: odoo/enterprise#120180
10 changes
Enhancements to existing features
This update streamlines the process of detecting new IoT boxes, reducing the time it takes for them to connect. Previously, a 5-second check was too slow, but we've reduced the interval to 2 seconds for a faster and more responsive experience. This improves user efficiency and reduces delays in integrating new devices.
Original PR description
IoT Boxes are almost connecting instantly, however, as we used to check for new boxes every 5s, it seemed very slow. We set the timer to search every 2s.
Resolved issues and error corrections
Fixed an issue where bank reconciliation rules that read amounts from transaction labels could fail or create incorrect journal entry balances for foreign-currency bank journals. The extracted amounts are now converted to the company currency, helping prevent reconciliation errors and inaccurate accounting entries.
Original PR description
### Issue: When a bank journal uses a foreign currency, reconciliation model lines with `Amount Type: From Label` (regex) could raise a constraint error or produce incorrect balances on the journal…
### Issue: When a bank journal uses a foreign currency, reconciliation model lines with `Amount Type: From Label` (regex) could raise a constraint error or produce incorrect balances on the journal entry ### Cause: The `balance` of the generated move line was set to the raw value extracted by the regex, without converting it from the journal currency to the company currency This violated the sign constraint between `balance` and `amount_currency` when the exchange rate caused a mismatch, raising a `_check_amount_currency_balance_sign` error The `amount_currency` was already correctly set Only the `balance` conversion was missing ### Steps to reproduce: - Install `accountant` - Enable a foreign currency (e.g. EUR) with two rates: yesterday: ratio < 1 (e.g. 0.5), today: ratio > 1 (e.g. 2.0) - Create a Bank journal in EUR - Open Bank Reconciliation for that journal - Add two transactions (one dated yesterday, one today) (Ref: "test BANK:0001690,00EUR EXP:00033,80", amount: 1656.20) - Create a reconciliation model (3 dots > Manage Models) (name: From Label): -- Account: 101401 Bank, Amount: BANK:0*(\d+),(\d+) -- Account: 600000 Expenses, Amount: EXP:0*(\d+),(\d+) - Apply the model on both transactions Before the fix, one raised an error due to the constraint violation - From the list view, open the Journal Entry for the other transaction Before the fix, `balance` was not converted to company currency opw-6292839
Users who choose to handle notifications in Odoo now receive an inbox alert when a signature request they sent is completed. This helps request owners stay informed without relying on email notifications.
Original PR description
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign*…
## Issue When a user sets their notification to "Handle in Odoo" (`inbox`) and a sign requested is completed, they do not receive the expected notification. ## Steps to reproduce 1. Install *Sign* (`sign`) 2. Sets the current user's notification preference to "Handle in Odoo" (`inbox`) 3. Create a sign request and send it to Marc Demo 4. As Marc Demo, sign the request 5. **The user who sent the sign request did not receive a notification to notify them that the request was signed.** ## Fix This is a partial backport of both https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda (saas-18.2) and a related fix https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 (19.0). Before the first commit, users would not receive inbox notification when sign requests would be completed. ## Note to reviewer The issue only occurs in 18.0, as it is fixed by https://github.com/odoo/enterprise/commit/463d6a2aae536356e6dee6b902f2e881dbc4fbda in 18.2, but we can backport the fix from https://github.com/odoo/enterprise/commit/41395dba4fd31222f5fd9fc94a84c977cf9334f9 from 18.2 to 18.4 if desired. opw-6251702 Forward-Port-Of: odoo/enterprise#122519 Forward-Port-Of: odoo/enterprise#120740
Bank reconciliation partner search now includes contacts owned by a selected branch company's parent company, as well as global contacts. This helps multi-company users find the right customer or vendor when matching bank transactions, reducing manual work and reconciliation errors.
Original PR description
When setting a partner from the bank reconciliation control panel, the partner lookup domain only considered global contacts and contacts directly linked to the selected company IDs. This caused a multi-company issue for branch companies, where users could not find contacts owned by their parent company. The domain is now updated to include: Global contacts (company_id = false) Contacts whose company is a parent of the selected companies (company_id parent_of companyIds)
The timesheet grid now correctly marks non-working days as unavailable when employees view their own timesheets. This helps users avoid entering time on days that are outside their personal working schedule.
Original PR description
To reproduce: ============= - modify Mitchel Admin's working schedule and remove a day of work - open timesheet app as Mitchel Admin - the removed day is not grayed out as unavailable Porblem: ======== the method `get_unavailabily` was handling only the case when calling it with `groupby=employee_id` otherwise it returns the company's unvailability Solution: ========= when the "My Timesheet" action is opened, the method `get_unavailabily` is now called with a specific context key, allowing to return the current user's unavailability instead of the company's one. opw-5949236 Forward-Port-Of: odoo/enterprise#122543 Forward-Port-Of: odoo/enterprise#113984
This update resolves a problem preventing bulk product imports when recurring invoices are used. A recent change attempted to use a helper function, but it wasn't properly ported to the 19.0 version of Odoo. This fix restores the missing function, allowing products to be imported correctly.
Original PR description
The port https://github.com/odoo/enterprise/commit/68640b5bddf51a8cbf58d3af3628cd4b57e08913 added a call to self._get_confirmed_order_lines() in product.template.write() (on import, when recurring_invoice changes), but the helper itself was never ported to 19.0. Importing products in bulk then fails with AttributeError: 'product.template' object has no attribute '_get_confirmed_order_lines'. Restores the method from master (PR https://github.com/odoo/enterprise/pull/117046) at the end of the ProductTemplate class.
This update ensures that work orders are properly updated when a product's bill of materials (BOM) is modified – specifically, when an operation is deleted or changed. Previously, the system didn't always unlink related work orders, leading to inconsistencies. This fix resolves this issue by correctly updating work orders linked to the BOM.
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
This update resolves an issue where the Tax Return report in Odoo incorrectly displayed inflated amounts due to duplicate early-payment discount lines during batch reconciliation. The fix ensures accurate tax reporting by merging duplicate lines, preventing double-counting and maintaining correct tax totals. This improves the reliability of financial reporting.
Original PR description
Steps to reproduce 1. Create two customer invoices that share the same VAT tax, with a payment term granting an early payment discount. 2. Create one bank statement line whose amount equals the sum…
Steps to reproduce 1. Create two customer invoices that share the same VAT tax, with a payment term granting an early payment discount. 2. Create one bank statement line whose amount equals the sum of both invoices' discounted totals. 3. From the bank reconciliation widget, select both invoices and validate in a single batch reconciliation. 4. Open Accounting > Reporting > Tax Return, switch the variant to "Group by: Account > Tax". Issue The cash-discount expense row shows a Net base column equal to twice the real discount base. The Tax column is correct. The bank-statement reconciliation paths (set_line_bank_statement_line, set_batch_payment_bank_statement_line, _reconcile_payments) loop over each invoice and call _apply_early_payment_discount one invoice at a time. Each call writes one discount base line and one discount tax line on the resulting bank entry, so when two invoices share the same tax the bank entry ends up with two pairs carrying the same (account, partner, currency, tax_repartition_line_id, tax_ids). The SQL that feeds the tax report at https://github.com/odoo/odoo/blob/d7d0efd39a65bfb6fee307b661cd2523a6b8231d/addons/account/models/account_move_line_tax_details.py#L100 matches every base line of a tax with every tax line of that tax inside the same move. With two pairs sharing one tax that turns two rows into four, and SUM(base_amount) doubles. The Tax column does not double because the same SQL redistributes each tax line's recorded amount across its matched rows so the totals still add back to the original tax. The payment register flow does not have this problem because it calls _get_invoice_counterpart_amls_for_early_payment_discount once with every invoice, and that helper already collapses duplicates with the merge key at https://github.com/odoo/odoo/blob/f3b317310b84edb073009f7d15d7fec002f3ccf0/addons/account/models/account_move.py#L5082-L5093 opw-6199906
This update corrects a bug in the barcode scanning feature for stock receipts. Previously, the displayed quantity didn't accurately reflect the actual quantity received when using packaged items. The fix ensures that quantities are correctly converted to the stock move UoM, resolving the discrepancy between the barcode view and the stock move quantity.
Original PR description
**Steps to reproduce:** - Install `stock` and `purchase` modules - Enable `Units of Measure and Packages` and `Storage Locations` from setting - Create a storable product with vendor purchase UoM set…
**Steps to reproduce:** - Install `stock` and `purchase` modules - Enable `Units of Measure and Packages` and `Storage Locations` from setting - Create a storable product with vendor purchase UoM set to "Pack of 6" - Create and confirm a Purchase Order with quantity 6 Units - Open the generated receipt - Update a move line in Detailed Operations: - Quantity: 1 - UoM: Pack of 6 - Save and open the Barcode view using smart button. - Increase quantity using "+" button by 1. - Exit barcode view without validating and refresh the receipt **Issue:** After refresh, the stock move quantity becomes 1 instead of 6, while the move line correctly shows 1 Pack of 6. **Cause:** https://github.com/odoo/enterprise/blob/2bfe0f32c0cec426fc7345ef716395146cc569ca/stock_barcode/static/src/components/main.js#L161-L162 - Exiting the barcode view triggers `__onExit()`, which forwards `reserved_uom_qty` and `qty_done` from move lines to `post_barcode_process()`. https://github.com/odoo/enterprise/blob/2bfe0f32c0cec426fc7345ef716395146cc569ca/stock_barcode/static/src/models/barcode_picking_model.js#L1885-L1898 This `post_barcode_process()` function triggers `_truncate_overreserved_moves()` https://github.com/odoo/enterprise/blob/2bfe0f32c0cec426fc7345ef716395146cc569ca/stock_barcode/models/stock_move.py#L56-L58 - During this flow, `_truncate_overreserved_moves()` updates the stock move quantity by taking the maximum of `qty_done` and `reserved_uom_qty`. However, it assigns this value directly to the move without converting it into the stock move UoM. - In this case, both values are 1 because the move line is UoM is "Pack of 6" Logically, 1 Pack corresponds to 6 units, but since the stock move UoM is in units, this conversion is skipped. As a result, the move quantity is incorrectly set to 1 instead of 6. https://github.com/odoo/enterprise/blob/2bfe0f32c0cec426fc7345ef716395146cc569ca/stock_barcode/models/stock_move.py#L52-L54 **Fix:** - Convert quantities coming from barcode processing into the stock move UoM before updating the move quantity, ensuring packaged UoM values are preserved correctly. ---- opw-5472598
This update resolves an error that prevented exporting the Deferred Revenue Report when annotations were added to invoices. The fix ensures the report can correctly handle invoices with deferred dates and annotations, improving report accuracy and functionality. This was caused by a missing variable initialization within the report generation process.
Original PR description
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Deferred Start Date** and **Deferred End Date** (Deferred Date) fields on invoice lines. * Create and post a customer…
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Deferred Start Date** and **Deferred End Date** (Deferred Date) fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to **Accounting → Review → Deferred Revenue Report**. * Add an annotation to a deferred revenue line by clicking the **message** icon next to the account. * Export the report in **XLSX** format. **Observed behavior:** * The export fails with a server error: `UnboundLocalError: cannot access local variable 'annotations_x_offset' where it is not associated with a value` **Cause:** * The variable `annotations_x_offset` is assigned inside the `for header_level_index, header_level in enumerate(options['column_headers'])` loop, which writes the "Annotations" column header for each header level. * The Deferred Revenue Report produces an empty `column_headers` list, so the loop body never executes and `annotations_x_offset` is never assigned. * When the code later tries to write annotation data for each report line, it references the unassigned variable, causing Python to raise `UnboundLocalError`. **Fix:** * Initialize `annotations_x_offset = None` before the header loop. * After writing all individual column headers (where `x_offset` already points to the first free column after all data columns), add a fallback: if `report_annotations` is set but `annotations_x_offset` is still `None`, assign it from the current `x_offset` and write the "Annotations" header. opw-6354473
7 changes
Resolved issues and error corrections
Urban Piper point-of-sale orders are now fetched together with other server orders instead of through extra back-to-back requests. This reduces waiting time during order refreshes and lowers unnecessary server load without changing the user workflow.
Original PR description
Issue: pos_urban_piper overrode getServerOrders() to add a separate loadServerOrders() call for it's own orders before delegating to super, resulting in up to an additional sequential RPCs on every order fetch. Fix: Extract the base query domain into a new overridable getServerOrdersDomain() method. Each module overrides it to OR in its own domain via Domain.or([super.getServerOrdersDomain(), extraDomain]), so all orders are fetched in a single RPC call instead of three. Task-6284860
This update improves the speed of closing Point of Sale sessions, particularly when using 'Identify Customer' for bank payments. Previously, closing a session with many payments could take over 10 minutes. Now, the process is significantly faster – around 75 seconds – due to batch processing of payments and reconciliation.
Original PR description
Steps to reproduce ------------------ 1. On a bank payment method, enable "Identify Customer". 2. Create a lot of orders paid with this method (the client reporting the issue had 1700), and put a customer on each order. 3. Close the session. With "Identify Customer" enabled, closing the session creates one `account.payment` for each payment and posts it one by one, then reconciles each payment separately. With many payments this is slow and the close takes several minutes and the worker is stopped by its time limit, so we get the error "Cursor already closed". Now we create and post all these payments at once in a single batch, and reconcile the payments in one call too. Benchmark --------- These numbers come from closing a session that has 1700 orders paid with such a payment method, on a test database: - before: the close did not finish after more than 10 minutes. - after: the close takes around 75 seconds. opw-6242303
This update resolves an issue where reloading the Odoo server could cause it to crash due to a race condition when handling `SIGHUP` signals. The fix ensures the server remains stable during reload operations, improving reliability and preventing service interruptions. This was triggered by multiple signals arriving simultaneously during a file change.
Original PR description
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP`…
### Summary When `dev_mode` includes `reload`, `ThreadedServer`'s FSWatcher reacts to a file change by sending the process a `SIGHUP` to trigger a phoenix restart. `signal_handler` turns `SIGHUP` into `KeyboardInterrupt`, which `ThreadedServer.run()`'s wait-loop catches. The catch is too narrow — a reload `SIGHUP` can kill the process through **three** windows that all sit outside the wait-loop's `try/except`, so the exception escapes `run()`/`main()`. Under Docker's default `restart: no`, PID 1 dies and the container stays down. ### The three windows 1. **Teardown duplicate (exit 130).** One file change can emit several FS events; the FSWatcher's `if not odoo.phoenix:` dedup races across threads and fires more than one `SIGHUP`. The first begins the phoenix teardown; the second lands during `stop()` / `watcher.stop()` / `_reexec()` and `KeyboardInterrupt` escapes. 2. **Exec-gap (exit 129).** `os.execve()` resets caught signal handlers to their default disposition (`SIGHUP` terminates) but preserves `SIG_IGN`; a `SIGHUP` arriving after the exec but before the re-exec'd process re-installs its handler kills the process outright. 3. **Startup (exit 130).** In the re-exec'd process, a `SIGHUP` anywhere in the startup section that precedes the wait-loop — `start()`, `preload_registries()` **and** `cron_spawn()` — escapes `run()`. ### Reproducer (deterministic) Boot a `ThreadedServer` (`--workers 0`) on any initialised db, then signal PID 1 a few times in quick succession: ```bash docker exec <container> sh -c 'i=0; while [ $i -lt 8 ]; do kill -HUP 1; sleep 0.1; i=$((i+1)); done' ``` Unpatched the process exits 130 or 129. Patched it stays up after one clean phoenix reload. Verified live on 17.0 and 18.0: stock `server.py` dies; the patched `server.py` survives sustained bursts (20/20 across repeated reload cycles on each version); `SIGINT`/`SIGTERM` still exit 0. ### Fix Minimal, in `signal_handler` + `run()` + `_reexec()`; `SIGINT`/`SIGTERM` untouched; one new instance attribute, no new module globals: - **Teardown duplicate:** ignore a `SIGHUP` once `quit_signals_received` is set (a restart/shutdown is already pending; the re-exec reloads fresh code). - **Startup:** a per-instance `in_preload` flag marks the entire startup section (`start()` + `preload_registries()` + `cron_spawn()`); a `SIGHUP` there sets the phoenix flag + counter and returns instead of raising, so the wait-loop exits right after startup and runs the normal restart. - **Exec-gap:** `signal.signal(signal.SIGHUP, signal.SIG_IGN)` just before `os.execve` so a `SIGHUP` in the gap is dropped rather than terminating the process. ### Related - #21209 (merged) — introduced the phoenix flag; did not guard these windows. - #206898 (merged), #207930 (open) — PreforkServer reload. ### CLA Covered by Codeforward B.V.'s corporate CLA; #269240 adds me to its contributor list (pending merge). Forward-Port-Of: odoo/odoo#269247
This update resolves a technical issue causing inconsistencies in the mod303 and mod390 tax reports for the Spanish (l10n_es) localization. The fix automatically adjusts tax grids to ensure accurate reporting, eliminating the need for manual adjustments. This improves the reliability of financial data for Spanish businesses.
Original PR description
### Steps to reproduce the issue: 1.Download Accounting and l10n_es 2. Switch to ES company 3. Make sure the reports mod303 and mod390 are empty for the month of May 2026 Tax 21% EU G (and 21% EU…
### Steps to reproduce the issue: 1.Download Accounting and l10n_es 2. Switch to ES company 3. Make sure the reports mod303 and mod390 are empty for the month of May 2026 Tax 21% EU G (and 21% EU IG): 3. Create a vendor bill with a line with the tax of 21% EU G in the month of May 2026 4. Create a refund (credit note) for that vendor bill in the month of May 2026 5. Look at the mod303 tax report for the month of May 2026 and notice that [27] in mod303 is not the same value as [34] in the mod390 report 6. Remove the +mod390[26] tag from the -100% refund line of the 21% EU G tax 7. Redo steps 2-4 and notice that [27] in the mod303 tax report is now the same value as [34] in the mod390 tax report, but also that [26] in the mod303 tax report is a different value now Tax 21% EU S: 1. Create a vendor bill with a line with the tax of 21% EU S in the month of May 2026 2. Create a refund for that vendor bill in the month of May 2026 3. Look at the mod303 tax report for the month of May 2026 and notice that [27] in mod303 is not the same value as [34] in the mod390 report. Also notice that [552] in mod390 is the same as [638] in mod390 4. Remove the +mod303[552] tag from the -100% refund line of the 21% EU S tax 5. Redo steps 2-4 and notice that [27] in the mod303 tax report is now the same value as [34] in the mod390 tax report, but also that [552] in mod390 is now different from [638] in mod390 ### Reason to introduce the fix: The report presented some discrepancies that can be fixed manually by changing the tax grid but it's still an error so it's better to also set the correct tax grids in the default taxes. opw-6277939 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update fixes an issue where expense accounts weren't being correctly applied during Point of Sale transactions. Now, the system prioritizes mapping expense accounts through the fiscal position when available, ensuring accurate financial reporting for sales without invoices. This improves the reliability of financial data generated by the PoS system.
Original PR description
**Steps to reproduce:** - Make a product with a category - In the category, make the inventory valuation to automated - Set the income and expense account - Set a cost for the product - Make a fiscal…
**Steps to reproduce:** - Make a product with a category - In the category, make the inventory valuation to automated - Set the income and expense account - Set a cost for the product - Make a fiscal position and set it as default for the PoS - In the Account Mapping tab, map the income and expense to two other accounts - Go to the PoS - Make a sale for that product, without invoice - Close the session and in the backend check the session - Check the journal entries - The income account has been mapped to the fiscal position's - The outcome account stayed the same as in the category's **Why the fix:** When we invoice an order, the income and expense accounts are immediately updated, in a different place than if it has not been invoiced. At the session's closure, we update the accounts for every order that hasn't been invoiced. In this flow, the account mapping defined on the fiscal position was not applied, so we took the one defined on the product's category. The income account was already mapped as we need to do it earlier than the session closure, so it had already been set as the right one before our flow. For the expense account, we only need it at this specific time, so we can map it as the session's closure. We now map the account depending on the fiscal position if we are able to find one, otherwise, we use the category's default as we did before. opw-6171677
This update resolves an issue where reversing invoices with credit notes in the Czech localization didn't correctly update the Taxable Supply Date (TSD). The fix ensures the TSD is accurately reflected during the reversal process, aligning with accounting requirements. This improves data integrity for Czech-based businesses using Odoo.
Original PR description
### Issue before this commit: When reversing an invoice with a credit note in the l10n_cz and l10n_sk only the invoice_date is updated with the reversal_date but not the TSD date. ### Steps to…
### Issue before this commit: When reversing an invoice with a credit note in the l10n_cz and l10n_sk only the invoice_date is updated with the reversal_date but not the TSD date. ### Steps to reproduce the issue: 1. Download Accounting and l10n_cz (same steps can be done for l10n_sk) 2. Go to invoices and put as not invisible the Accounting Date field 3. Create and post the invoice setting as Taxable Supply Date (TSD) a previous date 4. Create a credit note for the invoice with reversal date as today for example and then click Reverse 5. See the dates (as taxable supply date and accounting date) are not updated ### Cause of the issue: Prior to version 19, the taxable_supply_date (TSD) was a localization-specific field and did not exist in the core account.move model. Consequently, when the reverse_moves method: https://github.com/odoo/odoo/blob/3bf89b4f467390807c20f7b007a875a77542e76f/addons/account/wizard/account_move_reversal.py#L110-L174 executed, the accounting date was recomputed but the TSD was left unhandled. Thanks to PR https://github.com/odoo/odoo/pull/225035, which natively integrates this field into the core account module in version 19, the fields are now properly aligned and the issue is no longer reproducible. ### Reason to introduce the fix: The fix explicitly populates taxable_supply_date with the wizard's reverse_date during the reversal preparation process. opw-6102869 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update corrects a bug where reverting an inventory adjustment with a package resulted in negative quantities appearing within the package. The fix ensures that quantities are accurately restored after reverting, preventing inconsistencies in package inventory levels. This improves data reliability and simplifies inventory management.
Original PR description
Currently when the user reverts an inventory adjustment move line with a package the package contains extra line showing negative quantity of the product. ## Steps to produce: - Install Inventory…
Currently when the user reverts an inventory adjustment move line with a package the package contains extra line showing negative quantity of the product.
## Steps to produce:
- Install Inventory without demo data
- Settings Enable 'Packages'
- Create a product:
- Cheese burger
- On hand > Create a new quant
- Package: 'Burgerbox' and 'On Hand Quantity`: 1 and save
- Set the On Hand quantity to zero and save
- History > Revert the Inventory adjustment line from WH/stock to Inventory adjustment by selecting it and reverting via actions.
- Products > Packages > BurgerBox
## Observed Behaviour:
After reverting an inventory adjustment that set the product's physical quantity to 0, the package contains two lines for the same product with quantities 1 and -1.
This is inconsistent because a package should not contain a product with a negative quantity.
The package should be restored to its original state and contain only the expected positive quantity.
## Root cause:
When the user reverts the move line, `action_revert_inventory` is called. This method creates the revert move and then marks that move as done at [1].
Marking the move as done subsequently marks all related move lines as done at [2]. During this process, the system first unreserves the quantity from the virtual location / inventory adjustment and then removes the quantity from that location (resulting in a -1 quantity move line at that location). This is performed through `_synchronize_quant`, which is responsible for synchronizing the physical inventory with the move line at [3].
The `_synchronize_quant` method uses the move line's `package_id` when updating the corresponding quant at [4]. As a result, `_update_available_quantity` creates a new quant with the following values at [5]:
```
{
'product_id': 1,
'location_id': 14,
'lot_id': stock.lot(),
'package_id': 1,
'owner_id': res.partner(),
'in_date': datetime.datetime(2026, 6, 22, 12, 42, 11),
'quantity': -1.0,
}
```
This creates a quant with a negative quantity that is linked to the package because `package_id` is set on the newly created quant. Consequently, the move line with the negative quantity becomes associated with the package.
[1]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L1016-L1035
[2]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move.py#L1956 [3]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L662-L666
[4]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_move_line.py#L678-L687
[5]-
https://github.com/odoo/odoo/blob/333c279be7cba9fda17d2818be36f4d96d8cd0f6/addons/stock/models/stock_quant.py#L1130-L1143
## Solution:
Remove the source `package_id` when creating revert moves for inventory adjustment locations.
When an inventory adjustment sets a product's quantity to 0, the adjustment is completed without a destination package, meaning the product is effectively removed from the package. Therefore, the corresponding revert move should not retain the package as its source. Keeping the package as the source is inconsistent because package information should not exist on a virtual inventory adjustment location, and the original inventory adjustment removes the product from the package (there is no destination package).
By removing the source `package_id` from the revert move, the system avoids creating negative quants associated with the package during quant synchronization. This also ensures that, after the inventory adjustment is reverted, the quantities of products inside the package are restored correctly and match their state prior to the adjustment.
opw-6285739
Forward-Port-Of: odoo/odoo#2714403 changes
Resolved issues and error corrections
This update ensures that lot numbers are consistently applied to incoming stock movements created during Point of Sale refunds. Previously, the system wasn't correctly reusing the original lot number when a refund was processed, leading to inconsistencies in inventory tracking. This fix maintains accurate lot number traceability for products, improving inventory management.
Original PR description
Steps: ---------- - Install point_of_sale. - Create a trackable product with a lot and add an on-hand quantity. - Open a PoS config with "Ship Later" enabled. - Place an order for the trackable product with a lot and ship later, then validate the delivery picking in Inventory. - Refund the previous order from PoS and ship later, and check the receipt in Inventory. Issue: --------- - The delivery picking correctly assigns a lot number, but the corresponding receipt created during the refund does not. Cause: --------- - The system was not reusing the existing lot number when the picking type was incoming. Fix: -------- - Ensure the existing lot number is assigned to incoming pickings created during refunds. task-5005122
This update resolves an issue where PDF invoices from Nilvera were being corrupted due to incorrect storage. The fix ensures PDFs are properly decoded and stored as valid files, preventing invoice processing errors. This improves the reliability of invoice generation and submission.
Original PR description
## Short fix summary: The PDF fetched from Nilvera comes back as a base64 string. It was stored verbatim in the attachment's `raw` field (no decoding), producing a corrupt PDF. Store it in `datas`…
## Short fix summary: The PDF fetched from Nilvera comes back as a base64 string. It was stored verbatim in the attachment's `raw` field (no decoding), producing a corrupt PDF. Store it in `datas` instead, which base64-decodes its input into a valid PDF. ### How it slipped in The mocked test for PDF fetching never mirrored the real API response: it returned raw bytes instead of the base64 string Nilvera actually sends, and asserted nothing about the stored file. Because the mock misrepresented the response, a later fix for a `binascii.Error` on Python 3.14 was applied in the wrong layer, switching the attachment field from `datas` to `raw`. That silenced the error but stored the base64 text undecoded, corrupting the PDF. The mock on the test will be corrected on Forward port of 18.0 onward. ### Related PRs - **#266718** — introduced the regression: switched the attachment field from `datas` to `raw` to silence a `binascii.Error` on Python 3.14, but stored the base64 text undecoded, corrupting the PDF. - **#246884** — added the mocked test suite that misrepresented the Nilvera `/pdf` response (raw bytes instead of a base64 string), which masked the bug and made the wrong fix in #266718 appear correct. task-6312640 I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This update resolves a problem where automation rules on sales orders were failing due to an incorrect handling of messages. The fix ensures that automation messages are processed correctly, preventing errors and maintaining the expected behavior of sales order workflows. This improves the reliability of automated tasks.
Original PR description
Steps to reproduce: ---------------------------------------- 1. Install `industry_fsm_sale` and `base_automation` modules 2. Create a product with: * Type: Service * Create on order: Task * Project:…
Steps to reproduce:
----------------------------------------
1. Install `industry_fsm_sale` and `base_automation` modules
2. Create a product with:
* Type: Service
* Create on order: Task
* Project: Field Service
3. Create an automation rule with:
* Model: Sales order
* Trigger: Incoming message
4. Create and confirm a sale order with this product
5. Add another product to the SO via the catalog view:
* Change the quantity to 2 or more
Observation:
----------------------------------------
Traceback occurs:
```
File '/home/odoo/src/odoo/addons/base_automation/models/base_automation.py', line 871, in _message_post
message_sudo = message.sudo().with_context(active_test=False)
AttributeError: 'bool' object has no attribute 'sudo'
```
Root Cause:
----------------------------------------
* Catalog qty change calls `set_fsm_quantity()` method
* Setting `fsm_quantity` triggers its inverse `_inverse_fsm_quantity()`, which writes the new qty to the SOL, but passes `fsm_no_message_post=True` in context to suppress chatter noise
https://github.com/odoo/enterprise/blob/ac5d670832a5e0db714c0bd056e1406b50bb4c17/industry_fsm_sale/models/product_product.py#L72-L83
* `sale.order.line.write()` detects a qty change on a confirmed order and calls `_update_line_quantity()`, which posts a message on the parent sale order
* FSM's `message_post` override sees the context flag and returns `False`
* When `base_automation` has an `on_message_received` rule on `sale.order`, it wraps `message_post` at registry load time. That wrapper calls `sudo()` on whatever `message_post` returns, Which was `False`
Solution:
----------------------------------------
Return `self.env['mail.message']` (empty recordset) instead of False, it's still falsy, but it's a proper ORM object that `sudo()` can be called on
opw-6276916