com.shopizer.modules.shipping.canadapost.CanadaPostQuoteModule Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of shopizer-shipping-canadapost-module Show documentation
Show all versions of shopizer-shipping-canadapost-module Show documentation
Shopizer module for Canada Post rate
package com.shopizer.modules.shipping.canadapost;
import java.io.InputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ca.canadapost.cpcdp.rating.generated.messages.Messages;
import ca.canadapost.cpcdp.rating.generated.rating.MailingScenario;
import ca.canadapost.cpcdp.rating.generated.rating.MailingScenario.Destination;
import ca.canadapost.cpcdp.rating.generated.rating.MailingScenario.Destination.Domestic;
import ca.canadapost.cpcdp.rating.generated.rating.MailingScenario.Destination.International;
import ca.canadapost.cpcdp.rating.generated.rating.MailingScenario.Destination.UnitedStates;
import ca.canadapost.cpcdp.rating.generated.rating.MailingScenario.Services;
import ca.canadapost.cpcdp.rating.generated.rating.PriceQuotes;
import com.salesmanager.core.model.common.Delivery;
import com.salesmanager.core.model.merchant.MerchantStore;
import com.salesmanager.core.model.reference.country.Country;
import com.salesmanager.core.model.shipping.PackageDetails;
import com.salesmanager.core.model.shipping.ShippingConfiguration;
import com.salesmanager.core.model.shipping.ShippingOption;
import com.salesmanager.core.model.shipping.ShippingOrigin;
import com.salesmanager.core.model.shipping.ShippingQuote;
import com.salesmanager.core.model.system.CustomIntegrationConfiguration;
import com.salesmanager.core.model.system.IntegrationConfiguration;
import com.salesmanager.core.model.system.IntegrationModule;
import com.salesmanager.core.model.system.ModuleConfig;
import com.salesmanager.core.modules.integration.IntegrationException;
import com.salesmanager.core.modules.integration.shipping.model.ShippingQuoteModule;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.config.ClientConfig;
import com.sun.jersey.api.client.config.DefaultClientConfig;
/**
* Shipping Module for Canada Post GetRates service
* https://www.canadapost.ca/cpo/mc/business/productsservices/developers/services/rating/default.jsf
* @author carlsamson
*/
public class CanadaPostQuoteModule implements ShippingQuoteModule {
private static final Logger LOGGER = LoggerFactory.getLogger(CanadaPostQuoteModule.class);
private final static String CANADA_CODE = "CA";
private final static String US_CODE = "US";
//dev "https://ct.soa-gw.canadapost.ca/rs/ship/price";
//prod "https://soa-gw.canadapost.ca/rs/ship/price";
@Override
public void validateModuleConfiguration(
IntegrationConfiguration integrationConfiguration,
MerchantStore store) throws IntegrationException {
List errorFields = null;
Map keys = integrationConfiguration.getIntegrationKeys();
if(keys==null) {
IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
ex.setErrorFields(errorFields);
throw ex;
}
if(StringUtils.isBlank(keys.get("username"))) {
errorFields = new ArrayList();
errorFields.add("username");
}
if(StringUtils.isBlank(keys.get("password"))) {
errorFields = new ArrayList();
errorFields.add("password");
}
if(StringUtils.isBlank(keys.get("account"))) {
errorFields = new ArrayList();
errorFields.add("account");
}
if(StringUtils.isBlank(keys.get("apikey"))) {
errorFields = new ArrayList();
errorFields.add("apikey");
}
if(errorFields!=null) {
IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
ex.setErrorFields(errorFields);
throw ex;
}
}
@Override
public CustomIntegrationConfiguration getCustomModuleConfiguration(
MerchantStore store) throws IntegrationException {
// TODO Auto-generated method stub
return null;
}
@Override
public List getShippingQuotes(ShippingQuote quote,
List packages, BigDecimal orderTotal,
Delivery delivery, ShippingOrigin origin, MerchantStore store,
IntegrationConfiguration configuration, IntegrationModule module,
ShippingConfiguration shippingConfiguration, Locale locale)
throws IntegrationException {
Validate.notNull(shippingConfiguration, "Module Canadapost is not configured");
Validate.notNull(packages, "Packages are null");
Validate.notNull(delivery, "Delivery is null");
Validate.notNull(origin, "Origin is null");
Validate.notNull(origin.getPostalCode(), "Origin postal code is null");
if(StringUtils.isBlank(delivery.getPostalCode())) {
return null;
}
// only applies to Canada and US
Country country = delivery.getCountry();
if(!(country.getIsoCode().equals("US") || country.getIsoCode().equals("CA"))) {
throw new IntegrationException("Canadapost Not configured for shipping in country " + country.getIsoCode());
}
Map keys = configuration.getIntegrationKeys();
Map> options = configuration.getIntegrationOptions();
if(keys==null) {
throw new IntegrationException("Canadapost missing configuration keys");
}
if(options==null) {
throw new IntegrationException("Canadapost missing configuration options");
}
if(StringUtils.isBlank(keys.get("username"))) {
throw new IntegrationException("Canadapost missing configuration key username");
}
if(StringUtils.isBlank(keys.get("password"))) {
throw new IntegrationException("Canadapost missing configuration key password");
}
if(StringUtils.isBlank(keys.get("account"))) {
throw new IntegrationException("Canadapost missing configuration key account");
}
String username = keys.get("username");
String password = keys.get("password");
String client = keys.get("account");
List domesticServices = options.get("services-domestic");
List intlServices = options.get("services-intl");
List usaServices = options.get("services-usa");
String host = null;
String protocol = null;
String port = null;
String url = null;
//against which environment are we using the service
String env = configuration.getEnvironment();
Map moduleConfigsMap = module.getModuleConfigs();
for(String key : moduleConfigsMap.keySet()) {
ModuleConfig moduleConfig = (ModuleConfig)moduleConfigsMap.get(key);
if(moduleConfig.getEnv().equals(env)) {
host = moduleConfig.getHost();
protocol = moduleConfig.getScheme();
port = moduleConfig.getPort();
url = moduleConfig.getUri();
break;
}
}
StringBuilder link = new StringBuilder().append(protocol).append("://").append(host).append(":").append(port);
if(!StringUtils.isBlank(url)) {
link.append(url);
}
Client serviceClient = null;
ClientConfig config = new DefaultClientConfig();
serviceClient = Client.create(config);
serviceClient.addFilter(new com.sun.jersey.api.client.filter.HTTPBasicAuthFilter(username, password));
MailingScenario mailingScenario = new MailingScenario();
//mailingScenario.setCustomerNumber(client);
mailingScenario.setQuoteType("counter");
//if(!StringUtils.isEmpty(client)) {
// mailingScenario.setCustomerNumber(client);
//}
mailingScenario.setOriginPostalCode(origin.getPostalCode().replaceAll("\\s+","").toUpperCase());
Destination destination = new Destination();
if(delivery.getCountry().getIsoCode().equals(CANADA_CODE)) {
if(domesticServices==null || domesticServices.size()==0) {
throw new IntegrationException("Canadapost selected domestic services are missing");
}
Domestic domestic = new Domestic();
domestic.setPostalCode(delivery.getPostalCode().replaceAll("\\s+","").toUpperCase());
destination.setDomestic(domestic);
Services service = new Services();
for(String domesticService : domesticServices) {
service.getServiceCodes().add(domesticService);
}
mailingScenario.setServices(service);
} else if(delivery.getCountry().getIsoCode().equals(US_CODE)) {
if(usaServices==null || usaServices.size()==0) {
throw new IntegrationException("Canadapost selected USA services are missing");
}
UnitedStates unitedStates = new UnitedStates();
unitedStates.setZipCode(delivery.getPostalCode().trim());
destination.setUnitedStates(unitedStates);
Services service = new Services();
for(String usaService : usaServices) {
service.getServiceCodes().add(usaService);
}
mailingScenario.setServices(service);
} else {
if(intlServices==null || intlServices.size()==0) {
throw new IntegrationException("Canadapost selected International services are missing");
}
International international = new International();
international.setCountryCode(delivery.getCountry().getIsoCode());
destination.setInternational(international);
Services service = new Services();
for(String intlService : intlServices) {
service.getServiceCodes().add(intlService);
}
mailingScenario.setServices(service);
}
mailingScenario.setDestination(destination);
Map allOptions = new HashMap();
// Execute GetRates Request for each package
for(PackageDetails packageDetail : packages) {
MailingScenario.ParcelCharacteristics parcelCharacteristics = new MailingScenario.ParcelCharacteristics();
parcelCharacteristics.setWeight(new BigDecimal(packageDetail.getShippingWeight()));
MailingScenario.ParcelCharacteristics.Dimensions dimensions = new MailingScenario.ParcelCharacteristics.Dimensions();
convertPackageSizeAndWeight(store, packageDetail);//possible weight and size conversion
dimensions.setHeight(new BigDecimal(packageDetail.getShippingHeight()));
dimensions.setWidth(new BigDecimal(packageDetail.getShippingWidth()));
dimensions.setLength(new BigDecimal(packageDetail.getShippingLength()));
parcelCharacteristics.setDimensions(dimensions);
mailingScenario.setParcelCharacteristics(parcelCharacteristics);
WebResource webResource = serviceClient.resource(link.toString());
ClientResponse resp = webResource.accept("application/vnd.cpc.ship.rate-v3+xml").header("Content-Type", "application/vnd.cpc.ship.rate-v3+xml").acceptLanguage("en-CA").post(ClientResponse.class, mailingScenario);
InputStream respIS = resp.getEntityInputStream();
LOGGER.debug("HTTP Response Status: " + resp.getStatus() + " " + resp.getClientResponseStatus());
// Example of using JAXB to parse xml response
JAXBContext jc;
try {
jc = JAXBContext.newInstance(PriceQuotes.class, Messages.class);
Object entity = jc.createUnmarshaller().unmarshal(respIS);
// Determine whether response data matches GetRatesInfo schema.
if (entity instanceof PriceQuotes) {
PriceQuotes priceQuotes = (PriceQuotes) entity;
for (Iterator iter = priceQuotes.getPriceQuotes().iterator(); iter.hasNext();) {
PriceQuotes.PriceQuote aPriceQuote = (PriceQuotes.PriceQuote) iter.next();
ShippingOption option = allOptions.get(aPriceQuote.getServiceCode());
if(option==null) {
option = new ShippingOption();
option.setOptionCode(aPriceQuote.getServiceCode());
option.setOptionPrice(aPriceQuote.getPriceDetails().getDue());
option.setOptionName(aPriceQuote.getServiceName());
allOptions.put(aPriceQuote.getServiceCode(), option);
} else {
BigDecimal due = option.getOptionPrice().add(aPriceQuote.getPriceDetails().getDue());
option.setOptionPrice(due);
}
LOGGER.debug("Service Name: " + aPriceQuote.getServiceName());
LOGGER.debug("Price: $" + aPriceQuote.getPriceDetails().getDue());
}
} else {
// Assume Error Schema
Messages messageData = (Messages) entity;
StringBuilder messageBuilder = new StringBuilder();
for (Iterator iter = messageData.getMessage().iterator(); iter.hasNext();) {
Messages.Message aMessage = (Messages.Message) iter.next();
LOGGER.debug("Error Code: " + aMessage.getCode());
LOGGER.debug("Error Msg: " + aMessage.getDescription());
messageBuilder.append(aMessage.getCode()).append(" - ");
messageBuilder.append(aMessage.getDescription()).append(" ");
}
IntegrationException ex = new IntegrationException(messageBuilder.toString());
ex.setErrorCode(IntegrationException.TRANSACTION_EXCEPTION);
ex.setMessageCode(messageBuilder.toString());
throw ex;
}
} catch (Exception e) {
if(e instanceof IntegrationException) {
try {
throw e;
} catch (Exception e1) {}
}
IntegrationException ex = new IntegrationException(e);
ex.setErrorCode(IntegrationException.TRANSACTION_EXCEPTION);
throw ex;
}
serviceClient.destroy();
}
List shippingOptions = new ArrayList(allOptions.values());
return shippingOptions;
}
private void convertPackageSizeAndWeight(MerchantStore store, PackageDetails pack) {
if(!store.getSeizeunitcode().equals("CM")) {//canadapost requires centimeters
BigDecimal multiplier = new BigDecimal(2.54);
pack.setShippingHeight(new BigDecimal(pack.getShippingHeight()).multiply(multiplier).setScale(0, RoundingMode.CEILING).doubleValue());
pack.setShippingWidth(new BigDecimal(pack.getShippingWidth()).multiply(multiplier).setScale(0, RoundingMode.CEILING).doubleValue());
pack.setShippingLength(new BigDecimal(pack.getShippingLength()).multiply(multiplier).setScale(0, RoundingMode.CEILING).doubleValue());
}
if(!store.getWeightunitcode().equals("KG")) {//canadapost requires kilograms
BigDecimal multiplier = new BigDecimal(0.453592);
pack.setShippingWeight(new BigDecimal(pack.getShippingWeight()).multiply(multiplier).setScale(0, RoundingMode.CEILING).doubleValue());
}
return;
}
}