[MOV] delivery_fedex_hibou: from hibou-suite-enterprise:11.0

This commit is contained in:
Jared Kipe
2020-10-29 12:40:01 -07:00
parent d7234aebe3
commit 0e5166965e
7 changed files with 626 additions and 0 deletions

View File

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

View File

@@ -0,0 +1,19 @@
{
'name': 'Hibou Fedex Shipping',
'version': '11.0.1.0.0',
'category': 'Stock',
'author': "Hibou Corp.",
'license': 'AGPL-3',
'website': 'https://hibou.io/',
'depends': [
'delivery_fedex',
'delivery_hibou',
],
'data': [
'views/stock_views.xml',
],
'demo': [
],
'installable': True,
'application': False,
}

View File

@@ -0,0 +1,2 @@
from . import delivery_fedex
from . import stock

View File

@@ -0,0 +1,396 @@
import logging
import time
from odoo import fields, models, tools, _
from odoo.exceptions import UserError, ValidationError
from odoo.addons.delivery_fedex.models.delivery_fedex import _convert_curr_iso_fdx, _convert_weight
from .fedex_request import FedexRequest
pdf = tools.pdf
_logger = logging.getLogger(__name__)
class DeliveryFedex(models.Model):
_inherit = 'delivery.carrier'
fedex_service_type = fields.Selection(selection_add=[
('GROUND_HOME_DELIVERY', 'GROUND_HOME_DELIVERY'),
('FEDEX_EXPRESS_SAVER', 'FEDEX_EXPRESS_SAVER'),
])
def _get_fedex_is_third_party(self, order=None, picking=None):
third_party_account = self.get_third_party_account(order=order, picking=picking)
if third_party_account:
if not third_party_account.delivery_type == 'fedex':
raise ValidationError('Non-FedEx Shipping Account indicated during FedEx shipment.')
return True
return False
def _get_fedex_payment_account_number(self, order=None, picking=None):
"""
Common hook to customize what Fedex Account number to use.
:return: FedEx Account Number
"""
# Provided by Hibou Odoo Suite `delivery_hibou`
third_party_account = self.get_third_party_account(order=order, picking=picking)
if third_party_account:
if not third_party_account.delivery_type == 'fedex':
raise ValidationError('Non-FedEx Shipping Account indicated during FedEx shipment.')
return third_party_account.name
return self.fedex_account_number
def _get_fedex_account_number(self, order=None, picking=None):
if order:
# third_party_account = self.get_third_party_account(order=order, picking=picking)
# if third_party_account:
# if not third_party_account.delivery_type == 'fedex':
# raise ValidationError('Non-FedEx Shipping Account indicated during FedEx shipment.')
# return third_party_account.name
if order.warehouse_id.fedex_account_number:
return order.warehouse_id.fedex_account_number
return self.fedex_account_number
if picking:
if picking.picking_type_id.warehouse_id.fedex_account_number:
return picking.picking_type_id.warehouse_id.fedex_account_number
return self.fedex_account_number
def _get_fedex_meter_number(self, order=None, picking=None):
if order:
if order.warehouse_id.fedex_meter_number:
return order.warehouse_id.fedex_meter_number
return self.fedex_meter_number
if picking:
if picking.picking_type_id.warehouse_id.fedex_meter_number:
return picking.picking_type_id.warehouse_id.fedex_meter_number
return self.fedex_meter_number
def _get_fedex_recipient_is_residential(self, partner):
if self.fedex_service_type.find('HOME'):
return True
return not bool(partner.company)
def _fedex_srm_shipment_label(self, srm, label_format_type, image_type, label_stock_type, label_printing_orientation, label_order):
"""
This gets called when the shipment label details are being created.
Override this method, add new parameters if needed. Do not call super if you cannot curry your own parameters.
"""
srm.shipment_label(label_format_type, image_type, label_stock_type, label_printing_orientation, label_order)
##
# Main Overrides
#
# Note that a lot of these comments are from the overridden code, they are left here
# for easier diffing against Odoo Enterprise
"""
Overrides to use Hibou Delivery methods to get shipper etc. and to add 'transit_days' to result.
"""
def fedex_rate_shipment(self, order):
max_weight = _convert_weight(self.fedex_default_packaging_id.max_weight, self.fedex_weight_unit)
price = 0.0
is_india = order.partner_shipping_id.country_id.code == 'IN' and order.company_id.partner_id.country_id.code == 'IN'
# Estimate weight of the sales order; will be definitely recomputed on the picking field "weight"
est_weight_value = sum([(line.product_id.weight * line.product_uom_qty) for line in order.order_line]) or 0.0
weight_value = _convert_weight(est_weight_value, self.fedex_weight_unit)
# Some users may want to ship very lightweight items; in order to give them a rating, we round the
# converted weight of the shipping to the smallest value accepted by FedEx: 0.01 kg or lb.
# (in the case where the weight is actually 0.0 because weights are not set, don't do this)
if weight_value > 0.0:
weight_value = max(weight_value, 0.01)
order_currency = order.currency_id
superself = self.sudo()
shipper_company = superself.get_shipper_company(order=order)
shipper_warehouse = superself.get_shipper_warehouse(order=order)
recipient = superself.get_recipient(order=order)
acc_number = superself._get_fedex_account_number(order=order)
order_name = superself.get_order_name(order=order)
residential = self._get_fedex_recipient_is_residential(recipient)
date_planned = None
if self.env.context.get('date_planned'):
date_planned = self.env.context.get('date_planned')
# Authentication stuff
srm = FedexRequest(self.log_xml, request_type="rating", prod_environment=self.prod_environment)
srm.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password)
srm.client_detail(acc_number, superself.fedex_meter_number)
# Build basic rating request and set addresses
srm.transaction_detail(order_name)
srm.shipment_request(
self.fedex_droppoff_type,
self.fedex_service_type,
self.fedex_default_packaging_id.shipper_package_code,
self.fedex_weight_unit,
self.fedex_saturday_delivery,
)
srm.set_currency(_convert_curr_iso_fdx(order_currency.name))
srm.set_shipper(shipper_company, shipper_warehouse)
srm.set_recipient(recipient, residential=residential)
if max_weight and weight_value > max_weight:
total_package = int(weight_value / max_weight)
last_package_weight = weight_value % max_weight
for sequence in range(1, total_package + 1):
srm.add_package(max_weight, sequence_number=sequence, mode='rating')
if last_package_weight:
total_package = total_package + 1
srm.add_package(last_package_weight, sequence_number=total_package, mode='rating')
srm.set_master_package(weight_value, total_package)
else:
srm.add_package(weight_value, mode='rating')
srm.set_master_package(weight_value, 1)
# Commodities for customs declaration (international shipping)
if self.fedex_service_type in ['INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'] or is_india:
total_commodities_amount = 0.0
commodity_country_of_manufacture = order.warehouse_id.partner_id.country_id.code
for line in order.order_line.filtered(lambda l: l.product_id.type in ['product', 'consu']):
commodity_amount = line.price_total / line.product_uom_qty
total_commodities_amount += (commodity_amount * line.product_uom_qty)
commodity_description = line.product_id.name
commodity_number_of_piece = '1'
commodity_weight_units = self.fedex_weight_unit
commodity_weight_value = _convert_weight(line.product_id.weight * line.product_uom_qty, self.fedex_weight_unit)
commodity_quantity = line.product_uom_qty
commodity_quantity_units = 'EA'
commodity_harmonized_code = line.product_id.hs_code or ''
srm._commodities(_convert_curr_iso_fdx(order_currency.name), commodity_amount, commodity_number_of_piece, commodity_weight_units, commodity_weight_value, commodity_description, commodity_country_of_manufacture, commodity_quantity, commodity_quantity_units, commodity_harmonized_code)
srm.customs_value(_convert_curr_iso_fdx(order_currency.name), total_commodities_amount, "NON_DOCUMENTS")
srm.duties_payment(order.warehouse_id.partner_id.country_id.code, superself.fedex_account_number)
request = srm.rate(date_planned=date_planned)
warnings = request.get('warnings_message')
if warnings:
_logger.info(warnings)
if not request.get('errors_message'):
if _convert_curr_iso_fdx(order_currency.name) in request['price']:
price = request['price'][_convert_curr_iso_fdx(order_currency.name)]
else:
_logger.info("Preferred currency has not been found in FedEx response")
company_currency = order.company_id.currency_id
if _convert_curr_iso_fdx(company_currency.name) in request['price']:
price = company_currency.compute(request['price'][_convert_curr_iso_fdx(company_currency.name)], order_currency)
else:
price = company_currency.compute(request['price']['USD'], order_currency)
else:
return {'success': False,
'price': 0.0,
'error_message': _('Error:\n%s') % request['errors_message'],
'warning_message': False}
return {'success': True,
'price': float(price),
'error_message': False,
'transit_days': request.get('transit_days', False),
'date_delivered': request.get('date_delivered', False),
'warning_message': _('Warning:\n%s') % warnings if warnings else False}
"""
Overrides to use Hibou Delivery methods to get shipper etc. and add insurance.
"""
def fedex_send_shipping(self, pickings):
res = []
for picking in pickings:
srm = FedexRequest(self.log_xml, request_type="shipping", prod_environment=self.prod_environment)
superself = self.sudo()
shipper_company = superself.get_shipper_company(picking=picking)
shipper_warehouse = superself.get_shipper_warehouse(picking=picking)
recipient = superself.get_recipient(picking=picking)
acc_number = superself._get_fedex_account_number(picking=picking)
meter_number = superself._get_fedex_meter_number(picking=picking)
payment_acc_number = superself._get_fedex_payment_account_number()
order_name = superself.get_order_name(picking=picking)
attn = superself.get_attn(picking=picking)
insurance_value = superself.get_insurance_value(picking=picking)
residential = self._get_fedex_recipient_is_residential(recipient)
srm.web_authentication_detail(superself.fedex_developer_key, superself.fedex_developer_password)
srm.client_detail(acc_number, meter_number)
# Not the actual reference. Using `shipment_name` during `add_package` calls.
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
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_shipper(shipper_company, shipper_warehouse)
srm.set_recipient(recipient, attn=attn, residential=residential)
srm.shipping_charges_payment(payment_acc_number, third_party=bool(self.get_third_party_account(picking=picking)))
# Commonly this needs to be modified, e.g. for doc tabs. Do not want to have to patch this entire method.
#srm.shipment_label('COMMON2D', self.fedex_label_file_type, self.fedex_label_stock_type, 'TOP_EDGE_OF_TEXT_FIRST', 'SHIPPING_LABEL_FIRST')
self._fedex_srm_shipment_label(srm, 'COMMON2D', self.fedex_label_file_type, self.fedex_label_stock_type, 'TOP_EDGE_OF_TEXT_FIRST', 'SHIPPING_LABEL_FIRST')
order_currency = picking.sale_id.currency_id or picking.company_id.currency_id
net_weight = _convert_weight(picking.shipping_weight, self.fedex_weight_unit)
# Commodities for customs declaration (international shipping)
if self.fedex_service_type in ['INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY'] or (picking.partner_id.country_id.code == 'IN' and picking.picking_type_id.warehouse_id.partner_id.country_id.code == 'IN'):
commodity_currency = order_currency
total_commodities_amount = 0.0
commodity_country_of_manufacture = picking.picking_type_id.warehouse_id.partner_id.country_id.code
for operation in picking.move_line_ids:
commodity_amount = order_currency.compute(operation.product_id.list_price, commodity_currency)
total_commodities_amount += (commodity_amount * operation.qty_done)
commodity_description = operation.product_id.name
commodity_number_of_piece = '1'
commodity_weight_units = self.fedex_weight_unit
commodity_weight_value = _convert_weight(operation.product_id.weight * operation.qty_done, self.fedex_weight_unit)
commodity_quantity = operation.qty_done
commodity_quantity_units = 'EA'
srm.commodities(_convert_curr_iso_fdx(commodity_currency.name), commodity_amount, commodity_number_of_piece, commodity_weight_units, commodity_weight_value, commodity_description, commodity_country_of_manufacture, commodity_quantity, commodity_quantity_units)
srm.customs_value(_convert_curr_iso_fdx(commodity_currency.name), total_commodities_amount, "NON_DOCUMENTS")
srm.duties_payment(picking.picking_type_id.warehouse_id.partner_id.country_id.code, superself.fedex_account_number)
package_count = len(picking.package_ids) or 1
# TODO RIM master: factorize the following crap
################
# Multipackage #
################
if package_count > 1:
# Note: Fedex has a complex multi-piece shipping interface
# - Each package has to be sent in a separate request
# - First package is called "master" package and holds shipping-
# related information, including addresses, customs...
# - Last package responses contains shipping price and code
# - If a problem happens with a package, every previous package
# of the shipping has to be cancelled separately
# (Why doing it in a simple way when the complex way exists??)
master_tracking_id = False
package_labels = []
carrier_tracking_ref = ""
for sequence, package in enumerate(picking.package_ids, start=1):
package_weight = _convert_weight(package.shipping_weight, self.fedex_weight_unit)
# Hibou Delivery
# Add more details to package.
srm.add_package(package_weight, sequence_number=sequence, ref=('%s-%d' % (order_name, sequence)), insurance=insurance_value)
srm.set_master_package(net_weight, package_count, master_tracking_id=master_tracking_id)
request = srm.process_shipment()
package_name = package.name or sequence
warnings = request.get('warnings_message')
if warnings:
_logger.info(warnings)
# First package
if sequence == 1:
if not request.get('errors_message'):
master_tracking_id = request['master_tracking_id']
package_labels.append((package_name, srm.get_label()))
carrier_tracking_ref = request['tracking_number']
else:
raise UserError(request['errors_message'])
# Intermediary packages
elif sequence > 1 and sequence < package_count:
if not request.get('errors_message'):
package_labels.append((package_name, srm.get_label()))
carrier_tracking_ref = carrier_tracking_ref + "," + request['tracking_number']
else:
raise UserError(request['errors_message'])
# Last package
elif sequence == package_count:
# recuperer le label pdf
if not request.get('errors_message'):
package_labels.append((package_name, srm.get_label()))
if _convert_curr_iso_fdx(order_currency.name) in request['price']:
carrier_price = request['price'][_convert_curr_iso_fdx(order_currency.name)]
else:
_logger.info("Preferred currency has not been found in FedEx response")
company_currency = picking.company_id.currency_id
if _convert_curr_iso_fdx(company_currency.name) in request['price']:
carrier_price = company_currency.compute(request['price'][_convert_curr_iso_fdx(company_currency.name)], order_currency)
else:
carrier_price = company_currency.compute(request['price']['USD'], order_currency)
carrier_tracking_ref = carrier_tracking_ref + "," + request['tracking_number']
logmessage = _("Shipment created into Fedex<br/>"
"<b>Tracking Numbers:</b> %s<br/>"
"<b>Packages:</b> %s") % (carrier_tracking_ref, ','.join([pl[0] for pl in package_labels]))
if self.fedex_label_file_type != 'PDF':
attachments = [('LabelFedex-%s.%s' % (pl[0], self.fedex_label_file_type), pl[1]) for pl in package_labels]
if self.fedex_label_file_type == 'PDF':
attachments = [('LabelFedex.pdf', pdf.merge_pdf([pl[1] for pl in package_labels]))]
picking.message_post(body=logmessage, attachments=attachments)
shipping_data = {'exact_price': carrier_price,
'tracking_number': carrier_tracking_ref}
res = res + [shipping_data]
else:
raise UserError(request['errors_message'])
# TODO RIM handle if a package is not accepted (others should be deleted)
###############
# One package #
###############
elif package_count == 1:
# Hibou Delivery
# Add more details to package.
srm.add_package(net_weight, ref=order_name, insurance=insurance_value)
srm.set_master_package(net_weight, 1)
# Ask the shipping to fedex
request = srm.process_shipment()
warnings = request.get('warnings_message')
if warnings:
_logger.info(warnings)
if not request.get('errors_message'):
if _convert_curr_iso_fdx(order_currency.name) in request['price']:
carrier_price = request['price'][_convert_curr_iso_fdx(order_currency.name)]
else:
_logger.info("Preferred currency has not been found in FedEx response")
company_currency = picking.company_id.currency_id
if _convert_curr_iso_fdx(company_currency.name) in request['price']:
carrier_price = company_currency.compute(request['price'][_convert_curr_iso_fdx(company_currency.name)], order_currency)
else:
carrier_price = company_currency.compute(request['price']['USD'], order_currency)
carrier_tracking_ref = request['tracking_number']
logmessage = (_("Shipment created into Fedex <br/> <b>Tracking Number : </b>%s") % (carrier_tracking_ref))
fedex_labels = [('LabelFedex-%s-%s.%s' % (carrier_tracking_ref, index, self.fedex_label_file_type), label)
for index, label in enumerate(srm._get_labels(self.fedex_label_file_type))]
picking.message_post(body=logmessage, attachments=fedex_labels)
shipping_data = {'exact_price': carrier_price,
'tracking_number': carrier_tracking_ref}
res = res + [shipping_data]
else:
raise UserError(request['errors_message'])
##############
# No package #
##############
else:
raise UserError(_('No packages for this picking'))
return res

View File

@@ -0,0 +1,186 @@
import suds
from odoo.addons.delivery_fedex.models import fedex_request
from pprint import pformat
import logging
_logger = logging.getLogger(__name__)
STATECODE_REQUIRED_COUNTRIES = fedex_request.STATECODE_REQUIRED_COUNTRIES
def sanitize_name(name):
if isinstance(name, str):
return name.replace('[', '').replace(']', '')
return 'Unknown'
class FedexRequest(fedex_request.FedexRequest):
_transit_days = {
'ONE_DAYS': 1,
'ONE_DAY': 1,
'TWO_DAYS': 2,
'THREE_DAYS': 3,
'FOUR_DAYS': 4,
'FIVE_DAYS': 5,
'SIX_DAYS': 6,
'SEVEN_DAYS': 7,
'EIGHT_DAYS': 8,
'NINE_DAYS': 9,
'TEN_DAYS': 10,
}
_service_transit_days = {
'FEDEX_2_DAY': 2,
'FEDEX_2_DAY_AM': 2,
'FIRST_OVERNIGHT': 1,
'PRIORITY_OVERNIGHT': 1,
'STANDARD_OVERNIGHT': 1,
}
def set_recipient(self, recipient_partner, attn=None, residential=False):
"""
Adds ATTN: and sanitizes against known 'illegal' common characters in names.
:param recipient_partner: default
:param attn: NEW add to contact name as an ' ATTN: $attn'
:param residential: NEW allow ground home delivery
:return:
"""
Contact = self.client.factory.create('Contact')
if recipient_partner.is_company:
Contact.PersonName = ''
Contact.CompanyName = sanitize_name(recipient_partner.name)
elif recipient_partner.name == recipient_partner.parent_id.name:
Contact.PersonName = recipient_partner.name
Contact.CompanyName = ''
else:
Contact.PersonName = sanitize_name(recipient_partner.name)
Contact.CompanyName = sanitize_name(recipient_partner.parent_id.name or '')
if attn:
Contact.PersonName = Contact.PersonName + ' ATTN: ' + str(attn)
Contact.PhoneNumber = recipient_partner.phone or ''
Address = self.client.factory.create('Address')
Address.StreetLines = [recipient_partner.street or '', recipient_partner.street2 or '']
Address.City = recipient_partner.city or ''
if recipient_partner.country_id.code in STATECODE_REQUIRED_COUNTRIES:
Address.StateOrProvinceCode = recipient_partner.state_id.code or ''
else:
Address.StateOrProvinceCode = ''
Address.PostalCode = recipient_partner.zip or ''
Address.CountryCode = recipient_partner.country_id.code or ''
if residential:
Address.Residential = True
self.RequestedShipment.Recipient.Contact = Contact
self.RequestedShipment.Recipient.Address = Address
def add_package(self, weight_value, sequence_number=False, mode='shipping', ref=False, insurance=False):
"""
Adds ref type of object to include.
:param weight_value: default
:param sequence_number: default
:param mode: default
:param ref: NEW add CUSTOMER_REFERENCE object
:param insurance: NEW add Insurance amount
:return:
"""
package = self.client.factory.create('RequestedPackageLineItem')
package_weight = self.client.factory.create('Weight')
package_weight.Value = weight_value
package_weight.Units = self.RequestedShipment.TotalWeight.Units
if ref:
customer_ref = self.client.factory.create('CustomerReference')
customer_ref.CustomerReferenceType = 'CUSTOMER_REFERENCE'
customer_ref.Value = str(ref)
package.CustomerReferences.append(customer_ref)
if insurance:
insured = self.client.factory.create('Money')
insured.Amount = insurance
# TODO at some point someone might need currency here
insured.Currency = 'USD'
package.InsuredValue = insured
package.PhysicalPackaging = 'BOX'
package.Weight = package_weight
if mode == 'rating':
package.GroupPackageCount = 1
if sequence_number:
package.SequenceNumber = sequence_number
else:
self.hasOnePackage = True
if mode == 'rating':
self.RequestedShipment.RequestedPackageLineItems.append(package)
else:
self.RequestedShipment.RequestedPackageLineItems = package
def shipping_charges_payment(self, shipping_charges_payment_account, third_party=False):
"""
Allow 'shipping_charges_payment_account' to be considered 'third_party'
:param shipping_charges_payment_account: default
:param third_party: NEW add to indicate that the 'shipping_charges_payment_account' is third party.
:return:
"""
self.RequestedShipment.ShippingChargesPayment.PaymentType = 'SENDER' if not third_party else 'THIRD_PARTY'
Payor = self.client.factory.create('Payor')
Payor.ResponsibleParty.AccountNumber = shipping_charges_payment_account
self.RequestedShipment.ShippingChargesPayment.Payor = Payor
# Rating stuff
def rate(self, date_planned=None):
"""
Response will contain 'transit_days' key with number of days.
:param date_planned: Planned Outgoing shipment. Used to have FedEx tell us how long it will take for the package to arrive.
:return:
"""
formatted_response = {'price': {}}
del self.ClientDetail.Region
if date_planned:
# though Fedex sends BACK timestamps like `2020-01-01 00:00:00` they EXPECT `2020-01-01T00:00:00`
self.RequestedShipment.ShipTimestamp = date_planned.replace(' ', 'T')
try:
self.response = self.client.service.getRates(WebAuthenticationDetail=self.WebAuthenticationDetail,
ClientDetail=self.ClientDetail,
TransactionDetail=self.TransactionDetail,
Version=self.VersionId,
RequestedShipment=self.RequestedShipment,
ReturnTransitAndCommit=True) # New ReturnTransitAndCommit for CommitDetails in response
if (self.response.HighestSeverity != 'ERROR' and self.response.HighestSeverity != 'FAILURE'):
for rating in self.response.RateReplyDetails[0].RatedShipmentDetails:
formatted_response['price'][rating.ShipmentRateDetail.TotalNetFedExCharge.Currency] = rating.ShipmentRateDetail.TotalNetFedExCharge.Amount
if len(self.response.RateReplyDetails[0].RatedShipmentDetails) == 1:
if 'CurrencyExchangeRate' in self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail:
formatted_response['price'][self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.FromCurrency] = self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.TotalNetFedExCharge.Amount / self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.Rate
# Hibou Delivery Planning
if hasattr(self.response.RateReplyDetails[0], 'DeliveryTimestamp') and self.response.RateReplyDetails[0].DeliveryTimestamp:
formatted_response['date_delivered'] = self.response.RateReplyDetails[0].DeliveryTimestamp
elif hasattr(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)
elif 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
else:
errors_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if (n.Severity == 'ERROR' or n.Severity == 'FAILURE')])
formatted_response['errors_message'] = errors_message
if any([n.Severity == 'WARNING' for n in self.response.Notifications]):
warnings_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if n.Severity == 'WARNING'])
formatted_response['warnings_message'] = warnings_message
except suds.WebFault as fault:
formatted_response['errors_message'] = fault
except IOError:
formatted_response['errors_message'] = "Fedex Server Not Found"
return formatted_response

View File

@@ -0,0 +1,8 @@
from odoo import api, fields, models
class StockWarehouse(models.Model):
_inherit = 'stock.warehouse'
fedex_account_number = fields.Char(string='FedEx Account Number')
fedex_meter_number = fields.Char(string='FedEx Meter Number')

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record id="fedex_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="fedex_account_number"/>
<field name="fedex_meter_number"/>
</xpath>
</field>
</record>
</odoo>