# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import binascii
import logging
import re

from datetime import datetime, date
from os.path import join as opj
from odoo.tools.zeep import Client, Plugin, Settings
from odoo.tools.zeep.exceptions import Fault
from odoo.tools.zeep.wsdl.utils import etree_to_string

from odoo.tools import remove_accents, float_repr
from odoo.tools.misc import file_path


_logger = logging.getLogger(__name__)
# uncomment to enable logging of Zeep requests and responses
# logging.getLogger('zeep.transports').setLevel(logging.DEBUG)


STATECODE_REQUIRED_COUNTRIES = ['US', 'CA', 'PR ', 'IN']

# Why using standardized ISO codes? It's way more fun to use made up codes...
# https://www.fedex.com/us/developer/WebHelp/ws/2014/dvg/WS_DVG_WebHelp/Appendix_F_Currency_Codes.htm
FEDEX_CURR_MATCH = {
    u'UYU': u'UYP',
    u'XCD': u'ECD',
    u'MXN': u'NMP',
    u'KYD': u'CID',
    u'CHF': u'SFR',
    u'GBP': u'UKL',
    u'IDR': u'RPA',
    u'DOP': u'RDD',
    u'JPY': u'JYE',
    u'KRW': u'WON',
    u'SGD': u'SID',
    u'CLP': u'CHP',
    u'JMD': u'JAD',
    u'KWD': u'KUD',
    u'AED': u'DHS',
    u'TWD': u'NTD',
    u'ARS': u'ARN',
    u'LVL': u'EURO',
}

class LogPlugin(Plugin):
    """ Small plugin for zeep that catches out/ingoing XML requests and logs them"""
    def __init__(self, debug_logger):
        self.debug_logger = debug_logger

    def egress(self, envelope, http_headers, operation, binding_options):
        self.debug_logger(etree_to_string(envelope).decode(), 'fedex_request')
        return envelope, http_headers

    def ingress(self, envelope, http_headers, operation):
        self.debug_logger(etree_to_string(envelope).decode(), 'fedex_response')
        return envelope, http_headers

    def marshalled(self, context):
        context.envelope = context.envelope.prune()


class FedexRequest():
    """ Low-level object intended to interface Odoo recordsets with FedEx,
        through appropriate SOAP requests """

    def __init__(self, debug_logger, request_type="shipping", prod_environment=False, ):
        self.debug_logger = debug_logger
        self.hasCommodities = False

        wsdl_folder = 'prod' if prod_environment else 'test'
        if request_type == "shipping":
            wsdl_path = opj('fusion_shipping', 'api', 'fedex', 'wsdl', wsdl_folder, 'ShipService_v28.wsdl')
            self.start_shipping_transaction(wsdl_path)
        elif request_type == "rating":
            wsdl_path = opj('fusion_shipping', 'api', 'fedex', 'wsdl', wsdl_folder, 'RateService_v31.wsdl')
            self.start_rating_transaction(wsdl_path)

    # Authentification stuff

    def web_authentication_detail(self, key, password):
        WebAuthenticationCredential = self.factory.WebAuthenticationCredential()
        WebAuthenticationCredential.Key = key
        WebAuthenticationCredential.Password = password
        self.WebAuthenticationDetail = self.factory.WebAuthenticationDetail()
        self.WebAuthenticationDetail.UserCredential = WebAuthenticationCredential

    def transaction_detail(self, transaction_id):
        self.TransactionDetail = self.factory.TransactionDetail()
        self.TransactionDetail.CustomerTransactionId = transaction_id

    def client_detail(self, account_number, meter_number):
        self.ClientDetail = self.factory.ClientDetail()
        self.ClientDetail.AccountNumber = account_number
        self.ClientDetail.MeterNumber = meter_number

    # Common stuff

    def set_shipper(self, company_partner, warehouse_partner):
        Contact = self.factory.Contact()
        Contact.PersonName = remove_accents(company_partner.name) if not company_partner.is_company else ''
        Contact.CompanyName = remove_accents(company_partner.commercial_company_name) or ''
        Contact.PhoneNumber = warehouse_partner.phone or ''
        Contact.EMailAddress = warehouse_partner.email or ''
        # TODO fedex documentation asks for TIN number, but it seems to work without

        Address = self.factory.Address()
        Address.StreetLines = [remove_accents(warehouse_partner.street) or '',remove_accents(warehouse_partner.street2) or '']
        Address.City = remove_accents(warehouse_partner.city) or ''
        if warehouse_partner.country_id.code in STATECODE_REQUIRED_COUNTRIES:
            Address.StateOrProvinceCode = warehouse_partner.state_id.code or ''
        else:
            Address.StateOrProvinceCode = ''
        Address.PostalCode = warehouse_partner.zip or ''
        Address.CountryCode = warehouse_partner.country_id.code or ''

        self.RequestedShipment.Shipper = self.factory.Party()
        self.RequestedShipment.Shipper.Contact = Contact
        self.RequestedShipment.Shipper.Address = Address

    def set_recipient(self, recipient_partner):
        Contact = self.factory.Contact()
        if recipient_partner.is_company:
            Contact.PersonName = ''
            Contact.CompanyName = remove_accents(recipient_partner.name)
        else:
            Contact.PersonName = remove_accents(recipient_partner.name)
            Contact.CompanyName = remove_accents(recipient_partner.commercial_company_name) or ''
        Contact.PhoneNumber = recipient_partner.phone or ''
        Contact.EMailAddress = recipient_partner.email or ''

        Address = self.factory.Address()
        Address.StreetLines = [remove_accents(recipient_partner.street) or '', remove_accents(recipient_partner.street2) or '']
        Address.City = remove_accents(recipient_partner.city) or ''
        if recipient_partner.country_id.code in STATECODE_REQUIRED_COUNTRIES:
            Address.StateOrProvinceCode = recipient_partner.state_id.code or ''
        else:
            Address.StateOrProvinceCode = ''
        Address.PostalCode = recipient_partner.zip or ''
        Address.CountryCode = recipient_partner.country_id.code or ''

        self.RequestedShipment.Recipient = self.factory.Party()
        self.RequestedShipment.Recipient.Contact = Contact
        self.RequestedShipment.Recipient.Address = Address

    def shipment_request(self, dropoff_type, service_type, packaging_type, overall_weight_unit, saturday_delivery):
        self.RequestedShipment = self.factory.RequestedShipment()
        self.RequestedShipment.SpecialServicesRequested = self.factory.ShipmentSpecialServicesRequested()
        self.RequestedShipment.ShipTimestamp = datetime.now()
        self.RequestedShipment.DropoffType = dropoff_type
        self.RequestedShipment.ServiceType = service_type
        self.RequestedShipment.PackagingType = packaging_type
        # Resuest estimation of duties and taxes for international shipping
        if service_type in ['INTERNATIONAL_ECONOMY', 'INTERNATIONAL_PRIORITY']:
            self.RequestedShipment.EdtRequestType = 'ALL'
        else:
            self.RequestedShipment.EdtRequestType = 'NONE'
        self.RequestedShipment.PackageCount = 0
        self.RequestedShipment.TotalWeight = self.factory.Weight()
        self.RequestedShipment.TotalWeight.Units = overall_weight_unit
        self.RequestedShipment.TotalWeight.Value = 0
        self.listCommodities = []
        if saturday_delivery:
            timestamp_day = self.RequestedShipment.ShipTimestamp.strftime("%A")
            if (service_type == 'FEDEX_2_DAY' and timestamp_day == 'Thursday') or (service_type in ['PRIORITY_OVERNIGHT', 'FIRST_OVERNIGHT', 'INTERNATIONAL_PRIORITY'] and timestamp_day == 'Friday'):
                self.RequestedShipment.SpecialServicesRequested.SpecialServiceTypes.append('SATURDAY_DELIVERY')

    def set_currency(self, currency):
        # set perferred currency as GBP instead of UKL
        currency = 'GBP' if currency == 'UKL' else currency
        self.RequestedShipment.PreferredCurrency = currency
        # ask Fedex to include our preferred currency in the response
        self.RequestedShipment.RateRequestTypes = 'PREFERRED'

    def set_master_package(self, weight, package_count, master_tracking_id=False):
        self.RequestedShipment.TotalWeight.Value = weight
        self.RequestedShipment.PackageCount = package_count
        if master_tracking_id:
            self.RequestedShipment.MasterTrackingId = self.factory.TrackingId()
            self.RequestedShipment.MasterTrackingId.TrackingIdType = 'FEDEX'
            self.RequestedShipment.MasterTrackingId.TrackingNumber = master_tracking_id

    # weight_value, package_code=False, package_height=0, package_width=0, package_length=0,
    def add_package(self, carrier, delivery_package, fdx_company_currency, sequence_number=False, mode='shipping', po_number=False, dept_number=False, reference=False):
        package = self.factory.RequestedPackageLineItem()
        package_weight = self.factory.Weight()
        package_weight.Value = carrier._fedex_convert_weight(delivery_package.weight, carrier.fedex_weight_unit)
        package_weight.Units = self.RequestedShipment.TotalWeight.Units

        package.PhysicalPackaging = 'BOX'
        if delivery_package.packaging_type == 'YOUR_PACKAGING':
            package.Dimensions = self.factory.Dimensions()
            package.Dimensions.Height = int(delivery_package.dimension['height'])
            package.Dimensions.Width = int(delivery_package.dimension['width'])
            package.Dimensions.Length = int(delivery_package.dimension['length'])
            # TODO in master, add unit in product packaging and perform unit conversion
            package.Dimensions.Units = "IN" if self.RequestedShipment.TotalWeight.Units == 'LB' else 'CM'
        if po_number:
            po_reference = self.factory.CustomerReference()
            po_reference.CustomerReferenceType = 'P_O_NUMBER'
            po_reference.Value = po_number
            package.CustomerReferences.append(po_reference)
        if dept_number:
            dept_reference = self.factory.CustomerReference()
            dept_reference.CustomerReferenceType = 'DEPARTMENT_NUMBER'
            dept_reference.Value = dept_number
            package.CustomerReferences.append(dept_reference)
        if reference:
            customer_reference = self.factory.CustomerReference()
            customer_reference.CustomerReferenceType = 'CUSTOMER_REFERENCE'
            customer_reference.Value = reference
            package.CustomerReferences.append(customer_reference)

        if carrier.shipping_insurance:
            package.InsuredValue = self.factory.Money()
            insured_value = delivery_package.total_cost * carrier.shipping_insurance / 100
            pkg_order = delivery_package.order_id or delivery_package.picking_id.sale_id
            # Get the currency from the sale order if it exists, so that it matches that of customs_value
            if pkg_order:
                package.InsuredValue.Currency = _convert_curr_iso_fdx(pkg_order.currency_id.name)
                package.InsuredValue.Amount = float_repr(delivery_package.company_id.currency_id._convert(insured_value, pkg_order.currency_id, pkg_order.company_id, date.today()), 2)
            else:
                package.InsuredValue.Currency = fdx_company_currency
                package.InsuredValue.Amount = float_repr(insured_value, 2)

        package.Weight = package_weight
        if mode == 'rating':
            package.GroupPackageCount = 1
        if sequence_number:
            package.SequenceNumber = sequence_number

        if mode == 'rating':
            self.RequestedShipment.RequestedPackageLineItems.append(package)
        else:
            self.RequestedShipment.RequestedPackageLineItems = package

    # Rating stuff

    def start_rating_transaction(self, wsdl_path):
        settings = Settings(strict=False)
        self.client = Client(file_path(wsdl_path), plugins=[LogPlugin(self.debug_logger)], settings=settings)
        self.factory = self.client.type_factory('ns0')
        self.VersionId = self.factory.VersionId()
        self.VersionId.ServiceId = 'crs'
        self.VersionId.Major = '31'
        self.VersionId.Intermediate = '0'
        self.VersionId.Minor = '0'

    def rate(self, request):
        formatted_response = {'price': {}}
        try:
            self.response = self.client.service.getRates(WebAuthenticationDetail=request['WebAuthenticationDetail'],
                                                         ClientDetail=request['ClientDetail'],
                                                         TransactionDetail=request['TransactionDetail'],
                                                         Version=request['VersionId'],
                                                         RequestedShipment=request['RequestedShipment'])

            if (self.response.HighestSeverity != 'ERROR' and self.response.HighestSeverity != 'FAILURE'):
                if not getattr(self.response, "RateReplyDetails", False):
                    raise Exception("No rating found")
                for rating in self.response.RateReplyDetails[0].RatedShipmentDetails:
                    formatted_response['price'][rating.ShipmentRateDetail.TotalNetFedExCharge.Currency] = float(rating.ShipmentRateDetail.TotalNetFedExCharge.Amount)
                    if len(self.response.RateReplyDetails[0].RatedShipmentDetails) == 1:
                        if 'CurrencyExchangeRate' in self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail and self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail['CurrencyExchangeRate']:
                            formatted_response['price'][self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.FromCurrency] = float(self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.TotalNetFedExCharge.Amount) / float(self.response.RateReplyDetails[0].RatedShipmentDetails[0].ShipmentRateDetail.CurrencyExchangeRate.Rate)
            else:
                errors_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if (n.Severity == 'ERROR' or n.Severity == 'FAILURE')])
                formatted_response['errors_message'] = errors_message

            if any([n.Severity == 'WARNING' for n in self.response.Notifications]):
                warnings_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if n.Severity == 'WARNING'])
                formatted_response['warnings_message'] = warnings_message

        except Fault as fault:
            formatted_response['errors_message'] = fault
        except IOError:
            formatted_response['errors_message'] = "Fedex Server Not Found"
        except Exception as e:
            formatted_response['errors_message'] = e.args[0]

        return formatted_response

    # Shipping stuff

    def start_shipping_transaction(self, wsdl_path):
        self.client = Client(file_path(wsdl_path), plugins=[LogPlugin(self.debug_logger)])
        self.factory = self.client.type_factory("ns0")
        self.VersionId = self.factory.VersionId()
        self.VersionId.ServiceId = 'ship'
        self.VersionId.Major = '28'
        self.VersionId.Intermediate = '0'
        self.VersionId.Minor = '0'

    def shipment_label(self, label_format_type, image_type, label_stock_type, label_printing_orientation, label_order):
        LabelSpecification = self.factory.LabelSpecification()
        LabelSpecification.LabelFormatType = label_format_type
        LabelSpecification.ImageType = image_type
        LabelSpecification.LabelStockType = label_stock_type
        LabelSpecification.LabelPrintingOrientation = label_printing_orientation
        LabelSpecification.LabelOrder = label_order
        self.RequestedShipment.LabelSpecification = LabelSpecification

    def commercial_invoice(self, document_stock_type, send_etd=False):
        shipping_document = self.factory.ShippingDocumentSpecification()
        shipping_document.ShippingDocumentTypes = "COMMERCIAL_INVOICE"
        commercial_invoice_detail = self.factory.CommercialInvoiceDetail()
        commercial_invoice_detail.Format = self.factory.ShippingDocumentFormat()
        commercial_invoice_detail.Format.ImageType = "PDF"
        commercial_invoice_detail.Format.StockType = document_stock_type
        shipping_document.CommercialInvoiceDetail = commercial_invoice_detail
        self.RequestedShipment.ShippingDocumentSpecification = shipping_document
        if send_etd:
            self.RequestedShipment.SpecialServicesRequested.SpecialServiceTypes.append('ELECTRONIC_TRADE_DOCUMENTS')
            etd_details = self.factory.EtdDetail()
            etd_details.RequestedDocumentCopies.append('COMMERCIAL_INVOICE')
            self.RequestedShipment.SpecialServicesRequested.EtdDetail = etd_details

    def shipping_charges_payment(self, shipping_charges_payment_account):
        self.RequestedShipment.ShippingChargesPayment = self.factory.Payment()
        self.RequestedShipment.ShippingChargesPayment.PaymentType = 'SENDER'
        Payor = self.factory.Payor()
        Payor.ResponsibleParty = self.factory.Party()
        Payor.ResponsibleParty.AccountNumber = shipping_charges_payment_account
        self.RequestedShipment.ShippingChargesPayment.Payor = Payor

    def duties_payment(self, sender_party, responsible_account_number, payment_type):
        self.RequestedShipment.CustomsClearanceDetail.DutiesPayment = self.factory.Payment()
        self.RequestedShipment.CustomsClearanceDetail.DutiesPayment.PaymentType = payment_type
        if payment_type == 'SENDER':
            Payor = self.factory.Payor()
            Payor.ResponsibleParty = self.factory.Party()
            Payor.ResponsibleParty.Address = self.factory.Address()
            Payor.ResponsibleParty.Address.CountryCode = sender_party.country_id.code
            Payor.ResponsibleParty.AccountNumber = responsible_account_number
            self.RequestedShipment.CustomsClearanceDetail.DutiesPayment.Payor = Payor

    def customs_value(self, customs_value_currency, customs_value_amount, document_content):
        self.RequestedShipment.CustomsClearanceDetail = self.factory.CustomsClearanceDetail()
        if self.hasCommodities:
            self.RequestedShipment.CustomsClearanceDetail.Commodities = self.listCommodities
        self.RequestedShipment.CustomsClearanceDetail.CustomsValue = self.factory.Money()
        self.RequestedShipment.CustomsClearanceDetail.CustomsValue.Currency = customs_value_currency
        self.RequestedShipment.CustomsClearanceDetail.CustomsValue.Amount = float_repr(customs_value_amount, 2)
        if self.RequestedShipment.Shipper.Address.CountryCode == "IN" and self.RequestedShipment.Recipient.Address.CountryCode == "IN":
            if not self.RequestedShipment.CustomsClearanceDetail.CommercialInvoice:
                self.RequestedShipment.CustomsClearanceDetail.CommercialInvoice = self.factory.CommercialInvoice()
            else:
                del self.RequestedShipment.CustomsClearanceDetail.CommercialInvoice.TaxesOrMiscellaneousChargeType
            self.RequestedShipment.CustomsClearanceDetail.CommercialInvoice.Purpose = 'SOLD'
        # Old keys not requested anymore but still in WSDL; not removing them causes crash
        del self.RequestedShipment.CustomsClearanceDetail['ClearanceBrokerage']
        del self.RequestedShipment.CustomsClearanceDetail['FreightOnValue']

        self.RequestedShipment.CustomsClearanceDetail.DocumentContent = document_content

    def commodities(self, carrier, delivery_commodity, commodity_currency):
        self.hasCommodities = True
        commodity = self.factory.Commodity()
        commodity.UnitPrice = self.factory.Money()
        commodity.UnitPrice.Currency = commodity_currency
        commodity.UnitPrice.Amount = delivery_commodity.monetary_value
        commodity.NumberOfPieces = '1'
        commodity.CountryOfManufacture = delivery_commodity.country_of_origin

        commodity_weight = self.factory.Weight()
        commodity_weight.Value = carrier._fedex_convert_weight(delivery_commodity.product_id.weight * delivery_commodity.qty, carrier.fedex_weight_unit)
        commodity_weight.Units = carrier.fedex_weight_unit

        commodity.Weight = commodity_weight
        commodity.Description = re.sub(r'[\[\]<>;={}"|]', '', delivery_commodity.product_id.name)
        commodity.Quantity = delivery_commodity.qty
        commodity.QuantityUnits = 'EA'
        customs_value = self.factory.Money()
        customs_value.Currency = commodity_currency
        customs_value.Amount = delivery_commodity.monetary_value * delivery_commodity.qty
        commodity.CustomsValue = customs_value

        commodity.HarmonizedCode = delivery_commodity.product_id.hs_code.replace(".", "") if delivery_commodity.product_id.hs_code else ''

        self.listCommodities.append(commodity)

    def return_label(self, tracking_number, origin_date):
        return_details = self.factory.ReturnShipmentDetail()
        return_details.ReturnType = "PRINT_RETURN_LABEL"
        if tracking_number and origin_date:
            return_association = self.factory.ReturnAssociationDetail()
            return_association.TrackingNumber = tracking_number
            return_association.ShipDate = origin_date
            return_details.ReturnAssociation = return_association
        self.RequestedShipment.SpecialServicesRequested.SpecialServiceTypes.append("RETURN_SHIPMENT")
        self.RequestedShipment.SpecialServicesRequested.ReturnShipmentDetail = return_details
        if self.hasCommodities:
            bla = self.factory.CustomsOptionDetail()
            bla.Type = "FAULTY_ITEM"
            self.RequestedShipment.CustomsClearanceDetail.CustomsOptions = bla

    def process_shipment(self, request):
        formatted_response = {'tracking_number': 0.0,
                              'price': {},
                              'master_tracking_id': None,
                              'date': None}
        try:
            self.response = self.client.service.processShipment(WebAuthenticationDetail=request['WebAuthenticationDetail'],
                                                                ClientDetail=request['ClientDetail'],
                                                                TransactionDetail=request['TransactionDetail'],
                                                                Version=request['VersionId'],
                                                                RequestedShipment=request['RequestedShipment'])

            if (self.response.HighestSeverity != 'ERROR' and self.response.HighestSeverity != 'FAILURE'):
                formatted_response['tracking_number'] = self.response.CompletedShipmentDetail.CompletedPackageDetails[0].TrackingIds[0].TrackingNumber
                if 'CommitDate' in self.response.CompletedShipmentDetail.OperationalDetail:
                    formatted_response['date'] = self.response.CompletedShipmentDetail.OperationalDetail.CommitDate
                else:
                    formatted_response['date'] = date.today()

                if 'ShipmentRating' in self.response.CompletedShipmentDetail and self.response.CompletedShipmentDetail.ShipmentRating:
                    for rating in self.response.CompletedShipmentDetail.ShipmentRating.ShipmentRateDetails:
                        formatted_response['price'][rating.TotalNetFedExCharge.Currency] = float(rating.TotalNetFedExCharge.Amount)
                        if 'CurrencyExchangeRate' in rating and rating.CurrencyExchangeRate:
                            formatted_response['price'][rating.CurrencyExchangeRate.FromCurrency] = float(rating.TotalNetFedExCharge.Amount / rating.CurrencyExchangeRate.Rate)
                else:
                    formatted_response['price']['USD'] = 0.0
                if 'MasterTrackingId' in self.response.CompletedShipmentDetail:
                    formatted_response['master_tracking_id'] = self.response.CompletedShipmentDetail.MasterTrackingId.TrackingNumber

            else:
                errors_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if (n.Severity == 'ERROR' or n.Severity == 'FAILURE')])
                formatted_response['errors_message'] = errors_message

            if any([n.Severity == 'WARNING' for n in self.response.Notifications]):
                warnings_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if n.Severity == 'WARNING'])
                formatted_response['warnings_message'] = warnings_message

        except Fault as fault:
            formatted_response['errors_message'] = fault
        except IOError:
            formatted_response['errors_message'] = "Fedex Server Not Found"

        return formatted_response

    def _get_labels(self, file_type):
        labels = [self.get_label()]
        if file_type.upper() in ['PNG'] and self.response.CompletedShipmentDetail.CompletedPackageDetails[0].PackageDocuments:
            for auxiliary in self.response.CompletedShipmentDetail.CompletedPackageDetails[0].PackageDocuments[0].Parts:
                labels.append(auxiliary.Image)

        return labels

    def get_label(self):
        return self.response.CompletedShipmentDetail.CompletedPackageDetails[0].Label.Parts[0].Image

    def get_document(self):
        if self.response.CompletedShipmentDetail.ShipmentDocuments:
            return self.response.CompletedShipmentDetail.ShipmentDocuments[0].Parts[0].Image
        else:
            return False

    # Deletion stuff

    def set_deletion_details(self, tracking_number):
        self.TrackingId = self.factory.TrackingId()
        self.TrackingId.TrackingIdType = 'FEDEX'
        self.TrackingId.TrackingNumber = tracking_number

        self.DeletionControl = self.factory.DeletionControlType('DELETE_ALL_PACKAGES')

    def delete_shipment(self, request):
        formatted_response = {'delete_success': False}
        try:
            # Here, we send the Order 66
            self.response = self.client.service.deleteShipment(WebAuthenticationDetail=request['WebAuthenticationDetail'],
                                                               ClientDetail=request['ClientDetail'],
                                                               TransactionDetail=request['TransactionDetail'],
                                                               Version=request['VersionId'],
                                                               TrackingId=request['TrackingId'],
                                                               DeletionControl=request['DeletionControl'])

            if (self.response.HighestSeverity != 'ERROR' and self.response.HighestSeverity != 'FAILURE'):
                formatted_response['delete_success'] = True
            else:
                errors_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if (n.Severity == 'ERROR' or n.Severity == 'FAILURE')])
                formatted_response['errors_message'] = errors_message

            if any([n.Severity == 'WARNING' for n in self.response.Notifications]):
                warnings_message = '\n'.join([("%s: %s" % (n.Code, n.Message)) for n in self.response.Notifications if n.Severity == 'WARNING'])
                formatted_response['warnings_message'] = warnings_message

        except Fault as fault:
            formatted_response['errors_message'] = fault
        except IOError:
            formatted_response['errors_message'] = "Fedex Server Not Found"

        return formatted_response

def _convert_curr_fdx_iso(code):
    curr_match = {v: k for k, v in FEDEX_CURR_MATCH.items()}
    return curr_match.get(code, code)


def _convert_curr_iso_fdx(code):
    return FEDEX_CURR_MATCH.get(code, code)
