Author: sichen
Date: Thu Feb 8 10:41:20 2007 New Revision: 504996 URL: http://svn.apache.org/viewvc?view=rev&rev=504996 Log: Support for FedEx subscription and ship requests via FedEx Ship Manager Direct API Added: ofbiz/trunk/applications/product/servicedef/services_shipment_fedex.xml (with props) ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/fedex/ ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/fedex/FedexServices.java (with props) ofbiz/trunk/applications/product/templates/ ofbiz/trunk/applications/product/templates/shipment/ ofbiz/trunk/applications/product/templates/shipment/FedexShipRequestTemplate.xml (with props) ofbiz/trunk/applications/product/templates/shipment/FedexSubscriptionRequestTemplate.xml (with props) Modified: ofbiz/trunk/applications/ecommerce/data/DemoShipping.xml ofbiz/trunk/applications/product/config/ProductUiLabels.properties ofbiz/trunk/applications/product/config/shipment.properties ofbiz/trunk/applications/product/entitydef/entitymodel_shipment.xml ofbiz/trunk/applications/product/ofbiz-component.xml ofbiz/trunk/applications/product/webapp/facility/WEB-INF/controller.xml ofbiz/trunk/applications/product/webapp/facility/shipment/EditShipmentPackages.ftl ofbiz/trunk/applications/product/webapp/facility/shipment/EditShipmentRouteSegments.ftl Modified: ofbiz/trunk/applications/ecommerce/data/DemoShipping.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/ecommerce/data/DemoShipping.xml?view=diff&rev=504996&r1=504995&r2=504996 ============================================================================== --- ofbiz/trunk/applications/ecommerce/data/DemoShipping.xml (original) +++ ofbiz/trunk/applications/ecommerce/data/DemoShipping.xml Thu Feb 8 10:41:20 2007 @@ -45,6 +45,8 @@ <ShipmentMethodType description="No Shipping" shipmentMethodTypeId="NO_SHIPPING"/> <ShipmentMethodType description="Second Day" shipmentMethodTypeId="SECOND_DAY"/> <ShipmentMethodType description="Next Afternoon" shipmentMethodTypeId="NEXT_PM"/> + <ShipmentMethodType description="Next Morning" shipmentMethodTypeId="NEXT_AM"/> + <ShipmentMethodType description="Ground Home Delivery" shipmentMethodTypeId="GROUND_HOME"/> <CarrierShipmentMethod partyId="Company" roleTypeId="CARRIER" shipmentMethodTypeId="LOCAL_DELIVERY" sequenceNumber="4"/> <CarrierShipmentMethod partyId="USPS" roleTypeId="CARRIER" shipmentMethodTypeId="STANDARD" sequenceNumber="7" carrierServiceCode="Priority"/> @@ -58,9 +60,13 @@ <CarrierShipmentMethod partyId="DHL" roleTypeId="CARRIER" shipmentMethodTypeId="NEXT_PM" sequenceNumber="10" carrierServiceCode="N"/> <CarrierShipmentMethod partyId="DHL" roleTypeId="CARRIER" shipmentMethodTypeId="SECOND_DAY" sequenceNumber="11" carrierServiceCode="S"/> <CarrierShipmentMethod partyId="DHL" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND" sequenceNumber="12" carrierServiceCode="G"/> - <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="EXPRESS"/> - <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="SECOND_DAY"/> - <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND"/> + <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="NEXT_AM" sequenceNumber="13" carrierServiceCode="FIRSTOVERNIGHT"/> + <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="NEXT_DAY" sequenceNumber="14" carrierServiceCode="PRIORITYOVERNIGHT"/> + <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="NEXT_PM" sequenceNumber="15" carrierServiceCode="STANDARDOVERNIGHT"/> + <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="SECOND_DAY" sequenceNumber="16" carrierServiceCode="FEDEX2DAY"/> + <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="EXPRESS" sequenceNumber="17" carrierServiceCode="FEDEXEXPRESSSAVER"/> + <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND" sequenceNumber="18" carrierServiceCode="FEDEXGROUND"/> + <CarrierShipmentMethod partyId="FEDEX" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND_HOME" sequenceNumber="19" carrierServiceCode="GROUNDHOMEDELIVERY"/> <ProductStoreShipmentMeth productStoreId="9000" partyId="_NA_" includeNoChargeItems="Y" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="NO_SHIPPING" sequenceNumber="6"/> <ProductStoreShipmentMeth productStoreId="9000" partyId="UPS" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND" sequenceNumber="3"/> @@ -72,10 +78,14 @@ <ProductStoreShipmentMeth productStoreId="9000" partyId="DHL" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="NEXT_PM" sequenceNumber="8"/> <ProductStoreShipmentMeth productStoreId="9000" partyId="DHL" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="SECOND_DAY" sequenceNumber="9"/> <ProductStoreShipmentMeth productStoreId="9000" partyId="DHL" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND" sequenceNumber="10"/> - <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="EXPRESS" sequenceNumber="10"/> - <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="SECOND_DAY" sequenceNumber="11"/> - <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND" sequenceNumber="12"/> - + <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="NEXT_AM" sequenceNumber="11"/> + <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="NEXT_DAY" sequenceNumber="12"/> + <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="NEXT_PM" sequenceNumber="13"/> + <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="SECOND_DAY" sequenceNumber="14"/> + <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="EXPRESS" sequenceNumber="15"/> + <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND" sequenceNumber="16"/> + <ProductStoreShipmentMeth productStoreId="9000" partyId="FEDEX" includeNoChargeItems="N" allowUspsAddr="N" requireUspsAddr="N" roleTypeId="CARRIER" shipmentMethodTypeId="GROUND_HOME" sequenceNumber="17"/> + <QuantityBreak fromQuantity="0.0" quantityBreakId="9000" quantityBreakTypeId="SHIP_WEIGHT" thruQuantity="0.0"/> <QuantityBreak fromQuantity="0.0" quantityBreakId="9001" quantityBreakTypeId="SHIP_WEIGHT" thruQuantity="0.0"/> <QuantityBreak fromQuantity="0.0" quantityBreakId="9002" quantityBreakTypeId="SHIP_WEIGHT" thruQuantity="0.0"/> @@ -97,7 +107,36 @@ <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="9.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9101" shipmentMethodTypeId="NEXT_PM" carrierPartyId="DHL" carrierRoleTypeId="CARRIER" weightBreakId="9004" weightUnitPrice="0.2"/> <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="5.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9102" shipmentMethodTypeId="SECOND_DAY" carrierPartyId="DHL" carrierRoleTypeId="CARRIER" weightBreakId="9005" weightUnitPrice="0.2"/> <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="3.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9103" shipmentMethodTypeId="GROUND" carrierPartyId="DHL" carrierRoleTypeId="CARRIER" weightBreakId="9006" weightUnitPrice="0.1"/> - <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="12.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9203" shipmentMethodTypeId="EXPRESS" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER" weightBreakId="9007" weightUnitPrice="0.1"/> - <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="9.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9203" shipmentMethodTypeId="SECOND_DAY" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER" weightBreakId="9008" weightUnitPrice="0.1"/> - <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="3.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9203" shipmentMethodTypeId="GROUND" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER" weightBreakId="9009" weightUnitPrice="0.1"/> + <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="0.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9203" shipmentMethodTypeId="NEXT_AM" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER"/> + <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="0.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9204" shipmentMethodTypeId="NEXT_DAY" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER"/> + <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="0.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9205" shipmentMethodTypeId="NEXT_PM" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER"/> + <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="0.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9206" shipmentMethodTypeId="SECOND_DAY" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER"/> + <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="0.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9207" shipmentMethodTypeId="EXPRESS" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER"/> + <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="0.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9208" shipmentMethodTypeId="GROUND" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER"/> + <ShipmentCostEstimate productStoreId="9000" orderFlatPrice="0.0" orderItemFlatPrice="0.0" orderPricePercent="0.0" shipmentCostEstimateId="9209" shipmentMethodTypeId="GROUND_HOME" carrierPartyId="FEDEX" carrierRoleTypeId="CARRIER"/> + + <ShipmentBoxType shipmentBoxTypeId="FXENV" description="FedEx Envelope" dimensionUomId="LEN_in" boxLength="9.5" boxWidth="12.5" boxHeight="0"/> + <ShipmentBoxType shipmentBoxTypeId="FXENV_LGL" description="FedEx Envelope (Legal)" dimensionUomId="LEN_in" boxLength="10" boxWidth="15.75" boxHeight="0"/> + <ShipmentBoxType shipmentBoxTypeId="FXPAK_SM" description="FedEx Pak (Small)" dimensionUomId="LEN_in" boxLength="10.25" boxWidth="12.75" boxHeight="0"/> + <ShipmentBoxType shipmentBoxTypeId="FXPAK_LRG" description="FedEx Pak (Large)" dimensionUomId="LEN_in" boxLength="12" boxWidth="15.5" boxHeight="0"/> + <ShipmentBoxType shipmentBoxTypeId="FXBOX_SM" description="FedEx Box (Small)" dimensionUomId="LEN_in" boxLength="12.25" boxWidth="10.875" boxHeight="1.5"/> + <ShipmentBoxType shipmentBoxTypeId="FXBOX_MED" description="FedEx Box (Medium)" dimensionUomId="LEN_in" boxLength="13.25" boxWidth="11.5" boxHeight="2.375"/> + <ShipmentBoxType shipmentBoxTypeId="FXBOX_LRG" description="FedEx Box (Large)" dimensionUomId="LEN_in" boxLength="17.875" boxWidth="12.375" boxHeight="3"/> + <ShipmentBoxType shipmentBoxTypeId="FXTUBE" description="FedEx Tube" dimensionUomId="LEN_in" boxLength="38" boxWidth="6" boxHeight="5.2"/> + <ShipmentBoxType shipmentBoxTypeId="FX10KGBOX" description="FedEx 10KG Box" dimensionUomId="LEN_in" boxLength="15.8125" boxWidth="12.9375" boxHeight="10.1875"/> + <ShipmentBoxType shipmentBoxTypeId="FX25KGBOX" description="FedEx 25KG Box" dimensionUomId="LEN_in" boxLength="21.5625" boxWidth="16.5625" boxHeight="13.1875"/> + <ShipmentBoxType shipmentBoxTypeId="YOURPACKNG" description="Your Packaging" dimensionUomId="LEN_in" boxLength="" boxWidth="" boxHeight=""/> + + <CarrierShipmentBoxType shipmentBoxTypeId="FXENV" partyId="FEDEX" packagingTypeCode="FEDEXENVELOPE"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FXENV_LGL" partyId="FEDEX" packagingTypeCode="FEDEXENVELOPE"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FXPAK_SM" partyId="FEDEX" packagingTypeCode="FEDEXPAK"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FXPAK_LRG" partyId="FEDEX" packagingTypeCode="FEDEXPAK"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FXBOX_SM" partyId="FEDEX" packagingTypeCode="FEDEXBOX"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FXBOX_MED" partyId="FEDEX" packagingTypeCode="FEDEXBOX"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FXBOX_LRG" partyId="FEDEX" packagingTypeCode="FEDEXBOX"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FXTUBE" partyId="FEDEX" packagingTypeCode="FEDEXTUBE"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FX10KGBOX" partyId="FEDEX" packagingTypeCode="FEDEX10KGBOX"/> + <CarrierShipmentBoxType shipmentBoxTypeId="FX25KGBOX" partyId="FEDEX" packagingTypeCode="FEDEX25KGBOX"/> + <CarrierShipmentBoxType shipmentBoxTypeId="YOURPACKNG" partyId="FEDEX" packagingTypeCode="YOURPACKAGING"/> + </entity-engine-xml> Modified: ofbiz/trunk/applications/product/config/ProductUiLabels.properties URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/config/ProductUiLabels.properties?view=diff&rev=504996&r1=504995&r2=504996 ============================================================================== --- ofbiz/trunk/applications/product/config/ProductUiLabels.properties (original) +++ ofbiz/trunk/applications/product/config/ProductUiLabels.properties Thu Feb 8 10:41:20 2007 @@ -401,6 +401,7 @@ ProductConfirmSelectedMoves=Confirm selected moves ProductConfirmShipmentUps=Confirm Shipment with UPS ProductConfirmShipmentDHL=Confirm Shipment with DHL +ProductConfirmShipmentFedex=Confirm Shipment with Fedex ProductContactTypeInformation=Contact Type Information ProductContainerLetter=C ProductContent=Content @@ -1168,11 +1169,17 @@ ProductShipamountPrice=shipamount=shipamount + price ProductShipamountTotalQuantityPrice=shipamount=shipamount + (totalQuantity * price) ProductShipamount=shipamount +ProductShipmentBoxType=Box Type +ProductShipmentFedexHomeDateCertain=Date Certain +ProductShipmentFedexHomeDeliveryTypeDate=Home Delivery Type/Date (FedEx only) +ProductShipmentFedexHomeEvening=Evening +ProductShipmentFedexHomeAppointment=Appointment ProductShipmentId=Shipment Id ProductShipmentItemSeqId=Shipment Item Seq Id ProductShipmentManifest=Manifest for Shipment ProductShipmentMethod=Shipment Method ProductShipmentMethodType=Shipment Method Type +ProductShipmentNone=None ProductShipmentNotFoundId=The Shipment was not found with ID ProductShipmentPlan=Shipment Plan ProductShipmentPlanToOrderItems=Shipment Plan --> Order Items Modified: ofbiz/trunk/applications/product/config/shipment.properties URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/config/shipment.properties?view=diff&rev=504996&r1=504995&r2=504996 ============================================================================== --- ofbiz/trunk/applications/product/config/shipment.properties (original) +++ ofbiz/trunk/applications/product/config/shipment.properties Thu Feb 8 10:41:20 2007 @@ -21,6 +21,7 @@ # General Configuration ############################################ shipment.default.weight.uom=WT_lb +shipment.default.dimension.uom=LEN_in shipment.default.weight.value=1 ############################################ @@ -110,3 +111,48 @@ # DHL Shipment Label configuration shipment.dhl.label.image.format=PNG + + +############################################ +# FedEx Ship Manager Direct Configuration +############################################ + +# Template locations +shipment.template.fedex.ship.location=component://product/templates/shipment/FedexShipRequestTemplate.xml +shipment.template.fedex.subscription.location=component://product/templates/shipment/FedexSubscriptionRequestTemplate.xml + +# Credentials +shipment.fedex.access.accountNbr= +shipment.fedex.access.meterNumber= + +# Connection details +# https://gatewaybeta.fedex.com/GatewayDC - Test URL +# https://gateway.fedex.com/GatewayDC - Production URL +shipment.fedex.connect.url=https://gatewaybeta.fedex.com/GatewayDC +shipment.fedex.connect.timeout=60 + +# Label configuration +# labelImageType must be PDF or PNG (PNG valid only for intra-US shipments) +shipment.fedex.labelImageType=PNG + +# Default dropoff type +#REGULARPICKUP - Regular Pickup +#REQUESTCOURIER - Request Courier +#DROPBOX - Drop-Box +#BUSINESSSERVICECTR - Business Service Center +#STATION - Station +shipment.fedex.default.dropoffType=REGULARPICKUP + +# Default packaging type +#FXENV - FedEx Envelope +#FXENV_LGL - FedEx Envelope (Legal) +#FXPAK_SM - FedEx Pak (Small) +#FXPAK_LRG - FedEx Pak (Large) +#FXBOX_SM - FedEx Box (Small) +#FXBOX_MED - FedEx Box (Medium) +#FXBOX_LRG - FedEx Box (Large) +#FXTUBE - FedEx Tube +#FX10KGBOX - FedEx 10KG Box +#FX25KGBOX - FedEx 25KG Box +#YOURPACKNG - Your Packaging +shipment.fedex.default.packagingType=YOURPACKNG Modified: ofbiz/trunk/applications/product/entitydef/entitymodel_shipment.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/entitydef/entitymodel_shipment.xml?view=diff&rev=504996&r1=504995&r2=504996 ============================================================================== --- ofbiz/trunk/applications/product/entitydef/entitymodel_shipment.xml (original) +++ ofbiz/trunk/applications/product/entitydef/entitymodel_shipment.xml Thu Feb 8 10:41:20 2007 @@ -444,7 +444,7 @@ title="Carrier Shipment Method Entity"> <field name="shipmentBoxTypeId" type="id-ne"></field> <field name="partyId" type="id-ne"></field> - <field name="packagingTypeCode" type="very-short"></field> + <field name="packagingTypeCode" type="id"></field> <field name="oversizeCode" type="very-short"></field> <prim-key field="shipmentBoxTypeId"/> <prim-key field="partyId"/> @@ -1108,6 +1108,8 @@ <field name="trackingDigest" type="very-long"></field> <field name="updatedByUserLoginId" type="id-vlong"></field> <field name="lastUpdatedDate" type="date-time"></field> + <field name="homeDeliveryType" type="id"></field> + <field name="homeDeliveryDate" type="date-time"></field> <prim-key field="shipmentId"/> <prim-key field="shipmentRouteSegmentId"/> <relation type="one" fk-name="SHPMT_RTSEG_SHPMT" rel-entity-name="Shipment"> Modified: ofbiz/trunk/applications/product/ofbiz-component.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/ofbiz-component.xml?view=diff&rev=504996&r1=504995&r2=504996 ============================================================================== --- ofbiz/trunk/applications/product/ofbiz-component.xml (original) +++ ofbiz/trunk/applications/product/ofbiz-component.xml Thu Feb 8 10:41:20 2007 @@ -44,6 +44,7 @@ <service-resource type="model" loader="main" location="servicedef/services_picklist.xml"/> <service-resource type="model" loader="main" location="servicedef/services_pricepromo.xml"/> <service-resource type="model" loader="main" location="servicedef/services_shipment_dhl.xml"/> + <service-resource type="model" loader="main" location="servicedef/services_shipment_fedex.xml"/> <service-resource type="model" loader="main" location="servicedef/services_shipment_ups.xml"/> <service-resource type="model" loader="main" location="servicedef/services_shipment_usps.xml"/> <service-resource type="model" loader="main" location="servicedef/services_shipment.xml"/> Added: ofbiz/trunk/applications/product/servicedef/services_shipment_fedex.xml URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/servicedef/services_shipment_fedex.xml?view=auto&rev=504996 ============================================================================== --- ofbiz/trunk/applications/product/servicedef/services_shipment_fedex.xml (added) +++ ofbiz/trunk/applications/product/servicedef/services_shipment_fedex.xml Thu Feb 8 10:41:20 2007 @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<!-- +Licensed to the Apache Software Foundation (ASF) under one +or more contributor license agreements. See the NOTICE file +distributed with this work for additional information +regarding copyright ownership. The ASF licenses this file +to you under the Apache License, Version 2.0 (the +"License"); you may not use this file except in compliance +with the License. You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, +software distributed under the License is distributed on an +"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +KIND, either express or implied. See the License for the +specific language governing permissions and limitations +under the License. +--> + +<services xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.ofbiz.org/dtds/services.xsd"> + <description>Fedex Shipment Interface Services, based on Ship Manager Direct XML API</description> + + <!-- FDXSubscriptionRequest/FDXSubscriptionReply --> + <service name="fedexSubscriptionRequest" engine="java" location="org.ofbiz.shipment.thirdparty.fedex.FedexServices" invoke="fedexSubscriptionRequest" auth="false"> + <description>Sends a subscription request to FedEx to get the meter number, which is required for Fedex Ship Manager Direct as shipping credential. + You must supply a contact name and a partyId (usually your company's with a valid address and phone number per Fedex requirements.</description> + <attribute name="contactPartyName" type="String" mode="IN" optional="false"/> + <attribute name="companyPartyId" type="String" mode="IN" optional="false"/> + <attribute name="replaceMeterNumber" type="Boolean" mode="IN" optional="false"/> + <attribute name="meterNumber" type="String" mode="OUT" optional="false"/> + </service> + + <!-- FDXShipRequest/FDXShipReply --> + <service name="fedexShipRequest" engine="java" location="org.ofbiz.shipment.thirdparty.fedex.FedexServices" invoke="fedexShipRequest" auth="false"> + <description>Schedule a shipment route segment with FedEx. You will get back a label image and tracking number which are stored for you in the same + ShipmentRouteSegment.</description> + <attribute name="shipmentId" type="String" mode="IN" optional="false"/> + <attribute name="shipmentRouteSegmentId" type="String" mode="IN" optional="false"/> + </service> + +</services> Propchange: ofbiz/trunk/applications/product/servicedef/services_shipment_fedex.xml ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/applications/product/servicedef/services_shipment_fedex.xml ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/trunk/applications/product/servicedef/services_shipment_fedex.xml ------------------------------------------------------------------------------ svn:mime-type = text/xml Added: ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/fedex/FedexServices.java URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/fedex/FedexServices.java?view=auto&rev=504996 ============================================================================== --- ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/fedex/FedexServices.java (added) +++ ofbiz/trunk/applications/product/src/org/ofbiz/shipment/thirdparty/fedex/FedexServices.java Thu Feb 8 10:41:20 2007 @@ -0,0 +1,954 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ + +package org.ofbiz.shipment.thirdparty.fedex; + +import org.ofbiz.base.util.*; +import org.ofbiz.base.util.template.FreeMarkerWorker; +import org.ofbiz.service.DispatchContext; +import org.ofbiz.service.ServiceUtil; +import org.ofbiz.service.LocalDispatcher; +import org.ofbiz.service.GenericServiceException; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.entity.GenericDelegator; +import org.ofbiz.entity.GenericEntityException; +import org.ofbiz.entity.condition.EntityExpr; +import org.ofbiz.entity.condition.EntityOperator; +import org.ofbiz.entity.condition.EntityConditionList; +import org.ofbiz.entity.util.EntityUtil; +import org.ofbiz.party.party.PartyHelper; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.SAXException; + +import javax.xml.parsers.ParserConfigurationException; +import java.util.*; +import java.io.IOException; +import java.io.StringWriter; +import java.math.BigDecimal; +import java.sql.Timestamp; + +/** + * Fedex Shipment Services + * + * Implementation of Fedex shipment interface using Ship Manager Direct API + * + * TODO: FDXShipDeleteRequest/Reply (on error and via service call) + * TODO: FDXCloseRequest/Reply + * TODO: FDXRateRequest/Reply + * TODO: FDXTrackRequest/Reply + * TODO: International shipments + * TODO: Multi-piece shipments + * TODO: Freight shipments + */ +public class FedexServices { + + public final static String module = FedexServices.class.getName(); + public final static String shipmentPropertiesFile = "shipment.properties"; + + /** + * Opens a URL to Fedex and makes a request. + * + * @param xmlString XML message to send + * @return XML string response from FedEx + * @throws FedexConnectException + */ + public static String sendFedexRequest(String xmlString) throws FedexConnectException { + String url = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.fedex.connect.url"); + if (url == null) { + throw new FedexConnectException("Incomplete connection URL; check your Fedex configuration"); + } + + // xmlString should contain the auth document at the beginning + // all documents require an <?xml version="1.0" encoding="UTF-8" ?> header + if (! xmlString.matches( "^(?s)<\\?xml\\s+version=\"1\\.0\"\\s+encoding=\"UTF-8\"\\s*\\?>.*")) { + throw new FedexConnectException("XML header is malformed"); + } + + // prepare the connect string + url = url.trim(); + + String timeOutStr = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.fedex.connect.timeout", "60"); + int timeout = 60; + try { + timeout = Integer.parseInt(timeOutStr); + } catch (NumberFormatException e) { + Debug.logError(e, "Unable to set timeout to " + timeOutStr + " using default " + timeout); + } + + if (Debug.verboseOn()) { + Debug.logVerbose("Fedex Connect URL : " + url, module); + Debug.logVerbose("Fedex XML String : " + xmlString, module); + } + + HttpClient http = new HttpClient(url); + http.setTimeout(timeout * 1000); + String response = null; + try { + response = http.post(xmlString); + } catch ( HttpClientException e) { + Debug.logError(e, "Problem connecting to Fedex server", module); + throw new FedexConnectException("URL Connection problem", e); + } + + if (response == null) { + throw new FedexConnectException("Received a null response"); + } + if (Debug.verboseOn()) { + Debug.logVerbose("Fedex Response : " + response, module); + } + + return response; + } + + /* + * Register a Fedex account for shipping by obtaining the meter number + */ + public static Map fedexSubscriptionRequest( DispatchContext dctx, Map context) { + GenericDelegator delegator = dctx.getDelegator(); + List errorList = new ArrayList(); + + Boolean replaceMeterNumber = (Boolean) context.get("replaceMeterNumber"); + + if(! replaceMeterNumber.booleanValue()) { + String meterNumber = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.fedex.access.meterNumber"); + if (UtilValidate.isNotEmpty(meterNumber)) { + return ServiceUtil.returnError("MeterNumber already exists: " + shipmentPropertiesFile + ":shipment.fedex.access.meterNumber=" + meterNumber); + } + } + + String companyPartyId = (String) context.get("companyPartyId"); + String contactPartyName = (String) context.get("contactPartyName"); + + Map result = new HashMap(); + + String accountNumber = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.fedex.access.accountNbr"); + if (UtilValidate.isEmpty(accountNumber)) { + return ServiceUtil.returnError("accountNbr not found for Fedex subscription request."); + } + + if(UtilValidate.isEmpty(contactPartyName)) { + return ServiceUtil.returnError("Contact name can't be empty."); + } + + String companyName = null; + GenericValue postalAddress = null; + String phoneNumber = null; + String faxNumber = null; + String emailAddress = null; + try { + + // Make sure the company exists + GenericValue companyParty = delegator.findByPrimaryKeyCache("Party", UtilMisc.toMap("partyId", companyPartyId)); + if (companyParty == null) { + String errorMessage = "Party with partyId " + companyPartyId + " does not exist"; + Debug.logError(errorMessage, module); + return ServiceUtil.returnError(errorMessage); + } + + // Get the company name (required by Fedex) + companyName = PartyHelper.getPartyName(companyParty); + if (UtilValidate.isEmpty(companyName)) { + String errorMessage = "Party with partyId " + companyPartyId + " has no name"; + Debug.logError(errorMessage, module); + return ServiceUtil.returnError(errorMessage); + } + + // Get the contact information for the company + List partyContactDetails = delegator.findByAnd("PartyContactDetailByPurpose", UtilMisc.toMap("partyId", companyPartyId)); + partyContactDetails = EntityUtil.filterByDate(partyContactDetails); + partyContactDetails = EntityUtil.filterByDate(partyContactDetails, UtilDateTime.nowTimestamp(), "purposeFromDate", "purposeThruDate", true); + + // Get the first valid postal address (address1, city, postalCode and countryGeoId are required by Fedex) + List postalAddressConditions = new ArrayList(); + postalAddressConditions.add(new EntityExpr("contactMechTypeId", EntityOperator.EQUALS, "POSTAL_ADDRESS")); + postalAddressConditions.add(new EntityExpr("address1", EntityOperator.NOT_EQUAL, null)); + postalAddressConditions.add(new EntityExpr("address1", EntityOperator.NOT_EQUAL, "")); + postalAddressConditions.add(new EntityExpr("city", EntityOperator.NOT_EQUAL, null)); + postalAddressConditions.add(new EntityExpr("city", EntityOperator.NOT_EQUAL, "")); + postalAddressConditions.add(new EntityExpr("postalCode", EntityOperator.NOT_EQUAL, null)); + postalAddressConditions.add(new EntityExpr("postalCode", EntityOperator.NOT_EQUAL, "")); + postalAddressConditions.add(new EntityExpr("countryGeoId", EntityOperator.NOT_EQUAL, null)); + postalAddressConditions.add(new EntityExpr("countryGeoId", EntityOperator.NOT_EQUAL, "")); + List postalAddresses = EntityUtil.filterByCondition(partyContactDetails, new EntityConditionList(postalAddressConditions, EntityOperator.AND)); + + // Fedex requires USA or Canada addresses to have a state/province ID, so filter out the ones without + postalAddressConditions.clear(); + postalAddressConditions.add(new EntityExpr("countryGeoId", EntityOperator.IN, UtilMisc.toList("CAN", "USA"))); + postalAddressConditions.add(new EntityExpr("stateProvinceGeoId", EntityOperator.EQUALS, null)); + postalAddresses = EntityUtil.filterOutByCondition(postalAddresses, new EntityConditionList(postalAddressConditions, EntityOperator.AND)); + postalAddressConditions.clear(); + postalAddressConditions.add(new EntityExpr("countryGeoId", EntityOperator.IN, UtilMisc.toList("CAN", "USA"))); + postalAddressConditions.add(new EntityExpr("stateProvinceGeoId", EntityOperator.EQUALS, "")); + postalAddresses = EntityUtil.filterOutByCondition(postalAddresses, new EntityConditionList(postalAddressConditions, EntityOperator.AND)); + + postalAddress = EntityUtil.getFirst(postalAddresses); + if (UtilValidate.isEmpty(postalAddress)) { + String errorMessage = "Party with partyId " + companyPartyId + " does not have a current, fully populated postal address"; + Debug.logError(errorMessage, module); + return ServiceUtil.returnError(errorMessage); + } + GenericValue countryGeo = delegator.findByPrimaryKeyCache("Geo", UtilMisc.toMap("geoId", postalAddress.getString("countryGeoId"))); + String countryCode = countryGeo.getString("geoCode"); + String stateOrProvinceCode = null; + // Only add the StateOrProvinceCode element if the address is in USA or Canada + if (countryCode.equals("CA") || countryCode.equals("US")) { + GenericValue stateProvinceGeo = delegator.findByPrimaryKeyCache("Geo", UtilMisc.toMap("geoId", postalAddress.getString("stateProvinceGeoId"))); + stateOrProvinceCode = stateProvinceGeo.getString("geoCode"); + } + + // Get the first valid primary phone number (required by Fedex) + List phoneNumberConditions = new ArrayList(); + phoneNumberConditions.add(new EntityExpr("contactMechTypeId", EntityOperator.EQUALS, "TELECOM_NUMBER")); + phoneNumberConditions.add(new EntityExpr("contactMechPurposeTypeId", EntityOperator.EQUALS, "PRIMARY_PHONE")); + phoneNumberConditions.add(new EntityExpr("areaCode", EntityOperator.NOT_EQUAL, null)); + phoneNumberConditions.add(new EntityExpr("areaCode", EntityOperator.NOT_EQUAL, "")); + phoneNumberConditions.add(new EntityExpr("contactNumber", EntityOperator.NOT_EQUAL, null)); + phoneNumberConditions.add(new EntityExpr("contactNumber", EntityOperator.NOT_EQUAL, "")); + List phoneNumbers = EntityUtil.filterByCondition(partyContactDetails, new EntityConditionList(phoneNumberConditions, EntityOperator.AND)); + GenericValue phoneNumberValue = EntityUtil.getFirst(phoneNumbers); + if (UtilValidate.isEmpty(phoneNumberValue)) { + String errorMessage = "Party with partyId " + companyPartyId + " does not have a current, fully populated primary phone number"; + Debug.logError(errorMessage, module); + return ServiceUtil.returnError(errorMessage); + } + phoneNumber = phoneNumberValue.getString("areaCode") + phoneNumberValue.getString("contactNumber"); + if (UtilValidate.isNotEmpty(phoneNumberValue.getString("countryCode"))) phoneNumber = phoneNumberValue.getString("countryCode") + phoneNumber; + phoneNumber = phoneNumber.replaceAll("[^+\\d]", ""); + + // Get the first valid fax number + List faxNumberConditions = new ArrayList(); + faxNumberConditions.add(new EntityExpr("contactMechTypeId", EntityOperator.EQUALS, "TELECOM_NUMBER")); + faxNumberConditions.add(new EntityExpr("contactMechPurposeTypeId", EntityOperator.EQUALS, "FAX_NUMBER")); + faxNumberConditions.add(new EntityExpr("areaCode", EntityOperator.NOT_EQUAL, null)); + faxNumberConditions.add(new EntityExpr("areaCode", EntityOperator.NOT_EQUAL, "")); + faxNumberConditions.add(new EntityExpr("contactNumber", EntityOperator.NOT_EQUAL, null)); + faxNumberConditions.add(new EntityExpr("contactNumber", EntityOperator.NOT_EQUAL, "")); + List faxNumbers = EntityUtil.filterByCondition(partyContactDetails, new EntityConditionList(faxNumberConditions, EntityOperator.AND)); + GenericValue faxNumberValue = EntityUtil.getFirst(faxNumbers); + if(! UtilValidate.isEmpty(faxNumberValue)) { + faxNumber = faxNumberValue.getString("areaCode") + faxNumberValue.getString("contactNumber"); + if (UtilValidate.isNotEmpty(faxNumberValue.getString("countryCode"))) faxNumber = faxNumberValue.getString("countryCode") + faxNumber; + faxNumber = faxNumber.replaceAll("[^+\\d]", ""); + } + + // Get the first valid email address + List emailConditions = new ArrayList(); + emailConditions.add(new EntityExpr("contactMechTypeId", EntityOperator.EQUALS, "EMAIL_ADDRESS")); + emailConditions.add(new EntityExpr("infoString", EntityOperator.NOT_EQUAL, null)); + emailConditions.add(new EntityExpr("infoString", EntityOperator.NOT_EQUAL, "")); + List emailAddresses = EntityUtil.filterByCondition(partyContactDetails, new EntityConditionList(emailConditions, EntityOperator.AND)); + GenericValue emailAddressValue = EntityUtil.getFirst(emailAddresses); + if(! UtilValidate.isEmpty(emailAddressValue)) { + emailAddress = emailAddressValue.getString("infoString"); + } + + // Get the location of the Freemarker (XML) template for the FDXSubscriptionRequest + String templateLocation = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.template.fedex.subscription.location"); + if (UtilValidate.isEmpty(templateLocation)) { + return ServiceUtil.returnError("Can't find location for FDXSubscriptionRequest template - should be in " + shipmentPropertiesFile + ":shipment.template.fedex.subscription.location"); + } + + // Populate the Freemarker context + Map subscriptionRequestContext = new HashMap(); + subscriptionRequestContext.put("AccountNumber", accountNumber); + subscriptionRequestContext.put("PersonName", contactPartyName); + subscriptionRequestContext.put("CompanyName", companyName); + subscriptionRequestContext.put("PhoneNumber", phoneNumber); + if (UtilValidate.isNotEmpty(faxNumber)) { + subscriptionRequestContext.put("FaxNumber", faxNumber); + } + if (UtilValidate.isNotEmpty(emailAddress)) { + subscriptionRequestContext.put("EMailAddress", emailAddress); + } + subscriptionRequestContext.put("Line1", postalAddress.getString("address1")); + if (UtilValidate.isNotEmpty(postalAddress.getString("address2"))) { + subscriptionRequestContext.put("Line2", postalAddress.getString("address2")); + } + subscriptionRequestContext.put("City", postalAddress.getString("city")); + if (UtilValidate.isNotEmpty(stateOrProvinceCode)) { + subscriptionRequestContext.put("StateOrProvinceCode", stateOrProvinceCode); + } + subscriptionRequestContext.put("PostalCode", postalAddress.getString("postalCode")); + subscriptionRequestContext.put("CountryCode", countryCode); + + StringWriter outWriter = new StringWriter(); + try { + FreeMarkerWorker.renderTemplateAtLocation(templateLocation, subscriptionRequestContext, outWriter); + } catch (Exception e) { + String errorMessage = "Cannot send Fedex subscription request: Failed to render Fedex XML Subscription Request Template [" + templateLocation + "]."; + Debug.logError(e, errorMessage, module); + return ServiceUtil.returnError(errorMessage + ": " + e.getMessage()); + } + String fDXSubscriptionRequestString = outWriter.toString(); + + // Send the request + String fDXSubscriptionReplyString = null; + try { + fDXSubscriptionReplyString = sendFedexRequest(fDXSubscriptionRequestString); + Debug.log("Fedex response for FDXSubscriptionRequest:" + fDXSubscriptionReplyString); + } catch (FedexConnectException e) { + String errorMessage = "Error sending Fedex request for FDXSubscriptionRequest: " + e.toString(); + Debug.logError(e, errorMessage, module); + return ServiceUtil.returnError(errorMessage); + } + + Document fDXSubscriptionReplyDocument = null; + try { + fDXSubscriptionReplyDocument = UtilXml.readXmlDocument(fDXSubscriptionReplyString, false); + Debug.log("Fedex response for FDXSubscriptionRequest:" + fDXSubscriptionReplyString); + } catch ( SAXException se) { + String errorMessage = "Error parsing the FDXSubscriptionRequest response: " + se.toString(); + Debug.logError(se, errorMessage, module); + return ServiceUtil.returnError(errorMessage); + } catch ( ParserConfigurationException pce) { + String errorMessage = "Error parsing the FDXSubscriptionRequest response: " + pce.toString(); + Debug.logError(pce, errorMessage, module); + return ServiceUtil.returnError(errorMessage); + } catch (IOException ioe) { + String errorMessage = "Error parsing the FDXSubscriptionRequest response: " + ioe.toString(); + Debug.logError(ioe, errorMessage, module); + return ServiceUtil.returnError(errorMessage); + } + + Element fedexSubscriptionReplyElement = fDXSubscriptionReplyDocument.getDocumentElement(); + handleErrors(fedexSubscriptionReplyElement, errorList); + + if (UtilValidate.isNotEmpty(errorList)) { + return ServiceUtil.returnError(errorList); + } + + String meterNumber = UtilXml.childElementValue(fedexSubscriptionReplyElement, "MeterNumber"); + + result.put("meterNumber", meterNumber); + + } catch( GenericEntityException e ) { + Debug.logError(e, module); + return ServiceUtil.returnError(e.getMessage()); + } + + return result; + } + + /** + * + * Send a FDXShipRequest via the Ship Manager Direct API + */ + public static Map fedexShipRequest( DispatchContext dctx, Map context) { + GenericDelegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + Locale locale = (Locale) context.get("locale"); + Map result = ServiceUtil.returnSuccess(); + + String shipmentId = (String) context.get("shipmentId"); + String shipmentRouteSegmentId = (String) context.get("shipmentRouteSegmentId"); + + // Get the location of the Freemarker (XML) template for the FDXShipRequest + String templateLocation = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.template.fedex.ship.location"); + if (UtilValidate.isEmpty(templateLocation)) { + return ServiceUtil.returnError("Can't find location for FDXShipRequest template - should be in " + shipmentPropertiesFile + ":shipment.template.fedex.ship.location"); + } + + // Get the Fedex account number + String accountNumber = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.fedex.access.accountNbr"); + if (UtilValidate.isEmpty(accountNumber)) { + return ServiceUtil.returnError("accountNbr not found for Fedex ship request."); + } + + // Get the Fedex meter number + String meterNumber = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.fedex.access.meterNumber"); + if (UtilValidate.isEmpty(meterNumber)) { + return ServiceUtil.returnError("Meter number not found for Fedex ship request - should be in " + shipmentPropertiesFile + ":shipment.fedex.access.meterNumber (run the fedexSubscriptionRequest service)."); + } + + // Get the weight units to be used in the request + String weightUomId = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.default.weight.uom"); + if (UtilValidate.isEmpty(weightUomId)) { + return ServiceUtil.returnError("Default weightUomId not found for Fedex ship request - should be in " + shipmentPropertiesFile + ":shipment.default.weight.uom."); + } else if (! ("WT_lb".equals(weightUomId) || "WT_kg".equals(weightUomId))) { + return ServiceUtil.returnError("WeightUomId in " + shipmentPropertiesFile + ":shipment.default.weight.uom must be either WT_lb or WT_kg."); + } + + // Get the dimension units to be used in the request + String dimensionsUomId = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.default.dimension.uom"); + if (UtilValidate.isEmpty(dimensionsUomId)) { + return ServiceUtil.returnError("Default dimensionUomId not found for Fedex ship request - should be in " + shipmentPropertiesFile + ":shipment.default.dimension.uom."); + } else if (! ("LEN_in".equals(dimensionsUomId) || "LEN_cm".equals(dimensionsUomId))) { + return ServiceUtil.returnError("WeightUomId in " + shipmentPropertiesFile + ":shipment.default.dimension.uom must be either LEN_in or LEN_cm."); + } + + // Get the label image type to be returned + String labelImageType = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.fedex.labelImageType"); + if (UtilValidate.isEmpty(labelImageType)) { + return ServiceUtil.returnError("LabelImageType not found for Fedex ship request - should be in " + shipmentPropertiesFile + ":shipment.fedex.labelImageType."); + } else if (! ("PDF".equals(labelImageType) || "PNG".equals(labelImageType))) { + return ServiceUtil.returnError("LabelImageType in " + shipmentPropertiesFile + ":shipment.fedex.labelImageType must be either PDF or PNG."); + } + + // Get the default dropoff type + String dropoffType = UtilProperties.getPropertyValue(shipmentPropertiesFile, "shipment.fedex.default.dropoffType"); + if (UtilValidate.isEmpty(dropoffType)) { + return ServiceUtil.returnError("Default dropoff type not found for Fedex ship request - should be in " + shipmentPropertiesFile + ":shipment.fedex.default.dropoffType."); + } + + try { + + Map shipRequestContext = new HashMap(); + + // Get the shipment and the shipmentRouteSegment + GenericValue shipment = delegator.findByPrimaryKey("Shipment", UtilMisc.toMap("shipmentId", shipmentId)); + if (UtilValidate.isEmpty(shipment)) { + return ServiceUtil.returnError("Shipment not found with ID " + shipmentId); + } + GenericValue shipmentRouteSegment = delegator.findByPrimaryKey("ShipmentRouteSegment", UtilMisc.toMap("shipmentId", shipmentId, "shipmentRouteSegmentId", shipmentRouteSegmentId)); + if (UtilValidate.isEmpty(shipmentRouteSegment)) { + return ServiceUtil.returnError("ShipmentRouteSegment not found with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } + + // Determine the Fedex carrier + String carrierPartyId = shipmentRouteSegment.getString("carrierPartyId"); + if (! "FEDEX".equals(carrierPartyId)) { + return ServiceUtil.returnError("ERROR: The Carrier for ShipmentRouteSegment " + shipmentRouteSegmentId + " of Shipment " + shipmentId + ", is not Fedex."); + } + + // Check the shipmentRouteSegment's carrier status + if (UtilValidate.isNotEmpty(shipmentRouteSegment.getString("carrierServiceStatusId")) && !"SHRSCS_NOT_STARTED".equals(shipmentRouteSegment.getString("carrierServiceStatusId"))) { + return ServiceUtil.returnError("ERROR: The Carrier Service Status for ShipmentRouteSegment " + shipmentRouteSegmentId + " of Shipment " + shipmentId + ", is [" + shipmentRouteSegment.getString("carrierServiceStatusId") + "], but must be not-set or [SHRSCS_NOT_STARTED] to perform the Fedex Shipment Confirm operation."); + } + + // Translate shipmentMethodTypeId to Fedex service code and carrier code + String shipmentMethodTypeId = shipmentRouteSegment.getString("shipmentMethodTypeId"); + GenericValue carrierShipmentMethod = delegator.findByPrimaryKey("CarrierShipmentMethod", UtilMisc.toMap("shipmentMethodTypeId", shipmentMethodTypeId, "partyId", "FEDEX", "roleTypeId", "CARRIER")); + if (UtilValidate.isEmpty(carrierShipmentMethod)) { + return ServiceUtil.returnError("No CarrierShipmentMethod entry for carrier Fedex shipmentMethodTypeId " + shipmentMethodTypeId); + } + if (UtilValidate.isEmpty(carrierShipmentMethod.getString("carrierServiceCode"))) { + return ServiceUtil.returnError("No Carrier service code for carrier Fedex shipmentMethodTypeId " + shipmentMethodTypeId); + } + String service = carrierShipmentMethod.getString("carrierServiceCode"); + + // CarrierCode is FDXG only for FEDEXGROUND and GROUNDHOMEDELIVERY services. + boolean isGroundService = service.equals("FEDEXGROUND") || service.equals("GROUNDHOMEDELIVERY"); + String carrierCode = isGroundService ? "FDXG" : "FDXE"; + + // Determine the currency by trying the shipmentRouteSegment, then the Shipment, then the framework's default currency, and finally default to USD + String currencyCode = null; + if (UtilValidate.isNotEmpty(shipmentRouteSegment.getString("currencyUomId"))) { + currencyCode = shipmentRouteSegment.getString("currencyUomId"); + } else if (UtilValidate.isNotEmpty(shipmentRouteSegment.getString("currencyUomId"))) { + currencyCode = shipment.getString("currencyUomId"); + } else { + currencyCode = UtilProperties.getPropertyValue("general.properties", "currency.uom.id.default", "USD"); + } + + // Get and validate origin postal address + GenericValue originPostalAddress = shipmentRouteSegment.getRelatedOne("OriginPostalAddress"); + if (UtilValidate.isEmpty(originPostalAddress)) { + return ServiceUtil.returnError("OriginPostalAddress not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } else if (UtilValidate.isEmpty(originPostalAddress.getString("address1")) || + UtilValidate.isEmpty(originPostalAddress.getString("city")) || + UtilValidate.isEmpty(originPostalAddress.getString("postalCode")) || + UtilValidate.isEmpty(originPostalAddress.getString("countryGeoId"))) { + return ServiceUtil.returnError("OriginPostalAddress not complete for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId + " (missing address1, city, postalCode and/or countryGeoId)."); + } + GenericValue originCountryGeo = originPostalAddress.getRelatedOne("CountryGeo"); + if (UtilValidate.isEmpty(originCountryGeo)) { + return ServiceUtil.returnError("OriginCountryGeo not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } + String originAddressCountryCode = originCountryGeo.getString("geoCode"); + String originAddressStateOrProvinceCode = null; + + // Only add the StateOrProvinceCode element if the address is in USA or Canada + if (originAddressCountryCode.equals("CA") || originAddressCountryCode.equals("US")) { + if (UtilValidate.isEmpty(originPostalAddress.getString("stateProvinceGeoId"))) { + return ServiceUtil.returnError("OriginStateProvinceGeoId required in contactMechId " + originPostalAddress.getString("contactMechId") + " for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } + GenericValue stateProvinceGeo = delegator.findByPrimaryKeyCache("Geo", UtilMisc.toMap("geoId", originPostalAddress.getString("stateProvinceGeoId"))); + originAddressStateOrProvinceCode = stateProvinceGeo.getString("geoCode"); + } + + // Get and validate origin telecom number + GenericValue originTelecomNumber = shipmentRouteSegment.getRelatedOne("OriginTelecomNumber"); + if (UtilValidate.isEmpty(originTelecomNumber)) { + return ServiceUtil.returnError("OriginTelecomNumber not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } + String originContactPhoneNumber = originTelecomNumber.getString("areaCode") + originTelecomNumber.getString("contactNumber"); + + // Fedex doesn't want the North American country code + if (UtilValidate.isNotEmpty(originTelecomNumber.getString("countryCode")) && !(originAddressCountryCode.equals("CA") || originAddressCountryCode.equals("US"))) { + originContactPhoneNumber = originTelecomNumber.getString("countryCode") + originContactPhoneNumber; + } + originContactPhoneNumber = originContactPhoneNumber.replaceAll("[^+\\d]", ""); + + // Get the origin contact name from the owner of the origin facility + GenericValue partyFrom = null; + GenericValue originFacility = shipment.getRelatedOne("OriginFacility"); + if (UtilValidate.isEmpty(originFacility)) { + return ServiceUtil.returnError("Shipment.originFacilityId is required for Fedex shipments: shipmentId " + shipmentId + ", shipmentRouteSegmentId " + shipmentRouteSegmentId); + } else { + partyFrom = originFacility.getRelatedOne("OwnerParty"); + if (UtilValidate.isEmpty(partyFrom)) { + return ServiceUtil.returnError("Facility.ownerPartyId is required for Fedex shipments: shipmentId " + shipmentId + ", shipmentRouteSegmentId " + shipmentRouteSegmentId + ", facilityId " + originFacility.getString("facilityId")); + } + } + + String originContactKey = "PERSON".equals(partyFrom.getString("partyTypeId")) ? "OriginContactPersonName" : "OriginContactCompanyName"; + String originContactName = PartyHelper.getPartyName(partyFrom, false); + if (UtilValidate.isEmpty(originContactName)) { + return ServiceUtil.returnError("partyIdFrom for shipmentId " + shipmentId + ", shipmentRouteSegmentId " + shipmentRouteSegmentId + " has no name (required for Fedex shipments)" ); + } + + // Get and validate destination postal address + GenericValue destinationPostalAddress = shipmentRouteSegment.getRelatedOne("DestPostalAddress"); + if (UtilValidate.isEmpty(destinationPostalAddress)) { + return ServiceUtil.returnError("destinationPostalAddress not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } else if (UtilValidate.isEmpty(destinationPostalAddress.getString("address1")) || + UtilValidate.isEmpty(destinationPostalAddress.getString("city")) || + UtilValidate.isEmpty(destinationPostalAddress.getString("postalCode")) || + UtilValidate.isEmpty(destinationPostalAddress.getString("countryGeoId"))) { + return ServiceUtil.returnError("destinationPostalAddress not complete for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId + " (missing address1, city, postalCode and/or countryGeoId)."); + } + GenericValue destinationCountryGeo = destinationPostalAddress.getRelatedOne("CountryGeo"); + if (UtilValidate.isEmpty(destinationCountryGeo)) { + return ServiceUtil.returnError("destinationCountryGeo not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } + String destinationAddressCountryCode = destinationCountryGeo.getString("geoCode"); + String destinationAddressStateOrProvinceCode = null; + + // Only add the StateOrProvinceCode element if the address is in USA or Canada + if (destinationAddressCountryCode.equals("CA") || destinationAddressCountryCode.equals("US")) { + if (UtilValidate.isEmpty(destinationPostalAddress.getString("stateProvinceGeoId"))) { + return ServiceUtil.returnError("destinationStateProvinceGeoId required in contactMechId " + destinationPostalAddress.getString("contactMechId") + " for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } + GenericValue stateProvinceGeo = delegator.findByPrimaryKeyCache("Geo", UtilMisc.toMap("geoId", destinationPostalAddress.getString("stateProvinceGeoId"))); + destinationAddressStateOrProvinceCode = stateProvinceGeo.getString("geoCode"); + } + + // Get and validate destination telecom number + GenericValue destinationTelecomNumber = shipmentRouteSegment.getRelatedOne("DestTelecomNumber"); + if (UtilValidate.isEmpty(destinationTelecomNumber)) { + return ServiceUtil.returnError("destinationTelecomNumber not found for ShipmentRouteSegment with shipmentId " + shipmentId + " and shipmentRouteSegmentId " + shipmentRouteSegmentId); + } + String destinationContactPhoneNumber = destinationTelecomNumber.getString("areaCode") + destinationTelecomNumber.getString("contactNumber"); + + // Fedex doesn't want the North American country code + if (UtilValidate.isNotEmpty(destinationTelecomNumber.getString("countryCode")) && !(destinationAddressCountryCode.equals("CA") || destinationAddressCountryCode.equals("US"))) { + destinationContactPhoneNumber = destinationTelecomNumber.getString("countryCode") + destinationContactPhoneNumber; + } + destinationContactPhoneNumber = destinationContactPhoneNumber.replaceAll("[^+\\d]", ""); + + // Get the destination contact name + String destinationPartyId = shipment.getString("partyIdTo"); + if (UtilValidate.isEmpty(destinationPartyId)) { + return ServiceUtil.returnError("Shipment.partyIdTo is required for Fedex shipments: shipmentId " + shipmentId + ", shipmentRouteSegmentId " + shipmentRouteSegmentId); + } + GenericValue partyTo = delegator.findByPrimaryKey("Party", UtilMisc.toMap("partyId", destinationPartyId)); + String destinationContactKey = "PERSON".equals(partyTo.getString("partyTypeId")) ? "DestinationContactPersonName" : "DestinationContactCompanyName"; + String destinationContactName = PartyHelper.getPartyName(partyTo, false); + if (UtilValidate.isEmpty(destinationContactName)) { + return ServiceUtil.returnError("partyTo for shipmentId " + shipmentId + ", shipmentRouteSegmentId " + shipmentRouteSegmentId + " has no name (required for Fedex shipments)" ); + } + + String homeDeliveryType = null; + Timestamp homeDeliveryDate = null; + if ("GROUNDHOMEDELIVERY".equals(service)) { + |
Free forum by Nabble | Edit this page |