Skip to content
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

Merged
merged 11 commits into from
Jun 14, 2024

Conversation

jbaudoux
Copy link
Contributor

@jbaudoux jbaudoux commented Apr 17, 2024

In summary:

  • Cleanup code (use a single context variable to prevent re-execution, make dedicated methods for each purpose).
  • Increase performance (there was many recursive execution of the same delete/add line - code is now executed once and only what needs to be modified).
  • Make the module compatible with sale_order_carrier_auto_assign. 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#3081 Marked as migration v17.0 improvement
  • Make module more robust. Implement SO line create/write

Depends on:

Settings:
image

In details (one commit for each) - in reverse order:

Compatibility checks/fixes with other modules triggering refresh on SO create/write:

cc @pedrobaeza @santostelmo @yvaucher @simahawk @francesco-ooops @renda-dev

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
@jbaudoux jbaudoux force-pushed the 16-fix-delivery_auto_refresh branch 2 times, most recently from 71f141e to 568d49a Compare April 17, 2024 21:18
@jbaudoux jbaudoux force-pushed the 16-fix-delivery_auto_refresh branch from 568d49a to 46041b5 Compare April 17, 2024 21:26
@jbaudoux jbaudoux marked this pull request as ready for review April 17, 2024 21:43
@jbaudoux jbaudoux changed the title [16.0][IMP-FIX] delivery_aut_refresh [16.0][IMP-FIX] delivery_auto_refresh - code cleanup Apr 17, 2024
@jbaudoux jbaudoux changed the title [16.0][IMP-FIX] delivery_auto_refresh - code cleanup [16.0][IMP-FIX] delivery_auto_refresh - performance & compatibility & cleanup Apr 17, 2024
"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"],
Copy link
Member

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.

Copy link
Contributor Author

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?

Copy link
Member

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.

Copy link
Contributor Author

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

Copy link
Member

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.

Copy link
Contributor Author

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

@jbaudoux jbaudoux force-pushed the 16-fix-delivery_auto_refresh branch 3 times, most recently from a142e47 to 5ac2bf6 Compare April 18, 2024 13:28
@jbaudoux
Copy link
Contributor Author

Config parameters moved to company. sale_ prefix added to the parameters

@jbaudoux jbaudoux force-pushed the 16-fix-delivery_auto_refresh branch from 5ac2bf6 to 59b6e2c Compare April 18, 2024 13:51
@jbaudoux
Copy link
Contributor Author

Ready for final review

@pedrobaeza pedrobaeza added this to the 16.0 milestone Apr 18, 2024
Comment on lines 119 to 121
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
Copy link
Member

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?

Suggested change
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

Comment on lines 131 to 129
if not self.carrier_id:
self._remove_delivery_line()
elif self.is_all_service:
self._remove_delivery_line()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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):
Copy link
Member

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.

Copy link
Contributor Author

@jbaudoux jbaudoux Apr 19, 2024

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.

@jbaudoux jbaudoux force-pushed the 16-fix-delivery_auto_refresh branch from 59b6e2c to d3a54a1 Compare April 19, 2024 10:12
@jbaudoux jbaudoux force-pushed the 16-fix-delivery_auto_refresh branch from d3a54a1 to 4c45d35 Compare April 19, 2024 10:22
This commit can be reverted in the migration to 17.0
Move config to company level
Prefix config settings by sale
@jbaudoux jbaudoux force-pushed the 16-fix-delivery_auto_refresh branch from 4c45d35 to 516b510 Compare April 19, 2024 14:20
@cyrilmanuel
Copy link

hi @pedrobaeza could you review this PR please ?

Copy link
Member

@pedrobaeza pedrobaeza left a 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")
Copy link
Member

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?

Copy link
Contributor

@simahawk simahawk Jun 14, 2024

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 😉

Copy link
Member

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.

Copy link
Contributor Author

@jbaudoux jbaudoux Jun 14, 2024

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

Copy link
Member

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 😄

Copy link
Member

@pedrobaeza pedrobaeza left a 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

@OCA-git-bot
Copy link
Contributor

What a great day to merge this nice PR. Let's do it!
Prepared branch 16.0-ocabot-merge-pr-799-by-pedrobaeza-bump-nobump, awaiting test results.

@OCA-git-bot OCA-git-bot merged commit b2e5168 into OCA:16.0 Jun 14, 2024
4 of 5 checks passed
@OCA-git-bot
Copy link
Contributor

Congratulations, your PR was merged at 9a0492e. Thanks a lot for contributing to OCA. ❤️

@jbaudoux
Copy link
Contributor Author

Thanks again for your efforts.

@pedrobaeza Thanks for your time on this review :)

@rafaelbn
Copy link
Member

This PR affects MT-5997 @moduon and #815 which is being reviewed by @yajo

@Gelojr @fcvalgar please deep functional review 😄 ❤️

@rafaelbn
Copy link
Member

Hello @jbaudoux ,

We don't want to use sale_order_carrier_auto_assign module. It's mandatory?

We wouldn't be forced yo use it 😢

Let me know please! 😄

Thank you!

@jbaudoux
Copy link
Contributor Author

Hello @jbaudoux ,

We don't want to use sale_order_carrier_auto_assign module. It's mandatory?

We wouldn't be forced yo use it 😢.

Let me know please! 😄

Thank you!

There is no new dependency in v16.

@rafaelbn
Copy link
Member

OK, sorry. I miss some comments 🙏🏼 . Thank you! 😄

@yajo
Copy link
Member

yajo commented Jun 17, 2024

It seems v16 settings layout broke:

image

@rousseldenis
Copy link
Contributor

It seems v16 settings layout broke:

@jbaudoux

@toita86
Copy link

toita86 commented Jul 17, 2024

@rousseldenis I'm not sure if it can help, but this is my attempt to fix the layout e6214da

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants