[ADD] delivery_purolator

H10820
This commit is contained in:
Cedric Collins
2022-08-29 18:50:39 -05:00
committed by Jared Kipe
parent 33eaa2e7b9
commit a4626f2ef0
9 changed files with 253 additions and 0 deletions

View File

@@ -0,0 +1 @@
from . import models

View File

@@ -0,0 +1,28 @@
{
'name': 'Purolator Shipping',
'summary': 'Send your shippings through Purolator and track them online.',
'version': '15.0.1.0.1',
'author': "Hibou Corp.",
'category': 'Warehouse',
'license': 'OPL-1',
'images': [],
'website': "https://hibou.io",
'description': """
Purolator Shipping
==================
* Provides estimates on shipping costs.
* Send your shippings and track packages.
""",
'depends': [
'delivery_hibou',
],
'demo': [
'data/delivery_purolator_demo.xml',
],
'data': [
'views/delivery_purolator_views.xml',
],
'auto_install': False,
'installable': True,
}

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data noupdate="1">
<!-- Purolator Delivery Carriers -->
<record id="product_product_purolator_carrier" model="product.product">
<field name="name">Purolator Delivery</field>
<field name="default_code">Delivery_Puro</field>
<field name="type">service</field>
<field name="categ_id" ref="delivery.product_category_deliveries"/>
<field name="sale_ok" eval="False"/>
<field name="purchase_ok" eval="False"/>
<field name="list_price">0.0</field>
<field name="invoice_policy">order</field>
</record>
<record id="purolator_carrier" model="delivery.carrier">
<field name="name">Purolator Test Carrier</field>
<field name="product_id" ref="delivery_purolator.product_product_purolator_carrier"/>
<field name="delivery_type">purolator</field>
</record>
</data>
</odoo>

View File

@@ -0,0 +1 @@
from . import delivery_purolator

View File

@@ -0,0 +1,41 @@
from odoo import fields, models, _
from .purolator_services import PurolatorClient
class ProviderPurolator(models.Model):
_inherit = 'delivery.carrier'
delivery_type = fields.Selection(selection_add=[('purolator', 'Purolator')], ondelete={'purolator': 'cascade'})
purolator_api_key = fields.Char(string='Purolator API Key', groups='base.group_system')
purolator_password = fields.Char(string='Purolator Password', groups='base.group_system')
purolator_activation_key = fields.Char(string='Purolator Activation Key', groups='base.group_system')
purolator_account_number = fields.Char(string='Purolator Account Number', groups='base.group_system')
purolator_service_type = fields.Selection([('PurolatorExpress', 'PurolatorExpress')], default='PurolatorExpress')
def purolator_rate_shipment(self, order):
# sudoself = self.sudo()
sender = self.get_shipper_warehouse(order=order)
receiver = self.get_recipient(order=order)
receiver_address = {
'City': receiver.city,
'Province': receiver.state_id.code,
'Country': receiver.country_id.code,
'PostalCode': receiver.zip,
}
weight_uom_id = self.env['product.template']._get_weight_uom_id_from_ir_config_parameter()
weight = weight_uom_id._compute_quantity(order._get_estimated_weight(), self.env.ref('uom.product_uom_lb'), round=False)
client = PurolatorClient(self)
res = client.get_quick_estimate(sender.zip, receiver_address, 'CustomerPackaging', weight)
if res['error']:
return {
'success': False,
'price': 0.0,
'error_message': _(res['error']),
'warning_message': False,
}
return {
'success': True,
'price': res['price'],
'error_message': False,
'warning_message': False,
}

View File

@@ -0,0 +1,83 @@
from requests import Session
from requests.auth import HTTPBasicAuth
from zeep import Client
from zeep.cache import SqliteCache
from zeep.transports import Transport
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)
class PurolatorClient(object):
def __init__(self, carrier):
if carrier.delivery_type != 'purolator':
raise UserError('Invalid carrier: %s' % carrier.name)
self.api_key = carrier.purolator_api_key
self.password = carrier.purolator_password
self.activation_key = carrier.purolator_activation_key
self.account_number = carrier.purolator_account_number
self.service_type = carrier.purolator_service_type
self._wsdl_base = "https://devwebservices.purolator.com"
if carrier.prod_environment:
self._wsdl_base = "https://webservices.purolator.com"
session = Session()
session.auth = HTTPBasicAuth(self.api_key, self.password)
self.transport = Transport(cache=SqliteCache(), session=session)
def _get_client(self, wsdl_path):
client = Client(self._wsdl_base + wsdl_path,
transport=self.transport)
request_context = client.get_element('ns1:RequestContext')
header_value = request_context(
Version='2.0',
Language='en',
GroupID='xxx',
RequestReference='RatingExample',
UserToken=self.activation_key,
)
# _logger.warning('*** header_value:\n%s' % header_value)
client.set_default_soapheaders([header_value])
return client
def get_quick_estimate(self, sender_postal_code, receiver_address, package_type, total_weight):
""" Call GetQuickEstimate
:param sender_postal_code: string
:param receiver_address: dict {'City': string,
'Province': string,
'Country': string,
'PostalCode': string}
:param package_type: string
:param total_weight: float (in pounds)
:returns: dict
"""
client = self._get_client('/EWS/V2/Estimating/EstimatingService.asmx?wsdl')
response = client.service.GetQuickEstimate(
BillingAccountNumber=self.account_number,
SenderPostalCode=sender_postal_code,
ReceiverAddress=receiver_address,
PackageType=package_type,
TotalWeight={
'Value': 10.0,
'WeightUnit': 'lb',
},
)
# _logger.warning('**** GetQuickEstimate response:\n%s', response)
errors = response['body']['ResponseInformation']['Errors']
if errors:
return {
'price': 0.0,
'error': '\n'.join(['%s: %s' % (error['Code'], error['Description']) for error in errors['Error']]),
}
shipments = response['body']['ShipmentEstimates']['ShipmentEstimate']
shipment = list(filter(lambda s: s['ServiceID'] == self.service_type, shipments))
if shipment:
return {
'price': shipment[0]['TotalPrice'],
'error': False,
}
return {
'price': 0.0,
'error': 'Purolator ServiceID not found',
}

View File

@@ -0,0 +1 @@
from . import test_purolator

View File

@@ -0,0 +1,50 @@
from odoo.tests.common import Form, TransactionCase
class TestPurolator(TransactionCase):
def setUp(self):
super().setUp()
self.carrier = self.env.ref('delivery_purolator.purolator_carrier', raise_if_not_found=False)
if not self.carrier or not self.carrier.purolator_api_key:
self.skipTest('Purolator Shipping not configured, skipping tests.')
if self.carrier.prod_environment:
self.skipTest('Purolator Shipping configured to use production credentials, skipping tests.')
self.shipper_partner = self.env['res.partner'].create({
'name': 'Canadian Address',
'zip': 'L4W5M8',
})
self.shipper_warehouse = self.env['stock.warehouse'].create({
'partner_id': self.shipper_partner.id,
'name': 'Canadian Warehouse',
'code': 'CWH',
})
self.receiver_partner = self.env['res.partner'].create({
'name': 'Receiver Address',
'city': 'Burnaby',
'state_id': self.ref('base.state_ca_bc'),
'country_id': self.ref('base.ca'),
'zip': 'V5C5A9',
})
self.storage_box = self.env.ref('product.product_product_6')
self.sale_order = self.env['sale.order'].create({
'partner_id': self.receiver_partner.id,
'warehouse_id': self.shipper_warehouse.id,
'order_line': [(0, 0, {
'name': self.storage_box.name,
'product_id': self.storage_box.id,
'product_uom_qty': 3.0,
'product_uom': self.storage_box.uom_id.id,
'price_unit': self.storage_box.lst_price,
})],
})
def test_00_rate_order(self):
delivery_wizard = Form(self.env['choose.delivery.carrier'].with_context({
'default_order_id': self.sale_order.id,
'default_carrier_id': self.ref('delivery_purolator.purolator_carrier'),
}))
choose_delivery_carrier = delivery_wizard.save()
choose_delivery_carrier.update_price()
self.assertGreater(choose_delivery_carrier.delivery_price, 0.0, "Purolator delivery cost for this SO has not been correctly estimated.")

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_delivery_carrier_form_with_provider_purolator" model="ir.ui.view">
<field name="name">delivery.carrier.form.provider.purolator</field>
<field name="model">delivery.carrier</field>
<field name="inherit_id" ref="delivery.view_delivery_carrier_form"/>
<field name="arch" type="xml">
<xpath expr="//page[@name='destination']" position='before'>
<page string="Purolator Configuration" name="purolator_configuration" attrs="{'invisible': [('delivery_type', '!=', 'purolator')]}">
<group>
<group>
<field name="purolator_api_key" attrs="{'required': [('delivery_type', '=', 'purolator')]}"/>
<field name="purolator_password" attrs="{'required': [('delivery_type', '=', 'purolator')]}" password="True"/>
<field name="purolator_activation_key" attrs="{'required': [('delivery_type', '=', 'purolator')]}"/>
<field name="purolator_account_number" attrs="{'required': [('delivery_type', '=', 'purolator')]}"/>
<field name="purolator_service_type" attrs="{'required': [('delivery_type', '=', 'purolator')]}"/>
</group>
</group>
</page>
</xpath>
</field>
</record>
</odoo>