-
Notifications
You must be signed in to change notification settings - Fork 104
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ADD][10.0] add delivery price simulation for cart
- Loading branch information
Showing
6 changed files
with
390 additions
and
76 deletions.
There are no files selected for viewing
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 |
---|---|---|
@@ -1,6 +1,7 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
from . import backend | ||
from . import delivery_carrier | ||
from . import sale | ||
from . import shopinvader_notification | ||
from . import stock_picking |
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,66 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2019 ACSONE SA/NV (<http://acsone.eu>) | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). | ||
from contextlib import contextmanager | ||
|
||
from odoo import api, models | ||
|
||
|
||
class DeliveryCarrier(models.Model): | ||
_inherit = "delivery.carrier" | ||
|
||
@contextmanager | ||
def _simulate_delivery_cost(self, partner): | ||
""" | ||
Change the env mode (draft) to avoid real update on the partner. | ||
Then, restore the partner with previous values. | ||
:param partner: res.partner recordset | ||
:return: | ||
""" | ||
partner.read() | ||
partner_values = partner._convert_to_write(partner._cache) | ||
with partner.env.do_in_draft(): | ||
yield | ||
# Restore values | ||
partner.update(partner_values) | ||
|
||
@api.model | ||
def _load_country(self): | ||
""" | ||
Load the country from context | ||
:return: res.country recordset | ||
""" | ||
country_id = self.env.context.get("delivery_force_country_id", 0) | ||
return self.env["res.country"].browse(country_id) | ||
|
||
@api.model | ||
def _load_zip_code(self): | ||
""" | ||
Load the zip code from context | ||
:return: str | ||
""" | ||
return self.env.context.get("delivery_force_zip_code", "") | ||
|
||
@api.multi | ||
def verify_carrier(self, contact): | ||
""" | ||
Inherit the function to force some values on the given contact | ||
(only in cache). | ||
:param contact: res.partner recordset | ||
:return: False or self | ||
""" | ||
country = self._load_country() | ||
zip_code = self._load_zip_code() | ||
if country or zip_code: | ||
with self._simulate_delivery_cost(contact): | ||
# Edit country and zip | ||
# Even if some info are not provided, we have to fill them | ||
# Ex: if the zip code is not provided, we have to do the | ||
# simulation with an empty zip code on the partner. Because his | ||
# current zip could be related to another country and simulate | ||
# a wrong price. | ||
contact.update({"country_id": country.id, "zip": zip_code}) | ||
result = super(DeliveryCarrier, self).verify_carrier(contact) | ||
else: | ||
result = super(DeliveryCarrier, self).verify_carrier(contact) | ||
return result |
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 |
---|---|---|
@@ -1,3 +1,3 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
from . import abstract_sale | ||
from . import 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,73 @@ | ||
# -*- coding: utf-8 -*- | ||
# Copyright 2017 Akretion (http://www.akretion.com). | ||
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
from odoo.addons.component.core import AbstractComponent | ||
from odoo.tools import float_round | ||
|
||
|
||
class AbstractSaleService(AbstractComponent): | ||
_inherit = "shopinvader.abstract.sale.service" | ||
|
||
def _convert_shipping(self, cart): | ||
res = super(AbstractSaleService, self)._convert_shipping(cart) | ||
selected_carrier = {} | ||
if cart.carrier_id: | ||
carrier = cart.carrier_id | ||
selected_carrier = { | ||
"id": carrier.id, | ||
"name": carrier.name, | ||
"description": carrier.description, | ||
} | ||
res.update( | ||
{ | ||
"amount": { | ||
"tax": cart.shipping_amount_tax, | ||
"untaxed": cart.shipping_amount_untaxed, | ||
"total": cart.shipping_amount_total, | ||
}, | ||
"selected_carrier": selected_carrier, | ||
} | ||
) | ||
return res | ||
|
||
def _convert_amount(self, sale): | ||
""" | ||
Inherit to add amounts without shipping prices included | ||
:param sale: sale.order recordset | ||
:return: dict | ||
""" | ||
result = super(AbstractSaleService, self)._convert_amount(sale) | ||
# Remove the shipping amounts for originals amounts | ||
shipping_amounts = self._convert_shipping(sale).get("amount", {}) | ||
tax = result.get("tax", 0) - shipping_amounts.get("tax", 0) | ||
untaxed = result.get("untaxed", 0) - shipping_amounts.get("untaxed", 0) | ||
total = result.get("total", 0) - shipping_amounts.get("total", 0) | ||
precision = sale.currency_id.decimal_places | ||
result.update( | ||
{ | ||
"tax_without_shipping": float_round(tax, precision), | ||
"untaxed_without_shipping": float_round(untaxed, precision), | ||
"total_without_shipping": float_round(total, precision), | ||
} | ||
) | ||
return result | ||
|
||
def _prepare_carrier(self, carrier): | ||
return { | ||
"id": carrier.id, | ||
"name": carrier.name, | ||
"description": carrier.description, | ||
"price": carrier.price, | ||
} | ||
|
||
def _get_available_carrier(self, cart): | ||
return [ | ||
self._prepare_carrier(carrier) | ||
for carrier in cart._get_available_carrier() | ||
] | ||
|
||
def _is_item(self, line): | ||
res = super(AbstractSaleService, self)._is_item(line) | ||
return res and not line.is_delivery |
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 |
---|---|---|
|
@@ -3,94 +3,38 @@ | |
# @author Sébastien BEAU <[email protected]> | ||
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). | ||
|
||
|
||
import logging | ||
|
||
from odoo.addons.component.core import AbstractComponent, Component | ||
from odoo.addons.base_rest.components.service import to_int | ||
from odoo.addons.component.core import Component | ||
from odoo.exceptions import UserError | ||
from odoo.tools import float_round | ||
from odoo.tools.translate import _ | ||
|
||
_logger = logging.getLogger(__name__) | ||
|
||
|
||
class AbstractSaleService(AbstractComponent): | ||
_inherit = "shopinvader.abstract.sale.service" | ||
|
||
def _convert_shipping(self, cart): | ||
res = super(AbstractSaleService, self)._convert_shipping(cart) | ||
selected_carrier = {} | ||
if cart.carrier_id: | ||
carrier = cart.carrier_id | ||
selected_carrier = { | ||
"id": carrier.id, | ||
"name": carrier.name, | ||
"description": carrier.description, | ||
} | ||
res.update( | ||
{ | ||
"amount": { | ||
"tax": cart.shipping_amount_tax, | ||
"untaxed": cart.shipping_amount_untaxed, | ||
"total": cart.shipping_amount_total, | ||
}, | ||
"selected_carrier": selected_carrier, | ||
} | ||
) | ||
return res | ||
|
||
def _convert_amount(self, sale): | ||
""" | ||
Inherit to add amounts without shipping prices included | ||
:param sale: sale.order recordset | ||
:return: dict | ||
""" | ||
result = super(AbstractSaleService, self)._convert_amount(sale) | ||
# Remove the shipping amounts for originals amounts | ||
shipping_amounts = self._convert_shipping(sale).get("amount", {}) | ||
tax = result.get("tax", 0) - shipping_amounts.get("tax", 0) | ||
untaxed = result.get("untaxed", 0) - shipping_amounts.get("untaxed", 0) | ||
total = result.get("total", 0) - shipping_amounts.get("total", 0) | ||
precision = sale.currency_id.decimal_places | ||
result.update( | ||
{ | ||
"tax_without_shipping": float_round(tax, precision), | ||
"untaxed_without_shipping": float_round(untaxed, precision), | ||
"total_without_shipping": float_round(total, precision), | ||
} | ||
) | ||
return result | ||
|
||
def _prepare_carrier(self, carrier): | ||
return { | ||
"id": carrier.id, | ||
"name": carrier.name, | ||
"description": carrier.description, | ||
"price": carrier.price, | ||
} | ||
|
||
def _get_available_carrier(self, cart): | ||
return [ | ||
self._prepare_carrier(carrier) | ||
for carrier in cart._get_available_carrier() | ||
] | ||
|
||
def _is_item(self, line): | ||
res = super(AbstractSaleService, self)._is_item(line) | ||
return res and not line.is_delivery | ||
|
||
|
||
class CartService(Component): | ||
_inherit = "shopinvader.cart.service" | ||
|
||
def get_delivery_methods(self): | ||
def get_delivery_methods(self, **params): | ||
""" | ||
This service will return all possible delivery methods for the | ||
current cart | ||
:return: | ||
This service will return all possible delivery methods for the | ||
current cart (depending on country/zip) | ||
The cart is not updated with the given country/zip. The change is done | ||
only in memory. | ||
:param params: dict | ||
:return: dict | ||
""" | ||
cart = self._get() | ||
return self._get_available_carrier(cart) | ||
country = self._load_country(params) | ||
zip_code = self._load_zip_code(params) | ||
if country or zip_code: | ||
cart = cart.with_context( | ||
delivery_force_country_id=country.id, | ||
delivery_force_zip_code=zip_code, | ||
) | ||
result = self._get_available_carrier(cart) | ||
return result | ||
|
||
def apply_delivery_method(self, **params): | ||
""" | ||
|
@@ -123,9 +67,33 @@ def _validator_apply_delivery_method(self): | |
} | ||
|
||
def _validator_get_delivery_methods(self): | ||
return {} | ||
return { | ||
"country_id": { | ||
"coerce": to_int, | ||
"required": False, | ||
"type": "integer", | ||
}, | ||
"zip_code": {"required": False, "type": "string"}, | ||
} | ||
|
||
# internal methods | ||
def _load_country(self, params): | ||
""" | ||
Load the country from given params | ||
:param params: dict | ||
:return: res.country recordset | ||
""" | ||
country_id = params.pop("country_id", 0) | ||
return self.env["res.country"].browse(country_id) | ||
|
||
def _load_zip_code(self, params): | ||
""" | ||
Load the country from given params | ||
:param params: dict | ||
:return: str | ||
""" | ||
return params.pop("zip_code", "") | ||
|
||
def _add_item(self, cart, params): | ||
res = super(CartService, self)._add_item(cart, params) | ||
self._unset_carrier(cart) | ||
|
Oops, something went wrong.