-
-
Notifications
You must be signed in to change notification settings - Fork 366
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[16.0][IMP-FIX] delivery_auto_refresh - performance & compatibility & cleanup #799
Conversation
Don't modify standard method docstring
Limit change of write to calling the auto refresh feature Prevent to call auto refresh multiple times Don't pass discount variable in context
71f141e
to
568d49a
Compare
568d49a
to
46041b5
Compare
"category": "Delivery", | ||
"website": "https://github.com/OCA/delivery-carrier", | ||
"author": "Tecnativa, Odoo Community Association (OCA)", | ||
"license": "AGPL-3", | ||
"application": False, | ||
"installable": True, | ||
"depends": ["delivery"], | ||
"depends": ["delivery", "sale_order_carrier_auto_assign"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can't add a new dependency in this module in stable, but also because those using this module since the beginning don't want to have a new one.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Luckily it is in Beta stage and not Stable/Production
Don't you find it better to have the features implemented in the proper corresponding modules?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not really beta. It's that nobody has changed its maturity level (because nobody is worrying about that). I prefer to have it as is, and do the change on the next version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pedrobaeza I removed the dependency. I marked the code to drop in v17.0. I placed this in a separate commit.
I still have to change the config parameters to make them configurable per company
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, thanks for the efforts. Please include migration script for converting them smoothly out of the system parameters.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for sure :)
It's done
b73434f
to
1d19556
Compare
a142e47
to
5ac2bf6
Compare
Config parameters moved to company. |
5ac2bf6
to
59b6e2c
Compare
Ready for final review |
if self.env.context.get("auto_refresh_delivery"): | ||
return | ||
if not self._is_auto_add_delivery_line(): | ||
return | ||
if self.state not in ("draft", "sent"): | ||
return |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not compacting them for less lines and better readability?
if self.env.context.get("auto_refresh_delivery"): | |
return | |
if not self._is_auto_add_delivery_line(): | |
return | |
if self.state not in ("draft", "sent"): | |
return | |
if ( | |
self.env.context.get("auto_refresh_delivery") | |
or not self._is_auto_add_delivery_line() | |
or self.state not in ("draft", "sent") | |
): | |
return |
if not self.carrier_id: | ||
self._remove_delivery_line() | ||
elif self.is_all_service: | ||
self._remove_delivery_line() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if not self.carrier_id: | |
self._remove_delivery_line() | |
elif self.is_all_service: | |
self._remove_delivery_line() | |
if not self.carrier_id or self.is_all_service: | |
self._remove_delivery_line() |
return fields | ||
|
||
@api.model_create_multi | ||
def create(self, vals_list): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why all the create/write overrides? It seems a great overhead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For implementing the missing feature from the roadmap :)
* This is only working from user interface, as there's no way of making compatible the auto-refresh intercepting create/write methods from sale order lines.
59b6e2c
to
d3a54a1
Compare
Create or delete line only if necessary Update existing line if necessary
d3a54a1
to
4c45d35
Compare
This commit can be reverted in the migration to 17.0
Move config to company level Prefix config settings by sale
4c45d35
to
516b510
Compare
hi @pedrobaeza could you review this PR please ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for your patience, Jacques. Apart from the comments inline (which there can be several occurrences, but I have written only once):
As this code was originally mine, I would appreciate that you follow my coding style not adding empty lines inside a method (it's also something recommended - but not enforced - in Python style guides).
There are docstring changed to comments.
@@ -130,7 +196,7 @@ def _is_delivery_line_voidable(self): | |||
# nothing to be done either. If there are more than one delivery lines | |||
# we won't be doing anything as well. | |||
if ( | |||
self.state not in {"done", "sale"} | |||
self.state not in ("done", "sale") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The set was correct for faster operation. Why changing it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may answer: the usage of set
or list
is kind of wrong in all the cases where you have a fixed set of values and you don't need to purge duplicates or manipulate values afterwards.
Plus, have a look at the memory size:
>>> sys.getsizeof(("done", "sale"))
56
>>> sys.getsizeof({"done", "sale"})
216
In fact, sounds like something that the linter could prevent :)
Yet, such changes might be applied afterwards to reduce diff size in the future. You have a point here 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@yajo do you have at hand the times tests where sets beats inclusion comparison against lists? This is something of performance, not memory size.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pedrobaeza is right that sets are better optimized for inclusion comparison. But this is only relevant if the set is big enough.
>>> def in_test(iterable):
... for i in range(10):
... if i in iterable:
... pass
...
>>> from timeit import timeit
>>> timeit(
... "in_test(iterable)",
... setup="from __main__ import in_test; iterable = set(range(5))",
... number=10000)
0.030677038012072444
>>> timeit(
... "in_test(iterable)",
... setup="from __main__ import in_test; iterable = list(range(5))",
... number=10000)
0.014917187043465674
>>> timeit(
... "in_test(iterable)",
... setup="from __main__ import in_test; iterable = tuple(range(5))",
... number=10000)
0.009921401971951127
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi there! Your test is doomed:
>>> from timeit import timeit
>>> def in_test(iterable):
... return 1000 in iterable
>>> timeit("in_test(iterable)", setup="from __main__ import in_test; iterable = set(range(5))")
0.06247029999940423
>>> timeit("in_test(iterable)", setup="from __main__ import in_test; iterable = list(range(5))")
0.11310941600095248
>>> timeit("in_test(iterable)", setup="from __main__ import in_test; iterable = tuple(range(5))")
0.1125952110014623
Using set
for an in
construct is always faster. In a list
/tuple
of 5 elements, it's still 50% faster.
For this use case, the tuple contains 2 elements. Let's see:
>>> timeit("in_test(iterable)", setup="from __main__ import in_test; iterable = set(range(2))")
0.07049787299911259
>>> timeit("in_test(iterable)", setup="from __main__ import in_test; iterable = list(range(2))")
0.07827233200077899
>>> timeit("in_test(iterable)", setup="from __main__ import in_test; iterable = tuple(range(2))")
0.07647827899927506
Using set
is still faster, although barely noticeable. This means that, if you see a pattern such as a in (0, 1)
, it's probably not worth it to optimize it. But if you see one like a in {0, 1}
, it's definitely not worth it un-optimizing it to use a tuple.
It's not a matter of % of improvement, but of algorithmic complexity. Using a set will be of O1 complexity (constant), while using a list or tuple will be On complexity (linear). Thus, using a set is the default rule of thumb here.
It's not worth reverting this change for such a small improvement now that it's merged, but at least I hope you learned something today 😄
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again for your efforts.
/ocabot merge nobump
What a great day to merge this nice PR. Let's do it! |
Congratulations, your PR was merged at 9a0492e. Thanks a lot for contributing to OCA. ❤️ |
@pedrobaeza Thanks for your time on this review :) |
Hello @jbaudoux , We don't want to use We wouldn't be forced yo use it 😢 Let me know please! 😄 Thank you! |
There is no new dependency in v16. |
OK, sorry. I miss some comments 🙏🏼 . Thank you! 😄 |
|
@rousseldenis I'm not sure if it can help, but this is my attempt to fix the layout e6214da |
In summary:
Move carrier assignment to that module so that this module concentrate on cost delivery line update (i.e. refresh as from its name). See [16.0][IMP] sale_order_carrier_auto_assign: assign carrier on create sale-workflow#3081Marked as migration v17.0 improvementDepends on:
[16.0][IMP] sale_order_carrier_auto_assign: assign carrier on create sale-workflow#3081Settings:

In details (one commit for each) - in reverse order:
use [16.0][IMP] sale_order_carrier_auto_assign: assign carrier on create sale-workflow#3081integrated here and marked to move on v17.0Compatibility checks/fixes with other modules triggering refresh on SO create/write:
[16.0][FIX] product_packaging_container_deposit : performance product-attribute#1583
Solved
Looks good
[16.0][PERF] sale_product_multi_add : SO lines creation in batch sale-workflow#3084
cc @pedrobaeza @santostelmo @yvaucher @simahawk @francesco-ooops @renda-dev