Skip to content

Commit

Permalink
Merge PR #488 into 12.0
Browse files Browse the repository at this point in the history
Signed-off-by lmignon
  • Loading branch information
shopinvader-git-bot committed Oct 31, 2019
2 parents 81f71c5 + b2ee12b commit 549e059
Show file tree
Hide file tree
Showing 10 changed files with 553 additions and 21 deletions.
5 changes: 1 addition & 4 deletions shopinvader_delivery_carrier/controllers/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,12 @@
# Cédric Pigeon <[email protected]>
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).

import logging

from odoo.addons.shopinvader.controllers import main
from odoo.http import route

_logger = logging.getLogger(__name__)


class InvaderController(main.InvaderController):
@route(["/shopinvader/cart/get_delivery_methods"], methods=["GET"])
def get_delivery_methods(self, **params):
# deprecated!!!
return self._process_method("cart", "get_delivery_methods", params)
1 change: 1 addition & 0 deletions shopinvader_delivery_carrier/models/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from . import backend
from . import delivery_carrier
from . import sale
from . import shopinvader_notification
from . import stock_picking
68 changes: 68 additions & 0 deletions shopinvader_delivery_carrier/models/delivery_carrier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# -*- 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(["country_id", "zip"])
partner_values = partner._convert_to_write(partner._cache)
with partner.env.do_in_draft():
yield
# Restore values
partner.update(partner_values)

@api.model
def _get_country_from_context(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 _get_zip_from_context(self):
"""
Load the zip code from context
:return: str
"""
return self.env.context.get("delivery_force_zip_code", "")

@api.multi
def available_carriers(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._get_country_from_context()
zip_code = self._get_zip_from_context()
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).available_carriers(
contact
)
else:
result = super(DeliveryCarrier, self).available_carriers(contact)
return result
1 change: 1 addition & 0 deletions shopinvader_delivery_carrier/services/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import abstract_sale
from . import cart
from . import delivery_carrier
from . import delivery
65 changes: 53 additions & 12 deletions shopinvader_delivery_carrier/services/cart.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,62 @@
# 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).
import logging

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.translate import _

_logger = logging.getLogger(__name__)


class CartService(Component):
_inherit = "shopinvader.cart.service"

def set_carrier(self, **params):
"""
This service will set the given delivery method to the current
cart
:param params: The carrier_id to set
:return:
"""
cart = self._get()
if not cart:
raise UserError(_("There is not cart"))
else:
self._set_carrier(cart, params["carrier_id"])
return self._to_json(cart)

# DEPRECATED METHODS #
def get_delivery_methods(self):
"""
!!!!DEPRECATED!!!!! Uses delivery_carrier.search
This service will return all possible delivery methods for the
current cart
:return:
"""
cart = self._get()
return self._get_available_carrier(cart)
_logger.warning(
"DEPRECATED: You should use %s in service %s",
"search",
"delivery_carrier",
)
return self.component("delivery_carrier").search(
target="current_cart"
)["rows"]

def apply_delivery_method(self, **params):
"""
!!!!DEPRECATED!!!!! Uses set_carrier
This service will apply the given delivery method to the current
cart
:param params: Dict containing delivery method to apply
:return:
"""
cart = self._get()
if not cart:
raise UserError(_("There is not cart"))
else:
self._set_carrier(cart, params["carrier"]["id"])
return self._to_json(cart)
return self.set_carrier(carrier_id=params["carrier"]["id"])

# Validator
def _validator_apply_delivery_method(self):
Expand All @@ -50,9 +75,27 @@ 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"},
}

def _validator_set_carrier(self):
return {
"carrier_id": {
"coerce": int,
"nullable": True,
"required": True,
"type": "integer",
}
}

# internal methods

def _add_item(self, cart, params):
res = super()._add_item(cart, params)
self._unset_carrier(cart)
Expand All @@ -69,9 +112,7 @@ def _delete_item(self, cart, params):
return res

def _set_carrier(self, cart, carrier_id):
if carrier_id not in [
x["id"] for x in self._get_available_carrier(cart)
]:
if carrier_id not in [x["id"] for x in cart._get_available_carrier()]:
raise UserError(
_("This delivery method is not available for you order")
)
Expand Down
146 changes: 146 additions & 0 deletions shopinvader_delivery_carrier/services/delivery_carrier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
# -*- 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).
# pylint: disable=consider-merging-classes-inherited,method-required-super

from odoo.addons.base_rest.components.service import to_int
from odoo.addons.component.core import Component


class DeliveryCarrierService(Component):
_inherit = "base.shopinvader.service"
_name = "shopinvader.delivery.carrier.service"
_usage = "delivery_carrier"
_description = """
This service allows you to retrieve the informations of available
delivery carriers.
"""

# Public services:

def search(self, **params):
"""
Returns the list of available carriers
If the target params == current_cart, the list will be limited to the
carriers applying to the current cart and a price will be filled
into the response otherwise the price is not relevant (always 0).
The field type is a technical field only use inform if the carrier
provides some specialized functionalities
"""
cart = None
if params.get("target") == "current_cart":
cart = self.component(usage="cart")._get()
delivery_carriers = self._search(cart=cart, **params)
return {
"count": len(delivery_carriers),
"rows": [
self._prepare_carrier(dc, cart) for dc in delivery_carriers
],
}

# Validators

def _validator_search(self):
return {
"target": {
"type": "string",
"required": False,
"allowed": ["current_cart"],
},
"country_id": {
"coerce": to_int,
"required": False,
"type": "integer",
},
"zip_code": {"required": False, "type": "string"},
}

def _validator_return_search(self):
return {
"count": {"type": "integer", "required": True},
"rows": {
"type": "list",
"required": True,
"schema": {
"type": "dict",
"schema": {
"id": {"type": "integer", "required": True},
"name": {
"type": "string",
"required": False,
"nullable": True,
},
"description": {
"type": "string",
"required": False,
"nullable": True,
},
"price": {"type": "float", "required": False},
"type": {
"type": "string",
"required": False,
"allowed": self.allowed_carrier_types,
"nullable": True,
},
},
},
},
}

# Services implementation

def _search(self, cart, **params):
"""
Search for delivery carriers
:param: cart: if provided, the list will be limited to the carrier
applying to the given cart
:param params: see _validator_search
:return: delivery.carriers recordset
"""
if 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,
)
return cart._get_available_carrier()
return self.shopinvader_backend.carrier_ids

def _prepare_carrier(self, carrier, cart=None):
res = carrier.jsonify(self._json_parser_carrier)[0]
res["type"] = None
price = 0.0
if cart:
price = carrier.rate_shipment(cart).get("price", 0.0)
res["price"] = price
return res

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", "")

@property
def allowed_carrier_types(self):
return []

@property
def _json_parser_carrier(self):
return ["id", "name", "name:description"]
1 change: 1 addition & 0 deletions shopinvader_delivery_carrier/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
from . import test_carrier
from . import test_notification
from . import test_delivery_carrier
from . import test_delivery_service
19 changes: 14 additions & 5 deletions shopinvader_delivery_carrier/tests/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@


class CommonCarrierCase(CommonConnectedCartCase):
def setUp(self):
super(CommonCarrierCase, self).setUp()
self.free_carrier = self.env.ref("delivery.free_delivery_carrier")
self.poste_carrier = self.env.ref("delivery.delivery_carrier")
self.product_1 = self.env.ref("product.product_product_4b")
@classmethod
def setUpClass(cls):
super(CommonCarrierCase, cls).setUpClass()
cls.free_carrier = cls.env.ref("delivery.free_delivery_carrier")
cls.poste_carrier = cls.env.ref("delivery.delivery_carrier")
cls.product_1 = cls.env.ref("product.product_product_4b")
cls.precision = 2

def extract_cart(self, response):
self.shopinvader_session["cart_id"] = response["set_session"][
Expand Down Expand Up @@ -39,6 +41,13 @@ def delete_item(self, item_id):
)

def _set_carrier(self, carrier):
response = self.service.dispatch(
"set_carrier", params={"carrier_id": carrier.id}
)
self.assertEqual(self.cart.carrier_id.id, carrier.id)
return response["data"]

def _apply_delivery_method(self, carrier):
response = self.service.dispatch(
"apply_delivery_method", params={"carrier": {"id": carrier.id}}
)
Expand Down
Loading

0 comments on commit 549e059

Please sign in to comment.