Thursday, September 17, 2026
12 changes · 18.0
Resolved issues and error corrections
Project dashboards now show only the portion of an expense assigned to each project, rather than the full expense on every related project. This prevents overstated project costs and gives managers a more accurate view of profitability when expenses are split across projects.
Original PR description
## Steps to reproduce: - Install Project and Expenses modules - Create an expense for 100 euros - Confirm the expense and post its journal entries - Set analytic distribution for two different projects each for 50% - Notice the project dashboard for both projects is stating 100 euros ## Cause: When fetching the expenses profitability items we set the amount as the whole amount billed for the expense. ## Fix: We fetch the analytic distribution and multiply the amount by the percentage allocated for the project. opw-6457156
This fixes a Point of Sale loyalty discount issue where promotions could be calculated too low when an order included both regular products and negative-priced lines, causing customers to overpay. Discounts are now distributed proportionally across tax groups so the final reward amount matches the intended promotion.
Original PR description
Steps to reproduce: - Product A with a price-included tax, product B with a negative price and another tax (or none) - Promotion with a fixed amount discount on specific products (or on the order),…
Steps to reproduce: - Product A with a price-included tax, product B with a negative price and another tax (or none) - Promotion with a fixed amount discount on specific products (or on the order), both products eligible - Add both products to a PoS order Issue: The discount is split per tax group with a common factor, so the negative line gets a positive reward line, which is expected. But the reward lines add up to less than the discount and the customer pays too much. Cause: Since 7280f3597ece each tax group is capped with `Math.min(get_total_with_tax(), amount)`. A single tax group is compared with the total of the whole order: here the total includes the negative line, so the positive group is lowered while the negative one is kept as is. Fix: Apply the cap proportionally: every tax group is scaled by the ratio between the order total and the discountable amount when the total is lower. The scenario of 7280f3597ece gives the same result, and the reward lines add up to the discount whatever the number of tax groups. opw-6567973 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Credit notes for invoices already accepted in Poland's KSeF system now report the correct original KSeF reference instead of marking the invoice as issued outside KSeF. This helps ensure exported e-invoice XML files comply with Polish FA(3) requirements and reduces the risk of incorrect regulatory submissions.
Original PR description
### Issue before this commit: When generating a credit note for an invoice already accepted in the Polish KSeF system, the exported XML incorrectly includes the <NrKSeFN>1</NrKSeFN> tag. This tag…
### Issue before this commit: When generating a credit note for an invoice already accepted in the Polish KSeF system, the exported XML incorrectly includes the <NrKSeFN>1</NrKSeFN> tag. This tag falsely indicates that the original invoice was issued outside of KSeF, and the official KSeF number of the corrected invoice is entirely omitted from the file. ### Steps to reproduce the issue: 1. Download Accounting and l10n_pl 2. Go to Settings > Polish Localization > Insert certificate 3. Go to Invoices > Create an invoice > Send it to KSeF 4. Create a credit note for that invoice, reverse it and send it to KSeF 5. Tag <NrKSeFN>1</NrKSeFN> should not be there ### Cause of the issue: The tag <NrKSeFN>1</NrKSeFN> is emitted in every case without any rule handling it. ### Reason to introduce the fix: To comply with the official FA(3) logical structure rules. According to the specifications, if the corrected invoice was issued and accepted in KSeF, the XML must include the <NrKSeF>1</NrKSeF> flag and additionally provide the original KSeF number in the <NrKSeFFaKorygowanej> field. Otherwise, if the original invoice was issued outside of KSeF, the system must enter "1" in the <NrKSeFN> field and strictly omit the <NrKSeF> and <NrKSeFFaKorygowanej> fields. <img width="866" height="981" alt="image" src="https://github.com/user-attachments/assets/53b42f9f-aaab-4642-be38-2a5abc1d8539" /> opw-6541941 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Point of Sale now prevents users from opening a register when the server connection is unavailable. This avoids sessions being closed with sales that were never properly opened on the server, helping ensure accurate session records and opening cash tracking.
Original PR description
Steps to reproduce: - Open a PoS so that the Opening Control popup is displayed. - Cut the connection to the server without the browser going "offline" (e.g. the router stays up but the internet link…
Steps to reproduce: - Open a PoS so that the Opening Control popup is displayed. - Cut the connection to the server without the browser going "offline" (e.g. the router stays up but the internet link is down). - Click on "Open Register". - Restore the connection, make some orders, close the session. Issue: The session is closed with orders but was never opened on the server: it has no opening date, keeps its temporary name "<config>/00000", and the opening cash was never recorded. `set_opening_control` was called with the `queue` flag. On a ConnectionLostError the call was silently pushed to the in-memory unsync queue, and the popup marked the session as opened locally and closed itself. That queue is only replayed on the browser `online` event, which is never fired when the device stayed connected to its local network, and it is lost when the tab is closed or reloaded. Meanwhile the server accepts orders on a session in `opening_control`, and nothing checks it at closing. Opening the register is not an operation that can be deferred: the session must be opened before any order is made. The call is no longer queued. When the connection is lost, the user is told that the register cannot be opened offline, and the popup stays open so the opening can be retried once the connection is back. opw-6580262 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Employee spreadsheets now update their employee list when the active company selection changes. This prevents employees from removed companies from staying visible and avoids spreadsheet errors caused by outdated company filters.
Original PR description
Issue: When viewing a spreadsheet containing employee data, changing which companies are in context does not reliably update which employees are shown. When a user initially makes a spreadsheet from…
Issue: When viewing a spreadsheet containing employee data, changing which companies are in context does not reliably update which employees are shown. When a user initially makes a spreadsheet from an employee list view, the resulting spreadsheet will not, at the time of creation, include any employees from companies not in context. However, if the user later removes a company from context, employees from the removed company can remain visible in some cases. In later versions (19.0+), when a company is removed from context, every cell in the spreadsheet can show an error instead of data in certain circumstances. Steps to reproduce scenario where an employee from a company that was removed from context remains visible, in fresh database with the Employees app and the `spreadsheet_dashboard` module installed: 1. Make two companies, Company A and Company B. 2. Make a couple employees for each company. 3. Create an employee that is linked to the currently logged in user. That employee should be associated with Company A. 4. Make the employee created in step 3 the manager of any Company B employee. 5. Make sure both companies are in context. 6. Go to the employee app, and view all employees in list view. 7. In list view, select "All". 8. Insert the list view into a spreadsheet. 9. While looking at the spreadsheet, remove Company B from context. 10. Observe the spreadsheet has all the Company A employees, plus the Company B employee managed by the admin employee. Steps to reproduce scenario where every cell shows "error" in fresh 19.0+ database: 1. Make two companies, Company A and Company B. 2. Make a couple employees for each company. 3. Create an employee that is linked to the currently logged in user. That employee should be associated with Company B. 4. Make sure both companies are in context. 5. Go to the employee app, and view all employees in list view. 6. In list view, select "All". 7. Insert the list view into a spreadsheet. 8. While looking at the spreadsheet, remove Company B from context. 9. Observe the spreadsheet has "error" in all cells. Explanation: When a list view of hr.employee records is inserted into a spreadsheet, the domain is captured once as a literal snapshot at creation time and never re-evaluated. Company scoping is therefore enforced by two different mechanisms depending on when it happens: the frozen client domain at creation time, and the "Employee multi company rule" record rule for every read after that. These two mechanisms disagree in edge cases, since the record rule has exceptions the domain does not (e.g. an employee is always visible if they are connected to the current user, or are managed by the current user). Solution: In the hr module, patch the `getComputedDomain` method so that, for hr.employee specifically, any top-level ["company_id", "in", [...]] leaf in the computed domain has its value replaced with the currently active company ids before the domain is returned. This makes the domain track live company context on every read instead of staying frozen at creation time. Only "in" leaves are touched, so a leaf added via a sidebar company filter (which uses "child_of") is left untouched, preserving any narrower selection the user made explicitly when the list was first created. opw-6253926 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where grids could appear empty after part of a page was refreshed or recreated. The grid now recalculates immediately, reducing confusing blank screens and avoiding the need for users to scroll or resize the window to restore content.
Original PR description
See commit messages for details. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This fixes an issue where new US companies using AvaTax could generate tax entries without the required accounting account when the database was created without demo data. AvaTax invoice and refund accounts are now assigned during setup, helping invoices compute taxes correctly from the start.
Original PR description
Steps to reproduce: - Create a DB and Install `Accounting` without demo data - In Companies > Create New Company with `US` Localization - Switch to US Company > Add `Avatax` Credentials - Create a…
Steps to reproduce: - Create a DB and Install `Accounting` without demo data - In Companies > Create New Company with `US` Localization - Switch to US Company > Add `Avatax` Credentials - Create a Product with `Avatax Category` - Create a Invoice > In Other Info `Fiscal Position` - `Automatic Tax Mapping (AvaTax)` > `Compute Taxes` - In Taxes check newly created tax does not have a account ID Issue: AvaTax fiscal position created from chart templates have empty `avatax_invoice_account_id` and `avatax_refund_account_id` fields on a fresh database without demo data. Problem: Both fields use [defaults] based on `company.account_sale_tax_id`. During initial CoA loading, `_load_data()` creates the AvaTax fiscal position before `_post_load_data()` sets `company.account_sale_tax_id`. The defaults therefore resolve to an empty recordset and no tax account is assigned. This issue does not occur in databases with demo data because the demo company is already loaded, so `company.account_sale_tax_id` is already set when the AvaTax fiscal position is created. Solution: Set the invoice and refund accounts explicitly in the AvaTax fiscal position template to ensure they are correctly assigned during CoA loading. [defaults]: https://github.com/odoo/enterprise/blob/de17c107651394025e9a3d5cbed8d81bcfc2e76d/account_avatax/models/account_fiscal_position.py#L9-L13 opw-6347128
The Ecuador ATS tax export now consolidates invoices and totals from a company and its branches under the same RUC. This ensures the exported XML matches the consolidated tax return and avoids missing branch activity in regulatory filings.
Original PR description
In Ecuador, a company and its branches file under a single RUC, so the ATS is expected to consolidate all of them. However, currently the system exports only the active company report. Steps to…
In Ecuador, a company and its branches file under a single RUC, so the ATS is expected to consolidate all of them. However, currently the system exports only the active company report. Steps to reproduce: - Install the Ecuadorian localization - Create a parent company and a branch, assign the RUC of the parent to the branch, and set the legal name of the branch in Settings - Post a customer invoice with taxes in the parent (e.g. 750) and another one in the branch (e.g. 250) - Activate both companies in the company selector - Go to Accounting > Reporting > Tax return - Select "Report: 104 (EC)", the dashboard shows the consolidated values - Click on the gear icon next to "Tax Return" and select ATS Issue: The exported XML only contains the documents and the totals of the parent company (750). The branch (250) is omitted. Analysis: Currently the ATS export use self.env.company for all searches, which only retrieve the data of the first company set opw-6469807
Mexican customer payments now use the payment method configured on the selected bank journal instead of always defaulting to electronic transfer. This helps payment complements sent to SAT reflect the intended payment method, reducing incorrect tax document details.
Original PR description
Currently, payment way configured on a bank journal is not taken into account, payments will default to "03 Transferencia electrónica de fondos". Steps to reproduce: - Set the "Payment Way" of a bank journal to "04 Tarjeta de Crédito". - Manually create a customer payment in that journal - Look at the "Payment Way" of the payment, then send the payment complement (REP) to the SAT. Issue: The payment way is "03 Transferencia electrónica de fondos" and the REP carries FormaDePagoP="03" The one set on the journal is ignored. Analysis: We should evaluate the journal before the transferencia default so a payment inherits the payment way, and keep transferencia as the last possible value. opw-6493514 Forward-Port-Of: odoo/enterprise#130133
Fixed an issue where creating a planning shift from an overnight template could incorrectly extend the shift by an extra day. This helps planners keep night shift schedules accurate and avoids unintended staffing or payroll confusion.
Original PR description
This is a backport of this [commit](https://github.com/odoo/enterprise/commit/c02b8eccd72758127cc7cdc51ab8ec461a2ec45e) Issue: ---------------------------------------- Creating a night shift from a…
This is a backport of this [commit](https://github.com/odoo/enterprise/commit/c02b8eccd72758127cc7cdc51ab8ec461a2ec45e) Issue: ---------------------------------------- Creating a night shift from a template produces a shift spanning over one additional day. Steps to reproduce: ---------------------------------------- - Create a planning shift template form 23h to 1h the next day (2h) - It must have a span over 2 working days - Create a shift and use this template - The shift spans over one more day Cause: ---------------------------------------- In `_calculate_start_end_dates()`, we call `plan_days()` with `start` having the hours specified. So in `plan_days()` when retrieving the worked days, the first day is ignored because the resource is not supposed to be working from 23h to 1h. Then we count two days and so the end date is offset by one day. Solution: ---------------------------------------- We should call `plan_days()` without the hour specified so we make sure the first day is included in the count. opw-6535758
This fixes an issue in the HTML editor where Safari could delete selected text without inserting the newly typed character. Users editing notes or other rich text fields in Safari can now replace selected text normally, reducing editing mistakes and frustration.
Original PR description
When using Safari, if the first character of the editable is selected and a character is pressed, the selection content is removed, but the character is not inserted. It seems that Safari does not trigger the actual `input` event, nor its native behavior, if the initial anchor node is detached from the DOM after `beforeinput`. This commit avoids this issue by preventing Safari from proceeding with the insertion right after the deletion by instead re-triggering the `insertText` command. Steps to reproduce: - Use Safari - Go to a To do note - Select the first word - Press a letter => The first word was deleted but the letter was not inserted. task-6445669
The Colombian Libro Diario report now works correctly when comparison options are enabled and includes journal entries that do not have a partner assigned. This helps prevent reporting errors and ensures legally required accounting entries appear in the report.
Original PR description
## [FIX] l10n_co_reports: fix UNION ALL crash with multiple column groups ### Issue: Any comparison mode (Period, Analytic, etc.) in the Libro Diario raises an Odoo Server Error ### Cause: Each…
## [FIX] l10n_co_reports: fix UNION ALL crash with multiple column groups
### Issue:
Any comparison mode (Period, Analytic, etc.) in the Libro Diario raises an Odoo Server Error
### Cause:
Each sub-query in the `UNION ALL` had its own `ORDER BY` SQL only allows one global `ORDER BY` on a `UNION ALL`, or parentheses around each query — neither was the case
### Steps to reproduce:
- Install `l10n_co_reports` and `accountant`
- Enable Developer Mode in Settings
- Open the Libro Diario report and click the gear icon (top right)
- In the Options tab, enable Period Comparison
- Enable the Comparison for the Previous Period
Before the fix, an error is raised
------------------------------
## [FIX] l10n_co_reports: include partnerless entries in Libro Diario
### Issue:
Journal entries without a partner are excluded from the report but are legally required to appear
### Cause:
`_get_domain` called `super()` which adds `('partner_id', '!=', False)` to the domain, filtering out all partnerless entries
The SQL query also used a `JOIN` instead of `LEFT JOIN` on `res_partner`, excluding lines with no partner at the DB level
### Notes:
`NULL` values for `partner_name` or `line_label` caused the JS to hide the corresponding column headers
`header.js` matches columns to their header by `column_group_index`/`expression_label` and skips `None` values
Fixed by using `COALESCE` to return an empty string instead
### Steps to reproduce:
- Install `l10n_co_reports` and `accountant`
- Create a Journal Entry without a partner or label
- Open the Daily Journal Report
Before the fix, the entry doesn't appear
After the fix, check that PARTNER and LABEL headers are visible
opw-6430728