mirror of
https://gitlab.com/hibou-io/hibou-odoo/suite.git
synced 2025-01-20 12:37:31 +02:00
[IMP] delivery_purolator: refactors, add 3rd party, fix estimated weight
This commit is contained in:
@@ -83,13 +83,22 @@ class ProviderPurolator(models.Model):
|
|||||||
purolator_service_type = fields.Selection(selection=PUROLATOR_SERVICES,
|
purolator_service_type = fields.Selection(selection=PUROLATOR_SERVICES,
|
||||||
default='PurolatorGround')
|
default='PurolatorGround')
|
||||||
purolator_default_package_type_id = fields.Many2one('stock.package.type', string="Purolator Package Type")
|
purolator_default_package_type_id = fields.Many2one('stock.package.type', string="Purolator Package Type")
|
||||||
|
purolator_label_file_type = fields.Selection([
|
||||||
|
('PDF', 'PDF'),
|
||||||
|
('ZPL', 'ZPL'),
|
||||||
|
], default='ZPL', string="Purolator Label File Type")
|
||||||
|
|
||||||
def _purolator_weight(self, weight):
|
def purolator_convert_weight(self, weight):
|
||||||
weight_uom_id = self.env['product.template']._get_weight_uom_id_from_ir_config_parameter()
|
weight_uom_id = self.env['product.template']._get_weight_uom_id_from_ir_config_parameter()
|
||||||
return weight_uom_id._compute_quantity(weight, self.env.ref('uom.product_uom_lb'), round=False)
|
return weight_uom_id._compute_quantity(weight, self.env.ref('uom.product_uom_lb'), round=False)
|
||||||
|
|
||||||
|
def purolator_convert_length(self, length):
|
||||||
|
volume_uom_id = self.env['product.template']._get_weight_uom_id_from_ir_config_parameter()
|
||||||
|
return weight_uom_id._compute_quantity(weight, self.env.ref('uom.product_uom_lb'), round=False)
|
||||||
|
|
||||||
def purolator_rate_shipment(self, order):
|
def purolator_rate_shipment(self, order):
|
||||||
# sudoself = self.sudo()
|
# sudoself = self.sudo()
|
||||||
|
third_party = self.purolator_third_party(order=order)
|
||||||
sender = self.get_shipper_warehouse(order=order)
|
sender = self.get_shipper_warehouse(order=order)
|
||||||
receiver = self.get_recipient(order=order)
|
receiver = self.get_recipient(order=order)
|
||||||
receiver_address = {
|
receiver_address = {
|
||||||
@@ -99,15 +108,9 @@ class ProviderPurolator(models.Model):
|
|||||||
'PostalCode': receiver.zip,
|
'PostalCode': receiver.zip,
|
||||||
}
|
}
|
||||||
# TODO packaging volume/length/width/height
|
# TODO packaging volume/length/width/height
|
||||||
weight = self._purolator_weight(order._get_estimated_weight())
|
weight = self.purolator_convert_weight(order._get_estimated_weight())
|
||||||
client = PurolatorClient(
|
service = self._purolator_service()
|
||||||
self.purolator_api_key,
|
res = service.get_quick_estimate(
|
||||||
self.purolator_password,
|
|
||||||
self.purolator_activation_key,
|
|
||||||
self.purolator_account_number,
|
|
||||||
self.prod_environment,
|
|
||||||
)
|
|
||||||
res = client.get_quick_estimate(
|
|
||||||
sender.zip,
|
sender.zip,
|
||||||
receiver_address,
|
receiver_address,
|
||||||
self.purolator_default_package_type_id.shipper_package_code,
|
self.purolator_default_package_type_id.shipper_package_code,
|
||||||
@@ -130,7 +133,7 @@ class ProviderPurolator(models.Model):
|
|||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
'success': True,
|
'success': True,
|
||||||
'price': shipment[0]['TotalPrice'],
|
'price': shipment[0]['TotalPrice'] if not third_party else 0.0,
|
||||||
'error_message': False,
|
'error_message': False,
|
||||||
'warning_message': False,
|
'warning_message': False,
|
||||||
}
|
}
|
||||||
@@ -145,6 +148,7 @@ class ProviderPurolator(models.Model):
|
|||||||
return rates
|
return rates
|
||||||
|
|
||||||
def _purolator_rate_shipment_multi_package(self, order=None, picking=None, package=None):
|
def _purolator_rate_shipment_multi_package(self, order=None, picking=None, package=None):
|
||||||
|
third_party = self.purolator_third_party(order=order, picking=picking)
|
||||||
sender = self.get_shipper_warehouse(order=order, picking=picking)
|
sender = self.get_shipper_warehouse(order=order, picking=picking)
|
||||||
receiver = self.get_recipient(order=order, picking=picking)
|
receiver = self.get_recipient(order=order, picking=picking)
|
||||||
receiver_address = {
|
receiver_address = {
|
||||||
@@ -170,15 +174,9 @@ class ProviderPurolator(models.Model):
|
|||||||
package_code = package.package_type_id.shipper_package_code if package.package_type_id.package_carrier_type == 'purolator' else package_code
|
package_code = package.package_type_id.shipper_package_code if package.package_type_id.package_carrier_type == 'purolator' else package_code
|
||||||
else:
|
else:
|
||||||
weight = picking.shipping_weight or picking.weight
|
weight = picking.shipping_weight or picking.weight
|
||||||
weight = self._purolator_weight(weight)
|
weight = self.purolator_convert_weight(weight)
|
||||||
client = PurolatorClient(
|
service = self._purolator_service()
|
||||||
self.purolator_api_key,
|
res = service.get_quick_estimate(sender.zip, receiver_address, package_code, weight)
|
||||||
self.purolator_password,
|
|
||||||
self.purolator_activation_key,
|
|
||||||
self.purolator_account_number,
|
|
||||||
self.prod_environment,
|
|
||||||
)
|
|
||||||
res = client.get_quick_estimate(sender.zip, receiver_address, package_code, weight)
|
|
||||||
if res['error']:
|
if res['error']:
|
||||||
return [{'carrier': self,
|
return [{'carrier': self,
|
||||||
'success': False,
|
'success': False,
|
||||||
@@ -195,7 +193,7 @@ class ProviderPurolator(models.Model):
|
|||||||
'carrier': carrier,
|
'carrier': carrier,
|
||||||
'package': package or self.env['stock.quant.package'].browse(),
|
'package': package or self.env['stock.quant.package'].browse(),
|
||||||
'success': True,
|
'success': True,
|
||||||
'price': price,
|
'price': price if not third_party else 0.0,
|
||||||
'error_message': False,
|
'error_message': False,
|
||||||
'warning_message': _('TotalCharge not found.') if price == 0.0 else False,
|
'warning_message': _('TotalCharge not found.') if price == 0.0 else False,
|
||||||
'date_planned': date_planned,
|
'date_planned': date_planned,
|
||||||
@@ -215,6 +213,14 @@ class ProviderPurolator(models.Model):
|
|||||||
], limit=1)
|
], limit=1)
|
||||||
return carrier
|
return carrier
|
||||||
|
|
||||||
|
def purolator_third_party(self, order=None, picking=None):
|
||||||
|
third_party_account = self.get_third_party_account(order=order, picking=picking)
|
||||||
|
if third_party_account:
|
||||||
|
if not third_party_account.delivery_type == 'purolator':
|
||||||
|
raise ValidationError('Non-Purolator Shipping Account indicated during Purolator shipment.')
|
||||||
|
return third_party_account.name
|
||||||
|
return False
|
||||||
|
|
||||||
def _purolator_service(self):
|
def _purolator_service(self):
|
||||||
return PurolatorClient(
|
return PurolatorClient(
|
||||||
self.purolator_api_key,
|
self.purolator_api_key,
|
||||||
@@ -294,10 +300,15 @@ class ProviderPurolator(models.Model):
|
|||||||
shipment.PaymentInformation.PaymentType = 'Sender'
|
shipment.PaymentInformation.PaymentType = 'Sender'
|
||||||
shipment.PaymentInformation.RegisteredAccountNumber = self.purolator_account_number
|
shipment.PaymentInformation.RegisteredAccountNumber = self.purolator_account_number
|
||||||
shipment.PaymentInformation.BillingAccountNumber = self.purolator_account_number
|
shipment.PaymentInformation.BillingAccountNumber = self.purolator_account_number
|
||||||
# TODO switch to 'Receiver' or 'ThirdParty' if needed
|
third_party_account = self.purolator_third_party(picking=picking)
|
||||||
|
# when would it be 'Receiver' ?
|
||||||
|
if third_party_account:
|
||||||
|
shipment.PaymentInformation.PaymentType = 'ThirdParty'
|
||||||
|
shipment.PaymentInformation.BillingAccountNumber = third_party_account
|
||||||
|
|
||||||
shipment_res = service.shipment_create(shipment)
|
shipment_res = service.shipment_create(shipment,
|
||||||
_logger.info('purolator service.shipment_create for shipment %s resulted in %s' % (shipment, shipment_res))
|
printer_type=('Regular' if self.purolator_label_file_type == 'PDF' else 'Thermal'))
|
||||||
|
# _logger.info('purolator service.shipment_create for shipment %s resulted in %s' % (shipment, shipment_res))
|
||||||
|
|
||||||
errors = shipment_res.ResponseInformation.Errors
|
errors = shipment_res.ResponseInformation.Errors
|
||||||
if errors:
|
if errors:
|
||||||
@@ -312,21 +323,20 @@ class ProviderPurolator(models.Model):
|
|||||||
for p, pin in zip(picking_packages, piece_pins):
|
for p, pin in zip(picking_packages, piece_pins):
|
||||||
pin = pin.Value
|
pin = pin.Value
|
||||||
p.carrier_tracking_ref = pin
|
p.carrier_tracking_ref = pin
|
||||||
doc_res = service.document_by_pin(pin)
|
doc_res = service.document_by_pin(pin, output_type=self.purolator_label_file_type)
|
||||||
for n, blob in enumerate(self._purolator_extract_doc_blobs(doc_res), 1):
|
for n, blob in enumerate(self._purolator_extract_doc_blobs(doc_res), 1):
|
||||||
document_blobs.append(('PuroPackage-%s-%s.%s' % (pin, n, 'ZPL'), blob))
|
document_blobs.append(('PuroPackage-%s-%s.%s' % (pin, n, self.purolator_label_file_type), blob))
|
||||||
else:
|
else:
|
||||||
# retrieve shipment_pin document(s)
|
# retrieve shipment_pin document(s)
|
||||||
doc_res = service.document_by_pin(shipment_pin)
|
doc_res = service.document_by_pin(shipment_pin, output_type=self.purolator_label_file_type)
|
||||||
_logger.info('purolator service.document_by_pin for pin %s resulted in %s' % (shipment_pin, doc_res))
|
# _logger.info('purolator service.document_by_pin for pin %s resulted in %s' % (shipment_pin, doc_res))
|
||||||
for n, blob in enumerate(self._purolator_extract_doc_blobs(doc_res), 1):
|
for n, blob in enumerate(self._purolator_extract_doc_blobs(doc_res), 1):
|
||||||
document_blobs.append(('PuroShipment-%s-%s.%s' % (shipment_pin, n, 'ZPL'), blob))
|
document_blobs.append(('PuroShipment-%s-%s.%s' % (shipment_pin, n, self.purolator_label_file_type), blob))
|
||||||
|
|
||||||
if document_blobs:
|
if document_blobs:
|
||||||
logmessage = _("Shipment created in Purolator <br/> <b>Tracking Number/PIN : </b>%s") % (shipment_pin)
|
logmessage = _("Shipment created in Purolator <br/> <b>Tracking Number/PIN : </b>%s") % (shipment_pin)
|
||||||
picking.message_post(body=logmessage, attachments=document_blobs)
|
picking.message_post(body=logmessage, attachments=document_blobs)
|
||||||
|
|
||||||
|
|
||||||
picking.carrier_tracking_ref = shipment_pin
|
picking.carrier_tracking_ref = shipment_pin
|
||||||
shipping_data = {
|
shipping_data = {
|
||||||
'exact_price': 0.0, # TODO How can we know?!
|
'exact_price': 0.0, # TODO How can we know?!
|
||||||
|
|||||||
@@ -9,11 +9,27 @@ from odoo.exceptions import UserError
|
|||||||
class PurolatorClient(object):
|
class PurolatorClient(object):
|
||||||
|
|
||||||
# clients and factories
|
# clients and factories
|
||||||
|
_estimating_client = None
|
||||||
|
@property
|
||||||
|
def estimating_client(self):
|
||||||
|
if not self._estimating_client:
|
||||||
|
self._estimating_client = self._get_client('/EWS/V2/Estimating/EstimatingService.asmx?wsdl',
|
||||||
|
request_reference='Rating')
|
||||||
|
return self._estimating_client
|
||||||
|
|
||||||
|
_estimating_factory = None
|
||||||
|
@property
|
||||||
|
def estimating_factory(self):
|
||||||
|
if not self._estimating_factory:
|
||||||
|
self._estimating_factory = self.estimating_client.type_factory('ns1')
|
||||||
|
return self._estimating_factory
|
||||||
|
|
||||||
_shipping_client = None
|
_shipping_client = None
|
||||||
@property
|
@property
|
||||||
def shipping_client(self):
|
def shipping_client(self):
|
||||||
if not self._shipping_client:
|
if not self._shipping_client:
|
||||||
self._shipping_client = self._get_client('/EWS/V2/Shipping/ShippingService.asmx?wsdl')
|
self._shipping_client = self._get_client('/EWS/V2/Shipping/ShippingService.asmx?wsdl',
|
||||||
|
request_reference='Shipping')
|
||||||
return self._shipping_client
|
return self._shipping_client
|
||||||
|
|
||||||
_shipping_factory = None
|
_shipping_factory = None
|
||||||
@@ -27,7 +43,9 @@ class PurolatorClient(object):
|
|||||||
@property
|
@property
|
||||||
def shipping_documents_client(self):
|
def shipping_documents_client(self):
|
||||||
if not self._shipping_documents_client:
|
if not self._shipping_documents_client:
|
||||||
self._shipping_documents_client = self._get_client('/PWS/V1/ShippingDocuments/ShippingDocumentsService.asmx?wsdl', version='1.3')
|
self._shipping_documents_client = self._get_client('/PWS/V1/ShippingDocuments/ShippingDocumentsService.asmx?wsdl',
|
||||||
|
version='1.3',
|
||||||
|
request_reference='ShippingDocuments')
|
||||||
return self._shipping_documents_client
|
return self._shipping_documents_client
|
||||||
|
|
||||||
_shipping_documents_factory = None
|
_shipping_documents_factory = None
|
||||||
@@ -50,7 +68,7 @@ class PurolatorClient(object):
|
|||||||
session.auth = HTTPBasicAuth(self.api_key, self.password)
|
session.auth = HTTPBasicAuth(self.api_key, self.password)
|
||||||
self.transport = Transport(cache=SqliteCache(), session=session)
|
self.transport = Transport(cache=SqliteCache(), session=session)
|
||||||
|
|
||||||
def _get_client(self, wsdl_path, version='2.0'):
|
def _get_client(self, wsdl_path, version='2.0', request_reference='RatingExample'):
|
||||||
# version added because shipping documents needs a different one
|
# version added because shipping documents needs a different one
|
||||||
client = Client(self._wsdl_base + wsdl_path,
|
client = Client(self._wsdl_base + wsdl_path,
|
||||||
transport=self.transport)
|
transport=self.transport)
|
||||||
@@ -58,8 +76,8 @@ class PurolatorClient(object):
|
|||||||
header_value = request_context(
|
header_value = request_context(
|
||||||
Version=version,
|
Version=version,
|
||||||
Language='en',
|
Language='en',
|
||||||
GroupID='xxx',
|
GroupID='xxx', # TODO should we have a GroupID?
|
||||||
RequestReference='RatingExample', # TODO need to paramatarize this or something, doesn't make sense to shipment, maybe GroupID
|
RequestReference=request_reference,
|
||||||
UserToken=self.activation_key,
|
UserToken=self.activation_key,
|
||||||
)
|
)
|
||||||
client.set_default_soapheaders([header_value])
|
client.set_default_soapheaders([header_value])
|
||||||
@@ -77,14 +95,13 @@ class PurolatorClient(object):
|
|||||||
:param total_weight: float (in pounds)
|
:param total_weight: float (in pounds)
|
||||||
:returns: dict {'shipments': list, 'error': string or False}
|
:returns: dict {'shipments': list, 'error': string or False}
|
||||||
"""
|
"""
|
||||||
client = self._get_client('/EWS/V2/Estimating/EstimatingService.asmx?wsdl')
|
response = self.estimating_client.service.GetQuickEstimate(
|
||||||
response = client.service.GetQuickEstimate(
|
|
||||||
BillingAccountNumber=self.account_number,
|
BillingAccountNumber=self.account_number,
|
||||||
SenderPostalCode=sender_postal_code,
|
SenderPostalCode=sender_postal_code,
|
||||||
ReceiverAddress=receiver_address,
|
ReceiverAddress=receiver_address,
|
||||||
PackageType=package_type,
|
PackageType=package_type,
|
||||||
TotalWeight={ # TODO FIX/paramatarize
|
TotalWeight={
|
||||||
'Value': 10.0,
|
'Value': total_weight,
|
||||||
'WeightUnit': 'lb',
|
'WeightUnit': 'lb',
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@@ -128,7 +145,7 @@ class PurolatorClient(object):
|
|||||||
total_pieces = len(packages) or 1
|
total_pieces = len(packages) or 1
|
||||||
if not packages:
|
if not packages:
|
||||||
# setup default package
|
# setup default package
|
||||||
package_weight = picking.shipping_weight # TODO need conversion (lb) below
|
package_weight = carrier.purolator_convert_weight(picking.shipping_weight)
|
||||||
if package_weight < 1.0:
|
if package_weight < 1.0:
|
||||||
package_weight = 1.0
|
package_weight = 1.0
|
||||||
total_weight_value += package_weight
|
total_weight_value += package_weight
|
||||||
@@ -154,7 +171,7 @@ class PurolatorClient(object):
|
|||||||
shipment.PackageInformation.PiecesInformation.Piece.append(p)
|
shipment.PackageInformation.PiecesInformation.Piece.append(p)
|
||||||
else:
|
else:
|
||||||
for package in packages:
|
for package in packages:
|
||||||
package_weight = package.shipping_weight # TODO need conversion (lb) below
|
package_weight = carrier.purolator_convert_weight(package.shipping_weight)
|
||||||
if package_weight < 1.0:
|
if package_weight < 1.0:
|
||||||
package_weight = 1.0
|
package_weight = 1.0
|
||||||
package_type = package.package_type_id
|
package_type = package.package_type_id
|
||||||
|
|||||||
Reference in New Issue
Block a user