Since [1] whenever the image of a `product.template` is updated, the
write date of all its related `product.product` is updated. This was
done to force a change of the unique parameter on image fields, which is
based on the last update field.
After this commit the `product.product`'s last update is instead
computed by also taking the `product.template`'s last update into
account. This avoids the need for updating the write date when the
image is changed, but on the other hand it also forces product images to
be reloaded whenever any other field of the `product.template` is
changed.
[1] https://github.com/odoo/odoo/pull/71139
Related to https://github.com/odoo/odoo/pull/76309
task-2477438
closesodoo/odoo#78356
Signed-off-by: Romain Derie (rde) <rde@odoo.com>
Co-authored-by: Benoit Socias <bso@odoo.com>
Purpose
=======
The fields are not used, don't work correctly and there is a specific
report to generate the product prices according to the pricelist and
the ordered quantities
* Do not rely on context, everything should be cleary specified through
parameters
Catch context keys in an unique targeted place to improve code clarity
* Drop strange old API
* do not provide unused partner parameter anymore
* do not provide products, qty as a list of tuple, we only request the
same qty for all products anyway
* Clear methods, add/adapt comments and docstrings
* Reduce potential side-effects of context content.
- Create a report to show price on each template
--> Issue: The price is the same
closesodoo/odoo#78870
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
Before this commit, products relying on values of template fields (i.e.
image) were not considered updated when their fallback template field
was updated.
After this commit, upon update of a template image, all products that
would fallback on that template are "touched".
This avoids side-effects such as displaying an outdated template image
in the e-commerce for a given product.
task-2477438
closesodoo/odoo#71139
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
Regarding of the `display_default_code` context value, `display_name` is
supposed to return the product code or not, eg:
> product.display_name
> '[FURN_6666] Acoustic Bloc Screens'
> product.with_context(display_default_code=False).display_name
> 'Acoustic Bloc Screens'
But since the context was not considered when accessing this field, it would
always return the cached value, which was set from the first time that field
was read, with the `display_default_code` value used at that time.
tl;dr: `display_name` was ignoring the context once cached.
One of the critical issue was that internal code were displayed on the eshop
cart (not the eshop itself), see `name_short`.
task-2517830
closesodoo/odoo#70739
X-original-commit: b5b4d38adf1f3960cda21b795a26e67b978b2901
Signed-off-by: Raphael Collet (rco) <rco@openerp.com>
Signed-off-by: Romain Derie <rdeodoo@users.noreply.github.com>
The function `_get_possible_combinations` generates possibles combinations
for the product template attribute values (ptav) of each product template
attribute line (ptal) of a given product template. It used to iterate over
them using a cartesian product. A combination can be invalid if it
contains two incompatibles ptav. The problem is that it used to filter out
invalid combinations after generating them. It's a problem because there
can be a lot of invalid combinations to filter out before finding a valid
combination. Even before the first valid combination if the first ptav of
the two first ptal are incompatible.
The solution brought by this commit is to reject the invalid combinations
while building them rather than after. It does so by using a cartesian
product implementation with early rejection. The algorithm tests each
ptav when incorporating it in a partial combination and if it's
incompatible, it goes to the next partial combination and thus skips all
combinations starting with the invalid partial combination.
The client that reported the issue has a product template with about 25
ptal with an average of 9 ptav. The ptav of the first ptal was
incompatible with the first ptav of second ptal. It had to build and
filter out 5.76*10^15 ptav before finding the first valid ptav. If we
generate 10^6 ptav by second (it's much less) user would get first ptav
after 182 years. Now it's instantaneous.
opw-2335936
closesodoo/odoo#65809
X-original-commit: 98616c4676aa6ef5507110c0e407a640082abbaf
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
Behavior prior to this fix:
When archiving the last variant on a template, the product template
stays active (contrary to the comment indicating that `toggle_active`
will archive the related product.template if there is only one active
`product.product`).
Behavior after the fix:
When archiving the last variant on a template, the product template is
archived. When un-archiving that variant, the product template is
unarchived as well, without un-archiving the other variants.
Note: this is a remake of a fix implemented in 77e5472c041e, as that fix
did not correctly count the inactive variants.
opw-2349862
closesodoo/odoo#60641
X-original-commit: 01160ee5e7f726f3035c566a13e26825236dedfd
Signed-off-by: Nicolas Galler <nicocrm@users.noreply.github.com>
Issue
- Install Sales with Product Configurator
- Create a product with 2 dynamic variants:
- Color: blue, red
- Size: S, M
- Create a quotation with that product (any variant)
- Sales > Products > Products Variants
Your product variant is there
- Modify your product template and add "green"
to colors
- Sales > Products > Products Variants
Your product variant is archived
Cause
The logic which determines which variant
should not be archived is only applied
on products that don't have dynamic variants
See https://github.com/odoo/odoo/blob/820fe9a025e34e81368a189ee295b4abcf9fcbda/addons/product/models/product_template.py#L576
Solution
Do a separate logic for dynamic variants that doesn't compute
all possible combinations.
But being sure that it:
- doesn't archive when adding/removing a value
to an existing attribute line
- archive when adding/removing a new attribute line
OPW-2293346
closesodoo/odoo#55016
X-original-commit: 8517fdfa2605e8d15f5e38f2074ece7ba543d56b
Signed-off-by: Sébastien Theys (seb) <seb@odoo.com>
Updating the uom_id on a product_product will eventually change also the
uom_po_id to have them belonging to the same category. Saving the update
call write() on product with a dict of two values (uom_id and uom_po_id)
As product.product is inherited from product.template, the write() on
the corresponding product_template is called but in this case 2 times
for each values. The first time, only uom_id is updated. The _check_uom
constraint is triggered and obviously failed. The uom_po_id on the
template is not yet updated.
This commit makes the sync in the beginning of write() of product.template.
Which means before calling the constraint.
This commit also makes the onchanges on uom_id acts the same between
product.product and product.template.
Task : 2197818
closesodoo/odoo#48714
Signed-off-by: Arnold Moyaux <amoyaux@users.noreply.github.com>
Before this commit, pricelist boundaries were dates. It was not possible to get a modified price at a precise time: e.g. modify the formula at 12h00.
closesodoo/odoo#49030
Taskid: 2221094
Related: odoo/upgrade#1055
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Since the wizard to set a logo and chose a layout has been removed, we
don't need anymore to throw an error if they are not set because the
report can be generated.
closesodoo/odoo#48831
X-original-commit: b7c7039667d9ec816e647a0dd30570a4a690cca2
Signed-off-by: pimodoo <pimodoo@users.noreply.github.com>
Steps to reproduce:
* Create a template with 2 variants
* Archive one variant
* Unarchive this same variant
--> the template is archived
This is due to commit 6a13b565cbbad89ff1c4177b171b01f30c83edf9. If the
variant is the only one, toggle_active on the variant should be
reflected on the template. The issue is that toggle active do not count
archived variant. One active variant and one archived variant are
counted as 1.
This commit make toggle_active count all variants
closesodoo/odoo#34769
Signed-off-by: Simon Lejeune (sle) <sle@openerp.com>
Product templates standard_price (cost) is company_dependent,
because the product_product standard_price is company dependent.
closesodoo/odoo#47041
Forward-port-of: odoo/odoo#46841
X-original-commit: 30ee9f1ac411aca9c2bf2158fca9be7db743616d
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
Replace an assertRaises(StopIteration) by a next() with a default
value.
Following PEP 479, *any* StopIteration reaching the toplevel of a
generator triggers a DeprecationWarning. And while the assertRaises
looks innocuous, both _assertRaises and the underlying
clear_upon_failure are implemented with functools.contextmanager,
which wraps a generator.
As a result, exceptions raised in the assertRaises "body" get
reinjected inside the wrapped context manager[0] and if the exception
is a StopIteration it triggers the warning.
By not using assertRaises we side-step the issue.
[0] https://github.com/python/cpython/blob/b6999e5690c7006b0ba4049cfd638513c982a90c/Lib/contextlib.py#L131
Variants are generated depending on the configuration of attributes
and values on the template, so copying them does not make sense.
For convenience the template is copied instead and its first variant is
returned.
closes#38151
X-original-commit: 259f3b7fcdb88d1f458ee7ea3667964412b88ea1
In an onboarding situation, the company doesn't have a logo
make an invoice, send and print, print
The document layout editor's layout opens, because nothing is set up
on the company
Click Save
Before this commit, it was impossible to make the invoice print
because each time the document layout was displayed
After this commit, the invoice prints when clicking on Save
There is no default external layout for main_company
Also, the heuristic used to evaluate whether a company
has been set up, onboardingly speaking, has changed.
Before we used the existence of the logo, after we check if
a layout has been setup. When saving the document layout
modal, a report layout is written on the company
So, practically, the document layout modal only appears once
when trying to print invoices (or other documents)
closesodoo/odoo#37137
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
Have a product template, assign a dynamic attribute to
(the corresponding variant will be created when used in a SO)
Try to name_search for it
e.g.: in the product configurator modal, type some letters to catch it in theory
Before this commit, the product template was not found by the name search
this is because the template doesn't have any variant yet
After this commit, it is found by the name search
OPW 2060603closesodoo/odoo#36215
Signed-off-by: Lucas Perais (lpe) <lpe@odoo.com>
* account, hr_expense, mrp, sale, sale_product_configurator, stock_account,
website_sale, website_sale_comparison
Before this commit, the `product.attribute.value` were stored on the variants.
This required filtering of attribute lines to find the appropriate matching
`product.template.attribute.value` that were used in most of the business code,
such as when computing the `price_extra`.
This also prevented to have multiple attribute lines for the same attribute,
which is needed to handle use cases such as grape varieties for wine products.
This will be done in the following commit.
After this commit, the combination of `product.template.attribute.value` will be
directly stored on the product variant.
Other changes
=============
Add `combination_indices` on product, which allows to quickly find a variant
matching a combination (1 simple indexed equality query as opposed to 1 query
with as many joins as there are attribute lines), and to add an easy
SQL constraint to ensure active combination uniqueness.
Add active field on `product.template.attribute.line` and
`product.template.attribute.value`, with the same behavior as variants:
They become archived if they can't be unlinked. This allows to keep the database
consistent, such as archived variants correctly keeping all their values, sales
order lines keeping their custom and no_variant. This is done with the help of
`ondelete=restrict` on the corresponding m2m fields, and the `unlink` methods
falling back to archiving when `unlink` is restricted.
Part of task-1912579
PR: #32946
Manage pricelists through a common configuration between sale and point_of_sale
Remove lots of technical fields
Improved Pricelist Flow
-----------------------
if pricelists enabled (product.group_product_pricelist), two modes are proposed:
* basic(default): pricelists enabled, but only with basic rules
* advanced: pricelists enabled, but with advanced rules (product.group_sale_pricelist)
When pricelists are enabled, we can always access them through the menu OR access their product-targeted rules from the products/templates views.
Follow up of 58a2ffa26f
Variant specific field `image_raw_original` was meant to be renamed to
`image_variant_1920` instead of `image_variant_max` to follow the same naming
convention as the other fields (having the pixel number in the name).
closesodoo/odoo#35493
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
Usability improvements:
- Prevent the user from doing actions that will lead to exceptions.
- Improve error messages when exceptions do happen.
Also add more constraints to keep the database in a consistent state.
task-2035609
closesodoo/odoo#34833
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
image_original => image_1920 (now resized to 1920)
image_big => image_1024
image_large => image_256
image_medium => image_128
image_small => image_64
image replaced by image_1920 (when writing) or by image_1024 (when displaying
what was previously the big size)
+ add new intermediate format:
image_512
PR: #34925
Create a product template Pt with attibutes A1, A2,
respectively with values Va1_1, Va1_2, and Va2.
This should make 2 variants, V1 and V2.
Sell some of these variants.
Then they can't be deleted since they are linked to orders/invoices/...
Now delete attribute A2. We know that:
Warning: adding or deleting attributes will delete and recreate existing
variants and lead to the loss of their possible customizations.
In fact, old variants are only archived instead of deleted:
for variant in variants_to_unlink: ... variant.write({'active': False})
as a fallback.
Now add again the attribute A2 to Pt.
It creates a new variant with the correct attributes.
Since the product is not active and has valid attributes and attribute values,
it is reactivated.
As a result we get the same variant twice.
Here we can simply add a check: if there is already an existing variant with
the same values, we can skip this activation.
We add a tiny little test to make sure that we have correct number of variants.
It's basically unreadable but somewhat commented.
fix coauthored with @rco-odoo
opw 2029985
closesodoo/odoo#35013
Signed-off-by: Nans Lefebvre (len) <len@odoo.com>
The goal is to be coherent with the user property.
Actually, company_id and company_ids on the environment are no fields.
Calling env.company_id returns a browse record, not an id.
* = account, mrp, purchase_stock, sale, sale_product_configurator,
stock_account, website_sale
It is always better to create the product template attribute lines before
creating the variants. In a following commit, this will become mandatory.
The variants that are created should always match the combination of attributes
set on the template.
Finally explicitly call `create_variant_ids` when possible instead of reassigning
the attribute lines to implicitly call `create_variant_ids`.
closesodoo/odoo#34122
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
Purpose
=======
Allow the user to select the allowed companies for which he wants to see records
on top of selecting his current company.
It is confusing for users to see the records from the company he is connected to
and the records of the children companies.
Instead of using the hierarchy of companies to access records across companies,
the user can now select (from his set of allowed companies) the companies for
which he wants to access records.
/!\ This means that the user will interact with records from company A when in
company B.
Example: a SO has been created and confirmed in A. When in B, I create the
invoice from it.
Specifications
==============
1/ Deprecate the parent/children hierarchy on the res.company model. The fields are
kept on the res.company model to ensure the retro-compatibility, but won't be used
accross the standard code anymore. The only functional usage for this mechanism
was to allow to see records from several companies by creating a virtual parent
company, which will be possible with the new mechanism.
2/ By default, a user will only see the records of the company he is connected
to (or records without a company). (It is still editable by the user if needed).
For that, put this information in the user context, to allow having different
configurations on different browser tabs. Instead of having domains like
['|',
('company_id', '=', False),
('company_id', 'child_of', user.company_id.id)]
you'll have something like
['|',
('company_id', '=', False),
('company_id', 'in', company_ids)]
Note that the 'company_ids' is a value that is passed in the evaluation
context on the record rule, as we already have user, or time.
company_ids is a list of the ids of all the enabled companies in the
user's context.
3/ Out of the generic improvements brought by this task, this will illustrate
issues that could exist since several versions. For example, it should not be
possible to create a scrap order for the company A with a package of the company
B, or it should not be possible to create an invoice on the company A with
payment terms from the company B. Before the version 12.0, it was easy to
encounter this kind of issues as the admin was the SUPERUSER_ID. A positive side
effect of the fact that the SUPERUSER_ID has become an inactive user was to
make it more difficult to introduce mismatch on the records, but haven't solved
the issue, as it was still possible to do it with parent companies
configuration. Some of these issues have been fixed in this commit, but all the
business flows should be re-tested to check if an ir.rule should be introduced
(eg: a multi company rule for stock.quand.package), if the company of a record
is correctly transfered to another record created from the first record (eg:
From a SO, create an invoice and a payment, the company of the sales order
should be transfered on the invoice and the payment, even if the company of the
sales order is A and I'm logged into the company B with the company A enabled.
4/ Currently, if I click on a button on a notification email (example 'View
Task'), I face a traceback if I'm not logged into the company of the record.
Now, if you click on a button and if you have access to the record, the correct
company will be automatically set.
5/ If I display a kanban view with several records from several companies (and
an image), all the images should be displayed.
6/ Currently if you copy paste an url, this will crash if you're not in the
correct company. This won't be fixed because it's quite impossible to do it in
a clean way. This task brings a workaround. Copy/Paste -> Traceback -> Log into
the correct company, re-copy/paste -> Ok.
7/ 2 property methods have been added on the environment to retrieve the company
on which the user is logged in and the companies the user enabled, on a specific
tab.
That way, when creating a record, instead of doing
default=lambda self: self.env.user.company_id
do
default=lambda self: self.env.company_id
On the other hand, to retrieve the enabled companies, do
companies = self.env.company_ids
8/ Modify the Company Switcher widget to allow to log into another company
WITHOUT writing on the res.users (and thus bringing cache invalidation issues
and so on). Also allow to enable several companies and see records from several
companies, and independantly of the other browser's tabs.
9/ When focusing on a tab, save the current company configuration on the local
storage. That way, when doing 'CTRL+T' or a middle click, the context is
propagated to the new tab.
10/ Improve the error message in case of multi company access errors. Now, when
the user is in debug mode, display the related names of the records and the name
of the user who brings the issue.
11/ Remove the context erasing when writing on a res.users
This is probably coming from the migration to new API of the base module.
The context was not propagated at this moment, which was a common mistake at
that time. When migrating the module, probably by using the 'black box' method,
as the context was not propagated, it was erased on the new version. This is
now an issue because the context (i.e. the enabled companies) was erased when
writing on a res.users, leading to tracebacks.
See: https://github.com/odoo/odoo/commit/7eab8e26d3d46c53f4be924d6a34e80a66e74960#diff-4c2e738ee8f64f11806c889ea097b5e7R624
12/ Fix the crash manager on redirect warnings. The issue is the following
- Create an invoice on a company without a configured CoA.
- Set a partner
- On the onchange_partner_id, a redirect warning is raised to propose you
to configure a CoA
- Click on 'Go to the configuration panel'
- A generic warning says something like 'Do you want to discard your changes?'
- Click on yes, the page refreshes, but not on the redirect action.
Now, set correctly the action on the hash, and reload instead. The breadcrumb is
lost for example, but you reach the correct action at least.
13/ Introduce a res.group to enable/disable the multi company per tab
feature.
14/ To help the users to know which tab is in which company, add the
possibility to have a favicon per company. When creating a company,
the classical 'O' icon is colored by default in a random color.
15/ Remove the company switcher on the frontend. This was mainly there
to allow a user to swicth to the company linked to the website.
This behavior is now transparent to the user. If the website A is
activated, then the company set on the context is the company of the
website.
16/ Deprecated the _company_default_get method on the res.company
model. Remove the method _get_company on the res.users model.
17/ Add 'allowed_company_ids' and 'current_company_id' on the pyeval
context. You can now use those variables on domains in the views to
access directly to the activated company.ies on the current tab.
TaskID: 1960971
closesodoo/odoo#32341
Signed-off-by: Yannick Tivisse (yti) <yti@odoo.com>
Before this commit, if multiple variants exist for the same combination it would
consider the combination impossible if any of the variants was archived.
After this commit, it will consider the combination impossible only if all the
corresponding variants are archived.
opw-1959317
PR: #32691
Before this commit, the code would try to loop over all possible combinations
following their sequences, until it found the requested one, which could be
extremely slow if there was a lot of combinations.
Now if the given combination is possible, we skip that useless looping and
yield it directly.
To reproduce this: create a product template with millions of possible
combinations (using dynamic attributes) and try to add to cart a combination
that would be found late in the looping. Before the commit, the request would
take too much time.
opw-1958623
closesodoo/odoo#32433
Signed-off-by: Jérémy Kersten (jke) <jke@openerp.com>
Change the domain to not include `.id` and to use `in` to prevent subqueries
to be ran by the ORM for each attribute value.
On the filter, directly use `attribute_value_ids` instead of the computed field
`product_template_attribute_value_ids` that leads to the same result, to prevent
unnecessary compute of that non-stored field.
Cache the result of the method. The cache is invalidated when the configuration
of attributes and values change.
We can remove all cache invalidation from the tests since it is done at the
appropriate times in the business code now.
opw-1923999
task-1922055
PR: #30274
Take advantage of prefetch and api.multi, instead of calling plenty of methods
that didn't cache their result and did separate queries for each record.
opw-1923999
task-1922055
PR: #30274
We replace `_get_first_possible_combination` by a generator. By iterating it, we
can find as many possible combinations as we want, as suggested in task 1936680.
So if we need to get or to know if any arbitrary number of combinations exists,
we can just iterate on the generator multiple times, without having to start
over from the start every time.
opw-1923999
task-1922055
PR: #30274