Odoo18-Base/extra-addons/website_delivery_sendcloud/models/delivery_sendcloud.py

109 lines
6.0 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import ValidationError
from .sendcloud_locations_request import SendcloudLocationsRequest
# As Sendcloud API's schemas may evolve, hardcoded values are defined as static const to ease futur updates.
# _T stands for sendcloud technical names while _H define 'humanized' name
LAST_MILE_T = 'last_mile'
SERVICE_POINT_T = 'service_point'
LAST_MILE_H = 'Last mile'
SERVICE_POINT_H = 'Service point'
class ProviderSendcloud(models.Model):
_inherit = 'delivery.carrier'
sendcloud_can_customize_use_locations = fields.Boolean(default=False, compute='_compute_sendcloud_can_customize_use_locations')
sendcloud_use_locations = fields.Boolean(string='Use Sendcloud Locations',
help='Allows the ecommerce user to choose a pick-up point as delivery address.',
default=False, compute='_compute_sendcloud_use_locations', store=True)
sendcloud_locations_radius_value = fields.Integer(string='Sendcloud Locations Radius',
help='Maximum locations distance radius.',
default=10, required=True)
sendcloud_locations_radius_unit = fields.Many2one('uom.uom', compute='_compute_sendcloud_locations_radius_unit',
default=lambda self: self.env.ref('uom.product_uom_km'), search='_search_sendcloud_locations_radius_unit', store=True)
sendcloud_locations_radius_unit_name = fields.Char('Sendcloud Radius Unit Name', related='sendcloud_locations_radius_unit.display_name')
sendcloud_locations_id = fields.Integer(string='Locations Id')
@api.depends('sendcloud_shipping_id')
def _compute_sendcloud_can_customize_use_locations(self):
self.sendcloud_can_customize_use_locations = False
for sc_carrier in self:
product_func = sc_carrier.sendcloud_shipping_id.functionalities
if not product_func:
continue
last_mile_custo = product_func.get('customizable', {}).get(LAST_MILE_T)
# N.B. if last_mile is set, then it has at least a length of 2 as it appears in 'customizable'
if last_mile_custo and SERVICE_POINT_T in last_mile_custo:
# service point is available but not mandatory, let the user choose
sc_carrier.sendcloud_can_customize_use_locations = True
@api.depends('sendcloud_shipping_id')
def _compute_sendcloud_use_locations(self):
for sc_carrier in self:
product_func = sc_carrier.sendcloud_shipping_id.functionalities
if not product_func:
sc_carrier.sendcloud_use_locations = False
continue
if not sc_carrier.sendcloud_can_customize_use_locations and SERVICE_POINT_H in product_func.get('detail_func', {}).get(LAST_MILE_H, {}):
# the only available option is service point
sc_carrier.sendcloud_use_locations = True
else:
sc_carrier.sendcloud_use_locations = False
def _compute_sendcloud_locations_radius_unit(self):
for carrier in self:
carrier.sendcloud_locations_radius_unit = self._get_distance_uom_id_from_ir_config_parameter()
@api.model
def _get_distance_uom_id_from_ir_config_parameter(self):
distance_in_miles_param = self.env['ir.config_parameter'].sudo().get_param('product.volume_in_cubic_feet')
if distance_in_miles_param == '1':
return self.env.ref('uom.product_uom_mile')
return self.env.ref('uom.product_uom_km')
def _search_sendcloud_locations_radius_unit(self, operator, value):
return [('sendcloud_locations_radius_value', operator, value)]
@api.constrains("sendcloud_locations_radius_value")
def _check_radius_value(self):
uom_meter = self.env.ref('uom.product_uom_meter')
for delivery in self:
distance_meters = delivery.sendcloud_locations_radius_unit._compute_quantity(delivery.sendcloud_locations_radius_value, uom_meter)
if distance_meters > 50000:
# maximum distance to display in that specific unit
max_distance = uom_meter._compute_quantity(50000, delivery.sendcloud_locations_radius_unit)
raise ValidationError(_("The maximum radius allowed is %(distance)d%(unit)s", distance=max_distance, unit=delivery.sendcloud_locations_radius_unit.name))
if distance_meters < 100:
# minimum distance to display in that specific unit
min_distance = uom_meter._compute_quantity(100, delivery.sendcloud_locations_radius_unit)
raise ValidationError(_("The minimum radius allowed is %(distance)d%(unit)s", distance=min_distance, unit=delivery.sendcloud_locations_radius_unit.name))
def _sendcloud_get_close_locations(self, partner_address):
superself = self.sudo()
distance = int(self.sendcloud_locations_radius_unit._compute_quantity(self.sendcloud_locations_radius_value, self.env.ref('uom.product_uom_meter')))
slr = SendcloudLocationsRequest(superself.sendcloud_public_key, superself.sendcloud_secret_key, self.log_xml)
locations = slr.get_close_locations(partner_address, distance, self.sendcloud_shipping_id.carrier)
close_locations = []
for location in locations:
close_locations.append(dict(
id=location['id'],
name=location['name'].title(),
opening_hours=location['formatted_opening_times'],
street=f"{location['street'].title()} {location['house_number']}",
city=location['city'].title(),
zip_code=location['postal_code'],
country_code=location['country'],
latitude=location['latitude'],
longitude=location['longitude'],
))
return close_locations