mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[ADD] delivery_purolator
H10820
This commit is contained in:
committed by
Jared Kipe
parent
33eaa2e7b9
commit
a4626f2ef0
1
delivery_purolator/__init__.py
Normal file
1
delivery_purolator/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import models
|
||||||
28
delivery_purolator/__manifest__.py
Normal file
28
delivery_purolator/__manifest__.py
Normal 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,
|
||||||
|
}
|
||||||
23
delivery_purolator/data/delivery_purolator_demo.xml
Normal file
23
delivery_purolator/data/delivery_purolator_demo.xml
Normal 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>
|
||||||
1
delivery_purolator/models/__init__.py
Normal file
1
delivery_purolator/models/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import delivery_purolator
|
||||||
41
delivery_purolator/models/delivery_purolator.py
Normal file
41
delivery_purolator/models/delivery_purolator.py
Normal 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,
|
||||||
|
}
|
||||||
83
delivery_purolator/models/purolator_services.py
Normal file
83
delivery_purolator/models/purolator_services.py
Normal 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',
|
||||||
|
}
|
||||||
1
delivery_purolator/tests/__init__.py
Normal file
1
delivery_purolator/tests/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
from . import test_purolator
|
||||||
50
delivery_purolator/tests/test_purolator.py
Normal file
50
delivery_purolator/tests/test_purolator.py
Normal 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.")
|
||||||
25
delivery_purolator/views/delivery_purolator_views.xml
Normal file
25
delivery_purolator/views/delivery_purolator_views.xml
Normal 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>
|
||||||
Reference in New Issue
Block a user