-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Signed-off-by simahawk
- Loading branch information
Showing
33 changed files
with
1,565 additions
and
11 deletions.
There are no files selected for viewing
1 change: 1 addition & 0 deletions
1
setup/shopinvader_customer_price/odoo/addons/shopinvader_customer_price
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../../shopinvader_customer_price |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import setuptools | ||
|
||
setuptools.setup( | ||
setup_requires=['setuptools-odoo'], | ||
odoo_addon=True, | ||
) |
1 change: 1 addition & 0 deletions
1
setup/shopinvader_customer_price_wishlist/odoo/addons/shopinvader_customer_price_wishlist
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
../../../../shopinvader_customer_price_wishlist |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import setuptools | ||
|
||
setuptools.setup( | ||
setup_requires=['setuptools-odoo'], | ||
odoo_addon=True, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
========================== | ||
Shopinvader Customer Price | ||
========================== | ||
|
||
.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
!! This file is generated by oca-gen-addon-readme !! | ||
!! changes will be overwritten. !! | ||
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! | ||
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png | ||
:target: https://odoo-community.org/page/development-status | ||
:alt: Beta | ||
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png | ||
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html | ||
:alt: License: AGPL-3 | ||
.. |badge3| image:: https://img.shields.io/badge/github-shopinvader%2Fshopinvader-lightgray.png?logo=github | ||
:target: https://github.com/shopinvader/shopinvader/tree/13.0/shopinvader_customer_price | ||
:alt: shopinvader/shopinvader | ||
|
||
|badge1| |badge2| |badge3| | ||
|
||
Handle customer specific prices. | ||
|
||
Provides: | ||
|
||
* endpoint `/customer_price/products` to fetch customer prices for products. | ||
* backend configuration to state which pricelist should be used by partner | ||
(by selecting a partner field that relates to pricelists) | ||
|
||
|
||
**Use case** | ||
|
||
Thousands of customers and at least 1 pricelist per each customer. | ||
You want to display customer specific prices in the frontend on demand. | ||
For instance: product page, wishlists, etc. | ||
|
||
**Rationale** | ||
|
||
One of the key points of Shopinvader's speed | ||
is the delegation of products' data indexing to external search engines. | ||
|
||
While this is perfect for generic data and not so complex price rules, | ||
if you have very special prices per each customer that's a blocker, | ||
and you'd need to index all prices for all customers to make it work seemlessly. | ||
|
||
**Warning** | ||
|
||
It's strongly recommended to not call the endpoint for each product on search results | ||
otherwise you'll get potentially thousands of requests to Odoo. | ||
|
||
Also, when setting the pricelist field for the partner, | ||
beware that prices in the indexes might differ from the prices in the cart. | ||
|
||
**Table of contents** | ||
|
||
.. contents:: | ||
:local: | ||
|
||
Known issues / Roadmap | ||
====================== | ||
|
||
Probably the best option would be to have 1 index per customer | ||
which would even allow to sort and filter products by customer's prices | ||
but this requires a lot of work with current implementation of search engine machinery. | ||
|
||
If you use Algolia this is probably a no-go as it would cost too much. | ||
In the context of ElasticSearch instead you could afford it. | ||
|
||
Things that would be needed to go for an indexed solution: | ||
|
||
* make language not required on indexes (at the momemt the whole SE machinery relies on languages) | ||
* automatically generate one index per each pricelist/customer | ||
* make the frontend capable of switching indexes depending on the customer | ||
|
||
Bug Tracker | ||
=========== | ||
|
||
Bugs are tracked on `GitHub Issues <https://github.com/shopinvader/shopinvader/issues>`_. | ||
In case of trouble, please check there if your issue has already been reported. | ||
If you spotted it first, help us smashing it by providing a detailed and welcomed | ||
`feedback <https://github.com/shopinvader/shopinvader/issues/new?body=module:%20shopinvader_customer_price%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_. | ||
|
||
Do not contact contributors directly about support or help with technical issues. | ||
|
||
Credits | ||
======= | ||
|
||
Authors | ||
~~~~~~~ | ||
|
||
* Camptocamp | ||
|
||
Contributors | ||
~~~~~~~~~~~~ | ||
|
||
* Simone Orsi <[email protected]> | ||
|
||
Other credits | ||
~~~~~~~~~~~~~ | ||
|
||
The development of this module has been financially supported by: | ||
|
||
* Camptocamp | ||
* Cosanum | ||
|
||
Maintainers | ||
~~~~~~~~~~~ | ||
|
||
This module is part of the `shopinvader/shopinvader <https://github.com/shopinvader/shopinvader/tree/13.0/shopinvader_customer_price>`_ project on GitHub. | ||
|
||
You are welcome to contribute. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
from . import services | ||
from . import models |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Copyright 2020 Camptocamp SA | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
{ | ||
"name": "Shopinvader Customer Price", | ||
"summary": """Expose customer's specific prices.""", | ||
"version": "13.0.1.0.0", | ||
"license": "AGPL-3", | ||
"author": "Camptocamp,Odoo Community Association (OCA)", | ||
"website": "https://github.com/shopinvader/odoo-shopinvader", | ||
"depends": ["shopinvader"], | ||
"data": ["views/shopinvader_backend_views.xml"], | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import shopinvader_backend |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
# Copyright 2020 Camptocamp SA (http://www.camptocamp.com). | ||
# @author Simone Orsi <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from odoo import fields, models, tools | ||
|
||
|
||
class ShopinvaderBackend(models.Model): | ||
|
||
_inherit = "shopinvader.backend" | ||
|
||
cart_pricelist_partner_field_id = fields.Many2one( | ||
comodel_name="ir.model.fields", | ||
domain=[ | ||
("model", "=", "res.partner"), | ||
("ttype", "=", "many2one"), | ||
("relation", "=", "product.pricelist"), | ||
], | ||
help="Set the partner pricelist that will be used for the cart. " | ||
"WARNING: by changing this you might have a mismatch " | ||
"between the prices showed on the cart " | ||
"and the ones showed on product details. " | ||
"The default pricelist will still be used for products' indexes.", | ||
) | ||
|
||
@tools.ormcache("partner.id", "self.cart_pricelist_partner_field_id.id") | ||
def _get_cart_pricelist_id(self, partner): | ||
if self.cart_pricelist_partner_field_id: | ||
pricelist = partner[self.cart_pricelist_partner_field_id.name] | ||
return pricelist.id | ||
return None | ||
|
||
def _get_cart_pricelist(self, partner=None): | ||
pricelist = super()._get_cart_pricelist(partner) | ||
if partner: | ||
pricelist_id = self._get_cart_pricelist_id(partner) | ||
if pricelist_id: | ||
return self.env["product.pricelist"].browse(pricelist_id) | ||
return pricelist | ||
|
||
def _get_partner_pricelist(self, partner): | ||
pricelist = super()._get_partner_pricelist(partner) | ||
if pricelist is None: | ||
pricelist = partner.property_product_pricelist | ||
return pricelist | ||
|
||
@tools.ormcache("partner.id", "self.company_id.id") | ||
def _get_fiscal_position_id(self, partner): | ||
fp_model = self.env["account.fiscal.position"].with_context( | ||
force_company=self.company_id.id | ||
) | ||
fpos_id = fp_model.get_fiscal_position( | ||
partner.id, delivery_id=partner.id, | ||
) | ||
return fpos_id | ||
|
||
def _get_fiscal_position(self, partner): | ||
fpos_id = self._get_fiscal_position_id(partner) | ||
return ( | ||
self.env["account.fiscal.position"].browse(fpos_id) | ||
if fpos_id | ||
else self.env["account.fiscal.position"].browse() | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Simone Orsi <[email protected]> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
The development of this module has been financially supported by: | ||
|
||
* Camptocamp | ||
* Cosanum |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
Handle customer specific prices. | ||
|
||
Provides: | ||
|
||
* endpoint `/customer_price/products` to fetch customer prices for products. | ||
* backend configuration to state which pricelist should be used by partner | ||
(by selecting a partner field that relates to pricelists) | ||
|
||
|
||
**Use case** | ||
|
||
Thousands of customers and at least 1 pricelist per each customer. | ||
You want to display customer specific prices in the frontend on demand. | ||
For instance: product page, wishlists, etc. | ||
|
||
**Rationale** | ||
|
||
One of the key points of Shopinvader's speed | ||
is the delegation of products' data indexing to external search engines. | ||
|
||
While this is perfect for generic data and not so complex price rules, | ||
if you have very special prices per each customer that's a blocker, | ||
and you'd need to index all prices for all customers to make it work seemlessly. | ||
|
||
**Warning** | ||
|
||
It's strongly recommended to not call the endpoint for each product on search results | ||
otherwise you'll get potentially thousands of requests to Odoo. | ||
|
||
Also, when setting the pricelist field for the partner, | ||
beware that prices in the indexes might differ from the prices in the cart. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
Probably the best option would be to have 1 index per customer | ||
which would even allow to sort and filter products by customer's prices | ||
but this requires a lot of work with current implementation of search engine machinery. | ||
|
||
If you use Algolia this is probably a no-go as it would cost too much. | ||
In the context of ElasticSearch instead you could afford it. | ||
|
||
Things that would be needed to go for an indexed solution: | ||
|
||
* make language not required on indexes (at the momemt the whole SE machinery relies on languages) | ||
* automatically generate one index per each pricelist/customer | ||
* make the frontend capable of switching indexes depending on the customer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from . import customer_price |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
# Copyright 2020 Camptocamp (http://www.camptocamp.com). | ||
# @author Simone Orsi <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from odoo.osv import expression | ||
|
||
from odoo.addons.base_rest.components.service import to_int | ||
from odoo.addons.component.core import Component | ||
|
||
|
||
class CustomerPriceService(Component): | ||
"""Shopinvader service to expose customer specific product prices. | ||
""" | ||
|
||
_name = "shopinvader.customer.price.service" | ||
_inherit = "base.shopinvader.service" | ||
_usage = "customer_price" | ||
_expose_model = "shopinvader.variant" | ||
_description = __doc__ | ||
|
||
def products(self, **params): | ||
domain = expression.normalize_domain(self._get_base_search_domain()) | ||
domain = expression.AND([domain, [("id", "in", params["ids"])]]) | ||
records = self.env[self._expose_model].search(domain) | ||
return self._to_json(records, one=params.get("one")) | ||
|
||
def _validator_products(self): | ||
return { | ||
"ids": { | ||
"type": "list", | ||
"nullable": True, | ||
"required": True, | ||
"schema": {"coerce": to_int, "type": "integer"}, | ||
}, | ||
"one": {"type": "boolean", "nullable": True, "required": False}, | ||
} | ||
|
||
def _get_base_search_domain(self): | ||
if not self._is_logged_in(): | ||
return expression.FALSE_DOMAIN | ||
return super()._get_base_search_domain() | ||
|
||
def _to_json(self, records, **kw): | ||
return records.jsonify(self._json_parser(), **kw) | ||
|
||
def _json_parser(self): | ||
return [ | ||
"id", | ||
("record_id:objectID", lambda rec, fname: rec[fname].id), | ||
("price", self._get_price), | ||
] | ||
|
||
def _get_price(self, record, fname): | ||
pricelist = self.shopinvader_backend._get_cart_pricelist(self.partner) | ||
fposition = self.shopinvader_backend._get_fiscal_position(self.partner) | ||
company = self.shopinvader_backend.company_id | ||
return { | ||
self.invader_partner.role: record._get_price( | ||
pricelist, fposition, company=company | ||
) | ||
} |
Oops, something went wrong.