Wednesday, July 30, 2025
17 changes · 18.0
Resolved issues and error corrections
Installing Accounting with demo data for German databases no longer fails because of an audit trail protection error. The change lets the demo chart of accounts cleanup run safely during setup, improving first-time installation reliability.
Original PR description
When installing the Accounting app on a new database created with Germany as
country and with demo data loaded, the demo loader invokes in
`account/demo/account_demo.xml` the `<function name="try_loading">` call which
does a wholesale `records.with_context({MODULE_UNINSTALL_FLAG: True}).unlink()`. This
cascades into deleting mail.message records, but the audit‑trail hook in
only bypasses its check when the `bypass_audit` token is present not when `MODULE_UNINSTALL_FLAG is set
causing a “You cannot remove parts of the audit trail” UserError.
Steps to reproduce:
- Created new database, with Germany as country
- Download demo data
- Attempt to install Accounting application
! Receive error message
OPW- 4712364Payment providers are now consistently limited to those configured for the current website across checkout, saved payment methods, and payment links. This prevents customers in multi-website setups from seeing or using payment options intended for another site, reducing confusion and transaction mistakes.
Original PR description
In a multi-website environment, payment providers are often configured specifically for each website using the `website_id` field. While the checkout page (`/shop/payment`) correctly filters providers by the current website, other routes such as `/my/payment_method` or `/payment/pay` flows do not apply this filtering consistently. This patch ensures that the `website_id` constraint on payment providers is respected across all relevant flows, improving consistency and preventing users from seeing or using providers that are not available for their current website. Without this patch, users may see or select payment providers that are not intended for their site, leading to potential confusion, incorrect transactions, or access to providers that are not supported on the current website. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#218089
This fix ensures connected hardware devices are sent correctly right after pairing with a database. It prevents a stale saved token from blocking device updates before the system is restarted, improving reliability for newly paired setups.
Original PR description
Since the PR odoo/odoo#218109, the send_all_devices logic was refactored to always send whenever something changes. However, there was a bug introduced due to the fact the token is saved at start-up and never updated. This caused the devices to not get sent correctly immediately after pairing with a DB (in the time before checking out and restarting). --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Future time off balances now correctly account for yearly entitlements and carryover days that expire mid-year. This prevents employees and HR teams from seeing incorrect zero or carryover-only balances when checking future leave availability.
Original PR description
### Steps to reproduce: - Create an accrual plan with the following rule: — The employee has 20 days off in the first year. Total 20. — The employee has 21 days off in the second year and an…
### Steps to reproduce: - Create an accrual plan with the following rule: — The employee has 20 days off in the first year. Total 20. — The employee has 21 days off in the second year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 21 + 5 = 26 — The employee has 22 days off in the third year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 22 + 5 = 27 — The employee has 23 days off in the fourth year and an additional 5 days off if available from the previous year, which can be taken until 6 months. Total 23 + 5 = 28 - Create an accrual allocation with the created plan - Check future allocation data using 'Balance at the' - Notice the following behaviour: — until 31/12/2025 it CORRECTLY shows 20 days available. — from 01/01/2026 to 30/06/2026 it CORRECTLY shows 26 days (21 days for renewal and 5 days not used in 2025) — from 01/07/2026 it INCORRECTLY shows no days available. — from 01/01/2027 to 30/06/2027 it CORRECTLY shows 27 days (22 days for renewal and 5 days not used in 2026) — from 01/07/2027 it INCORRECTLY shows 5 days. — from 01/01/2028 to 30/06/2028 it CORRECTLY shows 28 days (23 days for renewal and 5 days not used in 2027) — from 01/07/2028 it INCORRECTLY shows no days available. — from 01/01/2029 it CORRECTLY shows 28 days again. — In the following years, after 6 months, one year shows 5 days and the next shows nothing. ### Cause: The first cause here is that when we have validity for the carryover then we will have two calls in each year one at the start of the year and another at the expiration date of the carryover. So, when we add the days to the allocation we don't consider the second call in the condition and we only check if the allocation.actual_lastcall is equal to one of the start dates for each year https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L588 The second cause where each two years one of them shows the number of carryover days from the previous year, this is happening because when we remove the expiring days for the first year we set the number of days to 0 https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L516-L517 And it will be 0 until we loop again and add the days to allocation https://github.com/odoo/odoo/blob/3fb37cbc59adc2caace8efcdae418d2466a9b750/addons/hr_holidays/models/hr_leave_allocation.py#L521-L522 and since this is happening after we already set the expiring days which in this year will be 0 we won't remove those expiring days from the year's allocation data ### Fix: We add a condition to check if the actual_lastcall is either a date in the start of the allocation or one of the expiration dates for the carryover. Also, before we set the value of the expiring_carryover_days we call _add_days_to_allocation to calculate on the correct number of days for the plan level we are checking. opw-4606886
Timesheet administrators who do not have Project app access can now open timesheet lists and related forms without being blocked by permission errors. This ensures authorized timesheet review work continues smoothly even when linked tasks or projects are private.
Original PR description
Steps to Reproduce: - Ensure the `sale_timesheet` module is installed. - Log in as a user with Timesheet Administrator permissions but without access to the Project module. - Attempt to open the…
Steps to Reproduce: - Ensure the `sale_timesheet` module is installed. - Log in as a user with Timesheet Administrator permissions but without access to the Project module. - Attempt to open the Timesheets list view results in an `AccessError` due to missing read rights on `project.task`. - Create a task in a private project linked to a timesheet and open its form view results in an `AccessError` due to missing read rights on `project.project`. Cause: - When a user has Timesheet Administrator access but lacks project access, they can view all timesheets, including those linked to tasks with private privacy visibility. However, these users do not have read access to the private tasks themselves. - The `_compute_commercial_partner` method reads `task_id.partner_id.commercial_partner_id` and `project_id.partner_id.commercial_partner_id`. When a user without read access to `project.task` or `project.project` tries to compute this field, an `AccessError` occurs because the code tries to access these related records without bypassing access rights. Solution: - Use `sudo()` on `task_id` and `project_id` when accessing their `partner_id` fields inside the compute method to bypass access rights checks, preventing ` AccessError` for users lacking read permissions. task-4798066 Forward-Port-Of: odoo/odoo#210826
This fix improves PDF printing from Odoo on Android and iOS mobile browsers. It gives the mobile print preview enough time to finish preparing the document, reducing failed or incomplete print attempts for users working from phones or tablets.
Original PR description
[FIX] web: Mobile print support on Android and iOS Currently, pdf.js does not support printing from mobile browsers, and the pdf.js team will not fix this issue [1]. I investigated and found that sometimes `window.print()` is asynchronous [2]. On Android and iOS, the print preview dialog re-renders the entire PDF within the preview, which can obviously take some time. Therefore, we need to account for this time in the overall duration of the asynchronous print process to ensure that the print preview works well. opw-4190135 [1]: https://github.com/mozilla/pdf.js/issues/12020 [2]: https://github.com/mozilla/pdf.js/blob/2d0ba7db08fb6bb597ba718635314d8e8998a7d0/web/pdf_print_service.js#L226 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#217526
Free self-service point-of-sale orders now create the required fulfillment record, just like paid orders. This prevents free product orders from being missed by inventory or preparation workflows.
Original PR description
Steps to reproduce: ------------------- 1. Create a free product 2. Add it to self_order 3. Make a self order with only that product -> Free order Sicne it's a free order, you will not be asked to…
Steps to reproduce: ------------------- 1. Create a free product 2. Add it to self_order 3. Make a self order with only that product -> Free order Sicne it's a free order, you will not be asked to pay, which is normal. However, the issue is, no picking is created for that order!! Why the issue? -------------- For a non free self order, we create a picking for it by calling `_process_saved_order` [1] with `draft` argument set to `True`, either after paying using the online payment method [2], or after paying it from the payment wizard [3]. However, since for free orders, we're not asked at any point to pay, and hence, we're not calling `_process_saved_order` with `draft=True` at any point, and as consequence, we're also not calling `_create_order_picking`, no picking will be created for it. The fix ------- After, marking the free order as 'paid', we manually call `_process_saved_order(True)`. We only do it for the free orders, since the flow is working as expected for non-free order. [1]: https://github.com/odoo/odoo/blob/a7a29ed691db4f1607c0d12929c56845681164fa/addons/point_of_sale/models/pos_order.py#L153C19-L153C31 [2]: https://github.com/odoo/odoo/blob/a7a29ed691db4f1607c0d12929c56845681164fa/addons/pos_online_payment/models/payment_transaction.py#L64 [3]: https://github.com/odoo/odoo/blob/a7a29ed691db4f1607c0d12929c56845681164fa/addons/point_of_sale/wizard/pos_payment.py#L70 opw-4739523
This fix ensures the accounting app uses the correct transaction information when predicting taxes. It helps prevent failed or missing tax suggestions, making accounting workflows more accurate and reliable.
Original PR description
Previously, when _predicted_field was invoked from _predict_specific_taxes, self did not have an associated move_id. As a result, _build_predictive_query was unable to construct the correct query, causing the prediction logic to fail and return False. With this fix, the correct move_id is passed through the context and later retrieved in _predicted_field. This ensures that the prediction logic uses the intended move_id and functions as expected. **task**-4943015 Community PR - https://github.com/odoo/odoo/pull/219911
Refunds in Mexican point of sale can now be completed when a gift card is used. This prevents checkout errors and correctly treats gift card top-ups as valid positive lines during refund processing.
Original PR description
**Problem:** When trying to make a refund in Mexico, with a gift card in the order, the order should be refunded on said gift card. But when doing so, two problems arise: - In the case of a gift…
**Problem:** When trying to make a refund in Mexico, with a gift card in the order, the order should be refunded on said gift card. But when doing so, two problems arise: - In the case of a gift card, *line[2].refunded_orderline_id* is not set, so we are trying to read the property of an undefined variable. - Another problem is that the order can not have any line that have a positive subtotal in the case of a refund. This was not taking the gift cards into accounts, as it makes sense for them to be positive in such a case. **Steps to reproduce:** - Set your company to a Mexican company - Make a purchase for a gift card - Make another purchase for a random product - Start the refund process and enter the gift card code we created before - Try to finalize the purchase, a traceback appears - If we were not trying to read an undefined variable, the purchase would still not go through as some lines are positive in a refund **Why the fix:** When refunding with a gift card, we should refill the gift card by the order's cost instead. With this in mind, it makes sense for the gift card to have a positive price even though we are in the context of a refund, which usually only permits negative priced lines. opw-4892935
Appointments in the evening could be incorrectly shown as unavailable when a next-day all-day calendar event existed in another timezone. The fix aligns all-day event checks with the user’s local timezone, preventing valid appointment slots from being blocked.
Original PR description
All-day calendar events were incorrectly causing unavailability for appointment slots scheduled on the previous evening, due to mismatches between local time and UTC. Previously, all-day events…
All-day calendar events were incorrectly causing unavailability for appointment slots scheduled on the previous evening, due to mismatches between local time and UTC. Previously, all-day events scheduled for Tuesday were stored with a start time of 00:00 UTC. In timezones like America/Chicago, this corresponds to 7:00 PM Monday. As a result, a valid appointment booked from 6:30 PM to 8:00 PM local time on Monday would partially fall into Tuesday in UTC (ending at 01:00 UTC), causing a false conflict with Tuesday’s all-day event. The `calendar_verify_availability` method now calls the newly added `_get_date_boundaries` which than computes naive datetime boundaries based on the user's local timezone by taking the end of the previous local day and the start of the next local day. This change resolves those edge cases where evening slots crossing the UTC boundary were falsely marked as unavailable due to timezone misalignment. opw-4614544 Forward-Port-Of: odoo/enterprise#85654
This fixes the payslip PDF so the basic wage is hidden when the salary structure option is enabled. It helps payroll teams keep printed payslips aligned with their configured confidentiality settings.
Original PR description
After this commit: odoo/enterprise@9dceed0896ce5089bccbc9cc2ce1e8c4b13f0048…
After this commit: odoo/enterprise@9dceed0896ce5089bccbc9cc2ce1e8c4b13f0048 [diff](https://github.com/odoo/enterprise/commit/9dceed0896ce5089bccbc9cc2ce1e8c4b13f0048#diff-de4a628e7837c273b67d71f93efab85b6a9ee957ea702f502066ebcc632a76cbL64) The condition that handles hiding the basic wage on the payslip was not added —possibly it was missed. That’s why the "Hide basic on PDF" feature doesn’t work, regardless of whether it’s enabled, as the necessary condition is missing in the template. Steps to reproduce (on runbot): - In a v18 runbot, open any payslip and go to the salary structure. Enable the "Hide basic on PDF" option. - Return to the payslip and print it. - You’ll see that the basic wage is still printed on the payslip. **Before Fix:** <img width="669" height="238" alt="payslipbefore" src="https://github.com/user-attachments/assets/2fce67a2-19d8-45d8-88fa-4fc6a1767e68" /> **After Fix:** <img width="683" height="289" alt="payslipafter" src="https://github.com/user-attachments/assets/adcb0104-9c4e-4a35-ba78-b3f278f6bfda" /> opw-4953831
Fixes an issue that prevented the Accounting app demo data from loading for some German trial databases. The change makes demo invoice setup use reliable predefined records, helping users install and evaluate Accounting without hitting an error.
Original PR description
The demo data for deferred invoices failed to load due to unresolved `journal_id` and `account_id` references caused by dynamic search, but if the search return Null a `violates not-null constraint ` occur . This commit replaces search with explicit `ref` IDs for journals and accounts to be sure they are exist. Steps to reproduce: - Created new database (odoo.com/trial), with Germany as country, and German as language - Download demo data - Attempt to install Accounting application - Receive error message OPW-4712364
Users who manage timesheets but do not have Project access can now open Timesheet list and kanban views without being blocked by an access error. This keeps timesheet review workflows available while respecting existing project permissions.
Original PR description
Steps to Reproduce: - Ensure the `timesheet_grid_holidays` module is installed. - Log in as a user with Timesheets Administrator access but no access to the Project module. - Navigate to the Timesheets > List or Kanban view. - An `AccessError` occurs due to missing read rights on the `project.task` model. Cause: - In the `timesheet_grid_holidays` module, the `_should_not_display_timer` method accesses `self.task_id.is_timeoff_task` without checking access rights, causing an `AccessError` when users who can view timesheets but lack read access to `project.task` try to access tasks linked to projects with private privacy visibility. Solution: - Use `sudo()` when accessing `self.task_id` in `_should_not_display_timer()` to avoid access errors. task-4798066 Forward-Port-Of: odoo/enterprise#86302
Upsell invoices for yearly subscriptions now show the correct split between the remaining current period and the next full billing period. This prevents misleading invoice descriptions and helps customers better understand what they are being charged for.
Original PR description
**Steps to Reproduce:** - Install `sale_subscription`. - Create a product (recurring product) with: - Type: Service - Invoicing Policy: Prepaid/Fixed Price - Create a subscription plan Yearly with: -…
**Steps to Reproduce:**
- Install `sale_subscription`.
- Create a product (recurring product) with:
- Type: Service
- Invoicing Policy: Prepaid/Fixed Price
- Create a subscription plan Yearly with:
- Billing Period: 1 year
- Align to period start: enabled
- Create and confirm a subscription for the product using the Yearly plan.
- Create and confirm the first invoice (shows remaining days like
185 days – 06/30/2025 to 12/31/2025 in product description).
- Create and confirm second invoice (check 1 year – 01/01/2026 to 12/31/2026).
- Go back to the subscription and create an upsell.
- Confirm the upsell and generate its invoice.
**Observation:**
- The upsell invoice line shows the wrong duration:
1 year (06/30/2025 to 12/31/2026).
- This is incorrect because the expected duration is:
185 days (from 06/30/2025 to 12/31/2025) + 1 year (01/01/2026 to 12/31/2026)
**Issue:**
- The duration calculation is based on the ratio of the first date and the end
date, but for the Upsell's ratio is always 1, so it considers fix duration,
i.e 1 year, 1 month
https://github.com/odoo/enterprise/blob/4bb43da79dba7ac1d0772fde814b3da6bade7db6/sale_subscription/models/sale_order_line.py#L346-L347
**Solution:**
- Corrected the logic to calculate the upsell duration by combining the remaining
current period (e.g., 185 days) with the standard 1-year period ratio.
Reference PR: https://github.com/odoo/enterprise/pull/68163/commits/cfed2d369960896f0f4d91a90eb24f3641627419
opw-4853426This fix restores proper display of long descriptions in the Italian Libro Giornale PDF report, so text in the Name column is no longer cut off. It also improves column spacing consistency, making exported reports easier to read and more reliable for accounting review.
Original PR description
Issue: In the Libro Giornale report (PDF), long descriptions in the 'Name' column were getting cut off, and column spacing appeared inconsistent in the generated PDF. These issues reappeared due to recent layout changes from commit https://github.com/odoo/enterprise/commit/233e82cf4e6908502a580be4bcd77fadd2aada53, which unintentionally removed previous fixes made to handle such cases. Fixes Applied: - Reintroduced the `o_overflow_name` class on the 'Name' column to ensure long descriptions wrap correctly and are not truncated in the PDF export. - Applied the `o_fixed_column_width` class to the 3rd column (currently 'Account Code') to resolve inconsistent spacing between columns caused by `wkhtmltopdf`.
Vendor batch payment reconciliation now uses the correct payable account instead of the receivable account. This prevents accounting entries from being posted to the wrong partner account when matching bank statements with vendor batch payments.
Original PR description
**Steps to reproduce:** - Install accountant - Go to "Accounting / Vendors / Payments" - Create a payment: * Payment Type: Send * Vendor: [any] * Amount: 1000 - Confirm the payment - From payments list, select the payment and create a batch - Validate the batch payment - From Accounting dashboard, go to Bank journal - Create a statement: * Partner: [None] * Amount: -1000 * Memo: [anything] - Reconcile the statement with the batch payment **Issue:** The receivable account of the partner is used for the batch line instead of his payable account. **Solution:** Select the type of the account to use depending on the type of the payment. opw-4952786
Rental-related invoice lines are now excluded from a cost entry process that is meant for sold goods. This prevents incorrect accounting entries for rental orders and helps keep financial reporting accurate.
Original PR description
…entries Modified the COGS generation logic to skip any invoice lines that come from a rental sales order. task-4919306 Forward-Port-Of: odoo/enterprise#90901