Merge branch 'wip/12.0/delivery_hibou__sig_req' into 12.0

# Conflicts:
#	delivery_hibou/models/stock.py
#	delivery_hibou/views/stock_views.xml
This commit is contained in:
Jared Kipe
2022-02-15 12:40:23 -08:00
68 changed files with 4255 additions and 240 deletions

View File

@@ -1 +1,3 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import models from . import models

View File

@@ -1,9 +1,9 @@
{ {
'name': 'Hibou Fedex Shipping', 'name': 'Hibou Fedex Shipping',
'version': '12.0.1.0.0', 'version': '12.0.1.1.0',
'category': 'Stock', 'category': 'Stock',
'author': "Hibou Corp.", 'author': "Hibou Corp.",
'license': 'AGPL-3', 'license': 'OPL-1',
'website': 'https://hibou.io/', 'website': 'https://hibou.io/',
'depends': [ 'depends': [
'delivery_fedex', 'delivery_fedex',

View File

@@ -1,2 +1,4 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import delivery_fedex from . import delivery_fedex
from . import stock from . import stock

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
import logging import logging
import pytz import pytz
from odoo import fields, models, tools, _ from odoo import fields, models, tools, _
@@ -36,6 +38,8 @@ class DeliveryFedex(models.Model):
if not third_party_account.delivery_type == 'fedex': if not third_party_account.delivery_type == 'fedex':
raise ValidationError('Non-FedEx Shipping Account indicated during FedEx shipment.') raise ValidationError('Non-FedEx Shipping Account indicated during FedEx shipment.')
return third_party_account.name return third_party_account.name
if picking and picking.picking_type_id.warehouse_id.fedex_account_number:
return picking.picking_type_id.warehouse_id.fedex_account_number
return self.fedex_account_number return self.fedex_account_number
def _get_fedex_account_number(self, order=None, picking=None): def _get_fedex_account_number(self, order=None, picking=None):
@@ -226,6 +230,15 @@ class DeliveryFedex(models.Model):
srm = FedexRequest(self.log_xml, request_type="shipping", prod_environment=self.prod_environment) srm = FedexRequest(self.log_xml, request_type="shipping", prod_environment=self.prod_environment)
superself = self.sudo() superself = self.sudo()
picking_packages = picking.package_ids
package_carriers = picking_packages.mapped('carrier_id')
if package_carriers:
# only ship ours
picking_packages = picking_packages.filtered(lambda p: p.carrier_id == self and not p.carrier_tracking_ref)
if package_carriers and not picking_packages:
continue
shipper_company = superself.get_shipper_company(picking=picking) shipper_company = superself.get_shipper_company(picking=picking)
shipper_warehouse = superself.get_shipper_warehouse(picking=picking) shipper_warehouse = superself.get_shipper_warehouse(picking=picking)
recipient = superself.get_recipient(picking=picking) recipient = superself.get_recipient(picking=picking)
@@ -234,7 +247,6 @@ class DeliveryFedex(models.Model):
payment_acc_number = superself._get_fedex_payment_account_number(picking=picking) payment_acc_number = superself._get_fedex_payment_account_number(picking=picking)
order_name = superself.get_order_name(picking=picking) order_name = superself.get_order_name(picking=picking)
attn = superself.get_attn(picking=picking) attn = superself.get_attn(picking=picking)
insurance_value = superself.get_insurance_value(picking=picking)
residential = self._get_fedex_recipient_is_residential(recipient) residential = self._get_fedex_recipient_is_residential(recipient)
srm.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password) srm.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password)
@@ -243,7 +255,7 @@ class DeliveryFedex(models.Model):
# Not the actual reference. Using `shipment_name` during `add_package` calls. # Not the actual reference. Using `shipment_name` during `add_package` calls.
srm.transaction_detail(picking.id) srm.transaction_detail(picking.id)
package_type = picking.package_ids and picking.package_ids[0].packaging_id.shipper_package_code or self.fedex_default_packaging_id.shipper_package_code package_type = picking_packages and picking_packages[0].packaging_id.shipper_package_code or self.fedex_default_packaging_id.shipper_package_code
srm.shipment_request(self.fedex_droppoff_type, self.fedex_service_type, package_type, self.fedex_weight_unit, self.fedex_saturday_delivery) srm.shipment_request(self.fedex_droppoff_type, self.fedex_service_type, package_type, self.fedex_weight_unit, self.fedex_saturday_delivery)
srm.set_currency(_convert_curr_iso_fdx(picking.company_id.currency_id.name)) srm.set_currency(_convert_curr_iso_fdx(picking.company_id.currency_id.name))
srm.set_shipper(shipper_company, shipper_warehouse) srm.set_shipper(shipper_company, shipper_warehouse)
@@ -284,7 +296,7 @@ class DeliveryFedex(models.Model):
srm.customs_value(_convert_curr_iso_fdx(commodity_currency.name), total_commodities_amount, "NON_DOCUMENTS") srm.customs_value(_convert_curr_iso_fdx(commodity_currency.name), total_commodities_amount, "NON_DOCUMENTS")
srm.duties_payment(shipper_warehouse.country_id.code, acc_number) srm.duties_payment(shipper_warehouse.country_id.code, acc_number)
package_count = len(picking.package_ids) or 1 package_count = len(picking_packages) or 1
# For india picking courier is not accepted without this details in label. # For india picking courier is not accepted without this details in label.
po_number = dept_number = False po_number = dept_number = False
@@ -312,16 +324,17 @@ class DeliveryFedex(models.Model):
package_labels = [] package_labels = []
carrier_tracking_ref = "" carrier_tracking_ref = ""
for sequence, package in enumerate(picking.package_ids, start=1): for sequence, package in enumerate(picking_packages, start=1):
package_weight = self._fedex_convert_weight(package.shipping_weight, self.fedex_weight_unit) package_weight = self._fedex_convert_weight(package.shipping_weight, self.fedex_weight_unit)
packaging = package.packaging_id packaging = package.packaging_id
packaging_code = packaging.shipper_package_code if (packaging.package_carrier_type == 'fedex' and packaging.shipper_package_code) else self.fedex_default_packaging_id.shipper_package_code
# Hibou Delivery # Hibou Delivery
# Add more details to package. # Add more details to package.
srm._add_package( srm._add_package(
package_weight, package_weight,
package_code=packaging.shipper_package_code, package_code=packaging_code,
package_height=packaging.height, package_height=packaging.height,
package_width=packaging.width, package_width=packaging.width,
package_length=packaging.length, package_length=packaging.length,
@@ -329,7 +342,8 @@ class DeliveryFedex(models.Model):
po_number=po_number, po_number=po_number,
dept_number=dept_number, dept_number=dept_number,
ref=('%s-%d' % (order_name, sequence)), ref=('%s-%d' % (order_name, sequence)),
insurance=insurance_value insurance=superself.get_insurance_value(picking=picking, package=package),
signature_required=superself.get_signature_required(picking=picking, package=package)
) )
srm.set_master_package(net_weight, package_count, master_tracking_id=master_tracking_id) srm.set_master_package(net_weight, package_count, master_tracking_id=master_tracking_id)
request = srm.process_shipment() request = srm.process_shipment()
@@ -398,19 +412,19 @@ class DeliveryFedex(models.Model):
# One package # # One package #
############### ###############
elif package_count == 1: elif package_count == 1:
packaging = picking.package_ids[:1].packaging_id or picking.carrier_id.fedex_default_packaging_id packaging = picking_packages[:1].packaging_id or self.fedex_default_packaging_id
# Hibou Delivery packaging_code = packaging.shipper_package_code if packaging.package_carrier_type == 'fedex' else self.fedex_default_packaging_id.shipper_package_code
# Add more details to package.
srm._add_package( srm._add_package(
net_weight, net_weight,
package_code=packaging.shipper_package_code, package_code=packaging_code,
package_height=packaging.height, package_height=packaging.height,
package_width=packaging.width, package_width=packaging.width,
package_length=packaging.length, package_length=packaging.length,
po_number=po_number, po_number=po_number,
dept_number=dept_number, dept_number=dept_number,
ref=order_name, ref=order_name,
insurance=insurance_value insurance=superself.get_insurance_value(picking=picking, package=picking_packages[:1]),
signature_required=superself.get_signature_required(picking=picking, package=picking_packages[:1])
) )
srm.set_master_package(net_weight, 1) srm.set_master_package(net_weight, 1)
@@ -460,21 +474,33 @@ class DeliveryFedex(models.Model):
return res return res
def fedex_rate_shipment_multi(self, order=None, picking=None): def fedex_rate_shipment_multi(self, order=None, picking=None, packages=None):
if not packages:
return self._fedex_rate_shipment_multi_package(order=order, picking=picking)
else:
rates = []
for package in packages:
rates += self._fedex_rate_shipment_multi_package(order=order, picking=picking, package=package)
return rates
def _fedex_rate_shipment_multi_package(self, order=None, picking=None, package=None):
if order: if order:
max_weight = self._fedex_convert_weight(self.fedex_default_packaging_id.max_weight, self.fedex_weight_unit) max_weight = self._fedex_convert_weight(self.fedex_default_packaging_id.max_weight, self.fedex_weight_unit)
is_india = order.partner_shipping_id.country_id.code == 'IN' and order.company_id.partner_id.country_id.code == 'IN' is_india = order.partner_shipping_id.country_id.code == 'IN' and order.company_id.partner_id.country_id.code == 'IN'
est_weight_value = sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0 est_weight_value = sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0
weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit) weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit)
order_currency = order.currency_id order_currency = order.currency_id
else: elif not package:
# max_weight = self._fedex_convert_weight(self.fedex_default_packaging_id.max_weight, self.fedex_weight_unit)
is_india = picking.partner_id.country_id.code == 'IN' and picking.company_id.partner_id.country_id.code == 'IN' is_india = picking.partner_id.country_id.code == 'IN' and picking.company_id.partner_id.country_id.code == 'IN'
# TODO must be per-package eventually
# theoretically just sum of all packages weights, but the rating itself will also need to change...
est_weight_value = sum([(line.product_id.weight * (line.qty_done or line.product_uom_qty)) for line in picking.move_line_ids]) or 0.0 est_weight_value = sum([(line.product_id.weight * (line.qty_done or line.product_uom_qty)) for line in picking.move_line_ids]) or 0.0
weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit) weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit)
order_currency = picking.sale_id.currency_id if picking.sale_id else picking.company_id.currency_id order_currency = picking.sale_id.currency_id if picking.sale_id else picking.company_id.currency_id
else:
is_india = picking.partner_id.country_id.code == 'IN' and picking.company_id.partner_id.country_id.code == 'IN'
order_currency = picking.sale_id.currency_id if picking.sale_id else picking.company_id.currency_id
est_weight_value = self._fedex_convert_weight(package.shipping_weight or package.weight)
weight_value = self._fedex_convert_weight(est_weight_value, self.fedex_weight_unit)
price = 0.0 price = 0.0
@@ -493,7 +519,8 @@ class DeliveryFedex(models.Model):
acc_number = superself._get_fedex_account_number(order=order, picking=picking) acc_number = superself._get_fedex_account_number(order=order, picking=picking)
meter_number = superself._get_fedex_meter_number(order=order, picking=picking) meter_number = superself._get_fedex_meter_number(order=order, picking=picking)
order_name = superself.get_order_name(order=order, picking=picking) order_name = superself.get_order_name(order=order, picking=picking)
insurance_value = superself.get_insurance_value(order=order, picking=picking) insurance_value = superself.get_insurance_value(order=order, picking=picking, package=package)
signature_required = superself.get_signature_required(order=order, picking=picking, package=package)
residential = self._get_fedex_recipient_is_residential(recipient) residential = self._get_fedex_recipient_is_residential(recipient)
date_planned = fields.Datetime.now() date_planned = fields.Datetime.now()
if self.env.context.get('date_planned'): if self.env.context.get('date_planned'):
@@ -561,9 +588,29 @@ class DeliveryFedex(models.Model):
) )
srm.set_master_package(weight_value, 1) srm.set_master_package(weight_value, 1)
else: else:
for sequence, package in enumerate(picking.package_ids, start=1): if package:
package_weight = self._fedex_convert_weight(package.shipping_weight, self.fedex_weight_unit) package_weight = self._fedex_convert_weight(package.shipping_weight or package.weight, self.fedex_weight_unit)
packaging = package.packaging_id packaging = package.packaging_id
package_code = package.packaging_id.shipper_package_code if packaging.package_carrier_type == 'fedex' else self.fedex_default_packaging_id.shipper_package_code
srm.add_package(
package_weight,
mode='rating',
package_code=package_code,
package_height=packaging.height,
package_width=packaging.width,
package_length=packaging.length,
sequence_number=1,
# po_number=po_number,
# dept_number=dept_number,
ref=('%s-%d' % (order_name, 1)),
insurance=insurance_value,
signature_required=signature_required
)
else:
# deliver all together...
package_weight = self._fedex_convert_weight(picking.shipping_weight or picking.weight, self.fedex_weight_unit)
packaging = self.fedex_default_packaging_id
srm.add_package( srm.add_package(
package_weight, package_weight,
@@ -572,11 +619,12 @@ class DeliveryFedex(models.Model):
package_height=packaging.height, package_height=packaging.height,
package_width=packaging.width, package_width=packaging.width,
package_length=packaging.length, package_length=packaging.length,
sequence_number=sequence, sequence_number=1,
# po_number=po_number, # po_number=po_number,
# dept_number=dept_number, # dept_number=dept_number,
ref=('%s-%d' % (order_name, sequence)), ref=('%s-%d' % (order_name, 1)),
insurance=insurance_value insurance=insurance_value,
signature_required=signature_required
) )
@@ -646,6 +694,7 @@ class DeliveryFedex(models.Model):
tz = pytz.timezone(self.delivery_calendar_id.tz) tz = pytz.timezone(self.delivery_calendar_id.tz)
date_delivered = tz.localize(date_delivered).astimezone(pytz.utc).replace(tzinfo=None) date_delivered = tz.localize(date_delivered).astimezone(pytz.utc).replace(tzinfo=None)
result.append({'carrier': carrier, result.append({'carrier': carrier,
'package': package or self.env['stock.quant.package'].browse(),
'success': True, 'success': True,
'price': price, 'price': price,
'error_message': False, 'error_message': False,
@@ -665,3 +714,27 @@ class DeliveryFedex(models.Model):
('fedex_service_type', '=', service_code) ('fedex_service_type', '=', service_code)
], limit=1) ], limit=1)
return carrier return carrier
def fedex_cancel_shipment(self, picking):
request = FedexRequest(self.log_xml, request_type="shipping", prod_environment=self.prod_environment)
superself = self.sudo()
request.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password)
acc_number = superself._get_fedex_account_number(picking=picking)
meter_number = superself._get_fedex_meter_number(picking=picking)
request.client_detail(acc_number, meter_number)
request.transaction_detail(picking.id)
master_tracking_id = picking.carrier_tracking_ref.split(',')[0]
request.set_deletion_details(master_tracking_id)
result = request.delete_shipment()
warnings = result.get('warnings_message')
if warnings:
_logger.info(warnings)
if result.get('delete_success') and not result.get('errors_message'):
picking.message_post(body=_(u'Shipment N° %s has been cancelled' % master_tracking_id))
picking.write({'carrier_tracking_ref': '',
'carrier_price': 0.0})
else:
raise UserError(result['errors_message'])

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
import suds import suds
from datetime import datetime from datetime import datetime
from copy import deepcopy from copy import deepcopy
@@ -30,6 +32,7 @@ class FedexRequest(fedex_request.FedexRequest):
_service_transit_days = { _service_transit_days = {
'FEDEX_2_DAY': 2, 'FEDEX_2_DAY': 2,
'FEDEX_2_DAY_AM': 2, 'FEDEX_2_DAY_AM': 2,
'FEDEX_3_DAY_FREIGHT': 3,
'FIRST_OVERNIGHT': 1, 'FIRST_OVERNIGHT': 1,
'PRIORITY_OVERNIGHT': 1, 'PRIORITY_OVERNIGHT': 1,
'STANDARD_OVERNIGHT': 1, 'STANDARD_OVERNIGHT': 1,
@@ -72,12 +75,12 @@ class FedexRequest(fedex_request.FedexRequest):
self.RequestedShipment.Recipient.Contact = Contact self.RequestedShipment.Recipient.Contact = Contact
self.RequestedShipment.Recipient.Address = Address self.RequestedShipment.Recipient.Address = Address
def add_package(self, weight_value, package_code=False, package_height=0, package_width=0, package_length=0, sequence_number=False, mode='shipping', ref=False, insurance=False): def add_package(self, weight_value, package_code=False, package_height=0, package_width=0, package_length=0, sequence_number=False, mode='shipping', ref=False, insurance=False, signature_required=False):
# TODO remove in master and change the signature of a public method # TODO remove in master and change the signature of a public method
return self._add_package(weight_value=weight_value, package_code=package_code, package_height=package_height, package_width=package_width, return self._add_package(weight_value=weight_value, package_code=package_code, package_height=package_height, package_width=package_width,
package_length=package_length, sequence_number=sequence_number, mode=mode, po_number=False, dept_number=False, ref=ref, insurance=insurance) package_length=package_length, sequence_number=sequence_number, mode=mode, po_number=False, dept_number=False, ref=ref, insurance=insurance, signature_required=signature_required)
def _add_package(self, weight_value, package_code=False, package_height=0, package_width=0, package_length=0, sequence_number=False, mode='shipping', po_number=False, dept_number=False, ref=False, insurance=False): def _add_package(self, weight_value, package_code=False, package_height=0, package_width=0, package_length=0, sequence_number=False, mode='shipping', po_number=False, dept_number=False, ref=False, insurance=False, signature_required=False):
package = self.client.factory.create('RequestedPackageLineItem') package = self.client.factory.create('RequestedPackageLineItem')
package_weight = self.client.factory.create('Weight') package_weight = self.client.factory.create('Weight')
package_weight.Value = weight_value package_weight.Value = weight_value
@@ -96,6 +99,12 @@ class FedexRequest(fedex_request.FedexRequest):
insured.Currency = 'USD' insured.Currency = 'USD'
package.InsuredValue = insured package.InsuredValue = insured
special_service = self.client.factory.create("PackageSpecialServicesRequested")
signature_detail = self.client.factory.create("SignatureOptionDetail")
signature_detail.OptionType = 'DIRECT' if signature_required else 'NO_SIGNATURE_REQUIRED'
special_service.SignatureOptionDetail = signature_detail
package.SpecialServicesRequested = special_service
package.PhysicalPackaging = 'BOX' package.PhysicalPackaging = 'BOX'
if package_code == 'YOUR_PACKAGING': if package_code == 'YOUR_PACKAGING':
package.Dimensions.Height = package_height package.Dimensions.Height = package_height
@@ -200,6 +209,10 @@ class FedexRequest(fedex_request.FedexRequest):
# Hibou Delivery Planning # Hibou Delivery Planning
if hasattr(self.response.RateReplyDetails[0], 'DeliveryTimestamp') and self.response.RateReplyDetails[0].DeliveryTimestamp: if hasattr(self.response.RateReplyDetails[0], 'DeliveryTimestamp') and self.response.RateReplyDetails[0].DeliveryTimestamp:
formatted_response['date_delivered'] = self.response.RateReplyDetails[0].DeliveryTimestamp formatted_response['date_delivered'] = self.response.RateReplyDetails[0].DeliveryTimestamp
if hasattr(self.response.RateReplyDetails[0].CommitDetails[0], 'TransitTime'):
transit_days = self.response.RateReplyDetails[0].CommitDetails[0].TransitTime
transit_days = self._transit_days.get(transit_days, 0)
formatted_response['transit_days'] = transit_days
elif hasattr(self.response.RateReplyDetails[0], 'CommitDetails') and hasattr(self.response.RateReplyDetails[0].CommitDetails[0], 'CommitTimestamp'): elif hasattr(self.response.RateReplyDetails[0], 'CommitDetails') and hasattr(self.response.RateReplyDetails[0].CommitDetails[0], 'CommitTimestamp'):
formatted_response['date_delivered'] = self.response.RateReplyDetails[0].CommitDetails[0].CommitTimestamp formatted_response['date_delivered'] = self.response.RateReplyDetails[0].CommitDetails[0].CommitTimestamp
formatted_response['transit_days'] = self._service_transit_days.get(self.response.RateReplyDetails[0].CommitDetails[0].ServiceType, 0) formatted_response['transit_days'] = self._service_transit_days.get(self.response.RateReplyDetails[0].CommitDetails[0].ServiceType, 0)
@@ -219,9 +232,14 @@ class FedexRequest(fedex_request.FedexRequest):
# Hibou Delivery Planning # Hibou Delivery Planning
if hasattr(rate_reply_detail, 'DeliveryTimestamp') and rate_reply_detail.DeliveryTimestamp: if hasattr(rate_reply_detail, 'DeliveryTimestamp') and rate_reply_detail.DeliveryTimestamp:
res['date_delivered'] = rate_reply_detail.DeliveryTimestamp res['date_delivered'] = rate_reply_detail.DeliveryTimestamp
res['transit_days'] = self._service_transit_days.get(rate_reply_detail.ServiceType, 0)
if not res['transit_days'] and hasattr(rate_reply_detail.CommitDetails[0], 'TransitTime'):
transit_days = rate_reply_detail.CommitDetails[0].TransitTime
transit_days = self._transit_days.get(transit_days, 0)
res['transit_days'] = transit_days
elif hasattr(rate_reply_detail, 'CommitDetails') and hasattr(rate_reply_detail.CommitDetails[0], 'CommitTimestamp'): elif hasattr(rate_reply_detail, 'CommitDetails') and hasattr(rate_reply_detail.CommitDetails[0], 'CommitTimestamp'):
res['date_delivered'] = rate_reply_detail.CommitDetails[0].CommitTimestamp res['date_delivered'] = rate_reply_detail.CommitDetails[0].CommitTimestamp
res['transit_days'] = self._service_transit_days.get(rate_reply_detail.CommitDetails[0].ServiceType, 0) res['transit_days'] = self._service_transit_days.get(rate_reply_detail.ServiceType, 0)
elif hasattr(rate_reply_detail, 'CommitDetails') and hasattr(rate_reply_detail.CommitDetails[0], 'TransitTime'): elif hasattr(rate_reply_detail, 'CommitDetails') and hasattr(rate_reply_detail.CommitDetails[0], 'TransitTime'):
transit_days = rate_reply_detail.CommitDetails[0].TransitTime transit_days = rate_reply_detail.CommitDetails[0].TransitTime
transit_days = self._transit_days.get(transit_days, 0) transit_days = self._transit_days.get(transit_days, 0)

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models from odoo import api, fields, models

View File

@@ -1 +1,3 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import models from . import models

View File

@@ -1,10 +1,10 @@
{ {
'name': 'Golden State Overnight (gso.com) Shipping', 'name': 'Golden State Overnight (gso.com) Shipping',
'summary': 'Send your shippings through gso.com and track them online.', 'summary': 'Send your shippings through gso.com and track them online.',
'version': '11.0.1.0.0', 'version': '12.0.1.1.0',
'author': "Hibou Corp.", 'author': "Hibou Corp.",
'category': 'Warehouse', 'category': 'Warehouse',
'license': 'AGPL-3', 'license': 'OPL-1',
'images': [], 'images': [],
'website': "https://hibou.io", 'website': "https://hibou.io",
'description': """ 'description': """

View File

@@ -1 +1,3 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import delivery_gso from . import delivery_gso

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
import pytz import pytz
from math import ceil from math import ceil
from base64 import b64decode from base64 import b64decode
@@ -170,7 +172,7 @@ class ProviderGSO(models.Model):
company = self.get_shipper_company(picking=picking) company = self.get_shipper_company(picking=picking)
from_ = self.get_shipper_warehouse(picking=picking) from_ = self.get_shipper_warehouse(picking=picking)
to = self.get_recipient(picking=picking) to = self.get_recipient(picking=picking)
address_type = 'B' if bool(to.company or to.parent_id.company) else 'R' address_type = 'B' if bool(to.is_company or to.parent_id.is_company) else 'R'
request_body = { request_body = {
'AccountNumber': sudoself.gso_account_number, 'AccountNumber': sudoself.gso_account_number,
@@ -185,22 +187,34 @@ class ProviderGSO(models.Model):
request_body['Shipment'].update(self._gso_make_shipper_address(from_, company)) request_body['Shipment'].update(self._gso_make_shipper_address(from_, company))
request_body['Shipment'].update(self._gso_make_ship_address(to)) request_body['Shipment'].update(self._gso_make_ship_address(to))
# Automatic insurance at $100.0
insurance_value = sudoself.get_insurance_value(picking=picking)
if insurance_value:
request_body['Shipment']['SignatureCode'] = 'SIG_REQD'
if insurance_value > 100.0:
# Documentation says to set DeclaredValue ONLY if over $100.00
request_body['Shipment']['DeclaredValue'] = insurance_value
cost = 0.0 cost = 0.0
labels = { labels = {
'thermal': [], 'thermal': [],
'paper': [], 'paper': [],
} }
if picking.package_ids: picking_packages = picking.package_ids
package_carriers = picking_packages.mapped('carrier_id')
if package_carriers:
# only ship ours
picking_packages = picking_packages.filtered(lambda p: p.carrier_id == self and not p.carrier_tracking_ref)
if picking_packages:
# Every package will be a transaction # Every package will be a transaction
for package in picking.package_ids: for package in picking_packages:
# Use Sale Order Number or fall back to Picking
shipment_ref = (picking.sale_id.name if picking.sale_id else picking.name) + '-' + package.name
insurance_value = sudoself.get_insurance_value(picking=picking, package=package)
if insurance_value > 100.0:
# Documentation says to set DeclaredValue ONLY if over $100.00
request_body['Shipment']['DeclaredValue'] = insurance_value
elif 'DeclaredValue' in request_body['Shipment']:
del request_body['Shipment']['DeclaredValue']
if sudoself.get_signature_required(picking=picking, package=package):
request_body['Shipment']['SignatureCode'] = 'SIG_REQD'
else:
request_body['Shipment']['SignatureCode'] = 'SIG_NOT_REQD'
request_body['Shipment']['Weight'] = self._gso_convert_weight(package.shipping_weight) request_body['Shipment']['Weight'] = self._gso_convert_weight(package.shipping_weight)
request_body['Shipment'].update(self._gso_get_package_dimensions(package)) request_body['Shipment'].update(self._gso_get_package_dimensions(package))
request_body['Shipment']['ShipmentReference'] = package.name request_body['Shipment']['ShipmentReference'] = package.name
@@ -217,10 +231,12 @@ class ProviderGSO(models.Model):
cost += response['ShipmentCharges']['TotalCharge'] cost += response['ShipmentCharges']['TotalCharge']
except HTTPError as e: except HTTPError as e:
raise ValidationError(e) raise ValidationError(e)
else: elif not package_carriers:
# ship the whole picking
shipment_ref = picking.sale_id.name if picking.sale_id else picking.name
request_body['Shipment']['Weight'] = self._gso_convert_weight(picking.shipping_weight) request_body['Shipment']['Weight'] = self._gso_convert_weight(picking.shipping_weight)
request_body['Shipment'].update(self._gso_get_package_dimensions()) request_body['Shipment'].update(self._gso_get_package_dimensions())
request_body['Shipment']['ShipmentReference'] = picking.name request_body['Shipment']['ShipmentReference'] = shipment_ref
request_body['Shipment']['TrackingNumber'] = self._gso_create_tracking_number(picking.name) request_body['Shipment']['TrackingNumber'] = self._gso_create_tracking_number(picking.name)
try: try:
response = service.post_shipment(request_body) response = service.post_shipment(request_body)
@@ -234,6 +250,8 @@ class ProviderGSO(models.Model):
cost += response['ShipmentCharges']['TotalCharge'] cost += response['ShipmentCharges']['TotalCharge']
except HTTPError as e: except HTTPError as e:
raise ValidationError(e) raise ValidationError(e)
else:
continue
# Handle results # Handle results
trackings = [l[0] for l in labels['thermal']] + [l[0] for l in labels['paper']] trackings = [l[0] for l in labels['thermal']] + [l[0] for l in labels['paper']]
@@ -262,7 +280,7 @@ class ProviderGSO(models.Model):
} }
for tracking in picking.carrier_tracking_ref.split(','): for tracking in picking.carrier_tracking_ref.split(','):
request_body['TrackingNumber'] = tracking request_body['TrackingNumber'] = tracking
_ = service.delete_shipment(request_body) cancel_res = service.delete_shipment(request_body)
except HTTPError as e: except HTTPError as e:
raise ValidationError(e) raise ValidationError(e)
picking.message_post(body=_('Shipment N° %s has been cancelled') % (picking.carrier_tracking_ref, )) picking.message_post(body=_('Shipment N° %s has been cancelled') % (picking.carrier_tracking_ref, ))
@@ -273,7 +291,7 @@ class ProviderGSO(models.Model):
service = sudoself._get_gso_service() service = sudoself._get_gso_service()
from_ = sudoself.get_shipper_warehouse(order=order) from_ = sudoself.get_shipper_warehouse(order=order)
to = sudoself.get_recipient(order=order) to = sudoself.get_recipient(order=order)
address_type = 'B' if bool(to.company or to.parent_id.company) else 'R' address_type = 'B' if bool(to.is_company or to.parent_id.is_company) else 'R'
est_weight_value = self._gso_convert_weight( est_weight_value = self._gso_convert_weight(
sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0) sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0)
@@ -331,18 +349,32 @@ class ProviderGSO(models.Model):
res.append('https://www.gso.com/Tracking') res.append('https://www.gso.com/Tracking')
return res return res
def gso_rate_shipment_multi(self, order=None, picking=None): def gso_rate_shipment_multi(self, order=None, picking=None, packages=None):
if not packages:
return self._gso_rate_shipment_multi_package(order=order, picking=picking)
else:
rates = []
for package in packages:
rates += self._gso_rate_shipment_multi_package(order=order, picking=picking, package=package)
return rates
def _gso_rate_shipment_multi_package(self, order=None, picking=None, package=None):
sudoself = self.sudo() sudoself = self.sudo()
service = sudoself._get_gso_service() try:
service = sudoself._get_gso_service()
except HTTPError as e:
# _logger.error(e)
return [{
'success': False,
'price': 0.0,
'error_message': _('GSO web service returned an error. ' + str(e)),
'warning_message': False,
}]
from_ = sudoself.get_shipper_warehouse(order=order, picking=picking) from_ = sudoself.get_shipper_warehouse(order=order, picking=picking)
to = sudoself.get_recipient(order=order, picking=picking) to = sudoself.get_recipient(order=order, picking=picking)
address_type = 'B' if bool(to.is_company or to.parent_id.is_company) else 'R' address_type = 'B' if bool(to.is_company or to.parent_id.is_company) else 'R'
package_dimensions = self._gso_get_package_dimensions(package=package)
if order:
est_weight_value = self._gso_convert_weight(
sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0)
else:
est_weight_value = self._gso_convert_weight(picking.shipping_weight)
date_planned = fields.Datetime.now() date_planned = fields.Datetime.now()
if self.env.context.get('date_planned'): if self.env.context.get('date_planned'):
@@ -353,10 +385,13 @@ class ProviderGSO(models.Model):
ship_date_gso = ship_date_utc.astimezone(pytz.timezone(GSO_TZ)) ship_date_gso = ship_date_utc.astimezone(pytz.timezone(GSO_TZ))
ship_date_gso = fields.Datetime.to_string(ship_date_gso) ship_date_gso = fields.Datetime.to_string(ship_date_gso)
if picking and picking.package_ids: if order:
package_dimensions = self._gso_get_package_dimensions(package=picking.package_ids[0]) est_weight_value = self._gso_convert_weight(
sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0)
elif not package:
est_weight_value = self._gso_convert_weight(picking.shipping_weight)
else: else:
package_dimensions = self._gso_get_package_dimensions() est_weight_value = self._gso_convert_weight(package.shipping_weight or package.weight)
request_body = { request_body = {
'AccountNumber': sudoself.gso_account_number, 'AccountNumber': sudoself.gso_account_number,
@@ -372,7 +407,7 @@ class ProviderGSO(models.Model):
result = service.get_rates_and_transit_time(request_body) result = service.get_rates_and_transit_time(request_body)
# _logger.warn('GSO result:\n%s' % result) # _logger.warn('GSO result:\n%s' % result)
except HTTPError as e: except HTTPError as e:
_logger.error(e) # _logger.error(e)
return [{ return [{
'success': False, 'success': False,
'price': 0.0, 'price': 0.0,
@@ -395,6 +430,7 @@ class ProviderGSO(models.Model):
if carrier: if carrier:
rates.append({ rates.append({
'carrier': carrier, 'carrier': carrier,
'package': package or self.env['stock.quant.package'].browse(),
'success': True, 'success': True,
'price': price, 'price': price,
'error_message': False, 'error_message': False,

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
import requests import requests
from json import dumps from json import dumps

View File

@@ -1,7 +1,7 @@
{ {
'name': 'Delivery Hibou', 'name': 'Delivery Hibou',
'summary': 'Adds underlying pinnings for things like "RMA Return Labels"', 'summary': 'Adds underlying pinnings for things like "RMA Return Labels"',
'version': '11.0.1.0.0', 'version': '12.0.1.2.0',
'author': "Hibou Corp.", 'author': "Hibou Corp.",
'category': 'Stock', 'category': 'Stock',
'license': 'AGPL-3', 'license': 'AGPL-3',

View File

@@ -1,5 +1,7 @@
from odoo import api, fields, models from odoo import api, fields, models
from odoo.tools.float_utils import float_compare
from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES from odoo.addons.stock.models.stock_move import PROCUREMENT_PRIORITIES
from odoo.exceptions import UserError
class DeliveryCarrier(models.Model): class DeliveryCarrier(models.Model):
@@ -8,6 +10,9 @@ class DeliveryCarrier(models.Model):
automatic_insurance_value = fields.Float(string='Automatic Insurance Value', automatic_insurance_value = fields.Float(string='Automatic Insurance Value',
help='Will be used during shipping to determine if the ' help='Will be used during shipping to determine if the '
'picking\'s value warrants insurance being added.') 'picking\'s value warrants insurance being added.')
automatic_sig_req_value = fields.Float(string='Automatic Signature Required Value',
help='Will be used during shipping to determine if the '
'picking\'s value warrants signature required being added.')
procurement_priority = fields.Selection(PROCUREMENT_PRIORITIES, procurement_priority = fields.Selection(PROCUREMENT_PRIORITIES,
string='Procurement Priority', string='Procurement Priority',
help='Priority for this carrier. Will affect pickings ' help='Priority for this carrier. Will affect pickings '
@@ -15,7 +20,7 @@ class DeliveryCarrier(models.Model):
# Utility # Utility
def get_insurance_value(self, order=None, picking=None): def get_insurance_value(self, order=None, picking=None, package=None):
value = 0.0 value = 0.0
if order: if order:
if order.order_line: if order.order_line:
@@ -23,13 +28,34 @@ class DeliveryCarrier(models.Model):
else: else:
return value return value
if picking: if picking:
value = picking.declared_value() value = picking.declared_value(package=package)
if picking.require_insurance == 'no': if package and not package.require_insurance:
value = 0.0
elif picking.require_insurance == 'auto' and self.automatic_insurance_value and self.automatic_insurance_value > value:
value = 0.0 value = 0.0
else:
if picking.require_insurance == 'no':
value = 0.0
elif picking.require_insurance == 'auto' and self.automatic_insurance_value and self.automatic_insurance_value > value:
value = 0.0
return value return value
def get_signature_required(self, order=None, picking=None, package=None):
value = 0.0
if order:
if order.order_line:
value = sum(order.order_line.filtered(lambda l: l.product_id.type != 'service').mapped('price_subtotal'))
else:
return False
if picking:
value = picking.declared_value(package=package)
if package:
return package.require_signature
else:
if picking.require_signature == 'no':
return False
elif picking.require_signature == 'yes':
return True
return self.automatic_sig_req_value and value >= self.automatic_sig_req_value
def get_third_party_account(self, order=None, picking=None): def get_third_party_account(self, order=None, picking=None):
if order and order.shipping_account_id: if order and order.shipping_account_id:
return order.shipping_account_id return order.shipping_account_id
@@ -162,11 +188,12 @@ class DeliveryCarrier(models.Model):
# API for external providers # # API for external providers #
# -------------------------- # # -------------------------- #
@api.multi @api.multi
def rate_shipment_multi(self, order=None, picking=None): def rate_shipment_multi(self, order=None, picking=None, packages=None):
''' Compute the price of the order shipment ''' Compute the price of the order shipment
:param order: record of sale.order or None :param order: record of sale.order or None
:param picking: record of stock.picking or None :param picking: record of stock.picking or None
:param packages: recordset of stock.quant.package or None (requires picking also set)
:return list: dict: { :return list: dict: {
'carrier': delivery.carrier(), 'carrier': delivery.carrier(),
'success': boolean, 'success': boolean,
@@ -177,6 +204,7 @@ class DeliveryCarrier(models.Model):
'date_delivered': a datetime for when the shipment is supposed to arrive, 'date_delivered': a datetime for when the shipment is supposed to arrive,
'transit_days': a Float for how many days it takes in transit, 'transit_days': a Float for how many days it takes in transit,
'service_code': a string that represents the service level/agreement, 'service_code': a string that represents the service level/agreement,
'package': stock.quant.package(),
} }
e.g. self == delivery.carrier(5, 6) e.g. self == delivery.carrier(5, 6)
@@ -191,12 +219,107 @@ class DeliveryCarrier(models.Model):
if picking: if picking:
self = self.with_context(date_planned=fields.Datetime.now()) self = self.with_context(date_planned=fields.Datetime.now())
if not packages:
packages = picking.package_ids
else: else:
if packages:
raise UserError('Cannot rate package without picking.')
self = self.with_context(date_planned=(order.date_planned or fields.Datetime.now())) self = self.with_context(date_planned=(order.date_planned or fields.Datetime.now()))
res = [] res = []
for carrier in self: for carrier in self:
carrier_packages = packages and packages.filtered(lambda p: not p.carrier_tracking_ref and
(not p.carrier_id or p.carrier_id == carrier) and
p.packaging_id.package_carrier_type in (False, '', 'none', carrier.delivery_type))
if packages and not carrier_packages:
continue
if hasattr(carrier, '%s_rate_shipment_multi' % self.delivery_type): if hasattr(carrier, '%s_rate_shipment_multi' % self.delivery_type):
carrier_rates = getattr(carrier, '%s_rate_shipment_multi' % carrier.delivery_type)(order=order, picking=picking) try:
res += carrier_rates res += getattr(carrier, '%s_rate_shipment_multi' % carrier.delivery_type)(order=order,
picking=picking,
packages=carrier_packages)
except TypeError:
# TODO remove catch if after Odoo 14
# This is intended to find ones that don't support packages= kwarg
res += getattr(carrier, '%s_rate_shipment_multi' % carrier.delivery_type)(order=order,
picking=picking)
return res return res
def cancel_shipment(self, pickings, packages=None):
''' Cancel a shipment
:param pickings: A recordset of pickings
:param packages: Optional recordset of packages (should be for this carrier)
'''
self.ensure_one()
if hasattr(self, '%s_cancel_shipment' % self.delivery_type):
# No good way to tell if this method takes the kwarg for packages
if packages:
try:
return getattr(self, '%s_cancel_shipment' % self.delivery_type)(pickings, packages=packages)
except TypeError:
# we won't be able to cancel the packages properly
# here we will TRY to make a good call here where we put the package references into the picking
# and let the original mechanisms try to work here
tracking_ref = ','.join(packages.mapped('carrier_tracking_ref'))
pickings.write({
'carrier_id': self.id,
'carrier_tracking_ref': tracking_ref,
})
return getattr(self, '%s_cancel_shipment' % self.delivery_type)(pickings)
class ChooseDeliveryPackage(models.TransientModel):
_inherit = 'choose.delivery.package'
package_declared_value = fields.Float(string='Declared Value')
package_require_insurance = fields.Boolean(string='Require Insurance')
package_require_signature = fields.Boolean(string='Require Signature')
@api.model
def default_get(self, fields_list):
defaults = super().default_get(fields_list)
if 'package_declared_value' in fields_list:
if self.env.context.get('default_picking_id'):
picking_id = self.env.context.get('default_picking_id')
package_id = self.env.context.get('default_stock_quant_package_id')
picking = self.env['stock.picking'].browse(picking_id)
move_line_ids = picking.move_line_ids.filtered(lambda m:
float_compare(m.qty_done, 0.0, precision_rounding=m.product_uom_id.rounding) > 0
and (not m.result_package_id or m.result_package_id.id == package_id)
)
total_value = 0.0
for ml in move_line_ids:
qty = ml.product_uom_id._compute_quantity(ml.qty_done, ml.product_id.uom_id)
total_value += qty * ml.product_id.standard_price
defaults['package_declared_value'] = total_value
elif self.env.context.get('default_stock_quant_package_id'):
stock_quant_package = self.env['stock.quant.package'].browse(self.env.context['default_stock_quant_package_id'])
defaults['package_declared_value'] = stock_quant_package.declared_value
return defaults
@api.onchange('package_declared_value')
def _onchange_package_declared_value(self):
picking_id = self.env.context.get('default_picking_id')
if picking_id:
picking = self.env['stock.picking'].browse(picking_id)
value = self.package_declared_value
if picking.require_insurance == 'auto':
self.package_require_insurance = value and picking.carrier_id.automatic_insurance_value and value >= picking.carrier_id.automatic_insurance_value
else:
self.package_require_insurance = picking.require_insurance == 'yes'
if picking.require_signature == 'auto':
self.package_require_signature = value and picking.carrier_id.automatic_sig_req_value and value >= picking.carrier_id.automatic_sig_req_value
else:
self.package_require_signature = picking.require_signature == 'yes'
def put_in_pack(self):
super().put_in_pack()
if self.stock_quant_package_id:
self.stock_quant_package_id.write({
'declared_value': self.package_declared_value,
'require_insurance': self.package_require_insurance,
'require_signature': self.package_require_signature,
})

View File

@@ -1,18 +1,68 @@
from odoo import api, fields, models from odoo import api, fields, models, _
from odoo.exceptions import UserError from odoo.exceptions import UserError
class StockQuantPackage(models.Model):
_inherit = 'stock.quant.package'
carrier_id = fields.Many2one('delivery.carrier', string='Carrier')
carrier_tracking_ref = fields.Char(string='Tracking Reference')
require_insurance = fields.Boolean(string='Require Insurance')
require_signature = fields.Boolean(string='Require Signature')
declared_value = fields.Float(string='Declared Value')
def _get_active_picking(self):
picking_id = self._context.get('active_id')
picking_model = self._context.get('active_model')
if not picking_id or picking_model != 'stock.picking':
picking_id = self._context.get('picking_active_id')
picking_model = self._context.get('picking_active_model')
if not picking_id or picking_model != 'stock.picking':
raise UserError('Cannot cancel package other than through shipment/picking.')
return self.env['stock.picking'].browse(picking_id)
def send_to_shipper(self):
picking = self._get_active_picking()
picking.with_context(packages=self).send_to_shipper()
def cancel_shipment(self):
picking = self._get_active_picking()
picking.with_context(packages=self).cancel_shipment()
class StockPicking(models.Model): class StockPicking(models.Model):
_inherit = 'stock.picking' _inherit = 'stock.picking'
shipping_account_id = fields.Many2one('partner.shipping.account', string='Shipping Account') shipping_account_id = fields.Many2one('partner.shipping.account', string='Shipping Account')
commercial_partner_id = fields.Many2one('res.partner', related='partner_id.commercial_partner_id')
require_insurance = fields.Selection([ require_insurance = fields.Selection([
('auto', 'Automatic'), ('auto', 'Automatic'),
('yes', 'Yes'), ('yes', 'Yes'),
('no', 'No'), ('no', 'No'),
], string='Require Insurance', default='auto', ], string='Require Insurance', default='auto',
help='If your carrier supports it, auto should be calculated off of the "Automatic Insurance Value" field.') help='If your carrier supports it, auto should be calculated off of the "Automatic Insurance Value" field.')
commercial_partner_id = fields.Many2one('res.partner', related='partner_id.commercial_partner_id') require_signature = fields.Selection([
('auto', 'Automatic'),
('yes', 'Yes'),
('no', 'No'),
], string='Require Signature', default='auto',
help='If your carrier supports it, auto should be calculated off of the "Automatic Signature Required Value" field.')
package_carrier_tracking_ref = fields.Char(string='Package Tracking Numbers', compute='_compute_package_carrier_tracking_ref')
@api.depends('package_ids.carrier_tracking_ref')
def _compute_package_carrier_tracking_ref(self):
for picking in self:
package_refs = picking.package_ids.filtered('carrier_tracking_ref').mapped('carrier_tracking_ref')
if package_refs:
picking.package_carrier_tracking_ref = ','.join(package_refs)
else:
picking.package_carrier_tracking_ref = False
@api.onchange('carrier_id')
def _onchange_carrier_id_for_priority(self):
for picking in self:
if picking.carrier_id and picking.carrier_id.procurement_priority:
picking.priority = picking.carrier_id.procurement_priority
@api.multi @api.multi
def button_test_rate_multi(self): def button_test_rate_multi(self):
@@ -33,18 +83,104 @@ class StockPicking(models.Model):
so = self.env['sale.order'].search([('name', '=', str(origin))], limit=1) so = self.env['sale.order'].search([('name', '=', str(origin))], limit=1)
if so and so.shipping_account_id: if so and so.shipping_account_id:
values['shipping_account_id'] = so.shipping_account_id.id values['shipping_account_id'] = so.shipping_account_id.id
carrier_id = values.get('carrier_id')
if carrier_id:
carrier = self.env['delivery.carrier'].browse(carrier_id)
if carrier.procurement_priority:
values['priority'] = carrier.procurement_priority
res = super(StockPicking, self).create(values) res = super(StockPicking, self).create(values)
return res return res
def declared_value(self): def declared_value(self, package=None):
self.ensure_one() self.ensure_one()
if package:
return package.declared_value
cost = sum([(l.product_id.standard_price * l.qty_done) for l in self.move_line_ids] or [0.0]) cost = sum([(l.product_id.standard_price * l.qty_done) for l in self.move_line_ids] or [0.0])
if not cost: if not cost:
# Assume Full Value # Assume Full Value
cost = sum([(l.product_id.standard_price * l.product_uom_qty) for l in self.move_lines] or [0.0]) cost = sum([(l.product_id.standard_price * l.product_uom_qty) for l in self.move_lines] or [0.0])
return cost return cost
def clear_carrier_tracking_ref(self):
self.write({'carrier_tracking_ref': False})
def reset_carrier_tracking_ref(self):
for picking in self:
picking.carrier_tracking_ref = picking.package_carrier_tracking_ref
# Override to send to specific packaging carriers
def send_to_shipper(self):
packages = self._context.get('packages')
self.ensure_one()
if not packages:
packages = self.package_ids
package_carriers = packages.mapped('carrier_id')
if not package_carriers:
# Original behavior
return super().send_to_shipper()
tracking_numbers = []
carrier_prices = []
order_currency = self.sale_id.currency_id or self.company_id.currency_id
for carrier in package_carriers:
self.carrier_id = carrier
carrier_packages = packages.filtered(lambda p: p.carrier_id == carrier)
res = carrier.send_shipping(self)
if res:
res = res[0]
if carrier.free_over and self.sale_id and self.sale_id._compute_amount_total_without_delivery() >= carrier.amount:
res['exact_price'] = 0.0
carrier_price = float(res['exact_price']) * (1.0 + (self.carrier_id.margin / 100.0))
carrier_prices.append(carrier_price)
tracking_number = ''
if res['tracking_number']:
tracking_number = res['tracking_number']
tracking_numbers.append(tracking_number)
# Try to add tracking to the individual packages.
potential_tracking_numbers = tracking_number.split(',')
if len(potential_tracking_numbers) == 1:
potential_tracking_numbers = tracking_number.split('+') # UPS for example...
if len(potential_tracking_numbers) >= len(carrier_packages):
for t, p in zip(potential_tracking_numbers, carrier_packages):
p.carrier_tracking_ref = t
else:
carrier_packages.write({'carrier_tracking_ref': tracking_number})
msg = _("Shipment sent to carrier %s for shipping with tracking number %s<br/>Cost: %.2f %s") % (carrier.name, tracking_number, carrier_price, order_currency.name)
self.message_post(body=msg)
self.carrier_price = sum(carrier_prices or [0.0])
self.carrier_tracking_ref = ','.join(tracking_numbers or [''])
# Override to provide per-package versions...
def cancel_shipment(self):
packages = self._context.get('packages')
pickings_with_package_tracking = self.filtered(lambda p: p.package_carrier_tracking_ref)
for picking in pickings_with_package_tracking:
if packages:
current_packages = packages
else:
current_packages = picking.package_ids
# Packages without a carrier can just be cleared
packages_without_carrier = current_packages.filtered(lambda p: not p.carrier_id and p.carrier_tracking_ref)
packages_without_carrier.write({
'carrier_tracking_ref': False,
})
# Packages with carrier can use the carrier method
packages_with_carrier = current_packages.filtered(lambda p: p.carrier_id and p.carrier_tracking_ref)
carriers = packages_with_carrier.mapped('carrier_id')
for carrier in carriers:
carrier_packages = packages_with_carrier.filtered(lambda p: p.carrier_id == carrier)
carrier.cancel_shipment(self, packages=carrier_packages)
package_refs = ','.join(carrier_packages.mapped('carrier_tracking_ref'))
msg = "Shipment %s cancelled" % package_refs
picking.message_post(body=msg)
carrier_packages.write({'carrier_tracking_ref': False})
pickings_without_package_tracking = self - pickings_with_package_tracking
if pickings_without_package_tracking:
# use original on these
super(StockPicking, pickings_without_package_tracking).cancel_shipment()
class StockMove(models.Model): class StockMove(models.Model):

View File

@@ -24,12 +24,14 @@ class TestDeliveryHibou(common.TransactionCase):
def test_delivery_hibou(self): def test_delivery_hibou(self):
# Assign a new shipping account # Assign a new shipping account
self.partner.shipping_account_id = self.shipping_account self.partner.shipping_account_ids = self.shipping_account
# Assign values to new Carrier # Assign values to new Carrier
test_insurance_value = 600 test_insurance_value = 600
test_procurement_priority = '2' test_sig_req_value = 300
test_procurement_priority = '1'
self.carrier.automatic_insurance_value = test_insurance_value self.carrier.automatic_insurance_value = test_insurance_value
self.carrier.automatic_sig_req_value = test_sig_req_value
self.carrier.procurement_priority = test_procurement_priority self.carrier.procurement_priority = test_procurement_priority
@@ -71,7 +73,9 @@ class TestDeliveryHibou(common.TransactionCase):
def test_carrier_hibou_out(self): def test_carrier_hibou_out(self):
test_insurance_value = 4000 test_insurance_value = 4000
test_sig_req_value = 4000
self.carrier.automatic_insurance_value = test_insurance_value self.carrier.automatic_insurance_value = test_insurance_value
self.carrier.automatic_sig_req_value = test_sig_req_value
picking_out = self.env.ref('stock.outgoing_shipment_main_warehouse') picking_out = self.env.ref('stock.outgoing_shipment_main_warehouse')
picking_out.action_assign() picking_out.action_assign()
@@ -88,21 +92,29 @@ class TestDeliveryHibou(common.TransactionCase):
# The 'value' is assumed to be all of the product value from the initial demand. # The 'value' is assumed to be all of the product value from the initial demand.
self.assertEqual(picking_out.declared_value(), 15.0 * 3300.0) self.assertEqual(picking_out.declared_value(), 15.0 * 3300.0)
self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), picking_out.declared_value()) self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), picking_out.declared_value())
self.assertTrue(picking_out.carrier_id.get_signature_required(picking=picking_out))
# Workflow where user explicitly opts out of insurance on the picking level. # Workflow where user explicitly opts out of insurance on the picking level.
picking_out.require_insurance = 'no' picking_out.require_insurance = 'no'
picking_out.require_signature = 'no'
self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 0.0) self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 0.0)
self.assertFalse(picking_out.carrier_id.get_signature_required(picking=picking_out))
picking_out.require_insurance = 'auto' picking_out.require_insurance = 'auto'
picking_out.require_signature = 'auto'
# Lets choose to only delivery one piece at the moment. # Lets choose to only delivery one piece at the moment.
# This does not meet the minimum on the carrier to have insurance value. # This does not meet the minimum on the carrier to have insurance value.
picking_out.move_line_ids.qty_done = 1.0 picking_out.move_line_ids.qty_done = 1.0
self.assertEqual(picking_out.declared_value(), 3300.0) self.assertEqual(picking_out.declared_value(), 3300.0)
self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 0.0) self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 0.0)
self.assertFalse(picking_out.carrier_id.get_signature_required(picking=picking_out))
# Workflow where user opts in to insurance. # Workflow where user opts in to insurance.
picking_out.require_insurance = 'yes' picking_out.require_insurance = 'yes'
picking_out.require_signature = 'yes'
self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 3300.0) self.assertEqual(picking_out.carrier_id.get_insurance_value(picking=picking_out), 3300.0)
self.assertTrue(picking_out.carrier_id.get_signature_required(picking=picking_out))
picking_out.require_insurance = 'auto' picking_out.require_insurance = 'auto'
picking_out.require_signature = 'auto'
# Test with picking having 3rd party account. # Test with picking having 3rd party account.
self.assertEqual(picking_out.carrier_id.get_third_party_account(picking=picking_out), None) self.assertEqual(picking_out.carrier_id.get_third_party_account(picking=picking_out), None)

View File

@@ -7,8 +7,26 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='integration_level']" position="after"> <xpath expr="//field[@name='integration_level']" position="after">
<field name="automatic_insurance_value"/> <field name="automatic_insurance_value"/>
<field name="automatic_sig_req_value"/>
<field name="procurement_priority"/> <field name="procurement_priority"/>
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="choose_delivery_package_view_form" model="ir.ui.view">
<field name="name">hibou.choose.delivery.package.form</field>
<field name="model">choose.delivery.package</field>
<field name="inherit_id" ref="delivery.choose_delivery_package_view_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='delivery_packaging_id']" position="attributes">
<attribute name="domain">[('product_id', '=', False)]</attribute>
</xpath>
<xpath expr="//field[@name='delivery_packaging_id']" position="after">
<field name="package_declared_value" />
<field name="package_require_insurance" />
<field name="package_require_signature" />
</xpath>
</field>
</record>
</odoo> </odoo>

View File

@@ -1,17 +1,53 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<record id="hibou_view_quant_package_form" model="ir.ui.view">
<field name="name">hibou.stock.quant.package.form</field>
<field name="model">stock.quant.package</field>
<field name="inherit_id" ref="stock.view_quant_package_form" />
<field name="arch" type="xml">
<xpath expr="//field[@name='location_id']" position="after">
<label for="carrier_id"/>
<div name="carrier">
<field name="carrier_id" class="oe_inline"/>
<button type="object" class="fa fa-arrow-right oe_link" name="send_to_shipper" string="Ship" attrs="{'invisible':['|',('carrier_tracking_ref','!=',False),('carrier_id','=', False)]}"/>
</div>
<label for="carrier_tracking_ref"/>
<div name="tracking">
<field name="carrier_tracking_ref" class="oe_inline" />
<button type="object" class="fa fa-arrow-right oe_link" name="cancel_shipment" string="Cancel" attrs="{'invisible':['|',('carrier_tracking_ref','=',False),('carrier_id','=', False)]}"/>
</div>
<field name="declared_value" />
<field name="require_insurance" />
<field name="require_signature" />
</xpath>
</field>
</record>
<record id="view_picking_withcarrier_out_form" model="ir.ui.view"> <record id="view_picking_withcarrier_out_form" model="ir.ui.view">
<field name="name">hibou.delivery.stock.picking_withcarrier.form.view</field> <field name="name">hibou.delivery.stock.picking_withcarrier.form.view</field>
<field name="model">stock.picking</field> <field name="model">stock.picking</field>
<field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form" /> <field name="inherit_id" ref="delivery.view_picking_withcarrier_out_form" />
<field name="priority" eval="200" />
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='carrier_id']" position="before"> <xpath expr="//field[@name='carrier_id']" position="before">
<field name="commercial_partner_id" invisible="1" /> <field name="commercial_partner_id" invisible="1" />
<field name="require_insurance" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/> <field name="require_insurance" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
<field name="require_signature" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"/>
<field name="shipping_account_id" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}" <field name="shipping_account_id" attrs="{'readonly': [('state', 'in', ('done', 'cancel'))]}"
options="{'no_create': True, 'no_open': True}" options="{'no_create': True, 'no_open': True}"
domain="[('partner_id', 'in', (False, partner_id, commercial_partner_id))]"/> domain="[('partner_id', 'in', (False, partner_id, commercial_partner_id))]"/>
<field name="package_carrier_tracking_ref" attrs="{'invisible': [('package_carrier_tracking_ref', '=', False)]}" />
<button name="clear_carrier_tracking_ref" type="object" string="Clear Tracking" attrs="{'invisible': [('carrier_tracking_ref', '!=', False)]}" />
<button name="reset_carrier_tracking_ref" type="object" string="Reset Tracking" attrs="{'invisible': [('package_carrier_tracking_ref', '!=', False)]}" />
<field name="package_ids" attrs="{'invisible': [('package_carrier_tracking_ref', '=', False)]}" nolabel="1" colspan="2">
<tree>
<field name="name" />
<field name="carrier_id" />
<field name="carrier_tracking_ref" />
<button type="object" name="cancel_shipment" string="Cancel" context="{'picking_active_id': parent.id, 'picking_active_model': 'stock.picking'}" />
</tree>
</field>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -3,7 +3,7 @@
{ {
'name': 'Stamps.com (USPS) Shipping', 'name': 'Stamps.com (USPS) Shipping',
'summary': 'Send your shippings through Stamps.com and track them online.', 'summary': 'Send your shippings through Stamps.com and track them online.',
'version': '12.0.2.0.1', 'version': '12.0.2.1.1',
'author': "Hibou Corp.", 'author': "Hibou Corp.",
'category': 'Warehouse', 'category': 'Warehouse',
'license': 'OPL-1', 'license': 'OPL-1',

View File

@@ -145,11 +145,13 @@ class ProviderStamps(models.Model):
ret_val.ContentType = self._stamps_content_type() ret_val.ContentType = self._stamps_content_type()
return ret_val return ret_val
def _get_stamps_shipping_multi(self, service, date_planned, order=False, picking=False): def _get_stamps_shipping_multi(self, service, date_planned, order=False, picking=False, package=False):
if order: if order:
weight = sum([(line.product_id.weight * line.product_qty) for line in order.order_line]) or 0.0 weight = sum([(line.product_id.weight * line.product_qty) for line in order.order_line]) or 0.0
else: elif not package:
weight = picking.shipping_weight weight = picking.shipping_weight
else:
weight = package.shipping_weight or package.weight
weight = self._stamps_convert_weight(weight) weight = self._stamps_convert_weight(weight)
shipper = self.get_shipper_warehouse(order=order, picking=picking) shipper = self.get_shipper_warehouse(order=order, picking=picking)
@@ -162,7 +164,7 @@ class ProviderStamps(models.Model):
ret_val.ShipDate = date_planned.strftime('%Y-%m-%d') if date_planned else date.today().isoformat() ret_val.ShipDate = date_planned.strftime('%Y-%m-%d') if date_planned else date.today().isoformat()
ret_val.From = self._stamps_address(service, shipper) ret_val.From = self._stamps_address(service, shipper)
ret_val.To = self._stamps_address(service, recipient) ret_val.To = self._stamps_address(service, recipient)
ret_val.PackageType = self._stamps_package_type() ret_val.PackageType = self._stamps_package_type(package=package)
ret_val.WeightLb = weight ret_val.WeightLb = weight
ret_val.ContentType = 'Merchandise' ret_val.ContentType = 'Merchandise'
return ret_val return ret_val
@@ -204,7 +206,13 @@ class ProviderStamps(models.Model):
if not all((from_partner.zip, to_partner.zip)): if not all((from_partner.zip, to_partner.zip)):
raise ValidationError('Stamps needs ZIP/PostalCode. From: ' + str(from_partner.zip) + ' To: ' + str(to_partner.zip)) raise ValidationError('Stamps needs ZIP/PostalCode. From: ' + str(from_partner.zip) + ' To: ' + str(to_partner.zip))
for package in picking.package_ids: picking_packages = picking.package_ids
package_carriers = picking_packages.mapped('carrier_id')
if package_carriers:
# only ship ours
picking_packages = picking_packages.filtered(lambda p: p.carrier_id == self and not p.carrier_tracking_ref)
for package in picking_packages:
weight = self._stamps_convert_weight(package.shipping_weight) weight = self._stamps_convert_weight(package.shipping_weight)
l, w, h = self._stamps_package_dimensions(package=package) l, w, h = self._stamps_package_dimensions(package=package)
@@ -221,7 +229,7 @@ class ProviderStamps(models.Model):
ret_val.WeightLb = weight ret_val.WeightLb = weight
ret_val.ContentType = self._stamps_content_type(package=package) ret_val.ContentType = self._stamps_content_type(package=package)
ret.append((package.name + ret_val.ShipDate + str(ret_val.WeightLb) + self._stamps_hash_partner(to_partner), ret_val)) ret.append((package.name + ret_val.ShipDate + str(ret_val.WeightLb) + self._stamps_hash_partner(to_partner), ret_val))
if not ret: if not ret and not package_carriers:
weight = self._stamps_convert_weight(picking.shipping_weight) weight = self._stamps_convert_weight(picking.shipping_weight)
l, w, h = self._stamps_package_dimensions() l, w, h = self._stamps_package_dimensions()
@@ -310,6 +318,8 @@ class ProviderStamps(models.Model):
package_labels = [] package_labels = []
shippings = self._stamps_get_shippings_for_picking(service, picking) shippings = self._stamps_get_shippings_for_picking(service, picking)
if not shippings:
continue
company, from_partner, to_partner = self._stamps_get_addresses_for_picking(picking) company, from_partner, to_partner = self._stamps_get_addresses_for_picking(picking)
customs = None customs = None
@@ -451,14 +461,23 @@ class ProviderStamps(models.Model):
except WebFault as e: except WebFault as e:
raise ValidationError(e) raise ValidationError(e)
def stamps_rate_shipment_multi(self, order=None, picking=None): def stamps_rate_shipment_multi(self, order=None, picking=None, packages=None):
if not packages:
return self._stamps_rate_shipment_multi_package(order=order, picking=picking)
else:
rates = []
for package in packages:
rates += self._stamps_rate_shipment_multi_package(order=order, picking=picking, package=package)
return rates
def _stamps_rate_shipment_multi_package(self, order=None, picking=None, package=None):
self.ensure_one() self.ensure_one()
date_planned = fields.Datetime.now() date_planned = fields.Datetime.now()
if self.env.context.get('date_planned'): if self.env.context.get('date_planned'):
date_planned = self.env.context.get('date_planned') date_planned = self.env.context.get('date_planned')
res = [] res = []
service = self._get_stamps_service() service = self._get_stamps_service()
shipping = self._get_stamps_shipping_multi(service, date_planned, order=order, picking=picking) shipping = self._get_stamps_shipping_multi(service, date_planned, order=order, picking=picking, package=package)
rates = service.get_rates(shipping) rates = service.get_rates(shipping)
for rate in rates: for rate in rates:
price = float(rate.Amount) price = float(rate.Amount)
@@ -484,6 +503,7 @@ class ProviderStamps(models.Model):
if carrier: if carrier:
res.append({ res.append({
'carrier': carrier, 'carrier': carrier,
'package': package or self.env['stock.quant.package'].browse(),
'success': True, 'success': True,
'price': price, 'price': price,
'error_message': False, 'error_message': False,

View File

@@ -32,7 +32,7 @@
<field name="model">product.packaging</field> <field name="model">product.packaging</field>
<field name="inherit_id" ref="delivery.product_packaging_delivery_form"/> <field name="inherit_id" ref="delivery.product_packaging_delivery_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='max_weight']" position='after'> <xpath expr="//field[@name='barcode']" position='before'>
<field name="stamps_cubic_pricing"/> <field name="stamps_cubic_pricing"/>
</xpath> </xpath>
</field> </field>

View File

@@ -1 +1,3 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import models from . import models

View File

@@ -1,15 +1,16 @@
{ {
'name': 'Hibou UPS Shipping', 'name': 'Hibou UPS Shipping',
'version': '12.0.1.0.0', 'version': '12.0.1.2.0',
'category': 'Stock', 'category': 'Stock',
'author': "Hibou Corp.", 'author': "Hibou Corp.",
'license': 'AGPL-3', 'license': 'OPL-1',
'website': 'https://hibou.io/', 'website': 'https://hibou.io/',
'depends': [ 'depends': [
'delivery_ups', 'delivery_ups',
'delivery_hibou', 'delivery_hibou',
], ],
'data': [ 'data': [
'views/stock_views.xml',
], ],
'demo': [ 'demo': [
], ],

View File

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

View File

@@ -0,0 +1,318 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/IF/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:ups="http://www.ups.com/XMLSchema" xmlns:IF="http://www.ups.com/XMLSchema/XOLTWS/IF/v1.0" elementFormDefault="qualified" version="201801">
<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="30"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CN22ContentType">
<xsd:sequence>
<xsd:element name="CN22ContentQuantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentDescription" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentWeight" type="IF:ProductWeightType" minOccurs="0"/>
<xsd:element name="CN22ContentTotalValue" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentCurrencyCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentCountryOfOrigin" type="xsd:string" minOccurs="0"/>
<xsd:element name="CN22ContentTariffNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ContactType">
<xsd:sequence>
<xsd:element name="ForwardAgent" type="IF:ForwardAgentType" minOccurs="0"/>
<xsd:element name="UltimateConsignee" type="IF:UltimateConsigneeType" minOccurs="0"/>
<xsd:element name="IntermediateConsignee" type="IF:IntermediateConsigneeType" minOccurs="0"/>
<xsd:element name="Producer" type="IF:ProducerType" minOccurs="0"/>
<xsd:element name="SoldTo" type="IF:SoldToType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ForwardAgentType">
<xsd:sequence>
<xsd:element name="CompanyName" type="xsd:string"/>
<xsd:element name="TaxIdentificationNumber" type="xsd:string"/>
<xsd:element name="Address" type="IF:AddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element name="AddressLine" type="xsd:string" maxOccurs="3"/>
<xsd:element name="City" type="xsd:string"/>
<xsd:element name="StateProvinceCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="Town" type="xsd:string" minOccurs="0"/>
<xsd:element name="PostalCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="CountryCode" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UltimateConsigneeType">
<xsd:sequence>
<xsd:element name="CompanyName" type="xsd:string"/>
<xsd:element name="Address" type="IF:AddressType"/>
<xsd:element name="UltimateConsigneeType" type="IF:UltimateConsigneeTypeType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="IntermediateConsigneeType">
<xsd:sequence>
<xsd:element name="CompanyName" type="xsd:string"/>
<xsd:element name="Address" type="IF:AddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ProducerType">
<xsd:sequence>
<xsd:element name="Option" type="xsd:string" minOccurs="0"/>
<xsd:element name="CompanyName" type="xsd:string" minOccurs="0"/>
<xsd:element name="TaxIdentificationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="IF:AddressType" minOccurs="0"/>
<xsd:element name="AttentionName" type="xsd:string" minOccurs="0"/>
<xsd:element name="Phone" type="IF:PhoneType" minOccurs="0"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ProductType">
<xsd:sequence>
<xsd:element name="Description" type="xsd:string" maxOccurs="3"/>
<xsd:element name="Unit" type="IF:UnitType" minOccurs="0"/>
<xsd:element name="CommodityCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="PartNumber" type="xsd:string" minOccurs="0" ups:usage="notused"/>
<xsd:element name="OriginCountryCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="JointProductionIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="NetCostCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="NetCostDateRange" type="IF:NetCostDateType" minOccurs="0"/>
<xsd:element name="PreferenceCriteria" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProducerInfo" type="xsd:string" minOccurs="0"/>
<xsd:element name="MarksAndNumbers" type="xsd:string" minOccurs="0"/>
<xsd:element name="NumberOfPackagesPerCommodity" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProductWeight" type="IF:ProductWeightType" minOccurs="0"/>
<xsd:element name="VehicleID" type="xsd:string" minOccurs="0"/>
<xsd:element name="ScheduleB" type="IF:ScheduleBType" minOccurs="0"/>
<xsd:element name="ExportType" type="xsd:string" minOccurs="0"/>
<xsd:element name="SEDTotalValue" type="xsd:string" minOccurs="0"/>
<xsd:element name="ExcludeFromForm" type="IF:ExcludeFromFormType" minOccurs="0"/>
<xsd:element name="ProductCurrencyCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackingListInfo" type="IF:PackingListInfoType" minOccurs="0"/>
<xsd:element name="EEIInformation" type="IF:EEIInformationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ExcludeFromFormType">
<xsd:sequence>
<xsd:element name="FormType" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UnitType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string"/>
<xsd:element name="UnitOfMeasurement" type="IF:UnitOfMeasurementType"/>
<xsd:element name="Value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackingListInfoType">
<xsd:sequence>
<xsd:element name="PackageAssociated" type="IF:PackageAssociatedType" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PackageAssociatedType">
<xsd:sequence>
<xsd:element name="PackageNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProductAmount" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UnitOfMeasurementType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NetCostDateType">
<xsd:sequence>
<xsd:element name="BeginDate" type="xsd:string"/>
<xsd:element name="EndDate" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ProductWeightType">
<xsd:sequence>
<xsd:element name="UnitOfMeasurement" type="IF:UnitOfMeasurementType"/>
<xsd:element name="Weight" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ScheduleBType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string"/>
<xsd:element name="Quantity" type="xsd:string" minOccurs="0" maxOccurs="2"/>
<xsd:element name="UnitOfMeasurement" type="IF:UnitOfMeasurementType" maxOccurs="2"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="IFChargesType">
<xsd:sequence>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="OtherChargesType">
<xsd:sequence>
<xsd:element name="MonetaryValue" type="xsd:string"/>
<xsd:element name="Description" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="BlanketPeriodType">
<xsd:sequence>
<xsd:element name="BeginDate" type="xsd:string"/>
<xsd:element name="EndDate" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LicenseType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string" minOccurs="0"/>
<xsd:element name="Date" type="xsd:string" minOccurs="0"/>
<xsd:element name="ExceptionCode" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="SoldToType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string"/>
<xsd:element name="AttentionName" type="xsd:string"/>
<xsd:element name="TaxIdentificationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Phone" type="IF:PhoneType" minOccurs="0"/>
<xsd:element name="Option" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="IF:AddressType"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PhoneType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string"/>
<xsd:element name="Extension" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DDTCInformationType">
<xsd:sequence>
<xsd:element name="ITARExemptionNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="USMLCategoryCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="EligiblePartyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="RegistrationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Quantity" type="xsd:string" minOccurs="0"/>
<xsd:element name="UnitOfMeasurement" type="IF:UnitOfMeasurementType"/>
<xsd:element name="SignificantMilitaryEquipmentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ACMNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="EEILicenseType">
<xsd:sequence>
<xsd:element name="Number" type="xsd:string" minOccurs="0"/>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="LicenseLineValue" type="xsd:string" minOccurs="0"/>
<xsd:element name="ECCNNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="EEIFilingOptionType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="EMailAddress" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
<xsd:element name="UPSFiled" type="IF:UPSFiledType" minOccurs="0"/>
<xsd:element name="ShipperFiled" type="IF:ShipperFiledType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UPSFiledType">
<xsd:sequence>
<xsd:element name="POA" type="IF:POAType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipperFiledType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
<xsd:element name="PreDepartureITNNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="ExemptionLegend" type="xsd:string" minOccurs="0"/>
<xsd:element name="EEIShipmentReferenceNumber" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="EEIInformationType">
<xsd:sequence>
<xsd:element name="ExportInformation" type="xsd:string" minOccurs="0"/>
<xsd:element name="License" type="IF:EEILicenseType" minOccurs="0"/>
<xsd:element name="DDTCInformation" type="IF:DDTCInformationType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="POAType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UltimateConsigneeTypeType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/LBRecovery/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:lbrec="http://www.ups.com/XMLSchema/XOLTWS/LBRecovery/v1.0" xmlns:ups="http://www.ups.com/XMLSchema" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" elementFormDefault="qualified" version="201707">
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" schemaLocation="common.xsd"/>
<xsd:element name="LabelRecoveryRequest">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Request"/>
<xsd:element name="LabelSpecification" type="lbrec:LabelSpecificationType" minOccurs="0"/>
<xsd:element name="Translate" type="lbrec:TranslateType" minOccurs="0"/>
<xsd:element name="LabelDelivery" type="lbrec:LabelDeliveryType" minOccurs="0"/>
<xsd:element name="TrackingNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="MailInnovationsTrackingNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="ReferenceValues" type="lbrec:ReferenceValuesType" minOccurs="0"/>
<xsd:element name="UPSPremiumCareForm" type="lbrec:LRUPSPremiumCareFormType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="ReferenceValuesType">
<xsd:sequence>
<xsd:element name="ReferenceNumber" type="lbrec:ReferenceNumberType"/>
<xsd:element name="ShipperNumber" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ReferenceNumberType">
<xsd:sequence>
<xsd:element name="Value" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelSpecificationType">
<xsd:sequence>
<xsd:element name="HTTPUserAgent" type="xsd:string" minOccurs="0"/>
<xsd:element name="LabelImageFormat" type="lbrec:LabelImageFormatType" minOccurs="0"/>
<xsd:element name="LabelStockSize" type="lbrec:LabelStockSizeType" 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="LabelImageFormatType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TranslateType">
<xsd:sequence>
<xsd:element name="LanguageCode" type="xsd:string"/>
<xsd:element name="DialectCode" type="xsd:string"/>
<xsd:element name="Code" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelDeliveryType">
<xsd:sequence>
<xsd:element name="LabelLinkIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="LabelRecoveryResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="common:Response"/>
<xsd:element name="ShipmentIdentificationNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="CODTurnInPage" type="lbrec:ResponseImageType" minOccurs="0"/>
<xsd:element name="Form" type="lbrec:FormType" minOccurs="0"/>
<xsd:element name="HighValueReport" type="lbrec:HighValueReportType" minOccurs="0"/>
<xsd:choice minOccurs="0" maxOccurs="unbounded">
<xsd:element name="LabelResults" type="lbrec:LabelResultsType"/>
<xsd:element name="TrackingCandidate" type="lbrec:TrackingCandidateType"/>
</xsd:choice>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="LabelResultsType">
<xsd:sequence>
<xsd:element name="TrackingNumber" type="xsd:string"/>
<xsd:element name="LabelImage" type="lbrec:LabelImageType"/>
<xsd:element name="Receipt" type="lbrec:ReceiptType" minOccurs="0"/>
<xsd:element name="Form" type="lbrec:FormType" minOccurs="0"/>
<xsd:element name="MailInnovationsTrackingNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="MailInnovationsLabelImage" type="lbrec:LabelImageType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LabelImageType">
<xsd:sequence>
<xsd:element name="LabelImageFormat" type="lbrec:LabelImageFormatType"/>
<xsd:element name="GraphicImage" type="xsd:string"/>
<xsd:element name="HTMLImage" type="xsd:string" minOccurs="0"/>
<xsd:element name="PDF417" type="xsd:string" minOccurs="0"/>
<xsd:element name="InternationalSignatureGraphicImage" type="xsd:string" minOccurs="0"/>
<xsd:element name="URL" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ReceiptType">
<xsd:sequence>
<xsd:element name="HTMLImage" type="xsd:string" minOccurs="0"/>
<xsd:element name="Image" type="lbrec:ImageType" minOccurs="0"/>
<xsd:element name="URL" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ImageType">
<xsd:sequence>
<xsd:element name="ImageFormat" type="lbrec:LabelImageFormatType" minOccurs="0"/>
<xsd:element name="GraphicImage" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TrackingCandidateType">
<xsd:sequence>
<xsd:element name="TrackingNumber" type="xsd:string"/>
<xsd:element name="DestinationPostalCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="DestinationCountryCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="PickupDateRange" type="lbrec:PickupDateRangeType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PickupDateRangeType">
<xsd:sequence>
<xsd:element name="BeginDate" type="xsd:string"/>
<xsd:element name="EndDate" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ResponseImageType">
<xsd:sequence>
<xsd:element name="Image" type="lbrec:ResponseImageDetailType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ResponseImageDetailType">
<xsd:sequence>
<xsd:element name="ImageFormat" type="lbrec:ImageFormatCodeType"/>
<xsd:element name="GraphicImage" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ImageFormatCodeType">
<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="FormType">
<xsd:sequence>
<xsd:element name="Image" type="lbrec:FormImageType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FormImageType">
<xsd:sequence>
<xsd:element name="ImageFormat" type="lbrec:ImageFormatCodeType"/>
<xsd:element name="GraphicImage" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HighValueReportType">
<xsd:sequence>
<xsd:element name="Image" type="lbrec:HVRImageType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HVRImageType">
<xsd:sequence>
<xsd:element name="ImageFormat" type="lbrec:ImageFormatCodeType"/>
<xsd:element name="GraphicImage" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="LRUPSPremiumCareFormType">
<xsd:sequence>
<xsd:element name="PageSize" type="xsd:string"/>
<xsd:element name="PrintType" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,54 @@
<?xml version="1.0" encoding="UTF-8"?>
<wsdl:definitions name="LabelRecovery" 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:lbrec="http://www.ups.com/XMLSchema/XOLTWS/LBRecovery/v1.0" xmlns:tns="http://www.ups.com/WSDL/XOLTWS/LBRecovery/v1.0" targetNamespace="http://www.ups.com/WSDL/XOLTWS/LBRecovery/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"/>
<!-- ################## Start MCEnrollment Specific schema ################### -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/LBRecovery/v1.0" schemaLocation="LBRecovery.xsd"/>
<!-- ################## End MCEnrollment specific schema ##################### -->
</xsd:schema>
</wsdl:types>
<wsdl:message name="LabelRecoveryRequestMessage">
<wsdl:part name="Body" element="lbrec:LabelRecoveryRequest"/>
<wsdl:part name="UPSSecurity" element="upss:UPSSecurity"/>
</wsdl:message>
<wsdl:message name="LabelRecoveryResponseMessage">
<wsdl:part name="Body" element="lbrec:LabelRecoveryResponse"/>
</wsdl:message>
<wsdl:message name="LabelRecoveryErrorMessage">
<wsdl:part name="LabelRecoveryError" element="error:Errors"/>
</wsdl:message>
<wsdl:portType name="PortType">
<wsdl:operation name="ProcessLabelRecovery">
<wsdl:input name="LabelRecoveryRequest" message="tns:LabelRecoveryRequestMessage"/>
<wsdl:output name="LabelRecoveryResponse" message="tns:LabelRecoveryResponseMessage"/>
<wsdl:fault name="LabelRecoveryError" message="tns:LabelRecoveryErrorMessage"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="LabelRecoveryBinding" type="tns:PortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="ProcessLabelRecovery">
<soap:operation soapAction="http://onlinetools.ups.com/webservices/ShipBinding/v1.1" style="document"/>
<wsdl:input name="LabelRecoveryRequest">
<soap:body parts="Body" use="literal"/>
<soap:header message="tns:LabelRecoveryRequestMessage" part="UPSSecurity" use="literal">
<soap:headerfault message="tns:LabelRecoveryErrorMessage" part="LabelRecoveryError" use="literal"/>
</soap:header>
</wsdl:input>
<wsdl:output name="LabelRecoveryResponse">
<soap:body parts="Body" use="literal"/>
</wsdl:output>
<wsdl:fault name="LabelRecoveryError">
<soap:fault name="LabelRecoveryError" use="literal"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="LBRecovery">
<wsdl:port name="Port" binding="tns:LabelRecoveryBinding">
<soap:address location="https://wwwcie.ups.com/webservices/LBRecovery"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

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

View File

@@ -0,0 +1,644 @@
<xsd:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1" xmlns:ups="http://www.ups.com/XMLSchema" xmlns:rate="http://www.ups.com/XMLSchema/XOLTWS/Rate/v1.1" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" version="201801">
<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 name="CustomerClassification" type="rate:CodeDescriptionType" minOccurs="0"/>
<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 name="RatedShipment" type="rate:RatedShipmentType" maxOccurs="unbounded"/>
</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 name="TransportationCharges" type="rate:ChargesType" minOccurs="0"/>
<xsd:element name="BaseServiceCharge" type="rate:ChargesType" minOccurs="0"/>
<xsd:element name="ServiceOptionsCharges" type="rate:ChargesType" minOccurs="0"/>
<xsd:element name="TotalCharges" type="rate:ChargesType" minOccurs="0"/>
<xsd:element name="Weight" type="xsd:string" minOccurs="0"/>
<xsd:element name="BillingWeight" type="rate:BillingWeightType" minOccurs="0"/>
<xsd:element name="Accessorial" type="rate:AccessorialType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="ItemizedCharges" type="rate:ChargesType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="NegotiatedCharges" type="rate: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="NegotiatedChargesType">
<xsd:sequence>
<xsd:element name="ItemizedCharges" type="rate:ChargesType" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RatedShipmentType">
<xsd:sequence>
<xsd:element name="Disclaimer" type="rate:DisclaimerType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="Service" type="rate:CodeDescriptionType"/>
<xsd:element name="RateChart" type="xsd:string" minOccurs="0"/>
<xsd:element name="RatedShipmentAlert" type="rate:RatedShipmentInfoType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="BillableWeightCalculationMethod" type="xsd:string" minOccurs="0"/>
<xsd:element name="RatingMethod" type="xsd:string" minOccurs="0"/>
<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 name="ItemizedCharges" type="rate:ChargesType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="FRSShipmentData" type="rate:FRSShipmentType" minOccurs="0"/>
<xsd:element name="ServiceOptionsCharges" type="rate:ChargesType"/>
<xsd:element name="TaxCharges" type="rate:TaxChargeType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="TotalCharges" type="rate:ChargesType"/>
<xsd:element name="TotalChargesWithTaxes" type="rate:ChargesType" minOccurs="0"/>
<xsd:element name="NegotiatedRateCharges" type="rate:TotalChargeType" minOccurs="0"/>
<xsd:element name="GuaranteedDelivery" type="rate:GuaranteedDeliveryType" minOccurs="0"/>
<xsd:element name="RatedPackage" type="rate:RatedPackageType" maxOccurs="unbounded"/>
<xsd:element name="TimeInTransit" type="rate:TimeInTransitResponseType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ReturnContractServicesType">
<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="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="AutoDutyCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="Disclaimer" type="xsd:string" minOccurs="0"/>
<xsd:element name="ServiceSummary" type="rate:ServiceSummaryType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ServiceSummaryType">
<xsd:sequence>
<xsd:element name="Service" type="rate:CodeDescriptionType"/>
<xsd:element name="EstimatedArrival" type="rate:EstimatedArrivalType"/>
<xsd:element name="GuaranteedIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Disclaimer" type="xsd:string" minOccurs="0"/>
<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 name="MonetaryValue" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="TotalChargeType">
<xsd:sequence>
<xsd:element name="ItemizedCharges" type="rate:ChargesType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="TaxCharges" type="rate:TaxChargeType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="TotalCharge" type="rate:ChargesType"/>
<xsd:element name="TotalChargesWithTaxes" type="rate:ChargesType" minOccurs="0"/>
</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 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="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 name="FreightDensityRate" type="rate:FreightDensityRateType" minOccurs="0"/>
<xsd:element name="HandlingUnits" type="rate:HandlingUnitsResponseType" minOccurs="0" maxOccurs="unbounded"/>
</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 name="AdjustedHeight" type="rate:AdjustedHeightType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="AddressType">
<xsd:sequence>
<xsd:element name="AddressLine" type="xsd:string" minOccurs="0" maxOccurs="3"/>
<xsd:element name="City" type="xsd:string" minOccurs="0"/>
<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="ShipToAddressType">
<xsd:complexContent>
<xsd:extension base="rate:AddressType">
<xsd:sequence>
<xsd:element name="ResidentialAddressIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
<xsd:complexType name="ShipAddressType">
<xsd:complexContent>
<xsd:extension base="rate:AddressType">
<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 name="Length" type="xsd:string" minOccurs="0"/>
<xsd:element name="Width" type="xsd:string" minOccurs="0"/>
<xsd:element name="Height" type="xsd:string" minOccurs="0"/>
</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 name="PackagingType" type="rate:CodeDescriptionType" minOccurs="0"/>
<xsd:element name="Dimensions" type="rate:DimensionsType" minOccurs="0"/>
<xsd:element name="DimWeight" type="rate:PackageWeightType" minOccurs="0"/>
<xsd:element name="PackageWeight" type="rate:PackageWeightType" minOccurs="0"/>
<xsd:element name="Commodity" type="rate:CommodityType" minOccurs="0"/>
<xsd:element name="LargePackageIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackageServiceOptions" type="rate:PackageServiceOptionsType" minOccurs="0"/>
<xsd:element name="AdditionalHandlingIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="UPSPremier" type="rate:UPSPremierType" minOccurs="0"/>
<xsd:element name="OversizeIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="MinimumBillableWeightIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CommodityType">
<xsd:sequence>
<xsd:element name="FreightClass" type="xsd:string"/>
<xsd:element name="NMFC" type="rate:NMFCCommodityType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="NMFCCommodityType">
<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="PackageServiceOptionsType">
<xsd:sequence>
<xsd:element name="DeliveryConfirmation" type="rate:DeliveryConfirmationType" minOccurs="0"/>
<xsd:element name="AccessPointCOD" type="rate:PackageServiceOptionsAccessPointCODType" minOccurs="0"/>
<xsd:element name="COD" type="rate:CODType" minOccurs="0"/>
<xsd:element name="DeclaredValue" type="rate:InsuredValueType" minOccurs="0"/>
<xsd:element name="ShipperDeclaredValue" type="rate:ShipperDeclaredValueType" minOccurs="0"/>
<xsd:element name="ShipperReleaseIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ProactiveIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="RefrigerationIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Insurance" type="rate:InsuranceType" minOccurs="0"/>
<xsd:element name="UPSPremiumCareIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="HazMat" type="rate:HazMatType" minOccurs="0"/>
<xsd:element name="DryIce" type="rate:DryIceType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UPSPremierType">
<xsd:sequence>
<xsd:element name="Category" type="xsd:string"/>
</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 name="MedicalUseIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="AuditRequired" type="xsd:string" minOccurs="0"/>
</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 name="BasicFlexibleParcelIndicator" type="rate:InsuranceValueType" minOccurs="0"/>
<xsd:element name="ExtendedFlexibleParcelIndicator" type="rate:InsuranceValueType" minOccurs="0"/>
<xsd:element name="TimeInTransitFlexibleParcelIndicator" type="rate:InsuranceValueType" minOccurs="0"/>
</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 name="Code" type="xsd:string" minOccurs="0"/>
<xsd:element name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CodeDescriptionType">
<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="ShipmentRatingOptionsType">
<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="UserLevelDiscountIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="TPFCNegotiatedRatesIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipFromType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string" minOccurs="0"/>
<xsd:element name="AttentionName" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="rate:ShipAddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipToType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string" minOccurs="0"/>
<xsd:element name="AttentionName" type="xsd:string" minOccurs="0"/>
<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 name="ShipFrom" type="rate:ShipFromType" minOccurs="0"/>
<xsd:element name="AlternateDeliveryAddress" type="rate:AlternateDeliveryAddressType" minOccurs="0"/>
<xsd:element name="ShipmentIndicationType" type="rate:IndicationType" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="PaymentDetails" type="rate:PaymentDetailsType" minOccurs="0"/>
<xsd:element name="FRSPaymentInformation" type="rate:FRSPaymentInfoType" minOccurs="0"/>
<xsd:element name="FreightShipmentInformation" type="rate:FreightShipmentInformationType" minOccurs="0"/>
<xsd:element name="GoodsNotInFreeCirculationIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Service" type="rate:CodeDescriptionType" minOccurs="0"/>
<xsd:element name="NumOfPieces" type="xsd:string" minOccurs="0"/>
<xsd:element name="ShipmentTotalWeight" type="rate:ShipmentWeightType" minOccurs="0"/>
<xsd:element name="DocumentsOnlyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Package" type="rate:PackageType" maxOccurs="unbounded"/>
<xsd:element name="ShipmentServiceOptions" type="rate:ShipmentServiceOptionsType" minOccurs="0"/>
<xsd:element name="ShipmentRatingOptions" type="rate:ShipmentRatingOptionsType" minOccurs="0"/>
<xsd:element name="InvoiceLineTotal" type="rate:InvoiceLineTotalType" 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="rate:PromotionalDiscountInformationType" minOccurs="0"/>
<xsd:element name="DeliveryTimeInformation" type="rate:TimeInTransitRequestType" minOccurs="0"/>
<xsd:element name="MasterCartonIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="WWEShipmentIndicator" type="xsd:string" 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:element name="ReturnContractServices" type="rate:ReturnContractServicesType" minOccurs="0" maxOccurs="unbounded"/>
</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 name="Name" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="rate:ADRType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ADRType">
<xsd:sequence>
<xsd:element name="AddressLine" type="xsd:string" minOccurs="0" maxOccurs="3"/>
<xsd:element name="City" type="xsd:string" minOccurs="0"/>
<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:element name="ResidentialAddressIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="POBoxIndicator" 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="ShipmentServiceOptionsType">
<xsd:sequence>
<xsd:element name="SaturdayPickupIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="SaturdayDeliveryIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="AccessPointCOD" type="rate:ShipmentServiceOptionsAccessPointCODType" minOccurs="0"/>
<xsd:element name="DeliverToAddresseeOnlyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="DirectDeliveryOnlyIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="COD" type="rate:CODType" minOccurs="0"/>
<xsd:element name="DeliveryConfirmation" type="rate:DeliveryConfirmationType" minOccurs="0"/>
<xsd:element name="ReturnOfDocumentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="UPScarbonneutralIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="CertificateOfOriginIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PickupOptions" type="rate:PickupOptionsType" minOccurs="0"/>
<xsd:element name="DeliveryOptions" type="rate:DeliveryOptionsType" minOccurs="0"/>
<xsd:element name="RestrictedArticles" type="rate:RestrictedArticlesType" minOccurs="0"/>
<xsd:element name="ShipperExportDeclarationIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="CommercialInvoiceRemovalIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ImportControl" type="rate:ImportControlType" minOccurs="0"/>
<xsd:element name="ReturnService" type="rate:ReturnServiceType" minOccurs="0"/>
<xsd:element name="SDLShipmentIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="EPRAIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="InsideDelivery" type="xsd:string" minOccurs="0"/>
<xsd:element name="ItemDisposalIndicator" type="xsd:string" minOccurs="0"/>
</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 name="Description" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ImportControlType">
<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="RestrictedArticlesType">
<xsd:sequence>
<xsd:element name="AlcoholicBeveragesIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="DiagnosticSpecimensIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PerishablesIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PlantsIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="SeedsIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="SpecialExceptionsIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="TobaccoIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ECigarettesIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="HempCBDIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PickupOptionsType">
<xsd:sequence>
<xsd:element name="LiftGateAtPickupIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="HoldForPickupIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="DeliveryOptionsType">
<xsd:sequence>
<xsd:element name="LiftGateAtDeliveryIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="DropOffAtUPSFacilityIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="ShipperType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string" minOccurs="0"/>
<xsd:element name="AttentionName" type="xsd:string" minOccurs="0"/>
<xsd:element name="ShipperNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="rate:AddressType"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="GuaranteedDeliveryType">
<xsd:sequence>
<xsd:element name="BusinessDaysInTransit" type="xsd:string" minOccurs="0"/>
<xsd:element name="DeliveryByTime" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FRSPaymentInfoType">
<xsd:sequence>
<xsd:element name="Type" type="rate:CodeDescriptionType"/>
<xsd:element name="AccountNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="Address" type="rate:PayerAddressType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="FreightShipmentInformationType">
<xsd:sequence>
<xsd:element name="FreightDensityInfo" type="rate:FreightDensityInfoType" minOccurs="0"/>
<xsd:element name="DensityEligibleIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="PayerAddressType">
<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="FreightDensityInfoType">
<xsd:sequence>
<xsd:element name="AdjustedHeightIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="AdjustedHeight" type="rate:AdjustedHeightType" minOccurs="0"/>
<xsd:element name="HandlingUnits" type="rate:HandlingUnitsType" maxOccurs="unbounded"/>
</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 name="CurrencyCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="MonetaryValue" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

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

View File

@@ -0,0 +1,933 @@
<?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="201801">
<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="CostCenterBarcodeIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackageID" type="xsd:string" minOccurs="0"/>
<xsd:element name="PackageIDBarcodeIndicator" 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="DGSignatoryInfo" type="ship:DGSignatoryInfoType" minOccurs="0"/>
<xsd:element name="MasterCartonID" type="xsd:string" minOccurs="0"/>
<xsd:element name="MasterCartonIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="Locale" type="xsd:string" minOccurs="0"/>
<xsd:element name="ShipmentValueThresholdCode" type="xsd:string" 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:element name="VendorInfo" type="ship:VendorInfoType" 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:element name="InsideDelivery" type="xsd:string" minOccurs="0"/>
<xsd:element name="ItemDisposal" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="RestrictedArticlesType">
<xsd:sequence>
<xsd:element name="DiagnosticSpecimensIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="AlcoholicBeveragesIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PerishablesIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="PlantsIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="SeedsIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="SpecialExceptionsIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="TobaccoIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="ECigarettesIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="HempCBDIndicator" 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="PalletDescription" type="xsd:string" minOccurs="0"/>
<xsd:element name="NumOfPieces" type="xsd:string" minOccurs="0"/>
<xsd:element name="UnitPrice" 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="5"/>
<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:element name="SimpleRate" type="ship:CodeDescriptionType" minOccurs="0"/>
<xsd:element name="UPSPremier" type="ship:UPSPremierType" minOccurs="0"/>
<xsd:element name="OversizeIndicator" type="xsd:string" minOccurs="0"/>
<xsd:element name="MinimumBillableWeightIndicator" type="xsd:string" 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="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:element name="RefrigerationIndicator" 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="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:element name="DGPaperImage" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
<xsd:element name="MasterCartonID" 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:element name="SimpleRate" type="ship:SimpleRateType" minOccurs="0"/>
<xsd:element name="SensorID" type="xsd:string" 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="GraphicImagePart" type="xsd:string" minOccurs="0" maxOccurs="unbounded"/>
<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:element name="OuterPackagingType" 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:element name="LocalTechnicalName" type="xsd:string" minOccurs="0"/>
<xsd:element name="LocalProperShippingName" 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:complexType name="DGSignatoryInfoType">
<xsd:sequence>
<xsd:element name="Name" type="xsd:string" minOccurs="0"/>
<xsd:element name="Title" type="xsd:string" minOccurs="0"/>
<xsd:element name="Place" type="xsd:string" minOccurs="0"/>
<xsd:element name="Date" type="xsd:string" minOccurs="0"/>
<xsd:element name="ShipperDeclaration" type="xsd:string" minOccurs="0"/>
<xsd:element name="UploadOnlyIndicator" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="UPSPremierType">
<xsd:sequence>
<xsd:element name="Category" type="xsd:string"/>
<xsd:element name="SensorID" type="xsd:string" minOccurs="0"/>
<xsd:element name="HandlingInstructions" type="ship:HandlingInstructionsType" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="HandlingInstructionsType">
<xsd:sequence>
<xsd:element name="Instruction" type="xsd:string" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="CodeDescriptionType">
<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="SimpleRateType">
<xsd:sequence>
<xsd:element name="Code" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
<xsd:complexType name="VendorInfoType">
<xsd:sequence>
<xsd:element name="VendorCollectIDTypeCode" type="xsd:string" minOccurs="0"/>
<xsd:element name="VendorCollectIDNumber" type="xsd:string" minOccurs="0"/>
<xsd:element name="ConsigneeType" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>

View File

@@ -0,0 +1,58 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- UPS Time In Transit Service WSDL Release Date Dec 29, 2007 -->
<!-- Copyright 2007-2008 United Parcel Service of America, Inc. All rights reserved. -->
<wsdl:definitions name="TimeInTransit" 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:tnt="http://www.ups.com/XMLSchema/XOLTWS/tnt/v1.0" xmlns:tns="http://www.ups.com/WSDL/XOLTWS/TNT/v1.0" targetNamespace="http://www.ups.com/WSDL/XOLTWS/TNT/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 TimeInTransit service data types -->
<xsd:import namespace="http://www.ups.com/XMLSchema/XOLTWS/tnt/v1.0" schemaLocation="TimeInTransitWebServiceSchema.xsd"/>
</xsd:schema>
</wsdl:types>
<wsdl:message name="TimeInTransitRequestMessage">
<wsdl:part name="Body" element="tnt:TimeInTransitRequest"/>
<wsdl:part name="UPSSecurity" element="upss:UPSSecurity"/>
</wsdl:message>
<wsdl:message name="TimeInTransitResponseMessage">
<wsdl:part name="Body" element="tnt:TimeInTransitResponse"/>
</wsdl:message>
<wsdl:message name="TimeInTransitErrorMessage">
<wsdl:part name="TimeInTransitError" element="error:Errors"/>
</wsdl:message>
<wsdl:portType name="TimeInTransitPortType">
<wsdl:operation name="ProcessTimeInTransit">
<wsdl:input name="TimeInTransitRequest" message="tns:TimeInTransitRequestMessage"/>
<wsdl:output name="TimeInTransitResponse" message="tns:TimeInTransitResponseMessage"/>
<wsdl:fault name="TimeInTransitError" message="tns:TimeInTransitErrorMessage"/>
</wsdl:operation>
</wsdl:portType>
<wsdl:binding name="TimeInTransitBinding" type="tns:TimeInTransitPortType">
<soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
<wsdl:operation name="ProcessTimeInTransit">
<soap:operation soapAction="http://onlinetools.ups.com/webservices/TimeInTransitBinding/v1.0" style="document"/>
<wsdl:input name="TimeInTransitRequest">
<soap:body parts="Body" use="literal"/>
<soap:header message="tns:TimeInTransitRequestMessage" part="UPSSecurity" use="literal">
<soap:headerfault message="tns:TimeInTransitErrorMessage" part="TimeInTransitError" use="literal"/>
</soap:header>
</wsdl:input>
<wsdl:output name="TimeInTransitResponse">
<soap:body parts="Body" use="literal"/>
</wsdl:output>
<wsdl:fault name="TimeInTransitError">
<soap:fault name="TimeInTransitError" use="literal"/>
</wsdl:fault>
</wsdl:operation>
</wsdl:binding>
<wsdl:service name="TimeInTransitService">
<wsdl:port name="TimeInTransitPort" binding="tns:TimeInTransitBinding">
<!-- Production URL -->
<!-- <soap:address location="https://onlinetools.ups.com/webservices/TimeInTransit"/> -->
<!-- CIE (Customer Integration Environment) URL -->
<soap:address location="https://wwwcie.ups.com/webservices/TimeInTransit"/>
</wsdl:port>
</wsdl:service>
</wsdl:definitions>

View File

@@ -0,0 +1,193 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xs:schema targetNamespace="http://www.ups.com/XMLSchema/XOLTWS/tnt/v1.0" xmlns:common="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tnt="http://www.ups.com/XMLSchema/XOLTWS/tnt/v1.0" elementFormDefault="qualified">
<xs:import namespace="http://www.ups.com/XMLSchema/XOLTWS/Common/v1.0" schemaLocation="common.xsd"/>
<!--++++++++++++++++++++Start of Common for Request & Response++++++++++++++++++++-->
<xs:complexType name="ResponseShipListAddressType">
<xs:sequence>
<xs:element name="Town" type="xs:string" minOccurs="0"/>
<xs:element name="City" type="xs:string"/>
<xs:element name="StateProvinceCode" type="xs:string" minOccurs="0"/>
<xs:element name="CountryCode" type="xs:string"/>
<xs:element name="PostcodePrimaryLow" type="xs:string" minOccurs="0"/>
<xs:element name="PostcodePrimaryHigh" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RequestShipFromAddressType">
<xs:sequence>
<xs:element name="Town" type="xs:string" minOccurs="0"/>
<xs:element name="City" type="xs:string" minOccurs="0"/>
<xs:element name="StateProvinceCode" type="xs:string" minOccurs="0"/>
<xs:element name="CountryCode" type="xs:string"/>
<xs:element name="PostalCode" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RequestShipToAddressType">
<xs:complexContent>
<xs:extension base="tnt:RequestShipFromAddressType">
<xs:sequence>
<xs:element name="ResidentialAddressIndicator" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="ResponseShipFromAddressType">
<xs:sequence>
<xs:element name="Town" type="xs:string" minOccurs="0"/>
<xs:element name="City" type="xs:string"/>
<xs:element name="StateProvinceCode" type="xs:string" minOccurs="0"/>
<xs:element name="CountryCode" type="xs:string"/>
<xs:element name="Country" type="xs:string"/>
<xs:element name="PostalCode" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ResponseShipToAddressType">
<xs:complexContent>
<xs:extension base="tnt:ResponseShipFromAddressType">
<xs:sequence>
<xs:element name="ResidentialAddressIndicator" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="RequestShipFromType">
<xs:sequence>
<xs:element name="Address" type="tnt:RequestShipFromAddressType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="RequestShipToType">
<xs:sequence>
<xs:element name="Address" type="tnt:RequestShipToAddressType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ResponseShipFromType">
<xs:sequence>
<xs:element name="Address" type="tnt:ResponseShipFromAddressType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ResponseShipToType">
<xs:sequence>
<xs:element name="Address" type="tnt:ResponseShipToAddressType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ShipmentWeightType">
<xs:sequence>
<xs:element name="UnitOfMeasurement" type="tnt:CodeDescriptionType"/>
<xs:element name="Weight" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="CodeDescriptionType">
<xs:sequence>
<xs:element name="Code" type="xs:string"/>
<xs:element name="Description" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="PickupType">
<xs:sequence>
<xs:element name="Date" type="xs:string"/>
<xs:element name="Time" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="InvoiceLineTotalType">
<xs:sequence>
<xs:element name="CurrencyCode" type="xs:string"/>
<xs:element name="MonetaryValue" type="xs:string"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ReturnContractServicesType">
<xs:sequence>
<xs:element name="Code" type="xs:string"/>
<xs:element name="Description" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<!--++++++++++++++++++++End of Common for Request & Response +++++++++++++++++++++-->
<!--++++++++++++++++++Start Request++++++++++++++++-->
<xs:element name="TimeInTransitRequest">
<xs:complexType>
<xs:sequence>
<xs:element ref="common:Request"/>
<xs:element name="ShipFrom" type="tnt:RequestShipFromType"/>
<xs:element name="ShipTo" type="tnt:RequestShipToType"/>
<xs:element name="Pickup" type="tnt:PickupType"/>
<xs:element name="ShipmentWeight" type="tnt:ShipmentWeightType" minOccurs="0"/>
<xs:element name="TotalPackagesInShipment" type="xs:string" minOccurs="0"/>
<xs:element name="InvoiceLineTotal" type="tnt:InvoiceLineTotalType" minOccurs="0"/>
<xs:element name="DocumentsOnlyIndicator" type="xs:string" minOccurs="0"/>
<xs:element name="BillType" type="xs:string" minOccurs="0"/>
<xs:element name="MaximumListSize" type="xs:string" minOccurs="0"/>
<xs:element name="SaturdayDeliveryInfoRequestIndicator" type="xs:string" minOccurs="0"/>
<xs:element name="DropOffAtFacilityIndicator" type="xs:string" minOccurs="0"/>
<xs:element name="HoldForPickupIndicator" type="xs:string" minOccurs="0"/>
<xs:element name="IncludeAllServicesIndicator" type="xs:string" minOccurs="0" tnt:usage="ups"/>
<xs:element name="ReturnContractServices" type="tnt:ReturnContractServicesType" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--++++++++++++++++++++End of Request +++++++++++++++++++++-->
<!--++++++++++++++++++++Start Response+++++++++++++++++++++-->
<xs:complexType name="EstimatedArrivalType">
<xs:sequence>
<xs:element name="Arrival" type="tnt:PickupType"/>
<xs:element name="BusinessDaysInTransit" type="xs:string"/>
<xs:element name="Pickup" type="tnt:PickupType"/>
<xs:element name="DayOfWeek" type="xs:string" minOccurs="0"/>
<xs:element name="CustomerCenterCutoff" type="xs:string" minOccurs="0"/>
<xs:element name="DelayCount" type="xs:string" minOccurs="0"/>
<xs:element name="HolidayCount" type="xs:string" minOccurs="0"/>
<xs:element name="RestDays" type="xs:string" minOccurs="0"/>
<xs:element name="TotalTransitDays" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ServiceSummaryType">
<xs:sequence>
<xs:element name="Service" type="tnt:CodeDescriptionType"/>
<xs:element name="GuaranteedIndicator" type="xs:string" minOccurs="0"/>
<xs:element name="Disclaimer" type="xs:string" minOccurs="0"/>
<xs:element name="EstimatedArrival" type="tnt:EstimatedArrivalType"/>
<xs:element name="SaturdayDelivery" type="xs:string" minOccurs="0"/>
<xs:element name="SaturdayDeliveryDisclaimer" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="TransitResponseType">
<xs:sequence>
<xs:element name="ShipFrom" type="tnt:ResponseShipFromType"/>
<xs:element name="ShipTo" type="tnt:ResponseShipToType"/>
<xs:element name="PickupDate" type="xs:string"/>
<xs:element name="ShipmentWeight" type="tnt:ShipmentWeightType" minOccurs="0"/>
<xs:element name="InvoiceLineTotal" type="tnt:InvoiceLineTotalType" minOccurs="0"/>
<xs:element name="DocumentsOnlyIndicator" type="xs:string" minOccurs="0"/>
<xs:element name="BillType" type="xs:string" minOccurs="0"/>
<xs:element name="MaximumListSize" type="xs:string" minOccurs="0"/>
<xs:element name="ServiceSummary" type="tnt:ServiceSummaryType" maxOccurs="unbounded"/>
<xs:element name="AutoDutyCode" type="xs:string" minOccurs="0"/>
<xs:element name="Disclaimer" type="xs:string" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="CandidateType">
<xs:sequence>
<xs:element name="Address" type="tnt:ResponseShipListAddressType"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="ShipListType">
<xs:sequence>
<xs:element name="Candidate" type="tnt:CandidateType" maxOccurs="unbounded"/>
</xs:sequence>
</xs:complexType>
<xs:complexType name="CandidateResponseType">
<xs:sequence>
<xs:element name="ShipFromList" type="tnt:ShipListType" minOccurs="0"/>
<xs:element name="ShipToList" type="tnt:ShipListType" minOccurs="0"/>
</xs:sequence>
</xs:complexType>
<xs:element name="TimeInTransitResponse">
<xs:complexType>
<xs:sequence>
<xs:element ref="common:Response"/>
<xs:choice>
<xs:element name="TransitResponse" type="tnt:TransitResponseType" minOccurs="0"/>
<xs:element name="CandidateResponse" type="tnt:CandidateResponseType" minOccurs="0"/>
</xs:choice>
</xs:sequence>
</xs:complexType>
</xs:element>
<!--+++++++++++++++++++End of Response++++++++++++++++++-->
</xs:schema>

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,2 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import delivery_ups from . import delivery_ups
from . import stock
from . import ups_request_patch from . import ups_request_patch

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models, _ from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
from odoo.addons.delivery_ups.models.ups_request import UPSRequest, Package from odoo.addons.delivery_ups.models.ups_request import UPSRequest, Package
@@ -9,6 +11,15 @@ _logger = logging.getLogger(__name__)
class ProviderUPS(models.Model): class ProviderUPS(models.Model):
_inherit = 'delivery.carrier' _inherit = 'delivery.carrier'
def _get_ups_signature_required_type(self, order=None, picking=None, package=None):
# '3' for Adult Sig.
return '2'
def _get_ups_signature_required(self, order=None, picking=None, package=None):
if self.get_signature_required(order=order, picking=picking, package=package):
return self._get_ups_signature_required_type(order=order, picking=picking, package=package)
return False
def _get_ups_is_third_party(self, order=None, picking=None): def _get_ups_is_third_party(self, order=None, picking=None):
third_party_account = self.get_third_party_account(order=order, picking=picking) third_party_account = self.get_third_party_account(order=order, picking=picking)
if third_party_account: if third_party_account:
@@ -19,6 +30,16 @@ class ProviderUPS(models.Model):
return True return True
return False return False
def _get_main_ups_account_number(self, order=None, picking=None):
wh = None
if order:
wh = order.warehouse_id
if picking:
wh = picking.picking_type_id.warehouse_id
if wh and wh.ups_shipper_number:
return wh.ups_shipper_number
return self.ups_shipper_number
def _get_ups_account_number(self, order=None, picking=None): def _get_ups_account_number(self, order=None, picking=None):
""" """
Common hook to customize what UPS Account number to use. Common hook to customize what UPS Account number to use.
@@ -32,6 +53,8 @@ class ProviderUPS(models.Model):
return third_party_account.name return third_party_account.name
if order and order.ups_carrier_account: if order and order.ups_carrier_account:
return order.ups_carrier_account return order.ups_carrier_account
if picking and picking.picking_type_id.warehouse_id.ups_shipper_number:
return picking.picking_type_id.warehouse_id.ups_shipper_number
if picking and picking.sale_id.ups_carrier_account: if picking and picking.sale_id.ups_carrier_account:
return picking.sale_id.ups_carrier_account return picking.sale_id.ups_carrier_account
return self.ups_shipper_number return self.ups_shipper_number
@@ -39,14 +62,20 @@ class ProviderUPS(models.Model):
def _get_ups_carrier_account(self, picking): def _get_ups_carrier_account(self, picking):
# 3rd party billing should return False if not used. # 3rd party billing should return False if not used.
account = self._get_ups_account_number(picking=picking) account = self._get_ups_account_number(picking=picking)
return account if account != self.ups_shipper_number else False return account if account not in (self.ups_shipper_number, picking.picking_type_id.warehouse_id.ups_shipper_number) else False
""" """
Overrides to use Hibou Delivery methods to get shipper etc. and to add 'transit_days' to result. Overrides to use Hibou Delivery methods to get shipper etc. and to add 'transit_days' to result.
""" """
def ups_rate_shipment(self, order): def ups_rate_shipment(self, order):
superself = self.sudo() superself = self.sudo()
srm = UPSRequest(self.log_xml, superself.ups_username, superself.ups_passwd, superself.ups_shipper_number, superself.ups_access_number, self.prod_environment) # Hibou Shipping
signature_required = superself._get_ups_signature_required(order=order)
insurance_value = superself.get_insurance_value(order=order)
currency = order.currency_id or order.company_id.currency_id
insurance_currency_code = currency.name
srm = UPSRequest(self.log_xml, superself.ups_username, superself.ups_passwd, superself._get_main_ups_account_number(order=order), superself.ups_access_number, self.prod_environment)
ResCurrency = self.env['res.currency'] ResCurrency = self.env['res.currency']
max_weight = self.ups_default_packaging_id.max_weight max_weight = self.ups_default_packaging_id.max_weight
packages = [] packages = []
@@ -61,11 +90,14 @@ class ProviderUPS(models.Model):
last_package_weight = total_weight % max_weight last_package_weight = total_weight % max_weight
for seq in range(total_package): for seq in range(total_package):
packages.append(Package(self, max_weight)) packages.append(Package(self, max_weight,
insurance_value=insurance_value, insurance_currency_code=insurance_currency_code, signature_required=signature_required))
if last_package_weight: if last_package_weight:
packages.append(Package(self, last_package_weight)) packages.append(Package(self, last_package_weight,
insurance_value=insurance_value, insurance_currency_code=insurance_currency_code, signature_required=signature_required))
else: else:
packages.append(Package(self, total_weight)) packages.append(Package(self, total_weight,
insurance_value=insurance_value, insurance_currency_code=insurance_currency_code, signature_required=signature_required))
shipment_info = { shipment_info = {
'total_qty': total_qty # required when service type = 'UPS Worldwide Express Freight' 'total_qty': total_qty # required when service type = 'UPS Worldwide Express Freight'
@@ -128,24 +160,38 @@ class ProviderUPS(models.Model):
def ups_send_shipping(self, pickings): def ups_send_shipping(self, pickings):
res = [] res = []
superself = self.sudo() superself = self.sudo()
srm = UPSRequest(self.log_xml, superself.ups_username, superself.ups_passwd, superself.ups_shipper_number, superself.ups_access_number, self.prod_environment)
ResCurrency = self.env['res.currency'] ResCurrency = self.env['res.currency']
for picking in pickings: for picking in pickings:
srm = UPSRequest(self.log_xml, superself.ups_username, superself.ups_passwd, superself._get_main_ups_account_number(picking=picking), superself.ups_access_number, self.prod_environment)
# Hibou Delivery # Hibou Delivery
shipper_company = superself.get_shipper_company(picking=picking) shipper_company = superself.get_shipper_company(picking=picking)
shipper_warehouse = superself.get_shipper_warehouse(picking=picking) shipper_warehouse = superself.get_shipper_warehouse(picking=picking)
recipient = superself.get_recipient(picking=picking) recipient = superself.get_recipient(picking=picking)
currency = picking.sale_id.currency_id if picking.sale_id else picking.company_id.currency_id
insurance_currency_code = currency.name
picking_packages = picking.package_ids
package_carriers = picking_packages.mapped('carrier_id')
if package_carriers:
# only ship ours
picking_packages = picking_packages.filtered(lambda p: p.carrier_id == self and not p.carrier_tracking_ref)
if not picking_packages:
continue
packages = [] packages = []
package_names = [] package_names = []
if picking.package_ids: if picking_packages:
# Create all packages # Create all packages
for package in picking.package_ids: for package in picking_packages:
packages.append(Package(self, package.shipping_weight, quant_pack=package.packaging_id, name=package.name)) packages.append(Package(self, package.shipping_weight, quant_pack=package.packaging_id, name=package.name,
insurance_value=superself.get_insurance_value(picking=picking, package=package), insurance_currency_code=insurance_currency_code, signature_required=superself._get_ups_signature_required(picking=picking, package=package)))
package_names.append(package.name) package_names.append(package.name)
# what is the point of weight_bulk?
# Create one package with the rest (the content that is not in a package) # Create one package with the rest (the content that is not in a package)
if picking.weight_bulk: # if picking.weight_bulk:
packages.append(Package(self, picking.weight_bulk)) # packages.append(Package(self, picking.weight_bulk))
invoice_line_total = 0 invoice_line_total = 0
for move in picking.move_lines: for move in picking.move_lines:
@@ -179,7 +225,7 @@ class ProviderUPS(models.Model):
if check_value: if check_value:
raise UserError(check_value) raise UserError(check_value)
package_type = picking.package_ids and picking.package_ids[0].packaging_id.shipper_package_code or self.ups_default_packaging_id.shipper_package_code package_type = picking_packages and picking_packages[0].packaging_id.shipper_package_code or self.ups_default_packaging_id.shipper_package_code
result = srm.send_shipping( result = srm.send_shipping(
shipment_info=shipment_info, packages=packages, shipper=shipper_company, ship_from=shipper_warehouse, shipment_info=shipment_info, packages=packages, shipper=shipper_company, ship_from=shipper_warehouse,
ship_to=recipient, packaging_type=package_type, service_type=ups_service_type, label_file_type=self.ups_label_file_type, ups_carrier_account=ups_carrier_account, ship_to=recipient, packaging_type=package_type, service_type=ups_service_type, label_file_type=self.ups_label_file_type, ups_carrier_account=ups_carrier_account,
@@ -219,14 +265,26 @@ class ProviderUPS(models.Model):
res = res + [shipping_data] res = res + [shipping_data]
return res return res
def ups_rate_shipment_multi(self, order=None, picking=None): def ups_rate_shipment_multi(self, order=None, picking=None, packages=None):
if not packages:
return self._ups_rate_shipment_multi_package(order=order, picking=picking)
else:
rates = []
for package in packages:
rates += self._ups_rate_shipment_multi_package(order=order, picking=picking, package=package)
return rates
def _ups_rate_shipment_multi_package(self, order=None, picking=None, package=None):
superself = self.sudo() superself = self.sudo()
srm = UPSRequest(self.log_xml, superself.ups_username, superself.ups_passwd, superself.ups_shipper_number, superself.ups_access_number, self.prod_environment) srm = UPSRequest(self.log_xml, superself.ups_username, superself.ups_passwd, superself._get_main_ups_account_number(order=order, picking=picking), superself.ups_access_number, self.prod_environment)
ResCurrency = self.env['res.currency'] ResCurrency = self.env['res.currency']
max_weight = self.ups_default_packaging_id.max_weight max_weight = self.ups_default_packaging_id.max_weight
packages = [] packages = []
if order: if order:
insurance_value = superself.get_insurance_value(order=order)
signature_required = superself._get_ups_signature_required(order=order)
currency = order.currency_id currency = order.currency_id
insurance_currency_code = currency.name
company = order.company_id company = order.company_id
date_order = order.date_order or fields.Date.today() date_order = order.date_order or fields.Date.today()
total_qty = 0 total_qty = 0
@@ -240,19 +298,27 @@ class ProviderUPS(models.Model):
last_package_weight = total_weight % max_weight last_package_weight = total_weight % max_weight
for seq in range(total_package): for seq in range(total_package):
packages.append(Package(self, max_weight)) packages.append(Package(self, max_weight, insurance_value=insurance_value, insurance_currency_code=insurance_currency_code, signature_required=signature_required))
if last_package_weight: if last_package_weight:
packages.append(Package(self, last_package_weight)) packages.append(Package(self, last_package_weight, insurance_value=insurance_value, insurance_currency_code=insurance_currency_code, signature_required=signature_required))
else: else:
packages.append(Package(self, total_weight)) packages.append(Package(self, total_weight, insurance_value=insurance_value, insurance_currency_code=insurance_currency_code, signature_required=signature_required))
else: else:
currency = picking.sale_id.currency_id if picking.sale_id else picking.company_id.currency_id currency = picking.sale_id.currency_id if picking.sale_id else picking.company_id.currency_id
insurance_currency_code = currency.name
company = picking.company_id company = picking.company_id
date_order = picking.sale_id.date_order or fields.Date.today() if picking.sale_id else fields.Date.today() date_order = picking.sale_id.date_order or fields.Date.today() if picking.sale_id else fields.Date.today()
# Is total quantity the number of packages or the number of items being shipped? # Is total quantity the number of packages or the number of items being shipped?
total_qty = len(picking.package_ids) if package:
packages = [Package(self, package.shipping_weight) for package in picking.package_ids] total_qty = 1
packages = [Package(self, package.shipping_weight, insurance_value=superself.get_insurance_value(picking=picking, package=package), insurance_currency_code=insurance_currency_code, signature_required=superself._get_ups_signature_required(picking=picking, package=package))]
elif picking.package_ids:
# all packages....
total_qty = len(picking.package_ids)
packages = [Package(self, package.shipping_weight, insurance_value=superself.get_insurance_value(picking=picking, package=package), insurance_currency_code=insurance_currency_code, signature_required=superself._get_ups_signature_required(picking=picking, package=package)) for package in picking.package_ids.filtered(lambda p: not p.carrier_id)]
else:
total_qty = 1
packages.append(Package(self, picking.shipping_weight or picking.weight, insurance_value=superself.get_insurance_value(picking=picking), insurance_currency_code=insurance_currency_code, signature_required=superself._get_ups_signature_required(picking=picking)))
shipment_info = { shipment_info = {
'total_qty': total_qty # required when service type = 'UPS Worldwide Express Freight' 'total_qty': total_qty # required when service type = 'UPS Worldwide Express Freight'
@@ -282,9 +348,8 @@ class ProviderUPS(models.Model):
'error_message': check_value, 'error_message': check_value,
'warning_message': False, 'warning_message': False,
}] }]
# We now use Shop if we send multi=True
#ups_service_type = order.ups_service_type or self.ups_default_service_type ups_service_type = (order.ups_service_type or self.ups_default_service_type) if order else self.ups_default_service_type
ups_service_type = None # See if this gets us all service types
result = srm.get_shipping_price( result = srm.get_shipping_price(
shipment_info=shipment_info, packages=packages, shipper=shipper_company, ship_from=shipper_warehouse, shipment_info=shipment_info, packages=packages, shipper=shipper_company, ship_from=shipper_warehouse,
ship_to=recipient, packaging_type=self.ups_default_packaging_id.shipper_package_code, service_type=ups_service_type, ship_to=recipient, packaging_type=self.ups_default_packaging_id.shipper_package_code, service_type=ups_service_type,
@@ -294,7 +359,14 @@ class ProviderUPS(models.Model):
response = [] response = []
for rate in result: for rate in result:
if rate.get('error_message'): if isinstance(rate, str):
# assume error
response.append({
'success': False, 'price': 0.0,
'error_message': _('Error:\n%s') % rate,
'warning_message': False,
})
elif rate.get('error_message'):
_logger.error('UPS error: %s' % rate['error_message']) _logger.error('UPS error: %s' % rate['error_message'])
response.append({ response.append({
'success': False, 'price': 0.0, 'success': False, 'price': 0.0,
@@ -318,6 +390,7 @@ class ProviderUPS(models.Model):
if carrier: if carrier:
response.append({ response.append({
'carrier': carrier, 'carrier': carrier,
'package': package or self.env['stock.quant.package'].browse(),
'success': True, 'success': True,
'price': price, 'price': price,
'error_message': False, 'error_message': False,

View File

@@ -0,0 +1,9 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import fields, models
class StockWarehouse(models.Model):
_inherit = 'stock.warehouse'
ups_shipper_number = fields.Char(string='UPS Shipper Number')

View File

@@ -1,9 +1,41 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from os import path as os_path
import suds import suds
from odoo.addons.delivery_ups.models.ups_request import UPSRequest from odoo.addons.delivery_ups.models.ups_request import UPSRequest, Package
SUDS_VERSION = suds.__version__
import logging import logging
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
SUDS_VERSION = suds.__version__ # If you're getting SOAP/suds errors
# logging.getLogger('suds.client').setLevel(logging.DEBUG)
TNT_CODE_MAP = {
'GND': '03',
# TODO fill in the rest if needed....
}
def patched__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 = '../api/RateWS.wsdl'
self.ship_wsdl = '../api/Ship.wsdl'
self.void_wsdl = '../api/Void.wsdl'
dirname = os_path.dirname(__file__)
self.tnt_wsdl = os_path.join(dirname, '../api/TNTWS.wsdl')
def patched_get_shipping_price(self, shipment_info, packages, shipper, ship_from, ship_to, packaging_type, service_type, def patched_get_shipping_price(self, shipment_info, packages, shipper, ship_from, ship_to, packaging_type, service_type,
@@ -11,10 +43,10 @@ def patched_get_shipping_price(self, shipment_info, packages, shipper, ship_from
client = self._set_client(self.rate_wsdl, 'Rate', 'RateRequest') client = self._set_client(self.rate_wsdl, 'Rate', 'RateRequest')
request = client.factory.create('ns0:RequestType') request = client.factory.create('ns0:RequestType')
request.RequestOption = 'Rate'
if multi: if multi:
request.RequestOption = 'Shop' request.RequestOption = 'Shop'
else:
request.RequestOption = 'Rate'
classification = client.factory.create('ns2:CodeDescriptionType') classification = client.factory.create('ns2:CodeDescriptionType')
classification.Code = '00' # Get rates for the shipper account classification.Code = '00' # Get rates for the shipper account
@@ -65,18 +97,17 @@ def patched_get_shipping_price(self, shipment_info, packages, shipper, ship_from
if not ship_to.commercial_partner_id.is_company: if not ship_to.commercial_partner_id.is_company:
shipment.ShipTo.Address.ResidentialAddressIndicator = suds.null() shipment.ShipTo.Address.ResidentialAddressIndicator = suds.null()
if not multi: shipment.Service.Code = service_type or ''
shipment.Service.Code = service_type or '' shipment.Service.Description = 'Service Code'
shipment.Service.Description = 'Service Code' if service_type == "96":
if service_type == "96": shipment.NumOfPieces = int(shipment_info.get('total_qty'))
shipment.NumOfPieces = int(shipment_info.get('total_qty'))
if saturday_delivery: if saturday_delivery:
shipment.ShipmentServiceOptions.SaturdayDeliveryIndicator = saturday_delivery shipment.ShipmentServiceOptions.SaturdayDeliveryIndicator = saturday_delivery
else: else:
shipment.ShipmentServiceOptions = '' shipment.ShipmentServiceOptions = ''
shipment.ShipmentRatingOptions.NegotiatedRatesIndicator = 1 shipment.ShipmentRatingOptions.NegotiatedRatesIndicator = '1'
try: try:
# Get rate using for provided detail # Get rate using for provided detail
@@ -84,13 +115,65 @@ def patched_get_shipping_price(self, shipment_info, packages, shipper, ship_from
# Check if ProcessRate is not success then return reason for that # Check if ProcessRate is not success then return reason for that
if response.Response.ResponseStatus.Code != "1": if response.Response.ResponseStatus.Code != "1":
error_message = self.get_error_message(response.Response.ResponseStatus.Code, return self.get_error_message(response.Response.ResponseStatus.Code,
response.Response.ResponseStatus.Description) response.Response.ResponseStatus.Description)
if multi:
return [error_message]
return error_message
if not multi: if multi:
result = []
tnt_response = None
tnt_ready = False
for rated_shipment in response.RatedShipment:
res = {}
res['service_code'] = rated_shipment.Service.Code
res['currency_code'] = rated_shipment.TotalCharges.CurrencyCode
negotiated_rate = 'NegotiatedRateCharges' in rated_shipment and rated_shipment.NegotiatedRateCharges.TotalCharge.MonetaryValue or None
res['price'] = negotiated_rate or rated_shipment.TotalCharges.MonetaryValue
# Hibou Delivery
if hasattr(rated_shipment, 'GuaranteedDelivery') and hasattr(rated_shipment.GuaranteedDelivery, 'BusinessDaysInTransit'):
res['transit_days'] = int(rated_shipment.GuaranteedDelivery.BusinessDaysInTransit)
if not res.get('transit_days') and date_planned:
if not tnt_response:
try:
tnt_client = self._set_client(self.tnt_wsdl, 'TimeInTransit', 'TimeInTransitRequest')
tnt_request = tnt_client.factory.create('tnt:TimeInTransitRequest')
tnt_request.Request.RequestOption = 'TNT'
tnt_request.ShipFrom.Address.City = ship_from.city or ''
tnt_request.ShipFrom.Address.CountryCode = ship_from.country_id.code or ''
tnt_request.ShipFrom.Address.PostalCode = ship_from.zip or ''
if ship_from.country_id.code in ('US', 'CA', 'IE'):
tnt_request.ShipFrom.Address.StateProvinceCode = ship_from.state_id.code or ''
tnt_request.ShipTo.Address.City = ship_to.city or ''
tnt_request.ShipTo.Address.CountryCode = ship_to.country_id.code or ''
tnt_request.ShipTo.Address.PostalCode = ship_to.zip or ''
if ship_to.country_id.code in ('US', 'CA', 'IE'):
tnt_request.ShipTo.Address.StateProvinceCode = ship_to.state_id.code or ''
tnt_request.Pickup.Date = date_planned.split(' ')[0].replace('-', '')
tnt_request.Pickup.Time = date_planned.split(' ')[1].replace(':', '')
# tnt_request_transit_from = tnt_client.factory.create('ns1:TransitFrom')
tnt_response = tnt_client.service.ProcessTimeInTransit(Request=tnt_request.Request,
ShipFrom=tnt_request.ShipFrom,
ShipTo=tnt_request.ShipTo,
Pickup=tnt_request.Pickup)
tnt_ready = tnt_response.Response.ResponseStatus.Code == "1"
except Exception as e:
_logger.warning('exception during the UPS Time In Transit request. ' + str(e))
tnt_ready = False
tnt_response = '-1'
if tnt_ready:
for service in tnt_response.TransitResponse.ServiceSummary:
if TNT_CODE_MAP.get(service.Service.Code) == service_type:
if hasattr(service, 'EstimatedArrival') and hasattr(service.EstimatedArrival, 'BusinessDaysInTransit'):
res['transit_days'] = int(service.EstimatedArrival.BusinessDaysInTransit)
break
# use TNT API to
result.append(res)
else:
result = {} result = {}
result['currency_code'] = response.RatedShipment[0].TotalCharges.CurrencyCode result['currency_code'] = response.RatedShipment[0].TotalCharges.CurrencyCode
@@ -99,30 +182,16 @@ def patched_get_shipping_price(self, shipment_info, packages, shipper, ship_from
0].NegotiatedRateCharges.TotalCharge.MonetaryValue or None 0].NegotiatedRateCharges.TotalCharge.MonetaryValue or None
result['price'] = negotiated_rate or response.RatedShipment[0].TotalCharges.MonetaryValue result['price'] = negotiated_rate or response.RatedShipment[0].TotalCharges.MonetaryValue
# Hibou Delivery # Hibou Delivery
if hasattr(response.RatedShipment[0], 'GuaranteedDelivery') and hasattr(response.RatedShipment[0].GuaranteedDelivery, 'BusinessDaysInTransit'): if hasattr(response.RatedShipment[0], 'GuaranteedDelivery') and hasattr(response.RatedShipment[0].GuaranteedDelivery, 'BusinessDaysInTransit'):
result['transit_days'] = int(response.RatedShipment[0].GuaranteedDelivery.BusinessDaysInTransit) result['transit_days'] = int(response.RatedShipment[0].GuaranteedDelivery.BusinessDaysInTransit)
# End
else:
result = []
for rated_shipment in response.RatedShipment:
rate = {}
rate['currency_code'] = rated_shipment.TotalCharges.CurrencyCode
# Some users are qualified to receive negotiated rates if not result.get('transit_days') and date_planned:
negotiated_rate = 'NegotiatedRateCharges' in rated_shipment and response.RatedShipment[ # use TNT API to
0].NegotiatedRateCharges.TotalCharge.MonetaryValue or None _logger.warning(' We would now use the TNT service. But who would show the transit days? 2')
rate['price'] = negotiated_rate or rated_shipment.TotalCharges.MonetaryValue # End
# Hibou Delivery
if hasattr(rated_shipment, 'GuaranteedDelivery') and hasattr(
rated_shipment.GuaranteedDelivery, 'BusinessDaysInTransit'):
rate['transit_days'] = int(rated_shipment.GuaranteedDelivery.BusinessDaysInTransit)
# End
rate['service_code'] = rated_shipment.Service.Code
result.append(rate)
return result return result
except suds.WebFault as e: except suds.WebFault as e:
@@ -130,17 +199,194 @@ def patched_get_shipping_price(self, shipment_info, packages, shipper, ship_from
prefix = '' prefix = ''
if SUDS_VERSION >= "0.6": if SUDS_VERSION >= "0.6":
prefix = '/Envelope/Body/Fault' prefix = '/Envelope/Body/Fault'
error_message = self.get_error_message( return self.get_error_message(
e.document.childAtPath(prefix + '/detail/Errors/ErrorDetail/PrimaryErrorCode/Code').getText(), e.document.childAtPath(prefix + '/detail/Errors/ErrorDetail/PrimaryErrorCode/Code').getText(),
e.document.childAtPath(prefix + '/detail/Errors/ErrorDetail/PrimaryErrorCode/Description').getText()) e.document.childAtPath(prefix + '/detail/Errors/ErrorDetail/PrimaryErrorCode/Description').getText())
if multi:
return [error_message]
return error_message
except IOError as e: except IOError as e:
error_message = self.get_error_message('0', 'UPS Server Not Found:\n%s' % e) return self.get_error_message('0', 'UPS Server Not Found:\n%s' % e)
if multi:
return [error_message]
return error_message
def patched_send_shipping(self, shipment_info, packages, shipper, ship_from, ship_to, packaging_type, service_type, saturday_delivery, cod_info=None, label_file_type='GIF', ups_carrier_account=False):
client = self._set_client(self.ship_wsdl, 'Ship', 'ShipmentRequest')
request = client.factory.create('ns0:RequestType')
request.RequestOption = 'nonvalidate'
namespace = 'ns3'
label = client.factory.create('{}:LabelSpecificationType'.format(namespace))
label.LabelImageFormat.Code = label_file_type
label.LabelImageFormat.Description = label_file_type
if label_file_type != 'GIF':
label.LabelStockSize.Height = '6'
label.LabelStockSize.Width = '4'
shipment = client.factory.create('{}:ShipmentType'.format(namespace))
shipment.Description = shipment_info.get('description')
for package in self.set_package_detail(client, packages, packaging_type, namespace, ship_from, ship_to, cod_info):
shipment.Package.append(package)
shipment.Shipper.AttentionName = shipper.name or ''
shipment.Shipper.Name = shipper.parent_id.name or shipper.name or ''
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.Number = self._clean_phone_number(shipper.phone)
shipment.ShipFrom.AttentionName = ship_from.name or ''
shipment.ShipFrom.Name = ship_from.parent_id.name or ship_from.name or ''
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.Number = self._clean_phone_number(ship_from.phone)
shipment.ShipTo.AttentionName = ship_to.name or ''
shipment.ShipTo.Name = ship_to.parent_id.name or ship_to.name or ''
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.Number = self._clean_phone_number(shipment_info['phone'])
if not ship_to.commercial_partner_id.is_company:
shipment.ShipTo.Address.ResidentialAddressIndicator = suds.null()
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.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.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 = client.factory.create('ns3:PaymentInformation')
shipcharge = client.factory.create('ns3:ShipmentCharge')
shipcharge.Type = '01'
# Bill Recevier 'Bill My Account'
if ups_carrier_account:
shipcharge.BillReceiver.AccountNumber = ups_carrier_account
shipcharge.BillReceiver.Address.PostalCode = ship_to.zip
else:
shipcharge.BillShipper.AccountNumber = self.shipper_number or ''
payment_info.ShipmentCharge = shipcharge
shipment.PaymentInformation = payment_info
if saturday_delivery:
shipment.ShipmentServiceOptions.SaturdayDeliveryIndicator = saturday_delivery
else:
shipment.ShipmentServiceOptions = ''
try:
response = client.service.ProcessShipment(
Request=request, Shipment=shipment,
LabelSpecification=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=label_file_type)
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.TotalCharge.MonetaryValue or None
result['price'] = negotiated_rate or response.ShipmentResults.ShipmentCharges.TotalCharges.MonetaryValue
return result
except suds.WebFault as e:
# childAtPath behaviour is changing at version 0.6
prefix = ''
if SUDS_VERSION >= "0.6":
prefix = '/Envelope/Body/Fault'
return self.get_error_message(e.document.childAtPath(prefix + '/detail/Errors/ErrorDetail/PrimaryErrorCode/Code').getText(),
e.document.childAtPath(prefix + '/detail/Errors/ErrorDetail/PrimaryErrorCode/Description').getText())
except IOError as e:
return self.get_error_message('0', 'UPS Server Not Found:\n%s' % e)
def patched_set_package_detail(self, client, packages, packaging_type, namespace, ship_from, ship_to, cod_info):
Packages = []
for i, p in enumerate(packages):
package = client.factory.create('{}:PackageType'.format(namespace))
if hasattr(package, 'Packaging'):
package.Packaging.Code = p.packaging_type or packaging_type or ''
elif hasattr(package, 'PackagingType'):
package.PackagingType.Code = p.packaging_type or packaging_type or ''
# Hibou Insurance & Signature Requirement
if p.insurance_value:
package.PackageServiceOptions.DeclaredValue.MonetaryValue = p.insurance_value
package.PackageServiceOptions.DeclaredValue.CurrencyCode = p.insurance_currency_code
if p.signature_required:
package.PackageServiceOptions.DeliveryConfirmation.DCISType = p.signature_required
if p.dimension_unit and any(p.dimension.values()):
package.Dimensions.UnitOfMeasurement.Code = p.dimension_unit or ''
package.Dimensions.Length = p.dimension['length'] or ''
package.Dimensions.Width = p.dimension['width'] or ''
package.Dimensions.Height = p.dimension['height'] or ''
if cod_info:
package.PackageServiceOptions.COD.CODFundsCode = str(cod_info['funds_code'])
package.PackageServiceOptions.COD.CODAmount.MonetaryValue = cod_info['monetary_value']
package.PackageServiceOptions.COD.CODAmount.CurrencyCode = cod_info['currency']
package.PackageWeight.UnitOfMeasurement.Code = p.weight_unit or ''
package.PackageWeight.Weight = p.weight or ''
# 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 ship_from.country_id.code in ('US') and ship_to.country_id.code in ('US')):
reference_number = client.factory.create('ns3:ReferenceNumberType')
reference_number.Code = 'PM'
reference_number.Value = p.name
reference_number.BarCodeIndicator = p.name
package.ReferenceNumber = reference_number
Packages.append(package)
return Packages
UPSRequest.__init__ = patched__init__
UPSRequest.get_shipping_price = patched_get_shipping_price UPSRequest.get_shipping_price = patched_get_shipping_price
UPSRequest.send_shipping = patched_send_shipping
UPSRequest.set_package_detail = patched_set_package_detail
def patched__init__2(self, carrier, weight, quant_pack=False, name='',
insurance_value=False, insurance_currency_code=False, signature_required=False):
self.weight = carrier._ups_convert_weight(weight, carrier.ups_package_weight_unit)
self.weight_unit = carrier.ups_package_weight_unit
self.name = name
self.dimension_unit = carrier.ups_package_dimension_unit
if quant_pack:
self.dimension = {'length': quant_pack.length, 'width': quant_pack.width, 'height': quant_pack.height}
else:
self.dimension = {'length': carrier.ups_default_packaging_id.length, 'width': carrier.ups_default_packaging_id.width, 'height': carrier.ups_default_packaging_id.height}
self.packaging_type = quant_pack and quant_pack.shipper_package_code or False
self.insurance_value = insurance_value
self.insurance_currency_code = insurance_currency_code
self.signature_required = signature_required
Package.__init__ = patched__init__2

View File

@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="ups_view_warehouse" model="ir.ui.view">
<field name="name">stock.warehouse</field>
<field name="model">stock.warehouse</field>
<field name="inherit_id" ref="stock.view_warehouse" />
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="ups_shipper_number"/>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,2 +1,4 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import wizard from . import wizard
from . import models from . import models

View File

@@ -1,10 +1,10 @@
{ {
'name': 'Sale Order Planner', 'name': 'Sale Order Planner',
'summary': 'Plans order dates and warehouses.', 'summary': 'Plans order dates and warehouses.',
'version': '12.0.1.0.0', 'version': '12.0.2.0.0',
'author': "Hibou Corp.", 'author': "Hibou Corp.",
'category': 'Sale', 'category': 'Sale',
'license': 'AGPL-3', 'license': 'OPL-1',
'complexity': 'expert', 'complexity': 'expert',
'images': [], 'images': [],
'website': "https://hibou.io", 'website': "https://hibou.io",
@@ -37,6 +37,7 @@ on the specific method's characteristics. (e.g. Do they deliver on Saturday?)
'views/stock.xml', 'views/stock.xml',
'views/delivery.xml', 'views/delivery.xml',
'views/product.xml', 'views/product.xml',
'views/res_config_settings_views.xml',
], ],
'auto_install': False, 'auto_install': False,
'installable': True, 'installable': True,

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import delivery from . import delivery
from . import partner from . import partner
from . import planning from . import planning
@@ -5,3 +7,4 @@ from . import product
from . import resource from . import resource
from . import sale from . import sale
from . import stock from . import stock
from . import res_config_settings

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from datetime import timedelta from datetime import timedelta
from odoo import api, fields, models from odoo import api, fields, models
@@ -61,6 +63,9 @@ class DeliveryCarrier(models.Model):
def calculate_transit_days(self, date_planned, date_delivered): def calculate_transit_days(self, date_planned, date_delivered):
self.ensure_one() self.ensure_one()
if not self.delivery_calendar_id:
return 0
if isinstance(date_planned, str): if isinstance(date_planned, str):
date_planned = fields.Datetime.from_string(date_planned) date_planned = fields.Datetime.from_string(date_planned)
if isinstance(date_delivered, str): if isinstance(date_delivered, str):

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models from odoo import api, fields, models
try: try:

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models from odoo import api, fields, models

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models from odoo import api, fields, models

View File

@@ -0,0 +1,79 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models
def sale_planner_warehouse_ids(env, company):
get_param = env['ir.config_parameter'].sudo().get_param
warehouse_ids = get_param('sale.planner.warehouse_ids.%s' % (company.id, )) or []
if warehouse_ids and isinstance(warehouse_ids, str):
try:
warehouse_ids = [int(i) for i in warehouse_ids.split(',')]
except:
warehouse_ids = []
return warehouse_ids
def sale_planner_carrier_ids(env, company):
get_param = env['ir.config_parameter'].sudo().get_param
carrier_ids = get_param('sale.planner.carrier_ids.%s' % (company.id, )) or []
if carrier_ids and isinstance(carrier_ids, str):
try:
carrier_ids = [int(c) for c in carrier_ids.split(',')]
except:
carrier_ids = []
return carrier_ids
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
sale_planner_warehouse_ids = fields.Many2many('stock.warehouse',
string='Sale Order Planner Warehouses',
compute='_compute_sale_planner_warehouse_ids',
inverse='_inverse_sale_planner_warehouse_ids')
sale_planner_carrier_ids = fields.Many2many('delivery.carrier',
string='Sale Order Planner Carriers',
compute='_compute_sale_planner_carrier_ids',
inverse='_inverse_sale_planner_carrier_ids')
def _compute_sale_planner_warehouse_ids_ids(self):
company = self.company_id or self.env.user.company_id
return sale_planner_warehouse_ids(self.env, company)
def _compute_sale_planner_carrier_ids_ids(self):
company = self.company_id or self.env.user.company_id
return sale_planner_carrier_ids(self.env, company)
def _compute_sale_planner_warehouse_ids(self):
for settings in self:
warehouse_ids = settings._compute_sale_planner_warehouse_ids_ids()
warehouses = self.env['stock.warehouse'].browse(warehouse_ids)
settings.sale_planner_warehouse_ids = warehouses
def _compute_sale_planner_carrier_ids(self):
for settings in self:
carrier_ids = settings._compute_sale_planner_carrier_ids_ids()
carriers = self.env['delivery.carrier'].browse(carrier_ids)
settings.sale_planner_carrier_ids = carriers
def _inverse_sale_planner_warehouse_ids(self):
set_param = self.env['ir.config_parameter'].sudo().set_param
company_id = self.company_id.id or self.env.user.company_id.id
for settings in self:
warehouse_ids = ','.join(str(i) for i in settings.sale_planner_warehouse_ids.ids)
set_param('sale.planner.warehouse_ids.%s' % (company_id, ), warehouse_ids)
def _inverse_sale_planner_carrier_ids(self):
set_param = self.env['ir.config_parameter'].sudo().set_param
company_id = self.company_id.id or self.env.user.company_id.id
for settings in self:
carrier_ids = ','.join(str(i) for i in settings.sale_planner_carrier_ids.ids)
set_param('sale.planner.carrier_ids.%s' % (company_id, ), carrier_ids)
@api.model
def get_values(self):
res = super(ResConfigSettings, self).get_values()
res['sale_planner_warehouse_ids'] = [(6, 0, self._compute_sale_planner_warehouse_ids_ids())]
res['sale_planner_carrier_ids'] = [(6, 0, self._compute_sale_planner_carrier_ids_ids())]
return res

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models from odoo import api, fields, models

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models from odoo import api, fields, models
@@ -7,3 +9,7 @@ class Warehouse(models.Model):
shipping_calendar_id = fields.Many2one( shipping_calendar_id = fields.Many2one(
'resource.calendar', 'Shipping Calendar', 'resource.calendar', 'Shipping Calendar',
help="This calendar represents shipping availability from the warehouse.") help="This calendar represents shipping availability from the warehouse.")
sale_planner_carrier_ids = fields.Many2many('delivery.carrier',
relation='sale_planner_carrier_wh_rel',
string='Sale Order Planner Base Carriers',
help='Overrides the global carriers.')

View File

@@ -1 +1,3 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import test_planner from . import test_planner

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo.tests import common from odoo.tests import common
from datetime import datetime, timedelta from datetime import datetime, timedelta
from json import loads as json_decode from json import loads as json_decode

View File

@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit</field>
<field name="model">res.config.settings</field>
<field name="priority" eval="49"/>
<field name="inherit_id" ref="delivery.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='sale_ebay']" position="after">
<h2>Sale Order Planner</h2>
<div class="col-lg-6 col-12 o_setting_box" id="sale_planner_carriers">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<label for="sale_planner_carrier_ids" />
<div class="text-muted">
Add a carrier that represents the 'base rate' for a carrier's type. <br/>
For example, you should add 1 FedEx carrier here and let us build up the
rates for your other FedEx shipping methods.
</div>
<field name="sale_planner_carrier_ids" class="oe_inline" options="{'no_create_edit': True, 'no_create': True}" />
</div>
</div>
<div class="col-lg-6 col-12 o_setting_box" id="sale_planner_warehouses">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<label for="sale_planner_warehouse_ids" />
<div class="text-muted">
Warehouses you typically ship inventory out of that you want to
include in the planning of sale orders.
</div>
<field name="sale_planner_warehouse_ids" class="oe_inline" options="{'no_create_edit': True, 'no_create': True}" />
</div>
</div>
</xpath>
</field>
</record>
</odoo>

View File

@@ -7,6 +7,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after"> <xpath expr="//field[@name='partner_id']" position="after">
<field name="shipping_calendar_id" /> <field name="shipping_calendar_id" />
<field name="sale_planner_carrier_ids" options="{'no_create_edit': True, 'no_create': True}" />
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -1 +1,3 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import order_planner from . import order_planner

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from math import sin, cos, sqrt, atan2, radians from math import sin, cos, sqrt, atan2, radians
from json import dumps, loads from json import dumps, loads
from copy import deepcopy from copy import deepcopy
@@ -15,6 +17,7 @@ except ImportError:
from odoo import api, fields, models, tools from odoo import api, fields, models, tools
from odoo.addons.base_geolocalize.models.res_partner import geo_find, geo_query_address from odoo.addons.base_geolocalize.models.res_partner import geo_find, geo_query_address
from ..models.res_config_settings import sale_planner_warehouse_ids, sale_planner_carrier_ids
class FakeCollection(): class FakeCollection():
@@ -26,10 +29,17 @@ class FakeCollection():
yield v yield v
def filtered(self, f): def filtered(self, f):
return filter(f, self.vals) return self.__class__([v for v in self.vals if f(v)])
def mapped(self, s):
# note this only maps to one level and doesn't really support recordset
return [v[s] for v in self.vals]
def sudo(self, *args, **kwargs):
return self
class FakePartner(): class FakePartner(FakeCollection):
def __init__(self, **kwargs): def __init__(self, **kwargs):
""" """
'delivery.carrier'.verify_carrier(contact) -> 'delivery.carrier'.verify_carrier(contact) ->
@@ -92,7 +102,7 @@ class FakePartner():
return getattr(self, item) return getattr(self, item)
class FakeOrderLine(): class FakeOrderLine(FakeCollection):
def __init__(self, **kwargs): def __init__(self, **kwargs):
""" """
'delivery.carrier'.get_price_available(order) -> 'delivery.carrier'.get_price_available(order) ->
@@ -302,19 +312,18 @@ class SaleOrderMakePlan(models.TransientModel):
if domain: if domain:
if not isinstance(domain, (list, tuple)): if not isinstance(domain, (list, tuple)):
domain = tools.safe_eval(domain) domain = tools.safe_eval(domain)
else:
domain = []
if self.env.context.get('warehouse_domain'): if self.env.context.get('warehouse_domain'):
if not domain:
domain = []
domain.extend(self.env.context.get('warehouse_domain')) domain.extend(self.env.context.get('warehouse_domain'))
if domain:
return warehouse.search(domain)
irconfig_parameter = self.env['ir.config_parameter'].sudo() # no domain, use global
if irconfig_parameter.get_param('sale.order.planner.warehouse_domain'): warehouse_ids = sale_planner_warehouse_ids(self.env, self.env.user.company_id)
domain.extend(tools.safe_eval(irconfig_parameter.get_param('sale.order.planner.warehouse_domain'))) return warehouse.browse(warehouse_ids)
return warehouse.search(domain) def get_shipping_carriers(self, carrier_id=None, domain=None, warehouse_id=None):
def get_shipping_carriers(self, carrier_id=None, domain=None):
Carrier = self.env['delivery.carrier'].sudo() Carrier = self.env['delivery.carrier'].sudo()
if carrier_id: if carrier_id:
return Carrier.browse(carrier_id) return Carrier.browse(carrier_id)
@@ -322,18 +331,20 @@ class SaleOrderMakePlan(models.TransientModel):
if domain: if domain:
if not isinstance(domain, (list, tuple)): if not isinstance(domain, (list, tuple)):
domain = tools.safe_eval(domain) domain = tools.safe_eval(domain)
else:
domain = []
if self.env.context.get('carrier_domain'): if self.env.context.get('carrier_domain'):
# potential bug here if this is textual if not domain:
domain = []
domain.extend(self.env.context.get('carrier_domain')) domain.extend(self.env.context.get('carrier_domain'))
if domain:
return Carrier.search(domain)
irconfig_parameter = self.env['ir.config_parameter'].sudo() # no domain, use global
if irconfig_parameter.get_param('sale.order.planner.carrier_domain'): if warehouse_id:
domain.extend(tools.safe_eval(irconfig_parameter.get_param('sale.order.planner.carrier_domain'))) warehouse = self.env['stock.warehouse'].sudo().browse(warehouse_id)
if warehouse.sale_planner_carrier_ids:
return Carrier.search(domain) return warehouse.sale_planner_carrier_ids.sudo()
carrier_ids = sale_planner_carrier_ids(self.env, self.env.user.company_id)
return Carrier.browse(carrier_ids)
def _generate_base_option(self, order_fake, policy_group): def _generate_base_option(self, order_fake, policy_group):
flag_force_closest = False flag_force_closest = False
@@ -614,6 +625,8 @@ class SaleOrderMakePlan(models.TransientModel):
return self._find_closest_warehouse(warehouses, partner.partner_latitude, partner.partner_longitude) return self._find_closest_warehouse(warehouses, partner.partner_latitude, partner.partner_longitude)
def _find_closest_warehouse(self, warehouses, latitude, longitude): def _find_closest_warehouse(self, warehouses, latitude, longitude):
if not warehouses:
return warehouses
distances = {distance(latitude, longitude, wh.partner_id.partner_latitude, wh.partner_id.partner_longitude): wh.id for wh in warehouses} distances = {distance(latitude, longitude, wh.partner_id.partner_latitude, wh.partner_id.partner_longitude): wh.id for wh in warehouses}
wh_id = distances[min(distances)] wh_id = distances[min(distances)]
return warehouses.filtered(lambda wh: wh.id == wh_id) return warehouses.filtered(lambda wh: wh.id == wh_id)
@@ -658,19 +671,19 @@ class SaleOrderMakePlan(models.TransientModel):
policy = line.product_id.product_tmpl_id.get_planning_policy() policy = line.product_id.product_tmpl_id.get_planning_policy()
if policy and policy.carrier_filter_id: if policy and policy.carrier_filter_id:
domain.extend(tools.safe_eval(policy.carrier_filter_id.domain)) domain.extend(tools.safe_eval(policy.carrier_filter_id.domain))
carriers = self.get_shipping_carriers(base_option.get('carrier_id'), domain=domain) carriers = self.get_shipping_carriers(base_option.get('carrier_id'), domain=domain, warehouse_id=base_option.get('warehouse_id'))
_logger.info('generate_shipping_options:: base_optoin: ' + str(base_option) + ' order_fake: ' + str(order_fake) + ' carriers: ' + str(carriers)) _logger.info('generate_shipping_options:: base_option: ' + str(base_option) + ' order_fake: ' + str(order_fake) + ' carriers: ' + str(carriers))
if not carriers: if not carriers:
return base_option return [base_option]
if not base_option.get('sub_options'): if not base_option.get('sub_options'):
options = [] options = []
# this locic comes from "delivery.models.sale_order.SaleOrder" # this locic comes from "delivery.models.sale_order.SaleOrder"
for carrier in carriers: for carrier in carriers:
option = self._generate_shipping_carrier_option(base_option, order_fake, carrier) carrier_options = self._generate_shipping_carrier_option(base_option, order_fake, carrier)
if option: if carrier_options:
options.append(option) options += carrier_options
if options: if options:
return options return options
return [base_option] return [base_option]
@@ -682,26 +695,40 @@ class SaleOrderMakePlan(models.TransientModel):
for carrier in carriers: for carrier in carriers:
new_base_option = deepcopy(base_option) new_base_option = deepcopy(base_option)
has_error = False has_error = False
found_carrier_ids = set()
for wh_id, wh_vals in base_option['sub_options'].items(): for wh_id, wh_vals in base_option['sub_options'].items():
if has_error: if has_error:
continue continue
order_fake.warehouse_id = warehouses.filtered(lambda wh: wh.id == wh_id) order_fake.warehouse_id = warehouses.filtered(lambda wh: wh.id == wh_id)
order_fake.order_line = FakeCollection(filter(lambda line: line.product_id.id in wh_vals['product_ids'], original_order_fake_order_line)) order_fake.order_line = FakeCollection(list(filter(lambda line: line.product_id.id in wh_vals['product_ids'], original_order_fake_order_line)))
wh_option = self._generate_shipping_carrier_option(wh_vals, order_fake, carrier) wh_carrier_options = self._generate_shipping_carrier_option(wh_vals, order_fake, carrier)
if not wh_option: if not wh_carrier_options:
has_error = True has_error = True
else: else:
new_base_option['sub_options'][wh_id] = wh_option for _option in wh_carrier_options:
if _option.get('carrier_id'):
found_carrier_ids.add(_option['carrier_id'])
new_base_option['sub_options'][wh_id] = wh_carrier_options
if has_error: if has_error:
continue continue
# now that we've collected, we can roll up some details.
new_base_option['carrier_id'] = carrier.id # now that we've collected details for this carrier, we likely have more than one carrier's rates
new_base_option['shipping_price'] = self._get_shipping_price_for_options(new_base_option['sub_options']) _logger.info(' from ' + str(carrier) + ' found ' + str(found_carrier_ids))
new_base_option['requested_date'] = self._get_max_requested_date(new_base_option['sub_options']) for carrier_id in found_carrier_ids:
new_base_option['transit_days'] = self._get_max_transit_days(new_base_option['sub_options']) carrier_option = deepcopy(base_option)
options.append(new_base_option) carrier_option['carrier_id'] = False
for wh_id, wh_vals in base_option['sub_options'].items():
for co in new_base_option['sub_options'].get(wh_id, []):
if co.get('carrier_id') == carrier_id:
# we have found the rate!
carrier_option['carrier_id'] = carrier_id
carrier_option['sub_options'][wh_id] = co
if carrier_option['carrier_id']:
carrier_option['shipping_price'] = self._get_shipping_price_for_options(carrier_option['sub_options'])
carrier_option['requested_date'] = self._get_max_requested_date(carrier_option['sub_options'])
carrier_option['transit_days'] = self._get_max_transit_days(carrier_option['sub_options'])
options.append(carrier_option)
#restore values in case more processing occurs #restore values in case more processing occurs
order_fake.warehouse_id = original_order_fake_warehouse_id order_fake.warehouse_id = original_order_fake_warehouse_id
@@ -730,6 +757,8 @@ class SaleOrderMakePlan(models.TransientModel):
def _generate_shipping_carrier_option(self, base_option, order_fake, carrier): def _generate_shipping_carrier_option(self, base_option, order_fake, carrier):
# some carriers look at the order carrier_id # some carriers look at the order carrier_id
order_fake.carrier_id = carrier order_fake.carrier_id = carrier
date_planned = base_option.get('date_planned')
order_fake.date_planned = date_planned
# this logic comes from "delivery.models.sale_order.SaleOrder" # this logic comes from "delivery.models.sale_order.SaleOrder"
try: try:
@@ -737,7 +766,9 @@ class SaleOrderMakePlan(models.TransientModel):
date_delivered = None date_delivered = None
transit_days = 0 transit_days = 0
if carrier.delivery_type not in ['fixed', 'base_on_rule']: if carrier.delivery_type not in ['fixed', 'base_on_rule']:
if hasattr(carrier, 'rate_shipment_date_planned'): if hasattr(carrier, 'rate_shipment_multi'):
result = carrier.rate_shipment_multi(order=order_fake)
elif hasattr(carrier, 'rate_shipment_date_planned'):
# New API # New API
result = carrier.rate_shipment_date_planned(order_fake, base_option.get('date_planned')) result = carrier.rate_shipment_date_planned(order_fake, base_option.get('date_planned'))
if result: if result:
@@ -747,7 +778,8 @@ class SaleOrderMakePlan(models.TransientModel):
elif hasattr(carrier, 'get_shipping_price_for_plan'): elif hasattr(carrier, 'get_shipping_price_for_plan'):
# Old API # Old API
result = carrier.get_shipping_price_for_plan(order_fake, base_option.get('date_planned')) result = carrier.get_shipping_price_for_plan(order_fake, base_option.get('date_planned'))
if result and isinstance(result, list): if result and isinstance(result, list) and not isinstance(result[0], dict):
# this detects the above only if it isn't a list of dictionaries (aka multi-rating result)
price_unit, transit_days, date_delivered = result[0] price_unit, transit_days, date_delivered = result[0]
elif not result: elif not result:
rate = carrier.rate_shipment(order_fake) rate = carrier.rate_shipment(order_fake)
@@ -769,13 +801,38 @@ class SaleOrderMakePlan(models.TransientModel):
if order_fake.company_id.currency_id.id != order_fake.pricelist_id.currency_id.id: if order_fake.company_id.currency_id.id != order_fake.pricelist_id.currency_id.id:
price_unit = order_fake.company_id.currency_id.with_context(date=order_fake.date_order).compute(price_unit, order_fake.pricelist_id.currency_id) price_unit = order_fake.company_id.currency_id.with_context(date=order_fake.date_order).compute(price_unit, order_fake.pricelist_id.currency_id)
final_price = float(price_unit) * (1.0 + (float(carrier.margin) / 100.0)) if result and isinstance(result, list):
option = deepcopy(base_option) res = []
option['carrier_id'] = carrier.id for rate in result:
option['shipping_price'] = final_price rate_carrier = rate.get('carrier')
option['requested_date'] = date_delivered if not rate_carrier:
option['transit_days'] = transit_days continue
return option price_unit = rate['price']
date_delivered = rate.get('date_delivered')
transit_days = rate.get('transit_days')
if date_planned and transit_days and not date_delivered:
# compute from planned date anc current rate carrier
date_delivered = rate_carrier.calculate_date_delivered(date_planned, transit_days)
elif date_planned and date_delivered and not transit_days:
transit_days = rate_carrier.calculate_transit_days(date_planned, date_delivered)
final_price = float(price_unit) * (1.0 + (float(rate_carrier.margin) / 100.0))
option = deepcopy(base_option)
option['carrier_id'] = rate_carrier.id
option['shipping_price'] = final_price
option['requested_date'] = fields.Datetime.to_string(date_delivered) if (date_delivered and isinstance(date_delivered, datetime)) else date_delivered
option['transit_days'] = transit_days
res.append(option)
return res
else:
final_price = float(price_unit) * (1.0 + (float(carrier.margin) / 100.0))
option = deepcopy(base_option)
option['carrier_id'] = carrier.id
option['shipping_price'] = final_price
option['requested_date'] = fields.Datetime.to_string(date_delivered) if (date_delivered and isinstance(date_delivered, datetime)) else date_delivered
option['transit_days'] = transit_days
return [option]
except Exception as e: except Exception as e:
_logger.info("Exception collecting carrier rates: " + str(e)) _logger.info("Exception collecting carrier rates: " + str(e))
# Want to see more? # Want to see more?

View File

@@ -1,2 +1,4 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import models from . import models
from . import wizard from . import wizard

View File

@@ -1,10 +1,10 @@
{ {
'name': 'Stock Delivery Planner', 'name': 'Stock Delivery Planner',
'summary': 'Get rates and choose carrier for delivery.', 'summary': 'Get rates and choose carrier for delivery.',
'version': '12.0.1.0.0', 'version': '12.0.1.1.0',
'author': "Hibou Corp.", 'author': "Hibou Corp.",
'category': 'Warehouse', 'category': 'Warehouse',
'license': 'AGPL-3', 'license': 'OPL-1',
'website': "https://hibou.io", 'website': "https://hibou.io",
'description': """ 'description': """
Stock Delivery Planner Stock Delivery Planner
@@ -19,6 +19,8 @@ Re-rate deliveries at packing time to find lowest-priced delivery method that st
'stock', 'stock',
], ],
'data': [ 'data': [
'security/ir.model.access.csv',
'views/res_config_settings_views.xml',
'views/stock_views.xml', 'views/stock_views.xml',
'wizard/stock_delivery_planner_views.xml', 'wizard/stock_delivery_planner_views.xml',
], ],

View File

@@ -1 +1,4 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from . import res_config_settings
from . import stock from . import stock

View File

@@ -0,0 +1,43 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models
class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
stock_delivery_planner_base_carrier_ids = fields.Many2many('delivery.carrier',
string='Delivery Planner Base Carriers',
compute='_compute_stock_delivery_planner_base_carrier_ids',
inverse='_inverse_stock_delivery_planner_base_carrier_ids')
def _compute_stock_delivery_planner_base_carrier_ids_ids(self):
# used to compute the field and update in get_values
get_param = self.env['ir.config_parameter'].sudo().get_param
company_id = self.company_id.id or self.env.user.company_id.id
carrier_ids = get_param('stock.delivery.planner.carrier_ids.%s' % (company_id,)) or []
if carrier_ids and isinstance(carrier_ids, str):
try:
carrier_ids = [int(c) for c in carrier_ids.split(',')]
except:
carrier_ids = []
return carrier_ids
def _compute_stock_delivery_planner_base_carrier_ids(self):
for settings in self:
carrier_ids = settings._compute_stock_delivery_planner_base_carrier_ids_ids()
carriers = self.env['delivery.carrier'].browse(carrier_ids)
settings.stock_delivery_planner_base_carrier_ids = carriers
def _inverse_stock_delivery_planner_base_carrier_ids(self):
set_param = self.env['ir.config_parameter'].sudo().set_param
company_id = self.company_id.id or self.env.user.company_id.id
for settings in self:
carrier_ids = ','.join(str(i) for i in settings.stock_delivery_planner_base_carrier_ids.ids)
set_param('stock.delivery.planner.carrier_ids.%s' % (company_id, ), carrier_ids)
@api.model
def get_values(self):
res = super(ResConfigSettings, self).get_values()
res['stock_delivery_planner_base_carrier_ids'] = [(6, 0, self._compute_stock_delivery_planner_base_carrier_ids_ids())]
return res

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models, tools, _ from odoo import api, fields, models, tools, _
from odoo.exceptions import UserError from odoo.exceptions import UserError
@@ -46,3 +48,12 @@ class StockPicking(models.Model):
domain.extend(tools.safe_eval(irconfig_parameter.get_param('sale.order.planner.carrier_domain'))) domain.extend(tools.safe_eval(irconfig_parameter.get_param('sale.order.planner.carrier_domain')))
return Carrier.search(domain) return Carrier.search(domain)
class Warehouse(models.Model):
_inherit = 'stock.warehouse'
delivery_planner_carrier_ids = fields.Many2many('delivery.carrier',
relation='delivery_planner_carrier_wh_rel',
string='Delivery Planner Base Carriers',
help='Overrides the global carriers.')

View File

@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_stock_delivery_planner_user,stock.delivery.planner user,model_stock_delivery_planner,stock.group_stock_user,1,1,1,0
access_stock_delivery_planner_option_user,stock.delivery.planner.option user,model_stock_delivery_planner_option,stock.group_stock_user,1,1,1,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_stock_delivery_planner_user stock.delivery.planner user model_stock_delivery_planner stock.group_stock_user 1 1 1 0
3 access_stock_delivery_planner_option_user stock.delivery.planner.option user model_stock_delivery_planner_option stock.group_stock_user 1 1 1 0

View File

@@ -1,3 +1,5 @@
# Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import fields from odoo import fields
from odoo.tests.common import Form, TransactionCase from odoo.tests.common import Form, TransactionCase
@@ -15,8 +17,8 @@ class TestStockDeliveryPlanner(TransactionCase):
self.skipTest('FedEx Shipping Connector demo data is required to run this test.') self.skipTest('FedEx Shipping Connector demo data is required to run this test.')
self.env['ir.config_parameter'].sudo().set_param('sale.order.planner.carrier_domain', self.env['ir.config_parameter'].sudo().set_param('sale.order.planner.carrier_domain',
"[('id', 'in', (%d,))]" % self.fedex_ground.id) "[('id', 'in', (%d,))]" % self.fedex_ground.id)
self.env['ir.config_parameter'].sudo().set_param('stock.delivery.planner.carrier_domain', self.env['ir.config_parameter'].sudo().set_param('stock.delivery.planner.carrier_ids.%s' % (self.env.user.company_id.id, ),
"[('id', 'in', (%d,))]" % self.fedex_ground.id) "%d" % self.fedex_ground.id)
# Does it make sense to set default package in fedex_rate_shipment_multi # Does it make sense to set default package in fedex_rate_shipment_multi
# instead of relying on a correctly configured delivery method? # instead of relying on a correctly configured delivery method?
self.fedex_package = self.browse_ref('delivery_fedex.fedex_packaging_FEDEX_25KG_BOX') self.fedex_package = self.browse_ref('delivery_fedex.fedex_packaging_FEDEX_25KG_BOX')
@@ -109,11 +111,11 @@ class TestStockDeliveryPlanner(TransactionCase):
self.assertEqual(self.picking.shipping_weight, 0.0) self.assertEqual(self.picking.shipping_weight, 0.0)
self.picking.move_line_ids.filtered(lambda ml: ml.product_id == self.product).qty_done = 5.0 self.picking.move_line_ids.filtered(lambda ml: ml.product_id == self.product).qty_done = 5.0
packing_action = self.picking.put_in_pack() packing_action = self.picking.action_put_in_pack()
packing_wizard = Form(self.env[packing_action['res_model']].with_context(packing_action['context'])) packing_wizard = Form(self.env[packing_action['res_model']].with_context(packing_action['context']))
packing_wizard.delivery_packaging_id = self.fedex_package packing_wizard.delivery_packaging_id = self.fedex_package
choose_delivery_package = packing_wizard.save() choose_delivery_package = packing_wizard.save()
choose_delivery_package.put_in_pack() choose_delivery_package.action_put_in_pack()
self.assertEqual(self.picking.shipping_weight, 5.0) self.assertEqual(self.picking.shipping_weight, 5.0)
action = self.picking.action_plan_delivery() action = self.picking.action_plan_delivery()

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="res_config_settings_view_form" model="ir.ui.view">
<field name="name">res.config.settings.view.form.inherit</field>
<field name="model">res.config.settings</field>
<field name="priority" eval="50"/>
<field name="inherit_id" ref="delivery.res_config_settings_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@id='sale_ebay']" position="after">
<h2>Delivery Planner</h2>
<div class="col-lg-6 col-12 o_setting_box" id="stock_delivery_planner">
<div class="o_setting_left_pane"/>
<div class="o_setting_right_pane">
<label for="stock_delivery_planner_base_carrier_ids" />
<div class="text-muted">
Add a carrier that represents the 'base rate' for a carrier's type. <br/>
For example, you should add 1 FedEx carrier here and let us build up the
rates for your other FedEx shipping methods.
</div>
<field name="stock_delivery_planner_base_carrier_ids" class="oe_inline" options="{'no_create_edit': True, 'no_create': True}" />
</div>
</div>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,13 +1,26 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
<record id="view_picking_form" model="ir.ui.view"> <record id="view_picking_form" model="ir.ui.view">
<field name="name">stock.picking.form.inherit.delivery.planner</field> <field name="name">stock.picking.form.inherit.delivery.planner</field>
<field name="model">stock.picking</field> <field name="model">stock.picking</field>
<field name="inherit_id" ref="stock.view_picking_form"/> <field name="inherit_id" ref="stock.view_picking_form"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//header" position="inside"> <xpath expr="//header" position="inside">
<button name="action_plan_delivery" type="object" string="Plan Shipment" attrs="{'invisible': [('picking_type_code', '!=', 'outgoing')]}"/> <button name="action_plan_delivery" type="object" string="Plan Shipment" class="oe_highlight" attrs="{'invisible': [('picking_type_code', '!=', 'outgoing')]}"/>
</xpath> </xpath>
</field> </field>
</record> </record>
<record id="view_warehouse_delivery_carriers" model="ir.ui.view">
<field name="name">stock.warehouse.delivery.carriers</field>
<field name="model">stock.warehouse</field>
<field name="inherit_id" ref="stock.view_warehouse" />
<field name="arch" type="xml">
<xpath expr="//field[@name='partner_id']" position="after">
<field name="delivery_planner_carrier_ids" options="{'no_create_edit': True, 'no_create': True}" />
</xpath>
</field>
</record>
</odoo> </odoo>

View File

@@ -1,4 +1,7 @@
from odoo import api, fields, models, tools # Part of Hibou Suite Professional. See LICENSE_PROFESSIONAL file for full copyright and licensing details.
from odoo import api, fields, models, _
from odoo.exceptions import UserError, ValidationError
import logging import logging
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)
@@ -9,29 +12,51 @@ class StockDeliveryPlanner(models.TransientModel):
picking_id = fields.Many2one('stock.picking', 'Transfer') picking_id = fields.Many2one('stock.picking', 'Transfer')
plan_option_ids = fields.One2many('stock.delivery.planner.option', 'plan_id', 'Options') plan_option_ids = fields.One2many('stock.delivery.planner.option', 'plan_id', 'Options')
packages_planned = fields.Boolean(compute='_compute_packages_planned')
@api.depends('plan_option_ids.selection')
def _compute_packages_planned(self):
for wiz in self:
packages = wiz.picking_id.package_ids
if not packages:
wiz.packages_planned = False
selected_options = wiz.plan_option_ids.filtered(lambda p: p.selection == 'selected')
wiz.packages_planned = len(selected_options) == len(packages)
def create(self, values): def create(self, values):
planner = super(StockDeliveryPlanner, self).create(values) planner = super(StockDeliveryPlanner, self).create(values)
base_carriers = self.env['delivery.carrier'] base_carriers = planner.picking_id.picking_type_id.warehouse_id.delivery_planner_carrier_ids
carrier_domain = self.env['ir.config_parameter'].sudo().get_param('stock.delivery.planner.carrier_domain') if not base_carriers:
if carrier_domain: carrier_ids = self.env['ir.config_parameter'].sudo().get_param('stock.delivery.planner.carrier_ids.%s' % (self.env.user.company_id.id, ))
base_carriers = base_carriers.search(tools.safe_eval(carrier_domain)) if carrier_ids:
try:
carrier_ids = [int(c) for c in carrier_ids.split(',')]
base_carriers = base_carriers.browse(carrier_ids)
except:
pass
base_carriers = base_carriers.sudo()
for carrier in base_carriers: for carrier in base_carriers:
rates = carrier.rate_shipment_multi(picking=planner.picking_id) try:
for rate in filter(lambda r: not r.get('success'), rates): rates = carrier.rate_shipment_multi(picking=planner.picking_id)
_logger.warning(rate.get('error_message')) for rate in filter(lambda r: not r.get('success'), rates):
for rate in filter(lambda r: r.get('success'), rates): _logger.warning(rate.get('error_message'))
rate = self.calculate_delivery_window(rate) for rate in filter(lambda r: r.get('success'), rates):
planner.plan_option_ids |= planner.plan_option_ids.create({ rate = self.calculate_delivery_window(rate)
'plan_id': self.id, # added late in API dev cycle
'carrier_id': rate['carrier'].id, package = rate.get('package') or self.env['stock.quant.package'].browse()
'price': rate['price'], planner.plan_option_ids |= planner.plan_option_ids.create({
'date_planned': rate['date_planned'], 'plan_id': self.id,
'requested_date': rate['date_delivered'], 'carrier_id': rate['carrier'].id,
'transit_days': rate['transit_days'], 'package_id': package.id,
}) 'price': rate['price'],
'date_planned': rate['date_planned'],
'requested_date': rate.get('date_delivered', False),
'transit_days': rate.get('transit_days', 0),
})
except (UserError, ValidationError) as e:
_logger.warning('Exception during delivery planning. %s' % str(e))
return planner return planner
@api.model @api.model
@@ -47,6 +72,12 @@ class StockDeliveryPlanner(models.TransientModel):
rate['date_delivered'] = carrier.calculate_date_delivered(date_planned, rate.get('transit_days')) rate['date_delivered'] = carrier.calculate_date_delivered(date_planned, rate.get('transit_days'))
return rate return rate
def action_plan(self):
self.ensure_one()
selected_package_options = self.plan_option_ids.filtered(lambda o: o.package_id and o.selection == 'selected')
selected_package_options._plan()
return {"type": "ir.actions.act_window_close"}
class StockDeliveryOption(models.TransientModel): class StockDeliveryOption(models.TransientModel):
_name = 'stock.delivery.planner.option' _name = 'stock.delivery.planner.option'
@@ -54,18 +85,46 @@ class StockDeliveryOption(models.TransientModel):
plan_id = fields.Many2one('stock.delivery.planner', 'Plan', ondelete='cascade') plan_id = fields.Many2one('stock.delivery.planner', 'Plan', ondelete='cascade')
carrier_id = fields.Many2one('delivery.carrier', 'Delivery Method') carrier_id = fields.Many2one('delivery.carrier', 'Delivery Method')
package_id = fields.Many2one('stock.quant.package', 'Package')
price = fields.Float('Shipping Price') price = fields.Float('Shipping Price')
date_planned = fields.Datetime('Planned Date') date_planned = fields.Datetime('Planned Date')
requested_date = fields.Datetime('Expected Delivery Date') requested_date = fields.Datetime('Expected Delivery Date')
transit_days = fields.Integer('Transit Days') transit_days = fields.Integer('Transit Days')
sale_requested_date = fields.Datetime('Sale Order Delivery Date', related='plan_id.picking_id.sale_id.requested_date') sale_requested_date = fields.Datetime('Sale Order Delivery Date', related='plan_id.picking_id.sale_id.requested_date')
days_different = fields.Float('Days Different', compute='_compute_days_different') # use carrier calendar days_different = fields.Float('Days Different', compute='_compute_days_different') # use carrier calendar
selection = fields.Selection([
('', 'None'),
('selected', 'Selected'),
('deselected', 'De-selected')
])
def _plan(self):
# this is intended to be used during selecting a whole plan
for option in self:
option.package_id.write({
'carrier_id': option.carrier_id.id,
})
@api.multi @api.multi
def select_plan(self): def select_plan(self):
for option in self.filtered('carrier_id'): self.ensure_one()
option.plan_id.picking_id.carrier_id = option.carrier_id self.selection = 'selected'
return if self.package_id:
# need to deselect other options for this package
deselected = self.plan_id.plan_option_ids.filtered(lambda o: o.package_id == self.package_id and o != self)
deselected.write({'selection': 'deselected'})
return {
'name': _('Delivery Rate Planner'),
'type': 'ir.actions.act_window',
'view_mode': 'form',
'res_model': 'stock.delivery.planner',
'res_id': self.plan_id.id,
'target': 'new',
}
else:
# Select plan for whole shipment
self.plan_id.picking_id.carrier_id = self.carrier_id
return {"type": "ir.actions.act_window_close"}
@api.depends('requested_date', 'sale_requested_date', 'carrier_id') @api.depends('requested_date', 'sale_requested_date', 'carrier_id')
def _compute_days_different(self): def _compute_days_different(self):

View File

@@ -6,22 +6,34 @@
<field name="type">form</field> <field name="type">form</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<field name="plan_option_ids"> <field name="packages_planned" invisible="1" />
<tree decoration-success="days_different &lt; 0.0" decoration-danger="days_different &gt; 0.0" <group>
create="false" edit="false" delete="false"> <field name="plan_option_ids" nolabel="1">
<field name="carrier_id"/> <tree decoration-info="selection == 'selected'"
<field name="date_planned"/> decoration-muted="selection == 'deselected'"
<field name="requested_date"/> decoration-bf="days_different == 0.0"
<field name="transit_days"/> default_order="package_id, price"
<field name="sale_requested_date"/> create="false" edit="false" delete="false">
<field name="days_different"/> <field name="package_id" />
<field name="price"/> <field name="carrier_id" />
<button class="eo_highlight" <field name="date_planned" invisible="1" />
name="select_plan" <field name="requested_date" decoration-danger="days_different &gt; 1.0" decoration-warning="days_different &gt; 0.0" decoration-success="days_different &lt; 0.0" />
string="Select" <field name="transit_days" decoration-warning="transit_days > 2.0" decoration-success="transit_days == 1.0"/>
type="object" /> <field name="sale_requested_date" decoration-danger="days_different &gt; 1.0" decoration-warning="days_different &gt; 0.0" decoration-success="days_different &lt; 0.0" />
</tree> <field name="days_different" decoration-danger="days_different &gt; 1.0" decoration-warning="days_different &gt; 0.0" decoration-success="days_different &lt; 0.0" />
</field> <field name="price" decoration-success="price &lt; 10.99" decoration-warning="price > 31.00 and price &lt; 50.00" decoration-danger="price >= 50.00" />
<field name="selection" invisible="1" />
<button class="eo_highlight"
name="select_plan"
string="Select"
type="object" />
</tree>
</field>
</group>
<footer>
<button type="object" name="action_plan" string="Plan" class="btn-primary" attrs="{'invisible': [('packages_planned', '=', False)]}"/>
<button string="Discard" special="cancel" class="btn-secondary"/>
</footer>
</form> </form>
</field> </field>
</record> </record>