package com.shopizer.modules.shipping.distance;
import java.math.BigDecimal;
import java.util.List;
import java.util.Locale;
import org.apache.commons.lang.Validate;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.maps.DistanceMatrixApi;
import com.google.maps.GeoApiContext;
import com.google.maps.GeocodingApi;
import com.google.maps.model.Distance;
import com.google.maps.model.DistanceMatrix;
import com.google.maps.model.DistanceMatrixRow;
import com.google.maps.model.GeocodingResult;
import com.google.maps.model.LatLng;
import com.salesmanager.core.model.common.Delivery;
import com.salesmanager.core.model.merchant.MerchantStore;
import com.salesmanager.core.model.shipping.PackageDetails;
import com.salesmanager.core.model.shipping.ShippingConfiguration;
import com.salesmanager.core.model.shipping.ShippingOrigin;
import com.salesmanager.core.model.shipping.ShippingQuote;
import com.salesmanager.core.model.system.IntegrationConfiguration;
import com.salesmanager.core.model.system.IntegrationModule;
import com.salesmanager.core.modules.constants.Constants;
import com.salesmanager.core.modules.integration.IntegrationException;
import com.salesmanager.core.modules.integration.shipping.model.ShippingQuotePrePostProcessModule;
/**
* Uses google api to get lng, lat and distance in km for a given delivery address
* The route will be displayed on a map to the end user and available
* from the admin section
*
* The module can be configured to use miles by changing distance.inMeters
*
* To use this pre-processor you will need a google api-key
*
* Access google developers console
* https://console.developers.google.com/project
*
* Geocoding
* Distance Matrix
* Directions
*
* Create new key for server application
* Copy API key
* https://console.developers.google.com
*
* https://developers.google.com/maps/documentation/webservices/client-library
* https://github.com/googlemaps/google-maps-services-java/tree/master/src/test/java/com/google/maps
*
* @author carlsamson
*
*/
public class ShippingDistancePreProcessorImpl implements ShippingQuotePrePostProcessModule {
private static final Logger LOGGER = LoggerFactory.getLogger(ShippingDistancePreProcessorImpl.class);
private final static String BLANK = " ";
private final static String MODULE_CODE = "shippingDistanceModule";
private String apiKey;
private List<String> allowedZonesCodes = null;
public List<String> getAllowedZonesCodes() {
return allowedZonesCodes;
}
public void setAllowedZonesCodes(List<String> allowedZonesCodes) {
this.allowedZonesCodes = allowedZonesCodes;
}
public void prePostProcessShippingQuotes(ShippingQuote quote,
List<PackageDetails> packages, BigDecimal orderTotal,
Delivery delivery, ShippingOrigin origin, MerchantStore store,
IntegrationConfiguration globalShippingConfiguration,
IntegrationModule currentModule,
ShippingConfiguration shippingConfiguration,
List<IntegrationModule> allModules, Locale locale)
throws IntegrationException {
/** which destinations are supported by this module **/
if(delivery.getZone()==null) {
return;
}
boolean zoneAllowed = false;
if(allowedZonesCodes!=null) {
for(String zoneCode : allowedZonesCodes) {
if(zoneCode.equals(delivery.getZone().getCode())) {
zoneAllowed = true;
break;
}
}
}
if(!zoneAllowed) {
return;
}
if(StringUtils.isBlank(delivery.getPostalCode())) {
return;
}
Validate.notNull(apiKey, "Requires the configuration of google apiKey");
GeoApiContext context = new GeoApiContext().setApiKey(apiKey);
//build origin address
StringBuilder originAddress = new StringBuilder();
originAddress.append(origin.getAddress()).append(BLANK)
.append(origin.getCity()).append(BLANK)
.append(origin.getPostalCode()).append(BLANK);
if(!StringUtils.isBlank(origin.getState())) {
originAddress.append(origin.getState()).append(" ");
}
if(origin.getZone()!=null) {
originAddress.append(origin.getZone().getCode()).append(" ");
}
originAddress.append(origin.getCountry().getIsoCode());
//build destination address
StringBuilder destinationAddress = new StringBuilder();
destinationAddress.append(delivery.getAddress()).append(BLANK);
if(!StringUtils.isBlank(delivery.getCity())) {
destinationAddress.append(delivery.getCity()).append(BLANK);
}
destinationAddress.append(delivery.getPostalCode()).append(BLANK);
if(!StringUtils.isBlank(delivery.getState())) {
destinationAddress.append(delivery.getState()).append(" ");
}
if(delivery.getZone()!=null) {
destinationAddress.append(delivery.getZone().getCode()).append(" ");
}
destinationAddress.append(delivery.getCountry().getIsoCode());
try {
GeocodingResult[] originAdressResult = GeocodingApi.geocode(context,
originAddress.toString()).await();
GeocodingResult[] destinationAdressResult = GeocodingApi.geocode(context,
destinationAddress.toString()).await();
if(originAdressResult.length>0 && destinationAdressResult.length>0) {
LatLng originLatLng = originAdressResult[0].geometry.location;
LatLng destinationLatLng = destinationAdressResult[0].geometry.location;
delivery.setLatitude(String.valueOf(destinationLatLng.lat));
delivery.setLongitude(String.valueOf(destinationLatLng.lng));
//keep latlng for further usage in order to display the map
DistanceMatrix distanceRequest = DistanceMatrixApi.newRequest(context)
.origins(new LatLng(originLatLng.lat, originLatLng.lng))
.destinations(new LatLng(destinationLatLng.lat, destinationLatLng.lng))
.awaitIgnoreError();
if(distanceRequest!=null) {
DistanceMatrixRow distanceMax = distanceRequest.rows[0];
Distance distance = distanceMax.elements[0].distance;
quote.getQuoteInformations().put(Constants.DISTANCE_KEY, 0.001 * distance.inMeters);
}
}
} catch (Exception e) {
LOGGER.error("Exception while calculating the shipping distance",e);
}
}
public String getApiKey() {
return apiKey;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public String getModuleCode() {
// TODO Auto-generated method stub
return MODULE_CODE;
}
}