All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.shopizer.modules.shipping.canadapost.CanadaPostQuoteModule Maven / Gradle / Ivy

There is a newer version: 2.15.0
Show newest version
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;
		
	}
	

	

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy