Daily updates from Odoo
Thursday, August 13, 2026
16 changes · 19.0
Enhancements to existing features
When a Bulgarian VAT return is validated, the system now automatically creates and attaches the required monthly SAF-T General Ledger, purchase, and sales report files alongside the PDF. This reduces manual work for large companies and helps them meet Bulgaria's monthly tax reporting requirements more reliably.
Original PR description
Bulgaria made it mandatory for large companies to present a monthly file
to report their VAT to the administration. To streamline that process,
when the VAT return is validated and PDF is added to the attachments,
the monthly General Ledger SAF-T file, the POKUPKI Purchase Report and
PRODAGBI Sale Report are produced and added as well.
Simplify the report file download error wizard's visuals and descriptions to improve readability.
task-6007963Resolved issues and error corrections
Studio approval rules can now be checked even when a sales user lacks access to accounting-related fields used in the rule. This prevents valid sales order confirmations from being blocked by an access error when approvals depend on related customer follow-up information.
Original PR description
continuation of [PR](https://github.com/odoo/enterprise/pull/121856) Issue: Inside _get_approval_spec filtered_domain is called a few times and due to a related field that calls an access rights group that the user who used the action isnt apart of is blocked by the filtered_domain. To Replicate: 1) Install studio, sale, Accounting and make sure "account_followup" is installed 2) create a related field on the sales.order form related to "customer -> follow up status" 3) Save 4) Create a "Studio Approval Rule" (studio.approval.rule) with a domain using the new related studio field -> method : "action_confirm" -> approver:admin 5)create a test user with no accounting access rights 6) in an incognito browser try and create a sales order, and then confirm it. it will throw the access rights error Solution: Go one up the stack where _get_approval_spec is called and add a syudo for those calls opw-6316069
Users with read-only accounting access can now see the General section in the Accounting tab on partner records. This restores access to expected bank account details for users who already have the proper permissions.
Original PR description
Problem: The General group of the Accounting tab of the partner form view is not visible to some users, even if they have the access rights to see it. Steps to reproduce: 1. Create a user or edit an existing one, giving them Accounting Read-Only access rights. 2. Log in with that user. 3. Go to Contacts and select a partner. 4. Open the Accounting tab 5. Notice how the General group (with the bank account details) is not visible. Cause: In the account_accountant module, the partner form view is inherited in one of the views to add additional groups to the General group of the Accounting tab. However, it doesn't add the new group, but instead replaces the existing groups with the new one. opw-6413683 Forward-Port-Of: odoo/enterprise#126679
This fix updates Belgian POS blackbox test setup so required dialog information is present. It prevents automated test crashes, helping keep validation runs reliable without changing business workflows.
Original PR description
This is a backport of https://github.com/odoo/enterprise/commit/f47930c28127662db4ce2a1e68dc2ed0b3486b87 ### Issue: During RunBot single module tests, some tests caused an error: `Maximum call stack…
This is a backport of https://github.com/odoo/enterprise/commit/f47930c28127662db4ce2a1e68dc2ed0b3486b87
### Issue:
During RunBot single module tests, some tests caused an error: `Maximum call stack size exceeded` after repeated: `[Owl] Unhandled error. Destroying the root component`
Affected tests:
- `sign_money_in_out.called at right time`
- `sign_drawer_open.called at right time`
- `sign_work_in.called when opening register, setting & resetting cashier`
- `sign_work_in_employee.called from login screen (closed session)`
### Cause:
The tests passed `dialogData: {}` to the component env But `dialogData` must at least define `scrollToOrigin`, which is called automatically in `onWillDestroy`:
https://github.com/odoo/odoo/blob/0042e83fb60353a49d4759a79a3ceb0eee6f74b6/addons/web/static/src/core/dialog/dialog.js#L122-L126
Calling `scrollToOrigin()` on an empty object raises a `TypeError`, which Owl catches and re-throws repeatedly until the call stack is exceeded
The full `dialogData` shape is defined in `makeDialogMockEnv`: https://github.com/odoo/odoo/blob/62c540d96fc49d9e74d8c660019754651cb0e085/addons/web/static/tests/_framework/env_test_helpers.js#L151-L161
### Steps to reproduce:
- Install `l10n_be_pos_blackbox` (fresh `-i`, or `-u` with `web` on an existing db)
- Run the tests in MobileWebSuite
Before the fix, the errors are triggered
runbot-941232A payroll-related automated test was updated to use a normal working day instead of a weekend date. This prevents false test failures and helps keep Belgian payroll validation checks stable without changing user-facing payroll behavior.
Original PR description
The test `test_float_holiday_attest` fails with a ValidationError: "The following employees are not supposed to work during that period". The previous patch (cf. PR odoo/enterprise#107490) froze time to "2026-02-01 08:00:00", which was a Sunday. When validating the leave created for `today`, check of the employee's calendar fails because zero working hours are scheduled on weekends. This commit updates `@freeze_time` to "2026-02-02 08:00:00" (Monday) so the leave validation runs against a valid working day. runbot-240132 runbot-241193
Australian payroll submissions to the ATO now check that required payslips or employees are present before sending. Instead of a system traceback, users receive a clear validation message, helping them correct incomplete Single Touch Payroll records.
Original PR description
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module -…
When submitting payroll data to the ATO from an STP record without any payslips or employees, a traceback is raised. Steps to reproduce the error: - Install ``l10n_au_hr_payroll_account`` module - Switch to ``My australian Company`` - Go to Payroll > Configuration > Settings > In Australian Localization, Set BMS ID > Set STP Responsible and his date of birth - Go to Payroll > Reporting > Single Touch Payroll > Create a new record > Set Payment Date > Submit to ATO > Sign & Submit to ATO Traceback: ```py IndexError: tuple index out of range ``` https://github.com/odoo/enterprise/blob/b0e48baaf99bdc4faefd2ffdd3bd5637fb548593/l10n_au_hr_payroll_account/models/l10n_au_stp.py#L228-L233 The traceback occurs because ``_get_fiscal_year_start()`` assumes that the STP record always contains at least one payslip or one employee. When these recordsets are empty, indexing the first element raises an IndexError. Solution: This commit validates that the required payslips or employees are present before the submission and raises a validation error instead of a traceback. Forward-Port-Of: odoo/enterprise#127584 Forward-Port-Of: odoo/enterprise#124096
Global invoices for Mexican POS orders now ignore cancelled refunds, preventing invoice creation errors when a customer return was started but not completed. This helps ensure valid paid refunds are processed correctly without incorrectly reducing the original order twice.
Original PR description
Steps to reproduce: ------------------- 1. Install `l10n_mx_edi_pos` and set the company to Mexico. 2. In PoS, make an order with one product and pay it. 3. Open the order in the backend, click…
Steps to reproduce: ------------------- 1. Install `l10n_mx_edi_pos` and set the company to Mexico. 2. In PoS, make an order with one product and pay it. 3. Open the order in the backend, click "Return Products" to make a refund, but don't pay it, cancel it instead. 4. From the same order, click "Return Products" again to make a second refund, and pay it normally. 5. Go to the orders list, select the main order and the paid refund (not the cancelled one), then Actions > Create Global Invoice. -> Observation: error in the global invoice. In the CFDI tab of the main order the line is "Send Global In Error", and hovering on it the detail says "Failed to distribute some negative lines". Why: ---- When we make the global invoice, we remove the refunds from the order. A cancelled refund was never paid, so we should not count it. But we were counting it too. So we removed the refund amount twice in our case, one for the paid refund, and one for the cancelled one, and we end up with an order with negative amount that cannot be distributed. The fix: -------- We now skip the cancelled orders when we search the refunds, the same way it is done above when we collect the refunded orders. opw-6261404 Forward-Port-Of: odoo/enterprise#127560 Forward-Port-Of: odoo/enterprise#120996
Fixed an issue that caused Deferred Revenue Report exports to fail when annotations were present. Users can now export annotated accounting reports to Excel without encountering a server error.
Original PR description
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to…
**Steps to reproduce:** * Install the **Accounting** module. * Unhide the **Start Date** and **End Date** fields on invoice lines. * Create and post a customer invoice with deferred dates. * Go to **Accounting → Reports → Deferred Revenue Report**. * Add an annotation to a deferred revenue line by clicking the **annotate** from three dots 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:** * Introduce a boolean flag `annotations_header_written = False` before the header loop to explicitly track whether the "Annotations" column header has already been written. * Inside the header loop, set `annotations_header_written = True` after writing the header. * 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_header_written` is still `False`, assign `annotations_x_offset` from the current `x_offset` and write the "Annotations" header. opw-6354473 Forward-Port-Of: odoo/enterprise#122768
This fix removes an ambiguity in how Web Studio approval rule conditions are interpreted. Approval rules with empty conditions now correctly apply to all relevant records, preventing inconsistent approval behavior.
Original PR description
Before this commit, there was an ambiguity with the usage of filtered_domain ie ``` self.assertTrue(record.filtered_domain(False)) self.assertFalse(record.filtered_domain(Domain(False))) ``` This is because in that case the API of filtered_domain was not respected After this commit, there is no ambiguity as we cast to a Domain the value we obtain from the rule: - False or None: all records should be impacted by the rule => Domain(True) - otherwise, let the domain do its job opw-6431607
The Sign Documents wizard now keeps the Employee role selectable when users choose multiple signature templates that use separately created roles with the same name. This prevents signature requests from being blocked when combining templates such as contracts and policies.
Original PR description
Problem: When selecting several sign templates with different signatory counts in the "Sign documents" wizard (e.g. a Contract template together with a Computer Policy template), the Employee Role…
Problem: When selecting several sign templates with different signatory counts in the "Sign documents" wizard (e.g. a Contract template together with a Computer Policy template), the Employee Role field would empty out or disappear entirely, with "No records" shown in the dropdown. This blocked users from sending the signature request at all. Purpose: `_compute_responsible_ids` matched roles across the selected templates by recordset identity (`&=`), i.e. by database id. Since the Sign Template Builder allows free-text role creation, two templates can end up with roles that are visually/semantically identical (same name, e.g. "Employee") but were created as separate `sign.item.role` records with different ids. The id-based intersection then evaluated to an empty recordset, which made the Employee Role field's domain empty and the field itself collapse in the UI. This fix matches roles by name instead of by id when computing the common roles across selected templates, and resolves the correct per-template role id by name in `validate_signature` instead of reusing a single id across every template. Steps to Reproduce On Runbot: 1. Go to Sign > Templates and create two templates, each with one role named "Employee", added independently (so they end up as two distinct sign.item.role records with the same name). 2. Go to an employee's Contract, click "Sign Documents". 3. Select both templates in "Documents to sign". 4. Observe the Employee Role field empties out / shows no records, and the request cannot be sent. opw-6445327
Swiss payroll now counts flexible employee absences using the dates selected in the time off request, avoiding an extra day caused by timezone conversion. This prevents one-day accident leave from being prorated as two days, helping keep regular wage and accident salary amounts accurate.
Original PR description
Issue: Swiss payslips count one extra absence day for employees without a working schedule. A one day accident leave can therefore be prorated as two days, reducing the regular wage and overstating…
Issue: Swiss payslips count one extra absence day for employees without a working schedule. A one day accident leave can therefore be prorated as two days, reducing the regular wage and overstating the accident salary. Steps to reproduce: * Install Swiss Payroll. * Configure a monthly employee without a working schedule. * Assign one day of accident time off. * Generate the payslip for that month. Cause: The Swiss wage computation derives absence boundaries from the date portion of the leave's UTC datetimes: https://github.com/odoo/enterprise/blob/16c29e1bab34b5bcb2b001477d928ec5eb294a97/l10n_ch_hr_payroll/models/hr_payslip.py#L313-L330 A fully flexible employee's full day leave starts at local midnight. In timezones ahead of UTC, that start is stored on the previous UTC date, so the inclusive calendar day computation adds an extra day. Solution: We need to use the requested time off dates for both payslip range filtering and absence proration. These fields preserve the calendar days selected by the user independently of timezone conversion, while leaving the UTC datetimes and half-day handling unchanged. opw-6435086
Payroll settings now only show Mexico-specific CFDI options when the selected company is based in Mexico. This prevents irrelevant configuration fields from appearing for companies in other countries and reduces setup confusion.
Original PR description
Steps to reproduce: 1. Switch to a non-Mexican company. 2. Go to Payroll > Configuration > Settings. 3. The CFDI settings block is visible. Reason: The CFDI block was missing a country check. Solution: Restrict the CFDI block visibility to Mexican companies. Task-6448440
Fixes a mobile Documents issue where the Info & Tags panel could appear enabled but remain hidden or inaccessible after reloads, view switches, previews, or selection changes. This keeps document details and chatter actions available in the correct state, reducing confusion for mobile users.
Original PR description
**Steps to reproduce:** - Go to Documents app in mobile - Go to the kanban view - Add some files and select one - Click on `Info & Tags` button in the control panel - Reload the page - Chatter is not…
**Steps to reproduce:** - Go to Documents app in mobile - Go to the kanban view - Add some files and select one - Click on `Info & Tags` button in the control panel - Reload the page - Chatter is not displayed but the button is still enabled - Switching to the list view properly shows it **Issue:** Original fix (see [1]) was not enough for every case. Additional issues: - Chatter hidden on init even when its panel has `visible = true` - State desynchronized with the view when switching menu type (kanban/list) or by previewing a document and coming back - When using the button with an open preview, chatter shows up in the background but is not accessible (and going back discards it) - Removing selection with an open chatter disable the related action **Fix:** - Disable the chatter on mobile init by default to avoid having to manually move it back - Reset chatter on selection removal to avoid getting stuck in the menu - Reset chatter on view switch to avoid being in the wrong state afterwards (and revert the previous css changes) Not a great fix (quite mobile-specific) and there might still be some edge cases. [1] original fix: https://github.com/odoo/enterprise/commit/cf3c2fce8a6b7b2d7547d44a0e4423f887986d52 opw-6061993
Return labels generated through Sendcloud no longer print the customer's house number twice. This makes return shipping labels clearer and helps avoid confusion or delivery issues for customers and carriers.
Original PR description
Issue ----- On return labels, the house number of the origin address (so the customer) is printed twice. Steps to reproduce ----- - Setup sendcloud - Select a return service - Enable "Generate Return Label" - Create a delivery using sendcloud - Validate the delviery > The return label has the house number printed twice Cause ----- For the origin address shown on labels, Sendcloud prints both the address line and the house number. There doesn't seem to be any parsing made on the address line to extract the house number. For the WH -> Customer label, the "from" address is taken directly from the Sendcloud account's configuration. For the Customer -> WH return, we provide it in the `from_` fields of the request. Note that, when including the house number on the address line in Sendcloud, the issue is also present. ----- Ticket: opw-6405054
Large accounting reports now render fewer hidden lines, reducing page weight and improving responsiveness when users fold sections or search. This helps teams work more smoothly with reports containing thousands of lines until the newer virtual grid technology is available.
Original PR description
When a report has 1 000+ lines, the DOM gets quite heavy which make DOM operation very slow. To help reduce this, we now will minimize the number of components rendered by removing components that previous were just hidden using "d-none" on the line. This will require more creation and suppression of components but it should make the DOM size smaller so it should help on larger reports where a lot of lines are hidden (by folding back a line, or by using the search bar). opw-6427411 opw-6442756 PR Note: this is only required until saas-19.5/20.0 since the virtual grids are added then which will resolve this issue since the virtual grids only render what's in the view of the user with long paddings on top and bottom so only ~70-80 lines are actually rendered.
This fix corrects an incorrect enumeration used in Swiss withholding tax mutation reporting. It helps ensure payroll declarations use the expected values, reducing the risk of reporting errors for Swiss payroll users.
Original PR description
task-6116327 Forward-Port-Of: odoo/enterprise#127745