feat: separate fusion field service and LTC into standalone modules, update core modules

- fusion_claims: separated field service logic, updated controllers/views
- fusion_tasks: updated task views and map integration
- fusion_authorizer_portal: added page 11 signing, schedule booking, migrations
- fusion_shipping: new standalone shipping module (Canada Post, FedEx, DHL, Purolator)
- fusion_ltc_management: new standalone LTC management module
This commit is contained in:
2026-03-11 16:19:52 +00:00
parent 1f79cdcaaf
commit 431052920e
274 changed files with 52782 additions and 7302 deletions

View File

@@ -0,0 +1,7 @@
from . import canada_post
from . import ups
from . import ups_rest
from . import fedex
from . import fedex_rest
from . import dhl
from . import dhl_rest

View File

@@ -0,0 +1,2 @@
from . import response
from . import utils

View File

@@ -0,0 +1,164 @@
import lxml
import datetime
import logging
from collections import defaultdict
from odoo.addons.fusion_shipping.api.canada_post.utils import get_dom_tree, python_2_unicode_compatible
import json
_logger = logging.getLogger(__name__)
@python_2_unicode_compatible
class ResponseDataObject():
def __init__(self, mydict, datetime_nodes=[]):
self._load_dict(mydict, list(datetime_nodes))
def __repr__(self):
return str(self)
def __str__(self):
return "%s" % self.__dict__
def has_key(self, name):
try:
getattr(self, name)
return True
except AttributeError:
return False
def get(self, name, default=None):
try:
return getattr(self, name)
except AttributeError:
return default
def _setattr(self, name, value, datetime_nodes):
if name.lower() in datetime_nodes:
try:
ts = "%s %s" % (value.partition('T')[0], value.partition('T')[2].partition('.')[0])
value = datetime.datetime.strptime(ts, '%Y-%m-%d %H:%M:%S')
except ValueError:
pass
setattr(self, name, value)
def _load_dict(self, mydict, datetime_nodes):
for a in list(mydict.items()):
if isinstance(a[1], dict):
o = ResponseDataObject(a[1], datetime_nodes)
setattr(self, a[0], o)
elif isinstance(a[1], list):
objs = []
for i in a[1]:
if i is None or isinstance(i, str) or isinstance(i, str):
objs.append(i)
else:
objs.append(ResponseDataObject(i, datetime_nodes))
setattr(self, a[0], objs)
else:
self._setattr(a[0], a[1], datetime_nodes)
class Response():
def __init__(self, obj, verb=None, parse_response=True):
self._obj = obj
if parse_response:
try:
self._dom = self._parse_xml(obj.content)
self._dict = self._etree_to_dict(self._dom)
if verb and 'Envelope' in list(self._dict.keys()):
elem = self._dom.find('Body').find('%sResponse' % verb)
if elem is not None:
self._dom = elem
self._dict = self._dict['Envelope']['Body'].get('%sResponse' % verb, self._dict)
elif verb:
elem = self._dom.find('%sResponse' % verb)
if elem is not None:
self._dom = elem
self._dict = self._dict.get('%sResponse' % verb, self._dict)
self.reply = ResponseDataObject(self._dict,[])
except lxml.etree.XMLSyntaxError as e:
_logger.debug('Response parse failed: %s' % e)
self.reply = ResponseDataObject({}, [])
else:
self.reply = ResponseDataObject({}, [])
def _get_node_path(self, t):
i = t
path = []
path.insert(0, i.tag)
while 1:
try:
path.insert(0, i.getparent().tag)
i = i.getparent()
except AttributeError:
break
return '.'.join(path)
@staticmethod
def _pullval(v):
if len(v) == 1:
return v[0]
else:
return v
def _etree_to_dict(self, t):
if type(t) == lxml.etree._Comment:
return {}
# remove xmlns from nodes
t.tag = self._get_node_tag(t)
d = {t.tag: {} if t.attrib else None}
children = list(t)
if children:
dd = defaultdict(list)
for dc in map(self._etree_to_dict, children):
for k, v in list(dc.items()):
dd[k].append(v)
d = {t.tag: dict((k, self._pullval(v)) for k, v in list(dd.items()))}
parent_path = self._get_node_path(t)
for k in list(d[t.tag].keys()):
path = "%s.%s" % (parent_path, k)
if t.attrib:
d[t.tag].update(('_' + k, v) for k, v in list(t.attrib.items()))
if t.text:
text = t.text.strip()
if children or t.attrib:
if text:
d[t.tag]['value'] = text
else:
d[t.tag] = text
return d
def __getattr__(self, name):
return getattr(self._obj, name)
def _parse_xml(self, xml):
return get_dom_tree(xml)
def _get_node_tag(self, node):
return node.tag.replace('{' + node.nsmap.get(node.prefix, '') + '}', '')
def dom(self, lxml=True):
if not lxml:
pass
return self._dom
def dict(self):
return self._dict
def json(self):
return json.dumps(self.dict())

View File

@@ -0,0 +1,215 @@
import sys
from lxml import etree as ET
def parse_yaml(yaml_file):
"""
This is simple approach to parsing a yaml config that is only
intended for this SDK as this only supports a very minimal subset
of yaml options.
"""
with open(yaml_file) as f:
data = {None: {}}
current_key = None
for line in f.readlines():
# ignore comments
if line.startswith('#'):
continue
# parse the header
elif line[0].isalnum():
key = line.strip().replace(':', '')
current_key = key
data[current_key] = {}
# parse the key: value line
elif line[0].isspace():
values = line.strip().split(':')
if len(values) == 2:
cval = values[1].strip()
if cval == '0':
cval = False
elif cval == '1':
cval = True
data[current_key][values[0].strip()] = cval
return data
def python_2_unicode_compatible(klass):
"""
A decorator that defines __unicode__ and __str__ methods under Python 2.
Under Python 3 it does nothing.
To support Python 2 and 3 with a single code base, define a __str__ method
returning text and apply this decorator to the class.
"""
if sys.version_info[0] < 3:
if '__str__' not in klass.__dict__:
raise ValueError("@python_2_unicode_compatible cannot be applied "
"to %s because it doesn't define __str__()." %
klass.__name__)
klass.__unicode__ = klass.__str__
klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
return klass
def get_dom_tree(xml):
tree = ET.fromstring(xml)
return tree.getroottree().getroot()
def attribute_check(root):
attrs = []
value = None
if isinstance(root, dict):
if '#text' in root:
value = root['#text']
if '@attrs' in root:
for ak, av in sorted(root.pop('@attrs').items()):
attrs.append(str('{0}="{1}"').format(ak, smart_encode(av)))
return attrs, value
def smart_encode(value):
try:
if sys.version_info[0] < 3:
return str(value).encode('utf-8')
else:
return value
except UnicodeDecodeError:
return value
def to_xml(root):
return dict2xml(root)
def dict2xml(root):
xml = str('')
if root is None:
return xml
if isinstance(root, dict):
for key in sorted(root.keys()):
if isinstance(root[key], dict):
attrs, value = attribute_check(root[key])
if not value:
value = dict2xml(root[key])
elif isinstance(value, dict):
value = dict2xml(value)
attrs_sp = str('')
if len(attrs) > 0:
attrs_sp = str(' ')
xml = str('{xml}<{tag}{attrs_sp}{attrs}>{value}</{tag}>') \
.format(**{'tag': key, 'xml': str(xml), 'attrs': str(' ').join(attrs),
'value': smart_encode(value), 'attrs_sp': attrs_sp})
elif isinstance(root[key], list):
for item in root[key]:
attrs, value = attribute_check(item)
if not value:
value = dict2xml(item)
elif isinstance(value, dict):
value = dict2xml(value)
attrs_sp = ''
if len(attrs) > 0:
attrs_sp = ' '
xml = str('{xml}<{tag}{attrs_sp}{attrs}>{value}</{tag}>') \
.format(**{'xml': str(xml), 'tag': key, 'attrs': ' '.join(attrs), 'value': smart_encode(value),
'attrs_sp': attrs_sp})
else:
value = root[key]
xml = str('{xml}<{tag}>{value}</{tag}>') \
.format(**{'xml': str(xml), 'tag': key, 'value': smart_encode(value)})
elif isinstance(root, str) or isinstance(root, int) \
or isinstance(root, str) or isinstance(root, int) \
or isinstance(root, float):
xml = str('{0}{1}').format(str(xml), root)
else:
raise Exception('Unable to serialize node of type %s (%s)' % \
(type(root), root))
return xml
def getValue(response_dict, *args, **kwargs):
args_a = [w for w in args]
first = args_a[0]
args_a.remove(first)
h = kwargs.get('mydict', {})
if h:
h = h.get(first, {})
else:
h = response_dict.get(first, {})
if len(args) == 1:
try:
return h.get('value', None)
except:
return h
last = args_a.pop()
for a in args_a:
h = h.get(a, {})
h = h.get(last, {})
try:
return h.get('value', None)
except:
return h
def getNodeText(node):
"Returns the node's text string."
rc = []
if hasattr(node, 'childNodes'):
for cn in node.childNodes:
if cn.nodeType == cn.TEXT_NODE:
rc.append(cn.data)
elif cn.nodeType == cn.CDATA_SECTION_NODE:
rc.append(cn.data)
return ''.join(rc)
def perftest_dict2xml():
sample_dict = {
'searchFilter': {'categoryId': {'#text': 222, '@attrs': {'site': 'US'}}},
'paginationInput': {
'pageNumber': '1',
'pageSize': '25'
},
'itemFilter': [
{'name': 'Condition',
'value': 'Used'},
{'name': 'LocatedIn',
'value': 'GB'},
],
'sortOrder': 'StartTimeNewest'
}
xml = dict2xml(sample_dict)
if __name__ == '__main__':
import timeit
import doctest
failure_count, test_count = doctest.testmod()
sys.exit(failure_count)

View File

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

View File

@@ -0,0 +1,343 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from lxml.etree import fromstring
from datetime import datetime, date, timedelta
from lxml import etree
from odoo.tools.zeep import Client, Plugin
from odoo.tools.zeep.wsdl.utils import etree_to_string
from odoo import _
from odoo import release
from odoo.exceptions import UserError
from odoo.tools import float_repr, float_round
from odoo.tools.misc import file_path
class DHLProvider():
def __init__(self, debug_logger, request_type='ship', prod_environment=False):
self.debug_logger = debug_logger
if not prod_environment:
self.url = 'https://xmlpitest-ea.dhl.com/XMLShippingServlet?isUTF8Support=true'
else:
self.url = 'https://xmlpi-ea.dhl.com/XMLShippingServlet?isUTF8Support=true'
if request_type == "ship":
self.client = self._set_client('ship-10.0.wsdl', 'Ship')
self.factory = self.client.type_factory('ns1')
elif request_type =="rate":
self.client = self._set_client('rate.wsdl', 'Rate')
self.factory = self.client.type_factory('ns1')
self.factory_dct_request = self.client.type_factory('ns2')
self.factory_dct_response = self.client.type_factory('ns3')
def _set_client(self, wsdl_filename, api):
wsdl_path = file_path(f'fusion_shipping/api/dhl/wsdl/{wsdl_filename}')
client = Client(wsdl_path)
return client
def _set_request(self, site_id, password):
request = self.factory.Request()
service_header = self.factory.ServiceHeader()
service_header.MessageTime = datetime.now()
service_header.MessageReference = 'ref:' + datetime.now().isoformat() #CHANGEME
service_header.SiteID = site_id
service_header.Password = password
request.ServiceHeader = service_header
metadata = self.factory.MetaData()
metadata.SoftwareName = release.product_name
metadata.SoftwareVersion = release.series
request.MetaData = metadata
return request
def _set_region_code(self, region_code):
return region_code
def _set_requested_pickup_time(self, requested_pickup):
if requested_pickup:
return "Y"
else:
return "N"
def _set_billing(self, shipper_account, payment_type, duty_payment_type, is_dutiable):
billing = self.factory.Billing()
billing.ShipperAccountNumber = shipper_account
billing.ShippingPaymentType = payment_type
if is_dutiable:
billing.DutyPaymentType = duty_payment_type
return billing
def _set_consignee(self, partner_id):
consignee = self.factory.Consignee()
consignee.CompanyName = partner_id.commercial_company_name or partner_id.name
consignee.AddressLine1 = partner_id.street or partner_id.street2
consignee.AddressLine2 = partner_id.street and partner_id.street2 or None
consignee.City = partner_id.city
if partner_id.state_id:
consignee.Division = partner_id.state_id.name
consignee.DivisionCode = partner_id.state_id.code
consignee.PostalCode = partner_id.zip
consignee.CountryCode = partner_id.country_id.code
consignee.CountryName = partner_id.country_id.name
contact = self.factory.Contact()
contact.PersonName = partner_id.name
contact.PhoneNumber = partner_id.phone
if partner_id.email:
contact.Email = partner_id.email
consignee.Contact = contact
return consignee
def _set_dct_to(self, partner_id):
to = self.factory_dct_request.DCTTo()
country_code = partner_id.country_id.code
zip_code = partner_id.zip or ''
if country_code == 'ES' and (zip_code.startswith('35') or zip_code.startswith('38')):
country_code = 'IC'
to.CountryCode = country_code
to.Postalcode = zip_code
to.City = partner_id.city
return to
def _set_shipper(self, account_number, company_partner_id, warehouse_partner_id):
shipper = self.factory.Shipper()
shipper.ShipperID = account_number
shipper.CompanyName = company_partner_id.name
shipper.AddressLine1 = warehouse_partner_id.street or warehouse_partner_id.street2
shipper.AddressLine2 = warehouse_partner_id.street and warehouse_partner_id.street2 or None
shipper.City = warehouse_partner_id.city
if warehouse_partner_id.state_id:
shipper.Division = warehouse_partner_id.state_id.name
shipper.DivisionCode = warehouse_partner_id.state_id.code
shipper.PostalCode = warehouse_partner_id.zip
shipper.CountryCode = warehouse_partner_id.country_id.code
shipper.CountryName = warehouse_partner_id.country_id.name
contact = self.factory.Contact()
contact.PersonName = warehouse_partner_id.name
contact.PhoneNumber = warehouse_partner_id.phone
if warehouse_partner_id.email:
contact.Email = warehouse_partner_id.email
shipper.Contact = contact
return shipper
def _set_dct_from(self, warehouse_partner_id):
dct_from = self.factory_dct_request.DCTFrom()
dct_from.CountryCode = warehouse_partner_id.country_id.code
dct_from.Postalcode = warehouse_partner_id.zip
dct_from.City = warehouse_partner_id.city
return dct_from
def _set_dutiable(self, total_value, currency_name, incoterm):
dutiable = self.factory.Dutiable()
dutiable.DeclaredValue = float_repr(total_value, 2)
dutiable.DeclaredCurrency = currency_name
if not incoterm:
raise UserError(_("Please define an incoterm in the associated sale order or set a default incoterm for the company in the accounting's settings."))
dutiable.TermsOfTrade = incoterm.code
return dutiable
def _set_dct_dutiable(self, total_value, currency_name):
dct_dutiable = self.factory_dct_request.DCTDutiable()
dct_dutiable.DeclaredCurrency = currency_name
dct_dutiable.DeclaredValue = total_value
return dct_dutiable
def _set_dct_bkg_details(self, carrier, packages):
bkg_details = self.factory_dct_request.BkgDetailsType()
bkg_details.PaymentCountryCode = packages[0].company_id.partner_id.country_id.code
bkg_details.Date = date.today()
bkg_details.ReadyTime = timedelta(hours=1,minutes=2)
bkg_details.DimensionUnit = "CM" if carrier.dhl_package_dimension_unit == "C" else "IN"
bkg_details.WeightUnit = "KG" if carrier.dhl_package_weight_unit == "K" else "LB"
bkg_details.InsuredValue = float_repr(sum(pkg.total_cost for pkg in packages) * carrier.shipping_insurance / 100, precision_digits=3)
bkg_details.InsuredCurrency = packages[0].currency_id.name
pieces = []
for sequence, package in enumerate(packages):
piece = self.factory_dct_request.PieceType()
piece.PieceID = sequence
piece.PackageTypeCode = package.packaging_type
piece.Height = package.dimension['height']
piece.Depth = package.dimension['length']
piece.Width = package.dimension['width']
piece.Weight = carrier._dhl_convert_weight(package.weight, carrier.dhl_package_weight_unit)
pieces.append(piece)
bkg_details.Pieces = {'Piece': pieces}
bkg_details.PaymentAccountNumber = carrier.sudo().dhl_account_number
if carrier.dhl_dutiable:
bkg_details.IsDutiable = "Y"
else:
bkg_details.IsDutiable = "N"
bkg_details.NetworkTypeCode = "AL"
return bkg_details
def _set_shipment_details(self, picking):
shipment_details = self.factory.ShipmentDetails()
pieces = []
packages = picking.carrier_id._get_packages_from_picking(picking, picking.carrier_id.dhl_default_package_type_id)
for sequence, package in enumerate(packages):
piece = self.factory.Piece()
piece.PieceID = sequence
piece.Height = package.dimension['height']
piece.Depth = package.dimension['length']
piece.Width = package.dimension['width']
piece.Weight = picking.carrier_id._dhl_convert_weight(package.weight, picking.carrier_id.dhl_package_weight_unit)
piece.PieceContents = package.name
pieces.append(piece)
shipment_details.Pieces = self.factory.Pieces(pieces)
shipment_details.WeightUnit = picking.carrier_id.dhl_package_weight_unit
shipment_details.GlobalProductCode = picking.carrier_id.dhl_product_code
shipment_details.LocalProductCode = picking.carrier_id.dhl_product_code
shipment_details.Date = date.today()
shipment_details.Contents = "MY DESCRIPTION"
shipment_details.DimensionUnit = picking.carrier_id.dhl_package_dimension_unit
shipment_details.InsuredAmount = float_repr(sum(pkg.total_cost for pkg in packages) * picking.carrier_id.shipping_insurance / 100, precision_digits=2)
if picking.carrier_id.dhl_dutiable:
shipment_details.IsDutiable = "Y"
sale = picking.reference_ids.sale_ids
currency = sale and sale[0].currency_id or picking.company_id.currency_id
shipment_details.CurrencyCode = currency.name
return shipment_details
def _set_label_image_format(self, label_image_format):
return label_image_format
def _set_label(self, label):
label_obj = self.factory.Label()
label_obj.LabelTemplate = label
return label_obj
def _set_return(self):
return_service = self.factory.SpecialService()
return_service.SpecialServiceType = "PV"
return return_service
def _set_insurance(self, shipment_details):
insurance_service = self.factory.SpecialService()
insurance_service.SpecialServiceType = "II"
insurance_service.ChargeValue = shipment_details.InsuredAmount
insurance_service.CurrencyCode = shipment_details.CurrencyCode
return insurance_service
def _process_shipment(self, shipment_request):
ShipmentRequest = self.client._Client__obj.get_element('ns0:ShipmentRequest')
document = etree.Element('root')
ShipmentRequest.render(document, shipment_request)
request_to_send = etree_to_string(list(document)[0])
headers = {'Content-Type': 'text/xml'}
response = self.client._Client__obj.transport.post(self.url, request_to_send, headers=headers)
if self.debug_logger:
self.debug_logger(request_to_send, 'dhl_shipment_request')
self.debug_logger(response.content, 'dhl_shipment_response')
response_element_xml = fromstring(response.content)
Response = self.client._Client__obj.get_element(response_element_xml.tag)
response_zeep = Response.type.parse_xmlelement(response_element_xml)
dict_response = {'tracking_number': 0.0,
'price': 0.0,
'currency': False}
# This condition handle both 'ShipmentValidateErrorResponse' and
# 'ErrorResponse', we could handle them differently if needed as
# the 'ShipmentValidateErrorResponse' is something you cannot do,
# and 'ErrorResponse' are bad values given in the request.
if hasattr(response_zeep.Response, 'Status'):
condition = response_zeep.Response.Status.Condition[0]
error_msg = "%s: %s" % (condition.ConditionCode, condition.ConditionData)
raise UserError(error_msg)
return response_zeep
def _process_rating(self, rating_request):
DCTRequest = self.client._Client__obj.get_element('ns0:DCTRequest')
document = etree.Element('root')
DCTRequest.render(document, rating_request)
request_to_send = etree_to_string(list(document)[0])
headers = {'Content-Type': 'text/xml'}
response = self.client._Client__obj.transport.post(self.url, request_to_send, headers=headers)
if self.debug_logger:
self.debug_logger(request_to_send, 'dhl_rating_request')
self.debug_logger(response.content, 'dhl_rating_response')
response_element_xml = fromstring(response.content)
dict_response = {'tracking_number': 0.0,
'price': 0.0,
'currency': False}
# This condition handle both 'ShipmentValidateErrorResponse' and
# 'ErrorResponse', we could handle them differently if needed as
# the 'ShipmentValidateErrorResponse' is something you cannot do,
# and 'ErrorResponse' are bad values given in the request.
if response_element_xml.find('GetQuoteResponse') is not None:
return response_element_xml
else:
condition = response_element_xml.find('Response/Status/Condition')
error_msg = "%s: %s" % (condition.find('ConditionCode').text, condition.find('ConditionData').text)
raise UserError(error_msg)
def check_required_value(self, carrier, recipient, shipper, order=False, picking=False):
carrier = carrier.sudo()
recipient_required_field = ['city', 'zip', 'country_id']
if not carrier.dhl_SiteID:
return _("DHL Site ID is missing, please modify your delivery method settings.")
if not carrier.dhl_password:
return _("DHL password is missing, please modify your delivery method settings.")
if not carrier.dhl_account_number:
return _("DHL account number is missing, please modify your delivery method settings.")
# The street isn't required if we compute the rate with a partial delivery address in the
# express checkout flow.
if not recipient.street and not recipient.street2 and not recipient.env.context.get(
'express_checkout_partial_delivery_address', False
):
recipient_required_field.append('street')
res = [field for field in recipient_required_field if not recipient[field]]
if res:
return _("The address of the customer is missing or wrong (Missing field(s) :\n %s)", ", ".join(res).replace("_id", ""))
shipper_required_field = ['city', 'zip', 'phone', 'country_id']
if not shipper.street and not shipper.street2:
shipper_required_field.append('street')
res = [field for field in shipper_required_field if not shipper[field]]
if res:
return _("The address of your company warehouse is missing or wrong (Missing field(s) :\n %s)", ", ".join(res).replace("_id", ""))
if order:
if not order.order_line:
return _("Please provide at least one item to ship.")
error_lines = order.order_line._get_invalid_delivery_weight_lines()
if error_lines:
return _("The estimated shipping price cannot be computed because the weight is missing for the following product(s): \n %s", ", ".join(error_lines.product_id.mapped('name')))
return False
def _set_export_declaration(self, carrier, picking, is_return=False):
export_lines = []
move_lines = picking.move_line_ids.filtered(lambda line: line.product_id.type == 'consu')
currency_id = picking.sale_id and picking.sale_id.currency_id or picking.company_id.currency_id
for sequence, line in enumerate(move_lines, start=1):
if line.move_id.sale_line_id:
unit_quantity = line.product_uom_id._compute_quantity(line.quantity, line.move_id.sale_line_id.product_uom_id)
else:
unit_quantity = line.product_uom_id._compute_quantity(line.quantity, line.product_id.uom_id)
rounded_qty = max(1, float_round(unit_quantity, precision_digits=0, rounding_method='HALF-UP'))
item = self.factory.ExportLineItem()
item.LineNumber = sequence
item.Quantity = int(rounded_qty)
item.QuantityUnit = 'PCS' # Pieces - very generic
if len(line.product_id.name) > 75:
raise UserError(_("DHL doesn't support products with name greater than 75 characters."))
item.Description = line.product_id.name
item.Value = float_repr(line.sale_price / rounded_qty, currency_id.decimal_places)
item.Weight = item.GrossWeight = {
"Weight": carrier._dhl_convert_weight(line.product_id.weight, carrier.dhl_package_weight_unit),
"WeightUnit": carrier.dhl_package_weight_unit,
}
item.ManufactureCountryCode = line.product_id.country_of_origin.code or line.picking_id.picking_type_id.warehouse_id.partner_id.country_id.code
if line.product_id.hs_code:
item.ImportCommodityCode = line.product_id.hs_code
item.CommodityCode = line.product_id.hs_code
export_lines.append(item)
export_declaration = self.factory.ExportDeclaration()
export_declaration.InvoiceDate = datetime.today()
export_declaration.InvoiceNumber = carrier.env['ir.sequence'].sudo().next_by_code('delivery_dhl.commercial_invoice')
if is_return:
export_declaration.ExportReason = 'RETURN'
export_declaration.ExportLineItem = export_lines
if picking.sale_id.client_order_ref:
export_declaration.ReceiverReference = picking.sale_id.client_order_ref
return export_declaration

View File

@@ -0,0 +1,92 @@
<?xml version="1.0"?>
<xsd:schema targetNamespace="http://www.dhl.com" xmlns:dhl="http://www.dhl.com/datatypes" xmlns:dct="http://www.dhl.com/DCTResponsedatatypes" xmlns="http://www.dhl.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="unqualified">
<xsd:import namespace="http://www.dhl.com/datatypes_global" schemaLocation="datatypes_global_v62.xsd" />
<xsd:import namespace="http://www.dhl.com/DCTResponsedatatypes" schemaLocation="DCTResponsedatatypes_global.xsd" />
<xsd:element name="DCTResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="GetQuoteResponse">
<xsd:annotation>
<xsd:documentation>Root element of Quote request
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Response">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>Generic response header</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="ServiceHeader" type="ServiceHeader" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="BkgDetails" minOccurs="0" type="dct:BkgDetailsType" maxOccurs="1" />
<xsd:element name="Srvs" minOccurs="0" maxOccurs="1">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Srv" type="dct:SrvType" minOccurs="0" maxOccurs="unbounded">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Note" minOccurs="0" type="dct:NoteType" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="GetCapabilityResponse">
<xsd:annotation>
<xsd:documentation>Root element of Capability request
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Response">
<xsd:complexType>
<xsd:annotation>
<xsd:documentation>Generic response header</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="ServiceHeader" type="ServiceHeader" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="BkgDetails" minOccurs="0" type="dct:BkgDetailsType" maxOccurs="1" />
<xsd:element name="Srvs" minOccurs="0" maxOccurs="1">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Srv" type="dct:SrvType" minOccurs="0" maxOccurs="unbounded">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Note" minOccurs="0" type="dct:NoteType" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="ServiceHeader">
<xsd:annotation>
<xsd:documentation>Standard routing header</xsd:documentation>
</xsd:annotation>
<xsd:sequence>
<xsd:element name="MessageTime" type="xsd:dateTime" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Time this message is sent</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="MessageReference" type="xsd:string" minOccurs="0">
<xsd:annotation>
<xsd:documentation>A string, peferably number, to uniquely identify individual messages. Minimum length must be 28 and maximum length is 32</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="SiteID" type="xsd:string" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,47 @@
<?xml version="1.0"?>
<xsd:schema targetNamespace="http://www.dhl.com" xmlns:dhl="http://www.dhl.com/datatypes_global" xmlns="http://www.dhl.com" xmlns:dct="http://www.dhl.com/DCTRequestdatatypes" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="unqualified">
<xsd:import namespace="http://www.dhl.com/datatypes_global" schemaLocation="datatypes_global_v62.xsd" />
<xsd:import namespace="http://www.dhl.com/DCTRequestdatatypes" schemaLocation="DCTRequestdatatypes_global.xsd" />
<xsd:element name="DCTRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:choice minOccurs="1" maxOccurs="1">
<xsd:element name="GetQuote">
<xsd:annotation>
<xsd:documentation>Root element of Quote request
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Request" type="dhl:Request" />
<xsd:element name="From" type="dct:DCTFrom" minOccurs="1" />
<xsd:element name="BkgDetails" minOccurs="1" type="dct:BkgDetailsType" />
<xsd:element name="To" minOccurs="1" type="dct:DCTTo" />
<xsd:element name="Dutiable" minOccurs="0" type="dct:DCTDutiable" />
<xsd:element name="GenReq" minOccurs="0" type="dct:GenReq" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="GetCapability">
<xsd:annotation>
<xsd:documentation>Root element of Capability request
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Request" type="dhl:Request" />
<xsd:element name="From" type="dct:DCTFrom" minOccurs="1" />
<xsd:element name="BkgDetails" minOccurs="1" type="dct:BkgDetailsType" />
<xsd:element name="To" minOccurs="1" type="dct:DCTTo" />
<xsd:element name="Dutiable" minOccurs="0" type="dct:DCTDutiable" />
<xsd:element name="GenReq" minOccurs="0" type="dct:GenReq" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:sequence>
<xsd:attribute name="schemaVersion" type="xsd:decimal" use="required" fixed="2.0" />
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,449 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.dhl.com/DCTRequestdatatypes" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.dhl.com/DCTRequestdatatypes" elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<xsd:element name="DCTRequestDataTypes">
<xsd:annotation>
<xsd:documentation>Comment describing your root element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="DCTFrom">
<xsd:sequence>
<xsd:element name="CountryCode" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="2" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Postalcode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="12" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="City" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="45" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Suburb" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="45" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BkgDetailsType">
<xsd:sequence>
<xsd:element name="PaymentCountryCode" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="2" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Date" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:date" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="ReadyTime">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>Time in hours and minutes (HH:MM)</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:duration" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="ReadyTimeGMTOffset" minOccurs="0">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Time in hours and minutes (HH:MM)
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:minLength value="0"></xsd:minLength>
<xsd:maxLength value="6"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DimensionUnit" minOccurs="1">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Dimension Unit I (inches);Centimeters (CM)
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="IN" />
<xsd:enumeration value="CM" />
<xsd:maxLength value="3"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightUnit" minOccurs="1">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Kilogram (KG),Pounds (LB)
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="KG" />
<xsd:enumeration value="LB" />
<xsd:maxLength value="3"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="NumberOfPieces" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:positiveInteger">
<xsd:minInclusive value="1" />
<xsd:maxInclusive value="999" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ShipmentWeight" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="15" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Volume" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="15" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="MaxPieceWeight" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="15" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="MaxPieceHeight" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="10" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="MaxPieceDepth" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="10" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="MaxPieceWidth" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="10" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Pieces" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Piece" type="PieceType" maxOccurs="999" minOccurs="1">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="PaymentAccountNumber" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="12"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="IsDutiable" minOccurs="0">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Y - Dutiable/Non-Doc,
N - Non-dutiable/Doc
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
<xsd:enumeration value="Y" />
<xsd:enumeration value="N" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="NetworkTypeCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="2" />
<xsd:enumeration value="DD" />
<xsd:enumeration value="TD" />
<xsd:enumeration value="AL" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="QtdShp" minOccurs="0" maxOccurs="unbounded" type="QtdShpType" />
<xsd:element name="InsuredValue" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="InsuredCurrency" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3"></xsd:length>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="PaymentType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Payment type - by method of payment ( DHL account)</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:enumeration value="D" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="AcctPickupCloseTime" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Account's Pickup Close Time to be retrieved from GCDB or specified by customer</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:dateTime"/>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DCTTo">
<xsd:sequence>
<xsd:element name="CountryCode" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="2" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Postalcode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="12" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="City" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="45" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Suburb" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="45" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DCTDutiable">
<xsd:sequence>
<xsd:element name="DeclaredCurrency" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DeclaredValue" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:float">
<xsd:minInclusive value="0.000" />
<xsd:maxInclusive value="999999999999999999.999" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PieceType">
<xsd:sequence>
<xsd:element name="PieceID" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[0-9]+"></xsd:pattern>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="PackageTypeCode" default="BOX" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
<xsd:enumeration value="FLY" />
<xsd:enumeration value="COY" />
<xsd:enumeration value="NCY" />
<xsd:enumeration value="PAL" />
<xsd:enumeration value="DBL" />
<xsd:enumeration value="BOX" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Height" minOccurs="0">
<xsd:annotation>
<xsd:documentation>required if width and depth are specified</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="10" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Depth" minOccurs="0">
<xsd:annotation>
<xsd:documentation>required if width and height are specified</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="10" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Width" minOccurs="0">
<xsd:annotation>
<xsd:documentation>required if height and depth are specified</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="10" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Weight" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="15" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="QtdShpType">
<xsd:sequence>
<xsd:element name="GlobalProductCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z0-9]+"></xsd:pattern>
<xsd:minLength value="0"></xsd:minLength>
<xsd:maxLength value="6"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="LocalProductCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:minLength value="0"></xsd:minLength>
<xsd:maxLength value="6"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="QtdShpExChrg" minOccurs="0" maxOccurs="unbounded" type="QtdShpExChrgType">
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="QtdShpExChrgType">
<xsd:sequence>
<xsd:element name="SpecialServiceType" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="6"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="LocalSpecialServiceType" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="3"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="GenReq">
<xsd:sequence>
<xsd:element name="OSINFO" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
<xsd:enumeration value="Y" />
<xsd:enumeration value="N" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="NXTPU" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
<xsd:enumeration value="Y" />
<xsd:enumeration value="N" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="FCNTWTYCD" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="2" />
<xsd:enumeration value="DD" />
<xsd:enumeration value="TD" />
<xsd:enumeration value="AL" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CUSTAGRIND" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
<xsd:enumeration value="Y" />
<xsd:enumeration value="N" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="VLDTRT_DD" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
<xsd:enumeration value="Y" />
<xsd:enumeration value="N" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,876 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.dhl.com/DCTResponsedatatypes" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.dhl.com/DCTResponsedatatypes" elementFormDefault="unqualified"
attributeFormDefault="unqualified">
<xsd:element name="DCTResponseDataTypes">
<xsd:annotation>
<xsd:documentation>Comment describing your root element
</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:complexType name="OrgnSvcAreaType">
<xsd:sequence>
<xsd:element name="FacilityCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ServiceAreaCode" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DestSvcAreaType">
<xsd:sequence>
<xsd:element name="FacilityCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ServiceAreaCode" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BkgDetailsType">
<xsd:sequence>
<xsd:element name="QtdShp" minOccurs="0" maxOccurs="unbounded" type="QtdShpType" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="SrvCombType">
<xsd:sequence>
<xsd:element name="GlobalServiceName" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="45" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="GlobalServiceCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="6" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="LocalServiceCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="LocalServiceTypeName" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="45" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeCodeType" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
<xsd:enumeration value="FEE" />
<xsd:enumeration value="SCH" />
<xsd:enumeration value="XCH" />
<xsd:enumeration value="NRI" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="SOfferedCustAgreement" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="SrvComb" minOccurs="0">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Prod" minOccurs="0" type="ProdType" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ProdType">
<xsd:sequence>
<xsd:element name="VldSrvComb" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="SpecialServiceType" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<!-- xsd:element name="VldMrkSrvComb" minOccurs="0" maxOccurs="unbounded"> <xsd:complexType> <xsd:sequence> <xsd:element name="LocalChargeCode" type="xsd:string" minOccurs="0" maxOccurs="1"> </xsd:element>
</xsd:sequence> </xsd:complexType> </xsd:element -->
<xsd:element name="LocalServiceType" type="xsd:string" minOccurs="0" maxOccurs="unbounded">
</xsd:element>
<xsd:element name="CombRSrv" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="RestrictedSpecialServiceType" minOccurs="0" type="xsd:string" maxOccurs="1">
</xsd:element>
<xsd:element name="RestrictedLocalServiceType" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="TotalDiscount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NoteType">
<xsd:sequence>
<xsd:element name="ActionStatus" type="xsd:string" minOccurs="0" maxOccurs="1"/>
<xsd:element name="Condition" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ConditionCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:minLength value="0"></xsd:minLength>
<xsd:maxLength value="10"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ConditionData" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="QtdShpExChrgType">
<xsd:sequence>
<xsd:element name="SpecialServiceType" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="6"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="LocalServiceType" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="3"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="GlobalServiceName" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<xsd:element name="LocalServiceTypeName" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<xsd:element name="SOfferedCustAgreement" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="ChargeCodeType" type="xsd:string" minOccurs="0"></xsd:element>
<xsd:element name="InsPrmRateInPercentage" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="8" />
<xsd:fractionDigits value="4" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeValue" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeTaxAmount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeTaxRate" minOccurs="0" maxOccurs="unbounded">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="6" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<!-- Added for Brazil DCT change -->
<xsd:element name="ChargeTaxAmountDet" minOccurs="0" type="ChargeTaxAmountDetType" maxOccurs="unbounded" />
<xsd:element name="QtdSExtrChrgInAdCur" minOccurs="0" type="QtdSExtrChrgInAdCurType" maxOccurs="unbounded" />
<!-- Added for Brazil DCT change -->
</xsd:sequence>
</xsd:complexType>
<!-- Start:Added for Brazil DCT changes -->
<xsd:complexType name="WeightChargeTaxDetType">
<xsd:sequence>
<xsd:element name="TaxTypeRate" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="8" />
<xsd:fractionDigits value="6" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="TaxTypeCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="6"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightChargeTax" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="BaseAmt" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ChargeTaxAmountDetType">
<xsd:sequence>
<xsd:element name="TaxTypeRate" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="8" />
<xsd:fractionDigits value="6" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="TaxTypeCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="6"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="TaxAmount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="BaseAmount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="QtdSInAdCurType">
<xsd:sequence>
<xsd:element name="CustomsValue" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ExchangeRate" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="6" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyRoleTypeCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="5" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightCharge" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="TotalAmount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="TotalTaxAmount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightChargeTax" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightChargeTaxDet" minOccurs="0" type="WeightChargeTaxDetType" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="QtdSExtrChrgInAdCurType">
<xsd:sequence>
<xsd:element name="ChargeValue" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeExchangeRate" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="6" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeTaxAmount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeTaxRate" minOccurs="0" maxOccurs="unbounded">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="6" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyRoleTypeCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="5" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeTaxAmountDet" minOccurs="0" type="ChargeTaxAmountDetType" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
<!-- End:Added for Brazil DCT changes -->
<xsd:complexType name="QtdShpType">
<xsd:sequence>
<xsd:element name="OriginServiceArea" minOccurs="1" maxOccurs="1" type="OrgnSvcAreaType" />
<xsd:element name="DestinationServiceArea" minOccurs="1" maxOccurs="1" type="DestSvcAreaType" />
<xsd:element name="GlobalProductCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="6"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="LocalProductCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="3"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ProductShortName" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<xsd:element name="LocalProductName" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<xsd:element name="NetworkTypeCode" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<xsd:element name="POfferedCustAgreement" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<xsd:element name="TransInd" type="xsd:string" minOccurs="0" maxOccurs="1"></xsd:element>
<xsd:element name="PickupDate" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:date" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="PickupCutoffTime" type="xsd:string" minOccurs="0" maxOccurs="1"></xsd:element>
<xsd:element name="BookingTime" minOccurs="0">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Booking Time
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:duration" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ExchangeRate" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="6" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightCharge" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightChargeTax" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="weightChargeTaxRate" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="6" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="TotalTransitDays" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:int"></xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="PickupPostalLocAddDays" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:int"></xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DeliveryPostalLocAddDays" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:int"></xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="PickupNonDHLCourierCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DeliveryNonDHLCourierCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DeliveryDate" minOccurs="0" maxOccurs="unbounded" type="DeliveryDate" />
<xsd:element name="DeliveryTime" minOccurs="0">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Delivery Time
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:duration" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="DeliveryTimeGMTOffset" minOccurs="0">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>
Delivery Time GMT Offset
</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="6" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DimensionalWeight" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="15" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightUnit" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="3"></xsd:maxLength>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="PickupDayOfWeekNum" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DestinationDayOfWeekNum" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="QuotedWeight" type="QuotedWeight" minOccurs="0" />
<xsd:element name="QuotedWeightUOM" type="QuotedWeightUOM" minOccurs="0" />
<xsd:element name="QtdShpExChrg" minOccurs="0" type="QtdShpExChrgType" maxOccurs="unbounded" />
<xsd:element name="PricingDate" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:date" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="ShippingCharge" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="TotalTaxAmount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="TotalDiscount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<!-- Added for Brazil DCT changes -->
<xsd:element name="QtdSInAdCur" minOccurs="0" type="QtdSInAdCurType" maxOccurs="unbounded" />
<xsd:element name="WeightChargeTaxDet" minOccurs="0" type="WeightChargeTaxDetType" maxOccurs="unbounded" />
<!-- End : Added for Brazil DCT changes -->
<xsd:element name="PickupWindowEarliestTime" minOccurs="1">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>Pickup window start time</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="PickupWindowLatestTime" minOccurs="1">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>Pickup window end time</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="BookingCutoffOffset" minOccurs="1">
<xsd:simpleType>
<xsd:annotation>
<xsd:documentation>Booking cut off time offset</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string" />
</xsd:simpleType>
</xsd:element>
<xsd:element name="PickupLeadTime" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="PickupCloseTime" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="WeightChargeDisc" minOccurs="0" type="WeightChargeDisc" maxOccurs="unbounded" />
<xsd:element name="QtdShpExChrgDisc" minOccurs="0" type="QtdShpExChrgDisc" maxOccurs="unbounded" />
<!-- <xsd:element name="QtdShpExChrg" minOccurs="0" type="QtdShpExChrg" /> -->
</xsd:sequence>
</xsd:complexType>
<xsd:simpleType name="QuotedWeight">
<xsd:annotation>
<xsd:documentation>Weight of piece or shipment</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:decimal">
<xsd:fractionDigits value="3" />
<xsd:minInclusive value="0.000" />
<xsd:maxInclusive value="999999.999" />
<xsd:totalDigits value="10" />
</xsd:restriction>
</xsd:simpleType>
<xsd:simpleType name="QuotedWeightUOM">
<xsd:annotation>
<xsd:documentation>WeightUOM</xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:minLength value="1" />
<xsd:maxLength value="3" />
<xsd:enumeration value="KG" />
<xsd:enumeration value="Lbs" />
</xsd:restriction>
</xsd:simpleType>
<xsd:complexType name="MrkSrvType">
<xsd:sequence>
<xsd:choice>
<xsd:element name="LocalProductCode" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="LocalServiceType" type="xsd:string" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<xsd:choice>
<xsd:element name="ProductShortName" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="GlobalServiceName" type="xsd:string" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<xsd:choice>
<xsd:element name="LocalProductName" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="LocalServiceTypeName" type="xsd:string" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<xsd:choice>
<!-- Added for Brazil DCT change -->
<xsd:element name="ProductDesc" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="ServiceDesc" type="xsd:string" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<!-- Added for Brazil DCT change -->
<xsd:element name="NetworkTypeCode" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<xsd:choice>
<xsd:element name="POfferedCustAgreement" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="SOfferedCustAgreement" type="xsd:string" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<xsd:element name="TransInd" type="xsd:string" minOccurs="0" maxOccurs="1">
</xsd:element>
<xsd:element name="ChargeCodeType" type="xsd:string" minOccurs="0" maxOccurs="unbounded">
</xsd:element>
<!--Start: Added for Brazil DCT change -->
<xsd:element name="MrkSrvInd" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<!--End: Added for Brazil DCT change -->
<xsd:element name="LocalProductCtryCd" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="2" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="LocalProductDesc" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="GlobalProductDesc" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="GlobalServiceType" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="BillingServiceIndicator" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="LocalServiceName" type="xsd:string" minOccurs="0" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ProdNtwrkType">
<xsd:sequence>
<xsd:element name="NetworkTypeCode" minOccurs="1">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="2" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="SrvType">
<xsd:sequence>
<xsd:element name="GlobalProductCode" type="xsd:string" minOccurs="1" maxOccurs="1">
</xsd:element>
<xsd:element name="MrkSrv" type="MrkSrvType" minOccurs="0" maxOccurs="unbounded">
</xsd:element>
<xsd:element name="SBTP" type="SBTPType" minOccurs="0" maxOccurs="1"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="SBTPType">
<xsd:sequence>
<xsd:element name="Prod" type="ProdType" minOccurs="0" maxOccurs="1"></xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DeliveryDate">
<xsd:sequence>
<xsd:element name="DeliveryType" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="DlvyDateTime" type="xsd:string" minOccurs="0" maxOccurs="1" />
<xsd:element name="DeliveryDateTimeOffset" type="xsd:string" minOccurs="0" maxOccurs="1" />
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="WeightChargeDisc">
<xsd:sequence>
<xsd:element name="DiscAmt" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="BaseAmount" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DiscType" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="1" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DiscPercentage" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="QtdShpExChrgDisc">
<xsd:sequence>
<xsd:element name="DiscAmt" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="5" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="BaseAmt" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="CurrencyRoleTypeCode" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:length value="5" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="DiscPercentage" minOccurs="0">
<xsd:simpleType>
<xsd:restriction base="xsd:decimal">
<xsd:totalDigits value="18" />
<xsd:fractionDigits value="3" />
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.dhl.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.dhl.com"
xmlns:dhl="http://www.dhl.com/datatypes_global" elementFormDefault="unqualified">
<xsd:import namespace="http://www.dhl.com/datatypes_global"
schemaLocation="datatypes_global_v62.xsd" />
<xsd:element name="ErrorResponse">
<xsd:annotation>
<xsd:documentation>Generic error response root element
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Response" type="dhl:ErrorResponse" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,9 @@
<definitions name="Ship" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:ns="http://www.dhl.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" targetNamespace="http://www.dhl.com">
<types>
<xsd:schema>
<xsd:import namespace="http://www.dhl.com" schemaLocation="DCT-req_global-2.0.xsd"/>
<xsd:import namespace="http://www.dhl.com" schemaLocation="DCT-Response_global-2.0.xsd"/>
<xsd:import namespace="http://www.dhl.com" schemaLocation="err-res.xsd"/>
</xsd:schema>
</types>
</definitions>

View File

@@ -0,0 +1,10 @@
<definitions name="Ship" xmlns="http://schemas.xmlsoap.org/wsdl/" xmlns:ns="http://www.dhl.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" targetNamespace="http://www.dhl.com">
<types>
<xsd:schema>
<xsd:import namespace="http://www.dhl.com" schemaLocation="ship-val-global-req-10.0.xsd"/>
<xsd:import namespace="http://www.dhl.com" schemaLocation="ship-val-global-res-10.0.xsd"/>
<xsd:import namespace="http://www.dhl.com" schemaLocation="ship-val-err-res-10.0.xsd"/>
<xsd:import namespace="http://www.dhl.com" schemaLocation="err-res.xsd"/>
</xsd:schema>
</types>
</definitions>

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.dhl.com"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.dhl.com"
xmlns:dhl="http://www.dhl.com/datatypes" elementFormDefault="unqualified">
<xsd:import namespace="http://www.dhl.com/datatypes"
schemaLocation="datatypes.xsd" />
<xsd:element name="ShipmentValidateErrorResponse">
<xsd:annotation>
<xsd:documentation>Shipment Validation error response root element
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Response" type="dhl:ErrorResponse" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,212 @@
<?xml version="1.0"?>
<xsd:schema xmlns:dhl="http://www.dhl.com/datatypes_global" xmlns="http://www.dhl.com" xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.dhl.com" elementFormDefault="unqualified">
<xsd:import namespace="http://www.dhl.com/datatypes_global" schemaLocation="datatypes_global_v10.xsd"/>
<xsd:element name="ShipmentRequest">
<xsd:annotation>
<xsd:documentation>Root element of Shipment Validation Global request</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Request" type="dhl:Request">
<xsd:annotation>
<xsd:documentation>The element contains the header information for the message. It is present in both the request and response XML message. The request element contains a complex data type Service Header</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="RegionCode" type="dhl:RegionCode" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The RegionCode element indicates the shipment to be route to the specific region eCom backend. It is a optional field. The valid values are AP, EU and AM</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="RequestedPickupTime" type="dhl:YesNo" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The RequestedPickupTime element indicates whether a pickup time is requested or not. It is a mandatory field. The valid vaues are Y (Yes) and N (No). If the value equals to Y, eCom Backend will return ReadyByTime and CallInTime, which query based on Postcode or City name. This logic only applicable for AM region</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="LanguageCode" type="dhl:LanguageCode" default="en">
<xsd:annotation>
<xsd:documentation>LanguageCode element contains the ISO language code used by the requestor. This element should be declared once in the Shipment validation request message</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="LatinResponseInd" type="dhl:YesNo" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The LatinResponseInd element contains the indication from user whether the response xml will be transliterated to Latin characters. Currently, it is only workable for Cyrillic configured countries</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Billing" type="dhl:Billing">
<xsd:annotation>
<xsd:documentation>The Billing element contains the billing information of the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Consignee" type="dhl:Consignee">
<xsd:annotation>
<xsd:documentation>Consignee element contains the details of the Consignee (Receiver of the shipment). This element should be declared once in the shipment validation request message</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Commodity" type="dhl:Commodity" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>The commodity element identifies the commodity or commodities being shipped. This element should be declared once in the shipment validation request message</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Dutiable" type="dhl:Dutiable" minOccurs="0">
<xsd:annotation>
<xsd:documentation>For non-domestic shipments, the Dutiable element provides information which defines the types of duties to be levied</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="UseDHLInvoice" type="dhl:YesNo" minOccurs="0" default="N">
<xsd:annotation>
<xsd:documentation>UseDHLInvoice element is an optional field. By providing UseDHLInvoice field value of Y, Shipment Validation service will generate DHL Custom Invoice image. With value of N, this means customer will use their own custom invoice for shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DHLInvoiceLanguageCode" type="dhl:InvLanguageCode" minOccurs="0" default="en">
<xsd:annotation>
<xsd:documentation>DHLInvoiceLanguageCode element is an optional field. This field indicates the DHL custom invoice language code. Default language code is en (English)</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DHLInvoiceType" type="dhl:InvoiceType" minOccurs="0" default="CMI">
<xsd:annotation>
<xsd:documentation>DHLInvoiceType element is an optional field. This field indicates the DHL Custom Invoice type. CMI for Commercial Invoice and PFI for Proforma Invoice</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ExportDeclaration" type="dhl:ExportDeclaration" minOccurs="0">
<xsd:annotation>
<xsd:documentation>For non-domestic shipments, the ExportDeclaration element provides information which is used to aid in the export of a shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Reference" type="dhl:Reference" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>This element identifies the reference information. It is an optional field in the shipment validation request. Only the first reference will be taken currently</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ShipmentDetails" type="dhl:ShipmentDetails">
<xsd:annotation>
<xsd:documentation>The ShipmentDetails element contains the details of the shipment. It must be declared once in the request message</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Shipper" type="dhl:Shipper">
<xsd:annotation>
<xsd:documentation>Shipper element contains the details of the Shipper. This element should be declared once in the Shipment validation Request message</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="SpecialService" type="dhl:SpecialService" minOccurs="0" maxOccurs="10">
<xsd:annotation>
<xsd:documentation>The SpecialService Element provides various special services for the shipment. It is an optional field. Please refer to the Reference Data and use appropriate Service codes enabled for the Country/Region</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Notification" type="dhl:Notification" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The Notification element contains the notification address and customized message to the designated recipient address for the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Place" type="dhl:Place" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The place element contains the address from the shipment has to be picked. This element should be declared once in the request message</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="EProcShip" type="dhl:YesNo" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The EProcShip element indicates whether shipment has to generate waybill or not. It is an optional field. Its value is either Y (Yes For not generating the waybill and not manifest the shipment) or N (No To generate the waybill)</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Airwaybill" type="dhl:AWBNumber" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The Airwaybill element indicates the waybill number of the Paperless Trade (PLT) shipment that will be used for Image Upload service. Note: This is only applicable for Image Upload service</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DocImages" type="dhl:DocImages" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The DocImages element indicates Paperless Trade (PLT) shipment related Commercial Invoice or other supporting document images</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="LabelImageFormat" type="dhl:LabelImageFormat" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The LabelImageFormat element indicates to receive the GLSs generated Transport label and Archive document image in Shipment Validation response XML for the required output format that supported by GLS</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="RequestArchiveDoc" type="dhl:YesNo" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The RequestArchiveDoc element indicates to receive the GLSs generated Archive document image in Shipment Validation response XML for the required output format that supported by GLS. With value of Y, Archive document image will be returned to Shipment Validation response XML if LabelImageFormat element is defined</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="NumberOfArchiveDoc" type="dhl:NumberOfArchiveDoc" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The NumberOfArchiveDoc element indicates the number of archive doc that user wants to generate. With value of 1, one archive document image will be returned to Shipment Validation response XML. With value of 2, two archive document image will be returned</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="RequestQRCode" type="dhl:YesNo" default="N" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The RequestQRCode element indicates for labelless shipment that user wants to generate the QR code. With value of 'Y', it will return the QR code in Shipment Validation response XML. With value of 'N', it will not return QR code in Shipment Validation response XML.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="RequestTransportLabel" type="dhl:YesNo" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The RequestTransportLabel element indicates whether user wants to generate the Transport Label. With value of 'Y', it will return the Transport Label in Shipment Validation response XML. With value of 'N', it will not return Transport Label in Shipment Validation response XML.The RequestTransportLabel element is an optional value to request for Transport Label. This element can be set as N only when requesting for a QRCode in the Shipment Validation response if RequestQRCode = Y ).</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Label" type="dhl:Label" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The Label element defines the required label template, customers logo image plus image format, and DPI resolution</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ODDLinkReq" type="dhl:YesNo" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The ODDLinkReq element indicates to receive the URL link for On Demand Delivery (ODD) page for the specified Waybill number, Shipper Account Number, Origin Service Area Code and Destination Service Area Code in Shipment Validation response XML. With value of Y, URL link for On Demand Delivery (ODD) page will be returned to Shipment Validation response XML if ODDLinkReq element is defined</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DGs" type="dhl:DGs" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The DGs element defines the details of the Dangerous Goods items that included in shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="GetPriceEstimate" type="dhl:YesNo" minOccurs="0" default="Y">
<xsd:annotation>
<xsd:documentation>The GetPriceEstimate element is the option for retrieving the product capability or/and estimatd tariff for the given origin, destination and shipment details. Default option is Yes (Y)</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="SinglePieceImage" type="dhl:YesNo" default="N" minOccurs="0">
<xsd:annotation>
<xsd:documentation>SinglePieceImage element is the option is generate the Transport Label and Waybill Document in single piece output.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ShipmentIdentificationNumber" type="dhl:AWBNumber" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The shipment identification number does not need to be transmitted in the request as the operation will assign a new number and return it in the response. Only used when UseOwnShipmentdentificationNumber set to Y and this feature enabled within customer profile.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="UseOwnShipmentIdentificationNumber" default="N" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Customer able to provide SID if set to Y. The default is N.
Y or 1 = allows you to define your own AWB in the tag above N or 0 = Auto-allocates the AWB from DHL Express</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:maxLength value="1"/>
<xsd:enumeration value="Y"/>
<xsd:enumeration value="N"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="Importer" type="dhl:Importer" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Party that makes (or on whose behalf an agent or broker makes) the import declaration, and who is liable for the payment of duties (if any) on the imported goods. Normally, this party is named either as the consignee in the shipping documents and/or as the buyer in the exporter's invoice.></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Exporter" type="dhl:Exporter" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The party who is responsible for the legality of the shipment under applicable export control laws, which includes determining the proper export classification and authorization needed to ship the Items.The Exporter is usually the party who controls the transaction, acts as declarant in its own name and provides the corresponding instructions for the export, regardless of who files the export declaration. The Exporter may or may not be the Shipper.></xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Seller" type="dhl:Seller" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The party that makes, offers or contracts to make a sale to an actual or potential buyer. Also called vendor.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Payer" type="dhl:Payer" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The party responsible for the full or partial payment of associated charges/cost. There can be many payers related to the different elements linked to a Shipment (e.g Services, fiscal charges).</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="schemaVersion" type="xsd:decimal" use="required" fixed="10.0"/>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,341 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.dhl.com" xmlns:dhl="http://www.dhl.com/datatypes_global" targetNamespace="http://www.dhl.com" elementFormDefault="unqualified">
<xsd:import namespace="http://www.dhl.com/datatypes_global" schemaLocation="datatypes_global_v10.xsd"/>
<xsd:element name="ShipmentResponse">
<xsd:annotation>
<xsd:documentation>Shipment Validation Global response root element</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Response" type="dhl:Response">
<xsd:annotation>
<xsd:documentation>The element contains the header information for the message. It is present in both the request and response XML message. The response element contains a complex datatype ServiceHeader</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="RegionCode" type="dhl:RegionCode">
<xsd:annotation>
<xsd:documentation>The RegionCode element indicates the shipment transaction originated from which region</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Note" type="dhl:Note">
<xsd:annotation>
<xsd:documentation>The Note element is a complex element which consists of two child elements “ActionNote” and “Condition” element. The Note element is returned by the backend service while processing the Shipment validation request. The element is a mandatory element</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="AirwayBillNumber" type="dhl:AWBNumber">
<xsd:annotation>
<xsd:documentation>The AirwayBillNumber element contains the DHL defines 10-digit waybill number. It is a mandatory field in the shipment validation response. If shipment validation request is successful, this is the actual waybill number assigned to the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DHLInvoiceLanguageCode" type="dhl:InvLanguageCode" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The DHLInvoiceLanguageCode identifies the Invoice Language code. It is a optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DHLInvoiceType" type="dhl:InvoiceType" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The DHLInvoiceType element identifies the type of invoice. It is a optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="BillingCode" type="dhl:BillCode" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The BillingCode element identifies how the shipment is billed. It is a optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="CurrencyCode" type="dhl:CurrencyCode">
<xsd:annotation>
<xsd:documentation>The CurrencyCode element identifies the shipment is billed in which currency</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="CourierMessage" type="dhl:CourierMsg" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The CourierMessage element contains the courier message. It is an optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DestinationServiceArea" type="dhl:DestinationServiceArea">
<xsd:annotation>
<xsd:documentation>The DestinationServiceArea element contains the information of the shipments destination along with the facility code and the inbound sort code information</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="OriginServiceArea" type="dhl:OriginServiceArea">
<xsd:annotation>
<xsd:documentation>The OriginServiceArea element contains the information of the shipments origin along with the outbound sort code info</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="PackageCharge" type="dhl:Money" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The PackageCharge element contains the package charge of the shipment. It is an optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Rated" type="dhl:YesNo">
<xsd:annotation>
<xsd:documentation>The Rated element indicates whether shipment is rated or not. It is a mandatory field. Its value is either Y (Yes) or N (No). “N” indicates that no rates could be retrieved for the given search criteria. Value will be “N” for third party or receiver payment type. “N” value when shipper is payer indicates that rates could not be obtained because of system configuration or availability reasons</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ShippingCharge" type="dhl:Money" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The ShipmentCharge element contains the shipment charge for the shipment. It is an optional field. This field will be filled if rated is Y</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ShipmentCharges" type="dhl:ShipmentCharges" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The shipmentcharges element consist of shipment details shipment charges. This element is optional</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="WeightUnit">
<xsd:annotation>
<xsd:documentation>The WeightUnit element contains the unit by which the shipment weight is measured. It is a mandatory field</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:restriction base="xsd:string">
<xsd:minLength value="0"/>
<xsd:maxLength value="1"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:element>
<xsd:element name="ChargeableWeight" type="dhl:Weight" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The ChargeableWeight element contains the weight that is used to calculate shipment charge. This is an optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DimensionalWeight" type="dhl:Weight" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The DimensionalWeight element contains the dimensional weight of the shipment. It is an optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ReadyByTime" type="dhl:TimeHM" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The ReadyByTime element indicates the ready by time of the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="PickupCharge" type="dhl:Money" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The PickupCharge element indicates pick up charges of the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="CallInTime" type="dhl:TimeHM" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The CallInTime indicates the Callin time of the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DaysAdvanceNotice" type="dhl:AdvanceDaysNotice" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The DaysAdvanceNotice element indicates the advance days notice required for the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ConversionRate" type="dhl:Money" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The ConversionRate indicates the conversion rate of the shipment if any</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="CountryCode" type="dhl:CountryCode">
<xsd:annotation>
<xsd:documentation>Its value should be valid DHL Country/Region code. This element must be declared once in the response element. Please refer to the Reference Data (DHL Country/Region) for Country/Region codes</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Barcodes">
<xsd:annotation>
<xsd:documentation>The Barcodes element contains the Barcode images for construction of Waybill and DHL Routing barcode. It is a mandatory field</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element name="AWBBarCode" type="dhl:BarCode">
<xsd:annotation>
<xsd:documentation>Air Waybill Barcode</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="OriginDestnBarcode" type="dhl:BarCode">
<xsd:annotation>
<xsd:documentation>Origin Destination Barcode</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ClientIDBarCode" type="dhl:BarCode" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Client ID Barcode</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="BarCode2D" type="dhl:BarCode" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>Barcode 2D</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DHLRoutingBarCode" type="dhl:BarCode" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>DHL Routing Barcode</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="Piece" type="xsd:positiveInteger" minOccurs="0"> <!-- Manually added minOccurs="0" - GOA -->
<xsd:annotation>
<xsd:documentation>No of pieces contained in shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Contents" type="xsd:string">
<xsd:annotation>
<xsd:documentation>The contents element contains the shipment content description. It is a mandatory field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Reference" type="dhl:Reference" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>This element identifies the reference information. It is an optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Consignee" type="dhl:Consignee">
<xsd:annotation>
<xsd:documentation>Consignee element contains the details of the Consignee (Receiver). This element should be declared once in the shipment validation response message</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Shipper" type="dhl:Shipper">
<xsd:annotation>
<xsd:documentation>Shipper element contains the details of the Shipper. This element should be declared once in the Book Shipment validation Response message</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="AccountNumber" type="dhl:AccountNumber" minOccurs="0">
<xsd:annotation>
<xsd:documentation>This element contains the DHL account number. It is a mandatory field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="CustomerID" type="xsd:string">
<xsd:annotation>
<xsd:documentation>This element contains the Customer ID</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ShipmentDate" type="dhl:Date">
<xsd:annotation>
<xsd:documentation>This element contains the date of the shipment. It is a mandatory field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="GlobalProductCode" type="dhl:GlobalProductCode">
<xsd:annotation>
<xsd:documentation>The GlobalProductCode element contains the DHL Global product code for the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="CustData" type="dhl:CustData" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The CustData element consists of customer data that required to be printed on shipment level in GLS transport label CI template</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="SpecialService" type="dhl:SpecialService" minOccurs="0" maxOccurs="5">
<xsd:annotation>
<xsd:documentation>The SpecialService Element provides various special services for shipment. It is an optional field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Billing" type="dhl:Billing" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The Billing element contains the billing information of the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Dutiable" type="dhl:Dutiable" minOccurs="0"> <!-- Manually added minOccurs="0" - GOA -->
<xsd:annotation>
<xsd:documentation>For non-domestic shipments, The Dutiable element provides informations which defines the types of duties to be levied</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ExportDeclaration" type="dhl:ExportDeclaration" minOccurs="0">
<xsd:annotation>
<xsd:documentation>For non -domestic shipments, the ExportDeclaration element provides information which is used for export declarartion documents.It is a mandatory field</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="NewShipper" type="dhl:YesNo" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The NewShipper element indicates whether shipper is new or not. The valid values are Y (Yes) and N (No)</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DHLRoutingCode" type="dhl:DHLRoutingCode" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>The DHL ISO Routing Barcode in plain text format. It contains destination Country/Region, destination zip code, transport products and associated product features</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DHLRoutingDataId" type="dhl:DHLRoutingCode" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>The DHL Routing barcode contains the data Identifier.The available values are 2L, 403</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ProductContentCode" type="xsd:string" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>The Product content code indicates the DHLs internal code of the product</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ProductShortName" type="xsd:string" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>The product short name indicates the type of the product name which the underlying transport service has been sold to the cusomter</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="InternalServiceCode" type="dhl:InternalServiceCode" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>The internal service code contains the DHLs product handling relevant services or features</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DeliveryDateCode" type="xsd:string" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>The delivery date code contains the date of delivery of the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DeliveryTimeCode" type="xsd:string" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>The delivery time code contains the time of delivery of the shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Pieces" type="dhl:ShipValResponsePieces" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation>The Pieces element contains the License Plate information and barcode along with the piece details</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="PLTStatus" type="dhl:PLTStatus" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The PLTStatus element indicates the shipper accounts PLT subscription status. The valid values are A, D and S.
For PLTStatus field value of 'A' Active, it signifies it is a valid PLT registered customer and allowed to proceed for PLT shipment process.
For PLTStatus field value of 'D' De-registered, XML-PI Shipment Validation service will stop the shipment processing and returned an error to the XML-PI client.
For PLTStatus field value of 'S' Suspended, XML-PI Shipment Validation service will stop the shipment processing and return an error message to the XML-PI client.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="QtdSInAdCur" type="dhl:QtdSInAdCur" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>The QtdSInAdCur element contains the multiple currency billing details returned for different billing role of shipment charges if available in DCT tariff. Note: For PLT shipment, it will be interface with DCT getQuote interface for tariff. For EU regular shipment, if it is switched to interface with DCT getQuote is configurable in XML Services application backend</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="LabelImage" type="dhl:LabelImage" minOccurs="0" maxOccurs="unbounded">
<xsd:annotation>
<xsd:documentation>The LabelImage element contains the GLSs generated Global and Archive label image output if it is required by user via LabelImageFormat element in request XML</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="ODDURLLink" type="xsd:string" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The ODDURLLink element contains the URL for the On Demand Delivery (ODD) page. This element is optional</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="DGs" type="dhl:DGs" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The DGs element defines the details of the Dangerous Goods items that included in shipment</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Label" type="dhl:Label" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The Label element defines the required label template used and its customers barcode type, barcode code and barcode text if available in clients request</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Importer" type="dhl:Importer" minOccurs="0">
<xsd:annotation>
<xsd:documentation>Party that makes (or on whose behalf an agent or broker makes) the import declaration, and who is liable for the payment of duties (if any) on the imported goods. Normally, this party is named either as the consignee in the shipping documents and/or as the buyer in the exporter's invoice.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Exporter" type="dhl:Exporter" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The party who is responsible for the legality of the shipment under applicable export control laws, which includes determining the proper export classification and authorization needed to ship the Items.The Exporter is usually the party who controls the transaction, acts as declarant in its own name and provides the corresponding instructions for the export, regardless of who files the export declaration. The Exporter may or may not be the Shipper.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Seller" type="dhl:Seller" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The party that makes, offers or contracts to make a sale to an actual or potential buyer. Also called vendor.</xsd:documentation>
</xsd:annotation>
</xsd:element>
<xsd:element name="Payer" type="dhl:Payer" minOccurs="0">
<xsd:annotation>
<xsd:documentation>The party responsible for the full or partial payment of associated charges/cost. There can be many payers related to the different elements linked to a Shipment (e.g Services, fiscal charges).</xsd:documentation>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

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

View File

@@ -0,0 +1,240 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import requests
from datetime import datetime
from json.decoder import JSONDecodeError
from requests.exceptions import RequestException
from odoo import _
from odoo.exceptions import ValidationError
from odoo.tools.float_utils import float_round, json_float_round
TEST_BASE_URL = 'https://express.api.dhl.com/mydhlapi/test/'
PROD_BASE_URL = 'https://express.api.dhl.com/mydhlapi/'
class DHLProvider:
def __init__(self, carrier):
super_carrier = carrier.sudo()
self.logger = super_carrier.log_xml
self.base_url = PROD_BASE_URL if super_carrier.prod_environment else TEST_BASE_URL
if not super_carrier.dhl_api_key:
raise ValidationError(_("DHL API key is missing, please modify your delivery method settings."))
if not super_carrier.dhl_api_secret:
raise ValidationError(_("DHL API secret is missing, please modify your delivery method settings."))
self.session = requests.Session()
self.session.auth = (super_carrier.dhl_api_key, super_carrier.dhl_api_secret)
def _send_request(self, url, method='GET', data=None, json=None):
url = f'{self.base_url}{url}'
self.logger(f'{url}\n{method}\n{data}\n{json}', f'dhl request {url}')
try:
res = self.session.request(method=method, url=url, data=data, json=json, timeout=15)
self.logger(f'{res.status_code} {res.text}', f'dhl response {url}')
except RequestException as err:
self.logger(str(err), f'dhl response {url}')
raise ValidationError(_('Something went wrong, please try again later!!')) from None
return res
def _process_errors(self, res_body):
err_msgs = [' '.join([res_body.get('title', ''), res_body.get('detail', '')])]
if res_body.get('additionalDetails'):
for detail in res_body['additionalDetails']:
err_msgs.append(detail)
return '\n'.join(err_msgs)
def _check_required_value(self, carrier, recipient, shipper, order=False, picking=False):
carrier = carrier.sudo()
recipient_required_field = ['city', 'zip', 'phone', 'country_id']
if not carrier.dhl_account_number:
return _("DHL account number is missing, please modify your delivery method settings.")
# The street isn't required if we compute the rate with a partial delivery address in the
# express checkout flow.
if not recipient.street and not recipient.street2 and not recipient.env.context.get(
'express_checkout_partial_delivery_address', False
):
recipient_required_field.append('street')
res = [field for field in recipient_required_field if not recipient[field]]
if res:
return _("The address of the customer is missing or wrong (Missing field(s) :\n %s)", ", ".join(res).replace("_id", ""))
shipper_required_field = ['city', 'zip', 'phone', 'country_id']
if not shipper.street2:
shipper_required_field.append('street')
res = [field for field in shipper_required_field if not shipper[field]]
if res:
return _("The address of your company warehouse is missing or wrong (Missing field(s) :\n %s)", ", ".join(res).replace("_id", ""))
if order:
if not order.order_line:
return _("Please provide at least one item to ship.")
error_lines = order.order_line._get_invalid_delivery_weight_lines()
if error_lines:
return _("The estimated shipping price cannot be computed because the weight is missing for the following product(s): \n %s", ", ".join(error_lines.product_id.mapped('name')))
return ''
def _get_from_vals(self, warehouse_partner_id):
return {
'countryCode': warehouse_partner_id.country_id.code,
'postalCode': warehouse_partner_id.zip,
'cityName': warehouse_partner_id.city,
}
def _get_to_vals(self, partner_id):
return {
'countryCode': partner_id.country_id.code,
'postalCode': partner_id.zip,
'cityName': partner_id.city,
}
def _get_package_vals(self, carrier, packages):
return [{
'weight': carrier._dhl_rest_convert_weight(p['weight']),
'dimensions': {
'length': p['dimension']['length'],
'width': p['dimension']['width'],
'height': p['dimension']['height'],
}
} for p in packages]
def _get_dutiable_vals(self, total_value, currency_name):
return [{
'typeCode': 'declaredValue',
'value': total_value,
'currency': currency_name,
}]
def _get_rates(self, rating_request):
url = 'rates'
res = self._send_request(url, method='POST', json=rating_request)
try:
res_body = res.json()
except JSONDecodeError as err:
self.logger(str(err), f'dhl response decoding error {url}')
raise ValidationError(_('Could not decode the response from DHL.')) from None
if not res.ok:
raise ValidationError(self._process_errors(res_body)) from None
return res_body
def _get_billing_vals(self, shipper_account, payment_type):
return [{
'typeCode': payment_type,
'number': shipper_account,
}]
def _get_consignee_vals(self, partner_id):
consignee_dict = {
'postalAddress': {
'postalCode': partner_id.zip,
'cityName': partner_id.city,
'countryCode': partner_id.country_id.code,
'addressLine1': partner_id.street or partner_id.street2,
},
'contactInformation': {
'phone': partner_id.phone,
'companyName': partner_id.commercial_company_name or partner_id.name,
'fullName': partner_id.name,
}
}
if partner_id.email:
consignee_dict['contactInformation']['email'] = partner_id.email
if partner_id.street2:
consignee_dict['postalAddress']['addressLine2'] = partner_id.street2
if partner_id.state_id:
consignee_dict['postalAddress']['provinceName'] = partner_id.state_id.name
consignee_dict['postalAddress']['provinceCode'] = partner_id.state_id.code
return consignee_dict
def _get_shipper_vals(self, company_partner_id, warehouse_partner_id):
shipper_dict = {
'postalAddress': {
'postalCode': warehouse_partner_id.zip,
'cityName': warehouse_partner_id.city,
'countryCode': warehouse_partner_id.country_id.code,
'addressLine1': warehouse_partner_id.street or warehouse_partner_id.street2,
},
'contactInformation': {
'phone': company_partner_id.phone,
'companyName': company_partner_id.commercial_company_name or company_partner_id.name,
'fullName': company_partner_id.name,
},
}
if company_partner_id.email:
shipper_dict['contactInformation']['email'] = company_partner_id.email
if warehouse_partner_id.street2:
shipper_dict['postalAddress']['addressLine2'] = warehouse_partner_id.street2
if warehouse_partner_id.state_id:
shipper_dict['postalAddress']['provinceName'] = warehouse_partner_id.state_id.name
shipper_dict['postalAddress']['provinceCode'] = warehouse_partner_id.state_id.code
return shipper_dict
def _get_export_declaration_vals(self, carrier, picking, is_return=False):
export_declaration = {}
export_lines = []
move_lines = picking.move_line_ids.filtered(lambda line: line.product_id.type in ['product', 'consu'])
for sequence, line in enumerate(move_lines, start=1):
if line.move_id.sale_line_id:
unit_quantity = line.product_uom_id._compute_quantity(line.quantity, line.move_id.sale_line_id.product_uom_id)
else:
unit_quantity = line.product_uom_id._compute_quantity(line.quantity, line.product_id.uom_id)
rounded_qty = max(1, float_round(unit_quantity, precision_digits=0, rounding_method='HALF-UP'))
item = {
'number': sequence,
'description': line.product_id.name,
'price': json_float_round(line.sale_price / rounded_qty, 3),
'quantity': {
'value': int(rounded_qty),
'unitOfMeasurement': 'PCS'
},
'weight': {
'netValue': carrier._dhl_rest_convert_weight(line.product_id.weight),
'grossValue': carrier._dhl_rest_convert_weight(line.product_id.weight),
},
'manufacturerCountry': line.picking_id.picking_type_id.warehouse_id.partner_id.country_id.code
}
if line.product_id.hs_code:
item['commodityCodes'] = [{'typeCode': 'inbound', 'value': line.product_id.hs_code}]
export_lines.append(item)
export_declaration['lineItems'] = export_lines
export_declaration['invoice'] = {
'number': carrier.env['ir.sequence'].sudo().next_by_code('delivery_dhl_rest.commercial_invoice'),
'date': datetime.today().strftime('%Y-%m-%d'),
}
if is_return:
export_declaration['exportReasonType'] = 'return'
if picking.sale_id.client_order_ref:
export_declaration['recipientReference'] = picking.sale_id.client_order_ref
return export_declaration
def _get_shipment_vals(self, picking):
packages = picking.carrier_id._dhl_rest_get_picking_packages(picking)
return [{
'weight': picking.carrier_id._dhl_rest_convert_weight(package['weight']),
'dimensions': {
'length': package.get('dimension', {}).get('length', 0),
'width': package.get('dimension', {}).get('width', 0),
'height': package.get('dimension', {}).get('height', 0),
},
'description': package.get('name', '')
} for package in packages]
def _get_insurance_vals(self, insurance_percentage, total_value, currency_name):
return {
'serviceCode': 'II',
'value': float_round(total_value * insurance_percentage / 100, precision_digits=3),
'currency': currency_name,
}
def _send_shipment(self, shipment_request):
url = 'shipments'
res = self._send_request(url, method='POST', json=shipment_request)
try:
res_body = res.json()
except JSONDecodeError as err:
self.logger(str(err), f'dhl response decoding error {url}')
raise ValidationError(_('Could not decode the response from DHL.')) from None
if not res.ok:
raise ValidationError(self._process_errors(res_body)) from None
return res_body

View File

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

View File

@@ -0,0 +1,502 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import binascii
import logging
import re
from datetime import datetime, date
from os.path import join as opj
from odoo.tools.zeep import Client, Plugin, Settings
from odoo.tools.zeep.exceptions import Fault
from odoo.tools.zeep.wsdl.utils import etree_to_string
from odoo.tools import remove_accents, float_repr
from odoo.tools.misc import file_path
_logger = logging.getLogger(__name__)
# uncomment to enable logging of Zeep requests and responses
# logging.getLogger('zeep.transports').setLevel(logging.DEBUG)
STATECODE_REQUIRED_COUNTRIES = ['US', 'CA', 'PR ', 'IN']
# Why using standardized ISO codes? It's way more fun to use made up codes...
# https://www.fedex.com/us/developer/WebHelp/ws/2014/dvg/WS_DVG_WebHelp/Appendix_F_Currency_Codes.htm
FEDEX_CURR_MATCH = {
u'UYU': u'UYP',
u'XCD': u'ECD',
u'MXN': u'NMP',
u'KYD': u'CID',
u'CHF': u'SFR',
u'GBP': u'UKL',
u'IDR': u'RPA',
u'DOP': u'RDD',
u'JPY': u'JYE',
u'KRW': u'WON',
u'SGD': u'SID',
u'CLP': u'CHP',
u'JMD': u'JAD',
u'KWD': u'KUD',
u'AED': u'DHS',
u'TWD': u'NTD',
u'ARS': u'ARN',
u'LVL': u'EURO',
}
class LogPlugin(Plugin):
""" Small plugin for zeep that catches out/ingoing XML requests and logs them"""
def __init__(self, debug_logger):
self.debug_logger = debug_logger
def egress(self, envelope, http_headers, operation, binding_options):
self.debug_logger(etree_to_string(envelope).decode(), 'fedex_request')
return envelope, http_headers
def ingress(self, envelope, http_headers, operation):
self.debug_logger(etree_to_string(envelope).decode(), 'fedex_response')
return envelope, http_headers
def marshalled(self, context):
context.envelope = context.envelope.prune()
class FedexRequest():
""" Low-level object intended to interface Odoo recordsets with FedEx,
through appropriate SOAP requests """
def __init__(self, debug_logger, request_type="shipping", prod_environment=False, ):
self.debug_logger = debug_logger
self.hasCommodities = False
wsdl_folder = 'prod' if prod_environment else 'test'
if request_type == "shipping":
wsdl_path = opj('fusion_shipping', 'api', 'fedex', 'wsdl', wsdl_folder, 'ShipService_v28.wsdl')
self.start_shipping_transaction(wsdl_path)
elif request_type == "rating":
wsdl_path = opj('fusion_shipping', 'api', 'fedex', 'wsdl', wsdl_folder, 'RateService_v31.wsdl')
self.start_rating_transaction(wsdl_path)
# Authentification stuff
def web_authentication_detail(self, key, password):
WebAuthenticationCredential = self.factory.WebAuthenticationCredential()
WebAuthenticationCredential.Key = key
WebAuthenticationCredential.Password = password
self.WebAuthenticationDetail = self.factory.WebAuthenticationDetail()
self.WebAuthenticationDetail.UserCredential = WebAuthenticationCredential
def transaction_detail(self, transaction_id):
self.TransactionDetail = self.factory.TransactionDetail()
self.TransactionDetail.CustomerTransactionId = transaction_id
def client_detail(self, account_number, meter_number):
self.ClientDetail = self.factory.ClientDetail()
self.ClientDetail.AccountNumber = account_number
self.ClientDetail.MeterNumber = meter_number
# Common stuff
def set_shipper(self, company_partner, warehouse_partner):
Contact = self.factory.Contact()
Contact.PersonName = remove_accents(company_partner.name) if not company_partner.is_company else ''
Contact.CompanyName = remove_accents(company_partner.commercial_company_name) or ''
Contact.PhoneNumber = warehouse_partner.phone or ''
Contact.EMailAddress = warehouse_partner.email or ''
# TODO fedex documentation asks for TIN number, but it seems to work without
Address = self.factory.Address()
Address.StreetLines = [remove_accents(warehouse_partner.street) or '',remove_accents(warehouse_partner.street2) or '']
Address.City = remove_accents(warehouse_partner.city) or ''
if warehouse_partner.country_id.code in STATECODE_REQUIRED_COUNTRIES:
Address.StateOrProvinceCode = warehouse_partner.state_id.code or ''
else:
Address.StateOrProvinceCode = ''
Address.PostalCode = warehouse_partner.zip or ''
Address.CountryCode = warehouse_partner.country_id.code or ''
self.RequestedShipment.Shipper = self.factory.Party()
self.RequestedShipment.Shipper.Contact = Contact
self.RequestedShipment.Shipper.Address = Address
def set_recipient(self, recipient_partner):
Contact = self.factory.Contact()
if recipient_partner.is_company:
Contact.PersonName = ''
Contact.CompanyName = remove_accents(recipient_partner.name)
else:
Contact.PersonName = remove_accents(recipient_partner.name)
Contact.CompanyName = remove_accents(recipient_partner.commercial_company_name) or ''
Contact.PhoneNumber = recipient_partner.phone or ''
Contact.EMailAddress = recipient_partner.email or ''
Address = self.factory.Address()
Address.StreetLines = [remove_accents(recipient_partner.street) or '', remove_accents(recipient_partner.street2) or '']
Address.City = remove_accents(recipient_partner.city) or ''
if recipient_partner.country_id.code in STATECODE_REQUIRED_COUNTRIES:
Address.StateOrProvinceCode = recipient_partner.state_id.code or ''
else:
Address.StateOrProvinceCode = ''
Address.PostalCode = recipient_partner.zip or ''
Address.CountryCode = recipient_partner.country_id.code or ''
self.RequestedShipment.Recipient = self.factory.Party()
self.RequestedShipment.Recipient.Contact = Contact
self.RequestedShipment.Recipient.Address = Address
def shipment_request(self, dropoff_type, service_type, packaging_type, overall_weight_unit, saturday_delivery):
self.RequestedShipment = self.factory.RequestedShipment()
self.RequestedShipment.SpecialServicesRequested = self.factory.ShipmentSpecialServicesRequested()
self.RequestedShipment.ShipTimestamp = datetime.now()
self.RequestedShipment.DropoffType = dropoff_type
self.RequestedShipment.ServiceType = service_type
self.RequestedShipment.PackagingType = packaging_type
# Resuest estimation of duties and taxes for international shipping
if service_type in ['INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY']:
self.RequestedShipment.EdtRequestType = 'ALL'
else:
self.RequestedShipment.EdtRequestType = 'NONE'
self.RequestedShipment.PackageCount = 0
self.RequestedShipment.TotalWeight = self.factory.Weight()
self.RequestedShipment.TotalWeight.Units = overall_weight_unit
self.RequestedShipment.TotalWeight.Value = 0
self.listCommodities = []
if saturday_delivery:
timestamp_day = self.RequestedShipment.ShipTimestamp.strftime("%A")
if (service_type == 'FEDEX_2_DAY' and timestamp_day == 'Thursday') or (service_type in ['PRIORITY_OVERNIGHT', 'FIRST_OVERNIGHT', 'INTERNATIONAL_PRIORITY'] and timestamp_day == 'Friday'):
self.RequestedShipment.SpecialServicesRequested.SpecialServiceTypes.append('SATURDAY_DELIVERY')
def set_currency(self, currency):
# set perferred currency as GBP instead of UKL
currency = 'GBP' if currency == 'UKL' else currency
self.RequestedShipment.PreferredCurrency = currency
# ask Fedex to include our preferred currency in the response
self.RequestedShipment.RateRequestTypes = 'PREFERRED'
def set_master_package(self, weight, package_count, master_tracking_id=False):
self.RequestedShipment.TotalWeight.Value = weight
self.RequestedShipment.PackageCount = package_count
if master_tracking_id:
self.RequestedShipment.MasterTrackingId = self.factory.TrackingId()
self.RequestedShipment.MasterTrackingId.TrackingIdType = 'FEDEX'
self.RequestedShipment.MasterTrackingId.TrackingNumber = master_tracking_id
# weight_value, package_code=False, package_height=0, package_width=0, package_length=0,
def add_package(self, carrier, delivery_package, fdx_company_currency, sequence_number=False, mode='shipping', po_number=False, dept_number=False, reference=False):
package = self.factory.RequestedPackageLineItem()
package_weight = self.factory.Weight()
package_weight.Value = carrier._fedex_convert_weight(delivery_package.weight, carrier.fedex_weight_unit)
package_weight.Units = self.RequestedShipment.TotalWeight.Units
package.PhysicalPackaging = 'BOX'
if delivery_package.packaging_type == 'YOUR_PACKAGING':
package.Dimensions = self.factory.Dimensions()
package.Dimensions.Height = int(delivery_package.dimension['height'])
package.Dimensions.Width = int(delivery_package.dimension['width'])
package.Dimensions.Length = int(delivery_package.dimension['length'])
# TODO in master, add unit in product packaging and perform unit conversion
package.Dimensions.Units = "IN" if self.RequestedShipment.TotalWeight.Units == 'LB' else 'CM'
if po_number:
po_reference = self.factory.CustomerReference()
po_reference.CustomerReferenceType = 'P_O_NUMBER'
po_reference.Value = po_number
package.CustomerReferences.append(po_reference)
if dept_number:
dept_reference = self.factory.CustomerReference()
dept_reference.CustomerReferenceType = 'DEPARTMENT_NUMBER'
dept_reference.Value = dept_number
package.CustomerReferences.append(dept_reference)
if reference:
customer_reference = self.factory.CustomerReference()
customer_reference.CustomerReferenceType = 'CUSTOMER_REFERENCE'
customer_reference.Value = reference
package.CustomerReferences.append(customer_reference)
if carrier.shipping_insurance:
package.InsuredValue = self.factory.Money()
insured_value = delivery_package.total_cost * carrier.shipping_insurance / 100
pkg_order = delivery_package.order_id or delivery_package.picking_id.sale_id
# Get the currency from the sale order if it exists, so that it matches that of customs_value
if pkg_order:
package.InsuredValue.Currency = _convert_curr_iso_fdx(pkg_order.currency_id.name)
package.InsuredValue.Amount = float_repr(delivery_package.company_id.currency_id._convert(insured_value, pkg_order.currency_id, pkg_order.company_id, date.today()), 2)
else:
package.InsuredValue.Currency = fdx_company_currency
package.InsuredValue.Amount = float_repr(insured_value, 2)
package.Weight = package_weight
if mode == 'rating':
package.GroupPackageCount = 1
if sequence_number:
package.SequenceNumber = sequence_number
if mode == 'rating':
self.RequestedShipment.RequestedPackageLineItems.append(package)
else:
self.RequestedShipment.RequestedPackageLineItems = package
# Rating stuff
def start_rating_transaction(self, wsdl_path):
settings = Settings(strict=False)
self.client = Client(file_path(wsdl_path), plugins=[LogPlugin(self.debug_logger)], settings=settings)
self.factory = self.client.type_factory('ns0')
self.VersionId = self.factory.VersionId()
self.VersionId.ServiceId = 'crs'
self.VersionId.Major = '31'
self.VersionId.Intermediate = '0'
self.VersionId.Minor = '0'
def rate(self, request):
formatted_response = {'price': {}}
try:
self.response = self.client.service.getRates(WebAuthenticationDetail=request['WebAuthenticationDetail'],
ClientDetail=request['ClientDetail'],
TransactionDetail=request['TransactionDetail'],
Version=request['VersionId'],
RequestedShipment=request['RequestedShipment'])
if (self.response.HighestSeverity != 'ERROR' and self.response.HighestSeverity != 'FAILURE'):
if not getattr(self.response, "RateReplyDetails", False):
raise Exception("No rating found")
for rating in self.response.RateReplyDetails[0].RatedShipmentDetails:
formatted_response['price'][rating.ShipmentRateDetail.TotalNetFedExCharge.Currency] = float(rating.ShipmentRateDetail.TotalNetFedExCharge.Amount)
if len(self.response.RateReplyDetails[0].RatedShipmentDetails) == 1:
if 'CurrencyExchangeRate' in self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail and self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail['CurrencyExchangeRate']:
formatted_response['price'][self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.FromCurrency] = float(self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.TotalNetFedExCharge.Amount) / float(self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.Rate)
else:
errors_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if (n.Severity == 'ERROR' or n.Severity == 'FAILURE')])
formatted_response['errors_message'] = errors_message
if any([n.Severity == 'WARNING' for n in self.response.Notifications]):
warnings_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if n.Severity == 'WARNING'])
formatted_response['warnings_message'] = warnings_message
except Fault as fault:
formatted_response['errors_message'] = fault
except IOError:
formatted_response['errors_message'] = "Fedex Server Not Found"
except Exception as e:
formatted_response['errors_message'] = e.args[0]
return formatted_response
# Shipping stuff
def start_shipping_transaction(self, wsdl_path):
self.client = Client(file_path(wsdl_path), plugins=[LogPlugin(self.debug_logger)])
self.factory = self.client.type_factory("ns0")
self.VersionId = self.factory.VersionId()
self.VersionId.ServiceId = 'ship'
self.VersionId.Major = '28'
self.VersionId.Intermediate = '0'
self.VersionId.Minor = '0'
def shipment_label(self, label_format_type, image_type, label_stock_type, label_printing_orientation, label_order):
LabelSpecification = self.factory.LabelSpecification()
LabelSpecification.LabelFormatType = label_format_type
LabelSpecification.ImageType = image_type
LabelSpecification.LabelStockType = label_stock_type
LabelSpecification.LabelPrintingOrientation = label_printing_orientation
LabelSpecification.LabelOrder = label_order
self.RequestedShipment.LabelSpecification = LabelSpecification
def commercial_invoice(self, document_stock_type, send_etd=False):
shipping_document = self.factory.ShippingDocumentSpecification()
shipping_document.ShippingDocumentTypes = "COMMERCIAL_INVOICE"
commercial_invoice_detail = self.factory.CommercialInvoiceDetail()
commercial_invoice_detail.Format = self.factory.ShippingDocumentFormat()
commercial_invoice_detail.Format.ImageType = "PDF"
commercial_invoice_detail.Format.StockType = document_stock_type
shipping_document.CommercialInvoiceDetail = commercial_invoice_detail
self.RequestedShipment.ShippingDocumentSpecification = shipping_document
if send_etd:
self.RequestedShipment.SpecialServicesRequested.SpecialServiceTypes.append('ELECTRONIC_TRADE_DOCUMENTS')
etd_details = self.factory.EtdDetail()
etd_details.RequestedDocumentCopies.append('COMMERCIAL_INVOICE')
self.RequestedShipment.SpecialServicesRequested.EtdDetail = etd_details
def shipping_charges_payment(self, shipping_charges_payment_account):
self.RequestedShipment.ShippingChargesPayment = self.factory.Payment()
self.RequestedShipment.ShippingChargesPayment.PaymentType = 'SENDER'
Payor = self.factory.Payor()
Payor.ResponsibleParty = self.factory.Party()
Payor.ResponsibleParty.AccountNumber = shipping_charges_payment_account
self.RequestedShipment.ShippingChargesPayment.Payor = Payor
def duties_payment(self, sender_party, responsible_account_number, payment_type):
self.RequestedShipment.CustomsClearanceDetail.DutiesPayment = self.factory.Payment()
self.RequestedShipment.CustomsClearanceDetail.DutiesPayment.PaymentType = payment_type
if payment_type == 'SENDER':
Payor = self.factory.Payor()
Payor.ResponsibleParty = self.factory.Party()
Payor.ResponsibleParty.Address = self.factory.Address()
Payor.ResponsibleParty.Address.CountryCode = sender_party.country_id.code
Payor.ResponsibleParty.AccountNumber = responsible_account_number
self.RequestedShipment.CustomsClearanceDetail.DutiesPayment.Payor = Payor
def customs_value(self, customs_value_currency, customs_value_amount, document_content):
self.RequestedShipment.CustomsClearanceDetail = self.factory.CustomsClearanceDetail()
if self.hasCommodities:
self.RequestedShipment.CustomsClearanceDetail.Commodities = self.listCommodities
self.RequestedShipment.CustomsClearanceDetail.CustomsValue = self.factory.Money()
self.RequestedShipment.CustomsClearanceDetail.CustomsValue.Currency = customs_value_currency
self.RequestedShipment.CustomsClearanceDetail.CustomsValue.Amount = float_repr(customs_value_amount, 2)
if self.RequestedShipment.Shipper.Address.CountryCode == "IN" and self.RequestedShipment.Recipient.Address.CountryCode == "IN":
if not self.RequestedShipment.CustomsClearanceDetail.CommercialInvoice:
self.RequestedShipment.CustomsClearanceDetail.CommercialInvoice = self.factory.CommercialInvoice()
else:
del self.RequestedShipment.CustomsClearanceDetail.CommercialInvoice.TaxesOrMiscellaneousChargeType
self.RequestedShipment.CustomsClearanceDetail.CommercialInvoice.Purpose = 'SOLD'
# Old keys not requested anymore but still in WSDL; not removing them causes crash
del self.RequestedShipment.CustomsClearanceDetail['ClearanceBrokerage']
del self.RequestedShipment.CustomsClearanceDetail['FreightOnValue']
self.RequestedShipment.CustomsClearanceDetail.DocumentContent = document_content
def commodities(self, carrier, delivery_commodity, commodity_currency):
self.hasCommodities = True
commodity = self.factory.Commodity()
commodity.UnitPrice = self.factory.Money()
commodity.UnitPrice.Currency = commodity_currency
commodity.UnitPrice.Amount = delivery_commodity.monetary_value
commodity.NumberOfPieces = '1'
commodity.CountryOfManufacture = delivery_commodity.country_of_origin
commodity_weight = self.factory.Weight()
commodity_weight.Value = carrier._fedex_convert_weight(delivery_commodity.product_id.weight * delivery_commodity.qty, carrier.fedex_weight_unit)
commodity_weight.Units = carrier.fedex_weight_unit
commodity.Weight = commodity_weight
commodity.Description = re.sub(r'[\[\]<>;={}"|]', '', delivery_commodity.product_id.name)
commodity.Quantity = delivery_commodity.qty
commodity.QuantityUnits = 'EA'
customs_value = self.factory.Money()
customs_value.Currency = commodity_currency
customs_value.Amount = delivery_commodity.monetary_value * delivery_commodity.qty
commodity.CustomsValue = customs_value
commodity.HarmonizedCode = delivery_commodity.product_id.hs_code.replace(".", "") if delivery_commodity.product_id.hs_code else ''
self.listCommodities.append(commodity)
def return_label(self, tracking_number, origin_date):
return_details = self.factory.ReturnShipmentDetail()
return_details.ReturnType = "PRINT_RETURN_LABEL"
if tracking_number and origin_date:
return_association = self.factory.ReturnAssociationDetail()
return_association.TrackingNumber = tracking_number
return_association.ShipDate = origin_date
return_details.ReturnAssociation = return_association
self.RequestedShipment.SpecialServicesRequested.SpecialServiceTypes.append("RETURN_SHIPMENT")
self.RequestedShipment.SpecialServicesRequested.ReturnShipmentDetail = return_details
if self.hasCommodities:
bla = self.factory.CustomsOptionDetail()
bla.Type = "FAULTY_ITEM"
self.RequestedShipment.CustomsClearanceDetail.CustomsOptions = bla
def process_shipment(self, request):
formatted_response = {'tracking_number': 0.0,
'price': {},
'master_tracking_id': None,
'date': None}
try:
self.response = self.client.service.processShipment(WebAuthenticationDetail=request['WebAuthenticationDetail'],
ClientDetail=request['ClientDetail'],
TransactionDetail=request['TransactionDetail'],
Version=request['VersionId'],
RequestedShipment=request['RequestedShipment'])
if (self.response.HighestSeverity != 'ERROR' and self.response.HighestSeverity != 'FAILURE'):
formatted_response['tracking_number'] = self.response.CompletedShipmentDetail.CompletedPackageDetails[0].TrackingIds[0].TrackingNumber
if 'CommitDate' in self.response.CompletedShipmentDetail.OperationalDetail:
formatted_response['date'] = self.response.CompletedShipmentDetail.OperationalDetail.CommitDate
else:
formatted_response['date'] = date.today()
if 'ShipmentRating' in self.response.CompletedShipmentDetail and self.response.CompletedShipmentDetail.ShipmentRating:
for rating in self.response.CompletedShipmentDetail.ShipmentRating.ShipmentRateDetails:
formatted_response['price'][rating.TotalNetFedExCharge.Currency] = float(rating.TotalNetFedExCharge.Amount)
if 'CurrencyExchangeRate' in rating and rating.CurrencyExchangeRate:
formatted_response['price'][rating.CurrencyExchangeRate.FromCurrency] = float(rating.TotalNetFedExCharge.Amount / rating.CurrencyExchangeRate.Rate)
else:
formatted_response['price']['USD'] = 0.0
if 'MasterTrackingId' in self.response.CompletedShipmentDetail:
formatted_response['master_tracking_id'] = self.response.CompletedShipmentDetail.MasterTrackingId.TrackingNumber
else:
errors_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if (n.Severity == 'ERROR' or n.Severity == 'FAILURE')])
formatted_response['errors_message'] = errors_message
if any([n.Severity == 'WARNING' for n in self.response.Notifications]):
warnings_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if n.Severity == 'WARNING'])
formatted_response['warnings_message'] = warnings_message
except Fault as fault:
formatted_response['errors_message'] = fault
except IOError:
formatted_response['errors_message'] = "Fedex Server Not Found"
return formatted_response
def _get_labels(self, file_type):
labels = [self.get_label()]
if file_type.upper() in ['PNG'] and self.response.CompletedShipmentDetail.CompletedPackageDetails[0].PackageDocuments:
for auxiliary in self.response.CompletedShipmentDetail.CompletedPackageDetails[0].PackageDocuments[0].Parts:
labels.append(auxiliary.Image)
return labels
def get_label(self):
return self.response.CompletedShipmentDetail.CompletedPackageDetails[0].Label.Parts[0].Image
def get_document(self):
if self.response.CompletedShipmentDetail.ShipmentDocuments:
return self.response.CompletedShipmentDetail.ShipmentDocuments[0].Parts[0].Image
else:
return False
# Deletion stuff
def set_deletion_details(self, tracking_number):
self.TrackingId = self.factory.TrackingId()
self.TrackingId.TrackingIdType = 'FEDEX'
self.TrackingId.TrackingNumber = tracking_number
self.DeletionControl = self.factory.DeletionControlType('DELETE_ALL_PACKAGES')
def delete_shipment(self, request):
formatted_response = {'delete_success': False}
try:
# Here, we send the Order 66
self.response = self.client.service.deleteShipment(WebAuthenticationDetail=request['WebAuthenticationDetail'],
ClientDetail=request['ClientDetail'],
TransactionDetail=request['TransactionDetail'],
Version=request['VersionId'],
TrackingId=request['TrackingId'],
DeletionControl=request['DeletionControl'])
if (self.response.HighestSeverity != 'ERROR' and self.response.HighestSeverity != 'FAILURE'):
formatted_response['delete_success'] = True
else:
errors_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if (n.Severity == 'ERROR' or n.Severity == 'FAILURE')])
formatted_response['errors_message'] = errors_message
if any([n.Severity == 'WARNING' for n in self.response.Notifications]):
warnings_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if n.Severity == 'WARNING'])
formatted_response['warnings_message'] = warnings_message
except Fault as fault:
formatted_response['errors_message'] = fault
except IOError:
formatted_response['errors_message'] = "Fedex Server Not Found"
return formatted_response
def _convert_curr_fdx_iso(code):
curr_match = {v: k for k, v in FEDEX_CURR_MATCH.items()}
return curr_match.get(code, code)
def _convert_curr_iso_fdx(code):
return FEDEX_CURR_MATCH.get(code, code)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -0,0 +1,656 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import json
from json import JSONDecodeError
import requests
from requests import RequestException
from odoo import _
from odoo.exceptions import ValidationError, UserError
from odoo.tools import float_repr
TEST_BASE_URL = "https://apis-sandbox.fedex.com"
PROD_BASE_URL = "https://apis.fedex.com"
# Why using standardized ISO codes? It's way more fun to use made up codes...
# https://developer.fedex.com/api/en-us/guides/api-reference.html#currencycodes
FEDEX_CURR_MATCH = {
'XCD': 'ECD',
'MXN': 'NMP',
'KYD': 'CID',
'CHF': 'SFR',
'DOP': 'RDD',
'JPY': 'JYE',
'KRW': 'WON',
'SGD': 'SID',
'CLP': 'CHP',
'JMD': 'JAD',
'KWD': 'KUD',
'AED': 'DHS',
'TWD': 'NTD',
'ARS': 'ARN',
'VES': 'VEF',
# 'LVL': 'EUR',
# 'UYU': 'UYP',
'GBP': 'UKL',
# 'IDR': 'RPA',
}
FEDEX_MX_STATE_MATCH = {
'AGU': 'AG',
'BCN': 'BC',
'BCS': 'BS',
'CAM': 'CM',
'CHH': 'CH',
'CHP': 'CS',
'CMX': 'DF',
'COA': 'CO',
'COL': 'CL',
'DUR': 'DG',
'GRO': 'GR',
'GUA': 'GT',
'HID': 'HG',
'JAL': 'JA',
'MEX': 'EM',
'MIC': 'MI',
'MOR': 'MO',
'NAY': 'NA',
'NLE': 'NL',
'OAX': 'OA',
'PUE': 'PU',
'QUE': 'QE',
'ROO': 'QR',
'SIN': 'SI',
'SLP': 'SL',
'SON': 'SO',
'TAB': 'TB',
'TAM': 'TM',
'TLA': 'TL',
'VER': 'VE',
'YUC': 'YU',
'ZAC': 'ZA'
}
FEDEX_AE_STATE_MATCH = {
'AZ': 'AB',
'AJ': 'AJ',
'DU': 'DU',
'FU': 'FU',
'RK': 'RA',
'SH': 'SH',
'UQ': 'UM',
}
FEDEX_STOCK_TYPE_MATCH = {
'PAPER_4X6.75': 'PAPER_4X675',
'PAPER_7X4.75': 'PAPER_7X475',
'PAPER_8.5X11_BOTTOM_HALF_LABEL': 'PAPER_85X11_BOTTOM_HALF_LABEL',
'PAPER_8.5X11_TOP_HALF_LABEL': 'PAPER_85X11_TOP_HALF_LABEL',
'STOCK_4X6.75': 'STOCK_4X675',
'STOCK_4X6.75_LEADING_DOC_TAB': 'STOCK_4X675_LEADING_DOC_TAB',
'STOCK_4X6.75_TRAILING_DOC_TAB': 'STOCK_4X675_TRAILING_DOC_TAB',
}
class FedexRequest:
def __init__(self, carrier):
super_carrier = carrier.sudo()
self.base_url = PROD_BASE_URL if super_carrier.prod_environment else TEST_BASE_URL
self.access_token = super_carrier.fedex_rest_access_token
self.client_id = super_carrier.fedex_rest_developer_key
self.client_secret = super_carrier.fedex_rest_developer_password
self.account_number = super_carrier.fedex_rest_account_number
self.weight_units = super_carrier.fedex_rest_weight_unit
self.vat_override = super_carrier.fedex_rest_override_shipper_vat
self.email_notifications = super_carrier.fedex_rest_email_notifications
self.documentation_type = super_carrier.fedex_rest_documentation_type
self.insurance = super_carrier.shipping_insurance
self.check_residential = super_carrier.fedex_rest_residential_address
self.dropoff_type = super_carrier.fedex_rest_droppoff_type
self.service_type = super_carrier.fedex_rest_service_type
self.label_stock = _convert_stock_type(super_carrier.fedex_rest_label_stock_type)
self.label_file = super_carrier.fedex_rest_label_file_type
self.duty_payment = super_carrier.fedex_rest_duty_payment
self.make_return = super_carrier.return_label_on_delivery
self.debug_logger = super_carrier.log_xml
self.carrier = super_carrier
self.session = requests.Session()
def _send_fedex_request(self, url, data, method='POST'):
new_token = False
if not self.access_token:
self.access_token = self._get_new_access_token()
self.carrier.fedex_rest_access_token = self.access_token
new_token = True
def _request_call():
try:
response = self.session.request(method, self.base_url + url, json=data, headers={
'Content-Type': "application/json",
'Authorization': "Bearer " + self.access_token
}, timeout=15
)
self.debug_logger("%s %s\n%s\n\n%s" % (
response.request.method,
response.request.url,
'\n'.join([f'{k}: {v}' for k, v in response.request.headers.items()]),
response.request.body.decode('utf-8')
), 'fedex_rest_request')
self.debug_logger("%s %s\n%s\n\n%s" % (
response.status_code,
response.reason,
'\n'.join([f'{k}: {v}' for k, v in response.headers.items()]),
response.text
), 'fedex_rest_response')
except RequestException:
raise ValidationError(_('Something went wrong, please try again later!!')) from None
return response
res = _request_call()
if res.status_code == 401 and not new_token:
self.access_token = self._get_new_access_token()
self.carrier.fedex_rest_access_token = self.access_token
res = _request_call()
try:
response_data = res.json()
except JSONDecodeError:
raise ValidationError(_('Could not decode response')) from None
if not res.ok:
raise ValidationError(self._process_errors(response_data))
if 'output' not in response_data:
raise ValidationError(_('Could not decode response'))
return response_data['output']
def _process_errors(self, res_body):
err_msgs = []
for err in res_body.get('errors', []):
err_msgs.append(f"{err['message']} ({err['code']})")
return ','.join(err_msgs)
def _process_alerts(self, response):
messages = []
alerts = response.get('alerts', [])
if 'rateReplyDetails' in response:
alerts += response['rateReplyDetails'][0].get('customerMessages', [])
for alert in alerts:
messages.append(f"{alert['message']} ({alert['code']})")
return '\n'.join(messages)
def _get_new_access_token(self):
if not self.client_id or not self.client_secret:
raise ValidationError(_('You must setup a client ID and secret on the carrier first'))
try:
response = self.session.post(
self.base_url + "/oauth/token",
f"grant_type=client_credentials&client_id={self.client_id}&client_secret={self.client_secret}",
headers={'Content-Type': "application/x-www-form-urlencoded"},
timeout=15
)
response_data = response.json()
except RequestException:
raise ValidationError(_('Something went wrong, please try again later!!')) from None
except JSONDecodeError:
raise ValidationError(_('Could not decode response')) from None
if not response.ok:
raise ValidationError(self._process_errors(response_data))
if 'access_token' not in response_data:
raise ValidationError(_('Could not decode response'))
return response_data['access_token']
def _parse_state_code(self, state_code, country_code):
if country_code == 'CH':
# For Switzerland, keep the part before the hyphen
return state_code.split('-')[0]
else:
# For other countries, keep the part after the hyphen
split_code = state_code.split('-')
if split_code[0] == country_code and len(split_code) > 1:
return split_code[1]
else:
return state_code
def _get_location_from_partner(self, partner, check_residential=False):
res = {'countryCode': partner.country_id.code}
if partner.city:
res['city'] = partner.city
if partner.zip:
res['postalCode'] = partner.zip
if partner.state_id:
state_code = self._parse_state_code(partner.state_id.code, partner.country_id.code)
# need to adhere to two character length state code
if partner.country_id.code == 'MX':
state_code = FEDEX_MX_STATE_MATCH[state_code]
if partner.country_id.code == 'AE':
state_code = FEDEX_AE_STATE_MATCH.get(state_code, state_code)
if partner.country_id.code == 'IN' and partner.state_id.code == 'UK':
state_code = 'UT'
if len(state_code) <= 2:
res['stateOrProvinceCode'] = state_code
if check_residential:
setting = self.check_residential
if setting == 'always' or (setting == 'check' and self._check_residential_address({**res, 'streetLines': [partner.street, partner.street2]})):
res['residential'] = True
return res
def _check_residential_address(self, address):
if not address['streetLines'][1]:
del address['streetLines'][1]
result = self._send_fedex_request('/address/v1/addresses/resolve', {
'addressesToValidate': [{'address': address}]
})
return result['resolvedAddresses'][0]['classification'] != 'BUSINESS' # We assume residential until proven otherwise
def _get_address_from_partner(self, partner, check_residential=False):
res = self._get_location_from_partner(partner, check_residential)
res['streetLines'] = [partner.street]
if partner.street2:
res['streetLines'].append(partner.street2)
return res
def _get_contact_from_partner(self, partner, company_partner=False):
res = {'phoneNumber': partner.phone}
if company_partner and not res['phoneNumber']:
# Fallback to phone on the company if none on the WH
res['phoneNumber'] = company_partner.phone
if company_partner:
# Always put the name of the company, if the partner is a WH
res['companyName'] = partner.name[:35]
res['personName'] = partner.name[:70]
elif partner.is_company:
res['companyName'] = partner.name[:35]
res['personName'] = partner.name[:70]
else:
res['personName'] = partner.name[:70]
if partner.parent_id:
res['companyName'] = partner.parent_id.name[:35]
elif partner.company_name:
res['companyName'] = partner.company_name[:35]
if partner.email:
res['emailAddress'] = partner.email
elif company_partner and company_partner.email:
res['emailAddress'] = company_partner.email
return res
def _get_package_info(self, package):
res = {
'weight': {
'units': self.weight_units,
'value': self.carrier._fedex_rest_convert_weight(package.weight)
},
}
if int(package.dimension['length']) or int(package.dimension['width']) or int(package.dimension['height']):
# FedEx will raise a warning when mixing imperial and metric units (MIXED.MEASURING.UNITS.INCLUDED).
# So we force the dimension unit based on the selected weight unit on the delivery method.
res['dimensions'] = {
'units': 'IN' if self.weight_units == 'LB' else 'CM',
'length': int(package.dimension['length']),
'width': int(package.dimension['width']),
'height': int(package.dimension['height']),
}
if self.insurance:
res['declaredValue'] = {
'amount': float_repr(package.total_cost * self.insurance / 100, 2),
'currency': _convert_curr_iso_fdx(package.currency_id.name),
}
return res
def _get_detailed_package_info(self, package, customPackaging, order_no=False):
res = self._get_package_info(package)
if customPackaging:
res['subPackagingType'] = 'PACKAGE'
description = ', '.join([c.product_id.name for c in package.commodities])
res['itemDescription'] = description[:50]
res['itemDescriptionForClearance'] = description
if order_no:
res['customerReferences'] = [{
'customerReferenceType': 'P_O_NUMBER',
'value': order_no
}]
return res
def _get_commodities_info(self, commodity, currency):
res = {
'description': commodity.product_id.name[:450],
'customsValue': ({'amount': commodity.monetary_value * commodity.qty, 'currency': currency}),
'unitPrice': ({'amount': commodity.monetary_value, 'currency': currency}),
'countryOfManufacture': commodity.country_of_origin,
'weight': {
'units': self.weight_units,
'value': self.carrier._fedex_rest_convert_weight(commodity.product_id.weight),
},
'quantity': commodity.qty,
'quantityUnits': commodity.product_id.uom_id.fedex_code,
'numberOfPieces': 1,
}
if commodity.product_id.hs_code:
res['harmonizedCode'] = commodity.product_id.hs_code
return res
def _get_tins_from_partner(self, partner, custom_vat=False):
res = []
if custom_vat:
res.append({
'number': self.vat_override,
'tinType': 'BUSINESS_UNION'
})
if partner.vat and partner.is_company:
res.append({'number': partner.vat, 'tinType': 'BUSINESS_NATIONAL'})
elif partner.parent_id and partner.parent_id.vat and partner.parent_id.is_company:
res.append({'number': partner.parent_id.vat, 'tinType': 'BUSINESS_NATIONAL'})
return res
def _get_shipping_price(self, ship_from, ship_to, packages, currency):
fedex_currency = _convert_curr_iso_fdx(currency)
request_data = {
'accountNumber': {'value': self.account_number},
'requestedShipment': {
'rateRequestType': ['PREFERRED'],
'preferredCurrency': fedex_currency,
'pickupType': self.dropoff_type,
'serviceType': self.service_type,
'packagingType': packages[0].packaging_type,
'shipper': {'address': self._get_location_from_partner(ship_from)},
'recipient': {'address': self._get_location_from_partner(ship_to, True)},
'requestedPackageLineItems': [self._get_package_info(p) for p in packages],
'customsClearanceDetail': {
'commercialInvoice': {'shipmentPurpose': 'SOLD'},
'commodities': [self._get_commodities_info(c, fedex_currency) for pkg in packages for c in pkg.commodities],
'freightOnValue': 'CARRIER_RISK' if self.insurance == 100 else 'OWN_RISK',
'dutiesPayment': {'paymentType': 'SENDER'} # Only allowed value...
}
}
}
self._add_extra_data_to_request(request_data, 'rate')
res = self._send_fedex_request("/rate/v1/rates/quotes", request_data)
try:
rate = next(filter(lambda d: d['currency'] == fedex_currency, res['rateReplyDetails'][0]['ratedShipmentDetails']), {})
if rate.get('totalNetChargeWithDutiesAndTaxes', 0):
price = rate['totalNetChargeWithDutiesAndTaxes']
else:
price = rate['totalNetCharge']
except KeyError:
raise ValidationError(_('Could not decode response')) from None
return {
'price': price,
'alert_message': self._process_alerts(res),
}
def _ship_package(self, ship_from_wh, ship_from_company, ship_to, sold_to, packages, currency, order_no, customer_ref, picking_no, incoterms, freight_charge):
fedex_currency = _convert_curr_iso_fdx(currency)
package_type = packages[0].packaging_type
request_data = {
'accountNumber': {'value': self.account_number},
'labelResponseOptions': 'LABEL',
'requestedShipment': {
'rateRequestType': ['PREFERRED'],
'preferredCurrency': fedex_currency,
'pickupType': self.dropoff_type,
'serviceType': self.service_type,
'packagingType': package_type,
'shippingChargesPayment': {'paymentType': 'SENDER'},
'labelSpecification': {'labelStockType': self.label_stock, 'imageType': self.label_file},
'shipper': {
'address': self._get_address_from_partner(ship_from_wh),
'contact': self._get_contact_from_partner(ship_from_wh, ship_from_company),
'tins': self._get_tins_from_partner(ship_from_company, self.vat_override),
},
'recipients': [{
'address': self._get_address_from_partner(ship_to, True),
'contact': self._get_contact_from_partner(ship_to),
'tins': self._get_tins_from_partner(ship_to),
}],
'requestedPackageLineItems': [self._get_detailed_package_info(p, package_type == 'YOUR_PACKAGING', order_no) for p in packages],
'customsClearanceDetail': {
'dutiesPayment': {'paymentType': self.duty_payment},
'commodities': [self._get_commodities_info(c, fedex_currency) for pkg in packages for c in pkg.commodities],
'commercialInvoice': {
'shipmentPurpose': 'SOLD',
'originatorName': ship_from_company.name,
'comments': ['', picking_no], # First one is special instructions
},
}
}
}
if freight_charge:
request_data['requestedShipment']['customsClearanceDetail']['commercialInvoice']['freightCharge'] = {
'amount': freight_charge,
'currency': fedex_currency,
}
if incoterms:
request_data['requestedShipment']['customsClearanceDetail']['commercialInvoice']['termsOfSale'] = incoterms
if customer_ref:
request_data['requestedShipment']['customsClearanceDetail']['commercialInvoice']['customerReferences'] = [{
'customerReferenceType': 'CUSTOMER_REFERENCE',
'value': customer_ref,
}]
if request_data['requestedShipment']['shipper']['address']['countryCode'] == 'IN' and request_data['requestedShipment']['recipients'][0]['address']['countryCode'] == 'IN':
request_data['requestedShipment']['customsClearanceDetail']['freightOnValue'] = 'CARRIER_RISK' if self.insurance == 100 else 'OWN_RISK'
if sold_to and sold_to != ship_to:
request_data['requestedShipment']['soldTo'] = {
'address': self._get_address_from_partner(sold_to),
'contact': self._get_contact_from_partner(sold_to),
'tins': self._get_tins_from_partner(sold_to),
}
if ship_to.vat or ship_to.parent_id.vat:
request_data['requestedShipment']['customsClearanceDetail']['recipientCustomsId'] = {
'type': 'COMPANY',
'value': ship_to.vat or ship_to.parent_id.vat,
}
if self.email_notifications and ship_to.email:
request_data['requestedShipment']['emailNotificationDetail'] = {
'aggregationType': 'PER_PACKAGE',
'emailNotificationRecipients': [{
'emailNotificationRecipientType': 'RECIPIENT',
'emailAddress': ship_to.email,
'name': ship_to.name,
'notificationFormatType': 'HTML',
'notificationType': 'EMAIL',
'notificationEventType': ['ON_DELIVERY', 'ON_EXCEPTION', 'ON_SHIPMENT', 'ON_TENDER', 'ON_ESTIMATED_DELIVERY']
}]
}
if self.documentation_type != 'none':
request_data['requestedShipment']['shippingDocumentSpecification'] = {
'shippingDocumentTypes': ['COMMERCIAL_INVOICE'],
'commercialInvoiceDetail': {
'documentFormat': {'stockType': 'PAPER_LETTER', 'docType': 'PDF'}
}
}
if self.documentation_type == 'etd':
request_data['requestedShipment']['shipmentSpecialServices'] = {
"specialServiceTypes": [
"ELECTRONIC_TRADE_DOCUMENTS"
],
"etdDetail": {
"requestedDocumentTypes": [
"COMMERCIAL_INVOICE"
]
}
}
if self.make_return:
request_data['requestedShipment']['customsClearanceDetail']['customsOption'] = {'type': 'COURTESY_RETURN_LABEL'}
self._add_extra_data_to_request(request_data, 'ship')
res = self._send_fedex_request("/ship/v1/shipments", request_data)
try:
shipment = res['transactionShipments'][0]
details = shipment['completedShipmentDetail']
pieces = shipment['pieceResponses']
# Sometimes the shipment might be created but no pricing calculated, we just set to 0.
price = self._decode_pricing(details['shipmentRating']) if 'shipmentRating' in details else 0.0
except KeyError:
raise ValidationError(_('Could not decode response')) from None
return {
'service_info': f"{details.get('carrierCode', '')} > {details.get('serviceDescription', {}).get('description', '')} > {details.get('packagingDescription', '')}",
'tracking_numbers': ','.join([
t.get('trackingNumber', '')
for pkg in details.get('completedPackageDetails', [])
for t in pkg.get('trackingIds', [])
]),
'labels': [
(
p.get('trackingNumber', ''),
next(filter(lambda d: d.get('contentType', '') == 'LABEL', p.get('packageDocuments', {})), {}).get('encodedLabel')
)
for p in pieces
],
'price': price,
'documents': ', '.join([
f"{d.get('minimumCopiesRequired')}x {d.get('type', '')}"
for d in details.get('documentRequirements', {}).get('generationDetails', {})
if d.get('minimumCopiesRequired', 0)
]),
'alert_message': self._process_alerts(shipment),
'invoice': next(filter(
lambda d: d.get('contentType', '') == 'COMMERCIAL_INVOICE',
shipment.get('shipmentDocuments', {})
), {}).get('encodedLabel', ''),
'date': shipment.get('shipDatestamp', ''),
}
def _return_package(self, ship_from, ship_to_company, ship_to_wh, packages, currency, tracking, date):
fedex_currency = _convert_curr_iso_fdx(currency)
package_type = packages[0].packaging_type
request_data = {
'accountNumber': {'value': self.account_number},
'labelResponseOptions': 'LABEL',
'requestedShipment': {
'rateRequestType': ['PREFERRED'],
'preferredCurrency': fedex_currency,
'pickupType': self.dropoff_type,
'serviceType': self.service_type,
'packagingType': package_type,
'shippingChargesPayment': {'paymentType': 'SENDER'},
'shipmentSpecialServices': {
'specialServiceTypes': ['RETURN_SHIPMENT'],
'returnShipmentDetail': {
'returnType': 'PRINT_RETURN_LABEL',
'returnAssociationDetail': {'trackingNumber': tracking, 'shipDatestamp': date},
}
},
'labelSpecification': {'labelStockType': self.label_stock, 'imageType': self.label_file},
'shipper': {
'address': self._get_address_from_partner(ship_from),
'contact': self._get_contact_from_partner(ship_from),
'tins': self._get_tins_from_partner(ship_from),
},
'recipients': [{
'address': self._get_address_from_partner(ship_to_wh, True),
'contact': self._get_contact_from_partner(ship_to_wh, ship_to_company),
'tins': self._get_tins_from_partner(ship_to_company, self.vat_override),
}],
'requestedPackageLineItems': [self._get_detailed_package_info(p, package_type == 'YOUR_PACKAGING') for p in packages],
'customsClearanceDetail': {
'dutiesPayment': {'paymentType': 'SENDER'}, # Only allowed value for returns
'commodities': [self._get_commodities_info(c, fedex_currency) for pkg in packages for c in pkg.commodities],
'customsOption': {'type': 'REJECTED'},
}
}
}
if request_data['requestedShipment']['shipper']['address']['countryCode'] == 'IN' and request_data['requestedShipment']['recipients'][0]['address']['countryCode'] == 'IN':
request_data['requestedShipment']['customsClearanceDetail']['freightOnValue'] = 'CARRIER_RISK' if self.insurance == 100 else 'OWN_RISK'
if self.vat_override or ship_to_company.vat:
request_data['requestedShipment']['customsClearanceDetail']['recipientCustomsId'] = {
'type': 'COMPANY',
'value': self.vat_override or ship_to_company.vat,
}
self._add_extra_data_to_request(request_data, 'return')
res = self._send_fedex_request("/ship/v1/shipments", request_data)
try:
shipment = res['transactionShipments'][0]
details = shipment['completedShipmentDetail']
pieces = shipment['pieceResponses']
except KeyError:
raise ValidationError(_('Could not decode response')) from None
return {
'tracking_numbers': ','.join([
t.get('trackingNumber', '')
for pkg in details.get('completedPackageDetails', [])
for t in pkg.get('trackingIds', [])
]),
'labels': [
(
p.get('trackingNumber', ''),
next(filter(lambda d: d.get('contentType', '') == 'LABEL', p.get('packageDocuments', {})), {}).get('encodedLabel')
)
for p in pieces
],
'documents': ', '.join([
f"{d.get('minimumCopiesRequired')}x {d.get('type', '')}"
for d in details.get('documentRequirements', {}).get('generationDetails', {})
if d.get('minimumCopiesRequired', 0)
]),
'alert_message': self._process_alerts(shipment),
}
def _decode_pricing(self, rating_result):
actual = next(filter(lambda d: d['rateType'] == rating_result['actualRateType'], rating_result['shipmentRateDetails']), {})
if actual.get('totalNetChargeWithDutiesAndTaxes', False):
return actual['totalNetChargeWithDutiesAndTaxes']
return actual['totalNetCharge']
def cancel_shipment(self, tracking_nr):
res = self._send_fedex_request('/ship/v1/shipments/cancel', {
'accountNumber': {'value': self.account_number},
'deletionControl': 'DELETE_ALL_PACKAGES', # Cancel the entire shipment, not only the individual package.
'trackingNumber': tracking_nr,
}, 'PUT')
if not res.get('cancelledShipment', False):
return {
'delete_success': False,
'errors_message': res.get('message', 'Cancel shipment failed. Reason unknown.'),
}
return {
'delete_success': True,
'alert_message': self._process_alerts(res),
}
def _add_extra_data_to_request(self, request, request_type):
"""Adds the extra data to the request.
When there are multiple items in a list, they will all be affected by
the change.
"""
extra_data_input = {
'rate': self.carrier.fedex_rest_extra_data_rate_request,
'ship': self.carrier.fedex_rest_extra_data_ship_request,
'return': self.carrier.fedex_rest_extra_data_return_request,
}.get(request_type) or ''
try:
extra_data = json.loads('{' + extra_data_input + '}')
except SyntaxError:
raise UserError(_('Invalid syntax for FedEx extra data.')) from None
def extra_data_to_request(request, extra_data):
"""recursive function that adds extra data to the current request."""
for key, new_value in extra_data.items():
request[key] = current_value = request.get(key)
if isinstance(current_value, list):
for item in current_value:
extra_data_to_request(item, new_value)
elif isinstance(new_value, dict) and isinstance(current_value, dict):
extra_data_to_request(current_value, new_value)
else:
request[key] = new_value
extra_data_to_request(request, extra_data)
def _convert_curr_fdx_iso(code):
curr_match = {v: k for k, v in FEDEX_CURR_MATCH.items()}
return curr_match.get(code, code)
def _convert_curr_iso_fdx(code):
return FEDEX_CURR_MATCH.get(code, code)
def _convert_stock_type(stock_type):
return FEDEX_STOCK_TYPE_MATCH.get(stock_type, stock_type)

View File

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

View File

@@ -0,0 +1,637 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import base64
import binascii
import io
import PIL.PdfImagePlugin # activate PDF support in PIL
from PIL import Image
import logging
import os
import re
from odoo.tools.zeep import Client, Plugin
from odoo.tools.zeep.exceptions import Fault
from odoo.tools.zeep.wsdl.utils import etree_to_string
from odoo.tools import _, LazyTranslate
from odoo.tools.float_utils import float_repr
from odoo.exceptions import UserError
_lt = LazyTranslate(__name__)
_logger = logging.getLogger(__name__)
# uncomment to enable logging of SOAP requests and responses
# logging.getLogger('zeep.transports').setLevel(logging.DEBUG)
UPS_ERROR_MAP = {
'110002': _lt("Please provide at least one item to ship."),
'110208': _lt("Please set a valid country in the recipient address."),
'110308': _lt("Please set a valid country in the warehouse address."),
'110548': _lt("A shipment cannot have a KGS/IN or LBS/CM as its unit of measurements. Configure it from the delivery method."),
'111057': _lt("This measurement system is not valid for the selected country. Please switch from LBS/IN to KGS/CM (or vice versa). Configure it from the delivery method."),
'111091': _lt("The selected service is not possible from your warehouse to the recipient address, please choose another service."),
'111100': _lt("The selected service is invalid from the requested warehouse, please choose another service."),
'111107': _lt("Please provide a valid zip code in the warehouse address."),
'111210': _lt("The selected service is invalid to the recipient address, please choose another service."),
'111212': _lt("Please provide a valid package type available for service and selected locations."),
'111500': _lt("The selected service is not valid with the selected packaging."),
'112111': _lt("Please provide a valid shipper number/Carrier Account."),
'113020': _lt("Please provide a valid zip code in the warehouse address."),
'113021': _lt("Please provide a valid zip code in the recipient address."),
'120031': _lt("Exceeds Total Number of allowed pieces per World Wide Express Shipment."),
'120100': _lt("Please provide a valid shipper number/Carrier Account."),
'120102': _lt("Please provide a valid street in shipper's address."),
'120105': _lt("Please provide a valid city in the shipper's address."),
'120106': _lt("Please provide a valid state in the shipper's address."),
'120107': _lt("Please provide a valid zip code in the shipper's address."),
'120108': _lt("Please provide a valid country in the shipper's address."),
'120109': _lt("Please provide a valid shipper phone number."),
'120113': _lt("Shipper number must contain alphanumeric characters only."),
'120114': _lt("Shipper phone extension cannot exceed the length of 4."),
'120115': _lt("Shipper Phone must be at least 10 alphanumeric characters."),
'120116': _lt("Shipper phone extension must contain only numbers."),
'120122': _lt("Please provide a valid shipper Number/Carrier Account."),
'120124': _lt("The requested service is unavailable between the selected locations."),
'120202': _lt("Please provide a valid street in the recipient address."),
'120205': _lt("Please provide a valid city in the recipient address."),
'120206': _lt("Please provide a valid state in the recipient address."),
'120207': _lt("Please provide a valid zipcode in the recipient address."),
'120208': _lt("Please provide a valid Country in recipient's address."),
'120209': _lt("Please provide a valid phone number for the recipient."),
'120212': _lt("Recipient PhoneExtension cannot exceed the length of 4."),
'120213': _lt("Recipient Phone must be at least 10 alphanumeric characters."),
'120214': _lt("Recipient PhoneExtension must contain only numbers."),
'120302': _lt("Please provide a valid street in the warehouse address."),
'120305': _lt("Please provide a valid City in the warehouse address."),
'120306': _lt("Please provide a valid State in the warehouse address."),
'120307': _lt("Please provide a valid Zip in the warehouse address."),
'120308': _lt("Please provide a valid Country in the warehouse address."),
'120309': _lt("Please provide a valid warehouse Phone Number"),
'120312': _lt("Warehouse PhoneExtension cannot exceed the length of 4."),
'120313': _lt("Warehouse Phone must be at least 10 alphanumeric characters."),
'120314': _lt("Warehouse Phone must contain only numbers."),
'120412': _lt("Please provide a valid shipper Number/Carrier Account."),
'121057': _lt("This measurement system is not valid for the selected country. Please switch from LBS/IN to KGS/CM (or vice versa). Configure it from delivery method"),
'121210': _lt("The requested service is unavailable between the selected locations."),
'128089': _lt("Access License number is Invalid. Provide a valid number (Length should be 0-35 alphanumeric characters)"),
'190001': _lt("Cancel shipment not available at this time , Please try again Later."),
'190100': _lt("Provided Tracking Ref. Number is invalid."),
'190109': _lt("Provided Tracking Ref. Number is invalid."),
'250001': _lt("Access License number is invalid for this provider.Please re-license."),
'250002': _lt("Username/Password is invalid for this delivery provider."),
'250003': _lt("Access License number is invalid for this delivery provider."),
'250004': _lt("Username/Password is invalid for this delivery provider."),
'250006': _lt("The maximum number of user access attempts was exceeded. So please try again later"),
'250007': _lt("The UserId is currently locked out; please try again in 24 hours."),
'250009': _lt("Provided Access License Number not found in the UPS database"),
'250038': _lt("Please provide a valid shipper number/Carrier Account."),
'250047': _lt("Access License number is revoked contact UPS to get access."),
'250052': _lt("Authorization system is currently unavailable , try again later."),
'250053': _lt("UPS Server Not Found"),
'9120200': _lt("Please provide at least one item to ship")
}
class LogPlugin(Plugin):
""" Small plugin for zeep that catches out/ingoing XML requests and logs them"""
def __init__(self, debug_logger):
self.debug_logger = debug_logger
def egress(self, envelope, http_headers, operation, binding_options):
self.debug_logger(etree_to_string(envelope).decode(), 'ups_request')
return envelope, http_headers
def ingress(self, envelope, http_headers, operation):
self.debug_logger(etree_to_string(envelope).decode(), 'ups_response')
return envelope, http_headers
class FixRequestNamespacePlug(Plugin):
def __init__(self, root):
self.root = root
def marshalled(self, context):
context.envelope = context.envelope.prune()
class UPSRequest():
def __init__(self, debug_logger, username, password, shipper_number, access_number, prod_environment):
self.debug_logger = debug_logger
# Product and Testing url
self.endurl = "https://onlinetools.ups.com/webservices/"
if not prod_environment:
self.endurl = "https://wwwcie.ups.com/webservices/"
# Basic detail require to authenticate
self.username = username
self.password = password
self.shipper_number = shipper_number
self.access_number = access_number
self.rate_wsdl = '../wsdl/RateWS.wsdl'
self.ship_wsdl = '../wsdl/Ship.wsdl'
self.void_wsdl = '../wsdl/Void.wsdl'
self.ns = {'err': "http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1"}
def _add_security_header(self, client, api):
# set the detail which require to authenticate
user_token = {'Username': self.username, 'Password': self.password}
access_token = {'AccessLicenseNumber': self.access_number}
security = client._Client__obj.get_element('ns0:UPSSecurity')(UsernameToken=user_token, ServiceAccessToken=access_token)
client._Client__obj.set_default_soapheaders([security])
def _set_service(self, client, api):
service = client.create_service(
next(iter(client._Client__obj.wsdl.bindings)),
'%s%s' % (self.endurl, api))
return service
def _set_client(self, wsdl, api, root):
wsdl_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), wsdl)
client = Client(wsdl_path, plugins=[FixRequestNamespacePlug(root), LogPlugin(self.debug_logger)])
self.factory_ns2 = client.type_factory('ns2')
self.factory_ns3 = client.type_factory('ns3')
# ns4 only exists for Ship API - we only use it for the invoice
self.factory_ns4 = client.type_factory('ns4') if api == 'Ship' else self.factory_ns3
self._add_security_header(client, api)
return client
def _clean_phone_number(self, phone):
return re.sub('[^0-9]','', phone)
def check_required_value(self, shipper, ship_from, ship_to, order=False, picking=False):
required_field = {'city': 'City', 'country_id': 'Country', 'phone': 'Phone'}
# Check required field for shipper
res = [required_field[field] for field in required_field if not shipper[field]]
if shipper.country_id.code in ('US', 'CA', 'IE') and not shipper.state_id.code:
res.append('State')
if not shipper.street and not shipper.street2:
res.append('Street')
if shipper.country_id.code != 'HK' and not shipper.zip:
res.append('ZIP code')
if res:
return _("The address of your company is missing or wrong.\n(Missing field(s) : %s)", ",".join(res))
if len(self._clean_phone_number(shipper.phone)) < 10:
return str(UPS_ERROR_MAP.get('120115'))
# Check required field for warehouse address
res = [required_field[field] for field in required_field if not ship_from[field]]
if ship_from.country_id.code in ('US', 'CA', 'IE') and not ship_from.state_id.code:
res.append('State')
if not ship_from.street and not ship_from.street2:
res.append('Street')
if ship_from.country_id.code != 'HK' and not ship_from.zip:
res.append('ZIP code')
if res:
return _("The address of your warehouse is missing or wrong.\n(Missing field(s) : %s)", ",".join(res))
if len(self._clean_phone_number(ship_from.phone)) < 10:
return str(UPS_ERROR_MAP.get('120313'))
# Check required field for recipient address
res = [required_field[field] for field in required_field if field != 'phone' and not ship_to[field]]
if ship_to.country_id.code in ('US', 'CA', 'IE') and not ship_to.state_id.code:
res.append('State')
# The street isn't required if we compute the rate with a partial delivery address in the
# express checkout flow.
if not ship_to.street and not ship_to.street2 and not ship_to.env.context.get(
'express_checkout_partial_delivery_address', False
):
res.append('Street')
if ship_to.country_id.code != 'HK' and not ship_to.zip:
res.append('ZIP code')
if len(ship_to.street or '') > 35 or len(ship_to.street2 or '') > 35:
return _("UPS address lines can only contain a maximum of 35 characters. You can split the contacts addresses on multiple lines to try to avoid this limitation.")
if picking and not order:
order = picking.sale_id
phone = ship_to.phone
if order and not phone:
phone = order.partner_id.phone
if order:
if not order.order_line:
return _("Please provide at least one item to ship.")
error_lines = order.order_line._get_invalid_delivery_weight_lines()
if error_lines:
return _("The estimated shipping price cannot be computed because the weight is missing for the following product(s): \n %s", ", ".join(error_lines.product_id.mapped('name')))
if picking:
if not all(ml.result_package_id or ml.product_id.weight for ml in picking.move_line_ids):
return _("The delivery cannot be done because the weight of your product is missing.")
packages_without_weight = picking.move_line_ids.mapped('result_package_id').filtered(lambda p: not p.shipping_weight)
if packages_without_weight:
return _('Packages %s do not have a positive shipping weight.', ', '.join(packages_without_weight.mapped('display_name')))
# The phone isn't required if we compute the rate with a partial delivery address in the
# express checkout flow.
if not phone and not ship_to.env.context.get(
'express_checkout_partial_delivery_address', False
):
res.append('Phone')
if res:
return _("The recipient address is missing or wrong.\n(Missing field(s) : %s)", ",".join(res))
# The phone isn't required if we compute the rate with a partial delivery address in the
# express checkout flow.
if not ship_to.env.context.get(
'express_checkout_partial_delivery_address', False
) and len(self._clean_phone_number(phone)) < 10:
return str(UPS_ERROR_MAP.get('120213'))
return False
def get_error_message(self, error_code, description):
result = {}
result['error_message'] = str(UPS_ERROR_MAP.get(error_code))
if result['error_message'] == "None":
result['error_message'] = description
return result
def save_label(self, image64, label_file_type='GIF'):
img_decoded = base64.decodebytes(image64.encode('utf-8'))
if label_file_type == 'GIF':
# Label format is GIF, so need to rotate and convert as PDF
image_string = io.BytesIO(img_decoded)
im = Image.open(image_string)
label_result = io.BytesIO()
im.save(label_result, 'pdf')
return label_result.getvalue()
else:
return img_decoded
def set_package_detail(self, carrier, client, packages, ship_from, ship_to, cod_info, request_type):
Packages = []
if request_type == "rating":
MeasurementType = self.factory_ns2.CodeDescriptionType
elif request_type == "shipping":
MeasurementType = self.factory_ns2.ShipUnitOfMeasurementType
for p in packages:
package = self.factory_ns2.PackageType()
if hasattr(package, 'Packaging'):
package.Packaging = self.factory_ns2.PackagingType()
package.Packaging.Code = p.packaging_type or ''
elif hasattr(package, 'PackagingType'):
package.PackagingType = self.factory_ns2.CodeDescriptionType()
package.PackagingType.Code = p.packaging_type or ''
package.Dimensions = self.factory_ns2.DimensionsType()
package.Dimensions.UnitOfMeasurement = MeasurementType()
package.Dimensions.UnitOfMeasurement.Code = carrier.ups_package_dimension_unit
package.Dimensions.Length = p.dimension['length']
package.Dimensions.Width = p.dimension['width']
package.Dimensions.Height = p.dimension['height']
package.PackageServiceOptions = self.factory_ns2.PackageServiceOptionsType()
if cod_info:
package.PackageServiceOptions.COD = self.factory_ns2.CODType()
package.PackageServiceOptions.COD.CODFundsCode = str(cod_info['funds_code'])
package.PackageServiceOptions.COD.CODAmount = self.factory_ns2.CODAmountType() if request_type == 'rating' else self.factory_ns2.CurrencyMonetaryType()
package.PackageServiceOptions.COD.CODAmount.MonetaryValue = cod_info['monetary_value']
package.PackageServiceOptions.COD.CODAmount.CurrencyCode = cod_info['currency']
if p.currency_id:
package.PackageServiceOptions.DeclaredValue = self.factory_ns2.InsuredValueType() if request_type == 'rating' else self.factory_ns2.PackageDeclaredValueType()
package.PackageServiceOptions.DeclaredValue.CurrencyCode = p.currency_id.name
package.PackageServiceOptions.DeclaredValue.MonetaryValue = float_repr(p.total_cost * carrier.shipping_insurance / 100, 2)
if request_type == "shipping":
package.PackageServiceOptions.DeclaredValue.Type = self.factory_ns2.DeclaredValueType()
package.PackageServiceOptions.DeclaredValue.Type.Code = '01' # EVS
package.PackageWeight = self.factory_ns2.PackageWeightType()
package.PackageWeight.UnitOfMeasurement = MeasurementType()
package.PackageWeight.UnitOfMeasurement.Code = carrier.ups_package_weight_unit
package.PackageWeight.Weight = carrier._ups_convert_weight(p.weight, carrier.ups_package_weight_unit)
# Package and shipment reference text is only allowed for shipments within
# the USA and within Puerto Rico. This is a UPS limitation.
if (p.name and not ' ' in p.name and ship_from.country_id.code in ('US') and ship_to.country_id.code in ('US')):
reference_number = self.factory_ns2.ReferenceNumberType()
reference_number.Code = 'PM'
reference_number.Value = p.name
reference_number.BarCodeIndicator = p.name
package.ReferenceNumber = reference_number
Packages.append(package)
return Packages
def set_invoice(self, shipment_info, commodities, ship_to):
invoice_products = []
for commodity in commodities:
uom_type = self.factory_ns4.UnitOfMeasurementType()
uom_type.Code = 'PC' if commodity.qty == 1 else 'PCS'
unit_type = self.factory_ns4.UnitType()
unit_type.Number = int(commodity.qty)
unit_type.Value = float_repr(commodity.monetary_value, 2)
unit_type.UnitOfMeasurement = uom_type
product = self.factory_ns4.ProductType()
# split the name of the product to maximum 3 substrings of length 35
name = commodity.product_id.name
product.Description = [line for line in [name[35 * i:35 * (i + 1)] for i in range(3)] if line]
product.Unit = unit_type
product.OriginCountryCode = commodity.country_of_origin
product.CommodityCode = commodity.product_id.hs_code or ''
invoice_products.append(product)
address_sold_to = self.factory_ns4.AddressType()
address_sold_to.AddressLine = [line for line in (ship_to.street, ship_to.street2) if line]
address_sold_to.City = ship_to.city or ''
address_sold_to.PostalCode = ship_to.zip or ''
address_sold_to.CountryCode = ship_to.country_id.code or ''
if ship_to.country_id.code in ('US', 'CA', 'IE'):
address_sold_to.StateProvinceCode = ship_to.state_id.code or ''
sold_to = self.factory_ns4.SoldToType()
if len(ship_to.commercial_partner_id.name) > 35:
raise UserError(_('The name of the customer should be no more than 35 characters.'))
sold_to.Name = ship_to.commercial_partner_id.name
sold_to.AttentionName = ship_to.name
sold_to.Address = address_sold_to
contact = self.factory_ns4.ContactType()
contact.SoldTo = sold_to
invoice = self.factory_ns4.InternationalFormType()
invoice.FormType = '01' # Invoice
invoice.Product = invoice_products
invoice.CurrencyCode = shipment_info.get('itl_currency_code')
invoice.InvoiceDate = shipment_info.get('invoice_date')
invoice.ReasonForExport = 'RETURN' if shipment_info.get('is_return', False) else 'SALE'
invoice.Contacts = contact
return invoice
def get_shipping_price(self, carrier, shipment_info, packages, shipper, ship_from, ship_to, service_type, saturday_delivery, cod_info):
client = self._set_client(self.rate_wsdl, 'Rate', 'RateRequest')
service = self._set_service(client, 'Rate')
request = self.factory_ns3.RequestType()
request.RequestOption = 'Rate'
classification = self.factory_ns2.CodeDescriptionType()
classification.Code = '00' # Get rates for the shipper account
classification.Description = 'Get rates for the shipper account'
request_type = "rating"
shipment = self.factory_ns2.ShipmentType()
for package in self.set_package_detail(carrier, client, packages, ship_from, ship_to, cod_info, request_type):
shipment.Package.append(package)
shipment.Shipper = self.factory_ns2.ShipperType()
shipment.Shipper.Name = shipper.name or ''
shipment.Shipper.Address = self.factory_ns2.AddressType()
shipment.Shipper.Address.AddressLine = [shipper.street or '', shipper.street2 or '']
shipment.Shipper.Address.City = shipper.city or ''
shipment.Shipper.Address.PostalCode = shipper.zip or ''
shipment.Shipper.Address.CountryCode = shipper.country_id.code or ''
if shipper.country_id.code in ('US', 'CA', 'IE'):
shipment.Shipper.Address.StateProvinceCode = shipper.state_id.code or ''
shipment.Shipper.ShipperNumber = self.shipper_number or ''
# shipment.Shipper.Phone.Number = shipper.phone or ''
shipment.ShipFrom = self.factory_ns2.ShipFromType()
shipment.ShipFrom.Name = ship_from.name or ''
shipment.ShipFrom.Address = self.factory_ns2.AddressType()
shipment.ShipFrom.Address.AddressLine = [ship_from.street or '', ship_from.street2 or '']
shipment.ShipFrom.Address.City = ship_from.city or ''
shipment.ShipFrom.Address.PostalCode = ship_from.zip or ''
shipment.ShipFrom.Address.CountryCode = ship_from.country_id.code or ''
if ship_from.country_id.code in ('US', 'CA', 'IE'):
shipment.ShipFrom.Address.StateProvinceCode = ship_from.state_id.code or ''
# shipment.ShipFrom.Phone.Number = ship_from.phone or ''
shipment.ShipTo = self.factory_ns2.ShipToType()
shipment.ShipTo.Name = ship_to.name or ''
shipment.ShipTo.Address = self.factory_ns2.AddressType()
shipment.ShipTo.Address.AddressLine = [ship_to.street or '', ship_to.street2 or '']
shipment.ShipTo.Address.City = ship_to.city or ''
shipment.ShipTo.Address.PostalCode = ship_to.zip or ''
shipment.ShipTo.Address.CountryCode = ship_to.country_id.code or ''
if ship_to.country_id.code in ('US', 'CA', 'IE'):
shipment.ShipTo.Address.StateProvinceCode = ship_to.state_id.code or ''
# shipment.ShipTo.Phone.Number = ship_to.phone or ''
if not ship_to.commercial_partner_id.is_company:
shipment.ShipTo.Address.ResidentialAddressIndicator = None
shipment.Service = self.factory_ns2.CodeDescriptionType()
shipment.Service.Code = service_type or ''
shipment.Service.Description = 'Service Code'
if service_type == "96":
shipment.NumOfPieces = int(shipment_info.get('total_qty'))
if saturday_delivery:
shipment.ShipmentServiceOptions = self.factory_ns2.ShipmentServiceOptionsType()
shipment.ShipmentServiceOptions.SaturdayDeliveryIndicator = saturday_delivery
else:
shipment.ShipmentServiceOptions = ''
shipment.ShipmentRatingOptions = self.factory_ns2.ShipmentRatingOptionsType()
shipment.ShipmentRatingOptions.NegotiatedRatesIndicator = 1
try:
# Get rate using for provided detail
response = service.ProcessRate(Request=request, CustomerClassification=classification, Shipment=shipment)
# Check if ProcessRate is not success then return reason for that
if response.Response.ResponseStatus.Code != "1":
return self.get_error_message(response.Response.ResponseStatus.Code, response.Response.ResponseStatus.Description)
rate = response.RatedShipment[0]
charge = rate.TotalCharges
# Some users are qualified to receive negotiated rates
if 'NegotiatedRateCharges' in rate and rate.NegotiatedRateCharges and rate.NegotiatedRateCharges.TotalCharge.MonetaryValue:
charge = rate.NegotiatedRateCharges.TotalCharge
return {
'currency_code': charge.CurrencyCode,
'price': charge.MonetaryValue,
}
except Fault as e:
code = e.detail.xpath("//err:PrimaryErrorCode/err:Code", namespaces=self.ns)[0].text
description = e.detail.xpath("//err:PrimaryErrorCode/err:Description", namespaces=self.ns)[0].text
return self.get_error_message(code, description)
except IOError as e:
return self.get_error_message('0', 'UPS Server Not Found:\n%s' % e)
def send_shipping(self, carrier, shipment_info, packages, shipper, ship_from, ship_to, service_type, saturday_delivery, duty_payment, cod_info=None, label_file_type='GIF', ups_carrier_account=False):
client = self._set_client(self.ship_wsdl, 'Ship', 'ShipmentRequest')
request = self.factory_ns3.RequestType()
request.RequestOption = 'nonvalidate'
request_type = "shipping"
label = self.factory_ns2.LabelSpecificationType()
label.LabelImageFormat = self.factory_ns2.LabelImageFormatType()
label.LabelImageFormat.Code = label_file_type
label.LabelImageFormat.Description = label_file_type
if label_file_type != 'GIF':
label.LabelStockSize = self.factory_ns2.LabelStockSizeType()
label.LabelStockSize.Height = '6'
label.LabelStockSize.Width = '4'
shipment = self.factory_ns2.ShipmentType()
shipment.Description = shipment_info.get('description')
for package in self.set_package_detail(carrier, client, packages, ship_from, ship_to, cod_info, request_type):
shipment.Package.append(package)
shipment.Shipper = self.factory_ns2.ShipperType()
shipment.Shipper.Address = self.factory_ns2.ShipAddressType()
shipment.Shipper.AttentionName = (shipper.name or '')[:35]
shipment.Shipper.Name = (shipper.parent_id.name or shipper.name or '')[:35]
shipment.Shipper.Address.AddressLine = [l for l in [shipper.street or '', shipper.street2 or ''] if l]
shipment.Shipper.Address.City = shipper.city or ''
shipment.Shipper.Address.PostalCode = shipper.zip or ''
shipment.Shipper.Address.CountryCode = shipper.country_id.code or ''
if shipper.country_id.code in ('US', 'CA', 'IE'):
shipment.Shipper.Address.StateProvinceCode = shipper.state_id.code or ''
shipment.Shipper.ShipperNumber = self.shipper_number or ''
shipment.Shipper.Phone = self.factory_ns2.ShipPhoneType()
shipment.Shipper.Phone.Number = self._clean_phone_number(shipper.phone)
shipment.Shipper.EMailAddress = shipper.email or ''
shipment.ShipFrom = self.factory_ns2.ShipFromType()
shipment.ShipFrom.Address = self.factory_ns2.ShipAddressType()
shipment.ShipFrom.AttentionName = (ship_from.name or '')[:35]
shipment.ShipFrom.Name = (ship_from.parent_id.name or ship_from.name or '')[:35]
shipment.ShipFrom.Address.AddressLine = [l for l in [ship_from.street or '', ship_from.street2 or ''] if l]
shipment.ShipFrom.Address.City = ship_from.city or ''
shipment.ShipFrom.Address.PostalCode = ship_from.zip or ''
shipment.ShipFrom.Address.CountryCode = ship_from.country_id.code or ''
if ship_from.country_id.code in ('US', 'CA', 'IE'):
shipment.ShipFrom.Address.StateProvinceCode = ship_from.state_id.code or ''
shipment.ShipFrom.Phone = self.factory_ns2.ShipPhoneType()
shipment.ShipFrom.Phone.Number = self._clean_phone_number(ship_from.phone)
shipment.ShipFrom.EMailAddress = ship_from.email or ''
shipment.ShipTo = self.factory_ns2.ShipToType()
shipment.ShipTo.Address = self.factory_ns2.ShipToAddressType()
shipment.ShipTo.AttentionName = (ship_to.name or '')[:35]
shipment.ShipTo.Name = (ship_to.parent_id.name or ship_to.name or '')[:35]
shipment.ShipTo.Address.AddressLine = [l for l in [ship_to.street or '', ship_to.street2 or ''] if l]
shipment.ShipTo.Address.City = ship_to.city or ''
shipment.ShipTo.Address.PostalCode = ship_to.zip or ''
shipment.ShipTo.Address.CountryCode = ship_to.country_id.code or ''
if ship_to.country_id.code in ('US', 'CA', 'IE'):
shipment.ShipTo.Address.StateProvinceCode = ship_to.state_id.code or ''
shipment.ShipTo.Phone = self.factory_ns2.ShipPhoneType()
shipment.ShipTo.Phone.Number = self._clean_phone_number(shipment_info['phone'])
shipment.ShipTo.EMailAddress = ship_to.email or ''
if not ship_to.commercial_partner_id.is_company:
shipment.ShipTo.Address.ResidentialAddressIndicator = None
shipment.Service = self.factory_ns2.ServiceType()
shipment.Service.Code = service_type or ''
shipment.Service.Description = 'Service Code'
if service_type == "96":
shipment.NumOfPiecesInShipment = int(shipment_info.get('total_qty'))
shipment.ShipmentRatingOptions = self.factory_ns2.RateInfoType()
shipment.ShipmentRatingOptions.NegotiatedRatesIndicator = 1
# Shipments from US to CA or PR require extra info
if ship_from.country_id.code == 'US' and ship_to.country_id.code in ['CA', 'PR']:
shipment.InvoiceLineTotal = self.factory_ns2.CurrencyMonetaryType()
shipment.InvoiceLineTotal.CurrencyCode = shipment_info.get('itl_currency_code')
shipment.InvoiceLineTotal.MonetaryValue = shipment_info.get('ilt_monetary_value')
# set the default method for payment using shipper account
payment_info = self.factory_ns2.PaymentInfoType()
shipcharge = self.factory_ns2.ShipmentChargeType()
shipcharge.Type = '01'
# Bill Recevier 'Bill My Account'
if ups_carrier_account:
shipcharge.BillReceiver = self.factory_ns2.BillReceiverType()
shipcharge.BillReceiver.Address = self.factory_ns2.BillReceiverAddressType()
shipcharge.BillReceiver.AccountNumber = ups_carrier_account
shipcharge.BillReceiver.Address.PostalCode = ship_to.zip
else:
shipcharge.BillShipper = self.factory_ns2.BillShipperType()
shipcharge.BillShipper.AccountNumber = self.shipper_number or ''
payment_info.ShipmentCharge = [shipcharge]
if duty_payment == 'SENDER':
duty_charge = self.factory_ns2.ShipmentChargeType()
duty_charge.Type = '02'
duty_charge.BillShipper = self.factory_ns2.BillShipperType()
duty_charge.BillShipper.AccountNumber = self.shipper_number or ''
payment_info.ShipmentCharge.append(duty_charge)
shipment.PaymentInformation = payment_info
sso = self.factory_ns2.ShipmentServiceOptionsType()
if shipment_info.get('require_invoice'):
sso.InternationalForms = self.set_invoice(shipment_info, [c for pkg in packages for c in pkg.commodities], ship_to)
sso.InternationalForms.TermsOfShipment = shipment_info.get('terms_of_shipment')
sso.InternationalForms.PurchaseOrderNumber = shipment_info.get('purchase_order_number')
if saturday_delivery:
sso.SaturdayDeliveryIndicator = saturday_delivery
shipment.ShipmentServiceOptions = sso
self.shipment = shipment
self.label = label
self.request = request
self.label_file_type = label_file_type
def return_label(self):
return_service = self.factory_ns2.ReturnServiceType()
return_service.Code = "9"
self.shipment.ReturnService = return_service
for p in self.shipment.Package:
p.Description = "Return of courtesy"
def process_shipment(self):
client = self._set_client(self.ship_wsdl, 'Ship', 'ShipmentRequest')
service = self._set_service(client, 'Ship')
try:
response = service.ProcessShipment(
Request=self.request, Shipment=self.shipment,
LabelSpecification=self.label)
# Check if shipment is not success then return reason for that
if response.Response.ResponseStatus.Code != "1":
return self.get_error_message(response.Response.ResponseStatus.Code, response.Response.ResponseStatus.Description)
result = {}
result['label_binary_data'] = {}
for package in response.ShipmentResults.PackageResults:
result['label_binary_data'][package.TrackingNumber] = self.save_label(package.ShippingLabel.GraphicImage, label_file_type=self.label_file_type)
if response.ShipmentResults.Form:
result['invoice_binary_data'] = self.save_label(response.ShipmentResults.Form.Image.GraphicImage, label_file_type='pdf') # only pdf supported currently
result['tracking_ref'] = response.ShipmentResults.ShipmentIdentificationNumber
result['currency_code'] = response.ShipmentResults.ShipmentCharges.TotalCharges.CurrencyCode
# Some users are qualified to receive negotiated rates
negotiated_rate = 'NegotiatedRateCharges' in response.ShipmentResults and response.ShipmentResults.NegotiatedRateCharges and response.ShipmentResults.NegotiatedRateCharges.TotalCharge.MonetaryValue or None
result['price'] = negotiated_rate or response.ShipmentResults.ShipmentCharges.TotalCharges.MonetaryValue
return result
except Fault as e:
code = e.detail.xpath("//err:PrimaryErrorCode/err:Code", namespaces=self.ns)[0].text
description = e.detail.xpath("//err:PrimaryErrorCode/err:Description", namespaces=self.ns)[0].text
return self.get_error_message(code, description)
except IOError as e:
return self.get_error_message('0', 'UPS Server Not Found:\n%s' % e)
def cancel_shipment(self, tracking_number):
client = self._set_client(self.void_wsdl, 'Void', 'VoidShipmentRequest')
service = self._set_service(client, 'Void')
request = self.factory_ns3.RequestType()
request.TransactionReference = self.factory_ns3.TransactionReferenceType()
request.TransactionReference.CustomerContext = "Cancle shipment"
voidshipment = {'ShipmentIdentificationNumber': tracking_number or ''}
result = {}
try:
response = service.ProcessVoid(
Request=request, VoidShipment=voidshipment
)
if response.Response.ResponseStatus.Code == "1":
return result
return self.get_error_message(response.Response.ResponseStatus.Code, response.Response.ResponseStatus.Description)
except Fault as e:
code = e.detail.xpath("//err:PrimaryErrorCode/err:Code", namespaces=self.ns)[0].text
description = e.detail.xpath("//err:PrimaryErrorCode/err:Description", namespaces=self.ns)[0].text
return self.get_error_message(code, description)
except IOError as e:
return self.get_error_message('0', 'UPS Server Not Found:\n%s' % e)

View File

@@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" xmlns:error="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="201707">
<xsd:element name="Errors">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ErrorDetail" type="error:ErrorDetailType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="ErrorDetailType">
<xsd:sequence>
<xsd:element name="Severity" type="xsd:string"/>
<xsd:element name="PrimaryErrorCode" type="error:CodeType"/>
<xsd:element name="MinimumRetrySeconds" type="xsd:string" minOccurs="0"/>
<xsd:element name="Location" type="error:LocationType" minOccurs="0"/>
<xsd:element name="SubErrorCode" type="error:CodeType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="AdditionalInformation" type="error:AdditionalInfoType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="ElementLevelInformation" type="error:ElementLevelInformationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ElementLevelInformationType">
<xsd:sequence>
<xsd:element name="Level" type="xsd:string"/>
<xsd:element name="ElementIdentifier" type="error:ElementIdentifierType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ElementIdentifierType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CodeType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
<xsd:element name="Digest" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AdditionalInfoType">
<xsd:sequence>
<xsd:element name="Type" type="xsd:string"/>
<xsd:element name="Value" type="error:AdditionalCodeDescType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AdditionalCodeDescType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LocationType">
<xsd:sequence>
<xsd:element name="LocationElementName" type="xsd:string" minOccurs="0"/>
<xsd:element name="XPathOfElement" type="xsd:string" minOccurs="0"/>
<xsd:element name="OriginalValue" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,318 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/IF/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ups="http://www.ups.com/XMLSchema" xmlns:IF="http://www.ups.com/XMLSchema/XOLTWS/IF/v1.0" elementFormDefault="qualified">
<xsd:complexType name="InternationalFormType">
<xsd:sequence>
<xsd:element name="FormType" type="xsd:string" maxOccurs="6"/>
<xsd:element name="UserCreatedForm" type="IF:UserCreatedFormType" minOccurs="0"/>
<xsd:element name="CN22Form" type="IF:CN22FormType" minOccurs="0"/>
<xsd:element name="UPSPremiumCareForm" type="IF:UPSPremiumCareFormType" minOccurs="0"/>
<xsd:element name="AdditionalDocumentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="FormGroupIdName" type="xsd:string" minOccurs="0"/>
<xsd:element name="SEDFilingOption" type="xsd:string" minOccurs="0"/>
<xsd:element name="EEIFilingOption" type="IF:EEIFilingOptionType" minOccurs="0"/>
<xsd:element name="Contacts" type="IF:ContactType" minOccurs="0"/>
<xsd:element name="Product" type="IF:ProductType" maxOccurs="50"/>
<xsd:element name="InvoiceNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="InvoiceDate" type="xsd:string" minOccurs="0"/>
<xsd:element name="PurchaseOrderNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="TermsOfShipment" type="xsd:string" minOccurs="0"/>
<xsd:element name="ReasonForExport" type="xsd:string" minOccurs="0"/>
<xsd:element name="Comments" type="xsd:string" minOccurs="0"/>
<xsd:element name="DeclarationStatement" type="xsd:string" minOccurs="0"/>
<xsd:element name="Discount" type="IF:IFChargesType" minOccurs="0"/>
<xsd:element name="FreightCharges" type="IF:IFChargesType" minOccurs="0"/>
<xsd:element name="InsuranceCharges" type="IF:IFChargesType" minOccurs="0"/>
<xsd:element name="OtherCharges" type="IF:OtherChargesType" minOccurs="0"/>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="BlanketPeriod" type="IF:BlanketPeriodType" minOccurs="0"/>
<xsd:element name="ExportDate" type="xsd:string" minOccurs="0"/>
<xsd:element name="ExportingCarrier" type="xsd:string" minOccurs="0"/>
<xsd:element name="CarrierID" type="xsd:string" minOccurs="0"/>
<xsd:element name="InBondCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="EntryNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="PointOfOrigin" type="xsd:string" minOccurs="0"/>
<xsd:element name="PointOfOriginType" type="xsd:string" minOccurs="0"/>
<xsd:element name="ModeOfTransport" type="xsd:string" minOccurs="0"/>
<xsd:element name="PortOfExport" type="xsd:string" minOccurs="0"/>
<xsd:element name="PortOfUnloading" type="xsd:string" minOccurs="0"/>
<xsd:element name="LoadingPier" type="xsd:string" minOccurs="0"/>
<xsd:element name="PartiesToTransaction" type="xsd:string" minOccurs="0"/>
<xsd:element name="RoutedExportTransactionIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ContainerizedIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="License" type="IF:LicenseType" minOccurs="0"/>
<xsd:element name="ECCNNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="OverridePaperlessIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ShipperMemo" type="xsd:string" minOccurs="0"/>
<xsd:element name="MultiCurrencyInvoiceLineTotal" type="xsd:string" minOccurs="0"/>
<xsd:element name="HazardousMaterialsIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UPSPremiumCareFormType">
<xsd:sequence>
<xsd:element name="ShipmentDate" type="xsd:string"/>
<xsd:element name="PageSize" type="xsd:string"/>
<xsd:element name="PrintType" type="xsd:string"/>
<xsd:element name="NumOfCopies" type="xsd:string"/>
<xsd:element name="LanguageForUPSPremiumCare" type="IF:LanguageForUPSPremiumCareType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LanguageForUPSPremiumCareType">
<xsd:sequence>
<xsd:element name="Language" type="xsd:string" maxOccurs="2"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UserCreatedFormType">
<xsd:sequence>
<xsd:element name="DocumentID" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CN22FormType">
<xsd:sequence>
<xsd:element name="LabelSize" type="xsd:string" minOccurs="0"/>
<xsd:element name="PrintsPerPage" type="xsd:string" minOccurs="0"/>
<xsd:element name="LabelPrintType" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22Type" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22OtherDescription" type="xsd:string" minOccurs="0"/>
<xsd:element name="FoldHereText" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22Content" type="IF:CN22ContentType" minOccurs="0" maxOccurs="3"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CN22ContentType">
<xsd:sequence>
<xsd:element name="CN22ContentQuantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentDescription" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentWeight" type="IF:ProductWeightType" minOccurs="0"/>
<xsd:element name="CN22ContentTotalValue" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentCurrencyCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentCountryOfOrigin" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentTariffNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ContactType">
<xsd:sequence>
<xsd:element name="ForwardAgent" type="IF:ForwardAgentType" minOccurs="0"/>
<xsd:element name="UltimateConsignee" type="IF:UltimateConsigneeType" minOccurs="0"/>
<xsd:element name="IntermediateConsignee" type="IF:IntermediateConsigneeType" minOccurs="0"/>
<xsd:element name="Producer" type="IF:ProducerType" minOccurs="0"/>
<xsd:element name="SoldTo" type="IF:SoldToType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ForwardAgentType">
<xsd:sequence>
<xsd:element name="CompanyName" type="xsd:string"/>
<xsd:element name="TaxIdentificationNumber" type="xsd:string"/>
<xsd:element name="Address" type="IF:AddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element name="AddressLine" type="xsd:string" maxOccurs="3"/>
<xsd:element name="City" type="xsd:string"/>
<xsd:element name="StateProvinceCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="Town" type="xsd:string" minOccurs="0"/>
<xsd:element name="PostalCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="CountryCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UltimateConsigneeType">
<xsd:sequence>
<xsd:element name="CompanyName" type="xsd:string"/>
<xsd:element name="Address" type="IF:AddressType"/>
<xsd:element name="UltimateConsigneeType" type="IF:UltimateConsigneeTypeType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="IntermediateConsigneeType">
<xsd:sequence>
<xsd:element name="CompanyName" type="xsd:string"/>
<xsd:element name="Address" type="IF:AddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ProducerType">
<xsd:sequence>
<xsd:element name="Option" type="xsd:string" minOccurs="0"/>
<xsd:element name="CompanyName" type="xsd:string" minOccurs="0"/>
<xsd:element name="TaxIdentificationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="IF:AddressType" minOccurs="0"/>
<xsd:element name="AttentionName" type="xsd:string" minOccurs="0"/>
<xsd:element name="Phone" type="IF:PhoneType" minOccurs="0"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ProductType">
<xsd:sequence>
<xsd:element name="Description" type="xsd:string" maxOccurs="3"/>
<xsd:element name="Unit" type="IF:UnitType" minOccurs="0"/>
<xsd:element name="CommodityCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="PartNumber" type="xsd:string" minOccurs="0" ups:usage="notused"/>
<xsd:element name="OriginCountryCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="JointProductionIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="NetCostCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="NetCostDateRange" type="IF:NetCostDateType" minOccurs="0"/>
<xsd:element name="PreferenceCriteria" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProducerInfo" type="xsd:string" minOccurs="0"/>
<xsd:element name="MarksAndNumbers" type="xsd:string" minOccurs="0"/>
<xsd:element name="NumberOfPackagesPerCommodity" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProductWeight" type="IF:ProductWeightType" minOccurs="0"/>
<xsd:element name="VehicleID" type="xsd:string" minOccurs="0"/>
<xsd:element name="ScheduleB" type="IF:ScheduleBType" minOccurs="0"/>
<xsd:element name="ExportType" type="xsd:string" minOccurs="0"/>
<xsd:element name="SEDTotalValue" type="xsd:string" minOccurs="0"/>
<xsd:element name="ExcludeFromForm" type="IF:ExcludeFromFormType" minOccurs="0"/>
<xsd:element name="ProductCurrencyCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackingListInfo" type="IF:PackingListInfoType" minOccurs="0"/>
<xsd:element name="EEIInformation" type="IF:EEIInformationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ExcludeFromFormType">
<xsd:sequence>
<xsd:element name="FormType" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UnitType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string"/>
<xsd:element name="UnitOfMeasurement" type="IF:UnitOfMeasurementType"/>
<xsd:element name="Value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackingListInfoType">
<xsd:sequence>
<xsd:element name="PackageAssociated" type="IF:PackageAssociatedType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageAssociatedType">
<xsd:sequence>
<xsd:element name="PackageNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProductAmount" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UnitOfMeasurementType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NetCostDateType">
<xsd:sequence>
<xsd:element name="BeginDate" type="xsd:string"/>
<xsd:element name="EndDate" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ProductWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="IF:UnitOfMeasurementType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ScheduleBType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string"/>
<xsd:element name="Quantity" type="xsd:string" minOccurs="0" maxOccurs="2"/>
<xsd:element name="UnitOfMeasurement" type="IF:UnitOfMeasurementType" maxOccurs="2"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="IFChargesType">
<xsd:sequence>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="OtherChargesType">
<xsd:sequence>
<xsd:element name="MonetaryValue" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BlanketPeriodType">
<xsd:sequence>
<xsd:element name="BeginDate" type="xsd:string"/>
<xsd:element name="EndDate" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LicenseType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string" minOccurs="0"/>
<xsd:element name="Date" type="xsd:string" minOccurs="0"/>
<xsd:element name="ExceptionCode" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="SoldToType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:element name="AttentionName" type="xsd:string"/>
<xsd:element name="TaxIdentificationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Phone" type="IF:PhoneType" minOccurs="0"/>
<xsd:element name="Option" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="IF:AddressType"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PhoneType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string"/>
<xsd:element name="Extension" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DDTCInformationType">
<xsd:sequence>
<xsd:element name="ITARExemptionNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="USMLCategoryCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="EligiblePartyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="RegistrationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Quantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="UnitOfMeasurement" type="IF:UnitOfMeasurementType"/>
<xsd:element name="SignificantMilitaryEquipmentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ACMNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="EEILicenseType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string" minOccurs="0"/>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="LicenseLineValue" type="xsd:string" minOccurs="0"/>
<xsd:element name="ECCNNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="EEIFilingOptionType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
<xsd:element name="UPSFiled" type="IF:UPSFiledType" minOccurs="0"/>
<xsd:element name="ShipperFiled" type="IF:ShipperFiledType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UPSFiledType">
<xsd:sequence>
<xsd:element name="POA" type="IF:POAType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipperFiledType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
<xsd:element name="PreDepartureITNNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="ExemptionLegend" type="xsd:string" minOccurs="0"/>
<xsd:element name="EEIShipmentReferenceNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="EEIInformationType">
<xsd:sequence>
<xsd:element name="ExportInformation" type="xsd:string" minOccurs="0"/>
<xsd:element name="License" type="IF:EEILicenseType" minOccurs="0"/>
<xsd:element name="DDTCInformation" type="IF:DDTCInformationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="POAType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UltimateConsigneeTypeType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- UPS Rate Service WSDL Release Date Dec 29, 2007 -->
<!-- Copyright 2007-2008 United Parcel Service of America, Inc. All rights reserved. -->
<wsdl:definitions name="RateWS" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:error="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" xmlns:upss="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0" xmlns:rate="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1" xmlns:tns="http://www.ups.com/WSDL/XOLTWS/Rate/v1.1" targetNamespace="http://www.ups.com/WSDL/XOLTWS/Rate/v1.1">
<wsdl:types>
<xsd:schema>
<!-- This schema defines the UPS Security header used for authorization purposes -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0" schemaLocation="UPSSecurity.xsd"/>
<!-- This schema defines the error detail data types returned within SOAPFaults to provide more specific information pertaining to the problem. -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" schemaLocation="Error1.1.xsd"/>
<!-- This schema defines the Rate service data types -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1" schemaLocation="RateWebServiceSchema.xsd"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="RateRequestMessage">
<wsdl:part name="Body" element="rate:RateRequest"/>
<wsdl:part name="UPSSecurity" element="upss:UPSSecurity"/>
</wsdl:message>
<wsdl:message name="RateResponseMessage">
<wsdl:part name="Body" element="rate:RateResponse"/>
</wsdl:message>
<wsdl:message name="RateErrorMessage">
<wsdl:part name="RateError" element="error:Errors"/>
</wsdl:message>
<wsdl:portType name="RatePortType">
<wsdl:operation name="ProcessRate">
<wsdl:input name="RateRequest" message="tns:RateRequestMessage"/>
<wsdl:output name="RateResponse" message="tns:RateResponseMessage"/>
<wsdl:fault name="RateError" message="tns:RateErrorMessage"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="RateBinding" type="tns:RatePortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="ProcessRate">
<soap:operation soapAction="http://onlinetools.ups.com/webservices/RateBinding/v1.1" style="document"/>
<wsdl:input name="RateRequest">
<soap:body parts="Body" use="literal"/>
<soap:header message="tns:RateRequestMessage" part="UPSSecurity" use="literal">
<soap:headerfault message="tns:RateErrorMessage" part="RateError" use="literal"/>
</soap:header>
</wsdl:input>
<wsdl:output name="RateResponse">
<soap:body parts="Body" use="literal"/>
</wsdl:output>
<wsdl:fault name="RateError">
<soap:fault name="RateError" use="literal"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="RateService">
<wsdl:port name="RatePort" binding="tns:RateBinding">
<!-- Production URL -->
<!-- <soap:address location="https://onlinetools.ups.com/webservices/Rate"/> -->
<!-- CIE (Customer Integration Environment) URL -->
<soap:address location="https://wwwcie.ups.com/webservices/Rate"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@@ -0,0 +1,619 @@
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" xmlns:rate="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1" xmlns:ups="http://www.ups.com/XMLSchema" elementFormDefault="qualified" targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1" version="201701">
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" schemaLocation="common.xsd"/>
<xsd:element name="RateRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Request"/>
<xsd:element name="PickupType" type="rate:CodeDescriptionType" minOccurs="0"/>
<xsd:element minOccurs="0" name="CustomerClassification" type="rate:CodeDescriptionType"/>
<xsd:element name="Shipment" type="rate:ShipmentType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="RateResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Response"/>
<xsd:element maxOccurs="unbounded" name="RatedShipment" type="rate:RatedShipmentType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="BillingWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="rate:CodeDescriptionType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RatedPackageType">
<xsd:sequence>
<xsd:element minOccurs="0" name="TransportationCharges" type="rate:ChargesType"/>
<xsd:element name="BaseServiceCharge" type="rate:ChargesType" minOccurs="0"/>
<xsd:element minOccurs="0" name="ServiceOptionsCharges" type="rate:ChargesType"/>
<xsd:element minOccurs="0" name="TotalCharges" type="rate:ChargesType"/>
<xsd:element minOccurs="0" name="Weight" type="xsd:string"/>
<xsd:element minOccurs="0" name="BillingWeight" type="rate:BillingWeightType"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="Accessorial" type="rate:AccessorialType"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="ItemizedCharges" type="rate:ChargesType"/>
<xsd:element minOccurs="0" name="NegotiatedCharges" type="rate:NegotiatedChargesType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AccessorialType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element minOccurs="0" name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NegotiatedChargesType">
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="ItemizedCharges" type="rate:ChargesType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RatedShipmentType">
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="Disclaimer" type="rate:DisclaimerType"/>
<xsd:element name="Service" type="rate:CodeDescriptionType"/>
<xsd:element minOccurs="0" name="RateChart" type="xsd:string"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="RatedShipmentAlert" type="rate:RatedShipmentInfoType"/>
<xsd:element minOccurs="0" name="BillableWeightCalculationMethod" type="xsd:string"/>
<xsd:element minOccurs="0" name="RatingMethod" type="xsd:string"/>
<xsd:element name="BillingWeight" type="rate:BillingWeightType"/>
<xsd:element name="TransportationCharges" type="rate:ChargesType"/>
<xsd:element name="BaseServiceCharge" type="rate:ChargesType" minOccurs="0"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="ItemizedCharges" type="rate:ChargesType"/>
<xsd:element minOccurs="0" name="FRSShipmentData" type="rate:FRSShipmentType"/>
<xsd:element name="ServiceOptionsCharges" type="rate:ChargesType"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="TaxCharges" type="rate:TaxChargeType"/>
<xsd:element name="TotalCharges" type="rate:ChargesType"/>
<xsd:element minOccurs="0" name="TotalChargesWithTaxes" type="rate:ChargesType"/>
<xsd:element minOccurs="0" name="NegotiatedRateCharges" type="rate:TotalChargeType"/>
<xsd:element minOccurs="0" name="GuaranteedDelivery" type="rate:GuaranteedDeliveryType"/>
<xsd:element maxOccurs="unbounded" name="RatedPackage" type="rate:RatedPackageType"/>
<xsd:element name="TimeInTransit" type="rate:TimeInTransitResponseType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TimeInTransitResponseType">
<xsd:sequence>
<xsd:element name="PickupDate" type="xsd:string"/>
<xsd:element name="DocumentsOnlyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackageBillType" type="xsd:string" minOccurs="0"/>
<xsd:element name="ServiceSummary" type="rate:ServiceSummaryType" maxOccurs="unbounded"/>
<xsd:element name="AutoDutyCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="Disclaimer" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ServiceSummaryType">
<xsd:sequence>
<xsd:element name="Service" type="rate:CodeDescriptionType"/>
<xsd:element name="GuaranteedIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Disclaimer" type="xsd:string" minOccurs="0"/>
<xsd:element name="EstimatedArrival" type="rate:EstimatedArrivalType"/>
<xsd:element name="SaturdayDelivery" type="xsd:string" minOccurs="0"/>
<xsd:element name="SaturdayDeliveryDisclaimer" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="EstimatedArrivalType">
<xsd:sequence>
<xsd:element name="Arrival" type="rate:PickupType"/>
<xsd:element name="BusinessDaysInTransit" type="xsd:string"/>
<xsd:element name="Pickup" type="rate:PickupType"/>
<xsd:element name="DayOfWeek" type="xsd:string" minOccurs="0"/>
<xsd:element name="CustomerCenterCutoff" type="xsd:string" minOccurs="0"/>
<xsd:element name="DelayCount" type="xsd:string" minOccurs="0"/>
<xsd:element name="HolidayCount" type="xsd:string" minOccurs="0"/>
<xsd:element name="RestDays" type="xsd:string" minOccurs="0"/>
<xsd:element name="TotalTransitDays" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DisclaimerType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TaxChargeType">
<xsd:sequence>
<xsd:element name="Type" type="xsd:string"/>
<xsd:element minOccurs="0" name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TotalChargeType">
<xsd:sequence>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="ItemizedCharges" type="rate:ChargesType"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="TaxCharges" type="rate:TaxChargeType"/>
<xsd:element name="TotalCharge" type="rate:ChargesType"/>
<xsd:element minOccurs="0" name="TotalChargesWithTaxes" type="rate:ChargesType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RatedShipmentInfoType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ChargesType">
<xsd:sequence>
<xsd:element minOccurs="0" name="Code" type="xsd:string"/>
<xsd:element minOccurs="0" name="Description" type="xsd:string"/>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
<xsd:element minOccurs="0" name="SubType" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TransportationChargesType">
<xsd:sequence>
<xsd:element name="GrossCharge" type="rate:ChargesType"/>
<xsd:element name="DiscountAmount" type="rate:ChargesType"/>
<xsd:element name="DiscountPercentage" type="xsd:string"/>
<xsd:element name="NetCharge" type="rate:ChargesType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FRSShipmentType">
<xsd:sequence>
<xsd:element name="TransportationCharges" type="rate:TransportationChargesType"/>
<xsd:element minOccurs="0" name="FreightDensityRate" type="rate:FreightDensityRateType"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="HandlingUnits" type="rate:HandlingUnitsResponseType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FreightDensityRateType">
<xsd:sequence>
<xsd:element name="Density" type="xsd:string"/>
<xsd:element name="TotalCubicFeet" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HandlingUnitsResponseType">
<xsd:sequence>
<xsd:element name="Quantity" type="xsd:string"/>
<xsd:element name="Type" type="rate:CodeDescriptionType"/>
<xsd:element name="Dimensions" type="rate:HandlingUnitsDimensionsType"/>
<xsd:element minOccurs="0" name="AdjustedHeight" type="rate:AdjustedHeightType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element maxOccurs="3" minOccurs="0" name="AddressLine" type="xsd:string"/>
<xsd:element minOccurs="0" name="City" type="xsd:string"/>
<xsd:element minOccurs="0" name="StateProvinceCode" type="xsd:string"/>
<xsd:element minOccurs="0" name="PostalCode" type="xsd:string"/>
<xsd:element name="CountryCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipToAddressType">
<xsd:complexContent>
<xsd:extension base="rate:AddressType">
<xsd:sequence>
<xsd:element minOccurs="0" name="ResidentialAddressIndicator" type="xsd:string"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ShipAddressType">
<xsd:complexContent>
<xsd:extension base="rate:AddressType">
<xsd:sequence>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="CODType">
<xsd:sequence>
<xsd:element name="CODFundsCode" type="xsd:string"/>
<xsd:element name="CODAmount" type="rate:CODAmountType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CODAmountType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DeliveryConfirmationType">
<xsd:sequence>
<xsd:element name="DCISType" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DimensionsType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="rate:CodeDescriptionType"/>
<xsd:element minOccurs="0" name="Length" type="xsd:string"/>
<xsd:element minOccurs="0" name="Width" type="xsd:string"/>
<xsd:element minOccurs="0" name="Height" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="InsuredValueType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageType">
<xsd:sequence>
<xsd:element minOccurs="0" name="PackagingType" type="rate:CodeDescriptionType"/>
<xsd:element minOccurs="0" name="Dimensions" type="rate:DimensionsType"/>
<xsd:element name="DimWeight" type="rate:PackageWeightType" minOccurs="0"/>
<xsd:element minOccurs="0" name="PackageWeight" type="rate:PackageWeightType"/>
<xsd:element minOccurs="0" name="Commodity" type="rate:CommodityType"/>
<xsd:element minOccurs="0" name="LargePackageIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="PackageServiceOptions" type="rate:PackageServiceOptionsType"/>
<xsd:element minOccurs="0" name="AdditionalHandlingIndicator" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CommodityType">
<xsd:sequence>
<xsd:element name="FreightClass" type="xsd:string"/>
<xsd:element minOccurs="0" name="NMFC" type="rate:NMFCCommodityType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NMFCCommodityType">
<xsd:sequence>
<xsd:element name="PrimeCode" type="xsd:string"/>
<xsd:element minOccurs="0" name="SubCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageServiceOptionsType">
<xsd:sequence>
<xsd:element minOccurs="0" name="DeliveryConfirmation" type="rate:DeliveryConfirmationType"/>
<xsd:element minOccurs="0" name="AccessPointCOD" type="rate:PackageServiceOptionsAccessPointCODType"/>
<xsd:element minOccurs="0" name="COD" type="rate:CODType"/>
<xsd:element minOccurs="0" name="DeclaredValue" type="rate:InsuredValueType"/>
<xsd:element minOccurs="0" name="ShipperDeclaredValue" type="rate:ShipperDeclaredValueType"/>
<xsd:element minOccurs="0" name="ProactiveIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="Insurance" type="rate:InsuranceType"/>
<xsd:element minOccurs="0" name="VerbalConfirmationIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="UPSPremiumCareIndicator" type="xsd:string"/>
<xsd:element name="HazMat" type="rate:HazMatType" minOccurs="0"/>
<xsd:element minOccurs="0" name="DryIce" type="rate:DryIceType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HazMatType">
<xsd:sequence>
<xsd:element name="PackageIdentifier" type="xsd:string" minOccurs="0"/>
<xsd:element name="QValue" type="xsd:string" minOccurs="0"/>
<xsd:element name="OverPackedIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="AllPackedInOneIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="HazMatChemicalRecord" type="rate:HazMatChemicalRecordType" maxOccurs="3"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HazMatChemicalRecordType">
<xsd:sequence>
<xsd:element name="ChemicalRecordIdentifier" type="xsd:string" minOccurs="0"/>
<xsd:element name="ClassDivisionNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="IDNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="TransportationMode" type="xsd:string"/>
<xsd:element name="RegulationSet" type="xsd:string"/>
<xsd:element name="EmergencyPhone" type="xsd:string" minOccurs="0"/>
<xsd:element name="EmergencyContact" type="xsd:string" minOccurs="0"/>
<xsd:element name="ReportableQuantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="SubRiskClass" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackagingGroupType" type="xsd:string" minOccurs="0"/>
<xsd:element name="Quantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="UOM" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackagingInstructionCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProperShippingName" type="xsd:string" minOccurs="0"/>
<xsd:element name="TechnicalName" type="xsd:string" minOccurs="0"/>
<xsd:element name="AdditionalDescription" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackagingType" type="xsd:string" minOccurs="0"/>
<xsd:element name="HazardLabelRequired" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackagingTypeQuantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="CommodityRegulatedLevelCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="TransportCategory" type="xsd:string" minOccurs="0"/>
<xsd:element name="TunnelRestrictionCode" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageServiceOptionsAccessPointCODType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DryIceType">
<xsd:sequence>
<xsd:element name="RegulationSet" type="xsd:string"/>
<xsd:element name="DryIceWeight" type="rate:DryIceWeightType"/>
<xsd:element minOccurs="0" name="MedicalUseIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="AuditRequired" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DryIceWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="rate:CodeDescriptionType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipperDeclaredValueType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="InsuranceType">
<xsd:sequence>
<xsd:element minOccurs="0" name="BasicFlexibleParcelIndicator" type="rate:InsuranceValueType"/>
<xsd:element minOccurs="0" name="ExtendedFlexibleParcelIndicator" type="rate:InsuranceValueType"/>
<xsd:element minOccurs="0" name="TimeInTransitFlexibleParcelIndicator" type="rate:InsuranceValueType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="InsuranceValueType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="rate:CodeDescriptionType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UOMCodeDescriptionType">
<xsd:sequence>
<xsd:element minOccurs="0" name="Code" type="xsd:string"/>
<xsd:element minOccurs="0" name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CodeDescriptionType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element minOccurs="0" name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentRatingOptionsType">
<xsd:sequence>
<xsd:element minOccurs="0" name="NegotiatedRatesIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="FRSShipmentIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="RateChartIndicator" type="xsd:string"/>
<xsd:element name="UserLevelDiscountIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipFromType">
<xsd:sequence>
<xsd:element minOccurs="0" name="Name" type="xsd:string"/>
<xsd:element name="Address" type="rate:ShipAddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipToType">
<xsd:sequence>
<xsd:element minOccurs="0" name="Name" type="xsd:string"/>
<xsd:element name="Address" type="rate:ShipToAddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentType">
<xsd:sequence>
<xsd:element name="OriginRecordTransactionTimestamp" type="xsd:string" minOccurs="0"/>
<xsd:element name="Shipper" type="rate:ShipperType"/>
<xsd:element name="ShipTo" type="rate:ShipToType"/>
<xsd:element minOccurs="0" name="ShipFrom" type="rate:ShipFromType"/>
<xsd:element minOccurs="0" name="AlternateDeliveryAddress" type="rate:AlternateDeliveryAddressType"/>
<xsd:element maxOccurs="unbounded" minOccurs="0" name="ShipmentIndicationType" type="rate:IndicationType"/>
<xsd:element name="PaymentDetails" type="rate:PaymentDetailsType" minOccurs="0"/>
<xsd:element minOccurs="0" name="FRSPaymentInformation" type="rate:FRSPaymentInfoType"/>
<xsd:element minOccurs="0" name="FreightShipmentInformation" type="rate:FreightShipmentInformationType"/>
<xsd:element name="GoodsNotInFreeCirculationIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element minOccurs="0" name="Service" type="rate:CodeDescriptionType"/>
<xsd:element minOccurs="0" name="NumOfPieces" type="xsd:string"/>
<xsd:element name="ShipmentTotalWeight" type="rate:ShipmentWeightType" minOccurs="0"/>
<xsd:element minOccurs="0" name="DocumentsOnlyIndicator" type="xsd:string"/>
<xsd:element maxOccurs="unbounded" name="Package" type="rate:PackageType"/>
<xsd:element minOccurs="0" name="ShipmentServiceOptions" type="rate:ShipmentServiceOptionsType"/>
<xsd:element minOccurs="0" name="ShipmentRatingOptions" type="rate:ShipmentRatingOptionsType"/>
<xsd:element minOccurs="0" name="InvoiceLineTotal" type="rate:InvoiceLineTotalType"/>
<xsd:element minOccurs="0" name="RatingMethodRequestedIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="TaxInformationIndicator" type="xsd:string"/>
<xsd:element name="PromotionalDiscountInformation" type="rate:PromotionalDiscountInformationType" minOccurs="0"/>
<xsd:element name="DeliveryTimeInformation" type="rate:TimeInTransitRequestType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TimeInTransitRequestType">
<xsd:sequence>
<xsd:element name="PackageBillType" type="xsd:string" minOccurs="0"/>
<xsd:element name="Pickup" type="rate:PickupType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PickupType">
<xsd:sequence>
<xsd:element name="Date" type="xsd:string"/>
<xsd:element name="Time" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PromotionalDiscountInformationType">
<xsd:sequence>
<xsd:element name="PromoCode" type="xsd:string"/>
<xsd:element name="PromoAliasCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="rate:CodeDescriptionType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PaymentDetailsType">
<xsd:sequence>
<xsd:element name="ShipmentCharge" type="rate:ShipmentChargeType" minOccurs="0" maxOccurs="2"/>
<xsd:element name="SplitDutyVATIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentChargeType">
<xsd:sequence>
<xsd:element name="Type" type="xsd:string"/>
<xsd:element name="BillShipper" type="rate:BillShipperChargeType" minOccurs="0"/>
<xsd:element name="BillReceiver" type="rate:BillReceiverChargeType" minOccurs="0"/>
<xsd:element name="BillThirdParty" type="rate:BillThirdPartyChargeType" minOccurs="0"/>
<xsd:element name="ConsigneeBilledIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillShipperChargeType">
<xsd:sequence>
<xsd:element name="AccountNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillReceiverChargeType">
<xsd:sequence>
<xsd:element name="AccountNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="rate:BillReceiverAddressType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillThirdPartyChargeType">
<xsd:sequence>
<xsd:element name="AccountNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="rate:AddressType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillReceiverAddressType">
<xsd:sequence>
<xsd:element name="PostalCode" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AlternateDeliveryAddressType">
<xsd:sequence>
<xsd:element minOccurs="0" name="Name" type="xsd:string"/>
<xsd:element name="Address" type="rate:ADRType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ADRType">
<xsd:sequence>
<xsd:element maxOccurs="3" minOccurs="0" name="AddressLine" type="xsd:string"/>
<xsd:element minOccurs="0" name="City" type="xsd:string"/>
<xsd:element minOccurs="0" name="StateProvinceCode" type="xsd:string"/>
<xsd:element minOccurs="0" name="PostalCode" type="xsd:string"/>
<xsd:element name="CountryCode" type="xsd:string"/>
<xsd:element minOccurs="0" name="ResidentialAddressIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="POBoxIndicator" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="IndicationType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element minOccurs="0" name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentServiceOptionsType">
<xsd:sequence>
<xsd:element minOccurs="0" name="SaturdayPickupIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="SaturdayDeliveryIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="AccessPointCOD" type="rate:ShipmentServiceOptionsAccessPointCODType"/>
<xsd:element minOccurs="0" name="DeliverToAddresseeOnlyIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="DirectDeliveryOnlyIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="COD" type="rate:CODType"/>
<xsd:element minOccurs="0" name="DeliveryConfirmation" type="rate:DeliveryConfirmationType"/>
<xsd:element minOccurs="0" name="ReturnOfDocumentIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="UPScarbonneutralIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="CertificateOfOriginIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="PickupOptions" type="rate:PickupOptionsType"/>
<xsd:element minOccurs="0" name="DeliveryOptions" type="rate:DeliveryOptionsType"/>
<xsd:element minOccurs="0" name="RestrictedArticles" type="rate:RestrictedArticlesType"/>
<xsd:element minOccurs="0" name="ShipperExportDeclarationIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="CommercialInvoiceRemovalIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="ImportControl" type="rate:ImportControlType"/>
<xsd:element minOccurs="0" name="ReturnService" type="rate:ReturnServiceType"/>
<xsd:element minOccurs="0" name="SDLShipmentIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="EPRAIndicator" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentServiceOptionsAccessPointCODType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ReturnServiceType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element minOccurs="0" name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ImportControlType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element minOccurs="0" name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RestrictedArticlesType">
<xsd:sequence>
<xsd:element minOccurs="0" name="AlcoholicBeveragesIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="DiagnosticSpecimensIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="PerishablesIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="PlantsIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="SeedsIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="SpecialExceptionsIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="TobaccoIndicator" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PickupOptionsType">
<xsd:sequence>
<xsd:element minOccurs="0" name="LiftGateAtPickupIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="HoldForPickupIndicator" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DeliveryOptionsType">
<xsd:sequence>
<xsd:element minOccurs="0" name="LiftGateAtDeliveryIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="DropOffAtUPSFacilityIndicator" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipperType">
<xsd:sequence>
<xsd:element minOccurs="0" name="Name" type="xsd:string"/>
<xsd:element minOccurs="0" name="ShipperNumber" type="xsd:string"/>
<xsd:element name="Address" type="rate:AddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="GuaranteedDeliveryType">
<xsd:sequence>
<xsd:element minOccurs="0" name="BusinessDaysInTransit" type="xsd:string"/>
<xsd:element minOccurs="0" name="DeliveryByTime" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FRSPaymentInfoType">
<xsd:sequence>
<xsd:element name="Type" type="rate:CodeDescriptionType"/>
<xsd:element minOccurs="0" name="AccountNumber" type="xsd:string"/>
<xsd:element minOccurs="0" name="Address" type="rate:PayerAddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FreightShipmentInformationType">
<xsd:sequence>
<xsd:element minOccurs="0" name="FreightDensityInfo" type="rate:FreightDensityInfoType"/>
<xsd:element minOccurs="0" name="DensityEligibleIndicator" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PayerAddressType">
<xsd:sequence>
<xsd:element minOccurs="0" name="PostalCode" type="xsd:string"/>
<xsd:element name="CountryCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FreightDensityInfoType">
<xsd:sequence>
<xsd:element minOccurs="0" name="AdjustedHeightIndicator" type="xsd:string"/>
<xsd:element minOccurs="0" name="AdjustedHeight" type="rate:AdjustedHeightType"/>
<xsd:element maxOccurs="unbounded" name="HandlingUnits" type="rate:HandlingUnitsType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AdjustedHeightType">
<xsd:sequence>
<xsd:element name="Value" type="xsd:string"/>
<xsd:element name="UnitOfMeasurement" type="rate:CodeDescriptionType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HandlingUnitsType">
<xsd:sequence>
<xsd:element name="Quantity" type="xsd:string"/>
<xsd:element name="Type" type="rate:CodeDescriptionType"/>
<xsd:element name="Dimensions" type="rate:HandlingUnitsDimensionsType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HandlingUnitsDimensionsType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="rate:CodeDescriptionType"/>
<xsd:element name="Length" type="xsd:string"/>
<xsd:element name="Width" type="xsd:string"/>
<xsd:element name="Height" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="InvoiceLineTotalType">
<xsd:sequence>
<xsd:element minOccurs="0" name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- UPS Ship Service WSDL Release Date Dec 29, 2007 -->
<!-- Copyright 2007-2008 United Parcel Service of America, Inc. All rights reserved. -->
<wsdl:definitions name="Ship" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:error="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" xmlns:upss="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0" xmlns:ship="http://www.ups.com/XMLSchema/XOLTWS/Ship/v1.0" xmlns:tns="http://www.ups.com/WSDL/XOLTWS/Ship/v1.0" targetNamespace="http://www.ups.com/WSDL/XOLTWS/Ship/v1.0">
<wsdl:types>
<xsd:schema>
<!-- This schema defines the UPS Security header used for authorization purposes -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0" schemaLocation="UPSSecurity.xsd"/>
<!-- This schema defines the error detail data types returned within SOAPFaults to provide more specific information pertaining to the problem. -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" schemaLocation="Error1.1.xsd"/>
<!-- This schema defines the Ship service data types -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Ship/v1.0" schemaLocation="ShipWebServiceSchema.xsd"/>
</xsd:schema>
</wsdl:types>
<!-- Ship request/response Message Calls -->
<wsdl:message name="ShipmentRequestMessage">
<wsdl:part name="Body" element="ship:ShipmentRequest"/>
<wsdl:part name="UPSSecurity" element="upss:UPSSecurity"/>
</wsdl:message>
<wsdl:message name="ShipmentResponseMessage">
<wsdl:part name="Body" element="ship:ShipmentResponse"/>
</wsdl:message>
<wsdl:message name="ShipmentErrorMessage">
<wsdl:part name="ShipmentError" element="error:Errors"/>
</wsdl:message>
<wsdl:message name="ShipConfirmRequestMessage">
<wsdl:part name="Body" element="ship:ShipConfirmRequest"/>
<wsdl:part name="UPSSecurity" element="upss:UPSSecurity"/>
</wsdl:message>
<wsdl:message name="ShipConfirmResponseMessage">
<wsdl:part name="Body" element="ship:ShipConfirmResponse"/>
</wsdl:message>
<wsdl:message name="ShipConfirmErrorMessage">
<wsdl:part name="ShipConfirmError" element="error:Errors"/>
</wsdl:message>
<wsdl:message name="ShipAcceptRequestMessage">
<wsdl:part name="Body" element="ship:ShipAcceptRequest"/>
<wsdl:part name="UPSSecurity" element="upss:UPSSecurity"/>
</wsdl:message>
<wsdl:message name="ShipAcceptResponseMessage">
<wsdl:part name="Body" element="ship:ShipAcceptResponse"/>
</wsdl:message>
<wsdl:message name="ShipAcceptErrorMessage">
<wsdl:part name="ShipAcceptError" element="error:Errors"/>
</wsdl:message>
<!-- -->
<!-- Ship Web Service port declaration -->
<wsdl:portType name="ShipPortType">
<wsdl:operation name="ProcessShipment">
<wsdl:input name="ShipmentRequest" message="tns:ShipmentRequestMessage"/>
<wsdl:output name="ShipmentResponse" message="tns:ShipmentResponseMessage"/>
<wsdl:fault name="ShipmentError" message="tns:ShipmentErrorMessage"/>
</wsdl:operation>
<wsdl:operation name="ProcessShipConfirm">
<wsdl:input name="ShipConfirmRequest" message="tns:ShipConfirmRequestMessage"/>
<wsdl:output name="ShipConfirmResponse" message="tns:ShipConfirmResponseMessage"/>
<wsdl:fault name="ShipConfirmError" message="tns:ShipConfirmErrorMessage"/>
</wsdl:operation>
<wsdl:operation name="ProcessShipAccept">
<wsdl:input name="ShipAcceptRequest" message="tns:ShipAcceptRequestMessage"/>
<wsdl:output name="ShipAcceptResponse" message="tns:ShipAcceptResponseMessage"/>
<wsdl:fault name="ShipAcceptError" message="tns:ShipAcceptErrorMessage"/>
</wsdl:operation>
</wsdl:portType>
<!-- Ship Web Service binding -->
<wsdl:binding name="ShipBinding" type="tns:ShipPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="ProcessShipment">
<soap:operation soapAction="http://onlinetools.ups.com/webservices/ShipBinding/v1.0" style="document"/>
<wsdl:input name="ShipmentRequest">
<soap:body parts="Body" use="literal"/>
<soap:header message="tns:ShipmentRequestMessage" part="UPSSecurity" use="literal">
<soap:headerfault message="tns:ShipmentErrorMessage" part="ShipmentError" use="literal"/>
</soap:header>
</wsdl:input>
<wsdl:output name="ShipmentResponse">
<soap:body parts="Body" use="literal"/>
</wsdl:output>
<wsdl:fault name="ShipmentError">
<soap:fault name="ShipmentError" use="literal"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="ProcessShipConfirm">
<soap:operation soapAction="http://onlinetools.ups.com/webservices/ShipBinding/v1.0" style="document"/>
<wsdl:input name="ShipConfirmRequest">
<soap:body parts="Body" use="literal"/>
<soap:header message="tns:ShipConfirmRequestMessage" part="UPSSecurity" use="literal">
<soap:headerfault message="tns:ShipConfirmErrorMessage" part="ShipConfirmError" use="literal"/>
</soap:header>
</wsdl:input>
<wsdl:output name="ShipConfirmResponse">
<soap:body parts="Body" use="literal"/>
</wsdl:output>
<wsdl:fault name="ShipConfirmError">
<soap:fault name="ShipConfirmError" use="literal"/>
</wsdl:fault>
</wsdl:operation>
<wsdl:operation name="ProcessShipAccept">
<soap:operation soapAction="http://onlinetools.ups.com/webservices/ShipBinding/v1.0" style="document"/>
<wsdl:input name="ShipAcceptRequest">
<soap:body parts="Body" use="literal"/>
<soap:header message="tns:ShipAcceptRequestMessage" part="UPSSecurity" use="literal">
<soap:headerfault message="tns:ShipAcceptErrorMessage" part="ShipAcceptError" use="literal"/>
</soap:header>
</wsdl:input>
<wsdl:output name="ShipAcceptResponse">
<soap:body parts="Body" use="literal"/>
</wsdl:output>
<wsdl:fault name="ShipAcceptError">
<soap:fault name="ShipAcceptError" use="literal"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<!-- Ship Web Service-->
<wsdl:service name="ShipService">
<wsdl:port name="ShipPort" binding="tns:ShipBinding">
<!-- Production URL -->
<!-- <soap:address location="https://onlinetools.ups.com/webservices/Ship"/> -->
<!-- CIE (Customer Integration Environment) URL -->
<soap:address location="https://wwwcie.ups.com/webservices/Ship"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@@ -0,0 +1,865 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/Ship/v1.0" xmlns:ups="http://www.ups.com/XMLSchema" xmlns:ship="http://www.ups.com/XMLSchema/XOLTWS/Ship/v1.0" xmlns:ifs="http://www.ups.com/XMLSchema/XOLTWS/IF/v1.0" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="201707">
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" schemaLocation="common.xsd"/>
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/IF/v1.0" schemaLocation="IFWS.xsd"/>
<xsd:element name="ShipmentRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Request"/>
<xsd:element name="Shipment" type="ship:ShipmentType"/>
<xsd:element name="LabelSpecification" type="ship:LabelSpecificationType" minOccurs="0"/>
<xsd:element name="ReceiptSpecification" type="ship:ReceiptSpecificationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ShipConfirmRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Request"/>
<xsd:element name="Shipment" type="ship:ShipmentType"/>
<xsd:element name="LabelSpecification" type="ship:LabelSpecificationType" minOccurs="0"/>
<xsd:element name="ReceiptSpecification" type="ship:ReceiptSpecificationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ShipAcceptRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Request"/>
<xsd:element name="ShipmentDigest" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ShipmentResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Response"/>
<xsd:element name="ShipmentResults" type="ship:ShipmentResultsType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ShipConfirmResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Response"/>
<xsd:element name="ShipmentResults" type="ship:ShipmentResultsType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ShipAcceptResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Response"/>
<xsd:element name="ShipmentResults" type="ship:ShipmentResultsType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="ShipmentType">
<xsd:sequence>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
<xsd:element name="ReturnService" type="ship:ReturnServiceType" minOccurs="0"/>
<xsd:element name="DocumentsOnlyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Shipper" type="ship:ShipperType"/>
<xsd:element name="ShipTo" type="ship:ShipToType"/>
<xsd:element name="AlternateDeliveryAddress" type="ship:AlternateDeliveryAddressType" minOccurs="0"/>
<xsd:element name="ShipFrom" type="ship:ShipFromType" minOccurs="0"/>
<xsd:element name="PaymentInformation" type="ship:PaymentInfoType" minOccurs="0"/>
<xsd:element name="FRSPaymentInformation" type="ship:FRSPaymentInfoType" minOccurs="0"/>
<xsd:element name="FreightShipmentInformation" type="ship:FreightShipmentInformationType" minOccurs="0"/>
<xsd:element name="GoodsNotInFreeCirculationIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ShipmentRatingOptions" type="ship:RateInfoType" minOccurs="0"/>
<xsd:element name="MovementReferenceNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="ReferenceNumber" type="ship:ReferenceNumberType" minOccurs="0" maxOccurs="2"/>
<xsd:element name="Service" type="ship:ServiceType"/>
<xsd:element name="InvoiceLineTotal" type="ship:CurrencyMonetaryType" minOccurs="0"/>
<xsd:element name="NumOfPiecesInShipment" type="xsd:string" minOccurs="0"/>
<xsd:element name="USPSEndorsement" type="xsd:string" minOccurs="0"/>
<xsd:element name="MILabelCN22Indicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="SubClassification" type="xsd:string" minOccurs="0"/>
<xsd:element name="CostCenter" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackageID" type="xsd:string" minOccurs="0"/>
<xsd:element name="IrregularIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ShipmentIndicationType" type="ship:IndicationType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="MIDualReturnShipmentKey" type="xsd:string" minOccurs="0"/>
<xsd:element name="MIDualReturnShipmentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="RatingMethodRequestedIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="TaxInformationIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PromotionalDiscountInformation" type="ship:PromotionalDiscountInformationType" minOccurs="0"/>
<xsd:element name="ShipmentServiceOptions" minOccurs="0">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="ship:ShipmentServiceOptionsType"/>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="Package" type="ship:PackageType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PromotionalDiscountInformationType">
<xsd:sequence>
<xsd:element name="PromoCode" type="xsd:string"/>
<xsd:element name="PromoAliasCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ReturnServiceType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipperType">
<xsd:complexContent>
<xsd:extension base="ship:CompanyInfoType">
<xsd:sequence>
<xsd:element name="ShipperNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="FaxNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="ship:ShipAddressType"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="CompanyInfoType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:element name="AttentionName" type="xsd:string" minOccurs="0"/>
<xsd:element name="CompanyDisplayableName" type="xsd:string" minOccurs="0"/>
<xsd:element name="TaxIdentificationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="TaxIDType" type="ship:TaxIDCodeDescType" minOccurs="0"/>
<xsd:element name="Phone" type="ship:ShipPhoneType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipPhoneType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string"/>
<xsd:element name="Extension" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipAddressType">
<xsd:sequence>
<xsd:element name="AddressLine" type="xsd:string" maxOccurs="3"/>
<xsd:element name="City" type="xsd:string"/>
<xsd:element name="StateProvinceCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="PostalCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="CountryCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipToType">
<xsd:complexContent>
<xsd:extension base="ship:CompanyInfoType">
<xsd:sequence>
<xsd:element name="FaxNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="ship:ShipToAddressType"/>
<xsd:element name="LocationID" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ShipToAddressType">
<xsd:complexContent>
<xsd:extension base="ship:ShipAddressType">
<xsd:sequence>
<xsd:element name="ResidentialAddressIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ShipFromType">
<xsd:complexContent>
<xsd:extension base="ship:CompanyInfoType">
<xsd:sequence>
<xsd:element name="FaxNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="ship:ShipAddressType"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="PrepaidType">
<xsd:sequence>
<xsd:element name="BillShipper" type="ship:BillShipperType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillShipperType">
<xsd:sequence>
<xsd:element name="AccountNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="CreditCard" type="ship:CreditCardType" minOccurs="0"/>
<xsd:element name="AlternatePaymentMethod" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CreditCardType">
<xsd:sequence>
<xsd:element name="Type" type="xsd:string"/>
<xsd:element name="Number" type="xsd:string"/>
<xsd:element name="ExpirationDate" type="xsd:string"/>
<xsd:element name="SecurityCode" type="xsd:string"/>
<xsd:element name="Address" type="ship:CreditCardAddressType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CreditCardAddressType">
<xsd:sequence>
<xsd:element name="AddressLine" type="xsd:string" maxOccurs="3"/>
<xsd:element name="City" type="xsd:string"/>
<xsd:element name="StateProvinceCode" type="xsd:string"/>
<xsd:element name="PostalCode" type="xsd:string"/>
<xsd:element name="CountryCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillThirdPartyChargeType">
<xsd:sequence>
<xsd:element name="AccountNumber" type="xsd:string"/>
<xsd:element name="Address" type="ship:AccountAddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AccountAddressType">
<xsd:sequence>
<xsd:element name="PostalCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="CountryCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FreightCollectType">
<xsd:sequence>
<xsd:element name="BillReceiver" type="ship:BillReceiverType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillReceiverType">
<xsd:sequence>
<xsd:element name="AccountNumber" type="xsd:string"/>
<xsd:element name="Address" type="ship:BillReceiverAddressType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillReceiverAddressType">
<xsd:sequence>
<xsd:element name="PostalCode" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PaymentInfoType">
<xsd:sequence>
<xsd:element name="ShipmentCharge" type="ship:ShipmentChargeType" maxOccurs="2"/>
<xsd:element name="SplitDutyVATIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentChargeType">
<xsd:sequence>
<xsd:element name="Type" type="xsd:string"/>
<xsd:element name="BillShipper" type="ship:BillShipperType" minOccurs="0"/>
<xsd:element name="BillReceiver" type="ship:BillReceiverType" minOccurs="0"/>
<xsd:element name="BillThirdParty" type="ship:BillThirdPartyChargeType" minOccurs="0"/>
<xsd:element name="ConsigneeBilledIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FRSPaymentInfoType">
<xsd:sequence>
<xsd:element name="Type" type="ship:PaymentType"/>
<xsd:element name="AccountNumber" type="xsd:string"/>
<xsd:element name="Address" type="ship:AccountAddressType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PaymentType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RateInfoType">
<xsd:sequence>
<xsd:element name="NegotiatedRatesIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="FRSShipmentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="RateChartIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="TPFCNegotiatedRatesIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="UserLevelDiscountIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ReferenceNumberType">
<xsd:sequence>
<xsd:element name="BarCodeIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ServiceType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CurrencyMonetaryType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentServiceOptionsType">
<xsd:sequence>
<xsd:element name="SaturdayDeliveryIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="SaturdayPickupIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="COD" type="ship:CODType" minOccurs="0"/>
<xsd:element name="AccessPointCOD" type="ship:ShipmentServiceOptionsAccessPointCODType" minOccurs="0"/>
<xsd:element name="DeliverToAddresseeOnlyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="DirectDeliveryOnlyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Notification" type="ship:NotificationType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="LabelDelivery" type="ship:LabelDeliveryType" minOccurs="0"/>
<xsd:element name="InternationalForms" type="ifs:InternationalFormType" minOccurs="0"/>
<xsd:element name="DeliveryConfirmation" type="ship:DeliveryConfirmationType" minOccurs="0"/>
<xsd:element name="ReturnOfDocumentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ImportControlIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="LabelMethod" type="ship:LabelMethodType" minOccurs="0"/>
<xsd:element name="CommercialInvoiceRemovalIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="UPScarbonneutralIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PreAlertNotification" type="ship:PreAlertNotificationType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="ExchangeForwardIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="HoldForPickupIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="DropoffAtUPSFacilityIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="LiftGateForPickUpIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="LiftGateForDeliveryIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="SDLShipmentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="EPRAReleaseCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="RestrictedArticles" type="ship:RestrictedArticlesType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RestrictedArticlesType">
<xsd:sequence>
<xsd:element name="DiagnosticSpecimensIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PreAlertNotificationType">
<xsd:sequence>
<xsd:element name="EMailMessage" type="ship:PreAlertEMailMessageType" minOccurs="0"/>
<xsd:element name="VoiceMessage" type="ship:PreAlertVoiceMessageType" minOccurs="0"/>
<xsd:element name="TextMessage" type="ship:PreAlertTextMessageType" minOccurs="0"/>
<xsd:element name="Locale" type="ship:LocaleType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PreAlertEMailMessageType">
<xsd:sequence>
<xsd:element name="EMailAddress" type="xsd:string"/>
<xsd:element name="UndeliverableEMailAddress" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LocaleType">
<xsd:sequence>
<xsd:element name="Language" type="xsd:string"/>
<xsd:element name="Dialect" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PreAlertVoiceMessageType">
<xsd:sequence>
<xsd:element name="PhoneNumber" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PreAlertTextMessageType">
<xsd:sequence>
<xsd:element name="PhoneNumber" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ContactInfoType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string" minOccurs="0"/>
<xsd:element name="Phone" type="ship:ShipPhoneType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CODType">
<xsd:sequence>
<xsd:element name="CODFundsCode" type="xsd:string"/>
<xsd:element name="CODAmount" type="ship:CurrencyMonetaryType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentServiceOptionsAccessPointCODType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NotificationType">
<xsd:sequence>
<xsd:element name="NotificationCode" type="xsd:string"/>
<xsd:element name="EMail" type="ship:EmailDetailsType"/>
<xsd:element name="VoiceMessage" type="ship:ShipmentServiceOptionsNotificationVoiceMessageType" minOccurs="0"/>
<xsd:element name="TextMessage" type="ship:ShipmentServiceOptionsNotificationTextMessageType" minOccurs="0"/>
<xsd:element name="Locale" type="ship:LocaleType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelDeliveryType">
<xsd:sequence>
<xsd:element name="EMail" type="ship:EmailDetailsType" minOccurs="0"/>
<xsd:element name="LabelLinksIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="EmailDetailsType">
<xsd:sequence>
<xsd:element name="EMailAddress" type="xsd:string" maxOccurs="unbounded"/>
<xsd:element name="UndeliverableEMailAddress" type="xsd:string" minOccurs="0"/>
<xsd:element name="FromEMailAddress" type="xsd:string" minOccurs="0"/>
<xsd:element name="FromName" type="xsd:string" minOccurs="0"/>
<xsd:element name="Memo" type="xsd:string" minOccurs="0"/>
<xsd:element name="Subject" type="xsd:string" minOccurs="0"/>
<xsd:element name="SubjectCode" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageType">
<xsd:sequence>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
<xsd:element name="Packaging" type="ship:PackagingType" minOccurs="0"/>
<xsd:element name="Dimensions" type="ship:DimensionsType" minOccurs="0"/>
<xsd:element name="DimWeight" type="ship:PackageWeightType" minOccurs="0"/>
<xsd:element name="PackageWeight" type="ship:PackageWeightType" minOccurs="0"/>
<xsd:element name="LargePackageIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ReferenceNumber" type="ship:ReferenceNumberType" minOccurs="0" maxOccurs="2"/>
<xsd:element name="AdditionalHandlingIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackageServiceOptions" type="ship:PackageServiceOptionsType" minOccurs="0"/>
<xsd:element name="Commodity" type="ship:CommodityType" minOccurs="0"/>
<xsd:element name="HazMatPackageInformation" type="ship:HazMatPackageInformationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackagingType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DimensionsType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="ship:ShipUnitOfMeasurementType"/>
<xsd:element name="Length" type="xsd:string"/>
<xsd:element name="Width" type="xsd:string"/>
<xsd:element name="Height" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipUnitOfMeasurementType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="ship:ShipUnitOfMeasurementType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageServiceOptionsType">
<xsd:sequence>
<xsd:element name="DeliveryConfirmation" type="ship:DeliveryConfirmationType" minOccurs="0"/>
<xsd:element name="DeclaredValue" type="ship:PackageDeclaredValueType" minOccurs="0"/>
<xsd:element name="COD" type="ship:PSOCODType" minOccurs="0"/>
<xsd:element name="AccessPointCOD" type="ship:PackageServiceOptionsAccessPointCODType" minOccurs="0"/>
<xsd:element name="VerbalConfirmation" type="ship:VerbalConfirmationType" minOccurs="0"/>
<xsd:element name="ShipperReleaseIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Notification" type="ship:PSONotificationType" minOccurs="0"/>
<xsd:element name="HazMat" type="ship:HazMatType" minOccurs="0" maxOccurs="3"/>
<xsd:element name="DryIce" type="ship:DryIceType" minOccurs="0"/>
<xsd:element name="UPSPremiumCareIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProactiveIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackageIdentifier" type="xsd:string" minOccurs="0"/>
<xsd:element name="ClinicalTrialsID" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageDeclaredValueType">
<xsd:sequence>
<xsd:element name="Type" type="ship:DeclaredValueType" minOccurs="0"/>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DeclaredValueType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DeliveryConfirmationType">
<xsd:sequence>
<xsd:element name="DCISType" type="xsd:string"/>
<xsd:element name="DCISNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelMethodType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="VerbalConfirmationType">
<xsd:sequence>
<xsd:element name="ContactInfo" type="ship:ContactInfoType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PSOCODType">
<xsd:sequence>
<xsd:element name="CODFundsCode" type="xsd:string"/>
<xsd:element name="CODAmount" type="ship:CurrencyMonetaryType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageServiceOptionsAccessPointCODType">
<xsd:sequence>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PSONotificationType">
<xsd:sequence>
<xsd:element name="NotificationCode" type="xsd:string"/>
<xsd:element name="EMail" type="ship:EmailDetailsType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelSpecificationType">
<xsd:sequence>
<xsd:element name="LabelImageFormat" type="ship:LabelImageFormatType"/>
<xsd:element name="HTTPUserAgent" type="xsd:string" minOccurs="0"/>
<xsd:element name="LabelStockSize" type="ship:LabelStockSizeType" minOccurs="0"/>
<xsd:element name="Instruction" type="ship:InstructionCodeDescriptionType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="CharacterSet" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="InstructionCodeDescriptionType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelImageFormatType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelStockSizeType">
<xsd:sequence>
<xsd:element name="Height" type="xsd:string"/>
<xsd:element name="Width" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CommodityType">
<xsd:sequence>
<xsd:element name="FreightClass" type="xsd:string"/>
<xsd:element name="NMFC" type="ship:NMFCType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NMFCType">
<xsd:sequence>
<xsd:element name="PrimeCode" type="xsd:string"/>
<xsd:element name="SubCode" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentResultsType">
<xsd:sequence>
<xsd:element name="Disclaimer" type="ship:DisclaimerType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="ShipmentCharges" type="ship:ShipmentChargesType" minOccurs="0"/>
<xsd:element name="NegotiatedRateCharges" type="ship:NegotiatedRateChargesType" minOccurs="0"/>
<xsd:element name="FRSShipmentData" type="ship:FRSShipmentDataType" minOccurs="0"/>
<xsd:element name="RatingMethod" type="xsd:string" minOccurs="0"/>
<xsd:element name="BillableWeightCalculationMethod" type="xsd:string" minOccurs="0"/>
<xsd:element name="BillingWeight" type="ship:BillingWeightType"/>
<xsd:element name="ShipmentIdentificationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="MIDualReturnShipmentKey" type="xsd:string" minOccurs="0"/>
<xsd:element name="ShipmentDigest" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackageResults" type="ship:PackageResultsType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="ControlLogReceipt" type="ship:ImageType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="Form" type="ship:FormType" minOccurs="0"/>
<xsd:element name="CODTurnInPage" type="ship:SCReportType" minOccurs="0"/>
<xsd:element name="HighValueReport" type="ship:HighValueReportType" minOccurs="0"/>
<xsd:element name="LabelURL" type="xsd:string" minOccurs="0"/>
<xsd:element name="LocalLanguageLabelURL" type="xsd:string" minOccurs="0"/>
<xsd:element name="ReceiptURL" type="xsd:string" minOccurs="0"/>
<xsd:element name="LocalLanguageReceiptURL" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DisclaimerType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentChargesType">
<xsd:sequence>
<xsd:element name="RateChart" type="xsd:string" minOccurs="0"/>
<xsd:element name="BaseServiceCharge" type="ship:ShipChargeType" minOccurs="0"/>
<xsd:element name="TransportationCharges" type="ship:ShipChargeType"/>
<xsd:element name="ItemizedCharges" type="ship:ShipChargeType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="ServiceOptionsCharges" type="ship:ShipChargeType"/>
<xsd:element name="TaxCharges" type="ship:TaxChargeType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="TotalCharges" type="ship:ShipChargeType"/>
<xsd:element name="TotalChargesWithTaxes" type="ship:ShipChargeType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NegotiatedRateChargesType">
<xsd:sequence>
<xsd:element name="ItemizedCharges" type="ship:ShipChargeType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="TaxCharges" type="ship:TaxChargeType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="TotalCharge" type="ship:ShipChargeType" minOccurs="0"/>
<xsd:element name="TotalChargesWithTaxes" type="ship:ShipChargeType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipChargeType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
<xsd:element name="CurrencyCode" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
<xsd:element name="SubType" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TaxChargeType">
<xsd:sequence>
<xsd:element name="Type" type="xsd:string"/>
<xsd:element name="MonetaryValue" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FRSShipmentDataType">
<xsd:sequence>
<xsd:element name="TransportationCharges" type="ship:TransportationChargeType"/>
<xsd:element name="FreightDensityRate" type="ship:FreightDensityRateType" minOccurs="0"/>
<xsd:element name="HandlingUnits" type="ship:HandlingUnitsResponseType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TransportationChargeType">
<xsd:sequence>
<xsd:element name="GrossCharge" type="ship:ShipChargeType"/>
<xsd:element name="DiscountAmount" type="ship:ShipChargeType"/>
<xsd:element name="DiscountPercentage" type="xsd:string"/>
<xsd:element name="NetCharge" type="ship:ShipChargeType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillingWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="ship:BillingUnitOfMeasurementType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BillingUnitOfMeasurementType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageResultsType">
<xsd:sequence>
<xsd:element name="TrackingNumber" type="xsd:string"/>
<xsd:element name="BaseServiceCharge" type="ship:ShipChargeType" minOccurs="0"/>
<xsd:element name="ServiceOptionsCharges" type="ship:ShipChargeType" minOccurs="0"/>
<xsd:element name="ShippingLabel" type="ship:LabelType" minOccurs="0"/>
<xsd:element name="ShippingReceipt" type="ship:ReceiptType" minOccurs="0"/>
<xsd:element name="USPSPICNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22Number" type="xsd:string" minOccurs="0"/>
<xsd:element name="Accessorial" type="ship:AccessorialType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="Form" type="ship:FormType" minOccurs="0"/>
<xsd:element name="ItemizedCharges" type="ship:ShipChargeType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="NegotiatedCharges" type="ship:NegotiatedChargesType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AccessorialType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelType">
<xsd:complexContent>
<xsd:extension base="ship:ImageType">
<xsd:sequence>
<xsd:element name="InternationalSignatureGraphicImage" type="xsd:string" minOccurs="0"/>
<xsd:element name="HTMLImage" type="xsd:string" minOccurs="0"/>
<xsd:element name="PDF417" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ReceiptType">
<xsd:complexContent>
<xsd:extension base="ship:ImageType"/>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ImageType">
<xsd:sequence>
<xsd:element name="ImageFormat" type="ship:ImageFormatType"/>
<xsd:element name="GraphicImage" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FormType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
<xsd:element name="Image" type="ship:FormImageType" minOccurs="0"/>
<xsd:element name="FormGroupId" type="xsd:string" minOccurs="0"/>
<xsd:element name="FormGroupIdName" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FormImageType">
<xsd:sequence>
<xsd:element name="ImageFormat" type="ship:ImageFormatType" minOccurs="0"/>
<xsd:element name="GraphicImage" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ImageFormatType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="SCReportType">
<xsd:sequence>
<xsd:element name="Image" type="ship:ImageType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HighValueReportType">
<xsd:sequence>
<xsd:element name="Image" type="ship:ImageType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HazMatPackageInformationType">
<xsd:sequence>
<xsd:element name="AllPackedInOneIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="OverPackedIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="QValue" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HazMatType">
<xsd:sequence>
<xsd:element name="PackagingTypeQuantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="RecordIdentifier1" type="xsd:string" minOccurs="0"/>
<xsd:element name="RecordIdentifier2" type="xsd:string" minOccurs="0"/>
<xsd:element name="RecordIdentifier3" type="xsd:string" minOccurs="0"/>
<xsd:element name="SubRiskClass" type="xsd:string" minOccurs="0"/>
<xsd:element name="aDRItemNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="aDRPackingGroupLetter" type="xsd:string" minOccurs="0"/>
<xsd:element name="TechnicalName" type="xsd:string" minOccurs="0"/>
<xsd:element name="HazardLabelRequired" type="xsd:string" minOccurs="0"/>
<xsd:element name="ClassDivisionNumber" type="xsd:string"/>
<xsd:element name="ReferenceNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Quantity" type="xsd:string"/>
<xsd:element name="UOM" type="xsd:string"/>
<xsd:element name="PackagingType" type="xsd:string"/>
<xsd:element name="IDNumber" type="xsd:string"/>
<xsd:element name="ProperShippingName" type="xsd:string"/>
<xsd:element name="AdditionalDescription" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackagingGroupType" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackagingInstructionCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="EmergencyPhone" type="xsd:string" minOccurs="0"/>
<xsd:element name="EmergencyContact" type="xsd:string" minOccurs="0"/>
<xsd:element name="ReportableQuantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="RegulationSet" type="xsd:string"/>
<xsd:element name="TransportationMode" type="xsd:string"/>
<xsd:element name="CommodityRegulatedLevelCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="TransportCategory" type="xsd:string" minOccurs="0"/>
<xsd:element name="TunnelRestrictionCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="ChemicalRecordIdentifier" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DryIceType">
<xsd:sequence>
<xsd:element name="RegulationSet" type="xsd:string"/>
<xsd:element name="DryIceWeight" type="ship:DryIceWeightType"/>
<xsd:element name="MedicalUseIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DryIceWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="ship:ShipUnitOfMeasurementType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ReceiptSpecificationType">
<xsd:sequence>
<xsd:element name="ImageFormat" type="ship:ReceiptImageFormatType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ReceiptImageFormatType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TaxIDCodeDescType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="IndicationType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AlternateDeliveryAddressType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string" minOccurs="0"/>
<xsd:element name="AttentionName" type="xsd:string" minOccurs="0"/>
<xsd:element name="UPSAccessPointID" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="ship:ADLAddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentServiceOptionsNotificationVoiceMessageType">
<xsd:sequence>
<xsd:element name="PhoneNumber" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipmentServiceOptionsNotificationTextMessageType">
<xsd:sequence>
<xsd:element name="PhoneNumber" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ADLAddressType">
<xsd:sequence>
<xsd:element name="AddressLine" type="xsd:string" maxOccurs="3"/>
<xsd:element name="City" type="xsd:string"/>
<xsd:element name="StateProvinceCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="PostalCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="CountryCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FreightShipmentInformationType">
<xsd:sequence>
<xsd:element name="FreightDensityInfo" type="ship:FreightDensityInfoType" minOccurs="0"/>
<xsd:element name="DensityEligibleIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HandlingUnitsType">
<xsd:sequence>
<xsd:element name="Quantity" type="xsd:string"/>
<xsd:element name="Type" type="ship:ShipUnitOfMeasurementType"/>
<xsd:element name="Dimensions" type="ship:HandlingUnitsDimensionsType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HandlingUnitsResponseType">
<xsd:sequence>
<xsd:element name="Quantity" type="xsd:string"/>
<xsd:element name="Type" type="ship:ShipUnitOfMeasurementType"/>
<xsd:element name="Dimensions" type="ship:HandlingUnitsDimensionsType"/>
<xsd:element name="AdjustedHeight" type="ship:AdjustedHeightType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HandlingUnitsDimensionsType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="ship:ShipUnitOfMeasurementType"/>
<xsd:element name="Length" type="xsd:string"/>
<xsd:element name="Width" type="xsd:string"/>
<xsd:element name="Height" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FreightDensityRateType">
<xsd:sequence>
<xsd:element name="Density" type="xsd:string" minOccurs="0"/>
<xsd:element name="TotalCubicFeet" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FreightDensityInfoType">
<xsd:sequence>
<xsd:element name="AdjustedHeightIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="AdjustedHeight" type="ship:AdjustedHeightType" minOccurs="0"/>
<xsd:element name="HandlingUnits" type="ship:HandlingUnitsType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AdjustedHeightType">
<xsd:sequence>
<xsd:element name="Value" type="xsd:string"/>
<xsd:element name="UnitOfMeasurement" type="ship:ShipUnitOfMeasurementType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NegotiatedChargesType">
<xsd:sequence>
<xsd:element name="ItemizedCharges" type="ship:ShipChargeType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,23 @@
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0" xmlns:upss="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xsd:element name="UPSSecurity">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="UsernameToken">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Username" type="xsd:string"/>
<xsd:element name="Password" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="ServiceAccessToken">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="AccessLicenseNumber" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- UPS Void Shipment Service WSDL Release Date Mar 11, 2008 -->
<!-- Copyright 2007-2008 United Parcel Service of America, Inc. All rights reserved. -->
<wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:error="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" xmlns:upss="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" xmlns:void="http://www.ups.com/XMLSchema/XOLTWS/Void/v1.1" xmlns:tns="http://www.ups.com/WSDL/XOLTWS/Void/v1.1" targetNamespace="http://www.ups.com/WSDL/XOLTWS/Void/v1.1">
<wsdl:types>
<xsd:schema>
<!-- This schema defines the UPS Security header used for authorization purposes -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/UPSS/v1.0" schemaLocation="UPSSecurity.xsd"/>
<!-- This schema defines the error detail data types returned within SOAPFaults to provide more specific information pertaining to the problem. -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Error/v1.1" schemaLocation="Error1.1.xsd"/>
<!-- This schema defines the Void Shipment service data types -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Void/v1.1" schemaLocation="VoidWebServiceSchema.xsd"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="VoidRequestMessage">
<wsdl:part name="Body" element="void:VoidShipmentRequest"/>
<wsdl:part name="UPSSecurity" element="upss:UPSSecurity"/>
</wsdl:message>
<wsdl:message name="VoidResponseMessage">
<wsdl:part name="Body" element="void:VoidShipmentResponse"/>
</wsdl:message>
<wsdl:message name="VoidErrorMessage">
<wsdl:part name="VoidError" element="error:Errors"/>
</wsdl:message>
<wsdl:portType name="VoidPortType">
<wsdl:operation name="ProcessVoid">
<wsdl:input name="VoidShipmentRequest" message="tns:VoidRequestMessage"/>
<wsdl:output name="VoidShipmentResponse" message="tns:VoidResponseMessage"/>
<wsdl:fault name="VoidError" message="tns:VoidErrorMessage"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="VoidBinding" type="tns:VoidPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="ProcessVoid">
<soap:operation soapAction="http://onlinetools.ups.com/webservices/VoidBinding/v1.1" style="document"/>
<wsdl:input name="VoidShipmentRequest">
<soap:body parts="Body" use="literal"/>
<soap:header message="tns:VoidRequestMessage" part="UPSSecurity" use="literal">
<soap:headerfault message="tns:VoidErrorMessage" part="VoidError" use="literal"/>
</soap:header>
</wsdl:input>
<wsdl:output name="VoidShipmentResponse">
<soap:body parts="Body" use="literal"/>
</wsdl:output>
<wsdl:fault name="VoidError">
<soap:fault name="VoidError" use="literal"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="VoidService">
<wsdl:port name="VoidPort" binding="tns:VoidBinding">
<!-- Production URL -->
<!-- <soap:address location="https://onlinetools.ups.com/webservices/Void"/> -->
<!-- CIE (Customer Integration Environment) URL -->
<soap:address location="https://wwwcie.ups.com/webservices/Void"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@@ -0,0 +1,45 @@
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/Void/v1.1" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:void="http://www.ups.com/XMLSchema/XOLTWS/Void/v1.1" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" elementFormDefault="qualified" version="201601">
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" schemaLocation="common.xsd"/>
<xsd:element name="VoidShipmentRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Request"/>
<xsd:element name="VoidShipment">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="ShipmentIdentificationNumber" type="xsd:string"/>
<xsd:element name="TrackingNumber" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="VoidShipmentResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Response"/>
<xsd:element name="SummaryResult">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Status" type="void:CodeDescriptionType"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="PackageLevelResult" type="void:PackageLevelResult" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="PackageLevelResult">
<xsd:sequence>
<xsd:element name="TrackingNumber" type="xsd:string"/>
<xsd:element name="Status" type="void:CodeDescriptionType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CodeDescriptionType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ups="http://www.ups.com/XMLSchema" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" elementFormDefault="qualified" version="201707">
<xsd:element name="Request" type="common:RequestType"/>
<xsd:element name="Response" type="common:ResponseType"/>
<xsd:element name="ClientInformation" type="common:ClientInformationType"/>
<xsd:complexType name="ClientInformationType">
<xsd:sequence>
<xsd:element name="Property" minOccurs="0" maxOccurs="unbounded">
<xsd:complexType>
<xsd:simpleContent>
<xsd:extension base="xsd:string">
<xsd:attribute name="Key" type="xsd:string" use="required"/>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
</xsd:element>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RequestType">
<xsd:sequence>
<xsd:element name="RequestOption" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="SubVersion" type="xsd:string" minOccurs="0"/>
<xsd:element name="TransactionReference" type="common:TransactionReferenceType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TransactionReferenceType">
<xsd:sequence>
<xsd:element name="CustomerContext" type="xsd:string" minOccurs="0"/>
<xsd:element name="TransactionIdentifier" type="xsd:string" minOccurs="0" ups:usage="notused"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ResponseType">
<xsd:sequence>
<xsd:element name="ResponseStatus" type="common:CodeDescriptionType"/>
<xsd:element name="Alert" type="common:CodeDescriptionType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="AlertDetail" type="common:DetailType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="TransactionReference" type="common:TransactionReferenceType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CodeDescriptionType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DetailType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
<xsd:element name="ElementLevelInformation" type="common:ElementLevelInformationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ElementLevelInformationType">
<xsd:sequence>
<xsd:element name="Level" type="xsd:string"/>
<xsd:element name="ElementIdentifier" type="common:ElementIdentifierType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ElementIdentifierType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

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

View File

@@ -0,0 +1,488 @@
import requests
import re
import base64
import io
# activate PDF support in PIL
import PIL.PdfImagePlugin # pylint: disable=W0611
from PIL import Image
from json.decoder import JSONDecodeError
from requests.exceptions import RequestException
from odoo import _
from odoo.exceptions import ValidationError
from odoo.tools import float_repr
from odoo.tools.urls import urljoin as url_join
TEST_BASE_URL = "https://wwwcie.ups.com"
PROD_BASE_URL = "https://onlinetools.ups.com"
API_VERSION = "v1"
TOKEN_TYPE = "Bearer"
class UPSRequest:
def __init__(self, carrier):
super_carrier = carrier.sudo()
self.logger = carrier.log_xml
self.base_url = PROD_BASE_URL if carrier.prod_environment else TEST_BASE_URL
self.access_token = super_carrier.ups_access_token
self.client_id = super_carrier.ups_client_id
self.client_secret = super_carrier.ups_client_secret
self.shipper_number = super_carrier.ups_shipper_number
self.carrier = carrier
self.session = requests.Session()
def _send_request(self, url, method='GET', data=None, json=None, headers=None, auth=None):
url = url_join(self.base_url, url)
def _request_call(req_headers):
if not req_headers and self.access_token:
req_headers = {
"Authorization": '%s %s' % (TOKEN_TYPE, self.access_token)
}
self.logger(f'{url}\n{method}\n{req_headers}\n{data}\n{json}', f'ups request {url}')
try:
res = self.session.request(method=method, url=url, json=json, data=data, headers=req_headers, auth=auth, timeout=15)
self.logger(f'{res.status_code} {res.text}', f'ups response {url}')
except RequestException as err:
self.logger(str(err), f'ups response {url}')
raise ValidationError(_('Something went wrong, please try again later!!'))
return res
res = _request_call(headers)
if res.status_code == 401 and auth is None:
self.access_token = self._get_new_access_token()
self.carrier.sudo().ups_access_token = self.access_token
res = _request_call(None)
return res
def _process_errors(self, res_body):
err_msgs = []
response = res_body.get('response')
if response:
for err in response.get('errors', []):
err_msgs.append(err['message'])
return ','.join(err_msgs)
def _process_alerts(self, response):
alerts = response.get('Alert', [])
if isinstance(alerts, list):
messages = [alert['Description'] for alert in alerts]
return '\n'.join(messages)
return alerts['Description']
def _get_new_access_token(self):
if not self.client_id or not self.client_secret:
raise ValidationError(_('You must setup a client ID and secret on the carrier first'))
url = '/security/v1/oauth/token'
headers = {
'x-merchant-id': self.client_id
}
data = {
"grant_type": "client_credentials"
}
res = self._send_request(url, 'POST', data=data, headers=headers, auth=(self.client_id, self.client_secret))
try:
res_body = res.json()
except JSONDecodeError as err:
self.logger(str(err), f'ups response decode error {url}')
raise ValidationError(_('Could not decode response'))
if not res.ok:
raise ValidationError(self._process_errors(res_body))
return res_body.get('access_token')
def _clean_phone_number(self, phone):
return re.sub('[^0-9]', '', phone)
def _save_label(self, image64, label_file_type='GIF'):
img_decoded = base64.decodebytes(image64.encode('utf-8'))
if label_file_type == 'GIF':
# Label format is GIF, so need to rotate and convert as PDF
image_string = io.BytesIO(img_decoded)
im = Image.open(image_string)
label_result = io.BytesIO()
im.save(label_result, 'pdf')
return label_result.getvalue()
else:
return img_decoded
def _check_required_value(self, order=False, picking=False, is_return=False):
is_express_checkout_partial_delivery_address = False
if order:
is_express_checkout_partial_delivery_address = order.env.context.get('express_checkout_partial_delivery_address')
shipper = order.company_id.partner_id
ship_from = order.warehouse_id.partner_id
ship_to = order.partner_shipping_id
elif picking and is_return:
ship_from = shipper = picking.partner_id
ship_to = picking.picking_type_id.warehouse_id.partner_id
else:
shipper = picking.company_id.partner_id
ship_from = picking.picking_type_id.warehouse_id.partner_id
ship_to = picking.partner_id
required_field = {'city': 'City', 'country_id': 'Country', 'phone': 'Phone'}
# Check required field for shipper
res = [required_field[field] for field in required_field if not shipper[field]]
if shipper.country_id.code in ('US', 'CA', 'IE') and not shipper.state_id.code:
res.append('State')
if not shipper.street and not shipper.street2:
res.append('Street')
if shipper.country_id.code != 'HK' and not shipper.zip:
res.append('ZIP code')
if res:
return _("The address of your company is missing or wrong.\n(Missing field(s) : %s)", ",".join(res))
if len(self._clean_phone_number(shipper.phone)) < 10:
return _("Shipper Phone must be at least 10 alphanumeric characters.")
# Check required field for warehouse address
res = [required_field[field] for field in required_field if not ship_from[field]]
if ship_from.country_id.code in ('US', 'CA', 'IE') and not ship_from.state_id.code:
res.append('State')
if not ship_from.street and not ship_from.street2:
res.append('Street')
if ship_from.country_id.code != 'HK' and not ship_from.zip:
res.append('ZIP code')
if res:
return _("The address of your warehouse is missing or wrong.\n(Missing field(s) : %s)", ",".join(res))
if len(self._clean_phone_number(ship_from.phone)) < 10:
return _("Warehouse Phone must be at least 10 alphanumeric characters."),
# Check required field for recipient address
res = [required_field[field] for field in required_field if field != 'phone' and not ship_to[field]]
if ship_to.country_id.code in ('US', 'CA', 'IE') and not ship_to.state_id.code:
res.append('State')
if not ship_to.street and not ship_to.street2 and not is_express_checkout_partial_delivery_address:
res.append('Street')
if ship_to.country_id.code != 'HK' and not ship_to.zip:
res.append('ZIP code')
if len(ship_to.street or '') > 35 or len(ship_to.street2 or '') > 35:
return _("UPS address lines can only contain a maximum of 35 characters. You can split the contacts addresses on multiple lines to try to avoid this limitation.")
if picking and not order:
order = picking.sale_id
phone = ship_to.phone
if order and not phone:
phone = order.partner_id.phone
if order:
if not order.order_line:
return _("Please provide at least one item to ship.")
if error_lines := order.order_line._get_invalid_delivery_weight_lines():
return _(
"The estimated shipping price cannot be computed because the weight is missing for the following product(s): \n %s",
", ".join(error_lines.product_id.mapped('name')),
)
if picking:
for ml in picking.move_line_ids.filtered(lambda ml: not ml.result_package_id and not ml.product_id.weight):
return _("The delivery cannot be done because the weight of your product %s is missing.", ml.product_id.display_name)
packages_without_weight = picking.move_line_ids.mapped('result_package_id').filtered(lambda p: not p.shipping_weight)
if packages_without_weight:
return _('Packages %s do not have a positive shipping weight.', ', '.join(packages_without_weight.mapped('display_name')))
if not phone and not is_express_checkout_partial_delivery_address:
res.append('Phone')
if res:
return _("The recipient address is missing or wrong.\n(Missing field(s) : %s)", ",".join(res))
if phone and len(self._clean_phone_number(phone)) < 10:
return _("Recipient Phone must be at least 10 alphanumeric characters."),
return False
def _set_package_details(self, packages, carrier, ship_from, ship_to, cod_info, ship=False, is_return=False):
# Package Type key in ship request and rate request are different
package_type_key = 'Packaging' if ship else 'PackagingType'
res_packages = []
for p in packages:
# merchandise description: product names (len: [1-35]), strip non-alphanumeric chars
desc = ','.join(['%s' % re.sub(r'[\W_]+', ' ', c.product_id.name) for c in p.commodities])
if is_return:
desc = 'return ' + desc
if len(desc) > 35:
desc = desc[:32] + '...'
package = {
package_type_key: {
'Code': p.packaging_type or '00',
},
'Description': desc or 'UPS shipment',
'PackageWeight': {
'UnitOfMeasurement': {
'Code': carrier.ups_package_weight_unit,
},
'Weight': str(carrier._ups_convert_weight(p.weight, carrier.ups_package_weight_unit)),
},
'Dimensions': {
'UnitOfMeasurement': {
'Code': carrier.ups_package_dimension_unit or '',
},
'Length': str(p.dimension['length']) or '',
'Width': str(p.dimension['width']) or '',
'Height': str(p.dimension['height']) or '',
}
}
package_service_options = {}
if cod_info:
package_service_options['COD'] = {
'CODFundsCode': cod_info['funds_code'],
'CODAmount': {
'MonetaryValue': str(cod_info['monetary_value']),
'CurrencyCode': cod_info['currency'],
}
}
if p.currency_id:
package_service_options['DeclaredValue'] = {
'CurrencyCode': p.currency_id.name,
'MonetaryValue': float_repr(p.total_cost * carrier.shipping_insurance / 100, 2),
}
if package_service_options:
package['PackageServiceOptions'] = package_service_options
# Package and shipment reference text is only allowed for shipments within
# the USA and within Puerto Rico. This is a UPS limitation.
if (p.name and ' ' not in p.name and ship_from.country_id.code in ('US') and ship_to.country_id.code in ('US')):
package.update({
'ReferenceNumber': {
'Code': 'PM',
'Value': p.name,
'BarCodeIndicator': p.name,
}
})
res_packages.append(package)
return res_packages
def _get_ship_data_from_partner(self, partner, shipper_no=None):
return {
'AttentionName': (partner.name or '')[:35],
'Name': (partner.parent_id.name or partner.name or '')[:35],
'EMailAddress': partner.email or '',
'ShipperNumber': shipper_no or '',
'Phone': {
'Number': (partner.phone or '').replace(' ', ''),
},
'Address': {
'AddressLine': [partner.street or '', partner.street2 or ''],
'City': partner.city or '',
'PostalCode': partner.zip or '',
'CountryCode': partner.country_id.code or '',
'StateProvinceCode': partner.state_id.code or '',
},
}
def _get_shipping_price(self, shipper, ship_from, ship_to, total_qty, packages, carrier, cod_info=None):
service_type = carrier.ups_default_service_type
saturday_delivery = carrier.ups_saturday_delivery
url = f'/api/rating/{API_VERSION}/Rate'
shipment_service_options = {}
if saturday_delivery:
shipment_service_options['SaturdayDeliveryIndicator'] = saturday_delivery
if carrier.ups_require_signature:
shipment_service_options['DeliveryConfirmation'] = {'DCISType': '1'}
data = {
'RateRequest': {
'Request': {
'RequestOption': 'Rate',
},
'Shipment': {
'Package': self._set_package_details(packages, carrier, ship_from, ship_to, cod_info),
'Shipper': self._get_ship_data_from_partner(shipper, self.shipper_number),
'ShipFrom': self._get_ship_data_from_partner(ship_from),
'ShipTo': self._get_ship_data_from_partner(ship_to),
'Service': {
'Code': service_type,
},
'NumOfPieces': str(int(total_qty)) if service_type == '96' else None,
'ShipmentServiceOptions': shipment_service_options if shipment_service_options else None,
'ShipmentRatingOptions': {
'NegotiatedRatesIndicator': "1",
}
}
},
}
res = self._send_request(url, method='POST', json=data)
if not res.ok:
return {'error_message': self._process_errors(res.json())}
res = res.json()
rate = res['RateResponse']['RatedShipment']
charge = rate['TotalCharges']
# Some users are qualified to receive negotiated rates
if 'NegotiatedRateCharges' in rate and rate['NegotiatedRateCharges']['TotalCharge']['MonetaryValue']:
charge = rate['NegotiatedRateCharges']['TotalCharge']
return {
'currency_code': charge['CurrencyCode'],
'price': charge['MonetaryValue'],
'alert_message': self._process_alerts(res['RateResponse']['Response']),
}
def _set_invoice(self, shipment_info, commodities, ship_to, is_return):
invoice_products = []
for commodity in commodities:
# split the name of the product to maximum 3 substrings of length 35
name = commodity.product_id.name
product = {
'Description': [line for line in [name[35 * i:35 * (i + 1)] for i in range(3)] if line],
'Unit': {
'Number': str(int(commodity.qty)),
'UnitOfMeasurement': {
'Code': 'PC' if commodity.qty == 1 else 'PCS',
},
'Value': float_repr(commodity.monetary_value, 2)
},
'OriginCountryCode': commodity.country_of_origin,
'CommodityCode': commodity.product_id.hs_code or '',
}
invoice_products.append(product)
if len(ship_to.commercial_partner_id.name) > 35:
raise ValidationError(_('The name of the customer should be no more than 35 characters.'))
contacts = {
'SoldTo': {
'Name': ship_to.commercial_partner_id.name,
'AttentionName': ship_to.name,
'Address': {
'AddressLine': [line for line in (ship_to.street, ship_to.street2) if line],
'City': ship_to.city,
'PostalCode': ship_to.zip,
'CountryCode': ship_to.country_id.code,
'StateProvinceCode': ship_to.state_id.code or '' if ship_to.country_id.code in ('US', 'CA', 'IE') else None
}
}
}
return {
'FormType': '01',
'Product': invoice_products,
'CurrencyCode': shipment_info.get('itl_currency_code'),
'InvoiceDate': shipment_info.get('invoice_date'),
'ReasonForExport': 'RETURN' if is_return else 'SALE',
'Contacts': contacts,
}
def _send_shipping(self, shipment_info, packages, carrier, shipper, ship_from, ship_to, service_type, duty_payment,
saturday_delivery=False, cod_info=None, label_file_type='GIF', ups_carrier_account=False, is_return=False):
url = f'/api/shipments/{API_VERSION}/ship'
# Payment Info
shipment_charge = {
'Type': '01',
}
payment_info = [shipment_charge]
if ups_carrier_account:
shipment_charge['BillReceiver'] = {
'AccountNumber': ups_carrier_account,
'Address': {
'PostalCode': ship_to.zip,
}
}
else:
shipment_charge['BillShipper'] = {
'AccountNumber': self.shipper_number,
}
if duty_payment == 'SENDER':
payment_info.append({
'Type': '02',
'BillShipper': {'AccountNumber': self.shipper_number},
})
shipment_service_options = {}
if shipment_info.get('require_invoice'):
shipment_service_options['InternationalForms'] = self._set_invoice(shipment_info, [c for pkg in packages for c in pkg.commodities],
ship_to, is_return)
shipment_service_options['InternationalForms']['PurchaseOrderNumber'] = shipment_info.get('purchase_order_number')
shipment_service_options['InternationalForms']['TermsOfShipment'] = shipment_info.get('terms_of_shipment')
if saturday_delivery:
shipment_service_options['SaturdayDeliveryIndicator'] = saturday_delivery
if carrier.ups_require_signature:
shipment_service_options['DeliveryConfirmation'] = {'DCISType': '1'}
request = {
'ShipmentRequest': {
'Request': {
'RequestOption': 'nonvalidate',
},
'LabelSpecification': {
'LabelImageFormat': {
'Code': label_file_type,
},
'LabelStockSize': {'Height': '6', 'Width': '4'} if label_file_type != 'GIF' else None,
},
'Shipment': {
'Description': shipment_info.get('description'),
'ReturnService': {'Code': '9'}if is_return else None,
'Package': self._set_package_details(packages, carrier, ship_from, ship_to, cod_info, ship=True, is_return=is_return),
'Shipper': self._get_ship_data_from_partner(shipper, self.shipper_number),
'ShipFrom': self._get_ship_data_from_partner(ship_from),
'ShipTo': self._get_ship_data_from_partner(ship_to),
'Service': {
'Code': service_type,
},
'NumOfPiecesInShipment': int(shipment_info.get('total_qty')) if service_type == '96' else None,
'ShipmentServiceOptions': shipment_service_options if shipment_service_options else None,
'ShipmentRatingOptions': {
'NegotiatedRatesIndicator': '1',
},
'PaymentInformation': {
'ShipmentCharge': payment_info,
},
},
},
}
# Include ReferenceNumber only if the shipment is not US/US or PR/PR
if not (
(ship_from.country_id.code == 'US' and ship_to.country_id.code == 'US') or
(ship_from.country_id.code == 'PR' and ship_to.country_id.code == 'PR')
):
request['ShipmentRequest']['Shipment']['ReferenceNumber'] = {
'Value': shipment_info.get('reference_number')
}
# Shipments from US to CA or PR require extra info
if ship_from.country_id.code == 'US' and ship_to.country_id.code in ['CA', 'PR']:
request['ShipmentRequest']['Shipment']['InvoiceLineTotal'] = {
'CurrencyCode': shipment_info.get('itl_currency_code'),
'MonetaryValue': shipment_info.get('ilt_monetary_value'),
}
res = self._send_request(url, 'POST', json=request)
if res.status_code == 401:
raise ValidationError(_("Invalid Authentication Information: Please check your credentials and configuration within UPS's system."))
try:
res_body = res.json()
except JSONDecodeError as err:
self.logger(str(err), f'ups response decode error {url}')
raise ValidationError(_('Could not decode response'))
if not res.ok:
raise ValidationError(self._process_errors(res.json()))
result = {}
shipment_result = res_body['ShipmentResponse']['ShipmentResults']
packs = shipment_result.get('PackageResults', [])
# get package labels
if not isinstance(packs, list):
packs = [packs]
result['tracking_ref'] = shipment_result['ShipmentIdentificationNumber']
labels_binary = [(pack['TrackingNumber'], self._save_label(pack['ShippingLabel']['GraphicImage'], label_file_type=label_file_type)) for pack in packs]
result['label_binary_data'] = labels_binary
# save international form if in response
international_form = shipment_result.get('Form', False)
if international_form:
result['invoice_binary_data'] = self._save_label(international_form['Image']['GraphicImage'], label_file_type='pdf')
# Some users are qualified to receive negotiated rates
if shipment_result.get('NegotiatedRateCharges'):
charge = shipment_result['NegotiatedRateCharges']['TotalCharge']
else:
charge = shipment_result['ShipmentCharges']['TotalCharges']
result['currency_code'] = charge['CurrencyCode']
result['price'] = charge['MonetaryValue']
return result
def _cancel_shipping(self, shipping_id):
url = f'/api/shipments/{API_VERSION}/void/cancel/{shipping_id}'
res = self._send_request(url, 'DELETE')
if res.status_code == 401:
raise ValidationError(_("Invalid Authentication Information: Please check your credentials and configuration within UPS's system."))
try:
res_body = res.json()
except JSONDecodeError as err:
self.logger(str(err), f'ups response decode error {url}')
raise ValidationError(_('Could not decode response'))
if not res.ok:
raise ValidationError(self._process_errors(res.json()))
return res_body['VoidShipmentResponse']['SummaryResult']['Status']