Skip to content

Commit

Permalink
[ADD][10.0] add delivery price simulation for cart
Browse files Browse the repository at this point in the history
  • Loading branch information
acsonefho committed Jul 8, 2019
1 parent d5d64db commit 2186a61
Show file tree
Hide file tree
Showing 6 changed files with 390 additions and 76 deletions.
1 change: 1 addition & 0 deletions shopinvader_delivery_carrier/models/__init__.py
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
66 changes: 66 additions & 0 deletions shopinvader_delivery_carrier/models/delivery_carrier.py
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
2 changes: 1 addition & 1 deletion shopinvader_delivery_carrier/services/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# -*- coding: utf-8 -*-

from . import abstract_sale
from . import cart
73 changes: 73 additions & 0 deletions shopinvader_delivery_carrier/services/abstract_sale.py
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
118 changes: 43 additions & 75 deletions shopinvader_delivery_carrier/services/cart.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 2186a61

Please sign in to comment.