/*
* Licensed to csti consulting
* You may obtain a copy of the License at
*
* http://www.csticonsulting.com
* Copyright (c) 2006-Aug 24, 2010 Consultation CS-TI inc.
*
* 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 com.salesmanager.core.module.impl.integration.shipping;
import java.io.BufferedReader;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.StringTokenizer;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.digester.Digester;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import com.salesmanager.core.constants.ShippingConstants;
import com.salesmanager.core.entity.customer.Customer;
import com.salesmanager.core.entity.merchant.MerchantConfiguration;
import com.salesmanager.core.entity.merchant.MerchantStore;
import com.salesmanager.core.entity.reference.CoreModuleService;
import com.salesmanager.core.entity.reference.Country;
import com.salesmanager.core.entity.reference.Zone;
import com.salesmanager.core.entity.shipping.PackageDetail;
import com.salesmanager.core.entity.shipping.ShippingOption;
import com.salesmanager.core.module.model.integration.ShippingQuotesModule;
import com.salesmanager.core.service.ServiceFactory;
import com.salesmanager.core.service.cache.RefCache;
import com.salesmanager.core.service.common.CommonService;
import com.salesmanager.core.service.common.model.IntegrationKeys;
import com.salesmanager.core.service.common.model.IntegrationProperties;
import com.salesmanager.core.service.merchant.ConfigurationRequest;
import com.salesmanager.core.service.merchant.ConfigurationResponse;
import com.salesmanager.core.service.merchant.MerchantService;
import com.salesmanager.core.util.CountryUtil;
import com.salesmanager.core.util.CurrencyUtil;
import com.salesmanager.core.util.LabelUtil;
import com.salesmanager.core.util.LanguageUtil;
import com.salesmanager.core.util.LogMerchantUtil;
public class UPSQuotesImpl implements ShippingQuotesModule {
private Logger log = Logger.getLogger(UPSQuotesImpl.class);
public String getShippingMethodDescription(Locale locale) {
return LabelUtil.getInstance().getText(locale, "module.upsxml");
}
private String getPackageCode(String codeId) {
if (StringUtils.isBlank(codeId)) {
log.warn("codeId is blank or null, will return standard overnight");
}
/**
*'00' (unknown), '01' (UPS letter), '02' (customer supplied package),
* '03'(tube), '04' (PAK), '21' (UPS express box), '2a' (UPS small
* express box), '2b' (UPS medium express box), '2c' (UPS large express
* box), '24' (UPS 25KG box), '25' (UPS 10KG box), '2a' (small express
* box), '2b' (medium express box), '2c' (large express box), or '30'
* (pallet)
*/
return null;
}
protected String getHeader(int merchantid, ConfigurationResponse vo)
throws Exception {
IntegrationKeys sk = (IntegrationKeys) vo
.getConfiguration("upsxml-keys");
if (sk == null) {
throw new Exception(
"Integration keys are null from configuration request upsxml");
}
StringBuffer xmlreqbuffer = new StringBuffer();
xmlreqbuffer.append("<?xml version=\"1.0\"?>");
xmlreqbuffer.append("<AccessRequest>");
xmlreqbuffer.append("<AccessLicenseNumber>");
xmlreqbuffer.append(sk.getKey1());
xmlreqbuffer.append("</AccessLicenseNumber>");
xmlreqbuffer.append("<UserId>");
xmlreqbuffer.append(sk.getUserid());
xmlreqbuffer.append("</UserId>");
xmlreqbuffer.append("<Password>");
xmlreqbuffer.append(sk.getPassword());
xmlreqbuffer.append("</Password>");
xmlreqbuffer.append("</AccessRequest>");
return xmlreqbuffer.toString();
}
public Collection<ShippingOption> getShippingQuote(
ConfigurationResponse config, BigDecimal orderTotal,
Collection<PackageDetail> packages, Customer customer,
MerchantStore store, Locale locale) {
CoreModuleService cis = null;
StringBuffer xmlbuffer = new StringBuffer();
BufferedReader reader = null;
PostMethod httppost = null;
try {
CommonService cservice = (CommonService) ServiceFactory
.getService(ServiceFactory.CommonService);
String countrycode = CountryUtil.getCountryIsoCodeById(store
.getCountry());
cis = cservice.getModule(countrycode, "upsxml");
if (cis == null) {
log.error("Can't retreive an integration service [countryid "
+ store.getCountry() + " ups subtype 1]");
// throw new
// Exception("UPS getQuote Can't retreive an integration service");
}
MerchantService service = (MerchantService) ServiceFactory
.getService(ServiceFactory.MerchantService);
ConfigurationRequest request_prefs = new ConfigurationRequest(store
.getMerchantId(),
ShippingConstants.MODULE_SHIPPING_RT_PKG_DOM_INT);
ConfigurationResponse vo_prefs = service
.getConfiguration(request_prefs);
String pack = (String) vo_prefs.getConfiguration("package-upsxml");
if (pack == null) {
log
.debug("Will assign packaging type 02 to UPS shipping for merchantid "
+ store.getMerchantId());
pack = "02";
}
ConfigurationRequest request = new ConfigurationRequest(store
.getMerchantId(), ShippingConstants.MODULE_SHIPPING_RT_CRED);
ConfigurationResponse vo = service.getConfiguration(request);
if (vo == null) {
throw new Exception("ConfigurationVO is null upsxml");
}
String xmlhead = getHeader(store.getMerchantId(), vo);
String weightCode = store.getWeightunitcode();
String measureCode = store.getSeizeunitcode();
if (weightCode.equals("KG")) {
weightCode = "KGS";
} else {
weightCode = "LBS";
}
String xml = "<?xml version=\"1.0\"?><RatingServiceSelectionRequest><Request><TransactionReference><CustomerContext>SalesManager Data</CustomerContext><XpciVersion>1.0001</XpciVersion></TransactionReference><RequestAction>Rate</RequestAction><RequestOption>Shop</RequestOption></Request>";
StringBuffer xmldatabuffer = new StringBuffer();
/**
* <Shipment>
*
* <Shipper> <Address> <City></City>
* <StateProvinceCode>QC</StateProvinceCode>
* <CountryCode>CA</CountryCode> <PostalCode></PostalCode>
* </Address> </Shipper>
*
* <ShipTo> <Address> <City>Redwood Shores</City>
* <StateProvinceCode>CA</StateProvinceCode>
* <CountryCode>US</CountryCode> <PostalCode></PostalCode>
* <ResidentialAddressIndicator/> </Address> </ShipTo>
*
* <Package> <PackagingType> <Code>21</Code> </PackagingType>
* <PackageWeight> <UnitOfMeasurement> <Code>LBS</Code>
* </UnitOfMeasurement> <Weight>1.1</Weight> </PackageWeight>
* <PackageServiceOptions> <InsuredValue>
* <CurrencyCode>CAD</CurrencyCode>
* <MonetaryValue>100</MonetaryValue> </InsuredValue>
* </PackageServiceOptions> </Package>
*
*
* </Shipment>
*
* <CustomerClassification> <Code>03</Code>
* </CustomerClassification> </RatingServiceSelectionRequest>
* **/
Map countriesMap = (Map) RefCache.getAllcountriesmap(LanguageUtil
.getLanguageNumberCode(locale.getLanguage()));
Map zonesMap = (Map) RefCache.getAllZonesmap(LanguageUtil
.getLanguageNumberCode(locale.getLanguage()));
Country storeCountry = (Country) countriesMap.get(store
.getCountry());
Country customerCountry = (Country) countriesMap.get(customer
.getCustomerCountryId());
int sZone = -1;
try {
sZone = Integer.parseInt(store.getZone());
} catch (Exception e) {
// TODO: handle exception
}
Zone storeZone = (Zone) zonesMap.get(sZone);
Zone customerZone = (Zone) zonesMap.get(customer
.getCustomerZoneId());
xmldatabuffer.append("<PickupType><Code>03</Code></PickupType>");
// xmldatabuffer.append("<Description>Daily Pickup</Description>");
xmldatabuffer.append("<Shipment><Shipper>");
xmldatabuffer.append("<Address>");
xmldatabuffer.append("<City>");
xmldatabuffer.append(store.getStorecity());
xmldatabuffer.append("</City>");
// if(!StringUtils.isBlank(store.getStorestateprovince())) {
if (storeZone != null) {
xmldatabuffer.append("<StateProvinceCode>");
xmldatabuffer.append(storeZone.getZoneCode());// zone code
xmldatabuffer.append("</StateProvinceCode>");
}
xmldatabuffer.append("<CountryCode>");
xmldatabuffer.append(storeCountry.getCountryIsoCode2());
xmldatabuffer.append("</CountryCode>");
xmldatabuffer.append("<PostalCode>");
xmldatabuffer.append(com.salesmanager.core.util.ShippingUtil
.trimPostalCode(store.getStorepostalcode()));
xmldatabuffer.append("</PostalCode></Address></Shipper>");
// ship to
xmldatabuffer.append("<ShipTo>");
xmldatabuffer.append("<Address>");
xmldatabuffer.append("<City>");
xmldatabuffer.append(customer.getCustomerCity());
xmldatabuffer.append("</City>");
// if(!StringUtils.isBlank(customer.getCustomerState())) {
if (customerZone != null) {
xmldatabuffer.append("<StateProvinceCode>");
xmldatabuffer.append(customerZone.getZoneCode());// zone code
xmldatabuffer.append("</StateProvinceCode>");
}
xmldatabuffer.append("<CountryCode>");
xmldatabuffer.append(customerCountry.getCountryIsoCode2());
xmldatabuffer.append("</CountryCode>");
xmldatabuffer.append("<PostalCode>");
xmldatabuffer.append(com.salesmanager.core.util.ShippingUtil
.trimPostalCode(customer.getCustomerPostalCode()));
xmldatabuffer.append("</PostalCode></Address></ShipTo>");
// xmldatabuffer.append("<Service><Code>11</Code></Service>");
Iterator packagesIterator = packages.iterator();
while (packagesIterator.hasNext()) {
PackageDetail detail = (PackageDetail) packagesIterator.next();
xmldatabuffer.append("<Package>");
xmldatabuffer.append("<PackagingType>");
xmldatabuffer.append("<Code>");
xmldatabuffer.append(pack);
xmldatabuffer.append("</Code>");
xmldatabuffer.append("</PackagingType>");
// weight
xmldatabuffer.append("<PackageWeight>");
xmldatabuffer.append("<UnitOfMeasurement>");
xmldatabuffer.append("<Code>");
xmldatabuffer.append(weightCode);
xmldatabuffer.append("</Code>");
xmldatabuffer.append("</UnitOfMeasurement>");
xmldatabuffer.append("<Weight>");
xmldatabuffer.append(new BigDecimal(detail.getShippingWeight())
.setScale(1, BigDecimal.ROUND_HALF_UP));
xmldatabuffer.append("</Weight>");
xmldatabuffer.append("</PackageWeight>");
// dimension
xmldatabuffer.append("<Dimensions>");
xmldatabuffer.append("<UnitOfMeasurement>");
xmldatabuffer.append("<Code>");
xmldatabuffer.append(measureCode);
xmldatabuffer.append("</Code>");
xmldatabuffer.append("</UnitOfMeasurement>");
xmldatabuffer.append("<Length>");
xmldatabuffer.append(new BigDecimal(detail.getShippingLength())
.setScale(2, BigDecimal.ROUND_HALF_UP));
xmldatabuffer.append("</Length>");
xmldatabuffer.append("<Width>");
xmldatabuffer.append(new BigDecimal(detail.getShippingWidth())
.setScale(2, BigDecimal.ROUND_HALF_UP));
xmldatabuffer.append("</Width>");
xmldatabuffer.append("<Height>");
xmldatabuffer.append(new BigDecimal(detail.getShippingHeight())
.setScale(2, BigDecimal.ROUND_HALF_UP));
xmldatabuffer.append("</Height>");
xmldatabuffer.append("</Dimensions>");
xmldatabuffer.append("</Package>");
}
xmldatabuffer.append("</Shipment>");
xmldatabuffer.append("</RatingServiceSelectionRequest>");
xmlbuffer.append(xmlhead).append(xml).append(
xmldatabuffer.toString());
log.debug("UPS QUOTE REQUEST " + xmlbuffer.toString());
String data = "";
IntegrationKeys keys = (IntegrationKeys) config
.getConfiguration("upsxml-keys");
IntegrationProperties props = (IntegrationProperties) config
.getConfiguration("upsxml-properties");
String host = cis.getCoreModuleServiceProdDomain();
String protocol = cis.getCoreModuleServiceProdProtocol();
String port = cis.getCoreModuleServiceProdPort();
String uri = cis.getCoreModuleServiceProdEnv();
if (props.getProperties1().equals(
String.valueOf(ShippingConstants.TEST_ENVIRONMENT))) {
host = cis.getCoreModuleServiceDevDomain();
protocol = cis.getCoreModuleServiceDevProtocol();
port = cis.getCoreModuleServiceDevPort();
uri = cis.getCoreModuleServiceDevEnv();
}
HttpClient client = new HttpClient();
httppost = new PostMethod(protocol + "://" + host + ":" + port
+ uri);
RequestEntity entity = new StringRequestEntity(
xmlbuffer.toString(), "text/plain", "UTF-8");
httppost.setRequestEntity(entity);
int result = client.executeMethod(httppost);
if (result != 200) {
log.error("Communication Error with ups quote " + result + " "
+ protocol + "://" + host + ":" + port + uri);
throw new Exception("UPS quote communication error " + result);
}
data = httppost.getResponseBodyAsString();
log.debug("ups quote response " + data);
UPSParsedElements parsed = new UPSParsedElements();
Digester digester = new Digester();
digester.push(parsed);
digester.addCallMethod(
"RatingServiceSelectionResponse/Response/Error",
"setErrorCode", 0);
digester.addCallMethod(
"RatingServiceSelectionResponse/Response/ErrorDescriprion",
"setError", 0);
digester
.addCallMethod(
"RatingServiceSelectionResponse/Response/ResponseStatusCode",
"setStatusCode", 0);
digester
.addCallMethod(
"RatingServiceSelectionResponse/Response/ResponseStatusDescription",
"setStatusMessage", 0);
digester
.addCallMethod(
"RatingServiceSelectionResponse/Response/Error/ErrorDescription",
"setError", 0);
digester.addObjectCreate(
"RatingServiceSelectionResponse/RatedShipment",
com.salesmanager.core.entity.shipping.ShippingOption.class);
// digester.addSetProperties(
// "RatingServiceSelectionResponse/RatedShipment", "sequence",
// "optionId" );
digester
.addCallMethod(
"RatingServiceSelectionResponse/RatedShipment/Service/Code",
"setOptionId", 0);
digester
.addCallMethod(
"RatingServiceSelectionResponse/RatedShipment/TotalCharges/MonetaryValue",
"setOptionPriceText", 0);
digester
.addCallMethod(
"RatingServiceSelectionResponse/RatedShipment/TotalCharges/CurrencyCode",
"setCurrency", 0);
digester
.addCallMethod(
"RatingServiceSelectionResponse/RatedShipment/Service/Code",
"setOptionCode", 0);
digester
.addCallMethod(
"RatingServiceSelectionResponse/RatedShipment/GuaranteedDaysToDelivery",
"setEstimatedNumberOfDays", 0);
digester.addSetNext("RatingServiceSelectionResponse/RatedShipment",
"addOption");
// <?xml
// version="1.0"?><AddressValidationResponse><Response><TransactionReference><CustomerContext>SalesManager
// Data</CustomerContext><XpciVersion>1.0</XpciVersion></TransactionReference><ResponseStatusCode>0</ResponseStatusCode><ResponseStatusDescription>Failure</ResponseStatusDescription><Error><ErrorSeverity>Hard</ErrorSeverity><ErrorCode>10002</ErrorCode><ErrorDescription>The
// XML document is well formed but the document is not
// valid</ErrorDescription><ErrorLocation><ErrorLocationElementName>AddressValidationRequest</ErrorLocationElementName></ErrorLocation></Error></Response></AddressValidationResponse>
Reader xmlreader = new StringReader(data);
digester.parse(xmlreader);
if (!StringUtils.isBlank(parsed.getErrorCode())) {
log.error("Can't process UPS statusCode="
+ parsed.getErrorCode() + " message= "
+ parsed.getError());
return null;
}
if (!StringUtils.isBlank(parsed.getStatusCode())
&& !parsed.getStatusCode().equals("1")) {
LogMerchantUtil.log(store.getMerchantId(),
"Can't process UPS statusCode="
+ parsed.getStatusCode() + " message= "
+ parsed.getError());
log.error("Can't process UPS statusCode="
+ parsed.getStatusCode() + " message= "
+ parsed.getError());
return null;
}
if (parsed.getOptions() == null || parsed.getOptions().size() == 0) {
log.warn("No options returned from UPS");
return null;
}
String carrier = getShippingMethodDescription(locale);
// cost is in CAD, need to do conversion
/*
* boolean requiresCurrencyConversion = false; String storeCurrency
* = store.getCurrency();
* if(!storeCurrency.equals(Constants.CURRENCY_CODE_CAD)) {
* requiresCurrencyConversion = true; }
*/
LabelUtil labelUtil = LabelUtil.getInstance();
Map serviceMap = com.salesmanager.core.util.ShippingUtil
.buildServiceMap("upsxml", locale);
/** Details on whit RT quote information to display **/
MerchantConfiguration rtdetails = config
.getMerchantConfiguration(ShippingConstants.MODULE_SHIPPING_DISPLAY_REALTIME_QUOTES);
int displayQuoteDeliveryTime = ShippingConstants.NO_DISPLAY_RT_QUOTE_TIME;
if (rtdetails != null) {
if (!StringUtils.isBlank(rtdetails.getConfigurationValue1())) {// display
// or
// not
// quotes
try {
displayQuoteDeliveryTime = Integer.parseInt(rtdetails
.getConfigurationValue1());
} catch (Exception e) {
log.error("Display quote is not an integer value ["
+ rtdetails.getConfigurationValue1() + "]");
}
}
}
/**/
Collection returnColl = null;
List options = parsed.getOptions();
if (options != null) {
Map selectedintlservices = (Map) config
.getConfiguration("service-global-upsxml");
Iterator i = options.iterator();
while (i.hasNext()) {
ShippingOption option = (ShippingOption) i.next();
// option.setCurrency(store.getCurrency());
StringBuffer description = new StringBuffer();
String code = option.getOptionCode();
option.setOptionCode(code);
// get description
String label = (String) serviceMap.get(code);
if (label == null) {
log
.warn("UPSXML cannot find description for service code "
+ code);
}
option.setOptionName(label);
description.append(option.getOptionName());
if (displayQuoteDeliveryTime == ShippingConstants.DISPLAY_RT_QUOTE_TIME) {
if (!StringUtils.isBlank(option
.getEstimatedNumberOfDays())) {
description.append(" (").append(
option.getEstimatedNumberOfDays()).append(
" ").append(
labelUtil.getText(locale,
"label.generic.days.lowercase"))
.append(")");
}
}
option.setDescription(description.toString());
// get currency
if (!option.getCurrency().equals(store.getCurrency())) {
option.setOptionPrice(CurrencyUtil.convertToCurrency(
option.getOptionPrice(), option.getCurrency(),
store.getCurrency()));
}
if (!selectedintlservices.containsKey(option
.getOptionCode())) {
if (returnColl == null) {
returnColl = new ArrayList();
}
returnColl.add(option);
// options.remove(option);
}
}
if (options.size() == 0) {
LogMerchantUtil
.log(
store.getMerchantId(),
" none of the service code returned by UPS ["
+ selectedintlservices
.keySet()
.toArray(
new String[selectedintlservices
.size()])
+ "] for this shipping is in your selection list");
}
}
return returnColl;
} catch (Exception e1) {
log.error(e1);
return null;
} finally {
if (reader != null) {
try {
reader.close();
} catch (Exception ignore) {
}
}
if (httppost != null) {
httppost.releaseConnection();
}
}
}
public void storeConfiguration(int merchantid, ConfigurationResponse vo, HttpServletRequest request)
throws Exception {
// TODO Auto-generated method stub
// stored in ShippingupsxmlAction class
}
public ConfigurationResponse getConfiguration(
MerchantConfiguration configurations, ConfigurationResponse vo)
throws Exception {
// what is the MerchantConfiguration ??
if (configurations.getConfigurationKey().equals(
ShippingConstants.MODULE_SHIPPING_RT_CRED)) {// handle
// credentials
if (!StringUtils.isBlank(configurations.getConfigurationValue1())) {
IntegrationKeys keys = ShippingUtil.getKeys(configurations
.getConfigurationValue1());
vo.addConfiguration("upsxml-keys", keys);
}
if (!StringUtils.isBlank(configurations.getConfigurationValue2())) {
IntegrationProperties props = ShippingUtil
.getProperties(configurations.getConfigurationValue2());
vo.addConfiguration("upsxml-properties", props);
}
}
if (configurations.getConfigurationKey().equals(
ShippingConstants.MODULE_SHIPPING_RT_PKG_DOM_INT)) {// handle
// packages
// &
// services
Map domesticmap = null;
Map globalmap = null;
// PKGOPTIONS
if (!StringUtils.isBlank(configurations.getConfigurationValue())) {
vo.addConfiguration("package-upsxml", configurations
.getConfigurationValue());
}
// Global
if (!StringUtils.isBlank(configurations.getConfigurationValue2())) {
globalmap = new HashMap();
String intl = configurations.getConfigurationValue2();
StringTokenizer st = new StringTokenizer(intl, ";");
while (st.hasMoreTokens()) {
String token = st.nextToken();
globalmap.put(token, token);
}
vo.addConfiguration("service-global-upsxml", globalmap);
}
}
vo.addMerchantConfiguration(configurations);
return vo;
}
private String responsecode = null;
private String responsetext = null;
public String getResponsecode() {
return responsecode;
}
public void setResponsecode(String responsecode) {
this.responsecode = responsecode;
}
public String getResponsetext() {
return responsetext;
}
public void setResponsetext(String responsetext) {
this.responsetext = responsetext;
}
}
class UPSParsedElements {
private String statusCode;
private String statusMessage;
private String error = "";
private String errorCode = "";
private List options = new ArrayList();
public void addOption(ShippingOption option) {
options.add(option);
}
public List getOptions() {
return options;
}
public String getStatusCode() {
return statusCode;
}
public void setStatusCode(String statusCode) {
this.statusCode = statusCode;
}
public String getStatusMessage() {
return statusMessage;
}
public void setStatusMessage(String statusMessage) {
this.statusMessage = statusMessage;
}
public String getError() {
return error;
}
public void setError(String error) {
this.error = error;
}
public String getErrorCode() {
return errorCode;
}
public void setErrorCode(String errorCode) {
this.errorCode = errorCode;
}
}