-
Notifications
You must be signed in to change notification settings - Fork 103
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] shopinvader_api_address: refactor API (paginate, code improvement #1425
Conversation
…haviour - add pagination - main address should be an invoice and a delivery address - move service logic from shopinvader_address to shopinvader_api_address
419380d
to
82df539
Compare
82df539
to
03d912c
Compare
"state_id": self.state_id, | ||
"country_id": self.country_id, | ||
} | ||
return self.model_dump(exclude_unset=True) |
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.
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.
@sebastienbeau Even if in this case we've a strict mapping between declared fields on the schema and fields on the res.partner model, we must avoid to return the result of the call to model_dump
as parameters for a call to the write' method on the
res.partnermodel. As discussed, this way you introduce a deep coupling between your schema and your model and this code will break if the schema is extended to add a field not defined on the odoo model. Nevertheless the call to
model_dumpwith the
exclude_unset=True` parameter could be good Idea to update only values set on the schema. But it's to use on purpose since you also lost default values defined on the schema (AFAIK).
fields = ["name", "street", "street2", "zip", "city", "phone", "email", "state_id", "country_id"]
values = self.model_dump(exclude_unset=True)
return {f: values[f] for f in fields if f in values }
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.
This is purely mapping code, converting the result of the business logic (even if trivial in this case) to the data structure of the API. So this is good to have it in the API layer.
IMHO, mapping code is better explicit. This is may take a few seconds more to write, but it is much much easier to read afterwards. And we collectively spend much more time reading code that writing it :)
Also it is safer, because if we map fields with same names automatically, we risk accidentally exposing data when we add fields to the API data structure.
- rename helper class - use FilteredDomainAdapter
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.
delivery address should return the main partner as address
I kind of remember we dicussed this in @AnizR's PR back then, and concluded to not do it for a good reason (that I don't remember).
@@ -13,15 +13,19 @@ | |||
"extendable", | |||
"extendable_fastapi", | |||
"fastapi", | |||
"shopinvader_address", | |||
"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.
Why removing shopinvader_address?
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.
After starting to move code from "res.partner" to the "shopinvader_api_cart.address_router.helper".
I realize that everything was really related to the router, so at the end I had no more code on "res.partner". I only had an hesitation on the method "_ensure_address_not_used" that may stay on "res.partner"
So at the end the module shopinvader_address had no code, so I remove it.
But maybe I miss some point and some code was think to be reuse outside of the router.
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 realize that everything was really related to the router, so at the end I had no more code on "res.partner". I only had an hesitation on the method "_ensure_address_not_used" that may stay on "res.partner"
I respectfully express my dissenting opinion on this matter. From my perspective, the code previously residing in res.partner does not appear to be exclusively tied to the router. Consider a scenario where one opts for a different framework other than FastAPI or has an Odoo module utilizing 'shopinvader addresses' independently of 'shopinvader_api_address.' In such cases, it seems essential to retain all functions originally present in shopinvader_address for broader compatibility and flexibility. This approach ensures that the functionality remains accessible even in diverse usage contexts beyond the current implementation.
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.
@sebastienbeau actually shopinvader_address
is the logic and high level methods that defines what invoicing and delivery addresses mean for shopinvader. There is business logic in there that defines what the invoicing address is what deletion means (= archival) etc.
We can easily imagine that some backend code will want to manipulate such addresses, and that code would then depend on shopinvader_address
to use these methods, and not shopinvader_api_address
.
This is the principle that we want to avoid business logic in the API layer as much as possible, and in this case we concluded that the address logic was non-trivial enough to go in its own module.
]._search(partner, paging, params) | ||
return PagedCollection[InvoicingAddress]( | ||
count=count, items=[InvoicingAddress.from_res_partner(rec) for rec in addresses] | ||
) |
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 think we had decided to not do paging nor search because there would never be tons of addresses for a given customer, and filtering could be easily done in the frontend. Just a remark en passant, nothing blocking.
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.
Indeed it make sens, but I would prefers to be consistent (a search always return a paginate).
I have a case where we plan to expose contact (it will done in shopinvader_api_contact, so we are going to expose a big list of contact ~200, so I will need paginatation. And it's look weird that on same object sometime we have pagination and sometime not)
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.
As I said, not blocking for me but I'd argue adding paging and search to small lists makes it more difficult for the front-end dev (unless they ignore it and assumes there will only ever be one page, but that is opening the door to bugs).
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 would also prefer to not do paging nor search on the addresses by default. (We could add a dedicated endpoint if necessary to some uses)
In odoo website, the main address can be used for invoicing and delivery, same in backoffice. And most of people use the same address for both. If you remember the reason, please share it. |
It's because, for instance, the main address cannot be deleted by the customer. #1361 is the PR where we distilled all this. There was a lot of thinking put into it as you see :) So please, pretty please, don't throw everything overboard. |
@sbidoul thanks for pointing the PR, I will read the comment done. |
I close this PR : I just keep the rename : #1442 |
Hi all
I have done some change for the address API. The main change are
Todo