Friday, March 24, 2023
12 changes · master
New functionality added to Odoo
Inventory picking can now prioritize using the smallest number of packages needed to fulfill a request. This helps warehouse teams reduce unnecessary unpacking, streamline logistics work, and keep packaged stock intact when possible.
Original PR description
[IMP] stock: add least_packages retrieval strategy ## Proposed feature and relevance Add a new retrieval strategy for gathering products: "Least packages". The goal of this strategy is to select…
[IMP] stock: add least_packages retrieval strategy ## Proposed feature and relevance Add a new retrieval strategy for gathering products: "Least packages". The goal of this strategy is to select specific product quantities from stock by using as few packages as possible, to allow for efficient logistics operations and avoid unnecessary opening/unpacking of packages. This strategy will behave as follows: - In case a negative quantity is requested this strategy will behave as a FIFO strategy. - Otherwise, the strategy will determine a combination using the least amount of packages that sum to the requested quantity, and adapt the provided domain to select only the quantities in these packages. This way no packages need to be opened to select the requested quantity. - In case an exact matching of current packages to get the requested quantity is not possible, a selection of packages is made where the largest packages are selected one by one until the requested quantity is reached, or until no more quantities are available. For this approach, one package needs to be unpacked as it will not be used completely. The final selected package that will be unpacked will be the smallest one possible, to try to unpack smaller packages over bigger packages. - In case the search for a minimal matching of packages results in an out-of-memory situation, the strategy will fall back to a FIFO strategy. - Loose items (not tied to a package) are considered as single-item packages for the purposes of package selection. **NOTE:** To force the selection strategy to "clean up" certain packages that have previously been opened, it is recommended to unpack these packages into single items, as they will then be consumed to "fill up" requested quantities in later retrievals. ## Changes to allow more complex strategies To allow for the integration of this new strategy the structure of `_gather()` needed to be adapted to allow a removal strategy to provide not only the SQL `ORDER BY` string but also adapt the domain used to retrieve the requested quantities. This change is reflected in the method signature of `_get_removal_strategy_domain_order()`. ## How the strategy works The strategy does one extra query of the database, to determine the different packages and their respective quantities (using the provided domain). Loose items (that do not belong to a package) are added as single-item packages to also consider them. For minimal exact package selection, an A* algorithm is used with 2 performance modifications: - Using the information that the packages are sorted by size (large -> small). - Using the information that the generated subtree for a specific package of size x is the same as all other packages of size x at a specific node. By using the A* algorithm, as soon as a matching packaging selection is found, it is ensured to be optimal and other combinations do not need to be considered. In case the A* algorithm runs out of memory the provided domain is just returned, which equates to a FIFO strategy. In case the A* algorithm does not find an exact matching of packages for the requested quantity, a selection is made using the least amount of packages, unpacking the smallest possible package (or until no more quantities are available, in which case effectively all quantities in the domain are returned). ## Used heuristic The heuristic used for the A* algorithm exploits the knowledge that our packages to select from are ordered by the highest to the lowest quantity (on the database side, SQL `ORDER BY`). It assumes the "best case scenario" as an estimate for the amount of packages remaining, which is if we were to "match" the required quantity using fractional multiples of the next biggest package size. ***Example**: Remaining quantity to select: 27 Remaining package sizes to select from: [10, 10, 5, 5, 5, 1, 1, 1] Heuristic for choosing package with qty 10 as next package: 27/10 = 2.7 Heuristic for choosing package with qty 5 as next package: 27/5 = 5.4 Heuristic for choosing package with qty 1 as next package: 27/1 = 27* This way the heuristic is always a "best case" (fractional) for the amount of packages that still need to be selected. As required by the A* algorithm this also results in an underestimation as the fractional result is not possible, and it is not certain that there are still enough packages of this size that can actually be selected, but favours larger packages to make the search converge more quickly. ## Performance ### CPU Two test cases were run to evaluate the performance. ***Total nr of pkg**: The total amount of different packages generated during data generation **Qty to select**: The total quantity that needs to be selected **Selected nr of pkg**: The amount of packages that was ultimately selected by the algorithm **Data generation time**: The time required to generate all packages **Assignment time**: The total time to run `_action_assign()` for the move **A\* time**: The time to run the `_run_least_packages_removal_strategy_astar()` method* #### First test case This scenario simulates a case with a large quantity to select from a large amount of packages, but of relatively homogenous size. Generate 30 different package sizes between 2 and 1000. For each package size, generate 100 to 250 packages each. Also add 100 to 250 "loose items". The quantity to select is chosen between 1 and 50000. | RESULTS | RUN 1 | RUN 2 | RUN 3 | RUN 4 | RUN 5 | AVG | |--------------------------|----------|-----------|------------|-----------|----------|------------| | Total nr of pkg | 5298 | 5772 | 5855 | 5533 | 5179 | 5527.4 | | Qty to select | 10319 | 20762 | 44422 | 39306 | 1783 | 23318.4 | | Selected nr of pkg | 11 | 22 | 48 | 41 | 3 | 25 | | Data generation time (s) | 64.59124 | 92.916682 | 133.673384 | 82.711438 | 85.54542 | 91.8876328 | | Assignment time (s) | 4.060216 | 11.212937 | 4.763776 | 8.60248 | 3.461941 | 6.42027 | | A* time (s) | 0.28 | 6.88 | 0.21 | 3.96 | 0.03 | 2.272 | #### Second test case This scenario generates a large amount of small packages of different sizes. Generate 250 different package sizes between 2 and 10. For each package size, generate 5 to 15 packages each. Also add 5 to 15 "loose items". The quantity to select is chosen between 1 and 10000. | RESULTS | RUN 1 | RUN 2 | RUN 3 | RUN 4 | RUN 5 | AVG | |--------------------------|-----------|-----------|-----------|-----------|----------|------------| | Total nr of pkg | 2485 | 2406 | 2491 | 2555 | 2542 | 2495.8 | | Amount to assign | 27 | 4029 | 3966 | 3049 | 1833 | 2580.8 | | Selected nr of pkg | 3 | 411 | 411 | 306 | 184 | 263 | | Data generation time (s) | 18.502933 | 18.692048 | 19.969955 | 19.169106 | 19.16439 | 19.0996864 | | Assignment time (s) | 1.35635 | 7.958852 | 8.470518 | 6.300406 | 3.895457 | 5.5963166 | | A* time (s) | 0.01 | 0.07 | 0.77 | 0.56 | 0.31 | 0.344 | ### Memory In cases with large amounts of different-sized packages (200+ different sizes and 200+ packages required to get an exact match) the memory performance of the A* strategy might become problematic. When lots of packages have the same size (which would be considered typical in cases where there are large amounts of packages) the specific modifications to the A* algorithm ensure that the strategy still delivers good memory performance for this use case as the tree size can be significantly reduced, even with large quantities. ### IO This strategy only requires one extra SQL query to fetch the different quantities and their respective packages. ## Limitations No tests for this strategy were done for non-integer quantities. In these cases the performance of the A* algorithm might not be satisfactory and another approach might be preferred. More research could be done for specific use cases where packaged quantities are non-integer values.
Enhancements to existing features
This update refreshes the spreadsheet component and improves everyday editing behavior. Users get smoother chart and figure interactions, clearer errors when sheet structure changes, and fixes for menu, side panel, and formula editor issues.
Original PR description
### Contains the following commits: https://github.com/odoo/o-spreadsheet/commit/59f25bb4 [REL] 16.3.0-alpha.2 https://github.com/odoo/o-spreadsheet/commit/d0189bd0 [FIX] config: bump owl version https://github.com/odoo/o-spreadsheet/commit/115e1d2b [FIX] tests: fix component tests and their organization https://github.com/odoo/o-spreadsheet/commit/e42786ad [FIX] Top_bar: Opening a menu should close the composer Task: 3076218 https://github.com/odoo/o-spreadsheet/commit/45f4c5c3 [FIX] range: show ref error after removing col/row https://github.com/odoo/o-spreadsheet/commit/c55d601d [IMP] figure: add snap to figure drag & drop https://github.com/odoo/o-spreadsheet/commit/7cbde524 [FIX] side panel: onSidePanelClose prop never call on X symbol click https://github.com/odoo/o-spreadsheet/commit/308e5d6c [IMP] figure_chart: Double click on chart open the sidepanel https://github.com/odoo/o-spreadsheet/commit/9781b7e3 [FIX] composer: fixed composer placeholder issues
Resolved issues and error corrections
This fixes a problem that could cause crashes when users sent messages in the chatter. The change keeps temporary message tracking internal so messages can be matched correctly without disrupting normal business communication.
Original PR description
Since [1], the `temporary_id` of a message is passed to the `message_post` route in order to renconciliate the temporary message on the client side and the real message created by the server. This led to crashes when sending message on the chatter because this parameter was not allowed as a `_notify_thread` parameter. Since this parameter is highly specific and isn't linked to any business/model code, this parameter is now passed via the context thus solving this issue. [1]: https://github.com/odoo/odoo/pull/116085
Code cleanup and technical improvements
This change improves how Odoo handles screens where the same field appears multiple times with different rules or filters. Each field instance can now use its own settings, reducing incorrect behavior in forms and lists across several apps.
Companies can now apply tax report tags from countries where they hold a foreign VAT number directly on taxes and journal items. This helps businesses report the same transaction in multiple country VAT reports without creating extra journal entries, reducing manual work for cross-border operations.
Original PR description
The aim of this commit is to allow any tax tag to be set on a journal item and to allow the user to put tax tag from foreign countries in which they have a VAT number on any tax. The end goal is to…
The aim of this commit is to allow any tax tag to be set on a journal item and to allow the user to put tax tag from foreign countries in which they have a VAT number on any tax. The end goal is to allow the user to impact tax reports from several country with the same journal item, avoiding the creation of a whole journal entry and setting the path for some more automation. Context: Our user has a company based in Belgium but has a warehouse in Netherland. Thus, when the company sells anything from that warehouse, it needs to fill the Dutch tax report directly. Moreover, the company needs to fill a grid on the Belgian VAT tax report. That means that the user would need to gather some journal items on both the Belgian tax report and the Dutch tax report. Before this commit: The user can't set tax tag from another country on its tax nor in the same move. After this commit: The user can set tax tags from any country for which its company has a foreign vat number on any tax and in a move task-id: 2810712 Description of the issue/feature this PR addresses: Current behavior before PR: Desired behavior after PR is merged: --- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
The Spanish accounting localization has been updated so its internal labels are maintained in English while still providing Spanish translations for users. Its tax definitions were also aligned with the latest tax taxonomy, helping improve consistency and compliance for Spanish accounting setups.
Original PR description
l10n_es localization was written in Spanish. We want the code to be fully written in English then translated to necessary languages. We also made taxes compliant to new taxonomy. Task-translation: 3235816 Task-taxonomy: 3052677 Enterprise: https://github.com/odoo/enterprise/pull/38468
The Chilean e-commerce flow now better captures the information needed to issue compliant invoices. When a shopper is classified as an end consumer, the system can use the required generic VAT number, reducing checkout errors and manual corrections.
Tax reports now include invoice lines tagged for another country's VAT report, even when the tax itself belongs to a different country. This reduces manual adjustments for companies operating across borders, such as Belgian businesses selling from Dutch warehouses.
Original PR description
The aim of this commit is to make the multi-vat feature allowing to impact several tax report with the same tax on one invoice. Context: A Belgian company with a warehouse in Netherland has to fill…
The aim of this commit is to make the multi-vat feature allowing to impact several tax report with the same tax on one invoice. Context: A Belgian company with a warehouse in Netherland has to fill the NL tax report when they sell goods coming from that warehouse. At the same time, if the goods were coming from Belgium, the company is suppose to fill the [47] tax grid. To avoid a lot of manual work, the customer would like to be able to put the belgian tax grid on a NL tax. To be consistent, if it works when applying local tag to foreign tax, it should also work when applying foreign tag on local tax. Before the commit: The tax tag is applied on the journal item but the Belgian tax report is ignoring it. Similarly, a NL tag on a belgian tax would be ignored too. After the commit: The Belgian tax report is taking the journal item with the Duch tax in account. Similarly, the Dutch tax report is also taking the journal item with the Belgian tax in account. Task-id: 2810712
The mail unread counter now better matches the actual messages users still need to read. This prevents notification-only items from inflating the count and ensures messages are marked as read correctly when a conversation is first opened.
Original PR description
This PR fixes several issues with the unread counter: - Notifications being considered as unread messages (which is not the case on the server side which resulted in inconsistencies). - Counter greater than it should be when the last seen message is not loaded. - Messages not marked as read on first thread opening. task-3239957
Domain rules in the web interface now catch more invalid entries before they can cause problems. This helps users and administrators spot configuration mistakes earlier, reducing errors in filters and field behavior.
Original PR description
We make the class Domain detect more invalid domains.
Original PR description
Before this commit, the use of multiple <field> with the same name in a view was not well supported. Why was this? Some Field components need to know information related to the <field> such as…
Before this commit, the use of multiple <field> with the same name in a view was not well supported. Why was this? Some Field components need to know information related to the <field> such as context, domain, required and readonly. The solution used before this commit to access this information is to use the getFieldContext, getFieldDomain, isReadonly, isRequired functions of the model. Unfortunately, these only take into account the last occurrence of the <field> because the model is not aware that the same field is present several times on the view. The information must therefore not come from the model. For example, it was not possible to have the same field twice with 2 different domains. It will use the domain of the last field for both. Solution: We will add the object "dynamicInfo" to the fieldInfo passed to the Fields extractProps function. This object will contain a getter to get the value of required, readonly, domain and context for the current <field>. If a Field needs one of its information, it will just have to get it from extractProps. Part of Task: 3179751
The Point of Sale barcode scanning logic has been reorganized to make it easier to maintain and more consistent across related POS features. Stores can now still open the POS even when barcode configuration is missing, with a clear error shown when scanning is attempted.
Original PR description
--- I confirm I have signed the CLA and read the PR guidelines at www.odoo.com/submit-pr
This change improves how Odoo handles screens that show the same field more than once with different rules. Each field instance can now use its own settings, reducing incorrect behavior in forms and related views.
Original PR description
Before this commit, the use of multiple <field> with the same name in a view was not well supported. Why was this? Some Field components need to know information related to the <field> such as…
Before this commit, the use of multiple <field> with the same name in a view was not well supported. Why was this? Some Field components need to know information related to the <field> such as context, domain, required and readonly. The solution used before this commit to access this information is to use the getFieldContext, getFieldDomain, isReadonly, isRequired functions of the model. Unfortunately, these only take into account the last occurrence of the <field> because the model is not aware that the same field is present several times on the view. The information must therefore not come from the model. For example, it was not possible to have the same field twice with 2 different domains. It will use the domain of the last field for both. Solution: We will add the object "dynamicInfo" to the fieldInfo passed to the Fields extractProps function. This object will contain a getter to get the value of required, readonly, domain and context for the current <field>. If a Field needs one of its information, it will just have to get it from extractProps. Part of Task: 3179751