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
7
fusion_shipping/README.md
Normal file
@@ -0,0 +1,7 @@
|
||||
# Nexa Systems Inc
|
||||
|
||||
## Changelog
|
||||
|
||||
### 19.0.1.0.0
|
||||
|
||||
- Initial version
|
||||
3
fusion_shipping/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from . import models
|
||||
from . import wizard
|
||||
from . import api
|
||||
32
fusion_shipping/__manifest__.py
Normal file
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Fusion Shipping",
|
||||
"version": "19.0.1.0.0",
|
||||
"category": "Inventory/Delivery",
|
||||
"summary": "All-in-one shipping integration — Canada Post, UPS, FedEx, DHL Express. "
|
||||
"Live pricing, label generation, shipment tracking, and multi-package support.",
|
||||
"license": "OPL-1",
|
||||
"depends": ["stock_delivery", "sale_management", "mail", "payment"],
|
||||
"data": [
|
||||
"security/ir.model.access.csv",
|
||||
"data/ir_sequence_data.xml",
|
||||
"data/fusion_shipping_data.xml",
|
||||
"data/ir_cron_data.xml",
|
||||
"views/fusion_shipment_views.xml",
|
||||
"views/delivery_carrier_view.xml",
|
||||
"views/choose_delivery_carrier_views.xml",
|
||||
"views/sale_order_views.xml",
|
||||
"views/stock_picking_views.xml",
|
||||
"views/res_partner_views.xml",
|
||||
"views/report_templates.xml",
|
||||
"views/menus.xml",
|
||||
"views/res_config_settings_views.xml",
|
||||
],
|
||||
"images": ["static/description/icon.png"],
|
||||
"author": "Nexa Systems Inc",
|
||||
"website": "https://nexasystems.ca",
|
||||
"maintainer": "Nexa Systems Inc",
|
||||
"support": "support@nexasystems.ca",
|
||||
"installable": True,
|
||||
"auto_install": False,
|
||||
"application": True,
|
||||
}
|
||||
7
fusion_shipping/api/__init__.py
Normal 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
|
||||
2
fusion_shipping/api/canada_post/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import response
|
||||
from . import utils
|
||||
164
fusion_shipping/api/canada_post/response.py
Normal 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())
|
||||
215
fusion_shipping/api/canada_post/utils.py
Normal 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)
|
||||
1
fusion_shipping/api/dhl/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import request
|
||||
343
fusion_shipping/api/dhl/request.py
Normal 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
|
||||
92
fusion_shipping/api/dhl/wsdl/DCT-Response_global-2.0.xsd
Normal 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>
|
||||
47
fusion_shipping/api/dhl/wsdl/DCT-req_global-2.0.xsd
Normal 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>
|
||||
449
fusion_shipping/api/dhl/wsdl/DCTRequestdatatypes_global.xsd
Normal 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>
|
||||
876
fusion_shipping/api/dhl/wsdl/DCTResponsedatatypes_global.xsd
Normal 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>
|
||||
2660
fusion_shipping/api/dhl/wsdl/datatypes.xsd
Normal file
4596
fusion_shipping/api/dhl/wsdl/datatypes_global_v10.xsd
Normal file
2470
fusion_shipping/api/dhl/wsdl/datatypes_global_v62.xsd
Normal file
18
fusion_shipping/api/dhl/wsdl/err-res.xsd
Normal 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>
|
||||
9
fusion_shipping/api/dhl/wsdl/rate.wsdl
Normal 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>
|
||||
10
fusion_shipping/api/dhl/wsdl/ship-10.0.wsdl
Normal 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>
|
||||
19
fusion_shipping/api/dhl/wsdl/ship-val-err-res-10.0.xsd
Normal 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>
|
||||
212
fusion_shipping/api/dhl/wsdl/ship-val-global-req-10.0.xsd
Normal 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 GLS’s 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 GLS’s 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, customer’s 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>
|
||||
341
fusion_shipping/api/dhl/wsdl/ship-val-global-res-10.0.xsd
Normal 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 shipment’s 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 shipment’s 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 DHL’s 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 DHL’s 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 account’s 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 GLS’s 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 customer’s barcode type, barcode code and barcode text if available in client’s 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>
|
||||
1
fusion_shipping/api/dhl_rest/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import request
|
||||
240
fusion_shipping/api/dhl_rest/request.py
Normal 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
|
||||
1
fusion_shipping/api/fedex/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import request
|
||||
502
fusion_shipping/api/fedex/request.py
Normal 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)
|
||||
BIN
fusion_shipping/api/fedex/wsdl/prod/._RateService_v31.wsdl
Normal file
BIN
fusion_shipping/api/fedex/wsdl/prod/._ShipService_v28.wsdl
Normal file
5047
fusion_shipping/api/fedex/wsdl/prod/RateService_v31.wsdl
Normal file
5778
fusion_shipping/api/fedex/wsdl/prod/ShipService_v28.wsdl
Normal file
BIN
fusion_shipping/api/fedex/wsdl/test/._RateService_v31.wsdl
Normal file
BIN
fusion_shipping/api/fedex/wsdl/test/._ShipService_v28.wsdl
Normal file
5047
fusion_shipping/api/fedex/wsdl/test/RateService_v31.wsdl
Normal file
5778
fusion_shipping/api/fedex/wsdl/test/ShipService_v28.wsdl
Normal file
1
fusion_shipping/api/fedex_rest/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import request
|
||||
656
fusion_shipping/api/fedex_rest/request.py
Normal 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)
|
||||
1
fusion_shipping/api/ups/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import request
|
||||
637
fusion_shipping/api/ups/request.py
Normal 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)
|
||||
59
fusion_shipping/api/ups/wsdl/Error1.1.xsd
Normal 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>
|
||||
318
fusion_shipping/api/ups/wsdl/IFWS.xsd
Normal 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>
|
||||
58
fusion_shipping/api/ups/wsdl/RateWS.wsdl
Normal 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>
|
||||
619
fusion_shipping/api/ups/wsdl/RateWebServiceSchema.xsd
Normal 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>
|
||||
123
fusion_shipping/api/ups/wsdl/Ship.wsdl
Normal 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>
|
||||
865
fusion_shipping/api/ups/wsdl/ShipWebServiceSchema.xsd
Normal 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>
|
||||
23
fusion_shipping/api/ups/wsdl/UPSSecurity.xsd
Normal 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>
|
||||
58
fusion_shipping/api/ups/wsdl/Void.wsdl
Normal 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>
|
||||
45
fusion_shipping/api/ups/wsdl/VoidWebServiceSchema.xsd
Normal 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>
|
||||
65
fusion_shipping/api/ups/wsdl/common.xsd
Normal 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>
|
||||
1
fusion_shipping/api/ups_rest/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import request
|
||||
488
fusion_shipping/api/ups_rest/request.py
Normal 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']
|
||||
560
fusion_shipping/data/fusion_shipping_data.xml
Normal file
@@ -0,0 +1,560 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<odoo>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- Package Types (noupdate="0" so they refresh on module upgrade) -->
|
||||
<!-- ================================================================== -->
|
||||
<data noupdate="0">
|
||||
|
||||
<!-- ── Standard Canada Post Box Sizes (inches / lbs) ── -->
|
||||
|
||||
<record id="fusion_cp_pkg_26x20x20" model="stock.package.type">
|
||||
<field name="name">CP Box 26x20x20 in, 35 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">26</field>
|
||||
<field name="width">20</field>
|
||||
<field name="height">20</field>
|
||||
<field name="max_weight">35</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_26x26x9" model="stock.package.type">
|
||||
<field name="name">CP Box 26x26x9 in, 15 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">26</field>
|
||||
<field name="width">26</field>
|
||||
<field name="height">9</field>
|
||||
<field name="max_weight">15</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_32x28x10" model="stock.package.type">
|
||||
<field name="name">CP Box 32x28x10 in, 12 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">32</field>
|
||||
<field name="width">28</field>
|
||||
<field name="height">10</field>
|
||||
<field name="max_weight">12</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_34x28x10" model="stock.package.type">
|
||||
<field name="name">CP Box 34x28x10 in, 10 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">34</field>
|
||||
<field name="width">28</field>
|
||||
<field name="height">10</field>
|
||||
<field name="max_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_9x25x27" model="stock.package.type">
|
||||
<field name="name">CP Box 9x25x27 in, 16 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">9</field>
|
||||
<field name="width">25</field>
|
||||
<field name="height">27</field>
|
||||
<field name="max_weight">16</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_9x25x29" model="stock.package.type">
|
||||
<field name="name">CP Box 9x25x29 in, 17 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">9</field>
|
||||
<field name="width">25</field>
|
||||
<field name="height">29</field>
|
||||
<field name="max_weight">17</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_10x10x6" model="stock.package.type">
|
||||
<field name="name">CP Box 10x10x6 in, 35 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">10</field>
|
||||
<field name="width">10</field>
|
||||
<field name="height">6</field>
|
||||
<field name="max_weight">35</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_25x15x30" model="stock.package.type">
|
||||
<field name="name">CP Box 25x15x30 in, 25 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">25</field>
|
||||
<field name="width">15</field>
|
||||
<field name="height">30</field>
|
||||
<field name="max_weight">25</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_10x10x10" model="stock.package.type">
|
||||
<field name="name">CP Box 10x10x10 in, 2 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">10</field>
|
||||
<field name="width">10</field>
|
||||
<field name="height">10</field>
|
||||
<field name="max_weight">2</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_28x15x30" model="stock.package.type">
|
||||
<field name="name">CP Box 28x15x30 in, 40 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">28</field>
|
||||
<field name="width">15</field>
|
||||
<field name="height">30</field>
|
||||
<field name="max_weight">40</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_28x10x30" model="stock.package.type">
|
||||
<field name="name">CP Box 28x10x30 in, 16 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">28</field>
|
||||
<field name="width">10</field>
|
||||
<field name="height">30</field>
|
||||
<field name="max_weight">16</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_22x10x6_cm" model="stock.package.type">
|
||||
<field name="name">CP Box 22x10x6 cm, 10 kg</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">22</field>
|
||||
<field name="width">10</field>
|
||||
<field name="height">6</field>
|
||||
<field name="max_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_22x13x6" model="stock.package.type">
|
||||
<field name="name">CP Box 22x13x6 in, 10 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">22</field>
|
||||
<field name="width">13</field>
|
||||
<field name="height">6</field>
|
||||
<field name="max_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_cp_pkg_12x10x5" model="stock.package.type">
|
||||
<field name="name">CP Box 12x10x5 in, 2 lb</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">12</field>
|
||||
<field name="width">10</field>
|
||||
<field name="height">5</field>
|
||||
<field name="max_weight">2</field>
|
||||
</record>
|
||||
|
||||
<!-- Old default box - replaced with a standard size -->
|
||||
<record id="fusion_cp_packaging_BOX" model="stock.package.type">
|
||||
<field name="name">CP Box 10x10x10 in (Legacy)</field>
|
||||
<field name="package_carrier_type">fusion_canada_post</field>
|
||||
<field name="packaging_length">10</field>
|
||||
<field name="width">10</field>
|
||||
<field name="height">10</field>
|
||||
<field name="max_weight">2</field>
|
||||
</record>
|
||||
|
||||
<!-- ── UPS REST Package Types ── -->
|
||||
|
||||
<record id="fusion_ups_rest_packaging_01" model="stock.package.type">
|
||||
<field name="name">UPS Letter</field>
|
||||
<field name="shipper_package_code">01</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">0.5</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_02" model="stock.package.type">
|
||||
<field name="name">UPS Package/customer supplied</field>
|
||||
<field name="shipper_package_code">02</field>
|
||||
<field name="height">10</field>
|
||||
<field name="width">10</field>
|
||||
<field name="packaging_length">10</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_03" model="stock.package.type">
|
||||
<field name="name">UPS Tube</field>
|
||||
<field name="shipper_package_code">03</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_04" model="stock.package.type">
|
||||
<field name="name">UPS Pak</field>
|
||||
<field name="shipper_package_code">04</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_21" model="stock.package.type">
|
||||
<field name="name">UPS Express Box</field>
|
||||
<field name="shipper_package_code">21</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_24" model="stock.package.type">
|
||||
<field name="name">UPS 25KG Box</field>
|
||||
<field name="shipper_package_code">24</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">25</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_25" model="stock.package.type">
|
||||
<field name="name">UPS 10KG Box</field>
|
||||
<field name="shipper_package_code">25</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_30" model="stock.package.type">
|
||||
<field name="name">UPS Pallet</field>
|
||||
<field name="shipper_package_code">30</field>
|
||||
<field name="height">10</field>
|
||||
<field name="width">10</field>
|
||||
<field name="packaging_length">10</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">1000</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_2a" model="stock.package.type">
|
||||
<field name="name">UPS Small Express Box</field>
|
||||
<field name="shipper_package_code">2a</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_2b" model="stock.package.type">
|
||||
<field name="name">UPS Medium Express Box</field>
|
||||
<field name="shipper_package_code">2b</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_rest_packaging_2c" model="stock.package.type">
|
||||
<field name="name">UPS Large Express Box</field>
|
||||
<field name="shipper_package_code">2c</field>
|
||||
<field name="package_carrier_type">fusion_ups_rest</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<!-- ── UPS SOAP (Legacy) Package Types ── -->
|
||||
|
||||
<record id="fusion_ups_packaging_01" model="stock.package.type">
|
||||
<field name="name">UPS Letter</field>
|
||||
<field name="shipper_package_code">01</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">0.5</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_02" model="stock.package.type">
|
||||
<field name="name">UPS Package/customer supplied</field>
|
||||
<field name="shipper_package_code">02</field>
|
||||
<field name="height">52</field>
|
||||
<field name="width">52</field>
|
||||
<field name="packaging_length">52</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_03" model="stock.package.type">
|
||||
<field name="name">UPS Tube</field>
|
||||
<field name="shipper_package_code">03</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_04" model="stock.package.type">
|
||||
<field name="name">UPS Pak</field>
|
||||
<field name="shipper_package_code">04</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_21" model="stock.package.type">
|
||||
<field name="name">UPS Express Box</field>
|
||||
<field name="shipper_package_code">21</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_24" model="stock.package.type">
|
||||
<field name="name">UPS 25KG Box</field>
|
||||
<field name="shipper_package_code">24</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">25</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_25" model="stock.package.type">
|
||||
<field name="name">UPS 10KG Box</field>
|
||||
<field name="shipper_package_code">25</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_30" model="stock.package.type">
|
||||
<field name="name">UPS Pallet</field>
|
||||
<field name="shipper_package_code">30</field>
|
||||
<field name="height">1920</field>
|
||||
<field name="width">2133</field>
|
||||
<field name="packaging_length">3048</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">1000</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_2a" model="stock.package.type">
|
||||
<field name="name">UPS Small Express Box</field>
|
||||
<field name="shipper_package_code">2a</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_2b" model="stock.package.type">
|
||||
<field name="name">UPS Medium Express Box</field>
|
||||
<field name="shipper_package_code">2b</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_ups_packaging_2c" model="stock.package.type">
|
||||
<field name="name">UPS Flat Pack</field>
|
||||
<field name="shipper_package_code">2c</field>
|
||||
<field name="package_carrier_type">fusion_ups</field>
|
||||
<field name="max_weight">68</field>
|
||||
</record>
|
||||
|
||||
<!-- ── FedEx REST Package Types ── -->
|
||||
|
||||
<record id="fusion_fedex_rest_packaging_FEDEX_BOX" model="stock.package.type">
|
||||
<field name="name">FedEx Box</field>
|
||||
<field name="shipper_package_code">FEDEX_BOX</field>
|
||||
<field name="package_carrier_type">fusion_fedex_rest</field>
|
||||
<field name="max_weight">9.07</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_rest_packaging_FEDEX_10KG_BOX" model="stock.package.type">
|
||||
<field name="name">FedEx 10kg Box</field>
|
||||
<field name="shipper_package_code">FEDEX_10KG_BOX</field>
|
||||
<field name="package_carrier_type">fusion_fedex_rest</field>
|
||||
<field name="max_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_rest_packaging_FEDEX_25KG_BOX" model="stock.package.type">
|
||||
<field name="name">FedEx 25kg Box</field>
|
||||
<field name="shipper_package_code">FEDEX_25KG_BOX</field>
|
||||
<field name="package_carrier_type">fusion_fedex_rest</field>
|
||||
<field name="max_weight">25</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_rest_packaging_FEDEX_ENVELOPE" model="stock.package.type">
|
||||
<field name="name">FedEx Letters</field>
|
||||
<field name="shipper_package_code">FEDEX_ENVELOPE</field>
|
||||
<field name="package_carrier_type">fusion_fedex_rest</field>
|
||||
<field name="max_weight">0.5</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_rest_packaging_FEDEX_PAK" model="stock.package.type">
|
||||
<field name="name">FedEx Pak</field>
|
||||
<field name="shipper_package_code">FEDEX_PAK</field>
|
||||
<field name="package_carrier_type">fusion_fedex_rest</field>
|
||||
<field name="max_weight">9.07</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_rest_packaging_FEDEX_TUBE" model="stock.package.type">
|
||||
<field name="name">FedEx Tube</field>
|
||||
<field name="shipper_package_code">FEDEX_TUBE</field>
|
||||
<field name="package_carrier_type">fusion_fedex_rest</field>
|
||||
<field name="max_weight">9.07</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_rest_packaging_YOUR_PACKAGING" model="stock.package.type">
|
||||
<field name="name">FedEx Your Packaging</field>
|
||||
<field name="shipper_package_code">YOUR_PACKAGING</field>
|
||||
<field name="package_carrier_type">fusion_fedex_rest</field>
|
||||
</record>
|
||||
|
||||
<!-- ── FedEx SOAP (Legacy) Package Types ── -->
|
||||
|
||||
<record id="fusion_fedex_packaging_FEDEX_BOX" model="stock.package.type">
|
||||
<field name="name">FedEx Box</field>
|
||||
<field name="shipper_package_code">FEDEX_BOX</field>
|
||||
<field name="package_carrier_type">fusion_fedex</field>
|
||||
<field name="max_weight">9.07</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_packaging_FEDEX_10KG_BOX" model="stock.package.type">
|
||||
<field name="name">FedEx 10kg Box</field>
|
||||
<field name="shipper_package_code">FEDEX_10KG_BOX</field>
|
||||
<field name="package_carrier_type">fusion_fedex</field>
|
||||
<field name="max_weight">10</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_packaging_FEDEX_25KG_BOX" model="stock.package.type">
|
||||
<field name="name">FedEx 25kg Box</field>
|
||||
<field name="shipper_package_code">FEDEX_25KG_BOX</field>
|
||||
<field name="package_carrier_type">fusion_fedex</field>
|
||||
<field name="max_weight">25</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_packaging_FEDEX_ENVELOPE" model="stock.package.type">
|
||||
<field name="name">FedEx Letters</field>
|
||||
<field name="shipper_package_code">FEDEX_ENVELOPE</field>
|
||||
<field name="package_carrier_type">fusion_fedex</field>
|
||||
<field name="max_weight">0.5</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_packaging_FEDEX_PAK" model="stock.package.type">
|
||||
<field name="name">FedEx Pak</field>
|
||||
<field name="shipper_package_code">FEDEX_PAK</field>
|
||||
<field name="package_carrier_type">fusion_fedex</field>
|
||||
<field name="max_weight">0</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_packaging_FEDEX_TUBE" model="stock.package.type">
|
||||
<field name="name">FedEx Tube</field>
|
||||
<field name="shipper_package_code">FEDEX_TUBE</field>
|
||||
<field name="package_carrier_type">fusion_fedex</field>
|
||||
<field name="max_weight">9.07</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_fedex_packaging_YOUR_PACKAGING" model="stock.package.type">
|
||||
<field name="name">FedEx Your Packaging</field>
|
||||
<field name="shipper_package_code">YOUR_PACKAGING</field>
|
||||
<field name="package_carrier_type">fusion_fedex</field>
|
||||
</record>
|
||||
|
||||
<!-- ── DHL REST Package Types ── -->
|
||||
|
||||
<record id="fusion_dhl_rest_packaging_FLY" model="stock.package.type">
|
||||
<field name="name">DHL Flyer/Smalls</field>
|
||||
<field name="shipper_package_code">FLY</field>
|
||||
<field name="package_carrier_type">fusion_dhl_rest</field>
|
||||
<field name="max_weight">0.23</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_rest_packaging_COY" model="stock.package.type">
|
||||
<field name="name">DHL Parcels/Conveyables</field>
|
||||
<field name="shipper_package_code">COY</field>
|
||||
<field name="package_carrier_type">fusion_dhl_rest</field>
|
||||
<field name="max_weight">31.5</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_rest_packaging_NCY" model="stock.package.type">
|
||||
<field name="name">DHL Non-conveyables</field>
|
||||
<field name="shipper_package_code">NCY</field>
|
||||
<field name="package_carrier_type">fusion_dhl_rest</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_rest_packaging_PAL" model="stock.package.type">
|
||||
<field name="name">DHL Pallets</field>
|
||||
<field name="shipper_package_code">PAL</field>
|
||||
<field name="height">160</field>
|
||||
<field name="width">120</field>
|
||||
<field name="packaging_length">120</field>
|
||||
<field name="package_carrier_type">fusion_dhl_rest</field>
|
||||
<field name="max_weight">1000</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_rest_packaging_DBL" model="stock.package.type">
|
||||
<field name="name">DHL Double Pallets</field>
|
||||
<field name="shipper_package_code">DBL</field>
|
||||
<field name="package_carrier_type">fusion_dhl_rest</field>
|
||||
<field name="max_weight">1000</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_rest_packaging_BOX" model="stock.package.type">
|
||||
<field name="name">DHL Box</field>
|
||||
<field name="shipper_package_code">BOX</field>
|
||||
<field name="height">40</field>
|
||||
<field name="width">44</field>
|
||||
<field name="packaging_length">54</field>
|
||||
<field name="package_carrier_type">fusion_dhl_rest</field>
|
||||
<field name="max_weight">70</field>
|
||||
</record>
|
||||
|
||||
<!-- ── DHL SOAP (Legacy) Package Types ── -->
|
||||
|
||||
<record id="fusion_dhl_packaging_FLY" model="stock.package.type">
|
||||
<field name="name">DHL Flyer/Smalls</field>
|
||||
<field name="shipper_package_code">FLY</field>
|
||||
<field name="package_carrier_type">fusion_dhl</field>
|
||||
<field name="max_weight">0.23</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_packaging_COY" model="stock.package.type">
|
||||
<field name="name">DHL Parcels/Conveyables</field>
|
||||
<field name="shipper_package_code">COY</field>
|
||||
<field name="package_carrier_type">fusion_dhl</field>
|
||||
<field name="max_weight">31.5</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_packaging_NCY" model="stock.package.type">
|
||||
<field name="name">DHL Non-conveyables</field>
|
||||
<field name="shipper_package_code">NCY</field>
|
||||
<field name="package_carrier_type">fusion_dhl</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_packaging_PAL" model="stock.package.type">
|
||||
<field name="name">DHL Pallets</field>
|
||||
<field name="shipper_package_code">PAL</field>
|
||||
<field name="height">1600</field>
|
||||
<field name="width">1200</field>
|
||||
<field name="packaging_length">1200</field>
|
||||
<field name="package_carrier_type">fusion_dhl</field>
|
||||
<field name="max_weight">1000</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_packaging_DBL" model="stock.package.type">
|
||||
<field name="name">DHL Double Pallets</field>
|
||||
<field name="shipper_package_code">DBL</field>
|
||||
<field name="package_carrier_type">fusion_dhl</field>
|
||||
<field name="max_weight">1000</field>
|
||||
</record>
|
||||
|
||||
<record id="fusion_dhl_packaging_BOX" model="stock.package.type">
|
||||
<field name="name">DHL Box</field>
|
||||
<field name="shipper_package_code">BOX</field>
|
||||
<field name="height">40</field>
|
||||
<field name="width">44</field>
|
||||
<field name="packaging_length">54</field>
|
||||
<field name="package_carrier_type">fusion_dhl</field>
|
||||
<field name="max_weight">70</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
<!-- ================================================================== -->
|
||||
<!-- Sequences & Products (noupdate="1") -->
|
||||
<!-- ================================================================== -->
|
||||
<data noupdate="1">
|
||||
|
||||
<!-- ── DHL Commercial Invoice Sequence ── -->
|
||||
|
||||
<record id="dhl_commercial_invoice_seq" model="ir.sequence">
|
||||
<field name="name">DHL Commercial Invoice</field>
|
||||
<field name="code">delivery_dhl_rest.commercial_invoice</field>
|
||||
<field name="prefix">CI</field>
|
||||
<field name="padding">5</field>
|
||||
</record>
|
||||
|
||||
<!-- ── Canada Post Delivery Product ── -->
|
||||
|
||||
<record id="product_product_delivery_fusion_canada_post" model="product.product">
|
||||
<field name="name">SHIPPING BY CANADA POST</field>
|
||||
<field name="default_code">CPSHIPPING</field>
|
||||
<field name="type">service</field>
|
||||
<field name="categ_id" ref="delivery.product_category_deliveries"/>
|
||||
<field name="sale_ok" eval="False"/>
|
||||
<field name="purchase_ok" eval="False"/>
|
||||
<field name="list_price">0.0</field>
|
||||
</record>
|
||||
|
||||
<!-- ── Default Canada Post Carrier ── -->
|
||||
|
||||
<record id="delivery_carrier_fusion_canada_post" model="delivery.carrier">
|
||||
<field name="name">Canada Post</field>
|
||||
<field
|
||||
name="product_id"
|
||||
ref="fusion_shipping.product_product_delivery_fusion_canada_post"
|
||||
/>
|
||||
<field name="delivery_type">fusion_canada_post</field>
|
||||
<field name="fusion_cp_type">commercial</field>
|
||||
<field name="fusion_cp_dimension_unit">in</field>
|
||||
<field name="option_code">SO</field>
|
||||
<field name="service_type">DOM.RP</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
|
||||
</odoo>
|
||||
14
fusion_shipping/data/ir_cron_data.xml
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="ir_cron_fusion_tracking_refresh" model="ir.cron">
|
||||
<field name="name">Fusion Shipping: Refresh Tracking</field>
|
||||
<field name="model_id" ref="model_fusion_shipment"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._cron_refresh_tracking()</field>
|
||||
<field name="interval_number">8</field>
|
||||
<field name="interval_type">hours</field>
|
||||
<field name="active">True</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
12
fusion_shipping/data/ir_sequence_data.xml
Normal file
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data noupdate="1">
|
||||
<record id="seq_fusion_shipment" model="ir.sequence">
|
||||
<field name="name">Fusion Shipment</field>
|
||||
<field name="code">fusion.shipment</field>
|
||||
<field name="prefix">FS-</field>
|
||||
<field name="padding">5</field>
|
||||
<field name="company_id" eval="False"/>
|
||||
</record>
|
||||
</data>
|
||||
</odoo>
|
||||
11
fusion_shipping/models/__init__.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from . import delivery_carrier
|
||||
from . import product_packaging
|
||||
from . import res_company
|
||||
from . import res_partner
|
||||
from . import payment_provider
|
||||
from . import uom_uom
|
||||
from . import fusion_shipment
|
||||
from . import fusion_tracking_event
|
||||
from . import fusion_order_package
|
||||
from . import sale_order
|
||||
from . import stock_picking
|
||||
3237
fusion_shipping/models/delivery_carrier.py
Normal file
40
fusion_shipping/models/fusion_order_package.py
Normal file
@@ -0,0 +1,40 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class FusionOrderPackage(models.Model):
|
||||
"""Stores per-package dimensions and service info on a sale order.
|
||||
|
||||
Created when the user confirms the "Add Shipping" wizard after
|
||||
defining one or more packages with dimensions.
|
||||
Used by ``send_shipping`` to apply the correct dimensions
|
||||
to each physical package on the delivery order.
|
||||
"""
|
||||
|
||||
_name = 'fusion.order.package'
|
||||
_description = 'Order Package'
|
||||
_order = 'sequence, id'
|
||||
|
||||
sale_order_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string='Sale Order',
|
||||
ondelete='cascade',
|
||||
required=True,
|
||||
index=True,
|
||||
)
|
||||
sequence = fields.Integer(default=10)
|
||||
package_type_id = fields.Many2one(
|
||||
'stock.package.type',
|
||||
string='Box Type',
|
||||
)
|
||||
package_length = fields.Float(string='Length')
|
||||
package_width = fields.Float(string='Width')
|
||||
package_height = fields.Float(string='Height')
|
||||
weight = fields.Float(string='Weight')
|
||||
service_code = fields.Char(string='Service Code')
|
||||
service_name = fields.Char(string='Service')
|
||||
price = fields.Float(string='Shipping Cost', digits='Product Price')
|
||||
expected_delivery = fields.Char(string='Expected Delivery')
|
||||
currency_id = fields.Many2one(
|
||||
'res.currency',
|
||||
related='sale_order_id.currency_id',
|
||||
)
|
||||
747
fusion_shipping/models/fusion_shipment.py
Normal file
@@ -0,0 +1,747 @@
|
||||
import base64
|
||||
import logging
|
||||
from datetime import datetime as dt_mod
|
||||
from lxml import etree
|
||||
from requests import request
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.fusion_shipping.api.canada_post.response import Response
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class FusionShipment(models.Model):
|
||||
_name = 'fusion.shipment'
|
||||
_description = 'Fusion Shipment'
|
||||
_inherit = ['mail.thread', 'mail.activity.mixin']
|
||||
_order = 'shipment_date desc, id desc'
|
||||
_rec_name = 'name'
|
||||
|
||||
name = fields.Char(
|
||||
string='Reference',
|
||||
required=True,
|
||||
readonly=True,
|
||||
default=lambda self: _('New'),
|
||||
copy=False,
|
||||
)
|
||||
carrier_type = fields.Selection(
|
||||
[
|
||||
('canada_post', 'Canada Post'),
|
||||
('ups', 'UPS'),
|
||||
('ups_rest', 'UPS (REST)'),
|
||||
('fedex', 'FedEx'),
|
||||
('fedex_rest', 'FedEx (REST)'),
|
||||
('dhl', 'DHL Express'),
|
||||
('dhl_rest', 'DHL Express (REST)'),
|
||||
],
|
||||
string='Carrier Type',
|
||||
readonly=True,
|
||||
tracking=True,
|
||||
help='The shipping carrier used for this shipment.',
|
||||
)
|
||||
tracking_number = fields.Char(
|
||||
string='Tracking Number',
|
||||
index=True,
|
||||
readonly=True,
|
||||
copy=False,
|
||||
tracking=True,
|
||||
)
|
||||
shipment_id = fields.Char(
|
||||
string='CP Shipment ID',
|
||||
readonly=True,
|
||||
copy=False,
|
||||
help='Canada Post internal shipment identifier',
|
||||
)
|
||||
sale_order_id = fields.Many2one(
|
||||
'sale.order',
|
||||
string='Sale Order',
|
||||
index=True,
|
||||
ondelete='set null',
|
||||
tracking=True,
|
||||
)
|
||||
picking_id = fields.Many2one(
|
||||
'stock.picking',
|
||||
string='Transfer',
|
||||
index=True,
|
||||
ondelete='set null',
|
||||
tracking=True,
|
||||
)
|
||||
carrier_id = fields.Many2one(
|
||||
'delivery.carrier',
|
||||
string='Carrier',
|
||||
ondelete='set null',
|
||||
)
|
||||
shipment_date = fields.Datetime(
|
||||
string='Shipment Date',
|
||||
default=fields.Datetime.now,
|
||||
tracking=True,
|
||||
)
|
||||
status = fields.Selection(
|
||||
[
|
||||
('draft', 'Draft'),
|
||||
('confirmed', 'Confirmed'),
|
||||
('shipped', 'Shipped'),
|
||||
('delivered', 'Delivered'),
|
||||
('returned', 'Returned'),
|
||||
('cancelled', 'Cancelled'),
|
||||
],
|
||||
string='Status',
|
||||
default='confirmed',
|
||||
tracking=True,
|
||||
)
|
||||
# Label attachments (Many2one for storage)
|
||||
label_attachment_id = fields.Many2one(
|
||||
'ir.attachment',
|
||||
string='Printable Label (4x6)',
|
||||
ondelete='set null',
|
||||
help='The thermal printer label (4x6 format)',
|
||||
)
|
||||
full_label_attachment_id = fields.Many2one(
|
||||
'ir.attachment',
|
||||
string='Full Label (8.5x11)',
|
||||
ondelete='set null',
|
||||
help='Full page label with instructions and receipt',
|
||||
)
|
||||
receipt_attachment_id = fields.Many2one(
|
||||
'ir.attachment',
|
||||
string='Receipt',
|
||||
ondelete='set null',
|
||||
)
|
||||
commercial_invoice_attachment_id = fields.Many2one(
|
||||
'ir.attachment',
|
||||
string='Commercial Invoice',
|
||||
ondelete='set null',
|
||||
)
|
||||
# Return label
|
||||
return_tracking_number = fields.Char(
|
||||
string='Return Tracking Number',
|
||||
readonly=True,
|
||||
copy=False,
|
||||
)
|
||||
return_label_attachment_id = fields.Many2one(
|
||||
'ir.attachment',
|
||||
string='Return Label',
|
||||
ondelete='set null',
|
||||
)
|
||||
# Shipment details
|
||||
shipping_cost = fields.Monetary(
|
||||
string='Shipping Cost',
|
||||
currency_field='currency_id',
|
||||
readonly=True,
|
||||
)
|
||||
service_type = fields.Char(
|
||||
string='Service Type',
|
||||
readonly=True,
|
||||
)
|
||||
weight = fields.Float(
|
||||
string='Weight',
|
||||
digits='Stock Weight',
|
||||
readonly=True,
|
||||
)
|
||||
package_name = fields.Char(
|
||||
string='Package',
|
||||
readonly=True,
|
||||
help='Name of the package this shipment covers',
|
||||
)
|
||||
# Address fields (computed)
|
||||
sender_name = fields.Char(
|
||||
string='Sender',
|
||||
compute='_compute_sender_fields',
|
||||
store=True,
|
||||
)
|
||||
sender_address = fields.Char(
|
||||
string='Sender Address',
|
||||
compute='_compute_sender_fields',
|
||||
store=True,
|
||||
)
|
||||
recipient_name = fields.Char(
|
||||
string='Recipient',
|
||||
compute='_compute_recipient_fields',
|
||||
store=True,
|
||||
)
|
||||
recipient_address = fields.Char(
|
||||
string='Recipient Address',
|
||||
compute='_compute_recipient_fields',
|
||||
store=True,
|
||||
)
|
||||
company_id = fields.Many2one(
|
||||
'res.company',
|
||||
string='Company',
|
||||
default=lambda self: self.env.company,
|
||||
)
|
||||
currency_id = fields.Many2one(
|
||||
'res.currency',
|
||||
related='company_id.currency_id',
|
||||
store=True,
|
||||
)
|
||||
# Tracking history
|
||||
tracking_event_ids = fields.One2many(
|
||||
'fusion.tracking.event',
|
||||
'shipment_id',
|
||||
string='Tracking Events',
|
||||
)
|
||||
tracking_event_count = fields.Integer(
|
||||
string='Tracking Events',
|
||||
compute='_compute_tracking_event_count',
|
||||
)
|
||||
last_tracking_update = fields.Datetime(
|
||||
string='Last Tracking Update',
|
||||
readonly=True,
|
||||
)
|
||||
delivery_date = fields.Datetime(
|
||||
string='Delivery Date',
|
||||
readonly=True,
|
||||
)
|
||||
|
||||
def _compute_tracking_event_count(self):
|
||||
for rec in self:
|
||||
rec.tracking_event_count = len(rec.tracking_event_ids)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
if vals.get('name', _('New')) == _('New'):
|
||||
vals['name'] = self.env['ir.sequence'].next_by_code(
|
||||
'fusion.shipment'
|
||||
) or _('New')
|
||||
return super().create(vals_list)
|
||||
|
||||
@api.depends('picking_id', 'picking_id.picking_type_id.warehouse_id.partner_id')
|
||||
def _compute_sender_fields(self):
|
||||
for rec in self:
|
||||
partner = (
|
||||
rec.picking_id.picking_type_id.warehouse_id.partner_id
|
||||
if rec.picking_id
|
||||
else False
|
||||
)
|
||||
if partner:
|
||||
rec.sender_name = partner.name or ''
|
||||
parts = filter(None, [
|
||||
partner.street,
|
||||
partner.city,
|
||||
partner.state_id.name if partner.state_id else '',
|
||||
partner.zip,
|
||||
])
|
||||
rec.sender_address = ', '.join(parts)
|
||||
else:
|
||||
rec.sender_name = ''
|
||||
rec.sender_address = ''
|
||||
|
||||
@api.depends('picking_id', 'picking_id.partner_id')
|
||||
def _compute_recipient_fields(self):
|
||||
for rec in self:
|
||||
partner = rec.picking_id.partner_id if rec.picking_id else False
|
||||
if partner:
|
||||
rec.recipient_name = partner.name or ''
|
||||
parts = filter(None, [
|
||||
partner.street,
|
||||
partner.city,
|
||||
partner.state_id.name if partner.state_id else '',
|
||||
partner.zip,
|
||||
])
|
||||
rec.recipient_address = ', '.join(parts)
|
||||
else:
|
||||
rec.recipient_name = ''
|
||||
rec.recipient_address = ''
|
||||
|
||||
def action_open_sale_order(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Sale Order',
|
||||
'res_model': 'sale.order',
|
||||
'res_id': self.sale_order_id.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def action_open_picking(self):
|
||||
self.ensure_one()
|
||||
return {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Transfer',
|
||||
'res_model': 'stock.picking',
|
||||
'res_id': self.picking_id.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'current',
|
||||
}
|
||||
|
||||
def _action_open_attachment(self, attachment):
|
||||
"""Open an attachment PDF in the browser viewer (new tab)."""
|
||||
self.ensure_one()
|
||||
if not attachment:
|
||||
return False
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': '/web/content/%s?download=false' % attachment.id,
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
def action_view_label(self):
|
||||
return self._action_open_attachment(self.label_attachment_id)
|
||||
|
||||
def action_view_full_label(self):
|
||||
return self._action_open_attachment(self.full_label_attachment_id)
|
||||
|
||||
def action_view_receipt(self):
|
||||
return self._action_open_attachment(self.receipt_attachment_id)
|
||||
|
||||
def action_view_commercial_invoice(self):
|
||||
return self._action_open_attachment(self.commercial_invoice_attachment_id)
|
||||
|
||||
# ── Tracking ──────────────────────────────────────────────
|
||||
|
||||
def action_refresh_tracking(self):
|
||||
"""Fetch latest tracking events from Canada Post VIS API."""
|
||||
self.ensure_one()
|
||||
if not self.tracking_number:
|
||||
raise ValidationError(
|
||||
_("No tracking number available for this shipment."))
|
||||
carrier = self.carrier_id
|
||||
if not carrier:
|
||||
raise ValidationError(
|
||||
_("No carrier linked to this shipment."))
|
||||
|
||||
# VIS tracking uses /vis/ path, not /rs/
|
||||
if carrier.prod_environment:
|
||||
base = "https://soa-gw.canadapost.ca"
|
||||
else:
|
||||
base = "https://ct.soa-gw.canadapost.ca"
|
||||
|
||||
url = "%s/vis/track/pin/%s/detail" % (base, self.tracking_number)
|
||||
headers = {
|
||||
'Accept': 'application/vnd.cpc.track-v2+xml',
|
||||
'Accept-language': 'en-CA',
|
||||
}
|
||||
|
||||
try:
|
||||
resp = request(
|
||||
method='GET', url=url, headers=headers,
|
||||
auth=(carrier.username, carrier.password))
|
||||
_logger.info("Tracking API %s → %s", url, resp.status_code)
|
||||
|
||||
if resp.status_code == 404:
|
||||
# "No Pin History" — normal for new/sandbox shipments
|
||||
self.last_tracking_update = fields.Datetime.now()
|
||||
self.message_post(
|
||||
body=_("No tracking history available yet for %s.") %
|
||||
self.tracking_number)
|
||||
return
|
||||
|
||||
if resp.status_code != 200:
|
||||
raise ValidationError(
|
||||
_("Canada Post tracking error: %s %s\n%s") % (
|
||||
resp.status_code, resp.reason,
|
||||
resp.text[:500] if resp.text else ''))
|
||||
api_resp = Response(resp)
|
||||
result = api_resp.dict()
|
||||
except ValidationError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise ValidationError(
|
||||
_("Failed to fetch tracking: %s") % str(e))
|
||||
|
||||
self._process_tracking_events(result)
|
||||
|
||||
def _process_tracking_events(self, result):
|
||||
"""Parse CP tracking detail response and store events."""
|
||||
detail = result.get('tracking-detail', result)
|
||||
sig_events = detail.get('significant-events', {})
|
||||
occurrences = sig_events.get('occurrence', [])
|
||||
|
||||
# Single event returns dict, multiple returns list
|
||||
if isinstance(occurrences, dict):
|
||||
occurrences = [occurrences]
|
||||
|
||||
# Replace existing events
|
||||
self.tracking_event_ids.unlink()
|
||||
|
||||
vals_list = []
|
||||
for occ in occurrences:
|
||||
event_date_str = occ.get('event-date', '')
|
||||
event_time_str = occ.get('event-time', '')
|
||||
|
||||
# Build combined datetime for sorting
|
||||
event_datetime = False
|
||||
if event_date_str:
|
||||
try:
|
||||
if event_time_str:
|
||||
event_datetime = dt_mod.strptime(
|
||||
'%s %s' % (event_date_str, event_time_str),
|
||||
'%Y-%m-%d %H:%M:%S')
|
||||
else:
|
||||
event_datetime = dt_mod.strptime(
|
||||
event_date_str, '%Y-%m-%d')
|
||||
except (ValueError, TypeError):
|
||||
pass
|
||||
|
||||
vals_list.append({
|
||||
'shipment_id': self.id,
|
||||
'event_date': event_date_str or False,
|
||||
'event_time': event_time_str or '',
|
||||
'event_datetime': event_datetime,
|
||||
'event_description': occ.get('event-description', ''),
|
||||
'event_type': occ.get('event-type', ''),
|
||||
'event_site': occ.get('event-site', ''),
|
||||
'event_province': occ.get('event-province', ''),
|
||||
'signatory_name': occ.get('signatory-name', ''),
|
||||
})
|
||||
|
||||
if vals_list:
|
||||
self.env['fusion.tracking.event'].create(vals_list)
|
||||
|
||||
self.last_tracking_update = fields.Datetime.now()
|
||||
self._update_status_from_tracking(detail)
|
||||
self.message_post(
|
||||
body=_("Tracking refreshed: %d events loaded.") % len(vals_list))
|
||||
|
||||
def _update_status_from_tracking(self, detail):
|
||||
"""Auto-update shipment status based on tracking data."""
|
||||
if self.status == 'cancelled':
|
||||
return
|
||||
|
||||
delivered_date = detail.get('actual-delivery-date', '')
|
||||
if delivered_date:
|
||||
if self._has_return_events():
|
||||
self.status = 'returned'
|
||||
else:
|
||||
self.status = 'delivered'
|
||||
try:
|
||||
self.delivery_date = dt_mod.strptime(
|
||||
delivered_date, '%Y-%m-%d')
|
||||
except (ValueError, TypeError):
|
||||
self.delivery_date = fields.Datetime.now()
|
||||
elif self._has_return_events():
|
||||
self.status = 'returned'
|
||||
elif self.status == 'confirmed' and self.tracking_event_ids:
|
||||
self.status = 'shipped'
|
||||
|
||||
def _has_return_events(self):
|
||||
"""Check if any tracking events indicate a return/RTS."""
|
||||
RETURN_TYPES = {'RTS', 'RETURN', 'RTS_LABEL_PROC'}
|
||||
for event in self.tracking_event_ids:
|
||||
if event.event_type in RETURN_TYPES:
|
||||
return True
|
||||
desc = (event.event_description or '').lower()
|
||||
if 'return to sender' in desc or 'item returned' in desc:
|
||||
return True
|
||||
return False
|
||||
|
||||
# ── Void & Reissue ─────────────────────────────────────
|
||||
|
||||
def action_void_shipment(self):
|
||||
"""Void this shipment via Canada Post API (DELETE endpoint)."""
|
||||
self.ensure_one()
|
||||
if self.status == 'cancelled':
|
||||
raise ValidationError(
|
||||
_("This shipment is already cancelled."))
|
||||
if not self.shipment_id:
|
||||
raise ValidationError(
|
||||
_("No CP shipment ID — cannot void."))
|
||||
|
||||
carrier = self.carrier_id
|
||||
if not carrier:
|
||||
raise ValidationError(
|
||||
_("No carrier linked to this shipment."))
|
||||
|
||||
if carrier.prod_environment:
|
||||
base = "https://soa-gw.canadapost.ca"
|
||||
else:
|
||||
base = "https://ct.soa-gw.canadapost.ca"
|
||||
customer = carrier.customer_number
|
||||
|
||||
if carrier.fusion_cp_type == 'commercial':
|
||||
url = "%s/rs/%s/%s/shipment/%s" % (
|
||||
base, customer, customer, self.shipment_id)
|
||||
accept_header = 'application/vnd.cpc.shipment-v8+xml'
|
||||
else:
|
||||
url = "%s/rs/%s/ncshipment/%s" % (
|
||||
base, customer, self.shipment_id)
|
||||
accept_header = 'application/vnd.cpc.ncshipment-v4+xml'
|
||||
|
||||
try:
|
||||
resp = request(
|
||||
method='DELETE', url=url,
|
||||
headers={
|
||||
'Accept': accept_header,
|
||||
'Accept-language': 'en-CA',
|
||||
},
|
||||
auth=(carrier.username, carrier.password))
|
||||
_logger.info(
|
||||
"Void Shipment %s → %s", url, resp.status_code)
|
||||
|
||||
if resp.status_code == 204:
|
||||
self.status = 'cancelled'
|
||||
self.message_post(
|
||||
body=_("Shipment voided successfully via "
|
||||
"Canada Post API."))
|
||||
else:
|
||||
# Parse CP error XML for a clean message
|
||||
error_msg = self._parse_cp_error_response(resp)
|
||||
except ValidationError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise ValidationError(
|
||||
_("Failed to void shipment: %s") % str(e))
|
||||
|
||||
def _parse_cp_error_response(self, resp):
|
||||
"""Parse a Canada Post error XML response and raise a clean
|
||||
ValidationError with the human-readable description.
|
||||
|
||||
If the response cannot be parsed, falls back to the raw text.
|
||||
"""
|
||||
description = ''
|
||||
try:
|
||||
root = etree.fromstring(resp.content)
|
||||
# Strip namespace for easy tag matching
|
||||
ns = {'cp': root.nsmap.get(None, '')}
|
||||
if ns['cp']:
|
||||
msgs = root.findall('.//cp:message', ns)
|
||||
else:
|
||||
msgs = root.findall('.//message')
|
||||
parts = []
|
||||
for msg in msgs:
|
||||
desc_el = msg.find(
|
||||
'cp:description', ns) if ns['cp'] else msg.find(
|
||||
'description')
|
||||
if desc_el is not None and desc_el.text:
|
||||
parts.append(desc_el.text.strip())
|
||||
if parts:
|
||||
description = '\n'.join(parts)
|
||||
except Exception:
|
||||
description = ''
|
||||
|
||||
if not description:
|
||||
description = (resp.text[:500]
|
||||
if resp.text else 'Unknown error')
|
||||
|
||||
raise ValidationError(
|
||||
_("Canada Post: %s") % description)
|
||||
|
||||
def action_reissue_shipment(self):
|
||||
"""Void current shipment and create a new one."""
|
||||
self.ensure_one()
|
||||
if self.status != 'cancelled':
|
||||
self.action_void_shipment()
|
||||
if not self.picking_id:
|
||||
raise ValidationError(
|
||||
_("No transfer linked — cannot reissue."))
|
||||
picking = self.picking_id
|
||||
carrier = picking.carrier_id or self.carrier_id
|
||||
if not carrier:
|
||||
raise ValidationError(
|
||||
_("No carrier found for reissue."))
|
||||
result = carrier.send_shipping(picking)
|
||||
if result:
|
||||
picking.carrier_tracking_ref = result[0].get(
|
||||
'tracking_number', '')
|
||||
self.message_post(
|
||||
body=_("Shipment reissued. See new shipment record."))
|
||||
|
||||
def action_track_on_carrier(self):
|
||||
"""Open the carrier's tracking website in a new tab."""
|
||||
self.ensure_one()
|
||||
if not self.tracking_number:
|
||||
raise ValidationError(
|
||||
_("No tracking number available for this shipment."))
|
||||
# Default tracking URLs per carrier type
|
||||
DEFAULT_TRACKING = {
|
||||
'canada_post': 'https://www.canadapost.ca/trackweb/en#/resultList?searchFor=',
|
||||
'ups': 'https://www.ups.com/track?tracknum=',
|
||||
'ups_rest': 'https://www.ups.com/track?tracknum=',
|
||||
'fedex': 'https://www.fedex.com/wtrk/track/?trknbr=',
|
||||
'fedex_rest': 'https://www.fedex.com/wtrk/track/?trknbr=',
|
||||
'dhl': 'https://www.dhl.com/en/express/tracking.html?AWB=',
|
||||
'dhl_rest': 'https://www.dhl.com/en/express/tracking.html?AWB=',
|
||||
}
|
||||
base_link = ''
|
||||
if self.carrier_id and self.carrier_id.tracking_link:
|
||||
base_link = self.carrier_id.tracking_link
|
||||
elif self.carrier_type:
|
||||
base_link = DEFAULT_TRACKING.get(self.carrier_type, '')
|
||||
if not base_link:
|
||||
base_link = 'https://www.google.com/search?q='
|
||||
return {
|
||||
'type': 'ir.actions.act_url',
|
||||
'url': '%s%s' % (base_link, self.tracking_number),
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
# ── Cron ─────────────────────────────────────────────────
|
||||
|
||||
@api.model
|
||||
def _cron_refresh_tracking(self):
|
||||
"""Auto-refresh tracking for all active (non-terminal) shipments."""
|
||||
shipments = self.search([
|
||||
('status', 'in', ('confirmed', 'shipped')),
|
||||
('tracking_number', '!=', False),
|
||||
])
|
||||
_logger.info(
|
||||
"Cron: refreshing tracking for %d shipments", len(shipments))
|
||||
for shipment in shipments:
|
||||
try:
|
||||
shipment.action_refresh_tracking()
|
||||
self.env.cr.commit()
|
||||
except Exception as e:
|
||||
self.env.cr.rollback()
|
||||
_logger.warning(
|
||||
"Cron: tracking refresh failed for %s: %s",
|
||||
shipment.name, str(e))
|
||||
|
||||
# ── Return Labels ────────────────────────────────────────
|
||||
|
||||
def action_view_return_label(self):
|
||||
return self._action_open_attachment(self.return_label_attachment_id)
|
||||
|
||||
def action_create_return_label(self):
|
||||
"""Create a prepaid return label via Canada Post Authorized
|
||||
Returns API. Bill-on-scan: charged only when the customer
|
||||
uses the label at a post office.
|
||||
"""
|
||||
self.ensure_one()
|
||||
if self.return_tracking_number:
|
||||
raise ValidationError(
|
||||
_("A return label has already been created "
|
||||
"for this shipment."))
|
||||
if not self.carrier_id:
|
||||
raise ValidationError(
|
||||
_("No carrier linked to this shipment."))
|
||||
if not self.picking_id:
|
||||
raise ValidationError(
|
||||
_("No transfer linked to this shipment."))
|
||||
|
||||
carrier = self.carrier_id
|
||||
customer = carrier.customer_number
|
||||
|
||||
warehouse_partner = (
|
||||
self.picking_id.picking_type_id.warehouse_id.partner_id)
|
||||
if not warehouse_partner:
|
||||
raise ValidationError(
|
||||
_("No warehouse address found. Please configure "
|
||||
"a contact on the warehouse."))
|
||||
|
||||
if carrier.prod_environment:
|
||||
base = "https://soa-gw.canadapost.ca"
|
||||
else:
|
||||
base = "https://ct.soa-gw.canadapost.ca"
|
||||
|
||||
url = "%s/rs/%s/%s/authorizedreturn" % (base, customer, customer)
|
||||
|
||||
xml = self._build_return_label_xml(carrier, warehouse_partner)
|
||||
headers = {
|
||||
'Content-Type': 'application/vnd.cpc.authreturn-v2+xml',
|
||||
'Accept': 'application/vnd.cpc.authreturn-v2+xml',
|
||||
'Accept-language': 'en-CA',
|
||||
}
|
||||
|
||||
try:
|
||||
resp = request(
|
||||
method='POST', url=url, data=xml,
|
||||
headers=headers,
|
||||
auth=(carrier.username, carrier.password))
|
||||
_logger.info(
|
||||
"Return Label API %s → %s", url, resp.status_code)
|
||||
|
||||
if resp.status_code not in (200, 201):
|
||||
self._parse_cp_error_response(resp)
|
||||
|
||||
self._process_return_label_response(resp, carrier)
|
||||
|
||||
except ValidationError:
|
||||
raise
|
||||
except Exception as e:
|
||||
raise ValidationError(
|
||||
_("Failed to create return label: %s") % str(e))
|
||||
|
||||
def _build_return_label_xml(self, carrier, return_to_partner):
|
||||
"""Build Authorized Return XML.
|
||||
|
||||
return_to_partner = warehouse address (where the return goes).
|
||||
"""
|
||||
ns = "http://www.canadapost.ca/ws/authreturn-v2"
|
||||
root = etree.Element("authorized-return", xmlns=ns)
|
||||
|
||||
etree.SubElement(root, "service-code").text = "DOM.EP"
|
||||
|
||||
# Receiver — warehouse where the item is returned to
|
||||
receiver = etree.SubElement(root, "receiver")
|
||||
rec_name = etree.SubElement(receiver, "name")
|
||||
rec_name.text = (return_to_partner.name or '')[:44]
|
||||
rec_company = etree.SubElement(receiver, "company")
|
||||
rec_company.text = (
|
||||
return_to_partner.commercial_company_name
|
||||
or return_to_partner.name or '')[:44]
|
||||
rec_addr = etree.SubElement(receiver, "domestic-address")
|
||||
etree.SubElement(rec_addr, "address-line-1").text = (
|
||||
return_to_partner.street or '')[:44]
|
||||
if return_to_partner.street2:
|
||||
etree.SubElement(rec_addr, "address-line-2").text = (
|
||||
return_to_partner.street2)[:44]
|
||||
etree.SubElement(rec_addr, "city").text = (
|
||||
return_to_partner.city or '')[:40]
|
||||
etree.SubElement(rec_addr, "province").text = (
|
||||
return_to_partner.state_id.code or '')
|
||||
etree.SubElement(rec_addr, "postal-code").text = (
|
||||
(return_to_partner.zip or '').replace(' ', ''))
|
||||
|
||||
# Parcel characteristics
|
||||
parcel = etree.SubElement(root, "parcel-characteristics")
|
||||
etree.SubElement(parcel, "weight").text = str(
|
||||
max(self.weight or 0.5, 0.1))
|
||||
|
||||
# Print preferences
|
||||
prefs = etree.SubElement(root, "print-preferences")
|
||||
etree.SubElement(prefs, "output-format").text = (
|
||||
carrier.fusion_cp_output_format or '8.5x11')
|
||||
|
||||
return etree.tostring(
|
||||
root, xml_declaration=True, encoding='UTF-8')
|
||||
|
||||
def _process_return_label_response(self, resp, carrier):
|
||||
"""Parse return label response, download label PDF,
|
||||
store on shipment.
|
||||
"""
|
||||
api_resp = Response(resp)
|
||||
result = api_resp.dict()
|
||||
|
||||
auth_return = result.get('authorized-return', result)
|
||||
tracking_pin = auth_return.get('tracking-pin', '')
|
||||
self.return_tracking_number = tracking_pin
|
||||
|
||||
# Get label artifact URL from links
|
||||
links = auth_return.get('links', {})
|
||||
link_list = links.get('link', [])
|
||||
if isinstance(link_list, dict):
|
||||
link_list = [link_list]
|
||||
|
||||
label_url = ''
|
||||
for link in link_list:
|
||||
if link.get('@rel') == 'labelDetails':
|
||||
label_url = link.get('@href', '')
|
||||
break
|
||||
|
||||
if label_url:
|
||||
label_resp = request(
|
||||
method='GET', url=label_url,
|
||||
headers={
|
||||
'Accept': 'application/pdf',
|
||||
'Accept-language': 'en-CA',
|
||||
},
|
||||
auth=(carrier.username, carrier.password))
|
||||
if label_resp.status_code == 200:
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'name': 'Return-Label-%s.pdf' % tracking_pin,
|
||||
'type': 'binary',
|
||||
'datas': base64.b64encode(
|
||||
label_resp.content).decode(),
|
||||
'res_model': self._name,
|
||||
'res_id': self.id,
|
||||
'mimetype': 'application/pdf',
|
||||
})
|
||||
self.return_label_attachment_id = attachment
|
||||
|
||||
self.message_post(
|
||||
body=_("Return label created. Tracking: %s") % tracking_pin,
|
||||
attachment_ids=(
|
||||
self.return_label_attachment_id.ids
|
||||
if self.return_label_attachment_id else []))
|
||||
44
fusion_shipping/models/fusion_tracking_event.py
Normal file
@@ -0,0 +1,44 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class FusionTrackingEvent(models.Model):
|
||||
_name = 'fusion.tracking.event'
|
||||
_description = 'Shipping Tracking Event'
|
||||
_order = 'event_datetime desc, id desc'
|
||||
_rec_name = 'event_description'
|
||||
|
||||
shipment_id = fields.Many2one(
|
||||
'fusion.shipment',
|
||||
string='Shipment',
|
||||
required=True,
|
||||
ondelete='cascade',
|
||||
index=True,
|
||||
)
|
||||
event_date = fields.Date(
|
||||
string='Event Date',
|
||||
)
|
||||
event_time = fields.Char(
|
||||
string='Event Time',
|
||||
help='Time from Canada Post (HH:MM:SS)',
|
||||
)
|
||||
event_datetime = fields.Datetime(
|
||||
string='Date/Time',
|
||||
help='Combined date and time for sorting',
|
||||
)
|
||||
event_description = fields.Char(
|
||||
string='Description',
|
||||
)
|
||||
event_type = fields.Char(
|
||||
string='Event Type',
|
||||
help='Canada Post event type code',
|
||||
)
|
||||
event_site = fields.Char(
|
||||
string='Location',
|
||||
)
|
||||
event_province = fields.Char(
|
||||
string='Province',
|
||||
)
|
||||
signatory_name = fields.Char(
|
||||
string='Signatory',
|
||||
help='Name of person who signed for delivery',
|
||||
)
|
||||
39
fusion_shipping/models/payment_provider.py
Normal file
@@ -0,0 +1,39 @@
|
||||
from odoo import _, api, models
|
||||
|
||||
from odoo.addons.payment import utils as payment_utils
|
||||
|
||||
|
||||
class PaymentProvider(models.Model):
|
||||
_inherit = 'payment.provider'
|
||||
|
||||
@api.model
|
||||
def _get_compatible_providers(self, *args, sale_order_id=None, report=None, **kwargs):
|
||||
""" Override of payment to allow only COD providers if allow_cash_on_delivery is enabled for
|
||||
selected UPS delivery method.
|
||||
|
||||
:param int sale_order_id: The sales order to be paid, if any, as a `sale.order` id.
|
||||
:param dict report: The availability report.
|
||||
:return: The compatible providers.
|
||||
:rtype: payment.provider
|
||||
"""
|
||||
compatible_providers = super()._get_compatible_providers(
|
||||
*args, sale_order_id=sale_order_id, report=report, **kwargs
|
||||
)
|
||||
|
||||
sale_order = self.env['sale.order'].browse(sale_order_id).exists()
|
||||
if (
|
||||
sale_order.carrier_id.delivery_type in ('fusion_ups', 'fusion_ups_rest')
|
||||
and sale_order.carrier_id.allow_cash_on_delivery
|
||||
):
|
||||
unfiltered_providers = compatible_providers
|
||||
compatible_providers = compatible_providers.filtered(
|
||||
lambda p: p.custom_mode == 'cash_on_delivery'
|
||||
)
|
||||
payment_utils.add_to_report(
|
||||
report,
|
||||
unfiltered_providers - compatible_providers,
|
||||
available=False,
|
||||
reason=_("UPS provider is configured to use only Collect on Delivery."),
|
||||
)
|
||||
|
||||
return compatible_providers
|
||||
15
fusion_shipping/models/product_packaging.py
Normal file
@@ -0,0 +1,15 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class PackageType(models.Model):
|
||||
_inherit = "stock.package.type"
|
||||
|
||||
package_carrier_type = fields.Selection(selection_add=[
|
||||
('fusion_canada_post', 'Canada Post'),
|
||||
('fusion_ups', 'UPS'),
|
||||
('fusion_ups_rest', 'UPS (REST)'),
|
||||
('fusion_fedex', 'FedEx'),
|
||||
('fusion_fedex_rest', 'FedEx (REST)'),
|
||||
('fusion_dhl', 'DHL Express'),
|
||||
('fusion_dhl_rest', 'DHL Express (REST)'),
|
||||
])
|
||||
15
fusion_shipping/models/res_company.py
Normal file
@@ -0,0 +1,15 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields
|
||||
|
||||
class ResCompany(models.Model):
|
||||
_inherit = "res.company"
|
||||
|
||||
def _default_uom_setting(self):
|
||||
weight_uom_id = self.env.ref('uom.product_uom_kgm', raise_if_not_found=False)
|
||||
if not weight_uom_id:
|
||||
uom_categ_id = self.env.ref('uom.product_uom_categ_kgm').id
|
||||
weight_uom_id = self.env['uom.uom'].search([('category_id', '=', uom_categ_id), ('factor', '=', 1)], limit=1)
|
||||
return weight_uom_id
|
||||
|
||||
|
||||
weight_unit_of_measurement_id = fields.Many2one('uom.uom',string="Weight Unit Of Measurement",help="Unit of measure for item weight",default=_default_uom_setting)
|
||||
11
fusion_shipping/models/res_partner.py
Normal file
@@ -0,0 +1,11 @@
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class ResPartner(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
property_ups_carrier_account = fields.Char(
|
||||
string="UPS Account Number",
|
||||
company_dependent=True,
|
||||
help="UPS carrier account number for bill-my-account shipping.",
|
||||
)
|
||||
70
fusion_shipping/models/sale_order.py
Normal file
@@ -0,0 +1,70 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class SaleOrder(models.Model):
|
||||
_inherit = 'sale.order'
|
||||
|
||||
fusion_service_code = fields.Char(
|
||||
string='Service Code',
|
||||
copy=False,
|
||||
help='Carrier service code selected during shipping method selection',
|
||||
)
|
||||
# Per-package dimensions & service info (replaces single-dim fields).
|
||||
fusion_package_ids = fields.One2many(
|
||||
'fusion.order.package',
|
||||
'sale_order_id',
|
||||
string='Packages',
|
||||
copy=False,
|
||||
)
|
||||
|
||||
# Legacy single-package dimension fields (kept for backward
|
||||
# compatibility with existing orders -- new orders populate the
|
||||
# One2many above and fill these from the first package).
|
||||
fusion_package_length = fields.Float(
|
||||
string='Package Length', copy=False)
|
||||
fusion_package_width = fields.Float(
|
||||
string='Package Width', copy=False)
|
||||
fusion_package_height = fields.Float(
|
||||
string='Package Height', copy=False)
|
||||
|
||||
fusion_shipment_ids = fields.One2many(
|
||||
'fusion.shipment',
|
||||
'sale_order_id',
|
||||
string='Shipments',
|
||||
)
|
||||
fusion_shipment_count = fields.Integer(
|
||||
string='Shipments',
|
||||
compute='_compute_fusion_shipment_count',
|
||||
)
|
||||
|
||||
partner_ups_carrier_account = fields.Char(
|
||||
related='partner_id.property_ups_carrier_account',
|
||||
string="UPS Carrier Account",
|
||||
readonly=False,
|
||||
)
|
||||
ups_bill_my_account = fields.Boolean(
|
||||
related='carrier_id.ups_bill_my_account',
|
||||
string="UPS Bill My Account",
|
||||
)
|
||||
|
||||
def _compute_fusion_shipment_count(self):
|
||||
for order in self:
|
||||
order.fusion_shipment_count = len(
|
||||
order.fusion_shipment_ids)
|
||||
|
||||
def action_view_fusion_shipments(self):
|
||||
self.ensure_one()
|
||||
shipments = self.env['fusion.shipment'].search(
|
||||
[('sale_order_id', '=', self.id)]
|
||||
)
|
||||
action = {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Shipments',
|
||||
'res_model': 'fusion.shipment',
|
||||
'view_mode': 'list,form',
|
||||
'domain': [('sale_order_id', '=', self.id)],
|
||||
}
|
||||
if len(shipments) == 1:
|
||||
action['view_mode'] = 'form'
|
||||
action['res_id'] = shipments.id
|
||||
return action
|
||||
34
fusion_shipping/models/stock_picking.py
Normal file
@@ -0,0 +1,34 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class StockPicking(models.Model):
|
||||
_inherit = 'stock.picking'
|
||||
|
||||
fusion_shipment_count = fields.Integer(
|
||||
string='Shipments',
|
||||
compute='_compute_fusion_shipment_count',
|
||||
)
|
||||
|
||||
def _compute_fusion_shipment_count(self):
|
||||
Shipment = self.env['fusion.shipment']
|
||||
for picking in self:
|
||||
picking.fusion_shipment_count = Shipment.search_count(
|
||||
[('picking_id', '=', picking.id)]
|
||||
)
|
||||
|
||||
def action_view_fusion_shipments(self):
|
||||
self.ensure_one()
|
||||
shipments = self.env['fusion.shipment'].search(
|
||||
[('picking_id', '=', self.id)]
|
||||
)
|
||||
action = {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': 'Shipments',
|
||||
'res_model': 'fusion.shipment',
|
||||
'view_mode': 'list,form',
|
||||
'domain': [('picking_id', '=', self.id)],
|
||||
}
|
||||
if len(shipments) == 1:
|
||||
action['view_mode'] = 'form'
|
||||
action['res_id'] = shipments.id
|
||||
return action
|
||||
7
fusion_shipping/models/uom_uom.py
Normal file
@@ -0,0 +1,7 @@
|
||||
from odoo import models, fields
|
||||
|
||||
|
||||
class UoM(models.Model):
|
||||
_inherit = 'uom.uom'
|
||||
|
||||
fedex_code = fields.Char(string='Fedex Code', help="UoM Code sent to FedEx")
|
||||
3
fusion_shipping/pyproject.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[build-system]
|
||||
requires = ["whool"]
|
||||
build-backend = "whool.buildapi"
|
||||
12
fusion_shipping/security/ir.model.access.csv
Normal file
@@ -0,0 +1,12 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_fusion_shipment_user,fusion.shipment.user,model_fusion_shipment,base.group_user,1,0,0,0
|
||||
access_fusion_shipment_stock_user,fusion.shipment.stock.user,model_fusion_shipment,stock.group_stock_user,1,1,1,0
|
||||
access_fusion_shipment_manager,fusion.shipment.manager,model_fusion_shipment,stock.group_stock_manager,1,1,1,1
|
||||
access_fusion_tracking_event_user,fusion.tracking.event.user,model_fusion_tracking_event,base.group_user,1,0,0,0
|
||||
access_fusion_tracking_event_stock_user,fusion.tracking.event.stock.user,model_fusion_tracking_event,stock.group_stock_user,1,1,1,0
|
||||
access_fusion_tracking_event_manager,fusion.tracking.event.manager,model_fusion_tracking_event,stock.group_stock_manager,1,1,1,1
|
||||
access_choose_delivery_fusion_rate_user,choose.delivery.fusion.rate.user,model_choose_delivery_fusion_rate,base.group_user,1,1,1,1
|
||||
access_choose_delivery_fusion_package_user,choose.delivery.fusion.package.user,model_choose_delivery_fusion_package,base.group_user,1,1,1,1
|
||||
access_fusion_order_package_user,fusion.order.package.user,model_fusion_order_package,base.group_user,1,0,0,0
|
||||
access_fusion_order_package_stock_user,fusion.order.package.stock.user,model_fusion_order_package,stock.group_stock_user,1,1,1,0
|
||||
access_fusion_order_package_manager,fusion.order.package.manager,model_fusion_order_package,stock.group_stock_manager,1,1,1,1
|
||||
|
BIN
fusion_shipping/static/description/S1.png
Normal file
|
After Width: | Height: | Size: 113 KiB |
BIN
fusion_shipping/static/description/S2.png
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
fusion_shipping/static/description/S3.png
Normal file
|
After Width: | Height: | Size: 179 KiB |
BIN
fusion_shipping/static/description/canada_post_banner.gif
Normal file
|
After Width: | Height: | Size: 990 KiB |
95
fusion_shipping/static/description/custom.css
Normal file
@@ -0,0 +1,95 @@
|
||||
html {
|
||||
padding: 50px;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
html h1 {
|
||||
text-align: center;
|
||||
}
|
||||
html h2 {
|
||||
text-align: center;
|
||||
color: grey;
|
||||
}
|
||||
#exampleSlider {
|
||||
position: relative;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
#exampleSlider {
|
||||
border-color: transparent;
|
||||
}
|
||||
}
|
||||
#exampleSlider .MS-content {
|
||||
margin: 15px 5%;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
border: 1px solid red;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
#exampleSlider .MS-content {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
#exampleSlider .MS-content .item {
|
||||
display: inline-block;
|
||||
height: 30%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
vertical-align: top;
|
||||
border: 1px solid green;
|
||||
border-right: none;
|
||||
width: 33.33%;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
#exampleSlider .MS-content .item {
|
||||
width: 25%;
|
||||
}
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
#exampleSlider .MS-content .item {
|
||||
width: 33.3333%;
|
||||
}
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
#exampleSlider .MS-content .item {
|
||||
width: 50%;
|
||||
}
|
||||
}
|
||||
#exampleSlider .MS-content .item p {
|
||||
font-size: 30px;
|
||||
text-align: center;
|
||||
line-height: 1;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 10px 0;
|
||||
}
|
||||
#exampleSlider .MS-controls button {
|
||||
position: absolute;
|
||||
border: none;
|
||||
background: transparent;
|
||||
font-size: 30px;
|
||||
outline: 0;
|
||||
top: 35px;
|
||||
}
|
||||
@media (max-width: 767px) {
|
||||
#exampleSlider .MS-controls button {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
#exampleSlider .MS-controls button:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
#exampleSlider .MS-controls .MS-left {
|
||||
left: 10px;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
#exampleSlider .MS-controls .MS-left {
|
||||
left: -2px;
|
||||
}
|
||||
}
|
||||
#exampleSlider .MS-controls .MS-right {
|
||||
right: 10px;
|
||||
}
|
||||
@media (max-width: 992px) {
|
||||
#exampleSlider .MS-controls .MS-right {
|
||||
right: -2px;
|
||||
}
|
||||
}
|
||||
BIN
fusion_shipping/static/description/dash.png
Normal file
|
After Width: | Height: | Size: 374 KiB |
BIN
fusion_shipping/static/description/icon.png
Normal file
|
After Width: | Height: | Size: 64 KiB |
BIN
fusion_shipping/static/description/images/icons_live_price.png
Normal file
|
After Width: | Height: | Size: 9.2 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 6.3 KiB |
173
fusion_shipping/static/description/index.html
Normal file
@@ -0,0 +1,173 @@
|
||||
<html>
|
||||
<head>
|
||||
<link href="custom.css" rel="stylesheet"/>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta charset="utf-8"/>
|
||||
<title>Canada Post Shipping Integration with Odoo</title>
|
||||
<meta name="description" content="Odoo Canada Post Shipping Integration. Canada Post Shipping connector for Odoo"/>
|
||||
<meta name="keywords" content="shipping connector, Odoo Canada Post, Delivery Canada Post, Odoo Canada Post shipping, Canada Post Shipping,
|
||||
integrate Canada Post, Canada Post odoo, shipping solution, accept shipment odoo, sync shipment odoo, Canada Post gateway integration"/>
|
||||
<meta name="robots" content="index, follow"/>
|
||||
<link type="text/css" rel="stylesheet" href="/assets/assets.css"/>
|
||||
<link type="text/css" rel="stylesheet"
|
||||
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css"/>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
|
||||
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
|
||||
<link href="https://fonts.googleapis.com/css2?family=Laila:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
|
||||
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
|
||||
crossorigin="anonymous"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="top"></div>
|
||||
<section class="oe_container bg-transparent fixed-top position-relative">
|
||||
<div class="o_equal_col_sm">
|
||||
<div class="shadow bg-white pb32 pt32 px-2"
|
||||
style="border-radius: 15px">
|
||||
|
||||
<h3 class="oe_slogan"
|
||||
style="color: #051f5a; font-family: Raleway; font-weight: 700; text-align: center; opacity: 1; font-size: 35px; margin-bottom: 25px; margin-top: 45px;">
|
||||
Odoo Canada Post Shipping Integration</h3>
|
||||
<img src="dash.png" style="width: 100%;">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container overflow-hidden"
|
||||
style="position-relative">
|
||||
<div class="o_equal_col_sm">
|
||||
<div class="px-2" style="border-radius:15px">
|
||||
<h3 class="oe_slogan"
|
||||
style="color:#0f1e40; font-family:Montserrat; font-weight:700; text-align:center; text-transform:uppercase; opacity:1; font-size:28px; margin-bottom:20px; margin-top:20px">
|
||||
<span style="color:#2971FD">Why</span> Canada Post Odoo Shipping Integration?
|
||||
</h3>
|
||||
<p class="mb16 text-center text-black-dark px-3"
|
||||
style="font-family:; font-weight:normal; color:#11335b; font-size:18px">
|
||||
Integrate Canada Post to streamline shipping processes by obtaining <b>real-time courier quotes for
|
||||
various services, generating shipping labels based on order details</b>, and providing <b>tracking
|
||||
numbers with
|
||||
links for shipment updates</b>
|
||||
ensuring a seamless and efficient logistics workflow
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="oe_container pb-5">
|
||||
<div class="mt64 mb64">
|
||||
<h2 style="color:#091E42; font-family:'Raleway'; text-align:center; margin:25px auto; text-transform:uppercase"
|
||||
class="oe_slogan">
|
||||
<b>Features</b>
|
||||
</h2>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12 mt32">
|
||||
<div class="container shadow" style="border-radius:10px; padding:10px 0px">
|
||||
<div class="col-md-3 shadow" style="float:left; margin: -10px 0px;">
|
||||
<img class="img img-responsive"
|
||||
src="images/icons_live_price.png"
|
||||
style="width: 100%;height: auto;"></div>
|
||||
<div class="col-md-9" style="padding-left:0; float:left; width:70%;margin-left: 20px;">
|
||||
<h3 class="mt16 mb0" style="font-family:Roboto; font-weight:500; font-size:22px">Live Shipping
|
||||
Price</h3>
|
||||
<p class=" mt8" style="font-family:Roboto;">Get live price to ensure the best price for
|
||||
your shipment</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6 col-sm-12 mt32">
|
||||
<div class="container shadow" style="border-radius:10px; padding:10px 0px">
|
||||
<div class="col-md-3 shadow" style="float:left; margin: -10px 0px;">
|
||||
<img class="img img-responsive"
|
||||
src="images/icons_shipping_label.png"
|
||||
style="width: 100%;height: auto;"></div>
|
||||
<div class="col-md-9" style="padding-left:0; float:left; width:70%;margin-left: 20px;">
|
||||
<h3 class="mt16 mb0" style="font-family:Roboto; font-weight:500; font-size:22px">Shipping
|
||||
Label</h3>
|
||||
<p class="mt8" style="font-family:Roboto;">Generate shipping label using order information</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-6 col-sm-12 mt32" style="margin: 0px auto;padding-top: 22px;">
|
||||
<div class="container shadow" style="border-radius:10px; padding:10px 0px">
|
||||
<div class="col-md-3 shadow" style="float:left; margin: -10px 0px;"><img class="img img-responsive"
|
||||
src="images/icons_track_and_trace.png"
|
||||
style="width: 100%;height: auto;">
|
||||
</div>
|
||||
<div class="col-md-9" style="padding-left:0; float:left; width:70%;margin-left: 20px;">
|
||||
<h3 class="mt16 mb0" style="font-family:Roboto; font-weight:500; font-size:22px">Track &
|
||||
Trace</h3>
|
||||
<p class="mt8 mid_p_1200" style="font-family:Roboto;">Live track your shipment using the Canada
|
||||
Post tracking number</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<section class="container">
|
||||
<div class="oe_row oe_spaced mt8 mb8" style="width: auto;">
|
||||
<h3 class="oe_slogan">Canada Post Shipping Configuration</h3>
|
||||
<div class="mt16 mb16" style="margin-left: 10px">
|
||||
<img src="S1.png"
|
||||
style="width: 100%; margin-top: 10px; border-radius: 5px; border: solid #E3E4E4; border-radius: 10px; border-width: 30px 7px 7px 7px;">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="oe_row oe_spaced mt8 mb8" style="width: auto;">
|
||||
<h3 class="oe_slogan">Create Sale Order With Canada Post Delivery Method</h3>
|
||||
<div class="mt16 mb16" style="margin-left: 10px">
|
||||
<img src="S2.png"
|
||||
style="width: 100%; margin-top: 10px; border-radius: 5px; border: solid #E3E4E4; border-radius: 10px; border-width: 30px 7px 7px 7px;">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="oe_row oe_spaced mt8 mb8" style="width: auto;">
|
||||
<h3 class="oe_slogan">Generate Shipment With Tracking Number And Shipping Label</h3>
|
||||
<div class="mt16 mb16" style="margin-left: 10px">
|
||||
<img src="S3.png"
|
||||
style="width: 100%; margin-top: 10px; border-radius: 5px; border: solid #E3E4E4; border-radius: 10px; border-width: 30px 7px 7px 7px;">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="container">
|
||||
<div class="oe_row oe_spaced mt8 mb8" style="width: auto;">
|
||||
<h3 class="oe_slogan">Generated Shipment Label</h3>
|
||||
<div class="mt16 mb16" style="margin: 0px auto;text-align: center;">
|
||||
<img src="label.png"
|
||||
style="margin-top: 10px; border-radius: 5px; border: solid #E3E4E4; border-radius: 10px; border-width: 7px 7px 7px 7px;">
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
||||
<div class="container">
|
||||
<section class="container">
|
||||
<h4 style="color:#00008b; text-align:center; margin:25px auto; text-transform:uppercase;font-weight: 600;"
|
||||
class="oe_slogan">
|
||||
Contact Us
|
||||
</h4>
|
||||
<div style="text-align:center">
|
||||
<span>Suggestions & Feedback to:</span> <a href="mailto:support@nexasystems.ca">support@nexasystems.ca</a>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<div class="container" align="center">
|
||||
<section class="container">
|
||||
<a href="#top">
|
||||
<img src="up_arrow.png" alt="up-arrow" style="height: 125px;">
|
||||
</a>
|
||||
</section>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
BIN
fusion_shipping/static/description/label.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
fusion_shipping/static/description/up_arrow.png
Normal file
|
After Width: | Height: | Size: 7.7 KiB |
89
fusion_shipping/views/choose_delivery_carrier_views.xml
Normal file
@@ -0,0 +1,89 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<record id="choose_delivery_carrier_view_form_fusion" model="ir.ui.view">
|
||||
<field name="name">choose.delivery.carrier.form.fusion</field>
|
||||
<field name="model">choose.delivery.carrier</field>
|
||||
<field name="inherit_id" ref="delivery.choose_delivery_carrier_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<!-- Hidden state fields -->
|
||||
<xpath expr="//field[@name='delivery_price']" position="after">
|
||||
<field name="fusion_selected_service" invisible="1"/>
|
||||
<field name="fusion_dimension_unit_label" invisible="1"/>
|
||||
<field name="fusion_weight_unit_label" invisible="1"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Hide base "Get rate" button for Fusion shipping carriers -->
|
||||
<xpath expr="//button[@name='update_price']" position="attributes">
|
||||
<attribute name="invisible">delivery_type in ('fixed', 'base_on_rule', 'fusion_canada_post')</attribute>
|
||||
</xpath>
|
||||
|
||||
<!-- "Get Prices" button (inside the Cost / Get-rate row) -->
|
||||
<xpath expr="//button[@name='update_price']" position="after">
|
||||
<button name="update_price" type="object"
|
||||
invisible="delivery_type != 'fusion_canada_post'">
|
||||
<i class="oi oi-arrow-right me-1"/>Get Prices
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<!--
|
||||
Full-width sections AFTER the outer <group>.
|
||||
This avoids them being crammed into the group's
|
||||
label-field grid and gives them the full dialog width.
|
||||
-->
|
||||
<xpath expr="//form/group" position="after">
|
||||
<!-- Package list -->
|
||||
<div invisible="delivery_type != 'fusion_canada_post'"
|
||||
class="px-3 mt-2">
|
||||
<span class="o_form_label fw-bold mb-1">Packages</span>
|
||||
<field name="fusion_package_ids" nolabel="1">
|
||||
<list editable="bottom">
|
||||
<field name="sequence" widget="handle"/>
|
||||
<field name="package_type_id" string="Box Type"/>
|
||||
<field name="package_length" string="L"/>
|
||||
<field name="package_width" string="W"/>
|
||||
<field name="package_height" string="H"/>
|
||||
<field name="weight" string="Weight"/>
|
||||
<field name="selected_price" string="Cost"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"
|
||||
optional="hide"/>
|
||||
<field name="currency_id" column_invisible="1"/>
|
||||
</list>
|
||||
</field>
|
||||
</div>
|
||||
|
||||
<!-- Service selection -->
|
||||
<div invisible="delivery_type != 'fusion_canada_post' or not fusion_rate_ids"
|
||||
class="px-3 mt-3">
|
||||
<span class="o_form_label fw-bold mb-1">Select a Service</span>
|
||||
<field name="fusion_rate_ids" nolabel="1">
|
||||
<list create="0" delete="0" no_open="1"
|
||||
decoration-bf="is_selected"
|
||||
decoration-success="is_selected">
|
||||
<field name="is_selected" column_invisible="1"/>
|
||||
<field name="service_name" string="Service"/>
|
||||
<field name="price" string="Shipping Cost"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"/>
|
||||
<field name="currency_id" column_invisible="1"/>
|
||||
<field name="expected_delivery"
|
||||
string="Expected Delivery"/>
|
||||
<button name="action_select" type="object"
|
||||
string="Select"
|
||||
class="btn-sm btn-link"
|
||||
icon="fa-circle-o"
|
||||
invisible="is_selected"/>
|
||||
<button name="action_select" type="object"
|
||||
string="Selected"
|
||||
class="btn-sm btn-primary"
|
||||
icon="fa-check-circle"
|
||||
invisible="not is_selected"/>
|
||||
</list>
|
||||
</field>
|
||||
</div>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
351
fusion_shipping/views/delivery_carrier_view.xml
Normal file
@@ -0,0 +1,351 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="delivery_carrier_form_view_fusion_shipping" model="ir.ui.view">
|
||||
<field name="name">delivery.carrier.form.view.fusion.shipping</field>
|
||||
<field name="model">delivery.carrier</field>
|
||||
<field name="inherit_id" ref="delivery.view_delivery_carrier_form"/>
|
||||
<field name="arch" type="xml">
|
||||
|
||||
<!-- ================================================================
|
||||
Integration Level: custom label for Fusion carriers
|
||||
================================================================ -->
|
||||
<xpath expr="//field[@name='integration_level']" position="attributes">
|
||||
<attribute name="invisible">delivery_type in ('fusion_canada_post', 'fusion_ups', 'fusion_ups_rest', 'fusion_fedex', 'fusion_fedex_rest', 'fusion_dhl', 'fusion_dhl_rest')</attribute>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='integration_level']" position="after">
|
||||
<field name="integration_level"
|
||||
invisible="delivery_type not in ('fusion_canada_post', 'fusion_ups', 'fusion_ups_rest', 'fusion_fedex', 'fusion_fedex_rest', 'fusion_dhl', 'fusion_dhl_rest')"
|
||||
widget="radio"
|
||||
options="{'horizontal': true}"
|
||||
help="Get Prices: only fetch shipping prices on sale orders. Get Prices and Create Shipment: also generate labels and tracking when the delivery order is validated."/>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//page[@name='destination']" position="before">
|
||||
|
||||
<!-- ════════════════════════════════════════════════════
|
||||
CANADA POST Configuration
|
||||
════════════════════════════════════════════════════ -->
|
||||
<page string="Canada Post Configuration" name="fusion_cp_configuration"
|
||||
invisible="delivery_type != 'fusion_canada_post'">
|
||||
<group string="API Credentials"
|
||||
invisible="delivery_type != 'fusion_canada_post'">
|
||||
<group>
|
||||
<field name="username" string="API Key"
|
||||
required="delivery_type == 'fusion_canada_post'"
|
||||
help="API key from the Canada Post Developer Program."/>
|
||||
<field name="password" string="API Password" password="True"
|
||||
required="delivery_type == 'fusion_canada_post'"
|
||||
help="API password from the Canada Post Developer Program."/>
|
||||
<field name="customer_number" required="delivery_type == 'fusion_canada_post'"
|
||||
help="Your Canada Post customer number (mailed-by number)."/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="fusion_cp_type" string="Account Type"
|
||||
required="delivery_type == 'fusion_canada_post'"/>
|
||||
<field name="fusion_cp_contract_id" required="fusion_cp_type == 'commercial'"
|
||||
invisible="fusion_cp_type == 'counter'"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Shipping Options">
|
||||
<field name="service_type" string="Default Service"
|
||||
required="delivery_type == 'fusion_canada_post'"
|
||||
help="Default shipping service. Users can choose a different service when adding shipping to a sale order."/>
|
||||
<field name="option_code" string="Shipping Option"/>
|
||||
<field name="reason_for_export"/>
|
||||
<field name="product_packaging_id"
|
||||
help="Optional default package type. Dimensions will pre-fill in the shipping wizard but can be overridden per shipment."/>
|
||||
<field name="fusion_cp_dimension_unit"
|
||||
required="delivery_type == 'fusion_canada_post'"
|
||||
help="Unit for package dimensions. Values are automatically converted to centimetres for the Canada Post API."/>
|
||||
</group>
|
||||
<group string="Payment & Tracking">
|
||||
<field name="fusion_cp_payment_method"
|
||||
string="Payment Method"
|
||||
required="delivery_type == 'fusion_canada_post'"/>
|
||||
<field name="tracking_link"
|
||||
help="Custom tracking URL. Leave blank to use the default Canada Post tracking page."/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Label Settings"
|
||||
invisible="delivery_type != 'fusion_canada_post'">
|
||||
<group>
|
||||
<field name="fusion_cp_output_format"
|
||||
required="delivery_type == 'fusion_canada_post'"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════
|
||||
UPS REST Configuration
|
||||
════════════════════════════════════════════════════ -->
|
||||
<page string="UPS REST Configuration" name="fusion_ups_rest_configuration"
|
||||
invisible="delivery_type != 'fusion_ups_rest'">
|
||||
<group>
|
||||
<group>
|
||||
<field name="ups_shipper_number" required="delivery_type == 'fusion_ups_rest'"/>
|
||||
<field name="ups_client_id" required="delivery_type == 'fusion_ups_rest'"/>
|
||||
<field name="ups_client_secret" required="delivery_type == 'fusion_ups_rest'"/>
|
||||
<field name="ups_default_service_type" required="delivery_type == 'fusion_ups_rest'"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="ups_default_packaging_id" required="delivery_type == 'fusion_ups_rest'"
|
||||
domain="[('package_carrier_type', '=', 'fusion_ups_rest')]"/>
|
||||
<field name="ups_package_weight_unit" string="Package Weight Unit"
|
||||
required="delivery_type == 'fusion_ups_rest'"/>
|
||||
<field name="ups_package_dimension_unit"
|
||||
required="delivery_type == 'fusion_ups_rest'"/>
|
||||
<field name="ups_label_file_type" string="Label Format"
|
||||
required="delivery_type == 'fusion_ups_rest'"/>
|
||||
</group>
|
||||
<group string="Options" name="ups_rest_vas" colspan="2">
|
||||
<group>
|
||||
<field name="ups_bill_my_account"
|
||||
invisible="delivery_type != 'fusion_ups_rest'"/>
|
||||
<field name="ups_saturday_delivery" string="Saturday Delivery"
|
||||
required="delivery_type == 'fusion_ups_rest'"
|
||||
invisible="ups_default_service_type in ['03','11','13','59','12','65','08']"/>
|
||||
<field name="allow_cash_on_delivery"
|
||||
required="delivery_type == 'fusion_ups_rest'"
|
||||
invisible="ups_default_service_type == '96'"
|
||||
help="This value added service enables UPS to collect the payment of the shipment from your customer."/>
|
||||
<field name="ups_cod_funds_code"
|
||||
required="delivery_type == 'fusion_ups_rest'"
|
||||
invisible="not allow_cash_on_delivery" widget="radio"/>
|
||||
<field name="can_generate_return" invisible="1"/>
|
||||
<field name="return_label_on_delivery" invisible="not can_generate_return"/>
|
||||
<field name="get_return_label_from_portal" invisible="not return_label_on_delivery"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="ups_require_signature"/>
|
||||
<field name="ups_duty_payment" string="Duties paid by"
|
||||
required="delivery_type == 'fusion_ups_rest'"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════
|
||||
UPS Legacy Configuration
|
||||
════════════════════════════════════════════════════ -->
|
||||
<page string="UPS Configuration" name="fusion_ups_configuration"
|
||||
invisible="delivery_type != 'fusion_ups'">
|
||||
<group>
|
||||
<group>
|
||||
<field name="ups_username" required="delivery_type == 'fusion_ups'"/>
|
||||
<field name="ups_passwd" required="delivery_type == 'fusion_ups'"/>
|
||||
<field name="ups_shipper_number" required="delivery_type == 'fusion_ups'"/>
|
||||
<field name="ups_access_number" required="delivery_type == 'fusion_ups'"/>
|
||||
<field name="ups_default_service_type" required="delivery_type == 'fusion_ups'"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="ups_default_package_type_id" required="delivery_type == 'fusion_ups'"
|
||||
domain="[('package_carrier_type', '=', 'fusion_ups')]"/>
|
||||
<field name="ups_package_weight_unit" string="Package Weight Unit"
|
||||
required="delivery_type == 'fusion_ups'"/>
|
||||
<field name="ups_package_dimension_unit"
|
||||
required="delivery_type == 'fusion_ups'"/>
|
||||
<field name="ups_label_file_type" string="Label Format"
|
||||
required="delivery_type == 'fusion_ups'"/>
|
||||
</group>
|
||||
<group string="Options" name="ups_legacy_vas">
|
||||
<field name="ups_bill_my_account" invisible="delivery_type != 'fusion_ups'"/>
|
||||
<field name="ups_saturday_delivery" string="Saturday Delivery"
|
||||
invisible="ups_default_service_type in ['03', '11', '13', '59', '12', '65', '08']"
|
||||
required="delivery_type == 'fusion_ups'"/>
|
||||
<field name="allow_cash_on_delivery"
|
||||
required="delivery_type == 'fusion_ups'"
|
||||
invisible="ups_default_service_type == '96'"
|
||||
help="This value added service enables UPS to collect the payment of the shipment from your customer."/>
|
||||
<field name="ups_cod_funds_code" invisible="not allow_cash_on_delivery"
|
||||
required="delivery_type == 'fusion_ups'" widget="radio"/>
|
||||
<field name="can_generate_return" invisible="1"/>
|
||||
<field name="return_label_on_delivery" invisible="not can_generate_return"/>
|
||||
<field name="get_return_label_from_portal" invisible="not return_label_on_delivery"/>
|
||||
<field name="ups_duty_payment" string="Duties paid by"
|
||||
required="delivery_type == 'fusion_ups'"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════
|
||||
FedEx REST Configuration
|
||||
════════════════════════════════════════════════════ -->
|
||||
<page string="FedEx REST Configuration" name="fusion_fedex_rest_configuration"
|
||||
invisible="delivery_type != 'fusion_fedex_rest'">
|
||||
<group>
|
||||
<group>
|
||||
<field name="fedex_rest_developer_key" required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
<field name="fedex_rest_developer_password" required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
<field name="fedex_rest_account_number" string="Account Number"
|
||||
required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
<field name="fedex_rest_service_type" required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
<field name="fedex_rest_droppoff_type" required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="fedex_rest_default_package_type_id"
|
||||
required="delivery_type == 'fusion_fedex_rest'"
|
||||
domain="[('package_carrier_type', '=', 'fusion_fedex_rest')]"/>
|
||||
<field name="fedex_rest_weight_unit" string="Package Weight Unit"
|
||||
required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
<div class="o_td_label">
|
||||
<span class="o_form_label">Package Length Unit</span>
|
||||
</div>
|
||||
<div class="o_field_widget">
|
||||
<span invisible="fedex_rest_weight_unit != 'KG'">Centimeters</span>
|
||||
<span invisible="fedex_rest_weight_unit != 'LB'">Inches</span>
|
||||
</div>
|
||||
<field name="fedex_rest_label_stock_type" required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
<field name="fedex_rest_label_file_type" string="Label Format"
|
||||
required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
</group>
|
||||
<group string="Options">
|
||||
<field name="return_label_on_delivery" invisible="not can_generate_return"/>
|
||||
<field name="get_return_label_from_portal" invisible="not return_label_on_delivery"/>
|
||||
<field name="fedex_rest_email_notifications"/>
|
||||
<field name="fedex_rest_duty_payment" string="Duties paid by"
|
||||
required="delivery_type == 'fusion_fedex_rest'"/>
|
||||
<field name="fedex_rest_residential_address"/>
|
||||
<field name="fedex_rest_documentation_type"/>
|
||||
<field name="fedex_rest_override_shipper_vat"/>
|
||||
</group>
|
||||
<group string="Extra Data" name="fedex_rest_extra_data" groups="base.group_no_one">
|
||||
<field name="fedex_rest_extra_data_rate_request"/>
|
||||
<field name="fedex_rest_extra_data_ship_request"/>
|
||||
<field name="fedex_rest_extra_data_return_request"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════
|
||||
FedEx Legacy Configuration
|
||||
════════════════════════════════════════════════════ -->
|
||||
<page string="FedEx Configuration" name="fusion_fedex_configuration"
|
||||
invisible="delivery_type != 'fusion_fedex'">
|
||||
<group>
|
||||
<group>
|
||||
<field name="fedex_developer_key" required="delivery_type == 'fusion_fedex'"/>
|
||||
<field name="fedex_developer_password" required="delivery_type == 'fusion_fedex'"/>
|
||||
<field name="fedex_account_number" string="Account Number"
|
||||
required="delivery_type == 'fusion_fedex'"/>
|
||||
<field name="fedex_meter_number" required="delivery_type == 'fusion_fedex'"/>
|
||||
<field name="fedex_service_type" required="delivery_type == 'fusion_fedex'"/>
|
||||
<field name="fedex_droppoff_type" required="delivery_type == 'fusion_fedex'"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="fedex_default_package_type_id"
|
||||
required="delivery_type == 'fusion_fedex'"
|
||||
domain="[('package_carrier_type', '=', 'fusion_fedex')]"/>
|
||||
<field name="fedex_weight_unit" string="Package Weight Unit"
|
||||
required="delivery_type == 'fusion_fedex'"/>
|
||||
<div class="o_td_label">
|
||||
<span class="o_form_label">Package Length Unit</span>
|
||||
</div>
|
||||
<div class="o_field_widget">
|
||||
<span invisible="fedex_weight_unit != 'KG'">CM</span>
|
||||
<span invisible="fedex_weight_unit != 'LB'">IN</span>
|
||||
</div>
|
||||
<field name="fedex_label_stock_type" required="delivery_type == 'fusion_fedex'"/>
|
||||
<field name="fedex_label_file_type" string="Label Format"
|
||||
required="delivery_type == 'fusion_fedex'"/>
|
||||
<field name="fedex_document_stock_type" required="delivery_type == 'fusion_fedex'"/>
|
||||
</group>
|
||||
<group string="Options">
|
||||
<field name="fedex_saturday_delivery" string="Saturday Delivery"
|
||||
invisible="fedex_service_type not in ['INTERNATIONAL_PRIORITY', 'FEDEX_2_DAY', 'FIRST_OVERNIGHT', 'PRIORITY_OVERNIGHT']"
|
||||
required="delivery_type == 'fusion_fedex'"/>
|
||||
<field name="can_generate_return" invisible="1"/>
|
||||
<field name="return_label_on_delivery" invisible="not can_generate_return"/>
|
||||
<field name="get_return_label_from_portal" invisible="not return_label_on_delivery"/>
|
||||
<field name="fedex_duty_payment" string="Duties paid by"
|
||||
required="delivery_type == 'fusion_fedex'"/>
|
||||
</group>
|
||||
<group string="Extra Data" name="fedex_legacy_extra_data" groups="base.group_no_one">
|
||||
<field name="fedex_extra_data_rate_request"/>
|
||||
<field name="fedex_extra_data_ship_request"/>
|
||||
<field name="fedex_extra_data_return_request"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════
|
||||
DHL REST Configuration
|
||||
════════════════════════════════════════════════════ -->
|
||||
<page string="DHL REST Configuration" name="fusion_dhl_rest_configuration"
|
||||
invisible="delivery_type != 'fusion_dhl_rest'">
|
||||
<group>
|
||||
<group>
|
||||
<field name="dhl_api_key" required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
<field name="dhl_api_secret" required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
<field name="dhl_account_number" required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
<field name="dhl_region_code" required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
<field name="dhl_product_code" required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="dhl_default_package_type_id"
|
||||
required="delivery_type == 'fusion_dhl_rest'"
|
||||
domain="[('package_carrier_type', '=', 'fusion_dhl_rest')]"/>
|
||||
<field name="dhl_unit_system" required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
<field name="dhl_label_image_format" string="Label Format"
|
||||
required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
<field name="dhl_label_template" required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
</group>
|
||||
<group string="Options">
|
||||
<field name="return_label_on_delivery" invisible="can_generate_return == False"/>
|
||||
<field name="get_return_label_from_portal" invisible="return_label_on_delivery == False"/>
|
||||
<field name="dhl_dutiable"/>
|
||||
<field name="dhl_duty_payment" string="Duties paid by"
|
||||
invisible="dhl_dutiable == False"
|
||||
required="delivery_type == 'fusion_dhl_rest'"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="Custom Data" name="dhl_rest_customs" groups="base.group_no_one">
|
||||
<field name="dhl_extra_data_rate_request" colspan="2"/>
|
||||
<field name="dhl_extra_data_ship_request" colspan="2"/>
|
||||
<field name="dhl_extra_data_return_request" colspan="2"/>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
<!-- ════════════════════════════════════════════════════
|
||||
DHL Legacy Configuration
|
||||
════════════════════════════════════════════════════ -->
|
||||
<page string="DHL Configuration" name="fusion_dhl_configuration"
|
||||
invisible="delivery_type != 'fusion_dhl'">
|
||||
<group>
|
||||
<group>
|
||||
<field name="dhl_SiteID" required="delivery_type == 'fusion_dhl'"/>
|
||||
<field name="dhl_password" required="delivery_type == 'fusion_dhl'"/>
|
||||
<field name="dhl_account_number" required="delivery_type == 'fusion_dhl'"/>
|
||||
<field name="dhl_region_code" required="delivery_type == 'fusion_dhl'"/>
|
||||
<field name="dhl_product_code" required="delivery_type == 'fusion_dhl'"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="dhl_default_package_type_id"
|
||||
required="delivery_type == 'fusion_dhl'"
|
||||
domain="[('package_carrier_type', '=', 'fusion_dhl')]"/>
|
||||
<field name="dhl_package_weight_unit" required="delivery_type == 'fusion_dhl'"/>
|
||||
<field name="dhl_package_dimension_unit" required="delivery_type == 'fusion_dhl'"/>
|
||||
<field name="dhl_label_image_format" string="Label Format"
|
||||
required="delivery_type == 'fusion_dhl'"/>
|
||||
<field name="dhl_label_template" required="delivery_type == 'fusion_dhl'"/>
|
||||
</group>
|
||||
<group string="Options">
|
||||
<field name="can_generate_return" invisible="1"/>
|
||||
<field name="return_label_on_delivery" invisible="not can_generate_return"/>
|
||||
<field name="get_return_label_from_portal" invisible="not return_label_on_delivery"/>
|
||||
<field name="dhl_dutiable"/>
|
||||
<field name="dhl_duty_payment" string="Duties paid by"
|
||||
invisible="not dhl_dutiable"
|
||||
required="delivery_type == 'fusion_dhl'"/>
|
||||
</group>
|
||||
<group string="Custom Data" name="dhl_legacy_customs" groups="base.group_no_one">
|
||||
<field name="dhl_custom_data_request" nolabel="1"
|
||||
placeholder="'rate': {}, 'ship': {}, 'return': {}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
323
fusion_shipping/views/fusion_shipment_views.xml
Normal file
@@ -0,0 +1,323 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Search View -->
|
||||
<record id="view_fusion_shipment_search" model="ir.ui.view">
|
||||
<field name="name">fusion.shipment.search</field>
|
||||
<field name="model">fusion.shipment</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="Search Shipments">
|
||||
<field name="name"/>
|
||||
<field name="tracking_number"/>
|
||||
<field name="shipment_id"/>
|
||||
<field name="sale_order_id"/>
|
||||
<field name="picking_id"/>
|
||||
<field name="recipient_name"/>
|
||||
<field name="carrier_type"/>
|
||||
<filter name="filter_confirmed" string="Confirmed"
|
||||
domain="[('status','=','confirmed')]"/>
|
||||
<filter name="filter_shipped" string="Shipped"
|
||||
domain="[('status','=','shipped')]"/>
|
||||
<filter name="filter_delivered" string="Delivered"
|
||||
domain="[('status','=','delivered')]"/>
|
||||
<filter name="filter_returned" string="Returned"
|
||||
domain="[('status','=','returned')]"/>
|
||||
<filter name="filter_cancelled" string="Cancelled"
|
||||
domain="[('status','=','cancelled')]"/>
|
||||
<group>
|
||||
<filter name="group_status" string="Status"
|
||||
context="{'group_by': 'status'}"/>
|
||||
<filter name="group_service" string="Service Type"
|
||||
context="{'group_by': 'service_type'}"/>
|
||||
<filter name="group_carrier_type" string="Carrier Type"
|
||||
context="{'group_by': 'carrier_type'}"/>
|
||||
<filter name="group_date" string="Shipment Date"
|
||||
context="{'group_by': 'shipment_date:month'}"/>
|
||||
</group>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- List View -->
|
||||
<record id="view_fusion_shipment_list" model="ir.ui.view">
|
||||
<field name="name">fusion.shipment.list</field>
|
||||
<field name="model">fusion.shipment</field>
|
||||
<field name="arch" type="xml">
|
||||
<list string="Shipments" default_order="shipment_date desc">
|
||||
<field name="name" decoration-bf="1"/>
|
||||
<field name="tracking_number"/>
|
||||
<field name="recipient_name"/>
|
||||
<field name="sale_order_id" optional="show"/>
|
||||
<field name="picking_id" optional="show"/>
|
||||
<field name="carrier_type" optional="show"/>
|
||||
<field name="service_type"/>
|
||||
<field name="currency_id" column_invisible="1"/>
|
||||
<field name="shipping_cost" sum="Total Cost"/>
|
||||
<field name="weight" optional="hide"/>
|
||||
<field name="package_name" optional="hide"/>
|
||||
<field name="shipment_date"/>
|
||||
<field name="status"
|
||||
decoration-info="status == 'draft'"
|
||||
decoration-success="status in ('confirmed','shipped')"
|
||||
decoration-bf="status == 'delivered'"
|
||||
decoration-warning="status == 'returned'"
|
||||
decoration-danger="status == 'cancelled'"
|
||||
widget="badge"/>
|
||||
</list>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Form View -->
|
||||
<record id="view_fusion_shipment_form" model="ir.ui.view">
|
||||
<field name="name">fusion.shipment.form</field>
|
||||
<field name="model">fusion.shipment</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Shipment">
|
||||
<header>
|
||||
<button name="action_refresh_tracking" type="object"
|
||||
string="Refresh Tracking"
|
||||
class="btn-primary"
|
||||
icon="fa-refresh"
|
||||
invisible="not tracking_number or status == 'cancelled'"/>
|
||||
<button name="action_track_on_carrier" type="object"
|
||||
string="Track Shipment"
|
||||
class="btn-secondary"
|
||||
icon="fa-external-link"
|
||||
invisible="not tracking_number"/>
|
||||
<button name="action_create_return_label" type="object"
|
||||
string="Create Return Label"
|
||||
class="btn-warning"
|
||||
icon="fa-mail-reply"
|
||||
invisible="status not in ('delivered', 'shipped') or return_tracking_number"
|
||||
confirm="Return labels may incur additional charges. Continue?"/>
|
||||
<button name="action_void_shipment" type="object"
|
||||
string="Void Shipment"
|
||||
class="btn-danger"
|
||||
icon="fa-ban"
|
||||
invisible="status in ('cancelled', 'delivered', 'returned')"
|
||||
confirm="Are you sure you want to void this shipment? This cannot be undone."/>
|
||||
<button name="action_reissue_shipment" type="object"
|
||||
string="Reissue Shipment"
|
||||
class="btn-warning"
|
||||
icon="fa-repeat"
|
||||
invisible="status != 'cancelled'"/>
|
||||
<field name="status" widget="statusbar"
|
||||
statusbar_visible="confirmed,shipped,delivered"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div name="button_box" class="oe_button_box">
|
||||
<button name="action_open_sale_order" type="object"
|
||||
class="oe_stat_button" icon="fa-shopping-cart"
|
||||
invisible="not sale_order_id">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_text">Sale Order</span>
|
||||
</div>
|
||||
</button>
|
||||
<button name="action_open_picking" type="object"
|
||||
class="oe_stat_button" icon="fa-truck"
|
||||
invisible="not picking_id">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_text">Transfer</span>
|
||||
</div>
|
||||
</button>
|
||||
<button name="action_refresh_tracking" type="object"
|
||||
class="oe_stat_button" icon="fa-map-marker"
|
||||
invisible="not tracking_number">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span class="o_stat_value">
|
||||
<field name="tracking_event_count"/>
|
||||
</span>
|
||||
<span class="o_stat_text">Events</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<label for="name"/>
|
||||
<h1><field name="name" readonly="1"/></h1>
|
||||
</div>
|
||||
<group>
|
||||
<group string="Shipment Details">
|
||||
<field name="tracking_number"/>
|
||||
<field name="shipment_id"/>
|
||||
<field name="carrier_id"/>
|
||||
<field name="carrier_type"/>
|
||||
<field name="service_type"/>
|
||||
<field name="shipment_date"/>
|
||||
<field name="shipping_cost"/>
|
||||
<field name="weight"/>
|
||||
<field name="package_name"
|
||||
invisible="not package_name"/>
|
||||
<field name="return_tracking_number"
|
||||
invisible="not return_tracking_number"/>
|
||||
</group>
|
||||
<group string="Links">
|
||||
<field name="sale_order_id"/>
|
||||
<field name="picking_id"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="Sender">
|
||||
<field name="sender_name"/>
|
||||
<field name="sender_address"/>
|
||||
</group>
|
||||
<group string="Recipient">
|
||||
<field name="recipient_name"/>
|
||||
<field name="recipient_address"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Labels & Documents" name="labels">
|
||||
<field name="label_attachment_id" invisible="1"/>
|
||||
<field name="full_label_attachment_id" invisible="1"/>
|
||||
<field name="receipt_attachment_id" invisible="1"/>
|
||||
<field name="commercial_invoice_attachment_id" invisible="1"/>
|
||||
<field name="return_label_attachment_id" invisible="1"/>
|
||||
<group string="Labels">
|
||||
<span class="o_form_label" invisible="not label_attachment_id">Printable Label (4x6)</span>
|
||||
<button name="action_view_label" type="object"
|
||||
class="btn btn-link p-0"
|
||||
icon="fa-file-pdf-o"
|
||||
string="Open"
|
||||
invisible="not label_attachment_id"/>
|
||||
<span class="o_form_label" invisible="not full_label_attachment_id">Full Label (8.5x11)</span>
|
||||
<button name="action_view_full_label" type="object"
|
||||
class="btn btn-link p-0"
|
||||
icon="fa-file-pdf-o"
|
||||
string="Open"
|
||||
invisible="not full_label_attachment_id"/>
|
||||
<span class="o_form_label" invisible="not return_label_attachment_id">Return Label</span>
|
||||
<button name="action_view_return_label" type="object"
|
||||
class="btn btn-link p-0"
|
||||
icon="fa-file-pdf-o"
|
||||
string="Open"
|
||||
invisible="not return_label_attachment_id"/>
|
||||
</group>
|
||||
<group string="Documents">
|
||||
<span class="o_form_label" invisible="not receipt_attachment_id">Receipt</span>
|
||||
<button name="action_view_receipt" type="object"
|
||||
class="btn btn-link p-0"
|
||||
icon="fa-file-pdf-o"
|
||||
string="Open"
|
||||
invisible="not receipt_attachment_id"/>
|
||||
<span class="o_form_label" invisible="not commercial_invoice_attachment_id">Commercial Invoice</span>
|
||||
<button name="action_view_commercial_invoice" type="object"
|
||||
class="btn btn-link p-0"
|
||||
icon="fa-file-pdf-o"
|
||||
string="Open"
|
||||
invisible="not commercial_invoice_attachment_id"/>
|
||||
</group>
|
||||
</page>
|
||||
<page string="Tracking History" name="tracking_history">
|
||||
<group>
|
||||
<group>
|
||||
<field name="last_tracking_update"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="delivery_date"
|
||||
invisible="status not in ('delivered', 'returned')"/>
|
||||
</group>
|
||||
</group>
|
||||
<field name="tracking_event_ids" readonly="1" nolabel="1">
|
||||
<list string="Tracking Events"
|
||||
default_order="event_datetime desc">
|
||||
<field name="event_datetime" string="Date/Time"/>
|
||||
<field name="event_description"/>
|
||||
<field name="event_site" string="Location"/>
|
||||
<field name="event_province"/>
|
||||
<field name="signatory_name" optional="hide"/>
|
||||
<field name="event_type" optional="hide"/>
|
||||
</list>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
<chatter/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Kanban View -->
|
||||
<record id="view_fusion_shipment_kanban" model="ir.ui.view">
|
||||
<field name="name">fusion.shipment.kanban</field>
|
||||
<field name="model">fusion.shipment</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban default_group_by="status" class="o_kanban_small_column">
|
||||
<field name="name"/>
|
||||
<field name="tracking_number"/>
|
||||
<field name="status"/>
|
||||
<field name="shipping_cost"/>
|
||||
<field name="shipment_date"/>
|
||||
<field name="recipient_name"/>
|
||||
<field name="service_type"/>
|
||||
<field name="carrier_type"/>
|
||||
<templates>
|
||||
<t t-name="card">
|
||||
<div class="oe_kanban_details">
|
||||
<strong><field name="name"/></strong>
|
||||
<div><field name="recipient_name"/></div>
|
||||
<div class="text-muted">
|
||||
<i class="fa fa-barcode"/> <field name="tracking_number"/>
|
||||
</div>
|
||||
<div class="text-muted">
|
||||
<field name="service_type"/> |
|
||||
<field name="shipment_date" widget="date"/>
|
||||
</div>
|
||||
<div>
|
||||
<strong>$<field name="shipping_cost"/></strong>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Window Actions -->
|
||||
<record id="action_fusion_shipment" model="ir.actions.act_window">
|
||||
<field name="name">All Shipments</field>
|
||||
<field name="res_model">fusion.shipment</field>
|
||||
<field name="view_mode">list,form,kanban</field>
|
||||
<field name="search_view_id" ref="view_fusion_shipment_search"/>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
No shipments yet
|
||||
</p>
|
||||
<p>Shipments are created automatically when you validate a delivery
|
||||
order with a shipping carrier.</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_fusion_shipment_confirmed" model="ir.actions.act_window">
|
||||
<field name="name">Confirmed</field>
|
||||
<field name="res_model">fusion.shipment</field>
|
||||
<field name="view_mode">list,form,kanban</field>
|
||||
<field name="domain">[('status', '=', 'confirmed')]</field>
|
||||
<field name="search_view_id" ref="view_fusion_shipment_search"/>
|
||||
</record>
|
||||
|
||||
<record id="action_fusion_shipment_shipped" model="ir.actions.act_window">
|
||||
<field name="name">Shipped</field>
|
||||
<field name="res_model">fusion.shipment</field>
|
||||
<field name="view_mode">list,form,kanban</field>
|
||||
<field name="domain">[('status', '=', 'shipped')]</field>
|
||||
<field name="search_view_id" ref="view_fusion_shipment_search"/>
|
||||
</record>
|
||||
|
||||
<record id="action_fusion_shipment_delivered" model="ir.actions.act_window">
|
||||
<field name="name">Delivered</field>
|
||||
<field name="res_model">fusion.shipment</field>
|
||||
<field name="view_mode">list,form,kanban</field>
|
||||
<field name="domain">[('status', '=', 'delivered')]</field>
|
||||
<field name="search_view_id" ref="view_fusion_shipment_search"/>
|
||||
</record>
|
||||
|
||||
<record id="action_fusion_shipment_returned" model="ir.actions.act_window">
|
||||
<field name="name">Returned</field>
|
||||
<field name="res_model">fusion.shipment</field>
|
||||
<field name="view_mode">list,form,kanban</field>
|
||||
<field name="domain">[('status', '=', 'returned')]</field>
|
||||
<field name="search_view_id" ref="view_fusion_shipment_search"/>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
70
fusion_shipping/views/menus.xml
Normal file
@@ -0,0 +1,70 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<!-- Top-level app menu -->
|
||||
<menuitem id="menu_fusion_shipping_root"
|
||||
name="Shipping"
|
||||
web_icon="fusion_shipping,static/description/icon.png"
|
||||
sequence="85"/>
|
||||
|
||||
<!-- Shipments parent -->
|
||||
<menuitem id="menu_fusion_shipments"
|
||||
name="Shipments"
|
||||
parent="menu_fusion_shipping_root"
|
||||
sequence="10"/>
|
||||
|
||||
<!-- Shipments sub-menus -->
|
||||
<menuitem id="menu_fusion_shipments_all"
|
||||
name="All Shipments"
|
||||
parent="menu_fusion_shipments"
|
||||
action="action_fusion_shipment"
|
||||
sequence="1"/>
|
||||
|
||||
<menuitem id="menu_fusion_shipments_confirmed"
|
||||
name="Confirmed"
|
||||
parent="menu_fusion_shipments"
|
||||
action="action_fusion_shipment_confirmed"
|
||||
sequence="10"/>
|
||||
|
||||
<menuitem id="menu_fusion_shipments_shipped"
|
||||
name="Shipped"
|
||||
parent="menu_fusion_shipments"
|
||||
action="action_fusion_shipment_shipped"
|
||||
sequence="20"/>
|
||||
|
||||
<menuitem id="menu_fusion_shipments_delivered"
|
||||
name="Delivered"
|
||||
parent="menu_fusion_shipments"
|
||||
action="action_fusion_shipment_delivered"
|
||||
sequence="30"/>
|
||||
|
||||
<menuitem id="menu_fusion_shipments_returned"
|
||||
name="Returned"
|
||||
parent="menu_fusion_shipments"
|
||||
action="action_fusion_shipment_returned"
|
||||
sequence="40"/>
|
||||
|
||||
<!-- Configuration parent -->
|
||||
<menuitem id="menu_fusion_config"
|
||||
name="Configuration"
|
||||
parent="menu_fusion_shipping_root"
|
||||
sequence="90"/>
|
||||
|
||||
<!-- Carrier Settings action -->
|
||||
<record id="action_fusion_carrier_settings" model="ir.actions.act_window">
|
||||
<field name="name">Shipping Carriers</field>
|
||||
<field name="res_model">delivery.carrier</field>
|
||||
<field name="view_mode">list,form</field>
|
||||
<field name="domain">[('delivery_type', 'like', 'fusion_')]</field>
|
||||
<field name="help" type="html">
|
||||
<p class="o_view_nocontent_smiling_face">
|
||||
Configure your shipping carriers
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_fusion_carrier"
|
||||
name="Carriers"
|
||||
parent="menu_fusion_config"
|
||||
action="action_fusion_carrier_settings"
|
||||
sequence="10"/>
|
||||
</odoo>
|
||||
77
fusion_shipping/views/report_templates.xml
Normal file
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
|
||||
<!-- Sale Order PDF: Shipping Information -->
|
||||
<template id="report_saleorder_shipping_info"
|
||||
inherit_id="sale.report_saleorder_document">
|
||||
<xpath expr="//div[@name='so_total_summary']" position="after">
|
||||
<t t-set="shipments" t-value="doc.fusion_shipment_ids.filtered(lambda s: s.status != 'cancelled')"/>
|
||||
<div t-if="shipments" class="mt-4">
|
||||
<h5><strong>Shipping Information</strong></h5>
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tracking Number</th>
|
||||
<th>Service</th>
|
||||
<th class="text-end">Weight</th>
|
||||
<th class="text-end">Cost</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr t-foreach="shipments" t-as="shipment">
|
||||
<td><span t-field="shipment.tracking_number"/></td>
|
||||
<td><span t-field="shipment.service_type"/></td>
|
||||
<td class="text-end">
|
||||
<span t-field="shipment.weight"/> kg
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-field="shipment.shipping_cost"
|
||||
t-options="{'widget': 'monetary', 'display_currency': shipment.currency_id}"/>
|
||||
</td>
|
||||
<td><span t-field="shipment.status"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
<!-- Invoice PDF: Shipping Information -->
|
||||
<template id="report_invoice_shipping_info"
|
||||
inherit_id="account.report_invoice_document">
|
||||
<xpath expr="//div[@id='payment_term']" position="before">
|
||||
<t t-set="sale_orders" t-value="o.line_ids.sale_line_ids.order_id"/>
|
||||
<t t-set="shipments" t-value="sale_orders.mapped('fusion_shipment_ids').filtered(lambda s: s.status != 'cancelled')" t-if="sale_orders"/>
|
||||
<div t-if="shipments" class="mt-4">
|
||||
<h5><strong>Shipping Information</strong></h5>
|
||||
<table class="table table-sm table-bordered">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Tracking Number</th>
|
||||
<th>Service</th>
|
||||
<th class="text-end">Weight</th>
|
||||
<th class="text-end">Cost</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr t-foreach="shipments" t-as="shipment">
|
||||
<td><span t-field="shipment.tracking_number"/></td>
|
||||
<td><span t-field="shipment.service_type"/></td>
|
||||
<td class="text-end">
|
||||
<span t-field="shipment.weight"/> kg
|
||||
</td>
|
||||
<td class="text-end">
|
||||
<span t-field="shipment.shipping_cost"
|
||||
t-options="{'widget': 'monetary', 'display_currency': shipment.currency_id}"/>
|
||||
</td>
|
||||
<td><span t-field="shipment.status"/></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</xpath>
|
||||
</template>
|
||||
|
||||
</odoo>
|
||||
41
fusion_shipping/views/res_config_settings_views.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="res_config_settings_view_form_fusion_shipping" model="ir.ui.view">
|
||||
<field name="name">res.config.settings.view.form.fusion.shipping</field>
|
||||
<field name="model">res.config.settings</field>
|
||||
<field name="inherit_id" ref="base.res_config_settings_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//form" position="inside">
|
||||
<app data-string="Shipping" string="Shipping"
|
||||
name="fusion_shipping">
|
||||
<block title="Carrier Configuration" name="carrier_config_block">
|
||||
<setting string="Shipping Carrier Settings"
|
||||
help="Configure your shipping API credentials, service types, label format, and shipping preferences.">
|
||||
<div class="content-group">
|
||||
<div class="mt8">
|
||||
<button name="%(fusion_shipping.action_fusion_carrier_settings)d"
|
||||
type="action"
|
||||
class="btn-link"
|
||||
icon="oi-arrow-right"
|
||||
string="Open Carrier Configuration"/>
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
<setting string="Shipment History"
|
||||
help="View and manage all shipments, labels, and tracking information.">
|
||||
<div class="content-group">
|
||||
<div class="mt8">
|
||||
<button name="%(fusion_shipping.action_fusion_shipment)d"
|
||||
type="action"
|
||||
class="btn-link"
|
||||
icon="oi-arrow-right"
|
||||
string="View Shipments"/>
|
||||
</div>
|
||||
</div>
|
||||
</setting>
|
||||
</block>
|
||||
</app>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
15
fusion_shipping/views/res_partner_views.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_partner_form_inherit_fusion_shipping" model="ir.ui.view">
|
||||
<field name="name">res.partner.form.inherit.fusion.shipping</field>
|
||||
<field name="model">res.partner</field>
|
||||
<field name="inherit_id" ref="base.view_partner_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='sales_purchases']//group[@name='sale']" position="inside">
|
||||
<field name="property_ups_carrier_account"
|
||||
string="UPS Account Number"
|
||||
help="If set, this customer can have UPS shipping charged to their own account."/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
49
fusion_shipping/views/sale_order_views.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_order_form_fusion_shipping" model="ir.ui.view">
|
||||
<field name="name">sale.order.form.fusion.shipping</field>
|
||||
<field name="model">sale.order</field>
|
||||
<field name="inherit_id" ref="sale.view_order_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_view_fusion_shipments" type="object"
|
||||
class="oe_stat_button" icon="fa-plane"
|
||||
invisible="fusion_shipment_count == 0">
|
||||
<field name="fusion_shipment_count" widget="statinfo"
|
||||
string="Shipments"/>
|
||||
</button>
|
||||
</xpath>
|
||||
|
||||
<!-- UPS Bill My Account fields -->
|
||||
<xpath expr="//field[@name='partner_shipping_id']" position="after">
|
||||
<field name="ups_bill_my_account" invisible="1"/>
|
||||
<field name="partner_ups_carrier_account"
|
||||
invisible="not ups_bill_my_account"/>
|
||||
</xpath>
|
||||
|
||||
<!-- Show package details on the sale order -->
|
||||
<xpath expr="//group[@name='note_group']" position="before">
|
||||
<group string="Shipping Packages"
|
||||
invisible="not fusion_package_ids"
|
||||
colspan="6">
|
||||
<field name="fusion_package_ids" nolabel="1"
|
||||
colspan="6" readonly="1">
|
||||
<list create="0" delete="0" no_open="1">
|
||||
<field name="package_type_id" string="Box Type"
|
||||
optional="show"/>
|
||||
<field name="package_length" string="Length"/>
|
||||
<field name="package_width" string="Width"/>
|
||||
<field name="package_height" string="Height"/>
|
||||
<field name="weight" string="Weight"/>
|
||||
<field name="service_name" string="Service"/>
|
||||
<field name="price" string="Cost"
|
||||
widget="monetary"
|
||||
options="{'currency_field': 'currency_id'}"/>
|
||||
<field name="currency_id" column_invisible="1"/>
|
||||
</list>
|
||||
</field>
|
||||
</group>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
18
fusion_shipping/views/stock_picking_views.xml
Normal file
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<record id="view_picking_form_fusion_shipping" model="ir.ui.view">
|
||||
<field name="name">stock.picking.form.fusion.shipping</field>
|
||||
<field name="model">stock.picking</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//div[@name='button_box']" position="inside">
|
||||
<button name="action_view_fusion_shipments" type="object"
|
||||
class="oe_stat_button" icon="fa-plane"
|
||||
invisible="fusion_shipment_count == 0">
|
||||
<field name="fusion_shipment_count" widget="statinfo"
|
||||
string="Shipments"/>
|
||||
</button>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
1
fusion_shipping/wizard/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import choose_delivery_fusion_rate
|
||||
446
fusion_shipping/wizard/choose_delivery_fusion_rate.py
Normal file
@@ -0,0 +1,446 @@
|
||||
import json
|
||||
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class ChooseDeliveryFusionPackage(models.TransientModel):
|
||||
"""One package row in the Add Shipping wizard."""
|
||||
|
||||
_name = 'choose.delivery.fusion.package'
|
||||
_description = 'Shipping Package (Wizard)'
|
||||
_order = 'sequence, id'
|
||||
|
||||
wizard_id = fields.Many2one(
|
||||
'choose.delivery.carrier',
|
||||
string='Wizard',
|
||||
ondelete='cascade',
|
||||
)
|
||||
sequence = fields.Integer(default=10)
|
||||
package_type_id = fields.Many2one(
|
||||
'stock.package.type',
|
||||
string='Box Type',
|
||||
domain="[('package_carrier_type', '=', 'fusion_canada_post')]",
|
||||
)
|
||||
package_length = fields.Float(string='Length')
|
||||
package_width = fields.Float(string='Width')
|
||||
package_height = fields.Float(string='Height')
|
||||
weight = fields.Float(string='Weight')
|
||||
|
||||
# Per-package cost for the selected service (updated on service select)
|
||||
selected_price = fields.Float(
|
||||
string='Cost', digits='Product Price', readonly=True)
|
||||
currency_id = fields.Many2one(
|
||||
'res.currency',
|
||||
related='wizard_id.currency_id',
|
||||
)
|
||||
|
||||
@api.onchange('package_type_id')
|
||||
def _onchange_package_type_id(self):
|
||||
"""Pre-fill dimensions from selected box type."""
|
||||
if self.package_type_id:
|
||||
self.package_length = self.package_type_id.packaging_length
|
||||
self.package_width = self.package_type_id.width
|
||||
self.package_height = self.package_type_id.height
|
||||
|
||||
|
||||
class ChooseDeliveryFusionRate(models.TransientModel):
|
||||
_name = 'choose.delivery.fusion.rate'
|
||||
_description = 'Shipping Rate Option'
|
||||
|
||||
wizard_id = fields.Many2one(
|
||||
'choose.delivery.carrier',
|
||||
string='Wizard',
|
||||
ondelete='cascade',
|
||||
)
|
||||
service_code = fields.Char(string='Service Code')
|
||||
service_name = fields.Char(string='Service')
|
||||
price = fields.Float(string='Shipping Cost', digits='Product Price')
|
||||
expected_delivery = fields.Char(string='Expected Delivery Date')
|
||||
is_selected = fields.Boolean(string='Selected', default=False)
|
||||
currency_id = fields.Many2one(
|
||||
'res.currency',
|
||||
related='wizard_id.currency_id',
|
||||
)
|
||||
# JSON: [{"pkg_id": <int>, "price": <float>}, ...]
|
||||
per_package_prices = fields.Text(string='Per-Package Prices')
|
||||
|
||||
def action_select(self):
|
||||
"""Select this rate and deselect others. Update per-package costs."""
|
||||
self.ensure_one()
|
||||
# Deselect all, then select this one
|
||||
self.wizard_id.fusion_rate_ids.write({'is_selected': False})
|
||||
self.is_selected = True
|
||||
|
||||
# Update per-package costs from stored JSON
|
||||
if self.per_package_prices:
|
||||
try:
|
||||
pkg_prices = json.loads(self.per_package_prices)
|
||||
for pp in pkg_prices:
|
||||
pkg = self.env['choose.delivery.fusion.package'].browse(
|
||||
pp['pkg_id'])
|
||||
if pkg.exists():
|
||||
pkg.selected_price = pp['price']
|
||||
except (json.JSONDecodeError, KeyError):
|
||||
pass
|
||||
|
||||
# Apply margin from the carrier
|
||||
carrier = self.wizard_id.carrier_id
|
||||
price = self.price
|
||||
if carrier:
|
||||
price = carrier._apply_margins(price, self.wizard_id.order_id)
|
||||
# Check free_over
|
||||
if carrier.free_over:
|
||||
order = self.wizard_id.order_id
|
||||
amount = order.currency_id._convert(
|
||||
order.amount_untaxed,
|
||||
order.company_id.currency_id,
|
||||
order.company_id,
|
||||
fields.Date.today(),
|
||||
)
|
||||
if amount >= carrier.amount:
|
||||
price = 0.0
|
||||
|
||||
self.wizard_id.write({
|
||||
'delivery_price': price,
|
||||
'display_price': price,
|
||||
'fusion_selected_service': self.service_code,
|
||||
'fusion_selected_service_name': self.service_name,
|
||||
'fusion_selected_expected_delivery': self.expected_delivery,
|
||||
})
|
||||
# Re-open the wizard to show updated selection
|
||||
return {
|
||||
'name': _('Add a shipping method'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'res_model': 'choose.delivery.carrier',
|
||||
'res_id': self.wizard_id.id,
|
||||
'view_mode': 'form',
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
|
||||
class ChooseDeliveryCarrier(models.TransientModel):
|
||||
_inherit = 'choose.delivery.carrier'
|
||||
|
||||
fusion_rate_ids = fields.One2many(
|
||||
'choose.delivery.fusion.rate',
|
||||
'wizard_id',
|
||||
string='Available Services',
|
||||
)
|
||||
fusion_selected_service = fields.Char(
|
||||
string='Selected Service Code',
|
||||
)
|
||||
fusion_selected_service_name = fields.Char(
|
||||
string='Selected Service Name',
|
||||
)
|
||||
fusion_selected_expected_delivery = fields.Char(
|
||||
string='Selected Expected Delivery',
|
||||
)
|
||||
|
||||
# -- Package list --
|
||||
fusion_package_ids = fields.One2many(
|
||||
'choose.delivery.fusion.package',
|
||||
'wizard_id',
|
||||
string='Packages',
|
||||
)
|
||||
|
||||
# -- Unit labels --
|
||||
fusion_dimension_unit_label = fields.Char(
|
||||
string='Dimension Unit',
|
||||
compute='_compute_fusion_dimension_unit_label',
|
||||
)
|
||||
fusion_weight_unit_label = fields.Char(
|
||||
string='Weight Unit',
|
||||
compute='_compute_fusion_weight_unit_label',
|
||||
)
|
||||
|
||||
@api.depends('carrier_id')
|
||||
def _compute_fusion_dimension_unit_label(self):
|
||||
for rec in self:
|
||||
if (rec.carrier_id
|
||||
and rec.carrier_id.delivery_type == 'fusion_canada_post'):
|
||||
rec.fusion_dimension_unit_label = (
|
||||
rec.carrier_id.fusion_cp_dimension_unit or 'cm')
|
||||
else:
|
||||
rec.fusion_dimension_unit_label = ''
|
||||
|
||||
@api.depends('carrier_id')
|
||||
def _compute_fusion_weight_unit_label(self):
|
||||
for rec in self:
|
||||
if (rec.carrier_id
|
||||
and rec.carrier_id.delivery_type == 'fusion_canada_post'):
|
||||
uom = (rec.order_id.company_id
|
||||
.weight_unit_of_measurement_id)
|
||||
rec.fusion_weight_unit_label = uom.name if uom else 'kg'
|
||||
else:
|
||||
rec.fusion_weight_unit_label = ''
|
||||
|
||||
@api.onchange('carrier_id')
|
||||
def _onchange_carrier_id_fusion_packages(self):
|
||||
"""When a CP carrier is selected, create one default package."""
|
||||
if (self.carrier_id
|
||||
and self.carrier_id.delivery_type == 'fusion_canada_post'
|
||||
and not self.fusion_package_ids):
|
||||
vals = {
|
||||
'sequence': 10,
|
||||
'weight': self.total_weight or 0.0,
|
||||
}
|
||||
# Pre-fill from default package type if set on carrier
|
||||
if self.carrier_id.product_packaging_id:
|
||||
pkg = self.carrier_id.product_packaging_id
|
||||
vals['package_type_id'] = pkg.id
|
||||
vals['package_length'] = pkg.packaging_length
|
||||
vals['package_width'] = pkg.width
|
||||
vals['package_height'] = pkg.height
|
||||
self.fusion_package_ids = [(5, 0, 0), (0, 0, vals)]
|
||||
|
||||
# -- Rate fetching --
|
||||
|
||||
def update_price(self):
|
||||
"""Override: for Canada Post, fetch all rates for all packages."""
|
||||
if self.carrier_id.delivery_type == 'fusion_canada_post':
|
||||
return self._update_fusion_rates()
|
||||
return super().update_price()
|
||||
|
||||
def _get_fusion_package_info_for_pkg(self, pkg):
|
||||
"""Build package_info dict for a single package, converted to cm."""
|
||||
carrier = self.carrier_id
|
||||
return {
|
||||
'length': round(carrier._fusion_cp_convert_dimension_to_cm(
|
||||
pkg.package_length), 1),
|
||||
'width': round(carrier._fusion_cp_convert_dimension_to_cm(
|
||||
pkg.package_width), 1),
|
||||
'height': round(carrier._fusion_cp_convert_dimension_to_cm(
|
||||
pkg.package_height), 1),
|
||||
}
|
||||
|
||||
def _update_fusion_rates(self):
|
||||
"""Fetch shipping service rates for every package and aggregate."""
|
||||
carrier = self.carrier_id
|
||||
packages = self.fusion_package_ids
|
||||
|
||||
if not packages:
|
||||
raise UserError(_(
|
||||
"Please add at least one package with dimensions."))
|
||||
|
||||
from_unit = (self.order_id.company_id
|
||||
.weight_unit_of_measurement_id)
|
||||
|
||||
# -- Validate every package --
|
||||
for pkg in packages:
|
||||
if not (pkg.package_length and pkg.package_width
|
||||
and pkg.package_height):
|
||||
raise UserError(_(
|
||||
"Please enter dimensions (L x W x H) "
|
||||
"for all packages."))
|
||||
if not pkg.weight:
|
||||
raise UserError(_(
|
||||
"Please enter weight for all packages."))
|
||||
package_info = self._get_fusion_package_info_for_pkg(pkg)
|
||||
weight_kg = pkg.weight
|
||||
if from_unit:
|
||||
weight_kg = round(carrier.convert_weight(
|
||||
from_unit, carrier.weight_uom_id, weight_kg), 2)
|
||||
carrier._fusion_cp_validate_package(weight_kg, package_info)
|
||||
|
||||
# -- Clear old rates --
|
||||
self.fusion_rate_ids.unlink()
|
||||
|
||||
# -- Fetch rates per package --
|
||||
# {service_code: {service_name, packages: [{pkg_id, price, exp}]}}
|
||||
all_service_rates = {}
|
||||
|
||||
for pkg in packages:
|
||||
package_info = self._get_fusion_package_info_for_pkg(pkg)
|
||||
carrier_ctx = carrier.with_context(
|
||||
order_weight=pkg.weight, # raw, in company UOM
|
||||
cp_package_info=package_info,
|
||||
)
|
||||
rates = carrier_ctx.fusion_canada_post_rate_shipment_all(
|
||||
self.order_id)
|
||||
|
||||
if isinstance(rates, dict) and rates.get('error_message'):
|
||||
raise UserError(rates['error_message'])
|
||||
|
||||
if not rates:
|
||||
raise UserError(_(
|
||||
"No shipping prices available for this order."))
|
||||
|
||||
for rate in rates:
|
||||
code = rate['service_code']
|
||||
if code not in all_service_rates:
|
||||
all_service_rates[code] = {
|
||||
'service_name': rate['service_name'],
|
||||
'packages': [],
|
||||
}
|
||||
all_service_rates[code]['packages'].append({
|
||||
'pkg_id': pkg.id,
|
||||
'price': rate['price'],
|
||||
'expected_delivery': rate.get(
|
||||
'expected_delivery', ''),
|
||||
})
|
||||
|
||||
# -- Keep only services available for ALL packages --
|
||||
num_packages = len(packages)
|
||||
available = {
|
||||
code: data
|
||||
for code, data in all_service_rates.items()
|
||||
if len(data['packages']) == num_packages
|
||||
}
|
||||
|
||||
if not available:
|
||||
raise UserError(_(
|
||||
"No single shipping service covers all packages. "
|
||||
"Try adjusting package dimensions or weight."))
|
||||
|
||||
# -- Find cheapest service --
|
||||
cheapest_code = min(
|
||||
available.keys(),
|
||||
key=lambda c: sum(
|
||||
p['price'] for p in available[c]['packages']))
|
||||
|
||||
# -- Create combined rate lines --
|
||||
vals_list = []
|
||||
for code, data in available.items():
|
||||
total_price = sum(p['price'] for p in data['packages'])
|
||||
expected_dates = [
|
||||
p['expected_delivery'] for p in data['packages']
|
||||
if p['expected_delivery']
|
||||
]
|
||||
expected = max(expected_dates) if expected_dates else ''
|
||||
is_sel = (code == cheapest_code)
|
||||
vals_list.append({
|
||||
'wizard_id': self.id,
|
||||
'service_code': code,
|
||||
'service_name': data['service_name'],
|
||||
'price': total_price,
|
||||
'expected_delivery': expected,
|
||||
'is_selected': is_sel,
|
||||
'per_package_prices': json.dumps(data['packages']),
|
||||
})
|
||||
|
||||
self.env['choose.delivery.fusion.rate'].create(vals_list)
|
||||
|
||||
# -- Auto-select cheapest: update packages and wizard --
|
||||
cheapest_data = available[cheapest_code]
|
||||
selected_price = sum(
|
||||
p['price'] for p in cheapest_data['packages'])
|
||||
|
||||
for pkg_data in cheapest_data['packages']:
|
||||
pkg_rec = packages.filtered(
|
||||
lambda p, pid=pkg_data['pkg_id']: p.id == pid)
|
||||
if pkg_rec:
|
||||
pkg_rec.selected_price = pkg_data['price']
|
||||
|
||||
# Apply carrier margins
|
||||
price = selected_price
|
||||
if self.carrier_id:
|
||||
price = self.carrier_id._apply_margins(
|
||||
price, self.order_id)
|
||||
if self.carrier_id.free_over:
|
||||
amount = self.order_id.currency_id._convert(
|
||||
self.order_id.amount_untaxed,
|
||||
self.order_id.company_id.currency_id,
|
||||
self.order_id.company_id,
|
||||
fields.Date.today(),
|
||||
)
|
||||
if amount >= self.carrier_id.amount:
|
||||
price = 0.0
|
||||
|
||||
expected_dates = [
|
||||
p['expected_delivery'] for p in cheapest_data['packages']
|
||||
if p['expected_delivery']
|
||||
]
|
||||
|
||||
self.write({
|
||||
'delivery_price': price,
|
||||
'display_price': price,
|
||||
'fusion_selected_service': cheapest_code,
|
||||
'fusion_selected_service_name': (
|
||||
cheapest_data['service_name']),
|
||||
'fusion_selected_expected_delivery': (
|
||||
max(expected_dates) if expected_dates else ''),
|
||||
})
|
||||
|
||||
return {
|
||||
'name': _('Add a shipping method'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'choose.delivery.carrier',
|
||||
'res_id': self.id,
|
||||
'target': 'new',
|
||||
}
|
||||
|
||||
# -- Confirm --
|
||||
|
||||
def button_confirm(self):
|
||||
"""Override: store per-package info on the sale order and enhance
|
||||
the delivery line description."""
|
||||
if self.carrier_id.delivery_type == 'fusion_canada_post':
|
||||
order = self.order_id
|
||||
|
||||
# Clear previous package records
|
||||
order.fusion_package_ids.unlink()
|
||||
|
||||
selected_code = self.fusion_selected_service or ''
|
||||
selected_name = self.fusion_selected_service_name or ''
|
||||
selected_delivery = (
|
||||
self.fusion_selected_expected_delivery or '')
|
||||
|
||||
pkg_vals = []
|
||||
for idx, pkg in enumerate(
|
||||
self.fusion_package_ids.sorted('sequence')):
|
||||
pkg_vals.append((0, 0, {
|
||||
'sequence': (idx + 1) * 10,
|
||||
'package_type_id': (
|
||||
pkg.package_type_id.id
|
||||
if pkg.package_type_id else False),
|
||||
'package_length': pkg.package_length,
|
||||
'package_width': pkg.package_width,
|
||||
'package_height': pkg.package_height,
|
||||
'weight': pkg.weight,
|
||||
'service_code': selected_code,
|
||||
'service_name': selected_name,
|
||||
'price': pkg.selected_price,
|
||||
'expected_delivery': selected_delivery,
|
||||
}))
|
||||
|
||||
write_vals = {
|
||||
'fusion_package_ids': pkg_vals,
|
||||
'fusion_cp_service_code': selected_code,
|
||||
}
|
||||
|
||||
# Backward compat: first-package dims in legacy fields
|
||||
first_pkg = self.fusion_package_ids.sorted('sequence')[:1]
|
||||
if first_pkg:
|
||||
write_vals['fusion_cp_package_length'] = (
|
||||
first_pkg.package_length)
|
||||
write_vals['fusion_cp_package_width'] = (
|
||||
first_pkg.package_width)
|
||||
write_vals['fusion_cp_package_height'] = (
|
||||
first_pkg.package_height)
|
||||
|
||||
order.write(write_vals)
|
||||
|
||||
res = super().button_confirm()
|
||||
|
||||
# Enhance delivery line description with service details
|
||||
if (self.carrier_id.delivery_type == 'fusion_canada_post'
|
||||
and self.fusion_selected_service_name):
|
||||
delivery_line = self.order_id.order_line.filtered(
|
||||
'is_delivery')
|
||||
if delivery_line:
|
||||
line = delivery_line[-1]
|
||||
parts = [line.name]
|
||||
parts.append(
|
||||
"Service: %s"
|
||||
% self.fusion_selected_service_name)
|
||||
num_pkgs = len(self.fusion_package_ids)
|
||||
if num_pkgs > 1:
|
||||
parts.append("Packages: %d" % num_pkgs)
|
||||
if self.fusion_selected_expected_delivery:
|
||||
parts.append(
|
||||
"Expected Delivery: %s"
|
||||
% self.fusion_selected_expected_delivery)
|
||||
line.name = '\n'.join(parts)
|
||||
return res
|
||||