Monday, August 31, 2026
43 changes · saas-19.3
Enhancements to existing features
Portal users can now search tasks by milestone much faster from the My Tasks page. This improves responsiveness for customers and external users working with project tasks, reducing a previously slow search from several seconds to near-instant results.
Original PR description
Go to `/my/tasks`. The search on milestones is really slow. Performance improvement for a portal user: | | Time | Query plan | |--------|--------|--------| | Before | ~3.6s |…
Go to `/my/tasks`. The search on milestones is really slow. Performance improvement for a portal user: | | Time | Query plan | |--------|--------|--------| | Before | ~3.6s | https://explain.dalibo.com/plan/dga21917bc86eg54 | | After | ~60ms | https://explain.dalibo.com/plan/91b818beg2f1077f | For portal users, complex record rules require joining the `project` table. Because the query includes a `limit=1`, the postgresql query planner assumes it will find a matching row almost immediately. Hoping for a "fast exit", it chooses to sequentially scan the `project_id` index to perform a Merge Join. However, if it doesn't find a match early on, it ends up scanning the entire index, resulting in a massive slowdown. We update the `search_count` constraint from `limit=1` to `limit=80`. By increasing the limit, we alter postgresql's cost estimation. The planner can no longer assume a cheap "fast exit" is guaranteed, which forces it to abandon the flawed Merge Join strategy. Instead, it correctly evaluates the query and chooses the index on `milestone_id` to retrieve the records. task-6373729 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Manufacturing planning now finds available work center time slots much faster when schedules are heavily booked. This reduces delays and system load in short-duration production scheduling scenarios, with benchmarked searches dropping from minutes to under a second in extreme cases.
Original PR description
### Description of the issue/feature this PR addresses: The workcenter planning logic in _get_first_available_slot can become inefficient when searching for very short available slots. The method…
### Description of the issue/feature this PR addresses: The workcenter planning logic in _get_first_available_slot can become inefficient when searching for very short available slots. The method repeatedly builds small candidate time windows and checks them against existing workorder and leave intervals, potentially iterating many times before finding a free slot. This leads to unnecessary computational overhead in scenarios where a large number of busy intervals exist and the remaining duration to schedule is small. ### Current behavior before PR: The planner checks for conflicts by computing the intersection between the candidate window and the busy intervals. When a conflict is detected, the candidate window is shifted forward (or backward) to the end (or start) of the intersection, and the process is repeated until a free slot is found. This approach requires repeatedly performing full interval merge operations, which becomes disproportionately expensive when the candidate windows are very small and the loop iterates many times. ### Desired behavior after PR is merged: The planner uses a new Intervals.conflicting() helper to retrieve the entire busy interval that overlaps with the candidate window. Instead of advancing only to the end of the intersection slice, the planner can jump directly to the end (or start) of the full busy interval. This avoids repeated full-merge work, reduces the number of iterations needed to find a valid slot, and prevents pathological performance slowdowns in short-duration planning scenarios. ### Benchmarks Profiling _get_first_available_slot with different workorder durations. Database has multiple months that are fully booked. Speedup is more dramatic with shorter durations but there is at minimum minor improvements across the board. | Work Order Duration | Before | After | | --- |---|---| | 1sec | ~2.5min | <1sec | | 1min | ~2sec | <1sec | ### References opw-5437256 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284278 Forward-Port-Of: odoo/odoo#246015
The French PDP pilot phase option has been removed because the early participation period has ended. This simplifies the registration and settings screens so companies now follow the standard e-invoicing onboarding flow.
Original PR description
The pilot phase was there if people wanted to send before the deadline. The deadline has been reached, so we can remove the field from the view. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285268 Forward-Port-Of: odoo/odoo#284186
The contract template screen now hides the Tax Deductions section when Professional Tax is disabled in Payroll settings. This avoids showing an empty or irrelevant section, making the setup experience clearer for users.
Original PR description
Prior to this commit, the "Tax Deductions" group caption on the contract template view remained visible even when Professional Tax (PT) was not enabled in the Payroll settings. This commit updates the visibility condition of the "Tax Deductions" group on the contract template view to be hidden when PT is disabled (`not l10n_in_pt`), preventing empty settings sections from displaying to users. Task: 6514274
POS users can now reprint an entire order as an order change from both the Product Screen and Ticket Screen. This makes it easier for restaurant and point-of-sale staff to recover or resend complete order information without printing changes one by one.
Original PR description
Before this commit: ------------------------------- - From the Product Screen, users could only reprint the last order change, while from the Ticket Screen, they could reprint all previous order changes one by one. After this commit: ----------------------------- - Users can now reprint the entire order as an order change directly from both the Product Screen and the Ticket Screen. Task-6230594 Forward-Port-Of: odoo/odoo#283892 Forward-Port-Of: odoo/odoo#266070
Resolved issues and error corrections
Point of Sale settlements that only pay existing invoices will no longer create a separate zero-amount invoice. This prevents validation failures in Argentina and avoids consuming official invoice numbers unnecessarily, while orders that include actual sales continue to be invoiced normally.
Original PR description
Steps to reproduce: - Argentinean company, Responsable Inscripto (l10n_ar_pos installed) - A posted customer invoice with VAT, partially paid - In the PoS, pick the customer, "Settle invoices",…
Steps to reproduce: - Argentinean company, Responsable Inscripto (l10n_ar_pos installed) - A posted customer invoice with VAT, partially paid - In the PoS, pick the customer, "Settle invoices", select that invoice, pay the balance by bank transfer and validate Issue: Validation fails with "There should be a single tax from the "VAT" tax group per line, but this is not the case for line ..." and the settlement cannot be recorded at all. The invoice being settled is correct; the rejected line belongs to a second invoice the PoS creates for the settlement itself. Cause: `setToInvoice` already refuses to invoice a settlement, but its condition, `is_settling_account and no line`, only describes a deposit: the deposit line is added at validation. When settling a due or an invoice, `is_settling_account` stays false and the order does carry lines - the settle lines - so the guard never fires. l10n_ar_pos then sets `to_invoice` on mount, as a sale must generate an electronic document in AR, and the settle line, untaxed on purpose since it pays an existing document rather than selling anything, reaches `_check_argentinean_invoice_taxes`. Fix: Refuse the flag as well when every line is a settle line. Such an order generates an empty document - all its lines, the receivable one included, have a zero balance - so it records nothing and only consumes a document number, which in AR means an AFIP number for a zero-amount invoice. An order that also sells something keeps its invoice, since the sale still has to be reported. Reconciliation is unaffected: it happens in `_reconcile_account_move_lines` at session close, and is already covered for both invoiced and non-invoiced settlement orders. opw-6464675 Forward-Port-Of: odoo/enterprise#128975
Point of Sale now correctly applies pricelist rules based on product categories when products are added after a session has already started. This prevents cashiers from charging the default sale price when a valid category discount or pricing rule should apply.
Original PR description
Steps to reproduce: - Create a pricelist with a rule applied on a product category and make it available in the PoS - Open a PoS session - From the backend, create a product in a new category covered…
Steps to reproduce: - Create a pricelist with a rule applied on a product category and make it available in the PoS - Open a PoS session - From the backend, create a product in a new category covered by such a rule - Back in the PoS, find that product through Search > Search more and add it to the order Issue: The product is priced at its sale price, the pricelist rule set on its category is ignored. Cause: A product that is not part of the initial payload is loaded on the fly by load_product_from_pos, which sends back the rules returned by get_pos_ui_product_pricelist_item_by_product. That domain only matches the rules set on the template or on the variant, never the ones set on a product category, and the payload carries no product.category record either. The client therefore has neither the rule nor the category: parentCategories walks categ_id, which resolves to nothing, so getCategoryRulesIds returns no rule and getPrice falls back to the sale price. This stayed unnoticed because product.category is fully loaded when the session starts, along with every category rule, so only the categories created after the session was opened are missing. Fix: Send the categories of the loaded products, since a rule set on a parent category applies to its children - along with the products, and match the rules set on those categories in get_pos_ui_product_pricelist_item_by_product. The initial loading domain of product.pricelist.item no longer filters the category rules on the loaded categories: such a rule has to be loaded whatever the products sent to the client are, since a product of that category may be loaded later on. opw-6477745 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285411 Forward-Port-Of: odoo/odoo#284660
Belgian accounting users can now import SODA XML files even if they do not have Analytic Accounting permissions. This prevents an unnecessary access error when Analytic Accounting is not enabled, keeping payroll-related accounting imports running smoothly.
Original PR description
**Description of the issue/feature this PR addresses:** When importing a SODA XML file, users without the Analytic Accounting group encounter an access rights error even if Analytic Accounting is not…
**Description of the issue/feature this PR addresses:** When importing a SODA XML file, users without the Analytic Accounting group encounter an access rights error even if Analytic Accounting is not enabled. This occurs because the import wizard reads the `analytic_account_id` field on the `soda.analytic.mapping` model to build an internal dictionary of departments. Because this field is restricted to the Analytic Accounting group, the evaluation of this field crashes the import for users even when the Analytic Accounting feature is disabled. This commit resolves the issue by using `.sudo()` on the analytic mapping recordset to bypass the field-level group restriction. **Steps to reproduce:** - Log in as Mitchell Admin, change company to “My Belgian Company” - Settings > Users & Companies > Users > Mitchell Admin > Access Rights > Extra Rights > ensure “Analytic Accounting” is unchecked - Also ensure Mitchell Admin is not part of the “Analytic Accounting” group - Accounting Dashboard > remove “Favorites” from filter > drag & drop a SODA XML file to “Miscellaneous Operations” > save > observe Access Error **Current behavior before PR:** - Users who don't belong to the Analytic Accounting group encounter an access error when attempting to import SODA XML files, even when the Analytic Accounting feature isn't enabled **Desired behavior after PR is merged:** - Those users no longer receive an access error opw-6376039 Forward-Port-Of: odoo/enterprise#127867
The timesheet assistant now displays the add and remove suggestion buttons correctly within their border. This prevents visual overflow and makes the assistant easier and cleaner to use.
Original PR description
This commit ensures that the buttons to add/remove suggestions fit the border. task-6492978 Forward-Port-Of: odoo/enterprise#129345
Customers who place takeout or delivery orders through POS self-order now receive access to their receipt in the confirmation email. This fixes a mismatch where emails said a receipt was included, but no receipt was actually provided.
Original PR description
Currently, when takeout and delivery mails are sent out to clients the mention "Attached you will find you receipt" can be seen but no receipt is sent. Steps to reproduce: ------------------- * Modify restaurent config * Enable QR + self ordering * Add Online payment method * Open the self order * Make an order for delivery or takout * Pay the order * Check the emails sent > No attachment provided Why the fix: ------------ Since this commit https://github.com/odoo/odoo/commit/a0b567508ffeb572a3c36bf28ae085d766d95f18 we now send the email only from the backend but the receipt couldn't be rendered from the backend at that time. In this version it is now possible so we cans attach the receipts with the mail. opw-6197985 Forward-Port-Of: odoo/odoo#266007
When a recurring task series is ended by deleting the latest task, remaining tasks no longer keep the Recurrent option selected by mistake. This avoids confusing users into thinking those tasks will continue generating future tasks when the recurrence has already stopped.
Original PR description
**Problem:** Deleting one task of a recurrence suite ends the recurrence, but the tasks that stay behind keep the "Recurrent" option ticked. They look recurrent while no recurrence exists any more,…
**Problem:** Deleting one task of a recurrence suite ends the recurrence, but the tasks that stay behind keep the "Recurrent" option ticked. They look recurrent while no recurrence exists any more, so closing one of them never produces the next occurrence. **Steps to reproduce:** 1. Create a project with "Recurring Tasks" enabled 2. Create a task, tick "Recurrent" and mark it as done 3. Repeat on each generated occurrence until 3 or 4 tasks exist 4. Delete the last generated task 5. Open one of the tasks left in the suite **Current behavior:** The remaining tasks still show "Recurrent" ticked, but marking one as done creates no new occurrence and the recurring tasks smart button is empty. **Expected behavior:** Ending the recurrence should turn the "Recurrent" option off on every task that was part of it. **Cause of the issue:** `unlink` deletes the `project.task.recurrence` when the last task of the suite is removed, and `recurrence_id` is set to NULL on the other tasks by the database. Nothing resets their `recurring_task` boolean, so it stays `True` with no recurrence behind it. The two other places that end a recurrence, `write` and `action_unlink_recurrence`, already clear the flag on the whole suite. **Fix:** Aligning `unlink` with those two paths keeps a single meaning for `recurring_task`: it is only ticked while a recurrence actually exists. The suite has to be read before the recurrence is deleted, since the one2many is empty afterwards, and the tasks of the batch being deleted are left out so that no write lands on records that are about to disappear. opw-6425292 Forward-Port-Of: odoo/odoo#282535
WhatsApp proxy calls now send subscription details in the format the receiving service expects. This helps ensure WhatsApp OAuth subscription checks can read the needed database identifier reliably, reducing failed connection or validation flows.
Original PR description
The calls to the WhatsApp proxy sent their parameters as a JSON body, which a `type='http'` route does not unpack into its arguments, so the proxy needed a decorator to read them back before `check_subscription` could see `db_uuid`. Send them as form fields instead. `requests` encodes a dict as `application/x-www-form-urlencoded` and sets the header itself, so the routes fill their arguments on their own and the decorator goes away on the proxy side. Forward-Port-Of: odoo/enterprise#129815
This fix prevents rare crashes in Intrastat reporting when company data is accessed under unusual permission conditions. It mainly protects future customizations or edge cases, with no expected change to normal day-to-day use.
Original PR description
Due to some trouble with tests, we found that in some cases, this function is called on the root company, and if the user does not have the access rights to read data from the company (users with system rights have them by default), it will cause a crash. This situation is not possible with the standard UI, but we fix it in case it becomes possible in a future version or customization. Forward-Port-Of: odoo/enterprise#129083 Forward-Port-Of: odoo/enterprise#128217
This fixes a forum access test so it uses the correct helper forum and verifies that users need the right karma level to comment on someone else's post or reply. It helps ensure forum participation rules are tested accurately and reduces the risk of permission issues going unnoticed.
Original PR description
**Issue:**
`website_helpdesk_forum` overrides the `ref('website_forum.forum_help')` in its demo data, allowing anyone to comment / post on it.
**Fix:**
Use the helper forum instead and properly requires `KARMA['com_all']` when posting a comment on someone else post/reply.
related: https://github.com/odoo/odoo/commit/ba19ef413e400a65e9f43a6fc6c4bc1586ea8983
runbot-944703
Forward-Port-Of: odoo/odoo#281757This fix prevents broad internal searches when access rules involve linked records, which could make document-related requests very slow on databases with many attachments. It improves reliability for product document access without changing user-facing functionality.
Original PR description
When the security domain uses a many2one field that needs the `search_domain` context, the field itself might not be present in the user-given domain. When this happens, we assumed to search on all records which is too much in the case of attachments. The practical example is product.document where a simple fetch could not be done anymore on databases having a lot of attachments. opw-6486492 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change reverts a recent GIF resizing update because it caused slow page loading and memory errors when views displayed multiple animated images. The rollback helps keep pages responsive and prevents crashes in image-heavy workflows.
Original PR description
Revert commit d9fae40571c4f10c17fe00efc087cb25b30b85ab as it's slow on odoo.com and the call to `frame.copy()` is raising a MemoryError when loading a KanbanView with multiple gifs. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284884 Forward-Port-Of: odoo/odoo#284479
Calendar invitation files now include the meeting's video call link in a standard URL field. This helps recipients and external calendar apps surface the join link more reliably.
Original PR description
Add the meeting's videocall_location as a URL property in generated iCalendar (.ics) invitation files. --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#283934 Forward-Port-Of: odoo/odoo#283562
Restaurant point-of-sale orders now remember when the guest count has already been entered on another device. This prevents staff from seeing the same guest-count prompt twice while keeping guest numbers consistent on buttons, receipts, and kitchen tickets.
Original PR description
Steps to reproduce: - Enable presets on a restaurant PoS and tick "Amount of Guests" on the preset used for tables - On device A, open a table and enter the number of guests - On device B, open the…
Steps to reproduce: - Enable presets on a restaurant PoS and tick "Amount of Guests" on the preset used for tables - On device A, open a table and enter the number of guests - On device B, open the same table Issue: Device B pops the guest count numpad again, even though the guest count was already entered on device A. Cause: ensureGuestCustomerCount guarded the popup on order.uiState.guestSetted. uiState is only serialized to IndexedDB (SERIALIZED_UI_STATE_PROP, used by serializeForIndexedDB); it is never sent to the server, so the flag is local to one browser and a second device always considers the guest count as not yet asked. customer_count is synced and could carry that information, but PosStore createNewOrder pre-filled it with the table seats, so it was never 0 for a table order and could not tell "not asked" from "answered". Fix: Stop storing the seats default on the record and expose it from getCustomerCount() instead, so customer_count == 0 means "no guest count entered yet". ensureGuestCustomerCount now guards on that synced value, so an order whose guest count was entered on another device is not asked for it again. Every display goes through getCustomerCount(), so the values shown on the Guests button, the receipt and the preparation ticket are unchanged. opw-6470180 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285094 Forward-Port-Of: odoo/odoo#283002
Users can now click non-editable links to open the link information popover, even when the content is read-only. This makes it possible to view or inspect inserted links instead of having clicks do nothing.
Original PR description
Problem: Clicking a non-editable link does nothing, making it impossible to open or inspect the link. Solution: Allow the link popover to open in read-only mode for non-editable links. Steps to reproduce: - Run `/article`. - Click on the inserted article link. - Observe that nothing happens. opw-6442026 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285310 Forward-Port-Of: odoo/odoo#280224
This update adjusts how Odoo loads email and certificate credentials so it remains compatible with newer operating system versions of a supporting security library. It prevents unnecessary warning messages in automated builds while keeping existing behavior for older environments.
Original PR description
pyOpenSSL 24.3.0 deprecated passing its own X509/PKey objects to Context.use_certificate()/use_privatekey(), and started accepting cryptography objects instead. Odoo pins pyopenssl 24.1.0, but the distro builds run the version shipped by the OS: since the test added by f0fb287c6502 covers that path, they now add a warning in the logs. Load the certificate and the key as cryptography objects when the installed pyOpenSSL supports them, keep the previous loaders otherwise. Reference: https://github.com/pyca/pyopenssl/commit/b0cb4b4 This fix is based on https://github.com/odoo/odoo/blob/a2b4f618328f3ce3f654fd2c1ee4410365706a7e/odoo/addons/base/models/ir_mail_server.py#L34-L46 runbot-944176 Forward-Port-Of: odoo/odoo#284802 Forward-Port-Of: odoo/odoo#277449
Users configuring the French PDP service now see a consistent message when a migration has been requested. This avoids misleading timing such as “available tomorrow” and gives clearer expectations while the migration status is pending.
Original PR description
Currently when the user requested a migration, we don't show it in any way to the user, and the only timeline we give ("available tomorrow") is completely false. Because we don't have any field we could use for this client-side (maybe from 19.3 we can use the catch-all-json field) So just make the message same for everybody.
no-task
Forward-Port-Of: odoo/odoo#283702
Forward-Port-Of: odoo/odoo#283594Peppol invoice imports and exports no longer use internal deferred revenue recognition dates. This prevents customers from receiving vendor-specific accounting timing information and avoids creating unintended deferred entries on imported vendor bills.
Original PR description
The current implementation of the Peppol XML export incorrectly populates the <cac:InvoicePeriod> nodes with internal deferred entry dates. These dates are intended for the vendor's revenue recognition process, and the customer has nothing to do with these dates. This commit ensures that: - deferred entries are never created when importing vendor bills. - <cac:InvoicePeriod> is no longer exported in invoices (for now). task-6014315 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#279548 Forward-Port-Of: odoo/odoo#265796
LinkedIn posts now show hashtags properly in the feed view. This makes social content easier to read and helps users review published or scheduled posts with the expected formatting.
Original PR description
Task-6323897
Changing a project's visibility no longer fails when the project document folder contains shortcuts. This lets users update project access as expected while still preventing direct access changes on shortcuts themselves.
Original PR description
Changing a project's visibility fails when its documents folder contains a shortcut. The visibility change is never applied and the following error is raised: "You can not update the access of a…
Changing a project's visibility fails when its documents folder contains a shortcut. The visibility change is never applied and the following error is raised: "You can not update the access of a shortcut, update its target instead." ### Reproduction steps - Create a project and add a document to its folder. - Create another document outside the project's folder. - Create a shortcut to that document in the project's folder. - Change the project's visibility. ### Cause Changing a project's visibility updates the access rights of its folder and documents together. The shortcut access check is meant to reject operations performed only on shortcuts. However, reading `shortcut_document_id` on a recordset returns the shortcut targets found across that recordset. Therefore, the presence of a single shortcut makes the check reject the whole operation. This prevents regular documents and the project folder from having their access updated. ### Fix Only reject access updates when all records involved are shortcuts. This preserves the protection against changing shortcut access directly while allowing project access updates to include shortcuts alongside regular documents and folders. opw-6472637 Forward-Port-Of: odoo/enterprise#129588 Forward-Port-Of: odoo/enterprise#128756
Large accounting reports now render fewer hidden lines, reducing page weight and improving responsiveness when users fold sections or search within reports. This helps teams work more smoothly with reports containing thousands of lines until newer virtual grid rendering 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. Forward-Port-Of: odoo/enterprise#127956 Forward-Port-Of: odoo/enterprise#127516
Planning now correctly calculates allocated hours when a shift is assigned to multiple employees with the same working schedule. This prevents misleading daily totals in the Gantt view, helping managers rely on the displayed workload information.
Original PR description
## Steps to reproduce: - Install Planning and Employee - Create a working schedule for example 38h/week (8h,8h,8h,8h,6h) - Create two employees and assign the created working schedule to them -…
## Steps to reproduce: - Install Planning and Employee - Create a working schedule for example 38h/week (8h,8h,8h,8h,6h) - Create two employees and assign the created working schedule to them - Create a shift in planning for the two employees for a week - Notice in gantt view the total allocated hours for each day are not calculated correctly ## Cause: When calculating each cell's duration we fetch the resources' intervals while doing this here https://github.com/odoo/enterprise/blob/1851d3046682020686f517dec3c744d88a38b049/planning/static/src/views/planning_gantt/planning_gantt_renderer.js#L354-L359 we loop over the first interval and instead of pushing to the intervals we overwrite on the whole list with the interval we fetched so when it comes to the next interval it won't find any intersection so it will set the resourceIntervals to an empty array. So here https://github.com/odoo/enterprise/blob/1851d3046682020686f517dec3c744d88a38b049/planning/static/src/views/planning_gantt/planning_gantt_renderer.js#L231-L234 it will mess up the percentage calculation which will lead to wrong allocated hours numbers. ## Fix: Instead of overwriting on resourceIntervals we push to it the intervals returned to keep the intervals for each resource. opw-6316368 Forward-Port-Of: odoo/enterprise#123750
Vendor bill payments with withholding tax no longer crash if the currency field is cleared during payment. The system now temporarily falls back to the company currency, keeping the payment flow stable while still requiring a currency before saving.
Original PR description
Currently, an error occurs when user tries to pay on a vendor bill and removes the currency. Steps to replicate: - Install `l10n_account_withholding_tax`and activate multiple currencies. - Open…
Currently, an error occurs when user tries to pay on a vendor bill and removes the currency.
Steps to replicate:
- Install `l10n_account_withholding_tax`and activate multiple currencies.
- Open Invoicing > Vendors > Bills and create a new bill and add a vendor and bill date.
- Add a product and tax `2% WTH`.
- From the Cog menu > Click Pay > Remove the Currency.
Error:
```
File '/home/odoo/src/odoo/saas-19.4/addons/l10n_account_withholding_tax/models/account_withholding_line.py', line 208, in _compute_original_amounts
line.original_base_amount = line_curr.round(base_amount * rate)
File '/home/odoo/src/odoo/saas-19.4/odoo/addons/base/models/res_currency.py', line 264, in round
self.ensure_one()
File '/home/odoo/src/odoo/saas-19.4/odoo/orm/models.py', line 5342, in ensure_one
raise ValueError('Expected singleton: %s' % self)
ValueError: Expected singleton: res.currency()
```
Cause:
- As the user removed currency, the `comodel_currency_id`is received as false.
- Later when we call `round()` on the empty res.currency recordset causes this error to occur.
Solution:
- Added the company currency as a fallback value when `currency_id` is removed by user, since `currency_id` is a required field user will need to select a currency when saving.
sentry-7616890592
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#283405
Forward-Port-Of: odoo/odoo#277507This fixes an issue where static file paths could be split incorrectly on Windows because the wrong path separator was used. It helps ensure Odoo can reliably serve static resources across operating systems without disrupting users.
Original PR description
In commit 31aad6c, path normalization was added which also resulted in `/` being converted into `\` on Windows. There the `path.split('/')` did not work.
This commit changes the `'/'` to `os.sep` to fix the issue.
---
I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
Forward-Port-Of: odoo/odoo#285265
Forward-Port-Of: odoo/odoo#285216The Accounting dashboard now shows the Import File button for credit card and cash journals when file-based transaction feeds are enabled. This removes a confusing gap where users could configure file imports but had no visible way to start them from the journal card.
Original PR description
The "Import File" button on the dashboard card only shows up for bank journals. Credit card journals are treated the same way as bank journals pretty much everywhere else: the dashboard card itself,…
The "Import File" button on the dashboard card only shows up for bank journals. Credit card journals are treated the same way as bank journals pretty much everywhere else: the dashboard card itself, the statements list, the "Transaction Feeds" setting on the journal form (where you can pick the file import option), and even `create_document_from_attachment` in this module, which already accepts them. So you end up with a credit card journal set to import files but nothing on its card to actually do it, and people assume the feature is simply not there. Show the button on credit card journals too. Steps to reproduce: - Install account_bank_statement_import_csv (or any other import format) - Create a "Credit Card" journal and set its Transaction Feeds to the file import option - Go to the Accounting dashboard - The bank journal card has an "Import File" button, the credit card one doesn't --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/enterprise#129546
The Assets list now remains accessible even when some records contain outdated or invalid analytic distribution data. This prevents users from being blocked by a repeated loading error while preserving read-only access to the asset records.
Original PR description
Issue - If there are any account.asset records with analytic distributions with accounts that do not exist, it causes a recursive traceback when opening the list view of the `account.asset` model. The issue stems from `jsonToData` attempting to save the distributions json via the `save` call, where one (or multiple) accounts are non existent, which in turn runs `jsonToData` after refetching via the `load` call - overwriting `record.data` with the original, still-corrupt JSON. This creates a loop with no exit condition. Solution - In the Assets list every row is readonly, so `save()` is never reached, so `root.load()` never fires, so there is no reload to re-read the corrupt JSON. Makes the list accessible, even though the JSON values for the `analytic_distribution` are invalid. opw-6500446 Forward-Port-Of: odoo/odoo#285527 Forward-Port-Of: odoo/odoo#285381
The Swiss payroll localization now limits the employee certificate dropdown to Swiss-specific choices. This prevents users working in the Swiss localization from seeing irrelevant default certificate options, reducing confusion and data entry mistakes.
Original PR description
The certificate field on the employee model was being extended by the swiss localization to add the swiss-specific certificates. This was done using selection_add on the field which was causing the selection to also show the original values defined on the base employee model. We don't want to see the original values but only the swiss ones when we operate in the swiss localization. At the same time, we can't just override the field (without using selection_add) because a warning is triggered. Other possible solustions like using the result of a function or changing the type of the field to Many2one to use a domain are either not working on a record-per-record basis or not stable compliant. The only working solution for stable is to keep the selection_add working and filter the results in the views using the filterable_selection widget. Task: 5948460 Forward-Port-Of: odoo/odoo#250046
This fix ensures that when employees join a course linked to skills, the related join notification is not posted more than once. It keeps activity messages cleaner and avoids confusing duplicate updates for users and managers.
Original PR description
`super` is idempotent, but the override is not --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Point of Sale product information popup now shows accurate tax details and the minimum combo price when combo choices are involved. This helps staff present correct pricing and tax information to customers, including cases where a combo option has no included item.
Original PR description
Product info popup was not showing the correct tax details for combo products. This commit fixes the issue. The popup display now the minimal price of a combo with an item selected for each combo choice; even if the combo choice isn't including any item. Forward-Port-Of: odoo/odoo#285022 Forward-Port-Of: odoo/odoo#282870
Fixes an issue where Factur-X e-invoices received through Peppol were not properly read because the embedded XML was not extracted first. This prevents failed or incomplete document imports and correctly identifies self-billed invoices in the French e-invoicing flow.
Original PR description
When importing new documents from Peppol into the database, we determine whether they are self-billed by checking a Type Code in the XML file. Factur-X is an hybrid format where the XML is embedded inside a PDF. Currently, we are not extracting the XML before searching for that Type Code, and it leads to an error that prevents the document from being imported correctly: - V17, V18: An empty invoice is created and linked with the attachment. - V19+: Only the attachment is created. Additionnaly, we only check for InvoiceTypeCode or CreditNoteTypeCode, but the CII XML format embedded inside the hybrid Factur-X format use TypeCode instead. This PR aims at fixing both these issues. Ticket: opw-6417682 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285513 Forward-Port-Of: odoo/odoo#280714
Fixed the Swedish tax report so Field 42 shows qualifying sales amounts as positive instead of negative. This helps Swedish companies review VAT reporting figures accurately and reduces confusion during tax checks.
Original PR description
**Steps to reproduce:** - Install the `l10n_se` module and switch to a SE Company. - Navigate to Invoicing > Configuration > Taxes. - Create a tax and set the tax grid to `se_42`. - Create and…
**Steps to reproduce:** - Install the `l10n_se` module and switch to a SE Company. - Navigate to Invoicing > Configuration > Taxes. - Create a tax and set the tax grid to `se_42`. - Create and confirm an invoice for a Swedish customer using this tax. - Navigate to Reporting > Tax Report. - Check the amount of `Fält 42` under `Block E`. **Observation:** The `Fält 42 – Övrig försäljning m.m.` field shows the amount as negative instead of positive. **Root Cause:** At [1], the `se_42` formula is missing the negative sign. These lines were missed by the `tax_tag_invert` revamp done in https://github.com/odoo/odoo/commit/17a6117ed88c29b5bc4db0c872bcdbc109a7d98b. **Fix:** This commit adds the missing negative sign to the `se_42` formula, ensuring that the amount for `Fält 42` is displayed as positive in the Swedish tax report, similar to [2]. [1]: https://github.com/odoo/odoo/blob/a56038c97e807388772ccc3a794cf0bf658a2076/addons/l10n_se/data/account_tax_report_data.xml#L356-L368 [2]: https://github.com/odoo/odoo/commit/b8125f38e80c1977eedda5fc6b9466ece5e9fd89 opw-6457529 Forward-Port-Of: odoo/odoo#281925
Romanian SAF-T (D406) XML exports now use the officially expected AuditFileVersion value of 2.0 instead of 2.4.8. This helps companies generate compliant files for Romanian tax reporting and avoids potential validation or submission issues.
Original PR description
**Steps to reproduce:** - Install the `l10n_ro_saft` module and switch to the RO Company. - Navigate to Accounting > Reporting > General Ledger. - Click the gear icon > SAF-T (D406 Declaration). - Open the generated XML file and check the `AuditFileVersion` node. **Observation:** The `AuditFileVersion` node is set to `2.4.8`. **Expected behavior:** The `AuditFileVersion` node should be set to `2.0` (confirmed with the PO [1]) **Root Cause:** At [2], the `file_version` value is incorrectly set to `2.4.8` instead of `2.0`. [1]: https://www.odoo.com/mail/message/1144385840 [2]: https://github.com/odoo/enterprise/blob/ce2ad80c91aea27b143a80018aa73ed10d16cdbe/l10n_ro_saft/models/account_general_ledger.py#L179-L183 opw-6452918 Forward-Port-Of: odoo/enterprise#127935
Fixed an error that could prevent customers or staff from opening the Field Service section from a helpdesk ticket preview after interventions were completed. This keeps the intervention list accessible and avoids a disruptive crash in the portal preview flow.
Original PR description
*=helpdesk_planning_field_service{,_sale_timesheet} Steps to reproduce: ------------------------- 1. Install helpdesk_planning_field_service_sale_timesheet with demo data. 2. Open a helpdesk team…
*=helpdesk_planning_field_service{,_sale_timesheet}
Steps to reproduce:
-------------------------
1. Install helpdesk_planning_field_service_sale_timesheet with demo data.
2. Open a helpdesk team (e.g., Customer Care) and enable field service planning.
3. Create a new ticket in Customer Care, plan two interventions, and mark them as completed.
4. Click the cog menu of the helpdesk ticket and click Preview.
5. In preview mode, click **Field Service** in the left sidebar.
Issue:
---------
A traceback occurs:
```python
File "/home/odoo/odoo/community/odoo/addons/base/models/ir_qweb.py", line 875, in _render_iterall
raise QWebError(qweb_error_info) from error
odoo.addons.base.models.ir_qweb.QWebError: Error while rendering the template:
KeyError: 'format_datetime'
Template: planning_field_service.portal_my_field_service_report_list
Reference: 866
Path: /t/t/t[3]/t/tbody/t/tr/td[1]/a/t
Element: <t t-out="format_datetime(intervention.start_datetime, dt_format='MMM d, YYYY')"/>
```
Cause:
---------
https://github.com/odoo/enterprise/blob/28637781cd3ffc4c3dc0c2016dd5d6051793f641/helpdesk_planning_field_service/controllers/portal.py#L59-L63
After this 6857d1a, date formatting was changed to use `format_datetime`, and [planning_field_service](https://github.com/odoo/enterprise/blob/28637781cd3ffc4c3dc0c2016dd5d6051793f641/planning_field_service/controllers/portal.py#L42) was updated accordingly. However, `helpdesk_planning_field_service` was not updated to pass `format_datetime` in the template values, causing a **KeyError** when opening the field service intervention list.
Solution:
-----------
Pass `format_datetime` in the template values, following the same approach used in `planning_field_service`.
opw-6467400
Forward-Port-Of: odoo/enterprise#128519The UAE FAF accounting report now opens the company details form correctly when users click the company warning link. This prevents an error that blocked users from completing required company information from the General Ledger.
Original PR description
Currently, an error occurs when trying to fill in the company details from the General Ledger. Steps to Reproduce: - Install `l10n_ae_faf` with demo data. - Switch to the `AE Company`. - Go to…
Currently, an error occurs when trying to fill in the company details from the General Ledger. Steps to Reproduce: - Install `l10n_ae_faf` with demo data. - Switch to the `AE Company`. - Go to `Accounting` > `Reporting` > `Ledgers` > `General Ledger`. - Click on `your company` in the company details warning. `AttributeError: The method 'account.report.action_fill_company_details' does not exist` In this commit, the company details warning was added to the l10n_ae_faf module, similar to account_saft. However, the action_fill_company_details method is only defined in account_saft, which is not a dependency of l10n_ae_faf. Therefore, when the user clicks on "your company" to open the company form [1], the method is not available and an error is raised. This commit ensures that action_fill_company_details is added to l10n_ae_faf so that clicking on `your company` opens the company form, as it does in account_saft. [this commit]: https://github.com/odoo/enterprise/commit/dffc4412df42507457810a0895be3b8f4dc7ec3f [1]- https://github.com/odoo/enterprise/blob/c8c2f13b7fd17e215044fc62774f2b4a378aaf8c/l10n_ae_faf/static/src/components/general_ledger/filters/warnings.xml#L3-L10 sentry-7676719103 Forward-Port-Of: odoo/enterprise#128327
This fix prevents invoice printing from failing when an Argentine company's partner record contains a VAT number that is valid internationally but not a valid Argentine CUIT. It improves reliability for users printing invoices in Argentina localization scenarios and avoids a disruptive error during invoicing.
Original PR description
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR)…
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR) Exento`` Company - Go to Invoicing > Configuration > Journals > Open ``Ventas Preimpreso`` journal > ARCA POS System: ``Electronic Invoice - Web Service`` > Save - Create a new invoice with ``ADHOC SA`` partner > Confirm the invoice - Open the ``(AR) Exento`` partner and set the VAT to ``BE0477472701`` - Open the Invoice > print Traceback: ```py ValueError: invalid literal for int() with base 10: 'BE0477472701' ``` After this [commit], companies outside the EU can use European VAT numbers. Consequently, an Argentine partner can have a CUIT number such as ``BE0477472701``, which is valid as a Belgian VAT number but not as a CUIT. When printing the invoice, the ``l10n_ar_vat`` field is computed from the partner's VAT and its value is passed to ``int()``, causing a traceback at the following line: https://github.com/odoo/enterprise/blob/d55486866d09f8aa87c2003dab722cfa323068b4/l10n_ar_edi/models/account_move.py#L138 [commit]: https://github.com/odoo/odoo/commit/a2afe3292e1cd0a4f339dc47707e469653d13ea0 Enterprise PR: https://github.com/odoo/enterprise/pull/127820 sentry-7666042143 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#284880 Forward-Port-Of: odoo/odoo#282454
This fix prevents invoice printing from crashing when an Argentine company partner has an invalid CUIT tax ID. Users can now print invoices without encountering a system error caused by incorrectly formatted partner identification data.
Original PR description
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR)…
When printing an invoice, a traceback will occur if the company's partner has an invalid CUIT. Steps to reproduce the error: - Install ``l10n_ar_edi`` module with demo data - Switch to ``(AR) Exento`` Company - Go to Invoicing > Configuration > Journals > Open ``Ventas Preimpreso`` journal > ARCA POS System: ``Electronic Invoice - Web Service`` > Save - Create a new invoice with ``ADHOC SA`` partner > Confirm the invoice - Open the ``(AR) Exento`` partner and set the VAT to ``BE0477472701`` - Open the Invoice > print Traceback: ```py ValueError: invalid literal for int() with base 10: 'BE0477472701' ``` The issue occurs because when the partner's identification type is CUIT, At [1] ``_run_check_identification()`` method does not include partners whose identification type has ``is_vat=True``. As a result, CUIT is not validated by ``_run_check_identification()`` method in ``l10n_ar`` module at [2]. So, partner's ``l10n_ar_vat`` field can be computed as ``BE0477472701``. Passing this value to ``int()`` raises the traceback during invoice printing at below line. https://github.com/odoo/enterprise/blob/d55486866d09f8aa87c2003dab722cfa323068b4/l10n_ar_edi/models/account_move.py#L138 [1]:https://github.com/odoo/odoo/blob/c2a39085ba0fbcf8a0e6a55228191e764499caea/addons/l10n_latam_base/models/res_partner.py#L24-L30 [2]:https://github.com/odoo/odoo/blob/c2a39085ba0fbcf8a0e6a55228191e764499caea/addons/l10n_ar/models/res_partner.py#L55-L65 Community PR: https://github.com/odoo/odoo/pull/282454 sentry-7666042143 Forward-Port-Of: odoo/enterprise#129449 Forward-Port-Of: odoo/enterprise#127820
This fixes a checkout issue where a new customer entering both a personal contact name and a company name with a valid VAT number could have their contact name replaced by the company name. The portal now keeps the individual contact and company details separate, improving data accuracy for ecommerce customers and sales records.
Original PR description
Steps to produce: --- - Install website_sale module without demo. - Create a new product and publish it. - From the incognito, go to shop and add that product to cart. - While doing checkout > fill…
Steps to produce: --- - Install website_sale module without demo. - Create a new product and publish it. - From the incognito, go to shop and add that product to cart. - While doing checkout > fill the address form. - Add the all details including the company name and valid VAT. (ex. BE0477472701) - Submit the form. Issue: --- - When a public or guest user submits a new address with both a contact name and a company name along with a valid VAT number, the contact's name was being overwritten with the company name. Root cause: --- - The _compute_is_company heuristic in res.partner automatically sets is_company=True for partners with valid VAT. In [commit] `_create_or_update_address`, the condition `elif partner_sudo.is_company:` was designed to rename existing companies, but incorrectly caught newly created individuals marked as companies due to VAT, causing their name to be overwritten instead of creating a parent company. Solution: --- - Replaced the is_company check with explicit conditions: the partner has no parent_id, has contact-type child_ids. - This ensures the rename-company branch only fires for actual company heads that the logged-in user belongs to, not for individuals that happen to have is_company=True due to a valid VAT. [commit]: https://github.com/odoo/odoo/commit/8f3a32170c842f5f42edc79bf8620276f0da7be4 opw-6356772 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#285495 Forward-Port-Of: odoo/odoo#275044
This fix ensures activity filters use the user's local calendar date instead of the UTC date. Users in time zones ahead of UTC will now see activities due today correctly listed under today's activities, matching what appears in the chatter.
Original PR description
#### Description of the issue: Activity filters using context_today() bucket against the UTC date instead of the user's local date, off by one for part of the day. Partial revert of #265250 (e048bb5), scoped to PyDate: UTC getters are right for PyDateTime, wrong for a calendar day. #### Current behavior before PR: A Perth (UTC+8) user finds an activity due today under "Future Activities" from 00:00 to 08:00 local, while the chatter labels the same activity "Today". #### Desired behavior after PR is merged: context_today(), today and current_date return the user's local calendar day, so filters agree with the chatter. PyDateTime and PyTime keep the UTC getters; now and time.strftime() are unchanged. opw-6415985 --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr Forward-Port-Of: odoo/odoo#281453 Forward-Port-Of: odoo/odoo#278761
Peruvian electronic invoices no longer get stuck when SUNAT has registered them but the official confirmation is not ready yet. Odoo will keep retrying automatically until the confirmation becomes available, reducing manual follow-up and repeated submission issues.
Original PR description
Steps to reproduce: - Post a Peruvian invoice so it is sent to SUNAT (directly or through Estela/Digiflow). - SUNAT's sendBill call hangs and Odoo's request times out (ReadTimeout / ConnectionError),…
Steps to reproduce: - Post a Peruvian invoice so it is sent to SUNAT (directly or through Estela/Digiflow). - SUNAT's sendBill call hangs and Odoo's request times out (ReadTimeout / ConnectionError), even though SUNAT actually finishes registering the document on its side a moment later. - Odoo retries sending the same invoice (either automatically through the EDI cron, or manually). SUNAT now replies with a "document already exists" SOAP fault (code 1033/4000), since it processed the previous attempt. - Odoo tries to recover from this by fetching the CDR through getStatusCdr, but SUNAT has not finished generating it yet, so the lookup also fails. Cause of the issue: _l10n_pe_edi_post_invoice_web_service() already has recovery logic for error codes 1033/4000: it calls _l10n_pe_edi_retrieve_cdr() to fetch the CDR and treat the invoice as sent. But when that lookup itself fails (CDR not generated yet), the resulting error keeps the 'blocking_level' set to 'error' from the original SOAP fault. Documents with blocking_level 'error' are excluded from the automatic EDI cron retries (see account.edi.document._cron_process_documents_web_services), so the invoice gets stuck needing a manual retry, which can lose the same race against SUNAT again and again. Solution: When the CDR can't be retrieved yet after a 1033/4000 duplicate error, mark the result as 'blocking_level': 'warning' instead of leaving it at 'error'. This keeps the invoice eligible for the automatic EDI cron retries, so Odoo keeps polling SUNAT until the CDR becomes available, instead of requiring manual intervention every time this race is lost. opw-6393231 Forward-Port-Of: odoo/enterprise#127484 Forward-Port-Of: odoo/enterprise#125053