shopizer-aplcache

Initial commit

6/22/2014 7:13:44 PM

Changes

sm-core/.classpath 12(+12 -0)

sm-core/.project 23(+23 -0)

sm-core/pom.xml 657(+657 -0)

Details

sm-core/.classpath 12(+12 -0)

diff --git a/sm-core/.classpath b/sm-core/.classpath
new file mode 100644
index 0000000..b77ae7b
--- /dev/null
+++ b/sm-core/.classpath
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java"/>
+	<classpathentry kind="src" path="target/generated-sources/querydsl"/>
+	<classpathentry kind="src" path="target/generated-sources/apt"/>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources"/>
+	<classpathentry kind="src" output="target/test-classes" path="src/test/java"/>
+	<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="con" path="org.maven.ide.eclipse.MAVEN2_CLASSPATH_CONTAINER"/>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>
diff --git a/sm-core/.gitignore b/sm-core/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/sm-core/.gitignore
@@ -0,0 +1 @@
+/target

sm-core/.project 23(+23 -0)

diff --git a/sm-core/.project b/sm-core/.project
new file mode 100644
index 0000000..23f3a60
--- /dev/null
+++ b/sm-core/.project
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>sm-core</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.maven.ide.eclipse.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.maven.ide.eclipse.maven2Nature</nature>
+	</natures>
+</projectDescription>

sm-core/pom.xml 657(+657 -0)

diff --git a/sm-core/pom.xml b/sm-core/pom.xml
new file mode 100644
index 0000000..9e97a00
--- /dev/null
+++ b/sm-core/pom.xml
@@ -0,0 +1,657 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>com.shopizer</groupId>
+	<artifactId>sm-core</artifactId>
+	<version>2.0-SNAPSHOT</version>
+	<packaging>jar</packaging>
+
+	<name>sm-core</name>
+	<url>http://www.shopizer.com</url>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<jdk.version>1.6</jdk.version>
+		
+		
+		<jackson-version>1.9.13</jackson-version>
+		<axis-version>1.4</axis-version>
+		<jaxws.api.version>2.1</jaxws.api.version>
+		<jaxws.version>2.1.4</jaxws.version>
+		<jsr181.version>1.0-MR1</jsr181.version>
+		<jsr250.version>1.0</jsr250.version>
+		<org.elasticsearch-version>0.90.2</org.elasticsearch-version>
+		<jasperreports-version>3.7.4</jasperreports-version>
+		
+		<freemarker.version>2.3.19</freemarker.version>
+		<org.slf4j-version>1.6.6</org.slf4j-version>
+		<hibernate.ehcache.version>3.5.1-Final</hibernate.ehcache.version>
+		<sm-core.hibernate-entitymanager-version>4.1.2</sm-core.hibernate-entitymanager-version>
+		<sm-core.hibernate-jpamodelgen.version>1.1.1.Final</sm-core.hibernate-jpamodelgen.version>
+		<sm-core.aspectj.version>1.5.4</sm-core.aspectj.version>
+		<sm-core.mysql-connector-java>5.1.19</sm-core.mysql-connector-java>
+		<sm-core.junit.version>4.9</sm-core.junit.version>
+		<sm-core.org.springframework.version>3.1.0.RELEASE</sm-core.org.springframework.version>
+		<sm-core.c3p0.version>0.9.1.2</sm-core.c3p0.version>
+		<sm-core.querydsl.version>2.3.3</sm-core.querydsl.version>
+		<sm-core.jodatime.version>2.0</sm-core.jodatime.version>
+		<sm-core.jodatime-hibernate.version>1.3</sm-core.jodatime-hibernate.version>
+		<sm-core.javassist.version>3.3</sm-core.javassist.version>
+		<sm-search.version>0.0.3</sm-search.version>
+	</properties>
+
+	<dependencies>
+	
+		<!--<dependency>
+    		<groupId>com.shopizer</groupId>
+    		<artifactId>com.shopizer.authorizenet</artifactId>
+    		<version>0.0.1-SNAPSHOT</version>
+		</dependency>-->
+		
+	    <!-- sm-search -->		
+		<dependency>
+			<groupId>com.shopizer</groupId>
+			<artifactId>sm-search</artifactId>
+			<version>${sm-search.version}</version>
+		</dependency>
+
+
+		<!-- Loggers -->
+		<dependency>
+			<groupId>org.slf4j</groupId>
+			<artifactId>slf4j-log4j12</artifactId>
+			<version>${org.slf4j-version}</version>
+		</dependency>
+
+		<!-- Hibernate -->
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-core</artifactId>
+			<version>${sm-core.hibernate-entitymanager-version}</version>
+			<exclusions>
+				<exclusion>
+					<artifactId>javassist</artifactId>
+					<groupId>org.javassist</groupId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-entitymanager</artifactId>
+			<version>${sm-core.hibernate-entitymanager-version}</version>
+			<exclusions>
+				<exclusion>
+					<groupId>asm</groupId>
+					<artifactId>asm</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>asm</groupId>
+					<artifactId>asm-attrs</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>cglib</groupId>
+					<artifactId>cglib</artifactId>
+				</exclusion>
+				<exclusion>
+					<artifactId>javassist</artifactId>
+					<groupId>javassist</groupId>
+				</exclusion>
+				<exclusion>
+					<groupId>org.hibernate</groupId>
+					<artifactId>hibernate-core</artifactId>
+				</exclusion>
+				<exclusion>
+					<artifactId>javassist</artifactId>
+					<groupId>org.javassist</groupId>
+				</exclusion>
+			</exclusions>
+		</dependency>
+
+		<!-- Hibernate ehcache -->
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-ehcache</artifactId>
+			<version>${hibernate.ehcache.version}</version>
+		</dependency>
+
+		<!-- Javassist -->
+		<dependency>
+			<groupId>javassist</groupId>
+			<artifactId>javassist</artifactId>
+			<version>${sm-core.javassist.version}</version>
+		</dependency>
+
+		<!-- QueryDsl -->
+		<dependency>
+			<groupId>com.mysema.querydsl</groupId>
+			<artifactId>querydsl-apt</artifactId>
+			<version>${sm-core.querydsl.version}</version>
+			<scope>provided</scope>
+		</dependency>
+		<dependency>
+			<groupId>com.mysema.querydsl</groupId>
+			<artifactId>querydsl-core</artifactId>
+			<version>${sm-core.querydsl.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.mysema.querydsl</groupId>
+			<artifactId>querydsl-jpa</artifactId>
+			<version>${sm-core.querydsl.version}</version>
+		</dependency>
+
+		<!-- Pool c3p0 -->
+		<dependency>
+			<groupId>c3p0</groupId>
+			<artifactId>c3p0</artifactId>
+			<version>${sm-core.c3p0.version}</version>
+		</dependency>
+
+		<!-- Spring -->
+		<!--
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-asm</artifactId>
+			<version>${sm-core.org.springframework-security.version}</version>
+		</dependency>
+		-->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-aop</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-aspects</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-beans</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-core</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-expression</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-orm</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-web</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+		</dependency>
+
+		<!-- JSR 303 with Hibernate Validator -->
+		<dependency>
+			<groupId>javax.validation</groupId>
+			<artifactId>validation-api</artifactId>
+			<version>1.0.0.GA</version>
+		</dependency>
+		<dependency>
+			<groupId>org.hibernate</groupId>
+			<artifactId>hibernate-validator</artifactId>
+			<version>4.3.0.Final</version>
+		</dependency>
+
+		<!-- AspectJ -->
+		<dependency>
+			<groupId>aspectj</groupId>
+			<artifactId>aspectjrt</artifactId>
+			<version>${sm-core.aspectj.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>aspectj</groupId>
+			<artifactId>aspectjweaver</artifactId>
+			<version>${sm-core.aspectj.version}</version>
+		</dependency>
+
+		<!-- Mysql Connector -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<version>${sm-core.mysql-connector-java}</version>
+		</dependency>
+		
+		<!-- H2 Connector -->
+		<dependency>
+			<groupId>com.h2database</groupId>
+			<artifactId>h2</artifactId>
+			<version>1.3.152</version>
+		</dependency>
+
+
+		<!-- Jackson JSON Processor -->
+		<dependency>
+			<groupId>org.codehaus.jackson</groupId>
+			<artifactId>jackson-mapper-asl</artifactId>
+			<version>${jackson-version}</version>
+		</dependency>
+		<dependency>
+			<groupId>com.googlecode.json-simple</groupId>
+			<artifactId>json-simple</artifactId>
+			<version>1.1.1</version>
+		</dependency>
+
+		<!-- File Upload -->
+		<dependency>
+			<groupId>commons-fileupload</groupId>
+			<artifactId>commons-fileupload</artifactId>
+			<version>1.2.2</version>
+		</dependency>
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>2.0.1</version>
+		</dependency>
+
+		<dependency>
+			<groupId>commons-collections</groupId>
+			<artifactId>commons-collections</artifactId>
+			<version>3.2.1</version>
+	   </dependency>
+	   
+		<!-- Apache common -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+			<version>3.0</version>
+		</dependency>
+		
+		<dependency>
+			<groupId>commons-validator</groupId>
+			<artifactId>commons-validator</artifactId>
+			<version>1.4.0</version>
+		</dependency>
+		
+		<!--
+		<dependency>
+  			<groupId>org.jboss.cache</groupId>
+  			<artifactId>jbosscache-core</artifactId>
+  			<version>3.2.5.GA</version>
+		</dependency>
+		-->
+		
+		<dependency>
+			<groupId>commons-lang</groupId>
+			<artifactId>commons-lang</artifactId>
+			<version>2.6</version>
+		</dependency>
+
+
+		<dependency>
+			<groupId>commons-httpclient</groupId>
+			<artifactId>commons-httpclient</artifactId>
+			<version>3.1</version>
+		</dependency>
+
+		
+
+		<!-- JodaTime -->
+		<dependency>
+			<groupId>joda-time</groupId>
+			<artifactId>joda-time</artifactId>
+			<version>${sm-core.jodatime.version}</version>
+		</dependency>
+		<dependency>
+			<groupId>org.jadira.usertype</groupId>
+			<artifactId>usertype.core</artifactId>
+			<version>3.0.0.CR1</version>
+		</dependency>
+
+
+        <!-- Infinispan -->
+  		<dependency>
+			<groupId>org.infinispan</groupId>
+    		<artifactId>infinispan-core</artifactId>
+    		<version>5.1.6.FINAL</version>
+  		</dependency>
+
+  		<!-- TO REMOVE -->
+  		<dependency>
+    		<groupId>org.infinispan</groupId>
+    		<artifactId>infinispan-cachestore-bdbje</artifactId>
+    		<version>5.1.4.FINAL</version>
+  		</dependency>
+
+		<dependency>      
+			<groupId>org.infinispan</groupId>      
+			<artifactId>infinispan-cachestore-jdbc</artifactId>      
+			<version>5.1.4.FINAL</version>
+		</dependency> 
+		
+		<dependency>
+			<groupId>org.infinispan</groupId>
+			<artifactId>infinispan-tree</artifactId>
+			<version>5.1.6.FINAL</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.freemarker</groupId>
+			<artifactId>freemarker</artifactId>
+			<version>${freemarker.version}</version>
+		</dependency>
+		
+		<dependency>
+			<groupId>javax.mail</groupId>
+			<artifactId>mail</artifactId>
+			<version>1.4.5</version>
+		</dependency>
+		
+
+		<dependency>
+			<groupId>org.jopendocument</groupId>
+			<artifactId>jOpenDocument</artifactId>
+			<version>1.3b1</version>
+		</dependency>
+		
+	    <dependency>
+			<groupId>com.lowagie</groupId>
+			<artifactId>itext</artifactId>
+			<version>4.2.1</version>
+		</dependency>
+		
+		
+		<!-- integration -->
+		<!--
+		<dependency>
+  			<groupId>com.paypal.sdk</groupId>
+  			<artifactId>rest-api-sdk</artifactId>
+  			<version>0.7.1</version>
+		</dependency>
+		-->
+		
+		<dependency>
+			<groupId>com.paypal.sdk</groupId>
+			<artifactId>merchantsdk</artifactId>
+			<version>2.6.109</version>
+		</dependency>
+		
+	    <dependency>
+	        <groupId>com.maxmind.geoip2</groupId>
+	        <artifactId>geoip2</artifactId>
+	        <version>0.7.0</version>
+	    </dependency>
+	    
+
+			
+		<!-- Test dependencies -->
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<version>${sm-core.junit.version}</version>
+			<scope>test</scope>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-test</artifactId>
+			<version>${sm-core.org.springframework.version}</version>
+			<scope>test</scope>
+		</dependency>
+
+		<!-- <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc5</artifactId> 
+			<version>11.1.0.7.0</version> <scope>provided</scope> </dependency> -->
+	</dependencies>
+	
+	<repositories>	
+		<!-- For testing against latest Spring snapshots -->
+		<repository>
+			<id>org.springframework.maven.snapshot</id>
+			<name>Spring Maven Snapshot Repository</name>
+			<url>http://maven.springframework.org/snapshot</url>
+			<releases><enabled>false</enabled></releases>
+			<snapshots><enabled>true</enabled></snapshots>
+		</repository>
+		<!-- For developing against latest Spring milestones -->
+		<repository>
+			<id>org.springframework.maven.milestone</id>
+			<name>Spring Maven Milestone Repository</name>
+			<url>http://maven.springframework.org/milestone</url>
+			<snapshots><enabled>false</enabled></snapshots>
+		</repository>
+		<repository>
+			<id>org.jboss.repository.releases</id>
+			<name>JBoss Maven Release Repository</name>			
+			<url>https://repository.jboss.org/nexus/content/repositories/releases</url>
+			<snapshots><enabled>false</enabled></snapshots>			
+		</repository>
+	</repositories>
+
+	<build>
+		<!-- 
+			Annotation processor to be generated in target/generated-sources
+			The build will generate the required annotated classes in generated-sources
+			Then will jump to the regular build in pluginManagement
+			
+			mvn clean
+			mvn install
+			
+			** if the install phase complains on missing Qxyz classes then
+			
+			mvn clean
+			mvn generate-sources
+			mvn install
+			
+			*** Want to have the schema generated
+			
+			** hbm2ddl not working 
+			mvn hibernate3:hbm2ddl
+			 
+		-->
+		<plugins>
+			<plugin>
+				<groupId>org.bsc.maven</groupId>
+				<artifactId>maven-processor-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals>
+							<goal>process</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>com.mysema.maven</groupId>
+				<artifactId>maven-apt-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals>
+							<goal>process</goal>
+						</goals>
+						<configuration>
+							<outputDirectory>target/generated-sources/querydsl</outputDirectory>
+							<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+		</plugins>
+		<pluginManagement>
+			<plugins>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-compiler-plugin</artifactId>
+					<version>2.3.2</version>
+					<configuration>
+						<source>${jdk.version}</source>
+						<target>${jdk.version}</target>
+						<encoding>${project.build.sourceEncoding}</encoding>
+						<compilerArgument>-proc:none</compilerArgument>
+					</configuration>
+				</plugin>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-surefire-plugin</artifactId>
+					<version>2.12</version>
+					<configuration>
+          				<skipTests>true</skipTests>
+        			</configuration>
+				</plugin>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-war-plugin</artifactId>
+					<version>2.2</version>
+				</plugin>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-install-plugin</artifactId>
+					<version>2.3.1</version>
+				</plugin>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-release-plugin</artifactId>
+					<version>2.2.2</version>
+				</plugin>
+				<plugin>
+					<groupId>org.apache.maven.plugins</groupId>
+					<artifactId>maven-assembly-plugin</artifactId>
+					<version>2.3</version>
+				</plugin>
+				<plugin>
+					<groupId>org.bsc.maven</groupId>
+					<artifactId>maven-processor-plugin</artifactId>
+					<version>2.0.5</version>
+					<configuration>
+						<outputDirectory>target/generated-sources</outputDirectory>
+						<options>
+							<fullyAnnotationConfigured>true</fullyAnnotationConfigured>
+							<addSuppressWarningsAnnotation>true</addSuppressWarningsAnnotation>
+						</options>
+					</configuration>
+					<executions>
+						<execution>
+							<id>process</id>
+							<goals>
+								<goal>process</goal>
+							</goals>
+							<phase>generate-sources</phase>
+						</execution>
+					</executions>
+				</plugin>
+				<plugin>
+					<groupId>org.bsc.maven</groupId>
+					<artifactId>maven-processor-plugin</artifactId>
+					<executions>
+						<execution>
+							<id>process</id>
+							<goals>
+								<goal>process</goal>
+							</goals>
+							<phase>generate-sources</phase>
+							<configuration>
+								<options>
+									<fullyAnnotationConfigured>true</fullyAnnotationConfigured>
+									<addSuppressWarningsAnnotation>true</addSuppressWarningsAnnotation>
+								</options>
+							</configuration>
+						</execution>
+					</executions>
+					<dependencies>
+						<dependency>
+							<groupId>org.hibernate</groupId>
+							<artifactId>hibernate-jpamodelgen</artifactId>
+							<version>${sm-core.hibernate-jpamodelgen.version}</version>
+						</dependency>
+					</dependencies>
+				</plugin>
+				<plugin>
+					<groupId>com.mysema.maven</groupId>
+					<artifactId>maven-apt-plugin</artifactId>
+					<version>1.0.2</version>
+					<configuration>
+						<outputDirectory>target/generated-sources/querydsl</outputDirectory>
+					</configuration>
+					<executions>
+						<execution>
+							<goals>
+								<goal>process</goal>
+							</goals>
+							<configuration>
+								<processor>com.mysema.query.apt.jpa.JPAAnnotationProcessor</processor>
+							</configuration>
+						</execution>
+					</executions>
+					<dependencies>
+						<dependency>
+							<groupId>com.mysema.querydsl</groupId>
+							<artifactId>querydsl-apt</artifactId>
+							<version>${sm-core.querydsl.version}</version>
+						</dependency>
+					</dependencies>
+				</plugin>
+				<!-- hbm2ddl Hibernate entities to schema -->
+				<plugin>
+					<groupId>org.codehaus.mojo</groupId>
+					<artifactId>hibernate3-maven-plugin</artifactId>
+					<version>2.2</version><!-- 2.2 -->
+					<executions>
+						<execution>
+							<phase>process-classes</phase>
+							<goals>
+								<goal>hbm2ddl</goal>
+							</goals>
+						</execution>
+					</executions>
+					<configuration>
+						<components>
+							<component>
+								<name>hbm2ddl</name>
+								<implementation>jpaconfiguration</implementation>
+							</component>
+						</components>
+						<componentProperties>
+							<persistenceunit>sm-unit</persistenceunit>
+							<!--<propertyfile>src/test/resources/hbm2ddl.properties</propertyfile>-->
+							<outputfilename>schema.ddl</outputfilename>
+							<drop>false</drop>
+							<create>true</create>
+							<export>false</export>
+							<format>true</format>
+						</componentProperties>
+					</configuration>
+				</plugin>
+				<!--This plugin's configuration is used to store Eclipse m2e settings 
+					only. It has no influence on the Maven build itself. -->
+				<plugin>
+					<groupId>org.eclipse.m2e</groupId>
+					<artifactId>lifecycle-mapping</artifactId>
+					<version>1.0.0</version>
+					<configuration>
+						<lifecycleMappingMetadata>
+							<pluginExecutions>
+								<pluginExecution>
+									<pluginExecutionFilter>
+										<groupId>org.codehaus.mojo</groupId>
+										<artifactId>aspectj-maven-plugin</artifactId>
+										<versionRange>[1.0,)</versionRange>
+										<goals>
+											<goal>test-compile</goal>
+											<goal>compile</goal>
+										</goals>
+									</pluginExecutionFilter>
+									<action>
+										<execute />
+									</action>
+								</pluginExecution>
+							</pluginExecutions>
+						</lifecycleMappingMetadata>
+					</configuration>
+				</plugin>
+			</plugins>
+		</pluginManagement>
+	</build>
+</project>
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/dao/CategoryDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/dao/CategoryDao.java
new file mode 100644
index 0000000..dff49b7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/dao/CategoryDao.java
@@ -0,0 +1,51 @@
+package com.salesmanager.core.business.catalog.category.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CategoryDao extends SalesManagerEntityDao<Long, Category> {
+
+	List<Category> listBySeUrl(MerchantStore store, String seUrl);
+
+	List<Category> listByStoreAndParent(MerchantStore store, Category category);
+
+	List<Category> listByLineage(MerchantStore store, String lineage);
+
+	List<Category> getByName(MerchantStore store, String name, Language language);
+
+	Category getByCode(MerchantStore store, String code);
+	
+	List<Category> listByStore(MerchantStore store);
+
+	List<Category> listByStore(MerchantStore store, Language language);
+
+	Category getById(Long id);
+
+	List<Category> listByDepth(MerchantStore store, int depth);
+
+	List<Category> listByDepth(MerchantStore store, int depth, Language language);
+
+	List<Category> listByLineage(String merchantStoreCode, String lineage);
+
+	Category getByCode(String merchantStoreCode, String code);
+
+	Category getBySeUrl(MerchantStore store, String seUrl);
+
+	List<Category> listByParent(Category category, Language language);
+
+	Category getByLanguage(long categoryId, Language language);
+
+	List<Object[]> countProductsByCategories(MerchantStore store,
+			List<Long> categoryIds);
+
+	List<Category> getByCodes(MerchantStore store, List<String> codes,
+			Language language);
+
+	List<Category> getByIds(MerchantStore store, List<Long> ids,
+			Language language);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/dao/CategoryDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/dao/CategoryDaoImpl.java
new file mode 100644
index 0000000..99cb5cd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/dao/CategoryDaoImpl.java
@@ -0,0 +1,370 @@
+package com.salesmanager.core.business.catalog.category.dao;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.Query;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.QCategory;
+import com.salesmanager.core.business.catalog.category.model.QCategoryDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("categoryDao")
+public class CategoryDaoImpl extends SalesManagerEntityDaoImpl<Long, Category> implements CategoryDao {
+
+	public CategoryDaoImpl() {
+		super();
+	}
+	
+	@Override
+	public List<Category> getByName(MerchantStore store, String name, Language language) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qDescription.name.like("%" + name + "%")
+			.and(qDescription.language.id.eq(language.getId()))
+			.and(qCategory.merchantStore.id.eq(store.getId())))
+			.orderBy(qCategory.sortOrder.asc());
+		
+
+		
+		List<Category> categories = query.list(qCategory);
+		return categories;
+	}
+	
+
+
+	@Override
+	public List<Category> listBySeUrl(MerchantStore store,String seUrl) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qDescription.seUrl.like(seUrl)
+			.and(qCategory.merchantStore.id.eq(store.getId())))
+			.orderBy(qDescription._super.title.desc(), qDescription._super.name.desc(), qDescription.language.id.desc()).orderBy(qCategory.sortOrder.asc());
+		
+		return query.list(qCategory);
+	}
+	
+	@Override
+	public Category getBySeUrl(MerchantStore store,String seUrl) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qDescription.seUrl.eq(seUrl)
+			.and(qCategory.merchantStore.id.eq(store.getId())));
+
+		
+		return query.uniqueResult(qCategory);
+	}
+	
+	@Override
+	public Category getByCode(MerchantStore store, String code) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.code.eq(code)
+			.and(qCategory.merchantStore.id.eq(store.getId())));
+
+		return query.uniqueResult(qCategory);
+	}
+	
+	@Override
+	public List<Category> getByCodes(MerchantStore store, List<String> codes, Language language) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.code.in(codes)
+			.and(qCategory.merchantStore.id.eq(store.getId()))
+			.and(qDescription.language.id.eq(language.getId())))
+			.orderBy(qCategory.sortOrder.asc(), qCategory.lineage.asc(), qCategory.lineage.asc(), qCategory.depth.asc(), qDescription.language.id.desc());
+		
+		return query.list(qCategory);
+	}
+	
+	@Override
+	public List<Category> getByIds(MerchantStore store, List<Long> ids, Language language) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.id.in(ids)
+			.and(qCategory.merchantStore.id.eq(store.getId()))
+			.and(qDescription.language.id.eq(language.getId())))
+			.orderBy(qCategory.sortOrder.asc(), qCategory.lineage.asc(), qCategory.lineage.asc(), qCategory.depth.asc(), qDescription.language.id.desc());
+		
+		return query.list(qCategory);
+	}
+	
+	@Override
+	public Category getByLanguage(long categoryId, Language language) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.id.eq(categoryId)
+			.and(qDescription.language.code.eq(language.getCode())));
+
+		
+		return query.uniqueResult(qCategory);
+	}
+	
+	@Override
+	public Category getByCode(String merchantStoreCode, String code) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.code.eq(code)
+			.and(qCategory.merchantStore.code.eq(merchantStoreCode)));
+
+		
+		return query.uniqueResult(qCategory);
+	}
+	
+	@Override
+	public Category getById(Long id) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.id.eq(id));
+
+		return query.uniqueResult(qCategory);
+	}
+	
+	@Override
+	public List<Category> listByLineage(MerchantStore store, String lineage) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.lineage.like(new StringBuilder().append(lineage).append("%").toString())
+			.and(qCategory.merchantStore.id.eq(store.getId())))
+			.orderBy(qCategory.sortOrder.asc(), qCategory.lineage.asc(), qCategory.lineage.asc(), qCategory.depth.asc(), qDescription.language.id.desc());
+		
+		return query.listDistinct(qCategory);
+	}
+	
+	@Override
+	public List<Category> listByLineage(String merchantStoreCode, String lineage) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.lineage.like(new StringBuilder().append(lineage).append("%").toString())
+			.and(qCategory.merchantStore.code.eq(merchantStoreCode)))
+			.orderBy(qCategory.sortOrder.asc(),qCategory.lineage.asc(), qCategory.lineage.asc(), qCategory.depth.asc(), qDescription.language.id.desc());
+		
+		return query.listDistinct(qCategory);
+	}
+	
+	@Override
+	public List<Category> listByDepth(MerchantStore store, int depth) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.depth.eq(depth)
+			.and(qCategory.merchantStore.id.eq(store.getId())))
+			.orderBy(qCategory.sortOrder.asc(), qCategory.lineage.asc(), qCategory.lineage.asc(), qCategory.depth.asc(), qDescription.language.id.desc());
+		
+		return query.listDistinct(qCategory);
+	}
+	
+	@Override
+	public List<Category> listByDepth(MerchantStore store, int depth, Language language) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.depth.eq(depth)
+			.and(qCategory.merchantStore.id.eq(store.getId()))
+			.and(qDescription.language.id.eq(language.getId())))
+			.orderBy(qCategory.sortOrder.asc(), qCategory.lineage.asc(), qCategory.lineage.asc(), qCategory.depth.asc(), qDescription.language.id.desc());
+		
+		return query.listDistinct(qCategory);
+	}
+	
+	@Override
+	public List<Category> listByParent(Category category, Language language) {
+		
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.leftJoin(qCategory.parent).fetch()
+			.where(qCategory.parent.id.eq(category.getId())
+			.and(qCategory.merchantStore.id.eq(category.getMerchantStore().getId())))
+			.orderBy(qCategory.lineage.asc(), qCategory.lineage.asc(), qCategory.depth.asc(), qDescription.language.id.desc());
+		
+		return query.listDistinct(qCategory);
+		
+	}
+	
+	
+
+	@Override
+	public List<Category> listByStoreAndParent(MerchantStore store, Category category) {
+		QCategory qCategory = QCategory.category;
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		if (store == null) {
+			if (category == null) {
+				query.from(qCategory)
+					.where(qCategory.parent.isNull())
+					.orderBy(qCategory.sortOrder.asc(),qCategory.id.desc());
+			} else {
+				query.from(qCategory)
+					.where(qCategory.parent.eq(category))
+					.orderBy(qCategory.sortOrder.asc(),qCategory.id.desc());
+			}
+		} else {
+			if (category == null) {
+				query.from(qCategory)
+					.where(qCategory.parent.isNull()
+						.and(qCategory.merchantStore.eq(store)))
+					.orderBy(qCategory.sortOrder.asc(),qCategory.id.desc());
+			} else {
+				query.from(qCategory)
+					.where(qCategory.parent.eq(category)
+						.and(qCategory.merchantStore.eq(store)))
+					.orderBy(qCategory.sortOrder.asc(),qCategory.id.desc());
+			}
+		}
+		
+		return query.list(qCategory);
+	}
+	
+	
+
+
+	@Override
+	public List<Category> listByStore(MerchantStore store) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where(qCategory.merchantStore.id.eq(store.getId()))
+			.orderBy(qCategory.sortOrder.asc(),qCategory.id.asc());
+		
+		return query.listDistinct(qCategory);
+	}
+	
+	@Override
+	public List<Object[]> countProductsByCategories(MerchantStore store, List<Long> categoryIds) {
+
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select categories, count(product.id) from Product product ");
+		qs.append("inner join product.categories categories ");
+		qs.append("where categories.id in (:cid) ");
+		qs.append("and product.available=true and product.dateAvailable<=:dt ");
+		qs.append("group by categories.id");
+		
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("cid", categoryIds);
+    	q.setParameter("dt", new Date());
+
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<Object[]> counts =  q.getResultList();
+
+    	
+    	return counts;
+		
+		
+	}
+	
+	@Override
+	public List<Category> listByStore(MerchantStore store, Language language) {
+		QCategory qCategory = QCategory.category;
+		QCategoryDescription qDescription = QCategoryDescription.categoryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCategory)
+			.leftJoin(qCategory.descriptions, qDescription).fetch()
+			.leftJoin(qCategory.merchantStore).fetch()
+			.where((qCategory.merchantStore.id.eq(store.getId()))
+			.and(qDescription.language.id.eq(language.getId())))
+			.orderBy(qCategory.sortOrder.asc(),qCategory.id.asc());
+		
+		return query.listDistinct(qCategory);
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/model/Category.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/model/Category.java
new file mode 100755
index 0000000..4c4e889
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/model/Category.java
@@ -0,0 +1,213 @@
+package com.salesmanager.core.business.catalog.category.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.UniqueConstraint;
+import javax.validation.Valid;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "CATEGORY", schema= SchemaConstant.SALESMANAGER_SCHEMA,uniqueConstraints=
+    @UniqueConstraint(columnNames = {"MERCHANT_ID", "CODE"}) )
+
+
+public class Category extends SalesManagerEntity<Long, Category> implements Auditable {
+	private static final long serialVersionUID = -846291242449186747L;
+	
+	@Id
+	@Column(name = "CATEGORY_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "CATEGORY_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+
+	@Valid
+	@OneToMany(mappedBy="category", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
+	private List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	@ManyToOne
+	@JoinColumn(name = "PARENT_ID")
+	private Category parent;
+	
+	@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, orphanRemoval = true)
+	private List<Category> categories = new ArrayList<Category>();
+	
+	@Column(name = "CATEGORY_IMAGE", length=100)
+	private String categoryImage;
+
+	@Column(name = "SORT_ORDER")
+	private Integer sortOrder = 0;
+
+	@Column(name = "CATEGORY_STATUS")
+	private boolean categoryStatus;
+
+	@Column(name = "VISIBLE")
+	private boolean visible;
+
+	@Column(name = "DEPTH")
+	private Integer depth;
+
+	@Column(name = "LINEAGE")
+	private String lineage;
+	
+	@NotEmpty
+	@Column(name="CODE", length=100, nullable=false)
+	private String code;
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public Category() {
+	}
+	
+	public Category(MerchantStore store) {
+		this.merchantStore = store;
+		this.id = 0L;
+	}
+	
+	@Override
+	public Long getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+	
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+	
+	@Override
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	public List<CategoryDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(List<CategoryDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	public String getCategoryImage() {
+		return categoryImage;
+	}
+
+	public void setCategoryImage(String categoryImage) {
+		this.categoryImage = categoryImage;
+	}
+
+	public Integer getSortOrder() {
+		return sortOrder;
+	}
+
+	public void setSortOrder(Integer sortOrder) {
+		this.sortOrder = sortOrder;
+	}
+
+	public boolean isCategoryStatus() {
+		return categoryStatus;
+	}
+
+	public void setCategoryStatus(boolean categoryStatus) {
+		this.categoryStatus = categoryStatus;
+	}
+
+	public boolean isVisible() {
+		return visible;
+	}
+
+	public void setVisible(boolean visible) {
+		this.visible = visible;
+	}
+
+	public Integer getDepth() {
+		return depth;
+	}
+
+	public void setDepth(Integer depth) {
+		this.depth = depth;
+	}
+
+	public String getLineage() {
+		return lineage;
+	}
+
+	public void setLineage(String lineage) {
+		this.lineage = lineage;
+	}
+
+	public Category getParent() {
+		return parent;
+	}
+
+	public void setParent(Category parent) {
+		this.parent = parent;
+	}
+	
+
+
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public List<Category> getCategories() {
+		return categories;
+	}
+
+	public void setCategories(List<Category> categories) {
+		this.categories = categories;
+	}
+	
+	public CategoryDescription getDescription() {
+		if(descriptions!=null && descriptions.size()>0) {
+			return descriptions.iterator().next();
+		}
+		
+		return null;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/model/CategoryDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/model/CategoryDescription.java
new file mode 100644
index 0000000..14b67f6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/model/CategoryDescription.java
@@ -0,0 +1,101 @@
+package com.salesmanager.core.business.catalog.category.model;
+
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Entity
+@Table(name="CATEGORY_DESCRIPTION", schema="SALESMANAGER",uniqueConstraints={
+		@UniqueConstraint(columnNames={
+			"CATEGORY_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class CategoryDescription extends Description {
+	private static final long serialVersionUID = -3248423008455359301L;
+	
+
+	@ManyToOne(targetEntity = Category.class)
+	@JoinColumn(name = "CATEGORY_ID", nullable = false)
+	private Category category;
+
+	@Column(name="SEF_URL", length=120)
+	private String seUrl;
+	
+	@Column(name = "CATEGORY_HIGHLIGHT")
+	private String categoryHighlight;
+
+	public String getCategoryHighlight() {
+		return categoryHighlight;
+	}
+
+	public void setCategoryHighlight(String categoryHighlight) {
+		this.categoryHighlight = categoryHighlight;
+	}
+
+	@Column(name="META_TITLE", length=120)
+	private String metatagTitle;
+	
+	@Column(name="META_KEYWORDS")
+	private String metatagKeywords;
+	
+	@Column(name="META_DESCRIPTION")
+	private String metatagDescription;
+	
+	public CategoryDescription() {
+	}
+	
+	public CategoryDescription(String name, Language language) {
+		this.setName(name);
+		this.setLanguage(language);
+		super.setId(0L);
+	}
+	
+	public String getSeUrl() {
+		return seUrl;
+	}
+
+	public void setSeUrl(String seUrl) {
+		this.seUrl = seUrl;
+	}
+
+	public String getMetatagTitle() {
+		return metatagTitle;
+	}
+
+	public void setMetatagTitle(String metatagTitle) {
+		this.metatagTitle = metatagTitle;
+	}
+
+	public String getMetatagKeywords() {
+		return metatagKeywords;
+	}
+
+	public void setMetatagKeywords(String metatagKeywords) {
+		this.metatagKeywords = metatagKeywords;
+	}
+
+	public String getMetatagDescription() {
+		return metatagDescription;
+	}
+
+	public void setMetatagDescription(String metatagDescription) {
+		this.metatagDescription = metatagDescription;
+	}
+
+	public Category getCategory() {
+		return category;
+	}
+
+	public void setCategory(Category category) {
+		this.category = category;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/service/CategoryService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/service/CategoryService.java
new file mode 100644
index 0000000..1238500
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/service/CategoryService.java
@@ -0,0 +1,102 @@
+package com.salesmanager.core.business.catalog.category.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CategoryService extends SalesManagerEntityService<Long, Category> {
+
+	List<Category> listByLineage(MerchantStore store, String lineage) throws ServiceException;
+	
+	List<Category> listBySeUrl(MerchantStore store, String seUrl) throws ServiceException;
+	
+	CategoryDescription getDescription(Category category, Language language) throws ServiceException;
+
+	void addCategoryDescription(Category category, CategoryDescription description) throws ServiceException;
+
+	void addChild(Category parent, Category child) throws ServiceException;
+
+	List<Category> listByParent(Category category) throws ServiceException;
+	
+	List<Category> listByStoreAndParent(MerchantStore store, Category category) throws ServiceException;
+	
+	
+	List<Category> getByName(MerchantStore store, String name, Language language) throws ServiceException;
+	
+	List<Category> listByStore(MerchantStore store) throws ServiceException;
+
+	Category getByCode(MerchantStore store, String code)
+			throws ServiceException;
+
+	List<Category> listByStore(MerchantStore store, Language language)
+			throws ServiceException;
+
+	void saveOrUpdate(Category category) throws ServiceException;
+
+	List<Category> listByDepth(MerchantStore store, int depth);
+
+	/**
+	 * Get root categories by store for a given language
+	 * @param store
+	 * @param depth
+	 * @param language
+	 * @return
+	 */
+	List<Category> listByDepth(MerchantStore store, int depth, Language language);
+
+	List<Category> listByLineage(String storeCode, String lineage)
+			throws ServiceException;
+
+	Category getByCode(String storeCode, String code) throws ServiceException;
+
+	Category getBySeUrl(MerchantStore store, String seUrl);
+
+	List<Category> listByParent(Category category, Language language);
+
+	Category getByLanguage(long categoryId, Language language);
+
+	/**
+	 * Returns a list by category containing the category code and the number of products
+	 * 1->obj[0] = book
+	 *    obj[1] = 150
+	 * 2->obj[0] = novell
+	 *    obj[1] = 35
+	 *   ...
+	 * @param store
+	 * @param categoryIds
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<Object[]> countProductsByCategories(MerchantStore store,
+			List<Long> categoryIds) throws ServiceException;
+
+	/**
+	 * Returns a list of Category by category code for a given language
+	 * @param store
+	 * @param codes
+	 * @param language
+	 * @return
+	 */
+	List<Category> listByCodes(MerchantStore store, List<String> codes,
+			Language language);
+
+	/**
+	 * List of Category by id
+	 * @param store
+	 * @param ids
+	 * @param language
+	 * @return
+	 */
+	List<Category> listByIds(MerchantStore store, List<Long> ids,
+			Language language);
+
+
+	
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/service/CategoryServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/service/CategoryServiceImpl.java
new file mode 100644
index 0000000..a8aea7b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/category/service/CategoryServiceImpl.java
@@ -0,0 +1,437 @@
+package com.salesmanager.core.business.catalog.category.service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import com.salesmanager.core.business.catalog.category.dao.CategoryDao;
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.service.ProductService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.constants.Constants;
+
+@Service("categoryService")
+public class CategoryServiceImpl extends SalesManagerEntityServiceImpl<Long, Category> implements CategoryService {
+	
+	private CategoryDao categoryDao;
+	
+
+	  
+	  @Autowired
+	  private ProductService productService;
+	  
+
+	
+	@Autowired
+	public CategoryServiceImpl(CategoryDao categoryDao) {
+		super(categoryDao);
+		
+		this.categoryDao = categoryDao;
+	}
+	
+	public void create(Category category) throws ServiceException {
+		
+		super.create(category);
+		
+		StringBuilder lineage = new StringBuilder();
+		Category parent = category.getParent();
+		if(parent!=null && parent.getId()!=null && parent.getId()!=0) {
+			lineage.append(parent.getLineage()).append("/").append(parent.getId());
+			category.setDepth(parent.getDepth()+1);
+		} else {
+			lineage.append("/");
+			category.setDepth(0);
+		}
+		category.setLineage(lineage.toString());
+		super.update(category);
+		
+		
+	}
+	
+	@Override
+	public List<Object[]> countProductsByCategories(MerchantStore store,
+			List<Long> categoryIds) throws ServiceException {
+		
+		return categoryDao.countProductsByCategories(store, categoryIds);
+		
+	}
+	
+	@Override
+	public List<Category> listByCodes(MerchantStore store, List<String> codes,
+			Language language) {
+		return categoryDao.getByCodes(store, codes, language);
+	}
+	
+	@Override
+	public List<Category> listByIds(MerchantStore store, List<Long> ids,
+			Language language) {
+		return categoryDao.getByIds(store, ids, language);
+	}
+	
+	@Override
+	public Category getByLanguage(long categoryId, Language language) {
+		return categoryDao.getByLanguage(categoryId, language);
+	}
+	
+	@Override
+	public void saveOrUpdate(Category category) throws ServiceException {
+		
+		
+		//save or update (persist and attach entities
+		if(category.getId()!=null && category.getId()>0) {
+
+			super.update(category);
+			
+		} else {
+			
+			super.save(category);
+			
+		}
+		
+	}
+
+	@Override
+	public List<Category> listByLineage(MerchantStore store, String lineage) throws ServiceException {
+		try {
+			return categoryDao.listByLineage(store, lineage);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+		
+	}
+	
+	@Override
+	public List<Category> listByLineage(String storeCode, String lineage) throws ServiceException {
+		try {
+			return categoryDao.listByLineage(storeCode, lineage);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+		
+	}
+	
+
+	@Override
+	public List<Category> listBySeUrl(MerchantStore store, String seUrl) throws ServiceException{
+		
+		try {
+			return categoryDao.listBySeUrl(store, seUrl);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+	@Override
+	public Category getBySeUrl(MerchantStore store,String seUrl) {
+		return categoryDao.getBySeUrl(store, seUrl);
+	}
+	
+	
+	@Override
+	public Category getByCode(MerchantStore store, String code) throws ServiceException {
+		
+		try {
+			return categoryDao.getByCode(store, code);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+	@Override
+	public Category getByCode(String storeCode, String code) throws ServiceException {
+		
+		try {
+			return categoryDao.getByCode(storeCode, code);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+	
+	@Override
+	public Category getById(Long id) {
+		
+
+			return categoryDao.getById(id);
+
+		
+	}
+	
+	@Override
+	public List<Category> listByParent(Category category) throws ServiceException {
+		
+		try {
+			return categoryDao.listByStoreAndParent(null, category);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+	@Override
+	public List<Category> listByStoreAndParent(MerchantStore store, Category category) throws ServiceException {
+		
+		try {
+			return categoryDao.listByStoreAndParent(store, category);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+	@Override
+	public List<Category> listByParent(Category category, Language language) {
+		Assert.notNull(category, "Category cannot be null");
+		Assert.notNull(language, "Language cannot be null");
+		Assert.notNull(category.getMerchantStore(), "category.merchantStore cannot be null");
+		
+		return categoryDao.listByParent(category, language);
+	}
+
+	
+	@Override
+	public void addCategoryDescription(Category category, CategoryDescription description)
+			throws ServiceException {
+		
+		
+		
+		try {
+			category.getDescriptions().add(description);
+			description.setCategory(category);
+			update(category);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+
+	}
+
+	
+	//@Override
+	public void delete(Category category) throws ServiceException {
+		
+		//get category with lineage (subcategories)
+		StringBuilder lineage = new StringBuilder();
+		lineage.append(category.getLineage()).append(category.getId()).append(Constants.SLASH);
+		List<Category> categories = this.listByLineage(category.getMerchantStore(), lineage.toString());
+		
+		Category dbCategory = this.getById( category.getId() );
+		
+		
+		if(dbCategory != null && dbCategory.getId().longValue() == category.getId().longValue() ) {			
+			
+			
+			categories.add(dbCategory);
+			
+			
+			Collections.reverse(categories);
+			
+			List<Long> categoryIds = new ArrayList<Long>();
+	
+				
+			for(Category c : categories) {		
+					categoryIds.add(c.getId());
+			}
+
+			List<Product> products = productService.getProducts(categoryIds);
+			org.hibernate.Session session = this.categoryDao.getEntityManager().unwrap(org.hibernate.Session.class);//need to refresh the session to update all product categories
+
+			
+			for(Product product : products) {
+				session.evict(product);//refresh product so we get all product categories
+				Product dbProduct = productService.getById(product.getId());
+				Set<Category> productCategories = dbProduct.getCategories();
+				if(productCategories.size()>1) {
+					for(Category c : categories) {
+						productCategories.remove(c);
+						productService.update(dbProduct);
+					}
+					
+					if(product.getCategories()==null || product.getCategories().size()==0) {
+						productService.delete(dbProduct);
+					}
+					
+				} else {
+					productService.delete(dbProduct);
+				}
+				
+				
+			}
+			
+			Category categ = this.getById(category.getId());
+			categoryDao.delete(categ);
+			
+		}
+		
+	}
+
+
+	//@Override
+	//public void addProduct(Category category, Product product) throws ServiceException {
+		//if (!category.getProducts().contains(product)) {
+		//	category.getProducts().add(product);
+		//	update(category);
+		//}
+	//}
+
+	//@Override
+	//public void removeProduct(Category category, Product product)
+			//throws ServiceException {
+		//if (category.getProducts().contains(product)) {
+		//	category.getProducts().remove(product);
+		//	update(category);
+		//}
+	//}
+
+	//@Override
+	//public void addProducts(Category category, List<Product> products)
+	//		throws ServiceException {
+		//if (!category.getProducts().contains(products)) {
+		//	category.getProducts().addAll(products);
+		//	update(category);
+		//}
+	//}
+
+	//@Override
+	//public void removeProducts(Category category, List<Product> products)
+		//	throws ServiceException {
+		//if (category.getProducts().contains(products)) {
+		//	category.getProducts().removeAll(products);
+		//	update(category);
+		//}
+	//}
+
+	@Override
+	public CategoryDescription getDescription(Category category, Language language) {
+		
+		
+		for (CategoryDescription description : category.getDescriptions()) {
+			if (description.getLanguage().equals(language)) {
+				return description;
+			}
+		}
+		return null;
+	}
+	
+	@Override
+	public void addChild(Category parent, Category child) throws ServiceException {
+		
+		
+		if(child==null || child.getMerchantStore()==null) {
+			throw new ServiceException("Child category and merchant store should not be null");
+		}
+		
+		try {
+			
+			if(parent==null) {
+				
+				//assign to root
+				child.setParent(null);
+				child.setDepth(0);
+				//child.setLineage(new StringBuilder().append("/").append(child.getId()).append("/").toString());
+				child.setLineage("/");
+				
+			} else {
+				
+				Category p = this.getById(parent.getId());//parent
+				
+				
+
+				
+				String lineage = p.getLineage();
+				int depth = p.getDepth();//TODO sometimes null
+				
+				child.setParent(p);
+				child.setDepth(depth+1);
+				child.setLineage(new StringBuilder().append(lineage).append(p.getId()).append("/").toString());
+				
+				
+			}
+			
+
+			update(child);
+			StringBuilder childLineage = new StringBuilder();
+			childLineage.append(child.getLineage()).append(child.getId()).append("/");
+			List<Category> subCategories = listByLineage(child.getMerchantStore(),childLineage.toString());
+			
+			
+			//ajust all sub categories lineages
+			if(subCategories!=null && subCategories.size()>0) {
+				for(Category subCategory : subCategories) {
+					if(child.getId()!=subCategory.getId()) {
+						addChild(child, subCategory);
+					}
+				}
+				
+			}
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+
+	}
+	
+	@Override
+	public List<Category> listByDepth(MerchantStore store, int depth) {
+		return categoryDao.listByDepth(store, depth);
+	}
+	
+	@Override
+	public List<Category> listByDepth(MerchantStore store, int depth, Language language) {
+		return categoryDao.listByDepth(store, depth, language);
+	}
+
+	@Override
+	public List<Category> getByName(MerchantStore store, String name, Language language) throws ServiceException {
+		
+		try {
+			return categoryDao.getByName(store, name, language);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+		
+	}
+	
+	
+
+	@Override
+	public List<Category> listByStore(MerchantStore store)
+			throws ServiceException {
+
+		try {
+			return categoryDao.listByStore(store);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	}
+	
+	@Override
+	public List<Category> listByStore(MerchantStore store, Language language)
+			throws ServiceException {
+
+		try {
+			return categoryDao.listByStore(store, language);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	}
+	
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/common/CatalogServiceHelper.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/common/CatalogServiceHelper.java
new file mode 100644
index 0000000..efab325
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/common/CatalogServiceHelper.java
@@ -0,0 +1,100 @@
+package com.salesmanager.core.business.catalog.common;
+
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionDescription;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValueDescription;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.constants.Constants;
+
+
+public class CatalogServiceHelper {
+	
+	/**
+	 * Filters descriptions and set the appropriate language
+	 * @param p
+	 * @param language
+	 */
+	public static void setToLanguage(Product p, int language) {
+		
+		
+	Set<ProductAttribute> attributes = p.getAttributes();
+		if(attributes!=null) {
+			
+			for(ProductAttribute attribute : attributes) {
+
+				ProductOption po = attribute.getProductOption();
+				Set<ProductOptionDescription> spod = po.getDescriptions();
+				if(spod!=null) {
+					Set<ProductOptionDescription> podDescriptions = new HashSet<ProductOptionDescription>();
+					for(ProductOptionDescription pod : spod) {
+						//System.out.println("    ProductOptionDescription : " + pod.getProductOptionName());
+						if(pod.getLanguage().getId()==language) {
+							podDescriptions.add(pod);
+						}
+					}
+					po.setDescriptions(podDescriptions);
+				}
+				
+				ProductOptionValue pov = attribute.getProductOptionValue();
+				
+				
+				Set<ProductOptionValueDescription> spovd = pov.getDescriptions();
+				if(spovd!=null) {
+					Set<ProductOptionValueDescription> povdDescriptions = new HashSet();
+					for(ProductOptionValueDescription povd : spovd) {
+						if(povd.getLanguage().getId()==language) {
+							povdDescriptions.add(povd);
+						}
+					}
+					pov.setDescriptions(povdDescriptions);
+				}
+					
+			}
+		}
+		
+	}
+	
+	/**
+	 * Overwrites the availability in order to return 1 price / region
+	 * @param product
+	 * @param locale
+	 */
+	public static void setToAvailability(Product product, Locale locale) {
+		
+		Set<ProductAvailability> availabilities =  product.getAvailabilities();
+		
+		ProductAvailability defaultAvailability = null;
+		ProductAvailability localeAvailability = null;
+		
+		for(ProductAvailability availability : availabilities) {
+			
+			if(availability.getRegion().equals(Constants.ALL_REGIONS)) {
+				defaultAvailability = availability;
+			} 
+			if(availability.getRegion().equals(locale.getCountry())) {
+				localeAvailability = availability;
+			}
+			
+		}
+		
+		if(defaultAvailability!=null || localeAvailability!=null) {
+			Set<ProductAvailability> productAvailabilities = new HashSet<ProductAvailability>();
+			if(defaultAvailability!=null) {
+				productAvailabilities.add(defaultAvailability);
+			}
+			if(localeAvailability!=null) {
+				productAvailabilities.add(localeAvailability);
+			}
+			product.setAvailabilities(productAvailabilities);
+		}
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductAttributeDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductAttributeDao.java
new file mode 100644
index 0000000..6e4546e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductAttributeDao.java
@@ -0,0 +1,24 @@
+package com.salesmanager.core.business.catalog.product.dao.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductAttributeDao extends SalesManagerEntityDao<Long, ProductAttribute> {
+
+	List<ProductAttribute> getByOptionId(MerchantStore store,
+			Long id);
+
+	List<ProductAttribute> getByOptionValueId(MerchantStore store,
+			Long id);
+
+	List<ProductAttribute> getByProduct(MerchantStore store,
+			Product product, Language language);
+
+	List<ProductAttribute> getByAttributeIds(MerchantStore store, List<Long> ids);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductAttributeDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductAttributeDaoImpl.java
new file mode 100644
index 0000000..d2e7b9e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductAttributeDaoImpl.java
@@ -0,0 +1,122 @@
+package com.salesmanager.core.business.catalog.product.dao.attribute;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.QProduct;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.QProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.QProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.QProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.QProductOptionValueDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("productAttributeDao")
+public class ProductAttributeDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductAttribute> 
+	implements ProductAttributeDao {
+	
+	
+	@Override
+	public ProductAttribute getById(Long id) {
+		QProductAttribute qEntity = QProductAttribute.productAttribute;
+		QProductOption qProductOption = QProductOption.productOption;
+		QProductOptionValue qProductOptionValue = QProductOptionValue.productOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+			.join(qEntity.product).fetch()
+			.leftJoin(qEntity.productOption, qProductOption).fetch()
+			.leftJoin(qEntity.productOptionValue, qProductOptionValue).fetch()
+			.leftJoin(qProductOption.descriptions).fetch()
+			.leftJoin(qProductOptionValue.descriptions).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qEntity.id.eq(id));
+		
+		return query.uniqueResult(qEntity);
+	}
+	
+	@Override
+	public List<ProductAttribute> getByOptionId(MerchantStore store, Long id) {
+		QProductAttribute qEntity = QProductAttribute.productAttribute;
+		QProductOption qProductOption = QProductOption.productOption;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+			.join(qEntity.product).fetch()
+			.leftJoin(qEntity.productOption, qProductOption).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.id.eq(id)
+			.and(qProductOption.merchantStore.id.eq(store.getId())));
+		
+		return query.list(qEntity);
+	}
+	
+	@Override
+	public List<ProductAttribute> getByAttributeIds(MerchantStore store, List<Long> ids) {
+		QProductAttribute qEntity = QProductAttribute.productAttribute;
+		QProductOption qProductOption = QProductOption.productOption;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+			.join(qEntity.product).fetch()
+			.leftJoin(qEntity.productOption, qProductOption).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qEntity.id.in(ids)
+			.and(qProductOption.merchantStore.id.eq(store.getId())));
+		
+		return query.list(qEntity);
+	}
+	
+	@Override
+	public List<ProductAttribute> getByOptionValueId(MerchantStore store, Long id) {
+		QProductAttribute qEntity = QProductAttribute.productAttribute;
+		QProductOptionValue qProductOptionValue = QProductOptionValue.productOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+			.join(qEntity.product).fetch()
+			.leftJoin(qEntity.productOptionValue, qProductOptionValue).fetch()
+			.leftJoin(qProductOptionValue.merchantStore).fetch()
+			.where(qProductOptionValue.id.eq(id)
+			.and(qProductOptionValue.merchantStore.id.eq(store.getId())));
+		
+		return query.list(qEntity);
+	}
+
+	
+	@Override
+	public List<ProductAttribute> getByProduct(MerchantStore store, Product product, Language language) {
+		QProductAttribute qEntity = QProductAttribute.productAttribute;
+		QProductOptionValue qProductOptionValue = QProductOptionValue.productOptionValue;
+		QProductOptionValueDescription qProductOptionValueDescription = QProductOptionValueDescription.productOptionValueDescription;
+		QProduct qProduct = QProduct.product;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+			.leftJoin(qEntity.productOptionValue, qProductOptionValue).fetch()
+			.leftJoin(qProductOptionValue.merchantStore).fetch()
+			.join(qEntity.product,qProduct).fetch()
+			.leftJoin(qProductOptionValue.descriptions,qProductOptionValueDescription).fetch()
+			.where(qProduct.id.eq(product.getId())
+			.and(qProductOptionValue.merchantStore.id.eq(store.getId()))
+			.and(qProductOptionValueDescription.language.id.eq(language.getId())));
+		
+		return query.list(qEntity);
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionDao.java
new file mode 100644
index 0000000..00dbc50
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionDao.java
@@ -0,0 +1,31 @@
+package com.salesmanager.core.business.catalog.product.dao.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductOptionDao extends SalesManagerEntityDao<Long, ProductOption> {
+
+	List<ProductOption> listByStore(MerchantStore store, Language language);
+
+	List<ProductOption> getByName(MerchantStore store, String name,
+			Language language);
+
+	void saveOrUpdate(ProductOption entity) throws ServiceException;
+
+	/**
+	 * Get read only attributes.
+	 * @param store
+	 * @param language
+	 * @return
+	 */
+	List<ProductOption> getReadOnly(MerchantStore store,
+			Language language);
+
+	ProductOption getByCode(MerchantStore store, String optionCode);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionDaoImpl.java
new file mode 100644
index 0000000..da21fd3
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionDaoImpl.java
@@ -0,0 +1,125 @@
+package com.salesmanager.core.business.catalog.product.dao.attribute;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.QProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.QProductOptionDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("productOptionDao")
+public class ProductOptionDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductOption>
+		implements ProductOptionDao {
+	
+	@Override
+	public List<ProductOption> listByStore(MerchantStore store, Language language) {
+		
+		QProductOption qProductOption = QProductOption.productOption;
+		QProductOptionDescription qDescription = QProductOptionDescription.productOptionDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.merchantStore.id.eq(store.getId())
+			.and(qDescription.language.id.eq(language.getId())))
+			.orderBy(qProductOption.id.asc());
+		
+		return query.listDistinct(qProductOption);
+		
+	}
+	
+	@Override
+	public ProductOption getById(Long id) {
+		QProductOption qProductOption = QProductOption.productOption;
+		QProductOptionDescription qDescription = QProductOptionDescription.productOptionDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.id.eq(id));
+		
+		return query.uniqueResult(qProductOption);
+	}
+	
+	@Override
+	public List<ProductOption> getByName(MerchantStore store, String name, Language language) {
+		QProductOption qProductOption = QProductOption.productOption;
+		QProductOptionDescription qDescription = QProductOptionDescription.productOptionDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qDescription.name.like("%" + name + "%")
+			.and(qDescription.language.id.eq(language.getId()))
+			.and(qProductOption.merchantStore.id.eq(store.getId())));
+		
+
+		
+		List<ProductOption> options = query.list(qProductOption);
+		return options;
+	}
+	
+	@Override
+	public List<ProductOption> getReadOnly(MerchantStore store, Language language) {
+		QProductOption qProductOption = QProductOption.productOption;
+		QProductOptionDescription qDescription = QProductOptionDescription.productOptionDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.readOnly.eq(true)
+			.and(qDescription.language.id.eq(language.getId()))
+			.and(qProductOption.merchantStore.id.eq(store.getId())));
+		
+
+		
+		List<ProductOption> options = query.list(qProductOption);
+		return options;
+	}
+	
+	@Override
+	public void saveOrUpdate(ProductOption entity) throws ServiceException {
+		
+		
+		//save or update (persist and attach entities
+		if(entity.getId()!=null && entity.getId()>0) {
+			super.update(entity);
+		} else {
+			super.save(entity);
+		}
+	}
+	
+	@Override
+	public ProductOption getByCode(MerchantStore store, String optionCode) {
+		QProductOption qProductOption = QProductOption.productOption;
+		QProductOptionDescription qDescription = QProductOptionDescription.productOptionDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.merchantStore.id.eq(store.getId())
+			.and(qProductOption.code.eq(optionCode)));
+		
+		return query.uniqueResult(qProductOption);
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionValueDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionValueDao.java
new file mode 100644
index 0000000..43bdfcb
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionValueDao.java
@@ -0,0 +1,24 @@
+package com.salesmanager.core.business.catalog.product.dao.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductOptionValueDao extends SalesManagerEntityDao<Long, ProductOptionValue> {
+
+	List<ProductOptionValue> listByStore(MerchantStore store, Language language);
+
+	ProductOptionValue getById(MerchantStore store, Long id);
+
+	List<ProductOptionValue> getByName(MerchantStore store, String name,
+			Language language);
+
+	List<ProductOptionValue> listByStoreNoReadOnly(MerchantStore store,
+			Language language);
+
+	ProductOptionValue getByCode(MerchantStore store, String optionValueCode);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionValueDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionValueDaoImpl.java
new file mode 100644
index 0000000..3c547b0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/attribute/ProductOptionValueDaoImpl.java
@@ -0,0 +1,120 @@
+package com.salesmanager.core.business.catalog.product.dao.attribute;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.QProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.QProductOptionValueDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("productOptionValueDao")
+public class ProductOptionValueDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductOptionValue>
+		implements ProductOptionValueDao {
+	
+	
+	@Override
+	public List<ProductOptionValue> listByStore(MerchantStore store, Language language) {
+		
+		QProductOptionValue qProductOption = QProductOptionValue.productOptionValue;
+		QProductOptionValueDescription qDescription = QProductOptionValueDescription.productOptionValueDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.merchantStore.id.eq(store.getId())
+			.and(qDescription.language.id.eq(language.getId())));
+			query.orderBy(qProductOption.id.asc());
+			
+			
+		
+		return query.listDistinct(qProductOption);
+		
+	}
+	
+	@Override
+	public List<ProductOptionValue> listByStoreNoReadOnly(MerchantStore store, Language language) {
+		
+		QProductOptionValue qProductOption = QProductOptionValue.productOptionValue;
+		QProductOptionValueDescription qDescription = QProductOptionValueDescription.productOptionValueDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.merchantStore.id.eq(store.getId())
+			.and(qProductOption.productOptionDisplayOnly.eq(false))
+			.and(qDescription.language.id.eq(language.getId())));
+			query.orderBy(qProductOption.id.asc());
+			
+			
+		
+		return query.listDistinct(qProductOption);
+		
+	}
+	
+
+	
+	@Override
+	public ProductOptionValue getById(MerchantStore store, Long id) {
+		QProductOptionValue qProductOption = QProductOptionValue.productOptionValue;
+		QProductOptionValueDescription qDescription = QProductOptionValueDescription.productOptionValueDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.id.eq(id)
+			.and(qProductOption.merchantStore.id.eq(store.getId())));
+		
+		return query.uniqueResult(qProductOption);
+	}
+	
+	@Override
+	public List<ProductOptionValue> getByName(MerchantStore store, String name, Language language) {
+		QProductOptionValue qProductOption = QProductOptionValue.productOptionValue;
+		QProductOptionValueDescription qDescription = QProductOptionValueDescription.productOptionValueDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qDescription.name.like("%" + name + "%")
+			.and(qDescription.language.id.eq(language.getId()))
+			.and(qProductOption.merchantStore.id.eq(store.getId())));
+		
+
+		
+		List<ProductOptionValue> options = query.list(qProductOption);
+		return options;
+	}
+	
+	@Override
+	public ProductOptionValue getByCode(MerchantStore store, String optionValueCode) {
+		QProductOptionValue qProductOption = QProductOptionValue.productOptionValue;
+		QProductOptionValueDescription qDescription = QProductOptionValueDescription.productOptionValueDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductOption)
+			.leftJoin(qProductOption.descriptions, qDescription).fetch()
+			.leftJoin(qProductOption.merchantStore).fetch()
+			.where(qProductOption.code.eq(optionValueCode)
+			.and(qProductOption.merchantStore.id.eq(store.getId())));
+		
+		return query.uniqueResult(qProductOption);
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/availability/ProductAvailabilityDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/availability/ProductAvailabilityDao.java
new file mode 100644
index 0000000..1f8baa4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/availability/ProductAvailabilityDao.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.catalog.product.dao.availability;
+
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+
+public interface ProductAvailabilityDao extends SalesManagerEntityDao<Long, ProductAvailability> {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/availability/ProductAvailabilityDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/availability/ProductAvailabilityDaoImpl.java
new file mode 100644
index 0000000..77c0346
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/availability/ProductAvailabilityDaoImpl.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.business.catalog.product.dao.availability;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+
+@Repository("productAvailabilityDao")
+public class ProductAvailabilityDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductAvailability>
+		implements ProductAvailabilityDao {
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/file/DigitalProductDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/file/DigitalProductDao.java
new file mode 100644
index 0000000..e88ac90
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/file/DigitalProductDao.java
@@ -0,0 +1,13 @@
+package com.salesmanager.core.business.catalog.product.dao.file;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.file.DigitalProduct;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+public interface DigitalProductDao extends SalesManagerEntityDao<Long, DigitalProduct> {
+
+	DigitalProduct getByProduct(MerchantStore store, Product product);
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/file/DigitalProductDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/file/DigitalProductDaoImpl.java
new file mode 100644
index 0000000..51ccee5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/file/DigitalProductDaoImpl.java
@@ -0,0 +1,58 @@
+package com.salesmanager.core.business.catalog.product.dao.file;
+
+import java.util.List;
+
+import javax.persistence.NonUniqueResultException;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.QProduct;
+import com.salesmanager.core.business.catalog.product.model.file.DigitalProduct;
+import com.salesmanager.core.business.catalog.product.model.file.QDigitalProduct;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+@Repository("digitalProductDao")
+public class DigitalProductDaoImpl extends SalesManagerEntityDaoImpl<Long, DigitalProduct> 
+	implements DigitalProductDao {
+	
+	@Override
+	public DigitalProduct getByProduct(MerchantStore store, Product product) {
+		
+		QDigitalProduct qDigitalProduct = QDigitalProduct.digitalProduct;
+		QProduct qProduct = QProduct.product;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qDigitalProduct)
+			.innerJoin(qDigitalProduct.product, qProduct).fetch()
+			.innerJoin(qProduct.merchantStore).fetch()
+			.where(qProduct.merchantStore.id.eq(store.getId())
+					.and(qProduct.id.eq(product.getId())));
+		
+		List<DigitalProduct> results = query.list(qDigitalProduct);
+        if (results.isEmpty()) return null;
+        
+        else if (results.size() == 1) return results.get(0);
+        throw new NonUniqueResultException();
+	}
+	
+	@Override
+	public DigitalProduct getById(Long id) {
+		
+		QDigitalProduct qDigitalProduct = QDigitalProduct.digitalProduct;
+		QProduct qProduct = QProduct.product;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qDigitalProduct)
+			.innerJoin(qDigitalProduct.product, qProduct).fetch()
+			.innerJoin(qProduct.merchantStore).fetch()
+					.where(qDigitalProduct.id.eq(id));
+		
+		return query.uniqueResult(qDigitalProduct);
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/image/ProductImageDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/image/ProductImageDao.java
new file mode 100644
index 0000000..cb921f9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/image/ProductImageDao.java
@@ -0,0 +1,10 @@
+package com.salesmanager.core.business.catalog.product.dao.image;
+
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+
+public interface ProductImageDao extends SalesManagerEntityDao<Long, ProductImage> {
+
+	ProductImage getProductImageById(Long id);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/image/ProductImageDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/image/ProductImageDaoImpl.java
new file mode 100644
index 0000000..1a703d3
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/image/ProductImageDaoImpl.java
@@ -0,0 +1,39 @@
+package com.salesmanager.core.business.catalog.product.dao.image;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.QProduct;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.catalog.product.model.image.QProductImage;
+import com.salesmanager.core.business.catalog.product.model.image.QProductImageDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+
+@Repository("productImageDao")
+public class ProductImageDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductImage> 
+	implements ProductImageDao {
+	
+	@Override
+	public ProductImage getProductImageById(Long id) {
+		
+		
+		QProductImage qProductImage = QProductImage.productImage1;
+		QProductImageDescription qProductImageDescription = QProductImageDescription.productImageDescription;
+		QProduct qProduct = QProduct.product;
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qProductImage)
+			.leftJoin(qProductImage.descriptions, qProductImageDescription).fetch()
+			.innerJoin(qProductImage.product,qProduct).fetch()
+			.innerJoin(qProduct.merchantStore).fetch()
+			.where(qProductImage.id.eq(id));
+		
+		return query.uniqueResult(qProductImage);
+		
+		
+		
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/manufacturer/ManufacturerDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/manufacturer/ManufacturerDao.java
new file mode 100644
index 0000000..c61da63
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/manufacturer/ManufacturerDao.java
@@ -0,0 +1,21 @@
+package com.salesmanager.core.business.catalog.product.dao.manufacturer;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ManufacturerDao extends SalesManagerEntityDao<Long, Manufacturer> {
+
+	List<Manufacturer> listByStore(MerchantStore store, Language language);
+
+	List<Manufacturer> listByStore(MerchantStore store);
+	
+	int getCountManufAttachedProducts(  Manufacturer manufacturer  );
+
+	List<Manufacturer> listByProductsByCategoriesId(MerchantStore store,
+			List<Long> ids, Language language);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/manufacturer/ManufacturerDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/manufacturer/ManufacturerDaoImpl.java
new file mode 100644
index 0000000..9f72490
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/manufacturer/ManufacturerDaoImpl.java
@@ -0,0 +1,117 @@
+package com.salesmanager.core.business.catalog.product.dao.manufacturer;
+
+import java.util.List;
+
+import javax.persistence.Query;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.QManufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.QManufacturerDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("manufacturerDao")
+public class ManufacturerDaoImpl extends SalesManagerEntityDaoImpl<Long, Manufacturer>
+		implements ManufacturerDao {
+	
+	@Override
+	public int getCountManufAttachedProducts(  Manufacturer manufacturer  ){
+		StringBuilder countBuilderSelect = new StringBuilder();
+		countBuilderSelect.append("select count(distinct p) from Product as p");
+		
+		StringBuilder countBuilderWhere = new StringBuilder();
+		countBuilderWhere.append(" where p.manufacturer.id=:mId");
+		
+		Query countQ = super.getEntityManager().createQuery(
+				countBuilderSelect.toString() + countBuilderWhere.toString());
+
+		countQ.setParameter("mId", manufacturer.getId() );
+		
+		Number count = (Number) countQ.getSingleResult ();
+
+		return count.intValue();
+	}
+	
+	@Override
+	public List<Manufacturer> listByStore(MerchantStore store, Language language) {
+		QManufacturer qManufacturer = QManufacturer.manufacturer;
+		QManufacturerDescription qManufacturerDescription = QManufacturerDescription.manufacturerDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qManufacturer)
+			.leftJoin(qManufacturer.descriptions, qManufacturerDescription).fetch()
+			.leftJoin(qManufacturer.merchantStore).fetch()
+			.where(qManufacturerDescription.language.id.eq(language.getId())
+			.and(qManufacturer.merchantStore.id.eq(store.getId())));
+		
+
+		
+		List<Manufacturer> manufacturers = query.list(qManufacturer);
+		return manufacturers;
+	}
+
+	public Manufacturer getById(Long id) {
+		QManufacturer qManufacturer = QManufacturer.manufacturer;
+		QManufacturerDescription qManufacturerDescription = QManufacturerDescription.manufacturerDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qManufacturer)
+			.leftJoin(qManufacturer.descriptions, qManufacturerDescription).fetch()
+			.leftJoin(qManufacturer.merchantStore).fetch()
+			.where(qManufacturer.id.eq(id));
+		
+
+		
+		return query.uniqueResult(qManufacturer);
+	}
+	
+	@Override
+	public List<Manufacturer> listByStore(MerchantStore store) {
+		QManufacturer qManufacturer = QManufacturer.manufacturer;
+		QManufacturerDescription qManufacturerDescription = QManufacturerDescription.manufacturerDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qManufacturer)
+			.leftJoin(qManufacturer.descriptions, qManufacturerDescription).fetch()
+			.leftJoin(qManufacturer.merchantStore).fetch()
+			.where(qManufacturer.merchantStore.id.eq(store.getId()));
+		
+
+		
+		List<Manufacturer> manufacturers = query.list(qManufacturer);
+		return manufacturers;
+	}
+	
+	
+	@SuppressWarnings("unchecked")
+	@Override
+	public List<Manufacturer> listByProductsByCategoriesId(MerchantStore store, List<Long> ids, Language language) {
+		StringBuilder builderSelect = new StringBuilder();
+		builderSelect.append("select distinct manufacturer from Product as p ");
+		builderSelect.append("join p.manufacturer manufacturer ");
+		builderSelect.append("join manufacturer.descriptions md ");
+		builderSelect.append("join p.categories categs ");
+		builderSelect.append("where categs.id in (:cid) ");
+		builderSelect.append("and md.language.id=:lang");
+
+		Query query = super.getEntityManager().createQuery(
+				builderSelect.toString());
+
+		query.setParameter("cid", ids);
+		query.setParameter("lang", language.getId());
+		
+		return query.getResultList();
+		
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/price/ProductPriceDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/price/ProductPriceDao.java
new file mode 100644
index 0000000..686277f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/price/ProductPriceDao.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.catalog.product.dao.price;
+
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+
+public interface ProductPriceDao extends SalesManagerEntityDao<Long, ProductPrice> {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/price/ProductPriceDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/price/ProductPriceDaoImpl.java
new file mode 100644
index 0000000..71d12dd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/price/ProductPriceDaoImpl.java
@@ -0,0 +1,37 @@
+package com.salesmanager.core.business.catalog.product.dao.price;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.QProduct;
+import com.salesmanager.core.business.catalog.product.model.availability.QProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.QProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.QProductPriceDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+
+@Repository("productPriceDao")
+public class ProductPriceDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductPrice> 
+	implements ProductPriceDao {
+	
+	@Override
+	public ProductPrice getById(Long id) {
+		QProductPrice qEntity = QProductPrice.productPrice;
+		QProductAvailability qAvailability = QProductAvailability.productAvailability;
+		QProductPriceDescription qEntityDescription = QProductPriceDescription.productPriceDescription;
+		QProduct qProduct = QProduct.product;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+			.innerJoin(qEntity.productAvailability,qAvailability).fetch()
+			.innerJoin(qAvailability.product,qProduct).fetch()
+			.leftJoin(qEntity.descriptions, qEntityDescription).fetch()
+			.innerJoin(qProduct.merchantStore).fetch()
+			.where(qEntity.id.eq(id));
+		
+		return query.uniqueResult(qEntity);
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/ProductDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/ProductDao.java
new file mode 100644
index 0000000..1d5ead0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/ProductDao.java
@@ -0,0 +1,47 @@
+package com.salesmanager.core.business.catalog.product.dao;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.ProductCriteria;
+import com.salesmanager.core.business.catalog.product.model.ProductList;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+
+public interface ProductDao extends SalesManagerEntityDao<Long, Product> {
+	
+	Product getProductForLocale(long productId, Language language, Locale locale);
+
+	@SuppressWarnings("rawtypes")
+	List<Product> getProductsForLocale(MerchantStore store, Set categoryIds, Language language,
+			Locale locale);
+
+	@SuppressWarnings("rawtypes")
+	List<Product> getProductsListByCategories(Set categoryIds);
+
+
+	/**
+	 * Method to be used for getting a list of products in a given language based on one to many criteria
+	 * @param store
+	 * @param language
+	 * @param criteria
+	 * @return
+	 */
+	ProductList listByStore(MerchantStore store, Language language, ProductCriteria criteria);
+
+	List<Product> listByStore(MerchantStore store);
+
+	List<Product> listByTaxClass(TaxClass taxClass);
+
+	List<Product> getProductsListByCategories(Set<Long> categoryIds,
+			Language language);
+
+	Product getBySeUrl(MerchantStore store, String seUrl, Locale locale);
+
+	Product getByCode(String productCode, Language language);
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/ProductDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/ProductDaoImpl.java
new file mode 100644
index 0000000..8ab2d84
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/ProductDaoImpl.java
@@ -0,0 +1,986 @@
+package com.salesmanager.core.business.catalog.product.dao;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.persistence.Query;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.ProductCriteria;
+import com.salesmanager.core.business.catalog.product.model.ProductList;
+import com.salesmanager.core.business.catalog.product.model.attribute.AttributeCriteria;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.constants.Constants;
+
+@Repository("productDao")
+public class ProductDaoImpl extends SalesManagerEntityDaoImpl<Long, Product> implements ProductDao {
+
+	public ProductDaoImpl() {
+		super();
+	}
+	
+	@Override
+	public Product getBySeUrl(MerchantStore store,String seUrl, Locale locale) {
+		
+		
+		List regionList = new ArrayList();
+		regionList.add("*");
+		regionList.add(locale.getCountry());
+		
+
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct p from Product as p ");
+		qs.append("join fetch p.availabilities pa ");
+		qs.append("join fetch p.descriptions pd ");
+		qs.append("join fetch p.merchantStore pm ");
+		qs.append("left join fetch pa.prices pap ");
+		qs.append("left join fetch pap.descriptions papd ");
+		
+		
+		//images
+		qs.append("left join fetch p.images images ");
+		//options
+		qs.append("left join fetch p.attributes pattr ");
+		qs.append("left join fetch pattr.productOption po ");
+		qs.append("left join fetch po.descriptions pod ");
+		qs.append("left join fetch pattr.productOptionValue pov ");
+		qs.append("left join fetch pov.descriptions povd ");
+		qs.append("left join fetch p.relationships pr ");
+		//other lefts
+		qs.append("left join fetch p.manufacturer manuf ");
+		qs.append("left join fetch manuf.descriptions manufd ");
+		qs.append("left join fetch p.type type ");
+		qs.append("left join fetch p.taxClass tx ");
+		
+		qs.append("where pa.region in (:lid) ");
+		qs.append("and pd.seUrl=:seUrl ");
+		qs.append("and p.available=true and p.dateAvailable<=:dt ");
+		qs.append("order by pattr.productOptionSortOrder ");
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+
+    	q.setParameter("lid", regionList);
+    	q.setParameter("dt", new Date());
+    	q.setParameter("seUrl", seUrl);
+
+    	Product p = null;
+    	
+    	try {
+    		p = (Product)q.getSingleResult();
+    	} catch(javax.persistence.NoResultException ignore) {
+
+    	}
+    			
+    			
+
+
+		return p;
+		
+	}
+	
+	@SuppressWarnings("rawtypes")
+	@Override
+	public List<Product> getProductsForLocale(MerchantStore store, Set categoryIds, Language language, Locale locale) {
+		
+		ProductList products = this.getProductsListForLocale(store, categoryIds, language, locale, 0, -1);
+		
+		return products.getProducts();
+	}
+	
+	@SuppressWarnings("rawtypes")
+	@Override
+	public List<Product> getProductsListByCategories(Set categoryIds) {
+		
+
+		//List regionList = new ArrayList();
+		//regionList.add("*");
+		//regionList.add(locale.getCountry());
+		
+
+		//TODO Test performance 
+		/**
+		 * Testing in debug mode takes a long time with this query
+		 * running in normal mode is fine
+		 */
+
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct p from Product as p ");
+		qs.append("join fetch p.merchantStore merch ");
+		qs.append("join fetch p.availabilities pa ");
+		qs.append("left join fetch pa.prices pap ");
+		
+		qs.append("join fetch p.descriptions pd ");
+		qs.append("join fetch p.categories categs ");
+		
+		
+		
+		qs.append("left join fetch pap.descriptions papd ");
+		
+		
+		//images
+		qs.append("left join fetch p.images images ");
+		
+		//options (do not need attributes for listings)
+		qs.append("left join fetch p.attributes pattr ");
+		qs.append("left join fetch pattr.productOption po ");
+		qs.append("left join fetch po.descriptions pod ");
+		qs.append("left join fetch pattr.productOptionValue pov ");
+		qs.append("left join fetch pov.descriptions povd ");
+		
+		//other lefts
+		qs.append("left join fetch p.manufacturer manuf ");
+		qs.append("left join fetch p.type type ");
+		qs.append("left join fetch p.taxClass tx ");
+		
+		//qs.append("where pa.region in (:lid) ");
+		qs.append("where categs.id in (:cid)");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("cid", categoryIds);
+
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<Product> products =  q.getResultList();
+
+    	
+    	return products;
+
+
+	}
+	
+	@Override
+	public List<Product> getProductsListByCategories(Set<Long> categoryIds, Language language) {
+		
+
+		//List regionList = new ArrayList();
+		//regionList.add("*");
+		//regionList.add(locale.getCountry());
+		
+
+		//TODO Test performance 
+		/**
+		 * Testing in debug mode takes a long time with this query
+		 * running in normal mode is fine
+		 */
+
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct p from Product as p ");
+		qs.append("join fetch p.merchantStore merch ");
+		qs.append("join fetch p.availabilities pa ");
+		qs.append("left join fetch pa.prices pap ");
+		
+		qs.append("join fetch p.descriptions pd ");
+		qs.append("join fetch p.categories categs ");
+		
+		
+		
+		qs.append("left join fetch pap.descriptions papd ");
+		
+		
+		//images
+		qs.append("left join fetch p.images images ");
+		
+		//options (do not need attributes for listings)
+		qs.append("left join fetch p.attributes pattr ");
+		qs.append("left join fetch pattr.productOption po ");
+		qs.append("left join fetch po.descriptions pod ");
+		qs.append("left join fetch pattr.productOptionValue pov ");
+		qs.append("left join fetch pov.descriptions povd ");
+		
+		//other lefts
+		qs.append("left join fetch p.manufacturer manuf ");
+		qs.append("left join fetch manuf.descriptions manufd ");
+		qs.append("left join fetch p.type type ");
+		qs.append("left join fetch p.taxClass tx ");
+		
+		//qs.append("where pa.region in (:lid) ");
+		qs.append("where categs.id in (:cid) ");
+		//qs.append("and pd.language.id=:lang and papd.language.id=:lang and manufd.language.id=:lang ");
+		qs.append("and pd.language.id=:lang and papd.language.id=:lang ");
+		qs.append("and p.available=true and p.dateAvailable<=:dt ");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("cid", categoryIds);
+    	q.setParameter("lang", language.getId());
+    	q.setParameter("dt", new Date());
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<Product> products =  q.getResultList();
+
+    	
+    	return products;
+
+
+	}
+	
+	
+/*	@Override
+	public ProductList getProductListByCategories(ProductCriteria criteria, Set<Long> categoryIds, Language language) {
+		
+
+		//List regionList = new ArrayList();
+		//regionList.add("*");
+		//regionList.add(locale.getCountry());
+		
+
+		//TODO Test performance 
+		*//**
+		 * Testing in debug mode takes a long time with this query
+		 * running in normal mode is fine
+		 *//*
+
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select p from Product as p ");
+		qs.append("join fetch p.merchantStore merch ");
+		qs.append("join fetch p.availabilities pa ");
+		qs.append("left join fetch pa.prices pap ");
+		
+		qs.append("join fetch p.descriptions pd ");
+		qs.append("join fetch p.categories categs ");
+		
+		
+		
+		qs.append("left join fetch pap.descriptions papd ");
+		
+		
+		//images
+		qs.append("left join fetch p.images images ");
+		
+		//options (do not need attributes for listings)
+		qs.append("left join fetch p.attributes pattr ");
+		qs.append("left join fetch pattr.productOption po ");
+		qs.append("left join fetch po.descriptions pod ");
+		qs.append("left join fetch pattr.productOptionValue pov ");
+		qs.append("left join fetch pov.descriptions povd ");
+		
+		//other lefts
+		qs.append("left join fetch p.manufacturer manuf ");
+		qs.append("left join fetch manuf.descriptions manufd ");
+		qs.append("left join fetch p.type type ");
+		qs.append("left join fetch p.taxClass tx ");
+		
+		//qs.append("where pa.region in (:lid) ");
+		qs.append("where categs.id in (:cid) ");
+		qs.append("and pd.language.id=:lang and papd.language.id=:lang ");
+		qs.append("and p.available=true and p.dateAvailable<=:dt ");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("cid", categoryIds);
+    	q.setParameter("lang", language.getId());
+    	q.setParameter("dt", new Date());
+
+    	q.setFirstResult(criteria.getStartIndex());
+    	q.setMaxResults(criteria.getMaxCount());
+    	
+    	@SuppressWarnings("unchecked")
+		List<Product> products =  q.getResultList();
+
+    	ProductList productList = new ProductList();
+    	productList.setProducts(products);
+    	
+    	
+    	return productList;
+
+
+	}*/
+	
+
+	@Override
+	public List<Product> listByTaxClass(TaxClass taxClass) {
+
+		
+		/**
+		 * Testing in debug mode takes a long time with this query
+		 * running in normal mode is fine
+		 */
+
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select p from Product as p ");
+		qs.append("join fetch p.merchantStore merch ");
+		qs.append("join fetch p.availabilities pa ");
+		qs.append("left join fetch pa.prices pap ");
+		
+		qs.append("join fetch p.descriptions pd ");
+		qs.append("join fetch p.categories categs ");
+		
+		
+		
+		qs.append("left join fetch pap.descriptions papd ");
+		
+		
+		//images
+		qs.append("left join fetch p.images images ");
+		
+		//options (do not need attributes for listings)
+		qs.append("left join fetch p.attributes pattr ");
+		qs.append("left join fetch pattr.productOption po ");
+		qs.append("left join fetch po.descriptions pod ");
+		qs.append("left join fetch pattr.productOptionValue pov ");
+		qs.append("left join fetch pov.descriptions povd ");
+		
+		//other lefts
+		qs.append("left join fetch p.manufacturer manuf ");
+		qs.append("left join fetch manuf.descriptions manufd ");
+		qs.append("left join fetch p.type type ");
+		qs.append("left join fetch p.taxClass tx ");
+		
+		//qs.append("where pa.region in (:lid) ");
+		qs.append("where tx.id=:tid");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("tid", taxClass.getId());
+
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<Product> products =  q.getResultList();
+
+    	
+    	return products;
+		
+		
+	}
+
+	
+	
+	
+	@Override
+	public List<Product> listByStore(MerchantStore store) {
+
+		
+		/**
+		 * Testing in debug mode takes a long time with this query
+		 * running in normal mode is fine
+		 */
+
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select p from Product as p ");
+		qs.append("join fetch p.merchantStore merch ");
+		qs.append("join fetch p.availabilities pa ");
+		qs.append("left join fetch pa.prices pap ");
+		
+		qs.append("join fetch p.descriptions pd ");
+		qs.append("join fetch p.categories categs ");
+		
+		
+		
+		qs.append("left join fetch pap.descriptions papd ");
+		
+		
+		//images
+		qs.append("left join fetch p.images images ");
+		
+		//options (do not need attributes for listings)
+		qs.append("left join fetch p.attributes pattr ");
+		qs.append("left join fetch pattr.productOption po ");
+		qs.append("left join fetch po.descriptions pod ");
+		qs.append("left join fetch pattr.productOptionValue pov ");
+		qs.append("left join fetch pov.descriptions povd ");
+		
+		//other lefts
+		qs.append("left join fetch p.manufacturer manuf ");
+		qs.append("left join fetch manuf.descriptions manufd ");
+		qs.append("left join fetch p.type type ");
+		qs.append("left join fetch p.taxClass tx ");
+		
+		//qs.append("where pa.region in (:lid) ");
+		qs.append("where merch.id=:mid");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("mid", store.getId());
+
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<Product> products =  q.getResultList();
+
+    	
+    	return products;
+		
+		
+	}
+	
+	
+	/**
+	 * Used for all purpose !
+	 * @param store
+	 * @param first
+	 * @param max
+	 * @return
+	 */
+	@Override
+	public ProductList listByStore(MerchantStore store, Language language, ProductCriteria criteria) {
+
+		ProductList productList = new ProductList();
+
+        
+		StringBuilder countBuilderSelect = new StringBuilder();
+		countBuilderSelect.append("select count(distinct p) from Product as p");
+		
+		StringBuilder countBuilderWhere = new StringBuilder();
+		countBuilderWhere.append(" where p.merchantStore.id=:mId");
+		
+		if(!CollectionUtils.isEmpty(criteria.getProductIds())) {
+			countBuilderWhere.append(" and p.id in (:pId)");
+		}
+
+		if(!StringUtils.isBlank(criteria.getProductName())) {
+			countBuilderSelect.append(" INNER JOIN p.descriptions pd");
+			countBuilderWhere.append(" and pd.language.id=:lang and lower(pd.name) like:nm");
+		}
+		
+		
+		if(!CollectionUtils.isEmpty(criteria.getCategoryIds())) {
+			countBuilderSelect.append(" INNER JOIN p.categories categs");
+			countBuilderWhere.append(" and categs.id in (:cid)");
+		}
+		
+		if(criteria.getManufacturerId()!=null) {
+			countBuilderSelect.append(" INNER JOIN p.manufacturer manuf");
+			countBuilderWhere.append(" and manuf.id = :manufid");
+		}
+		
+		if(!StringUtils.isBlank(criteria.getCode())) {
+			
+			countBuilderWhere.append(" and lower(p.sku) like :sku");
+		}
+		
+		if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) {
+		
+			countBuilderSelect.append(" INNER JOIN p.attributes pattr");
+			countBuilderSelect.append(" INNER JOIN pattr.productOption po");
+			countBuilderSelect.append(" INNER JOIN pattr.productOptionValue pov ");
+			countBuilderSelect.append(" INNER JOIN pov.descriptions povd ");
+			int count = 0;
+			for(AttributeCriteria attributeCriteria : criteria.getAttributeCriteria()) {
+				if(count==0) {
+					countBuilderWhere.append(" and po.code =:").append(attributeCriteria.getAttributeCode());
+					countBuilderWhere.append(" and povd.description like :").append("val").append(count).append(attributeCriteria.getAttributeCode());
+				} 
+				count++;
+			}
+			countBuilderWhere.append(" and povd.language.id=:lang");
+
+		}
+		
+		
+		if(criteria.getAvailable()!=null) {
+			if(criteria.getAvailable().booleanValue()) {
+				countBuilderWhere.append(" and p.available=true and p.dateAvailable<=:dt");
+			} else {
+				countBuilderWhere.append(" and p.available=false or p.dateAvailable>:dt");
+			}
+		}
+
+		Query countQ = super.getEntityManager().createQuery(
+				countBuilderSelect.toString() + countBuilderWhere.toString());
+
+		countQ.setParameter("mId", store.getId());
+		
+		
+		if(!CollectionUtils.isEmpty(criteria.getCategoryIds())) {
+			countQ.setParameter("cid", criteria.getCategoryIds());
+		}
+		
+
+		if(criteria.getAvailable()!=null) {
+			countQ.setParameter("dt", new Date());
+		}
+		
+		if(!StringUtils.isBlank(criteria.getCode())) {
+			countQ.setParameter("sku", new StringBuilder().append("%").append(criteria.getCode().toLowerCase()).append("%").toString());
+		}
+		
+		if(criteria.getManufacturerId()!=null) {
+			countQ.setParameter("manufid", criteria.getManufacturerId());
+		}
+		
+		if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) {
+			int count = 0;
+			for(AttributeCriteria attributeCriteria : criteria.getAttributeCriteria()) {
+				countQ.setParameter(attributeCriteria.getAttributeCode(),attributeCriteria.getAttributeCode());
+				countQ.setParameter("val" + count + attributeCriteria.getAttributeCode(),"%" + attributeCriteria.getAttributeValue() + "%");
+				count ++;
+			}
+			countQ.setParameter("lang", language.getId());
+		}
+		
+		if(!StringUtils.isBlank(criteria.getProductName())) {
+			countQ.setParameter("nm", new StringBuilder().append("%").append(criteria.getProductName().toLowerCase()).append("%").toString());
+			countQ.setParameter("lang", language.getId());
+		}
+		
+		if(!CollectionUtils.isEmpty(criteria.getProductIds())) {
+			countQ.setParameter("pId", criteria.getProductIds());
+		}
+
+		Number count = (Number) countQ.getSingleResult ();
+
+		productList.setTotalCount(count.intValue());
+		
+        if(count.intValue()==0)
+        	return productList;
+
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct p from Product as p ");
+		qs.append("join fetch p.merchantStore merch ");
+		qs.append("join fetch p.availabilities pa ");
+		qs.append("left join fetch pa.prices pap ");
+		
+		qs.append("join fetch p.descriptions pd ");
+		qs.append("left join fetch p.categories categs ");
+		
+
+		//images
+		qs.append("left join fetch p.images images ");
+		
+
+		//other lefts
+		qs.append("left join fetch p.manufacturer manuf ");
+		qs.append("left join fetch manuf.descriptions manufd ");
+		qs.append("left join fetch p.type type ");
+		qs.append("left join fetch p.taxClass tx ");
+		
+		
+		//attributes
+		if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) {
+			qs.append(" inner join p.attributes pattr");
+			qs.append(" inner join pattr.productOption po");
+			qs.append(" inner join po.descriptions pod");
+			qs.append(" inner join pattr.productOptionValue pov ");
+			qs.append(" inner join pov.descriptions povd");
+		} else {
+			qs.append(" left join fetch p.attributes pattr");
+			qs.append(" left join fetch pattr.productOption po");
+			qs.append(" left join fetch po.descriptions pod");
+			qs.append(" left join fetch pattr.productOptionValue pov");
+			qs.append(" left join fetch pov.descriptions povd");
+		}
+		
+		qs.append(" left join fetch p.relationships pr");
+		
+
+		qs.append(" where merch.id=:mId");
+		qs.append(" and pd.language.id=:lang");
+		
+		if(!CollectionUtils.isEmpty(criteria.getProductIds())) {
+			qs.append(" and p.id in (:pId)");
+		}
+		
+		if(!CollectionUtils.isEmpty(criteria.getCategoryIds())) {
+			qs.append(" and categs.id in (:cid)");
+		}
+		
+		if(criteria.getManufacturerId()!=null) {
+			qs.append(" and manuf.id = :manufid");
+		}
+		
+
+		if(criteria.getAvailable()!=null) {
+			if(criteria.getAvailable().booleanValue()) {
+				qs.append(" and p.available=true and p.dateAvailable<=:dt");
+			} else {
+				qs.append(" and p.available=false and p.dateAvailable>:dt");
+			}
+		}
+		
+		if(!StringUtils.isBlank(criteria.getProductName())) {
+			qs.append(" and lower(pd.name) like :nm");
+		}
+		
+		if(!StringUtils.isBlank(criteria.getCode())) {
+			qs.append(" and lower(p.sku) like :sku");
+		}
+		
+		if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) {
+			int cnt = 0;
+			for(AttributeCriteria attributeCriteria : criteria.getAttributeCriteria()) {
+				qs.append(" and po.code =:").append(attributeCriteria.getAttributeCode());
+				qs.append(" and povd.description like :").append("val").append(cnt).append(attributeCriteria.getAttributeCode());
+				cnt++;
+			}
+			qs.append(" and povd.language.id=:lang");
+
+		}
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+
+    	q.setParameter("lang", language.getId());
+    	q.setParameter("mId", store.getId());
+    	
+    	if(!CollectionUtils.isEmpty(criteria.getCategoryIds())) {
+    		q.setParameter("cid", criteria.getCategoryIds());
+    	}
+    	
+		if(!CollectionUtils.isEmpty(criteria.getProductIds())) {
+			q.setParameter("pId", criteria.getProductIds());
+		}
+		
+		if(criteria.getAvailable()!=null) {
+			q.setParameter("dt", new Date());
+		}
+		
+		if(criteria.getManufacturerId()!=null) {
+			q.setParameter("manufid", criteria.getManufacturerId());
+		}
+		
+		if(!StringUtils.isBlank(criteria.getCode())) {
+			q.setParameter("sku", new StringBuilder().append("%").append(criteria.getCode().toLowerCase()).append("%").toString());
+		}
+		
+		if(!CollectionUtils.isEmpty(criteria.getAttributeCriteria())) {
+			int cnt = 0;
+			for(AttributeCriteria attributeCriteria : criteria.getAttributeCriteria()) {
+				q.setParameter(attributeCriteria.getAttributeCode(),attributeCriteria.getAttributeCode());
+				q.setParameter("val" + cnt  + attributeCriteria.getAttributeCode(),"%" + attributeCriteria.getAttributeValue() + "%");
+				cnt++;
+			}
+		}
+		
+		if(!StringUtils.isBlank(criteria.getProductName())) {
+			q.setParameter("nm", new StringBuilder().append("%").append(criteria.getProductName().toLowerCase()).append("%").toString());
+		}
+    	
+    	if(criteria.getMaxCount()>0) {
+    		
+    		
+	    	q.setFirstResult(criteria.getStartIndex());
+	    	if(criteria.getMaxCount()<count.intValue()) {
+	    		q.setMaxResults(criteria.getMaxCount());
+	    	}
+	    	else {
+	    		q.setMaxResults(count.intValue());
+	    	}
+    	}
+    	
+    	@SuppressWarnings("unchecked")
+		List<Product> products =  q.getResultList();
+    	productList.setProducts(products);
+    	
+    	return productList;
+
+		
+		
+		
+	}
+	
+	
+	
+	/**
+	 * This query is used for category listings. All collections are not fully loaded, only the required objects
+	 * so the listing page can display everything related to all products
+	 */
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	private ProductList getProductsListForLocale(MerchantStore store, Set categoryIds, Language language, Locale locale, int first, int max) {
+		
+
+				List regionList = new ArrayList();
+				regionList.add(Constants.ALL_REGIONS);
+				if(locale!=null) {
+					regionList.add(locale.getCountry());
+				}
+				
+				ProductList productList = new ProductList();
+
+		        
+				Query countQ = super.getEntityManager().createQuery(
+							"select count(p) from Product as p INNER JOIN p.availabilities pa INNER JOIN p.categories categs where p.merchantStore.id=:mId and categs.id in (:cid) and pa.region in (:lid) and p.available=1 and p.dateAvailable<=:dt");
+							//"select p from Product as p join fetch p.availabilities pa join fetch p.categories categs where categs.id in (:cid) and pa.region in (:lid) and p.available=1 and p.dateAvailable<=:dt");
+				
+				countQ.setParameter("cid", categoryIds);
+				countQ.setParameter("lid", regionList);
+				countQ.setParameter("dt", new Date());
+				countQ.setParameter("mId", store.getId());
+				
+				//List<Product> ps =  countQ.getResultList();
+
+				Number count = (Number) countQ.getSingleResult ();
+
+				
+				productList.setTotalCount(count.intValue());
+				
+				if(count.intValue()==0)
+		        	return productList;
+		        
+		        
+
+				
+				StringBuilder qs = new StringBuilder();
+				qs.append("select p from Product as p ");
+				qs.append("join fetch p.merchantStore merch ");
+				qs.append("join fetch p.availabilities pa ");
+				qs.append("left join fetch pa.prices pap ");
+				
+				qs.append("join fetch p.descriptions pd ");
+				qs.append("join fetch p.categories categs ");
+			
+				
+				
+				//not necessary
+				//qs.append("join fetch pap.descriptions papd ");
+				
+				
+				//images
+				qs.append("left join fetch p.images images ");
+				
+				//options (do not need attributes for listings)
+				//qs.append("left join fetch p.attributes pattr ");
+				//qs.append("left join fetch pattr.productOption po ");
+				//qs.append("left join fetch po.descriptions pod ");
+				//qs.append("left join fetch pattr.productOptionValue pov ");
+				//qs.append("left join fetch pov.descriptions povd ");
+				
+				//other lefts
+				qs.append("left join fetch p.manufacturer manuf ");
+				qs.append("left join fetch manuf.descriptions manufd ");
+				qs.append("left join fetch p.type type ");
+				qs.append("left join fetch p.taxClass tx ");
+				
+				//qs.append("where pa.region in (:lid) ");
+				qs.append("where p.merchantStore.id=mId and categs.id in (:cid) and pa.region in (:lid) ");
+				//qs.append("and p.available=true and p.dateAvailable<=:dt and pd.language.id=:lang and manufd.language.id=:lang");
+				qs.append("and p.available=true and p.dateAvailable<=:dt and pd.language.id=:lang ");
+
+
+		    	String hql = qs.toString();
+				Query q = super.getEntityManager().createQuery(hql);
+
+		    	q.setParameter("cid", categoryIds);
+		    	q.setParameter("lid", regionList);
+		    	q.setParameter("dt", new Date());
+		    	q.setParameter("lang", language.getId());
+		    	q.setParameter("mId", store.getId());
+		    	
+		    	
+		    	q.setFirstResult(first);
+		    	if(max>0) {
+		    			int maxCount = first + max;
+
+		    			if(maxCount < count.intValue()) {
+		    				q.setMaxResults(maxCount);
+		    			} else {
+		    				q.setMaxResults(count.intValue());
+		    			}
+		    	}
+		    	
+		    	List<Product> products =  q.getResultList();
+		    	productList.setProducts(products);
+		    	
+		    	return productList;
+
+		
+	}
+	
+	@Override
+	public Product getProductForLocale(long productId, Language language, Locale locale) {
+
+
+				
+				List regionList = new ArrayList();
+				regionList.add("*");
+				regionList.add(locale.getCountry());
+				
+
+				StringBuilder qs = new StringBuilder();
+				qs.append("select distinct p from Product as p ");
+				qs.append("join fetch p.availabilities pa ");
+				qs.append("join fetch p.descriptions pd ");
+				qs.append("join fetch p.merchantStore pm ");
+				qs.append("left join fetch pa.prices pap ");
+				qs.append("left join fetch pap.descriptions papd ");
+				
+				
+				
+				
+				//images
+				qs.append("left join fetch p.images images ");
+				//options
+				qs.append("left join fetch p.attributes pattr ");
+				qs.append("left join fetch pattr.productOption po ");
+				qs.append("left join fetch po.descriptions pod ");
+				qs.append("left join fetch pattr.productOptionValue pov ");
+				qs.append("left join fetch pov.descriptions povd ");
+				qs.append("left join fetch p.relationships pr ");
+				//other lefts
+				qs.append("left join fetch p.manufacturer manuf ");
+				qs.append("left join fetch manuf.descriptions manufd ");
+				qs.append("left join fetch p.type type ");
+				qs.append("left join fetch p.taxClass tx ");
+				
+				qs.append("where p.id=:pid and pa.region in (:lid) ");
+				qs.append("and pd.language.id=:lang and papd.language.id=:lang ");
+				qs.append("and p.available=true and p.dateAvailable<=:dt ");
+				//this cannot be done on child elements from left join
+				//qs.append("and pod.languageId=:lang and povd.languageId=:lang");
+
+		    	String hql = qs.toString();
+				Query q = super.getEntityManager().createQuery(hql);
+
+		    	q.setParameter("pid", productId);
+		    	q.setParameter("lid", regionList);
+		    	q.setParameter("dt", new Date());
+		    	q.setParameter("lang", language.getId());
+
+		    	Product p = (Product)q.getSingleResult();
+
+
+				return p;
+				
+	}
+
+	@Override
+	public Product getById(Long productId) {
+		
+		try {
+			
+
+
+			StringBuilder qs = new StringBuilder();
+			qs.append("select distinct p from Product as p ");
+			qs.append("join fetch p.availabilities pa ");
+			qs.append("join fetch p.merchantStore merch ");
+			qs.append("join fetch p.descriptions pd ");
+			qs.append("left join fetch p.categories categs ");
+			qs.append("left join fetch pa.prices pap ");
+			qs.append("left join fetch pap.descriptions papd ");
+			qs.append("left join fetch categs.descriptions categsd ");
+			
+			//images
+			qs.append("left join fetch p.images images ");
+			//options
+			qs.append("left join fetch p.images images ");
+			qs.append("left join fetch p.attributes pattr ");
+			qs.append("left join fetch pattr.productOption po ");
+			qs.append("left join fetch po.descriptions pod ");
+			qs.append("left join fetch pattr.productOptionValue pov ");
+			qs.append("left join fetch pov.descriptions povd ");
+			qs.append("left join fetch p.relationships pr ");
+			//other lefts
+			qs.append("left join fetch p.manufacturer manuf ");
+			qs.append("left join fetch manuf.descriptions manufd ");
+			qs.append("left join fetch p.type type ");
+			qs.append("left join fetch p.taxClass tx ");
+			
+			qs.append("where p.id=:pid");
+	
+	
+	    	String hql = qs.toString();
+			Query q = super.getEntityManager().createQuery(hql);
+	
+	    	q.setParameter("pid", productId);
+	
+	
+	    	Product p = (Product)q.getSingleResult();
+	
+	
+			return p;
+		
+		} catch(javax.persistence.NoResultException ers) {
+			return null;
+		}
+		
+	}
+	
+	@Override
+	public Product getByCode(String productCode, Language language) {
+		
+		try {
+			
+
+
+			StringBuilder qs = new StringBuilder();
+			qs.append("select distinct p from Product as p ");
+			qs.append("join fetch p.availabilities pa ");
+			qs.append("join fetch p.descriptions pd ");
+			qs.append("join fetch p.merchantStore pm ");
+			qs.append("left join fetch pa.prices pap ");
+			qs.append("left join fetch pap.descriptions papd ");
+			
+			
+			
+			
+			//images
+			qs.append("left join fetch p.images images ");
+			//options
+			qs.append("left join fetch p.attributes pattr ");
+			qs.append("left join fetch pattr.productOption po ");
+			qs.append("left join fetch po.descriptions pod ");
+			qs.append("left join fetch pattr.productOptionValue pov ");
+			qs.append("left join fetch pov.descriptions povd ");
+			qs.append("left join fetch p.relationships pr ");
+			//other lefts
+			qs.append("left join fetch p.manufacturer manuf ");
+			qs.append("left join fetch manuf.descriptions manufd ");
+			qs.append("left join fetch p.type type ");
+			qs.append("left join fetch p.taxClass tx ");
+			
+			qs.append("where p.sku=:code ");
+			qs.append("and pd.language.id=:lang and papd.language.id=:lang");
+			//this cannot be done on child elements from left join
+			//qs.append("and pod.languageId=:lang and povd.languageId=:lang");
+
+	    	String hql = qs.toString();
+			Query q = super.getEntityManager().createQuery(hql);
+
+	    	q.setParameter("code", productCode);
+	    	q.setParameter("lang", language.getId());
+
+	    	Product p = (Product)q.getSingleResult();
+
+
+			return p;
+		
+		} catch(javax.persistence.NoResultException ers) {
+			return null;
+		}
+		
+	}
+}
+
+
+	
+	
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/relationship/ProductRelationshipDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/relationship/ProductRelationshipDao.java
new file mode 100644
index 0000000..c924b0f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/relationship/ProductRelationshipDao.java
@@ -0,0 +1,31 @@
+package com.salesmanager.core.business.catalog.product.dao.relationship;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationship;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductRelationshipDao extends SalesManagerEntityDao<Long, ProductRelationship> {
+
+	List<ProductRelationship> getByType(MerchantStore store, String type, Product product, Language language);
+
+	List<ProductRelationship> getByType(MerchantStore store, String type,
+			Product product);
+
+	List<ProductRelationship> getByType(MerchantStore store, String type);
+
+	List<ProductRelationship> listByProducts(Product product);
+
+	List<ProductRelationship> getByType(MerchantStore store, String type,
+			Language language);
+
+	List<ProductRelationship> getGroups(MerchantStore store);
+
+	List<ProductRelationship> getByGroup(MerchantStore store, String group);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/relationship/ProductRelationshipDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/relationship/ProductRelationshipDaoImpl.java
new file mode 100644
index 0000000..a987585
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/relationship/ProductRelationshipDaoImpl.java
@@ -0,0 +1,290 @@
+package com.salesmanager.core.business.catalog.product.dao.relationship;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.Query;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationship;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("productRelationshipDao")
+public class ProductRelationshipDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductRelationship>
+		implements ProductRelationshipDao {
+	
+	@Override
+	public List<ProductRelationship> getByType(MerchantStore store, String type, Product product, Language language) {
+		//QDSL cannot interpret the following query, that is why it is in native format
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct pr from ProductRelationship as pr ");
+		qs.append("left join fetch pr.product p ");
+		qs.append("join fetch pr.relatedProduct rp ");
+		qs.append("left join fetch rp.descriptions rpd ");
+
+		qs.append("where pr.code=:code ");
+		qs.append("and p.id=:id ");
+		qs.append("and rpd.language.id=:langId");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("code", type);
+    	q.setParameter("id", product.getId());
+    	q.setParameter("langId", language.getId());
+
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<ProductRelationship> relations =  q.getResultList();
+
+    	
+    	return relations;
+		
+
+	}
+	
+	@Override
+	public List<ProductRelationship> getByType(MerchantStore store, String type, Language language) {
+		//QDSL cannot interpret the following query, that is why it is in native format
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct pr from ProductRelationship as pr ");
+		qs.append("left join fetch pr.product p ");
+		qs.append("join fetch pr.relatedProduct rp ");
+		
+		qs.append("left join fetch rp.attributes pattr ");
+		qs.append("left join fetch rp.descriptions rpd ");
+		qs.append("left join fetch rp.images pd ");
+		qs.append("left join fetch rp.merchantStore rpm ");
+		qs.append("left join fetch rpm.currency rpmc ");
+		qs.append("left join fetch rp.availabilities pa ");
+		qs.append("left join fetch rp.manufacturer m ");
+		qs.append("left join fetch m.descriptions md ");
+		qs.append("left join fetch pa.prices pap ");
+		qs.append("left join fetch pap.descriptions papd ");
+
+		qs.append("where pr.code=:code ");
+		qs.append("and rpd.language.id=:langId");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("code", type);
+    	q.setParameter("langId", language.getId());
+
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<ProductRelationship> relations =  q.getResultList();
+
+    	
+    	return relations;
+		
+
+	}
+	
+	@Override
+	public List<ProductRelationship> getByGroup(MerchantStore store, String group) {
+		//QDSL cannot interpret the following query, that is why it is in native format
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct pr from ProductRelationship as pr ");
+		qs.append("left join fetch pr.product p ");
+		qs.append("left join fetch pr.relatedProduct rp ");
+		
+		qs.append("left join fetch rp.attributes pattr ");
+		qs.append("left join fetch rp.descriptions rpd ");
+		qs.append("left join fetch rp.images pd ");
+		qs.append("left join fetch rp.merchantStore rpm ");
+		qs.append("left join fetch rpm.currency rpmc ");
+		qs.append("left join fetch rp.availabilities pa ");
+		qs.append("left join fetch pa.prices pap ");
+		qs.append("left join fetch pap.descriptions papd ");
+		qs.append("left join fetch rp.manufacturer manuf ");
+		qs.append("left join fetch manuf.descriptions manufd ");
+		qs.append("left join fetch rp.type type ");
+
+		qs.append("where pr.code=:code ");
+
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("code", group);
+
+
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<ProductRelationship> relations =  q.getResultList();
+
+    	
+    	return relations;
+		
+
+	}
+	
+	@Override
+	public List<ProductRelationship> getGroups(MerchantStore store) {
+
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct pr from ProductRelationship as pr ");
+		qs.append("where pr.store.id=:store ");
+		
+		qs.append("and pr.product=null");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("store", store.getId());
+
+
+    	
+    	@SuppressWarnings("unchecked")
+		List<ProductRelationship> relations =  q.getResultList();
+    	
+    	Map<String,ProductRelationship> relationMap = new HashMap<String,ProductRelationship>();
+    	for(ProductRelationship relationship : relations) {
+    		if(!relationMap.containsKey(relationship.getCode())) {
+    			relationMap.put(relationship.getCode(), relationship);
+    		}
+    	}
+    	
+    	List<ProductRelationship> returnList = new ArrayList<ProductRelationship>(relationMap.values());
+
+    	
+    	return returnList;
+		
+
+	}
+	
+	
+	@Override
+	public List<ProductRelationship> getByType(MerchantStore store, String type) {
+		//QDSL cannot interpret the following query, that is why it is in native format
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct pr from ProductRelationship as pr ");
+		qs.append("left join fetch pr.product p ");
+		qs.append("join fetch pr.relatedProduct rp ");
+		qs.append("left join fetch rp.descriptions rpd ");
+
+		qs.append("where pr.code=:code");
+
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("code", type);
+
+
+    	@SuppressWarnings("unchecked")
+		List<ProductRelationship> relations =  q.getResultList();
+
+    	
+    	return relations;
+		
+
+	}
+	
+	@Override
+	public List<ProductRelationship> listByProducts(Product product) {
+		//QDSL cannot interpret the following query, that is why it is in native format
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select pr from ProductRelationship as pr ");
+		qs.append("left join fetch pr.product p ");
+		qs.append("left join fetch pr.relatedProduct rp ");
+		qs.append("left join fetch rp.attributes pattr ");
+		qs.append("left join fetch p.descriptions pd ");
+		qs.append("left join fetch rp.descriptions rpd ");
+
+		qs.append("where p.id=:id");
+		qs.append(" or rp.id=:id");
+
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("id", product.getId());
+
+
+    	@SuppressWarnings("unchecked")
+		List<ProductRelationship> relations =  q.getResultList();
+
+    	
+    	return relations;
+		
+
+	}
+	
+	@Override
+	public List<ProductRelationship> getByType(MerchantStore store, String type, Product product) {
+		//QDSL cannot interpret the following query, that is why it is in native format
+		
+		
+		StringBuilder qs = new StringBuilder();
+		
+		qs.append("select distinct pr from ProductRelationship as pr ");
+		qs.append("left join fetch pr.product p ");
+		qs.append("left join fetch pr.relatedProduct rp ");
+		
+		qs.append("left join fetch rp.attributes pattr ");
+		qs.append("left join fetch rp.descriptions rpd ");
+		qs.append("left join fetch rp.images pd ");
+		qs.append("left join fetch rp.merchantStore rpm ");
+		qs.append("left join fetch rpm.currency rpmc ");
+		qs.append("left join fetch rp.availabilities pa ");
+		qs.append("left join fetch pa.prices pap ");
+		qs.append("left join fetch pap.descriptions papd ");
+		
+		qs.append("left join fetch rp.manufacturer manuf ");
+		qs.append("left join fetch manuf.descriptions manufd ");
+		qs.append("left join fetch rp.type type ");
+
+		qs.append("where pr.code=:code ");
+		qs.append("and p.id=:pId");
+
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("code", type);
+    	q.setParameter("pId", product.getId());
+
+
+		@SuppressWarnings("unchecked")
+		List<ProductRelationship> relations =  q.getResultList();
+
+    	
+    	return relations;
+		
+
+	}
+
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/review/ProductReviewDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/review/ProductReviewDao.java
new file mode 100644
index 0000000..086bfcb
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/review/ProductReviewDao.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.business.catalog.product.dao.review;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.review.ProductReview;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductReviewDao extends SalesManagerEntityDao<Long, ProductReview> {
+
+	List<ProductReview> getByCustomer(Customer customer);
+	List<ProductReview> getByProduct(Product product);
+	List<ProductReview> getByProduct(Product product, Language language);
+	ProductReview getByProductAndCustomer(Long productId, Long customerId);
+
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/review/ProductReviewDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/review/ProductReviewDaoImpl.java
new file mode 100644
index 0000000..710065c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/review/ProductReviewDaoImpl.java
@@ -0,0 +1,175 @@
+package com.salesmanager.core.business.catalog.product.dao.review;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.QProduct;
+import com.salesmanager.core.business.catalog.product.model.review.ProductReview;
+import com.salesmanager.core.business.catalog.product.model.review.QProductReview;
+import com.salesmanager.core.business.catalog.product.model.review.QProductReviewDescription;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.QCustomer;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerAttribute;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionValue;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("productReviewDao")
+public class ProductReviewDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductReview>
+		implements ProductReviewDao {
+
+
+
+	@Override
+	public List<ProductReview> getByCustomer(Customer customer) {
+		
+		QProductReview qEntity = QProductReview.productReview;
+		QProductReviewDescription qDescription = QProductReviewDescription.productReviewDescription;
+		QCustomer qCustomer = QCustomer.customer;
+		QProduct qProduct = QProduct.product;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+		.join(qEntity.customer,qCustomer).fetch()
+		.join(qEntity.product,qProduct).fetch()
+		.leftJoin(qProduct.merchantStore).fetch()
+		.leftJoin(qEntity.descriptions,qDescription).fetch()
+		.where(qCustomer.id.eq(customer.getId()));
+		
+		return query.list(qEntity);
+		
+		
+		
+	}
+
+	@Override
+	public List<ProductReview> getByProduct(Product product) {
+		
+		
+		QProductReview qEntity = QProductReview.productReview;
+		QProductReviewDescription qDescription = QProductReviewDescription.productReviewDescription;
+		QProduct qProduct = QProduct.product;
+		QCustomer qCustomer = QCustomer.customer;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+		.join(qEntity.customer, qCustomer).fetch()
+		.join(qCustomer.merchantStore).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+		.join(qEntity.product,qProduct).fetch()
+		.leftJoin(qProduct.merchantStore).fetch()
+		.leftJoin(qEntity.descriptions,qDescription).fetch()
+		.where(qProduct.id.eq(product.getId()));
+		
+		return query.list(qEntity);
+		
+		
+	}
+	
+	
+	@Override
+	public ProductReview getByProductAndCustomer(Long productId, Long customerId) {
+		
+		
+		QProductReview qEntity = QProductReview.productReview;
+		QProductReviewDescription qDescription = QProductReviewDescription.productReviewDescription;
+		QProduct qProduct = QProduct.product;
+		QCustomer qCustomer = QCustomer.customer;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+		.join(qEntity.customer, qCustomer).fetch()
+		.join(qCustomer.merchantStore).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+		.join(qEntity.product,qProduct).fetch()
+		.leftJoin(qProduct.merchantStore).fetch()
+		.leftJoin(qEntity.descriptions,qDescription).fetch()
+		.where(qProduct.id.eq(productId).and(qCustomer.id.eq(customerId)));
+		
+		return query.uniqueResult(qEntity);
+		
+		
+	}
+	
+	@Override
+	public List<ProductReview> getByProduct(Product product, Language language) {
+		
+		
+		QProductReview qEntity = QProductReview.productReview;
+		QProductReviewDescription qDescription = QProductReviewDescription.productReviewDescription;
+		QProduct qProduct = QProduct.product;
+		QCustomer qCustomer = QCustomer.customer;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+				.join(qEntity.customer, qCustomer).fetch()
+		.join(qCustomer.merchantStore).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+		.join(qEntity.product,qProduct).fetch()
+		.leftJoin(qProduct.merchantStore).fetch()
+		.leftJoin(qEntity.descriptions,qDescription).fetch()
+		.where(qProduct.id.eq(product.getId())
+				.and(qDescription.language.id.eq(language.getId())));
+		
+		return query.list(qEntity);
+		
+		
+	}
+	
+	@Override
+	public ProductReview getById(Long id) {
+
+		QProductReview qEntity = QProductReview.productReview;
+		QProductReviewDescription qDescription = QProductReviewDescription.productReviewDescription;
+		QProduct qProduct = QProduct.product;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qEntity)
+			.join(qEntity.customer).fetch()
+			.join(qEntity.product,qProduct).fetch()
+			.leftJoin(qProduct.merchantStore).fetch()
+			.leftJoin(qEntity.descriptions,qDescription).fetch()
+			.where(qEntity.id.eq(id));
+		
+		return query.uniqueResult(qEntity);
+		
+		
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/type/ProductTypeDao.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/type/ProductTypeDao.java
new file mode 100644
index 0000000..7fe254d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/type/ProductTypeDao.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.catalog.product.dao.type;
+
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+
+public interface ProductTypeDao extends SalesManagerEntityDao<Long, ProductType> {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/type/ProductTypeDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/type/ProductTypeDaoImpl.java
new file mode 100644
index 0000000..b49d8e0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/dao/type/ProductTypeDaoImpl.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.business.catalog.product.dao.type;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+
+@Repository("productTypeDao")
+public class ProductTypeDaoImpl extends SalesManagerEntityDaoImpl<Long, ProductType>
+		implements ProductTypeDao {
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/AttributeCriteria.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/AttributeCriteria.java
new file mode 100644
index 0000000..f317615
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/AttributeCriteria.java
@@ -0,0 +1,26 @@
+package com.salesmanager.core.business.catalog.product.model.attribute;
+
+import java.io.Serializable;
+
+public class AttributeCriteria implements Serializable {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private String attributeCode;
+	private String attributeValue;
+	public void setAttributeCode(String attributeCode) {
+		this.attributeCode = attributeCode;
+	}
+	public String getAttributeCode() {
+		return attributeCode;
+	}
+	public void setAttributeValue(String attributeValue) {
+		this.attributeValue = attributeValue;
+	}
+	public String getAttributeValue() {
+		return attributeValue;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductAttribute.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductAttribute.java
new file mode 100755
index 0000000..30b8f91
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductAttribute.java
@@ -0,0 +1,241 @@
+package com.salesmanager.core.business.catalog.product.model.attribute;
+
+import java.math.BigDecimal;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name="PRODUCT_ATTRIBUTE", schema=SchemaConstant.SALESMANAGER_SCHEMA,
+	uniqueConstraints={
+		@UniqueConstraint(columnNames={
+				"OPTION_ID",
+				"OPTION_VALUE_ID",
+				"PRODUCT_ID"
+			})
+	}
+)
+public class ProductAttribute extends SalesManagerEntity<Long, ProductAttribute> {
+	private static final long serialVersionUID = -6537491946539803265L;
+	
+	@Id
+	@Column(name = "PRODUCT_ATTRIBUTE_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_ATTR_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	
+	@Column(name="PRODUCT_ATRIBUTE_PRICE")
+	private BigDecimal productAttributePrice;
+
+
+	@Column(name="PRODUCT_ATTRIBUTE_SORT_ORD")
+	private Integer productOptionSortOrder;
+	
+	@Column(name="PRODUCT_ATTRIBUTE_FREE")
+	private boolean productAttributeIsFree;
+	
+
+	@Column(name="PRODUCT_ATTRIBUTE_WEIGHT")
+	private BigDecimal productAttributeWeight;
+	
+	@Column(name="PRODUCT_ATTRIBUTE_DEFAULT")
+	private boolean attributeDefault=false;
+	
+	@Column(name="PRODUCT_ATTRIBUTE_REQUIRED")
+	private boolean attributeRequired=false;
+	
+	/**
+	 * a read only attribute is considered as a core attribute addition
+	 */
+	@Column(name="PRODUCT_ATTRIBUTE_FOR_DISP")
+	private boolean attributeDisplayOnly=false;
+	
+
+	@Column(name="PRODUCT_ATTRIBUTE_DISCOUNTED")
+	private boolean attributeDiscounted=false;
+	
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="OPTION_ID", nullable=false)
+	private ProductOption productOption;
+	
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="OPTION_VALUE_ID", nullable=false)
+	private ProductOptionValue productOptionValue;
+	
+	
+	/**
+	 * This transient object property
+	 * is a utility used only to submit from a free text
+	 */
+	@Transient
+	private String attributePrice = "0";
+	
+	
+	/**
+	 * This transient object property
+	 * is a utility used only to submit from a free text
+	 */
+	@Transient
+	private String attributeSortOrder = "0";
+	
+
+
+	/**
+	 * This transient object property
+	 * is a utility used only to submit from a free text
+	 */
+	@Transient
+	private String attributeAdditionalWeight = "0";
+	
+	public String getAttributePrice() {
+		return attributePrice;
+	}
+
+	public void setAttributePrice(String attributePrice) {
+		this.attributePrice = attributePrice;
+	}
+
+	@ManyToOne(targetEntity = Product.class)
+	@JoinColumn(name = "PRODUCT_ID", nullable = false)
+	private Product product;
+	
+	public ProductAttribute() {
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+	public Integer getProductOptionSortOrder() {
+		return productOptionSortOrder;
+	}
+
+	public void setProductOptionSortOrder(Integer productOptionSortOrder) {
+		this.productOptionSortOrder = productOptionSortOrder;
+	}
+
+	public boolean getProductAttributeIsFree() {
+		return productAttributeIsFree;
+	}
+
+	public void setProductAttributeIsFree(boolean productAttributeIsFree) {
+		this.productAttributeIsFree = productAttributeIsFree;
+	}
+
+	public BigDecimal getProductAttributeWeight() {
+		return productAttributeWeight;
+	}
+
+	public void setProductAttributeWeight(BigDecimal productAttributeWeight) {
+		this.productAttributeWeight = productAttributeWeight;
+	}
+
+	public boolean getAttributeDefault() {
+		return attributeDefault;
+	}
+
+	public void setAttributeDefault(boolean attributeDefault) {
+		this.attributeDefault = attributeDefault;
+	}
+
+	public boolean getAttributeRequired() {
+		return attributeRequired;
+	}
+
+	public void setAttributeRequired(boolean attributeRequired) {
+		this.attributeRequired = attributeRequired;
+	}
+
+	public boolean getAttributeDisplayOnly() {
+		return attributeDisplayOnly;
+	}
+
+	public void setAttributeDisplayOnly(boolean attributeDisplayOnly) {
+		this.attributeDisplayOnly = attributeDisplayOnly;
+	}
+
+	public boolean getAttributeDiscounted() {
+		return attributeDiscounted;
+	}
+
+	public void setAttributeDiscounted(boolean attributeDiscounted) {
+		this.attributeDiscounted = attributeDiscounted;
+	}
+
+	public ProductOption getProductOption() {
+		return productOption;
+	}
+
+	public void setProductOption(ProductOption productOption) {
+		this.productOption = productOption;
+	}
+
+	public ProductOptionValue getProductOptionValue() {
+		return productOptionValue;
+	}
+
+	public void setProductOptionValue(ProductOptionValue productOptionValue) {
+		this.productOptionValue = productOptionValue;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+	
+	
+	public String getAttributeSortOrder() {
+		return attributeSortOrder;
+	}
+
+	public void setAttributeSortOrder(String attributeSortOrder) {
+		this.attributeSortOrder = attributeSortOrder;
+	}
+
+	public String getAttributeAdditionalWeight() {
+		return attributeAdditionalWeight;
+	}
+
+	public void setAttributeAdditionalWeight(String attributeAdditionalWeight) {
+		this.attributeAdditionalWeight = attributeAdditionalWeight;
+	}
+	
+	public BigDecimal getProductAttributePrice() {
+		return productAttributePrice;
+	}
+
+	public void setProductAttributePrice(BigDecimal productAttributePrice) {
+		this.productAttributePrice = productAttributePrice;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOption.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOption.java
new file mode 100755
index 0000000..e05353c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOption.java
@@ -0,0 +1,149 @@
+package com.salesmanager.core.business.catalog.product.model.attribute;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+import javax.validation.constraints.Pattern;
+
+import org.hibernate.annotations.Index;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@Table(name="PRODUCT_OPTION", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints=
+	@UniqueConstraint(columnNames = {"MERCHANT_ID", "PRODUCT_OPTION_CODE"}))
+public class ProductOption extends SalesManagerEntity<Long, ProductOption> {
+	private static final long serialVersionUID = -2019269055342226086L;
+	
+	@Id
+	@Column(name="PRODUCT_OPTION_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_OPTION_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column(name="PRODUCT_OPTION_SORT_ORD")
+	private Integer productOptionSortOrder;
+	
+	@Column(name="PRODUCT_OPTION_TYPE", length=10)
+	private String productOptionType;
+	
+
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "productOption")
+	private Set<ProductOptionDescription> descriptions = new HashSet<ProductOptionDescription>();
+	
+	@Transient
+	private List<ProductOptionDescription> descriptionsList = new ArrayList<ProductOptionDescription>();
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	@Column(name="PRODUCT_OPTION_READ")
+	private boolean readOnly;
+	
+	@NotEmpty
+	@Pattern(regexp="^[a-zA-Z0-9_]*$")
+	@Column(name="PRODUCT_OPTION_CODE")
+	@Index(name="PRD_OPTION_CODE_IDX")
+	private String code;
+	
+	public ProductOption() {
+	}
+	
+	public Integer getProductOptionSortOrder() {
+		return productOptionSortOrder;
+	}
+	
+	public void setProductOptionSortOrder(Integer productOptionSortOrder) {
+		this.productOptionSortOrder = productOptionSortOrder;
+	}
+	
+	public String getProductOptionType() {
+		return productOptionType;
+	}
+
+	public void setProductOptionType(String productOptionType) {
+		this.productOptionType = productOptionType;
+	}
+	
+	public Set<ProductOptionDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(Set<ProductOptionDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+	
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public void setDescriptionsList(List<ProductOptionDescription> descriptionsList) {
+		this.descriptionsList = descriptionsList;
+	}
+
+	public List<ProductOptionDescription> getDescriptionsList() {
+		return descriptionsList;
+	}
+	
+
+	public List<ProductOptionDescription> getDescriptionsSettoList() {
+		if(descriptionsList==null || descriptionsList.size()==0) {
+			descriptionsList = new ArrayList<ProductOptionDescription>(this.getDescriptions());
+		} 
+		return descriptionsList;
+
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setReadOnly(boolean readOnly) {
+		this.readOnly = readOnly;
+	}
+
+	public boolean isReadOnly() {
+		return readOnly;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionDescription.java
new file mode 100755
index 0000000..d458f2c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionDescription.java
@@ -0,0 +1,51 @@
+package com.salesmanager.core.business.catalog.product.model.attribute;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import org.hibernate.annotations.Type;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name="PRODUCT_OPTION_DESC", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints={
+	@UniqueConstraint(columnNames={
+			"PRODUCT_OPTION_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class ProductOptionDescription extends Description {
+	private static final long serialVersionUID = -3158504904707188465L;
+	
+	@ManyToOne(targetEntity = ProductOption.class)
+	@JoinColumn(name = "PRODUCT_OPTION_ID", nullable = false)
+	private ProductOption productOption;
+	
+	@Column(name="PRODUCT_OPTION_COMMENT")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String productOptionComment;
+	
+	public ProductOptionDescription() {
+	}
+	
+	public String getProductOptionComment() {
+		return productOptionComment;
+	}
+	public void setProductOptionComment(String productOptionComment) {
+		this.productOptionComment = productOptionComment;
+	}
+
+	public ProductOption getProductOption() {
+		return productOption;
+	}
+
+	public void setProductOption(ProductOption productOption) {
+		this.productOption = productOption;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionType.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionType.java
new file mode 100644
index 0000000..1c1ab6b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.catalog.product.model.attribute;
+
+public enum ProductOptionType {
+	
+	Text, Radio, Select, Checkbox
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionValue.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionValue.java
new file mode 100755
index 0000000..376a19c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionValue.java
@@ -0,0 +1,160 @@
+package com.salesmanager.core.business.catalog.product.model.attribute;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+import javax.validation.constraints.Pattern;
+
+import org.hibernate.annotations.Index;
+import org.hibernate.validator.constraints.NotEmpty;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@Table(name="PRODUCT_OPTION_VALUE", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints=
+	@UniqueConstraint(columnNames = {"MERCHANT_ID", "PRODUCT_OPTION_VAL_CODE"}))
+public class ProductOptionValue extends SalesManagerEntity<Long, ProductOptionValue> {
+	private static final long serialVersionUID = 3736085877929910891L;
+
+	@Id
+	@Column(name="PRODUCT_OPTION_VALUE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_OPT_VAL_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column(name="PRODUCT_OPT_VAL_SORT_ORD")
+	private Integer productOptionValueSortOrder;
+	
+	@Column(name="PRODUCT_OPT_VAL_IMAGE")
+	private String productOptionValueImage;
+	
+	@Column(name="PRODUCT_OPT_FOR_DISP")
+	private boolean productOptionDisplayOnly=false;
+	
+	@NotEmpty
+	@Pattern(regexp="^[a-zA-Z0-9_]*$")
+	@Column(name="PRODUCT_OPTION_VAL_CODE")
+	@Index(name="PRD_OPTION_VAL_CODE_IDX")
+	private String code;
+	
+	@Transient
+	private MultipartFile image = null;
+	
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "productOptionValue")
+	private Set<ProductOptionValueDescription> descriptions = new HashSet<ProductOptionValueDescription>();
+	
+	@Transient
+	private List<ProductOptionValueDescription> descriptionsList = new ArrayList<ProductOptionValueDescription>();
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	public ProductOptionValue() {
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Integer getProductOptionValueSortOrder() {
+		return productOptionValueSortOrder;
+	}
+
+	public void setProductOptionValueSortOrder(Integer productOptionValueSortOrder) {
+		this.productOptionValueSortOrder = productOptionValueSortOrder;
+	}
+
+	public String getProductOptionValueImage() {
+		return productOptionValueImage;
+	}
+
+	public void setProductOptionValueImage(String productOptionValueImage) {
+		this.productOptionValueImage = productOptionValueImage;
+	}
+
+	public Set<ProductOptionValueDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(Set<ProductOptionValueDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public void setDescriptionsList(List<ProductOptionValueDescription> descriptionsList) {
+		this.descriptionsList = descriptionsList;
+	}
+
+	public List<ProductOptionValueDescription> getDescriptionsList() {
+		return descriptionsList; 
+	}
+	
+	public List<ProductOptionValueDescription> getDescriptionsSettoList() {
+		if(descriptionsList==null || descriptionsList.size()==0) {
+			descriptionsList = new ArrayList<ProductOptionValueDescription>(this.getDescriptions());
+		} 
+		return descriptionsList;
+	}
+
+	public void setImage(MultipartFile image) {
+		this.image = image;
+	}
+
+	public MultipartFile getImage() {
+		return image;
+	}
+	
+	public boolean isProductOptionDisplayOnly() {
+		return productOptionDisplayOnly;
+	}
+
+	public void setProductOptionDisplayOnly(boolean productOptionDisplayOnly) {
+		this.productOptionDisplayOnly = productOptionDisplayOnly;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionValueDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionValueDescription.java
new file mode 100644
index 0000000..08fab19
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/attribute/ProductOptionValueDescription.java
@@ -0,0 +1,38 @@
+package com.salesmanager.core.business.catalog.product.model.attribute;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name = "PRODUCT_OPTION_VALUE_DESCRIPTION", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints={
+	@UniqueConstraint(columnNames={
+			"PRODUCT_OPTION_VALUE_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class ProductOptionValueDescription extends Description {
+	private static final long serialVersionUID = 7402155175956813576L;
+	
+	@ManyToOne(targetEntity = ProductOptionValue.class)
+	@JoinColumn(name = "PRODUCT_OPTION_VALUE_ID")
+	private ProductOptionValue productOptionValue;
+	
+	public ProductOptionValueDescription() {
+	}
+
+	public ProductOptionValue getProductOptionValue() {
+		return productOptionValue;
+	}
+
+	public void setProductOptionValue(ProductOptionValue productOptionValue) {
+		this.productOptionValue = productOptionValue;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/availability/ProductAvailability.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/availability/ProductAvailability.java
new file mode 100755
index 0000000..c425f04
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/availability/ProductAvailability.java
@@ -0,0 +1,184 @@
+package com.salesmanager.core.business.catalog.product.model.availability;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+import javax.validation.constraints.NotNull;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+
+@Entity
+@Table(name="PRODUCT_AVAILABILITY", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class ProductAvailability extends SalesManagerEntity<Long, ProductAvailability> {
+	private static final long serialVersionUID = 7449264635180797762L;
+
+	@Id
+	@Column(name = "PRODUCT_AVAIL_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_AVAIL_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+
+	@ManyToOne(targetEntity = Product.class)
+	@JoinColumn(name = "PRODUCT_ID", nullable = false)
+	private Product product;
+	
+	@NotNull
+	@Column(name="QUANTITY")
+	private Integer productQuantity = 0;
+	
+	@Temporal(TemporalType.DATE)
+	@Column(name="DATE_AVAILABLE")
+	private Date productDateAvailable;
+	
+	@Column(name="REGION")
+	private String region = Constants.ALL_REGIONS;
+	
+	@Column(name="REGION_VARIANT")
+	private String regionVariant;
+	
+	@Column(name="STATUS")
+	private boolean productStatus = true;
+	
+	@Column(name="FREE_SHIPPING")
+	private boolean productIsAlwaysFreeShipping;
+	
+	@Column(name="QUANTITY_ORD_MIN")
+	private Integer productQuantityOrderMin = 0;
+	
+	@Column(name="QUANTITY_ORD_MAX")
+	private Integer productQuantityOrderMax = 0;
+	
+	@OneToMany(fetch = FetchType.LAZY, mappedBy="productAvailability", cascade = CascadeType.REMOVE)	
+	private Set<ProductPrice> prices = new HashSet<ProductPrice>();
+	
+	@Transient
+	public ProductPrice defaultPrice() {
+		
+		for(ProductPrice price : prices) {
+			if(price.isDefaultPrice()) {
+				return price;
+			}
+		}
+		return new ProductPrice();
+	}
+	
+	public ProductAvailability() {
+	}
+
+	public Integer getProductQuantity() {
+		return productQuantity;
+	}
+
+	public void setProductQuantity(Integer productQuantity) {
+		this.productQuantity = productQuantity;
+	}
+
+	public Date getProductDateAvailable() {
+		return CloneUtils.clone(productDateAvailable);
+	}
+
+	public void setProductDateAvailable(Date productDateAvailable) {
+		this.productDateAvailable = CloneUtils.clone(productDateAvailable);
+	}
+
+	public String getRegion() {
+		return region;
+	}
+
+	public void setRegion(String region) {
+		this.region = region;
+	}
+
+	public String getRegionVariant() {
+		return regionVariant;
+	}
+
+	public void setRegionVariant(String regionVariant) {
+		this.regionVariant = regionVariant;
+	}
+
+	public boolean getProductStatus() {
+		return productStatus;
+	}
+
+	public void setProductStatus(boolean productStatus) {
+		this.productStatus = productStatus;
+	}
+
+	public boolean getProductIsAlwaysFreeShipping() {
+		return productIsAlwaysFreeShipping;
+	}
+
+	public void setProductIsAlwaysFreeShipping(boolean productIsAlwaysFreeShipping) {
+		this.productIsAlwaysFreeShipping = productIsAlwaysFreeShipping;
+	}
+
+	public Integer getProductQuantityOrderMin() {
+		return productQuantityOrderMin;
+	}
+
+	public void setProductQuantityOrderMin(Integer productQuantityOrderMin) {
+		this.productQuantityOrderMin = productQuantityOrderMin;
+	}
+
+	public Integer getProductQuantityOrderMax() {
+		return productQuantityOrderMax;
+	}
+
+	public void setProductQuantityOrderMax(Integer productQuantityOrderMax) {
+		this.productQuantityOrderMax = productQuantityOrderMax;
+	}
+
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+
+
+	public Set<ProductPrice> getPrices() {
+		return prices;
+	}
+
+	public void setPrices(Set<ProductPrice> prices) {
+		this.prices = prices;
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/description/ProductDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/description/ProductDescription.java
new file mode 100644
index 0000000..5d4774f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/description/ProductDescription.java
@@ -0,0 +1,105 @@
+package com.salesmanager.core.business.catalog.product.model.description;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.common.model.Description;
+
+@Entity
+@Table(name = "PRODUCT_DESCRIPTION", schema="SALESMANAGER", uniqueConstraints={
+	@UniqueConstraint(columnNames={
+			"PRODUCT_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class ProductDescription extends Description {
+	private static final long serialVersionUID = -7991123535661321865L;
+	
+	@ManyToOne(targetEntity = Product.class)
+	@JoinColumn(name = "PRODUCT_ID", nullable = false)
+	private Product product;
+	
+	@Column(name = "PRODUCT_HIGHLIGHT")
+	private String productHighlight;
+
+	@Column(name = "DOWNLOAD_LNK")
+	private String productExternalDl;
+
+	@Column(name = "SEF_URL")
+	private String seUrl;
+
+	@Column(name = "META_TITLE")
+	private String metatagTitle;
+
+	@Column(name = "META_KEYWORDS")
+	private String metatagKeywords;
+
+	@Column(name = "META_DESCRIPTION")
+	private String metatagDescription;
+
+	public ProductDescription() {
+	}
+
+	public String getProductHighlight() {
+		return productHighlight;
+	}
+
+	public void setProductHighlight(String productHighlight) {
+		this.productHighlight = productHighlight;
+	}
+
+	public String getProductExternalDl() {
+		return productExternalDl;
+	}
+
+	public void setProductExternalDl(String productExternalDl) {
+		this.productExternalDl = productExternalDl;
+	}
+
+	public String getSeUrl() {
+		return seUrl;
+	}
+
+	public void setSeUrl(String seUrl) {
+		this.seUrl = seUrl;
+	}
+
+	public String getMetatagTitle() {
+		return metatagTitle;
+	}
+
+	public void setMetatagTitle(String metatagTitle) {
+		this.metatagTitle = metatagTitle;
+	}
+
+	public String getMetatagKeywords() {
+		return metatagKeywords;
+	}
+
+	public void setMetatagKeywords(String metatagKeywords) {
+		this.metatagKeywords = metatagKeywords;
+	}
+
+	public String getMetatagDescription() {
+		return metatagDescription;
+	}
+
+	public void setMetatagDescription(String metatagDescription) {
+		this.metatagDescription = metatagDescription;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/file/DigitalProduct.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/file/DigitalProduct.java
new file mode 100644
index 0000000..130b669
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/file/DigitalProduct.java
@@ -0,0 +1,76 @@
+package com.salesmanager.core.business.catalog.product.model.file;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+/**
+ * Representation of a digital product
+ * @author csamson777
+ *
+ */
+@Entity
+@Table(name = "PRODUCT_DIGITAL", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints=
+	@UniqueConstraint(columnNames = {"PRODUCT_ID", "FILE_NAME"}))
+public class DigitalProduct extends SalesManagerEntity<Long, DigitalProduct> {
+
+
+	private static final long serialVersionUID = 1L;
+	
+	
+	@Id
+	@Column(name = "PRODUCT_DIGITAL_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_DGT_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	
+	@ManyToOne(targetEntity = Product.class)
+	@JoinColumn(name = "PRODUCT_ID", nullable = false)
+	private Product product;
+
+
+	@Column(name="FILE_NAME",nullable=false)
+	private String productFileName;
+	
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getProductFileName() {
+		return productFileName;
+	}
+
+	public void setProductFileName(String productFileName) {
+		this.productFileName = productFileName;
+	}
+	
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/file/ProductImageSize.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/file/ProductImageSize.java
new file mode 100755
index 0000000..6db38a9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/file/ProductImageSize.java
@@ -0,0 +1,10 @@
+package com.salesmanager.core.business.catalog.product.model.file;
+
+public enum ProductImageSize {
+	
+	LARGE,
+	SMALL
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/image/ProductImage.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/image/ProductImage.java
new file mode 100755
index 0000000..91d8664
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/image/ProductImage.java
@@ -0,0 +1,132 @@
+package com.salesmanager.core.business.catalog.product.model.image;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+
+@Entity
+@Table(name = "PRODUCT_IMAGE", schema="SALESMANAGER")
+public class ProductImage extends SalesManagerEntity<Long, ProductImage> {
+	private static final long serialVersionUID = 247514890386076337L;
+	
+	@Id
+	@Column(name = "PRODUCT_IMAGE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_IMG_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@OneToMany(fetch = FetchType.LAZY, mappedBy = "productImage", cascade = CascadeType.ALL)
+	private List<ProductImageDescription> descriptions = new ArrayList<ProductImageDescription>();
+
+	
+	@Column(name = "PRODUCT_IMAGE")
+	private String productImage;
+	
+	@Column(name = "DEFAULT_IMAGE")
+	private boolean defaultImage = true;
+	
+	@Column(name = "IMAGE_TYPE")
+	private int imageType;
+	
+	@Column(name = "IMAGE_CROP")
+	private boolean imageCrop;
+	
+	@ManyToOne(targetEntity = Product.class)
+	@JoinColumn(name = "PRODUCT_ID", nullable = false)
+	private Product product;
+	
+	@Transient
+	private InputStream image = null;
+	
+	//private MultiPartFile image
+
+	public ProductImage(){
+	}
+
+	public String getProductImage() {
+		return productImage;
+	}
+
+	public void setProductImage(String productImage) {
+		this.productImage = productImage;
+	}
+
+	public boolean isDefaultImage() {
+		return defaultImage;
+	}
+
+	public void setDefaultImage(boolean defaultImage) {
+		this.defaultImage = defaultImage;
+	}
+
+	public int getImageType() {
+		return imageType;
+	}
+
+	public void setImageType(int imageType) {
+		this.imageType = imageType;
+	}
+
+	public boolean isImageCrop() {
+		return imageCrop;
+	}
+
+	public void setImageCrop(boolean imageCrop) {
+		this.imageCrop = imageCrop;
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+	public void setDescriptions(List<ProductImageDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	public List<ProductImageDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public InputStream getImage() {
+		return image;
+	}
+
+	public void setImage(InputStream image) {
+		this.image = image;
+	}
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/image/ProductImageDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/image/ProductImageDescription.java
new file mode 100644
index 0000000..c945f3e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/image/ProductImageDescription.java
@@ -0,0 +1,48 @@
+package com.salesmanager.core.business.catalog.product.model.image;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name="PRODUCT_IMAGE_DESCRIPTION", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints={
+		@UniqueConstraint(columnNames={
+			"PRODUCT_IMAGE_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class ProductImageDescription extends Description {
+	private static final long serialVersionUID = 247514890386076337L;
+	
+	@ManyToOne(targetEntity = ProductImage.class)
+	@JoinColumn(name = "PRODUCT_IMAGE_ID", nullable = false)
+	private ProductImage productImage;
+	
+	@Column(name="ALT_TAG", length=100)
+	private String altTag;
+
+	public ProductImage getProductImage() {
+		return productImage;
+	}
+
+	public void setProductImage(ProductImage productImage) {
+		this.productImage = productImage;
+	}
+
+	public String getAltTag() {
+		return altTag;
+	}
+
+	public void setAltTag(String altTag) {
+		this.altTag = altTag;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/manufacturer/Manufacturer.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/manufacturer/Manufacturer.java
new file mode 100644
index 0000000..7e79634
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/manufacturer/Manufacturer.java
@@ -0,0 +1,113 @@
+package com.salesmanager.core.business.catalog.product.model.manufacturer;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "MANUFACTURER", schema="SALESMANAGER")
+public class Manufacturer extends SalesManagerEntity<Long, Manufacturer> implements Auditable {
+	private static final long serialVersionUID = 80693964563570099L;
+	
+	@Id
+	@Column(name = "MANUFACTURER_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "MANUFACT_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@OneToMany(mappedBy = "manufacturer", cascade = CascadeType.ALL , fetch = FetchType.EAGER)
+	private Set<ManufacturerDescription> descriptions = new HashSet<ManufacturerDescription>();
+	
+	@Column(name = "MANUFACTURER_IMAGE")
+	private String image;
+	
+	@Column(name="SORT_ORDER")
+	private Integer order = new Integer(0);
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+
+	public Manufacturer() {
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+	
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+	
+	@Override
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	public String getImage() {
+		return image;
+	}
+
+	public void setImage(String image) {
+		this.image = image;
+	}
+
+	public Set<ManufacturerDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(Set<ManufacturerDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public void setOrder(Integer order) {
+		this.order = order;
+	}
+
+	public Integer getOrder() {
+		return order;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/manufacturer/ManufacturerDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/manufacturer/ManufacturerDescription.java
new file mode 100644
index 0000000..8f82404
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/manufacturer/ManufacturerDescription.java
@@ -0,0 +1,72 @@
+package com.salesmanager.core.business.catalog.product.model.manufacturer;
+
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+
+@Entity
+@Table(name = "MANUFACTURER_DESCRIPTION", schema="SALESMANAGER", uniqueConstraints={
+	@UniqueConstraint(columnNames={
+			"MANUFACTURER_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class ManufacturerDescription extends Description {
+	private static final long serialVersionUID = -2164581613773995282L;
+	
+	@ManyToOne(targetEntity = Manufacturer.class)
+	@JoinColumn(name = "MANUFACTURER_ID", nullable = false)
+	private Manufacturer manufacturer;
+	
+	@Column(name = "MANUFACTURERS_URL")
+	private String url;
+	
+	@Column(name = "URL_CLICKED")
+	private Integer urlClicked;
+	
+	@Column(name = "DATE_LAST_CLICK")
+	private Date dateLastClick;
+	
+	public ManufacturerDescription() {
+	}
+
+	public String getUrl() {
+		return url;
+	}
+
+	public void setUrl(String url) {
+		this.url = url;
+	}
+
+	public Integer getUrlClicked() {
+		return urlClicked;
+	}
+
+	public void setUrlClicked(Integer urlClicked) {
+		this.urlClicked = urlClicked;
+	}
+
+	public Date getDateLastClick() {
+		return dateLastClick;
+	}
+
+	public void setDateLastClick(Date dateLastClick) {
+		this.dateLastClick = dateLastClick;
+	}
+
+	public Manufacturer getManufacturer() {
+		return manufacturer;
+	}
+
+	public void setManufacturer(Manufacturer manufacturer) {
+		this.manufacturer = manufacturer;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/FinalPrice.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/FinalPrice.java
new file mode 100755
index 0000000..4caf675
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/FinalPrice.java
@@ -0,0 +1,107 @@
+package com.salesmanager.core.business.catalog.product.model.price;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Transient entity used to display
+ * different price information in the catalogue
+ * @author Carl Samson
+ *
+ */
+public class FinalPrice implements Serializable {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private BigDecimal discountedPrice = null;//final price if a discount is applied
+	private BigDecimal originalPrice = null;//original price
+	private BigDecimal finalPrice = null;//final price discount or not
+	private boolean discounted = false;
+	private int discountPercent = 0;
+	
+	private Date discountEndDate = null;
+	
+	private boolean defaultPrice;
+	private ProductPrice productPrice;
+	List<FinalPrice> additionalPrices;
+
+	public List<FinalPrice> getAdditionalPrices() {
+		return additionalPrices;
+	}
+
+	public void setAdditionalPrices(List<FinalPrice> additionalPrices) {
+		this.additionalPrices = additionalPrices;
+	}
+
+	public BigDecimal getOriginalPrice() {
+		return originalPrice;
+	}
+
+	public void setOriginalPrice(BigDecimal originalPrice) {
+		this.originalPrice = originalPrice;
+	}
+
+
+
+	public int getDiscountPercent() {
+		return discountPercent;
+	}
+
+	public void setDiscountPercent(int discountPercent) {
+		this.discountPercent = discountPercent;
+	}
+
+	public Date getDiscountEndDate() {
+		return discountEndDate;
+	}
+
+	public void setDiscountEndDate(Date discountEndDate) {
+		this.discountEndDate = discountEndDate;
+	}
+
+	public boolean isDiscounted() {
+		return discounted;
+	}
+
+	public void setDiscounted(boolean discounted) {
+		this.discounted = discounted;
+	}
+
+	public void setDiscountedPrice(BigDecimal discountedPrice) {
+		this.discountedPrice = discountedPrice;
+	}
+
+	public BigDecimal getDiscountedPrice() {
+		return discountedPrice;
+	}
+
+
+	public void setFinalPrice(BigDecimal finalPrice) {
+		this.finalPrice = finalPrice;
+	}
+
+	public BigDecimal getFinalPrice() {
+		return finalPrice;
+	}
+
+	public void setDefaultPrice(boolean defaultPrice) {
+		this.defaultPrice = defaultPrice;
+	}
+
+	public boolean isDefaultPrice() {
+		return defaultPrice;
+	}
+
+	public void setProductPrice(ProductPrice productPrice) {
+		this.productPrice = productPrice;
+	}
+
+	public ProductPrice getProductPrice() {
+		return productPrice;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPrice.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPrice.java
new file mode 100644
index 0000000..78ee7fa
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPrice.java
@@ -0,0 +1,182 @@
+package com.salesmanager.core.business.catalog.product.model.price;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.validation.constraints.Pattern;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+@Entity
+@Table(name = "PRODUCT_PRICE", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class ProductPrice extends SalesManagerEntity<Long, ProductPrice> {
+	private static final long serialVersionUID = -9186473817468772165L;
+	
+	private final static String DEFAULT_PRICE_CODE="base";
+
+	@Id
+	@Column(name = "PRODUCT_PRICE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_PRICE_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@OneToMany(fetch = FetchType.LAZY, mappedBy = "productPrice", cascade = CascadeType.ALL)
+	private Set<ProductPriceDescription> descriptions = new HashSet<ProductPriceDescription>();
+
+	@NotEmpty
+	@Pattern(regexp="^[a-zA-Z0-9_]*$")
+	@Column(name = "PRODUCT_PRICE_CODE", nullable=false)
+	private String code = DEFAULT_PRICE_CODE;
+
+	@Column(name = "PRODUCT_PRICE_AMOUNT", nullable=false)
+	private BigDecimal productPriceAmount = new BigDecimal(0);
+
+	@Column(name = "PRODUCT_PRICE_TYPE", length=20)
+	@Enumerated(value = EnumType.STRING)
+	private ProductPriceType productPriceType = ProductPriceType.ONE_TIME;
+
+	@Column(name = "DEFAULT_PRICE")
+	private boolean defaultPrice = false;
+
+	@Temporal(TemporalType.DATE)
+	@Column(name = "PRODUCT_PRICE_SPECIAL_ST_DATE")
+	private Date productPriceSpecialStartDate;
+
+	@Temporal(TemporalType.DATE)
+	@Column(name = "PRODUCT_PRICE_SPECIAL_END_DATE")
+	private Date productPriceSpecialEndDate;
+
+	@Column(name = "PRODUCT_PRICE_SPECIAL_AMOUNT")
+	private BigDecimal productPriceSpecialAmount;
+	
+
+	@ManyToOne(targetEntity = ProductAvailability.class)
+	@JoinColumn(name = "PRODUCT_AVAIL_ID", nullable = false)
+	private ProductAvailability productAvailability;
+	
+
+	public ProductPrice() {
+	}
+	
+	@Override
+	public Long getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+
+	public BigDecimal getProductPriceAmount() {
+		return productPriceAmount;
+	}
+
+	public void setProductPriceAmount(BigDecimal productPriceAmount) {
+		this.productPriceAmount = productPriceAmount;
+	}
+
+
+	
+	public Date getProductPriceSpecialStartDate() {
+		return CloneUtils.clone(productPriceSpecialStartDate);
+	}
+
+	public void setProductPriceSpecialStartDate(
+			Date productPriceSpecialStartDate) {
+		this.productPriceSpecialStartDate = CloneUtils.clone(productPriceSpecialStartDate);
+	}
+
+	public Date getProductPriceSpecialEndDate() {
+		return CloneUtils.clone(productPriceSpecialEndDate);
+	}
+
+	public void setProductPriceSpecialEndDate(Date productPriceSpecialEndDate) {
+		this.productPriceSpecialEndDate = CloneUtils.clone(productPriceSpecialEndDate);
+	}
+
+
+
+	public BigDecimal getProductPriceSpecialAmount() {
+		return productPriceSpecialAmount;
+	}
+
+	public void setProductPriceSpecialAmount(
+			BigDecimal productPriceSpecialAmount) {
+		this.productPriceSpecialAmount = productPriceSpecialAmount;
+	}
+
+
+
+	public Set<ProductPriceDescription> getDescriptions() {
+		return descriptions;
+	}
+
+
+
+	public void setDescriptions(Set<ProductPriceDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+
+
+	public boolean isDefaultPrice() {
+		return defaultPrice;
+	}
+
+	public void setDefaultPrice(boolean defaultPrice) {
+		this.defaultPrice = defaultPrice;
+	}
+
+	public void setProductAvailability(ProductAvailability productAvailability) {
+		this.productAvailability = productAvailability;
+	}
+
+	public ProductAvailability getProductAvailability() {
+		return productAvailability;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setProductPriceType(ProductPriceType productPriceType) {
+		this.productPriceType = productPriceType;
+	}
+
+	public ProductPriceType getProductPriceType() {
+		return productPriceType;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPriceDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPriceDescription.java
new file mode 100644
index 0000000..65f94a8
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPriceDescription.java
@@ -0,0 +1,41 @@
+package com.salesmanager.core.business.catalog.product.model.price;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name="PRODUCT_PRICE_DESCRIPTION", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints={
+		@UniqueConstraint(columnNames={
+			"PRODUCT_PRICE_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class ProductPriceDescription extends Description {
+	private static final long serialVersionUID = 270521409645392808L;
+	
+	public final static String DEFAULT_PRICE_DESCRIPTION = "DEFAULT";
+	
+	@ManyToOne(targetEntity = ProductPrice.class)
+	@JoinColumn(name = "PRODUCT_PRICE_ID", nullable = false)
+	private ProductPrice productPrice;
+	
+	public ProductPriceDescription() {
+	}
+
+	public ProductPrice getProductPrice() {
+		return productPrice;
+	}
+
+	public void setProductPrice(ProductPrice productPrice) {
+		this.productPrice = productPrice;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPriceType.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPriceType.java
new file mode 100644
index 0000000..46115c3
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/price/ProductPriceType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.catalog.product.model.price;
+
+public enum ProductPriceType {
+	
+	ONE_TIME, MONTHLY
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/Product.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/Product.java
new file mode 100755
index 0000000..57b7376
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/Product.java
@@ -0,0 +1,418 @@
+package com.salesmanager.core.business.catalog.product.model;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.validation.constraints.Pattern;
+
+import org.hibernate.annotations.Cascade;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationship;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "PRODUCT", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class Product extends SalesManagerEntity<Long, Product> implements Auditable {
+	private static final long serialVersionUID = -6228066416290007047L;
+
+	@Id
+	@Column(name = "PRODUCT_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "product")
+	private Set<ProductDescription> descriptions = new HashSet<ProductDescription>();
+	
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, mappedBy="product", orphanRemoval = true)
+	private Set<ProductAvailability> availabilities = new HashSet<ProductAvailability>();
+
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, mappedBy = "product")
+	private Set<ProductAttribute> attributes = new HashSet<ProductAttribute>();
+	
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, mappedBy = "product")
+	private Set<ProductImage> images = new HashSet<ProductImage>();
+
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, mappedBy = "product")
+	private Set<ProductRelationship> relationships = new HashSet<ProductRelationship>();
+	
+
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	@ManyToMany(fetch=FetchType.LAZY, cascade = {CascadeType.REFRESH})
+	@JoinTable(name = "PRODUCT_CATEGORY", schema=SchemaConstant.SALESMANAGER_SCHEMA, joinColumns = { 
+			@JoinColumn(name = "PRODUCT_ID", nullable = false, updatable = false) }
+			, 
+			inverseJoinColumns = { @JoinColumn(name = "CATEGORY_ID", 
+					nullable = false, updatable = false) }
+	)
+	@Cascade({
+		org.hibernate.annotations.CascadeType.DETACH,
+		org.hibernate.annotations.CascadeType.LOCK,
+		org.hibernate.annotations.CascadeType.REFRESH,
+		org.hibernate.annotations.CascadeType.REPLICATE
+		
+	})
+	private Set<Category> categories = new HashSet<Category>();
+	
+	@Column(name="DATE_AVAILABLE")
+	@Temporal(TemporalType.TIMESTAMP)
+	private Date dateAvailable = new Date();
+	
+	
+	@Column(name="AVAILABLE")
+	private boolean available = true;
+	
+
+	@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH})
+	@JoinColumn(name="MANUFACTURER_ID", nullable=true)
+	private Manufacturer manufacturer;
+
+	@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH})
+	@JoinColumn(name="PRODUCT_TYPE_ID", nullable=true)
+	private ProductType type;
+
+	@ManyToOne(fetch = FetchType.LAZY, cascade = {CascadeType.REFRESH})
+	@JoinColumn(name="TAX_CLASS_ID", nullable=true)
+	private TaxClass taxClass;
+
+	@Column(name = "PRODUCT_VIRTUAL")
+	private boolean productVirtual = false;
+	
+	@Column(name = "PRODUCT_SHIP")
+	private boolean productShipeable = false;
+
+
+	@Column(name = "PRODUCT_FREE")
+	private boolean productIsFree;
+
+	@Column(name = "PRODUCT_LENGTH")
+	private BigDecimal productLength;
+
+	@Column(name = "PRODUCT_WIDTH")
+	private BigDecimal productWidth;
+
+	@Column(name = "PRODUCT_HEIGHT")
+	private BigDecimal productHeight;
+
+	@Column(name = "PRODUCT_WEIGHT")
+	private BigDecimal productWeight;
+
+	@Column(name = "REVIEW_AVG")
+	private BigDecimal productReviewAvg;
+
+	@Column(name = "REVIEW_COUNT")
+	private Integer productReviewCount;
+
+	@Column(name = "QUANTITY_ORDERED")
+	private Integer productOrdered;
+	
+	@Column(name = "SORT_ORDER")
+	private Integer sortOrder = new Integer(0);
+
+	@NotEmpty
+	@Pattern(regexp="^[a-zA-Z0-9_]*$")
+	@Column(name = "SKU")
+	private String sku;
+
+	public Product() {
+	}
+
+	@Override
+	public Long getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+
+	public boolean isProductVirtual() {
+		return productVirtual;
+	}
+
+
+
+	public BigDecimal getProductLength() {
+		return productLength;
+	}
+
+	public void setProductLength(BigDecimal productLength) {
+		this.productLength = productLength;
+	}
+
+	public BigDecimal getProductWidth() {
+		return productWidth;
+	}
+
+	public void setProductWidth(BigDecimal productWidth) {
+		this.productWidth = productWidth;
+	}
+
+	public BigDecimal getProductHeight() {
+		return productHeight;
+	}
+
+	public void setProductHeight(BigDecimal productHeight) {
+		this.productHeight = productHeight;
+	}
+
+	public BigDecimal getProductWeight() {
+		return productWeight;
+	}
+
+	public void setProductWeight(BigDecimal productWeight) {
+		this.productWeight = productWeight;
+	}
+
+	public BigDecimal getProductReviewAvg() {
+		return productReviewAvg;
+	}
+
+	public void setProductReviewAvg(BigDecimal productReviewAvg) {
+		this.productReviewAvg = productReviewAvg;
+	}
+
+	public Integer getProductReviewCount() {
+		return productReviewCount;
+	}
+
+	public void setProductReviewCount(Integer productReviewCount) {
+		this.productReviewCount = productReviewCount;
+	}
+
+
+
+	public Integer getProductOrdered() {
+		return productOrdered;
+	}
+
+	public void setProductOrdered(Integer productOrdered) {
+		this.productOrdered = productOrdered;
+	}
+
+	public String getSku() {
+		return sku;
+	}
+
+	public void setSku(String sku) {
+		this.sku = sku;
+	}
+
+	public Set<ProductDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(Set<ProductDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+
+	public boolean getProductVirtual() {
+		return productVirtual;
+	}
+
+	public void setProductVirtual(boolean productVirtual) {
+		this.productVirtual = productVirtual;
+	}
+
+	public boolean getProductIsFree() {
+		return productIsFree;
+	}
+
+	public void setProductIsFree(boolean productIsFree) {
+		this.productIsFree = productIsFree;
+	}
+
+
+
+	public Set<ProductAttribute> getAttributes() {
+		return attributes;
+	}
+
+	public void setAttributes(Set<ProductAttribute> attributes) {
+		this.attributes = attributes;
+	}
+
+
+
+	public Manufacturer getManufacturer() {
+		return manufacturer;
+	}
+
+	public void setManufacturer(Manufacturer manufacturer) {
+		this.manufacturer = manufacturer;
+	}
+
+	public ProductType getType() {
+		return type;
+	}
+
+	public void setType(ProductType type) {
+		this.type = type;
+	}
+
+
+
+	public Set<ProductAvailability> getAvailabilities() {
+		return availabilities;
+	}
+
+	public void setAvailabilities(Set<ProductAvailability> availabilities) {
+		this.availabilities = availabilities;
+	}
+
+	public TaxClass getTaxClass() {
+		return taxClass;
+	}
+
+	public void setTaxClass(TaxClass taxClass) {
+		this.taxClass = taxClass;
+	}
+
+	public Set<ProductImage> getImages() {
+		return images;
+	}
+
+	public void setImages(Set<ProductImage> images) {
+		this.images = images;
+	}
+
+	public Set<ProductRelationship> getRelationships() {
+		return relationships;
+	}
+
+	public void setRelationships(Set<ProductRelationship> relationships) {
+		this.relationships = relationships;
+	}
+
+
+	public Set<Category> getCategories() {
+		return categories;
+	}
+
+	public void setCategories(Set<Category> categories) {
+		this.categories = categories;
+	}
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+
+
+	public Date getDateAvailable() {
+		return dateAvailable;
+	}
+
+	public void setDateAvailable(Date dateAvailable) {
+		this.dateAvailable = dateAvailable;
+	}
+
+	public void setSortOrder(Integer sortOrder) {
+		this.sortOrder = sortOrder;
+	}
+
+	public Integer getSortOrder() {
+		return sortOrder;
+	}
+
+
+
+	public void setAvailable(boolean available) {
+		this.available = available;
+	}
+
+	public boolean isAvailable() {
+		return available;
+	}
+	
+	public boolean isProductShipeable() {
+		return productShipeable;
+	}
+
+	public void setProductShipeable(boolean productShipeable) {
+		this.productShipeable = productShipeable;
+	}
+
+	
+	public ProductDescription getProductDescription() {
+		if(this.getDescriptions()!=null && this.getDescriptions().size()>0) {
+			return this.getDescriptions().iterator().next();
+		}
+		return null;
+	}
+	
+	public ProductImage getProductImage() {
+		ProductImage productImage = null;
+		if(this.getImages()!=null && this.getImages().size()>0) {
+			for(ProductImage image : this.getImages()) {
+				productImage = image;
+				if(productImage.isDefaultImage()) {
+					break;
+				}
+			}
+		}
+		return productImage;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/ProductCriteria.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/ProductCriteria.java
new file mode 100644
index 0000000..40b5ceb
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/ProductCriteria.java
@@ -0,0 +1,82 @@
+package com.salesmanager.core.business.catalog.product.model;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.attribute.AttributeCriteria;
+import com.salesmanager.core.business.common.model.Criteria;
+
+public class ProductCriteria extends Criteria {
+	
+	
+	private String productName;
+	private List<AttributeCriteria> attributeCriteria;
+
+	
+	private Boolean available = null;
+	
+	private List<Long> categoryIds;
+	private List<String> availabilities;
+	private List<Long> productIds;
+	
+	private Long manufacturerId = null;
+
+	public String getProductName() {
+		return productName;
+	}
+
+	public void setProductName(String productName) {
+		this.productName = productName;
+	}
+
+
+	public List<Long> getCategoryIds() {
+		return categoryIds;
+	}
+
+	public void setCategoryIds(List<Long> categoryIds) {
+		this.categoryIds = categoryIds;
+	}
+
+	public List<String> getAvailabilities() {
+		return availabilities;
+	}
+
+	public void setAvailabilities(List<String> availabilities) {
+		this.availabilities = availabilities;
+	}
+
+	public Boolean getAvailable() {
+		return available;
+	}
+
+	public void setAvailable(Boolean available) {
+		this.available = available;
+	}
+
+	public void setAttributeCriteria(List<AttributeCriteria> attributeCriteria) {
+		this.attributeCriteria = attributeCriteria;
+	}
+
+	public List<AttributeCriteria> getAttributeCriteria() {
+		return attributeCriteria;
+	}
+
+	public void setProductIds(List<Long> productIds) {
+		this.productIds = productIds;
+	}
+
+	public List<Long> getProductIds() {
+		return productIds;
+	}
+
+	public void setManufacturerId(Long manufacturerId) {
+		this.manufacturerId = manufacturerId;
+	}
+
+	public Long getManufacturerId() {
+		return manufacturerId;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/ProductList.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/ProductList.java
new file mode 100644
index 0000000..5c6754c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/ProductList.java
@@ -0,0 +1,25 @@
+package com.salesmanager.core.business.catalog.product.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.salesmanager.core.business.common.model.EntityList;
+
+public class ProductList extends EntityList {
+	
+
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 7267292601646149482L;
+	private List<Product> products = new ArrayList<Product>();
+	public List<Product> getProducts() {
+		return products;
+	}
+	public void setProducts(List<Product> products) {
+		this.products = products;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/relationship/ProductRelationship.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/relationship/ProductRelationship.java
new file mode 100644
index 0000000..f91fd0d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/relationship/ProductRelationship.java
@@ -0,0 +1,121 @@
+package com.salesmanager.core.business.catalog.product.model.relationship;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name = "PRODUCT_RELATIONSHIP", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class ProductRelationship extends SalesManagerEntity<Long, ProductRelationship> implements Serializable {
+	private static final long serialVersionUID = -9045331138054246299L;
+	
+	@Id
+	@Column(name = "PRODUCT_RELATIONSHIP_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRODUCT_RELATION_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@ManyToOne(targetEntity = MerchantStore.class)
+	@JoinColumn(name="MERCHANT_ID",nullable=false)  
+	private MerchantStore store;
+	
+	@ManyToOne(targetEntity = Product.class)
+	@JoinColumn(name="PRODUCT_ID",updatable=false,nullable=true) 
+	private Product product = null;
+	
+	@ManyToOne(targetEntity = Product.class)
+	@JoinColumn(name="RELATED_PRODUCT_ID",updatable=false,nullable=true) 
+	private Product relatedProduct = null;
+	
+	@Column(name="CODE")
+	private String code;
+	
+	@Column(name="ACTIVE")
+	private boolean active = true;
+	
+	public Product getProduct() {
+		return product;
+	}
+
+
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+
+
+	public Product getRelatedProduct() {
+		return relatedProduct;
+	}
+
+
+
+	public void setRelatedProduct(Product relatedProduct) {
+		this.relatedProduct = relatedProduct;
+	}
+
+
+
+	public String getCode() {
+		return code;
+	}
+
+
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+
+
+	public boolean isActive() {
+		return active;
+	}
+
+
+
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+
+
+	public ProductRelationship() {
+	}
+
+
+
+	public MerchantStore getStore() {
+		return store;
+	}
+
+	public void setStore(MerchantStore store) {
+		this.store = store;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/relationship/ProductRelationshipType.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/relationship/ProductRelationshipType.java
new file mode 100755
index 0000000..60937e5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/relationship/ProductRelationshipType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.catalog.product.model.relationship;
+
+public enum ProductRelationshipType {
+	
+	FEATURED_ITEM, RELATED_ITEM, BUNDLED_ITEM
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/review/ProductReview.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/review/ProductReview.java
new file mode 100644
index 0000000..1601785
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/review/ProductReview.java
@@ -0,0 +1,150 @@
+package com.salesmanager.core.business.catalog.product.model.review;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "PRODUCT_REVIEW", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class ProductReview extends SalesManagerEntity<Long, ProductReview> implements Auditable {
+	private static final long serialVersionUID = -7509351278087554383L;
+
+	@Id
+	@Column(name = "PRODUCT_REVIEW_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+	pkColumnValue = "PRODUCT_REVIEW_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Embedded
+	private AuditSection audit = new AuditSection();
+	
+	@Column(name = "REVIEWS_RATING")
+	private Double reviewRating;
+	
+	@Column(name = "REVIEWS_READ")
+	private Long reviewRead;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name = "REVIEW_DATE")
+	private Date reviewDate;
+	
+	@Column(name = "STATUS")
+	private Integer status;
+
+	@ManyToOne
+	@JoinColumn(name="CUSTOMERS_ID")
+	private Customer customer;
+	
+	@OneToOne
+	@JoinColumn(name="PRODUCT_ID")
+	private Product product;
+
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "productReview")
+	private Set<ProductReviewDescription> descriptions = new HashSet<ProductReviewDescription>();
+	
+	public ProductReview() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Double getReviewRating() {
+		return reviewRating;
+	}
+
+	public void setReviewRating(Double reviewRating) {
+		this.reviewRating = reviewRating;
+	}
+
+	public Long getReviewRead() {
+		return reviewRead;
+	}
+
+	public void setReviewRead(Long reviewRead) {
+		this.reviewRead = reviewRead;
+	}
+
+	public Integer getStatus() {
+		return status;
+	}
+
+	public void setStatus(Integer status) {
+		this.status = status;
+	}
+
+	public Customer getCustomer() {
+		return customer;
+	}
+
+	public void setCustomer(Customer customer) {
+		this.customer = customer;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+	public Set<ProductReviewDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(Set<ProductReviewDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+	
+	@Override
+	public AuditSection getAuditSection() {
+		return audit;
+	}
+	
+	@Override
+	public void setAuditSection(AuditSection audit) {
+		this.audit = audit;
+	}
+	
+	public Date getReviewDate() {
+		return reviewDate;
+	}
+
+	public void setReviewDate(Date reviewDate) {
+		this.reviewDate = reviewDate;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/review/ProductReviewDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/review/ProductReviewDescription.java
new file mode 100644
index 0000000..4ba872b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/review/ProductReviewDescription.java
@@ -0,0 +1,56 @@
+/*
+ * 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.business.catalog.product.model.review;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name = "PRODUCT_REVIEW_DESCRIPTION", schema = SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints={
+	@UniqueConstraint(columnNames={
+		"PRODUCT_REVIEW_ID",
+		"LANGUAGE_ID"
+	})
+})
+public class ProductReviewDescription extends Description {
+	private static final long serialVersionUID = -1957502640742695406L;
+
+	@ManyToOne(targetEntity = ProductReview.class)
+	@JoinColumn(name="PRODUCT_REVIEW_ID")
+	private ProductReview productReview;
+
+	public ProductReviewDescription() {
+	}
+
+	public ProductReviewDescription(Language language, String name) {
+		this.setLanguage(language);
+		this.setName(name);
+	}
+
+	public ProductReview getProductReview() {
+		return productReview;
+	}
+
+	public void setProductReview(ProductReview productReview) {
+		this.productReview = productReview;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/type/ProductType.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/type/ProductType.java
new file mode 100644
index 0000000..018b824
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/model/type/ProductType.java
@@ -0,0 +1,84 @@
+package com.salesmanager.core.business.catalog.product.model.type;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "PRODUCT_TYPE", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class ProductType extends SalesManagerEntity<Long, ProductType> implements Auditable {
+	private static final long serialVersionUID = 65541494628227593L;
+	
+	public final static String GENERAL_TYPE = "GENERAL";
+	
+	@Id
+	@Column(name = "PRODUCT_TYPE_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PRD_TYPE_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@Column(name = "PRD_TYPE_CODE")
+	private String code;
+	
+	@Column(name = "PRD_TYPE_ADD_TO_CART")
+	private Boolean allowAddToCart;
+	
+	public ProductType() {
+	}
+	
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	public boolean isAllowAddToCart() {
+		return allowAddToCart;
+	}
+
+	public void setAllowAddToCart(boolean allowAddToCart) {
+		this.allowAddToCart = allowAddToCart;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductAttributeService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductAttributeService.java
new file mode 100644
index 0000000..4e492d6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductAttributeService.java
@@ -0,0 +1,29 @@
+package com.salesmanager.core.business.catalog.product.service.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductAttributeService extends
+		SalesManagerEntityService<Long, ProductAttribute> {
+
+	void saveOrUpdate(ProductAttribute productAttribute)
+			throws ServiceException;
+	
+	List<ProductAttribute> getByOptionId(MerchantStore store,
+			Long id) throws ServiceException;
+
+	List<ProductAttribute> getByOptionValueId(MerchantStore store,
+			Long id) throws ServiceException;
+
+	List<ProductAttribute> getByProductId(MerchantStore store, Product product, Language language)
+			throws ServiceException;
+
+	List<ProductAttribute> getByAttributeIds(MerchantStore store, List<Long> ids)
+			throws ServiceException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductAttributeServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductAttributeServiceImpl.java
new file mode 100644
index 0000000..ebf245e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductAttributeServiceImpl.java
@@ -0,0 +1,92 @@
+package com.salesmanager.core.business.catalog.product.service.attribute;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.dao.attribute.ProductAttributeDao;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Service("productAttributeService")
+public class ProductAttributeServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, ProductAttribute> implements ProductAttributeService {
+	
+	private ProductAttributeDao productAttributeDao;
+
+	@Autowired
+	public ProductAttributeServiceImpl(ProductAttributeDao productAttributeDao) {
+		super(productAttributeDao);
+		this.productAttributeDao = productAttributeDao;
+	}
+	
+	@Override
+	public ProductAttribute getById(Long id) {
+		
+		return productAttributeDao.getById(id);
+		
+	}
+	
+	
+	@Override
+	public List<ProductAttribute> getByOptionId(MerchantStore store,
+			Long id) throws ServiceException {
+		
+		return productAttributeDao.getByOptionId(store, id);
+		
+	}
+	
+	@Override
+	public List<ProductAttribute> getByAttributeIds(MerchantStore store,
+			List<Long> ids) throws ServiceException {
+		
+		return productAttributeDao.getByAttributeIds(store, ids);
+		
+	}
+	
+	@Override
+	public List<ProductAttribute> getByOptionValueId(MerchantStore store,
+			Long id) throws ServiceException {
+		
+		return productAttributeDao.getByOptionValueId(store, id);
+		
+	}
+	
+	/**
+	 * Returns all product attributes
+	 */
+	@Override
+	public List<ProductAttribute> getByProductId(MerchantStore store,
+			Product product, Language language) throws ServiceException {
+		return productAttributeDao.getByProduct(store, product, language);
+		
+	}
+
+
+	@Override
+	public void saveOrUpdate(ProductAttribute productAttribute)
+			throws ServiceException {
+		if(productAttribute.getId()!=null && productAttribute.getId()>0) {
+			productAttributeDao.update(productAttribute);
+		} else {
+			productAttributeDao.save(productAttribute);
+		}
+		
+	}
+	
+	@Override
+	public void delete(ProductAttribute attribute) throws ServiceException {
+		
+		//override method, this allows the error that we try to remove a detached instance
+		attribute = this.getById(attribute.getId());
+		super.delete(attribute);
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionService.java
new file mode 100644
index 0000000..a0f709c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionService.java
@@ -0,0 +1,32 @@
+package com.salesmanager.core.business.catalog.product.service.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductOptionService extends SalesManagerEntityService<Long, ProductOption> {
+
+	List<ProductOption> listByStore(MerchantStore store, Language language)
+			throws ServiceException;
+
+
+	List<ProductOption> getByName(MerchantStore store, String name,
+			Language language) throws ServiceException;
+
+	void saveOrUpdate(ProductOption entity) throws ServiceException;
+
+
+	List<ProductOption> listReadOnly(MerchantStore store, Language language)
+			throws ServiceException;
+
+
+	ProductOption getByCode(MerchantStore store, String optionCode);
+	
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionServiceImpl.java
new file mode 100644
index 0000000..4fe12d7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionServiceImpl.java
@@ -0,0 +1,105 @@
+package com.salesmanager.core.business.catalog.product.service.attribute;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.dao.attribute.ProductOptionDao;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Service("productOptionService")
+public class ProductOptionServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, ProductOption> implements ProductOptionService {
+
+	
+	private ProductOptionDao productOptionDao;
+	
+	@Autowired
+	private ProductAttributeService productAttributeService;
+	
+	@Autowired
+	public ProductOptionServiceImpl(
+			ProductOptionDao productOptionDao) {
+			super(productOptionDao);
+			this.productOptionDao = productOptionDao;
+	}
+	
+	@Override
+	public List<ProductOption> listByStore(MerchantStore store, Language language) throws ServiceException {
+		
+		
+		return productOptionDao.listByStore(store, language);
+		
+		
+	}
+	
+	@Override
+	public List<ProductOption> listReadOnly(MerchantStore store, Language language) throws ServiceException {
+
+		return productOptionDao.getReadOnly(store, language);
+		
+		
+	}
+	
+
+	
+	@Override
+	public List<ProductOption> getByName(MerchantStore store, String name, Language language) throws ServiceException {
+		
+		try {
+			return productOptionDao.getByName(store, name, language);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+		
+	}
+	
+	@Override
+	public void saveOrUpdate(ProductOption entity) throws ServiceException {
+		
+		
+		//save or update (persist and attach entities
+		if(entity.getId()!=null && entity.getId()>0) {
+			super.update(entity);
+		} else {
+			super.save(entity);
+		}
+		
+	}
+	
+	@Override
+	public void delete(ProductOption entity) throws ServiceException {
+		
+		//remove all attributes having this option
+		List<ProductAttribute> attributes = productAttributeService.getByOptionId(entity.getMerchantStore(), entity.getId());
+		
+		for(ProductAttribute attribute : attributes) {
+			productAttributeService.delete(attribute);
+		}
+		
+		ProductOption option = this.getById(entity.getId());
+		
+		//remove option
+		super.delete(option);
+		
+	}
+	
+	@Override
+	public ProductOption getByCode(MerchantStore store, String optionCode) {
+		return productOptionDao.getByCode(store, optionCode);
+	}
+	
+
+	
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionValueService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionValueService.java
new file mode 100644
index 0000000..4a2854d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionValueService.java
@@ -0,0 +1,29 @@
+package com.salesmanager.core.business.catalog.product.service.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductOptionValueService extends SalesManagerEntityService<Long, ProductOptionValue> {
+
+	void saveOrUpdate(ProductOptionValue entity) throws ServiceException;
+
+	List<ProductOptionValue> getByName(MerchantStore store, String name,
+			Language language) throws ServiceException;
+
+	ProductOptionValue getById(MerchantStore store, Long id)
+			throws ServiceException;
+
+	List<ProductOptionValue> listByStore(MerchantStore store, Language language)
+			throws ServiceException;
+
+	List<ProductOptionValue> listByStoreNoReadOnly(MerchantStore store,
+			Language language) throws ServiceException;
+
+	ProductOptionValue getByCode(MerchantStore store, String optionValueCode);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionValueServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionValueServiceImpl.java
new file mode 100644
index 0000000..1830556
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/attribute/ProductOptionValueServiceImpl.java
@@ -0,0 +1,110 @@
+package com.salesmanager.core.business.catalog.product.service.attribute;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.dao.attribute.ProductOptionValueDao;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Service("productOptionValueService")
+public class ProductOptionValueServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, ProductOptionValue> implements
+		ProductOptionValueService {
+
+	@Autowired
+	private ProductAttributeService productAttributeService;
+	
+	private ProductOptionValueDao productOptionValueDao;
+	
+	@Autowired
+	public ProductOptionValueServiceImpl(
+			ProductOptionValueDao productOptionValueDao) {
+			super(productOptionValueDao);
+			this.productOptionValueDao = productOptionValueDao;
+	}
+	
+	
+	@Override
+	public List<ProductOptionValue> listByStore(MerchantStore store, Language language) throws ServiceException {
+		
+		return productOptionValueDao.listByStore(store, language);
+	}
+	
+	@Override
+	public List<ProductOptionValue> listByStoreNoReadOnly(MerchantStore store, Language language) throws ServiceException {
+		
+		return productOptionValueDao.listByStoreNoReadOnly(store, language);
+	}
+	
+	@Override
+	public ProductOptionValue getById(MerchantStore store, Long id) throws ServiceException {
+		
+		try {
+			return productOptionValueDao.getById(store, id);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+	@Override
+	public List<ProductOptionValue> getByName(MerchantStore store, String name, Language language) throws ServiceException {
+		
+		try {
+			return productOptionValueDao.getByName(store, name, language);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+		
+	}
+	
+	@Override
+	public void saveOrUpdate(ProductOptionValue entity) throws ServiceException {
+		
+		
+		//save or update (persist and attach entities
+		if(entity.getId()!=null && entity.getId()>0) {
+
+			super.update(entity);
+			
+		} else {
+			
+			super.save(entity);
+			
+		}
+		
+	}
+	
+	
+	public void delete(ProductOptionValue entity) throws ServiceException {
+		
+		//remove all attributes having this option
+		List<ProductAttribute> attributes = productAttributeService.getByOptionValueId(entity.getMerchantStore(), entity.getId());
+		
+		for(ProductAttribute attribute : attributes) {
+			productAttributeService.delete(attribute);
+		}
+		
+		ProductOptionValue option = this.getById(entity.getMerchantStore(), entity.getId());
+		
+		//remove option
+		super.delete(option);
+		
+	}
+	
+	@Override
+	public ProductOptionValue getByCode(MerchantStore store, String optionValueCode) {
+		return productOptionValueDao.getByCode(store, optionValueCode);
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/availability/ProductAvailabilityService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/availability/ProductAvailabilityService.java
new file mode 100644
index 0000000..cf9dbeb
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/availability/ProductAvailabilityService.java
@@ -0,0 +1,12 @@
+package com.salesmanager.core.business.catalog.product.service.availability;
+
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+
+public interface ProductAvailabilityService extends
+		SalesManagerEntityService<Long, ProductAvailability> {
+
+	void saveOrUpdate(ProductAvailability availability) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/availability/ProductAvailabilityServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/availability/ProductAvailabilityServiceImpl.java
new file mode 100644
index 0000000..7d693fd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/availability/ProductAvailabilityServiceImpl.java
@@ -0,0 +1,42 @@
+package com.salesmanager.core.business.catalog.product.service.availability;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.dao.availability.ProductAvailabilityDao;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+
+@Service("productAvailabilityService")
+public class ProductAvailabilityServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, ProductAvailability> implements
+		ProductAvailabilityService {
+
+	
+	private ProductAvailabilityDao productAvailabilityDao;
+	
+	@Autowired
+	public ProductAvailabilityServiceImpl(
+			ProductAvailabilityDao productAvailabilityDao) {
+			super(productAvailabilityDao);
+			this.productAvailabilityDao = productAvailabilityDao;
+	}
+	
+	
+	@Override
+	public void saveOrUpdate(ProductAvailability availability) throws ServiceException {
+		
+		if(availability.getId()!=null && availability.getId()>0) {
+			
+			this.update(availability);
+			
+		} else {
+			this.create(availability);
+		}
+		
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/file/DigitalProductService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/file/DigitalProductService.java
new file mode 100644
index 0000000..5deb29b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/file/DigitalProductService.java
@@ -0,0 +1,24 @@
+package com.salesmanager.core.business.catalog.product.service.file;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.file.DigitalProduct;
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+
+public interface DigitalProductService extends SalesManagerEntityService<Long, DigitalProduct> {
+
+	void saveOrUpdate(DigitalProduct digitalProduct) throws ServiceException;
+
+	void addProductFile(Product product, DigitalProduct digitalProduct,
+			InputContentFile inputFile) throws ServiceException;
+
+
+
+	DigitalProduct getByProduct(MerchantStore store, Product product)
+			throws ServiceException;
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/file/DigitalProductServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/file/DigitalProductServiceImpl.java
new file mode 100644
index 0000000..684bc6c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/file/DigitalProductServiceImpl.java
@@ -0,0 +1,110 @@
+package com.salesmanager.core.business.catalog.product.service.file;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import com.salesmanager.core.business.catalog.product.dao.file.DigitalProductDao;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.file.DigitalProduct;
+import com.salesmanager.core.business.catalog.product.service.ProductService;
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.modules.cms.content.StaticContentFileManager;
+
+@Service("digitalProductService")
+public class DigitalProductServiceImpl extends SalesManagerEntityServiceImpl<Long, DigitalProduct> 
+	implements DigitalProductService {
+	
+
+	private DigitalProductDao digitalProductDao;
+	
+    @Autowired
+    StaticContentFileManager productDownloadsFileManager;
+    
+    @Autowired
+    ProductService productService;
+
+	@Autowired
+	public DigitalProductServiceImpl(DigitalProductDao digitalProductDao) {
+		super(digitalProductDao);
+		this.digitalProductDao = digitalProductDao;
+	}
+	
+	@Override
+	public void addProductFile(Product product, DigitalProduct digitalProduct, InputContentFile inputFile) throws ServiceException {
+	
+		Assert.notNull(digitalProduct,"DigitalProduct cannot be null");
+		Assert.notNull(product,"Product cannot be null");
+		digitalProduct.setProduct(product);
+
+		try {
+			
+			Assert.notNull(inputFile.getFile(),"InputContentFile.file cannot be null");
+			
+			Assert.notNull(product.getMerchantStore(),"Product.merchantStore cannot be null");
+			this.saveOrUpdate(digitalProduct);
+			
+			productDownloadsFileManager.addFile(product.getMerchantStore().getCode(), inputFile);
+			
+			product.setProductVirtual(true);
+			productService.update(product);
+		
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		} finally {
+			try {
+
+				if(inputFile.getFile()!=null) {
+					inputFile.getFile().close();
+				}
+
+			} catch(Exception ignore) {}
+		}
+		
+		
+	}
+	
+	@Override
+	public DigitalProduct getByProduct(MerchantStore store, Product product) throws ServiceException {
+		return digitalProductDao.getByProduct(store, product);
+	}
+	
+	@Override
+	public void delete(DigitalProduct digitalProduct) throws ServiceException {
+		
+		Assert.notNull(digitalProduct,"DigitalProduct cannot be null");
+		Assert.notNull(digitalProduct.getProduct(),"DigitalProduct.product cannot be null");
+		//refresh file
+		digitalProduct = this.getById(digitalProduct.getId());
+		super.delete(digitalProduct);
+		productDownloadsFileManager.removeFile(digitalProduct.getProduct().getMerchantStore().getCode(), FileContentType.PRODUCT, digitalProduct.getProductFileName());
+		digitalProduct.getProduct().setProductVirtual(false);
+		productService.update(digitalProduct.getProduct());
+	}
+	
+	
+	@Override
+	public void saveOrUpdate(DigitalProduct digitalProduct) throws ServiceException {
+		
+		Assert.notNull(digitalProduct,"DigitalProduct cannot be null");
+		Assert.notNull(digitalProduct.getProduct(),"DigitalProduct.product cannot be null");
+		if(digitalProduct.getId()==null || digitalProduct.getId().longValue()==0) {
+			super.save(digitalProduct);
+		} else {
+			super.create(digitalProduct);
+		}
+		
+		digitalProduct.getProduct().setProductVirtual(true);
+		productService.update(digitalProduct.getProduct());
+		
+		
+	}
+	
+
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/image/ProductImageService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/image/ProductImageService.java
new file mode 100644
index 0000000..877f831
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/image/ProductImageService.java
@@ -0,0 +1,66 @@
+package com.salesmanager.core.business.catalog.product.service.image;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.file.ProductImageSize;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.content.model.ImageContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+
+
+public interface ProductImageService extends SalesManagerEntityService<Long, ProductImage> {
+	
+	
+	
+	/**
+	 * Add a ProductImage to the persistence and an entry to the CMS
+	 * @param product
+	 * @param productImage
+	 * @param file
+	 * @throws ServiceException
+	 */
+	void addProductImage(Product product, ProductImage productImage, ImageContentFile inputImage)
+			throws ServiceException;
+
+	/**
+	 * Get the image ByteArrayOutputStream and content description from CMS
+	 * @param productImage
+	 * @return
+	 * @throws ServiceException
+	 */
+	OutputContentFile getProductImage(ProductImage productImage, ProductImageSize size)
+			throws ServiceException;
+
+	/**
+	 * Returns all Images for a given product
+	 * @param product
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<OutputContentFile> getProductImages(Product product)
+			throws ServiceException;
+
+	void removeProductImage(ProductImage productImage) throws ServiceException;
+
+	void saveOrUpdate(ProductImage productImage) throws ServiceException;
+
+	/**
+	 * Returns an image file from required identifier. This method is
+	 * used by the image servlet
+	 * @param store
+	 * @param product
+	 * @param fileName
+	 * @param size
+	 * @return
+	 * @throws ServiceException
+	 */
+	OutputContentFile getProductImage(String storeCode, String productCode,
+			String fileName, final ProductImageSize size) throws ServiceException;
+
+	void addProductImages(Product product, List<ProductImage> productImages)
+			throws ServiceException;
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/image/ProductImageServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/image/ProductImageServiceImpl.java
new file mode 100644
index 0000000..9b29ef7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/image/ProductImageServiceImpl.java
@@ -0,0 +1,206 @@
+package com.salesmanager.core.business.catalog.product.service.image;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import com.salesmanager.core.business.catalog.product.dao.image.ProductImageDao;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.file.ProductImageSize;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImageDescription;
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.ImageContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.modules.cms.product.ProductFileManager;
+
+@Service("productImage")
+public class ProductImageServiceImpl extends SalesManagerEntityServiceImpl<Long, ProductImage> 
+	implements ProductImageService {
+	
+	private ProductImageDao productImageDao;
+
+	@Autowired
+	public ProductImageServiceImpl(ProductImageDao productImageDao) {
+		super(productImageDao);
+		this.productImageDao = productImageDao;
+	}
+	
+	@Autowired
+	private ProductFileManager productFileManager;
+	
+
+	
+	
+	public ProductImage getById(Long id) {
+		
+		
+		return productImageDao.getProductImageById(id);
+	}
+	
+	
+	@Override
+	public void addProductImages(Product product, List<ProductImage> productImages) throws ServiceException {
+		
+		try {
+			for(ProductImage productImage : productImages) {
+				
+				Assert.notNull(productImage.getImage());
+				
+		        InputStream inputStream = productImage.getImage();
+		        ImageContentFile cmsContentImage = new ImageContentFile();
+		        cmsContentImage.setFileName( productImage.getProductImage() );
+		        cmsContentImage.setFile( inputStream );
+		        cmsContentImage.setFileContentType(FileContentType.PRODUCT);
+		        
+
+		        
+	
+				addProductImage(product,productImage,cmsContentImage);			
+			}
+		
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+
+	}
+	
+	
+	@Override
+	public void addProductImage(Product product, ProductImage productImage, ImageContentFile inputImage) throws ServiceException {
+		
+		
+		
+		
+		productImage.setProduct(product);
+
+		try {
+			
+			Assert.notNull(inputImage.getFile(),"ImageContentFile.file cannot be null");
+
+
+			
+			productFileManager.addProductImage(productImage, inputImage);
+	
+			//insert ProductImage
+			this.saveOrUpdate(productImage);
+			
+
+		
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		} finally {
+			try {
+				
+				//if(inputImage.getBufferedImage()!=null){
+				//	inputImage.getBufferedImage().flush();
+				//}
+				
+				if(inputImage.getFile()!=null) {
+					inputImage.getFile().close();
+				}
+
+			} catch(Exception ignore) {
+				
+			}
+		}
+		
+		
+	}
+	
+	@Override
+	public void saveOrUpdate(ProductImage productImage) throws ServiceException {
+		
+		
+		//save or update (persist and attach entities
+		if(productImage.getId()!=null && productImage.getId()>0) {
+
+			super.update(productImage);
+			
+		} else {
+			
+			List<ProductImageDescription> descriptions = productImage.getDescriptions();
+			productImage.setDescriptions(null);
+			super.save(productImage);
+			
+			if(descriptions!=null && descriptions.size()>0) {
+				for(ProductImageDescription description : descriptions) {
+					this.addProductImageDescription(productImage, description);
+				}
+			}
+			
+		}
+		
+	}
+	
+	public void addProductImageDescription(ProductImage productImage, ProductImageDescription description)
+	throws ServiceException {
+
+		
+			if(productImage.getDescriptions()==null) {
+				productImage.setDescriptions(new ArrayList<ProductImageDescription>());
+			}
+			
+			productImage.getDescriptions().add(description);
+			description.setProductImage(productImage);
+			update(productImage);
+
+
+	}
+	
+	//TODO get default product image
+
+	
+	@Override
+	public OutputContentFile getProductImage(ProductImage productImage, ProductImageSize size) throws ServiceException {
+
+		
+		ProductImage pi = new ProductImage();
+		String imageName = productImage.getProductImage();
+		if(size == ProductImageSize.LARGE) {
+			imageName = "L-" + imageName;
+		}
+		
+		if(size == ProductImageSize.SMALL) {
+			imageName = "S-" + imageName;
+		}
+		
+		pi.setProductImage(imageName);
+		pi.setProduct(productImage.getProduct());
+		
+		OutputContentFile outputImage = productFileManager.getProductImage(pi);
+		
+		return outputImage;
+		
+	}
+	
+	@Override
+	public OutputContentFile getProductImage(final String storeCode, final String productCode, final String fileName, final ProductImageSize size) throws ServiceException {
+		OutputContentFile outputImage = productFileManager.getProductImage(storeCode, productCode, fileName, size);
+		return outputImage;
+		
+	}
+	
+	@Override
+	public List<OutputContentFile> getProductImages(Product product) throws ServiceException {
+		return productFileManager.getImages(product);
+	}
+	
+	@Override
+	public void removeProductImage(ProductImage productImage) throws ServiceException {
+
+		productFileManager.removeProductImage(productImage);
+		
+		ProductImage p = this.getById(productImage.getId());
+		
+		
+		this.delete(p);
+		
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/manufacturer/ManufacturerService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/manufacturer/ManufacturerService.java
new file mode 100644
index 0000000..be7c120
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/manufacturer/ManufacturerService.java
@@ -0,0 +1,38 @@
+package com.salesmanager.core.business.catalog.product.service.manufacturer;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ManufacturerService extends SalesManagerEntityService<Long, Manufacturer> {
+
+	List<Manufacturer> listByStore(MerchantStore store, Language language)
+			throws ServiceException;
+
+	List<Manufacturer> listByStore(MerchantStore store) throws ServiceException;
+
+	void saveOrUpdate(Manufacturer manufacturer) throws ServiceException;
+	
+	void addManufacturerDescription(Manufacturer manufacturer, ManufacturerDescription description) throws ServiceException;
+	
+	int getCountManufAttachedProducts( Manufacturer manufacturer )  throws ServiceException;
+	
+	void delete(Manufacturer manufacturer) throws ServiceException;
+
+	/**
+	 * List manufacturers by products from a given list of categories
+	 * @param store
+	 * @param ids
+	 * @param language
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<Manufacturer> listByProductsByCategoriesId(MerchantStore store,
+			List<Long> ids, Language language) throws ServiceException;
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/manufacturer/ManufacturerServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/manufacturer/ManufacturerServiceImpl.java
new file mode 100644
index 0000000..77a1905
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/manufacturer/ManufacturerServiceImpl.java
@@ -0,0 +1,98 @@
+package com.salesmanager.core.business.catalog.product.service.manufacturer;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.dao.manufacturer.ManufacturerDao;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.service.CustomerServiceImpl;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.search.service.SearchService;
+
+
+
+@Service("manufacturerService")
+public class ManufacturerServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, Manufacturer> implements ManufacturerService {
+
+	@Autowired
+	SearchService searchService;
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ManufacturerServiceImpl.class);
+	private ManufacturerDao manufacturerDao;
+	
+	@Autowired
+	public ManufacturerServiceImpl(
+		ManufacturerDao manufacturerDao) {
+		super(manufacturerDao);
+		this.manufacturerDao = manufacturerDao;		
+	}
+	
+	@Override 
+	public void delete(Manufacturer manufacturer) throws ServiceException{
+		manufacturer =  this.getById(manufacturer.getId() );
+		super.delete( manufacturer );
+	}
+	
+	@Override
+	public int getCountManufAttachedProducts( Manufacturer manufacturer ) throws ServiceException {
+		return manufacturerDao.getCountManufAttachedProducts( manufacturer );
+	}
+	
+	
+	@Override
+	public List<Manufacturer> listByStore(MerchantStore store, Language language) throws ServiceException {
+		return manufacturerDao.listByStore(store, language);
+	}
+	
+	@Override
+	public List<Manufacturer> listByStore(MerchantStore store) throws ServiceException {
+		return manufacturerDao.listByStore(store);
+	}
+	
+	@Override
+	public List<Manufacturer> listByProductsByCategoriesId(MerchantStore store, List<Long> ids, Language language) throws ServiceException {
+		return manufacturerDao.listByProductsByCategoriesId(store, ids, language);
+	}
+
+	@Override
+	public void addManufacturerDescription(Manufacturer manufacturer, ManufacturerDescription description)
+			throws ServiceException {
+		
+		
+		if(manufacturer.getDescriptions()==null) {
+			manufacturer.setDescriptions(new HashSet<ManufacturerDescription>());
+		}
+		
+		manufacturer.getDescriptions().add(description);
+		description.setManufacturer(manufacturer);
+		update(manufacturer);
+	}
+	
+	@Override	
+	public void saveOrUpdate(Manufacturer manufacturer) throws ServiceException {
+
+		LOGGER.debug("Creating Manufacturer");
+		
+		if(manufacturer.getId()!=null && manufacturer.getId()>0) {
+		   super.update(manufacturer);  
+			
+		} else {						
+		   super.create(manufacturer);
+
+		}
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/price/ProductPriceService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/price/ProductPriceService.java
new file mode 100644
index 0000000..ff00729
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/price/ProductPriceService.java
@@ -0,0 +1,15 @@
+package com.salesmanager.core.business.catalog.product.service.price;
+
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+
+public interface ProductPriceService extends SalesManagerEntityService<Long, ProductPrice> {
+
+	void addDescription(ProductPrice price, ProductPriceDescription description) throws ServiceException;
+
+	void saveOrUpdate(ProductPrice price) throws ServiceException;
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/price/ProductPriceServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/price/ProductPriceServiceImpl.java
new file mode 100644
index 0000000..5752204
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/price/ProductPriceServiceImpl.java
@@ -0,0 +1,65 @@
+package com.salesmanager.core.business.catalog.product.service.price;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.dao.price.ProductPriceDao;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+
+@Service("productPrice")
+public class ProductPriceServiceImpl extends SalesManagerEntityServiceImpl<Long, ProductPrice> 
+	implements ProductPriceService {
+
+	@Autowired
+	public ProductPriceServiceImpl(ProductPriceDao productPriceDao) {
+		super(productPriceDao);
+	}
+
+	@Override
+	public void addDescription(ProductPrice price,
+			ProductPriceDescription description) throws ServiceException {
+		price.getDescriptions().add(description);
+		//description.setPrice(price);
+		update(price);
+	}
+	
+	
+	@Override
+	public void saveOrUpdate(ProductPrice price) throws ServiceException {
+		
+		if(price.getId()!=null && price.getId()>0) {
+			this.update(price);
+		} else {
+			
+			Set<ProductPriceDescription> descriptions = price.getDescriptions();
+			price.setDescriptions(new HashSet<ProductPriceDescription>());
+			this.create(price);
+			for(ProductPriceDescription description : descriptions) {
+				description.setProductPrice(price);
+				this.addDescription(price, description);
+			}
+			
+		}
+		
+		
+		
+	}
+	
+	@Override
+	public void delete(ProductPrice price) throws ServiceException {
+		
+		//override method, this allows the error that we try to remove a detached instance
+		price = this.getById(price.getId());
+		super.delete(price);
+		
+	}
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/PricingService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/PricingService.java
new file mode 100644
index 0000000..8a5ff43
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/PricingService.java
@@ -0,0 +1,102 @@
+package com.salesmanager.core.business.catalog.product.service;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Locale;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+
+
+/**
+ * Services for Product item price calculation. 
+ * @author Carl Samson
+ *
+ */
+public interface PricingService {
+
+	/**
+	 * Calculates the FinalPrice of a Product taking into account
+	 * all defined prices and possible rebates
+	 * @param product
+	 * @return
+	 * @throws ServiceException
+	 */
+	FinalPrice calculateProductPrice(Product product) throws ServiceException;
+
+	/**
+	 * Calculates the FinalPrice of a Product taking into account
+	 * all defined prices and possible rebates. It also applies other calculation
+	 * based on the customer
+	 * @param product
+	 * @param customer
+	 * @return
+	 * @throws ServiceException
+	 */
+	FinalPrice calculateProductPrice(Product product, Customer customer)
+			throws ServiceException;
+
+	/**
+	 * Calculates the FinalPrice of a Product taking into account
+	 * all defined prices and possible rebates. This method should be used to calculate
+	 * any additional prices based on the default attributes or based on the user selected attributes.
+	 * @param product
+	 * @param attributes
+	 * @return
+	 * @throws ServiceException
+	 */
+	FinalPrice calculateProductPrice(Product product,
+			List<ProductAttribute> attributes) throws ServiceException;
+
+	/**
+	 * Calculates the FinalPrice of a Product taking into account
+	 * all defined prices and possible rebates. This method should be used to calculate
+	 * any additional prices based on the default attributes or based on the user selected attributes.
+	 * It also applies other calculation based on the customer
+	 * @param product
+	 * @param attributes
+	 * @param customer
+	 * @return
+	 * @throws ServiceException
+	 */
+	FinalPrice calculateProductPrice(Product product,
+			List<ProductAttribute> attributes, Customer customer)
+			throws ServiceException;
+
+	/**
+	 * Method to be used to print a displayable formated amount to the end user
+	 * @param amount
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	String getDisplayAmount(BigDecimal amount, MerchantStore store)
+			throws ServiceException;
+	
+	/**
+	 * Method to be used when building an amount formatted with the appropriate currency
+	 * @param amount
+	 * @param locale
+	 * @param currency
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	String getDisplayAmount(BigDecimal amount, Locale locale, Currency currency, MerchantStore store)
+			throws ServiceException;
+	
+	/**
+	 * String format of the money amount without currency symbol
+	 * @param amount
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	String getStringAmount(BigDecimal amount, MerchantStore store)
+			throws ServiceException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/PricingServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/PricingServiceImpl.java
new file mode 100644
index 0000000..af8c787
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/PricingServiceImpl.java
@@ -0,0 +1,94 @@
+package com.salesmanager.core.business.catalog.product.service;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Locale;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.utils.ProductPriceUtils;
+
+/**
+ * Contains all the logic required to calculate product price
+ * @author Carl Samson
+ *
+ */
+@Service("pricingService")
+public class PricingServiceImpl implements PricingService {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(PricingServiceImpl.class);
+	
+
+	@Autowired
+	private ProductPriceUtils priceUtil;
+	
+	@Override
+	public FinalPrice calculateProductPrice(Product product) throws ServiceException {
+		return priceUtil.getFinalPrice(product);
+	}
+	
+	@Override
+	public FinalPrice calculateProductPrice(Product product, Customer customer) throws ServiceException {
+		/** TODO add rules for price calculation **/
+		return priceUtil.getFinalPrice(product);
+	}
+	
+	@Override
+	public FinalPrice calculateProductPrice(Product product, List<ProductAttribute> attributes) throws ServiceException {
+		return priceUtil.getFinalProductPrice(product, attributes);
+	}
+	
+	@Override
+	public FinalPrice calculateProductPrice(Product product, List<ProductAttribute> attributes, Customer customer) throws ServiceException {
+		/** TODO add rules for price calculation **/
+		return priceUtil.getFinalProductPrice(product, attributes);
+	}
+
+	@Override
+	public String getDisplayAmount(BigDecimal amount, MerchantStore store) throws ServiceException {
+		try {
+			String price= priceUtil.getStoreFormatedAmountWithCurrency(store,amount);
+			return price;
+		} catch (Exception e) {
+			LOGGER.error("An error occured when trying to format an amount " + amount.toString());
+			throw new ServiceException(e);
+		}
+	}
+	
+	@Override
+	public String getDisplayAmount(BigDecimal amount, Locale locale,
+			Currency currency, MerchantStore store) throws ServiceException {
+		try {
+			String price= priceUtil.getFormatedAmountWithCurrency(locale, currency, amount);
+			return price;
+		} catch (Exception e) {
+			LOGGER.error("An error occured when trying to format an amunt " + amount.toString() + " using locale " + locale.toString() + " and currency " + currency.toString());
+			throw new ServiceException(e);
+		}
+	}
+
+	@Override
+	public String getStringAmount(BigDecimal amount, MerchantStore store)
+			throws ServiceException {
+		try {
+			String price = priceUtil.getAdminFormatedAmount(store, amount);
+			return price;
+		} catch (Exception e) {
+			LOGGER.error("An error occured when trying to format an amount " + amount.toString());
+			throw new ServiceException(e);
+		}
+	}
+
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/ProductService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/ProductService.java
new file mode 100644
index 0000000..f7f707f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/ProductService.java
@@ -0,0 +1,58 @@
+package com.salesmanager.core.business.catalog.product.service;
+
+import java.util.List;
+import java.util.Locale;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.ProductCriteria;
+import com.salesmanager.core.business.catalog.product.model.ProductList;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+
+
+
+public interface ProductService extends SalesManagerEntityService<Long, Product> {
+
+	void addProductDescription(Product product, ProductDescription description) throws ServiceException;
+	
+	ProductDescription getProductDescription(Product product, Language language);
+	
+	Product getProductForLocale(long productId, Language language, Locale locale) throws ServiceException;
+	
+	List<Product> getProductsForLocale(Category category, Language language, Locale locale) throws ServiceException;
+
+	List<Product> getProducts(List<Long> categoryIds) throws ServiceException;
+
+
+
+	ProductList listByStore(MerchantStore store, Language language,
+			ProductCriteria criteria);
+
+
+
+	void saveOrUpdate(Product product) throws ServiceException;
+
+	List<Product> listByStore(MerchantStore store);
+
+	List<Product> listByTaxClass(TaxClass taxClass);
+
+	List<Product> getProducts(List<Long> categoryIds, Language language)
+			throws ServiceException;
+
+	Product getBySeUrl(MerchantStore store, String seUrl, Locale locale);
+
+	/**
+	 * Get a product by sku (code) field  and the language
+	 * @param productCode
+	 * @param language
+	 * @return
+	 */
+	Product getByCode(String productCode, Language language);
+	
+}
+	
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/ProductServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/ProductServiceImpl.java
new file mode 100644
index 0000000..60cb6d5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/ProductServiceImpl.java
@@ -0,0 +1,401 @@
+package com.salesmanager.core.business.catalog.product.service;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import org.apache.commons.lang.Validate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.service.CategoryService;
+import com.salesmanager.core.business.catalog.common.CatalogServiceHelper;
+import com.salesmanager.core.business.catalog.product.dao.ProductDao;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.ProductCriteria;
+import com.salesmanager.core.business.catalog.product.model.ProductList;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationship;
+import com.salesmanager.core.business.catalog.product.service.attribute.ProductAttributeService;
+import com.salesmanager.core.business.catalog.product.service.availability.ProductAvailabilityService;
+import com.salesmanager.core.business.catalog.product.service.image.ProductImageService;
+import com.salesmanager.core.business.catalog.product.service.price.ProductPriceService;
+import com.salesmanager.core.business.catalog.product.service.relationship.ProductRelationshipService;
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.ImageContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.search.service.SearchService;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.utils.CoreConfiguration;
+
+@Service("productService")
+public class ProductServiceImpl extends SalesManagerEntityServiceImpl<Long, Product> implements ProductService {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImpl.class);
+	
+	ProductDao productDao;
+	
+	@Autowired
+	CategoryService categoryService;
+	
+	@Autowired
+	ProductAvailabilityService productAvailabilityService;
+	
+	@Autowired
+	ProductPriceService productPriceService;
+	
+	
+	@Autowired
+	ProductAttributeService productAttributeService;
+	
+	@Autowired
+	ProductRelationshipService productRelationshipService;
+	
+	@Autowired
+	SearchService searchService;
+	
+	@Autowired
+	ProductImageService productImageService;
+	
+	@Autowired
+	CoreConfiguration configuration;
+	
+	@Autowired
+	public ProductServiceImpl(ProductDao productDao) {
+		super(productDao);
+		this.productDao = productDao;
+	}
+
+	@Override
+	public void addProductDescription(Product product, ProductDescription description)
+			throws ServiceException {
+		
+		
+		if(product.getDescriptions()==null) {
+			product.setDescriptions(new HashSet<ProductDescription>());
+		}
+		
+		product.getDescriptions().add(description);
+		description.setProduct(product);
+		update(product);
+		searchService.index(product.getMerchantStore(), product);
+	}
+	
+	@Override
+	public List<Product> getProducts(List<Long> categoryIds) throws ServiceException {
+		
+		@SuppressWarnings({ "unchecked", "rawtypes" })
+		Set ids = new HashSet(categoryIds);
+		return productDao.getProductsListByCategories(ids);
+		
+	}
+	
+	@Override
+	public List<Product> getProducts(List<Long> categoryIds, Language language) throws ServiceException {
+		
+		@SuppressWarnings({ "unchecked", "rawtypes" })
+		Set<Long> ids = new HashSet(categoryIds);
+		return productDao.getProductsListByCategories(ids, language);
+		
+	}
+	
+	//@Override
+/*	public ProductList getProductList(ProductCriteria criteria, List<Long> categoryIds, Language language) throws ServiceException {
+		
+		@SuppressWarnings({ "unchecked", "rawtypes" })
+		Set<Long> ids = new HashSet(categoryIds);
+		return productDao.getProductListByCategories(criteria, ids, language);
+		
+	}*/
+
+	@Override
+	public ProductDescription getProductDescription(Product product, Language language) {
+		for (ProductDescription description : product.getDescriptions()) {
+			if (description.getLanguage().equals(language)) {
+				return description;
+			}
+		}
+		return null;
+	}
+	
+	@Override
+	public Product getBySeUrl(MerchantStore store, String seUrl, Locale locale) {
+		return productDao.getBySeUrl(store, seUrl, locale);
+	}
+
+	@Override
+	public Product getProductForLocale(long productId, Language language, Locale locale)
+			throws ServiceException {
+		Product product =  productDao.getProductForLocale(productId, language, locale);
+		
+
+		CatalogServiceHelper.setToAvailability(product, locale);
+		CatalogServiceHelper.setToLanguage(product, language.getId());
+		return product;
+	}
+
+	@Override
+	public List<Product> getProductsForLocale(Category category,
+			Language language, Locale locale) throws ServiceException {
+		
+		if(category==null) {
+			throw new ServiceException("The category is null");
+		}
+		
+		//Get the category list
+		StringBuilder lineage = new StringBuilder().append(category.getLineage()).append(category.getId()).append("/");
+		List<Category> categories = categoryService.listByLineage(category.getMerchantStore(),lineage.toString());
+		Set<Long> categoryIds = new HashSet<Long>();
+		for(Category c : categories) {
+			
+			categoryIds.add(c.getId());
+			
+		}
+		
+		categoryIds.add(category.getId());
+		
+		//Get products
+		List<Product> products = productDao.getProductsForLocale(category.getMerchantStore(), categoryIds, language, locale);
+		
+		//Filter availability
+		
+		return products;
+	}
+	
+	@Override
+	public ProductList listByStore(MerchantStore store,
+			Language language, ProductCriteria criteria) {
+		
+		return productDao.listByStore(store, language, criteria);
+	}
+	
+	@Override
+	public List<Product> listByStore(MerchantStore store) {
+		
+		return productDao.listByStore(store);
+	}
+	
+	@Override
+	public List<Product> listByTaxClass(TaxClass taxClass) {
+		return productDao.listByTaxClass(taxClass);
+	}
+	
+	@Override
+	public Product getByCode(String productCode, Language language) {
+		return productDao.getByCode(productCode, language);
+	}
+		
+
+
+	
+
+	@Override
+	public void delete(Product product) throws ServiceException {
+		LOGGER.debug("Deleting product");
+		Validate.notNull(product, "Product cannot be null");
+		Validate.notNull(product.getMerchantStore(), "MerchantStore cannot be null in product");
+		product = this.getById(product.getId());//Prevents detached entity error
+		product.setCategories(null);
+		
+		Set<ProductImage> images = product.getImages();
+		
+		for(ProductImage image : images) {
+			productImageService.removeProductImage(image);
+		}
+		
+		product.setImages(null);
+		
+		//related - featured
+		List<ProductRelationship> relationships = productRelationshipService.listByProduct(product);
+		for(ProductRelationship relationship : relationships) {
+			productRelationshipService.delete(relationship);
+		}
+		
+		super.delete(product);
+		searchService.deleteIndex(product.getMerchantStore(), product);
+		
+	}
+	
+	@Override
+	public void create(Product product) throws ServiceException {
+		super.create(product);
+		searchService.index(product.getMerchantStore(), product);
+	}
+	
+
+	
+	@Override	
+	public void saveOrUpdate(Product product) throws ServiceException {
+
+		LOGGER.debug("Save or update product ");
+		Validate.notNull(product,"product cannot be null");
+		Validate.notNull(product.getAvailabilities(),"product must have at least one availability");
+		Validate.notEmpty(product.getAvailabilities(),"product must have at least one availability");
+
+		//List of original availabilities
+		Set<ProductAvailability> originalAvailabilities = null;
+		
+		//List of original attributes
+		Set<ProductAttribute> originalAttributes = null;
+		
+		//List of original reviews
+		Set<ProductRelationship> originalRelationships = null;
+		
+		//List of original images
+		Set<ProductImage> originalProductImages = null;
+		
+		
+		if(product.getId()!=null && product.getId()>0) {
+			LOGGER.debug("Update product",product.getId());
+			//get original product
+			Product originalProduct = this.getById(product.getId());
+			originalAvailabilities = originalProduct.getAvailabilities();
+			originalAttributes = originalProduct.getAttributes();
+			originalRelationships = originalProduct.getRelationships();
+			originalProductImages = originalProduct.getImages();
+		} else {
+			
+			Set<ProductDescription> productDescriptions = product.getDescriptions();
+			product.setDescriptions(null);
+			
+			super.create(product);
+			
+			for(ProductDescription productDescription : productDescriptions) {
+				addProductDescription(product,productDescription);
+			}
+		}
+
+		
+		LOGGER.debug("Creating availabilities");
+		
+		//get availabilities
+		Set<ProductAvailability> availabilities = product.getAvailabilities();
+		List<Long> newAvailabilityIds = new ArrayList<Long>();
+		if(availabilities!=null && availabilities.size()>0) {
+			for(ProductAvailability availability : availabilities) {
+				availability.setProduct(product);
+				productAvailabilityService.saveOrUpdate(availability);
+				newAvailabilityIds.add(availability.getId());
+				//check prices
+				Set<ProductPrice> prices = availability.getPrices();
+				if(prices!=null && prices.size()>0) {
+
+					for(ProductPrice price : prices) {
+						price.setProductAvailability(availability);
+						productPriceService.saveOrUpdate(price);
+					}
+				}	
+			}
+		}
+		
+		//cleanup old availability
+		if(originalAvailabilities!=null) {
+			for(ProductAvailability availability : originalAvailabilities) {
+				if(!newAvailabilityIds.contains(availability.getId())) {
+					productAvailabilityService.delete(availability);
+				}
+			}
+		}
+		
+		LOGGER.debug("Creating attributes");
+		List<Long> newAttributesIds = new ArrayList<Long>();
+		if(product.getAttributes()!=null && product.getAttributes().size()>0) {
+			Set<ProductAttribute> attributes = product.getAttributes();
+			for(ProductAttribute attribute : attributes) {
+				attribute.setProduct(product);
+				productAttributeService.saveOrUpdate(attribute);
+				newAttributesIds.add(attribute.getId());
+			}
+		}
+		
+		//cleanup old attributes
+		if(originalAttributes!=null) {
+			for(ProductAttribute attribute : originalAttributes) {
+				if(!newAttributesIds.contains(attribute.getId())) {
+					productAttributeService.delete(attribute);
+				}
+			}
+		}
+		
+		
+		LOGGER.debug("Creating relationships");
+		List<Long> newRelationshipIds = new ArrayList<Long>();
+		if(product.getRelationships()!=null && product.getRelationships().size()>0) {
+			Set<ProductRelationship> relationships = product.getRelationships();
+			for(ProductRelationship relationship : relationships) {
+				relationship.setProduct(product);
+				productRelationshipService.saveOrUpdate(relationship);
+				newRelationshipIds.add(relationship.getId());
+			}
+		}
+		//cleanup old relationships
+		if(originalRelationships!=null) {
+			for(ProductRelationship relationship : originalRelationships) {
+				if(!newRelationshipIds.contains(relationship.getId())) {
+					productRelationshipService.delete(relationship);
+				}
+			}
+		}
+		
+		
+		LOGGER.debug("Creating images");
+
+		//get images
+		List<Long> newImageIds = new ArrayList<Long>();
+		Set<ProductImage> images = product.getImages();
+		if(images!=null && images.size()>0) {
+			for(ProductImage image : images) {
+				if(image.getImage()!=null && (image.getId()==null || image.getId()==0L)) {
+					image.setProduct(product);
+					
+			        InputStream inputStream = image.getImage();
+			        ImageContentFile cmsContentImage = new ImageContentFile();
+			        cmsContentImage.setFileName( image.getProductImage() );
+			        cmsContentImage.setFile( inputStream );
+			        cmsContentImage.setFileContentType(FileContentType.PRODUCT);
+					
+					
+					productImageService.addProductImage(product, image, cmsContentImage);
+					newImageIds.add(image.getId());
+				} else {
+					productImageService.update(image);
+					newImageIds.add(image.getId());
+				}
+			}
+		}
+		
+		//cleanup old images
+		if(originalProductImages!=null) {
+			for(ProductImage image : originalProductImages) {
+				if(!newImageIds.contains(image.getId())) {
+					productImageService.delete(image);
+				}
+			}
+		}
+		
+		if(product.getId()!=null && product.getId()>0) {
+			super.update(product);
+		}
+		
+		searchService.index(product.getMerchantStore(), product);
+
+	}
+	
+	
+
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/relationship/ProductRelationshipService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/relationship/ProductRelationshipService.java
new file mode 100644
index 0000000..fa7ad61
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/relationship/ProductRelationshipService.java
@@ -0,0 +1,89 @@
+package com.salesmanager.core.business.catalog.product.service.relationship;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationship;
+import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationshipType;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductRelationshipService extends
+		SalesManagerEntityService<Long, ProductRelationship> {
+
+	void saveOrUpdate(ProductRelationship relationship) throws ServiceException;
+
+	/**
+	 * Get product relationship List for a given type (RELATED, FEATURED...) and language allows
+	 * to return the product description in the appropriate language
+	 * @param store
+	 * @param product
+	 * @param type
+	 * @param language
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<ProductRelationship> getByType(MerchantStore store, Product product,
+			ProductRelationshipType type, Language language) throws ServiceException;
+
+	/**
+	 * Get product relationship List for a given type (RELATED, FEATURED...) and a given base product
+	 * @param store
+	 * @param product
+	 * @param type
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<ProductRelationship> getByType(MerchantStore store, Product product,
+			ProductRelationshipType type)
+			throws ServiceException;
+
+	/**
+	 * Get product relationship List for a given type (RELATED, FEATURED...) 
+	 * @param store
+	 * @param type
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<ProductRelationship> getByType(MerchantStore store,
+			ProductRelationshipType type) throws ServiceException;
+
+	List<ProductRelationship> listByProduct(Product product)
+			throws ServiceException;
+
+	List<ProductRelationship> getByType(MerchantStore store,
+			ProductRelationshipType type, Language language)
+			throws ServiceException;
+
+	/**
+	 * Get a list of relationship acting as groups of products
+	 * @param store
+	 * @return
+	 */
+	List<ProductRelationship> getGroups(MerchantStore store);
+
+	/**
+	 * Creates a product group
+	 * @param groupName
+	 * @throws ServiceException
+	 */
+	void addGroup(MerchantStore store, String groupName) throws ServiceException;
+
+	List<ProductRelationship> getByGroup(MerchantStore store, String groupName)
+			throws ServiceException;
+
+	void deleteGroup(MerchantStore store, String groupName)
+			throws ServiceException;
+
+	void deactivateGroup(MerchantStore store, String groupName)
+			throws ServiceException;
+
+	void activateGroup(MerchantStore store, String groupName)
+			throws ServiceException;
+
+	List<ProductRelationship> getByGroup(MerchantStore store, String groupName,
+			Language language) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/relationship/ProductRelationshipServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/relationship/ProductRelationshipServiceImpl.java
new file mode 100644
index 0000000..9f2d265
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/relationship/ProductRelationshipServiceImpl.java
@@ -0,0 +1,147 @@
+package com.salesmanager.core.business.catalog.product.service.relationship;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.dao.relationship.ProductRelationshipDao;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationship;
+import com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationshipType;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Service("productRelationshipService")
+public class ProductRelationshipServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, ProductRelationship> implements
+		ProductRelationshipService {
+
+	
+	private ProductRelationshipDao productRelationshipDao;
+	
+	@Autowired
+	public ProductRelationshipServiceImpl(
+			ProductRelationshipDao productRelationshipDao) {
+			super(productRelationshipDao);
+			this.productRelationshipDao = productRelationshipDao;
+	}
+	
+	@Override
+	public void saveOrUpdate(ProductRelationship relationship) throws ServiceException {
+		
+		if(relationship.getId()!=null && relationship.getId()>0) {
+			
+			this.update(relationship);
+			
+		} else {
+			this.create(relationship);
+		}
+		
+	}
+	
+	
+	@Override
+	public void addGroup(MerchantStore store, String groupName) throws ServiceException {
+		ProductRelationship relationship = new ProductRelationship();
+		relationship.setCode(groupName);
+		relationship.setStore(store);
+		relationship.setActive(true);
+		this.save(relationship);
+	}
+	
+	@Override
+	public List<ProductRelationship> getGroups(MerchantStore store) {
+		return productRelationshipDao.getGroups(store);
+	}
+	
+	@Override
+	public void deleteGroup(MerchantStore store, String groupName) throws ServiceException {
+		List<ProductRelationship> entities = productRelationshipDao.getByGroup(store, groupName);
+		for(ProductRelationship relation : entities) {
+			this.delete(relation);
+		}
+	}
+	
+	@Override
+	public void deactivateGroup(MerchantStore store, String groupName) throws ServiceException {
+		List<ProductRelationship> entities = productRelationshipDao.getByGroup(store, groupName);
+		for(ProductRelationship relation : entities) {
+			relation.setActive(false);
+			this.saveOrUpdate(relation);
+		}
+	}
+	
+	@Override
+	public void activateGroup(MerchantStore store, String groupName) throws ServiceException {
+		List<ProductRelationship> entities = this.getByGroup(store, groupName);
+		for(ProductRelationship relation : entities) {
+			relation.setActive(true);
+			this.saveOrUpdate(relation);
+		}
+	}
+	
+	public void delete(ProductRelationship relationship) throws ServiceException {
+		
+		//throws detached exception so need to query first
+		relationship = this.getById(relationship.getId());
+		super.delete(relationship);
+		
+		
+	}
+	
+	@Override
+	public List<ProductRelationship> listByProduct(Product product) throws ServiceException {
+
+		return productRelationshipDao.listByProducts(product);
+
+	}
+	
+	
+	@Override
+	public List<ProductRelationship> getByType(MerchantStore store, Product product, ProductRelationshipType type, Language language) throws ServiceException {
+
+		return productRelationshipDao.getByType(store, type.name(), product, language);
+
+	}
+	
+	@Override
+	public List<ProductRelationship> getByType(MerchantStore store, ProductRelationshipType type, Language language) throws ServiceException {
+		return productRelationshipDao.getByType(store, type.name(), language);
+	}
+	
+	@Override
+	public List<ProductRelationship> getByType(MerchantStore store, ProductRelationshipType type) throws ServiceException {
+
+		return productRelationshipDao.getByType(store, type.name());
+
+	}
+	
+	@Override
+	public List<ProductRelationship> getByGroup(MerchantStore store, String groupName) throws ServiceException {
+
+		return productRelationshipDao.getByType(store, groupName);
+
+	}
+	
+	@Override
+	public List<ProductRelationship> getByGroup(MerchantStore store, String groupName, Language language) throws ServiceException {
+
+		return productRelationshipDao.getByType(store, groupName, language);
+
+	}
+	
+	@Override
+	public List<ProductRelationship> getByType(MerchantStore store, Product product, ProductRelationshipType type) throws ServiceException {
+		
+
+		return productRelationshipDao.getByType(store, type.name(), product);
+				
+		
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/review/ProductReviewService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/review/ProductReviewService.java
new file mode 100644
index 0000000..bc6c031
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/review/ProductReviewService.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.business.catalog.product.service.review;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.review.ProductReview;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ProductReviewService extends
+		SalesManagerEntityService<Long, ProductReview> {
+	
+	
+	List<ProductReview> getByCustomer(Customer customer);
+	List<ProductReview> getByProduct(Product product);
+	List<ProductReview> getByProduct(Product product, Language language);
+	ProductReview getByProductAndCustomer(Long productId, Long customerId);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/review/ProductReviewServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/review/ProductReviewServiceImpl.java
new file mode 100644
index 0000000..51b559a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/review/ProductReviewServiceImpl.java
@@ -0,0 +1,95 @@
+package com.salesmanager.core.business.catalog.product.service.review;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import com.salesmanager.core.business.catalog.product.dao.review.ProductReviewDao;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.review.ProductReview;
+import com.salesmanager.core.business.catalog.product.service.ProductService;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Service("productReviewService")
+public class ProductReviewServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, ProductReview> implements
+		ProductReviewService {
+
+
+	private ProductReviewDao productReviewDao;
+	
+	@Autowired
+	private ProductService productService;
+	
+	@Autowired
+	public ProductReviewServiceImpl(
+			ProductReviewDao productReviewDao) {
+			super(productReviewDao);
+			this.productReviewDao = productReviewDao;
+	}
+
+	@Override
+	public List<ProductReview> getByCustomer(Customer customer) {
+		return productReviewDao.getByCustomer(customer);
+	}
+
+	@Override
+	public List<ProductReview> getByProduct(Product product) {
+		return productReviewDao.getByProduct(product);
+	}
+	
+	@Override
+	public ProductReview getByProductAndCustomer(Long productId, Long customerId) {
+		return productReviewDao.getByProductAndCustomer(productId, customerId);
+	}
+	
+	@Override
+	public List<ProductReview> getByProduct(Product product, Language language) {
+		return productReviewDao.getByProduct(product, language);
+	}
+	
+	public void create(ProductReview review) throws ServiceException {
+		
+		//adjust score
+		
+		//refresh product
+		Product product = productService.getById(review.getProduct().getId());
+		
+		//ajust product rating
+		Integer count = 0;
+		if(product.getProductReviewCount()!=null) {
+			count = product.getProductReviewCount();
+		}
+				
+		
+		
+
+		BigDecimal averageRating = product.getProductReviewAvg();
+		if(averageRating==null) {
+			averageRating = new BigDecimal(0);
+		}
+		//get reviews
+
+		
+		BigDecimal totalRating = averageRating.multiply(new BigDecimal(count));
+		totalRating = totalRating.add(new BigDecimal(review.getReviewRating()));
+		
+		count = count + 1;
+		double avg = totalRating.doubleValue() / count.intValue();
+		
+		product.setProductReviewAvg(new BigDecimal(avg));
+		product.setProductReviewCount(count);
+		super.create(review);
+		
+		productService.update(product);
+		
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/type/ProductTypeService.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/type/ProductTypeService.java
new file mode 100644
index 0000000..fef6a47
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/type/ProductTypeService.java
@@ -0,0 +1,11 @@
+package com.salesmanager.core.business.catalog.product.service.type;
+
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+
+public interface ProductTypeService extends SalesManagerEntityService<Long, ProductType> {
+
+	ProductType getProductType(String productTypeCode) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/type/ProductTypeServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/type/ProductTypeServiceImpl.java
new file mode 100644
index 0000000..fe77059
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/catalog/product/service/type/ProductTypeServiceImpl.java
@@ -0,0 +1,34 @@
+package com.salesmanager.core.business.catalog.product.service.type;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.dao.type.ProductTypeDao;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType_;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+
+@Service("productTypeService")
+public class ProductTypeServiceImpl extends SalesManagerEntityServiceImpl<Long, ProductType>
+		implements ProductTypeService {
+
+	private ProductTypeDao productTypeDao;
+	
+	@Autowired
+	public ProductTypeServiceImpl(
+			ProductTypeDao productTypeDao) {
+			super(productTypeDao);
+			this.productTypeDao = productTypeDao;
+	}
+	
+	@Override
+	public ProductType getProductType(String productTypeCode) throws ServiceException {
+		
+		return getByField(ProductType_.code, productTypeCode);
+		
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/Address.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Address.java
new file mode 100644
index 0000000..a8fe241
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Address.java
@@ -0,0 +1,62 @@
+package com.salesmanager.core.business.common.model;
+
+import java.io.Serializable;
+
+
+public class Address implements Serializable {
+	
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private String city;
+	private String postalCode;
+	private String stateProvince;
+	private String zone;//code
+	private String country;//code
+
+	public void setStateProvince(String stateProvince) {
+		this.stateProvince = stateProvince;
+	}
+
+	public void setCountry(String country) {
+		this.country = country;
+	}
+
+
+	public String getCity() {
+		return city;
+	}
+
+	public void setCity(String city) {
+		this.city = city;
+	}
+
+	public String getPostalCode() {
+		return postalCode;
+	}
+
+	public void setPostalCode(String postalCode) {
+		this.postalCode = postalCode;
+	}
+
+	public String getStateProvince() {
+		return stateProvince;
+	}
+
+	public String getCountry() {
+		return country;
+	}
+
+	public void setZone(String zone) {
+		this.zone = zone;
+	}
+
+	public String getZone() {
+		return zone;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/Auditable.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/Auditable.java
new file mode 100644
index 0000000..58c0332
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/Auditable.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.common.model.audit;
+
+public interface Auditable {
+	
+	AuditSection getAuditSection();
+	
+	void setAuditSection(AuditSection audit);
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/AuditListener.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/AuditListener.java
new file mode 100644
index 0000000..a4b7ebf
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/AuditListener.java
@@ -0,0 +1,24 @@
+package com.salesmanager.core.business.common.model.audit;
+
+import java.util.Date;
+
+import javax.persistence.PrePersist;
+import javax.persistence.PreUpdate;
+
+public class AuditListener {
+	
+	@PrePersist
+	@PreUpdate
+	public void onSaveOrUpdate(Object o) {
+		if (o instanceof Auditable) {
+			Auditable audit = (Auditable) o;
+			AuditSection auditSection = audit.getAuditSection();
+			
+			auditSection.setDateModified(new Date());
+			if (auditSection.getDateCreated() == null) {
+				auditSection.setDateCreated(new Date());
+			}
+			audit.setAuditSection(auditSection);
+		}
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/AuditSection.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/AuditSection.java
new file mode 100644
index 0000000..438498b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/audit/AuditSection.java
@@ -0,0 +1,57 @@
+package com.salesmanager.core.business.common.model.audit;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import com.salesmanager.core.utils.CloneUtils;
+
+@Embeddable
+//@org.hibernate.annotations.Entity(dynamicUpdate = true, dynamicInsert = true)
+public class AuditSection implements Serializable {
+
+
+	private static final long serialVersionUID = -1934446958975060889L;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name = "DATE_CREATED")
+	private Date dateCreated;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name = "DATE_MODIFIED")
+	private Date dateModified;
+
+	@Column(name = "UPDT_ID", length=20)
+	private String modifiedBy;
+	
+	public AuditSection() {
+	}
+
+	public Date getDateCreated() {
+		return CloneUtils.clone(dateCreated);
+	}
+
+	public void setDateCreated(Date dateCreated) {
+		this.dateCreated = CloneUtils.clone(dateCreated);
+	}
+
+	public Date getDateModified() {
+		return CloneUtils.clone(dateModified);
+	}
+
+	public void setDateModified(Date dateModified) {
+		this.dateModified = CloneUtils.clone(dateModified);
+	}
+
+	public String getModifiedBy() {
+		return modifiedBy;
+	}
+
+	public void setModifiedBy(String modifiedBy) {
+		this.modifiedBy = modifiedBy;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/Billing.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Billing.java
new file mode 100755
index 0000000..97be079
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Billing.java
@@ -0,0 +1,139 @@
+package com.salesmanager.core.business.common.model;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+
+@Embeddable
+public class Billing {
+	
+	@NotEmpty
+	@Column (name ="BILLING_LAST_NAME", length=64, nullable=false)
+	private String lastName;
+
+	@NotEmpty
+	@Column (name ="BILLING_FIRST_NAME", length=64, nullable=false)
+	private String firstName;
+	
+
+
+	@Column (name ="BILLING_COMPANY", length=100)
+	private String company;
+	
+	@Column (name ="BILLING_STREET_ADDRESS", length=256)
+	private String address;
+	
+	
+	@Column (name ="BILLING_CITY", length=100)
+	private String city;
+	
+	@Column (name ="BILLING_POSTCODE", length=20)
+	private String postalCode;
+	
+	@Column(name="BILLING_TELEPHONE", length=32)
+	private String telephone;
+	
+	@Column (name ="BILLING_STATE", length=100)
+	private String state;
+
+
+	@ManyToOne(fetch = FetchType.EAGER, targetEntity = Country.class)
+	@JoinColumn(name="BILLING_COUNTRY_ID", nullable=false)
+	private Country country;
+	
+	
+	@ManyToOne(fetch = FetchType.EAGER, targetEntity = Zone.class)
+	@JoinColumn(name="BILLING_ZONE_ID", nullable=true)
+	private Zone zone;
+
+
+
+	public String getCompany() {
+		return company;
+	}
+
+	public void setCompany(String company) {
+		this.company = company;
+	}
+
+	public String getAddress() {
+		return address;
+	}
+
+	public void setAddress(String address) {
+		this.address = address;
+	}
+
+	public String getCity() {
+		return city;
+	}
+
+	public void setCity(String city) {
+		this.city = city;
+	}
+
+	public String getPostalCode() {
+		return postalCode;
+	}
+
+	public void setPostalCode(String postalCode) {
+		this.postalCode = postalCode;
+	}
+	
+	public Country getCountry() {
+		return country;
+	}
+
+	public void setCountry(Country country) {
+		this.country = country;
+	}
+
+	public Zone getZone() {
+		return zone;
+	}
+
+	public void setZone(Zone zone) {
+		this.zone = zone;
+	}
+	
+	public String getState() {
+		return state;
+	}
+
+	public void setState(String state) {
+		this.state = state;
+	}
+
+	public void setTelephone(String telephone) {
+		this.telephone = telephone;
+	}
+
+	public String getTelephone() {
+		return telephone;
+	}
+	
+	
+	public String getLastName() {
+		return lastName;
+	}
+
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
+	}
+	
+	public String getFirstName() {
+		return firstName;
+	}
+
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/Criteria.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Criteria.java
new file mode 100644
index 0000000..a800521
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Criteria.java
@@ -0,0 +1,40 @@
+package com.salesmanager.core.business.common.model;
+
+public class Criteria {
+	
+	private int startIndex = 0;
+	private int maxCount = 0;
+	private String code;
+	
+	
+	private CriteriaOrderBy orderBy = CriteriaOrderBy.DESC;
+	
+	
+	public int getMaxCount() {
+		return maxCount;
+	}
+	public void setMaxCount(int maxCount) {
+		this.maxCount = maxCount;
+	}
+	public int getStartIndex() {
+		return startIndex;
+	}
+	public void setStartIndex(int startIndex) {
+		this.startIndex = startIndex;
+	}
+	public String getCode() {
+		return code;
+	}
+	public void setCode(String code) {
+		this.code = code;
+	}
+	public void setOrderBy(CriteriaOrderBy orderBy) {
+		this.orderBy = orderBy;
+	}
+	public CriteriaOrderBy getOrderBy() {
+		return orderBy;
+	}
+
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/CriteriaOrderBy.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/CriteriaOrderBy.java
new file mode 100644
index 0000000..c9a8eb7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/CriteriaOrderBy.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.common.model;
+
+public enum CriteriaOrderBy {
+
+	
+	ASC, DESC
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/Delivery.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Delivery.java
new file mode 100755
index 0000000..5c3faf9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Delivery.java
@@ -0,0 +1,138 @@
+package com.salesmanager.core.business.common.model;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.persistence.FetchType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+
+@Embeddable
+public class Delivery {
+	
+	@Column (name ="DELIVERY_LAST_NAME", length=64)
+	private String lastName;
+
+
+
+
+	@Column (name ="DELIVERY_FIRST_NAME", length=64)
+	private String firstName;
+
+	
+
+
+	@Column (name ="DELIVERY_COMPANY", length=100)
+	private String company;
+	
+	@Column (name ="DELIVERY_STREET_ADDRESS", length=256)
+	private String address;
+
+	@Column (name ="DELIVERY_CITY", length=100)
+	private String city;
+	
+	@Column (name ="DELIVERY_POSTCODE", length=20)
+	private String postalCode;
+	
+	@Column (name ="DELIVERY_STATE", length=100)
+	private String state;
+	
+	@Column(name="DELIVERY_TELEPHONE", length=32)
+	private String telephone;
+	
+	@ManyToOne(fetch = FetchType.EAGER, targetEntity = Country.class)
+	@JoinColumn(name="DELIVERY_COUNTRY_ID", nullable=true)
+	private Country country;
+	
+
+	@ManyToOne(fetch = FetchType.EAGER, targetEntity = Zone.class)
+	@JoinColumn(name="DELIVERY_ZONE_ID", nullable=true)
+	private Zone zone;
+	
+
+
+	public String getCompany() {
+		return company;
+	}
+
+	public void setCompany(String company) {
+		this.company = company;
+	}
+
+	public String getAddress() {
+		return address;
+	}
+
+	public void setAddress(String address) {
+		this.address = address;
+	}
+
+	public String getCity() {
+		return city;
+	}
+
+	public void setCity(String city) {
+		this.city = city;
+	}
+
+	public String getPostalCode() {
+		return postalCode;
+	}
+
+	public void setPostalCode(String postalCode) {
+		this.postalCode = postalCode;
+	}
+
+	public Country getCountry() {
+		return country;
+	}
+
+	public void setCountry(Country country) {
+		this.country = country;
+	}
+
+	public Zone getZone() {
+		return zone;
+	}
+
+	public void setZone(Zone zone) {
+		this.zone = zone;
+	}
+	
+
+	public String getState() {
+		return state;
+	}
+
+	public void setState(String state) {
+		this.state = state;
+	}
+
+	public void setTelephone(String telephone) {
+		this.telephone = telephone;
+	}
+
+	public String getTelephone() {
+		return telephone;
+	}	
+	
+	public String getLastName() {
+		return lastName;
+	}
+
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
+	}
+	
+	public String getFirstName() {
+		return firstName;
+	}
+
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/Description.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Description.java
new file mode 100644
index 0000000..59e917f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/Description.java
@@ -0,0 +1,113 @@
+package com.salesmanager.core.business.common.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.EntityListeners;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Inheritance;
+import javax.persistence.InheritanceType;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.MappedSuperclass;
+import javax.persistence.TableGenerator;
+
+import org.hibernate.annotations.Type;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@MappedSuperclass
+@EntityListeners(value = AuditListener.class)
+@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
+public class Description implements Auditable, Serializable {
+	private static final long serialVersionUID = -4335863941736710046L;
+	
+	@Id
+	@Column(name = "DESCRIPTION_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "DESCRIPTION_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@ManyToOne(optional = false)
+	@JoinColumn(name = "LANGUAGE_ID")
+	private Language language;
+	
+	@NotEmpty
+	@Column(name="NAME", nullable = false, length=120)
+	private String name;
+	
+	@Column(name="TITLE", length=100)
+	private String title;
+	
+	@Column(name="DESCRIPTION")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String description;
+	
+	public Description() {
+	}
+	
+	public Description(Language language, String name) {
+		this.setLanguage(language);
+		this.setName(name);
+	}
+	
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	public Language getLanguage() {
+		return language;
+	}
+
+	public void setLanguage(Language language) {
+		this.language = language;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/EntityList.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/EntityList.java
new file mode 100644
index 0000000..ce03d25
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/EntityList.java
@@ -0,0 +1,21 @@
+package com.salesmanager.core.business.common.model;
+
+import java.io.Serializable;
+
+public class EntityList implements Serializable {
+	
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 6135941880202635567L;
+	private int totalCount;
+	
+	public int getTotalCount() {
+		return totalCount;
+	}
+	public void setTotalCount(int totalCount) {
+		this.totalCount = totalCount;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/common/model/OrderTotalItem.java b/sm-core/src/main/java/com/salesmanager/core/business/common/model/OrderTotalItem.java
new file mode 100644
index 0000000..b383e83
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/common/model/OrderTotalItem.java
@@ -0,0 +1,27 @@
+package com.salesmanager.core.business.common.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+public class OrderTotalItem implements Serializable {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private BigDecimal itemPrice;
+	private String itemCode;
+	public void setItemPrice(BigDecimal itemPrice) {
+		this.itemPrice = itemPrice;
+	}
+	public BigDecimal getItemPrice() {
+		return itemPrice;
+	}
+	public void setItemCode(String itemCode) {
+		this.itemCode = itemCode;
+	}
+	public String getItemCode() {
+		return itemCode;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/dao/ContentDao.java b/sm-core/src/main/java/com/salesmanager/core/business/content/dao/ContentDao.java
new file mode 100755
index 0000000..82bf93e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/dao/ContentDao.java
@@ -0,0 +1,50 @@
+package com.salesmanager.core.business.content.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.content.model.Content;
+import com.salesmanager.core.business.content.model.ContentDescription;
+import com.salesmanager.core.business.content.model.ContentType;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface ContentDao extends SalesManagerEntityDao<Long, Content> {
+
+	List<Content> listByType(ContentType contentType, MerchantStore store,
+			Language language) throws ServiceException;
+
+	List<Content> listByType(List<ContentType> contentType, MerchantStore store,
+			Language language) throws ServiceException;
+
+	Content getByCode(String code, MerchantStore store)
+			throws ServiceException;
+
+	Content getByCode(String code, MerchantStore store, Language language)
+			throws ServiceException;
+
+	List<Content> listByType(List<ContentType> contentType, MerchantStore store)
+			throws ServiceException;
+
+	List<Content> listByType(ContentType contentType, MerchantStore store)
+			throws ServiceException;
+
+	/**
+	 * List ContentDescription objects. Removes non visible content
+	 * @param contentType
+	 * @param store
+	 * @param language
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<ContentDescription> listNameByType(List<ContentType> contentType,
+			MerchantStore store, Language language) throws ServiceException;
+
+	Content getByLanguage(Long id, Language language) throws ServiceException;
+
+	ContentDescription getBySeUrl(MerchantStore store, String seUrl);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/dao/ContentDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/content/dao/ContentDaoImpl.java
new file mode 100755
index 0000000..a413671
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/dao/ContentDaoImpl.java
@@ -0,0 +1,266 @@
+package com.salesmanager.core.business.content.dao;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.content.model.Content;
+import com.salesmanager.core.business.content.model.ContentDescription;
+import com.salesmanager.core.business.content.model.ContentType;
+import com.salesmanager.core.business.content.model.QContent;
+import com.salesmanager.core.business.content.model.QContentDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("contentDao")
+public class ContentDaoImpl extends SalesManagerEntityDaoImpl<Long, Content> implements ContentDao {
+
+	public ContentDaoImpl() {
+		super();
+	}
+	
+	@Override
+	public List<Content> listByType(ContentType contentType, MerchantStore store, Language language) throws ServiceException {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContentDescription.language.id.eq(language.getId())
+			.and(qContent.merchantStore.id.eq(store.getId()))
+			.and(qContent.contentType.eq(contentType))
+			).orderBy(qContent.sortOrder.asc());
+		
+		List<Content> contents = query.list(qContent);
+		
+		return contents;
+	}
+	
+	@Override
+	public List<Content> listByType(ContentType contentType, MerchantStore store) throws ServiceException {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContent.merchantStore.id.eq(store.getId())
+			.and(qContent.contentType.eq(contentType))
+			).orderBy(qContent.sortOrder.asc());
+		
+		List<Content> contents = query.list(qContent);
+		
+		return contents;
+	}
+	
+	
+	@Override
+	public List<Content> listByType(List<ContentType> contentType, MerchantStore store, Language language) throws ServiceException {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContentDescription.language.id.eq(language.getId())
+			.and(qContent.merchantStore.id.eq(store.getId()))
+			.and(qContent.contentType.in(contentType))
+			).orderBy(qContent.sortOrder.asc());
+		
+		List<Content> contents = query.list(qContent);
+		
+		return contents;
+	}
+	
+	@Override
+	public List<ContentDescription> listNameByType(List<ContentType> contentType, MerchantStore store, Language language) throws ServiceException {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContentDescription.language.id.eq(language.getId())
+			.and(qContent.merchantStore.id.eq(store.getId()))
+			.and(qContent.contentType.in(contentType))
+			.and(qContent.visible.eq(true))
+		).orderBy(qContent.sortOrder.asc());
+		
+
+		
+		List<Content> contents = query.list(qContent);
+		
+		List<ContentDescription> descriptions = new ArrayList<ContentDescription>();
+		for(Content c : contents) {
+				String name = c.getDescription().getName();
+				String url = c.getDescription().getSeUrl();
+				ContentDescription contentDescription = new ContentDescription();
+				contentDescription.setName(name);
+				contentDescription.setSeUrl(url);
+				descriptions.add(contentDescription);
+		}
+		
+		return descriptions;
+	}
+	
+	@Override
+	public List<Content> listByType(List<ContentType> contentType, MerchantStore store) throws ServiceException {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContent.merchantStore.id.eq(store.getId())
+			.and(qContent.contentType.in(contentType))
+			).orderBy(qContent.sortOrder.asc());
+		
+		List<Content> contents = query.list(qContent);
+		
+		return contents;
+	}
+	
+	@Override
+	public Content getByCode(String code, MerchantStore store) throws ServiceException {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContent.merchantStore.id.eq(store.getId())
+			.and(qContent.code.eq(code))
+			);
+		
+		Content content = query.singleResult(qContent);
+		
+		return content;
+	}
+	
+	@Override
+	public Content getByLanguage(Long id, Language language) throws ServiceException {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContent.id.eq(id)
+			.and(qContentDescription.language.code.eq(language.getCode())));
+		
+		Content content = query.singleResult(qContent);
+		
+		return content;
+	}
+	
+	@Override
+	public Content getById(Long id) {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContent.id.eq(id)
+			);
+		
+		Content content = query.singleResult(qContent);
+		
+		return content;
+	}
+	
+	@Override
+	public Content getByCode(String code, MerchantStore store, Language language) throws ServiceException {
+
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContentDescription.language.id.eq(language.getId())
+			.and(qContent.merchantStore.id.eq(store.getId())
+			.and(qContent.code.eq(code)))
+			);
+		
+		Content content = query.singleResult(qContent);
+		
+		return content;
+	}
+	
+	@Override
+	public ContentDescription getBySeUrl(MerchantStore store,String seUrl) {
+		
+		QContent qContent = QContent.content;
+		QContentDescription qContentDescription = QContentDescription.contentDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		
+		query.from(qContent)
+			.leftJoin(qContent.descriptions, qContentDescription).fetch()
+			.leftJoin(qContent.merchantStore).fetch()
+			.where(qContentDescription.seUrl.eq(seUrl)
+			.and(qContent.merchantStore.id.eq(store.getId()))
+			.and(qContent.visible.eq(true))
+		);
+		
+
+		
+		Content content = query.uniqueResult(qContent);
+		
+
+		if(content!=null) {
+				return content.getDescription();
+		}
+		
+		return null;
+		
+		
+	}
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/Content.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/Content.java
new file mode 100755
index 0000000..20b4be0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/Content.java
@@ -0,0 +1,170 @@
+package com.salesmanager.core.business.content.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.UniqueConstraint;
+import javax.validation.Valid;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "CONTENT", schema= SchemaConstant.SALESMANAGER_SCHEMA,uniqueConstraints=
+    @UniqueConstraint(columnNames = {"MERCHANT_ID", "CODE"}) )
+public class Content extends SalesManagerEntity<Long, Content> implements Serializable {
+
+	
+
+	private static final long serialVersionUID = 1772757159185494620L;
+	
+	@Id
+	@Column(name = "CONTENT_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "CONTENT_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@Valid
+	@OneToMany(mappedBy="content", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
+	private List<ContentDescription> descriptions = new ArrayList<ContentDescription>();
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	@NotEmpty
+	@Column(name="CODE", length=100, nullable=false)
+	private String code;
+	
+	@Column(name = "VISIBLE")
+	private boolean visible;
+	
+	@Column(name = "CONTENT_POSITION", length=10, nullable=true)
+	@Enumerated(value = EnumType.STRING)
+	private ContentPosition contentPosition;
+	
+	//Used for grouping
+	//BOX, SECTION, PAGE
+	@Column(name = "CONTENT_TYPE", length=10, nullable=true)
+	@Enumerated(value = EnumType.STRING)
+	private ContentType contentType; 
+	
+	@Column(name = "SORT_ORDER")
+	private Integer sortOrder = 0;
+	
+	@Override
+	public Long getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+		
+	}
+
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public boolean isVisible() {
+		return visible;
+	}
+
+	public void setVisible(boolean visible) {
+		this.visible = visible;
+	}
+
+
+
+	public List<ContentDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(List<ContentDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	public void setContentType(ContentType contentType) {
+		this.contentType = contentType;
+	}
+
+	public ContentType getContentType() {
+		return contentType;
+	}
+	
+	public ContentDescription getDescription() {
+		
+		if(this.getDescriptions()!=null && this.getDescriptions().size()>0) {
+			return this.getDescriptions().get(0);
+		}
+		
+		return null;
+		
+	}
+
+	public void setSortOrder(Integer sortOrder) {
+		this.sortOrder = sortOrder;
+	}
+
+	public Integer getSortOrder() {
+		return sortOrder;
+	}
+
+	public void setContentPosition(ContentPosition contentPosition) {
+		this.contentPosition = contentPosition;
+	}
+
+	public ContentPosition getContentPosition() {
+		return contentPosition;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentDescription.java
new file mode 100755
index 0000000..4efeaff
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentDescription.java
@@ -0,0 +1,98 @@
+package com.salesmanager.core.business.content.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Entity
+@Table(name="CONTENT_DESCRIPTION", schema="SALESMANAGER",uniqueConstraints={
+		@UniqueConstraint(columnNames={
+			"CONTENT_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class ContentDescription extends Description implements Serializable {
+	
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -1252756716545768599L;
+
+	@ManyToOne(targetEntity = Content.class)
+	@JoinColumn(name = "CONTENT_ID", nullable = false)
+	private Content content;
+
+	@Column(name="SEF_URL", length=120)
+	private String seUrl;
+
+	
+	@Column(name="META_KEYWORDS")
+	private String metatagKeywords;
+	
+	@Column(name="META_TITLE")
+	private String metatagTitle;
+	
+	public String getMetatagTitle() {
+		return metatagTitle;
+	}
+
+	public void setMetatagTitle(String metatagTitle) {
+		this.metatagTitle = metatagTitle;
+	}
+
+	@Column(name="META_DESCRIPTION")
+	private String metatagDescription;
+	
+	public ContentDescription() {
+	}
+	
+	public ContentDescription(String name, Language language) {
+		this.setName(name);
+		this.setLanguage(language);
+		super.setId(0L);
+	}
+
+	public Content getContent() {
+		return content;
+	}
+
+	public void setContent(Content content) {
+		this.content = content;
+	}
+
+	public String getSeUrl() {
+		return seUrl;
+	}
+
+	public void setSeUrl(String seUrl) {
+		this.seUrl = seUrl;
+	}
+
+
+	public String getMetatagKeywords() {
+		return metatagKeywords;
+	}
+
+	public void setMetatagKeywords(String metatagKeywords) {
+		this.metatagKeywords = metatagKeywords;
+	}
+
+	public String getMetatagDescription() {
+		return metatagDescription;
+	}
+
+	public void setMetatagDescription(String metatagDescription) {
+		this.metatagDescription = metatagDescription;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentFile.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentFile.java
new file mode 100644
index 0000000..36f3e48
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentFile.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.business.content.model;
+
+public abstract class ContentFile {
+	
+	
+	private String fileName;
+	private String mimeType;
+	public void setMimeType(String mimeType) {
+		this.mimeType = mimeType;
+	}
+	public String getMimeType() {
+		return mimeType;
+	}
+	public void setFileName(String fileName) {
+		this.fileName = fileName;
+	}
+	public String getFileName() {
+		return fileName;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentPosition.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentPosition.java
new file mode 100644
index 0000000..c9fdfb5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentPosition.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.content.model;
+
+public enum ContentPosition {
+	
+	LEFT, RIGHT
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentType.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentType.java
new file mode 100755
index 0000000..18f53d2
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ContentType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.content.model;
+
+public enum ContentType {
+	
+	BOX, PAGE, SECTION
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/FileContentType.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/FileContentType.java
new file mode 100644
index 0000000..d610aa4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/FileContentType.java
@@ -0,0 +1,25 @@
+/**
+ * 
+ */
+package com.salesmanager.core.business.content.model;
+
+/**
+ * Enum defining type of static content.
+ * Currently following type of static content can be store and managed within 
+ * Shopizer CMS system
+ * <pre>
+ * 1. Static content like JS, CSS file etc
+ * 2. Digital Data (audio,video)
+ * </pre>
+ * 
+ * StaticContentType will be used to distinguish between Digital data and other type of static data
+ * stored with in the system.
+ * 
+ * @author Umesh Awasthi
+ * @since 1.2
+ *
+ */
+public enum FileContentType
+{
+  STATIC_FILE, IMAGE, LOGO, PRODUCT, PRODUCTLG, PROPERTY, MANUFACTURER, PRODUCT_DIGITAL
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/ImageContentFile.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ImageContentFile.java
new file mode 100644
index 0000000..7524194
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/ImageContentFile.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.business.content.model;
+
+import java.io.Serializable;
+
+public class ImageContentFile extends InputContentFile implements Serializable {
+
+	
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -5321162403524229224L;
+	//private BufferedImage bufferedImage;
+
+	//public void setBufferedImage(BufferedImage bufferedImage) {
+	//	this.bufferedImage = bufferedImage;
+	//}
+
+	//public BufferedImage getBufferedImage() {
+	//	return bufferedImage;
+	//}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/InputContentFile.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/InputContentFile.java
new file mode 100644
index 0000000..4cd71bc
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/InputContentFile.java
@@ -0,0 +1,26 @@
+package com.salesmanager.core.business.content.model;
+
+import java.io.InputStream;
+import java.io.Serializable;
+
+
+public class InputContentFile extends StaticContentFile implements Serializable 
+{
+
+    private static final long serialVersionUID = 1L;
+   
+    private InputStream file;
+   
+    
+    public InputStream getFile()
+    {
+        return file;
+    }
+    public void setFile( InputStream file )
+    {
+        this.file = file;
+    }
+   
+    
+    
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/OutputContentFile.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/OutputContentFile.java
new file mode 100644
index 0000000..cd4bbe1
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/OutputContentFile.java
@@ -0,0 +1,26 @@
+package com.salesmanager.core.business.content.model;
+
+import java.io.ByteArrayOutputStream;
+import java.io.Serializable;
+
+/**
+ * Data class responsible for carrying out static content data from Infispan cache to 
+ * service layer.
+ * 
+ * @author Umesh Awasthi
+ * @since 1.2
+ */
+public class OutputContentFile extends StaticContentFile implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+    private ByteArrayOutputStream file;
+    public ByteArrayOutputStream getFile()
+    {
+        return file;
+    }
+    public void setFile( ByteArrayOutputStream file )
+    {
+        this.file = file;
+    }
+    
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/model/StaticContentFile.java b/sm-core/src/main/java/com/salesmanager/core/business/content/model/StaticContentFile.java
new file mode 100644
index 0000000..975116c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/model/StaticContentFile.java
@@ -0,0 +1,18 @@
+package com.salesmanager.core.business.content.model;
+
+public abstract class StaticContentFile extends ContentFile {
+	
+	private FileContentType fileContentType;
+
+	public FileContentType getFileContentType() {
+		return fileContentType;
+	}
+
+	public void setFileContentType(FileContentType fileContentType) {
+		this.fileContentType = fileContentType;
+	}
+
+
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/service/ContentService.java b/sm-core/src/main/java/com/salesmanager/core/business/content/service/ContentService.java
new file mode 100755
index 0000000..77d1412
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/service/ContentService.java
@@ -0,0 +1,149 @@
+package com.salesmanager.core.business.content.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.content.model.Content;
+import com.salesmanager.core.business.content.model.ContentDescription;
+import com.salesmanager.core.business.content.model.ContentType;
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+
+
+/**
+ * 
+ * Interface defining methods responsible for CMSContentService.
+ * ContentServive will be be entry point for CMS and take care of following functionalities.
+ * <li>Adding,removing Content images for given merchant store</li>
+ * <li>Get,Save,Update Content data for given merchant store</li>
+ *  
+ * @author Umesh Awasthhi
+ *
+ */
+public interface ContentService
+    extends SalesManagerEntityService<Long, Content>
+{
+
+    public List<Content> listByType( ContentType contentType, MerchantStore store, Language language )
+        throws ServiceException;
+
+    public List<Content> listByType( List<ContentType> contentType, MerchantStore store, Language language )
+        throws ServiceException;
+
+    Content getByCode( String code, MerchantStore store )
+        throws ServiceException;
+
+    void saveOrUpdate( Content content )
+        throws ServiceException;
+
+    Content getByCode( String code, MerchantStore store, Language language )
+        throws ServiceException;
+
+    /**
+     * Method responsible for storing content file for given Store.Files for given merchant store will be stored in
+     * Infinispan.
+     * 
+     * @param merchantStoreCode merchant store whose content images are being saved.
+     * @param contentFile content image being stored
+     * @throws ServiceException
+     */
+    void addContentFile( String merchantStoreCode, InputContentFile contentFile )
+        throws ServiceException;
+
+   
+    /**
+     * Method responsible for storing list of content image for given Store.Images for given merchant store will be stored in
+     * Infinispan.
+     * 
+     * @param merchantStoreCode  merchant store whose content images are being saved.
+     * @param contentImagesList list of content images being stored.
+     * @throws ServiceException
+     */
+    void addContentFiles(String merchantStoreCode,List<InputContentFile> contentFilesList) throws ServiceException;
+    
+    
+    /**
+     * Method to remove given content image.Images are stored in underlying system based on there name.
+     * Name will be used to search given image for removal
+     * @param imageContentType
+     * @param imageName
+     * @param merchantStoreCode merchant store code
+     * @throws ServiceException
+     */
+    public void removeFile( String merchantStoreCode, FileContentType fileContentType, String fileName) throws ServiceException;
+    
+    
+    /**
+     * Method to remove all images for a given merchant.It will take merchant store as an input and will
+     * remove all images associated with given merchant store.
+     * 
+     * @param merchantStoreCode
+     * @throws ServiceException
+     */
+    public void removeFiles( String merchantStoreCode ) throws ServiceException;
+    
+    /**
+     * Method responsible for fetching particular content image for a given merchant store. Requested image will be
+     * search in Infinispan tree cache and OutputContentImage will be sent, in case no image is found null will
+     * returned.
+     * 
+     * @param merchantStoreCode
+     * @param imageName
+     * @return {@link OutputContentImage}
+     * @throws ServiceException
+     */
+    public OutputContentFile getContentFile( String merchantStoreCode, FileContentType fileContentType, String fileName )
+        throws ServiceException;
+    
+    
+    /**
+     * Method to get list of all images associated with a given merchant store.In case of no image method will return an empty list.
+     * @param merchantStoreCode
+     * @param imageContentType
+     * @return list of {@link OutputContentImage}
+     * @throws ServiceException
+     */
+    public List<OutputContentFile> getContentFiles( String merchantStoreCode, FileContentType fileContentType )
+                    throws ServiceException;
+
+	
+    List<String> getContentFilesNames(String merchantStoreCode,
+			FileContentType fileContentType) throws ServiceException;
+
+    /**
+     * Add the store logo
+     * @param merchantStoreCode
+     * @param cmsContentImage
+     * @throws ServiceException
+     */
+	void addLogo(String merchantStoreCode, InputContentFile cmsContentImage)
+			throws ServiceException;
+
+	/**
+	 * Adds a property (option) image
+	 * @param merchantStoreId
+	 * @param cmsContentImage
+	 * @throws ServiceException
+	 */
+	void addOptionImage(String merchantStoreCode, InputContentFile cmsContentImage)
+			throws ServiceException;
+
+
+
+	List<Content> listByType(List<ContentType> contentType, MerchantStore store)
+			throws ServiceException;
+
+	List<ContentDescription> listNameByType(List<ContentType> contentType,
+			MerchantStore store, Language language) throws ServiceException;
+
+	Content getByLanguage(Long id, Language language) throws ServiceException;
+
+	ContentDescription getBySeUrl(MerchantStore store, String seUrl);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/content/service/ContentServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/content/service/ContentServiceImpl.java
new file mode 100755
index 0000000..d8c53d3
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/content/service/ContentServiceImpl.java
@@ -0,0 +1,390 @@
+package com.salesmanager.core.business.content.service;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.Assert;
+
+import com.salesmanager.core.business.content.dao.ContentDao;
+import com.salesmanager.core.business.content.model.Content;
+import com.salesmanager.core.business.content.model.ContentDescription;
+import com.salesmanager.core.business.content.model.ContentType;
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.modules.cms.content.StaticContentFileManager;
+
+@Service( "contentService" )
+public class ContentServiceImpl
+    extends SalesManagerEntityServiceImpl<Long, Content>
+    implements ContentService
+{
+
+    private static final Logger LOG = LoggerFactory.getLogger( ContentServiceImpl.class );
+
+    private final ContentDao contentDao;
+
+    @Autowired
+    StaticContentFileManager staticContentFileManager;
+    
+    @Autowired
+    StaticContentFileManager contentFileManager;
+
+    @Autowired
+    public ContentServiceImpl( final ContentDao contentDao )
+    {
+        super( contentDao );
+
+        this.contentDao = contentDao;
+    }
+
+    @Override
+    public List<Content> listByType( final ContentType contentType, final MerchantStore store, final Language language )
+        throws ServiceException
+    {
+
+        return contentDao.listByType( contentType, store, language );
+    }
+    
+    @Override
+    public void delete(Content content) throws ServiceException {
+    	
+    	Content c = this.getById(content.getId());
+    	super.delete(c);
+    	
+    	
+    }
+    
+    @Override
+    public Content getByLanguage(Long id, Language language) throws ServiceException {
+    	return contentDao.getByLanguage(id, language);
+    }
+    
+
+
+    @Override
+    public List<Content> listByType( final List<ContentType> contentType, final MerchantStore store, final Language language )
+        throws ServiceException
+    {
+
+
+        return contentDao.listByType( contentType, store, language );
+    }
+    
+    @Override
+    public List<ContentDescription> listNameByType( final List<ContentType> contentType, final MerchantStore store, final Language language )
+            throws ServiceException
+    {
+
+
+            return contentDao.listNameByType(contentType, store, language);
+    }
+    
+    @Override
+    public List<Content> listByType( final List<ContentType> contentType, final MerchantStore store )
+    throws ServiceException
+    {
+
+
+	    return contentDao.listByType( contentType, store );
+    }
+
+    @Override
+    public Content getByCode( final String code, final MerchantStore store )
+        throws ServiceException
+    {
+
+        return contentDao.getByCode( code, store );
+
+    }
+    
+    @Override
+    public Content getById( Long id ) {
+    	return contentDao.getById(id);
+    }
+
+    @Override
+    public void saveOrUpdate( final Content content )
+        throws ServiceException
+    {
+
+        // save or update (persist and attach entities
+        if ( content.getId() != null && content.getId() > 0 )
+        {
+            super.update( content );
+        }
+        else
+        {
+            super.save( content );
+        }
+
+    }
+
+    @Override
+    public Content getByCode( final String code, final MerchantStore store, final Language language )
+        throws ServiceException
+    {
+        return contentDao.getByCode( code, store, language );
+    }
+
+    /**
+     * Method responsible for adding content file for given merchant store in underlying Infinispan tree
+     * cache. It will take  {@link InputContentFile} and will store file for given merchant store according to its type.
+     * it can save an image or any type of file (pdf, css, js ...)
+     * @param merchantStoreCode Merchant store
+     * @param contentFile {@link InputContentFile} being stored
+     * @throws ServiceException service exception
+     */
+    @Override
+    public void addContentFile( final String merchantStoreCode, final InputContentFile contentFile )
+        throws ServiceException
+    {
+        Assert.notNull( merchantStoreCode, "Merchant store Id can not be null" );
+        Assert.notNull( contentFile, "InputContentFile image can not be null" );
+        Assert.notNull( contentFile.getFileContentType(), "InputContentFile.fileContentType can not be null" );
+        
+        if(contentFile.getFileContentType().name().equals(FileContentType.IMAGE.name())
+        		|| contentFile.getFileContentType().name().equals(FileContentType.STATIC_FILE.name())) {
+        	addFile(merchantStoreCode,contentFile);
+        } else {
+        	addImage(merchantStoreCode,contentFile);
+        }
+        
+       
+
+    }
+    
+    @Override
+    public void addLogo( final String merchantStoreCode, InputContentFile cmsContentImage )
+    throws ServiceException {
+    	
+    	
+		    Assert.notNull( merchantStoreCode, "Merchant store Id can not be null" );
+		    Assert.notNull( cmsContentImage, "CMSContent image can not be null" );
+
+		    
+		    cmsContentImage.setFileContentType(FileContentType.LOGO);
+		    addImage(merchantStoreCode,cmsContentImage);
+		   
+
+    }
+    
+    @Override
+    public void addOptionImage( final String merchantStoreCode, InputContentFile cmsContentImage )
+    throws ServiceException {
+    	
+    	
+		    Assert.notNull( merchantStoreCode, "Merchant store Id can not be null" );
+		    Assert.notNull( cmsContentImage, "CMSContent image can not be null" );
+		    cmsContentImage.setFileContentType(FileContentType.PROPERTY);
+		    addImage(merchantStoreCode,cmsContentImage);
+		   
+
+    }
+    
+    
+    private void addImage(final String merchantStoreCode, InputContentFile contentImage ) throws ServiceException {
+    	
+    	try
+	    {
+	        LOG.info( "Adding content image for merchant id {}", merchantStoreCode);
+	        contentFileManager.addFile( merchantStoreCode, contentImage );
+	        
+	    } catch ( Exception e )
+		 {
+		        LOG.error( "Error while trying to convert input stream to buffered image", e );
+		        throw new ServiceException( e );
+		
+		 } finally {
+			 
+			 try {
+				if(contentImage.getFile()!=null) {
+					contentImage.getFile().close();
+				}
+			} catch (Exception ignore) {}
+			 
+		 }
+
+    }
+    
+    private void addFile(final String merchantStoreCode, InputContentFile contentImage ) throws ServiceException {
+    	
+    	try
+	    {
+	        LOG.info( "Adding content file for merchant id {}", merchantStoreCode);
+	        staticContentFileManager.addFile(merchantStoreCode, contentImage);
+	        
+	    } catch ( Exception e )
+		 {
+		        LOG.error( "Error while trying to convert input stream to buffered image", e );
+		        throw new ServiceException( e );
+		
+		 } finally {
+			 
+			 try {
+				if(contentImage.getFile()!=null) {
+					contentImage.getFile().close();
+				}
+			} catch (Exception ignore) {}
+		 }
+
+    }
+
+
+
+    /**
+     * Method responsible for adding list of content images for given merchant store in underlying Infinispan tree
+     * cache. It will take list of {@link CMSContentImage} and will store them for given merchant store.
+     * 
+     * @param merchantStoreCode Merchant store
+     * @param contentImagesList list of {@link CMSContentImage} being stored
+     * @throws ServiceException service exception
+     */
+	@Override
+	public void addContentFiles(String merchantStoreCode,
+			List<InputContentFile> contentFilesList) throws ServiceException {
+		
+        Assert.notNull( merchantStoreCode, "Merchant store ID can not be null" );
+        Assert.notEmpty( contentFilesList, "File list can not be empty" );
+        LOG.info( "Adding total {} images for given merchant",contentFilesList.size() );
+		
+        LOG.info( "Adding content images for merchant...." );
+        //contentFileManager.addImages( merchantStoreCode, contentImagesList );
+        staticContentFileManager.addFiles(merchantStoreCode, contentFilesList);
+        
+        try {
+			for(InputContentFile file : contentFilesList) {
+				if(file.getFile()!=null) {
+					file.getFile().close();
+				}
+			}
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+    /**
+     * Method to remove given content image.Images are stored in underlying system based on there name.
+     * Name will be used to search given image for removal
+     * @param contentImage
+     * @param merchantStoreCode merchant store
+     * @throws ServiceException
+     */
+	@Override
+	public void removeFile(String merchantStoreCode,
+			FileContentType fileContentType, String fileName)
+			throws ServiceException {
+        Assert.notNull( merchantStoreCode, "Merchant Store Id can not be null" );
+        Assert.notNull( fileContentType, "Content file type can not be null" );
+        Assert.notNull( fileName, "Content Image type can not be null" );
+        
+        
+        //check where to remove the file
+        if(fileContentType.name().equals(FileContentType.IMAGE.name())
+        		|| fileContentType.name().equals(FileContentType.STATIC_FILE.name())) {
+        	staticContentFileManager.removeFile(merchantStoreCode, fileContentType, fileName);
+        } else {
+        	contentFileManager.removeFile( merchantStoreCode, fileContentType, fileName );
+        }
+		
+	}
+
+    /**
+     * Method to remove all images for a given merchant.It will take merchant store as an input and will
+     * remove all images associated with given merchant store.
+     * 
+     * @param merchantStoreCode
+     * @throws ServiceException
+     */
+	@Override
+	public void removeFiles(String merchantStoreCode) throws ServiceException {
+        Assert.notNull( merchantStoreCode, "Merchant Store Id can not be null" );
+        
+
+        
+        contentFileManager.removeFiles( merchantStoreCode );
+        staticContentFileManager.removeFiles(merchantStoreCode);
+		
+	}
+
+	
+    /**
+     * Implementation for getContentImage method defined in {@link ContentService} interface. Methods will return
+     * Content image with given image name for the Merchant store or will return null if no image with given name found
+     * for requested Merchant Store in Infinispan tree cache.
+     * 
+     * @param store Merchant merchantStoreCode
+     * @param imageName name of requested image
+     * @return {@link OutputContentImage}
+     * @throws ServiceException
+     */
+	@Override
+	public OutputContentFile getContentFile(String merchantStoreCode,
+			FileContentType fileContentType, String fileName)
+			throws ServiceException {
+        Assert.notNull( merchantStoreCode, "Merchant store ID can not be null" );
+        Assert.notNull( fileName, "File name can not be null" );
+        
+        if(fileContentType.name().equals(FileContentType.IMAGE.name())
+        		|| fileContentType.name().equals(FileContentType.STATIC_FILE.name())) {
+        	return staticContentFileManager.getFile(merchantStoreCode, fileContentType, fileName);
+        	
+        } else {
+        	return contentFileManager.getFile( merchantStoreCode, fileContentType, fileName );
+        }
+        
+
+	}
+
+    /**
+     * Implementation for getContentImages method defined in {@link ContentService} interface. Methods will return list of all
+     * Content image associated with given  Merchant store or will return empty list if no image is associated with
+     * given Merchant Store in Infinispan tree cache.
+     * 
+     * @param merchantStoreId Merchant store
+     * @return list of {@link OutputContentImage}
+     * @throws ServiceException
+     */
+	@Override
+	public List<OutputContentFile> getContentFiles(String merchantStoreCode,
+			FileContentType fileContentType) throws ServiceException {
+        Assert.notNull( merchantStoreCode, "Merchant store Id can not be null" );
+        return staticContentFileManager.getFiles(merchantStoreCode, fileContentType);
+	}
+
+    /**
+     * Returns the image names for a given merchant and store
+     * @param merchantStoreCode
+     * @param imageContentType
+     * @return images name list
+     * @throws ServiceException
+     */
+	@Override
+	public List<String> getContentFilesNames(String merchantStoreCode,
+			FileContentType fileContentType) throws ServiceException {
+        Assert.notNull( merchantStoreCode, "Merchant store Id can not be null" );
+        
+        if(fileContentType.name().equals(FileContentType.IMAGE.name())
+        		|| fileContentType.name().equals(FileContentType.STATIC_FILE.name())) {
+        	return staticContentFileManager.getFileNames(merchantStoreCode, fileContentType);
+        } else {
+        	return contentFileManager.getFileNames(merchantStoreCode, fileContentType);
+        }
+	}
+	
+	@Override
+	public ContentDescription getBySeUrl(MerchantStore store,String seUrl) {
+		return contentDao.getBySeUrl(store, seUrl);
+	}
+
+    
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/CustomerRegistrationException.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/CustomerRegistrationException.java
new file mode 100644
index 0000000..2fce46a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/CustomerRegistrationException.java
@@ -0,0 +1,33 @@
+package com.salesmanager.core.business.customer;
+
+
+
+/**
+ * <p>Exception thrown when system able register customer
+ * </p>
+ * 
+ * @author Umesh Awasthi
+ * @since 1.2
+ *
+ */
+public class CustomerRegistrationException extends Exception
+{
+
+    private static final long serialVersionUID = 879320340641131133L;
+    
+    public CustomerRegistrationException(final String msg, final Throwable cause)
+    {
+        super(msg, cause);
+    }
+
+    public CustomerRegistrationException(final String msg)
+    {
+        super(msg);
+    }
+    
+    public CustomerRegistrationException(Throwable t)
+    {
+        super(t);
+    }
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerAttributeDao.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerAttributeDao.java
new file mode 100644
index 0000000..cd3df64
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerAttributeDao.java
@@ -0,0 +1,21 @@
+package com.salesmanager.core.business.customer.dao.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.attribute.CustomerAttribute;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+public interface CustomerAttributeDao extends SalesManagerEntityDao<Long, CustomerAttribute> {
+
+	CustomerAttribute getByOptionId(MerchantStore store, Long customerId, Long id);
+
+	List<CustomerAttribute> getByOptionValueId(MerchantStore store, Long id);
+
+	List<CustomerAttribute> getByOptionId(MerchantStore store, Long id);
+
+	List<CustomerAttribute> getByCustomerId(MerchantStore store, Long customerId);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerAttributeDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerAttributeDaoImpl.java
new file mode 100644
index 0000000..dea06d2
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerAttributeDaoImpl.java
@@ -0,0 +1,140 @@
+package com.salesmanager.core.business.customer.dao.attribute;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.customer.model.QCustomer;
+import com.salesmanager.core.business.customer.model.attribute.CustomerAttribute;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerAttribute;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionValue;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+@Repository("customerAttributeDao")
+public class CustomerAttributeDaoImpl extends SalesManagerEntityDaoImpl<Long, CustomerAttribute> 
+	implements CustomerAttributeDao {
+	
+	
+	@Override
+	public CustomerAttribute getById(Long id) {
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerAttribute)
+			.join(qCustomerAttribute.customer).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(qCustomerAttribute.id.eq(id));
+		
+		return query.uniqueResult(qCustomerAttribute);
+
+	}
+	
+	@Override
+	public CustomerAttribute getByOptionId(MerchantStore store, Long customerId, Long id) {
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomer qCustomer = QCustomer.customer;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerAttribute)
+		.join(qCustomerAttribute.customer,qCustomer).fetch()
+		.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+		.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+		.leftJoin(qCustomerOption.descriptions).fetch()
+		.leftJoin(qCustomerOptionValue.descriptions).fetch()
+		.where(qCustomerOption.merchantStore.id.eq(store.getId())
+				.and(qCustomerOption.id.eq(id))
+				.and(qCustomer.id.eq(customerId)));
+
+		
+		return query.uniqueResult(qCustomerAttribute);
+	}
+	
+	@Override
+	public List<CustomerAttribute> getByCustomerId(MerchantStore store, Long customerId) {
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomer qCustomer = QCustomer.customer;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		
+		query.from(qCustomerAttribute)
+		.join(qCustomerAttribute.customer,qCustomer).fetch()
+		.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+		.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+		.leftJoin(qCustomerOption.descriptions).fetch()
+		.leftJoin(qCustomerOptionValue.descriptions).fetch()
+		.where(qCustomerOption.merchantStore.id.eq(store.getId())
+				.and(qCustomer.id.eq(customerId)));
+
+		System.out.println("done");
+		
+		return query.listDistinct(qCustomerAttribute);
+	}
+	
+	@Override
+	public List<CustomerAttribute> getByOptionValueId(MerchantStore store, Long id) {
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerAttribute)
+		.join(qCustomerAttribute.customer).fetch()
+		.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+		.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+		.leftJoin(qCustomerOption.descriptions).fetch()
+		.leftJoin(qCustomerOptionValue.descriptions).fetch()
+		.where(qCustomerOptionValue.merchantStore.id.eq(store.getId())
+				.and(qCustomerOptionValue.id.eq(id)));
+
+		
+		return query.list(qCustomerAttribute);
+	}
+	
+	@Override
+	public List<CustomerAttribute> getByOptionId(MerchantStore store, Long id) {
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerAttribute)
+		.join(qCustomerAttribute.customer).fetch()
+		.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+		.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+		.leftJoin(qCustomerOption.descriptions).fetch()
+		.leftJoin(qCustomerOptionValue.descriptions).fetch()
+		.where(qCustomerOptionValue.merchantStore.id.eq(store.getId())
+				.and(qCustomerOption.id.eq(id)));
+
+		
+		return query.list(qCustomerAttribute);
+	}
+
+
+	
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionDao.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionDao.java
new file mode 100644
index 0000000..1dc0ed9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionDao.java
@@ -0,0 +1,28 @@
+package com.salesmanager.core.business.customer.dao.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.attribute.CustomerOption;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CustomerOptionDao extends SalesManagerEntityDao<Long, CustomerOption> {
+
+	List<CustomerOption> listByStore(MerchantStore store, Language language);
+
+
+
+	void saveOrUpdate(CustomerOption entity) throws ServiceException;
+
+
+	/**
+	 * Get a unique CustomerOption by code
+	 * @param store
+	 * @param optionCode
+	 * @return
+	 */
+	CustomerOption getByCode(MerchantStore store, String optionCode);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionDaoImpl.java
new file mode 100644
index 0000000..312613a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionDaoImpl.java
@@ -0,0 +1,107 @@
+package com.salesmanager.core.business.customer.dao.attribute;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("customerOptionDao")
+public class CustomerOptionDaoImpl extends SalesManagerEntityDaoImpl<Long, CustomerOption>
+		implements CustomerOptionDao {
+	
+	@Override
+	public List<CustomerOption> listByStore(MerchantStore store, Language language) {
+		
+
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionDescription qCustomerOptionDescription = QCustomerOptionDescription.customerOptionDescription;
+		
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOption)
+			.leftJoin(qCustomerOption.descriptions, qCustomerOptionDescription).fetch()
+			.leftJoin(qCustomerOption.merchantStore).fetch()
+			.where(qCustomerOption.merchantStore.id.eq(store.getId())
+			.and(qCustomerOptionDescription.language.id.eq(language.getId())))
+			.orderBy(qCustomerOption.sortOrder.asc());
+		
+		return query.listDistinct(qCustomerOption);
+
+	}
+	
+	@Override
+	public CustomerOption getById(Long id) {
+		
+		
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionDescription qCustomerOptionDescription = QCustomerOptionDescription.customerOptionDescription;
+		
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOption)
+			.leftJoin(qCustomerOption.descriptions, qCustomerOptionDescription).fetch()
+			.leftJoin(qCustomerOption.merchantStore).fetch()
+			.where(qCustomerOption.id.eq(id));
+		
+		return query.uniqueResult(qCustomerOption);
+		
+
+
+	}
+	
+	@Override
+	public CustomerOption getByCode(MerchantStore store, String optionCode) {
+		
+		
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionDescription qCustomerOptionDescription = QCustomerOptionDescription.customerOptionDescription;
+		
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOption)
+			.leftJoin(qCustomerOption.descriptions, qCustomerOptionDescription).fetch()
+			.leftJoin(qCustomerOption.merchantStore).fetch()
+			.where(qCustomerOption.merchantStore.id.eq(store.getId())
+			.and(qCustomerOption.code.eq(optionCode)));
+		
+		return query.uniqueResult(qCustomerOption);
+		
+
+
+	}
+	
+
+	
+	@Override
+	public void saveOrUpdate(CustomerOption entity) throws ServiceException {
+
+		if(entity.getId()!=null && entity.getId()>0) {
+
+			super.update(entity);
+			
+		} else {
+			
+			super.save(entity);
+			
+		}
+		
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionSetDao.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionSetDao.java
new file mode 100644
index 0000000..0f1f9f5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionSetDao.java
@@ -0,0 +1,26 @@
+package com.salesmanager.core.business.customer.dao.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionSet;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CustomerOptionSetDao extends SalesManagerEntityDao<Long, CustomerOptionSet> {
+
+	List<CustomerOptionSet> getByOptionId(MerchantStore store, Long id);
+
+	List<CustomerOptionSet> listByStore(MerchantStore store, Language language);
+
+	CustomerOptionSet getById(Long customerOptionSetId);
+
+	List<CustomerOptionSet> getByOptionValueId(MerchantStore store, Long id);
+
+
+
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionSetDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionSetDaoImpl.java
new file mode 100644
index 0000000..8079ce9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionSetDaoImpl.java
@@ -0,0 +1,150 @@
+package com.salesmanager.core.business.customer.dao.attribute;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionSet;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionDescription;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionSet;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionValue;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionValueDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("customerOptionSetDao")
+public class CustomerOptionSetDaoImpl extends SalesManagerEntityDaoImpl<Long, CustomerOptionSet> implements CustomerOptionSetDao {
+	
+
+	@Override
+	public CustomerOptionSet getById(Long customerOptionSetId) {
+		QCustomerOptionSet qCustomerOptionSet= QCustomerOptionSet.customerOptionSet;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOptionSet)
+			.join(qCustomerOptionSet.customerOption,qCustomerOption).fetch()
+			.join(qCustomerOptionSet.customerOptionValue,qCustomerOptionValue).fetch()
+			.join(qCustomerOption.merchantStore).fetch()
+			.join(qCustomerOptionValue.merchantStore).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(qCustomerOptionSet.id.eq(customerOptionSetId)
+			);
+		
+		return query.uniqueResult(qCustomerOptionSet);
+
+
+	}
+	
+	@Override
+	public List<CustomerOptionSet> getByOptionId(MerchantStore store, Long id) {
+		QCustomerOptionSet qCustomerOptionSet= QCustomerOptionSet.customerOptionSet;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOptionSet)
+			.join(qCustomerOptionSet.customerOption,qCustomerOption).fetch()
+			.join(qCustomerOption.merchantStore).fetch()
+			.join(qCustomerOptionSet.customerOptionValue,qCustomerOptionValue).fetch()
+			.join(qCustomerOptionValue.merchantStore).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(qCustomerOption.id.eq(id)
+					.and(qCustomerOption.merchantStore.id.eq(store.getId())));
+
+		
+		return query.list(qCustomerOptionSet);
+	}
+	
+	@Override
+	public List<CustomerOptionSet> getByOptionValueId(MerchantStore store, Long id) {
+		QCustomerOptionSet qCustomerOptionSet= QCustomerOptionSet.customerOptionSet;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOptionSet)
+			.join(qCustomerOptionSet.customerOption,qCustomerOption).fetch()
+			.join(qCustomerOption.merchantStore).fetch()
+			.join(qCustomerOptionSet.customerOptionValue,qCustomerOptionValue).fetch()
+			.join(qCustomerOptionValue.merchantStore).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(qCustomerOptionValue.id.eq(id)
+					.and(qCustomerOption.merchantStore.id.eq(store.getId())));
+
+		
+		return query.list(qCustomerOptionSet);
+	}
+	
+	@Override
+	public List<CustomerOptionSet> listByStore(MerchantStore store, Language language) {
+
+		
+		QCustomerOptionSet qCustomerOptionSet= QCustomerOptionSet.customerOptionSet;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionDescription qCustomerOptionDescription = QCustomerOptionDescription.customerOptionDescription;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		QCustomerOptionValueDescription qCustomerOptionValueDescription = QCustomerOptionValueDescription.customerOptionValueDescription;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOptionSet)
+			.join(qCustomerOptionSet.customerOption,qCustomerOption).fetch()
+			.join(qCustomerOptionSet.customerOptionValue,qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions,qCustomerOptionDescription).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions,qCustomerOptionValueDescription).fetch()
+			.where(qCustomerOption.merchantStore.id.eq(store.getId())
+			.and(qCustomerOptionDescription.language.id.eq(language.getId()))
+			.and(qCustomerOptionValueDescription.language.id.eq(language.getId()))
+			).orderBy(qCustomerOptionSet.sortOrder.asc());
+
+		
+		return query.list(qCustomerOptionSet);
+		
+		
+		
+/*		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct cos from CustomerOptionSet as cos ");
+		qs.append("join fetch cos.customerOption po ");
+		qs.append("join fetch cos.customerOptionValue ov ");
+		qs.append("join fetch po.merchantStore pm ");
+		qs.append("left join fetch po.descriptions pop ");
+		qs.append("left join fetch ov.descriptions ovd ");
+		qs.append("where pm.id =:mid ");
+		qs.append("and pop.language.id =:lid ");
+		qs.append("and ovd.language.id =:lid ");
+		qs.append("order by cos.sortOrder asc");
+		
+		String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+
+    	q.setParameter("mid", store.getId());
+    	q.setParameter("lid", language.getId());
+
+		
+		@SuppressWarnings("unchecked")
+		List<CustomerOptionSet> returnList = q.getResultList();
+		return returnList;*/
+	}
+	
+
+	
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionValueDao.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionValueDao.java
new file mode 100644
index 0000000..d7b9753
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionValueDao.java
@@ -0,0 +1,18 @@
+package com.salesmanager.core.business.customer.dao.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionValue;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CustomerOptionValueDao extends SalesManagerEntityDao<Long, CustomerOptionValue> {
+
+	List<CustomerOptionValue> listByStore(MerchantStore store, Language language);
+
+	CustomerOptionValue getByCode(MerchantStore store, String optionValueCode);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionValueDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionValueDaoImpl.java
new file mode 100644
index 0000000..88c1bbe
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/attribute/CustomerOptionValueDaoImpl.java
@@ -0,0 +1,92 @@
+package com.salesmanager.core.business.customer.dao.attribute;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionValue;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionValue;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionValueDescription;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("customerOptionValueDao")
+public class CustomerOptionValueDaoImpl extends SalesManagerEntityDaoImpl<Long, CustomerOptionValue>
+		implements CustomerOptionValueDao {
+	
+	
+	@Override
+	public List<CustomerOptionValue> listByStore(MerchantStore store, Language language) {
+		
+		
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		QCustomerOptionValueDescription qCustomerOptionValueDescription = QCustomerOptionValueDescription.customerOptionValueDescription;
+		
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOptionValue)
+			.leftJoin(qCustomerOptionValue.descriptions, qCustomerOptionValueDescription).fetch()
+			.leftJoin(qCustomerOptionValue.merchantStore).fetch()
+			.where(qCustomerOptionValue.merchantStore.id.eq(store.getId())
+			.and(qCustomerOptionValueDescription.language.id.eq(language.getId())))
+			.orderBy(qCustomerOptionValue.sortOrder.asc());
+		
+		return query.listDistinct(qCustomerOptionValue);
+
+		
+	}
+	
+
+	
+
+	
+	@Override
+	public CustomerOptionValue getById(Long id) {
+		
+		
+		
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		QCustomerOptionValueDescription qCustomerOptionValueDescription = QCustomerOptionValueDescription.customerOptionValueDescription;
+		
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOptionValue)
+			.leftJoin(qCustomerOptionValue.descriptions, qCustomerOptionValueDescription).fetch()
+			.leftJoin(qCustomerOptionValue.merchantStore).fetch()
+			.where(qCustomerOptionValue.id.eq(id));
+		
+		return query.uniqueResult(qCustomerOptionValue);
+
+	}
+	
+	@Override
+	public CustomerOptionValue getByCode(MerchantStore store, String optionValueCode) {
+		
+		
+		
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		QCustomerOptionValueDescription qCustomerOptionValueDescription = QCustomerOptionValueDescription.customerOptionValueDescription;
+		
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomerOptionValue)
+			.leftJoin(qCustomerOptionValue.descriptions, qCustomerOptionValueDescription).fetch()
+			.leftJoin(qCustomerOptionValue.merchantStore).fetch()
+			.where(qCustomerOptionValue.merchantStore.id.eq(store.getId())
+			.and(qCustomerOptionValue.code.eq(optionValueCode)));
+		
+		return query.uniqueResult(qCustomerOptionValue);
+
+	}
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/CustomerDAO.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/CustomerDAO.java
new file mode 100644
index 0000000..3688b10
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/CustomerDAO.java
@@ -0,0 +1,24 @@
+package com.salesmanager.core.business.customer.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerCriteria;
+import com.salesmanager.core.business.customer.model.CustomerList;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+public interface CustomerDAO extends SalesManagerEntityDao<Long, Customer> {
+	
+	public List<Customer> getByName(String name);
+
+	List<Customer> listByStore(MerchantStore store);
+
+	Customer getByNick(String nick);
+
+	CustomerList listByStore(MerchantStore store, CustomerCriteria criteria);
+
+	Customer getByNick(String nick, int storeId);
+	
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/CustomerDAOImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/CustomerDAOImpl.java
new file mode 100644
index 0000000..69aa086
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/dao/CustomerDAOImpl.java
@@ -0,0 +1,332 @@
+package com.salesmanager.core.business.customer.dao;
+
+import java.util.List;
+
+import javax.persistence.NoResultException;
+import javax.persistence.Query;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.BooleanBuilder;
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerCriteria;
+import com.salesmanager.core.business.customer.model.CustomerList;
+import com.salesmanager.core.business.customer.model.QCustomer;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerAttribute;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.QCustomerOptionValue;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.merchant.model.QMerchantStore;
+import com.salesmanager.core.business.reference.country.model.QCountry;
+import com.salesmanager.core.business.reference.zone.model.QZone;
+
+@Repository("customerDao")
+public class CustomerDAOImpl extends SalesManagerEntityDaoImpl<Long, Customer> implements CustomerDAO {
+
+	public CustomerDAOImpl() {
+		super();
+	}
+	
+	
+	@Override
+	public Customer getById(Long id){
+		QCustomer qCustomer = QCustomer.customer;
+		QCountry qCountry = QCountry.country;
+		QZone qZone = QZone.zone;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomer)
+			.join(qCustomer.merchantStore).fetch()
+			//.leftJoin(qCustomer.billing.country,qCountry).fetch()
+			//.leftJoin(qCustomer.billing.zone,qZone).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(qCustomer.id.eq(id));
+		
+		return query.uniqueResult(qCustomer);
+	}
+	
+
+	
+	@Override
+	public List<Customer> getByName(String name){
+		QCustomer qCustomer = QCustomer.customer;
+		QCountry qCountry = QCountry.country;
+		QZone qZone = QZone.zone;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomer)
+			.join(qCustomer.merchantStore).fetch()
+			//.leftJoin(qCustomer.billing.country,qCountry).fetch()
+			//.leftJoin(qCustomer.billing.zone,qZone).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(
+					qCustomer.billing.firstName.eq(name).or(qCustomer.billing.lastName.eq(name))
+					
+			);
+		
+		return query.list(qCustomer);
+	}
+	
+	@Override
+	public CustomerList listByStore(MerchantStore store, CustomerCriteria criteria) {
+		
+		
+		
+		CustomerList customerList = new CustomerList();
+		StringBuilder countBuilderSelect = new StringBuilder();
+		countBuilderSelect.append("select count(c) from Customer as c");
+		
+		StringBuilder countBuilderWhere = new StringBuilder();
+		countBuilderWhere.append(" where c.merchantStore.id=:mId");
+
+		if(!StringUtils.isBlank(criteria.getName())) {
+			countBuilderWhere.append(" and c.billing.firstName like:nm");
+			countBuilderWhere.append(" or c.billing.lastName like:nm");
+		}
+		
+		if(!StringUtils.isBlank(criteria.getFirstName())) {
+			countBuilderWhere.append(" and c..billing.firstName like:fn");
+		}
+		
+		if(!StringUtils.isBlank(criteria.getLastName())) {
+			countBuilderWhere.append(" and c.billing.lastName like:ln");
+		}
+		
+		if(!StringUtils.isBlank(criteria.getEmail())) {
+			countBuilderWhere.append(" and c.emailAddress like:email");
+		}
+		
+		if(!StringUtils.isBlank(criteria.getCountry())) {
+			countBuilderWhere.append(" and c.billing.country.isoCode like:country");
+		}
+
+		Query countQ = super.getEntityManager().createQuery(
+				countBuilderSelect.toString() + countBuilderWhere.toString());
+
+		countQ.setParameter("mId", store.getId());
+		
+
+		if(!StringUtils.isBlank(criteria.getName())) {
+			countQ.setParameter("nm",new StringBuilder().append("%").append(criteria.getName()).append("%").toString());
+		}
+		
+		if(!StringUtils.isBlank(criteria.getFirstName())) {
+			countQ.setParameter("fn",new StringBuilder().append("%").append(criteria.getFirstName()).append("%").toString());
+		}
+		
+		if(!StringUtils.isBlank(criteria.getLastName())) {
+			countQ.setParameter("ln",new StringBuilder().append("%").append(criteria.getLastName()).append("%").toString());
+		}
+		
+		if(!StringUtils.isBlank(criteria.getEmail())) {
+			countQ.setParameter("email",new StringBuilder().append("%").append(criteria.getEmail()).append("%").toString());
+		}
+		
+		if(!StringUtils.isBlank(criteria.getCountry())) {
+			countQ.setParameter("country",new StringBuilder().append("%").append(criteria.getCountry()).append("%").toString());
+		}
+		
+
+
+		Number count = (Number) countQ.getSingleResult ();
+
+		customerList.setTotalCount(count.intValue());
+		
+        if(count.intValue()==0)
+        	return customerList;
+		
+		
+		
+		QCustomer qCustomer = QCustomer.customer;
+		QCountry qCountry = QCountry.country;
+		QZone qZone = QZone.zone;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomer)
+			.join(qCustomer.merchantStore).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch();
+
+			query.where(qCustomer.merchantStore.id.eq(store.getId()));
+			BooleanBuilder pBuilder = null;
+
+		if(!StringUtils.isBlank(criteria.getName())) {
+			if(pBuilder==null) {
+				pBuilder = new BooleanBuilder();
+			}
+			pBuilder.and(qCustomer.billing.firstName.like(new StringBuilder().append("%").append(criteria.getName()).append("%").toString())
+					.or(qCustomer.billing.lastName.like(new StringBuilder().append("%").append(criteria.getName()).append("%").toString())));
+
+		}
+		
+		
+		if(!StringUtils.isBlank(criteria.getFirstName())) {
+			if(pBuilder==null) {
+				pBuilder = new BooleanBuilder();
+			}
+			pBuilder.and(qCustomer.billing.firstName.like(new StringBuilder().append("%").append(criteria.getFirstName()).append("%").toString()));
+		}
+		
+		if(!StringUtils.isBlank(criteria.getLastName())) {
+			if(pBuilder==null) {
+				pBuilder = new BooleanBuilder();
+			}
+			pBuilder.and(qCustomer.billing.lastName.like(new StringBuilder().append("%").append(criteria.getLastName()).append("%").toString()));
+		}
+		
+		if(!StringUtils.isBlank(criteria.getEmail())) {
+			if(pBuilder==null) {
+				pBuilder = new BooleanBuilder();
+			}
+			pBuilder.and(qCustomer.emailAddress.like(new StringBuilder().append("%").append(criteria.getEmail()).append("%").toString()));
+		}
+		
+		if(!StringUtils.isBlank(criteria.getCountry())) {
+			if(pBuilder==null) {
+				pBuilder = new BooleanBuilder();
+			}
+			pBuilder.and(qCustomer.billing.country.isoCode.like(new StringBuilder().append("%").append(criteria.getCountry()).append("%").toString()));
+		}
+		
+		if(pBuilder!=null) {
+			query.where(pBuilder);
+		}
+		
+
+		
+		if(criteria.getMaxCount()>0) {
+			query.limit(criteria.getMaxCount());
+			query.offset(criteria.getStartIndex());
+		}
+		
+		
+		customerList.setCustomers(query.list(qCustomer));
+
+		return customerList;
+		
+	}
+	
+
+	@Override
+	public Customer getByNick(String nick){
+		QCustomer qCustomer = QCustomer.customer;
+		QCountry qCountry = QCountry.country;
+		QZone qZone = QZone.zone;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomer)
+			.join(qCustomer.merchantStore).fetch()
+			//.leftJoin(qCustomer.billing.country,qCountry).fetch()
+			//.leftJoin(qCustomer.billing.zone,qZone).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.groups).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(qCustomer.nick.eq(nick));
+		
+		return query.uniqueResult(qCustomer);
+	}
+	
+	@Override
+	public Customer getByNick(String nick, int storeId){
+		QCustomer qCustomer = QCustomer.customer;
+		QMerchantStore qMerchantStore = QMerchantStore.merchantStore;
+		QCountry qCountry = QCountry.country;
+		QZone qZone = QZone.zone;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		try {
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomer)
+			.join(qCustomer.merchantStore, qMerchantStore).fetch()
+			//.leftJoin(qCustomer.billing.country,qCountry).fetch()
+			//.leftJoin(qCustomer.billing.zone,qZone).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.groups).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(qCustomer.nick.eq(nick).and(qMerchantStore.id.eq(storeId)));
+		
+		return query.uniqueResult(qCustomer);
+		
+		} catch(NoResultException nre) {
+			return null;
+		}
+	}
+	
+	@Override
+	public List<Customer> listByStore(MerchantStore store){
+		QCustomer qCustomer = QCustomer.customer;
+		QCountry qCountry = QCountry.country;
+		QZone qZone = QZone.zone;
+		QCustomerAttribute qCustomerAttribute = QCustomerAttribute.customerAttribute;
+		QCustomerOption qCustomerOption = QCustomerOption.customerOption;
+		QCustomerOptionValue qCustomerOptionValue = QCustomerOptionValue.customerOptionValue;
+		
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCustomer)
+			.join(qCustomer.merchantStore).fetch()
+			//.leftJoin(qCustomer.billing.country,qCountry).fetch()
+			//.leftJoin(qCustomer.billing.zone,qZone).fetch()
+			.leftJoin(qCustomer.defaultLanguage).fetch()
+			.leftJoin(qCustomer.attributes,qCustomerAttribute).fetch()
+			.leftJoin(qCustomerAttribute.customerOption, qCustomerOption).fetch()
+			.leftJoin(qCustomerAttribute.customerOptionValue, qCustomerOptionValue).fetch()
+			.leftJoin(qCustomerOption.descriptions).fetch()
+			.leftJoin(qCustomerOptionValue.descriptions).fetch()
+			.where(qCustomer.merchantStore.id.eq(store.getId()));
+		
+		return query.list(qCustomer);
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/exception/CustomerNotFoundException.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/exception/CustomerNotFoundException.java
new file mode 100644
index 0000000..ccb3ff7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/exception/CustomerNotFoundException.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.business.customer.exception;
+
+public class CustomerNotFoundException extends Exception
+{
+
+   private static final long serialVersionUID = 132801185016247023L;
+
+    public CustomerNotFoundException(final String msg, final Throwable cause)
+    {
+        super(msg, cause);
+    }
+
+    public CustomerNotFoundException(final String msg)
+    {
+        super(msg);
+    }
+    
+    public CustomerNotFoundException(Throwable t)
+    {
+        super(t);
+    }
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerAttribute.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerAttribute.java
new file mode 100644
index 0000000..043e599
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerAttribute.java
@@ -0,0 +1,104 @@
+package com.salesmanager.core.business.customer.model.attribute;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name="CUSTOMER_ATTRIBUTE", schema=SchemaConstant.SALESMANAGER_SCHEMA,
+	uniqueConstraints={
+		@UniqueConstraint(columnNames={
+				"OPTION_ID",
+				"CUSTOMER_ID"
+			})
+	}
+)
+public class CustomerAttribute extends SalesManagerEntity<Long, CustomerAttribute> {
+	private static final long serialVersionUID = -6537491946539803265L;
+	
+	@Id
+	@Column(name = "CUSTOMER_ATTRIBUTE_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "CUST_ATTR_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="OPTION_ID", nullable=false)
+	private CustomerOption customerOption;
+	
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="OPTION_VALUE_ID", nullable=false)
+	private CustomerOptionValue customerOptionValue;
+	
+	@Column(name="CUSTOMER_ATTR_TXT_VAL")
+	private String textValue;
+
+
+	@ManyToOne(targetEntity = Customer.class)
+	@JoinColumn(name = "CUSTOMER_ID", nullable = false)
+	private Customer customer;
+	
+	public CustomerAttribute() {
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+	public CustomerOption getCustomerOption() {
+		return customerOption;
+	}
+
+	public void setCustomerOption(CustomerOption customerOption) {
+		this.customerOption = customerOption;
+	}
+
+	public CustomerOptionValue getCustomerOptionValue() {
+		return customerOptionValue;
+	}
+
+	public void setCustomerOptionValue(CustomerOptionValue customerOptionValue) {
+		this.customerOptionValue = customerOptionValue;
+	}
+
+
+	public Customer getCustomer() {
+		return customer;
+	}
+
+	public void setCustomer(Customer customer) {
+		this.customer = customer;
+	}
+
+	public void setTextValue(String textValue) {
+		this.textValue = textValue;
+	}
+
+	public String getTextValue() {
+		return textValue;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOption.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOption.java
new file mode 100644
index 0000000..467e2f7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOption.java
@@ -0,0 +1,182 @@
+package com.salesmanager.core.business.customer.model.attribute;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+import javax.validation.Valid;
+import javax.validation.constraints.Pattern;
+
+import org.hibernate.annotations.Index;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@Table(name="CUSTOMER_OPTION", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints=
+	@UniqueConstraint(columnNames = {"MERCHANT_ID", "CUSTOMER_OPT_CODE"}))
+public class CustomerOption extends SalesManagerEntity<Long, CustomerOption> {
+	private static final long serialVersionUID = -2019269055342226086L;
+	
+	@Id
+	@Column(name="CUSTOMER_OPTION_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "CUSTOMER_OPTION_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column(name="SORT_ORDER")
+	private Integer sortOrder = 0;
+	
+	@Column(name="CUSTOMER_OPTION_TYPE", length=10)
+	private String customerOptionType;
+	
+	@NotEmpty
+	@Pattern(regexp="^[a-zA-Z0-9_]*$")
+	@Column(name="CUSTOMER_OPT_CODE")
+	@Index(name="CUST_OPT_CODE_IDX")
+	private String code;
+	
+	@Column(name="CUSTOMER_OPT_ACTIVE")
+	private boolean active;
+	
+	@Column(name="CUSTOMER_OPT_PUBLIC")
+	private boolean publicOption;
+	
+	@Valid
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "customerOption")
+	private Set<CustomerOptionDescription> descriptions = new HashSet<CustomerOptionDescription>();
+	
+	@Transient
+	private List<CustomerOptionDescription> descriptionsList = new ArrayList<CustomerOptionDescription>();
+
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	public CustomerOption() {
+	}
+	
+
+	
+	public Set<CustomerOptionDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(Set<CustomerOptionDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+	
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public void setDescriptionsList(List<CustomerOptionDescription> descriptionsList) {
+		this.descriptionsList = descriptionsList;
+	}
+
+	public List<CustomerOptionDescription> getDescriptionsList() {
+		return descriptionsList;
+	}
+	
+
+	public List<CustomerOptionDescription> getDescriptionsSettoList() {
+		if(descriptionsList==null || descriptionsList.size()==0) {
+			descriptionsList = new ArrayList<CustomerOptionDescription>(this.getDescriptions());
+		} 
+		return descriptionsList;
+
+	}
+
+	public String getCustomerOptionType() {
+		return customerOptionType;
+	}
+
+
+
+	public void setCustomerOptionType(String customerOptionType) {
+		this.customerOptionType = customerOptionType;
+	}
+
+
+
+	public String getCode() {
+		return code;
+	}
+
+
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+
+
+	public boolean isActive() {
+		return active;
+	}
+
+
+
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+
+
+	public boolean isPublicOption() {
+		return publicOption;
+	}
+
+
+
+	public void setPublicOption(boolean publicOption) {
+		this.publicOption = publicOption;
+	}
+
+
+
+	public void setSortOrder(Integer sortOrder) {
+		this.sortOrder = sortOrder;
+	}
+
+
+
+	public Integer getSortOrder() {
+		return sortOrder;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionDescription.java
new file mode 100644
index 0000000..9d31fd6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionDescription.java
@@ -0,0 +1,58 @@
+package com.salesmanager.core.business.customer.model.attribute;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import org.hibernate.annotations.Type;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name="CUSTOMER_OPTION_DESC", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints={
+	@UniqueConstraint(columnNames={
+			"CUSTOMER_OPTION_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class CustomerOptionDescription extends Description {
+	private static final long serialVersionUID = -3158504904707188465L;
+	
+	@ManyToOne(targetEntity = CustomerOption.class)
+	@JoinColumn(name = "CUSTOMER_OPTION_ID", nullable = false)
+	private CustomerOption customerOption;
+	
+	@Column(name="CUSTOMER_OPTION_COMMENT")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String customerOptionComment;
+	
+
+	
+	public CustomerOptionDescription() {
+	}
+
+	public CustomerOption getCustomerOption() {
+		return customerOption;
+	}
+
+	public void setCustomerOption(CustomerOption customerOption) {
+		this.customerOption = customerOption;
+	}
+
+	public String getCustomerOptionComment() {
+		return customerOptionComment;
+	}
+
+	public void setCustomerOptionComment(String customerOptionComment) {
+		this.customerOptionComment = customerOptionComment;
+	}
+
+
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionSet.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionSet.java
new file mode 100644
index 0000000..98d04ea
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionSet.java
@@ -0,0 +1,92 @@
+package com.salesmanager.core.business.customer.model.attribute;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name="CUSTOMER_OPTION_SET", schema=SchemaConstant.SALESMANAGER_SCHEMA,
+	uniqueConstraints={
+		@UniqueConstraint(columnNames={
+				"CUSTOMER_OPTION_ID",
+				"CUSTOMER_OPTION_VALUE_ID"
+			})
+	}
+)
+public class CustomerOptionSet extends SalesManagerEntity<Long, CustomerOptionSet> {
+
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@Column(name = "CUSTOMER_OPTIONSET_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "CUST_OPTSET_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="CUSTOMER_OPTION_ID", nullable=false)
+	private CustomerOption customerOption = null;
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="CUSTOMER_OPTION_VALUE_ID", nullable=false)
+	private CustomerOptionValue customerOptionValue = null;
+	
+
+
+	@Column(name="SORT_ORDER")
+	private Integer sortOrder = new Integer(0);
+	
+
+
+	public int getSortOrder() {
+		return sortOrder;
+	}
+
+	public void setSortOrder(int sortOrder) {
+		this.sortOrder = sortOrder;
+	}
+
+	public void setCustomerOptionValue(CustomerOptionValue customerOptionValue) {
+		this.customerOptionValue = customerOptionValue;
+	}
+
+	public CustomerOptionValue getCustomerOptionValue() {
+		return customerOptionValue;
+	}
+
+	public void setCustomerOption(CustomerOption customerOption) {
+		this.customerOption = customerOption;
+	}
+
+	public CustomerOption getCustomerOption() {
+		return customerOption;
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionType.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionType.java
new file mode 100644
index 0000000..97ef780
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.customer.model.attribute;
+
+public enum CustomerOptionType {
+	
+	Text, Radio, Select, Checkbox
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionValue.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionValue.java
new file mode 100644
index 0000000..af34d60
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionValue.java
@@ -0,0 +1,154 @@
+package com.salesmanager.core.business.customer.model.attribute;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+import javax.validation.Valid;
+import javax.validation.constraints.Pattern;
+
+import org.hibernate.annotations.Index;
+import org.hibernate.validator.constraints.NotEmpty;
+import org.springframework.web.multipart.MultipartFile;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@Table(name="CUSTOMER_OPTION_VALUE", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints=
+	@UniqueConstraint(columnNames = {"MERCHANT_ID", "CUSTOMER_OPT_VAL_CODE"}))
+public class CustomerOptionValue extends SalesManagerEntity<Long, CustomerOptionValue> {
+	private static final long serialVersionUID = 3736085877929910891L;
+
+	@Id
+	@Column(name="CUSTOMER_OPTION_VALUE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "CUSTOMER_OPT_VAL_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column(name="SORT_ORDER")
+	private Integer sortOrder = 0;
+	
+	@Column(name="CUSTOMER_OPT_VAL_IMAGE")
+	private String customerOptionValueImage;
+	
+	@NotEmpty
+	@Pattern(regexp="^[a-zA-Z0-9_]*$")
+	@Column(name="CUSTOMER_OPT_VAL_CODE")
+	@Index(name="CUST_OPT_VAL_CODE_IDX")
+	private String code;
+	
+	@Transient
+	private MultipartFile image = null;
+	
+	@Valid
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "customerOptionValue")
+	private Set<CustomerOptionValueDescription> descriptions = new HashSet<CustomerOptionValueDescription>();
+	
+	@Transient
+	private List<CustomerOptionValueDescription> descriptionsList = new ArrayList<CustomerOptionValueDescription>();
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+
+	public CustomerOptionValue() {
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+	public Set<CustomerOptionValueDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(Set<CustomerOptionValueDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public void setDescriptionsList(List<CustomerOptionValueDescription> descriptionsList) {
+		this.descriptionsList = descriptionsList;
+	}
+
+	public List<CustomerOptionValueDescription> getDescriptionsList() {
+		return descriptionsList; 
+	}
+	
+	public List<CustomerOptionValueDescription> getDescriptionsSettoList() {
+		if(descriptionsList==null || descriptionsList.size()==0) {
+			descriptionsList = new ArrayList<CustomerOptionValueDescription>(this.getDescriptions());
+		} 
+		return descriptionsList;
+	}
+
+	public void setImage(MultipartFile image) {
+		this.image = image;
+	}
+
+	public MultipartFile getImage() {
+		return image;
+	}
+
+
+	public String getCustomerOptionValueImage() {
+		return customerOptionValueImage;
+	}
+
+	public void setCustomerOptionValueImage(String customerOptionValueImage) {
+		this.customerOptionValueImage = customerOptionValueImage;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+
+	public void setSortOrder(Integer sortOrder) {
+		this.sortOrder = sortOrder;
+	}
+
+	public Integer getSortOrder() {
+		return sortOrder;
+	}
+	
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionValueDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionValueDescription.java
new file mode 100644
index 0000000..33f2308
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/attribute/CustomerOptionValueDescription.java
@@ -0,0 +1,39 @@
+package com.salesmanager.core.business.customer.model.attribute;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name = "CUSTOMER_OPT_VAL_DESCRIPTION", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints={
+	@UniqueConstraint(columnNames={
+			"CUSTOMER_OPT_VAL_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class CustomerOptionValueDescription extends Description {
+	private static final long serialVersionUID = 7402155175956813576L;
+	
+	@ManyToOne(targetEntity = CustomerOptionValue.class)
+	@JoinColumn(name = "CUSTOMER_OPT_VAL_ID")
+	private CustomerOptionValue customerOptionValue;
+	
+	
+	public CustomerOptionValueDescription() {
+	}
+
+	public CustomerOptionValue getCustomerOptionValue() {
+		return customerOptionValue;
+	}
+
+	public void setCustomerOptionValue(CustomerOptionValue customerOptionValue) {
+		this.customerOptionValue = customerOptionValue;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/Customer.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/Customer.java
new file mode 100644
index 0000000..48e29f5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/Customer.java
@@ -0,0 +1,290 @@
+package com.salesmanager.core.business.customer.model;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+import javax.validation.Valid;
+
+import org.hibernate.annotations.Cascade;
+import org.hibernate.validator.constraints.Email;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.catalog.product.model.review.ProductReview;
+import com.salesmanager.core.business.customer.model.attribute.CustomerAttribute;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.user.model.Group;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+@Entity
+@Table(name = "CUSTOMER", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class Customer extends SalesManagerEntity<Long, Customer> {
+	private static final long serialVersionUID = -6966934116557219193L;
+	
+	@Id
+	@Column(name = "CUSTOMER_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+	pkColumnValue = "CUSTOMER_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.REMOVE, mappedBy = "customer")
+	private Set<CustomerAttribute> attributes = new HashSet<CustomerAttribute>();
+	
+	@Column(name="CUSTOMER_GENDER", length=1, nullable=true)
+	@Enumerated(value = EnumType.STRING)
+	private CustomerGender gender;
+
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name="CUSTOMER_DOB")
+	private Date dateOfBirth;
+	
+	@Email
+	@NotEmpty
+	@Column(name="CUSTOMER_EMAIL_ADDRESS", length=96, nullable=false)
+	private String emailAddress;
+	
+	@Column(name="CUSTOMER_NICK", length=96)
+	private String nick;
+
+	@Column(name="CUSTOMER_COMPANY", length=100)
+	private String company;
+	
+
+	@Column(name="CUSTOMER_PASSWORD", length=50)
+	private String password;
+
+	
+	@Column(name="CUSTOMER_ANONYMOUS")
+	private boolean anonymous;
+	
+
+	
+	@ManyToOne(fetch = FetchType.LAZY, targetEntity = Language.class)
+	@JoinColumn(name = "LANGUAGE_ID", nullable=false)
+	private Language defaultLanguage;
+	
+
+
+	@OneToMany(mappedBy = "customer", targetEntity = ProductReview.class)
+	private List<ProductReview> reviews = new ArrayList<ProductReview>();
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+
+	@Embedded
+	private com.salesmanager.core.business.common.model.Delivery delivery = null;
+	
+	@Valid
+	@Embedded
+	private com.salesmanager.core.business.common.model.Billing billing = null;
+	
+	
+	@ManyToMany(fetch=FetchType.LAZY, cascade = {CascadeType.REFRESH})
+	@JoinTable(name = "CUSTOMER_GROUP", schema=SchemaConstant.SALESMANAGER_SCHEMA, joinColumns = { 
+			@JoinColumn(name = "CUSTOMER_ID", nullable = false, updatable = false) }
+			, 
+			inverseJoinColumns = { @JoinColumn(name = "GROUP_ID", 
+					nullable = false, updatable = false) }
+	)
+	@Cascade({
+		org.hibernate.annotations.CascadeType.DETACH,
+		org.hibernate.annotations.CascadeType.LOCK,
+		org.hibernate.annotations.CascadeType.REFRESH,
+		org.hibernate.annotations.CascadeType.REPLICATE
+		
+	})
+	private List<Group> groups = new ArrayList<Group>();
+	
+	@Transient
+	private String showCustomerStateList;
+	
+	@Transient
+	private String showBillingStateList;
+	
+	@Transient
+	private String showDeliveryStateList;
+	
+	
+	public Customer() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+	public Date getDateOfBirth() {
+		return CloneUtils.clone(dateOfBirth);
+	}
+
+	public void setDateOfBirth(Date dateOfBirth) {
+		this.dateOfBirth = CloneUtils.clone(dateOfBirth);
+	}
+
+	public String getEmailAddress() {
+		return emailAddress;
+	}
+
+	public void setEmailAddress(String emailAddress) {
+		this.emailAddress = emailAddress;
+	}
+
+	public String getNick() {
+		return nick;
+	}
+
+	public void setNick(String nick) {
+		this.nick = nick;
+	}
+
+	public String getCompany() {
+		return company;
+	}
+
+	public void setCompany(String company) {
+		this.company = company;
+	}
+
+
+
+	public String getPassword() {
+		return password;
+	}
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+
+
+	public boolean isAnonymous() {
+		return anonymous;
+	}
+
+	public void setAnonymous(boolean anonymous) {
+		this.anonymous = anonymous;
+	}
+
+
+	public List<ProductReview> getReviews() {
+		return reviews;
+	}
+
+	public void setReviews(List<ProductReview> reviews) {
+		this.reviews = reviews;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setDelivery(com.salesmanager.core.business.common.model.Delivery delivery) {
+		this.delivery = delivery;
+	}
+
+	public com.salesmanager.core.business.common.model.Delivery getDelivery() {
+		return delivery;
+	}
+
+	public void setBilling(com.salesmanager.core.business.common.model.Billing billing) {
+		this.billing = billing;
+	}
+
+	public com.salesmanager.core.business.common.model.Billing getBilling() {
+		return billing;
+	}
+
+	public void setGroups(List<Group> groups) {
+		this.groups = groups;
+	}
+
+	public List<Group> getGroups() {
+		return groups;
+	}
+	public String getShowCustomerStateList() {
+		return showCustomerStateList;
+	}
+
+	public void setShowCustomerStateList(String showCustomerStateList) {
+		this.showCustomerStateList = showCustomerStateList;
+	}
+
+	public String getShowBillingStateList() {
+		return showBillingStateList;
+	}
+
+	public void setShowBillingStateList(String showBillingStateList) {
+		this.showBillingStateList = showBillingStateList;
+	}
+
+	public String getShowDeliveryStateList() {
+		return showDeliveryStateList;
+	}
+
+	public void setShowDeliveryStateList(String showDeliveryStateList) {
+		this.showDeliveryStateList = showDeliveryStateList;
+	}
+	
+	public Language getDefaultLanguage() {
+		return defaultLanguage;
+	}
+
+	public void setDefaultLanguage(Language defaultLanguage) {
+		this.defaultLanguage = defaultLanguage;
+	}
+
+	public void setAttributes(Set<CustomerAttribute> attributes) {
+		this.attributes = attributes;
+	}
+
+	public Set<CustomerAttribute> getAttributes() {
+		return attributes;
+	}
+
+	public void setGender(CustomerGender gender) {
+		this.gender = gender;
+	}
+
+	public CustomerGender getGender() {
+		return gender;
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerCriteria.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerCriteria.java
new file mode 100644
index 0000000..7873a77
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerCriteria.java
@@ -0,0 +1,43 @@
+package com.salesmanager.core.business.customer.model;
+
+import com.salesmanager.core.business.common.model.Criteria;
+
+public class CustomerCriteria extends Criteria {
+	
+	private String firstName;
+	private String lastName;
+	private String name;
+	private String email;
+	private String country;
+	public String getFirstName() {
+		return firstName;
+	}
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
+	}
+	public String getLastName() {
+		return lastName;
+	}
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getEmail() {
+		return email;
+	}
+	public void setEmail(String email) {
+		this.email = email;
+	}
+	public String getCountry() {
+		return country;
+	}
+	public void setCountry(String country) {
+		this.country = country;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerGender.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerGender.java
new file mode 100644
index 0000000..46859fd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerGender.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.customer.model;
+
+public enum CustomerGender {
+	
+	M, F
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerList.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerList.java
new file mode 100644
index 0000000..707d652
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/model/CustomerList.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.business.customer.model;
+
+import java.util.List;
+
+import com.salesmanager.core.business.common.model.EntityList;
+
+public class CustomerList extends EntityList {
+
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -3108842276158069739L;
+	private List<Customer> customers;
+	public void setCustomers(List<Customer> customers) {
+		this.customers = customers;
+	}
+	public List<Customer> getCustomers() {
+		return customers;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerAttributeService.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerAttributeService.java
new file mode 100644
index 0000000..6ec476c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerAttributeService.java
@@ -0,0 +1,29 @@
+package com.salesmanager.core.business.customer.service.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.attribute.CustomerAttribute;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+public interface CustomerAttributeService extends
+		SalesManagerEntityService<Long, CustomerAttribute> {
+
+	void saveOrUpdate(CustomerAttribute customerAttribute)
+			throws ServiceException;
+
+	CustomerAttribute getByCustomerOptionId(MerchantStore store,
+			Long customerId, Long id);
+
+	List<CustomerAttribute> getByCustomerOptionValueId(MerchantStore store,
+			Long id);
+
+	List<CustomerAttribute> getByOptionId(MerchantStore store, Long id);
+
+
+	List<CustomerAttribute> getByCustomer(MerchantStore store, Customer customer);
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerAttributeServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerAttributeServiceImpl.java
new file mode 100644
index 0000000..e7c1291
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerAttributeServiceImpl.java
@@ -0,0 +1,78 @@
+package com.salesmanager.core.business.customer.service.attribute;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.customer.dao.attribute.CustomerAttributeDao;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.attribute.CustomerAttribute;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+@Service("customerAttributeService")
+public class CustomerAttributeServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, CustomerAttribute> implements CustomerAttributeService {
+	
+	private CustomerAttributeDao customerAttributeDao;
+
+	@Autowired
+	public CustomerAttributeServiceImpl(CustomerAttributeDao customerAttributeDao) {
+		super(customerAttributeDao);
+		this.customerAttributeDao = customerAttributeDao;
+	}
+	
+
+
+
+
+	@Override
+	public void saveOrUpdate(CustomerAttribute customerAttribute)
+			throws ServiceException {
+		if(customerAttribute.getId()!=null && customerAttribute.getId()>0) {
+			customerAttributeDao.update(customerAttribute);
+		} else {
+			customerAttributeDao.save(customerAttribute);
+		}
+		
+	}
+	
+	@Override
+	public void delete(CustomerAttribute attribute) throws ServiceException {
+		
+		//override method, this allows the error that we try to remove a detached instance
+		attribute = this.getById(attribute.getId());
+		super.delete(attribute);
+		
+	}
+	
+
+
+	@Override
+	public CustomerAttribute getByCustomerOptionId(MerchantStore store, Long customerId, Long id) {
+		return customerAttributeDao.getByOptionId(store, customerId, id);
+	}
+
+
+
+	@Override
+	public List<CustomerAttribute> getByCustomer(MerchantStore store, Customer customer) {
+		return customerAttributeDao.getByCustomerId(store, customer.getId());
+	}
+
+
+	@Override
+	public List<CustomerAttribute> getByCustomerOptionValueId(MerchantStore store,
+			Long id) {
+		return customerAttributeDao.getByOptionValueId(store, id);
+	}
+	
+	@Override
+	public List<CustomerAttribute> getByOptionId(MerchantStore store,
+			Long id) {
+		return customerAttributeDao.getByOptionId(store, id);
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionService.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionService.java
new file mode 100644
index 0000000..0f43b22
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionService.java
@@ -0,0 +1,27 @@
+package com.salesmanager.core.business.customer.service.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.attribute.CustomerOption;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CustomerOptionService extends SalesManagerEntityService<Long, CustomerOption> {
+
+	List<CustomerOption> listByStore(MerchantStore store, Language language)
+			throws ServiceException;
+
+
+
+	void saveOrUpdate(CustomerOption entity) throws ServiceException;
+
+
+
+	CustomerOption getByCode(MerchantStore store, String optionCode);
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionServiceImpl.java
new file mode 100644
index 0000000..3cdc6e9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionServiceImpl.java
@@ -0,0 +1,94 @@
+package com.salesmanager.core.business.customer.service.attribute;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.customer.dao.attribute.CustomerOptionDao;
+import com.salesmanager.core.business.customer.model.attribute.CustomerAttribute;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionSet;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Service("customerOptionService")
+public class CustomerOptionServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, CustomerOption> implements CustomerOptionService {
+
+	
+	private CustomerOptionDao customerOptionDao;
+	
+	@Autowired
+	private CustomerAttributeService customerAttributeService;
+	
+	@Autowired
+	private CustomerOptionSetService customerOptionSetService;
+	
+
+	@Autowired
+	public CustomerOptionServiceImpl(
+			CustomerOptionDao customerOptionDao) {
+			super(customerOptionDao);
+			this.customerOptionDao = customerOptionDao;
+	}
+	
+	@Override
+	public List<CustomerOption> listByStore(MerchantStore store, Language language) throws ServiceException {
+
+		return customerOptionDao.listByStore(store, language);
+
+	}
+	
+
+	@Override
+	public void saveOrUpdate(CustomerOption entity) throws ServiceException {
+		
+		
+		//save or update (persist and attach entities
+		if(entity.getId()!=null && entity.getId()>0) {
+			super.update(entity);
+		} else {
+			super.save(entity);
+		}
+		
+	}
+
+
+	@Override
+	public void delete(CustomerOption customerOption) throws ServiceException {
+		
+		//remove all attributes having this option
+		List<CustomerAttribute> attributes = customerAttributeService.getByOptionId(customerOption.getMerchantStore(), customerOption.getId());
+		
+		for(CustomerAttribute attribute : attributes) {
+			customerAttributeService.delete(attribute);
+		}
+		
+		CustomerOption option = this.getById(customerOption.getId());
+		
+		List<CustomerOptionSet> optionSets = customerOptionSetService.listByOption(customerOption, customerOption.getMerchantStore());
+		
+		for(CustomerOptionSet optionSet : optionSets) {
+			customerOptionSetService.delete(optionSet);
+		}
+		
+		//remove option
+		super.delete(option);
+		
+	}
+	
+	@Override
+	public CustomerOption getByCode(MerchantStore store, String optionCode) {
+		return customerOptionDao.getByCode(store, optionCode);
+	}
+	
+
+	
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionSetService.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionSetService.java
new file mode 100644
index 0000000..cf93835
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionSetService.java
@@ -0,0 +1,35 @@
+package com.salesmanager.core.business.customer.service.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.attribute.CustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionSet;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionValue;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CustomerOptionSetService extends SalesManagerEntityService<Long, CustomerOptionSet> {
+
+
+
+	void saveOrUpdate(CustomerOptionSet entity) throws ServiceException;
+
+
+
+
+	List<CustomerOptionSet> listByStore(MerchantStore store,
+			Language language) throws ServiceException;
+
+
+
+
+	List<CustomerOptionSet> listByOption(CustomerOption option,
+			MerchantStore store) throws ServiceException;
+	
+
+	List<CustomerOptionSet> listByOptionValue(CustomerOptionValue optionValue,
+			MerchantStore store) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionSetServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionSetServiceImpl.java
new file mode 100644
index 0000000..76033c6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionSetServiceImpl.java
@@ -0,0 +1,84 @@
+package com.salesmanager.core.business.customer.service.attribute;
+
+import java.util.List;
+
+import org.apache.commons.lang.Validate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.customer.dao.attribute.CustomerOptionSetDao;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionSet;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionValue;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Service("customerOptionSetService")
+public class CustomerOptionSetServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, CustomerOptionSet> implements CustomerOptionSetService {
+
+
+	@Autowired
+	private CustomerOptionSetDao customerOptionSetDao;
+	
+
+	@Autowired
+	public CustomerOptionSetServiceImpl(
+			CustomerOptionSetDao customerOptionSetDao) {
+			super(customerOptionSetDao);
+			this.customerOptionSetDao = customerOptionSetDao;
+	}
+	
+
+	@Override
+	public List<CustomerOptionSet> listByOption(CustomerOption option, MerchantStore store) throws ServiceException {
+		Validate.notNull(store,"merchant store cannot be null");
+		Validate.notNull(option,"option cannot be null");
+		
+		return customerOptionSetDao.getByOptionId(store, option.getId());
+	}
+	
+	@Override
+	public void delete(CustomerOptionSet customerOptionSet) throws ServiceException {
+		customerOptionSet = customerOptionSetDao.getById(customerOptionSet.getId());
+		super.delete(customerOptionSet);
+	}
+	
+	@Override
+	public List<CustomerOptionSet> listByStore(MerchantStore store, Language language) throws ServiceException {
+		Validate.notNull(store,"merchant store cannot be null");
+
+		
+		return customerOptionSetDao.listByStore(store,language);
+	}
+
+
+	@Override
+	public void saveOrUpdate(CustomerOptionSet entity) throws ServiceException {
+		Validate.notNull(entity,"customer option set cannot be null");
+
+		if(entity.getId()>0) {
+			super.update(entity);
+		} else {
+			super.create(entity);
+		}
+		
+	}
+
+
+	@Override
+	public List<CustomerOptionSet> listByOptionValue(
+			CustomerOptionValue optionValue, MerchantStore store)
+			throws ServiceException {
+		return customerOptionSetDao.getByOptionValueId(store, optionValue.getId());
+	}
+
+
+	
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionValueService.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionValueService.java
new file mode 100644
index 0000000..0f6271e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionValueService.java
@@ -0,0 +1,24 @@
+package com.salesmanager.core.business.customer.service.attribute;
+
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionValue;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CustomerOptionValueService extends SalesManagerEntityService<Long, CustomerOptionValue> {
+
+
+
+	List<CustomerOptionValue> listByStore(MerchantStore store, Language language)
+			throws ServiceException;
+
+	void saveOrUpdate(CustomerOptionValue entity) throws ServiceException;
+
+	CustomerOptionValue getByCode(MerchantStore store, String optionValueCode);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionValueServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionValueServiceImpl.java
new file mode 100644
index 0000000..0b4f649
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/attribute/CustomerOptionValueServiceImpl.java
@@ -0,0 +1,94 @@
+package com.salesmanager.core.business.customer.service.attribute;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.customer.dao.attribute.CustomerOptionValueDao;
+import com.salesmanager.core.business.customer.model.attribute.CustomerAttribute;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionSet;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionValue;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Service("customerOptionValueService")
+public class CustomerOptionValueServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, CustomerOptionValue> implements
+		CustomerOptionValueService {
+
+	@Autowired
+	private CustomerAttributeService customerAttributeService;
+	
+	private CustomerOptionValueDao customerOptionValueDao;
+	
+	@Autowired
+	private CustomerOptionSetService customerOptionSetService;
+	
+	@Autowired
+	public CustomerOptionValueServiceImpl(
+			CustomerOptionValueDao customerOptionValueDao) {
+			super(customerOptionValueDao);
+			this.customerOptionValueDao = customerOptionValueDao;
+	}
+	
+	
+	@Override
+	public List<CustomerOptionValue> listByStore(MerchantStore store, Language language) throws ServiceException {
+		
+		return customerOptionValueDao.listByStore(store, language);
+	}
+	
+
+
+	
+	@Override
+	public void saveOrUpdate(CustomerOptionValue entity) throws ServiceException {
+		
+		
+		//save or update (persist and attach entities
+		if(entity.getId()!=null && entity.getId()>0) {
+
+			super.update(entity);
+			
+		} else {
+			
+			super.save(entity);
+			
+		}
+		
+	}
+	
+	
+	public void delete(CustomerOptionValue customerOptionValue) throws ServiceException {
+		
+		//remove all attributes having this option
+		List<CustomerAttribute> attributes = customerAttributeService.getByCustomerOptionValueId(customerOptionValue.getMerchantStore(), customerOptionValue.getId());
+		
+		for(CustomerAttribute attribute : attributes) {
+			customerAttributeService.delete(attribute);
+		}
+		
+		List<CustomerOptionSet> optionSets = customerOptionSetService.listByOptionValue(customerOptionValue, customerOptionValue.getMerchantStore());
+		
+		for(CustomerOptionSet optionSet : optionSets) {
+			customerOptionSetService.delete(optionSet);
+		}
+		
+		CustomerOptionValue option = super.getById(customerOptionValue.getId());
+		
+		//remove option
+		super.delete(option);
+		
+	}
+	
+	@Override
+	public CustomerOptionValue getByCode(MerchantStore store, String optionValueCode) {
+		return customerOptionValueDao.getByCode(store, optionValueCode);
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/CustomerService.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/CustomerService.java
new file mode 100644
index 0000000..386bdfd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/CustomerService.java
@@ -0,0 +1,38 @@
+package com.salesmanager.core.business.customer.service;
+
+
+import java.util.List;
+
+import com.salesmanager.core.business.common.model.Address;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerCriteria;
+import com.salesmanager.core.business.customer.model.CustomerList;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+public interface CustomerService  extends SalesManagerEntityService<Long, Customer> {
+
+	public List<Customer> getByName(String firstName);
+
+	List<Customer> listByStore(MerchantStore store);
+
+	Customer getByNick(String nick);
+	void saveOrUpdate(Customer customer) throws ServiceException ;
+
+	CustomerList listByStore(MerchantStore store, CustomerCriteria criteria);
+
+	Customer getByNick(String nick, int storeId);
+
+	/**
+	 * Return an {@link com.salesmanager.core.business.common.model.Address} object from the client IP address. Uses underlying GeoLocation module
+	 * @param store
+	 * @param ipAddress
+	 * @return
+	 * @throws ServiceException
+	 */
+	Address getCustomerAddress(MerchantStore store, String ipAddress)
+			throws ServiceException;
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/customer/service/CustomerServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/CustomerServiceImpl.java
new file mode 100644
index 0000000..6e1fb02
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/customer/service/CustomerServiceImpl.java
@@ -0,0 +1,112 @@
+package com.salesmanager.core.business.customer.service;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.common.model.Address;
+import com.salesmanager.core.business.customer.dao.CustomerDAO;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerCriteria;
+import com.salesmanager.core.business.customer.model.CustomerList;
+import com.salesmanager.core.business.customer.model.attribute.CustomerAttribute;
+import com.salesmanager.core.business.customer.service.attribute.CustomerAttributeService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.modules.utils.GeoLocation;
+
+@Service("customerService")
+public class CustomerServiceImpl extends SalesManagerEntityServiceImpl<Long, Customer> implements CustomerService {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(CustomerServiceImpl.class);
+	
+	private CustomerDAO customerDAO;
+	
+	@Autowired
+	private CustomerAttributeService customerAttributeService;
+	
+	@Autowired
+	private GeoLocation geoLocation;
+
+	
+	@Autowired
+	public CustomerServiceImpl(CustomerDAO customerDAO) {
+		super(customerDAO);
+		this.customerDAO = customerDAO;
+	}
+
+	@Override
+	public List<Customer> getByName(String firstName) {
+		return customerDAO.getByName(firstName);
+	}
+	
+	@Override
+	public Customer getById(Long id) {
+			return customerDAO.getById(id);		
+	}
+	
+	@Override
+	public Customer getByNick(String nick) {
+		return customerDAO.getByNick(nick);	
+	}
+	
+	@Override
+	public Customer getByNick(String nick, int storeId) {
+		return customerDAO.getByNick(nick, storeId);	
+	}
+	
+	@Override
+	public List<Customer> listByStore(MerchantStore store) {
+		return customerDAO.listByStore(store);
+	}
+	
+	@Override
+	public CustomerList listByStore(MerchantStore store, CustomerCriteria criteria) {
+		return customerDAO.listByStore(store,criteria);
+	}
+	
+	@Override
+	public Address getCustomerAddress(MerchantStore store, String ipAddress) throws ServiceException {
+		
+		try {
+			return geoLocation.getAddress(ipAddress);
+		} catch(Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+
+	@Override	
+	public void saveOrUpdate(Customer customer) throws ServiceException {
+
+		LOGGER.debug("Creating Customer");
+		
+		if(customer.getId()!=null && customer.getId()>0) {
+			super.update(customer);
+		} else {			
+		
+			super.create(customer);
+
+		}
+	}
+
+	public void delete(Customer customer) throws ServiceException {
+		customer = getById(customer.getId());
+		
+		//delete attributes
+		List<CustomerAttribute> attributes =customerAttributeService.getByCustomer(customer.getMerchantStore(), customer);
+		if(attributes!=null) {
+			for(CustomerAttribute attribute : attributes) {
+				customerAttributeService.delete(attribute);
+			}
+		}
+		customerDAO.delete(customer);
+
+	}
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerEntityDao.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerEntityDao.java
new file mode 100644
index 0000000..b694983
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerEntityDao.java
@@ -0,0 +1,104 @@
+package com.salesmanager.core.business.generic.dao;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.Order;
+import javax.persistence.metamodel.SingularAttribute;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+
+
+/**
+ * @param <E> type entity
+ */
+public interface SalesManagerEntityDao<K extends Serializable & Comparable<K>, E extends SalesManagerEntity<K, ?>> {
+
+	/**
+	 * @param clazz class
+	 * @param id id
+	 * @return entity
+	 */
+	E getEntity(Class<? extends E> clazz, K id);
+	
+	/**
+	 * @param id id
+	 * @return entity
+	 */
+	E getById(K id);
+	
+	/**
+	 * @param entity entity
+	 */
+	void save(E entity);
+	
+	/**
+	 * @param entity entity
+	 */
+	void update(E entity);
+	
+	/** 
+	 * @param entity entity
+	 */
+	void delete(E entity);
+	
+	/**
+	 * @param entity entity
+	 */
+	E refresh(E entity);
+	
+	/**
+	 * @return liste d'entitys
+	 */
+	List<E> list();
+	
+	/**
+	 * @return nombre d'entitys
+	 */
+	Long count();
+	
+	void flush();
+	
+	void clear();
+
+	/**
+	 * @param <V> type value
+	 * @param attribute
+	 * @param fieldValue
+	 * @return numbers of entities
+	 */
+	<V> Long countByField(SingularAttribute<? super E, V> attribute, V fieldValue);
+
+	/**
+	 * @param <V> type value
+	 * @param attribute
+	 * @param fieldValue
+	 * @return entities
+	 */
+	<V> List<E> listByField(SingularAttribute<? super E, V> attribute, V fieldValue);
+
+	/**
+	 * @param <V>
+	 * @param attribute
+	 * @param fieldValue
+	 * @return
+	 * @throws NoResultException
+	 * @throws {@link NonUniqueResultException}
+	 */
+	<V> E getByField(SingularAttribute<? super E, V> attribute, V fieldValue);
+
+	<T extends E> List<T> list(Class<T> objectClass, Expression<Boolean> filter, Integer limit, Integer offset, Order... orders);
+
+	Long count(Expression<Boolean> filter);
+	
+	EntityManager getEntityManager();
+
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerEntityDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerEntityDaoImpl.java
new file mode 100644
index 0000000..ba7e2e9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerEntityDaoImpl.java
@@ -0,0 +1,102 @@
+package com.salesmanager.core.business.generic.dao;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.Order;
+import javax.persistence.metamodel.SingularAttribute;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.generic.util.GenericEntityUtils;
+
+/**
+ * @param <T> entity type
+ */
+public abstract class SalesManagerEntityDaoImpl<K extends Serializable & Comparable<K>, E extends SalesManagerEntity<K, ?>>
+		extends SalesManagerJpaDaoSupport
+		implements SalesManagerEntityDao<K, E> {
+	
+	private Class<E> objectClass;
+	
+	@SuppressWarnings("unchecked")
+	public SalesManagerEntityDaoImpl() {
+		this.objectClass = (Class<E>) GenericEntityUtils.getGenericEntityClassFromComponentDefinition(getClass());
+	}
+	
+	protected final Class<E> getObjectClass() {
+		return objectClass;
+	}
+	
+	
+	public E getEntity(Class<? extends E> clazz, K id) {
+		return super.getEntity(getObjectClass(), id);
+	}
+	
+	
+	public E getById(K id) {
+		return super.getEntity(getObjectClass(), id);
+	}
+	
+	
+	public <V> E getByField(SingularAttribute<? super E, V> attribute, V fieldValue) {
+		return super.getByField(getObjectClass(), attribute, fieldValue);
+	}
+	
+	
+	public void update(E entity) {
+		super.update(entity);
+	}
+	
+	
+	public void save(E entity) {
+		super.save(entity);
+	}
+	
+	
+	public void delete(E entity) {
+		super.delete(entity);
+	}
+	
+	
+	public E refresh(E entity) {
+		return super.refresh(entity);
+	}
+	
+	
+	public List<E> list() {
+		return super.listEntity(getObjectClass());
+	}
+	
+	
+	public <V> List<E> listByField(SingularAttribute<? super E, V> attribute, V fieldValue) {
+		return super.listEntityByField(getObjectClass(), attribute, fieldValue);
+	}
+	
+	
+	public <T extends E> List<T> list(Class<T> objectClass, Expression<Boolean> filter, Integer limit, Integer offset, Order... orders) {
+		return super.listEntity(objectClass, filter, limit, offset, orders);
+	}
+	
+	
+	public Long count() {
+		return super.countEntity(getObjectClass());
+	}
+	
+	
+	public <V> Long countByField(SingularAttribute<? super E, V> attribute, V fieldValue) {
+		return super.countEntityByField(getObjectClass(), attribute, fieldValue);
+	}
+	
+	
+	public Long count(Expression<Boolean> filter) {
+		return super.countEntity(getObjectClass(), filter);
+	}
+	
+	
+	@Override
+	public EntityManager getEntityManager() {
+		return super.getEntityManager();
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerJpaDaoSupport.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerJpaDaoSupport.java
new file mode 100644
index 0000000..ab5c979
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/dao/SalesManagerJpaDaoSupport.java
@@ -0,0 +1,221 @@
+package com.salesmanager.core.business.generic.dao;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ListIterator;
+
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.persistence.PersistenceContext;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.Order;
+import javax.persistence.criteria.Root;
+import javax.persistence.metamodel.SingularAttribute;
+
+import org.springframework.stereotype.Repository;
+import org.springframework.transaction.annotation.Transactional;
+
+@Repository("entityDao")
+@Transactional
+public class SalesManagerJpaDaoSupport {
+
+	@PersistenceContext
+	private EntityManager entityManager;
+	
+	/**
+	 * Cree la requete et applique les conditions de limite / offset et retourne la {@link TypedQuery}
+	 * correspondante.
+	 * 
+	 * @param <T> le type de l'entite retournee
+	 * @param criteria
+	 * @param limit null si pas de limite
+	 * @param offset null si pas d'offset
+	 * @return la {@link TypedQuery} avec limite et offset le cas echeant
+	 */
+	protected <T> TypedQuery<T> buildTypedQuery(CriteriaQuery<T> criteria, Integer limit, Integer offset) {
+		TypedQuery<T> query = getEntityManager().createQuery(criteria);
+		if (offset != null) {
+			query.setFirstResult(offset);
+		}
+		if (limit != null) {
+			query.setMaxResults(limit);
+		}
+		return query;
+		
+	}
+	
+	protected void filterCriteriaQuery(CriteriaQuery<?> criteria, Expression<Boolean> filter) {
+		if (filter != null) {
+			criteria.where(filter);
+		}
+	}
+	
+	protected <T> Root<T> rootCriteriaQuery(CriteriaBuilder builder, CriteriaQuery<?> criteria, Class<T> objectClass) {
+		return criteria.from(objectClass);
+	}
+	
+	public <T, K> T getEntity(Class<T> clazz, K id) {
+		return getEntityManager().find(clazz, id);
+	}
+	
+	public <T, V> T getByField(Class<T> clazz, SingularAttribute<? super T, V> attribute, V fieldValue) {
+		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
+		CriteriaQuery<T> criteria = builder.createQuery(clazz);
+		Root<T> root = criteria.from(clazz);
+		criteria.where(builder.equal(root.get(attribute), fieldValue));
+		
+		try {
+			return buildTypedQuery(criteria, null, null).getSingleResult();
+		} catch (NoResultException e) {
+			return null;
+		}
+	}
+	
+	protected <T> void update(T entity) {
+		if (!getEntityManager().contains(entity)) {
+			getEntityManager().merge(entity);
+			//throw new PersistenceException("Updated entity must be attached");
+		}
+		//TODO: http://blog.xebia.com/2009/03/23/jpa-implementation-patterns-saving-detached-entities/
+	}
+	
+	protected <T> void save(T entity) {
+		getEntityManager().persist(entity);
+	}
+	
+	protected <T> void delete(T entity) {
+		if (!getEntityManager().contains(entity)) {
+			getEntityManager().merge(entity);
+			//throw new PersistenceException("Failed to delete a detached entity");
+		}
+		getEntityManager().remove(entity);
+	}
+	
+	protected <T> T refresh(T entity) {
+		getEntityManager().refresh(entity);
+		
+		return entity;
+	}
+	
+	public void flush() {
+		getEntityManager().flush();
+	}
+	
+	public void clear() {
+		getEntityManager().clear();
+	}
+	
+	protected <T> List<T> listEntity(Class<T> objectClass, Expression<Boolean> filter, Integer limit, Integer offset, Order... orders) {
+		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
+		CriteriaQuery<T> criteria = builder.createQuery(objectClass);
+		rootCriteriaQuery(builder, criteria, objectClass);
+		
+		if (filter != null) {
+			filterCriteriaQuery(criteria, filter);
+		}
+		if (orders != null && orders.length > 0) {
+			criteria.orderBy(orders);
+		}
+		TypedQuery<T> query = buildTypedQuery(criteria, limit, offset);
+		
+		List<T> entities = query.getResultList();
+		
+		if (orders == null || orders.length == 0) {
+			sort(entities);
+		}
+		
+		return entities;
+	}
+	
+	protected <T> List<T> listEntity(Class<T> objectClass) {
+		return listEntity(objectClass, null, null, null);
+	}
+	
+	protected <T> List<T> listEntity(Class<T> objectClass, Expression<Boolean> filter) {
+		return listEntity(objectClass, filter, null, null);
+	}
+	
+	protected <T, V> List<T> listEntityByField(Class<T> objectClass, SingularAttribute<? super T, V> attribute, V fieldValue) {
+		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
+		CriteriaQuery<T> criteria = builder.createQuery(objectClass);
+		
+		Root<T> root = rootCriteriaQuery(builder, criteria, objectClass);
+		criteria.where(builder.equal(root.get(attribute), fieldValue));
+		
+		List<T> entities = buildTypedQuery(criteria, null, null).getResultList();
+		
+		sort(entities);
+		
+		return entities;
+	}
+	
+	protected <T> Long countEntity(Class<T> clazz) {
+		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
+		CriteriaQuery<Long> criteria = builder.createQuery(Long.class);
+		Root<T> root = rootCriteriaQuery(builder, criteria, clazz);
+		
+		criteria.select(builder.count(root));
+		
+		return buildTypedQuery(criteria, null, null).getSingleResult();
+	}
+	
+	protected <T, V> Long countEntityByField(Class<T> clazz, SingularAttribute<? super T, V> attribute, V fieldValue) {
+		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
+		CriteriaQuery<Long> criteria = builder.createQuery(Long.class);
+		
+		Root<T> root = rootCriteriaQuery(builder, criteria, clazz);
+		criteria.select(builder.count(root));
+		
+		Expression<Boolean> filter = builder.equal(root.get(attribute), fieldValue);
+		filterCriteriaQuery(criteria, filter);
+		
+		return buildTypedQuery(criteria, null, null).getSingleResult();
+	}
+	
+	protected <T> Long countEntity(Class<T> clazz, Expression<Boolean> filter) {
+		CriteriaBuilder builder = getEntityManager().getCriteriaBuilder();
+		CriteriaQuery<Long> criteria = builder.createQuery(Long.class);
+		
+		Root<T> root = rootCriteriaQuery(builder, criteria, clazz);
+		criteria.select(builder.count(root));
+		
+		filterCriteriaQuery(criteria, filter);
+		
+		return buildTypedQuery(criteria, null, null).getSingleResult();
+	}
+	
+	protected <E> E getSingleResultOrNull(CriteriaQuery<E> cq) {
+		try {
+			return getEntityManager().createQuery(cq).getSingleResult();
+		} catch (NoResultException e) {
+			return null;
+		}
+	}
+	
+	protected <E> E getSingleResultOrNull(TypedQuery<E> tq) {
+		try {
+			return tq.getSingleResult();
+		} catch (NoResultException e) {
+			return null;
+		}
+	}
+	
+	protected EntityManager getEntityManager() {
+		return entityManager;
+	}
+	
+	@SuppressWarnings("unchecked")
+	protected <T> void sort(List<T> entities) {
+		Object[] a = entities.toArray();
+		Arrays.sort(a);
+		ListIterator<T> i = entities.listIterator();
+		for (int j = 0; j < a.length; j++) {
+			i.next();
+			i.set((T) a[j]);
+		}
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/exception/ConversionException.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/exception/ConversionException.java
new file mode 100644
index 0000000..2537042
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/exception/ConversionException.java
@@ -0,0 +1,31 @@
+/**
+ * 
+ */
+package com.salesmanager.core.business.generic.exception;
+
+/**
+ * @author Umesh A
+ *
+ */
+public class ConversionException extends Exception
+{
+  private static final long serialVersionUID = 687400310032876603L;
+  
+  public ConversionException(final String msg, final Throwable cause)
+  {
+      super(msg, cause);
+  }
+
+  public ConversionException(final String msg)
+  {
+      super(msg);
+  }
+  
+  public ConversionException(Throwable t)
+  {
+      super(t);
+  }
+  
+  
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/exception/ServiceException.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/exception/ServiceException.java
new file mode 100644
index 0000000..dccab11
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/exception/ServiceException.java
@@ -0,0 +1,71 @@
+package com.salesmanager.core.business.generic.exception;
+
+/**
+ * <p>Exception générée par les services de l'application.</p>
+ */
+public class ServiceException extends Exception {
+
+	private static final long serialVersionUID = -6854945379036729034L;
+	private int exceptionType = 0;//regular error
+	
+
+
+
+	public final static int EXCEPTION_VALIDATION = 99;
+	public final static int EXCEPTION_PAYMENT_DECLINED = 100;
+	public final static int EXCEPTION_TRANSACTION_DECLINED = 101;
+	
+	private String messageCode = null;
+
+
+
+	public void setMessageCode(String messageCode) {
+		this.messageCode = messageCode;
+	}
+
+	public ServiceException() {
+		super();
+	}
+	
+	public ServiceException(String messageCode) {
+		super();
+		this.messageCode = messageCode;
+	}
+
+	public ServiceException(String message, Throwable cause) {
+		super(message, cause);
+	}
+
+	public ServiceException(Throwable cause) {
+		super(cause);
+	}
+	
+	public ServiceException(int exceptionType) {
+		super();
+		this.exceptionType = exceptionType;
+	}
+	
+	public ServiceException(int exceptionType, String message) {
+		super(message);
+		this.exceptionType = exceptionType;
+	}
+	
+	public ServiceException(int exceptionType, String message, String messageCode) {
+		super(message);
+		this.messageCode = messageCode;
+		this.exceptionType = exceptionType;
+	}
+	
+	public int getExceptionType() {
+		return exceptionType;
+	}
+	
+	public void setExceptionType(int exceptionType) {
+		this.exceptionType = exceptionType;
+	}
+	
+	public String getMessageCode() {
+		return messageCode;
+	}
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/model/SalesManagerEntity.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/model/SalesManagerEntity.java
new file mode 100644
index 0000000..5c8662c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/model/SalesManagerEntity.java
@@ -0,0 +1,105 @@
+package com.salesmanager.core.business.generic.model;
+
+import java.io.Serializable;
+import java.text.Collator;
+import java.util.Locale;
+
+import org.hibernate.Hibernate;
+
+
+/**
+ * <p>Entité racine pour la persistence des objets via JPA.</p>
+ *
+ * @param <E> type de l'entité
+ */
+public abstract class SalesManagerEntity<K extends Serializable & Comparable<K>, E extends SalesManagerEntity<K, ?>>
+		implements Serializable, Comparable<E> {
+
+	private static final long serialVersionUID = -3988499137919577054L;
+	
+	public static final Collator DEFAULT_STRING_COLLATOR = Collator.getInstance(Locale.FRENCH);
+	
+	static {
+		DEFAULT_STRING_COLLATOR.setStrength(Collator.PRIMARY);
+	}
+	
+	/**
+	 * Retourne la valeur de l'identifiant unique.
+	 * 
+	 * @return id
+	 */
+	public abstract K getId();
+
+	/**
+	 * Définit la valeur de l'identifiant unique.
+	 * 
+	 * @param id id
+	 */
+	public abstract void setId(K id);
+	
+	/**
+	 * Indique si l'objet a déjà été persisté ou non
+	 * 
+	 * @return vrai si l'objet n'a pas encore été persisté
+	 */
+	public boolean isNew() {
+		return getId() == null;
+	}
+
+	
+	@SuppressWarnings("unchecked")
+	@Override
+	public boolean equals(Object object) {
+		if (object == null) {
+			return false;
+		}
+		if (object == this) {
+			return true;
+		}
+		
+		// l'objet peut être proxyfié donc on utilise Hibernate.getClass() pour sortir la vraie classe
+		if (Hibernate.getClass(object) != Hibernate.getClass(this)) {
+			return false;
+		}
+
+		SalesManagerEntity<K, E> entity = (SalesManagerEntity<K, E>) object; // NOSONAR : traité au-dessus mais wrapper Hibernate 
+		K id = getId();
+
+		if (id == null) {
+			return false;
+		}
+
+		return id.equals(entity.getId());
+	}
+
+	@Override
+	public int hashCode() {
+		int hash = 7;
+		
+		K id = getId();
+		hash = 31 * hash + ((id == null) ? 0 : id.hashCode());
+
+		return hash;
+	}
+
+	public int compareTo(E o) {
+		if (this == o) {
+			return 0;
+		}
+		return this.getId().compareTo(o.getId());
+	}
+
+	@Override
+	public String toString() {
+		StringBuilder builder = new StringBuilder();
+		builder.append("entity.");
+		builder.append(Hibernate.getClass(this).getSimpleName());
+		builder.append("<");
+		builder.append(getId());
+		builder.append("-");
+		builder.append(super.toString());
+		builder.append(">");
+		
+		return builder.toString();
+	}
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/service/SalesManagerEntityService.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/service/SalesManagerEntityService.java
new file mode 100644
index 0000000..6aa7420
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/service/SalesManagerEntityService.java
@@ -0,0 +1,92 @@
+package com.salesmanager.core.business.generic.service;
+
+import java.io.Serializable;
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.user.model.User;
+
+/**
+ * <p>Service racine pour la gestion des entités.</p>
+ *
+ * @param <T> type d'entité
+ */
+public interface SalesManagerEntityService<K extends Serializable & Comparable<K>, E extends SalesManagerEntity<K, ?>> extends TransactionalAspectAwareService{
+
+	/**
+	 * Crée l'entité dans la base de données. Mis à part dans les tests pour faire des sauvegardes simples, utiliser
+	 * create() car il est possible qu'il y ait des listeners sur la création d'une entité.
+	 * 
+	 * @param entity entité
+	 */
+	void save(E entity) throws ServiceException;
+	
+	/**
+	 * Met à jour l'entité dans la base de données.
+	 * 
+	 * @param entity entité
+	 */
+	void update(E entity) throws ServiceException;
+	
+	/**
+	 * Crée l'entité dans la base de données.
+	 * 
+	 * @param entity entité
+	 */
+	void create(E entity) throws ServiceException;
+
+	/**
+	 * Supprime l'entité de la base de données
+	 * 
+	 * @param entity entité
+	 */
+	void delete(E entity) throws ServiceException;
+	
+	/**
+	 * Rafraîchit l'entité depuis la base de données
+	 * 
+	 * @param entity entité
+	 */
+	E refresh(E entity);
+	
+
+	/**
+	 * Retourne une entité à partir de son id.
+	 * 
+	 * @param id identifiant
+	 * @return entité
+	 */
+	E getById(K id);
+	
+	/**
+	 * Renvoie la liste de l'ensemble des entités de ce type.
+	 * 
+	 * @return liste d'entités
+	 */
+	List<E> list();
+	
+	/**
+	 * Retourne une entité à partir de sa classe et son id.
+	 * 
+	 * @param clazz classe
+	 * @param id identifiant
+	 * @return entité
+	 */
+	E getEntity(Class<? extends E> clazz, K id);
+	
+	/**
+	 * Compte le nombre d'entités de ce type présentes dans la base.
+	 * 
+	 * @return nombre d'entités
+	 */
+	Long count();
+	
+	/**
+	 * Flushe la session.
+	 */
+	void flush();
+
+	void clear();
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/service/SalesManagerEntityServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/service/SalesManagerEntityServiceImpl.java
new file mode 100644
index 0000000..17a7fdc
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/service/SalesManagerEntityServiceImpl.java
@@ -0,0 +1,121 @@
+package com.salesmanager.core.business.generic.service;
+
+import java.io.Serializable;
+import java.util.List;
+
+import javax.persistence.metamodel.SingularAttribute;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.generic.util.GenericEntityUtils;
+
+/**
+ * @param <T> entity type
+ */
+public abstract class SalesManagerEntityServiceImpl<K extends Serializable & Comparable<K>, E extends SalesManagerEntity<K, ?>>
+	implements SalesManagerEntityService<K, E> {
+	
+	/**
+	 * Classe de l'entité, déterminé à partir des paramètres generics.
+	 */
+	private Class<E> objectClass;
+
+	private SalesManagerEntityDao<K, E> genericDao;
+
+	@SuppressWarnings("unchecked")
+	public SalesManagerEntityServiceImpl(SalesManagerEntityDao<K, E> genericDao) {
+		this.genericDao = genericDao;
+		
+		this.objectClass = (Class<E>) GenericEntityUtils.getGenericEntityClassFromComponentDefinition(getClass());
+	}
+	
+	protected final Class<E> getObjectClass() {
+		return objectClass;
+	}
+
+	
+	public E getEntity(Class<? extends E> clazz, K id) {
+		return genericDao.getEntity(clazz, id);
+	}
+
+	
+	public E getById(K id) {
+		return genericDao.getById(id);
+	}
+
+	/**
+	 * @param fieldName condition field
+	 * @param fieldValue field value
+	 * @return entity
+	 */
+	protected <V> E getByField(SingularAttribute<? super E, V> fieldName, V fieldValue) {
+		return genericDao.getByField(fieldName, fieldValue);
+	}
+	
+	
+	public void save(E entity) throws ServiceException {
+		genericDao.save(entity);
+	}
+	
+	
+	public void create(E entity) throws ServiceException {
+		createEntity(entity);
+	}
+	
+	
+	protected void createEntity(E entity) throws ServiceException {
+		save(entity);
+	}
+	
+	
+	public final void update(E entity) throws ServiceException {
+		updateEntity(entity);
+	}
+	
+	protected void updateEntity(E entity) throws ServiceException {
+		genericDao.update(entity);
+	}
+	
+	
+	public void delete(E entity) throws ServiceException {
+		genericDao.delete(entity);
+	}
+	
+	
+	public void flush() {
+		genericDao.flush();
+	}
+	
+	
+	public void clear() {
+		genericDao.clear();
+	}
+	
+	
+	public E refresh(E entity) {
+		return genericDao.refresh(entity);
+	}
+
+	
+	public List<E> list() {
+		return genericDao.list();
+	}
+	
+	/**
+	 * Renvoie la liste des entités dont le champ donné en paramètre a la bonne valeur.
+	 * 
+	 * @param fieldName le champ sur lequel appliquer la condition
+	 * @param fieldValue valeur du champ
+	 * @return liste d'entités
+	 */
+	protected <V> List<E> listByField(SingularAttribute<? super E, V> fieldName, V fieldValue) {
+		return genericDao.listByField(fieldName, fieldValue);
+	}
+	
+	
+	public Long count() {
+		return genericDao.count();
+	}
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/service/TransactionalAspectAwareService.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/service/TransactionalAspectAwareService.java
new file mode 100644
index 0000000..f7a6b0a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/service/TransactionalAspectAwareService.java
@@ -0,0 +1,12 @@
+package com.salesmanager.core.business.generic.service;
+
+/**
+ * Indique que le service doit être rendu transactionnel via un aspect.
+ * 
+ * Cela permet de simplifier la configuration Spring de la partie transactionnelle car
+ * il suffit alors de déclarer le pointcut de l'aspect sur
+ * this(com.salesmanager.core.business.generic.service.ITransactionalAspectAwareService)
+ */
+public interface TransactionalAspectAwareService {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/util/EntityManagerUtils.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/util/EntityManagerUtils.java
new file mode 100644
index 0000000..84c5ce2
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/util/EntityManagerUtils.java
@@ -0,0 +1,53 @@
+package com.salesmanager.core.business.generic.util;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContext;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.orm.jpa.EntityManagerFactoryUtils;
+import org.springframework.orm.jpa.EntityManagerHolder;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.support.TransactionSynchronizationManager;
+
+/**
+ * <p>Classe permettant de manipuler le EntityManager.</p>
+ * 
+ * <p>Utilisée dans les tests pour ouvrir la session au début d'un test et la fermet à la fin</p>
+ */
+@Component
+public class EntityManagerUtils {
+	
+	@Autowired
+	private EntityManagerFactory entityManagerFactory;
+	
+	@PersistenceContext
+	private EntityManager entityManager;
+	
+	/**
+	 * Mise en place du EntityManager
+	 */
+	public EntityManager openEntityManager() {
+		if (TransactionSynchronizationManager.hasResource(entityManagerFactory)) {
+			return ((EntityManagerHolder) TransactionSynchronizationManager.getResource(entityManagerFactory)).getEntityManager();
+		} else {
+			EntityManager entityManager = entityManagerFactory.createEntityManager();
+			TransactionSynchronizationManager.bindResource(entityManagerFactory, new EntityManagerHolder(entityManager));
+			return entityManager;
+		}
+	}
+	
+	/**
+	 * Suppression du EntityManager.
+	 */
+	public void closeEntityManager() {
+		if (TransactionSynchronizationManager.hasResource(entityManagerFactory)) {
+			EntityManagerHolder entityManagerHolder = (EntityManagerHolder) TransactionSynchronizationManager.unbindResource(entityManagerFactory);
+			EntityManagerFactoryUtils.closeEntityManager(entityManagerHolder.getEntityManager());
+		}
+	}
+	
+	public EntityManager getEntityManager() {
+		return entityManager;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/generic/util/GenericEntityUtils.java b/sm-core/src/main/java/com/salesmanager/core/business/generic/util/GenericEntityUtils.java
new file mode 100644
index 0000000..7443d04
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/generic/util/GenericEntityUtils.java
@@ -0,0 +1,44 @@
+package com.salesmanager.core.business.generic.util;
+
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+
+public final class GenericEntityUtils {
+
+	public static Class<?> getGenericEntityClassFromComponentDefinition(Class<?> clazz) {
+		int retriesCount = 0;
+		
+		while(true) {
+			if (clazz.getGenericSuperclass() instanceof ParameterizedType) {
+				Type[] argumentTypes = ((ParameterizedType) clazz.getGenericSuperclass()).getActualTypeArguments();
+				
+				for (Type argumentType : argumentTypes) {
+					Class<?> argumentClass;
+					
+					if (argumentType instanceof ParameterizedType) {
+						argumentClass = (Class<?>) ((ParameterizedType) argumentType).getRawType();
+					} else {
+						argumentClass = (Class<?>) argumentType;
+					}
+					
+					if (SalesManagerEntity.class.isAssignableFrom(argumentClass)) {
+						return argumentClass;
+					}
+				}
+			}
+			
+			clazz = clazz.getSuperclass();
+			retriesCount ++;
+			
+			if (retriesCount > 5) {
+				throw new IllegalArgumentException("Unable to find a generic type extending GenericEntity.");
+			}
+		}
+	}
+	
+	private GenericEntityUtils() {
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/merchant/dao/MerchantStoreDao.java b/sm-core/src/main/java/com/salesmanager/core/business/merchant/dao/MerchantStoreDao.java
new file mode 100644
index 0000000..8d5db68
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/merchant/dao/MerchantStoreDao.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.business.merchant.dao;
+
+import java.util.Collection;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+public interface MerchantStoreDao extends SalesManagerEntityDao<Integer, MerchantStore> {
+	
+	public Collection<Product> getProducts(MerchantStore merchantStore) throws ServiceException;
+	
+	public MerchantStore getMerchantStore(Integer merchantStoreId);
+
+	public MerchantStore getMerchantStore(String code) throws ServiceException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/merchant/dao/MerchantStoreDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/merchant/dao/MerchantStoreDaoImpl.java
new file mode 100644
index 0000000..5fc4cda
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/merchant/dao/MerchantStoreDaoImpl.java
@@ -0,0 +1,146 @@
+package com.salesmanager.core.business.merchant.dao;
+
+import java.util.Collection;
+
+import org.hibernate.Session;
+import org.hibernate.criterion.CriteriaSpecification;
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.merchant.model.QMerchantStore;
+
+
+@Repository("merchantStoreDao")
+public class MerchantStoreDaoImpl extends SalesManagerEntityDaoImpl<Integer, MerchantStore> implements MerchantStoreDao {
+
+	public MerchantStoreDaoImpl() {
+		super();
+	}
+	
+	@Override
+	public Collection<Product> getProducts(MerchantStore merchantStore) throws ServiceException {
+		
+
+		
+
+		StringBuilder qs = new StringBuilder();
+	
+		
+		qs.append("from ProductMerchant as pm, Product as p ");
+		qs.append("join fetch p.availabilities pa ");
+		qs.append("join fetch p.descriptions pd ");
+		qs.append("join fetch pa.prices pap ");
+		qs.append("join fetch pap.descriptions papd ");
+		//images
+		qs.append("left join fetch p.images images ");
+		//options
+		qs.append("left join fetch p.attributes pattr ");
+		qs.append("left join fetch pattr.productOption po ");
+		qs.append("left join fetch po.descriptions pod ");
+		qs.append("left join fetch pattr.productOptionValue pov ");
+		qs.append("left join fetch pov.descriptions povd ");
+		
+		qs.append("where pm.merchantId=:mid ");
+		qs.append("and pm.productId=p.productId ");
+
+		
+		
+		
+		
+		// TODO : WTF?
+    	String hql = qs.toString();
+		//Query q = this.entityManager.createQuery(hql);
+    	
+		Session session = (Session)super.getEntityManager().getDelegate();
+		org.hibernate.Query q = session.createQuery(qs.toString());
+		q.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
+
+		
+
+    	q.setInteger("mid", merchantStore.getId());
+    	//q.setParameterList("lid", regionList);
+    	//@TODO languageUtil
+    	//q.setParameter("lang", 1);
+		
+		Collection<Product> results = q.list();
+    	//MerchantStore s = (MerchantStore)q.getSingleResult();
+    	//Collection<Product> results = s.getProducts();
+
+		return results;
+
+		
+		
+		
+	}
+	
+	@Override
+	public MerchantStore getById(Integer id)  {
+		
+		QMerchantStore qMerchantStore = QMerchantStore.merchantStore;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		query.from(qMerchantStore)
+			.innerJoin(qMerchantStore.defaultLanguage).fetch()
+			.leftJoin(qMerchantStore.currency).fetch()
+			.leftJoin(qMerchantStore.country).fetch()
+			.leftJoin(qMerchantStore.zone).fetch()
+			.leftJoin(qMerchantStore.languages).fetch()
+			.where(qMerchantStore.id.eq(id));
+		
+		return query.uniqueResult(qMerchantStore);
+		
+	}
+	
+	@Override
+	public MerchantStore getMerchantStore(String code)   throws ServiceException {
+	
+/*		
+		String q = "from MerchantStore m join fetch m.defaultLanguage left join fetch m.currency left join fetch m.country left join fetch m.zone left join fetch m.languages where m.code=:code";
+		
+		
+		Query queryQ = super.getEntityManager().createQuery(q);
+		queryQ.setParameter("code", code);
+		
+		return (MerchantStore)queryQ.getSingleResult();*/
+		//TODO add fetch
+		QMerchantStore qMerchantStore = QMerchantStore.merchantStore;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		query.from(qMerchantStore)
+			.innerJoin(qMerchantStore.defaultLanguage).fetch()
+			.leftJoin(qMerchantStore.currency).fetch()
+			.leftJoin(qMerchantStore.country).fetch()
+			.leftJoin(qMerchantStore.zone).fetch()
+			.leftJoin(qMerchantStore.languages).fetch()
+			.where(qMerchantStore.code.eq(code));
+		
+		return query.uniqueResult(qMerchantStore);
+	}
+	
+	public MerchantStore getMerchantStore(Integer merchantStoreId) {
+		
+		
+		QMerchantStore qMerchantStore = QMerchantStore.merchantStore;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		//TODO Zone country
+		query.from(qMerchantStore)
+			.innerJoin(qMerchantStore.defaultLanguage)
+			.leftJoin(qMerchantStore.currency)
+			.leftJoin(qMerchantStore.country)
+			.leftJoin(qMerchantStore.zone)
+			.leftJoin(qMerchantStore.languages)
+			.where(qMerchantStore.id.eq(merchantStoreId));
+		
+		return query.uniqueResult(qMerchantStore);
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/merchant/model/MerchantStore.java b/sm-core/src/main/java/com/salesmanager/core/business/merchant/model/MerchantStore.java
new file mode 100755
index 0000000..35e77dd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/merchant/model/MerchantStore.java
@@ -0,0 +1,385 @@
+package com.salesmanager.core.business.merchant.model;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+import javax.validation.constraints.Pattern;
+
+import org.hibernate.validator.constraints.Email;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.constants.MeasureUnit;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+@Entity
+@Table(name = "MERCHANT_STORE", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class MerchantStore extends SalesManagerEntity<Integer, MerchantStore> {
+	private static final long serialVersionUID = 7671103335743647655L;
+	
+	
+	public final static String DEFAULT_STORE = "DEFAULT";
+	
+	@Id
+	@Column(name = "MERCHANT_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+		pkColumnValue = "STORE_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Integer id;
+
+	@NotEmpty
+	@Column(name = "STORE_NAME", nullable=false, length=100)
+	private String storename;
+	
+	@NotEmpty
+	@Pattern(regexp="^[a-zA-Z0-9_]*$")
+	@Column(name = "STORE_CODE", nullable=false, unique=true, length=100)
+	private String code;
+	
+	@NotEmpty
+	@Column(name = "STORE_PHONE", length=50)
+	private String storephone;
+
+	@Column(name = "STORE_ADDRESS")
+	private String storeaddress;
+
+	@NotEmpty
+	@Column(name = "STORE_CITY", length=100)
+	private String storecity;
+
+	@NotEmpty
+	@Column(name = "STORE_POSTAL_CODE", length=15)
+	private String storepostalcode;
+
+	@ManyToOne(fetch = FetchType.LAZY, targetEntity = Country.class)
+	@JoinColumn(name="COUNTRY_ID", nullable=false, updatable=true)
+	private Country country;
+
+	@ManyToOne(fetch = FetchType.LAZY, targetEntity = Zone.class)
+	@JoinColumn(name="ZONE_ID", nullable=true, updatable=true)
+	private Zone zone;
+
+	@Column(name = "STORE_STATE_PROV", length=100)
+	private String storestateprovince;
+	
+	@Column(name = "WEIGHTUNITCODE", length=5)
+	private String weightunitcode = MeasureUnit.LB.name();
+
+	@Column(name = "SEIZEUNITCODE", length=5)
+	private String seizeunitcode = MeasureUnit.IN.name();
+
+	@Temporal(TemporalType.DATE)
+	@Column(name = "IN_BUSINESS_SINCE")
+	private Date inBusinessSince = new Date();
+	
+	@Transient
+	private String dateBusinessSince;
+
+	@ManyToOne(fetch = FetchType.LAZY, targetEntity = Language.class)
+	@JoinColumn(name = "LANGUAGE_ID", nullable=false)
+	private Language defaultLanguage;
+
+	@NotEmpty
+	@ManyToMany(fetch = FetchType.LAZY)
+	@JoinTable(name = "MERCHANT_LANGUAGE")
+	private List<Language> languages = new ArrayList<Language>();
+	
+	@Column(name = "USE_CACHE")
+	private boolean useCache = false;
+	
+	@Column(name="STORE_TEMPLATE", length=25)
+	private String storeTemplate;
+	
+	@Column(name="INVOICE_TEMPLATE", length=25)
+	private String invoiceTemplate;
+	
+	@Column(name="DOMAIN_NAME", length=80)
+	private String domainName;
+	
+	@Column(name="CONTINUESHOPPINGURL", length=150)
+	private String continueshoppingurl;
+	
+	@Email
+	@NotEmpty
+	@Column(name = "STORE_EMAIL", length=60, nullable=false)
+	private String storeEmailAddress;
+	
+	@Column(name="STORE_LOGO", length=100)
+	private String storeLogo;
+	
+	@ManyToOne(fetch = FetchType.LAZY, targetEntity = Currency.class)
+	@JoinColumn(name = "CURRENCY_ID", nullable=false)
+	private Currency currency;
+	
+	@Column(name = "CURRENCY_FORMAT_NATIONAL")
+	private boolean currencyFormatNational;
+	
+	public MerchantStore() {
+	}
+	
+	public boolean isUseCache() {
+		return useCache;
+	}
+
+	public void setUseCache(boolean useCache) {
+		this.useCache = useCache;
+	}
+	
+	@Override
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	@Override
+	public Integer getId() {
+		return this.id;
+	}
+	
+	public String getStorename() {
+		return storename;
+	}
+
+	public void setStorename(String storename) {
+		this.storename = storename;
+	}
+
+	public String getStorephone() {
+		return storephone;
+	}
+
+	public void setStorephone(String storephone) {
+		this.storephone = storephone;
+	}
+
+	public String getStoreaddress() {
+		return storeaddress;
+	}
+
+	public void setStoreaddress(String storeaddress) {
+		this.storeaddress = storeaddress;
+	}
+
+	public String getStorecity() {
+		return storecity;
+	}
+
+	public void setStorecity(String storecity) {
+		this.storecity = storecity;
+	}
+
+	public String getStorepostalcode() {
+		return storepostalcode;
+	}
+
+	public void setStorepostalcode(String storepostalcode) {
+		this.storepostalcode = storepostalcode;
+	}
+
+	public Country getCountry() {
+		return country;
+	}
+
+	public void setCountry(Country country) {
+		this.country = country;
+	}
+
+	public Zone getZone() {
+		return zone;
+	}
+
+	public void setZone(Zone zone) {
+		this.zone = zone;
+	}
+
+	public String getStorestateprovince() {
+		return storestateprovince;
+	}
+
+	public void setStorestateprovince(String storestateprovince) {
+		this.storestateprovince = storestateprovince;
+	}
+
+	public Currency getCurrency() {
+		return currency;
+	}
+
+	public void setCurrency(Currency currency) {
+		this.currency = currency;
+	}
+
+	public String getWeightunitcode() {
+		return weightunitcode;
+	}
+
+	public void setWeightunitcode(String weightunitcode) {
+		this.weightunitcode = weightunitcode;
+	}
+
+	public String getSeizeunitcode() {
+		return seizeunitcode;
+	}
+
+	public void setSeizeunitcode(String seizeunitcode) {
+		this.seizeunitcode = seizeunitcode;
+	}
+
+
+
+	public Date getInBusinessSince() {
+		return CloneUtils.clone(inBusinessSince);
+	}
+
+	public void setInBusinessSince(Date inBusinessSince) {
+		this.inBusinessSince = CloneUtils.clone(inBusinessSince);
+	}
+
+	public Language getDefaultLanguage() {
+		return defaultLanguage;
+	}
+
+	public void setDefaultLanguage(Language defaultLanguage) {
+		this.defaultLanguage = defaultLanguage;
+	}
+
+
+
+	public List<Language> getLanguages() {
+		return languages;
+	}
+
+	public void setLanguages(List<Language> languages) {
+		this.languages = languages;
+	}
+	
+	//reverse mappings
+/*	@SuppressWarnings("unused")
+	@ManyToMany(fetch = FetchType.LAZY, mappedBy = "stores", cascade = { CascadeType.REFRESH})
+	private Set<Manufacturer> manufacturers = new HashSet<Manufacturer>();*/
+	
+	
+/*	@SuppressWarnings("unused")
+	@ManyToMany(fetch = FetchType.LAZY, mappedBy = "stores", cascade = CascadeType.REMOVE)
+	private Set<TaxClass> taxClasses = new HashSet<TaxClass>();*/
+	
+/*	@SuppressWarnings("unused")
+	@ManyToMany(fetch = FetchType.LAZY, mappedBy = "stores", cascade = CascadeType.REMOVE)
+	private Set<ProductOption> productOptions = new HashSet<ProductOption>();*/
+	
+/*	@SuppressWarnings("unused")
+	@ManyToMany(fetch = FetchType.LAZY, mappedBy = "stores", cascade = CascadeType.REMOVE)
+	private Set<ProductOptionValue> productOptionValues = new HashSet<ProductOptionValue>();*/
+	
+/*	@SuppressWarnings("unused")
+	@ManyToMany(fetch = FetchType.LAZY, mappedBy = "stores", cascade = CascadeType.REMOVE)
+	private Set<Product> products = new HashSet<Product>();*/
+	
+
+/*	
+	//TODO ManyToMany
+	@SuppressWarnings("unused")
+	@OneToMany(mappedBy = "merchant", cascade = CascadeType.REMOVE)
+	private List<TaxRate> taxRates = new ArrayList<TaxRate>();*/
+	
+
+	
+	public String getStoreLogo() {
+		return storeLogo;
+	}
+
+	public void setStoreLogo(String storeLogo) {
+		this.storeLogo = storeLogo;
+	}
+
+	public String getStoreTemplate() {
+		return storeTemplate;
+	}
+
+	public void setStoreTemplate(String storeTemplate) {
+		this.storeTemplate = storeTemplate;
+	}
+
+	public String getInvoiceTemplate() {
+		return invoiceTemplate;
+	}
+
+	public void setInvoiceTemplate(String invoiceTemplate) {
+		this.invoiceTemplate = invoiceTemplate;
+	}
+
+	public String getDomainName() {
+		return domainName;
+	}
+
+	public void setDomainName(String domainName) {
+		this.domainName = domainName;
+	}
+
+	public String getContinueshoppingurl() {
+		return continueshoppingurl;
+	}
+
+	public void setContinueshoppingurl(String continueshoppingurl) {
+		this.continueshoppingurl = continueshoppingurl;
+	}
+
+	public String getStoreEmailAddress() {
+		return storeEmailAddress;
+	}
+
+	public void setStoreEmailAddress(String storeEmailAddress) {
+		this.storeEmailAddress = storeEmailAddress;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public void setDateBusinessSince(String dateBusinessSince) {
+		this.dateBusinessSince = dateBusinessSince;
+	}
+
+	public String getDateBusinessSince() {
+		return dateBusinessSince;
+	}
+
+	public void setCurrencyFormatNational(boolean currencyFormatNational) {
+		this.currencyFormatNational = currencyFormatNational;
+	}
+
+	public boolean isCurrencyFormatNational() {
+		return currencyFormatNational;
+	}
+
+
+
+
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/merchant/service/MerchantStoreService.java b/sm-core/src/main/java/com/salesmanager/core/business/merchant/service/MerchantStoreService.java
new file mode 100755
index 0000000..10524c2
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/merchant/service/MerchantStoreService.java
@@ -0,0 +1,20 @@
+package com.salesmanager.core.business.merchant.service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+public interface MerchantStoreService extends SalesManagerEntityService<Integer, MerchantStore>{
+	
+
+	//Collection<Product> getProducts(MerchantStore merchantStore) throws ServiceException;
+	
+	//MerchantStore getMerchantStore(Integer merchantStoreId) throws ServiceException;
+
+	MerchantStore getMerchantStore(String merchantStoreCode)
+			throws ServiceException;
+	
+	MerchantStore getByCode(String code) throws ServiceException ;
+
+	void saveOrUpdate(MerchantStore store) throws ServiceException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/merchant/service/MerchantStoreServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/merchant/service/MerchantStoreServiceImpl.java
new file mode 100755
index 0000000..e1417a8
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/merchant/service/MerchantStoreServiceImpl.java
@@ -0,0 +1,159 @@
+package com.salesmanager.core.business.merchant.service;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.service.CategoryService;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.service.manufacturer.ManufacturerService;
+import com.salesmanager.core.business.catalog.product.service.type.ProductTypeService;
+import com.salesmanager.core.business.content.service.ContentService;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.service.CustomerService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.dao.MerchantStoreDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.service.OrderService;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.service.MerchantConfigurationService;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.business.tax.service.TaxClassService;
+import com.salesmanager.core.business.user.model.User;
+import com.salesmanager.core.business.user.service.UserService;
+
+@Service("merchantService")
+public class MerchantStoreServiceImpl extends SalesManagerEntityServiceImpl<Integer, MerchantStore> 
+		implements MerchantStoreService {
+	
+
+		
+	@Autowired
+	protected ProductTypeService productTypeService;
+	
+	@Autowired
+	private TaxClassService taxClassService;
+	
+	@Autowired
+	private ContentService contentService;
+	
+	@Autowired
+	private MerchantConfigurationService merchantConfigurationService;
+	
+	@Autowired
+	private CategoryService categoryService;
+	
+	@Autowired
+	private UserService userService;
+	
+	@Autowired
+	private OrderService orderService;
+	
+	@Autowired
+	private CustomerService customerService;
+	
+	@Autowired
+	private ManufacturerService manufacturerService;
+	
+	private MerchantStoreDao merchantStoreDao;
+	
+	@Autowired
+	public MerchantStoreServiceImpl(MerchantStoreDao merchantStoreDao) {
+		super(merchantStoreDao);
+		this.merchantStoreDao = merchantStoreDao;
+	}
+
+	
+	//@Override
+	public MerchantStore getMerchantStore(String merchantStoreCode) throws ServiceException {
+		return merchantStoreDao.getMerchantStore(merchantStoreCode);
+	}
+	
+	@Override
+	public void saveOrUpdate(MerchantStore store) throws ServiceException {
+		
+		if(store.getId()==null) {
+			super.save(store);
+		} else {
+			super.update(store);
+		}
+	}
+	
+
+	
+	//@Override
+	//public Collection<Product> getProducts(MerchantStore merchantStore) throws ServiceException {
+		
+
+	//	return merchantStoreDao.getProducts(merchantStore);
+		
+		
+	//}
+
+	@Override
+	public MerchantStore getByCode(String code) throws ServiceException {
+		
+		return merchantStoreDao.getMerchantStore(code);
+	}
+	
+	@Override
+	public void delete(MerchantStore merchant) throws ServiceException {
+		
+		merchant = this.getById(merchant.getId());
+		
+		
+		//reference
+		List<Manufacturer> manufacturers = manufacturerService.listByStore(merchant);
+		for(Manufacturer manufacturer : manufacturers) {
+			manufacturerService.delete(manufacturer);
+		}
+		
+		List<MerchantConfiguration> configurations = merchantConfigurationService.listByStore(merchant);
+		for(MerchantConfiguration configuration : configurations) {
+			merchantConfigurationService.delete(configuration);
+		}
+		
+
+		//TODO taxService
+		List<TaxClass> taxClasses = taxClassService.listByStore(merchant);
+		for(TaxClass taxClass : taxClasses) {
+			taxClassService.delete(taxClass);
+		}
+		
+		//content
+		contentService.removeFiles(merchant.getCode());
+		//TODO staticContentService.removeImages
+		
+		//category / product
+		List<Category> categories = categoryService.listByStore(merchant);
+		for(Category category : categories) {
+			categoryService.delete(category);
+		}
+
+		//users
+		List<User> users = userService.listByStore(merchant);
+		for(User user : users) {
+			userService.delete(user);
+		}
+		
+		//customers
+		List<Customer> customers = customerService.listByStore(merchant);
+		for(Customer customer : customers) {
+			customerService.delete(customer);
+		}
+		
+		//orders
+		List<Order> orders = orderService.listByStore(merchant);
+		for(Order order : orders) {
+			orderService.delete(order);
+		}
+		
+		super.delete(merchant);
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderaccount/OrderAccountDao.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderaccount/OrderAccountDao.java
new file mode 100644
index 0000000..3183e9e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderaccount/OrderAccountDao.java
@@ -0,0 +1,9 @@
+package com.salesmanager.core.business.order.dao.orderaccount;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.order.model.orderaccount.OrderAccount;
+
+public interface OrderAccountDao  extends SalesManagerEntityDao<Long, OrderAccount > {
+
+}
+
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderaccount/OrderAccountDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderaccount/OrderAccountDaoImpl.java
new file mode 100644
index 0000000..0a0b493
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderaccount/OrderAccountDaoImpl.java
@@ -0,0 +1,15 @@
+package com.salesmanager.core.business.order.dao.orderaccount;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.order.model.orderaccount.OrderAccount;
+
+@Repository("orderAccountDao")
+public class OrderAccountDaoImpl extends SalesManagerEntityDaoImpl<Long, OrderAccount> implements OrderAccountDao {
+
+	public OrderAccountDaoImpl() {
+		super();
+	}
+	
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderDao.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderDao.java
new file mode 100644
index 0000000..53e1c95
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderDao.java
@@ -0,0 +1,13 @@
+package com.salesmanager.core.business.order.dao;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderCriteria;
+import com.salesmanager.core.business.order.model.OrderList;
+
+public interface OrderDao extends SalesManagerEntityDao<Long, Order> {
+	
+	OrderList listByStore(MerchantStore store, OrderCriteria criteria);
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderDaoImpl.java
new file mode 100644
index 0000000..9855e0c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderDaoImpl.java
@@ -0,0 +1,173 @@
+package com.salesmanager.core.business.order.dao;
+
+import javax.persistence.Query;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.BooleanBuilder;
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.common.model.CriteriaOrderBy;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderCriteria;
+import com.salesmanager.core.business.order.model.OrderList;
+import com.salesmanager.core.business.order.model.QOrder;
+import com.salesmanager.core.business.order.model.QOrderTotal;
+import com.salesmanager.core.business.order.model.orderproduct.QOrderProduct;
+import com.salesmanager.core.business.order.model.orderproduct.QOrderProductAttribute;
+import com.salesmanager.core.business.order.model.orderstatus.QOrderStatusHistory;
+
+@Repository("orderDao")
+public class OrderDaoImpl  extends SalesManagerEntityDaoImpl<Long, Order> implements OrderDao {
+
+	public OrderDaoImpl() {
+		super();
+	}
+	
+	@Override
+	public Order getById(Long id) {
+		
+		
+		QOrder qOrder = QOrder.order;
+		QOrderProduct qOrderProduct = QOrderProduct.orderProduct;
+		QOrderTotal qOrderTotal = QOrderTotal.orderTotal;
+		QOrderStatusHistory qOrderStatusHistory = QOrderStatusHistory.orderStatusHistory;
+		QOrderProductAttribute qOrderProductAttribute = QOrderProductAttribute.orderProductAttribute;
+		//OrderAccount not loaded for now
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qOrder)
+			.join(qOrder.orderProducts, qOrderProduct).fetch()
+			.join(qOrder.orderTotal, qOrderTotal).fetch()
+			.leftJoin(qOrder.orderHistory, qOrderStatusHistory).fetch()
+			.leftJoin(qOrderProduct.downloads).fetch()
+			.leftJoin(qOrderProduct.orderAttributes,qOrderProductAttribute).fetch()
+			.leftJoin(qOrderProduct.prices).fetch()
+			.where(qOrder.id.eq(id));
+
+		
+		return query.uniqueResult(qOrder);
+		
+	}
+
+
+
+	@Override
+	public OrderList listByStore(MerchantStore store, OrderCriteria criteria) {
+
+		OrderList orderList = new OrderList();
+		StringBuilder countBuilderSelect = new StringBuilder();
+		countBuilderSelect.append("select count(o) from Order as o");
+		
+		StringBuilder countBuilderWhere = new StringBuilder();
+		countBuilderWhere.append(" where o.merchant.id=:mId");
+
+		if(!StringUtils.isBlank(criteria.getCustomerName())) {
+			countBuilderWhere.append(" and o.billing.firstName like:nm");
+			countBuilderWhere.append(" or o.billing.lastName like:nm");
+		}
+		
+		if(!StringUtils.isBlank(criteria.getPaymentMethod())) {
+			countBuilderWhere.append(" and o.paymentModuleCode like:pm");
+		}
+		
+		if(criteria.getCustomerId()!=null) {
+			countBuilderWhere.append(" and o.customerId =:cid");
+		}
+
+		Query countQ = super.getEntityManager().createQuery(
+				countBuilderSelect.toString() + countBuilderWhere.toString());
+
+		countQ.setParameter("mId", store.getId());
+		
+		if(!StringUtils.isBlank(criteria.getCustomerName())) {
+			countQ.setParameter("nm",new StringBuilder().append("%").append(criteria.getCustomerName()).append("%").toString());
+		}
+		
+		if(!StringUtils.isBlank(criteria.getPaymentMethod())) {
+			countQ.setParameter("pm",new StringBuilder().append("%").append(criteria.getPaymentMethod()).append("%").toString());
+		}
+		
+		if(criteria.getCustomerId()!=null) {
+			countQ.setParameter("cid", criteria.getCustomerId());
+		}
+		
+
+
+		Number count = (Number) countQ.getSingleResult ();
+
+		orderList.setTotalCount(count.intValue());
+		
+        if(count.intValue()==0)
+        	return orderList;
+		
+		
+		
+		QOrder qOrder = QOrder.order;
+		QOrderProduct qOrderProduct = QOrderProduct.orderProduct;
+		QOrderTotal qOrderTotal = QOrderTotal.orderTotal;
+		QOrderStatusHistory qOrderStatusHistory = QOrderStatusHistory.orderStatusHistory;
+		QOrderProductAttribute qOrderProductAttribute = QOrderProductAttribute.orderProductAttribute;
+		//OrderAccount not loaded for now
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qOrder)
+			.join(qOrder.orderProducts, qOrderProduct).fetch()
+			.join(qOrder.orderTotal, qOrderTotal).fetch()
+			.leftJoin(qOrder.orderHistory, qOrderStatusHistory).fetch()
+			.leftJoin(qOrderProduct.downloads).fetch()
+			.leftJoin(qOrderProduct.orderAttributes,qOrderProductAttribute).fetch()
+			.leftJoin(qOrderProduct.prices).fetch();
+			
+			query.where(qOrder.merchant.id.eq(store.getId()))
+			.orderBy(qOrder.id.desc());
+			BooleanBuilder pBuilder = null;
+
+		if(!StringUtils.isBlank(criteria.getCustomerName())) {
+			if(pBuilder==null) {
+				pBuilder = new BooleanBuilder();
+			}			pBuilder.and(qOrder.billing.firstName.like(new StringBuilder().append("%").append(criteria.getCustomerName()).append("%").toString())
+					.or(qOrder.billing.lastName.like(new StringBuilder().append("%").append(criteria.getCustomerName()).append("%").toString())));
+		}
+		
+		if(!StringUtils.isBlank(criteria.getPaymentMethod())) {
+			if(pBuilder==null) {
+				pBuilder = new BooleanBuilder();
+			}
+			pBuilder.and(qOrder.paymentModuleCode.stringValue().like(new StringBuilder().append("%").append(criteria.getPaymentMethod()).append("%").toString()));
+		}
+		
+		if(criteria.getCustomerId()!=null) {
+			if(pBuilder==null) {
+				pBuilder = new BooleanBuilder();
+			}
+			pBuilder.and(qOrder.customerId.eq(criteria.getCustomerId()));
+		}
+		
+		if(pBuilder!=null) {
+			query.where(pBuilder);
+		}
+		
+		if(criteria.getOrderBy().name().equals(CriteriaOrderBy.ASC)) {
+			query.orderBy(qOrder.datePurchased.asc());
+		} else {
+			query.orderBy(qOrder.datePurchased.desc());
+		}
+		
+		if(criteria.getMaxCount()>0) {
+			query.limit(criteria.getMaxCount());
+			query.offset(criteria.getStartIndex());
+		}
+		
+		
+		orderList.setOrders(query.list(qOrder));
+
+		return orderList;
+		
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDao.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDao.java
new file mode 100644
index 0000000..616f576
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDao.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.order.dao.orderproduct;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+
+public interface OrderProductDao extends SalesManagerEntityDao<Long, OrderProduct> {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDaoImpl.java
new file mode 100644
index 0000000..770d2ee
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDaoImpl.java
@@ -0,0 +1,15 @@
+package com.salesmanager.core.business.order.dao.orderproduct;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+
+@Repository("orderProductDao")
+public class OrderProductDaoImpl extends SalesManagerEntityDaoImpl<Long, OrderProduct> implements OrderProductDao{
+
+	
+	public OrderProductDaoImpl() {
+		super();
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDownloadDao.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDownloadDao.java
new file mode 100644
index 0000000..dc9ff73
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDownloadDao.java
@@ -0,0 +1,12 @@
+package com.salesmanager.core.business.order.dao.orderproduct;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload;
+
+public interface OrderProductDownloadDao extends SalesManagerEntityDao<Long, OrderProductDownload> {
+
+	List<OrderProductDownload> getByOrderId(Long orderId);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDownloadDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDownloadDaoImpl.java
new file mode 100644
index 0000000..0210992
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/orderproduct/OrderProductDownloadDaoImpl.java
@@ -0,0 +1,59 @@
+package com.salesmanager.core.business.order.dao.orderproduct;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.order.model.QOrder;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload;
+import com.salesmanager.core.business.order.model.orderproduct.QOrderProduct;
+import com.salesmanager.core.business.order.model.orderproduct.QOrderProductDownload;
+
+@Repository("orderProductDownloadDao")
+public class OrderProductDownloadDaoImpl extends SalesManagerEntityDaoImpl<Long, OrderProductDownload> implements OrderProductDownloadDao{
+
+	@Override
+	public OrderProductDownload getById(Long id) {
+		
+		QOrderProductDownload qOrderProductDownload = QOrderProductDownload.orderProductDownload;
+		QOrderProduct qOrderProduct = QOrderProduct.orderProduct;
+		QOrder qOrder = QOrder.order;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qOrderProductDownload)
+			.leftJoin(qOrderProductDownload.orderProduct, qOrderProduct).fetch()
+			.leftJoin(qOrderProduct.order, qOrder).fetch()
+			.leftJoin(qOrder.merchant).fetch()
+			.where(qOrderProductDownload.id.eq(id));
+		
+
+		
+		OrderProductDownload orderProduct = query.uniqueResult(qOrderProductDownload);
+		return orderProduct;
+	}
+	
+	@Override
+	public List<OrderProductDownload> getByOrderId(Long orderId) {
+		
+		QOrderProductDownload qOrderProductDownload = QOrderProductDownload.orderProductDownload;
+		QOrderProduct qOrderProduct = QOrderProduct.orderProduct;
+		QOrder qOrder = QOrder.order;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qOrderProductDownload)
+			.leftJoin(qOrderProductDownload.orderProduct, qOrderProduct).fetch()
+			.leftJoin(qOrderProduct.order, qOrder).fetch()
+			.leftJoin(qOrder.merchant).fetch()
+			.where(qOrder.id.eq(orderId));
+		
+
+		
+		return query.list(qOrderProductDownload);
+		
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderTotalDao.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderTotalDao.java
new file mode 100644
index 0000000..59b3981
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderTotalDao.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.order.dao;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.order.model.OrderTotal;
+
+public interface OrderTotalDao extends SalesManagerEntityDao<Long, OrderTotal > {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderTotalDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderTotalDaoImpl.java
new file mode 100644
index 0000000..8d5208f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/dao/OrderTotalDaoImpl.java
@@ -0,0 +1,15 @@
+package com.salesmanager.core.business.order.dao;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.order.model.OrderTotal;
+
+@Repository("orderTotalDao")
+public class OrderTotalDaoImpl extends SalesManagerEntityDaoImpl<Long, OrderTotal> implements OrderTotalDao {
+
+	public OrderTotalDaoImpl() {
+		super();
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/filehistory/FileHistory.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/filehistory/FileHistory.java
new file mode 100644
index 0000000..23293f7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/filehistory/FileHistory.java
@@ -0,0 +1,136 @@
+
+package com.salesmanager.core.business.order.model.filehistory;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+@Entity
+@Table (name="FILE_HISTORY", schema=SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints={
+		@UniqueConstraint(
+			columnNames={
+				"MERCHANT_ID",
+				"FILE_ID"
+			}
+		)
+	}
+)
+public class FileHistory implements Serializable {
+	private static final long serialVersionUID = 1321251632883237664L;
+	
+	@Id
+	@Column(name = "FILE_HISTORY_ID", unique = true, nullable = false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+		pkColumnValue = "FILE_HISTORY_ID_NEXT_VALUE")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@ManyToOne(targetEntity = MerchantStore.class)
+	@JoinColumn(name = "MERCHANT_ID", nullable = false)
+	private MerchantStore store;
+	
+	@Column(name = "FILE_ID")
+	private Long fileId;
+
+	@Column ( name="FILESIZE", nullable=false )
+	private Integer filesize;
+	
+	@Temporal(TemporalType.TIMESTAMP )
+	@Column ( name="DATE_ADDED", length=0, nullable=false )
+	private Date dateAdded;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column ( name="DATE_DELETED", length=0 )
+	private Date dateDeleted;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column ( name="ACCOUNTED_DATE", length=0 )
+	private Date accountedDate;
+	
+	@Column ( name="DOWNLOAD_COUNT", nullable=false )
+	private Integer downloadCount;
+	
+	public FileHistory() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public MerchantStore getStore() {
+		return store;
+	}
+
+	public void setStore(MerchantStore store) {
+		this.store = store;
+	}
+
+	public Long getFileId() {
+		return fileId;
+	}
+
+	public void setFileId(Long fileId) {
+		this.fileId = fileId;
+	}
+
+	public Integer getFilesize() {
+		return filesize;
+	}
+
+	public void setFilesize(Integer filesize) {
+		this.filesize = filesize;
+	}
+
+	public Date getDateAdded() {
+		return CloneUtils.clone(dateAdded);
+	}
+
+	public void setDateAdded(Date dateAdded) {
+		this.dateAdded = CloneUtils.clone(dateAdded);
+	}
+
+	public Date getDateDeleted() {
+		return CloneUtils.clone(dateDeleted);
+	}
+
+	public void setDateDeleted(Date dateDeleted) {
+		this.dateDeleted = CloneUtils.clone(dateDeleted);
+	}
+
+	public Date getAccountedDate() {
+		return CloneUtils.clone(accountedDate);
+	}
+
+	public void setAccountedDate(Date accountedDate) {
+		this.accountedDate = CloneUtils.clone(accountedDate);
+	}
+
+	public Integer getDownloadCount() {
+		return downloadCount;
+	}
+
+	public void setDownloadCount(Integer downloadCount) {
+		this.downloadCount = downloadCount;
+	}
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/Order.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/Order.java
new file mode 100644
index 0000000..641819c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/Order.java
@@ -0,0 +1,365 @@
+package com.salesmanager.core.business.order.model;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.LinkedHashSet;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.validation.Valid;
+
+import org.hibernate.annotations.OrderBy;
+import org.hibernate.annotations.Type;
+
+import com.salesmanager.core.business.common.model.Billing;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatus;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory;
+import com.salesmanager.core.business.order.model.payment.CreditCard;
+import com.salesmanager.core.business.payments.model.PaymentType;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+@Entity
+@Table (name="ORDERS", schema = SchemaConstant.SALESMANAGER_SCHEMA)
+public class Order extends SalesManagerEntity<Long, Order> {
+	
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@Column (name ="ORDER_ID" , unique=true , nullable=false )
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+		pkColumnValue = "ORDER_ID_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column (name ="ORDER_STATUS")
+	@Enumerated(value = EnumType.STRING)
+	private OrderStatus status;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column (name ="LAST_MODIFIED")
+	private Date lastModified;
+	
+	//the customer object can be detached. An order can exist and the customer deleted
+	@Column (name ="CUSTOMER_ID")
+	private Long customerId;
+	
+	@Temporal(TemporalType.DATE)
+	@Column (name ="DATE_PURCHASED")
+	private Date datePurchased;
+	
+	//used for an order payable on multiple installment
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column (name ="ORDER_DATE_FINISHED")
+	private Date orderDateFinished;
+	
+	//What was the exchange rate
+	@Column (name ="CURRENCY_VALUE")
+	private BigDecimal currencyValue = new BigDecimal(1);//default 1-1
+	
+	@Column (name ="ORDER_TOTAL")
+	private BigDecimal total;
+
+	@Column (name ="IP_ADDRESS")
+	private String ipAddress;
+
+	@Column (name ="CHANNEL")
+	@Enumerated(value = EnumType.STRING)
+	private OrderChannel channel;
+
+	@Column (name ="ORDER_TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private OrderType orderType = OrderType.ORDER;
+
+	@Column (name ="PAYMENT_TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private PaymentType paymentType;
+	
+	@Column (name ="PAYMENT_MODULE_CODE")
+	private String paymentModuleCode;
+	
+	
+	@Column (name ="SHIPPING_MODULE_CODE")
+	private String shippingModuleCode;
+
+	
+	@Embedded
+	private Delivery delivery = null;
+	
+	@Valid
+	@Embedded
+	private Billing billing = null;
+	
+	@Embedded
+	private CreditCard creditCard = null;
+
+	
+	@ManyToOne(targetEntity = Currency.class)
+	@JoinColumn(name = "CURRENCY_ID")
+	private Currency currency;
+	
+	@Type(type="locale")  
+	@Column (name ="LOCALE")
+	private Locale locale; 
+	
+
+
+	@ManyToOne(targetEntity = MerchantStore.class)
+	@JoinColumn(name="MERCHANTID")
+	private MerchantStore merchant;
+	
+	//@OneToMany(mappedBy = "order")
+	//private Set<OrderAccount> orderAccounts = new HashSet<OrderAccount>();
+	
+	@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
+	private Set<OrderProduct> orderProducts = new LinkedHashSet<OrderProduct>();
+	
+	@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
+	@OrderBy(clause = "sort_order asc")
+	private Set<OrderTotal> orderTotal = new LinkedHashSet<OrderTotal>();
+	
+	@OneToMany(mappedBy = "order", cascade = CascadeType.ALL)
+	@OrderBy(clause = "ORDER_STATUS_HISTORY_ID asc")
+	private Set<OrderStatusHistory> orderHistory = new LinkedHashSet<OrderStatusHistory>();
+	
+	public Order() {
+	}
+	
+	@Column (name ="CUSTOMER_EMAIL_ADDRESS", length=50, nullable=false)
+	private String customerEmailAddress;
+
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+	
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public OrderStatus getStatus() {
+		return status;
+	}
+
+	public void setStatus(OrderStatus status) {
+		this.status = status;
+	}
+
+	public Date getLastModified() {
+		return CloneUtils.clone(lastModified);
+	}
+
+	public void setLastModified(Date lastModified) {
+		this.lastModified = CloneUtils.clone(lastModified);
+	}
+
+	public Date getDatePurchased() {
+		return CloneUtils.clone(datePurchased);
+	}
+
+	public void setDatePurchased(Date datePurchased) {
+		this.datePurchased = CloneUtils.clone(datePurchased);
+	}
+
+	public Date getOrderDateFinished() {
+		return CloneUtils.clone(orderDateFinished);
+	}
+
+	public void setOrderDateFinished(Date orderDateFinished) {
+		this.orderDateFinished = CloneUtils.clone(orderDateFinished);
+	}
+
+	public BigDecimal getCurrencyValue() {
+		return currencyValue;
+	}
+
+	public void setCurrencyValue(BigDecimal currencyValue) {
+		this.currencyValue = currencyValue;
+	}
+
+	public BigDecimal getTotal() {
+		return total;
+	}
+
+	public void setTotal(BigDecimal total) {
+		this.total = total;
+	}
+
+
+	public String getIpAddress() {
+		return ipAddress;
+	}
+
+	public void setIpAddress(String ipAddress) {
+		this.ipAddress = ipAddress;
+	}
+
+
+	public String getPaymentModuleCode() {
+		return paymentModuleCode;
+	}
+
+	public void setPaymentModuleCode(String paymentModuleCode) {
+		this.paymentModuleCode = paymentModuleCode;
+	}
+
+
+
+	public String getShippingModuleCode() {
+		return shippingModuleCode;
+	}
+
+	public void setShippingModuleCode(String shippingModuleCode) {
+		this.shippingModuleCode = shippingModuleCode;
+	}
+
+
+
+	public Currency getCurrency() {
+		return currency;
+	}
+
+	public void setCurrency(Currency currency) {
+		this.currency = currency;
+	}
+
+	public MerchantStore getMerchant() {
+		return merchant;
+	}
+
+	public void setMerchant(MerchantStore merchant) {
+		this.merchant = merchant;
+	}
+
+	public Set<OrderProduct> getOrderProducts() {
+		return orderProducts;
+	}
+
+	public void setOrderProducts(Set<OrderProduct> orderProducts) {
+		this.orderProducts = orderProducts;
+	}
+
+	public Set<OrderTotal> getOrderTotal() {
+		return orderTotal;
+	}
+
+	public void setOrderTotal(Set<OrderTotal> orderTotal) {
+		this.orderTotal = orderTotal;
+	}
+
+	public Set<OrderStatusHistory> getOrderHistory() {
+		return orderHistory;
+	}
+
+	public void setOrderHistory(Set<OrderStatusHistory> orderHistory) {
+		this.orderHistory = orderHistory;
+	}
+
+
+	public void setDelivery(Delivery delivery) {
+		this.delivery = delivery;
+	}
+
+	public Delivery getDelivery() {
+		return delivery;
+	}
+
+	public void setBilling(Billing billing) {
+		this.billing = billing;
+	}
+
+	public Billing getBilling() {
+		return billing;
+	}
+
+	public Long getCustomerId() {
+		return customerId;
+	}
+
+	public void setCustomerId(Long customerId) {
+		this.customerId = customerId;
+	}
+	
+
+	public String getCustomerEmailAddress() {
+		return customerEmailAddress;
+	}
+
+	public void setCustomerEmailAddress(String customerEmailAddress) {
+		this.customerEmailAddress = customerEmailAddress;
+	}
+
+
+	public void setChannel(OrderChannel channel) {
+		this.channel = channel;
+	}
+
+
+	public OrderChannel getChannel() {
+		return channel;
+	}
+
+
+	public void setCreditCard(CreditCard creditCard) {
+		this.creditCard = creditCard;
+	}
+
+
+	public CreditCard getCreditCard() {
+		return creditCard;
+	}
+
+
+	public void setPaymentType(PaymentType paymentType) {
+		this.paymentType = paymentType;
+	}
+
+
+	public PaymentType getPaymentType() {
+		return paymentType;
+	}
+	
+	public OrderType getOrderType() {
+		return orderType;
+	}
+
+	public void setOrderType(OrderType orderType) {
+		this.orderType = orderType;
+	}
+	
+	public Locale getLocale() {
+		return locale;
+	}
+
+	public void setLocale(Locale locale) {
+		this.locale = locale;
+	}
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderaccount/OrderAccount.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderaccount/OrderAccount.java
new file mode 100644
index 0000000..dec1522
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderaccount/OrderAccount.java
@@ -0,0 +1,106 @@
+package com.salesmanager.core.business.order.model.orderaccount;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+@Entity
+@Table(name = "ORDER_ACCOUNT", schema = SchemaConstant.SALESMANAGER_SCHEMA)
+public class OrderAccount extends SalesManagerEntity<Long, OrderAccount> {
+private static final long serialVersionUID = -2429388347536330540L;
+
+	@Id
+	@Column(name = "ORDER_ACCOUNT_ID", unique = true, nullable = false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "ORDER_ACCOUNT_ID_NEXT_VALUE")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@ManyToOne
+	@JoinColumn(name = "ORDER_ID", nullable = false)
+	private Order order;
+	
+	@Temporal(TemporalType.DATE)
+	@Column(name = "ORDER_ACCOUNT_START_DATE", nullable = false, length = 0)
+	private Date orderAccountStartDate;
+	
+	@Temporal(TemporalType.DATE)
+	@Column(name = "ORDER_ACCOUNT_END_DATE", length = 0)
+	private Date orderAccountEndDate;
+
+	@Column(name = "ORDER_ACCOUNT_BILL_DAY", nullable = false)
+	private Integer orderAccountBillDay;
+
+	@OneToMany(mappedBy = "orderAccount", cascade = CascadeType.ALL)
+	private Set<OrderAccountProduct> orderAccountProducts = new HashSet<OrderAccountProduct>();
+
+	public OrderAccount() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Order getOrder() {
+		return order;
+	}
+
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+
+	public Date getOrderAccountStartDate() {
+		return CloneUtils.clone(orderAccountStartDate);
+	}
+
+	public void setOrderAccountStartDate(Date orderAccountStartDate) {
+		this.orderAccountStartDate = CloneUtils.clone(orderAccountStartDate);
+	}
+
+	public Date getOrderAccountEndDate() {
+		return CloneUtils.clone(orderAccountEndDate);
+	}
+
+	public void setOrderAccountEndDate(Date orderAccountEndDate) {
+		this.orderAccountEndDate = CloneUtils.clone(orderAccountEndDate);
+	}
+
+	public Integer getOrderAccountBillDay() {
+		return orderAccountBillDay;
+	}
+
+	public void setOrderAccountBillDay(Integer orderAccountBillDay) {
+		this.orderAccountBillDay = orderAccountBillDay;
+	}
+
+	public Set<OrderAccountProduct> getOrderAccountProducts() {
+		return orderAccountProducts;
+	}
+
+	public void setOrderAccountProducts(
+			Set<OrderAccountProduct> orderAccountProducts) {
+		this.orderAccountProducts = orderAccountProducts;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderaccount/OrderAccountProduct.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderaccount/OrderAccountProduct.java
new file mode 100644
index 0000000..b8c997a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderaccount/OrderAccountProduct.java
@@ -0,0 +1,166 @@
+package com.salesmanager.core.business.order.model.orderaccount;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+@Entity
+@Table (name="ORDER_ACCOUNT_PRODUCT", schema=SchemaConstant.SALESMANAGER_SCHEMA )
+public class OrderAccountProduct implements Serializable {
+	private static final long serialVersionUID = -7437197293537758668L;
+
+	@Id
+	@Column (name="ORDER_ACCOUNT_PRODUCT_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+		pkColumnValue = "ORDERACCOUNTPRODUCT_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long orderAccountProductId;
+
+	@ManyToOne
+	@JoinColumn(name = "ORDER_ACCOUNT_ID" , nullable=false)
+	private OrderAccount orderAccount;
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name = "ORDER_PRODUCT_ID" , nullable=false)
+	private OrderProduct orderProduct;
+
+	@Temporal(TemporalType.DATE)
+	@Column (name="ORDER_ACCOUNT_PRODUCT_ST_DT" , length=0 , nullable=false)
+	private Date orderAccountProductStartDate;
+
+	@Temporal(TemporalType.DATE)
+	@Column (name="ORDER_ACCOUNT_PRODUCT_END_DT", length=0)
+	private Date orderAccountProductEndDate;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column (name="ORDER_ACCOUNT_PRODUCT_EOT"  , length=0 )
+	private Date orderAccountProductEot;
+
+	@Temporal(TemporalType.DATE)
+	@Column (name="ORDER_ACCOUNT_PRODUCT_ACCNT_DT"  , length=0 )
+	private Date orderAccountProductAccountedDate;
+
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column (name="ORDER_ACCOUNT_PRODUCT_L_ST_DT"  , length=0 )
+	private Date orderAccountProductLastStatusDate;
+
+	@Column (name="ORDER_ACCOUNT_PRODUCT_L_TRX_ST" , nullable=false )
+	private Integer orderAccountProductLastTransactionStatus;
+
+	@Column (name="ORDER_ACCOUNT_PRODUCT_PM_FR_TY" , nullable=false )
+	private Integer orderAccountProductPaymentFrequencyType;
+
+	@Column (name="ORDER_ACCOUNT_PRODUCT_STATUS" , nullable=false )
+	private Integer orderAccountProductStatus;
+
+	public OrderAccountProduct() {
+	}
+
+	public Long getOrderAccountProductId() {
+		return orderAccountProductId;
+	}
+
+	public void setOrderAccountProductId(Long orderAccountProductId) {
+		this.orderAccountProductId = orderAccountProductId;
+	}
+
+	public OrderAccount getOrderAccount() {
+		return orderAccount;
+	}
+
+	public void setOrderAccount(OrderAccount orderAccount) {
+		this.orderAccount = orderAccount;
+	}
+
+	public OrderProduct getOrderProduct() {
+		return orderProduct;
+	}
+
+	public void setOrderProduct(OrderProduct orderProduct) {
+		this.orderProduct = orderProduct;
+	}
+
+	public Date getOrderAccountProductStartDate() {
+		return CloneUtils.clone(orderAccountProductStartDate);
+	}
+
+	public void setOrderAccountProductStartDate(Date orderAccountProductStartDate) {
+		this.orderAccountProductStartDate = CloneUtils.clone(orderAccountProductStartDate);
+	}
+
+	public Date getOrderAccountProductEndDate() {
+		return CloneUtils.clone(orderAccountProductEndDate);
+	}
+
+	public void setOrderAccountProductEndDate(Date orderAccountProductEndDate) {
+		this.orderAccountProductEndDate = CloneUtils.clone(orderAccountProductEndDate);
+	}
+
+	public Date getOrderAccountProductEot() {
+		return CloneUtils.clone(orderAccountProductEot);
+	}
+
+	public void setOrderAccountProductEot(Date orderAccountProductEot) {
+		this.orderAccountProductEot = CloneUtils.clone(orderAccountProductEot);
+	}
+
+	public Date getOrderAccountProductAccountedDate() {
+		return CloneUtils.clone(orderAccountProductAccountedDate);
+	}
+
+	public void setOrderAccountProductAccountedDate(
+			Date orderAccountProductAccountedDate) {
+		this.orderAccountProductAccountedDate = CloneUtils.clone(orderAccountProductAccountedDate);
+	}
+
+	public Date getOrderAccountProductLastStatusDate() {
+		return CloneUtils.clone(orderAccountProductLastStatusDate);
+	}
+
+	public void setOrderAccountProductLastStatusDate(
+			Date orderAccountProductLastStatusDate) {
+		this.orderAccountProductLastStatusDate = CloneUtils.clone(orderAccountProductLastStatusDate);
+	}
+
+	public Integer getOrderAccountProductLastTransactionStatus() {
+		return orderAccountProductLastTransactionStatus;
+	}
+
+	public void setOrderAccountProductLastTransactionStatus(
+			Integer orderAccountProductLastTransactionStatus) {
+		this.orderAccountProductLastTransactionStatus = orderAccountProductLastTransactionStatus;
+	}
+
+	public Integer getOrderAccountProductPaymentFrequencyType() {
+		return orderAccountProductPaymentFrequencyType;
+	}
+
+	public void setOrderAccountProductPaymentFrequencyType(
+			Integer orderAccountProductPaymentFrequencyType) {
+		this.orderAccountProductPaymentFrequencyType = orderAccountProductPaymentFrequencyType;
+	}
+
+	public Integer getOrderAccountProductStatus() {
+		return orderAccountProductStatus;
+	}
+
+	public void setOrderAccountProductStatus(Integer orderAccountProductStatus) {
+		this.orderAccountProductStatus = orderAccountProductStatus;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderChannel.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderChannel.java
new file mode 100644
index 0000000..c26c9d1
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderChannel.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.order.model;
+
+public enum OrderChannel {
+	
+	ONLINE
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderCriteria.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderCriteria.java
new file mode 100755
index 0000000..b74948d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderCriteria.java
@@ -0,0 +1,35 @@
+package com.salesmanager.core.business.order.model;
+
+import com.salesmanager.core.business.common.model.Criteria;
+
+public class OrderCriteria extends Criteria {
+	
+	private String customerName;
+	private String paymentMethod;
+	private Long customerId;
+	public void setPaymentMethod(String paymentMethod) {
+		this.paymentMethod = paymentMethod;
+	}
+	public String getPaymentMethod() {
+		return paymentMethod;
+	}
+	public void setCustomerName(String customerName) {
+		this.customerName = customerName;
+	}
+	public String getCustomerName() {
+		return customerName;
+	}
+    public Long getCustomerId()
+    {
+        return customerId;
+    }
+    public void setCustomerId( Long customerId )
+    {
+        this.customerId = customerId;
+    }
+   
+	
+	
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderList.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderList.java
new file mode 100644
index 0000000..a4ffe72
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderList.java
@@ -0,0 +1,23 @@
+package com.salesmanager.core.business.order.model;
+
+import java.util.List;
+
+import com.salesmanager.core.business.common.model.EntityList;
+
+public class OrderList extends EntityList {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -6645927228659963628L;
+	private List<Order> orders;
+
+	public void setOrders(List<Order> orders) {
+		this.orders = orders;
+	}
+
+	public List<Order> getOrders() {
+		return orders;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProduct.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProduct.java
new file mode 100644
index 0000000..1e48b5e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProduct.java
@@ -0,0 +1,140 @@
+package com.salesmanager.core.business.order.model.orderproduct;
+
+import java.math.BigDecimal;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table (name="ORDER_PRODUCT" , schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class OrderProduct extends SalesManagerEntity<Long, OrderProduct> {
+	private static final long serialVersionUID = 176131742783954627L;
+	
+	@Id
+	@Column (name="ORDER_PRODUCT_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "ORDER_PRODUCT_ID_NEXT_VALUE")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@Column (name="PRODUCT_SKU")
+	private String sku;
+
+	@Column (name="PRODUCT_NAME" , length=64 , nullable=false)
+	private String productName;
+
+	@Column (name="PRODUCT_QUANTITY")
+	private int productQuantity;
+
+	@Column (name="ONETIME_CHARGE" , nullable=false )
+	private BigDecimal oneTimeCharge;
+
+
+	@ManyToOne(targetEntity = Order.class)
+	@JoinColumn(name = "ORDER_ID", nullable = false)
+	private Order order;
+
+	@OneToMany(mappedBy = "orderProduct", cascade = CascadeType.ALL)
+	private Set<OrderProductAttribute> orderAttributes = new HashSet<OrderProductAttribute>();
+
+	@OneToMany(mappedBy = "orderProduct", cascade = CascadeType.ALL)
+	private Set<OrderProductPrice> prices = new HashSet<OrderProductPrice>();
+
+	@OneToMany(mappedBy = "orderProduct", cascade = CascadeType.ALL)
+	private Set<OrderProductDownload> downloads = new HashSet<OrderProductDownload>();
+	
+	public OrderProduct() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+	public String getProductName() {
+		return productName;
+	}
+
+	public void setProductName(String productName) {
+		this.productName = productName;
+	}
+
+	public int getProductQuantity() {
+		return productQuantity;
+	}
+
+	public void setProductQuantity(int productQuantity) {
+		this.productQuantity = productQuantity;
+	}
+
+
+
+	public Order getOrder() {
+		return order;
+	}
+
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+
+
+	public Set<OrderProductAttribute> getOrderAttributes() {
+		return orderAttributes;
+	}
+
+	public void setOrderAttributes(Set<OrderProductAttribute> orderAttributes) {
+		this.orderAttributes = orderAttributes;
+	}
+
+	public Set<OrderProductPrice> getPrices() {
+		return prices;
+	}
+
+	public void setPrices(Set<OrderProductPrice> prices) {
+		this.prices = prices;
+	}
+
+	public Set<OrderProductDownload> getDownloads() {
+		return downloads;
+	}
+
+	public void setDownloads(Set<OrderProductDownload> downloads) {
+		this.downloads = downloads;
+	}
+
+
+	public void setSku(String sku) {
+		this.sku = sku;
+	}
+
+	public String getSku() {
+		return sku;
+	}
+
+	public void setOneTimeCharge(BigDecimal oneTimeCharge) {
+		this.oneTimeCharge = oneTimeCharge;
+	}
+
+	public BigDecimal getOneTimeCharge() {
+		return oneTimeCharge;
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductAttribute.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductAttribute.java
new file mode 100644
index 0000000..c0369e3
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductAttribute.java
@@ -0,0 +1,132 @@
+package com.salesmanager.core.business.order.model.orderproduct;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table (name="ORDER_PRODUCT_ATTRIBUTE" , schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class OrderProductAttribute implements Serializable {
+	private static final long serialVersionUID = 6037571119918073015L;
+
+	@Id
+	@Column (name="ORDER_PRODUCT_ATTRIBUTE_ID", nullable=false , unique=true )
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "ORDER_PRODUCT_ATTR_ID_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@Column ( name= "PRODUCT_ATTRIBUTE_PRICE" , nullable=false , precision=15 , scale=4 )
+	private BigDecimal productAttributePrice;
+
+	@Column ( name= "PRODUCT_ATTRIBUTE_IS_FREE" , nullable=false )
+	private boolean productAttributeIsFree;
+
+	@Column ( name= "PRODUCT_ATTRIBUTE_WEIGHT" , precision=15 , scale=4 )
+	private java.math.BigDecimal productAttributeWeight;
+	
+	@ManyToOne
+	@JoinColumn(name = "ORDER_PRODUCT_ID", nullable = false)
+	private OrderProduct orderProduct;
+	
+	@Column(name = "PRODUCT_OPTION_ID", nullable = false)
+	private Long productOptionId;
+
+
+	@Column(name = "PRODUCT_OPTION_VALUE_ID", nullable = false)
+	private Long productOptionValueId;
+	
+	@Column ( name= "PRODUCT_ATTRIBUTE_NAME")
+	private String productAttributeName;
+	
+	@Column ( name= "PRODUCT_ATTRIBUTE_VAL_NAME")
+	private String productAttributeValueName;
+
+	public OrderProductAttribute() {
+	}
+	
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+	public boolean isProductAttributeIsFree() {
+		return productAttributeIsFree;
+	}
+
+	public void setProductAttributeIsFree(boolean productAttributeIsFree) {
+		this.productAttributeIsFree = productAttributeIsFree;
+	}
+
+	public java.math.BigDecimal getProductAttributeWeight() {
+		return productAttributeWeight;
+	}
+
+	public void setProductAttributeWeight(
+			java.math.BigDecimal productAttributeWeight) {
+		this.productAttributeWeight = productAttributeWeight;
+	}
+
+	public OrderProduct getOrderProduct() {
+		return orderProduct;
+	}
+
+	public void setOrderProduct(OrderProduct orderProduct) {
+		this.orderProduct = orderProduct;
+	}
+
+	public String getProductAttributeName() {
+		return productAttributeName;
+	}
+
+	public void setProductAttributeName(String productAttributeName) {
+		this.productAttributeName = productAttributeName;
+	}
+
+	public String getProductAttributeValueName() {
+		return productAttributeValueName;
+	}
+
+	public void setProductAttributeValueName(String productAttributeValueName) {
+		this.productAttributeValueName = productAttributeValueName;
+	}
+
+	public BigDecimal getProductAttributePrice() {
+		return productAttributePrice;
+	}
+
+	public void setProductAttributePrice(BigDecimal productAttributePrice) {
+		this.productAttributePrice = productAttributePrice;
+	}
+
+	public Long getProductOptionId() {
+		return productOptionId;
+	}
+
+	public void setProductOptionId(Long productOptionId) {
+		this.productOptionId = productOptionId;
+	}
+
+	public Long getProductOptionValueId() {
+		return productOptionValueId;
+	}
+
+	public void setProductOptionValueId(Long productOptionValueId) {
+		this.productOptionValueId = productOptionValueId;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductDownload.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductDownload.java
new file mode 100644
index 0000000..8d5395b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductDownload.java
@@ -0,0 +1,90 @@
+package com.salesmanager.core.business.order.model.orderproduct;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table (name="ORDER_PRODUCT_DOWNLOAD", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class OrderProductDownload extends SalesManagerEntity<Long, OrderProductDownload> implements Serializable {
+	private static final long serialVersionUID = -8935511990745477240L;
+	
+	public final static int DEFAULT_DOWNLOAD_MAX_DAYS = 31;
+	
+	@Id
+	@Column (name="ORDER_PRODUCT_DOWNLOAD_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "ORDER_PRODUCT_DL_ID_NEXT_VALUE")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@ManyToOne
+	@JoinColumn(name = "ORDER_PRODUCT_ID", nullable = false)
+	private OrderProduct orderProduct; 
+
+	@Column(name = "ORDER_PRODUCT_FILENAME", nullable = false)
+	private String orderProductFilename;
+	
+	@Column(name = "DOWNLOAD_MAXDAYS", nullable = false)
+	private Integer maxdays = DEFAULT_DOWNLOAD_MAX_DAYS;
+	
+	@Column(name = "DOWNLOAD_COUNT", nullable = false)
+	private Integer downloadCount;
+	
+
+	
+	public OrderProductDownload() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public OrderProduct getOrderProduct() {
+		return orderProduct;
+	}
+
+	public void setOrderProduct(OrderProduct orderProduct) {
+		this.orderProduct = orderProduct;
+	}
+
+	public String getOrderProductFilename() {
+		return orderProductFilename;
+	}
+
+	public void setOrderProductFilename(String orderProductFilename) {
+		this.orderProductFilename = orderProductFilename;
+	}
+
+	public Integer getMaxdays() {
+		return maxdays;
+	}
+
+	public void setMaxdays(Integer maxdays) {
+		this.maxdays = maxdays;
+	}
+
+	public Integer getDownloadCount() {
+		return downloadCount;
+	}
+
+	public void setDownloadCount(Integer downloadCount) {
+		this.downloadCount = downloadCount;
+	}
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductPrice.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductPrice.java
new file mode 100644
index 0000000..b7a9094
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderproduct/OrderProductPrice.java
@@ -0,0 +1,138 @@
+package com.salesmanager.core.business.order.model.orderproduct;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table (name="ORDER_PRODUCT_PRICE" , schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class OrderProductPrice implements Serializable {
+	private static final long serialVersionUID = 3734737890163564311L;
+
+	@Id
+	@Column (name="ORDER_PRODUCT_PRICE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+		pkColumnValue = "ORDER_PRD_PRICE_ID_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@ManyToOne
+	@JoinColumn(name = "ORDER_PRODUCT_ID", nullable = false)
+	private OrderProduct orderProduct;
+
+
+	@Column(name = "PRODUCT_PRICE_CODE", nullable = false , length=64 )
+	private String productPriceCode;
+
+	@Column(name = "PRODUCT_PRICE", nullable = false)
+	private BigDecimal productPrice;
+	
+	@Column(name = "PRODUCT_PRICE_SPECIAL")
+	private BigDecimal productPriceSpecial;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column (name="PRD_PRICE_SPECIAL_ST_DT" , length=0)
+	private Date productPriceSpecialStartDate;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column (name="PRD_PRICE_SPECIAL_END_DT" , length=0)
+	private Date productPriceSpecialEndDate;
+
+
+	@Column(name = "DEFAULT_PRICE", nullable = false)
+	private Boolean defaultPrice;
+
+
+	@Column(name = "PRODUCT_PRICE_NAME", nullable = true)
+	private String productPriceName;
+	
+	public OrderProductPrice() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Boolean getDefaultPrice() {
+		return defaultPrice;
+	}
+
+	public void setDefaultPrice(Boolean defaultPrice) {
+		this.defaultPrice = defaultPrice;
+	}
+
+	public String getProductPriceName() {
+		return productPriceName;
+	}
+
+	public void setProductPriceName(String productPriceName) {
+		this.productPriceName = productPriceName;
+	}
+
+	public OrderProduct getOrderProduct() {
+		return orderProduct;
+	}
+
+	public void setOrderProduct(OrderProduct orderProduct) {
+		this.orderProduct = orderProduct;
+	}
+
+	public void setProductPriceCode(String productPriceCode) {
+		this.productPriceCode = productPriceCode;
+	}
+
+	public String getProductPriceCode() {
+		return productPriceCode;
+	}
+
+	public void setProductPriceSpecialStartDate(
+			Date productPriceSpecialStartDate) {
+		this.productPriceSpecialStartDate = productPriceSpecialStartDate;
+	}
+
+	public Date getProductPriceSpecialStartDate() {
+		return productPriceSpecialStartDate;
+	}
+
+	public void setProductPriceSpecialEndDate(Date productPriceSpecialEndDate) {
+		this.productPriceSpecialEndDate = productPriceSpecialEndDate;
+	}
+
+	public Date getProductPriceSpecialEndDate() {
+		return productPriceSpecialEndDate;
+	}
+
+	public void setProductPriceSpecial(BigDecimal productPriceSpecial) {
+		this.productPriceSpecial = productPriceSpecial;
+	}
+
+	public BigDecimal getProductPriceSpecial() {
+		return productPriceSpecial;
+	}
+
+	public void setProductPrice(BigDecimal productPrice) {
+		this.productPrice = productPrice;
+	}
+
+	public BigDecimal getProductPrice() {
+		return productPrice;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderstatus/OrderStatus.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderstatus/OrderStatus.java
new file mode 100644
index 0000000..ee45847
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderstatus/OrderStatus.java
@@ -0,0 +1,20 @@
+package com.salesmanager.core.business.order.model.orderstatus;
+
+public enum OrderStatus {
+	
+	ORDERED("ordered"),
+	PROCESSED("processed"),
+	DELIVERED("delivered"),
+	REFUNDED("refunded"),
+	;
+	
+	private String value;
+	
+	private OrderStatus(String value) {
+		this.value = value;
+	}
+	
+	public String getValue() {
+		return value;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderstatus/OrderStatusHistory.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderstatus/OrderStatusHistory.java
new file mode 100644
index 0000000..b204a84
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/orderstatus/OrderStatusHistory.java
@@ -0,0 +1,107 @@
+package com.salesmanager.core.business.order.model.orderstatus;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.hibernate.annotations.Type;
+
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.CloneUtils;
+
+@Entity
+@Table (name="ORDER_STATUS_HISTORY" , schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class OrderStatusHistory implements Serializable {
+	private static final long serialVersionUID = 3438730310126102187L;
+	
+	@Id
+	@Column ( name="ORDER_STATUS_HISTORY_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+		pkColumnValue = "STATUS_HIST_ID_NEXT_VALUE")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@ManyToOne(targetEntity = Order.class)
+	@JoinColumn(name = "ORDER_ID", nullable = false)
+	private Order order;
+	
+	@Enumerated(value = EnumType.STRING)
+	private OrderStatus status;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name = "DATE_ADDED", nullable = false)
+	private Date dateAdded;
+	
+	@Column(name = "CUSTOMER_NOTIFIED")
+	private java.lang.Integer customerNotified;
+	
+	@Column(name = "COMMENTS")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String comments;
+	
+	public OrderStatusHistory() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public Order getOrder() {
+		return order;
+	}
+
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+
+	public OrderStatus getStatus() {
+		return status;
+	}
+
+	public void setStatus(OrderStatus status) {
+		this.status = status;
+	}
+
+	public Date getDateAdded() {
+		return CloneUtils.clone(dateAdded);
+	}
+
+	public void setDateAdded(Date dateAdded) {
+		this.dateAdded = CloneUtils.clone(dateAdded);
+	}
+
+	public java.lang.Integer getCustomerNotified() {
+		return customerNotified;
+	}
+
+	public void setCustomerNotified(java.lang.Integer customerNotified) {
+		this.customerNotified = customerNotified;
+	}
+
+	public String getComments() {
+		return comments;
+	}
+
+	public void setComments(String comments) {
+		this.comments = comments;
+	}
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderSummary.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderSummary.java
new file mode 100644
index 0000000..99fc69b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderSummary.java
@@ -0,0 +1,40 @@
+package com.salesmanager.core.business.order.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import com.salesmanager.core.business.shipping.model.ShippingSummary;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+
+
+/**
+ * This object is used as input object for many services
+ * such as order total calculation and tax calculation
+ * @author Carl Samson
+ *
+ */
+public class OrderSummary implements Serializable {
+	
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private ShippingSummary shippingSummary;
+	private List<ShoppingCartItem> products = new ArrayList<ShoppingCartItem>();
+
+	public void setProducts(List<ShoppingCartItem> products) {
+		this.products = products;
+	}
+	public List<ShoppingCartItem> getProducts() {
+		return products;
+	}
+	public void setShippingSummary(ShippingSummary shippingSummary) {
+		this.shippingSummary = shippingSummary;
+	}
+	public ShippingSummary getShippingSummary() {
+		return shippingSummary;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotal.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotal.java
new file mode 100644
index 0000000..a22c44d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotal.java
@@ -0,0 +1,155 @@
+package com.salesmanager.core.business.order.model;
+
+import java.math.BigDecimal;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import org.hibernate.annotations.Type;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+/**
+ * Order line items related to an order.
+ * @author casams1
+ *
+ */
+
+@Entity
+@Table (name="ORDER_TOTAL" , schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class OrderTotal extends SalesManagerEntity<Long, OrderTotal> {
+	private static final long serialVersionUID = -5885315557404081674L;
+	
+	@Id
+	@Column(name = "ORDER_ACCOUNT_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "ORDER_TOTAL_ID_NEXT_VALUE")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column (name ="CODE", nullable=false)
+	private String orderTotalCode;//SHIPPING, TAX
+	
+	@Column (name ="TITLE", nullable=true)
+	private String title;
+	
+	@Column (name ="TEXT", nullable=true)
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String text;
+	
+	@Column (name ="VALUE", precision=15, scale=4, nullable=false )
+	private BigDecimal value;
+	
+	@Column (name ="MODULE", length=60 , nullable=true )
+	private String module;
+	
+	@Column (name ="ORDER_VALUE_TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private OrderValueType orderValueType = OrderValueType.ONE_TIME;
+	
+	@Column (name ="ORDER_TOTAL_TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private OrderTotalType orderTotalType = null;
+	
+	@Column (name ="SORT_ORDER", nullable=false)
+	private int sortOrder;
+	
+	@ManyToOne(targetEntity = Order.class)
+	@JoinColumn(name = "ORDER_ID", nullable=false)
+	private Order order;
+	
+	public OrderTotal() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getText() {
+		return text;
+	}
+
+	public void setText(String text) {
+		this.text = text;
+	}
+
+	public BigDecimal getValue() {
+		return value;
+	}
+
+	public void setValue(BigDecimal value) {
+		this.value = value;
+	}
+
+	public String getModule() {
+		return module;
+	}
+
+	public void setModule(String module) {
+		this.module = module;
+	}
+
+	public int getSortOrder() {
+		return sortOrder;
+	}
+
+	public void setSortOrder(int sortOrder) {
+		this.sortOrder = sortOrder;
+	}
+
+	public Order getOrder() {
+		return order;
+	}
+
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+
+	public void setOrderTotalCode(String orderTotalCode) {
+		this.orderTotalCode = orderTotalCode;
+	}
+
+	public String getOrderTotalCode() {
+		return orderTotalCode;
+	}
+
+	public void setOrderValueType(OrderValueType orderValueType) {
+		this.orderValueType = orderValueType;
+	}
+
+	public OrderValueType getOrderValueType() {
+		return orderValueType;
+	}
+
+	public void setOrderTotalType(OrderTotalType orderTotalType) {
+		this.orderTotalType = orderTotalType;
+	}
+
+	public OrderTotalType getOrderTotalType() {
+		return orderTotalType;
+	}
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotalSummary.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotalSummary.java
new file mode 100644
index 0000000..9339888
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotalSummary.java
@@ -0,0 +1,56 @@
+package com.salesmanager.core.business.order.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+/**
+ * Output object after total calculation
+ * @author Carl Samson
+ *
+ */
+public class OrderTotalSummary implements Serializable {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private BigDecimal subTotal;//one time price for items
+	private BigDecimal total;//final price
+	private BigDecimal taxTotal;//total of taxes
+	
+	private List<OrderTotal> totals;//all other fees (tax, shipping ....)
+
+	public BigDecimal getSubTotal() {
+		return subTotal;
+	}
+
+	public void setSubTotal(BigDecimal subTotal) {
+		this.subTotal = subTotal;
+	}
+
+	public BigDecimal getTotal() {
+		return total;
+	}
+
+	public void setTotal(BigDecimal total) {
+		this.total = total;
+	}
+
+	public List<OrderTotal> getTotals() {
+		return totals;
+	}
+
+	public void setTotals(List<OrderTotal> totals) {
+		this.totals = totals;
+	}
+
+	public BigDecimal getTaxTotal() {
+		return taxTotal;
+	}
+
+	public void setTaxTotal(BigDecimal taxTotal) {
+		this.taxTotal = taxTotal;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotalType.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotalType.java
new file mode 100644
index 0000000..32f905e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderTotalType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.order.model;
+
+public enum OrderTotalType {
+	
+	SHIPPING, HANDLING, TAX, PRODUCT, SUBTOTAL, TOTAL, CREDIT, REFUND
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderType.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderType.java
new file mode 100644
index 0000000..39e1311
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.order.model;
+
+public enum OrderType {
+	
+	ORDER, BOOKING
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderValueType.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderValueType.java
new file mode 100644
index 0000000..d716472
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/OrderValueType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.order.model;
+
+public enum OrderValueType {
+	
+	ONE_TIME, MONTHLY
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/model/payment/CreditCard.java b/sm-core/src/main/java/com/salesmanager/core/business/order/model/payment/CreditCard.java
new file mode 100644
index 0000000..090a603
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/model/payment/CreditCard.java
@@ -0,0 +1,69 @@
+package com.salesmanager.core.business.order.model.payment;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+
+import com.salesmanager.core.business.payments.model.CreditCardType;
+
+@Embeddable
+public class CreditCard {
+	
+	@Column (name ="CARD_TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private CreditCardType cardType;
+	
+	@Column (name ="CC_OWNER")
+	private String ccOwner;
+	
+	@Column (name ="CC_NUMBER")
+	private String ccNumber;
+	
+	@Column (name ="CC_EXPIRES")
+	private String ccExpires;
+	
+	@Column (name ="CC_CVV")
+	private String ccCvv;
+
+	public String getCcOwner() {
+		return ccOwner;
+	}
+
+	public void setCcOwner(String ccOwner) {
+		this.ccOwner = ccOwner;
+	}
+
+	public String getCcNumber() {
+		return ccNumber;
+	}
+
+	public void setCcNumber(String ccNumber) {
+		this.ccNumber = ccNumber;
+	}
+
+	public String getCcExpires() {
+		return ccExpires;
+	}
+
+	public void setCcExpires(String ccExpires) {
+		this.ccExpires = ccExpires;
+	}
+
+	public String getCcCvv() {
+		return ccCvv;
+	}
+
+	public void setCcCvv(String ccCvv) {
+		this.ccCvv = ccCvv;
+	}
+
+	public void setCardType(CreditCardType cardType) {
+		this.cardType = cardType;
+	}
+
+	public CreditCardType getCardType() {
+		return cardType;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/service/orderproduct/OrderProductDownloadService.java b/sm-core/src/main/java/com/salesmanager/core/business/order/service/orderproduct/OrderProductDownloadService.java
new file mode 100644
index 0000000..60d4adf
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/service/orderproduct/OrderProductDownloadService.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.business.order.service.orderproduct;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload;
+
+public interface OrderProductDownloadService extends SalesManagerEntityService<Long, OrderProductDownload> {
+
+	/**
+	 * List {@link OrderProductDownload} by order id
+	 * @param orderId
+	 * @return
+	 */
+	List<OrderProductDownload> getByOrderId(Long orderId);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/service/orderproduct/OrderProductDownloadServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/order/service/orderproduct/OrderProductDownloadServiceImpl.java
new file mode 100644
index 0000000..e46d150
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/service/orderproduct/OrderProductDownloadServiceImpl.java
@@ -0,0 +1,58 @@
+package com.salesmanager.core.business.order.service.orderproduct;
+
+import java.util.List;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.customer.service.CustomerService;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.order.dao.orderproduct.OrderProductDownloadDao;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload;
+import com.salesmanager.core.business.payments.service.PaymentService;
+import com.salesmanager.core.business.payments.service.TransactionService;
+import com.salesmanager.core.business.shipping.service.ShippingService;
+import com.salesmanager.core.business.tax.service.TaxService;
+import com.salesmanager.core.modules.order.InvoiceModule;
+
+
+@Service("orderProductDownloadService")
+public class OrderProductDownloadServiceImpl  extends SalesManagerEntityServiceImpl<Long, OrderProductDownload> implements OrderProductDownloadService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(OrderProductDownloadServiceImpl.class);
+
+    @Autowired
+    private InvoiceModule invoiceModule;
+
+    @Autowired
+    private ShippingService shippingService;
+    
+    @Autowired
+    private PaymentService paymentService;
+
+    @Autowired
+    private TaxService taxService;
+    
+    @Autowired
+    private CustomerService customerService;
+    
+    @Autowired
+    private TransactionService transactionService;
+
+    private final OrderProductDownloadDao orderProductDownloadDao;
+
+    @Autowired
+    public OrderProductDownloadServiceImpl(final OrderProductDownloadDao orderProductDownloadDao) {
+        super(orderProductDownloadDao);
+        this.orderProductDownloadDao = orderProductDownloadDao;
+    }
+    
+    @Override
+    public List<OrderProductDownload> getByOrderId(Long orderId) {
+    	return orderProductDownloadDao.getByOrderId(orderId);
+    }
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/service/OrderService.java b/sm-core/src/main/java/com/salesmanager/core/business/order/service/OrderService.java
new file mode 100644
index 0000000..0307ad5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/service/OrderService.java
@@ -0,0 +1,108 @@
+package com.salesmanager.core.business.order.service;
+
+import java.io.ByteArrayOutputStream;
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderCriteria;
+import com.salesmanager.core.business.order.model.OrderList;
+import com.salesmanager.core.business.order.model.OrderSummary;
+import com.salesmanager.core.business.order.model.OrderTotalSummary;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+
+public interface OrderService extends SalesManagerEntityService<Long, Order> {
+
+    void addOrderStatusHistory(Order order, OrderStatusHistory history)
+                    throws ServiceException;
+
+    /**
+     * Can be used to calculates the final prices of all items contained in checkout page
+     * @param orderSummary
+     * @param customer
+     * @param store
+     * @param language
+     * @return
+     * @throws ServiceException
+     */
+    OrderTotalSummary caculateOrderTotal(OrderSummary orderSummary,
+                                         Customer customer, MerchantStore store, Language language)
+                                                         throws ServiceException;
+
+    /**
+     * Can be used to calculates the final prices of all items contained in a ShoppingCart
+     * @param orderSummary
+     * @param store
+     * @param language
+     * @return
+     * @throws ServiceException
+     */
+    OrderTotalSummary caculateOrderTotal(OrderSummary orderSummary,
+                                         MerchantStore store, Language language) throws ServiceException;
+
+
+    /**
+     * Can be used to calculates the final prices of all items contained in checkout page
+     * @param shoppingCart
+     * @param customer
+     * @param store
+     * @param language
+     * @return  @return {@link OrderTotalSummary}
+     * @throws ServiceException
+     */
+    OrderTotalSummary calculateShoppingCartTotal(final ShoppingCart shoppingCart,final Customer customer, final MerchantStore store, final Language language) throws ServiceException;
+
+    /**
+     * Can be used to calculates the final prices of all items contained in a ShoppingCart
+     * @param shoppingCart
+     * @param store
+     * @param language
+     * @return {@link OrderTotalSummary}
+     * @throws ServiceException
+     */
+    OrderTotalSummary calculateShoppingCartTotal(final ShoppingCart shoppingCart,final MerchantStore store, final Language language) throws ServiceException;
+
+    ByteArrayOutputStream generateInvoice(MerchantStore store, Order order,
+                                          Language language) throws ServiceException;
+
+    Order getOrder(Long id);
+
+    List<Order> listByStore(MerchantStore merchantStore);
+
+    
+
+    
+    
+    OrderList listByStore(MerchantStore store, OrderCriteria criteria);
+
+    void saveOrUpdate(Order order) throws ServiceException;
+
+	Order processOrder(Order order, Customer customer,
+			List<ShoppingCartItem> items, OrderTotalSummary summary,
+			Payment payment, MerchantStore store) throws ServiceException;
+
+	Order processOrder(Order order, Customer customer,
+			List<ShoppingCartItem> items, OrderTotalSummary summary,
+			Payment payment, Transaction transaction, MerchantStore store)
+			throws ServiceException;
+
+
+
+	
+	/**
+	 * Determines if an Order has download files
+	 * @param order
+	 * @return
+	 * @throws ServiceException
+	 */
+	boolean hasDownloadFiles(Order order) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/order/service/OrderServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/order/service/OrderServiceImpl.java
new file mode 100644
index 0000000..146f3d6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/order/service/OrderServiceImpl.java
@@ -0,0 +1,516 @@
+package com.salesmanager.core.business.order.service;
+
+import java.io.ByteArrayOutputStream;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang.Validate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.service.CustomerService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.dao.OrderDao;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderCriteria;
+import com.salesmanager.core.business.order.model.OrderList;
+import com.salesmanager.core.business.order.model.OrderSummary;
+import com.salesmanager.core.business.order.model.OrderTotal;
+import com.salesmanager.core.business.order.model.OrderTotalSummary;
+import com.salesmanager.core.business.order.model.OrderTotalType;
+import com.salesmanager.core.business.order.model.OrderValueType;
+import com.salesmanager.core.business.order.model.Order_;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatus;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.payments.service.PaymentService;
+import com.salesmanager.core.business.payments.service.TransactionService;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.service.ShippingService;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.tax.model.TaxItem;
+import com.salesmanager.core.business.tax.service.TaxService;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.modules.order.InvoiceModule;
+
+
+@Service("orderService")
+public class OrderServiceImpl  extends SalesManagerEntityServiceImpl<Long, Order> implements OrderService {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(OrderServiceImpl.class);
+
+    @Autowired
+    private InvoiceModule invoiceModule;
+
+    @Autowired
+    private ShippingService shippingService;
+    
+    @Autowired
+    private PaymentService paymentService;
+
+    @Autowired
+    private TaxService taxService;
+    
+    @Autowired
+    private CustomerService customerService;
+    
+    @Autowired
+    private TransactionService transactionService;
+
+    private final OrderDao orderDao;
+
+    @Autowired
+    public OrderServiceImpl(final OrderDao orderDao) {
+        super(orderDao);
+        this.orderDao = orderDao;
+    }
+
+    @Override
+    public void addOrderStatusHistory(final Order order, final OrderStatusHistory history) throws ServiceException {
+        order.getOrderHistory().add(history);
+        history.setOrder(order);
+        update(order);
+    }
+    
+    @Override
+    public Order processOrder(Order order, Customer customer, List<ShoppingCartItem> items, OrderTotalSummary summary, Payment payment, MerchantStore store) throws ServiceException {
+    	
+    	return this.process(order, customer, items, summary, payment, null, store);
+    }
+    
+    @Override
+    public Order processOrder(Order order, Customer customer, List<ShoppingCartItem> items, OrderTotalSummary summary, Payment payment, Transaction transaction, MerchantStore store) throws ServiceException {
+    	
+    	return this.process(order, customer, items, summary, payment, transaction, store);
+    }
+    
+    private Order process(Order order, Customer customer, List<ShoppingCartItem> items, OrderTotalSummary summary, Payment payment, Transaction transaction, MerchantStore store) throws ServiceException {
+    	
+    	
+    	Validate.notNull(order, "Order cannot be null");
+    	Validate.notNull(customer, "Customer cannot be null (even if anonymous order)");
+    	Validate.notEmpty(items, "ShoppingCart items cannot be null");
+    	Validate.notNull(payment, "Payment cannot be null");
+    	Validate.notNull(store, "MerchantStore cannot be null");
+    	Validate.notNull(summary, "Order total Summary cannot be null");
+    	
+    	//first process payment
+    	Transaction processTransaction = paymentService.processPayment(customer, store, payment, items, order);
+    	//transactionService.save(processTransaction);
+    	
+    	if(order.getOrderHistory()==null || order.getOrderHistory().size()==0 || order.getStatus()==null) {
+    		OrderStatus status = order.getStatus();
+    		if(status==null) {
+    			status = OrderStatus.ORDERED;
+    			order.setStatus(status);
+    		}
+    		Set<OrderStatusHistory> statusHistorySet = new HashSet<OrderStatusHistory>();
+    		OrderStatusHistory statusHistory = new OrderStatusHistory();
+    		statusHistory.setStatus(status);
+    		statusHistory.setDateAdded(new Date());
+    		statusHistory.setOrder(order);
+    		statusHistorySet.add(statusHistory);
+    		order.setOrderHistory(statusHistorySet);
+    		
+    	}
+    	
+    	if(customer.getId()==null || customer.getId()==0) {
+    		customerService.create(customer);
+    	}
+    	
+    	order.setCustomerId(customer.getId());
+    	
+    	this.create(order);
+
+    	if(transaction!=null) {
+    		transaction.setOrder(order);
+    		if(transaction.getId()==null || transaction.getId()==0) {
+    			transactionService.create(transaction);
+    		} else {
+    			transactionService.update(transaction);
+    		}
+    	}
+    	
+    	if(processTransaction!=null) {
+    		processTransaction.setOrder(order);
+    		if(processTransaction.getId()==null || processTransaction.getId()==0) {
+    			transactionService.create(processTransaction);
+    		} else {
+    			transactionService.update(processTransaction);
+    		}
+    	}
+    	
+    	return order;
+    	
+    	
+    }
+
+    private OrderTotalSummary caculateOrder(final OrderSummary summary, final Customer customer, final MerchantStore store, final Language language) throws Exception {
+
+        OrderTotalSummary totalSummary = new OrderTotalSummary();
+        List<OrderTotal> orderTotals = new ArrayList<OrderTotal>();
+        Map<String,OrderTotal> otherPricesTotals = new HashMap<String,OrderTotal>();
+
+        ShippingConfiguration shippingConfiguration = null;
+
+        BigDecimal grandTotal = new BigDecimal(0);
+        grandTotal.setScale(2, RoundingMode.HALF_UP);
+
+        //price by item
+        /**
+         * qty * price
+         * subtotal
+         */
+        BigDecimal subTotal = new BigDecimal(0);
+        subTotal.setScale(2, RoundingMode.HALF_UP);
+        for(ShoppingCartItem item : summary.getProducts()) {
+
+            BigDecimal st = item.getItemPrice().multiply(new BigDecimal(item.getQuantity()));
+            item.setSubTotal(st);
+            subTotal = subTotal.add(st);
+            //Other prices
+            FinalPrice finalPrice = item.getFinalPrice();
+            if(finalPrice!=null) {
+                List<FinalPrice> otherPrices = finalPrice.getAdditionalPrices();
+                if(otherPrices!=null) {
+                    for(FinalPrice price : otherPrices) {
+                        if(!price.isDefaultPrice()) {
+                            OrderTotal itemSubTotal = otherPricesTotals.get(price.getProductPrice().getCode());
+
+                            if(itemSubTotal==null) {
+                                itemSubTotal = new OrderTotal();
+                                itemSubTotal.setModule(Constants.OT_ITEM_PRICE_MODULE_CODE);
+                                itemSubTotal.setText(Constants.OT_ITEM_PRICE_MODULE_CODE);
+                                itemSubTotal.setTitle(Constants.OT_ITEM_PRICE_MODULE_CODE);
+                                itemSubTotal.setOrderTotalCode(price.getProductPrice().getCode());
+                                itemSubTotal.setOrderTotalType(OrderTotalType.PRODUCT);
+                                itemSubTotal.setSortOrder(0);
+                                otherPricesTotals.put(price.getProductPrice().getCode(), itemSubTotal);
+                            }
+
+                            BigDecimal orderTotalValue = itemSubTotal.getValue();
+                            if(orderTotalValue==null) {
+                                orderTotalValue = new BigDecimal(0);
+                                orderTotalValue.setScale(2, RoundingMode.HALF_UP);
+                            }
+
+                            orderTotalValue = orderTotalValue.add(price.getFinalPrice());
+                            itemSubTotal.setValue(orderTotalValue);
+                            if(price.getProductPrice().getProductPriceType().name().equals(OrderValueType.ONE_TIME)) {
+                                subTotal = subTotal.add(price.getFinalPrice());
+                            }
+                        }
+                    }
+                }
+            }
+
+        }
+
+
+        totalSummary.setSubTotal(subTotal);
+        grandTotal=grandTotal.add(subTotal);
+
+        OrderTotal orderTotalSubTotal = new OrderTotal();
+        orderTotalSubTotal.setModule(Constants.OT_SUBTOTAL_MODULE_CODE);
+        orderTotalSubTotal.setOrderTotalType(OrderTotalType.SUBTOTAL);
+        orderTotalSubTotal.setOrderTotalCode("order.total.subtotal");
+        orderTotalSubTotal.setTitle(Constants.OT_SUBTOTAL_MODULE_CODE);
+        orderTotalSubTotal.setText("order.total.subtotal");
+        orderTotalSubTotal.setSortOrder(5);
+        orderTotalSubTotal.setValue(subTotal);
+
+        //TODO autowire a list of post processing modules for price calculation - drools, custom modules
+        //may affect the sub total
+
+        orderTotals.add(orderTotalSubTotal);
+
+
+        //shipping
+        if(summary.getShippingSummary()!=null) {
+
+
+	            OrderTotal shippingSubTotal = new OrderTotal();
+	            shippingSubTotal.setModule(Constants.OT_SHIPPING_MODULE_CODE);
+	            shippingSubTotal.setOrderTotalType(OrderTotalType.SHIPPING);
+	            shippingSubTotal.setOrderTotalCode("order.total.shipping");
+	            shippingSubTotal.setTitle(Constants.OT_SHIPPING_MODULE_CODE);
+	            shippingSubTotal.setText("order.total.shipping");
+	            shippingSubTotal.setSortOrder(10);
+	
+	            orderTotals.add(shippingSubTotal);
+
+            if(!summary.getShippingSummary().isFreeShipping()) {
+                shippingSubTotal.setValue(summary.getShippingSummary().getShipping());
+                grandTotal=grandTotal.add(summary.getShippingSummary().getShipping());
+            } else {
+                shippingSubTotal.setValue(new BigDecimal(0));
+                grandTotal=grandTotal.add(new BigDecimal(0));
+            }
+
+            //check handling fees
+            shippingConfiguration = shippingService.getShippingConfiguration(store);
+            if(summary.getShippingSummary().getHandling()!=null && summary.getShippingSummary().getHandling().doubleValue()>0) {
+                if(shippingConfiguration.getHandlingFees()!=null && shippingConfiguration.getHandlingFees().doubleValue()>0) {
+                    OrderTotal handlingubTotal = new OrderTotal();
+                    handlingubTotal.setModule(Constants.OT_HANDLING_MODULE_CODE);
+                    handlingubTotal.setOrderTotalType(OrderTotalType.HANDLING);
+                    handlingubTotal.setOrderTotalCode("order.total.handling");
+                    handlingubTotal.setTitle(Constants.OT_HANDLING_MODULE_CODE);
+                    handlingubTotal.setText("order.total.handling");
+                    handlingubTotal.setSortOrder(12);
+                    handlingubTotal.setValue(summary.getShippingSummary().getHandling());
+                    orderTotals.add(handlingubTotal);
+                    grandTotal=grandTotal.add(summary.getShippingSummary().getHandling());
+                }
+            }
+        }
+
+        //tax
+        List<TaxItem> taxes = taxService.calculateTax(summary, customer, store, language);
+        if(taxes!=null && taxes.size()>0) {
+        	BigDecimal totalTaxes = new BigDecimal(0);
+        	totalTaxes.setScale(2, RoundingMode.HALF_UP);
+            int taxCount = 20;
+            for(TaxItem tax : taxes) {
+
+                OrderTotal taxLine = new OrderTotal();
+                taxLine.setModule(Constants.OT_TAX_MODULE_CODE);
+                taxLine.setOrderTotalType(OrderTotalType.TAX);
+                taxLine.setOrderTotalCode(tax.getLabel());
+                taxLine.setSortOrder(taxCount);
+                taxLine.setTitle(Constants.OT_TAX_MODULE_CODE);
+                taxLine.setText(tax.getLabel());
+                taxLine.setValue(tax.getItemPrice());
+
+                totalTaxes = totalTaxes.add(tax.getItemPrice());
+                orderTotals.add(taxLine);
+                //grandTotal=grandTotal.add(tax.getItemPrice());
+
+                taxCount ++;
+
+            }
+            grandTotal = grandTotal.add(totalTaxes);
+            totalSummary.setTaxTotal(totalTaxes);
+        }
+
+        // grand total
+        OrderTotal orderTotal = new OrderTotal();
+        orderTotal.setModule(Constants.OT_TOTAL_MODULE_CODE);
+        orderTotal.setOrderTotalType(OrderTotalType.TOTAL);
+        orderTotal.setOrderTotalCode("order.total.total");
+        orderTotal.setTitle(Constants.OT_TOTAL_MODULE_CODE);
+        orderTotal.setText("order.total.total");
+        orderTotal.setSortOrder(300);
+        orderTotal.setValue(grandTotal);
+        orderTotals.add(orderTotal);
+
+        totalSummary.setTotal(grandTotal);
+        totalSummary.setTotals(orderTotals);
+        return totalSummary;
+
+    }
+
+
+    @Override
+    public OrderTotalSummary caculateOrderTotal(final OrderSummary orderSummary, final Customer customer, final MerchantStore store, final Language language) throws ServiceException {
+        Validate.notNull(orderSummary,"Order summary cannot be null");
+        Validate.notNull(orderSummary.getProducts(),"Order summary.products cannot be null");
+        Validate.notNull(store,"MerchantStore cannot be null");
+        Validate.notNull(customer,"Customer cannot be null");
+
+        try {
+            return caculateOrder(orderSummary, customer, store, language);
+        } catch (Exception e) {
+            throw new ServiceException(e);
+        }
+
+    }
+
+
+
+    @Override
+    public OrderTotalSummary caculateOrderTotal(final OrderSummary orderSummary, final MerchantStore store, final Language language) throws ServiceException {
+        Validate.notNull(orderSummary,"Order summary cannot be null");
+        Validate.notNull(orderSummary.getProducts(),"Order summary.products cannot be null");
+        Validate.notNull(store,"MerchantStore cannot be null");
+
+        try {
+            return caculateOrder(orderSummary, null, store, language);
+        } catch (Exception e) {
+            throw new ServiceException(e);
+        }
+
+    }
+
+    private OrderTotalSummary caculateShoppingCart( final ShoppingCart shoppingCart, final Customer customer, final MerchantStore store, final Language language) throws Exception {
+
+        
+    	
+    	
+    	
+    	OrderSummary orderSummary = new OrderSummary();
+    	
+    	List<ShoppingCartItem> itemsSet = new ArrayList<ShoppingCartItem>(shoppingCart.getLineItems());
+    	orderSummary.setProducts(itemsSet);
+    	
+    	
+    	return this.caculateOrder(orderSummary, customer, store, language);
+
+    }
+
+
+    /**
+     * <p>Method will be used to calculate Shopping cart total as well will update price for each
+     * line items.
+     * </p>
+     * @param shoppingCart
+     * @param customer
+     * @param store
+     * @param language
+     * @return {@link OrderTotalSummary}
+     * @throws ServiceException
+     * 
+     */
+    @Override
+    public OrderTotalSummary calculateShoppingCartTotal(
+                                                        final ShoppingCart shoppingCart, final Customer customer, final MerchantStore store,
+                                                        final Language language) throws ServiceException {
+        Validate.notNull(shoppingCart,"Order summary cannot be null");
+        Validate.notNull(customer,"Customery cannot be null");
+        Validate.notNull(store,"MerchantStore cannot be null.");
+        try {
+            return caculateShoppingCart(shoppingCart, customer, store, language);
+        } catch (Exception e) {
+            LOGGER.error( "Error while calculating shopping cart total" +e );
+            throw new ServiceException(e);
+        }
+
+    }
+
+
+
+
+    /**
+     * <p>Method will be used to calculate Shopping cart total as well will update price for each
+     * line items.
+     * </p>
+     * @param shoppingCart
+     * @param store
+     * @param language
+     * @return {@link OrderTotalSummary}
+     * @throws ServiceException
+     * 
+     */
+    @Override
+    public OrderTotalSummary calculateShoppingCartTotal(
+                                                        final ShoppingCart shoppingCart, final MerchantStore store, final Language language)
+                                                                        throws ServiceException {
+        Validate.notNull(shoppingCart,"Order summary cannot be null");
+        Validate.notNull(store,"MerchantStore cannot be null");
+
+        try {
+            return caculateShoppingCart(shoppingCart, null, store, language);
+        } catch (Exception e) {
+            LOGGER.error( "Error while calculating shopping cart total" +e );
+            throw new ServiceException(e);
+        }
+    }
+
+    @Override
+    public void delete(final Order order) throws ServiceException {
+
+
+        super.delete(order);
+    }
+
+
+    @Override
+    public ByteArrayOutputStream generateInvoice(final MerchantStore store, final Order order, final Language language) throws ServiceException {
+
+        Validate.notNull(order.getOrderProducts(),"Order products cannot be null");
+        Validate.notNull(order.getOrderTotal(),"Order totals cannot be null");
+
+        try {
+            ByteArrayOutputStream stream = invoiceModule.createInvoice(store, order, language);
+            return stream;
+        } catch(Exception e) {
+            throw new ServiceException(e);
+        }
+
+
+
+    }
+
+    @Override
+    public Order getOrder(final Long orderId ) {
+        return getById(orderId);
+    }
+
+
+
+    @Override
+    public List<Order> listByStore(final MerchantStore merchantStore) {
+        return listByField(Order_.merchant, merchantStore);
+    }
+
+    @Override
+    public OrderList listByStore(final MerchantStore store, final OrderCriteria criteria) {
+
+        return orderDao.listByStore(store, criteria);
+    }
+
+
+    @Override
+    public void saveOrUpdate(final Order order) throws ServiceException {
+
+        if(order.getId()!=null && order.getId()>0) {
+            LOGGER.debug("Updating Order");
+            super.update(order);
+
+        } else {
+            LOGGER.debug("Creating Order");
+            super.create(order);
+
+        }
+    }
+
+	@Override
+	public boolean hasDownloadFiles(Order order) throws ServiceException {
+		
+		Validate.notNull(order,"Order cannot be null");
+		Validate.notNull(order.getOrderProducts(),"Order products cannot be null");
+		Validate.notEmpty(order.getOrderProducts(),"Order products cannot be empty");
+		
+		boolean hasDownloads = false;
+		for(OrderProduct orderProduct : order.getOrderProducts()) {
+			
+			if(CollectionUtils.isNotEmpty(orderProduct.getDownloads())) {
+				hasDownloads = true;
+				break;
+			}
+		}
+		
+		return hasDownloads;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/dao/TransactionDao.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/dao/TransactionDao.java
new file mode 100644
index 0000000..9aa89cb
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/dao/TransactionDao.java
@@ -0,0 +1,15 @@
+package com.salesmanager.core.business.payments.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.Transaction;
+
+public interface TransactionDao extends SalesManagerEntityDao<Long, Transaction> {
+
+	List<Transaction> listByOrder(Order order);
+
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/dao/TransactionDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/dao/TransactionDaoImpl.java
new file mode 100644
index 0000000..9fb2528
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/dao/TransactionDaoImpl.java
@@ -0,0 +1,33 @@
+package com.salesmanager.core.business.payments.dao;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.QTransaction;
+import com.salesmanager.core.business.payments.model.Transaction;
+
+@Repository("transactionDao")
+public class TransactionDaoImpl extends SalesManagerEntityDaoImpl<Long, Transaction>
+		implements TransactionDao {
+	
+	@Override
+	public List<Transaction> listByOrder(Order order){
+		QTransaction qTransaction = QTransaction.transaction;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTransaction)
+			.join(qTransaction.order).fetch()
+			.where(qTransaction.order.id.eq(order.getId()));
+		
+		return query.list(qTransaction);
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/BasicPayment.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/BasicPayment.java
new file mode 100644
index 0000000..41fbee4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/BasicPayment.java
@@ -0,0 +1,11 @@
+package com.salesmanager.core.business.payments.model;
+
+
+/**
+ * When the user performs a payment using money order or cheque
+ * @author Carl Samson
+ *
+ */
+public class BasicPayment extends Payment {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/CreditCardPayment.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/CreditCardPayment.java
new file mode 100644
index 0000000..2a5d4b0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/CreditCardPayment.java
@@ -0,0 +1,53 @@
+package com.salesmanager.core.business.payments.model;
+
+/**
+ * When the user performs a payment using a credit card
+ * @author Carl Samson
+ *
+ */
+public class CreditCardPayment extends Payment {
+	
+	private String creditCardNumber;
+	private String credidCardValidationNumber;
+	private String expirationMonth;
+	private String expirationYear;
+	private String cardOwner;
+	private CreditCardType creditCard;
+	public String getCreditCardNumber() {
+		return creditCardNumber;
+	}
+	public void setCreditCardNumber(String creditCardNumber) {
+		this.creditCardNumber = creditCardNumber;
+	}
+	public String getCredidCardValidationNumber() {
+		return credidCardValidationNumber;
+	}
+	public void setCredidCardValidationNumber(String credidCardValidationNumber) {
+		this.credidCardValidationNumber = credidCardValidationNumber;
+	}
+	public String getExpirationMonth() {
+		return expirationMonth;
+	}
+	public void setExpirationMonth(String expirationMonth) {
+		this.expirationMonth = expirationMonth;
+	}
+	public String getExpirationYear() {
+		return expirationYear;
+	}
+	public void setExpirationYear(String expirationYear) {
+		this.expirationYear = expirationYear;
+	}
+	public String getCardOwner() {
+		return cardOwner;
+	}
+	public void setCardOwner(String cardOwner) {
+		this.cardOwner = cardOwner;
+	}
+	public CreditCardType getCreditCard() {
+		return creditCard;
+	}
+	public void setCreditCard(CreditCardType creditCard) {
+		this.creditCard = creditCard;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/CreditCardType.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/CreditCardType.java
new file mode 100644
index 0000000..7c7699d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/CreditCardType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.payments.model;
+
+public enum CreditCardType {
+	
+	AMEX, VISA, MASTERCARD, DINERS, DISCOVERY
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/Payment.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/Payment.java
new file mode 100644
index 0000000..785933b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/Payment.java
@@ -0,0 +1,44 @@
+package com.salesmanager.core.business.payments.model;
+
+import com.salesmanager.core.business.reference.currency.model.Currency;
+
+public class Payment {
+	
+	private PaymentType paymentType;
+	private TransactionType transactionType = TransactionType.AUTHORIZECAPTURE;
+	private String moduleName;
+	private Currency currency;
+
+	public void setPaymentType(PaymentType paymentType) {
+		this.paymentType = paymentType;
+	}
+
+	public PaymentType getPaymentType() {
+		return paymentType;
+	}
+
+	public void setTransactionType(TransactionType transactionType) {
+		this.transactionType = transactionType;
+	}
+
+	public TransactionType getTransactionType() {
+		return transactionType;
+	}
+
+	public void setModuleName(String moduleName) {
+		this.moduleName = moduleName;
+	}
+
+	public String getModuleName() {
+		return moduleName;
+	}
+
+	public Currency getCurrency() {
+		return currency;
+	}
+
+	public void setCurrency(Currency currency) {
+		this.currency = currency;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaymentMethod.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaymentMethod.java
new file mode 100644
index 0000000..effca46
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaymentMethod.java
@@ -0,0 +1,57 @@
+package com.salesmanager.core.business.payments.model;
+
+import java.io.Serializable;
+
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+
+/**
+ * Object to be used in store front with meta data and configuration
+ * informations required to display to the end user
+ * @author Carl Samson
+ *
+ */
+public class PaymentMethod implements Serializable {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private String paymentMethodCode;
+	private PaymentType paymentType;
+	private boolean defaultSelected;
+	private IntegrationModule module;
+	private IntegrationConfiguration informations;
+
+	public PaymentType getPaymentType() {
+		return paymentType;
+	}
+	public void setPaymentType(PaymentType paymentType) {
+		this.paymentType = paymentType;
+	}
+	public String getPaymentMethodCode() {
+		return paymentMethodCode;
+	}
+	public void setPaymentMethodCode(String paymentMethodCode) {
+		this.paymentMethodCode = paymentMethodCode;
+	}
+	public boolean isDefaultSelected() {
+		return defaultSelected;
+	}
+	public void setDefaultSelected(boolean defaultSelected) {
+		this.defaultSelected = defaultSelected;
+	}
+	public IntegrationModule getModule() {
+		return module;
+	}
+	public void setModule(IntegrationModule module) {
+		this.module = module;
+	}
+	public IntegrationConfiguration getInformations() {
+		return informations;
+	}
+	public void setInformations(IntegrationConfiguration informations) {
+		this.informations = informations;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaymentType.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaymentType.java
new file mode 100644
index 0000000..0bbd1eb
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaymentType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.payments.model;
+
+public enum PaymentType {
+	
+	CREDITCARD, FREE, COD, MONEYORDER, PAYPAL
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaypalPayment.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaypalPayment.java
new file mode 100644
index 0000000..67b5880
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/PaypalPayment.java
@@ -0,0 +1,31 @@
+package com.salesmanager.core.business.payments.model;
+
+/**
+ * When the user performs a payment using paypal
+ * @author Carl Samson
+ *
+ */
+public class PaypalPayment extends Payment {
+	
+	//express checkout
+	private String payerId;
+	private String paymentToken;
+	
+	public PaypalPayment() {
+		super.setPaymentType(PaymentType.PAYPAL);
+	}
+	
+	public void setPayerId(String payerId) {
+		this.payerId = payerId;
+	}
+	public String getPayerId() {
+		return payerId;
+	}
+	public void setPaymentToken(String paymentToken) {
+		this.paymentToken = paymentToken;
+	}
+	public String getPaymentToken() {
+		return paymentToken;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/Transaction.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/Transaction.java
new file mode 100644
index 0000000..50eff18
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/Transaction.java
@@ -0,0 +1,183 @@
+package com.salesmanager.core.business.payments.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.Transient;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.hibernate.annotations.Type;
+import org.json.simple.JSONAware;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "SM_TRANSACTION", schema= SchemaConstant.SALESMANAGER_SCHEMA)
+public class Transaction extends SalesManagerEntity<Long, Transaction> implements Serializable, Auditable, JSONAware {
+	
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(Transaction.class);
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@Column(name = "TRANSACTION_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "TRANSACT_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="ORDER_ID", nullable=true)
+	private Order order;
+	
+	@Column(name="AMOUNT")
+	private BigDecimal amount;
+	
+	@Column(name="TRANSACTION_DATE")
+	@Temporal(TemporalType.TIMESTAMP)
+	private Date transactionDate;
+	
+	@Column(name="TRANSACTION_TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private TransactionType transactionType;
+	
+	@Column(name="PAYMENT_TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private PaymentType paymentType;
+	
+	@Column(name="DETAILS")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String details;
+	
+	@Transient
+	private Map<String,String> transactionDetails= new HashMap<String,String>();
+
+	@Override
+	public AuditSection getAuditSection() {
+		return this.auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection audit) {
+		this.auditSection = audit;
+		
+	}
+
+	@Override
+	public Long getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+		
+	}
+
+	public Order getOrder() {
+		return order;
+	}
+
+	public void setOrder(Order order) {
+		this.order = order;
+	}
+
+	public BigDecimal getAmount() {
+		return amount;
+	}
+
+	public void setAmount(BigDecimal amount) {
+		this.amount = amount;
+	}
+
+	public Date getTransactionDate() {
+		return transactionDate;
+	}
+
+	public void setTransactionDate(Date transactionDate) {
+		this.transactionDate = transactionDate;
+	}
+
+	public TransactionType getTransactionType() {
+		return transactionType;
+	}
+
+	public void setTransactionType(TransactionType transactionType) {
+		this.transactionType = transactionType;
+	}
+
+	public PaymentType getPaymentType() {
+		return paymentType;
+	}
+
+	public void setPaymentType(PaymentType paymentType) {
+		this.paymentType = paymentType;
+	}
+
+	public String getDetails() {
+		return details;
+	}
+
+	public void setDetails(String details) {
+		this.details = details;
+	}
+
+	public Map<String, String> getTransactionDetails() {
+		return transactionDetails;
+	}
+
+	public void setTransactionDetails(Map<String, String> transactionDetails) {
+		this.transactionDetails = transactionDetails;
+	}
+
+	@Override
+	public String toJSONString() {
+		
+		if(this.getTransactionDetails()!=null && this.getTransactionDetails().size()>0) {
+			ObjectMapper mapper = new ObjectMapper();
+			try {
+				return mapper.writeValueAsString(this.getTransactionDetails());
+			} catch (Exception e) {
+				LOGGER.error("Cannot parse transactions map",e);
+			}
+			
+		}
+		
+		return null;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/model/TransactionType.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/TransactionType.java
new file mode 100644
index 0000000..3015853
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/model/TransactionType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.payments.model;
+
+public enum TransactionType {
+	
+	INIT, AUTHORIZE, CAPTURE, AUTHORIZECAPTURE, REFUND
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/service/PaymentService.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/service/PaymentService.java
new file mode 100644
index 0000000..ef7bc9c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/service/PaymentService.java
@@ -0,0 +1,103 @@
+package com.salesmanager.core.business.payments.service;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Map;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.CreditCardType;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.PaymentMethod;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.modules.integration.payment.model.PaymentModule;
+
+public interface PaymentService {
+
+
+
+	public List<IntegrationModule> getPaymentMethods(MerchantStore store)
+			throws ServiceException;
+
+	Map<String, IntegrationConfiguration> getPaymentModulesConfigured(
+			MerchantStore store) throws ServiceException;
+	
+	Transaction processPayment(Customer customer, MerchantStore store, Payment payment, List<ShoppingCartItem> items, Order order) throws ServiceException;
+	Transaction processRefund(Order order, Customer customer, MerchantStore store, BigDecimal amount) throws ServiceException;
+
+	/**
+	 * Get a specific Payment module by payment type CREDITCART, MONEYORDER ...
+	 * @param store
+	 * @param type (payment type)
+	 * @return IntegrationModule
+	 * @throws ServiceException
+	 */
+	IntegrationModule getPaymentMethodByType(MerchantStore store, String type)
+			throws ServiceException;
+	
+	/**
+	 * Get a specific Payment module by payment code (defined in integrationmoduel.json) paypal, authorizenet ..
+	 * @param store
+	 * @param name
+	 * @return IntegrationModule
+	 * @throws ServiceException
+	 */
+	IntegrationModule getPaymentMethodByCode(MerchantStore store, String name)
+			throws ServiceException;
+
+	/**
+	 * Saves a payment module configuration
+	 * @param configuration
+	 * @param store
+	 * @throws ServiceException
+	 */
+	void savePaymentModuleConfiguration(IntegrationConfiguration configuration,
+			MerchantStore store) throws ServiceException;
+
+	/**
+	 * Validates if the credit card input information are correct
+	 * @param number
+	 * @param type
+	 * @param month
+	 * @param date
+	 * @throws ServiceException
+	 */
+	void validateCreditCard(String number, CreditCardType creditCard, String month, String date)
+			throws ServiceException;
+
+	/**
+	 * Get the integration configuration
+	 * for a specific payment module
+	 * @param moduleCode
+	 * @param store
+	 * @return IntegrationConfiguration
+	 * @throws ServiceException
+	 */
+	IntegrationConfiguration getPaymentConfiguration(String moduleCode,
+			MerchantStore store) throws ServiceException;
+
+	void removePaymentModuleConfiguration(String moduleCode, MerchantStore store)
+			throws ServiceException;
+
+	Transaction processCapturePayment(Order order, Customer customer,
+			MerchantStore store)
+			throws ServiceException;
+
+	List<PaymentMethod> getAcceptedPaymentMethods(MerchantStore store)
+			throws ServiceException;
+
+	/**
+	 * Returns a PaymentModule based on the payment code
+	 * @param paymentModuleCode
+	 * @return PaymentModule
+	 * @throws ServiceException
+	 */
+	PaymentModule getPaymentModule(String paymentModuleCode)
+			throws ServiceException;
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/service/PaymentServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/service/PaymentServiceImpl.java
new file mode 100644
index 0000000..3adc63a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/service/PaymentServiceImpl.java
@@ -0,0 +1,694 @@
+package com.salesmanager.core.business.payments.service;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang.Validate;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderTotal;
+import com.salesmanager.core.business.order.model.OrderTotalType;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatus;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory;
+import com.salesmanager.core.business.order.service.OrderService;
+import com.salesmanager.core.business.payments.model.CreditCardPayment;
+import com.salesmanager.core.business.payments.model.CreditCardType;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.PaymentMethod;
+import com.salesmanager.core.business.payments.model.PaymentType;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.payments.model.TransactionType;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.service.MerchantConfigurationService;
+import com.salesmanager.core.business.system.service.ModuleConfigurationService;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.payment.model.PaymentModule;
+import com.salesmanager.core.modules.utils.Encryption;
+import com.salesmanager.core.utils.reference.ConfigurationModulesLoader;
+
+@Service("paymentService")
+public class PaymentServiceImpl implements PaymentService {
+	
+	
+
+	private final static String PAYMENT_MODULES = "PAYMENT";
+	
+	@Autowired
+	private MerchantConfigurationService merchantConfigurationService;
+	
+	@Autowired
+	private ModuleConfigurationService moduleConfigurationService;
+	
+	@Autowired
+	private TransactionService transactionService;
+	
+	@Autowired
+	private OrderService orderService;
+	
+	@Autowired
+	@Resource(name="paymentModules")
+	private Map<String,PaymentModule> paymentModules;
+	
+	@Autowired
+	private Encryption encryption;
+	
+	@Override
+	public List<IntegrationModule> getPaymentMethods(MerchantStore store) throws ServiceException {
+		
+		List<IntegrationModule> modules =  moduleConfigurationService.getIntegrationModules(PAYMENT_MODULES);
+		List<IntegrationModule> returnModules = new ArrayList<IntegrationModule>();
+		
+		for(IntegrationModule module : modules) {
+			if(module.getRegionsSet().contains(store.getCountry().getIsoCode())
+					|| module.getRegionsSet().contains("*")) {
+				
+				returnModules.add(module);
+			}
+		}
+		
+		return returnModules;
+	}
+	
+	@Override
+	public List<PaymentMethod> getAcceptedPaymentMethods(MerchantStore store) throws ServiceException {
+		
+		Map<String,IntegrationConfiguration> modules =  this.getPaymentModulesConfigured(store);
+
+		List<PaymentMethod> returnModules = new ArrayList<PaymentMethod>();
+		
+		for(String module : modules.keySet()) {
+			IntegrationConfiguration config = modules.get(module);
+			if(config.isActive()) {
+				
+				IntegrationModule md = this.getPaymentMethodByCode(store, config.getModuleCode());
+				if(md==null) {
+					continue;
+				}
+				PaymentMethod paymentMethod = new PaymentMethod();
+				
+				paymentMethod.setDefaultSelected(config.isDefaultSelected());
+				paymentMethod.setPaymentMethodCode(config.getModuleCode());
+				paymentMethod.setModule(md);
+				paymentMethod.setInformations(config);
+				PaymentType type = PaymentType.COD;
+				if(md.getType().equalsIgnoreCase(PaymentType.CREDITCARD.name())) {
+					type = PaymentType.CREDITCARD;
+				} else 	if(md.getType().equalsIgnoreCase(PaymentType.FREE.name())) {
+					type = PaymentType.FREE;
+				} else 	if(md.getType().equalsIgnoreCase(PaymentType.MONEYORDER.name())) {
+					type = PaymentType.MONEYORDER;
+				} else 	if(md.getType().equalsIgnoreCase(PaymentType.PAYPAL.name())) {
+					type = PaymentType.PAYPAL;
+				}
+				paymentMethod.setPaymentType(type);
+				returnModules.add(paymentMethod);
+			}
+		}
+		
+		return returnModules;
+		
+		
+	}
+	
+	@Override
+	public IntegrationModule getPaymentMethodByType(MerchantStore store, String type) throws ServiceException {
+		List<IntegrationModule> modules =  getPaymentMethods(store);
+
+		for(IntegrationModule module : modules) {
+			if(module.getModule().equals(type)) {
+				
+				return module;
+			}
+		}
+		
+		return null;
+	}
+	
+	@Override
+	public IntegrationModule getPaymentMethodByCode(MerchantStore store,
+			String code) throws ServiceException {
+		List<IntegrationModule> modules =  getPaymentMethods(store);
+
+		for(IntegrationModule module : modules) {
+			if(module.getCode().equals(code)) {
+				
+				return module;
+			}
+		}
+		
+		return null;
+	}
+	
+	@Override
+	public IntegrationConfiguration getPaymentConfiguration(String moduleCode, MerchantStore store) throws ServiceException {
+
+		
+		Map<String,IntegrationConfiguration> configuredModules = getPaymentModulesConfigured(store);
+		if(configuredModules!=null) {
+			for(String key : configuredModules.keySet()) {
+				if(key.equals(moduleCode)) {
+					return configuredModules.get(key);	
+				}
+			}
+		}
+		
+		return null;
+		
+	}
+	
+
+	
+	@Override
+	public Map<String,IntegrationConfiguration> getPaymentModulesConfigured(MerchantStore store) throws ServiceException {
+		
+		try {
+		
+			Map<String,IntegrationConfiguration> modules = new HashMap<String,IntegrationConfiguration>();
+			MerchantConfiguration merchantConfiguration = merchantConfigurationService.getMerchantConfiguration(PAYMENT_MODULES, store);
+			if(merchantConfiguration!=null) {
+				
+				if(!StringUtils.isBlank(merchantConfiguration.getValue())) {
+					
+					String decrypted = encryption.decrypt(merchantConfiguration.getValue());
+					modules = ConfigurationModulesLoader.loadIntegrationConfigurations(decrypted);
+					
+					
+				}
+			}
+			return modules;
+		
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	}
+	
+	@Override
+	public void savePaymentModuleConfiguration(IntegrationConfiguration configuration, MerchantStore store) throws ServiceException {
+		
+		//validate entries
+		try {
+			
+			String moduleCode = configuration.getModuleCode();
+			PaymentModule module = (PaymentModule)paymentModules.get(moduleCode);
+			if(module==null) {
+				throw new ServiceException("Payment module " + moduleCode + " does not exist");
+			}
+			module.validateModuleConfiguration(configuration, store);
+			
+		} catch (IntegrationException ie) {
+			throw ie;
+		}
+		
+		try {
+			Map<String,IntegrationConfiguration> modules = new HashMap<String,IntegrationConfiguration>();
+			MerchantConfiguration merchantConfiguration = merchantConfigurationService.getMerchantConfiguration(PAYMENT_MODULES, store);
+			if(merchantConfiguration!=null) {
+				if(!StringUtils.isBlank(merchantConfiguration.getValue())) {
+					
+					String decrypted = encryption.decrypt(merchantConfiguration.getValue());
+					
+					modules = ConfigurationModulesLoader.loadIntegrationConfigurations(decrypted);
+				}
+			} else {
+				merchantConfiguration = new MerchantConfiguration();
+				merchantConfiguration.setMerchantStore(store);
+				merchantConfiguration.setKey(PAYMENT_MODULES);
+			}
+			modules.put(configuration.getModuleCode(), configuration);
+			
+			String configs =  ConfigurationModulesLoader.toJSONString(modules);
+			
+			String encrypted = encryption.encrypt(configs);
+			merchantConfiguration.setValue(encrypted);
+			
+			merchantConfigurationService.saveOrUpdate(merchantConfiguration);
+			
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+   }
+	
+	@Override
+	public void removePaymentModuleConfiguration(String moduleCode, MerchantStore store) throws ServiceException {
+		
+		
+
+		try {
+			Map<String,IntegrationConfiguration> modules = new HashMap<String,IntegrationConfiguration>();
+			MerchantConfiguration merchantConfiguration = merchantConfigurationService.getMerchantConfiguration(PAYMENT_MODULES, store);
+			if(merchantConfiguration!=null) {
+
+				if(!StringUtils.isBlank(merchantConfiguration.getValue())) {
+					
+					String decrypted = encryption.decrypt(merchantConfiguration.getValue());
+					modules = ConfigurationModulesLoader.loadIntegrationConfigurations(decrypted);
+				}
+				
+				modules.remove(moduleCode);
+				String configs =  ConfigurationModulesLoader.toJSONString(modules);
+				
+				String encrypted = encryption.encrypt(configs);
+				merchantConfiguration.setValue(encrypted);
+				
+				merchantConfigurationService.saveOrUpdate(merchantConfiguration);
+				
+				
+			} 
+			
+			MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(moduleCode, store);
+			
+			if(configuration!=null) {//custom module
+
+				merchantConfigurationService.delete(configuration);
+			}
+
+			
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	
+	}
+	
+
+	
+
+
+	@Override
+	public Transaction processPayment(Customer customer,
+			MerchantStore store, Payment payment, List<ShoppingCartItem> items, Order order)
+			throws ServiceException {
+
+
+		Validate.notNull(customer);
+		Validate.notNull(store);
+		Validate.notNull(payment);
+		Validate.notNull(order);
+		Validate.notNull(order.getTotal());
+		
+		payment.setCurrency(store.getCurrency());
+		
+		BigDecimal amount = order.getTotal();
+
+		//must have a shipping module configured
+		Map<String, IntegrationConfiguration> modules = this.getPaymentModulesConfigured(store);
+		if(modules==null){
+			throw new ServiceException("No payment module configured");
+		}
+		
+		IntegrationConfiguration configuration = modules.get(payment.getModuleName());
+		
+		if(configuration==null) {
+			throw new ServiceException("Payment module " + payment.getModuleName() + " is not configured");
+		}
+		
+		if(!configuration.isActive()) {
+			throw new ServiceException("Payment module " + payment.getModuleName() + " is not active");
+		}
+		
+		String sTransactionType = configuration.getIntegrationKeys().get("transaction");
+		if(sTransactionType==null) {
+			sTransactionType = TransactionType.AUTHORIZECAPTURE.name();
+		}
+		
+
+		if(sTransactionType.equals(TransactionType.AUTHORIZE.name())) {
+			payment.setTransactionType(TransactionType.AUTHORIZE);
+		} else {
+			payment.setTransactionType(TransactionType.AUTHORIZECAPTURE);
+		} 
+		
+
+		PaymentModule module = this.paymentModules.get(payment.getModuleName());
+		
+		if(module==null) {
+			throw new ServiceException("Payment module " + payment.getModuleName() + " does not exist");
+		}
+		
+		if(payment instanceof CreditCardPayment) {
+			CreditCardPayment creditCardPayment = (CreditCardPayment)payment;
+			validateCreditCard(creditCardPayment.getCreditCardNumber(),creditCardPayment.getCreditCard(),creditCardPayment.getExpirationMonth(),creditCardPayment.getExpirationYear());
+		}
+		
+		IntegrationModule integrationModule = getPaymentMethodByCode(store,payment.getModuleName());
+		TransactionType transactionType = TransactionType.valueOf(sTransactionType);
+		if(transactionType==null) {
+			transactionType = payment.getTransactionType();
+			if(transactionType.equals(TransactionType.CAPTURE.name())) {
+				throw new ServiceException("This method does not allow to process capture transaction. Use processCapturePayment");
+			}
+		}
+		
+		Transaction transaction = null;
+		if(transactionType == TransactionType.AUTHORIZE)  {
+			transaction = module.authorize(store, customer, items, amount, payment, configuration, integrationModule);
+		} else if(transactionType == TransactionType.AUTHORIZECAPTURE)  {
+			transaction = module.authorizeAndCapture(store, customer, items, amount, payment, configuration, integrationModule);
+		} else if(transactionType == TransactionType.INIT)  {
+			transaction = module.initTransaction(store, customer, amount, payment, configuration, integrationModule);
+		}
+
+
+		if(transactionType != TransactionType.INIT) {
+			transactionService.create(transaction);
+		}
+		
+		if(transactionType == TransactionType.AUTHORIZECAPTURE)  {
+			order.setStatus(OrderStatus.ORDERED);
+			if(payment.getPaymentType().name()!=PaymentType.MONEYORDER.name()) {
+				order.setStatus(OrderStatus.PROCESSED);
+			}
+		}
+
+		return transaction;
+
+		
+
+	}
+	
+	@Override
+	public PaymentModule getPaymentModule(String paymentModuleCode) throws ServiceException {
+		return paymentModules.get(paymentModuleCode);
+	}
+	
+	@Override
+	public Transaction processCapturePayment(Order order, Customer customer,
+			MerchantStore store)
+			throws ServiceException {
+
+
+		Validate.notNull(customer);
+		Validate.notNull(store);
+		Validate.notNull(order);
+
+		
+
+		//must have a shipping module configured
+		Map<String, IntegrationConfiguration> modules = this.getPaymentModulesConfigured(store);
+		if(modules==null){
+			throw new ServiceException("No payment module configured");
+		}
+		
+		IntegrationConfiguration configuration = modules.get(order.getPaymentModuleCode());
+		
+		if(configuration==null) {
+			throw new ServiceException("Payment module " + order.getPaymentModuleCode() + " is not configured");
+		}
+		
+		if(!configuration.isActive()) {
+			throw new ServiceException("Payment module " + order.getPaymentModuleCode() + " is not active");
+		}
+		
+		
+		PaymentModule module = this.paymentModules.get(order.getPaymentModuleCode());
+		
+		if(module==null) {
+			throw new ServiceException("Payment module " + order.getPaymentModuleCode() + " does not exist");
+		}
+		
+
+		IntegrationModule integrationModule = getPaymentMethodByCode(store,order.getPaymentModuleCode());
+		
+		//TransactionType transactionType = payment.getTransactionType();
+
+			//get the previous transaction
+		Transaction trx = transactionService.getCapturableTransaction(order);
+		if(trx==null) {
+			throw new ServiceException("No capturable transaction for order id " + order.getId());
+		}
+		Transaction transaction = module.capture(store, customer, order, trx, configuration, integrationModule);
+		transaction.setOrder(order);
+		
+		
+
+		transactionService.create(transaction);
+		
+		
+		OrderStatusHistory orderHistory = new OrderStatusHistory();
+		orderHistory.setOrder(order);
+		orderHistory.setStatus(OrderStatus.PROCESSED);
+		orderHistory.setDateAdded(new Date());
+		
+		orderService.addOrderStatusHistory(order, orderHistory);
+		
+		order.setStatus(OrderStatus.PROCESSED);
+		orderService.saveOrUpdate(order);
+
+		return transaction;
+
+		
+
+	}
+
+	@Override
+	public Transaction processRefund(Order order, Customer customer,
+			MerchantStore store, BigDecimal amount)
+			throws ServiceException {
+		
+		
+		Validate.notNull(customer);
+		Validate.notNull(store);
+		Validate.notNull(amount);
+		Validate.notNull(order);
+		Validate.notNull(order.getOrderTotal());
+		
+		
+		BigDecimal orderTotal = order.getTotal();
+		
+		if(amount.doubleValue()>orderTotal.doubleValue()) {
+			throw new ServiceException("Invalid amount, the refunded amount is greater than the total allowed");
+		}
+
+		
+		String module = order.getPaymentModuleCode();
+		Map<String, IntegrationConfiguration> modules = this.getPaymentModulesConfigured(store);
+		if(modules==null){
+			throw new ServiceException("No payment module configured");
+		}
+		
+		IntegrationConfiguration configuration = modules.get(module);
+		
+		if(configuration==null) {
+			throw new ServiceException("Payment module " + module + " is not configured");
+		}
+		
+		PaymentModule paymentModule = this.paymentModules.get(module);
+		
+		if(paymentModule==null) {
+			throw new ServiceException("Payment module " + paymentModule + " does not exist");
+		}
+		
+		boolean partial = false;
+		if(amount.doubleValue()!=order.getTotal().doubleValue()) {
+			partial = true;
+		}
+		
+		IntegrationModule integrationModule = getPaymentMethodByCode(store,module);
+		
+		//get the associated transaction
+		Transaction refundable = transactionService.getRefundableTransaction(order);
+		
+		if(refundable==null) {
+			throw new ServiceException("No refundable transaction for this order");
+		}
+		
+		Transaction transaction = paymentModule.refund(partial, store, refundable, order, amount, configuration, integrationModule);
+		transaction.setOrder(order);
+		transactionService.create(transaction);
+		
+        OrderTotal refund = new OrderTotal();
+        refund.setModule(Constants.OT_REFUND_MODULE_CODE);
+        refund.setText(Constants.OT_REFUND_MODULE_CODE);
+        refund.setTitle(Constants.OT_REFUND_MODULE_CODE);
+        refund.setOrderTotalCode(Constants.OT_REFUND_MODULE_CODE);
+        refund.setOrderTotalType(OrderTotalType.REFUND);
+        refund.setValue(amount);
+        refund.setSortOrder(100);
+        refund.setOrder(order);
+        
+        order.getOrderTotal().add(refund);
+        
+		//update order total
+		orderTotal = orderTotal.subtract(amount);
+        
+        //update ordertotal refund
+        Set<OrderTotal> totals = order.getOrderTotal();
+        for(OrderTotal total : totals) {
+        	if(total.getModule().equals(Constants.OT_TOTAL_MODULE_CODE)) {
+        		total.setValue(orderTotal);
+        	}
+        }
+
+		
+
+		order.setTotal(orderTotal);
+		order.setStatus(OrderStatus.REFUNDED);
+		
+		
+		
+		OrderStatusHistory orderHistory = new OrderStatusHistory();
+		orderHistory.setOrder(order);
+		orderHistory.setStatus(OrderStatus.REFUNDED);
+		orderHistory.setDateAdded(new Date());
+        order.getOrderHistory().add(orderHistory);
+        
+        orderService.saveOrUpdate(order);
+
+		return transaction;
+	}
+	
+	@Override
+	public void validateCreditCard(String number, CreditCardType creditCard, String month, String date)
+	throws ServiceException {
+
+		try {
+			Integer.parseInt(month);
+			Integer.parseInt(date);
+		} catch (NumberFormatException nfe) {
+			ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid date format","messages.error.creditcard.dateformat");
+			throw ex;
+		}
+		
+		if (StringUtils.isBlank(number)) {
+			ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid card number","messages.error.creditcard.number");
+			throw ex;
+		}
+		
+		Matcher m = Pattern.compile("[^\\d\\s.-]").matcher(number);
+		
+		if (m.find()) {
+			ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid card number","messages.error.creditcard.number");
+			throw ex;
+		}
+		
+		Matcher matcher = Pattern.compile("[\\s.-]").matcher(number);
+		
+		number = matcher.replaceAll("");
+		validateCreditCardDate(Integer.parseInt(month), Integer.parseInt(date));
+		validateCreditCardNumber(number, creditCard);
+	}
+
+	private void validateCreditCardDate(int m, int y) throws ServiceException {
+		java.util.Calendar cal = new java.util.GregorianCalendar();
+		int monthNow = cal.get(java.util.Calendar.MONTH) + 1;
+		int yearNow = cal.get(java.util.Calendar.YEAR);
+		if (yearNow > y) {
+			ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid date format","messages.error.creditcard.dateformat");
+			throw ex;
+		}
+		// OK, change implementation
+		if (yearNow == y && monthNow > m) {
+			ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid date format","messages.error.creditcard.dateformat");
+			throw ex;
+		}
+	
+	}
+	
+	private void validateCreditCardNumber(String number, CreditCardType creditCard)
+	throws ServiceException {
+
+		//TODO implement
+		if(CreditCardType.MASTERCARD.equals(creditCard.name())) {
+			if (number.length() != 16
+					|| Integer.parseInt(number.substring(0, 2)) < 51
+					|| Integer.parseInt(number.substring(0, 2)) > 55) {
+				ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid card number","messages.error.creditcard.number");
+				throw ex;
+			}
+		}
+		
+		if(CreditCardType.VISA.equals(creditCard.name())) {
+			if ((number.length() != 13 && number.length() != 16)
+					|| Integer.parseInt(number.substring(0, 1)) != 4) {
+				ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid card number","messages.error.creditcard.number");
+				throw ex;
+			}
+		}
+		
+		if(CreditCardType.AMEX.equals(creditCard.name())) {
+			if (number.length() != 15
+					|| (Integer.parseInt(number.substring(0, 2)) != 34 && Integer
+							.parseInt(number.substring(0, 2)) != 37)) {
+				ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid card number","messages.error.creditcard.number");
+				throw ex;
+			}
+		}
+		
+		if(CreditCardType.DINERS.equals(creditCard.name())) {
+			if (number.length() != 14
+					|| ((Integer.parseInt(number.substring(0, 2)) != 36 && Integer
+							.parseInt(number.substring(0, 2)) != 38)
+							&& Integer.parseInt(number.substring(0, 3)) < 300 || Integer
+							.parseInt(number.substring(0, 3)) > 305)) {
+				ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid card number","messages.error.creditcard.number");
+				throw ex;
+			}
+		}
+		
+		if(CreditCardType.DISCOVERY.equals(creditCard.name())) {
+			if (number.length() != 16
+					|| Integer.parseInt(number.substring(0, 5)) != 6011) {
+				ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid card number","messages.error.creditcard.number");
+				throw ex;
+			}
+		}
+
+		luhnValidate(number);
+	}
+
+	// The Luhn algorithm is basically a CRC type
+	// system for checking the validity of an entry.
+	// All major credit cards use numbers that will
+	// pass the Luhn check. Also, all of them are based
+	// on MOD 10.
+	
+	private void luhnValidate(String numberString)
+			throws ServiceException {
+		char[] charArray = numberString.toCharArray();
+		int[] number = new int[charArray.length];
+		int total = 0;
+	
+		for (int i = 0; i < charArray.length; i++) {
+			number[i] = Character.getNumericValue(charArray[i]);
+		}
+	
+		for (int i = number.length - 2; i > -1; i -= 2) {
+			number[i] *= 2;
+	
+			if (number[i] > 9)
+				number[i] -= 9;
+		}
+	
+		for (int i = 0; i < number.length; i++)
+			total += number[i];
+	
+		if (total % 10 != 0) {
+			ServiceException ex = new ServiceException(ServiceException.EXCEPTION_VALIDATION,"Invalid card number","messages.error.creditcard.number");
+			throw ex;
+		}
+	
+	}
+
+
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/service/TransactionService.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/service/TransactionService.java
new file mode 100644
index 0000000..c8ba2ff
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/service/TransactionService.java
@@ -0,0 +1,27 @@
+package com.salesmanager.core.business.payments.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.Transaction;
+
+
+public interface TransactionService extends SalesManagerEntityService<Long, Transaction> {
+
+	/**
+	 * Obtain a previous transaction that has type authorize for a give order
+	 * @param order
+	 * @return
+	 * @throws ServiceException
+	 */
+	Transaction getCapturableTransaction(Order order) throws ServiceException;
+
+	Transaction getRefundableTransaction(Order order) throws ServiceException;
+
+	List<Transaction> listTransactions(Order order) throws ServiceException;
+
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/payments/service/TransactionServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/payments/service/TransactionServiceImpl.java
new file mode 100644
index 0000000..c8ffa31
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/payments/service/TransactionServiceImpl.java
@@ -0,0 +1,157 @@
+package com.salesmanager.core.business.payments.service;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.mysql.jdbc.log.Log;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.dao.TransactionDao;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.payments.model.TransactionType;
+
+@Service("transactionService")
+public class TransactionServiceImpl  extends SalesManagerEntityServiceImpl<Long, Transaction> implements TransactionService {
+	
+
+	TransactionDao transactionDao;
+	
+	@Autowired
+	public TransactionServiceImpl(TransactionDao transactionDao) {
+		super(transactionDao);
+		this.transactionDao = transactionDao;
+	}
+	
+	@Override
+	public void create(Transaction transaction) throws ServiceException {
+		
+		//parse JSON string
+		String transactionDetails = transaction.toJSONString();
+		if(!StringUtils.isBlank(transactionDetails)) {
+			transaction.setDetails(transactionDetails);
+		}
+		
+		super.create(transaction);
+		
+		
+	}
+	
+	@Override
+	public List<Transaction> listTransactions(Order order) throws ServiceException {
+		
+		List<Transaction> transactions = transactionDao.listByOrder(order);
+		ObjectMapper mapper = new ObjectMapper();
+		for(Transaction transaction : transactions) {
+				if(!StringUtils.isBlank(transaction.getDetails())) {
+					try {
+						@SuppressWarnings("unchecked")
+						Map<String,String> objects = mapper.readValue(transaction.getDetails(), Map.class);
+						transaction.setTransactionDetails(objects);
+					} catch (Exception e) {
+						throw new ServiceException(e);
+					}
+				}
+		}
+		
+		return transactions;
+	}
+
+	@Override
+	public Transaction getCapturableTransaction(Order order)
+			throws ServiceException {
+		List<Transaction> transactions = transactionDao.listByOrder(order);
+		ObjectMapper mapper = new ObjectMapper();
+		Transaction capturable = null;
+		for(Transaction transaction : transactions) {
+			if(transaction.getTransactionType().name().equals(TransactionType.AUTHORIZE.name())) {
+				if(!StringUtils.isBlank(transaction.getDetails())) {
+					try {
+						@SuppressWarnings("unchecked")
+						Map<String,String> objects = mapper.readValue(transaction.getDetails(), Map.class);
+						transaction.setTransactionDetails(objects);
+						capturable = transaction;
+					} catch (Exception e) {
+						throw new ServiceException(e);
+					}
+				}
+			}
+			if(transaction.getTransactionType().name().equals(TransactionType.CAPTURE.name())) {
+				break;
+			}
+			if(transaction.getTransactionType().name().equals(TransactionType.REFUND.name())) {
+				break;
+			}
+		}
+		
+		return capturable;
+	}
+	
+	@Override
+	public Transaction getRefundableTransaction(Order order)
+		throws ServiceException {
+		List<Transaction> transactions = transactionDao.listByOrder(order);
+		Map<String,Transaction> finalTransactions = new HashMap<String,Transaction>();
+		Transaction finalTransaction = null;
+		for(Transaction transaction : transactions) {
+			//System.out.println("Transaction type " + transaction.getTransactionType().name());
+			if(transaction.getTransactionType().name().equals(TransactionType.AUTHORIZECAPTURE.name())) {
+				finalTransactions.put(TransactionType.AUTHORIZECAPTURE.name(),transaction);
+				continue;
+			}
+			if(transaction.getTransactionType().name().equals(TransactionType.CAPTURE.name())) {
+				finalTransactions.put(TransactionType.CAPTURE.name(),transaction);
+				continue;
+			}
+			if(transaction.getTransactionType().name().equals(TransactionType.REFUND.name())) {
+				//check transaction id
+				Transaction previousRefund = finalTransactions.get(TransactionType.REFUND.name());
+				if(previousRefund!=null) {
+					Date previousDate = previousRefund.getTransactionDate();
+					Date currentDate = transaction.getTransactionDate();
+					if(previousDate.before(currentDate)) {
+						finalTransactions.put(TransactionType.REFUND.name(),transaction);
+						continue;
+					}
+				} else {
+					finalTransactions.put(TransactionType.REFUND.name(),transaction);
+					continue;
+				}
+			}
+		}
+		
+		if(finalTransactions.containsKey(TransactionType.AUTHORIZECAPTURE.name())) {
+			finalTransaction = finalTransactions.get(TransactionType.AUTHORIZECAPTURE.name());
+		}
+		
+		if(finalTransactions.containsKey(TransactionType.CAPTURE.name())) {
+			finalTransaction = finalTransactions.get(TransactionType.CAPTURE.name());
+		}
+		
+		//if(finalTransactions.containsKey(TransactionType.REFUND.name())) {
+		//	finalTransaction = finalTransactions.get(TransactionType.REFUND.name());
+		//}
+
+		
+		if(finalTransaction!=null && !StringUtils.isBlank(finalTransaction.getDetails())) {
+			try {
+				ObjectMapper mapper = new ObjectMapper();
+				@SuppressWarnings("unchecked")
+				Map<String,String> objects = mapper.readValue(finalTransaction.getDetails(), Map.class);
+				finalTransaction.setTransactionDetails(objects);
+			} catch (Exception e) {
+				throw new ServiceException(e);
+			}
+		}
+		
+		return finalTransaction;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/country/dao/CountryDao.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/dao/CountryDao.java
new file mode 100644
index 0000000..44ddfc6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/dao/CountryDao.java
@@ -0,0 +1,12 @@
+package com.salesmanager.core.business.reference.country.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CountryDao extends SalesManagerEntityDao<Integer,Country> {
+
+	public List<Country> listByLanguage(Language language);
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/country/dao/CountryDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/dao/CountryDaoImpl.java
new file mode 100644
index 0000000..42b76c9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/dao/CountryDaoImpl.java
@@ -0,0 +1,36 @@
+package com.salesmanager.core.business.reference.country.dao;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.model.QCountry;
+import com.salesmanager.core.business.reference.country.model.QCountryDescription;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("countryDao")
+public class CountryDaoImpl extends SalesManagerEntityDaoImpl<Integer, Country> implements CountryDao {
+
+	
+	@Override
+	public List<Country> listByLanguage(Language language) {
+		QCountry qCountry = QCountry.country;
+		QCountryDescription qDescription = QCountryDescription.countryDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCountry)
+			.leftJoin(qCountry.descriptions, qDescription).fetch()
+			.where(qDescription.language.id.eq(language.getId()))
+			.orderBy(qDescription.name.asc());
+		
+
+		
+		List<Country> countries = query.list(qCountry);
+		return countries;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/country/model/Country.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/model/Country.java
new file mode 100644
index 0000000..6be29db
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/model/Country.java
@@ -0,0 +1,130 @@
+package com.salesmanager.core.business.reference.country.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Cacheable;
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.reference.geozone.model.GeoZone;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name = "COUNTRY", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+@Cacheable
+public class Country extends SalesManagerEntity<Integer, Country> {
+	private static final long serialVersionUID = -7388011537255588035L;
+
+	@Id
+	@Column(name="COUNTRY_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+	pkColumnValue = "COUNTRY_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Integer id;
+	
+	@OneToMany(mappedBy = "country", cascade = CascadeType.ALL)
+	private List<CountryDescription> descriptions = new ArrayList<CountryDescription>();
+	
+	@OneToMany(mappedBy = "country")
+	private List<Zone> zones = new ArrayList<Zone>();
+	
+	@ManyToOne(targetEntity = GeoZone.class)
+	@JoinColumn(name = "GEOZONE_ID")
+	private GeoZone geoZone;
+	
+	@Column(name = "COUNTRY_SUPPORTED")
+	private boolean supported = true;
+	
+	@Column(name = "COUNTRY_ISOCODE", unique=true, nullable = false)
+	private String isoCode;
+	
+	@Transient
+	private String name;
+	
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public Country() {
+	}
+	
+	public Country(String isoCode) {
+		this.setIsoCode(isoCode);
+	}
+	
+	public boolean getSupported() {
+		return supported;
+	}
+
+	public void setSupported(boolean supported) {
+		this.supported = supported;
+	}
+
+	public String getIsoCode() {
+		return isoCode;
+	}
+
+	public void setIsoCode(String isoCode) {
+		this.isoCode = isoCode;
+	}
+
+
+	@Override
+	public Integer getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public List<Zone> getZones() {
+		return zones;
+	}
+
+	public void setZones(List<Zone> zones) {
+		this.zones = zones;
+	}
+
+	public List<CountryDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(List<CountryDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	public GeoZone getGeoZone() {
+		return geoZone;
+	}
+
+	public void setGeoZone(GeoZone geoZone) {
+		this.geoZone = geoZone;
+	}
+
+/*	public GeoZone getGeoZone() {
+		return geoZone;
+	}
+
+	public void setGeoZone(GeoZone geoZone) {
+		this.geoZone = geoZone;
+	}*/
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/country/model/CountryDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/model/CountryDescription.java
new file mode 100644
index 0000000..c63c039
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/model/CountryDescription.java
@@ -0,0 +1,43 @@
+package com.salesmanager.core.business.reference.country.model;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Entity
+@Table(name = "COUNTRY_DESCRIPTION", schema="SALESMANAGER", uniqueConstraints={
+	@UniqueConstraint(columnNames={
+			"COUNTRY_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class CountryDescription extends Description {
+	private static final long serialVersionUID = 9048940117896071174L;
+	
+	@ManyToOne(targetEntity = Country.class)
+	@JoinColumn(name = "COUNTRY_ID", nullable = false)
+	private Country country;
+	
+	public CountryDescription() {
+	}
+	
+	public CountryDescription(Language language, String name) {
+		this.setLanguage(language);
+		this.setName(name);
+	}
+	
+	public Country getCountry() {
+		return country;
+	}
+
+	public void setCountry(Country country) {
+		this.country = country;
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/country/service/CountryService.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/service/CountryService.java
new file mode 100644
index 0000000..09733a3
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/service/CountryService.java
@@ -0,0 +1,25 @@
+package com.salesmanager.core.business.reference.country.service;
+
+import java.util.List;
+import java.util.Map;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.model.CountryDescription;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface CountryService extends SalesManagerEntityService<Integer, Country> {
+
+	public Country getByCode(String code) throws ServiceException;
+	
+	public void addCountryDescription(Country country, CountryDescription description) throws ServiceException;
+
+	public List<Country> getCountries(Language language) throws ServiceException;
+
+	Map<String, Country> getCountriesMap(Language language)
+			throws ServiceException;
+
+	List<Country> getCountries(List<String> isoCodes, Language language)
+			throws ServiceException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/country/service/CountryServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/service/CountryServiceImpl.java
new file mode 100644
index 0000000..c67609b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/country/service/CountryServiceImpl.java
@@ -0,0 +1,125 @@
+package com.salesmanager.core.business.reference.country.service;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.reference.country.dao.CountryDao;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.model.CountryDescription;
+import com.salesmanager.core.business.reference.country.model.Country_;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.utils.CacheUtils;
+
+@Service("countryService")
+public class CountryServiceImpl extends SalesManagerEntityServiceImpl<Integer, Country>
+		implements CountryService {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(CountryServiceImpl.class);
+	
+	private CountryDao countryDao;
+	
+	@Autowired
+	private CacheUtils cache;
+
+	
+	@Autowired
+	public CountryServiceImpl(CountryDao countryDao) {
+		super(countryDao);
+		this.countryDao = countryDao;
+	}
+	
+	public Country getByCode(String code) throws ServiceException {
+		return countryDao.getByField(Country_.isoCode, code);
+	}
+
+	@Override
+	public void addCountryDescription(Country country, CountryDescription description) throws ServiceException {
+		country.getDescriptions().add(description);
+		description.setCountry(country);
+		update(country);
+	}
+	
+	@Override
+	public Map<String,Country> getCountriesMap(Language language) throws ServiceException {
+		
+		List<Country> countries = this.getCountries(language);
+		
+		Map<String,Country> returnMap = new LinkedHashMap<String,Country>();
+		
+		for(Country country : countries) {
+			returnMap.put(country.getIsoCode(), country);
+		}
+		
+		return returnMap;
+	}
+	
+	
+	@Override
+	public List<Country> getCountries(final List<String> isoCodes, final Language language) throws ServiceException {
+		List<Country> countryList = getCountries(language);
+		List<Country> requestedCountryList = new ArrayList<Country>();
+		if(!CollectionUtils.isEmpty(countryList)) {
+			for(Country c : countryList) {
+				if(isoCodes.contains(c.getIsoCode())) {
+					requestedCountryList.add(c);
+				}
+			}
+		}
+		return requestedCountryList;
+	}
+	
+	
+	@SuppressWarnings("unchecked")
+	@Override
+	public List<Country> getCountries(Language language) throws ServiceException {
+		
+		List<Country> countries = null;
+		try {
+			
+			//CacheUtils cacheUtils = CacheUtils.getInstance();
+			
+			countries = (List<Country>) cache.getFromCache("COUNTRIES_" + language.getCode());
+
+		
+		
+			if(countries==null) {
+			
+				countries = countryDao.listByLanguage(language);
+			
+				//set names
+				for(Country country : countries) {
+					
+					CountryDescription description = country.getDescriptions().get(0);
+					country.setName(description.getName());
+					
+				}
+				
+				cache.putInCache(countries, "COUNTRIES_" + language.getCode());
+				
+			}
+			
+			
+		
+		
+		
+		} catch (Exception e) {
+			LOGGER.error("getCountries()", e);
+		}
+		
+		return countries;
+		
+		
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/dao/CurrencyDao.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/dao/CurrencyDao.java
new file mode 100644
index 0000000..67ae75a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/dao/CurrencyDao.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.reference.currency.dao;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+
+public interface CurrencyDao extends SalesManagerEntityDao<Long, Currency> {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/dao/CurrencyDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/dao/CurrencyDaoImpl.java
new file mode 100644
index 0000000..7118fe5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/dao/CurrencyDaoImpl.java
@@ -0,0 +1,35 @@
+package com.salesmanager.core.business.reference.currency.dao;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.currency.model.QCurrency;
+
+@Repository("currencyDao")
+public class CurrencyDaoImpl extends SalesManagerEntityDaoImpl<Long, Currency> 
+	implements CurrencyDao {
+
+	
+	@Override
+	public List<Currency> list() {
+		QCurrency qCurrency = QCurrency.currency1;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qCurrency)
+			.orderBy(qCurrency.code.asc());
+		
+
+		
+		List<Currency> currencies = query.list(qCurrency);
+		return currencies;
+	}
+	
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/model/Currency.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/model/Currency.java
new file mode 100644
index 0000000..0e1912c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/model/Currency.java
@@ -0,0 +1,90 @@
+package com.salesmanager.core.business.reference.currency.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name = "CURRENCY", schema = SchemaConstant.SALESMANAGER_SCHEMA)
+@Cacheable
+public class Currency extends SalesManagerEntity<Long, Currency> implements Serializable {
+	private static final long serialVersionUID = -999926410367685145L;
+	
+	@Id
+	@Column(name = "CURRENCY_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "CURRENCY_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column(name = "CURRENCY_CURRENCY_CODE" ,nullable = false, unique = true)
+	private java.util.Currency currency;
+	
+	@Column(name = "CURRENCY_SUPPORTED")
+	private Boolean supported = true;
+	
+	@Column(name = "CURRENCY_CODE", unique = true)
+	private String code;
+	
+	@Column(name = "CURRENCY_NAME", unique = true)
+	private String name;
+	
+	public Currency() {
+	}
+	
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public java.util.Currency getCurrency() {
+		return currency;
+	}
+
+	public void setCurrency(java.util.Currency currency) {
+		this.currency = currency;
+		this.code = currency.getCurrencyCode();
+	}
+
+	public Boolean getSupported() {
+		return supported;
+	}
+
+	public void setSupported(Boolean supported) {
+		this.supported = supported;
+	}
+	
+	public String getCode() {
+		if (currency.getCurrencyCode() != code) {
+			return currency.getCurrencyCode();
+		}
+		return code;
+	}
+	
+	public String getSymbol() {
+		return currency.getSymbol();
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/service/CurrencyService.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/service/CurrencyService.java
new file mode 100644
index 0000000..c7796bc
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/service/CurrencyService.java
@@ -0,0 +1,10 @@
+package com.salesmanager.core.business.reference.currency.service;
+
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+
+public interface CurrencyService extends SalesManagerEntityService<Long, Currency> {
+
+	Currency getByCode(String code);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/service/CurrencyServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/service/CurrencyServiceImpl.java
new file mode 100644
index 0000000..870cf4a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/currency/service/CurrencyServiceImpl.java
@@ -0,0 +1,25 @@
+package com.salesmanager.core.business.reference.currency.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.reference.currency.dao.CurrencyDao;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.currency.model.Currency_;
+
+@Service("currencyService")
+public class CurrencyServiceImpl extends SalesManagerEntityServiceImpl<Long, Currency>
+	implements CurrencyService {
+	
+	@Autowired
+	public CurrencyServiceImpl(CurrencyDao currencyDao) {
+		super(currencyDao);
+	}
+	
+	@Override
+	public Currency getByCode(String code) {
+		return getByField(Currency_.code, code);
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/geozone/model/GeoZone.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/geozone/model/GeoZone.java
new file mode 100644
index 0000000..f957d1d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/geozone/model/GeoZone.java
@@ -0,0 +1,92 @@
+package com.salesmanager.core.business.reference.geozone.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.reference.country.model.Country;
+
+@Entity
+@Table(name = "GEOZONE", schema="SALESMANAGER")
+// TODO : create DAO / Service
+public class GeoZone extends SalesManagerEntity<Long, GeoZone> {
+	private static final long serialVersionUID = -5992008645857938825L;
+	
+	@Id
+	@Column(name = "GEOZONE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "GEOZONE_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@OneToMany(mappedBy = "geoZone", cascade = CascadeType.ALL)
+	private List<GeoZoneDescription> descriptions = new ArrayList<GeoZoneDescription>();
+	
+	@OneToMany(mappedBy = "geoZone", targetEntity = Country.class)
+	private List<Country> countries = new ArrayList<Country>();
+	
+
+	
+	@Column(name = "GEOZONE_NAME")
+	private String name;
+	
+	@Column(name = "GEOZONE_CODE")
+	private String code;
+	
+	public GeoZone() {
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public List<Country> getCountries() {
+		return countries;
+	}
+
+	public void setCountries(List<Country> countries) {
+		this.countries = countries;
+	}
+
+	public List<GeoZoneDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(List<GeoZoneDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/geozone/model/GeoZoneDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/geozone/model/GeoZoneDescription.java
new file mode 100644
index 0000000..15925b6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/geozone/model/GeoZoneDescription.java
@@ -0,0 +1,36 @@
+package com.salesmanager.core.business.reference.geozone.model;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+
+@Entity
+@Table(name="GEOZONE_DESCRIPTION", schema="SALESMANAGER", uniqueConstraints={
+		@UniqueConstraint(columnNames={
+			"GEOZONE_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class GeoZoneDescription extends Description {
+	private static final long serialVersionUID = 7759498146450786218L;
+	
+	@ManyToOne(targetEntity = GeoZone.class)
+	@JoinColumn(name = "GEOZONE_ID")
+	private GeoZone geoZone;
+	
+	public GeoZoneDescription() {
+	}
+
+	public GeoZone getGeoZone() {
+		return geoZone;
+	}
+
+	public void setGeoZone(GeoZone geoZone) {
+		this.geoZone = geoZone;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/init/service/InitializationDatabase.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/init/service/InitializationDatabase.java
new file mode 100644
index 0000000..7c6266f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/init/service/InitializationDatabase.java
@@ -0,0 +1,11 @@
+package com.salesmanager.core.business.reference.init.service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+public interface InitializationDatabase {
+	
+	boolean isEmpty();
+	
+	void populate(String name) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/init/service/InitializationDatabaseImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/init/service/InitializationDatabaseImpl.java
new file mode 100644
index 0000000..1f7c3f0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/init/service/InitializationDatabaseImpl.java
@@ -0,0 +1,269 @@
+package com.salesmanager.core.business.reference.init.service;
+
+import java.sql.Date;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.catalog.product.service.type.ProductTypeService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.merchant.service.MerchantStoreService;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.model.CountryDescription;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.currency.service.CurrencyService;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.reference.zone.model.ZoneDescription;
+import com.salesmanager.core.business.reference.zone.service.ZoneService;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.service.ModuleConfigurationService;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.business.tax.service.TaxClassService;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.core.utils.reference.IntegrationModulesLoader;
+import com.salesmanager.core.utils.reference.ZonesLoader;
+
+@Service("initializationDatabase")
+public class InitializationDatabaseImpl implements InitializationDatabase {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(InitializationDatabaseImpl.class);
+	
+
+	
+	@Autowired
+	private ZoneService zoneService;
+	
+	@Autowired
+	private LanguageService languageService;
+	
+	@Autowired
+	private CountryService countryService;
+	
+	@Autowired
+	private CurrencyService currencyService;
+	
+	@Autowired
+	protected MerchantStoreService merchantService;
+		
+	@Autowired
+	protected ProductTypeService productTypeService;
+	
+	@Autowired
+	private TaxClassService taxClassService;
+	
+	@Autowired
+	private ZonesLoader zonesLoader;
+	
+	@Autowired
+	private IntegrationModulesLoader modulesLoader;
+	
+	@Autowired
+	private ModuleConfigurationService moduleConfigurationService;
+	
+
+	
+	private String name;
+	
+	public boolean isEmpty() {
+		return languageService.count() == 0;
+	}
+	
+	@Transactional
+	public void populate(String contextName) throws ServiceException {
+		this.name =  contextName;
+		
+		createLanguages();
+		createCountries();
+		createZones();
+		createCurrencies();
+		createSubReferences();
+		createModules();
+		createMerchant();
+
+
+	}
+	
+
+
+	private void createCurrencies() throws ServiceException {
+		LOGGER.info(String.format("%s : Populating Currencies ", name));
+
+		//Locale [] locales = Locale.getAvailableLocales();
+		//Locale l = locales[0];
+		
+		for (String code : SchemaConstant.CURRENCY_MAP.keySet()) {
+
+		      
+            try {
+            	java.util.Currency c = java.util.Currency.getInstance(code);
+            	
+            	if(c==null) {
+            		LOGGER.info(String.format("%s : Populating Currencies : no currency for code : %s", name, code));
+            	}
+            	
+            		//check if it exist
+            		
+	            	Currency currency = new Currency();
+	            	currency.setName(c.getCurrencyCode());
+	            	currency.setCurrency(c);
+	            	currencyService.create(currency);
+
+            //System.out.println(l.getCountry() + "   " + c.getSymbol() + "  " + c.getSymbol(l));
+            } catch (IllegalArgumentException e) {
+            	LOGGER.info(String.format("%s : Populating Currencies : no currency for code : %s", name, code));
+            }
+        }  
+	}
+
+	private void createCountries() throws ServiceException {
+		LOGGER.info(String.format("%s : Populating Countries ", name));
+		List<Language> languages = languageService.list();
+		for(String code : SchemaConstant.COUNTRY_ISO_CODE) {
+			Locale locale = SchemaConstant.LOCALES.get(code);
+			if (locale != null) {
+				Country country = new Country(code);
+				countryService.create(country);
+				
+				for (Language language : languages) {
+					String name = locale.getDisplayCountry(new Locale(language.getCode()));
+					CountryDescription description = new CountryDescription(language, name);
+					countryService.addCountryDescription(country, description);
+				}
+			}
+		}
+	}
+	
+	private void createZones() throws ServiceException {
+		LOGGER.info(String.format("%s : Populating Zones ", name));
+        try {
+
+    		  Map<String,Zone> zonesMap = new HashMap<String,Zone>();
+    		  zonesMap = zonesLoader.loadZones("reference/zoneconfig.json");
+              
+              for (Map.Entry<String, Zone> entry : zonesMap.entrySet()) {
+            	    String key = entry.getKey();
+            	    Zone value = entry.getValue();
+            	    if(value.getDescriptions()==null) {
+            	    	LOGGER.warn("This zone " + key + " has no descriptions");
+            	    	continue;
+            	    }
+            	    
+            	    List<ZoneDescription> zoneDescriptions = value.getDescriptions();
+            	    value.setDescriptons(null);
+
+            	    zoneService.create(value);
+            	    
+            	    for(ZoneDescription description : zoneDescriptions) {
+            	    	description.setZone(value);
+            	    	zoneService.addDescription(value, description);
+            	    }
+              }
+
+  		} catch (Exception e) {
+  		    
+  			throw new ServiceException(e);
+  		}
+
+	}
+
+	private void createLanguages() throws ServiceException {
+		LOGGER.info(String.format("%s : Populating Languages ", name));
+		for(String code : SchemaConstant.LANGUAGE_ISO_CODE) {
+			Language language = new Language(code);
+			languageService.create(language);
+		}
+	}
+	
+	private void createMerchant() throws ServiceException {
+		LOGGER.info(String.format("%s : Creating merchant ", name));
+		
+		Date date = new Date(System.currentTimeMillis());
+		
+		Language en = languageService.getByCode("en");
+		Country ca = countryService.getByCode("CA");
+		Currency currency = currencyService.getByCode("CAD");
+		Zone qc = zoneService.getByCode("QC");
+		
+		List<Language> supportedLanguages = new ArrayList<Language>();
+		supportedLanguages.add(en);
+		
+		//create a merchant
+		MerchantStore store = new MerchantStore();
+		store.setCountry(ca);
+		store.setCurrency(currency);
+		store.setDefaultLanguage(en);
+		store.setInBusinessSince(date);
+		store.setZone(qc);
+		store.setStorename("Default store");
+		store.setStorephone("888-888-8888");
+		store.setCode(MerchantStore.DEFAULT_STORE);
+		store.setStorecity("My city");
+		store.setStoreaddress("1234 Street address");
+		store.setStorepostalcode("H2H-2H2");
+		store.setStoreEmailAddress("test@test.com");
+		store.setDomainName("localhost:8080");
+		store.setStoreTemplate("bootstrap");
+		store.setLanguages(supportedLanguages);
+		
+		merchantService.create(store);
+		
+		
+		TaxClass taxclass = new TaxClass(TaxClass.DEFAULT_TAX_CLASS);
+		taxclass.setMerchantStore(store);
+		
+		taxClassService.create(taxclass);
+		
+		
+	}
+
+	private void createModules() throws ServiceException {
+		
+		try {
+			
+			List<IntegrationModule> modules = modulesLoader.loadIntegrationModules("reference/integrationmodules.json");
+            for (IntegrationModule entry : modules) {
+        	    moduleConfigurationService.create(entry);
+          }
+			
+			
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+		
+	}
+	
+	private void createSubReferences() throws ServiceException {
+		
+		LOGGER.info(String.format("%s : Loading catalog sub references ", name));
+		
+
+		
+		ProductType productType = new ProductType();
+		productType.setCode(ProductType.GENERAL_TYPE);
+		productTypeService.create(productType);
+
+
+		
+		
+	}
+	
+
+	
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/language/dao/LanguageDao.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/dao/LanguageDao.java
new file mode 100644
index 0000000..fc0ff60
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/dao/LanguageDao.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.reference.language.dao;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface LanguageDao extends SalesManagerEntityDao<Integer, Language> {
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/language/dao/LanguageDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/dao/LanguageDaoImpl.java
new file mode 100644
index 0000000..b80df29
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/dao/LanguageDaoImpl.java
@@ -0,0 +1,10 @@
+package com.salesmanager.core.business.reference.language.dao;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Repository("languageDao")
+public class LanguageDaoImpl extends SalesManagerEntityDaoImpl<Integer, Language> implements LanguageDao {
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/language/model/Language.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/model/Language.java
new file mode 100644
index 0000000..d359f59
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/model/Language.java
@@ -0,0 +1,114 @@
+package com.salesmanager.core.business.reference.language.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Cacheable;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "LANGUAGE", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+@Cacheable
+public class Language extends SalesManagerEntity<Integer, Language> implements Auditable {
+	private static final long serialVersionUID = -7676627812941330669L;
+	
+
+	
+	@Id
+	@Column(name="LANGUAGE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+	pkColumnValue = "LANG_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Integer id;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+
+	@Column(name="CODE", nullable = false)
+	private String code;
+	
+	@Column(name="SORT_ORDER")
+	private Integer sortOrder;
+	
+	@SuppressWarnings("unused")
+	@OneToMany(mappedBy = "defaultLanguage", targetEntity = MerchantStore.class)
+	private List<MerchantStore> storesDefaultLanguage;
+	
+	@SuppressWarnings("unused")
+	@ManyToMany(mappedBy = "languages", targetEntity = MerchantStore.class)
+	private List<MerchantStore> stores = new ArrayList<MerchantStore>();
+	
+	public Language() {
+	}
+	
+	public Language(String code) {
+		this.setCode(code);
+	}
+	
+	@Override
+	public Integer getId() {
+		return id;
+	}
+	
+	@Override
+	public void setId(Integer id) {
+		this.id = id;
+	}
+	
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public Integer getSortOrder() {
+		return sortOrder;
+	}
+
+	public void setSortOrder(Integer sortOrder) {
+		this.sortOrder = sortOrder;
+	}
+	
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+	
+	@Override
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+	
+	@Override
+	public boolean equals(Object obj) {
+		if (null == obj)
+			return false;
+		if (!(obj instanceof Language)) {
+			return false;
+		} else {
+			Language language = (Language) obj;
+			return (this.id == language.getId());
+		}
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/language/service/LanguageService.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/service/LanguageService.java
new file mode 100644
index 0000000..6296660
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/service/LanguageService.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.business.reference.language.service;
+
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface LanguageService extends SalesManagerEntityService<Integer, Language> {
+
+	Language getByCode(String code) throws ServiceException;
+
+	Map<String, Language> getLanguagesMap() throws ServiceException;
+
+	List<Language> getLanguages() throws ServiceException;
+
+	Locale toLocale(Language language);
+
+	Language toLanguage(Locale locale);
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/language/service/LanguageServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/service/LanguageServiceImpl.java
new file mode 100644
index 0000000..429ed17
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/language/service/LanguageServiceImpl.java
@@ -0,0 +1,108 @@
+package com.salesmanager.core.business.reference.language.service;
+
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.reference.language.dao.LanguageDao;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.model.Language_;
+import com.salesmanager.core.utils.CacheUtils;
+
+@Service("languageService")
+public class LanguageServiceImpl extends SalesManagerEntityServiceImpl<Integer, Language>
+	implements LanguageService {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(LanguageServiceImpl.class);
+	
+	@Autowired
+	private CacheUtils cache;
+	
+	@Autowired
+	public LanguageServiceImpl(LanguageDao languageDao) {
+		super(languageDao);
+	}
+	
+	@Override
+	public Language getByCode(String code) throws ServiceException {
+		return getByField(Language_.code, code);
+	}
+	
+	@Override
+	public Locale toLocale(Language language) {
+		return new Locale(language.getCode());
+	}
+	
+	@Override
+	public Language toLanguage(Locale locale) {
+		
+		try {
+			Language lang = getLanguagesMap().get(locale.getLanguage());
+			return lang;
+		} catch (Exception e) {
+			LOGGER.error("Cannot convert locale " + locale.getLanguage() + " to language");
+		}
+		
+		return null;
+
+	}
+	
+	@Override
+	public Map<String,Language> getLanguagesMap() throws ServiceException {
+		
+		List<Language> langs = this.getLanguages();
+
+		Map<String,Language> returnMap = new LinkedHashMap<String,Language>();
+		
+		for(Language lang : langs) {
+			
+			returnMap.put(lang.getCode(), lang);
+			
+		}
+		
+		return returnMap;
+		
+		
+	}
+	
+	
+	@Override
+	@SuppressWarnings("unchecked")
+	public List<Language> getLanguages() throws ServiceException {
+		
+		
+		List<Language> langs = null;
+		try {
+			
+			//CacheUtils cacheUtils = CacheUtils.getInstance();
+			
+			langs = (List<Language>) cache.getFromCache("LANGUAGES");
+
+		
+		
+			if(langs==null) {
+				langs = this.list();
+				cache.putInCache(langs, "LANGUAGES");
+			}
+			
+			
+		
+		
+		
+		} catch (Exception e) {
+			LOGGER.error("getCountries()", e);
+		}
+		
+		return langs;
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/dao/ZoneDao.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/dao/ZoneDao.java
new file mode 100644
index 0000000..b0f1e0b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/dao/ZoneDao.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.business.reference.zone.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+
+
+public interface ZoneDao extends SalesManagerEntityDao<Long,Zone> {
+
+	List<Zone> listByLanguageAndCountry(Country country, Language language);
+
+	List<Zone> listByLanguage(Language language);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/dao/ZoneDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/dao/ZoneDaoImpl.java
new file mode 100644
index 0000000..9b48d28
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/dao/ZoneDaoImpl.java
@@ -0,0 +1,54 @@
+package com.salesmanager.core.business.reference.zone.dao;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.QZone;
+import com.salesmanager.core.business.reference.zone.model.QZoneDescription;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+
+@Repository("zoneDao")
+public class ZoneDaoImpl extends SalesManagerEntityDaoImpl<Long, Zone> implements ZoneDao {
+	
+	@Override
+	public List<Zone> listByLanguageAndCountry(Country country, Language language) {
+		QZone qZone = QZone.zone;
+		QZoneDescription qDescription = QZoneDescription.zoneDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qZone)
+			.leftJoin(qZone.descriptions, qDescription).fetch()
+			.where(qDescription.language.id.eq(language.getId())
+					.and(qZone.country.isoCode.eq(country.getIsoCode())))
+					.orderBy(qDescription.name.asc());
+		
+
+		
+		List<Zone> zones = query.list(qZone);
+		return zones;
+	}
+	
+	@Override
+	public List<Zone> listByLanguage(Language language) {
+		QZone qZone = QZone.zone;
+		QZoneDescription qDescription = QZoneDescription.zoneDescription;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qZone)
+			.leftJoin(qZone.descriptions, qDescription).fetch()
+			.where(qDescription.language.id.eq(language.getId()))
+					.orderBy(qDescription.name.asc());
+
+		List<Zone> zones = query.list(qZone);
+		return zones;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/imports/ZoneLoader.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/imports/ZoneLoader.java
new file mode 100644
index 0000000..faf5221
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/imports/ZoneLoader.java
@@ -0,0 +1,31 @@
+package com.salesmanager.core.business.reference.zone.imports;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.type.TypeReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+public class ZoneLoader {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ZoneLoader.class);
+	
+	 public Map<String, List<ZoneTransient>> loadZoneConfigurations() {
+		
+		ObjectMapper mapper = new ObjectMapper();
+		InputStream in = this.getClass().getResourceAsStream("/reference/zoneconfig.json");
+		Map<String,List<ZoneTransient>> zoneConfigurations = new HashMap<String, List<ZoneTransient>>();
+		try {
+			zoneConfigurations = mapper.readValue(in, new TypeReference<HashMap<String,List<ZoneTransient>>>() { });
+		} catch (Exception e) {
+			LOGGER.error("Error import zones.", e);
+		}
+		
+		return zoneConfigurations;
+	 }
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/imports/ZoneTransient.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/imports/ZoneTransient.java
new file mode 100644
index 0000000..899d974
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/imports/ZoneTransient.java
@@ -0,0 +1,28 @@
+package com.salesmanager.core.business.reference.zone.imports;
+
+public class ZoneTransient {
+	
+	private String zoneCode;
+	private String zoneName;
+	private String countryCode;
+	
+	public String getZoneCode() {
+		return zoneCode;
+	}
+	public void setZoneCode(String zoneCode) {
+		this.zoneCode = zoneCode;
+	}
+	public String getZoneName() {
+		return zoneName;
+	}
+	public void setZoneName(String zoneName) {
+		this.zoneName = zoneName;
+	}
+	public String getCountryCode() {
+		return countryCode;
+	}
+	public void setCountryCode(String countryCode) {
+		this.countryCode = countryCode;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/model/Zone.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/model/Zone.java
new file mode 100644
index 0000000..36401ac
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/model/Zone.java
@@ -0,0 +1,102 @@
+package com.salesmanager.core.business.reference.zone.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name = "ZONE", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class Zone extends SalesManagerEntity<Long, Zone>{
+	private static final long serialVersionUID = 1L;
+	
+	@Id
+	@Column(name="ZONE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT",
+	pkColumnValue = "ZONE_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@OneToMany(mappedBy = "zone", cascade = CascadeType.ALL)
+	private List<ZoneDescription> descriptions = new ArrayList<ZoneDescription>();
+	
+	@ManyToOne
+	@JoinColumn(name="COUNTRY_ID", nullable = false)
+	private Country country;
+	
+	@Transient
+	private String name;
+	
+
+	
+	@Column(name = "ZONE_CODE", unique=true, nullable = false)
+	private String code;
+	
+	public Zone() {
+	}
+	
+	public Zone(Country country, String name, String code) {
+		this.setCode(code);
+		this.setCountry(country);
+		this.setCode(name);
+	}
+	
+	public Country getCountry() {
+		return country;
+	}
+
+	public void setCountry(Country country) {
+		this.country = country;
+	}
+
+
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+	public List<ZoneDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptons(List<ZoneDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/model/ZoneDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/model/ZoneDescription.java
new file mode 100644
index 0000000..234d3da
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/model/ZoneDescription.java
@@ -0,0 +1,43 @@
+package com.salesmanager.core.business.reference.zone.model;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Entity
+@Table(name="ZONE_DESCRIPTION", uniqueConstraints={
+		@UniqueConstraint(columnNames={
+			"ZONE_ID",
+			"LANGUAGE_ID"
+		})
+	}
+)
+public class ZoneDescription extends Description {
+	private static final long serialVersionUID = 6448836326562270923L;
+	
+	@ManyToOne(targetEntity = Zone.class)
+	@JoinColumn(name = "ZONE_ID", nullable = false)
+	private Zone zone;
+	
+	public ZoneDescription() {
+	}
+	
+	public ZoneDescription(Zone zone, Language language, String name) {
+		setZone(zone);
+		setLanguage(language);
+		setName(name);
+	}
+	
+	public Zone getZone() {
+		return zone;
+	}
+
+	public void setZone(Zone zone) {
+		this.zone = zone;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/service/ZoneService.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/service/ZoneService.java
new file mode 100644
index 0000000..ce0daeb
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/service/ZoneService.java
@@ -0,0 +1,25 @@
+package com.salesmanager.core.business.reference.zone.service;
+
+import java.util.List;
+import java.util.Map;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.reference.zone.model.ZoneDescription;
+
+public interface ZoneService extends SalesManagerEntityService<Long, Zone> {
+	
+	Zone getByCode(String code);
+
+	void addDescription(Zone zone, ZoneDescription description) throws ServiceException;
+
+	List<Zone> getZones(Country country, Language language)
+			throws ServiceException;
+
+	Map<String, Zone> getZones(Language language) throws ServiceException;
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/service/ZoneServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/service/ZoneServiceImpl.java
new file mode 100644
index 0000000..7d16657
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/reference/zone/service/ZoneServiceImpl.java
@@ -0,0 +1,132 @@
+package com.salesmanager.core.business.reference.zone.service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.dao.ZoneDao;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.reference.zone.model.ZoneDescription;
+import com.salesmanager.core.business.reference.zone.model.Zone_;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.utils.CacheUtils;
+
+@Service("zoneService")
+public class ZoneServiceImpl extends SalesManagerEntityServiceImpl<Long, Zone> implements
+		ZoneService {
+	
+	private final static String ZONE_CACHE_PREFIX = "ZONES_";
+
+	private ZoneDao zoneDao;
+	
+	@Autowired
+	private CacheUtils cache;
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ZoneServiceImpl.class);
+
+	@Autowired
+	public ZoneServiceImpl(ZoneDao zoneDao) {
+		super(zoneDao);
+		this.zoneDao = zoneDao;
+	}
+
+	@Override
+	public Zone getByCode(String code) {
+		return getByField(Zone_.code, code);
+	}
+
+	@Override
+	public void addDescription(Zone zone, ZoneDescription description) throws ServiceException {
+		if (zone.getDescriptions()!=null) {
+				if(!zone.getDescriptions().contains(description)) {
+					zone.getDescriptions().add(description);
+					update(zone);
+				}
+		} else {
+			List<ZoneDescription> descriptions = new ArrayList<ZoneDescription>();
+			descriptions.add(description);
+			zone.setDescriptons(descriptions);
+			update(zone);
+		}
+	}
+	
+	@SuppressWarnings("unchecked")
+	@Override
+	public List<Zone> getZones(Country country, Language language) throws ServiceException {
+		
+		List<Zone> zones = null;
+		try {
+
+			String cacheKey = ZONE_CACHE_PREFIX + country.getIsoCode() + Constants.UNDERSCORE + language.getCode();
+			
+			zones = (List<Zone>) cache.getFromCache(cacheKey);
+
+		
+		
+			if(zones==null) {
+			
+				zones = zoneDao.listByLanguageAndCountry(country, language);
+			
+				//set names
+				for(Zone zone : zones) {
+					ZoneDescription description = zone.getDescriptions().get(0);
+					zone.setName(description.getName());
+					
+				}
+				cache.putInCache(zones, cacheKey);
+			}
+
+		} catch (Exception e) {
+			LOGGER.error("getZones()", e);
+		}
+		return zones;
+		
+		
+	}
+	
+	@Override
+	@SuppressWarnings("unchecked")
+	public Map<String, Zone> getZones(Language language) throws ServiceException {
+		
+		Map<String, Zone> zones = null;
+		try {
+
+			String cacheKey = ZONE_CACHE_PREFIX + language.getCode();
+			
+			zones = (Map<String, Zone>) cache.getFromCache(cacheKey);
+
+		
+		
+			if(zones==null) {
+				zones = new HashMap<String, Zone>();
+				List<Zone> zns = zoneDao.listByLanguage(language);
+			
+				//set names
+				for(Zone zone : zns) {
+					ZoneDescription description = zone.getDescriptions().get(0);
+					zone.setName(description.getName());
+					zones.put(zone.getCode(), zone);
+					
+				}
+				cache.putInCache(zones, cacheKey);
+			}
+
+		} catch (Exception e) {
+			LOGGER.error("getZones()", e);
+		}
+		return zones;
+		
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/search/model/IndexProduct.java b/sm-core/src/main/java/com/salesmanager/core/business/search/model/IndexProduct.java
new file mode 100644
index 0000000..4e15b0c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/search/model/IndexProduct.java
@@ -0,0 +1,148 @@
+package com.salesmanager.core.business.search.model;
+
+import java.util.List;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+public class IndexProduct implements JSONAware {
+	
+	private String name;
+	private Double price;
+	private List<String> categories;//category code
+	private String manufacturer;//id of the manufacturer
+	private boolean available;
+	private String description;
+	private List<String> tags;//keywords ?
+	private String highlight;
+	private String store;
+	private String lang;
+	private String id;//required by the search framework
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		
+		
+		
+		
+		JSONObject obj = new JSONObject();
+		obj.put("name", this.getName());
+		obj.put("price", this.getPrice());
+		obj.put("description", this.getDescription());
+		obj.put("highlight", this.getHighlight());
+		obj.put("store", this.getStore());
+		obj.put("manufacturer", this.getManufacturer());
+		obj.put("lang", this.getLang());
+		obj.put("id", this.getId());
+		if(categories!=null) {
+			JSONArray categoriesArray = new JSONArray();
+			for(String category : categories) {
+				categoriesArray.add(category);
+			}
+			obj.put("categories", categoriesArray);
+		}
+		
+		if(tags!=null) {
+			JSONArray tagsArray = new JSONArray();
+			for(String tag : tags) {
+				tagsArray.add(tag);
+			}
+			obj.put("tags", tagsArray);
+		}
+		
+		return obj.toJSONString();
+
+	}
+
+	public String getName() {
+		return name;
+	}
+
+	public void setName(String name) {
+		this.name = name;
+	}
+
+
+	public List<String> getCategories() {
+		return categories;
+	}
+
+	public void setCategories(List<String> categories) {
+		this.categories = categories;
+	}
+
+	public boolean isAvailable() {
+		return available;
+	}
+
+	public void setAvailable(boolean available) {
+		this.available = available;
+	}
+
+	public String getDescription() {
+		return description;
+	}
+
+	public void setDescription(String description) {
+		this.description = description;
+	}
+
+	public List<String> getTags() {
+		return tags;
+	}
+
+	public void setTags(List<String> tags) {
+		this.tags = tags;
+	}
+
+	public String getHighlight() {
+		return highlight;
+	}
+
+	public void setHighlight(String highlight) {
+		this.highlight = highlight;
+	}
+
+	public void setPrice(Double price) {
+		this.price = price;
+	}
+
+	public Double getPrice() {
+		return price;
+	}
+
+	public void setStore(String store) {
+		this.store = store;
+	}
+
+	public String getStore() {
+		return store;
+	}
+
+	public void setLang(String lang) {
+		this.lang = lang;
+	}
+
+	public String getLang() {
+		return lang;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public void setManufacturer(String manufacturer) {
+		this.manufacturer = manufacturer;
+	}
+
+	public String getManufacturer() {
+		return manufacturer;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchEntry.java b/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchEntry.java
new file mode 100644
index 0000000..5b6ba57
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchEntry.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.business.search.model;
+
+import java.util.List;
+
+public class SearchEntry {
+	
+	private IndexProduct indexProduct;//product as saved in the index
+	private List<String> highlights;
+	public void setHighlights(List<String> highlights) {
+		this.highlights = highlights;
+	}
+	public List<String> getHighlights() {
+		return highlights;
+	}
+	public void setIndexProduct(IndexProduct indexProduct) {
+		this.indexProduct = indexProduct;
+	}
+	public IndexProduct getIndexProduct() {
+		return indexProduct;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchFacet.java b/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchFacet.java
new file mode 100644
index 0000000..840f883
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchFacet.java
@@ -0,0 +1,27 @@
+package com.salesmanager.core.business.search.model;
+
+public class SearchFacet {
+	
+	private String name;
+	private String key;
+	private long count;
+	public void setKey(String key) {
+		this.key = key;
+	}
+	public String getKey() {
+		return key;
+	}
+	public void setName(String name) {
+		this.name = name;
+	}
+	public String getName() {
+		return name;
+	}
+	public void setCount(long count) {
+		this.count = count;
+	}
+	public long getCount() {
+		return count;
+	};
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchKeywords.java b/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchKeywords.java
new file mode 100644
index 0000000..0ef1d3e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchKeywords.java
@@ -0,0 +1,34 @@
+package com.salesmanager.core.business.search.model;
+
+import java.util.List;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+public class SearchKeywords implements JSONAware{
+	
+	private List<String> keywords;
+
+	public void setKeywords(List<String> keywords) {
+		this.keywords = keywords;
+	}
+
+	public List<String> getKeywords() {
+		return keywords;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		JSONArray jsonArray = new JSONArray();
+		for(String kw : keywords) {
+			JSONObject data = new JSONObject();
+			data.put("name", kw);
+			data.put("value", kw);
+			jsonArray.add(data);
+		}
+		return jsonArray.toJSONString();
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchResponse.java b/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchResponse.java
new file mode 100644
index 0000000..986c87a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/search/model/SearchResponse.java
@@ -0,0 +1,39 @@
+package com.salesmanager.core.business.search.model;
+
+import java.util.List;
+import java.util.Map;
+
+public class SearchResponse {
+	
+	private int totalCount = 0;//total number of entries
+	private int entryCount = 0;//number of entries asked
+	
+	private List<SearchEntry> entries;
+	private Map<String,List<SearchFacet>> facets;//facet key (example : category) & facet description (example : category code)
+	
+	public void setTotalCount(int totalCount) {
+		this.totalCount = totalCount;
+	}
+	public int getTotalCount() {
+		return totalCount;
+	}
+	public void setEntryCount(int entryCount) {
+		this.entryCount = entryCount;
+	}
+	public int getEntryCount() {
+		return entryCount;
+	}
+	public void setEntries(List<SearchEntry> entries) {
+		this.entries = entries;
+	}
+	public List<SearchEntry> getEntries() {
+		return entries;
+	}
+	public void setFacets(Map<String,List<SearchFacet>> facets) {
+		this.facets = facets;
+	}
+	public Map<String,List<SearchFacet>> getFacets() {
+		return facets;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/search/service/SearchService.java b/sm-core/src/main/java/com/salesmanager/core/business/search/service/SearchService.java
new file mode 100644
index 0000000..7f63e2c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/search/service/SearchService.java
@@ -0,0 +1,58 @@
+package com.salesmanager.core.business.search.service;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.search.model.SearchKeywords;
+import com.salesmanager.core.business.search.model.SearchResponse;
+
+public interface SearchService {
+	
+	/**
+	 * The indexing service for products. The index service must be invoked when a product is
+	 * created or updated
+	 * @param store
+	 * @param product
+	 * @throws ServiceException
+	 */
+	void index(MerchantStore store, Product product) throws ServiceException;
+
+	/**
+	 * Deletes an index in the appropriate language. Must be invoked when a product is deleted
+	 * @param store
+	 * @param product
+	 * @throws ServiceException
+	 */
+	void deleteIndex(MerchantStore store, Product product)
+			throws ServiceException;
+
+	/**
+	 * Similar keywords based on a a series of characters. Used in the auto-complete
+	 * functionality
+	 * @param collectionName
+	 * @param jsonString
+	 * @param entriesCount
+	 * @return
+	 * @throws ServiceException
+	 */
+	SearchKeywords searchForKeywords(String collectionName,
+			String jsonString, int entriesCount) throws ServiceException;
+
+	/**
+	 * Search products based on user entry
+	 * @param store
+	 * @param languageCode
+	 * @param jsonString
+	 * @param entriesCount
+	 * @param startIndex
+	 * @throws ServiceException
+	 */
+	SearchResponse search(MerchantStore store, String languageCode, String jsonString,
+			int entriesCount, int startIndex) throws ServiceException;
+
+	/**
+	 * Initializes search service in order to avoid lazy initialization
+	 */
+	void initService();
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/search/service/SearchServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/search/service/SearchServiceImpl.java
new file mode 100644
index 0000000..5065aa4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/search/service/SearchServiceImpl.java
@@ -0,0 +1,316 @@
+package com.salesmanager.core.business.search.service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.elasticsearch.common.text.Text;
+import org.elasticsearch.search.highlight.HighlightField;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.catalog.product.service.PricingService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.search.model.IndexProduct;
+import com.salesmanager.core.business.search.model.SearchEntry;
+import com.salesmanager.core.business.search.model.SearchFacet;
+import com.salesmanager.core.business.search.model.SearchKeywords;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.utils.CoreConfiguration;
+import com.shopizer.search.services.Facet;
+import com.shopizer.search.services.SearchHit;
+import com.shopizer.search.services.SearchRequest;
+import com.shopizer.search.services.SearchResponse;
+
+
+@Service("productSearchService")
+public class SearchServiceImpl implements SearchService {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(SearchServiceImpl.class);
+	
+	
+	private final static String PRODUCT_INDEX_NAME = "product";
+	private final static String UNDERSCORE = "_";
+	private final static String INDEX_PRODUCTS = "INDEX_PRODUCTS";
+
+	@Autowired
+	private com.shopizer.search.services.SearchService searchService;
+	
+	@Autowired
+	private PricingService pricingService;
+	
+	@Autowired
+	private CoreConfiguration configuration;
+	
+	@Override
+	public void initService() {
+		searchService.initService();
+	}
+
+	@SuppressWarnings("rawtypes")
+	@Override
+	public void index(MerchantStore store, Product product)
+			throws ServiceException {
+		
+		/**
+		 * When a product is saved or updated the indexing process occurs
+		 * 
+		 * A product entity will have to be transformed to a bean ProductIndex
+		 * which contains the indices as described in product.json
+		 * 
+		 * {"product": {
+						"properties" :  {
+							"name" : {"type":"string","index":"analyzed"},
+							"price" : {"type":"string","index":"not_analyzed"},
+							"category" : {"type":"string","index":"not_analyzed"},
+							"lang" : {"type":"string","index":"not_analyzed"},
+							"available" : {"type":"string","index":"not_analyzed"},
+							"description" : {"type":"string","index":"analyzed","index_analyzer":"english"}, 
+							"tags" : {"type":"string","index":"not_analyzed"} 
+						 } 
+			            }
+			}
+		 *
+		 * productService saveOrUpdate as well as create and update will invoke
+		 * productSearchService.index	
+		 * 
+		 * A copy of properies between Product to IndexProduct
+		 * Then IndexProduct will be transformed to a json representation by the invocation
+		 * of .toJSONString on IndexProduct
+		 * 
+		 * Then index product
+		 * searchService.index(json, "product_<LANGUAGE_CODE>_<MERCHANT_CODE>", "product");
+		 * 
+		 * example ...index(json,"product_en_default",product)
+		 * 
+		 */
+		
+		if(configuration.getProperty(INDEX_PRODUCTS)==null || configuration.getProperty(INDEX_PRODUCTS).equals(Constants.FALSE)) {
+			return;
+		}
+		
+		FinalPrice price = pricingService.calculateProductPrice(product);
+
+		
+		Set<ProductDescription> descriptions = product.getDescriptions();
+		for(ProductDescription description : descriptions) {
+			
+			StringBuilder collectionName = new StringBuilder();
+			collectionName.append(PRODUCT_INDEX_NAME).append(UNDERSCORE).append(description.getLanguage().getCode()).append(UNDERSCORE).append(store.getCode().toLowerCase());
+			
+			IndexProduct index = new IndexProduct();
+
+			index.setId(String.valueOf(product.getId()));
+			index.setStore(store.getCode().toLowerCase());
+			index.setLang(description.getLanguage().getCode());
+			index.setAvailable(product.isAvailable());
+			index.setDescription(description.getDescription());
+			index.setName(description.getName());
+			if(product.getManufacturer()!=null) {
+				index.setManufacturer(String.valueOf(product.getManufacturer().getId()));
+			}
+			if(price!=null) {
+				index.setPrice(price.getFinalPrice().doubleValue());
+			}
+			index.setHighlight(description.getProductHighlight());
+			if(!StringUtils.isBlank(description.getMetatagKeywords())){
+				String[] tags = description.getMetatagKeywords().split(",");
+				@SuppressWarnings("unchecked")
+				List<String> tagsList = new ArrayList(Arrays.asList(tags));
+				index.setTags(tagsList);
+			}
+
+			
+			Set<Category> categories = product.getCategories();
+			if(!CollectionUtils.isEmpty(categories)) {
+				List<String> categoryList = new ArrayList<String>();
+				for(Category category : categories) {
+					categoryList.add(category.getCode());
+				}
+				index.setCategories(categoryList);
+			}
+			
+			String jsonString = index.toJSONString();
+			try {
+				searchService.index(jsonString, collectionName.toString(), new StringBuilder().append(PRODUCT_INDEX_NAME).append(UNDERSCORE).append(description.getLanguage().getCode()).toString());
+			} catch (Exception e) {
+				throw new ServiceException("Cannot index product id [" + product.getId() + "], " + e.getMessage() ,e);
+			}
+		}
+	}
+
+	@Override
+	public void deleteIndex(MerchantStore store, Product product) throws ServiceException {
+		
+		if(configuration.getProperty(INDEX_PRODUCTS)==null || configuration.getProperty(INDEX_PRODUCTS).equals(Constants.FALSE)) {
+			return;
+		}
+		
+		Set<ProductDescription> descriptions = product.getDescriptions();
+		for(ProductDescription description : descriptions) {
+			
+			StringBuilder collectionName = new StringBuilder();
+			collectionName.append(PRODUCT_INDEX_NAME).append(UNDERSCORE).append(description.getLanguage().getCode()).append(UNDERSCORE).append(store.getCode().toLowerCase());
+
+			try {
+				searchService.deleteObject(collectionName.toString(), new StringBuilder().append(PRODUCT_INDEX_NAME).append(UNDERSCORE).append(description.getLanguage().getCode()).toString(), String.valueOf(product.getId()));
+			} catch (Exception e) {
+				LOGGER.error("Cannot delete index for product id [" + product.getId() + "], ",e);
+			}
+		}
+	
+	}
+	
+	@Override
+	public SearchKeywords searchForKeywords(String collectionName, String jsonString, int entriesCount) throws ServiceException {
+		
+		/**
+		 * 	$('#search').searchAutocomplete({
+			url: '<%=request.getContextPath()%>/search/autocomplete/keyword_en'
+		  		//filter: function() { 
+				//return '\"filter\" : {\"numeric_range\" : {\"price\" : {\"from\" : \"22\",\"to\" : \"45\",\"include_lower\" : true,\"include_upper\" : true}}}';
+		  		//}
+     		});
+     		
+     	**/	
+     		
+		try {
+
+			SearchResponse response = searchService.searchAutoComplete(collectionName, jsonString, entriesCount);
+			
+			SearchKeywords keywords = new SearchKeywords();
+			keywords.setKeywords(Arrays.asList(response.getInlineSearchList()));
+			
+			return keywords;
+			
+		} catch (Exception e) {
+			LOGGER.error("Error while searching keywords " + jsonString,e);
+			throw new ServiceException(e);
+		}
+
+		
+	}
+	
+	@Override
+	public com.salesmanager.core.business.search.model.SearchResponse search(MerchantStore store, String languageCode, String jsonString, int entriesCount, int startIndex) throws ServiceException {
+		
+
+		try {
+			
+			StringBuilder collectionName = new StringBuilder();
+			collectionName.append(PRODUCT_INDEX_NAME).append(UNDERSCORE).append(languageCode).append(UNDERSCORE).append(store.getCode().toLowerCase());
+			
+			
+			SearchRequest request = new SearchRequest();
+			request.setCollection(collectionName.toString());
+			request.setSize(entriesCount);
+			request.setStart(startIndex);
+			request.setJson(jsonString);
+			
+			SearchResponse response =searchService.search(request);
+			
+			com.salesmanager.core.business.search.model.SearchResponse resp = new com.salesmanager.core.business.search.model.SearchResponse();
+			
+			
+			resp.setTotalCount(response.getCount());
+			
+			List<SearchEntry> entries = new ArrayList<SearchEntry>();
+			
+			Collection<SearchHit> hits = response.getSearchHits();
+			for(SearchHit hit : hits) {
+				
+				SearchEntry entry = new SearchEntry();
+				
+				Map<String,Object> metaEntries = hit.getMetaEntries();
+				IndexProduct indexProduct = new IndexProduct();
+				Map sourceEntries = (Map)metaEntries.get("source");
+				
+				indexProduct.setDescription((String)sourceEntries.get("description"));
+				indexProduct.setHighlight((String)sourceEntries.get("highlight"));
+				indexProduct.setId((String)sourceEntries.get("id"));
+				indexProduct.setLang((String)sourceEntries.get("lang"));
+				indexProduct.setName(((String)sourceEntries.get("name")));
+				indexProduct.setManufacturer(((String)sourceEntries.get("manufacturer")));
+				indexProduct.setPrice(((Double)sourceEntries.get("price")));
+				indexProduct.setStore(((String)sourceEntries.get("store")));
+				entry.setIndexProduct(indexProduct);
+				entries.add(entry);
+				
+				Map<String, HighlightField> fields = hit.getHighlightFields();
+				if(fields!=null) {
+					List<String> highlights = new ArrayList<String>();
+					for(HighlightField field : fields.values()) {
+						
+						Text[] text = field.getFragments();
+						//text[0]
+						String f = field.getName();
+						highlights.add(f);
+						
+						
+					}
+					
+					entry.setHighlights(highlights);
+				
+				}
+			}
+			
+			resp.setEntries(entries);
+			
+			Map<String,Facet> facets = response.getFacets();
+			if(facets!=null) {
+				Map<String,List<SearchFacet>> searchFacets = new HashMap<String,List<SearchFacet>>();
+				for(String key : facets.keySet()) {
+					
+					Facet f = facets.get(key);
+					
+					List<SearchFacet> fs = searchFacets.get(key);
+					if(fs==null) {
+						fs = new ArrayList<SearchFacet>();
+						searchFacets.put(key, fs);
+					}
+					
+					List<com.shopizer.search.services.Entry> facetEntries = f.getEntries();
+					for(com.shopizer.search.services.Entry facetEntry : facetEntries) {
+					
+						SearchFacet searchFacet = new SearchFacet();
+						searchFacet.setKey(facetEntry.getName());
+						searchFacet.setName(facetEntry.getName());
+						searchFacet.setCount(f.getEntries().size());
+						
+						fs.add(searchFacet);
+					
+					}
+					
+				}
+				
+				resp.setFacets(searchFacets);
+			
+			}
+			
+			
+			
+			return resp;
+			
+			
+		} catch (Exception e) {
+			LOGGER.error("Error while searching keywords " + jsonString,e);
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+}
+
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/PackageDetails.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/PackageDetails.java
new file mode 100644
index 0000000..0464ac5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/PackageDetails.java
@@ -0,0 +1,65 @@
+package com.salesmanager.core.business.shipping.model;
+
+public class PackageDetails {
+	
+	private double shippingWeight;
+	private double shippingMaxWeight;
+	private double shippingLength;
+	private double shippingHeight;
+	private double shippingWidth;
+	private int shippingQuantity;
+	private int treshold;
+	
+	private String itemName = "";
+	
+	
+	public String getItemName() {
+		return itemName;
+	}
+	public void setItemName(String itemName) {
+		this.itemName = itemName;
+	}
+	public double getShippingWeight() {
+		return shippingWeight;
+	}
+	public void setShippingWeight(double shippingWeight) {
+		this.shippingWeight = shippingWeight;
+	}
+	public double getShippingMaxWeight() {
+		return shippingMaxWeight;
+	}
+	public void setShippingMaxWeight(double shippingMaxWeight) {
+		this.shippingMaxWeight = shippingMaxWeight;
+	}
+	public double getShippingLength() {
+		return shippingLength;
+	}
+	public void setShippingLength(double shippingLength) {
+		this.shippingLength = shippingLength;
+	}
+	public double getShippingHeight() {
+		return shippingHeight;
+	}
+	public void setShippingHeight(double shippingHeight) {
+		this.shippingHeight = shippingHeight;
+	}
+	public double getShippingWidth() {
+		return shippingWidth;
+	}
+	public void setShippingWidth(double shippingWidth) {
+		this.shippingWidth = shippingWidth;
+	}
+	public int getShippingQuantity() {
+		return shippingQuantity;
+	}
+	public void setShippingQuantity(int shippingQuantity) {
+		this.shippingQuantity = shippingQuantity;
+	}
+	public int getTreshold() {
+		return treshold;
+	}
+	public void setTreshold(int treshold) {
+		this.treshold = treshold;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingBasisType.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingBasisType.java
new file mode 100644
index 0000000..a28f2b5
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingBasisType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.shipping.model;
+
+public enum ShippingBasisType {
+	
+	BILLING, SHIPPING
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingConfiguration.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingConfiguration.java
new file mode 100644
index 0000000..3b6101c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingConfiguration.java
@@ -0,0 +1,359 @@
+package com.salesmanager.core.business.shipping.model;
+
+import java.math.BigDecimal;
+
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+/**
+ * Object saved in the database maintaining various shipping options
+ * @author casams1
+ *
+ */
+public class ShippingConfiguration implements JSONAware {
+	
+	//enums
+	private ShippingType shippingType = ShippingType.NATIONAL;
+	private ShippingBasisType shippingBasisType = ShippingBasisType.SHIPPING;
+	private ShippingOptionPriceType shippingOptionPriceType = ShippingOptionPriceType.ALL;
+	private ShippingPackageType shippingPackageType = ShippingPackageType.ITEM;
+	private ShippingDescription shippingDescription = ShippingDescription.SHORT_DESCRIPTION;
+	private ShippingType freeShippingType = null;
+	
+	private int boxWidth = 0;
+	private int boxHeight = 0;
+	private int boxLength = 0;
+	private double boxWeight = 0;
+	private double maxWeight = 0;
+	
+	//free shipping
+	private boolean freeShippingEnabled = false;
+	private BigDecimal orderTotalFreeShipping = null;
+	
+	
+	private BigDecimal handlingFees = null;
+	private boolean taxOnShipping = false;
+	
+	
+	//JSON bindings
+	private String shipType;
+	private String shipBaseType;
+	private String shipOptionPriceType = ShippingOptionPriceType.ALL.name();
+	private String shipPackageType;
+	private String shipDescription;
+	private String shipFreeType;
+	
+	//Transient
+	private String orderTotalFreeShippingText = null;
+	private String handlingFeesText = null;
+	
+	
+	public String getShipType() {
+		return shipType;
+	}
+
+
+	public String getShipBaseType() {
+		return shipBaseType;
+	}
+
+
+	public String getShipOptionPriceType() {
+		return shipOptionPriceType;
+	}
+
+
+
+	public void setShippingOptionPriceType(ShippingOptionPriceType shippingOptionPriceType) {
+		this.shippingOptionPriceType = shippingOptionPriceType;
+		this.shipOptionPriceType = this.shippingOptionPriceType.name();
+	}
+
+
+	public ShippingOptionPriceType getShippingOptionPriceType() {
+		return shippingOptionPriceType;
+	}
+
+
+	public void setShippingBasisType(ShippingBasisType shippingBasisType) {
+		this.shippingBasisType = shippingBasisType;
+		this.shipBaseType = this.shippingBasisType.name();
+	}
+
+
+	public ShippingBasisType getShippingBasisType() {
+		return shippingBasisType;
+	}
+
+
+	public void setShippingType(ShippingType shippingType) {
+		this.shippingType = shippingType;
+		this.shipType = this.shippingType.name();
+	}
+
+
+	public ShippingType getShippingType() {
+		return shippingType;
+	}
+	
+	public ShippingPackageType getShippingPackageType() {
+		return shippingPackageType;
+	}
+
+
+	public void setShippingPackageType(ShippingPackageType shippingPackageType) {
+		this.shippingPackageType = shippingPackageType;
+		this.shipPackageType = shippingPackageType.name();
+	}
+	
+	
+	public String getShipPackageType() {
+		return shipPackageType;
+	}
+
+	
+	/** JSON bindding **/
+	public void setShipType(String shipType) {
+		this.shipType = shipType;
+		ShippingType sType = ShippingType.NATIONAL;
+		if(shipType.equals(ShippingType.INTERNATIONAL.name())) {
+			sType = ShippingType.INTERNATIONAL;
+		}
+		setShippingType(sType);
+	}
+
+
+	public void setShipOptionPriceType(String shipOptionPriceType) {
+		this.shipOptionPriceType = shipOptionPriceType;
+		ShippingOptionPriceType sType = ShippingOptionPriceType.ALL;
+		if(shipOptionPriceType.equals(ShippingOptionPriceType.HIGHEST.name())) {
+			sType = ShippingOptionPriceType.HIGHEST;
+		}
+		if(shipOptionPriceType.equals(ShippingOptionPriceType.LEAST.name())) {
+			sType = ShippingOptionPriceType.LEAST;
+		}
+		setShippingOptionPriceType(sType);
+	}
+
+
+	public void setShipBaseType(String shipBaseType) {
+		this.shipBaseType = shipBaseType;
+		ShippingBasisType sType = ShippingBasisType.SHIPPING;
+		if(shipBaseType.equals(ShippingBasisType.BILLING.name())) {
+			sType = ShippingBasisType.BILLING;
+		}
+		setShippingBasisType(sType);
+	}
+
+
+
+	public void setShipPackageType(String shipPackageType) {
+		this.shipPackageType = shipPackageType;
+		ShippingPackageType sType = ShippingPackageType.ITEM;
+		if(shipPackageType.equals(ShippingPackageType.BOX.name())) {
+			sType = ShippingPackageType.BOX;
+		}
+		this.setShippingPackageType(sType);
+	}
+	
+	public void setShipDescription(String shipDescription) {
+		this.shipDescription = shipDescription;
+		ShippingDescription sType = ShippingDescription.SHORT_DESCRIPTION;
+		if(shipDescription.equals(ShippingDescription.LONG_DESCRIPTION.name())) {
+			sType = ShippingDescription.LONG_DESCRIPTION;
+		}
+		this.setShippingDescription(sType);
+	}
+	
+	public void setShipFreeType(String shipFreeType) {
+		this.shipFreeType = shipFreeType;
+		ShippingType sType = ShippingType.NATIONAL;
+		if(shipFreeType.equals(ShippingType.INTERNATIONAL.name())) {
+			sType = ShippingType.INTERNATIONAL;
+		}
+		setFreeShippingType(sType);
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		JSONObject data = new JSONObject();
+		data.put("shipBaseType", this.getShippingBasisType().name());
+		data.put("shipOptionPriceType", this.getShippingOptionPriceType().name());
+		data.put("shipType", this.getShippingType().name());
+		data.put("shipPackageType", this.getShippingPackageType().name());
+		if(shipFreeType!=null) {
+			data.put("shipFreeType", this.getFreeShippingType().name());
+		}
+		data.put("shipDescription", this.getShippingDescription().name());
+		
+		
+		data.put("boxWidth", this.getBoxWidth());
+		data.put("boxHeight", this.getBoxHeight());
+		data.put("boxLength", this.getBoxLength());
+		data.put("boxWeight", this.getBoxWeight());
+		data.put("maxWeight", this.getMaxWeight());
+		data.put("freeShippingEnabled", this.freeShippingEnabled);
+		data.put("orderTotalFreeShipping", this.orderTotalFreeShipping);
+		data.put("handlingFees", this.handlingFees);
+		data.put("taxOnShipping", this.taxOnShipping);
+		
+		
+		return data.toJSONString();
+	}
+
+
+	public int getBoxWidth() {
+		return boxWidth;
+	}
+
+
+	public void setBoxWidth(int boxWidth) {
+		this.boxWidth = boxWidth;
+	}
+
+
+	public int getBoxHeight() {
+		return boxHeight;
+	}
+
+
+	public void setBoxHeight(int boxHeight) {
+		this.boxHeight = boxHeight;
+	}
+
+
+	public int getBoxLength() {
+		return boxLength;
+	}
+
+
+	public void setBoxLength(int boxLength) {
+		this.boxLength = boxLength;
+	}
+
+
+	public double getBoxWeight() {
+		return boxWeight;
+	}
+
+
+	public void setBoxWeight(double boxWeight) {
+		this.boxWeight = boxWeight;
+	}
+
+
+	public double getMaxWeight() {
+		return maxWeight;
+	}
+
+
+	public void setMaxWeight(double maxWeight) {
+		this.maxWeight = maxWeight;
+	}
+
+
+	public boolean isFreeShippingEnabled() {
+		return freeShippingEnabled;
+	}
+
+
+	public void setFreeShippingEnabled(boolean freeShippingEnabled) {
+		this.freeShippingEnabled = freeShippingEnabled;
+	}
+
+
+	public BigDecimal getOrderTotalFreeShipping() {
+		return orderTotalFreeShipping;
+	}
+
+
+	public void setOrderTotalFreeShipping(BigDecimal orderTotalFreeShipping) {
+		this.orderTotalFreeShipping = orderTotalFreeShipping;
+	}
+
+
+	public void setHandlingFees(BigDecimal handlingFees) {
+		this.handlingFees = handlingFees;
+	}
+
+
+	public BigDecimal getHandlingFees() {
+		return handlingFees;
+	}
+
+
+	public void setTaxOnShipping(boolean taxOnShipping) {
+		this.taxOnShipping = taxOnShipping;
+	}
+
+
+	public boolean isTaxOnShipping() {
+		return taxOnShipping;
+	}
+
+
+
+
+
+	public String getShipDescription() {
+		return shipDescription;
+	}
+
+
+	public void setShippingDescription(ShippingDescription shippingDescription) {
+		this.shippingDescription = shippingDescription;
+	}
+
+
+	public ShippingDescription getShippingDescription() {
+		return shippingDescription;
+	}
+
+
+	public void setFreeShippingType(ShippingType freeShippingType) {
+		this.freeShippingType = freeShippingType;
+	}
+
+
+	public ShippingType getFreeShippingType() {
+		return freeShippingType;
+	}
+
+
+
+	public String getShipFreeType() {
+		return shipFreeType;
+	}
+
+
+	public void setOrderTotalFreeShippingText(String orderTotalFreeShippingText) {
+		this.orderTotalFreeShippingText = orderTotalFreeShippingText;
+	}
+
+
+	public String getOrderTotalFreeShippingText() {
+		return orderTotalFreeShippingText;
+	}
+
+
+	public void setHandlingFeesText(String handlingFeesText) {
+		this.handlingFeesText = handlingFeesText;
+	}
+
+
+	public String getHandlingFeesText() {
+		return handlingFeesText;
+	}
+
+
+
+
+
+
+
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingDescription.java
new file mode 100644
index 0000000..97b6f98
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingDescription.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.shipping.model;
+
+public enum ShippingDescription {
+
+	
+	SHORT_DESCRIPTION, LONG_DESCRIPTION
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingOption.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingOption.java
new file mode 100644
index 0000000..3cafa82
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingOption.java
@@ -0,0 +1,101 @@
+package com.salesmanager.core.business.shipping.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ShippingOption implements Serializable {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ShippingOption.class);
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private BigDecimal optionPrice;
+
+	private String optionName;
+	private String optionCode;
+	private String optionDeliveryDate;
+	private String optionShippingDate;
+	private String optionPriceText;
+	private String optionId;
+	private String description;
+	
+	private String estimatedNumberOfDays;
+
+	
+
+	public BigDecimal getOptionPrice() {
+		
+		if(!StringUtils.isBlank(this.getOptionPriceText())) {
+			try {
+				this.optionPrice = new BigDecimal(this.getOptionPriceText());
+			} catch(Exception e) {
+				LOGGER.equals("Can't convert price text " + this.getOptionPriceText() + " to big decimal");
+			}
+		}
+		
+		return optionPrice;
+	}
+	
+	public void setOptionPrice(BigDecimal optionPrice) {
+		this.optionPrice = optionPrice;
+	}
+
+	public void setOptionCode(String optionCode) {
+		this.optionCode = optionCode;
+	}
+	public String getOptionCode() {
+		return optionCode;
+	}
+	public void setOptionName(String optionName) {
+		this.optionName = optionName;
+	}
+	public String getOptionName() {
+		return optionName;
+	}
+
+	public void setOptionPriceText(String optionPriceText) {
+		this.optionPriceText = optionPriceText;
+	}
+	public String getOptionPriceText() {
+		return optionPriceText;
+	}
+	public void setOptionId(String optionId) {
+		this.optionId = optionId;
+	}
+	public String getOptionId() {
+		return optionId;
+	}
+	public void setOptionDeliveryDate(String optionDeliveryDate) {
+		this.optionDeliveryDate = optionDeliveryDate;
+	}
+	public String getOptionDeliveryDate() {
+		return optionDeliveryDate;
+	}
+	public void setOptionShippingDate(String optionShippingDate) {
+		this.optionShippingDate = optionShippingDate;
+	}
+	public String getOptionShippingDate() {
+		return optionShippingDate;
+	}
+	public void setDescription(String description) {
+		this.description = description;
+	}
+	public String getDescription() {
+		return description;
+	}
+	public void setEstimatedNumberOfDays(String estimatedNumberOfDays) {
+		this.estimatedNumberOfDays = estimatedNumberOfDays;
+	}
+	public String getEstimatedNumberOfDays() {
+		return estimatedNumberOfDays;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingOptionPriceType.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingOptionPriceType.java
new file mode 100644
index 0000000..91c9ed7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingOptionPriceType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.shipping.model;
+
+public enum ShippingOptionPriceType {
+	
+	LEAST, HIGHEST, ALL
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingPackageType.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingPackageType.java
new file mode 100644
index 0000000..215c842
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingPackageType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.shipping.model;
+
+public enum ShippingPackageType {
+	
+	ITEM, BOX
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingProduct.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingProduct.java
new file mode 100644
index 0000000..f7c6b42
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingProduct.java
@@ -0,0 +1,27 @@
+package com.salesmanager.core.business.shipping.model;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+
+public class ShippingProduct {
+	
+	public ShippingProduct(Product product) {
+		this.product = product;
+
+	}
+	
+	private int quantity = 1;
+	private Product product;
+	public void setQuantity(int quantity) {
+		this.quantity = quantity;
+	}
+	public int getQuantity() {
+		return quantity;
+	}
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+	public Product getProduct() {
+		return product;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingQuote.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingQuote.java
new file mode 100644
index 0000000..2e70b13
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingQuote.java
@@ -0,0 +1,99 @@
+package com.salesmanager.core.business.shipping.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.List;
+
+public class ShippingQuote implements Serializable {
+	
+	
+	
+	
+
+
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	public final static String NO_SHIPPING_TO_SELECTED_COUNTRY = "NO_SHIPPING_TO_SELECTED_COUNTRY";
+	public final static String NO_SHIPPING_MODULE_CONFIGURED= "NO_SHIPPING_MODULE_CONFIGURED";
+	public final static String ERROR= "ERROR";
+
+	private String shippingModuleCode;
+	private List<ShippingOption> shippingOptions = null;
+	/** if an error occurs, this field will be populated from constants defined above **/
+	private String shippingReturnCode = null;
+	/** indicates if this quote is configured with free shipping **/
+	private boolean freeShipping;
+	/** the threshold amount for being free shipping **/
+	private BigDecimal freeShippingAmount;
+	/** handling fees to be added on top of shipping fees **/
+	private BigDecimal handlingFees;
+	/** apply tax on shipping **/
+	private boolean applyTaxOnShipping;
+	
+	private ShippingOption selectedShippingOption = null;
+	
+	private String quoteError = null;
+	
+	
+	
+	public void setShippingOptions(List<ShippingOption> shippingOptions) {
+		this.shippingOptions = shippingOptions;
+	}
+	public List<ShippingOption> getShippingOptions() {
+		return shippingOptions;
+	}
+	public void setShippingModuleCode(String shippingModuleCode) {
+		this.shippingModuleCode = shippingModuleCode;
+	}
+	public String getShippingModuleCode() {
+		return shippingModuleCode;
+	}
+	public void setShippingReturnCode(String shippingReturnCode) {
+		this.shippingReturnCode = shippingReturnCode;
+	}
+	public String getShippingReturnCode() {
+		return shippingReturnCode;
+	}
+	public void setFreeShipping(boolean freeShipping) {
+		this.freeShipping = freeShipping;
+	}
+	public boolean isFreeShipping() {
+		return freeShipping;
+	}
+	public void setFreeShippingAmount(BigDecimal freeShippingAmount) {
+		this.freeShippingAmount = freeShippingAmount;
+	}
+	public BigDecimal getFreeShippingAmount() {
+		return freeShippingAmount;
+	}
+	public void setHandlingFees(BigDecimal handlingFees) {
+		this.handlingFees = handlingFees;
+	}
+	public BigDecimal getHandlingFees() {
+		return handlingFees;
+	}
+	public void setApplyTaxOnShipping(boolean applyTaxOnShipping) {
+		this.applyTaxOnShipping = applyTaxOnShipping;
+	}
+	public boolean isApplyTaxOnShipping() {
+		return applyTaxOnShipping;
+	}
+	public void setSelectedShippingOption(ShippingOption selectedShippingOption) {
+		this.selectedShippingOption = selectedShippingOption;
+	}
+	public ShippingOption getSelectedShippingOption() {
+		return selectedShippingOption;
+	}
+	public String getQuoteError() {
+		return quoteError;
+	}
+	public void setQuoteError(String quoteError) {
+		this.quoteError = quoteError;
+	}
+	
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingSummary.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingSummary.java
new file mode 100644
index 0000000..58b9e3e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingSummary.java
@@ -0,0 +1,60 @@
+package com.salesmanager.core.business.shipping.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * Contains shipping fees according to user selections
+ * @author casams1
+ *
+ */
+public class ShippingSummary implements Serializable {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private BigDecimal shipping;
+	private BigDecimal handling;
+	private String shippingModule;
+	private String shippingOption;
+	private boolean freeShipping;
+	private boolean taxOnShipping;
+	public BigDecimal getShipping() {
+		return shipping;
+	}
+	public void setShipping(BigDecimal shipping) {
+		this.shipping = shipping;
+	}
+	public BigDecimal getHandling() {
+		return handling;
+	}
+	public void setHandling(BigDecimal handling) {
+		this.handling = handling;
+	}
+	public String getShippingModule() {
+		return shippingModule;
+	}
+	public void setShippingModule(String shippingModule) {
+		this.shippingModule = shippingModule;
+	}
+	public String getShippingOption() {
+		return shippingOption;
+	}
+	public void setShippingOption(String shippingOption) {
+		this.shippingOption = shippingOption;
+	}
+	public boolean isFreeShipping() {
+		return freeShipping;
+	}
+	public void setFreeShipping(boolean freeShipping) {
+		this.freeShipping = freeShipping;
+	}
+	public boolean isTaxOnShipping() {
+		return taxOnShipping;
+	}
+	public void setTaxOnShipping(boolean taxOnShipping) {
+		this.taxOnShipping = taxOnShipping;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingType.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingType.java
new file mode 100644
index 0000000..af8bd46
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/model/ShippingType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.shipping.model;
+
+public enum ShippingType {
+	
+	NATIONAL, INTERNATIONAL
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/service/ShippingService.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/service/ShippingService.java
new file mode 100755
index 0000000..9b5ccca
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/service/ShippingService.java
@@ -0,0 +1,198 @@
+package com.salesmanager.core.business.shipping.service;
+
+import java.util.List;
+import java.util.Map;
+
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingOption;
+import com.salesmanager.core.business.shipping.model.ShippingProduct;
+import com.salesmanager.core.business.shipping.model.ShippingQuote;
+import com.salesmanager.core.business.shipping.model.ShippingSummary;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.CustomIntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+
+public interface ShippingService {
+
+	/**
+	 * Returns a list of supported countries (ship to country list) configured by merchant
+	 * when the merchant configured shipping National and has saved a list of ship to country
+	 * from the list
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	public  List<String> getSupportedCountries(MerchantStore store)
+			throws ServiceException;
+
+	public  void setSupportedCountries(MerchantStore store,
+			List<String> countryCodes) throws ServiceException;
+
+	/**
+	 * Returns a list of available shipping modules
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	public List<IntegrationModule> getShippingMethods(MerchantStore store)
+			throws ServiceException;
+
+	
+	/**
+	 * Returns a list of configured shipping modules for a given merchant
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	Map<String, IntegrationConfiguration> getShippingModulesConfigured(
+			MerchantStore store) throws ServiceException;
+
+	/**
+	 * Adds a Shipping configuration
+	 * @param configuration
+	 * @param store
+	 * @throws ServiceException
+	 */
+	void saveShippingQuoteModuleConfiguration(IntegrationConfiguration configuration,
+			MerchantStore store) throws ServiceException;
+
+	/**
+	 * ShippingType (NATIONAL, INTERNATIONSL)
+	 * ShippingBasisType (SHIPPING, BILLING)
+	 * ShippingPriceOptionType (ALL, LEAST, HIGHEST)
+	 * Packages
+	 * Handling
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	ShippingConfiguration getShippingConfiguration(MerchantStore store)
+			throws ServiceException;
+
+	/**
+	 * Saves ShippingConfiguration for a given MerchantStore
+	 * @param shippingConfiguration
+	 * @param store
+	 * @throws ServiceException
+	 */
+	void saveShippingConfiguration(ShippingConfiguration shippingConfiguration,
+			MerchantStore store) throws ServiceException;
+
+	void removeShippingQuoteModuleConfiguration(String moduleCode,
+			MerchantStore store) throws ServiceException;
+
+	/**
+	 * Provides detailed information on boxes that will be used
+	 * when getting a ShippingQuote
+	 * @param products
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<PackageDetails> getPackagesDetails(List<ShippingProduct> products,
+			MerchantStore store) throws ServiceException;
+
+	/**
+	 * Get a list of ShippingQuote from a configured
+	 * shipping gateway. The quotes are displayed to the end user so he can pick
+	 * the ShippingOption he wants
+	 * @param store
+	 * @param customer
+	 * @param products
+	 * @param language
+	 * @return
+	 * @throws ServiceException
+	 */
+	ShippingQuote getShippingQuote(MerchantStore store, Delivery delivery,
+			List<ShippingProduct> products, Language language)
+			throws ServiceException;
+	
+
+	/**
+	 * Returns a shipping module configuration given a moduleCode
+	 * @param moduleCode
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	IntegrationConfiguration getShippingConfiguration(String moduleCode,
+			MerchantStore store) throws ServiceException;
+	
+	/**
+	 * Retrieves the custom configuration for a given module
+	 * @param moduleCode
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+
+
+	CustomIntegrationConfiguration getCustomShippingConfiguration(
+			String moduleCode, MerchantStore store) throws ServiceException;
+
+	/**
+	 * Weight based configuration
+	 * @param moduleCode
+	 * @param shippingConfiguration
+	 * @param store
+	 * @throws ServiceException
+	 */
+	void saveCustomShippingConfiguration(String moduleCode,
+			CustomIntegrationConfiguration shippingConfiguration,
+			MerchantStore store) throws ServiceException;
+
+	/**
+	 * Removes a custom shipping quote
+	 * module
+	 * @param moduleCode
+	 * @param store
+	 * @throws ServiceException
+	 */
+	void removeCustomShippingQuoteModuleConfiguration(String moduleCode,
+			MerchantStore store) throws ServiceException;
+
+	/**
+	 * The {@link ShippingSummary} is built from the ShippingOption the user has selected
+	 * The ShippingSummary is used for order calculation
+	 * @param store
+	 * @param shippingQuote
+	 * @param selectedShippingOption
+	 * @return
+	 * @throws ServiceException
+	 */
+	ShippingSummary getShippingSummary(MerchantStore store, ShippingQuote shippingQuote, 
+			ShippingOption selectedShippingOption) throws ServiceException;
+
+	/**
+	 * Returns a list of supported countries (ship to country list) configured by merchant
+	 * If the merchant configured shipping National, then only store country will be in the list
+	 * If the merchant configured shipping International, then the list of accepted country is returned
+	 * from the list
+	 * @param store
+	 * @param language
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<Country> getShipToCountryList(MerchantStore store, Language language)
+			throws ServiceException;
+	
+	/**
+	 * Determines if Shipping should be proposed to the customer
+	 * @param items
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	boolean requiresShipping(List<ShoppingCartItem> items, MerchantStore store) throws ServiceException;
+
+
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shipping/service/ShippingServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/shipping/service/ShippingServiceImpl.java
new file mode 100755
index 0000000..cca2e23
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shipping/service/ShippingServiceImpl.java
@@ -0,0 +1,750 @@
+package com.salesmanager.core.business.shipping.service;
+
+import java.math.BigDecimal;
+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 java.util.Set;
+
+import javax.annotation.Resource;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.json.simple.JSONArray;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.catalog.product.service.PricingService;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingOption;
+import com.salesmanager.core.business.shipping.model.ShippingOptionPriceType;
+import com.salesmanager.core.business.shipping.model.ShippingPackageType;
+import com.salesmanager.core.business.shipping.model.ShippingProduct;
+import com.salesmanager.core.business.shipping.model.ShippingQuote;
+import com.salesmanager.core.business.shipping.model.ShippingSummary;
+import com.salesmanager.core.business.shipping.model.ShippingType;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.CustomIntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.model.MerchantLog;
+import com.salesmanager.core.business.system.service.MerchantConfigurationService;
+import com.salesmanager.core.business.system.service.MerchantLogService;
+import com.salesmanager.core.business.system.service.ModuleConfigurationService;
+import com.salesmanager.core.constants.ShippingConstants;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.shipping.model.Packaging;
+import com.salesmanager.core.modules.integration.shipping.model.ShippingQuoteModule;
+import com.salesmanager.core.modules.utils.Encryption;
+import com.salesmanager.core.utils.reference.ConfigurationModulesLoader;
+
+@Service("shippingService")
+public class ShippingServiceImpl implements ShippingService {
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ShippingServiceImpl.class);
+	
+	
+	private final static String SUPPORTED_COUNTRIES = "SUPPORTED_CNTR";
+	private final static String SHIPPING_MODULES = "SHIPPING";
+	
+	@Autowired
+	private MerchantConfigurationService merchantConfigurationService;
+	
+
+	@Autowired
+	private PricingService pricingService;
+	
+	@Autowired
+	private ModuleConfigurationService moduleConfigurationService;
+	
+	@Autowired
+	private Packaging packaging;
+	
+	@Autowired
+	private CountryService countryService;
+	
+	@Autowired
+	private LanguageService languageService;
+	
+	@Autowired
+	private Encryption encryption;
+	
+	@Autowired
+	private MerchantLogService merchantLogService;
+	
+	@Autowired
+	@Resource(name="shippingModules")
+	private Map<String,ShippingQuoteModule> shippingModules;
+	
+	@Override
+	public ShippingConfiguration getShippingConfiguration(MerchantStore store) throws ServiceException {
+
+		MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(ShippingConstants.SHIPPING_CONFIGURATION, store);
+		
+		ShippingConfiguration shippingConfiguration = null;
+		
+		if(configuration!=null) {
+			String value = configuration.getValue();
+			
+			ObjectMapper mapper = new ObjectMapper();
+			try {
+				shippingConfiguration = mapper.readValue(value, ShippingConfiguration.class);
+			} catch(Exception e) {
+				throw new ServiceException("Cannot parse json string " + value);
+			}
+		}
+		return shippingConfiguration;
+		
+	}
+	
+	@Override
+	public IntegrationConfiguration getShippingConfiguration(String moduleCode, MerchantStore store) throws ServiceException {
+
+		
+		Map<String,IntegrationConfiguration> configuredModules = getShippingModulesConfigured(store);
+		if(configuredModules!=null) {
+			for(String key : configuredModules.keySet()) {
+				if(key.equals(moduleCode)) {
+					return configuredModules.get(key);	
+				}
+			}
+		}
+		
+		return null;
+		
+	}
+	
+	@Override
+	public CustomIntegrationConfiguration getCustomShippingConfiguration(String moduleCode, MerchantStore store) throws ServiceException {
+
+		
+		ShippingQuoteModule quoteModule = (ShippingQuoteModule)shippingModules.get(moduleCode);
+		if(quoteModule==null) {
+			return null;
+		}
+		return quoteModule.getCustomModuleConfiguration(store);
+		
+	}
+	
+	@Override
+	public void saveShippingConfiguration(ShippingConfiguration shippingConfiguration, MerchantStore store) throws ServiceException {
+		
+		MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(ShippingConstants.SHIPPING_CONFIGURATION, store);
+
+		if(configuration==null) {
+			configuration = new MerchantConfiguration();
+			configuration.setMerchantStore(store);
+			configuration.setKey(ShippingConstants.SHIPPING_CONFIGURATION);
+		}
+		
+		String value = shippingConfiguration.toJSONString();
+		configuration.setValue(value);
+		merchantConfigurationService.saveOrUpdate(configuration);
+		
+	}
+	
+	@Override
+	public void saveCustomShippingConfiguration(String moduleCode, CustomIntegrationConfiguration shippingConfiguration, MerchantStore store) throws ServiceException {
+		
+		
+		ShippingQuoteModule quoteModule = (ShippingQuoteModule)shippingModules.get(moduleCode);
+		if(quoteModule==null) {
+			throw new ServiceException("Shipping module " + moduleCode + " does not exist");
+		}
+		
+		String configurationValue = shippingConfiguration.toJSONString();
+		
+		
+		try {
+
+			MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(moduleCode, store);
+	
+			if(configuration==null) {
+
+				configuration = new MerchantConfiguration();
+				configuration.setKey(moduleCode);
+				configuration.setMerchantStore(store);
+			}
+			configuration.setValue(configurationValue);
+			merchantConfigurationService.saveOrUpdate(configuration);
+		
+		} catch (Exception e) {
+			throw new IntegrationException(e);
+		}
+
+		
+		
+	}
+	
+
+	@Override
+	public List<IntegrationModule> getShippingMethods(MerchantStore store) throws ServiceException {
+		
+		List<IntegrationModule> modules =  moduleConfigurationService.getIntegrationModules(SHIPPING_MODULES);
+		List<IntegrationModule> returnModules = new ArrayList<IntegrationModule>();
+		
+		for(IntegrationModule module : modules) {
+			if(module.getRegionsSet().contains(store.getCountry().getIsoCode())
+					|| module.getRegionsSet().contains("*")) {
+				
+				returnModules.add(module);
+			}
+		}
+		
+		return returnModules;
+	}
+	
+	@Override
+	public void saveShippingQuoteModuleConfiguration(IntegrationConfiguration configuration, MerchantStore store) throws ServiceException {
+		
+			//validate entries
+			try {
+				
+				String moduleCode = configuration.getModuleCode();
+				ShippingQuoteModule quoteModule = (ShippingQuoteModule)shippingModules.get(moduleCode);
+				if(quoteModule==null) {
+					throw new ServiceException("Shipping quote module " + moduleCode + " does not exist");
+				}
+				quoteModule.validateModuleConfiguration(configuration, store);
+				
+			} catch (IntegrationException ie) {
+				throw ie;
+			}
+			
+			try {
+				Map<String,IntegrationConfiguration> modules = new HashMap<String,IntegrationConfiguration>();
+				MerchantConfiguration merchantConfiguration = merchantConfigurationService.getMerchantConfiguration(SHIPPING_MODULES, store);
+				if(merchantConfiguration!=null) {
+					if(!StringUtils.isBlank(merchantConfiguration.getValue())) {
+						
+						String decrypted = encryption.decrypt(merchantConfiguration.getValue());
+						modules = ConfigurationModulesLoader.loadIntegrationConfigurations(decrypted);
+					}
+				} else {
+					merchantConfiguration = new MerchantConfiguration();
+					merchantConfiguration.setMerchantStore(store);
+					merchantConfiguration.setKey(SHIPPING_MODULES);
+				}
+				modules.put(configuration.getModuleCode(), configuration);
+				
+				String configs =  ConfigurationModulesLoader.toJSONString(modules);
+				
+				String encrypted = encryption.encrypt(configs);
+				merchantConfiguration.setValue(encrypted);
+				merchantConfigurationService.saveOrUpdate(merchantConfiguration);
+				
+			} catch (Exception e) {
+				throw new ServiceException(e);
+			}
+	}
+	
+	
+	@Override
+	public void removeShippingQuoteModuleConfiguration(String moduleCode, MerchantStore store) throws ServiceException {
+		
+		
+
+		try {
+			Map<String,IntegrationConfiguration> modules = new HashMap<String,IntegrationConfiguration>();
+			MerchantConfiguration merchantConfiguration = merchantConfigurationService.getMerchantConfiguration(SHIPPING_MODULES, store);
+			if(merchantConfiguration!=null) {
+				if(!StringUtils.isBlank(merchantConfiguration.getValue())) {
+					String decrypted = encryption.decrypt(merchantConfiguration.getValue());
+					modules = ConfigurationModulesLoader.loadIntegrationConfigurations(decrypted);
+				}
+				
+				modules.remove(moduleCode);
+				String configs =  ConfigurationModulesLoader.toJSONString(modules);
+				String encrypted = encryption.encrypt(configs);
+				merchantConfiguration.setValue(encrypted);
+				merchantConfigurationService.saveOrUpdate(merchantConfiguration);
+				
+				
+			} 
+			
+			MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(moduleCode, store);
+			
+			if(configuration!=null) {//custom module
+
+				merchantConfigurationService.delete(configuration);
+			}
+
+			
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	
+	}
+	
+	@Override
+	public void removeCustomShippingQuoteModuleConfiguration(String moduleCode, MerchantStore store) throws ServiceException {
+		
+		
+
+		try {
+			
+			removeShippingQuoteModuleConfiguration(moduleCode,store);
+			MerchantConfiguration merchantConfiguration = merchantConfigurationService.getMerchantConfiguration(moduleCode, store);
+			if(merchantConfiguration!=null) {
+				merchantConfigurationService.delete(merchantConfiguration);
+			} 
+			
+			
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	
+	}
+	
+	@Override
+	public Map<String,IntegrationConfiguration> getShippingModulesConfigured(MerchantStore store) throws ServiceException {
+		try {
+			
+
+			Map<String,IntegrationConfiguration> modules = new HashMap<String,IntegrationConfiguration>();
+			MerchantConfiguration merchantConfiguration = merchantConfigurationService.getMerchantConfiguration(SHIPPING_MODULES, store);
+			if(merchantConfiguration!=null) {
+				if(!StringUtils.isBlank(merchantConfiguration.getValue())) {
+					String decrypted = encryption.decrypt(merchantConfiguration.getValue());
+					modules = ConfigurationModulesLoader.loadIntegrationConfigurations(decrypted);
+					
+				}
+			}
+			return modules;
+		
+		
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+	}
+	
+	@Override
+	public ShippingSummary getShippingSummary(MerchantStore store, ShippingQuote shippingQuote, ShippingOption selectedShippingOption) throws ServiceException {
+		
+		ShippingSummary shippingSummary = new ShippingSummary();
+		shippingSummary.setFreeShipping(shippingQuote.isFreeShipping());
+		shippingSummary.setHandling(shippingQuote.getHandlingFees());
+		shippingSummary.setShipping(selectedShippingOption.getOptionPrice());
+		shippingSummary.setShippingModule(shippingQuote.getShippingModuleCode());
+		shippingSummary.setShippingOption(selectedShippingOption.getDescription());
+		
+		return shippingSummary;
+	}
+
+	@Override
+	public ShippingQuote getShippingQuote(MerchantStore store, Delivery delivery, List<ShippingProduct> products, Language language) throws ServiceException  {
+		
+		ShippingQuote shippingQuote = new ShippingQuote();
+		ShippingQuoteModule shippingQuoteModule = null;
+		
+		try {
+		
+			//get configuration
+			ShippingConfiguration shippingConfiguration = getShippingConfiguration(store);
+			ShippingType shippingType = ShippingType.INTERNATIONAL;
+			
+			if(shippingConfiguration==null) {
+				shippingConfiguration = new ShippingConfiguration();
+			}
+			
+			if(shippingConfiguration.getShippingType()!=null) {
+					shippingType = shippingConfiguration.getShippingType();
+			}
+
+			//look if customer country code excluded
+			Country shipCountry = delivery.getCountry();
+			if(shipCountry==null) {
+				throw new ServiceException("Delivery country is null");
+			}
+			
+			//a ship to country is required
+			Validate.notNull(shipCountry);
+			Validate.notNull(store.getCountry());
+			
+			if(shippingType.name().equals(ShippingType.NATIONAL.name())){
+				//customer country must match store country
+				if(!shipCountry.getIsoCode().equals(store.getCountry().getIsoCode())) {
+					shippingQuote.setShippingReturnCode(ShippingQuote.NO_SHIPPING_TO_SELECTED_COUNTRY + " " + shipCountry.getIsoCode());
+					return shippingQuote;
+				}
+			} else if(shippingType.name().equals(ShippingType.INTERNATIONAL.name())){
+				
+				//customer shipping country code must be in accepted list
+				List<String> supportedCountries = this.getSupportedCountries(store);
+				if(!supportedCountries.contains(shipCountry.getIsoCode())) {
+					shippingQuote.setShippingReturnCode(ShippingQuote.NO_SHIPPING_TO_SELECTED_COUNTRY + " " + shipCountry.getIsoCode());
+					return shippingQuote;
+				}
+			}
+			
+			//must have a shipping module configured
+			Map<String, IntegrationConfiguration> modules = this.getShippingModulesConfigured(store);
+			if(modules==null){
+				shippingQuote.setShippingReturnCode(ShippingQuote.NO_SHIPPING_MODULE_CONFIGURED);
+				return shippingQuote;
+			}
+
+			
+			/** uses this module name **/
+			String moduleName = null;
+			IntegrationConfiguration configuration = null;
+			for(String module : modules.keySet()) {
+				moduleName = module;
+				configuration = modules.get(module);
+				//use the first active module
+				if(configuration.isActive()) {
+					shippingQuoteModule = this.shippingModules.get(module);
+					break;
+				}
+			}
+			
+			if(shippingQuoteModule==null){
+				shippingQuote.setShippingReturnCode(ShippingQuote.NO_SHIPPING_MODULE_CONFIGURED);
+				return shippingQuote;
+			}
+			
+			/** merchant module configs **/
+			List<IntegrationModule> shippingMethods = this.getShippingMethods(store);
+			IntegrationModule shippingModule = null;
+			for(IntegrationModule mod : shippingMethods) {
+				if(mod.getCode().equals(moduleName)){
+					shippingModule = mod;
+					break;
+				}
+			}
+			
+			/** general module configs **/
+			if(shippingModule==null) {
+				shippingQuote.setShippingReturnCode(ShippingQuote.NO_SHIPPING_MODULE_CONFIGURED);
+				return shippingQuote;
+			}
+			
+			//calculate order total
+			BigDecimal orderTotal = calculateOrderTotal(products,store);
+			List<PackageDetails> packages = this.getPackagesDetails(products, store);
+			
+			//free shipping ?
+			if(shippingConfiguration.isFreeShippingEnabled()) {
+				BigDecimal freeShippingAmount = shippingConfiguration.getOrderTotalFreeShipping();
+				if(freeShippingAmount!=null) {
+					if(orderTotal.doubleValue()>freeShippingAmount.doubleValue()) {
+						if(shippingConfiguration.getFreeShippingType() == ShippingType.NATIONAL) {
+							if(store.getCountry().getIsoCode().equals(shipCountry.getIsoCode())) {
+								shippingQuote.setFreeShipping(true);
+								shippingQuote.setFreeShippingAmount(freeShippingAmount);
+								return shippingQuote;
+							}
+						} else {//international all
+							shippingQuote.setFreeShipping(true);
+							shippingQuote.setFreeShippingAmount(freeShippingAmount);
+							return shippingQuote;
+						}
+	
+					}
+				}
+			}
+			
+
+			//handling fees
+			BigDecimal handlingFees = shippingConfiguration.getHandlingFees();
+			if(handlingFees!=null) {
+				shippingQuote.setHandlingFees(handlingFees);
+			}
+			
+			//tax basis
+			shippingQuote.setApplyTaxOnShipping(shippingConfiguration.isTaxOnShipping());
+			
+
+			Locale locale = languageService.toLocale(language);
+
+			//invoke module
+			List<ShippingOption> shippingOptions = null;
+					
+			try {
+				shippingOptions = shippingQuoteModule.getShippingQuotes(packages, orderTotal, delivery, store, configuration, shippingModule, shippingConfiguration, locale);
+			} catch(Exception e) {
+				LOGGER.error("Error while calculating shipping", e);
+				merchantLogService.save(
+						new MerchantLog(store,
+								"Can't process " + shippingModule.getModule()
+								+ " -> "
+								+ e.getMessage()));
+				shippingQuote.setQuoteError(e.getMessage());
+				shippingQuote.setShippingReturnCode(ShippingQuote.ERROR);
+				return shippingQuote;
+			}
+			
+			if(shippingOptions==null) {
+				shippingQuote.setShippingReturnCode(ShippingQuote.NO_SHIPPING_TO_SELECTED_COUNTRY);
+			}
+			
+			
+			shippingQuote.setShippingModuleCode(moduleName);	
+			
+			//filter shipping options
+			ShippingOptionPriceType shippingOptionPriceType = shippingConfiguration.getShippingOptionPriceType();
+			ShippingOption selectedOption = null;
+			
+			if(shippingOptions!=null) {
+				
+				for(ShippingOption option : shippingOptions) {
+					if(selectedOption==null) {
+						selectedOption = option;
+					}
+					//set price text
+					String priceText = pricingService.getDisplayAmount(option.getOptionPrice(), store);
+					option.setOptionPriceText(priceText);
+				
+					if(StringUtils.isBlank(option.getOptionName())) {
+						
+						String countryName = delivery.getCountry().getName();
+						if(countryName == null) {
+							Map<String,Country> deliveryCountries = countryService.getCountriesMap(language);
+							Country dCountry = (Country)deliveryCountries.get(delivery.getCountry().getIsoCode());
+							if(dCountry!=null) {
+								countryName = dCountry.getName();
+							} else {
+								countryName = delivery.getCountry().getIsoCode();
+							}
+						}
+							option.setOptionName(countryName);		
+					}
+				
+					if(shippingOptionPriceType.name().equals(ShippingOptionPriceType.HIGHEST.name())) {
+
+						if (option.getOptionPrice()
+								.longValue() > selectedOption
+								.getOptionPrice()
+								.longValue()) {
+							selectedOption = option;
+						}
+					}
+
+				
+					if(shippingOptionPriceType.name().equals(ShippingOptionPriceType.LEAST.name())) {
+
+						if (option.getOptionPrice()
+								.longValue() < selectedOption
+								.getOptionPrice()
+								.longValue()) {
+							selectedOption = option;
+						}
+					}
+					
+				
+					if(shippingOptionPriceType.name().equals(ShippingOptionPriceType.ALL.name())) {
+	
+						if (option.getOptionPrice()
+								.longValue() < selectedOption
+								.getOptionPrice()
+								.longValue()) {
+							selectedOption = option;
+						}
+					}
+
+				}
+				
+				shippingQuote.setSelectedShippingOption(selectedOption);
+				
+				if(selectedOption!=null && !shippingOptionPriceType.name().equals(ShippingOptionPriceType.ALL.name())) {
+					shippingOptions = new ArrayList<ShippingOption>();
+					shippingOptions.add(selectedOption);
+				}
+			
+			}
+			
+			shippingQuote.setShippingOptions(shippingOptions);
+			
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+		
+		return shippingQuote;
+		
+	}
+
+	@Override
+	public List<String> getSupportedCountries(MerchantStore store) throws ServiceException {
+		
+		List<String> supportedCountries = new ArrayList<String>();
+		MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(SUPPORTED_COUNTRIES, store);
+		
+		if(configuration!=null) {
+			
+			String countries = configuration.getValue();
+			if(!StringUtils.isBlank(countries)) {
+
+				Object objRegions=JSONValue.parse(countries); 
+				JSONArray arrayRegions=(JSONArray)objRegions;
+				@SuppressWarnings("rawtypes")
+				Iterator i = arrayRegions.iterator();
+				while(i.hasNext()) {
+					supportedCountries.add((String)i.next());
+				}
+			}
+			
+		}
+		
+		return supportedCountries;
+	}
+	
+	@Override
+	public List<Country> getShipToCountryList(MerchantStore store, Language language) throws ServiceException {
+		
+		
+		ShippingConfiguration shippingConfiguration = getShippingConfiguration(store);
+		ShippingType shippingType = ShippingType.INTERNATIONAL;
+		List<String> supportedCountries = new ArrayList<String>();
+		if(shippingConfiguration==null) {
+			shippingConfiguration = new ShippingConfiguration();
+		}
+		
+		if(shippingConfiguration.getShippingType()!=null) {
+				shippingType = shippingConfiguration.getShippingType();
+		}
+
+		
+		if(shippingType.name().equals(ShippingType.NATIONAL.name())){
+			
+			supportedCountries.add(store.getCountry().getIsoCode());
+			
+		} else {
+
+			MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(SUPPORTED_COUNTRIES, store);
+			
+			if(configuration!=null) {
+				
+				String countries = configuration.getValue();
+				if(!StringUtils.isBlank(countries)) {
+
+					Object objRegions=JSONValue.parse(countries); 
+					JSONArray arrayRegions=(JSONArray)objRegions;
+					@SuppressWarnings("rawtypes")
+					Iterator i = arrayRegions.iterator();
+					while(i.hasNext()) {
+						supportedCountries.add((String)i.next());
+					}
+				}
+				
+			}
+
+		}
+		
+		return countryService.getCountries(supportedCountries, language);
+
+	}
+	
+
+	@Override
+	public void setSupportedCountries(MerchantStore store, List<String> countryCodes) throws ServiceException {
+		
+		
+		//transform a list of string to json entry
+		ObjectMapper mapper = new ObjectMapper();
+		
+		try {
+			String value  = mapper.writeValueAsString(countryCodes);
+			
+			MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(SUPPORTED_COUNTRIES, store);
+			
+			if(configuration==null) {
+				configuration = new MerchantConfiguration();
+				configuration.
+				setKey(SUPPORTED_COUNTRIES);
+				configuration.setMerchantStore(store);
+			} 
+			
+			configuration.setValue(value);
+
+			merchantConfigurationService.saveOrUpdate(configuration);
+			
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+
+	}
+	
+
+	private BigDecimal calculateOrderTotal(List<ShippingProduct> products, MerchantStore store) throws Exception {
+		
+		BigDecimal total = new BigDecimal(0);
+		for(ShippingProduct shippingProduct : products) {
+			FinalPrice price = pricingService.calculateProductPrice(shippingProduct.getProduct());
+			
+			BigDecimal currentPrice = price.getFinalPrice();
+			currentPrice = currentPrice.multiply(new BigDecimal(shippingProduct.getQuantity()));
+			total = total.add(currentPrice);
+		}
+		
+		
+		return total;
+		
+		
+	}
+
+	@Override
+	public List<PackageDetails> getPackagesDetails(
+			List<ShippingProduct> products, MerchantStore store)
+			throws ServiceException {
+		
+		List<PackageDetails> packages = null;
+		
+		ShippingConfiguration shippingConfiguration = this.getShippingConfiguration(store);
+		//determine if the system has to use BOX or ITEM
+		ShippingPackageType shippingPackageType = ShippingPackageType.ITEM;
+		if(shippingConfiguration!=null) {
+			shippingPackageType = shippingConfiguration.getShippingPackageType();
+		}
+		
+		if(shippingPackageType.name().equals(ShippingPackageType.BOX.name())){
+			packages = packaging.getBoxPackagesDetails(products, store);
+		} else {
+			packages = packaging.getItemPackagesDetails(products, store);
+		}
+		
+		return packages;
+		
+	}
+
+	@Override
+	public boolean requiresShipping(List<ShoppingCartItem> items,
+			MerchantStore store) throws ServiceException {
+
+		boolean requiresShipping = false;
+		for(ShoppingCartItem item : items) {
+			Product product = item.getProduct();
+			if(!product.isProductVirtual() && product.isProductShipeable()) {
+				requiresShipping = true;
+			}
+		}
+
+		return requiresShipping;		
+	}
+	
+
+
+
+
+}
+
+
+
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartDao.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartDao.java
new file mode 100644
index 0000000..4c804dd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartDao.java
@@ -0,0 +1,34 @@
+package com.salesmanager.core.business.shoppingcart.dao;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+
+public interface ShoppingCartDao extends SalesManagerEntityDao<Long, ShoppingCart> {
+
+	ShoppingCart getById(Long id, MerchantStore store);
+
+	ShoppingCart getByCustomer(Customer customer);
+
+	ShoppingCart getByCode(String code, MerchantStore store);
+
+	/**
+	 * Get a ShoppingCart object without collection objects
+	 * @param id
+	 * @return
+	 */
+	ShoppingCart getShoppingCartById(Long id);
+
+	/**
+	 * Get a ShoppingCart object without collection objects
+	 * @param code
+	 * @return
+	 */
+	ShoppingCart getShoppingCartByCode(String code);
+
+	public void removeShoppingCart(ShoppingCart cart);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartDaoImpl.java
new file mode 100644
index 0000000..b0ddde4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartDaoImpl.java
@@ -0,0 +1,160 @@
+package com.salesmanager.core.business.shoppingcart.dao;
+
+import java.util.List;
+
+import javax.persistence.NonUniqueResultException;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shoppingcart.model.QShoppingCart;
+import com.salesmanager.core.business.shoppingcart.model.QShoppingCartItem;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+
+@Repository("shoppingCartDao")
+public class ShoppingCartDaoImpl extends SalesManagerEntityDaoImpl<Long, ShoppingCart>
+		implements ShoppingCartDao {
+
+
+	@Override
+	public ShoppingCart getById(final Long id) {
+
+		try {
+			QShoppingCart qShoppingCart = QShoppingCart.shoppingCart;
+			QShoppingCartItem qShoppingCartItem = QShoppingCartItem.shoppingCartItem;
+
+			JPQLQuery query = new JPAQuery (getEntityManager());
+
+			query.from(qShoppingCart)
+				.leftJoin(qShoppingCart.lineItems, qShoppingCartItem).fetch()
+				.leftJoin(qShoppingCartItem.attributes).fetch()
+				.leftJoin(qShoppingCart.merchantStore).fetch()
+				.where(qShoppingCart.id.eq(id));
+
+			return query.uniqueResult(qShoppingCart);
+		} catch(javax.persistence.NoResultException ers) {
+			return null;
+		}
+
+	}
+
+	@Override
+	public ShoppingCart getShoppingCartById(final Long id) {
+
+			QShoppingCart qShoppingCart = QShoppingCart.shoppingCart;
+
+			JPQLQuery query = new JPAQuery (getEntityManager());
+
+			query.from(qShoppingCart)
+				.leftJoin(qShoppingCart.merchantStore).fetch()
+				.where(qShoppingCart.id.eq(id));
+
+			return query.uniqueResult(qShoppingCart);
+
+	}
+
+	@Override
+	public ShoppingCart getShoppingCartByCode(final String code) {
+
+			QShoppingCart qShoppingCart = QShoppingCart.shoppingCart;
+
+			JPQLQuery query = new JPAQuery (getEntityManager());
+
+			query.from(qShoppingCart)
+				.leftJoin(qShoppingCart.merchantStore).fetch()
+				.where(qShoppingCart.shoppingCartCode.eq(code));
+
+			List<ShoppingCart> results = query.list(qShoppingCart);
+	        if (results.isEmpty()) return null;
+	        
+	        else if (results.size() >= 1) return results.get(0);
+	        return null;
+
+
+	}
+
+	@Override
+	public ShoppingCart getById(final Long id, final MerchantStore store) {
+
+		try {
+
+			QShoppingCart qShoppingCart = QShoppingCart.shoppingCart;
+			QShoppingCartItem qShoppingCartItem = QShoppingCartItem.shoppingCartItem;
+
+			JPQLQuery query = new JPAQuery (getEntityManager());
+
+			query.from(qShoppingCart)
+				.leftJoin(qShoppingCart.lineItems, qShoppingCartItem).fetch()
+				.leftJoin(qShoppingCartItem.attributes).fetch()
+				.leftJoin(qShoppingCart.merchantStore).fetch()
+				.where(qShoppingCart.id.eq(id)
+						.and(qShoppingCart.merchantStore.id.eq(store.getId())));
+
+			return query.uniqueResult(qShoppingCart);
+
+		} catch(javax.persistence.NoResultException ers) {
+			return null;
+		}
+
+	}
+
+	@Override
+	public ShoppingCart getByCode(final String code, final MerchantStore store) {
+
+
+			QShoppingCart qShoppingCart = QShoppingCart.shoppingCart;
+			QShoppingCartItem qShoppingCartItem = QShoppingCartItem.shoppingCartItem;
+
+			JPQLQuery query = new JPAQuery (getEntityManager());
+
+			query.from(qShoppingCart)
+				.leftJoin(qShoppingCart.lineItems, qShoppingCartItem).fetch()
+				.leftJoin(qShoppingCartItem.attributes).fetch()
+				.leftJoin(qShoppingCart.merchantStore).fetch()
+				.where(qShoppingCart.shoppingCartCode.eq(code)
+						.and(qShoppingCart.merchantStore.id.eq(store.getId())));
+
+			List<ShoppingCart> results = query.list(qShoppingCart);
+	        if (results.isEmpty()) return null;
+	        
+	        else if (results.size() >= 1) return results.get(0);
+	        return null;
+
+	}
+
+	@Override
+	public ShoppingCart getByCustomer(final Customer customer) {
+
+			QShoppingCart qShoppingCart = QShoppingCart.shoppingCart;
+			QShoppingCartItem qShoppingCartItem = QShoppingCartItem.shoppingCartItem;
+
+			JPQLQuery query = new JPAQuery (getEntityManager());
+
+			query.from(qShoppingCart)
+				.leftJoin(qShoppingCart.lineItems, qShoppingCartItem).fetch()
+				.leftJoin(qShoppingCartItem.attributes).fetch()
+				.leftJoin(qShoppingCart.merchantStore).fetch()
+				.where(qShoppingCart.customerId.eq(customer.getId()));
+			
+			List<ShoppingCart> results = query.list(qShoppingCart);
+	        if (results.isEmpty()) return null;
+	        
+	        else if (results.size() >= 1) return results.get(0);
+	        return null;
+
+	}
+
+    @Override
+    public void removeShoppingCart( final ShoppingCart cart )
+    {
+            ShoppingCart shoppingCart=getEntityManager().merge( cart );
+            getEntityManager().remove( shoppingCart );
+   }
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartItemDao.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartItemDao.java
new file mode 100644
index 0000000..3c88594
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartItemDao.java
@@ -0,0 +1,10 @@
+package com.salesmanager.core.business.shoppingcart.dao;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+
+public interface ShoppingCartItemDao extends SalesManagerEntityDao<Long, ShoppingCartItem> {
+
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartItemDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartItemDaoImpl.java
new file mode 100644
index 0000000..9212f88
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/dao/ShoppingCartItemDaoImpl.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.business.shoppingcart.dao;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+
+@Repository("shoppingCartItemDao")
+public class ShoppingCartItemDaoImpl extends SalesManagerEntityDaoImpl<Long, ShoppingCartItem>
+		implements ShoppingCartItemDao {
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCart.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCart.java
new file mode 100644
index 0000000..7635a7c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCart.java
@@ -0,0 +1,150 @@
+/**
+ * 
+ */
+package com.salesmanager.core.business.shoppingcart.model;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+
+import org.hibernate.annotations.Index;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+/**
+ * <p>Shopping cart is responsible for storing and carrying
+ * shopping cart information.Shopping Cart consists of {@link ShoppingCartItem}
+ * which represents individual lines items associated with the shopping cart</p> 
+ * @author Umesh Awasthi
+ * version 2.0
+ *
+ */
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "SHOPPING_CART", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class ShoppingCart extends SalesManagerEntity<Long, ShoppingCart> implements Auditable{
+
+	
+	private static final long serialVersionUID = 1L;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@Id
+	@Column(name = "SHP_CART_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "SHP_CRT_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	/**
+	 * Will be used to fetch shopping cart model from the controller
+	 * this is a unique code that should be attributed from the client (UI)
+	 * 
+	 */
+	@Index(name="SHP_CART_CODE_IDX")
+	@Column(name = "SHP_CART_CODE", unique=true, nullable=false)
+	private String shoppingCartCode;
+	
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval=true, mappedBy = "shoppingCart")
+	private Set<ShoppingCartItem> lineItems = new HashSet<ShoppingCartItem>();
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	@Index(name="SHP_CART_CUSTOMER_IDX")
+	@Column(name = "CUSTOMER_ID", nullable = true)
+	private Long customerId;
+	
+	@Transient
+	private boolean obsolete = false;//when all items are obsolete
+    
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection audit) {
+		this.auditSection = audit;
+		
+	}
+	
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+		
+	}
+	
+
+	public boolean isObsolete() {
+		return obsolete;
+	}
+
+	public void setObsolete(boolean obsolete) {
+		this.obsolete = obsolete;
+	}
+
+	public Set<ShoppingCartItem> getLineItems() {
+		return lineItems;
+	}
+
+	public void setLineItems(Set<ShoppingCartItem> lineItems) {
+		this.lineItems = lineItems;
+	}
+
+    public String getShoppingCartCode()
+    {
+        return shoppingCartCode;
+    }
+
+    public void setShoppingCartCode( String shoppingCartCode )
+    {
+        this.shoppingCartCode = shoppingCartCode;
+    }
+
+
+	public void setCustomerId(Long customerId) {
+		this.customerId = customerId;
+	}
+
+	public Long getCustomerId() {
+		return customerId;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCartAttributeItem.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCartAttributeItem.java
new file mode 100644
index 0000000..717fbb4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCartAttributeItem.java
@@ -0,0 +1,115 @@
+package com.salesmanager.core.business.shoppingcart.model;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "SHOPPING_CART_ATTR_ITEM", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class ShoppingCartAttributeItem extends SalesManagerEntity<Long, ShoppingCartAttributeItem> implements Auditable {
+
+
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@Column(name = "SHP_CART_ATTR_ITEM_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "SHP_CRT_ATTR_ITM_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+
+	
+	@Column(name="PRODUCT_ATTR_ID", nullable=false)
+	private Long productAttributeId;
+	
+	@Transient
+	private ProductAttribute productAttribute;
+	
+
+	
+	@ManyToOne(targetEntity = ShoppingCartItem.class)
+	@JoinColumn(name = "SHP_CART_ITEM_ID", nullable = false)
+	private ShoppingCartItem shoppingCartItem;
+	
+	public ShoppingCartAttributeItem(ShoppingCartItem shoppingCartItem, ProductAttribute productAttribute) {
+		this.shoppingCartItem = shoppingCartItem;
+		this.productAttribute = productAttribute;
+		this.productAttributeId = productAttribute.getId();
+	}
+	
+	public ShoppingCartAttributeItem() {
+
+	}
+	
+	
+
+	public ShoppingCartItem getShoppingCartItem() {
+		return shoppingCartItem;
+	}
+
+	public void setShoppingCartItem(ShoppingCartItem shoppingCartItem) {
+		this.shoppingCartItem = shoppingCartItem;
+	}
+
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection audit) {
+		this.auditSection = audit;
+		
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+		
+	}
+
+
+	public void setProductAttributeId(Long productAttributeId) {
+		this.productAttributeId = productAttributeId;
+	}
+
+	public Long getProductAttributeId() {
+		return productAttributeId;
+	}
+
+	public void setProductAttribute(ProductAttribute productAttribute) {
+		this.productAttribute = productAttribute;
+	}
+
+	public ProductAttribute getProductAttribute() {
+		return productAttribute;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCartItem.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCartItem.java
new file mode 100644
index 0000000..9283bee
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/model/ShoppingCartItem.java
@@ -0,0 +1,229 @@
+package com.salesmanager.core.business.shoppingcart.model;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "SHOPPING_CART_ITEM", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class ShoppingCartItem extends SalesManagerEntity<Long, ShoppingCartItem> implements Auditable, Serializable {
+
+
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@Column(name = "SHP_CART_ITEM_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "SHP_CRT_ITM_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@ManyToOne(targetEntity = ShoppingCart.class)
+	@JoinColumn(name = "SHP_CART_ID", nullable = false)
+	private ShoppingCart shoppingCart;
+
+	@Column(name="QUANTITY")
+	private Integer quantity = new Integer(1);
+
+
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@Column(name="PRODUCT_ID", nullable=false)
+	private Long productId;
+	
+	@Transient
+	private boolean productVirtual;
+
+	@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval=true, mappedBy = "shoppingCartItem")
+	private Set<ShoppingCartAttributeItem> attributes = new HashSet<ShoppingCartAttributeItem>();
+	
+	@Transient
+	private BigDecimal itemPrice;//item final price including all rebates
+	
+	@Transient
+	private BigDecimal subTotal;//item final price * quantity
+	
+	@Transient
+	private FinalPrice finalPrice;//contains price details (raw prices)
+	
+
+	@Transient
+	private Product product;
+	
+	@Transient
+	private boolean obsolete = false;
+
+
+
+
+	public ShoppingCartItem(ShoppingCart shoppingCart, Product product) {
+		this.product = product;
+		this.productId = product.getId();
+		this.quantity = 1;
+		this.shoppingCart = shoppingCart;
+		
+	}
+	
+	public ShoppingCartItem(Product product) {
+		this.product = product;
+		this.productId = product.getId();
+		this.quantity = 1;
+
+	}
+	
+	public ShoppingCartItem() {
+		
+	}
+
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection audit) {
+		this.auditSection = audit;
+		
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+		
+	}
+
+
+
+	public void setAttributes(Set<ShoppingCartAttributeItem> attributes) {
+	    this.attributes.clear();
+	    this.attributes.addAll( attributes );
+	    //this.attributes = attributes;
+	}
+
+	public Set<ShoppingCartAttributeItem> getAttributes() {
+		return attributes;
+	}
+
+	public void setItemPrice(BigDecimal itemPrice) {
+		this.itemPrice = itemPrice;
+	}
+
+	public BigDecimal getItemPrice() {
+		return itemPrice;
+	}
+
+	public void setQuantity(Integer quantity) {
+		this.quantity = quantity;
+	}
+
+	public Integer getQuantity() {
+		return quantity;
+	}
+
+
+
+	public ShoppingCart getShoppingCart() {
+		return shoppingCart;
+	}
+
+	public void setShoppingCart(ShoppingCart shoppingCart) {
+		this.shoppingCart = shoppingCart;
+	}
+
+	public void setProductId(Long productId) {
+		this.productId = productId;
+	}
+
+	public Long getProductId() {
+		return productId;
+	}
+
+	public void setProduct(Product product) {
+		this.product = product;
+	}
+
+	public Product getProduct() {
+		return product;
+	}
+	
+	public void addAttributes(ShoppingCartAttributeItem shoppingCartAttributeItem)
+	{
+	    this.attributes.add(shoppingCartAttributeItem);
+	}
+	
+	public void removeAttributes(ShoppingCartAttributeItem shoppingCartAttributeItem)
+	{
+	    this.attributes.remove(shoppingCartAttributeItem);
+	}
+
+	public void removeAllAttributes(){
+		this.attributes.removeAll(Collections.EMPTY_SET);
+	}
+
+	public void setSubTotal(BigDecimal subTotal) {
+		this.subTotal = subTotal;
+	}
+
+	public BigDecimal getSubTotal() {
+		return subTotal;
+	}
+
+	public void setFinalPrice(FinalPrice finalPrice) {
+		this.finalPrice = finalPrice;
+	}
+
+	public FinalPrice getFinalPrice() {
+		return finalPrice;
+	}
+	
+	public boolean isObsolete() {
+		return obsolete;
+	}
+
+	public void setObsolete(boolean obsolete) {
+		this.obsolete = obsolete;
+	}
+	
+
+	public boolean isProductVirtual() {
+		return productVirtual;
+	}
+
+	public void setProductVirtual(boolean productVirtual) {
+		this.productVirtual = productVirtual;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartCalculationService.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartCalculationService.java
new file mode 100644
index 0000000..f5543d9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartCalculationService.java
@@ -0,0 +1,43 @@
+/**
+ *
+ */
+package com.salesmanager.core.business.shoppingcart.service;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.OrderTotalSummary;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+
+/**
+ * Interface declaring various methods used to calculate {@link ShoppingCart}
+ * object details.
+ * @author Umesh Awasthi
+ * @since 1.2
+ *
+ */
+public interface ShoppingCartCalculationService
+{
+    /**
+     * Method which will be used to calculate price for each line items as
+     * well Total and Sub-total for {@link ShoppingCart}.
+     * @param cartModel ShoopingCart mode representing underlying DB object
+     * @param customer
+     * @param store
+     * @param language
+     * @throws ServiceException
+     */
+    public OrderTotalSummary calculate(final ShoppingCart cartModel,final Customer customer, final MerchantStore store, final Language language) throws ServiceException;
+
+
+    /**
+     * Method which will be used to calculate price for each line items as
+     * well Total and Sub-total for {@link ShoppingCart}.
+     * @param cartModel ShoopingCart mode representing underlying DB object
+     * @param store
+     * @param language
+     * @throws ServiceException
+     */
+    public OrderTotalSummary calculate(final ShoppingCart cartModel, final MerchantStore store, final Language language) throws ServiceException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartCalculationServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartCalculationServiceImpl.java
new file mode 100644
index 0000000..d6d9375
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartCalculationServiceImpl.java
@@ -0,0 +1,123 @@
+/**
+ *
+ */
+package com.salesmanager.core.business.shoppingcart.service;
+
+import org.apache.commons.lang.Validate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.OrderTotalSummary;
+import com.salesmanager.core.business.order.service.OrderService;
+import com.salesmanager.core.business.order.service.OrderServiceImpl;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+/**
+ * <p>Implementation class responsible for calculating state of shopping cart.
+ * This class will take care of calculating price of each line items of shopping cart
+ * as well any discount including sub-total and total amount.
+ * </p>
+ *
+ * @author Umesh Awasthi
+ * @version 1.2
+ */
+@Service("shoppingCartCalculationService")
+public class ShoppingCartCalculationServiceImpl implements ShoppingCartCalculationService
+{
+
+
+    protected  final Logger LOG = LoggerFactory.getLogger(getClass());
+
+    @Autowired
+    private ShoppingCartService shoppingCartService;
+
+    @Autowired
+    private OrderService orderService;
+
+
+
+    /**
+     * <p>Method used to recalculate state of shopping cart every time any change has been made
+     * to underlying {@link ShoppingCart} object in DB.</p>
+     * Following operations will be performed by this method.
+     *
+     * <li>Calculate price for each {@link ShoppingCartItem} and update it. </li>
+     * <p>
+     * This method is backbone method for all price calculation related to shopping cart.</p>
+     *
+     * @see OrderServiceImpl
+     *
+     * @param cartModel
+     * @param customer
+     * @param store
+     * @param language
+     * @throws ServiceException
+     */
+    @Override
+    public OrderTotalSummary calculate( final ShoppingCart cartModel ,final Customer customer, final MerchantStore store, final Language language ) throws ServiceException
+    {
+
+        Validate.notNull(cartModel,"cart cannot be null");
+        Validate.notNull(cartModel.getLineItems(),"Cart should have line items.");
+        Validate.notNull(store,"MerchantStore cannot be null");
+        Validate.notNull(customer,"Customer cannot be null");
+        OrderTotalSummary orderTotalSummary=orderService.calculateShoppingCartTotal( cartModel, customer,store, language );
+        updateCartModel(cartModel);
+        return orderTotalSummary;
+
+
+    }
+
+
+    /**
+     * <p>Method used to recalculate state of shopping cart every time any change has been made
+     * to underlying {@link ShoppingCart} object in DB.</p>
+     * Following operations will be performed by this method.
+     *
+     * <li>Calculate price for each {@link ShoppingCartItem} and update it. </li>
+     * <p>
+     * This method is backbone method for all price calculation related to shopping cart.</p>
+     *
+     * @see OrderServiceImpl
+     *
+     * @param cartModel
+     * @param store
+     * @param language
+     * @throws ServiceException
+     */
+    @Override
+    public OrderTotalSummary calculate( final ShoppingCart cartModel , final MerchantStore store, final Language language ) throws ServiceException
+    {
+
+        Validate.notNull(cartModel,"cart cannot be null");
+        Validate.notNull(cartModel.getLineItems(),"Cart should have line items.");
+        Validate.notNull(store,"MerchantStore cannot be null");
+        OrderTotalSummary orderTotalSummary=orderService.calculateShoppingCartTotal( cartModel, store, language );
+        updateCartModel(cartModel);
+        return orderTotalSummary;
+
+
+    }
+
+
+
+    public ShoppingCartService getShoppingCartService()
+    {
+        return shoppingCartService;
+    }
+
+
+    private void updateCartModel(final ShoppingCart cartModel) throws ServiceException{
+        shoppingCartService.saveOrUpdate( cartModel );
+    }
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartService.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartService.java
new file mode 100644
index 0000000..6c3cab8
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartService.java
@@ -0,0 +1,86 @@
+package com.salesmanager.core.business.shoppingcart.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shipping.model.ShippingProduct;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+
+
+public interface ShoppingCartService extends SalesManagerEntityService<Long, ShoppingCart> {
+
+	ShoppingCart getShoppingCart(Customer customer) throws ServiceException;
+
+	void saveOrUpdate(ShoppingCart shoppingCart) throws ServiceException;
+
+	ShoppingCart getById(Long id, MerchantStore store) throws ServiceException;
+
+	ShoppingCart getByCode(String code, MerchantStore store)
+			throws ServiceException;
+
+	ShoppingCart getByCustomer(Customer customer) throws ServiceException;
+
+	/**
+	 * Creates a list of ShippingProduct based on the ShoppingCart
+	 * if items are virtual return list will be null
+	 * @param cart
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<ShippingProduct> createShippingProduct(ShoppingCart cart)
+			throws ServiceException;
+
+
+
+	/**
+	 * Looks if the items in the ShoppingCart are free of charges
+	 * @param cart
+	 * @return
+	 * @throws ServiceException
+	 */
+	boolean isFreeShoppingCart(ShoppingCart cart) throws ServiceException;
+	
+	boolean isFreeShoppingCart(List<ShoppingCartItem> items) throws ServiceException;
+
+	/**
+	 * Populates a ShoppingCartItem from a Product and attributes if any
+	 * @param product
+	 * @return
+	 * @throws ServiceException
+	 */
+	ShoppingCartItem populateShoppingCartItem(Product product)
+			throws ServiceException;
+	
+	void deleteCart(ShoppingCart cart) throws ServiceException;
+
+
+	void removeShoppingCart(ShoppingCart cart) throws ServiceException;
+
+	/**
+	 *
+	 * @param userShoppingModel
+	 * @param sessionCart
+	 * @param store
+	 * @return {@link ShoppingCart} merged Shopping Cart
+	 * @throws Exception
+	 */
+	public ShoppingCart mergeShoppingCarts(final ShoppingCart userShoppingCart,final ShoppingCart sessionCart,final MerchantStore store  ) throws Exception;
+
+	/**
+	 * Determines if the shopping cart requires shipping
+	 * @param cart
+	 * @return
+	 * @throws ServiceException
+	 */
+	boolean requiresShipping(ShoppingCart cart) throws ServiceException;
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartServiceImpl.java
new file mode 100644
index 0000000..bfdf486
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/shoppingcart/service/ShoppingCartServiceImpl.java
@@ -0,0 +1,542 @@
+package com.salesmanager.core.business.shoppingcart.service;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.lang3.Validate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.catalog.product.service.PricingService;
+import com.salesmanager.core.business.catalog.product.service.ProductService;
+import com.salesmanager.core.business.catalog.product.service.attribute.ProductAttributeService;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shipping.model.ShippingProduct;
+import com.salesmanager.core.business.shoppingcart.dao.ShoppingCartDao;
+import com.salesmanager.core.business.shoppingcart.dao.ShoppingCartItemDao;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartAttributeItem;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+
+@Service("shoppingCartService")
+public class ShoppingCartServiceImpl extends SalesManagerEntityServiceImpl<Long, ShoppingCart> implements ShoppingCartService {
+
+
+	private final ShoppingCartDao shoppingCartDao;
+
+	@Autowired
+	private ProductService productService;
+
+	@Autowired
+	private ShoppingCartItemDao shoppingCartItemDao;
+
+	@Autowired
+	private PricingService pricingService;
+
+	@Autowired
+    private ProductAttributeService productAttributeService;
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(ShoppingCartServiceImpl.class);
+
+	@Autowired
+	public ShoppingCartServiceImpl(
+			final ShoppingCartDao shoppingCartDao) {
+		super(shoppingCartDao);
+		this.shoppingCartDao = shoppingCartDao;
+
+	}
+
+
+	/**
+	 * Retrieve a {@link ShoppingCart} cart for a given customer
+	 */
+	@Override
+    @Transactional
+	public ShoppingCart getShoppingCart(final Customer customer) throws ServiceException {
+
+		try {
+
+			ShoppingCart shoppingCart = shoppingCartDao.getByCustomer(customer);
+			populateShoppingCart(shoppingCart);
+			if(shoppingCart!=null && shoppingCart.isObsolete()) {
+				delete(shoppingCart);
+				return null;
+			} else {
+				return shoppingCart;
+			}
+
+
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+
+	}
+
+	/**
+	 * Save or update a {@link ShoppingCart} for a given customer
+	 */
+	@Override
+    public void saveOrUpdate(final ShoppingCart shoppingCart) throws ServiceException {
+		if(shoppingCart.getId()==null || shoppingCart.getId().longValue()==0) {
+			super.create(shoppingCart);
+		} else {
+			super.update(shoppingCart);
+		}
+	}
+
+	/**
+	 * Get a {@link ShoppingCart} for a given id and MerchantStore. Will update the shopping cart
+	 * prices and items based on the actual inventory. This method will remove the shopping cart if
+	 * no items are attached.
+	 */
+	@Override
+	@Transactional
+	public ShoppingCart getById(final Long id, final MerchantStore store) throws ServiceException {
+
+		try {
+			ShoppingCart shoppingCart = shoppingCartDao.getById(id, store);
+			if(shoppingCart==null) {
+				return null;
+			}
+			populateShoppingCart(shoppingCart);
+
+			if(shoppingCart.isObsolete()) {
+				delete(shoppingCart);
+				return null;
+			} else {
+				return shoppingCart;
+			}
+
+
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+
+
+	}
+
+	/**
+	 * Get a {@link ShoppingCart} for a given id. Will update the shopping cart
+	 * prices and items based on the actual inventory. This method will remove the shopping cart if
+	 * no items are attached.
+	 */
+	@Override
+	public ShoppingCart getById(final Long id) {
+
+
+		try {
+			ShoppingCart shoppingCart = shoppingCartDao.getById(id);
+			if(shoppingCart==null) {
+				return null;
+			}
+			populateShoppingCart(shoppingCart);
+
+
+			if(shoppingCart.isObsolete()) {
+				delete(shoppingCart);
+				return null;
+			} else {
+				return shoppingCart;
+			}
+			} catch (Exception e) {
+				// TODO Auto-generated catch block
+				e.printStackTrace();
+			}
+			return null;
+
+	}
+
+	/**
+	 * Get a {@link ShoppingCart} for a given code. Will update the shopping cart
+	 * prices and items based on the actual inventory. This method will remove the shopping cart if
+	 * no items are attached.
+	 */
+	@Override
+	@Transactional
+	public ShoppingCart getByCode(final String code, final MerchantStore store) throws ServiceException {
+
+		try {
+			ShoppingCart shoppingCart = shoppingCartDao.getByCode(code, store);
+			if(shoppingCart==null) {
+				return null;
+			}
+			populateShoppingCart(shoppingCart);
+
+
+			if(shoppingCart.isObsolete()) {
+				delete(shoppingCart);
+				return null;
+			} else {
+				return shoppingCart;
+			}
+
+		}catch(javax.persistence.NoResultException nre) {
+			return null;
+		} catch (RuntimeException e) {
+			throw new ServiceException(e);
+		} catch (Exception ee) {
+			throw new ServiceException(ee);
+		} catch (Throwable t) {
+			throw new ServiceException(t);
+		} 
+
+
+	}
+
+	@Override
+	public void deleteCart(final ShoppingCart shoppingCart) throws ServiceException {
+		ShoppingCart cart = this.getById(shoppingCart.getId());
+		if(cart!=null) {
+			super.delete(cart);
+		}
+	}
+
+
+	@Override
+	public ShoppingCart getByCustomer(final Customer customer) throws ServiceException {
+
+		try {
+			ShoppingCart shoppingCart = shoppingCartDao.getByCustomer(customer);
+			if(shoppingCart==null) {
+				return null;
+			}
+			return populateShoppingCart(shoppingCart);
+
+
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	}
+
+	@Transactional(noRollbackFor={org.springframework.dao.EmptyResultDataAccessException.class})
+	private ShoppingCart populateShoppingCart(final ShoppingCart shoppingCart) throws Exception {
+
+		try {
+
+			boolean cartIsObsolete = true;
+			if(shoppingCart!=null) {
+
+				Set<ShoppingCartItem> items = shoppingCart.getLineItems();
+				if(items==null || items.size()==0) {
+					shoppingCart.setObsolete(true);
+					return shoppingCart;
+
+				}
+
+				//Set<ShoppingCartItem> shoppingCartItems = new HashSet<ShoppingCartItem>();
+				for(ShoppingCartItem item : items) {
+					LOGGER.debug("Populate item " + item.getId());
+					populateItem(item);
+					LOGGER.debug("Obsolete item ? " + item.isObsolete());
+					if(item.isObsolete()) {
+					} else {
+						cartIsObsolete = false;
+					}
+				}
+
+				//shoppingCart.setLineItems(shoppingCartItems);
+				boolean refreshCart = false;
+                Set<ShoppingCartItem> refreshedItems = new HashSet<ShoppingCartItem>();
+                for(ShoppingCartItem item : items) {
+                	if(!item.isObsolete()) {
+                		refreshedItems.add(item);
+                	} else {
+                		refreshCart = true;
+                	}
+                }
+
+                if(refreshCart) {
+                	shoppingCart.setLineItems(refreshedItems);
+                	update(shoppingCart);
+                }
+
+				if(cartIsObsolete) {
+					shoppingCart.setObsolete(true);
+				}
+				return shoppingCart;
+			}
+
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+
+		return shoppingCart;
+
+	}
+
+	@Override
+	public ShoppingCartItem populateShoppingCartItem(final Product product) throws ServiceException {
+		Validate.notNull(product, "Product should not be null");
+		Validate.notNull(product.getMerchantStore(), "Product.merchantStore should not be null");
+
+
+		ShoppingCartItem item = new ShoppingCartItem(product);
+
+		//Set<ProductAttribute> productAttributes = product.getAttributes();
+		//Set<ShoppingCartAttributeItem> attributesList = new HashSet<ShoppingCartAttributeItem>();
+		//if(!CollectionUtils.isEmpty(productAttributes)) {
+
+		//	for(ProductAttribute productAttribute : productAttributes) {
+		//			ShoppingCartAttributeItem attributeItem = new ShoppingCartAttributeItem();
+		//			attributeItem.setShoppingCartItem(item);
+		//			attributeItem.setProductAttribute(productAttribute);
+		//			attributeItem.setProductAttributeId(productAttribute.getId());
+		//			attributesList.add(attributeItem);
+
+		//	}
+
+		//	item.setAttributes(attributesList);
+		//}
+		
+		item.setProductVirtual(product.isProductVirtual());
+
+		//set item price
+		FinalPrice price = pricingService.calculateProductPrice(product);
+		item.setItemPrice(price.getFinalPrice());
+		return item;
+
+
+	}
+
+
+	private void populateItem(final ShoppingCartItem item) throws Exception {
+
+		Product product = null;
+
+		Long productId = item.getProductId();
+		product = productService.getById(productId);
+
+		if(product==null) {
+			item.setObsolete(true);
+			return;
+		}
+
+
+		item.setProduct(product);
+		
+		if(product.isProductVirtual()) {
+			item.setProductVirtual(true);
+		}
+
+		Set<ShoppingCartAttributeItem> attributes = item.getAttributes();
+		Set<ProductAttribute> productAttributes = product.getAttributes();
+		List<ProductAttribute> attributesList = new ArrayList<ProductAttribute>();
+		if(productAttributes!=null && productAttributes.size()>0 && attributes!=null && attributes.size()>0) {
+			for(ShoppingCartAttributeItem attribute : attributes) {
+				long attributeId = attribute.getProductAttributeId().longValue();
+				for(ProductAttribute productAttribute : productAttributes) {
+
+					if(productAttribute.getId().longValue()==attributeId) {
+						attribute.setProductAttribute(productAttribute);
+						attributesList.add(productAttribute);
+						break;
+					}
+
+				}
+
+			}
+		}
+
+		//set item price
+		FinalPrice price = pricingService.calculateProductPrice(product, attributesList);
+		item.setItemPrice(price.getFinalPrice());
+		item.setFinalPrice(price);
+
+
+
+		BigDecimal subTotal = item.getItemPrice().multiply(new BigDecimal(item.getQuantity().intValue()));
+		item.setSubTotal(subTotal);
+
+
+	}
+
+	@Override
+	public List<ShippingProduct> createShippingProduct(final ShoppingCart cart) throws ServiceException {
+		/**
+		 * Determines if products are virtual
+		 */
+		Set<ShoppingCartItem> items = cart.getLineItems();
+		List<ShippingProduct> shippingProducts = null;
+		for(ShoppingCartItem item : items) {
+			Product product = item.getProduct();
+			if(!product.isProductVirtual() && product.isProductShipeable()) {
+				if(shippingProducts==null) {
+					shippingProducts = new ArrayList<ShippingProduct>();
+				}
+				ShippingProduct shippingProduct = new ShippingProduct(product);
+				shippingProduct.setQuantity(item.getQuantity());
+				shippingProducts.add(shippingProduct);
+			}
+		}
+
+		return shippingProducts;
+
+	}
+
+
+	@Override
+	public boolean isFreeShoppingCart(final ShoppingCart cart) throws ServiceException {
+		/**
+		 * Determines if products are free
+		 */
+		Set<ShoppingCartItem> items = cart.getLineItems();
+		for(ShoppingCartItem item : items) {
+			Product product = item.getProduct();
+			FinalPrice finalPrice = pricingService.calculateProductPrice(product);
+			if(finalPrice.getFinalPrice().longValue()>0) {
+				return false;
+			}
+		}
+		
+		return true;
+
+	}
+	
+	@Override
+	public boolean requiresShipping(final ShoppingCart cart) throws ServiceException {
+		
+		Validate.notNull(cart,"Shopping cart cannot be null");
+		Validate.notNull(cart.getLineItems(),"ShoppingCart items cannot be null");
+		boolean requiresShipping = false;
+		for(ShoppingCartItem item : cart.getLineItems()) {
+			Product product = item.getProduct();
+			if(product.isProductShipeable()) {
+				requiresShipping = true;
+				break;
+			}
+		}
+		
+		return requiresShipping;
+		
+	}
+
+    @Override
+    public void  removeShoppingCart( final ShoppingCart cart )
+        throws ServiceException
+    {
+         shoppingCartDao.removeShoppingCart( cart );
+    }
+
+
+    @Override
+    public ShoppingCart mergeShoppingCarts( final ShoppingCart userShoppingModel, final ShoppingCart sessionCart,final MerchantStore store ) throws Exception
+    {
+        if(sessionCart.getCustomerId() !=null && sessionCart.getCustomerId() ==userShoppingModel.getCustomerId() ){
+            LOGGER.info( "Session Shopping cart belongs to same logged in user" );
+            if(CollectionUtils.isNotEmpty( userShoppingModel.getLineItems() ) && CollectionUtils.isNotEmpty( sessionCart.getLineItems() )){
+                return userShoppingModel;
+            }
+        }
+
+        LOGGER.info( "Starting merging shopping carts" );
+        if(CollectionUtils.isNotEmpty( sessionCart.getLineItems() )){
+            Set<ShoppingCartItem> shoppingCartItemsSet=getShoppingCartItems(sessionCart,store,userShoppingModel);
+            boolean duplicateFound = false;
+            if(CollectionUtils.isNotEmpty(shoppingCartItemsSet)) {
+                for(ShoppingCartItem sessionShoppingCartItem : shoppingCartItemsSet){
+                    if(CollectionUtils.isNotEmpty(userShoppingModel.getLineItems())){
+                        for(ShoppingCartItem cartItem : userShoppingModel.getLineItems()){
+                            if(cartItem.getProduct().getId().longValue()==sessionShoppingCartItem.getProduct().getId().longValue()) {
+                                if(CollectionUtils.isNotEmpty(cartItem.getAttributes())) {
+                                    if(!duplicateFound) {
+                                        LOGGER.info( "Dupliate item found..updating exisitng product quantity" );
+                                        cartItem.setQuantity(cartItem.getQuantity() + sessionShoppingCartItem.getQuantity());
+                                        duplicateFound = true;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    if(!duplicateFound) {
+                        LOGGER.info( "New item found..adding item to Shopping cart" );
+                        userShoppingModel.getLineItems().add( sessionShoppingCartItem );
+                    }
+                }
+
+            }
+
+        }
+        LOGGER.info( "Shopping Cart merged successfully.....");
+        saveOrUpdate( userShoppingModel );
+        removeShoppingCart( sessionCart );
+
+        return userShoppingModel;
+    }
+
+
+
+    private Set<ShoppingCartItem> getShoppingCartItems( final ShoppingCart sessionCart,final MerchantStore store,final ShoppingCart cartModel )
+                    throws Exception
+                {
+
+                    Set<ShoppingCartItem> shoppingCartItemsSet=null;
+                    if(CollectionUtils.isNotEmpty( sessionCart.getLineItems() )){
+                        shoppingCartItemsSet=new HashSet<ShoppingCartItem>();
+                        for(ShoppingCartItem shoppingCartItem : sessionCart.getLineItems()){
+                            Product product = productService.getById( shoppingCartItem.getProductId() );
+                            if ( product == null )
+                            {
+                                throw new Exception( "Item with id " + shoppingCartItem.getProductId() + " does not exist" );
+                            }
+
+                            if ( product.getMerchantStore().getId().intValue() != store.getId().intValue() )
+                            {
+                                throw new Exception( "Item with id " + shoppingCartItem.getProductId() + " does not belong to merchant "
+                                    + store.getId() );
+                            }
+
+                            ShoppingCartItem item= populateShoppingCartItem( product );
+                            item.setQuantity( shoppingCartItem.getQuantity() );
+                            item.setShoppingCart( cartModel );
+
+                            List<ShoppingCartAttributeItem> cartAttributes = new ArrayList<ShoppingCartAttributeItem>( shoppingCartItem.getAttributes() );
+                            if(CollectionUtils.isNotEmpty( cartAttributes )){
+                                for(ShoppingCartAttributeItem shoppingCartAttributeItem :cartAttributes ){
+                                    ProductAttribute productAttribute =productAttributeService.getById( shoppingCartAttributeItem.getId() );
+                                    if ( productAttribute != null
+                                                    && productAttribute.getProduct().getId().longValue() == product.getId().longValue() ){
+
+                                        ShoppingCartAttributeItem attributeItem=new ShoppingCartAttributeItem(item,productAttribute);
+                                        if ( shoppingCartAttributeItem.getId() > 0 )
+                                        {
+                                            attributeItem.setId( shoppingCartAttributeItem.getId() );
+                                        }
+                                        item.addAttributes( attributeItem );
+
+                                    }
+                                }
+                            }
+
+                            shoppingCartItemsSet.add( item );
+                        }
+
+                    }
+                     return shoppingCartItemsSet;
+              }
+
+
+	@Override
+	public boolean isFreeShoppingCart(List<ShoppingCartItem> items)
+			throws ServiceException {
+		ShoppingCart cart = new ShoppingCart();
+		Set<ShoppingCartItem> cartItems = new HashSet<ShoppingCartItem>(items);
+		cart.setLineItems(cartItems);
+		return this.isFreeShoppingCart(cart);
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantConfigurationDao.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantConfigurationDao.java
new file mode 100755
index 0000000..008f5f0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantConfigurationDao.java
@@ -0,0 +1,21 @@
+package com.salesmanager.core.business.system.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.model.MerchantConfigurationType;
+
+public interface MerchantConfigurationDao extends SalesManagerEntityDao<Long, MerchantConfiguration> {
+
+	
+	
+	MerchantConfiguration getMerchantConfiguration(String key, MerchantStore store);
+
+	List<MerchantConfiguration> getMerchantConfigurations(MerchantStore store);
+
+	List<MerchantConfiguration> listByType(MerchantConfigurationType type,
+			MerchantStore store);
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantConfigurationDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantConfigurationDaoImpl.java
new file mode 100755
index 0000000..55aa335
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantConfigurationDaoImpl.java
@@ -0,0 +1,69 @@
+package com.salesmanager.core.business.system.dao;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.model.MerchantConfigurationType;
+import com.salesmanager.core.business.system.model.QMerchantConfiguration;
+
+@Repository("merchantConfigurationDao")
+public class MerchantConfigurationDaoImpl extends SalesManagerEntityDaoImpl<Long, MerchantConfiguration>
+		implements MerchantConfigurationDao {
+
+
+	@Override
+	public MerchantConfiguration getMerchantConfiguration(String key, MerchantStore store) {
+		
+		
+		
+		QMerchantConfiguration qMerchantConfiguration = QMerchantConfiguration.merchantConfiguration;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		query.from(qMerchantConfiguration)
+			.innerJoin(qMerchantConfiguration.merchantStore).fetch()
+			.where(qMerchantConfiguration.merchantStore.id.eq(store.getId())
+			.and(qMerchantConfiguration.key.eq(key)));
+		
+		return query.uniqueResult(qMerchantConfiguration);
+
+	}
+	
+	@Override
+	public List<MerchantConfiguration> getMerchantConfigurations(MerchantStore store) {
+
+		QMerchantConfiguration qMerchantConfiguration = QMerchantConfiguration.merchantConfiguration;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		query.from(qMerchantConfiguration)
+			.innerJoin(qMerchantConfiguration.merchantStore).fetch()
+			.where(qMerchantConfiguration.merchantStore.id.eq(store.getId()));
+		
+		return query.list(qMerchantConfiguration);
+
+	}
+	
+	@Override
+	public List<MerchantConfiguration> listByType(MerchantConfigurationType type, MerchantStore store) {
+		
+
+		QMerchantConfiguration qMerchantConfiguration = QMerchantConfiguration.merchantConfiguration;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		query.from(qMerchantConfiguration)
+			.innerJoin(qMerchantConfiguration.merchantStore).fetch()
+			.where(qMerchantConfiguration.merchantStore.id.eq(store.getId())
+			.and(qMerchantConfiguration.merchantConfigurationType.eq(type)));
+		
+		return query.list(qMerchantConfiguration);
+
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantLogDao.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantLogDao.java
new file mode 100644
index 0000000..cff3990
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantLogDao.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.business.system.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.system.model.MerchantLog;
+
+public interface MerchantLogDao extends SalesManagerEntityDao<Long, MerchantLog> {
+
+
+	List<MerchantLog> listByMerchant(MerchantStore store);
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantLogDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantLogDaoImpl.java
new file mode 100644
index 0000000..3f0ff64
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/MerchantLogDaoImpl.java
@@ -0,0 +1,34 @@
+package com.salesmanager.core.business.system.dao;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.system.model.MerchantLog;
+
+@Repository("merchantLogDao")
+public class MerchantLogDaoImpl extends SalesManagerEntityDaoImpl<Long, MerchantLog>
+		implements MerchantLogDao {
+
+
+
+	
+	@Override
+	public List<MerchantLog> listByMerchant(MerchantStore store) {
+
+/*		QMerchantLog qMerchantLog = QMerchantLog.
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		query.from(qMerchantCnfiguration)
+			.innerJoin(qMerchantCnfiguration.merchantStore).fetch()
+			.where(qMerchantCnfiguration.merchantStore.id.eq(store.getId()));
+		
+		return query.list(qMerchantCnfiguration);*/
+		
+		return null;
+
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/ModuleConfigurationDao.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/ModuleConfigurationDao.java
new file mode 100755
index 0000000..a3c0100
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/ModuleConfigurationDao.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.business.system.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+
+public interface ModuleConfigurationDao extends SalesManagerEntityDao<Long, IntegrationModule> {
+
+	List<IntegrationModule> getModulesConfiguration(String module);
+
+	IntegrationModule getByCode(String moduleCode);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/ModuleConfigurationDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/ModuleConfigurationDaoImpl.java
new file mode 100755
index 0000000..db53779
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/ModuleConfigurationDaoImpl.java
@@ -0,0 +1,52 @@
+package com.salesmanager.core.business.system.dao;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.QIntegrationModule;
+
+@Repository("integrationModuleDao")
+public class ModuleConfigurationDaoImpl extends SalesManagerEntityDaoImpl<Long, IntegrationModule>
+		implements ModuleConfigurationDao {
+
+
+	@Override
+	public List<IntegrationModule> getModulesConfiguration(String module) {
+		
+		
+		
+		QIntegrationModule qIntegrationModule = QIntegrationModule.integrationModule;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		query.from(qIntegrationModule)
+			.where(qIntegrationModule.module.eq(module));
+		
+		return query.list(qIntegrationModule);
+
+
+	}
+	
+	@Override
+	public IntegrationModule getByCode(String moduleCode) {
+		
+		
+		
+		QIntegrationModule qIntegrationModule = QIntegrationModule.integrationModule;
+
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		query.from(qIntegrationModule)
+			.where(qIntegrationModule.code.eq(moduleCode));
+		
+		return query.uniqueResult(qIntegrationModule);
+
+
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemConfigurationDao.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemConfigurationDao.java
new file mode 100644
index 0000000..7199265
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemConfigurationDao.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.system.dao;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.system.model.SystemConfiguration;
+
+public interface SystemConfigurationDao extends SalesManagerEntityDao<Long, SystemConfiguration> {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemConfigurationDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemConfigurationDaoImpl.java
new file mode 100644
index 0000000..c513587
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemConfigurationDaoImpl.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.business.system.dao;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.system.model.SystemConfiguration;
+
+@Repository("systemConfigurationDao")
+public class SystemConfigurationDaoImpl extends SalesManagerEntityDaoImpl<Long, SystemConfiguration>
+		implements SystemConfigurationDao {
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemNotificationDao.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemNotificationDao.java
new file mode 100755
index 0000000..febef93
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemNotificationDao.java
@@ -0,0 +1,8 @@
+package com.salesmanager.core.business.system.dao;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.system.model.SystemNotification;
+
+public interface SystemNotificationDao extends SalesManagerEntityDao<Long, SystemNotification> {
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemNotificationDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemNotificationDaoImpl.java
new file mode 100755
index 0000000..554604e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/dao/SystemNotificationDaoImpl.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.business.system.dao;
+
+import org.springframework.stereotype.Repository;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.system.model.SystemNotification;
+
+@Repository("systemNotificationDao")
+public class SystemNotificationDaoImpl extends SalesManagerEntityDaoImpl<Long, SystemNotification>
+		implements SystemNotificationDao {
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/CustomIntegrationConfiguration.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/CustomIntegrationConfiguration.java
new file mode 100644
index 0000000..365fb8e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/CustomIntegrationConfiguration.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.business.system.model;
+
+import org.json.simple.JSONAware;
+
+/**
+ * Used as a marker interface to commit additional
+ * integration module information to the database
+ * @author casams1
+ *
+ */
+public interface CustomIntegrationConfiguration extends JSONAware{
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/Environment.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/Environment.java
new file mode 100644
index 0000000..3eae1d8
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/Environment.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.system.model;
+
+public enum Environment {
+	
+	TEST, PRODUCTION
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/IntegrationConfiguration.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/IntegrationConfiguration.java
new file mode 100755
index 0000000..25e57a6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/IntegrationConfiguration.java
@@ -0,0 +1,169 @@
+package com.salesmanager.core.business.system.model;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+/**
+ * Object used to contain the integration information with an external gateway
+ * Uses simple JSON to encode the object in JSON by implementing JSONAware
+ * and uses jackson JSON decode to parse JSON String to an Object
+ * @author csamson
+ *
+ */
+public class IntegrationConfiguration implements JSONAware {
+	
+
+	public final static String TEST_ENVIRONMENT = "TEST";
+	public final static String PRODUCTION_ENVIRONMENT = "PRODUCTION";
+	
+	private String moduleCode;
+	private boolean active;
+	private boolean defaultSelected;
+	//private boolean customModule;
+	private Map<String,String> integrationKeys= new HashMap<String,String>();
+	private Map<String,List<String>> integrationOptions= new HashMap<String,List<String>>();
+	private String environment;
+	
+	
+	public String getModuleCode() {
+		return moduleCode;
+	}
+	@JsonProperty("moduleCode")  
+	public void setModuleCode(String moduleCode) {
+		this.moduleCode = moduleCode;
+	}
+	public boolean isActive() {
+		return active;
+	}
+	@JsonProperty("active")
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+	public Map<String, String> getIntegrationKeys() {
+		return integrationKeys;
+	}
+	@JsonProperty("integrationKeys")
+	public void setIntegrationKeys(Map<String, String> integrationKeys) {
+		this.integrationKeys = integrationKeys;
+	}
+
+	
+	protected String getJsonInfo() {
+		
+		StringBuilder returnString = new StringBuilder();
+		returnString.append("{");
+		returnString.append("\"moduleCode\"").append(":\"").append(this.getModuleCode()).append("\"");
+		returnString.append(",");
+		returnString.append("\"active\"").append(":").append(this.isActive());
+		returnString.append(",");
+		returnString.append("\"defaultSelected\"").append(":").append(this.isDefaultSelected());
+		returnString.append(",");
+		//returnString.append("\"customModule\"").append(":").append(this.isCustomModule());
+		//returnString.append(",");
+		returnString.append("\"environment\"").append(":\"").append(this.getEnvironment()).append("\"");
+		//returnString.append("}");
+		return returnString.toString();
+		
+	}
+	
+	
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		
+		
+		StringBuilder returnString = new StringBuilder();
+		returnString.append(getJsonInfo());
+
+		if(this.getIntegrationKeys().size()>0) {
+
+				JSONObject data = new JSONObject();
+				Set<String> keys = this.getIntegrationKeys().keySet();
+				for(String key : keys) {
+					data.put(key, this.getIntegrationKeys().get(key));
+				}
+				String dataField = data.toJSONString();
+
+				returnString.append(",").append("\"integrationKeys\"").append(":");
+				returnString.append(dataField.toString());
+
+				
+		 }
+		
+		
+		if(this.getIntegrationOptions()!=null && this.getIntegrationOptions().size()>0) {
+
+				//JSONObject data = new JSONObject();
+				StringBuilder optionDataEntries = new StringBuilder();
+				Set<String> keys = this.getIntegrationOptions().keySet();
+				int countOptions = 0;
+				for(String key : keys) {
+
+					List<String> values = this.getIntegrationOptions().get(key);
+					StringBuilder optionsEntries = new StringBuilder();
+					StringBuilder dataEntries = new StringBuilder();
+					
+					int count = 0;
+					for(String value : values) {
+						
+						dataEntries.append("\"").append(value).append("\"");
+						if(count<values.size()-1) {
+							dataEntries.append(",");
+						}
+						count++;
+					}
+					
+					optionsEntries.append("[").append(dataEntries.toString()).append("]");
+					
+					optionDataEntries.append("\"").append(key).append("\":").append(optionsEntries.toString());
+
+					if(countOptions<keys.size()-1) {
+						optionDataEntries.append(",");
+					}
+					countOptions ++;
+					
+				}
+				String dataField = optionDataEntries.toString();
+
+				returnString.append(",").append("\"integrationOptions\"").append(":{");
+				returnString.append(dataField.toString());
+				returnString.append("}");
+				
+		 }
+			
+
+		returnString.append("}");
+
+		
+		return returnString.toString();
+
+	}
+	public void setEnvironment(String environment) {
+		this.environment = environment;
+	}
+	public String getEnvironment() {
+		return environment;
+	}
+	public Map<String,List<String>> getIntegrationOptions() {
+		return integrationOptions;
+	}
+	public void setIntegrationOptions(Map<String,List<String>> integrationOptions) {
+		this.integrationOptions = integrationOptions;
+	}
+	public boolean isDefaultSelected() {
+		return defaultSelected;
+	}
+	public void setDefaultSelected(boolean defaultSelected) {
+		this.defaultSelected = defaultSelected;
+	}
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/IntegrationModule.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/IntegrationModule.java
new file mode 100755
index 0000000..8eb317e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/IntegrationModule.java
@@ -0,0 +1,255 @@
+package com.salesmanager.core.business.system.model;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+
+import org.hibernate.annotations.Type;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "MODULE_CONFIGURATION", schema= SchemaConstant.SALESMANAGER_SCHEMA)
+
+
+public class IntegrationModule extends SalesManagerEntity<Long, IntegrationModule> implements Serializable, Auditable {
+
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -357523134800965997L;
+
+	@Id
+	@Column(name = "MODULE_CONF_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "MOD_CONF_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	
+
+	@Column(name="MODULE")
+	private String module;
+	
+	@Column(name="CODE", nullable=false)
+	private String code;
+	
+	@Column(name="REGIONS")
+	private String regions;
+	
+	@Column(name="CONFIGURATION")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String configuration;
+	
+	@Column(name="DETAILS")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String configDetails;
+	
+	@Column(name="TYPE")
+	private String type;
+
+
+	@Column(name="IMAGE")
+	private String image;
+	
+	@Column(name="CUSTOM_IND")
+	private boolean customModule = false;
+	
+	@Transient
+	private Set<String> regionsSet = new HashSet<String>();
+	
+	/**
+	 * Contains a map of module config by environment (DEV,PROD)
+	 */
+	@Transient
+	private Map<String,ModuleConfig> moduleConfigs = new HashMap<String,ModuleConfig>();
+	
+	
+	@Transient
+	private Map<String,String> details = new HashMap<String,String>();
+
+	
+	public Map<String, String> getDetails() {
+		return details;
+	}
+
+
+
+	public void setDetails(Map<String, String> details) {
+		this.details = details;
+	}
+
+
+
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+
+
+
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+
+
+	@Override
+	public void setAuditSection(AuditSection audit) {
+		this.auditSection = audit;
+		
+	}
+
+
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+	public String getModule() {
+		return module;
+	}
+
+
+
+	public void setModule(String module) {
+		this.module = module;
+	}
+
+
+
+	public String getRegions() {
+		return regions;
+	}
+
+
+
+	public void setRegions(String regions) {
+		this.regions = regions;
+	}
+
+
+
+	public String getConfiguration() {
+		return configuration;
+	}
+
+
+
+	public void setConfiguration(String configuration) {
+		this.configuration = configuration;
+	}
+
+
+
+	public void setRegionsSet(Set<String> regionsSet) {
+		this.regionsSet = regionsSet;
+	}
+
+
+
+	public Set<String> getRegionsSet() {
+		return regionsSet;
+	}
+
+
+
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+
+
+	public String getCode() {
+		return code;
+	}
+
+
+
+	public void setModuleConfigs(Map<String,ModuleConfig> moduleConfigs) {
+		this.moduleConfigs = moduleConfigs;
+	}
+
+
+
+	public Map<String,ModuleConfig> getModuleConfigs() {
+		return moduleConfigs;
+	}
+
+
+
+	public void setImage(String image) {
+		this.image = image;
+	}
+
+
+
+	public String getImage() {
+		return image;
+	}
+
+
+
+	public void setCustomModule(boolean customModule) {
+		this.customModule = customModule;
+	}
+
+
+
+	public boolean isCustomModule() {
+		return customModule;
+	}
+
+	public String getConfigDetails() {
+		return configDetails;
+	}
+
+
+
+	public void setConfigDetails(String configDetails) {
+		this.configDetails = configDetails;
+	}
+
+
+
+	public void setType(String type) {
+		this.type = type;
+	}
+
+
+
+	public String getType() {
+		return type;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfig.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfig.java
new file mode 100644
index 0000000..ae5d8f6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfig.java
@@ -0,0 +1,110 @@
+package com.salesmanager.core.business.system.model;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+public class MerchantConfig implements Serializable, JSONAware {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private boolean displayCustomerSection =false;
+	private boolean displayContactUs =false;
+	private boolean displayStoreAddress = false;
+	private boolean displayAddToCartOnFeaturedItems = false;
+	
+	/** Store default search json config **/
+	private Map<String,Boolean> useDefaultSearchConfig= new HashMap<String,Boolean>();//language code | true or false
+	private Map<String,String> defaultSearchConfigPath= new HashMap<String,String>();//language code | file path
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		JSONObject data = new JSONObject();
+		data.put("displayCustomerSection", this.isDisplayCustomerSection());
+		data.put("displayContactUs", this.isDisplayContactUs());
+		data.put("displayStoreAddress", this.isDisplayStoreAddress());
+		data.put("displayAddToCartOnFeaturedItems", this.isDisplayAddToCartOnFeaturedItems());
+		
+		if(useDefaultSearchConfig!=null) {
+			JSONObject obj = new JSONObject();
+			for(String key : useDefaultSearchConfig.keySet()) {
+				Boolean val = (Boolean)useDefaultSearchConfig.get(key);
+				if(val!=null) {
+					obj.put(key,val);
+				}
+			}
+			data.put("useDefaultSearchConfig", obj);
+		}
+		
+		if(defaultSearchConfigPath!=null) {
+			JSONObject obj = new JSONObject();
+			for(String key : defaultSearchConfigPath.keySet()) {
+				String val = (String)defaultSearchConfigPath.get(key);
+				if(!StringUtils.isBlank(val)) {
+					obj.put(key, val);
+				}
+			}
+			data.put("defaultSearchConfigPath", obj);
+		}
+		
+		
+		return data.toJSONString();
+	}
+
+	public void setDisplayCustomerSection(boolean displayCustomerSection) {
+		this.displayCustomerSection = displayCustomerSection;
+	}
+
+	public boolean isDisplayCustomerSection() {
+		return displayCustomerSection;
+	}
+
+	public void setDisplayContactUs(boolean displayContactUs) {
+		this.displayContactUs = displayContactUs;
+	}
+
+	public boolean isDisplayContactUs() {
+		return displayContactUs;
+	}
+
+	public boolean isDisplayStoreAddress() {
+		return displayStoreAddress;
+	}
+
+	public void setDisplayStoreAddress(boolean displayStoreAddress) {
+		this.displayStoreAddress = displayStoreAddress;
+	}
+
+	public void setUseDefaultSearchConfig(Map<String,Boolean> useDefaultSearchConfig) {
+		this.useDefaultSearchConfig = useDefaultSearchConfig;
+	}
+
+	public Map<String,Boolean> getUseDefaultSearchConfig() {
+		return useDefaultSearchConfig;
+	}
+
+	public void setDefaultSearchConfigPath(Map<String,String> defaultSearchConfigPath) {
+		this.defaultSearchConfigPath = defaultSearchConfigPath;
+	}
+
+	public Map<String,String> getDefaultSearchConfigPath() {
+		return defaultSearchConfigPath;
+	}
+
+	public void setDisplayAddToCartOnFeaturedItems(
+			boolean displayAddToCartOnFeaturedItems) {
+		this.displayAddToCartOnFeaturedItems = displayAddToCartOnFeaturedItems;
+	}
+
+	public boolean isDisplayAddToCartOnFeaturedItems() {
+		return displayAddToCartOnFeaturedItems;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfiguration.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfiguration.java
new file mode 100755
index 0000000..6a9a5fc
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfiguration.java
@@ -0,0 +1,124 @@
+package com.salesmanager.core.business.system.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.UniqueConstraint;
+
+import org.hibernate.annotations.Type;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+/**
+ * Merchant configuration information
+ * @author Carl Samson
+ *
+ */
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "MERCHANT_CONFIGURATION", schema= SchemaConstant.SALESMANAGER_SCHEMA, uniqueConstraints=
+	@UniqueConstraint(columnNames = {"MERCHANT_ID", "CONFIG_KEY"}))
+public class MerchantConfiguration extends SalesManagerEntity<Long, MerchantConfiguration> implements Serializable, Auditable {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 4246917986731953459L;
+
+	@Id
+	@Column(name = "MERCHANT_CONFIG_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "MERCH_CONF_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=true)
+	private MerchantStore merchantStore;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@Column(name="CONFIG_KEY")
+	private String key;
+
+	
+	@Column(name="VALUE")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String value;
+	
+	@Column(name="TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private MerchantConfigurationType merchantConfigurationType = MerchantConfigurationType.INTEGRATION;
+
+	public void setKey(String key) {
+		this.key = key;
+	}
+
+	public String getKey() {
+		return key;
+	}
+
+	public void setValue(String value) {
+		this.value = value;
+	}
+
+	public String getValue() {
+		return value;
+	}
+
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public void setMerchantConfigurationType(MerchantConfigurationType merchantConfigurationType) {
+		this.merchantConfigurationType = merchantConfigurationType;
+	}
+
+	public MerchantConfigurationType getMerchantConfigurationType() {
+		return merchantConfigurationType;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfigurationType.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfigurationType.java
new file mode 100644
index 0000000..a496272
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantConfigurationType.java
@@ -0,0 +1,9 @@
+package com.salesmanager.core.business.system.model;
+
+public enum MerchantConfigurationType {
+	
+	INTEGRATION,
+	SHOP,
+	CONFIG
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantLog.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantLog.java
new file mode 100644
index 0000000..bcf1c15
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/MerchantLog.java
@@ -0,0 +1,106 @@
+package com.salesmanager.core.business.system.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import org.hibernate.annotations.Type;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "MERCHANT_LOG", schema= SchemaConstant.SALESMANAGER_SCHEMA)
+public class MerchantLog extends SalesManagerEntity<Long, MerchantLog> implements Serializable {
+
+	
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+
+	@Id
+	@Column(name = "MERCHANT_LOG_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "MOD_CONF_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore store;
+
+	@Column(name="MODULE", length=25, nullable=true)
+	private String module;
+	
+
+	@Column(name="LOG")
+	@Type(type = "org.hibernate.type.StringClobType")
+	private String log;
+	
+	public MerchantLog(MerchantStore store, String log) {
+		this.store = store;
+		this.log = log;
+	}
+	
+	public MerchantLog(MerchantStore store, String module, String log) {
+		this.store = store;
+		this.module = module;
+		this.log = log;
+	}
+
+
+	public Long getId() {
+		return id;
+	}
+
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+	public MerchantStore getStore() {
+		return store;
+	}
+
+
+	public void setStore(MerchantStore store) {
+		this.store = store;
+	}
+
+
+	public String getModule() {
+		return module;
+	}
+
+
+	public void setModule(String module) {
+		this.module = module;
+	}
+
+
+	public String getLog() {
+		return log;
+	}
+
+
+	public void setLog(String log) {
+		this.log = log;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/Module.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/Module.java
new file mode 100755
index 0000000..98c1bb0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/Module.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.system.model;
+
+public enum Module {
+	
+	PAYMENT, SHIPPING
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/ModuleConfig.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/ModuleConfig.java
new file mode 100755
index 0000000..138c721
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/ModuleConfig.java
@@ -0,0 +1,56 @@
+package com.salesmanager.core.business.system.model;
+
+public class ModuleConfig {
+
+	
+	private String scheme;
+	private String host;
+	private String port;
+	private String uri;
+	private String env;
+	private String config1;
+	private String config2;
+	public String getScheme() {
+		return scheme;
+	}
+	public void setScheme(String scheme) {
+		this.scheme = scheme;
+	}
+	public String getHost() {
+		return host;
+	}
+	public void setHost(String host) {
+		this.host = host;
+	}
+	public String getPort() {
+		return port;
+	}
+	public void setPort(String port) {
+		this.port = port;
+	}
+	public String getUri() {
+		return uri;
+	}
+	public void setUri(String uri) {
+		this.uri = uri;
+	}
+	public void setEnv(String env) {
+		this.env = env;
+	}
+	public String getEnv() {
+		return env;
+	}
+	public String getConfig1() {
+		return config1;
+	}
+	public void setConfig1(String config1) {
+		this.config1 = config1;
+	}
+	public String getConfig2() {
+		return config2;
+	}
+	public void setConfig2(String config2) {
+		this.config2 = config2;
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/SystemConfiguration.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/SystemConfiguration.java
new file mode 100644
index 0000000..c32b7e0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/SystemConfiguration.java
@@ -0,0 +1,80 @@
+package com.salesmanager.core.business.system.model;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+/**
+ * Global system configuration information
+ * @author casams1
+ *
+ */
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "SYSTEM_CONFIGURATION", schema= SchemaConstant.SALESMANAGER_SCHEMA)
+public class SystemConfiguration extends SalesManagerEntity<Long, SystemConfiguration> implements Serializable, Auditable {
+	private static final long serialVersionUID = 6831573162350751684L;
+	
+	@Id
+	@Column(name = "SYSTEM_CONFIG_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "SYST_CONF_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column(name="CONFIG_KEY")
+	private String key;
+	
+	@Column(name="VALUE")
+	private String value;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getKey() {
+		return key;
+	}
+
+	public void setKey(String key) {
+		this.key = key;
+	}
+
+	public String getValue() {
+		return value;
+	}
+
+	public void setValue(String value) {
+		this.value = value;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/model/SystemNotification.java b/sm-core/src/main/java/com/salesmanager/core/business/system/model/SystemNotification.java
new file mode 100755
index 0000000..b7f696e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/model/SystemNotification.java
@@ -0,0 +1,138 @@
+package com.salesmanager.core.business.system.model;
+
+import java.io.Serializable;
+import java.util.Date;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.user.model.User;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+
+@Table(name = "SYSTEM_NOTIFICATION", schema= SchemaConstant.SALESMANAGER_SCHEMA,uniqueConstraints=
+    @UniqueConstraint(columnNames = {"MERCHANT_ID", "CONFIG_KEY"}) )
+public class SystemNotification extends SalesManagerEntity<Long, SystemNotification> implements Serializable, Auditable {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = -6269172313628887000L;
+
+	@Id
+	@Column(name = "SYSTEM_NOTIF_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "SYST_NOTIF_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Column(name="CONFIG_KEY")
+	private String key;
+	
+	@Column(name="VALUE")
+	private String value;
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=true)
+	private MerchantStore merchantStore;
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="USER_ID", nullable=true)
+	private User user;
+	
+	@Temporal(TemporalType.DATE)
+	@Column(name = "START_DATE")
+	private Date startDate;
+	
+	@Temporal(TemporalType.DATE)
+	@Column(name = "END_DATE")
+	private Date endDate;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	@Override
+	public Long getId() {
+		return id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public String getKey() {
+		return key;
+	}
+
+	public void setKey(String key) {
+		this.key = key;
+	}
+
+	public String getValue() {
+		return value;
+	}
+
+	public void setValue(String value) {
+		this.value = value;
+	}
+
+	public void setStartDate(Date startDate) {
+		this.startDate = startDate;
+	}
+
+	public Date getStartDate() {
+		return startDate;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setEndDate(Date endDate) {
+		this.endDate = endDate;
+	}
+
+	public Date getEndDate() {
+		return endDate;
+	}
+
+	public void setUser(User user) {
+		this.user = user;
+	}
+
+	public User getUser() {
+		return user;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/EmailService.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/EmailService.java
new file mode 100644
index 0000000..632f54b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/EmailService.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.business.system.service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.modules.email.Email;
+import com.salesmanager.core.modules.email.EmailConfig;
+
+
+public interface EmailService {
+
+	public void sendHtmlEmail(MerchantStore store, Email email) throws ServiceException, Exception;
+	
+	public EmailConfig getEmailConfiguration(MerchantStore store) throws ServiceException;
+	
+	public void saveEmailConfiguration(EmailConfig emailConfig, MerchantStore store) throws ServiceException;
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/EmailServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/EmailServiceImpl.java
new file mode 100644
index 0000000..15ccb51
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/EmailServiceImpl.java
@@ -0,0 +1,66 @@
+package com.salesmanager.core.business.system.service;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.modules.email.Email;
+import com.salesmanager.core.modules.email.EmailConfig;
+import com.salesmanager.core.modules.email.HtmlEmailSender;
+
+@Service("emailService")
+public class EmailServiceImpl implements EmailService {
+
+	@Autowired
+	private MerchantConfigurationService merchantConfigurationService;
+	
+	@Autowired
+	private HtmlEmailSender sender;
+	
+	@Override
+	public void sendHtmlEmail(MerchantStore store, Email email) throws ServiceException, Exception {
+
+		EmailConfig emailConfig = getEmailConfiguration(store);
+		
+		sender.setEmailConfig(emailConfig);
+		sender.send(email);
+	}
+
+	@Override
+	public EmailConfig getEmailConfiguration(MerchantStore store) throws ServiceException {
+		
+		MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(Constants.EMAIL_CONFIG, store);
+		EmailConfig emailConfig = null;
+		if(configuration!=null) {
+			String value = configuration.getValue();
+			
+			ObjectMapper mapper = new ObjectMapper();
+			try {
+				emailConfig = mapper.readValue(value, EmailConfig.class);
+			} catch(Exception e) {
+				throw new ServiceException("Cannot parse json string " + value);
+			}
+		}
+		return emailConfig;
+	}
+	
+	
+	@Override
+	public void saveEmailConfiguration(EmailConfig emailConfig, MerchantStore store) throws ServiceException {
+		MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(Constants.EMAIL_CONFIG, store);
+		if(configuration==null) {
+			configuration = new MerchantConfiguration();
+			configuration.setMerchantStore(store);
+			configuration.setKey(Constants.EMAIL_CONFIG);
+		}
+		
+		String value = emailConfig.toJSONString();
+		configuration.setValue(value);
+		merchantConfigurationService.saveOrUpdate(configuration);
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantConfigurationService.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantConfigurationService.java
new file mode 100755
index 0000000..2147f58
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantConfigurationService.java
@@ -0,0 +1,31 @@
+package com.salesmanager.core.business.system.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.system.model.MerchantConfig;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.model.MerchantConfigurationType;
+
+public interface MerchantConfigurationService extends
+		SalesManagerEntityService<Long, MerchantConfiguration> {
+	
+	MerchantConfiguration getMerchantConfiguration(String key, MerchantStore store) throws ServiceException;
+	
+	public void saveOrUpdate(MerchantConfiguration entity) throws ServiceException;
+
+	List<MerchantConfiguration> listByStore(MerchantStore store)
+			throws ServiceException;
+
+	List<MerchantConfiguration> listByType(MerchantConfigurationType type,
+			MerchantStore store) throws ServiceException;
+
+	MerchantConfig getMerchantConfig(MerchantStore store)
+			throws ServiceException;
+
+	void saveMerchantConfig(MerchantConfig config, MerchantStore store)
+			throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantConfigurationServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantConfigurationServiceImpl.java
new file mode 100755
index 0000000..4673bc3
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantConfigurationServiceImpl.java
@@ -0,0 +1,116 @@
+package com.salesmanager.core.business.system.service;
+
+import java.util.List;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.system.dao.MerchantConfigurationDao;
+import com.salesmanager.core.business.system.model.MerchantConfig;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.model.MerchantConfigurationType;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.constants.ShippingConstants;
+
+@Service("merchantConfigurationService")
+public class MerchantConfigurationServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, MerchantConfiguration> implements
+		MerchantConfigurationService {
+
+	private MerchantConfigurationDao merchantConfigurationDao;
+	
+	@Autowired
+	public MerchantConfigurationServiceImpl(
+			MerchantConfigurationDao merchantConfigurationDao) {
+			super(merchantConfigurationDao);
+			this.merchantConfigurationDao = merchantConfigurationDao;
+	}
+	
+
+	@Override
+	public MerchantConfiguration getMerchantConfiguration(String key, MerchantStore store) throws ServiceException {
+		return merchantConfigurationDao.getMerchantConfiguration(key, store);
+	}
+	
+	@Override
+	public List<MerchantConfiguration> listByStore(MerchantStore store) throws ServiceException {
+		return merchantConfigurationDao.getMerchantConfigurations(store);
+	}
+	
+	@Override
+	public List<MerchantConfiguration> listByType(MerchantConfigurationType type, MerchantStore store) throws ServiceException {
+		return merchantConfigurationDao.listByType(type, store);
+	}
+	
+	@Override
+	public void saveOrUpdate(MerchantConfiguration entity) throws ServiceException {
+		
+
+		
+		if(entity.getId()!=null && entity.getId()>0) {
+			super.update(entity);
+		} else {
+			super.create(entity);
+
+		}
+	}
+	
+	
+	@Override
+	public void delete(MerchantConfiguration merchantConfiguration) throws ServiceException {
+		MerchantConfiguration config = merchantConfigurationDao.getById(merchantConfiguration.getId());
+		if(config!=null) {
+			super.delete(config);
+		}
+	}
+	
+	@Override
+	public MerchantConfig getMerchantConfig(MerchantStore store) throws ServiceException {
+
+		MerchantConfiguration configuration = merchantConfigurationDao.getMerchantConfiguration(Constants.MERCHANT_CONFIG, store);
+		
+		MerchantConfig config = null;
+		if(configuration!=null) {
+			String value = configuration.getValue();
+			
+			ObjectMapper mapper = new ObjectMapper();
+			try {
+				config = mapper.readValue(value, MerchantConfig.class);
+			} catch(Exception e) {
+				throw new ServiceException("Cannot parse json string " + value);
+			}
+		}
+		return config;
+		
+	}
+	
+	@Override
+	public void saveMerchantConfig(MerchantConfig config, MerchantStore store) throws ServiceException {
+		
+		MerchantConfiguration configuration = merchantConfigurationDao.getMerchantConfiguration(Constants.MERCHANT_CONFIG, store);
+
+		if(configuration==null) {
+			configuration = new MerchantConfiguration();
+			configuration.setMerchantStore(store);
+			configuration.setKey(Constants.MERCHANT_CONFIG);
+		}
+		
+		String value = config.toJSONString();
+		configuration.setValue(value);
+		if(configuration.getId()!=null && configuration.getId()>0) {
+			super.update(configuration);
+		} else {
+			super.create(configuration);
+
+		}
+		
+	}
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantLogService.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantLogService.java
new file mode 100644
index 0000000..5906d18
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantLogService.java
@@ -0,0 +1,12 @@
+package com.salesmanager.core.business.system.service;
+
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.system.model.MerchantLog;
+
+public interface MerchantLogService extends
+		SalesManagerEntityService<Long, MerchantLog> {
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantLogServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantLogServiceImpl.java
new file mode 100644
index 0000000..79738af
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/MerchantLogServiceImpl.java
@@ -0,0 +1,36 @@
+package com.salesmanager.core.business.system.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.system.dao.MerchantLogDao;
+import com.salesmanager.core.business.system.model.MerchantLog;
+
+@Service("merchantLogService")
+public class MerchantLogServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, MerchantLog> implements
+		MerchantLogService {
+	
+	@SuppressWarnings("unused")
+	private static final Logger LOGGER = LoggerFactory.getLogger(MerchantLogServiceImpl.class);
+
+
+	
+	private MerchantLogDao merchantLogDao;
+	
+	@Autowired
+	public MerchantLogServiceImpl(
+			MerchantLogDao merchantLogDao) {
+			super(merchantLogDao);
+			this.merchantLogDao = merchantLogDao;
+	}
+
+
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/ModuleConfigurationService.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/ModuleConfigurationService.java
new file mode 100755
index 0000000..1ba92b7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/ModuleConfigurationService.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.business.system.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+
+public interface ModuleConfigurationService extends
+		SalesManagerEntityService<Long, IntegrationModule> {
+
+	List<IntegrationModule> getIntegrationModules(String module);
+
+	IntegrationModule getByCode(String moduleCode);
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/ModuleConfigurationServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/ModuleConfigurationServiceImpl.java
new file mode 100755
index 0000000..f7b9522
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/ModuleConfigurationServiceImpl.java
@@ -0,0 +1,144 @@
+package com.salesmanager.core.business.system.service;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.json.simple.JSONArray;
+import org.json.simple.JSONValue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.system.dao.ModuleConfigurationDao;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.ModuleConfig;
+import com.salesmanager.core.utils.CacheUtils;
+
+@Service("moduleConfigurationService")
+public class ModuleConfigurationServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, IntegrationModule> implements
+		ModuleConfigurationService {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ModuleConfigurationServiceImpl.class);
+
+
+	
+	private ModuleConfigurationDao integrationModuleDao;
+	
+	@Autowired
+	private CacheUtils cache;
+	
+	@Autowired
+	public ModuleConfigurationServiceImpl(
+			ModuleConfigurationDao integrationModuleDao) {
+			super(integrationModuleDao);
+			this.integrationModuleDao = integrationModuleDao;
+	}
+	
+	@Override
+	public IntegrationModule getByCode(String moduleCode) {
+		return integrationModuleDao.getByCode(moduleCode);
+	}
+	
+	
+	@SuppressWarnings({ "unchecked", "rawtypes" })
+	@Override
+	public List<IntegrationModule> getIntegrationModules(String module) {
+		
+		
+		List<IntegrationModule> modules = null;
+		try {
+			
+			//CacheUtils cacheUtils = CacheUtils.getInstance();
+			modules = (List<IntegrationModule>) cache.getFromCache("INTEGRATION_M)" + module);
+			if(modules==null) {
+				modules = integrationModuleDao.getModulesConfiguration(module);
+				//set json objects
+				for(IntegrationModule mod : modules) {
+					
+					String regions = mod.getRegions();
+					if(regions!=null) {
+						Object objRegions=JSONValue.parse(regions); 
+						JSONArray arrayRegions=(JSONArray)objRegions;
+						Iterator i = arrayRegions.iterator();
+						while(i.hasNext()) {
+							mod.getRegionsSet().add((String)i.next());
+						}
+					}
+					
+					
+					String details = mod.getConfigDetails();
+					if(details!=null) {
+						
+						//Map objects = mapper.readValue(config, Map.class);
+
+						Map<String,String> objDetails= (Map<String, String>) JSONValue.parse(details); 
+						mod.setDetails(objDetails);
+
+						
+					}
+					
+					
+					String configs = mod.getConfiguration();
+					if(configs!=null) {
+						
+						//Map objects = mapper.readValue(config, Map.class);
+
+						Object objConfigs=JSONValue.parse(configs); 
+						JSONArray arrayConfigs=(JSONArray)objConfigs;
+						
+						Map<String,ModuleConfig> moduleConfigs = new HashMap<String,ModuleConfig>();
+						
+						Iterator i = arrayConfigs.iterator();
+						while(i.hasNext()) {
+							
+							Map values = (Map)i.next();
+							String env = (String)values.get("env");
+		            		ModuleConfig config = new ModuleConfig();
+		            		config.setScheme((String)values.get("scheme"));
+		            		config.setHost((String)values.get("host"));
+		            		config.setPort((String)values.get("port"));
+		            		config.setUri((String)values.get("uri"));
+		            		config.setEnv((String)values.get("env"));
+		            		if((String)values.get("config1")!=null) {
+		            			config.setConfig1((String)values.get("config1"));
+		            		}
+		            		if((String)values.get("config2")!=null) {
+		            			config.setConfig1((String)values.get("config2"));
+		            		}
+		            		
+		            		moduleConfigs.put(env, config);
+		            		
+		            		
+							
+						}
+						
+						mod.setModuleConfigs(moduleConfigs);
+						
+
+					}
+
+
+				}
+				cache.putInCache(modules, "INTEGRATION_M)" + module);
+			}
+
+		} catch (Exception e) {
+			LOGGER.error("getIntegrationModules()", e);
+		}
+		return modules;
+		
+		
+	}
+	
+	
+
+	
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/SystemConfigurationService.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/SystemConfigurationService.java
new file mode 100644
index 0000000..08d1d35
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/SystemConfigurationService.java
@@ -0,0 +1,12 @@
+package com.salesmanager.core.business.system.service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.system.model.SystemConfiguration;
+
+public interface SystemConfigurationService extends
+		SalesManagerEntityService<Long, SystemConfiguration> {
+	
+	SystemConfiguration getByKey(String key) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/system/service/SystemConfigurationServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/system/service/SystemConfigurationServiceImpl.java
new file mode 100644
index 0000000..03b295e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/system/service/SystemConfigurationServiceImpl.java
@@ -0,0 +1,34 @@
+package com.salesmanager.core.business.system.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.system.dao.SystemConfigurationDao;
+import com.salesmanager.core.business.system.model.SystemConfiguration;
+import com.salesmanager.core.business.system.model.SystemConfiguration_;
+
+@Service("systemConfigurationService")
+public class SystemConfigurationServiceImpl extends
+		SalesManagerEntityServiceImpl<Long, SystemConfiguration> implements
+		SystemConfigurationService {
+
+	
+	private SystemConfigurationDao systemConfigurationDao;
+	
+	@Autowired
+	public SystemConfigurationServiceImpl(
+			SystemConfigurationDao systemConfigurationDao) {
+			super(systemConfigurationDao);
+			this.systemConfigurationDao = systemConfigurationDao;
+	}
+	
+	public SystemConfiguration getByKey(String key) throws ServiceException {
+		return super.getByField(SystemConfiguration_.key, key);
+	}
+	
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxclass/TaxClassDao.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxclass/TaxClassDao.java
new file mode 100644
index 0000000..ba767ee
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxclass/TaxClassDao.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.business.tax.dao.taxclass;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+
+public interface TaxClassDao  extends SalesManagerEntityDao<Long, TaxClass> {
+
+	List<TaxClass> listByStore(MerchantStore store);
+
+	TaxClass getByCode(String code);
+
+	TaxClass getByCode(String code, MerchantStore store);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxclass/TaxClassDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxclass/TaxClassDaoImpl.java
new file mode 100644
index 0000000..2c5ca43
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxclass/TaxClassDaoImpl.java
@@ -0,0 +1,78 @@
+package com.salesmanager.core.business.tax.dao.taxclass;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.tax.model.taxclass.QTaxClass;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+
+@Repository("taxClassDao")
+public class TaxClassDaoImpl extends SalesManagerEntityDaoImpl<Long, TaxClass> implements TaxClassDao{
+	
+	public TaxClassDaoImpl() {
+		super();
+	}
+	
+	
+	@Override
+	public List<TaxClass> listByStore(MerchantStore store) {
+		QTaxClass qTax = QTaxClass.taxClass;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.where(qTax.merchantStore.id.eq(store.getId())
+			.or(qTax.merchantStore.isNull()));
+		
+		List<TaxClass> taxes = query.list(qTax);
+		return taxes;
+	}
+	
+	
+	@Override
+	public TaxClass getByCode(String code) {
+		QTaxClass qTax = QTaxClass.taxClass;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.where(qTax.code.eq(code));
+		
+		return query.uniqueResult(qTax);
+	}
+	
+	@Override
+	public TaxClass getByCode(String code, MerchantStore store) {
+		QTaxClass qTax = QTaxClass.taxClass;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.where(qTax.code.eq(code).and(qTax.merchantStore.id.eq(store.getId())));
+		
+		return query.uniqueResult(qTax);
+	}
+	
+	@Override
+	public TaxClass getById(Long id) {
+		QTaxClass qTax = QTaxClass.taxClass;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.where(qTax.id.eq(id));
+		
+		return query.uniqueResult(qTax);
+	}
+	
+	
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxrate/TaxRateDao.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxrate/TaxRateDao.java
new file mode 100644
index 0000000..01acc69
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxrate/TaxRateDao.java
@@ -0,0 +1,28 @@
+package com.salesmanager.core.business.tax.dao.taxrate;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRate;
+
+public interface TaxRateDao  extends SalesManagerEntityDao<Long, TaxRate> {
+
+	List<TaxRate> listByStore(MerchantStore store);
+
+	List<TaxRate> listByCountryZoneAndTaxClass(Country country, Zone zone,
+			TaxClass taxClass, MerchantStore store, Language language);
+
+	List<TaxRate> listByCountryStateProvinceAndTaxClass(Country country,
+			String stateProvince, TaxClass taxClass, MerchantStore store,
+			Language language);
+
+	TaxRate getByCode(String code, MerchantStore store);
+
+	List<TaxRate> listByStore(MerchantStore store, Language language);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxrate/TaxRateDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxrate/TaxRateDaoImpl.java
new file mode 100644
index 0000000..2520eff
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/dao/taxrate/TaxRateDaoImpl.java
@@ -0,0 +1,185 @@
+package com.salesmanager.core.business.tax.dao.taxrate;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.business.tax.model.taxrate.QTaxRate;
+import com.salesmanager.core.business.tax.model.taxrate.QTaxRateDescription;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRate;
+
+@Repository("taxRateDao")
+public class TaxRateDaoImpl extends SalesManagerEntityDaoImpl<Long, TaxRate> implements TaxRateDao{
+	
+	public TaxRateDaoImpl() {
+		super();
+	}
+	
+	@Override
+	public List<TaxRate> listByStore(MerchantStore store) {
+		
+		
+		QTaxRate qTax = QTaxRate.taxRate1;
+		QTaxRateDescription qTaxDescription = QTaxRateDescription.taxRateDescription;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.leftJoin(qTax.descriptions,qTaxDescription).fetch()
+			.join(qTax.country).fetch()
+			.leftJoin(qTax.zone).fetch()
+			.leftJoin(qTax.parent).fetch()
+			.where(qTax.merchantStore.id.eq(store.getId())
+			).orderBy(qTax.taxPriority.asc());
+		
+		List<TaxRate> taxes = query.list(qTax);
+		return taxes;
+		
+		
+		
+	}
+	
+	@Override
+	public List<TaxRate> listByStore(MerchantStore store, Language language) {
+		
+		
+		QTaxRate qTax = QTaxRate.taxRate1;
+		QTaxRateDescription qTaxDescription = QTaxRateDescription.taxRateDescription;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.leftJoin(qTax.descriptions,qTaxDescription).fetch()
+			.join(qTax.country).fetch()
+			.leftJoin(qTax.zone).fetch()
+			.leftJoin(qTax.parent).fetch()
+			.where(qTax.merchantStore.id.eq(store.getId())
+			.and(qTaxDescription.language.id.eq(language.getId())))
+			.orderBy(qTax.taxPriority.asc());
+		
+		List<TaxRate> taxes = query.list(qTax);
+		return taxes;
+		
+		
+		
+	}
+	
+	@Override
+	public TaxRate getByCode(String code, MerchantStore store) {
+		
+		
+		QTaxRate qTax = QTaxRate.taxRate1;
+		QTaxRateDescription qTaxDescription = QTaxRateDescription.taxRateDescription;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.leftJoin(qTax.descriptions,qTaxDescription).fetch()
+			.join(qTax.country).fetch()
+			.leftJoin(qTax.zone).fetch()
+			.leftJoin(qTax.parent).fetch()
+			.where(qTax.merchantStore.id.eq(store.getId())
+			.and(qTax.code.eq(code))		
+			).orderBy(qTax.taxPriority.asc());
+		
+		TaxRate tax = query.uniqueResult(qTax);
+		return tax;
+		
+		
+		
+	}
+	
+	@Override
+	public TaxRate getById(Long id) {
+		
+		
+		QTaxRate qTax = QTaxRate.taxRate1;
+		QTaxRateDescription qTaxDescription = QTaxRateDescription.taxRateDescription;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.leftJoin(qTax.descriptions,qTaxDescription).fetch()
+			.join(qTax.country).fetch()
+			.leftJoin(qTax.zone).fetch()
+			.leftJoin(qTax.parent).fetch()
+			.where(qTax.id.eq(id)
+			).orderBy(qTax.taxPriority.asc());
+		
+		TaxRate tax = query.uniqueResult(qTax);
+		return tax;
+		
+		
+		
+	}
+	
+	@Override
+	public List<TaxRate> listByCountryZoneAndTaxClass(Country country, Zone zone, TaxClass taxClass, MerchantStore store, Language language) {
+		
+		
+		QTaxRate qTax = QTaxRate.taxRate1;
+		QTaxRateDescription qTaxDescription = QTaxRateDescription.taxRateDescription;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.leftJoin(qTax.descriptions,qTaxDescription).fetch()
+			.join(qTax.country).fetch()
+			.leftJoin(qTax.zone).fetch()
+			.leftJoin(qTax.parent).fetch()
+			.where(qTax.merchantStore.id.eq(store.getId())
+			.and(
+					qTax.isNotNull().and(qTax.zone.id.eq(zone.getId())).or(qTax.isNull())
+			)
+			.and(qTax.country.id.eq(country.getId())
+			.and(qTaxDescription.language.id.eq(language.getId())))
+			).orderBy(qTax.taxPriority.asc());
+		
+		List<TaxRate> taxes = query.list(qTax);
+		return taxes;
+
+	}
+	
+	
+	@Override
+	public List<TaxRate> listByCountryStateProvinceAndTaxClass(Country country, String stateProvince, TaxClass taxClass, MerchantStore store, Language language) {
+		
+		
+		QTaxRate qTax = QTaxRate.taxRate1;
+		QTaxRateDescription qTaxDescription = QTaxRateDescription.taxRateDescription;
+
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qTax)
+			.leftJoin(qTax.merchantStore).fetch()
+			.leftJoin(qTax.descriptions,qTaxDescription).fetch()
+			.join(qTax.country).fetch()
+			.leftJoin(qTax.parent).fetch()
+			.where(qTax.merchantStore.id.eq(store.getId())
+			.and(
+					qTax.stateProvince.eq(stateProvince)
+			)
+			.and(qTax.country.id.eq(country.getId())
+			.and(qTaxDescription.language.id.eq(language.getId())))
+			).orderBy(qTax.taxPriority.asc());
+		
+		List<TaxRate> taxes = query.list(qTax);
+		return taxes;
+
+	}
+	
+	
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxBasisCalculation.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxBasisCalculation.java
new file mode 100644
index 0000000..ecbd64c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxBasisCalculation.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.tax.model;
+
+public enum TaxBasisCalculation {
+	
+	STOREADDRESS, SHIPPINGADDRESS, BILLINGADDRESS
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxclass/TaxClass.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxclass/TaxClass.java
new file mode 100644
index 0000000..5b24f3a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxclass/TaxClass.java
@@ -0,0 +1,123 @@
+package com.salesmanager.core.business.tax.model.taxclass;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.UniqueConstraint;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRate;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@Table(name = "TAX_CLASS", schema = SchemaConstant.SALESMANAGER_SCHEMA,uniqueConstraints=
+    @UniqueConstraint(columnNames = {"MERCHANT_ID", "TAX_CLASS_CODE"}) )
+public class TaxClass extends SalesManagerEntity<Long, TaxClass> {
+	private static final long serialVersionUID = -325750148480212355L;
+	
+	public final static String DEFAULT_TAX_CLASS = "DEFAULT";
+	
+	public TaxClass(String code) {
+		this.code = code;
+		this.title = code;
+	}
+	
+	@Id
+	@Column(name = "TAX_CLASS_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "TX_CLASS_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@NotEmpty
+	@Column(name="TAX_CLASS_CODE", nullable=false, length=10)
+	private String code;
+	
+	@NotEmpty
+	@Column(name = "TAX_CLASS_TITLE" , nullable=false , length=32 )
+	private String title;
+	
+
+
+	@OneToMany(mappedBy = "taxClass", targetEntity = Product.class)
+	private List<Product> products = new ArrayList<Product>();
+	
+
+/*	@ManyToMany(fetch=FetchType.LAZY, cascade = CascadeType.ALL)
+	@JoinTable(name = "MERCHANT_TAXCLASS", schema=SchemaConstant.SALESMANAGER_SCHEMA, joinColumns = { 
+			@JoinColumn(name = "TAX_CLASS_ID", nullable = false) }, 
+			inverseJoinColumns = { @JoinColumn(name = "MERCHANT_ID", 
+					nullable = false) })
+	private Set<MerchantStore> stores = new HashSet<MerchantStore>();*/
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=true)
+	private MerchantStore merchantStore;
+
+	
+	@OneToMany(mappedBy = "taxClass")
+	private List<TaxRate> taxRates = new ArrayList<TaxRate>();
+	
+	public TaxClass() {
+		super();
+	}
+	
+	@Override
+	public Long getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+
+	public String getTitle() {
+		return title;
+	}
+
+	public void setTitle(String title) {
+		this.title = title;
+	}
+
+	public String getCode() {
+		return code;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public List<TaxRate> getTaxRates() {
+		return taxRates;
+	}
+
+	public void setTaxRates(List<TaxRate> taxRates) {
+		this.taxRates = taxRates;
+	}
+
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxConfiguration.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxConfiguration.java
new file mode 100644
index 0000000..6fd726e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxConfiguration.java
@@ -0,0 +1,53 @@
+package com.salesmanager.core.business.tax.model;
+
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+/**
+ * Set of various tax configuration settings saved in MerchantConfiguration
+ * @author carl samson
+ *
+ */
+public class TaxConfiguration implements JSONAware {
+	
+	private TaxBasisCalculation taxBasisCalculation = TaxBasisCalculation.SHIPPINGADDRESS;
+	
+	private boolean collectTaxIfDifferentProvinceOfStoreCountry = true;
+	private boolean collectTaxIfDifferentCountryOfStoreCountry = false;
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		JSONObject data = new JSONObject();
+		data.put("taxBasisCalculation", this.getTaxBasisCalculation().name());
+		
+		return data.toJSONString();
+	}
+
+	public void setTaxBasisCalculation(TaxBasisCalculation taxBasisCalculation) {
+		this.taxBasisCalculation = taxBasisCalculation;
+	}
+
+	public TaxBasisCalculation getTaxBasisCalculation() {
+		return taxBasisCalculation;
+	}
+
+	public void setCollectTaxIfDifferentProvinceOfStoreCountry(
+			boolean collectTaxIfDifferentProvinceOfStoreCountry) {
+		this.collectTaxIfDifferentProvinceOfStoreCountry = collectTaxIfDifferentProvinceOfStoreCountry;
+	}
+
+	public boolean isCollectTaxIfDifferentProvinceOfStoreCountry() {
+		return collectTaxIfDifferentProvinceOfStoreCountry;
+	}
+
+	public void setCollectTaxIfDifferentCountryOfStoreCountry(
+			boolean collectTaxIfDifferentCountryOfStoreCountry) {
+		this.collectTaxIfDifferentCountryOfStoreCountry = collectTaxIfDifferentCountryOfStoreCountry;
+	}
+
+	public boolean isCollectTaxIfDifferentCountryOfStoreCountry() {
+		return collectTaxIfDifferentCountryOfStoreCountry;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxItem.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxItem.java
new file mode 100644
index 0000000..61440b9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/TaxItem.java
@@ -0,0 +1,32 @@
+package com.salesmanager.core.business.tax.model;
+
+import com.salesmanager.core.business.common.model.OrderTotalItem;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRate;
+
+public class TaxItem extends OrderTotalItem {
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	private String label;
+	private TaxRate taxRate=null;
+
+	public void setLabel(String label) {
+		this.label = label;
+	}
+
+	public String getLabel() {
+		return label;
+	}
+
+	public void setTaxRate(TaxRate taxRate) {
+		this.taxRate = taxRate;
+	}
+
+	public TaxRate getTaxRate() {
+		return taxRate;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxrate/TaxRate.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxrate/TaxRate.java
new file mode 100644
index 0000000..e08e5b2
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxrate/TaxRate.java
@@ -0,0 +1,252 @@
+/*
+ * 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.business.tax.model.taxrate;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Transient;
+import javax.persistence.UniqueConstraint;
+import javax.validation.Valid;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "TAX_RATE" , schema = SchemaConstant.SALESMANAGER_SCHEMA,uniqueConstraints={
+		@UniqueConstraint(columnNames={
+				"TAX_CODE",
+				"MERCHANT_ID"
+			})
+		}
+	)
+public class TaxRate  extends SalesManagerEntity<Long, TaxRate> implements Auditable {
+	private static final long serialVersionUID = 3356827741612925066L;
+	
+	@Id
+	@Column(name = "TAX_RATE_ID")
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "TAX_RATE_ID_NEXT_VALUE")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@Column(name = "TAX_PRIORITY")
+	private Integer taxPriority = 0;
+	
+	@Column(name = "TAX_RATE" , nullable= false , precision=7, scale=4)
+	private BigDecimal taxRate;
+	
+	@NotEmpty
+	@Column(name = "TAX_CODE")
+	private String code;
+	
+
+	@Column(name = "PIGGYBACK")
+	private boolean piggyback;
+	
+	@ManyToOne
+	@JoinColumn(name = "TAX_CLASS_ID" , nullable=false)
+	private TaxClass taxClass;
+	
+
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	@Valid
+	@OneToMany(mappedBy = "taxRate", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
+	private List<TaxRateDescription> descriptions = new ArrayList<TaxRateDescription>();
+	
+	@ManyToOne(fetch = FetchType.LAZY, targetEntity = Country.class)
+	@JoinColumn(name="COUNTRY_ID", nullable=false, updatable=true)
+	private Country country;
+
+	@OneToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="ZONE_ID", nullable=true, updatable=true)
+	private Zone zone;
+
+	@Column(name = "STORE_STATE_PROV", length=100)
+	private String stateProvince;
+	
+	@ManyToOne
+	@JoinColumn(name = "PARENT_ID")
+	private TaxRate parent;
+	
+	@OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE, orphanRemoval = true)
+	private List<TaxRate> taxRates = new ArrayList<TaxRate>();
+	
+	@Transient
+	private String rateText;
+	
+	
+	public String getRateText() {
+		return rateText;
+	}
+
+	public void setRateText(String rateText) {
+		this.rateText = rateText;
+	}
+
+	public TaxRate() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+	
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+	
+	@Override
+	public void setAuditSection(AuditSection auditSection) {
+		this.auditSection = auditSection;
+	}
+
+	public Integer getTaxPriority() {
+		return taxPriority;
+	}
+
+	public void setTaxPriority(Integer taxPriority) {
+		this.taxPriority = taxPriority;
+	}
+
+	public BigDecimal getTaxRate() {
+		return taxRate;
+	}
+
+	public void setTaxRate(BigDecimal taxRate) {
+		this.taxRate = taxRate;
+	}
+
+	public boolean isPiggyback() {
+		return piggyback;
+	}
+
+	public void setPiggyback(boolean piggyback) {
+		this.piggyback = piggyback;
+	}
+
+	public TaxClass getTaxClass() {
+		return taxClass;
+	}
+
+	public void setTaxClass(TaxClass taxClass) {
+		this.taxClass = taxClass;
+	}
+
+
+
+	public List<TaxRateDescription> getDescriptions() {
+		return descriptions;
+	}
+
+	public void setDescriptions(List<TaxRateDescription> descriptions) {
+		this.descriptions = descriptions;
+	}
+
+
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public void setCountry(Country country) {
+		this.country = country;
+	}
+
+	public Country getCountry() {
+		return country;
+	}
+
+	public void setZone(Zone zone) {
+		this.zone = zone;
+	}
+
+	public Zone getZone() {
+		return zone;
+	}
+
+
+	public void setTaxRates(List<TaxRate> taxRates) {
+		this.taxRates = taxRates;
+	}
+
+	public List<TaxRate> getTaxRates() {
+		return taxRates;
+	}
+
+	public void setParent(TaxRate parent) {
+		this.parent = parent;
+	}
+
+	public TaxRate getParent() {
+		return parent;
+	}
+
+	public void setStateProvince(String stateProvince) {
+		this.stateProvince = stateProvince;
+	}
+
+	public String getStateProvince() {
+		return stateProvince;
+	}
+
+	public void setCode(String code) {
+		this.code = code;
+	}
+
+	public String getCode() {
+		return code;
+	}
+}
\ No newline at end of file
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxrate/TaxRateDescription.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxrate/TaxRateDescription.java
new file mode 100644
index 0000000..6265fca
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/model/taxrate/TaxRateDescription.java
@@ -0,0 +1,52 @@
+/*
+ * 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.business.tax.model.taxrate;
+
+import javax.persistence.Entity;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.UniqueConstraint;
+
+import com.salesmanager.core.business.common.model.Description;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@Table(name = "TAX_RATE_DESCRIPTION" , schema=SchemaConstant.SALESMANAGER_SCHEMA ,uniqueConstraints={
+		@UniqueConstraint(columnNames={
+				"TAX_RATE_ID",
+				"LANGUAGE_ID"
+			})
+		}
+	)
+public class TaxRateDescription extends Description {
+	private static final long serialVersionUID = -4752794805878361822L;
+
+	@ManyToOne(targetEntity = TaxRate.class)
+	@JoinColumn(name = "TAX_RATE_ID")
+	private TaxRate taxRate;
+	
+	public TaxRateDescription() {
+	}
+
+	public TaxRate getTaxRate() {
+		return taxRate;
+	}
+
+	public void setTaxRate(TaxRate taxRate) {
+		this.taxRate = taxRate;
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxClassService.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxClassService.java
new file mode 100644
index 0000000..988e347
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxClassService.java
@@ -0,0 +1,19 @@
+package com.salesmanager.core.business.tax.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+
+public interface TaxClassService extends SalesManagerEntityService<Long, TaxClass> {
+
+	public List<TaxClass> listByStore(MerchantStore store) throws ServiceException;
+
+	TaxClass getByCode(String code) throws ServiceException;
+
+	TaxClass getByCode(String code, MerchantStore store)
+			throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxClassServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxClassServiceImpl.java
new file mode 100644
index 0000000..7505048
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxClassServiceImpl.java
@@ -0,0 +1,56 @@
+package com.salesmanager.core.business.tax.service;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.tax.dao.taxclass.TaxClassDao;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+
+@Service("taxClassService")
+public class TaxClassServiceImpl extends SalesManagerEntityServiceImpl<Long, TaxClass>
+		implements TaxClassService {
+
+	private TaxClassDao taxClassDao;
+	
+	@Autowired
+	public TaxClassServiceImpl(TaxClassDao taxClassDao) {
+		super(taxClassDao);
+		
+		this.taxClassDao = taxClassDao;
+	}
+	
+	@Override
+	public List<TaxClass> listByStore(MerchantStore store) throws ServiceException {	
+		return taxClassDao.listByStore(store);
+	}
+	
+	@Override
+	public TaxClass getByCode(String code) throws ServiceException {
+		return taxClassDao.getByCode(code);
+	}
+	
+	@Override
+	public TaxClass getByCode(String code, MerchantStore store) throws ServiceException {
+		return taxClassDao.getByCode(code, store);
+	}
+	
+	@Override
+	public void delete(TaxClass taxClass) throws ServiceException {
+		
+		TaxClass t = this.getById(taxClass.getId());
+		super.delete(t);
+		
+	}
+	
+	@Override
+	public TaxClass getById(Long id) {
+		return taxClassDao.getById(id);
+	}
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxRateService.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxRateService.java
new file mode 100644
index 0000000..db7e9af
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxRateService.java
@@ -0,0 +1,34 @@
+package com.salesmanager.core.business.tax.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRate;
+
+public interface TaxRateService extends SalesManagerEntityService<Long, TaxRate> {
+
+	public List<TaxRate> listByStore(MerchantStore store) throws ServiceException;
+
+	List<TaxRate> listByCountryZoneAndTaxClass(Country country, Zone zone,
+			TaxClass taxClass, MerchantStore store, Language language)
+			throws ServiceException;
+
+	List<TaxRate> listByCountryStateProvinceAndTaxClass(Country country,
+			String stateProvince, TaxClass taxClass, MerchantStore store,
+			Language language) throws ServiceException;
+
+	 TaxRate getByCode(String code, MerchantStore store)
+			throws ServiceException;
+
+	List<TaxRate> listByStore(MerchantStore store, Language language)
+			throws ServiceException;
+	
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxRateServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxRateServiceImpl.java
new file mode 100644
index 0000000..be56d0b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxRateServiceImpl.java
@@ -0,0 +1,70 @@
+package com.salesmanager.core.business.tax.service;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.tax.dao.taxrate.TaxRateDao;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRate;
+
+@Service("taxRateService")
+public class TaxRateServiceImpl extends SalesManagerEntityServiceImpl<Long, TaxRate>
+		implements TaxRateService {
+
+	private TaxRateDao taxRateDao;
+	
+	@Autowired
+	public TaxRateServiceImpl(TaxRateDao taxRateDao) {
+		super(taxRateDao);
+		
+		this.taxRateDao = taxRateDao;
+	}
+
+	@Override
+	public List<TaxRate> listByStore(MerchantStore store)
+			throws ServiceException {
+		return taxRateDao.listByStore(store);
+	}
+	
+	@Override
+	public List<TaxRate> listByStore(MerchantStore store, Language language)
+			throws ServiceException {
+		return taxRateDao.listByStore(store, language);
+	}
+	
+	
+	@Override
+	public TaxRate getByCode(String code, MerchantStore store)
+			throws ServiceException {
+		return taxRateDao.getByCode(code,store);
+	}
+	
+	@Override
+	public List<TaxRate> listByCountryZoneAndTaxClass(Country country, Zone zone, TaxClass taxClass, MerchantStore store, Language language) throws ServiceException {
+		return taxRateDao.listByCountryZoneAndTaxClass(country, zone, taxClass, store, language);
+	}
+	
+	@Override
+	public List<TaxRate> listByCountryStateProvinceAndTaxClass(Country country, String stateProvince, TaxClass taxClass, MerchantStore store, Language language) throws ServiceException {
+		return taxRateDao.listByCountryStateProvinceAndTaxClass(country, stateProvince, taxClass, store, language);
+	}
+	
+	@Override
+	public void delete(TaxRate taxRate) throws ServiceException {
+		
+		TaxRate t = this.getById(taxRate.getId());
+		super.delete(t);
+		
+	}
+		
+
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxService.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxService.java
new file mode 100644
index 0000000..15d3ca3
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxService.java
@@ -0,0 +1,48 @@
+package com.salesmanager.core.business.tax.service;
+
+import java.util.List;
+import java.util.Locale;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.OrderSummary;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.tax.model.TaxConfiguration;
+import com.salesmanager.core.business.tax.model.TaxItem;
+
+
+public interface TaxService   {
+
+	/**
+	 * Retrieves tax configurations (TaxConfiguration) for a given MerchantStore
+	 * @param store
+	 * @return
+	 * @throws ServiceException
+	 */
+	TaxConfiguration getTaxConfiguration(MerchantStore store)
+			throws ServiceException;
+
+	/**
+	 * Saves ShippingConfiguration to MerchantConfiguration table
+	 * @param shippingConfiguration
+	 * @param store
+	 * @throws ServiceException
+	 */
+	void saveTaxConfiguration(TaxConfiguration shippingConfiguration,
+			MerchantStore store) throws ServiceException;
+
+	/**
+	 * Calculates tax over an OrderSummary
+	 * @param orderSummary
+	 * @param customer
+	 * @param store
+	 * @param locale
+	 * @return
+	 * @throws ServiceException
+	 */
+	List<TaxItem> calculateTax(OrderSummary orderSummary, Customer customer,
+			MerchantStore store, Language language) throws ServiceException;
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxServiceImpl.java
new file mode 100644
index 0000000..1671534
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/tax/service/TaxServiceImpl.java
@@ -0,0 +1,305 @@
+package com.salesmanager.core.business.tax.service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+import org.apache.commons.lang3.StringUtils;
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.common.model.Billing;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.OrderSummary;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.shipping.model.ShippingSummary;
+import com.salesmanager.core.business.shipping.service.ShippingService;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.service.MerchantConfigurationService;
+import com.salesmanager.core.business.tax.model.TaxBasisCalculation;
+import com.salesmanager.core.business.tax.model.TaxConfiguration;
+import com.salesmanager.core.business.tax.model.TaxItem;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRate;
+
+@Service("taxService")
+public class TaxServiceImpl 
+		implements TaxService {
+	
+	private final static String TAX_CONFIGURATION = "TAX_CONFIG";
+	private final static String DEFAULT_TAX_CLASS = "DEFAULT";
+	
+	@Autowired
+	private MerchantConfigurationService merchantConfigurationService;
+	
+	@Autowired
+	private TaxRateService taxRateService;
+	
+	@Autowired
+	private LanguageService languageService;
+	
+	@Autowired
+	private ShippingService shippingService;
+	
+	@Autowired
+	private TaxClassService taxClassService;
+	
+	@Override
+	public TaxConfiguration getTaxConfiguration(MerchantStore store) throws ServiceException {
+		
+		
+		
+		MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(TAX_CONFIGURATION, store);
+		TaxConfiguration taxConfiguration = null;
+		if(configuration!=null) {
+			String value = configuration.getValue();
+			
+			ObjectMapper mapper = new ObjectMapper();
+			try {
+				taxConfiguration = mapper.readValue(value, TaxConfiguration.class);
+			} catch(Exception e) {
+				throw new ServiceException("Cannot parse json string " + value);
+			}
+		}
+		return taxConfiguration;
+	}
+	
+	
+	@Override
+	public void saveTaxConfiguration(TaxConfiguration shippingConfiguration, MerchantStore store) throws ServiceException {
+		
+		MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(TAX_CONFIGURATION, store);
+
+		if(configuration==null) {
+			configuration = new MerchantConfiguration();
+			configuration.setMerchantStore(store);
+			configuration.setKey(TAX_CONFIGURATION);
+		}
+		
+		String value = shippingConfiguration.toJSONString();
+		configuration.setValue(value);
+		merchantConfigurationService.saveOrUpdate(configuration);
+		
+	}
+	
+	@Override
+	public List<TaxItem> calculateTax(OrderSummary orderSummary, Customer customer, MerchantStore store, Language language) throws ServiceException {
+		
+
+		if(customer==null) {
+			return null;
+		}
+
+		List<ShoppingCartItem> items = orderSummary.getProducts();
+		
+		List<TaxItem> taxLines = new ArrayList<TaxItem>();
+		
+		if(items==null) {
+			return taxLines;
+		}
+		
+		//determine tax calculation basis
+		TaxConfiguration taxConfiguration = this.getTaxConfiguration(store);
+		if(taxConfiguration==null) {
+			taxConfiguration = new TaxConfiguration();
+			taxConfiguration.setTaxBasisCalculation(TaxBasisCalculation.SHIPPINGADDRESS);
+		}
+		
+		Country country = customer.getBilling().getCountry();
+		Zone zone = customer.getBilling().getZone();
+		String stateProvince = customer.getBilling().getState();
+		
+		TaxBasisCalculation taxBasisCalculation = taxConfiguration.getTaxBasisCalculation();
+		if(taxBasisCalculation.name().equals(TaxBasisCalculation.SHIPPINGADDRESS)){
+			Delivery shipping = customer.getDelivery();
+			if(shipping!=null) {
+				country = shipping.getCountry();
+				zone = shipping.getZone();
+				stateProvince = shipping.getState();
+			}
+		} else if(taxBasisCalculation.name().equals(TaxBasisCalculation.BILLINGADDRESS)){
+			Billing billing = customer.getBilling();
+			if(billing!=null) {
+				country = billing.getCountry();
+				zone = billing.getZone();
+				stateProvince = billing.getState();
+			}
+		} else if(taxBasisCalculation.name().equals(TaxBasisCalculation.STOREADDRESS)){
+			country = store.getCountry();
+			zone = store.getZone();
+			stateProvince = store.getStorestateprovince();
+		}
+		
+		//check other conditions
+		//do not collect tax on other provinces of same country
+		if(!taxConfiguration.isCollectTaxIfDifferentProvinceOfStoreCountry()) {
+			if((zone!=null && store.getZone()!=null) && (zone.getId().longValue() != store.getZone().getId().longValue())) {
+				return null;
+			}
+			if(!StringUtils.isBlank(stateProvince)) {
+				if(store.getZone()!=null) {
+					if(!store.getZone().getName().equals(stateProvince)) {
+						return null;
+					}
+				}
+				else if(!StringUtils.isBlank(store.getStorestateprovince())) {
+
+					if(!store.getStorestateprovince().equals(stateProvince)) {
+						return null;
+					}
+				}
+			}
+		}
+		
+		//collect tax in different countries
+		if(taxConfiguration.isCollectTaxIfDifferentCountryOfStoreCountry()) {
+			//use store country
+			country = store.getCountry();
+			zone = store.getZone();
+			stateProvince = store.getStorestateprovince();
+		}
+		
+		Map<Long,TaxClass> taxClasses =  new HashMap<Long,TaxClass>();
+			
+		//put items in a map by tax class id
+		Map<Long,BigDecimal> taxClassAmountMap = new HashMap<Long,BigDecimal>();
+		for(ShoppingCartItem item : items) {
+				
+				BigDecimal itemPrice = item.getItemPrice();
+				TaxClass taxClass = item.getProduct().getTaxClass();
+				int quantity = item.getQuantity();
+				itemPrice = itemPrice.multiply(new BigDecimal(quantity));
+				if(taxClass==null) {
+					taxClass = taxClassService.getByCode(DEFAULT_TAX_CLASS);
+				}
+				BigDecimal subTotal = taxClassAmountMap.get(taxClass.getId());
+				if(subTotal==null) {
+					subTotal = new BigDecimal(0);
+					subTotal.setScale(2, RoundingMode.HALF_UP);
+				}
+					
+				subTotal = subTotal.add(itemPrice);
+				taxClassAmountMap.put(taxClass.getId(), subTotal);
+				taxClasses.put(taxClass.getId(), taxClass);
+				
+		}
+		
+		//tax on shipping ?
+		//ShippingConfiguration shippingConfiguration = shippingService.getShippingConfiguration(store);	
+		
+		/** always calculate tax on shipping **/
+		//if(shippingConfiguration!=null) {
+			//if(shippingConfiguration.isTaxOnShipping()){
+				//use default tax class for shipping
+				TaxClass defaultTaxClass = taxClassService.getByCode(TaxClass.DEFAULT_TAX_CLASS);
+				//taxClasses.put(defaultTaxClass.getId(), defaultTaxClass);
+				BigDecimal amnt = taxClassAmountMap.get(defaultTaxClass.getId());
+				if(amnt==null) {
+					amnt = new BigDecimal(0);
+					amnt.setScale(2, RoundingMode.HALF_UP);
+				}
+				ShippingSummary shippingSummary = orderSummary.getShippingSummary();
+				if(shippingSummary!=null && shippingSummary.getShipping()!=null && shippingSummary.getShipping().doubleValue()>0) {
+					amnt = amnt.add(shippingSummary.getShipping());
+					if(shippingSummary.getHandling()!=null && shippingSummary.getHandling().doubleValue()>0) {
+						amnt = amnt.add(shippingSummary.getHandling());
+					}
+				}
+				taxClassAmountMap.put(defaultTaxClass.getId(), amnt);
+			//}
+		//}
+		
+		
+		List<TaxItem> taxItems = new ArrayList<TaxItem>();
+		
+		//iterate through the tax class and get appropriate rates
+		for(Long taxClassId : taxClassAmountMap.keySet()) {
+			
+			//get taxRate by tax class
+			List<TaxRate> taxRates = null; 
+			if(!StringUtils.isBlank(stateProvince)&& zone==null) {
+				taxRates = taxRateService.listByCountryStateProvinceAndTaxClass(country, stateProvince, taxClasses.get(taxClassId), store, language);
+			} else {
+				taxRates = taxRateService.listByCountryZoneAndTaxClass(country, zone, taxClasses.get(taxClassId), store, language);
+			}
+			
+			if(taxRates==null || taxRates.size()==0){
+				continue;
+			}
+			BigDecimal taxedItemValue = null;
+			BigDecimal totalTaxedItemValue = new BigDecimal(0);
+			totalTaxedItemValue.setScale(2, RoundingMode.HALF_UP);
+			BigDecimal beforeTaxeAmount = taxClassAmountMap.get(taxClassId);
+			for(TaxRate taxRate : taxRates) {
+				
+				double taxRateDouble = taxRate.getTaxRate().doubleValue();//5% ... 8% ...
+				
+
+				if(taxRate.isPiggyback()) {//(compound)
+					if(totalTaxedItemValue.doubleValue()>0) {
+						beforeTaxeAmount = totalTaxedItemValue;
+					}
+				} //else just use nominal taxing (combine)
+				
+				double value  = (beforeTaxeAmount.doubleValue() * taxRateDouble)/100;
+				double roundedValue = new BigDecimal(value).setScale(2, RoundingMode.HALF_UP).doubleValue();
+				taxedItemValue = new BigDecimal(roundedValue).setScale(2, RoundingMode.HALF_UP);
+				totalTaxedItemValue = beforeTaxeAmount.add(taxedItemValue);
+				
+				TaxItem taxItem = new TaxItem();
+				taxItem.setItemPrice(taxedItemValue);
+				taxItem.setLabel(taxRate.getDescriptions().get(0).getName());
+				taxItem.setTaxRate(taxRate);
+				taxItems.add(taxItem);
+				
+			}
+			
+		}
+		
+		
+		
+		Map<String,TaxItem> taxItemsMap = new TreeMap<String,TaxItem>();
+		//consolidate tax rates of same code
+		for(TaxItem taxItem : taxItems) {
+			
+			TaxRate taxRate = taxItem.getTaxRate();
+			if(!taxItemsMap.containsKey(taxRate.getCode())) {
+				taxItemsMap.put(taxRate.getCode(), taxItem);
+			} 
+			
+			TaxItem item = taxItemsMap.get(taxRate.getCode());
+			BigDecimal amount = item.getItemPrice();
+			amount = amount.add(taxItem.getItemPrice());			
+			
+		}
+		
+		if(taxItemsMap.size()==0) {
+			return null;
+		}
+			
+			
+		@SuppressWarnings("rawtypes")
+		Collection<TaxItem> values = taxItemsMap.values();
+		
+		
+		@SuppressWarnings("unchecked")
+		List<TaxItem> list = new ArrayList<TaxItem>(values);
+		return list;
+
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/dao/GroupDao.java b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/GroupDao.java
new file mode 100755
index 0000000..39b287b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/GroupDao.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.business.user.dao;
+
+import java.util.List;
+import java.util.Set;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.user.model.Group;
+import com.salesmanager.core.business.user.model.GroupType;
+
+public interface GroupDao extends SalesManagerEntityDao<Integer, Group> {
+
+	List<Group> getGroupsListBypermissions(Set<Integer> ids);
+
+	List<Group> listGroup(GroupType groupType);
+
+	List<Group> listGroupByIds(Set<Integer> ids);
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/dao/GroupDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/GroupDaoImpl.java
new file mode 100755
index 0000000..4f7582e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/GroupDaoImpl.java
@@ -0,0 +1,77 @@
+package com.salesmanager.core.business.user.dao;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.Query;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.user.model.Group;
+import com.salesmanager.core.business.user.model.GroupType;
+import com.salesmanager.core.business.user.model.QGroup;
+
+@Repository("groupDao")
+public class GroupDaoImpl extends SalesManagerEntityDaoImpl<Integer, Group> implements
+		GroupDao {
+
+	@SuppressWarnings("rawtypes")
+	@Override
+	public List<Group> getGroupsListBypermissions(Set permissionIds) {
+		StringBuilder qs = new StringBuilder();
+		qs.append("select g from Group as g ");
+		qs.append("join fetch g.permissions perms ");
+		qs.append("where perms.id in (:cid) ");
+
+
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("cid", permissionIds);
+	
+    	@SuppressWarnings("unchecked")
+		List<Group> groups =  q.getResultList();
+
+    	
+    	return groups;
+	}
+	
+	@Override
+	public List<Group> listGroupByIds(Set<Integer> ids) {
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct g from Group as g ");
+		qs.append("join fetch g.permissions perms ");
+		qs.append("where g.id in (:gid) ");
+		
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("gid", ids);
+	
+    	@SuppressWarnings("unchecked")
+		List<Group> groups =  q.getResultList();
+
+    	
+    	return groups;
+		
+	}
+
+	@Override
+	public List<Group> listGroup(GroupType groupType) {
+		QGroup qGroup = QGroup.group;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qGroup)
+			.where(qGroup.groupType.eq(groupType))
+			.orderBy(qGroup.id.asc());
+		
+		return query.listDistinct(qGroup);
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/dao/PermissionDao.java b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/PermissionDao.java
new file mode 100755
index 0000000..9c86310
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/PermissionDao.java
@@ -0,0 +1,23 @@
+package com.salesmanager.core.business.user.dao;
+
+import java.util.List;
+import java.util.Set;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.user.model.Permission;
+import com.salesmanager.core.business.user.model.PermissionCriteria;
+import com.salesmanager.core.business.user.model.PermissionList;
+
+public interface PermissionDao extends SalesManagerEntityDao<Integer, Permission> {
+
+	List<Permission> listPermission();
+
+	Permission getById(Integer permissionId);
+
+	List<Permission> getPermissionsListByGroups(Set permissionIds);
+
+	PermissionList listByCriteria(PermissionCriteria criteria);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/dao/PermissionDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/PermissionDaoImpl.java
new file mode 100755
index 0000000..115d119
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/PermissionDaoImpl.java
@@ -0,0 +1,140 @@
+package com.salesmanager.core.business.user.dao;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
+import javax.persistence.Query;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.ProductList;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.user.model.Permission;
+import com.salesmanager.core.business.user.model.PermissionCriteria;
+import com.salesmanager.core.business.user.model.PermissionList;
+import com.salesmanager.core.business.user.model.QPermission;
+
+@Repository("permissionDao")
+public class PermissionDaoImpl extends SalesManagerEntityDaoImpl<Integer, Permission> implements
+		PermissionDao {
+
+	@Override
+	public List<Permission> listPermission() {
+		QPermission qPermission = QPermission.permission;
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qPermission)
+			.orderBy(qPermission.id.asc());
+		
+		return query.listDistinct(qPermission);
+		}
+
+	@Override
+	public Permission getById(Integer permissionId) {
+		QPermission qPermission = QPermission.permission;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qPermission)
+			.where(qPermission.id.eq(permissionId));
+		
+		return query.uniqueResult(qPermission);
+	}
+
+
+	@Override
+	public List<Permission> getPermissionsListByGroups(Set groupIds) {
+		StringBuilder qs = new StringBuilder();
+		qs.append("select distinct p from Permission as p ");
+		qs.append("join fetch p.groups grous ");
+		qs.append("where grous.id in (:cid)");
+
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+    	q.setParameter("cid", groupIds);
+    	
+    	@SuppressWarnings("unchecked")
+		List<Permission> permissions =  q.getResultList();
+    	
+    	return permissions;
+	}
+
+	@Override
+	public PermissionList listByCriteria(PermissionCriteria criteria) {
+		PermissionList permissionList = new PermissionList();
+
+        
+		StringBuilder countBuilderSelect = new StringBuilder();
+		countBuilderSelect.append("select count(p) from Permission as p");
+		
+		StringBuilder countBuilderWhere = new StringBuilder();
+		
+		
+		if(criteria.getGroupIds()!=null && criteria.getGroupIds().size()>0) {
+			countBuilderSelect.append(" INNER JOIN p.groups grous");
+			countBuilderWhere.append(" where grous.id in (:cid)");
+		}
+		
+	
+		Query countQ = super.getEntityManager().createQuery(
+				countBuilderSelect.toString() + countBuilderWhere.toString());
+
+		if(criteria.getGroupIds()!=null && criteria.getGroupIds().size()>0) {
+			countQ.setParameter("cid", criteria.getGroupIds());
+		}
+		
+
+		Number count = (Number) countQ.getSingleResult ();
+
+		permissionList.setTotalCount(count.intValue());
+		
+        if(count.intValue()==0)
+        	return permissionList;
+
+		
+		StringBuilder qs = new StringBuilder();
+		qs.append("select p from Permission as p ");
+		qs.append("join fetch p.groups grous ");
+		
+		if(criteria.getGroupIds()!=null && criteria.getGroupIds().size()>0) {
+			qs.append(" where grous.id in (:cid)");
+		}
+		
+		qs.append(" order by p.id asc ");
+		
+    	String hql = qs.toString();
+		Query q = super.getEntityManager().createQuery(hql);
+
+
+    	if(criteria.getGroupIds()!=null && criteria.getGroupIds().size()>0) {
+    		q.setParameter("cid", criteria.getGroupIds());
+    	}
+    	
+    	if(criteria.getMaxCount()>0) {
+    		
+    		
+	    	q.setFirstResult(criteria.getStartIndex());
+	    	if(criteria.getMaxCount()<count.intValue()) {
+	    		q.setMaxResults(criteria.getMaxCount());
+	    		permissionList.setTotalCount(criteria.getMaxCount());
+	    	}
+	    	else {
+	    		q.setMaxResults(count.intValue());
+	    		permissionList.setTotalCount(count.intValue());
+	    	}
+    	}
+    	
+    	@SuppressWarnings("unchecked")
+		List<Permission> permissions =  q.getResultList();
+    	permissionList.setPermissions(permissions);
+    	
+    	return permissionList;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/dao/UserDao.java b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/UserDao.java
new file mode 100755
index 0000000..fd0928c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/UserDao.java
@@ -0,0 +1,19 @@
+package com.salesmanager.core.business.user.dao;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDao;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.user.model.User;
+
+public interface UserDao extends SalesManagerEntityDao<Long, User> {
+
+	User getByUserName(String userName);
+
+	List<User> listUser();
+
+	List<User> listUserByStore(MerchantStore store);
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/dao/UserDaoImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/UserDaoImpl.java
new file mode 100755
index 0000000..0aad078
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/dao/UserDaoImpl.java
@@ -0,0 +1,90 @@
+package com.salesmanager.core.business.user.dao;
+
+import java.util.List;
+
+import org.springframework.stereotype.Repository;
+
+import com.mysema.query.jpa.JPQLQuery;
+import com.mysema.query.jpa.impl.JPAQuery;
+import com.salesmanager.core.business.generic.dao.SalesManagerEntityDaoImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.user.model.QGroup;
+import com.salesmanager.core.business.user.model.QUser;
+import com.salesmanager.core.business.user.model.User;
+
+@Repository("userDao")
+public class UserDaoImpl extends SalesManagerEntityDaoImpl<Long, User> implements
+		UserDao {
+	
+	@Override
+	public User getByUserName(String userName) {
+		
+		
+		QUser qUser = QUser.user;
+		QGroup qGroup = QGroup.group;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qUser)
+			.innerJoin(qUser.groups, qGroup).fetch()
+			.innerJoin(qUser.merchantStore).fetch()
+			.leftJoin(qUser.defaultLanguage).fetch()
+			.where(qUser.adminName.eq(userName));
+		
+		
+
+		User user = query.uniqueResult(qUser);
+		return user;
+	}
+	
+	@Override
+	public User getById(Long id) {
+		
+		
+		QUser qUser = QUser.user;
+		QGroup qGroup = QGroup.group;
+		
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qUser)
+			.innerJoin(qUser.groups, qGroup).fetch()
+			.innerJoin(qUser.merchantStore).fetch()
+			.leftJoin(qUser.defaultLanguage).fetch()
+			.where(qUser.id.eq(id));
+		
+		
+
+		User user = query.uniqueResult(qUser);
+		return user;
+	}
+
+	@Override
+	public List<User> listUser() {
+		QUser qUser = QUser.user;
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qUser)
+			.innerJoin(qUser.groups).fetch()
+			.innerJoin(qUser.merchantStore).fetch()
+			.leftJoin(qUser.defaultLanguage).fetch()
+			.orderBy(qUser.id.asc());
+		
+		return query.listDistinct(qUser);
+	}
+	
+	@Override
+	public List<User> listUserByStore(MerchantStore store) {
+		QUser qUser = QUser.user;
+		JPQLQuery query = new JPAQuery (getEntityManager());
+		
+		query.from(qUser)
+			.innerJoin(qUser.groups).fetch()
+			.innerJoin(qUser.merchantStore).fetch()
+			.leftJoin(qUser.defaultLanguage).fetch()
+			.orderBy(qUser.id.asc())
+			.where(qUser.merchantStore.id.eq(store.getId()));
+		
+		return query.listDistinct(qUser);
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/model/Group.java b/sm-core/src/main/java/com/salesmanager/core/business/user/model/Group.java
new file mode 100755
index 0000000..82077e9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/model/Group.java
@@ -0,0 +1,112 @@
+package com.salesmanager.core.business.user.model;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "SM_GROUP", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class Group extends SalesManagerEntity<Integer, Group> implements Auditable {
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 3786127652573709701L;
+	@Id
+	@Column(name = "GROUP_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "GROUP_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Integer id;
+	
+	public Group() {
+		
+	}
+	
+	@Column (name ="GROUP_TYPE")
+	@Enumerated(value = EnumType.STRING)
+	private GroupType groupType;
+	
+	@NotEmpty
+	@Column(name="GROUP_NAME", unique=true)
+	private String groupName;
+	
+	public Group(String groupName) {
+		this.groupName = groupName;
+	}
+	
+	@ManyToMany(mappedBy = "groups")
+	private Set<Permission> permissions = new HashSet<Permission>();	
+	
+	public Set<Permission> getPermissions() {
+		return permissions;
+	}
+
+	public void setPermissions(Set<Permission> permissions) {
+		this.permissions = permissions;
+	}
+
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	
+	@Override
+	public AuditSection getAuditSection() {
+		return this.auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection audit) {
+			this.auditSection = audit;
+	}
+
+	@Override
+	public Integer getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Integer id) {
+		this.id = id;
+	}
+
+	public String getGroupName() {
+		return groupName;
+	}
+
+	public void setGroupName(String groupName) {
+		this.groupName = groupName;
+	}
+
+	public void setGroupType(GroupType groupType) {
+		this.groupType = groupType;
+	}
+
+	public GroupType getGroupType() {
+		return groupType;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/model/GroupType.java b/sm-core/src/main/java/com/salesmanager/core/business/user/model/GroupType.java
new file mode 100644
index 0000000..2bcbfea
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/model/GroupType.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.business.user.model;
+
+public enum GroupType {
+	
+	ADMIN, CUSTOMER
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/model/Permission.java b/sm-core/src/main/java/com/salesmanager/core/business/user/model/Permission.java
new file mode 100755
index 0000000..d5e306e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/model/Permission.java
@@ -0,0 +1,116 @@
+package com.salesmanager.core.business.user.model;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+
+import org.hibernate.annotations.Cascade;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "PERMISSION", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class Permission extends SalesManagerEntity<Integer, Permission> implements Auditable {
+
+	
+
+	private static final long serialVersionUID = 813468140197420748L;
+
+	@Id
+	@Column(name = "PERMISSION_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "PERMISSION_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Integer id;
+	
+	public Permission() {
+		
+	}
+	
+	public Permission(String permissionName) {
+		this.permissionName = permissionName;
+	}
+	
+	
+	@NotEmpty
+	@Column(name="PERMISSION_NAME", unique=true)
+	private String permissionName;
+	
+	@ManyToMany(fetch=FetchType.LAZY, cascade = {CascadeType.REFRESH})
+	@JoinTable(name = "PERMISSION_GROUP", schema=SchemaConstant.SALESMANAGER_SCHEMA, joinColumns = { 
+			@JoinColumn(name = "PERMISSION_ID", nullable = false, updatable = false) }
+			, 
+			inverseJoinColumns = { @JoinColumn(name = "GROUP_ID", 
+					nullable = false, updatable = false) }
+	)
+	@Cascade({
+		org.hibernate.annotations.CascadeType.DETACH,
+		org.hibernate.annotations.CascadeType.LOCK,
+		org.hibernate.annotations.CascadeType.REFRESH,
+		org.hibernate.annotations.CascadeType.REPLICATE
+		
+	})
+	private List<Group> groups = new ArrayList<Group>();
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	
+	@Override
+	public Integer getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Integer id) {
+		this.id = id;
+		
+	}
+
+	@Override
+	public AuditSection getAuditSection() {
+		return this.auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection audit) {
+		this.auditSection = audit;
+		
+	}
+
+	public String getPermissionName() {
+		return permissionName;
+	}
+
+	public void setPermissionName(String permissionName) {
+		this.permissionName = permissionName;
+	}
+	
+	public void setGroups(List<Group> groups) {
+		this.groups = groups;
+	}
+
+	public List<Group> getGroups() {
+		return groups;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/model/PermissionCriteria.java b/sm-core/src/main/java/com/salesmanager/core/business/user/model/PermissionCriteria.java
new file mode 100644
index 0000000..7717f94
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/model/PermissionCriteria.java
@@ -0,0 +1,54 @@
+package com.salesmanager.core.business.user.model;
+
+import java.util.List;
+import java.util.Set;
+
+import com.salesmanager.core.business.common.model.Criteria;
+
+public class PermissionCriteria extends Criteria {
+	
+	
+	private String permissionName;
+
+	
+	private Boolean available = null;
+	
+	private Set<Integer> groupIds;
+	
+	private List<String> availabilities;
+
+
+	public List<String> getAvailabilities() {
+		return availabilities;
+	}
+
+	public void setAvailabilities(List<String> availabilities) {
+		this.availabilities = availabilities;
+	}
+
+	public Boolean getAvailable() {
+		return available;
+	}
+
+	public void setAvailable(Boolean available) {
+		this.available = available;
+	}
+
+	public String getPermissionName() {
+		return permissionName;
+	}
+
+	public void setPermissionName(String permissionName) {
+		this.permissionName = permissionName;
+	}
+
+	public Set<Integer> getGroupIds() {
+		return groupIds;
+	}
+
+	public void setGroupIds(Set<Integer> groupIds) {
+		this.groupIds = groupIds;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/model/PermissionList.java b/sm-core/src/main/java/com/salesmanager/core/business/user/model/PermissionList.java
new file mode 100644
index 0000000..89f78f2
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/model/PermissionList.java
@@ -0,0 +1,26 @@
+package com.salesmanager.core.business.user.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+public class PermissionList implements Serializable {
+	
+
+	private static final long serialVersionUID = -3122326940968441727L;
+	private int totalCount;
+	private List<Permission> permissions = new ArrayList<Permission>();
+	public int getTotalCount() {
+		return totalCount;
+	}
+	public void setTotalCount(int totalCount) {
+		this.totalCount = totalCount;
+	}
+	public List<Permission> getPermissions() {
+		return permissions;
+	}
+	public void setPermissions(List<Permission> permissions) {
+		this.permissions = permissions;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/model/User.java b/sm-core/src/main/java/com/salesmanager/core/business/user/model/User.java
new file mode 100755
index 0000000..d0df6f1
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/model/User.java
@@ -0,0 +1,298 @@
+package com.salesmanager.core.business.user.model;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.persistence.CascadeType;
+import javax.persistence.Column;
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.EntityListeners;
+import javax.persistence.FetchType;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+import javax.persistence.TableGenerator;
+import javax.persistence.Temporal;
+import javax.persistence.TemporalType;
+
+import org.hibernate.annotations.Cascade;
+import org.hibernate.validator.constraints.Email;
+import org.hibernate.validator.constraints.NotEmpty;
+
+import com.salesmanager.core.business.common.model.audit.AuditListener;
+import com.salesmanager.core.business.common.model.audit.AuditSection;
+import com.salesmanager.core.business.generic.model.SalesManagerEntity;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.common.model.audit.Auditable;
+import com.salesmanager.core.constants.SchemaConstant;
+
+@Entity
+@EntityListeners(value = AuditListener.class)
+@Table(name = "USER", schema=SchemaConstant.SALESMANAGER_SCHEMA)
+public class User extends SalesManagerEntity<Long, User> implements Auditable {
+	
+	
+	private static final long serialVersionUID = 5401059537544058710L;
+	
+	@Id
+	@Column(name = "USER_ID", unique=true, nullable=false)
+	@TableGenerator(name = "TABLE_GEN", table = "SM_SEQUENCER", pkColumnName = "SEQ_NAME", valueColumnName = "SEQ_COUNT", pkColumnValue = "USER_SEQ_NEXT_VAL")
+	@GeneratedValue(strategy = GenerationType.TABLE, generator = "TABLE_GEN")
+	private Long id;
+	
+	public User() {
+		
+	}
+	
+	public User(String userName,String password, String email) {
+		
+		this.adminName = userName;
+		this.adminPassword = password;
+		this.adminEmail = email;
+	}
+	
+	@NotEmpty
+	@Column(name="ADMIN_NAME", length=100, unique=true)
+	private String adminName;
+	
+	@ManyToMany(fetch=FetchType.LAZY, cascade = {CascadeType.REFRESH})
+	@JoinTable(name = "USER_GROUP", schema=SchemaConstant.SALESMANAGER_SCHEMA, joinColumns = { 
+			@JoinColumn(name = "USER_ID", nullable = false, updatable = false) }
+			, 
+			inverseJoinColumns = { @JoinColumn(name = "GROUP_ID", 
+					nullable = false, updatable = false) }
+	)
+	@Cascade({
+		org.hibernate.annotations.CascadeType.DETACH,
+		org.hibernate.annotations.CascadeType.LOCK,
+		org.hibernate.annotations.CascadeType.REFRESH,
+		org.hibernate.annotations.CascadeType.REPLICATE
+		
+	})
+	private List<Group> groups = new ArrayList<Group>();
+	
+	@NotEmpty
+	@Email
+	@Column(name="ADMIN_EMAIL")
+	private String adminEmail;
+	
+	@NotEmpty
+	@Column(name="ADMIN_PASSWORD", length=50)
+	private String adminPassword;
+	
+	@ManyToOne(fetch = FetchType.LAZY)
+	@JoinColumn(name="MERCHANT_ID", nullable=false)
+	private MerchantStore merchantStore;
+	
+	
+	@Column(name="ADMIN_FIRST_NAME")
+	private String firstName;
+	
+	@Column(name="ACTIVE")
+	private boolean active = true;
+	
+	
+	@Column(name="ADMIN_LAST_NAME")
+	private String lastName;
+	
+	@ManyToOne(fetch = FetchType.LAZY, targetEntity = Language.class)
+	@JoinColumn(name = "LANGUAGE_ID")
+	private Language defaultLanguage;
+	
+	
+	@Column(name="ADMIN_Q1")
+	private String question1;
+	
+	@Column(name="ADMIN_Q2")
+	private String question2;
+	
+	@Column(name="ADMIN_Q3")
+	private String question3;
+	
+	@Column(name="ADMIN_A1")
+	private String answer1;
+	
+	@Column(name="ADMIN_A2")
+	private String answer2;
+	
+	@Column(name="ADMIN_A3")
+	private String answer3;
+	
+	
+	@Embedded
+	private AuditSection auditSection = new AuditSection();
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name = "LAST_ACCESS")
+	private Date lastAccess;
+	
+	@Temporal(TemporalType.TIMESTAMP)
+	@Column(name = "LOGIN_ACCESS")
+	private Date loginTime;
+
+	@Override
+	public Long getId() {
+		return this.id;
+	}
+
+	@Override
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	@Override
+	public AuditSection getAuditSection() {
+		return auditSection;
+	}
+
+	@Override
+	public void setAuditSection(AuditSection audit) {
+		auditSection = audit;
+		
+	}
+
+	public String getAdminName() {
+		return adminName;
+	}
+
+	public void setAdminName(String adminName) {
+		this.adminName = adminName;
+	}
+
+	public String getAdminEmail() {
+		return adminEmail;
+	}
+
+	public void setAdminEmail(String adminEmail) {
+		this.adminEmail = adminEmail;
+	}
+
+	public String getAdminPassword() {
+		return adminPassword;
+	}
+
+	public void setAdminPassword(String adminPassword) {
+		this.adminPassword = adminPassword;
+	}
+
+	public String getFirstName() {
+		return firstName;
+	}
+
+	public void setFirstName(String firstName) {
+		this.firstName = firstName;
+	}
+
+	public String getLastName() {
+		return lastName;
+	}
+
+	public void setLastName(String lastName) {
+		this.lastName = lastName;
+	}
+
+	public Language getDefaultLanguage() {
+		return defaultLanguage;
+	}
+
+	public void setDefaultLanguage(Language defaultLanguage) {
+		this.defaultLanguage = defaultLanguage;
+	}
+
+	public String getQuestion1() {
+		return question1;
+	}
+
+	public void setQuestion1(String question1) {
+		this.question1 = question1;
+	}
+
+	public String getQuestion2() {
+		return question2;
+	}
+
+	public void setQuestion2(String question2) {
+		this.question2 = question2;
+	}
+
+	public String getQuestion3() {
+		return question3;
+	}
+
+	public void setQuestion3(String question3) {
+		this.question3 = question3;
+	}
+
+	public String getAnswer1() {
+		return answer1;
+	}
+
+	public void setAnswer1(String answer1) {
+		this.answer1 = answer1;
+	}
+
+	public String getAnswer2() {
+		return answer2;
+	}
+
+	public void setAnswer2(String answer2) {
+		this.answer2 = answer2;
+	}
+
+	public String getAnswer3() {
+		return answer3;
+	}
+
+	public void setAnswer3(String answer3) {
+		this.answer3 = answer3;
+	}
+
+	public void setGroups(List<Group> groups) {
+		this.groups = groups;
+	}
+
+	public List<Group> getGroups() {
+		return groups;
+	}
+
+	public MerchantStore getMerchantStore() {
+		return merchantStore;
+	}
+
+	public void setMerchantStore(MerchantStore merchantStore) {
+		this.merchantStore = merchantStore;
+	}
+
+	public void setActive(boolean active) {
+		this.active = active;
+	}
+
+	public boolean isActive() {
+		return active;
+	}
+
+	public void setLastAccess(Date lastAccess) {
+		this.lastAccess = lastAccess;
+	}
+
+	public Date getLastAccess() {
+		return lastAccess;
+	}
+
+	public void setLoginTime(Date loginTime) {
+		this.loginTime = loginTime;
+	}
+
+	public Date getLoginTime() {
+		return loginTime;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/service/GroupService.java b/sm-core/src/main/java/com/salesmanager/core/business/user/service/GroupService.java
new file mode 100755
index 0000000..26b0408
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/service/GroupService.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.business.user.service;
+
+import java.util.List;
+import java.util.Set;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.user.model.Group;
+import com.salesmanager.core.business.user.model.GroupType;
+
+public interface GroupService extends SalesManagerEntityService<Integer, Group> {
+
+
+	List<Group> listGroup(GroupType groupType) throws ServiceException;
+	List<Group> listGroupByIds(Set<Integer> ids) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/service/GroupServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/user/service/GroupServiceImpl.java
new file mode 100755
index 0000000..87947ab
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/service/GroupServiceImpl.java
@@ -0,0 +1,52 @@
+package com.salesmanager.core.business.user.service;
+
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.user.dao.GroupDao;
+import com.salesmanager.core.business.user.model.Group;
+import com.salesmanager.core.business.user.model.GroupType;
+
+@Service("groupService")
+public class GroupServiceImpl extends
+		SalesManagerEntityServiceImpl<Integer, Group> implements GroupService {
+
+	GroupDao groupDao;
+
+
+	@Autowired
+	public GroupServiceImpl(GroupDao groupDao) {
+		super(groupDao);
+		this.groupDao = groupDao;
+
+	}
+
+
+
+
+
+
+	@Override
+	public List<Group> listGroup(GroupType groupType) throws ServiceException {
+		try {
+			return groupDao.listGroup(groupType);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	}
+	
+	public List<Group> listGroupByIds(Set<Integer> ids) throws ServiceException {
+		try {
+			return groupDao.listGroupByIds(ids);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/service/PermissionService.java b/sm-core/src/main/java/com/salesmanager/core/business/user/service/PermissionService.java
new file mode 100755
index 0000000..ec7e750
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/service/PermissionService.java
@@ -0,0 +1,32 @@
+package com.salesmanager.core.business.user.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.user.model.Group;
+import com.salesmanager.core.business.user.model.Permission;
+import com.salesmanager.core.business.user.model.PermissionCriteria;
+import com.salesmanager.core.business.user.model.PermissionList;
+
+public interface PermissionService extends SalesManagerEntityService<Integer, Permission> {
+
+	List<Permission> getByName();
+
+	List<Permission> listPermission()  throws ServiceException;
+
+	Permission getById(Integer permissionId);
+
+	void saveOrUpdate(Permission permission);
+
+//	void deletePermission(Permission permission) throws ServiceException;
+
+	List<Permission> getPermissions(List<Integer> groupIds) throws ServiceException;
+
+	void deletePermission(Permission permission) throws ServiceException;
+
+	PermissionList listByCriteria(PermissionCriteria criteria) throws ServiceException ;
+
+	void removePermission(Permission permission, Group group) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/service/PermissionServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/user/service/PermissionServiceImpl.java
new file mode 100755
index 0000000..d8acfcf
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/service/PermissionServiceImpl.java
@@ -0,0 +1,106 @@
+package com.salesmanager.core.business.user.service;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.service.MerchantStoreService;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.user.dao.PermissionDao;
+import com.salesmanager.core.business.user.model.Group;
+import com.salesmanager.core.business.user.model.Permission;
+import com.salesmanager.core.business.user.model.PermissionCriteria;
+import com.salesmanager.core.business.user.model.PermissionList;
+
+@Service("permissionService")
+public class PermissionServiceImpl extends
+		SalesManagerEntityServiceImpl<Integer, Permission> implements
+		PermissionService {
+
+	PermissionDao permissionDao;
+
+	@Autowired
+	private LanguageService languageService;
+
+	@Autowired
+	private MerchantStoreService merchantService;
+	
+	@Autowired
+	private GroupService groupService;
+
+	@Autowired
+	public PermissionServiceImpl(PermissionDao permissionDao) {
+		super(permissionDao);
+		this.permissionDao = permissionDao;
+
+	}
+
+	@Override
+	public List<Permission> getByName() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+
+	@Override
+	public Permission getById(Integer permissionId) {
+		return permissionDao.getById(permissionId);
+
+	}
+
+	@Override
+	public void saveOrUpdate(Permission permission) {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void deletePermission(Permission permission) throws ServiceException {
+		permission = this.getById(permission.getId());//Prevents detached entity error
+		permission.setGroups(null);
+		
+		this.delete(permission);
+	}
+	
+
+	@Override
+	public List<Permission> getPermissions(List<Integer> groupIds)
+			throws ServiceException {
+		@SuppressWarnings({ "unchecked", "rawtypes" })
+		Set ids = new HashSet(groupIds);
+		return permissionDao.getPermissionsListByGroups(ids);
+	}
+
+	@Override
+	public PermissionList listByCriteria(PermissionCriteria criteria)
+			throws ServiceException {
+		return permissionDao.listByCriteria(criteria);
+	}
+
+	@Override
+	public void removePermission(Permission permission,Group group) throws ServiceException {
+		permission = this.getById(permission.getId());//Prevents detached entity error
+	
+		permission.getGroups().remove(group);
+		
+		
+//		this.delete(permission);
+	}
+
+	@Override
+	public List<Permission> listPermission() throws ServiceException {
+		return permissionDao.listPermission();
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserService.java b/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserService.java
new file mode 100755
index 0000000..b40003d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserService.java
@@ -0,0 +1,28 @@
+package com.salesmanager.core.business.user.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityService;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.user.model.User;
+import com.salesmanager.core.modules.email.Email;
+
+public interface UserService extends SalesManagerEntityService<Long, User> {
+
+	User getByUserName(String userName) throws ServiceException;
+
+	List<User> listUser() throws ServiceException;
+	
+	/**
+	 * Create or update a User
+	 * @param user
+	 * @throws ServiceException
+	 */
+	void saveOrUpdate(User user) throws ServiceException;
+
+	List<User> listByStore(MerchantStore store) throws ServiceException;
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserServiceImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserServiceImpl.java
new file mode 100755
index 0000000..a9788e0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserServiceImpl.java
@@ -0,0 +1,77 @@
+package com.salesmanager.core.business.user.service;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.service.SalesManagerEntityServiceImpl;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.system.service.EmailService;
+import com.salesmanager.core.business.user.dao.UserDao;
+import com.salesmanager.core.business.user.model.User;
+import com.salesmanager.core.modules.email.Email;
+
+
+public class UserServiceImpl extends SalesManagerEntityServiceImpl<Long, User>
+		implements UserService {
+
+
+	private UserDao userDao;
+	
+	@Autowired
+	public UserServiceImpl(UserDao userDao) {
+		super(userDao);
+		this.userDao = userDao;
+
+	}
+	
+	@Autowired
+	private EmailService emailService;
+	
+	@Override
+	public User getByUserName(String userName) throws ServiceException {
+		
+		return userDao.getByUserName(userName);
+		
+	}
+	
+	@Override
+	public void delete(User user) throws ServiceException {
+		
+		User u = this.getById(user.getId());
+		super.delete(u);
+		
+	}
+
+	@Override
+	public List<User> listUser() throws ServiceException {
+		try {
+			return userDao.listUser();
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	}
+	
+	@Override
+	public List<User> listByStore(MerchantStore store) throws ServiceException {
+		try {
+			return userDao.listUserByStore(store);
+		} catch (Exception e) {
+			throw new ServiceException(e);
+		}
+	}
+
+	
+	@Override
+	public void saveOrUpdate(User user) throws ServiceException {
+		
+		if(user.getId()==null || user.getId().longValue()==0) {
+			userDao.save(user);
+		} else {
+			userDao.update(user);
+		}
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserServiceLDAPImpl.java b/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserServiceLDAPImpl.java
new file mode 100644
index 0000000..fc84915
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/business/user/service/UserServiceLDAPImpl.java
@@ -0,0 +1,106 @@
+package com.salesmanager.core.business.user.service;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.user.model.User;
+import com.salesmanager.core.modules.email.Email;
+
+public class UserServiceLDAPImpl implements UserService {
+
+	@Override
+	public void save(User entity) throws ServiceException {
+		throw new ServiceException("Not implemented");
+
+	}
+
+	@Override
+	public void update(User entity) throws ServiceException {
+		throw new ServiceException("Not implemented");
+
+	}
+
+	@Override
+	public void create(User entity) throws ServiceException {
+		throw new ServiceException("Not implemented");
+
+	}
+
+	@Override
+	public void delete(User entity) throws ServiceException {
+		throw new ServiceException("Not implemented");
+
+	}
+
+	@Override
+	public User refresh(User entity) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public User getById(Long id) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public List<User> list() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+
+
+	@Override
+	public Long count() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public void flush() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public void clear() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public User getByUserName(String userName) throws ServiceException {
+		// TODO Auto-generated method stub
+		throw new ServiceException("Not implemented");
+	}
+
+	@Override
+	public List<User> listUser() throws ServiceException {
+		// TODO Auto-generated method stub
+		throw new ServiceException("Not implemented");
+	}
+
+	@Override
+	public void saveOrUpdate(User user) throws ServiceException {
+		throw new ServiceException("Not implemented");
+
+	}
+
+	@Override
+	public List<User> listByStore(MerchantStore store)
+			throws ServiceException {
+		// TODO Auto-generated method stub
+		throw new ServiceException("Not implemented");
+	}
+
+	@Override
+	public User getEntity(Class<? extends User> clazz, Long id) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/constants/Constants.java b/sm-core/src/main/java/com/salesmanager/core/constants/Constants.java
new file mode 100644
index 0000000..8647615
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/constants/Constants.java
@@ -0,0 +1,34 @@
+package com.salesmanager.core.constants;
+
+import java.util.Currency;
+import java.util.Locale;
+
+public class Constants {
+	
+	public final static String TEST_ENVIRONMENT= "TEST";
+	public final static String PRODUCTION_ENVIRONMENT= "PRODUCTION";
+	public final static String SHOP_URI = "/shop";
+	
+	public static final String ALL_REGIONS = "*";
+	public final static String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
+	public final static String DEFAULT_DATE_FORMAT_YEAR = "yyyy";
+	
+	public final static String EMAIL_CONFIG = "EMAIL_CONFIG";
+	public final static String MERCHANT_CONFIG = "MERCHANT_CONFIG";
+	
+	public final static String UNDERSCORE = "_";
+	public final static String SLASH = "/";
+	public final static String TRUE = "true";
+	public final static String FALSE = "false";
+	public final static String OT_ITEM_PRICE_MODULE_CODE = "itemprice";
+	public final static String OT_SUBTOTAL_MODULE_CODE = "subtotal";
+	public final static String OT_TOTAL_MODULE_CODE = "total";
+	public final static String OT_SHIPPING_MODULE_CODE = "shipping";
+	public final static String OT_HANDLING_MODULE_CODE = "handling";
+	public final static String OT_TAX_MODULE_CODE = "tax";
+	public final static String OT_REFUND_MODULE_CODE = "refund";
+	
+	public final static Locale DEFAULT_LOCALE = Locale.US;
+	public final static Currency DEFAULT_CURRENCY = Currency.getInstance(Locale.US);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/constants/MeasureUnit.java b/sm-core/src/main/java/com/salesmanager/core/constants/MeasureUnit.java
new file mode 100644
index 0000000..2d6607b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/constants/MeasureUnit.java
@@ -0,0 +1,7 @@
+package com.salesmanager.core.constants;
+
+public enum MeasureUnit {
+	
+	KG, LB, CM, IN
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/constants/SchemaConstant.java b/sm-core/src/main/java/com/salesmanager/core/constants/SchemaConstant.java
new file mode 100644
index 0000000..8e842d6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/constants/SchemaConstant.java
@@ -0,0 +1,268 @@
+package com.salesmanager.core.constants;
+
+import java.util.HashMap;
+import java.util.Locale;
+
+public class SchemaConstant {
+
+	public final static String SALESMANAGER_SCHEMA = "SALESMANAGER";
+
+	/**
+	 * Languages iso codes
+	 * 
+	 */
+	public static final String[] LANGUAGE_ISO_CODE = {"en", "fr"};
+
+	/**
+	 * Country iso codes
+	 */
+	public static final String[] COUNTRY_ISO_CODE = { "AF","AX","AL","DZ",
+		"AS","AD","AO","AI","AQ","AG","AR","AM","AW","AU","AT","AZ","BS","BH",
+		"BD","BB","BY","BE","BZ","BJ","BM","BT","BO","BA","BW","BV","BR","IO",
+		"BN","BG","BF","BI","KH","CM","CA","CV","KY","CF","TD","CL","CN","CX",
+		"CC","CO","KM","CG","CD","CK","CR","CI","HR","CU","CY","CZ","DK","DJ",
+		"DM","DO","EC","EG","SV","GQ","ER","EE","ET","FK","FO","FJ","FI","FR",
+		"GF","PF","TF","GA","GM","GE","DE","GH","GI","GR","GL","GD","GP","GU",
+		"GT","GG","GN","GW","GY","HT","HM","VA","HN","HK","HU","IS","IN","ID",
+		"IR","IQ","IE","IM","IL","IT","JM","JP","JE","JO","KZ","KE","KI","KP",
+		"KR","KW","KG","LA","LV","LB","LS","LR","LY","LI","LT","LU","MO","MK",
+		"MG","MW","MY","MV","ML","MT","MH","MQ","MR","MU","YT","MX","FM","MD",
+		"MC","MN","ME","MS","MA","MZ","MM","NA","NR","NP","NL","AN","NC","NZ",
+		"NI","NE","NG","NU","NF","MP","NO","OM","PK","PW","PS","PA","PG","PY",
+		"PE","PH","PN","PL","PT","PR","QA","RE","RO","RU","RW","SH","KN","LC",
+		"PM","VC","WS","SM","ST","SA","SN","RS","SC","SL","SG","SK","SI","SB",
+		"SO","ZA","GS","ES","LK","SD","SR","SJ","SZ","SE","CH","SY","TW","TJ",
+		"TZ","TH","TL","TG","TK","TO","TT","TN","TR","TM","TC","TV","UG","UA",
+		"AE","GB","US","UM","UY","UZ","VU","VE","VN","VG","VI","WF","EH",
+	    "YE","ZM","ZW" };
+
+	/**
+	 * Locale per country iso codes
+	 */
+	public static final HashMap<String, Locale> LOCALES = new HashMap<String, Locale>();
+
+	static {
+		for (Locale locale : Locale.getAvailableLocales()) {
+			LOCALES.put(locale.getCountry(), locale);
+		}
+	}
+	
+	/**
+	 * Currency codes with name
+	 */
+	public static final HashMap<String, String> CURRENCY_MAP = new HashMap<String, String>();
+	
+	static {
+		CURRENCY_MAP.put("AFN", "Afghani");
+		CURRENCY_MAP.put("EUR", "Euro");
+		CURRENCY_MAP.put("ALL", "Lek");
+		CURRENCY_MAP.put("DZD", "Algerian Dinar");
+		CURRENCY_MAP.put("USD", "US Dollar");
+		CURRENCY_MAP.put("AOA", "Kwanza");
+		CURRENCY_MAP.put("XCD", "East Caribbean Dollar");
+		CURRENCY_MAP.put("ARS", "Argentine Peso");
+		CURRENCY_MAP.put("AMD", "Armenian Dram");
+		CURRENCY_MAP.put("AWG", "Aruban Florin");
+		CURRENCY_MAP.put("AUD", "Australian Dollar");
+		CURRENCY_MAP.put("AZN", "Azerbaijanian Manat");
+		CURRENCY_MAP.put("BSD", "Bahamian Dollar");
+		CURRENCY_MAP.put("BHD", "Bahraini Dinar");
+		CURRENCY_MAP.put("BDT", "Taka");
+		CURRENCY_MAP.put("BBD", "Barbados Dollar");
+		CURRENCY_MAP.put("BYR", "Belarussian Ruble");
+		CURRENCY_MAP.put("BZD", "Belize Dollar");
+		CURRENCY_MAP.put("XOF", "CFA Franc BCEAO");
+		CURRENCY_MAP.put("BMD", "Bermudian Dollar");
+		CURRENCY_MAP.put("BTN", "Ngultrum");
+		CURRENCY_MAP.put("INR", "Indian Rupee");
+		CURRENCY_MAP.put("BOB", "Boliviano");
+		CURRENCY_MAP.put("BOV", "Mvdol");
+		CURRENCY_MAP.put("BAM", "Convertible Mark");
+		CURRENCY_MAP.put("BWP", "Pula");
+		CURRENCY_MAP.put("NOK", "Norwegian Krone");
+		CURRENCY_MAP.put("BRL", "Brazilian Real");
+		CURRENCY_MAP.put("BND", "Brunei Dollar");
+		CURRENCY_MAP.put("BGN", "Bulgarian Lev");
+		CURRENCY_MAP.put("XOF", "CFA Franc BCEAO");
+		CURRENCY_MAP.put("BIF", "Burundi Franc");
+		CURRENCY_MAP.put("KHR", "Riel");
+		CURRENCY_MAP.put("XAF", "CFA Franc BEAC");
+		CURRENCY_MAP.put("CAD", "Canadian Dollar");
+		CURRENCY_MAP.put("CVE", "Cape Verde Escudo");
+		CURRENCY_MAP.put("KYD", "Cayman Islands Dollar");
+		CURRENCY_MAP.put("CLF", "Unidades de fomento");
+		CURRENCY_MAP.put("CLP", "Chilean Peso");
+		CURRENCY_MAP.put("CNY", "Yuan Renminbi");
+		CURRENCY_MAP.put("COP", "Colombian Peso");
+		//CURRENCY_MAP.put("COU", "Unidad de Valor Real");
+		CURRENCY_MAP.put("KMF", "Comoro Franc");
+		CURRENCY_MAP.put("XAF", "CFA Franc BEAC");
+		CURRENCY_MAP.put("CDF", "Congolese Franc");
+		CURRENCY_MAP.put("NZD", "New Zealand Dollar");
+		CURRENCY_MAP.put("CRC", "Costa Rican Colon");
+		CURRENCY_MAP.put("XOF", "CFA Franc BCEAO");
+		CURRENCY_MAP.put("HRK", "Croatian Kuna");
+		//CURRENCY_MAP.put("CUC", "Peso Convertible");
+		CURRENCY_MAP.put("CUP", "Cuban Peso");
+		CURRENCY_MAP.put("ANG", "Netherlands Antillean Guilder");
+		CURRENCY_MAP.put("CZK", "Czech Koruna");
+		CURRENCY_MAP.put("DKK", "Danish Krone");
+		CURRENCY_MAP.put("DJF", "Djibouti Franc");
+		CURRENCY_MAP.put("XCD", "East Caribbean Dollar");
+		CURRENCY_MAP.put("DOP", "Dominican Peso");
+		CURRENCY_MAP.put("EGP", "Egyptian Pound");
+		CURRENCY_MAP.put("SVC", "El Salvador Colon");
+		CURRENCY_MAP.put("XAF", "CFA Franc BEAC");
+		CURRENCY_MAP.put("ERN", "Nakfa");
+		CURRENCY_MAP.put("ETB", "Ethiopian Birr");
+		CURRENCY_MAP.put("FKP", "Falkland Islands Pound");
+		CURRENCY_MAP.put("DKK", "Danish Krone");
+		CURRENCY_MAP.put("FJD", "Fiji Dollar");
+		CURRENCY_MAP.put("XPF", "CFP Franc");
+		CURRENCY_MAP.put("XAF", "CFA Franc BEAC");
+		CURRENCY_MAP.put("GMD", "Dalasi");
+		CURRENCY_MAP.put("GEL", "Lari");
+		CURRENCY_MAP.put("GHS", "Ghana Cedi");
+		CURRENCY_MAP.put("GIP", "Gibraltar Pound");
+		CURRENCY_MAP.put("DKK", "Danish Krone");
+		CURRENCY_MAP.put("XCD", "East Caribbean Dollar");
+		CURRENCY_MAP.put("GTQ", "Quetzal");
+		CURRENCY_MAP.put("GBP", "Pound Sterling");
+		CURRENCY_MAP.put("GNF", "Guinea Franc");
+		CURRENCY_MAP.put("XOF", "CFA Franc BCEAO");
+		CURRENCY_MAP.put("GYD", "Guyana Dollar");
+		CURRENCY_MAP.put("HTG", "Gourde");
+		CURRENCY_MAP.put("HNL", "Lempira");
+		CURRENCY_MAP.put("HKD", "Hong Kong Dollar");
+		CURRENCY_MAP.put("HUF", "Forint");
+		CURRENCY_MAP.put("ISK", "Iceland Krona");
+		CURRENCY_MAP.put("INR", "Indian Rupee");
+		CURRENCY_MAP.put("IDR", "Rupiah");
+		CURRENCY_MAP.put("XDR", "SDR (Special Drawing Right)");
+		CURRENCY_MAP.put("IRR", "Iranian Rial");
+		CURRENCY_MAP.put("IQD", "Iraqi Dinar");
+		CURRENCY_MAP.put("GBP", "Pound Sterling");
+		CURRENCY_MAP.put("ILS", "New Israeli Sheqel");
+		CURRENCY_MAP.put("JMD", "Jamaican Dollar");
+		CURRENCY_MAP.put("JPY", "Yen");
+		CURRENCY_MAP.put("GBP", "Pound Sterling");
+		CURRENCY_MAP.put("JOD", "Jordanian Dinar");
+		CURRENCY_MAP.put("KZT", "Tenge");
+		CURRENCY_MAP.put("KES", "Kenyan Shilling");
+		CURRENCY_MAP.put("AUD", "Australian Dollar");
+		CURRENCY_MAP.put("KPW", "North Korean Won");
+		CURRENCY_MAP.put("KRW", "Won");
+		CURRENCY_MAP.put("KWD", "Kuwaiti Dinar");
+		CURRENCY_MAP.put("KGS", "Som");
+		CURRENCY_MAP.put("LAK", "Kip");
+		CURRENCY_MAP.put("LVL", "Latvian Lats");
+		CURRENCY_MAP.put("LBP", "Lebanese Pound");
+		CURRENCY_MAP.put("LSL", "Loti");
+		CURRENCY_MAP.put("ZAR", "Rand");
+		CURRENCY_MAP.put("LRD", "Liberian Dollar");
+		CURRENCY_MAP.put("LYD", "Libyan Dinar");
+		CURRENCY_MAP.put("CHF", "Swiss Franc");
+		CURRENCY_MAP.put("LTL", "Lithuanian Litas");
+		CURRENCY_MAP.put("EUR", "Euro");
+		CURRENCY_MAP.put("MOP", "Pataca");
+		CURRENCY_MAP.put("MKD", "Denar");
+		CURRENCY_MAP.put("MGA", "Malagasy Ariary");
+		CURRENCY_MAP.put("MWK", "Kwacha");
+		CURRENCY_MAP.put("MYR", "Malaysian Ringgit");
+		CURRENCY_MAP.put("MVR", "Rufiyaa");
+		CURRENCY_MAP.put("XOF", "CFA Franc BCEAO");
+		CURRENCY_MAP.put("MRO", "Ouguiya");
+		CURRENCY_MAP.put("MUR", "Mauritius Rupee");
+		//CURRENCY_MAP.put("XUA", "ADB Unit of Account");
+		CURRENCY_MAP.put("MXN", "Mexican Peso");
+		CURRENCY_MAP.put("MXV", "Mexican Unidad de Inversion (UDI)");
+		CURRENCY_MAP.put("MDL", "Moldovan Leu");
+		CURRENCY_MAP.put("MNT", "Tugrik");
+		CURRENCY_MAP.put("XCD", "East Caribbean Dollar");
+		CURRENCY_MAP.put("MAD", "Moroccan Dirham");
+		CURRENCY_MAP.put("MZN", "Mozambique Metical");
+		CURRENCY_MAP.put("MMK", "Kyat");
+		CURRENCY_MAP.put("NAD", "Namibia Dollar");
+		CURRENCY_MAP.put("ZAR", "Rand");
+		CURRENCY_MAP.put("NPR", "Nepalese Rupee");
+		CURRENCY_MAP.put("XPF", "CFP Franc");
+		CURRENCY_MAP.put("NZD", "New Zealand Dollar");
+		CURRENCY_MAP.put("NIO", "Cordoba Oro");
+		CURRENCY_MAP.put("XOF", "CFA Franc BCEAO");
+		CURRENCY_MAP.put("NGN", "Naira");
+		CURRENCY_MAP.put("NZD", "New Zealand Dollar");
+		CURRENCY_MAP.put("AUD", "Australian Dollar");
+		CURRENCY_MAP.put("NOK", "Norwegian Krone");
+		CURRENCY_MAP.put("OMR", "Rial Omani");
+		CURRENCY_MAP.put("PKR", "Pakistan Rupee");
+		CURRENCY_MAP.put("PAB", "Balboa");
+		CURRENCY_MAP.put("PGK", "Kina");
+		CURRENCY_MAP.put("PYG", "Guarani");
+		CURRENCY_MAP.put("PEN", "Nuevo Sol");
+		CURRENCY_MAP.put("PHP", "Philippine Peso");
+		CURRENCY_MAP.put("NZD", "New Zealand Dollar");
+		CURRENCY_MAP.put("PLN", "Zloty");
+		CURRENCY_MAP.put("USD", "US Dollar");
+		CURRENCY_MAP.put("QAR", "Qatari Rial");
+		CURRENCY_MAP.put("RON", "New Romanian Leu");
+		CURRENCY_MAP.put("RUB", "Russian Ruble");
+		CURRENCY_MAP.put("RWF", "Rwanda Franc");
+		CURRENCY_MAP.put("SHP", "Saint Helena Pound");
+		CURRENCY_MAP.put("XCD", "East Caribbean Dollar");
+		CURRENCY_MAP.put("WST", "Tala");
+		CURRENCY_MAP.put("STD", "Dobra");
+		CURRENCY_MAP.put("SAR", "Saudi Riyal");
+		CURRENCY_MAP.put("XOF", "CFA Franc BCEAO");
+		CURRENCY_MAP.put("RSD", "Serbian Dinar");
+		CURRENCY_MAP.put("SCR", "Seychelles Rupee");
+		CURRENCY_MAP.put("SLL", "Leone");
+		CURRENCY_MAP.put("SGD", "Singapore Dollar");
+		CURRENCY_MAP.put("ANG", "Netherlands Antillean Guilder");
+		//CURRENCY_MAP.put("XSU", "Sucre");
+		CURRENCY_MAP.put("SBD", "Solomon Islands Dollar");
+		CURRENCY_MAP.put("SOS", "Somali Shilling");
+		CURRENCY_MAP.put("ZAR", "Rand");
+		//CURRENCY_MAP.put("SSP", "South Sudanese Pound");
+		CURRENCY_MAP.put("LKR", "Sri Lanka Rupee");
+		CURRENCY_MAP.put("SDG", "Sudanese Pound");
+		CURRENCY_MAP.put("SRD", "Surinam Dollar");
+		CURRENCY_MAP.put("NOK", "Norwegian Krone");
+		CURRENCY_MAP.put("SZL", "Lilangeni");
+		CURRENCY_MAP.put("SEK", "Swedish Krona");
+		//CURRENCY_MAP.put("CHE", "WIR Euro");
+		CURRENCY_MAP.put("CHF", "Swiss Franc");
+		//CURRENCY_MAP.put("CHW", "WIR Franc");
+		CURRENCY_MAP.put("SYP", "Syrian Pound");
+		CURRENCY_MAP.put("TWD", "New Taiwan Dollar");
+		CURRENCY_MAP.put("TJS", "Somoni");
+		CURRENCY_MAP.put("TZS", "Tanzanian Shilling");
+		CURRENCY_MAP.put("THB", "Baht");
+		CURRENCY_MAP.put("USD", "US Dollar");
+		CURRENCY_MAP.put("XOF", "CFA Franc BCEAO");
+		CURRENCY_MAP.put("NZD", "New Zealand Dollar");
+		CURRENCY_MAP.put("TTD", "Trinidad and Tobago Dollar");
+		CURRENCY_MAP.put("TND", "Tunisian Dinar");
+		CURRENCY_MAP.put("TRY", "Turkish Lira");
+		//CURRENCY_MAP.put("TMT", "Turkmenistan New Manat");
+		CURRENCY_MAP.put("AUD", "Australian Dollar");
+		CURRENCY_MAP.put("UGX", "Uganda Shilling");
+		CURRENCY_MAP.put("UAH", "Hryvnia");
+		CURRENCY_MAP.put("AED", "UAE Dirham");
+		CURRENCY_MAP.put("GBP", "Pound Sterling");
+		//CURRENCY_MAP.put("UYI", "Uruguay Peso en Unidades Indexadas (URUIURUI)");
+		CURRENCY_MAP.put("UYU", "Peso Uruguayo");
+		CURRENCY_MAP.put("UZS", "Uzbekistan Sum");
+		CURRENCY_MAP.put("VUV", "Vatu");
+		CURRENCY_MAP.put("VEF", "Bolivar Fuerte");
+		CURRENCY_MAP.put("VND", "Dong");
+		CURRENCY_MAP.put("USD", "US Dollar");
+		CURRENCY_MAP.put("XPF", "CFP Franc");
+		CURRENCY_MAP.put("MAD", "Moroccan Dirham");
+		CURRENCY_MAP.put("YER", "Yemeni Rial");
+		CURRENCY_MAP.put("ZMK", "Zambian Kwacha");
+		//CURRENCY_MAP.put("ZWL", "Zimbabwe Dollar");
+		
+
+
+	}
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/constants/ShippingConstants.java b/sm-core/src/main/java/com/salesmanager/core/constants/ShippingConstants.java
new file mode 100644
index 0000000..8384db4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/constants/ShippingConstants.java
@@ -0,0 +1,10 @@
+package com.salesmanager.core.constants;
+
+
+public class ShippingConstants {
+	
+	public final static String SHIPPING_CONFIGURATION= "SHIPPING_CONFIG";
+	public final static String SHIPPING_NATIONAL = "NATIONAL";
+	public final static String SHIPPING_INTERNATIONAL = "INTERNATIONAL";
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/constants/SystemConstants.java b/sm-core/src/main/java/com/salesmanager/core/constants/SystemConstants.java
new file mode 100644
index 0000000..218be09
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/constants/SystemConstants.java
@@ -0,0 +1,11 @@
+package com.salesmanager.core.constants;
+
+public class SystemConstants {
+	
+	
+
+	public final static String SYSTEM_USER = "SYSTEM";
+	public final static String CONFIG_VALUE_TRUE = "true";
+	public final static String CONFIG_VALUE_FALSE = "false";
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/ImageGet.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/ImageGet.java
new file mode 100755
index 0000000..526df7b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/ImageGet.java
@@ -0,0 +1,15 @@
+package com.salesmanager.core.modules.cms.common;
+
+import java.util.List;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+public interface ImageGet
+{
+
+    public List<OutputContentFile> getImages( final String merchantStoreCode, FileContentType imageContentType )
+        throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/ImageRemove.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/ImageRemove.java
new file mode 100755
index 0000000..a767e91
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/ImageRemove.java
@@ -0,0 +1,11 @@
+package com.salesmanager.core.modules.cms.common;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+
+public interface ImageRemove {
+	
+	
+	public void removeImages(final String merchantStoreCode) throws ServiceException;
+	
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/StaticContentData.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/StaticContentData.java
new file mode 100644
index 0000000..121f0af
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/common/StaticContentData.java
@@ -0,0 +1,52 @@
+/**
+ * 
+ */
+package com.salesmanager.core.modules.cms.common;
+
+import java.io.Serializable;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+
+
+/**
+ * Abstract class for Static content data containing common attributes
+ * for handling static content data.
+ * 
+ * @author Umesh Awasthi
+ *@since 1.2
+ */
+public abstract class StaticContentData implements Serializable
+{
+
+   
+    private static final long serialVersionUID = 1L;
+    private String fileName;
+    private FileContentType contentType = FileContentType.STATIC_FILE;
+    private String fileContentType;
+    
+    public String getFileName()
+    {
+        return fileName;
+    }
+    public void setFileName( String fileName )
+    {
+        this.fileName = fileName;
+    }
+
+    public String getFileContentType()
+    {
+        return fileContentType;
+    }
+    public void setFileContentType( String fileContentType )
+    {
+        this.fileContentType = fileContentType;
+    }
+	public void setContentType(FileContentType contentType) {
+		this.contentType = contentType;
+	}
+	public FileContentType getContentType() {
+		return contentType;
+	}
+    
+    
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/CmsStaticContentFileManagerInfinispanImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/CmsStaticContentFileManagerInfinispanImpl.java
new file mode 100644
index 0000000..df01248
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/CmsStaticContentFileManagerInfinispanImpl.java
@@ -0,0 +1,445 @@
+/**
+ * 
+ */
+package com.salesmanager.core.modules.cms.content;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.net.FileNameMap;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.infinispan.tree.Fqn;
+import org.infinispan.tree.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.modules.cms.impl.CacheManager;
+
+
+
+/**
+ * Manages
+ * - Images
+ * - Files (js, pdf, css...)
+ * @author Umesh Awasthi
+ * @since 1.2
+ *
+ */
+public class CmsStaticContentFileManagerInfinispanImpl implements FilePut,FileGet,FileRemove
+{
+
+    private static final Logger LOGGER = LoggerFactory.getLogger( CmsStaticContentFileManagerInfinispanImpl.class );
+    private static CmsStaticContentFileManagerInfinispanImpl fileManager = null;
+    private static final String ROOT_NAME="static-merchant-";
+    
+    private String rootName = ROOT_NAME;
+    
+    private CacheManager cacheManager;
+    
+    public void stopFileManager()
+    {
+
+        try
+        {
+            cacheManager.getManager().stop();
+            LOGGER.info( "Stopping CMS" );
+        }
+        catch ( final Exception e )
+        {
+            LOGGER.error( "Error while stopping CmsStaticContentFileManager", e );
+        }
+    }
+
+    public static CmsStaticContentFileManagerInfinispanImpl getInstance()
+    {
+
+        if ( fileManager == null )
+        {
+            fileManager = new CmsStaticContentFileManagerInfinispanImpl();
+        }
+
+        return fileManager;
+
+    }
+
+    
+    /**
+     * <p>Method to add static content data for given merchant.Static content data can be of following type
+     * <pre>
+     * 1. CSS and JS files
+     * 2. Digital Data like audio or video
+     * </pre>
+     * </p>
+     * <p>
+     * Merchant store code will be used to create cache node where merchant data will be stored,input data will
+     * contain name, file as well type of data being stored.
+     * @see FileContentType
+     * </p>
+     *  
+     * @param merchantStoreCode merchant store for whom data is being stored
+     * @param inputStaticContentData data object being stored
+     * @throws ServiceException
+     * 
+     */
+    @Override
+    public void addFile( final String merchantStoreCode, final InputContentFile inputStaticContentData )
+        throws ServiceException
+    {
+        if ( cacheManager.getTreeCache() == null )
+        {
+            LOGGER.error( "Unable to find cacheManager.getTreeCache() in Infinispan.." );
+            throw new ServiceException( "CmsStaticContentFileManagerInfinispanImpl has a null cacheManager.getTreeCache()" );
+        }
+        try
+        {
+            
+    		String nodePath = this.getNodePath(merchantStoreCode, inputStaticContentData.getFileContentType());
+        	
+    		final Node<String, Object> merchantNode = this.getNode(nodePath);
+    		
+    		merchantNode.put(inputStaticContentData.getFileName(), IOUtils.toByteArray( inputStaticContentData.getFile() ));
+            
+            LOGGER.info( "Content data added successfully." );
+        }
+        catch ( final Exception e )
+        {
+            LOGGER.error( "Error while saving static content data", e );
+            throw new ServiceException( e );
+
+        }
+        
+    }
+
+    /**
+     * <p>
+     * Method to add files for given store.Files will be stored in Infinispan and will be retrieved based on
+     * the storeID. Following steps will be performed to store static content files
+     * </p>
+     * <li>Merchant Node will be retrieved from the cacheTree if it exists else new node will be created.</li> <li>
+     * Files will be stored in StaticContentCacheAttribute , which eventually will be stored in Infinispan</li>
+     * 
+     * @param merchantStoreCode Merchant store for which files are getting stored in Infinispan.
+     * @param inputStaticContentDataList input static content file list which will get {@link InputContentImage} stored
+     * @throws ServiceException if content file storing process fail.
+     * @see InputStaticContentData
+     * @see StaticContentCacheAttribute
+     */
+    @Override
+    public void addFiles( final String merchantStoreCode, final List<InputContentFile> inputStaticContentDataList )
+        throws ServiceException
+    {
+        if ( cacheManager.getTreeCache() == null )
+        {
+            LOGGER.error( "Unable to find cacheManager.getTreeCache() in Infinispan.." );
+            throw new ServiceException( "CmsStaticContentFileManagerInfinispanImpl has a null cacheManager.getTreeCache()" );
+        }
+        try
+        {
+          
+          for(final InputContentFile inputStaticContentData:inputStaticContentDataList){
+ 
+
+    		  String nodePath = this.getNodePath(merchantStoreCode, inputStaticContentData.getFileContentType());
+    		  final Node<String, Object> merchantNode = this.getNode(nodePath);
+    		  merchantNode.put(inputStaticContentData.getFileName(), IOUtils.toByteArray( inputStaticContentData.getFile() ));
+            
+
+            }
+          
+          
+            
+            LOGGER.info( "Total {} files added successfully.",inputStaticContentDataList.size() );
+
+        }
+        catch ( final Exception e )
+        {
+            LOGGER.error( "Error while saving content image", e );
+            throw new ServiceException( e );
+
+        }
+     }
+ 
+
+    /**
+     * Method to return static data for given Merchant store based on the file name. Content data will be searched
+     * in underlying Infinispan cache tree and {@link OutputStaticContentData} will be returned on finding an associated
+     * file. In case of no file, null be returned.
+     * 
+     * @param store Merchant store
+     * @param contentFileName name of file being requested
+     * @return {@link OutputStaticContentData}
+     * @throws ServiceException
+     */
+    @Override
+    public OutputContentFile getFile( final String merchantStoreCode, final FileContentType fileContentType, final String contentFileName )
+        throws ServiceException
+    {
+       
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsStaticContentFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+        OutputContentFile outputStaticContentData=null;
+        InputStream input = null;
+        try
+        {
+            
+        	
+    		String nodePath = this.getNodePath(merchantStoreCode, fileContentType);
+        	
+    		final Node<String, Object> merchantNode = this.getNode(nodePath);
+    		
+
+            final byte[] fileBytes= (byte[]) merchantNode.get( contentFileName );
+            
+            if ( fileBytes == null )
+            {
+                LOGGER.warn( "file byte is null, no file found" );
+                return null;
+            }
+
+            input=new ByteArrayInputStream( fileBytes );
+           
+            final ByteArrayOutputStream output = new ByteArrayOutputStream();
+            IOUtils.copy( input, output );
+            
+            outputStaticContentData=new OutputContentFile();
+            outputStaticContentData.setFile( output );
+            outputStaticContentData.setMimeType( URLConnection.getFileNameMap().getContentTypeFor(contentFileName) );
+            outputStaticContentData.setFileName( contentFileName );
+            outputStaticContentData.setFileContentType( fileContentType );
+            
+        }
+        catch ( final Exception e )
+        {
+            LOGGER.error( "Error while fetching file for {} merchant ", merchantStoreCode);
+            throw new ServiceException( e );
+        }
+       return outputStaticContentData != null ? outputStaticContentData : null;
+    }
+    
+    
+	@Override
+	public List<OutputContentFile> getFiles(
+			final String merchantStoreCode, final FileContentType staticContentType) throws ServiceException {
+
+		
+		
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsStaticContentFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+        List<OutputContentFile> images = new ArrayList<OutputContentFile>();
+        try
+        {
+            
+        	FileNameMap fileNameMap = URLConnection.getFileNameMap();
+    		String nodePath = this.getNodePath(merchantStoreCode, staticContentType);
+        	
+    		final Node<String, Object> merchantNode = this.getNode(nodePath);
+    		
+            for(String key : merchantNode.getKeys()) {
+            	
+                byte[] imageBytes = (byte[])merchantNode.get( key );
+
+                OutputContentFile contentImage = new OutputContentFile();
+
+                InputStream input = new ByteArrayInputStream( imageBytes );
+                ByteArrayOutputStream output = new ByteArrayOutputStream();
+                IOUtils.copy( input, output );
+
+                String contentType = fileNameMap.getContentTypeFor( key );
+
+                contentImage.setFile( output );
+                contentImage.setMimeType( contentType );
+                contentImage.setFileName( key );
+
+                images.add( contentImage );
+            	
+            	
+            }
+            
+
+            
+        }
+        catch ( final Exception e )
+        {
+            LOGGER.error( "Error while fetching file for {} merchant ", merchantStoreCode);
+            throw new ServiceException( e );
+        }
+
+		
+		return images;
+		
+		
+	}
+    
+    
+
+    @Override
+    public void removeFile( final String merchantStoreCode, final FileContentType staticContentType, final String fileName )
+        throws ServiceException
+    {
+
+    	
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsStaticContentFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+
+        try
+        {
+            
+        	
+        	String nodePath = this.getNodePath(merchantStoreCode, staticContentType);
+        	final Node<String, Object> merchantNode = this.getNode(nodePath);
+        	
+        	merchantNode.remove(fileName);
+
+        }
+        catch ( final Exception e )
+        {
+            LOGGER.error( "Error while fetching file for {} merchant ", merchantStoreCode);
+            throw new ServiceException( e );
+        }
+
+        
+    }
+
+    /**
+     * Removes the data in a given merchant node
+     */
+    @SuppressWarnings("unchecked")
+	@Override
+    public void removeFiles( final String merchantStoreCode )
+        throws ServiceException
+    {
+        
+        LOGGER.info( "Removing all images for {} merchant ",merchantStoreCode);
+        if ( cacheManager.getTreeCache() == null )
+        {
+            LOGGER.error( "Unable to find cacheManager.getTreeCache() in Infinispan.." );
+            throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+        
+        try
+        {
+            
+        	
+			final StringBuilder merchantPath = new StringBuilder();
+	        merchantPath.append( getRootName()).append(merchantStoreCode );
+	        cacheManager.getTreeCache().getRoot().remove(merchantPath.toString());
+        	
+        	
+
+
+        }
+        catch ( final Exception e )
+        {
+            LOGGER.error( "Error while deleting content image for {} merchant ", merchantStoreCode);
+            throw new ServiceException( e );
+        }
+
+    }
+    
+	@SuppressWarnings({ "unchecked"})
+	private Node<String, Object> getNode( final String node )
+    {
+        LOGGER.debug( "Fetching node for store {} from Infinispan", node );
+        final StringBuilder merchantPath = new StringBuilder();
+        merchantPath.append( getRootName() ).append(node);
+
+        Fqn contentFilesFqn = Fqn.fromString(merchantPath.toString()); 
+
+		Node<String,Object> nd = cacheManager.getTreeCache().getRoot().getChild(contentFilesFqn); 
+        
+        if(nd==null) {
+
+            cacheManager.getTreeCache().getRoot().addChild(contentFilesFqn);
+            nd = cacheManager.getTreeCache().getRoot().getChild(contentFilesFqn); 
+
+        }
+        
+        return nd;
+
+    }
+    
+    private String getNodePath(final String storeCode,final FileContentType contentType) {
+    	
+		StringBuilder nodePath = new StringBuilder();
+		nodePath.append(storeCode).append("/").append(contentType.name());
+    	
+		return nodePath.toString();
+    	
+    }
+    
+
+    
+    public CacheManager getCacheManager() {
+        return cacheManager;
+    }
+
+    public void setCacheManager(CacheManager cacheManager) {
+        this.cacheManager = cacheManager;
+    }
+
+
+    /**
+     * Queries the CMS to retrieve all static content files. Only the name of the file will be returned to the client
+     * @param merchantStoreCode
+     * @return
+     * @throws ServiceException
+     */
+	@Override
+	public List<String> getFileNames(final String merchantStoreCode, final FileContentType staticContentType)
+			throws ServiceException {
+		
+		
+		
+	       if ( cacheManager.getTreeCache() == null )
+	        {
+	            throw new ServiceException( "CmsStaticContentFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+	        }
+
+	        try
+	        {
+
+	        	
+	        	
+	        	String nodePath = this.getNodePath(merchantStoreCode, staticContentType);
+	        	final Node<String, Object> objectNode = this.getNode(nodePath);
+	    		
+	    		if(objectNode.getKeys().isEmpty()) {
+	    			LOGGER.warn( "Unable to find content attribute for given merchant" );
+	                return Collections.<String> emptyList();
+	    		}
+	    		return new ArrayList<String>(objectNode.getKeys());
+
+	        }
+	        catch ( final Exception e )
+	        {
+	            LOGGER.error( "Error while fetching file for {} merchant ", merchantStoreCode);
+	            throw new ServiceException( e );
+	        }
+
+	}
+
+	public void setRootName(String rootName) {
+		this.rootName = rootName;
+	}
+
+	public String getRootName() {
+		return rootName;
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ContentImageGet.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ContentImageGet.java
new file mode 100755
index 0000000..df285ea
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ContentImageGet.java
@@ -0,0 +1,15 @@
+package com.salesmanager.core.modules.cms.content;
+
+import java.util.List;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.modules.cms.common.ImageGet;
+
+public interface ContentImageGet extends ImageGet {
+	
+	public OutputContentFile getImage(final String merchantStoreCode, String imageName,FileContentType imageContentType) throws ServiceException;
+	public List<String> getImageNames(final String merchantStoreCode, FileContentType imageContentType) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ContentImageRemove.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ContentImageRemove.java
new file mode 100755
index 0000000..75f0c89
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ContentImageRemove.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.modules.cms.content;
+
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.modules.cms.common.ImageRemove;
+
+public interface ContentImageRemove extends ImageRemove {
+	
+	
+	
+	public void removeImage(final String merchantStoreCode,final FileContentType imageContentType, final String imageName) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FileGet.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FileGet.java
new file mode 100644
index 0000000..80bddc8
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FileGet.java
@@ -0,0 +1,21 @@
+package com.salesmanager.core.modules.cms.content;
+
+import java.util.List;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+
+/**
+ * Methods to retrieve the static content from the CMS
+ * @author Carl Samson
+ *
+ */
+public interface FileGet
+{
+
+	public OutputContentFile getFile(final String merchantStoreCode, FileContentType fileContentType, String contentName) throws ServiceException;
+    public List<String> getFileNames(final String merchantStoreCode,FileContentType fileContentType) throws ServiceException;
+    public List<OutputContentFile> getFiles(final String merchantStoreCode, FileContentType fileContentType) throws ServiceException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FilePut.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FilePut.java
new file mode 100644
index 0000000..e6c78c9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FilePut.java
@@ -0,0 +1,20 @@
+/**
+ * 
+ */
+package com.salesmanager.core.modules.cms.content;
+
+import java.util.List;
+
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+
+/**
+ * @author Umesh Awasthi
+ *
+ */
+public interface FilePut
+{
+    public void addFile(final String merchantStoreCode, InputContentFile inputStaticContentData) throws ServiceException;
+    public void addFiles(final String merchantStoreCode, List<InputContentFile> inputStaticContentDataList) throws ServiceException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FileRemove.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FileRemove.java
new file mode 100644
index 0000000..bc72996
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/FileRemove.java
@@ -0,0 +1,19 @@
+/**
+ * 
+ */
+package com.salesmanager.core.modules.cms.content;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+
+/**
+ * @author Umesh Awasthi
+ *
+ */
+public interface FileRemove
+{
+    public void removeFile(String merchantStoreCode, FileContentType staticContentType, String fileName) throws ServiceException;
+    public void removeFiles(String merchantStoreCode) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ImagePut.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ImagePut.java
new file mode 100755
index 0000000..1702794
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/ImagePut.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.modules.cms.content;
+
+import java.util.List;
+
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+public interface ImagePut {
+	
+	
+	public void addImage(final String merchantStoreCode, InputContentFile image) throws ServiceException;
+	public void addImages(final String merchantStoreCode, List<InputContentFile> imagesList) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/StaticContentFileManager.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/StaticContentFileManager.java
new file mode 100644
index 0000000..73b6669
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/StaticContentFileManager.java
@@ -0,0 +1,13 @@
+/**
+ * 
+ */
+package com.salesmanager.core.modules.cms.content;
+
+/**
+ * @author Umesh Awasthi
+ *
+ */
+public abstract class StaticContentFileManager implements FileGet,FilePut,FileRemove
+{
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/StaticContentFileManagerImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/StaticContentFileManagerImpl.java
new file mode 100644
index 0000000..a2b6fc6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/content/StaticContentFileManagerImpl.java
@@ -0,0 +1,110 @@
+/**
+ * 
+ */
+package com.salesmanager.core.modules.cms.content;
+
+import java.util.List;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+
+/**
+ * @author Umesh Awasthi
+ *
+ */
+public class StaticContentFileManagerImpl extends StaticContentFileManager
+{
+
+    private FilePut uploadFile;
+    private FileGet getFile;
+    private FileRemove removeFile;
+
+
+    
+    @Override
+    public void addFile( final String merchantStoreCode, final InputContentFile inputStaticContentData )
+        throws ServiceException
+    {
+    	uploadFile.addFile( merchantStoreCode, inputStaticContentData );
+        
+    }
+    
+    /**
+     * Implementation for add static data files. This method will called respected add files method of underlying
+     * CMSStaticContentManager. For CMS Content files {@link CmsStaticContentFileManagerInfinispanImpl} will take care of adding
+     * given content images with Infinispan cache.
+     * 
+     * @param merchantStoreCode merchant store.
+     * @param inputStaticContentDataList Input content images
+     * @throws ServiceException
+     */
+    @Override
+    public void addFiles( final String merchantStoreCode, final List<InputContentFile> inputStaticContentDataList )
+        throws ServiceException
+    {
+    	uploadFile.addFiles( merchantStoreCode, inputStaticContentDataList );
+    }
+    @Override
+    public void removeFile( final String merchantStoreCode, final FileContentType staticContentType, final String fileName)
+        throws ServiceException
+    {
+    	removeFile.removeFile(merchantStoreCode, staticContentType, fileName);
+        
+    }
+
+
+	@Override
+	public OutputContentFile getFile(String merchantStoreCode,
+			FileContentType fileContentType, String contentName)
+			throws ServiceException {
+		return getFile.getFile(merchantStoreCode, fileContentType, contentName);
+	}
+
+	@Override
+	public List<String> getFileNames(String merchantStoreCode,
+			FileContentType fileContentType) throws ServiceException {
+		return getFile.getFileNames(merchantStoreCode, fileContentType);
+	}
+
+	@Override
+	public List<OutputContentFile> getFiles(String merchantStoreCode,
+			FileContentType fileContentType) throws ServiceException {
+		return getFile.getFiles(merchantStoreCode, fileContentType);
+	}
+
+	@Override
+	public void removeFiles(String merchantStoreCode) throws ServiceException {
+		removeFile.removeFiles(merchantStoreCode);
+	}
+    
+   
+
+	public void setRemoveFile(FileRemove removeFile) {
+		this.removeFile = removeFile;
+	}
+
+	public FileRemove getRemoveFile() {
+		return removeFile;
+	}
+
+	public void setGetFile(FileGet getFile) {
+		this.getFile = getFile;
+	}
+
+	public FileGet getGetFile() {
+		return getFile;
+	}
+
+	public void setUploadFile(FilePut uploadFile) {
+		this.uploadFile = uploadFile;
+	}
+
+	public FilePut getUploadFile() {
+		return uploadFile;
+	}
+  
+    
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/CacheManager.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/CacheManager.java
new file mode 100644
index 0000000..7a678dc
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/CacheManager.java
@@ -0,0 +1,13 @@
+package com.salesmanager.core.modules.cms.impl;
+
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.infinispan.tree.TreeCache;
+
+public interface CacheManager {
+	
+	public EmbeddedCacheManager getManager();
+	
+	@SuppressWarnings("rawtypes")
+	public TreeCache getTreeCache();
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/CacheManagerImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/CacheManagerImpl.java
new file mode 100644
index 0000000..e45234c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/CacheManagerImpl.java
@@ -0,0 +1,65 @@
+package com.salesmanager.core.modules.cms.impl;
+
+import org.infinispan.Cache;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.infinispan.tree.TreeCache;
+import org.infinispan.tree.TreeCacheFactory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public abstract class CacheManagerImpl implements CacheManager {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(CacheManagerImpl.class);
+
+	@SuppressWarnings("rawtypes")
+	private TreeCache treeCache = null;
+
+	@SuppressWarnings("unchecked")
+	protected void init(String namedCache) {
+		
+		
+		try {
+			
+
+				 //manager = new DefaultCacheManager(repositoryFileName);
+			
+				 VendorCacheManager cacheManager =  VendorCacheManager.getInstance();
+
+				 @SuppressWarnings("rawtypes")
+				 Cache cache = cacheManager.getManager().getCache(namedCache);
+				 cache.getCacheConfiguration().invocationBatching().enabled();
+		    
+				 TreeCacheFactory f = new TreeCacheFactory();
+		    
+				 treeCache = f.createTreeCache(cache);
+				 
+				 cache.start();
+	
+		         LOGGER.debug("CMS started");
+
+
+
+      } catch (Exception e) {
+      	LOGGER.error("Error while instantiating CmsImageFileManager",e);
+      } finally {
+          
+      }
+		
+		
+		
+		
+		
+	}
+	
+	public EmbeddedCacheManager getManager() {
+		return VendorCacheManager.getInstance().getManager();
+	}
+
+	@SuppressWarnings("rawtypes")
+	public TreeCache getTreeCache() {
+		return treeCache;
+	}
+	
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/StaticContentCacheManagerImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/StaticContentCacheManagerImpl.java
new file mode 100644
index 0000000..d974b40
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/StaticContentCacheManagerImpl.java
@@ -0,0 +1,42 @@
+/**
+ * 
+ */
+package com.salesmanager.core.modules.cms.impl;
+
+/**
+ * Cache manager to handle static content data in Infinispan cache.
+ * static content data can be of following type
+ * <pre>
+ * 1. CSS files.
+ * 2. JS Files.
+ * 3. Digital Data.
+ * </pre> 
+ * @author Umesh Awasthi
+ * @version 1.2
+ * 
+ *
+ */
+public class StaticContentCacheManagerImpl extends CacheManagerImpl
+{
+    private static  StaticContentCacheManagerImpl cacheManager = null;
+    private final static String NAMED_CACHE = "FilesRepository";
+    
+
+    private StaticContentCacheManagerImpl() {
+        
+        super.init(NAMED_CACHE);
+        
+        
+    }
+
+   public static StaticContentCacheManagerImpl getInstance() {
+        
+        if(cacheManager==null) {
+            cacheManager = new StaticContentCacheManagerImpl();
+        }
+        
+        return cacheManager;
+      
+        
+    }
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/StoreCacheManagerImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/StoreCacheManagerImpl.java
new file mode 100644
index 0000000..dd13a92
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/StoreCacheManagerImpl.java
@@ -0,0 +1,42 @@
+package com.salesmanager.core.modules.cms.impl;
+
+
+
+/**
+ * Used for managing images
+ * @author casams1
+ *
+ */
+public class StoreCacheManagerImpl extends CacheManagerImpl {
+	
+	
+	private static  StoreCacheManagerImpl cacheManager = null;
+	private final static String NAMED_CACHE = "StoreRepository";
+	
+
+	
+
+	private StoreCacheManagerImpl() {
+		
+		super.init(NAMED_CACHE);
+		
+		
+	}
+
+	
+	public static StoreCacheManagerImpl getInstance() {
+		
+		if(cacheManager==null) {
+			cacheManager = new StoreCacheManagerImpl();
+
+		}
+		
+		return cacheManager;
+		
+		
+	}
+
+
+
+}
+
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/VendorCacheManager.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/VendorCacheManager.java
new file mode 100644
index 0000000..ea7d509
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/impl/VendorCacheManager.java
@@ -0,0 +1,41 @@
+package com.salesmanager.core.modules.cms.impl;
+
+import org.infinispan.manager.DefaultCacheManager;
+import org.infinispan.manager.EmbeddedCacheManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class VendorCacheManager {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(VendorCacheManager.class);
+	private EmbeddedCacheManager manager = null;
+	private static VendorCacheManager vendorCacheManager = null;
+	private String repositoryFileName = "cms/infinispan_configuration.xml";
+	
+
+	
+	private VendorCacheManager(){
+		
+		try {
+			manager = new DefaultCacheManager(repositoryFileName);
+		} catch (Exception e) {
+			LOGGER.error("Cannot start manager " + e.toString());
+		}
+		
+	}
+
+
+	public static VendorCacheManager getInstance() {
+		if(vendorCacheManager==null) {
+			vendorCacheManager = new VendorCacheManager();
+
+		}
+		return vendorCacheManager;
+	}
+
+
+	public EmbeddedCacheManager getManager() {
+		return manager;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/CmsImageFileManagerInfinispanImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/CmsImageFileManagerInfinispanImpl.java
new file mode 100755
index 0000000..514c14f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/CmsImageFileManagerInfinispanImpl.java
@@ -0,0 +1,515 @@
+package com.salesmanager.core.modules.cms.product;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.net.FileNameMap;
+import java.net.URLConnection;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.commons.io.IOUtils;
+import org.infinispan.tree.Fqn;
+import org.infinispan.tree.Node;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.file.ProductImageSize;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.ImageContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.modules.cms.impl.CacheManager;
+
+/**
+ * Manager for storing in retrieving image files from the CMS This is a layer on top of Infinispan
+ * https://docs.jboss.org/author/display/ISPN/Tree+API+Module
+ * 
+ * Manages
+ * - Product images
+ * @author Carl Samson
+ */
+public class CmsImageFileManagerInfinispanImpl
+    implements ProductImagePut, ProductImageGet, ProductImageRemove
+{
+
+    private static final Logger LOGGER = LoggerFactory.getLogger( CmsImageFileManagerInfinispanImpl.class );
+
+    private static CmsImageFileManagerInfinispanImpl fileManager = null;
+    
+    private final static String ROOT_NAME = "product-merchant";
+    
+    private final static String SMALL = "SMALL";
+    private final static String LARGE = "LARGE";
+    
+    private String rootName = ROOT_NAME;
+
+    private CacheManager cacheManager;
+
+    /**
+     * Requires to stop the engine when image servlet un-deploys
+     */
+    public void stopFileManager()
+    {
+
+        try
+        {
+        	cacheManager.getManager().stop();
+            LOGGER.info( "Stopping CMS" );
+        }
+        catch ( Exception e )
+        {
+            LOGGER.error( "Error while stopping CmsImageFileManager", e );
+        }
+    }
+
+    public static CmsImageFileManagerInfinispanImpl getInstance()
+    {
+
+        if ( fileManager == null )
+        {
+            fileManager = new CmsImageFileManagerInfinispanImpl();
+        }
+
+        return fileManager;
+
+    }
+
+    private CmsImageFileManagerInfinispanImpl()
+    {
+
+    }
+
+    /**
+     * root -productFiles -merchant-id PRODUCT-ID(key) -> CacheAttribute(value) - image 1 - image 2 - image 3
+     */
+
+    @Override
+    public void addProductImage( ProductImage productImage,
+    		ImageContentFile contentImage )
+        throws ServiceException
+    {
+
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+
+        try
+        {
+
+            // node
+        	StringBuilder nodePath = new StringBuilder();
+        	nodePath.append(productImage.getProduct().getMerchantStore().getCode()).append(Constants.SLASH).append(productImage.getProduct().getSku()).append(Constants.SLASH);
+
+            
+        	if(contentImage.getFileContentType().name().equals(FileContentType.PRODUCT.name())) {
+        		nodePath.append(SMALL);
+        	} else if(contentImage.getFileContentType().name().equals(FileContentType.PRODUCTLG.name())) {
+        		nodePath.append(LARGE);
+        	}
+        	
+        	Node<String, Object> productNode = this.getNode(nodePath.toString());
+
+            
+            InputStream isFile = contentImage.getFile();
+            
+            ByteArrayOutputStream output = new ByteArrayOutputStream();
+            IOUtils.copy( isFile, output );
+            
+
+            // object for a given product containing all images
+            productNode.put(contentImage.getFileName(), output.toByteArray());
+
+
+        }
+        catch ( Exception e )
+        {
+
+            throw new ServiceException( e );
+
+        }
+
+    }
+
+    @Override
+    public OutputContentFile getProductImage( ProductImage productImage )
+        throws ServiceException
+    {
+
+       return getProductImage(productImage.getProduct().getMerchantStore().getCode(),productImage.getProduct().getSku(),productImage.getProductImage());
+
+    }
+
+
+    public List<OutputContentFile> getImages( MerchantStore store, FileContentType imageContentType )
+        throws ServiceException
+    {
+
+         return getImages(store.getCode(),imageContentType);
+
+    }
+
+    @Override
+    public List<OutputContentFile> getImages( Product product )
+        throws ServiceException
+    {
+
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+
+        List<OutputContentFile> images = new ArrayList<OutputContentFile>();
+        
+
+        try
+        {
+
+
+        	FileNameMap fileNameMap = URLConnection.getFileNameMap();
+        	StringBuilder nodePath = new StringBuilder();
+        	nodePath.append(product.getMerchantStore().getCode());
+
+            Node<String, Object> merchantNode = this.getNode(nodePath.toString());
+
+            if ( merchantNode == null )
+            {
+                return null;
+            }
+            
+            
+            for(String key : merchantNode.getKeys()) {
+            	
+                byte[] imageBytes = (byte[])merchantNode.get( key );
+
+                OutputContentFile contentImage = new OutputContentFile();
+
+                InputStream input = new ByteArrayInputStream( imageBytes );
+                ByteArrayOutputStream output = new ByteArrayOutputStream();
+                IOUtils.copy( input, output );
+
+                String contentType = fileNameMap.getContentTypeFor( key );
+
+                contentImage.setFile( output );
+                contentImage.setMimeType( contentType );
+                contentImage.setFileName( key );
+
+                images.add( contentImage );
+            	
+            	
+            }
+            
+            
+        }
+
+        catch ( Exception e )
+        {
+            throw new ServiceException( e );
+        }
+        finally
+        {
+
+        }
+
+        return images;
+    }
+
+
+
+	@SuppressWarnings("unchecked")
+	@Override
+    public void removeImages( final String merchantStoreCode )
+        throws ServiceException
+    {
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+
+        try
+        {
+
+
+			final StringBuilder merchantPath = new StringBuilder();
+	        merchantPath.append( getRootName()).append(merchantStoreCode );
+	        cacheManager.getTreeCache().getRoot().remove(merchantPath.toString());
+			
+
+
+        }
+        catch ( Exception e )
+        {
+            throw new ServiceException( e );
+        }
+        finally
+        {
+
+        }
+
+    }
+
+
+    @Override
+    public void removeProductImage( ProductImage productImage )
+        throws ServiceException
+    {
+
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+
+        try
+        {
+
+        	
+        	StringBuilder nodePath = new StringBuilder();
+        	nodePath.append(productImage.getProduct().getMerchantStore().getCode()).append(Constants.SLASH).append(productImage.getProduct().getSku());
+        	
+        	
+        	Node<String, Object> productNode = this.getNode(nodePath.toString());
+        	productNode.remove(productImage.getProductImage());
+        	
+
+            
+            
+
+        }
+        catch ( Exception e )
+        {
+            throw new ServiceException( e );
+        }
+        finally
+        {
+
+        }
+
+    }
+
+    @Override
+    public void removeProductImages( Product product )
+        throws ServiceException
+    {
+
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+
+        try
+        {
+
+        	
+        	StringBuilder nodePath = new StringBuilder();
+        	nodePath.append(product.getMerchantStore().getCode());
+        	
+        	
+        	Node<String, Object> merchantNode = this.getNode(nodePath.toString());
+        	
+        	merchantNode.remove(product.getSku());
+        	
+
+            
+
+        }
+        catch ( Exception e )
+        {
+            throw new ServiceException( e );
+        }
+        finally
+        {
+
+        }
+
+    }
+
+
+    @Override
+	public List<OutputContentFile> getImages(final String merchantStoreCode,
+			FileContentType imageContentType) throws ServiceException {
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+        List<OutputContentFile> images = new ArrayList<OutputContentFile>();
+        FileNameMap fileNameMap = URLConnection.getFileNameMap();
+
+        try
+        {
+
+        	
+        	StringBuilder nodePath = new StringBuilder();
+        	nodePath.append(merchantStoreCode);
+        	
+        	
+        	Node<String, Object> merchantNode = this.getNode(nodePath.toString());
+        	
+        	Set<Node<String,Object>> childs = merchantNode.getChildren();
+        	
+        	Iterator<Node<String,Object>> iterator = childs.iterator();
+        	//TODO image sizes
+        	while(iterator.hasNext()) {
+        		
+        		Node<String,Object> node = iterator.next();
+        		
+                for(String key : node.getKeys()) {
+                	
+
+                    byte[] imageBytes = (byte[])merchantNode.get( key );
+
+                    OutputContentFile contentImage = new OutputContentFile();
+
+                    InputStream input = new ByteArrayInputStream( imageBytes );
+                    ByteArrayOutputStream output = new ByteArrayOutputStream();
+                    IOUtils.copy( input, output );
+
+                    String contentType = fileNameMap.getContentTypeFor( key );
+
+                    contentImage.setFile( output );
+                    contentImage.setMimeType( contentType );
+                    contentImage.setFileName( key );
+
+                    images.add( contentImage );
+                	
+                	
+                }
+        		
+        	}
+        	
+          
+
+
+        }
+        catch ( Exception e )
+        {
+            throw new ServiceException( e );
+        }
+        finally
+        {
+
+        }
+
+        return images;
+	}
+
+	@Override
+	public OutputContentFile getProductImage(String merchantStoreCode,
+			String productCode, String imageName) throws ServiceException {
+		return getProductImage(merchantStoreCode, productCode, imageName, ProductImageSize.SMALL.name());
+	}
+	
+	@Override
+	public OutputContentFile getProductImage(String merchantStoreCode,
+			String productCode, String imageName, ProductImageSize size)
+			throws ServiceException {
+		return getProductImage(merchantStoreCode, productCode, imageName, size.name());
+	}
+	
+	private OutputContentFile getProductImage(String merchantStoreCode,
+			String productCode, String imageName, String size) throws ServiceException {
+		
+        if ( cacheManager.getTreeCache() == null )
+        {
+            throw new ServiceException( "CmsImageFileManagerInfinispan has a null cacheManager.getTreeCache()" );
+        }
+        InputStream input = null;
+        OutputContentFile contentImage = new OutputContentFile();
+        try
+        {
+        	
+        	FileNameMap fileNameMap = URLConnection.getFileNameMap();
+        	
+        	//SMALL by default
+        	StringBuilder nodePath = new StringBuilder();
+        	nodePath.append(merchantStoreCode).append(Constants.SLASH).append(productCode).append(Constants.SLASH).append(size);
+        	
+        	Node<String,Object> productNode = this.getNode(nodePath.toString());
+        	
+            byte[] imageBytes = (byte[])productNode.get( imageName );
+
+
+
+            input = new ByteArrayInputStream( imageBytes );
+            ByteArrayOutputStream output = new ByteArrayOutputStream();
+            IOUtils.copy( input, output );
+
+            String contentType = fileNameMap.getContentTypeFor( imageName );
+
+            contentImage.setFile( output );
+            contentImage.setMimeType( contentType );
+            contentImage.setFileName( imageName );
+
+
+
+        }
+        catch ( Exception e )
+        {
+            throw new ServiceException( e );
+        }
+        finally
+        {
+            if ( input != null )
+            {
+                try
+                {
+                    input.close();
+                }
+                catch ( Exception ignore )
+                {
+                }
+            }
+        }
+
+        return contentImage;
+		
+	}
+
+	
+	@SuppressWarnings("unchecked")
+	private Node<String, Object> getNode( final String node )
+    {
+        LOGGER.debug( "Fetching node for store {} from Infinispan", node );
+        final StringBuilder merchantPath = new StringBuilder();
+        merchantPath.append( getRootName() ).append(node);
+
+        Fqn contentFilesFqn = Fqn.fromString(merchantPath.toString()); 
+
+		Node<String,Object> nd = cacheManager.getTreeCache().getRoot().getChild(contentFilesFqn); 
+        
+        if(nd==null) {
+
+            cacheManager.getTreeCache().getRoot().addChild(contentFilesFqn);
+            nd = cacheManager.getTreeCache().getRoot().getChild(contentFilesFqn); 
+
+        }
+        
+        return nd;
+
+    }
+
+	public CacheManager getCacheManager() {
+		return cacheManager;
+	}
+
+	public void setCacheManager(CacheManager cacheManager) {
+		this.cacheManager = cacheManager;
+	}
+
+	public void setRootName(String rootName) {
+		this.rootName = rootName;
+	}
+
+	public String getRootName() {
+		return rootName;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductFileManager.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductFileManager.java
new file mode 100755
index 0000000..63c2417
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductFileManager.java
@@ -0,0 +1,11 @@
+package com.salesmanager.core.modules.cms.product;
+
+
+
+
+public abstract class  ProductFileManager implements ProductImagePut, ProductImageGet, ProductImageRemove {
+	
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductFileManagerImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductFileManagerImpl.java
new file mode 100755
index 0000000..dce5a90
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductFileManagerImpl.java
@@ -0,0 +1,356 @@
+package com.salesmanager.core.modules.cms.product;
+
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.FileNameMap;
+import java.net.URLConnection;
+import java.util.List;
+
+import javax.imageio.ImageIO;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.file.ProductImageSize;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.ImageContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.utils.CoreConfiguration;
+import com.salesmanager.core.utils.ProductImageCropUtils;
+import com.salesmanager.core.utils.ProductImageSizeUtils;
+
+
+public class ProductFileManagerImpl extends ProductFileManager {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ProductFileManagerImpl.class);
+	
+
+	private ProductImagePut uploadImage;
+	private ProductImageGet getImage;
+	private ProductImageRemove removeImage;
+	
+	private CoreConfiguration configuration;
+	
+	private final static String PRODUCT_IMAGE_HEIGHT_SIZE = "PRODUCT_IMAGE_HEIGHT_SIZE";
+	private final static String PRODUCT_IMAGE_WIDTH_SIZE = "PRODUCT_IMAGE_WIDTH_SIZE";
+	private final static String CROP_UPLOADED_IMAGES ="CROP_UPLOADED_IMAGES";
+
+
+	public CoreConfiguration getConfiguration() {
+		return configuration;
+	}
+
+
+	public void setConfiguration(CoreConfiguration configuration) {
+		this.configuration = configuration;
+	}
+
+
+	public ProductImageRemove getRemoveImage() {
+		return removeImage;
+	}
+
+
+	public void setRemoveImage(ProductImageRemove removeImage) {
+		this.removeImage = removeImage;
+	}
+
+
+	public void addProductImage(ProductImage productImage, ImageContentFile contentImage)
+	throws ServiceException {
+	
+	
+	try {
+		
+		/** copy to input stream **/
+	    ByteArrayOutputStream baos = new ByteArrayOutputStream();
+	    // Fake code simulating the copy
+	    // You can generally do better with nio if you need...
+	    // And please, unlike me, do something about the Exceptions :D
+	    byte[] buffer = new byte[1024];
+	    int len;
+	    while ((len = contentImage.getFile().read(buffer)) > -1 ) {
+	        baos.write(buffer, 0, len);
+	    }
+	    baos.flush();
+
+	    // Open new InputStreams using the recorded bytes
+	    // Can be repeated as many times as you wish
+	    InputStream is1 = new ByteArrayInputStream(baos.toByteArray()); 
+	    InputStream is2 = new ByteArrayInputStream(baos.toByteArray()); 
+	    
+	    BufferedImage bufferedImage = ImageIO.read(is2);
+	    //contentImage.setBufferedImage(bufferedImage);
+	    contentImage.setFile(is1);
+
+
+		//upload original -- L
+	    contentImage.setFileContentType(FileContentType.PRODUCTLG);
+		uploadImage.addProductImage(productImage, contentImage);
+
+/*				//default large
+		InputContentImage largeContentImage = new InputContentImage(ImageContentType.PRODUCT);
+		largeContentImage.setFile(contentImage.getFile());
+		largeContentImage.setDefaultImage(productImage.isDefaultImage());
+		largeContentImage.setImageName(new StringBuilder().append("L-").append(productImage.getProductImage()).toString());
+
+		
+		uploadImage.uploadProductImage(configuration, productImage, largeContentImage);*/
+		
+/*				//default small
+		InputContentImage smallContentImage = new InputContentImage(ImageContentType.PRODUCT);
+		smallContentImage.setFile(contentImage.getFile());
+		smallContentImage.setDefaultImage(productImage.isDefaultImage());
+		smallContentImage.setImageName(new StringBuilder().append("S-").append(productImage.getProductImage()).toString());
+		
+		uploadImage.uploadProductImage(configuration, productImage, smallContentImage);*/
+		
+		
+		//get template properties file
+			
+		String slargeImageHeight = configuration.getProperty(PRODUCT_IMAGE_HEIGHT_SIZE);
+		String slargeImageWidth = configuration.getProperty(PRODUCT_IMAGE_WIDTH_SIZE);
+		
+		//String ssmallImageHeight = configuration.getProperty("SMALL_IMAGE_HEIGHT_SIZE");
+		//String ssmallImageWidth = configuration.getProperty("SMALL_IMAGE_WIDTH_SIZE");
+
+			
+		if(!StringUtils.isBlank(slargeImageHeight) && !StringUtils.isBlank(slargeImageWidth)) { //&& !StringUtils.isBlank(ssmallImageHeight) && !StringUtils.isBlank(ssmallImageWidth)) {
+			
+			
+			FileNameMap fileNameMap = URLConnection.getFileNameMap();
+			
+			String contentType = fileNameMap.getContentTypeFor(contentImage.getFileName());
+			String extension = null;
+			if(contentType!=null) {
+				extension = contentType.substring(contentType.indexOf("/")+1,contentType.length());
+			}
+
+			if(extension==null){
+				extension="jpeg";
+			}
+			
+			
+			int largeImageHeight = Integer.parseInt(slargeImageHeight);
+			int largeImageWidth = Integer.parseInt(slargeImageWidth);
+			
+			if(largeImageHeight<=0 || largeImageWidth<=0) {
+				String sizeMsg = "Image configuration set to an invalid value [PRODUCT_IMAGE_HEIGHT_SIZE] " + largeImageHeight + " , [PRODUCT_IMAGE_WIDTH_SIZE] " + largeImageWidth;
+				LOGGER.error(sizeMsg);
+				throw new ServiceException(sizeMsg);
+			}
+
+			if(!StringUtils.isBlank(configuration.getProperty(CROP_UPLOADED_IMAGES)) && configuration.getProperty(CROP_UPLOADED_IMAGES).equals(Constants.TRUE)) {
+					//crop image
+					ProductImageCropUtils utils = new ProductImageCropUtils(bufferedImage, largeImageWidth, largeImageHeight);
+					if(utils.isCropeable()) {
+						bufferedImage = utils.getCroppedImage();
+					} 
+			} 
+				
+				
+			//TODO print cropped image
+			
+			
+				//do not keep a large image for now, just take care of the regular image and a small image
+				
+				//resize large
+				//ByteArrayOutputStream output = new ByteArrayOutputStream();
+				BufferedImage largeResizedImage = ProductImageSizeUtils.resizeWithRatio(bufferedImage, largeImageWidth, largeImageHeight);
+				
+				
+				File tempLarge = File.createTempFile(new StringBuilder().append(productImage.getProduct().getId()).append("tmpLarge").toString(), "." + extension );
+				ImageIO.write(largeResizedImage, extension, tempLarge);
+
+				FileInputStream isLarge = new FileInputStream(tempLarge);
+				
+				 
+	            //IOUtils.copy(isLarge, output);
+				
+
+	            ImageContentFile largeContentImage = new ImageContentFile();
+	            largeContentImage.setFileContentType(FileContentType.PRODUCT);
+	            largeContentImage.setFileName(productImage.getProductImage());
+	            largeContentImage.setFile(isLarge);
+	            
+	            
+	            //largeContentImage.setBufferedImage(bufferedImage);
+				
+	            //largeContentImage.setFile(output);
+				//largeContentImage.setDefaultImage(false);
+				//largeContentImage.setImageName(new StringBuilder().append("L-").append(productImage.getProductImage()).toString());
+
+
+				uploadImage.addProductImage(productImage, largeContentImage);
+				
+				//output.flush();
+				//output.close();
+				
+				tempLarge.delete();
+				
+				//now upload original
+				
+				
+				
+/*						//resize small
+				BufferedImage smallResizedImage = ProductImageSizeUtils.resize(cropped, smallImageWidth, smallImageHeight);
+				File tempSmall = File.createTempFile(new StringBuilder().append(productImage.getProduct().getId()).append("tmpSmall").toString(), "." + extension );
+				ImageIO.write(smallResizedImage, extension, tempSmall);
+				
+				//byte[] is = IOUtils.toByteArray(new FileInputStream(tempSmall));
+				
+				FileInputStream isSmall = new FileInputStream(tempSmall);
+				
+				output = new ByteArrayOutputStream(); 
+	            IOUtils.copy(isSmall, output);
+				
+
+				smallContentImage = new InputContentImage(ImageContentType.PRODUCT);
+				smallContentImage.setFile(output);
+				smallContentImage.setDefaultImage(false);
+				smallContentImage.setImageName(new StringBuilder().append("S-").append(productImage.getProductImage()).toString());
+				
+				uploadImage.uploadProductImage(configuration, productImage, smallContentImage);
+				
+				output.flush();
+				output.close();
+				
+				tempSmall.delete();*/
+			
+			
+
+		} else {
+			//small will be the same as the original
+			contentImage.setFileContentType(FileContentType.PRODUCT);
+			uploadImage.addProductImage(productImage, contentImage);
+		}
+		
+		
+
+
+	
+		
+		
+	} catch (Exception e) {
+		throw new ServiceException(e);
+	} finally {
+		try {
+			productImage.getImage().close();
+		} catch(Exception ignore) {}
+	}
+
+}
+
+	
+	public OutputContentFile getProductImage(ProductImage productImage) throws ServiceException {
+		//will return original
+		return getImage.getProductImage(productImage);
+	}
+
+	
+	@Override
+	public List<OutputContentFile> getImages(final String merchantStoreCode, FileContentType imageContentType)
+			throws ServiceException {
+		//will return original
+		return getImage.getImages(merchantStoreCode,FileContentType.PRODUCT);
+	}
+	
+	@Override
+	public List<OutputContentFile> getImages(Product product)
+			throws ServiceException {
+		return getImage.getImages(product);
+	}
+
+
+
+
+
+
+	@Override
+	public void removeProductImage(ProductImage productImage)
+			throws ServiceException {
+
+		this.removeImage.removeProductImage(productImage);
+		
+/*		ProductImage large = new ProductImage();
+		large.setProduct(productImage.getProduct());
+		large.setProductImage("L" + productImage.getProductImage());
+		
+		this.removeImage.removeProductImage(large);
+		
+		ProductImage small = new ProductImage();
+		small.setProduct(productImage.getProduct());
+		small.setProductImage("S" + productImage.getProductImage());
+		
+		this.removeImage.removeProductImage(small);*/
+		
+	}
+
+
+	@Override
+	public void removeProductImages(Product product) throws ServiceException {
+
+		this.removeImage.removeProductImages(product);
+		
+	}
+
+
+	@Override
+	public void removeImages(final String merchantStoreCode) throws ServiceException {
+		
+		this.removeImage.removeImages(merchantStoreCode);
+		
+	}
+
+
+	public ProductImagePut getUploadImage() {
+		return uploadImage;
+	}
+
+
+	public void setUploadImage(ProductImagePut uploadImage) {
+		this.uploadImage = uploadImage;
+	}
+
+
+	
+
+	public ProductImageGet getGetImage() {
+		return getImage;
+	}
+
+
+	public void setGetImage(ProductImageGet getImage) {
+		this.getImage = getImage;
+	}
+
+
+	@Override
+	public OutputContentFile getProductImage(String merchantStoreCode,
+			String productCode, String imageName) throws ServiceException {
+		return getImage.getProductImage(merchantStoreCode, productCode, imageName);
+	}
+
+
+
+	@Override
+	public OutputContentFile getProductImage(String merchantStoreCode,
+			String productCode, String imageName, ProductImageSize size)
+			throws ServiceException {
+		return getImage.getProductImage(merchantStoreCode, productCode, imageName, size);
+	}
+
+
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImageGet.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImageGet.java
new file mode 100755
index 0000000..ab21b7d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImageGet.java
@@ -0,0 +1,28 @@
+package com.salesmanager.core.modules.cms.product;
+
+import java.util.List;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.file.ProductImageSize;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.modules.cms.common.ImageGet;
+
+public interface ProductImageGet extends ImageGet{
+	
+	/**
+	 * Used for accessing the path directly
+	 * @param merchantStoreCode
+	 * @param product
+	 * @param imageName
+	 * @return
+	 * @throws ServiceException
+	 */
+	public OutputContentFile getProductImage(final String merchantStoreCode, final String productCode, final String imageName) throws ServiceException;
+	public OutputContentFile getProductImage(final String merchantStoreCode, final String productCode, final String imageName, final ProductImageSize size) throws ServiceException;
+	public OutputContentFile getProductImage(ProductImage productImage) throws ServiceException;
+	public List<OutputContentFile> getImages(Product product) throws ServiceException;
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImagePut.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImagePut.java
new file mode 100755
index 0000000..34bc3a0
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImagePut.java
@@ -0,0 +1,14 @@
+package com.salesmanager.core.modules.cms.product;
+
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.content.model.ImageContentFile;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+
+public interface ProductImagePut {
+	
+	
+	public void addProductImage(ProductImage productImage, ImageContentFile contentImage) throws ServiceException;
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImageRemove.java b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImageRemove.java
new file mode 100755
index 0000000..a81776f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/cms/product/ProductImageRemove.java
@@ -0,0 +1,17 @@
+package com.salesmanager.core.modules.cms.product;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.modules.cms.common.ImageRemove;
+
+
+public interface ProductImageRemove extends ImageRemove {
+	
+	
+	public void removeProductImage(ProductImage productImage) throws ServiceException;
+	public void removeProductImages(Product product) throws ServiceException;
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/email/Email.java b/sm-core/src/main/java/com/salesmanager/core/modules/email/Email.java
new file mode 100755
index 0000000..5a6ce76
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/email/Email.java
@@ -0,0 +1,70 @@
+package com.salesmanager.core.modules.email;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.Map;
+
+public class Email implements Serializable {
+	
+	
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 6481794982612826257L;
+	private String from;
+	private String fromEmail;
+	private String to;
+	private String subject;
+	private String templateName;
+	
+	private Map<String,String> templateTokens = new HashMap<String,String>();
+
+	public String getFrom() {
+		return from;
+	}
+
+	public void setFrom(String from) {
+		this.from = from;
+	}
+
+	public String getTo() {
+		return to;
+	}
+
+	public void setTo(String to) {
+		this.to = to;
+	}
+
+	public String getSubject() {
+		return subject;
+	}
+
+	public void setSubject(String subject) {
+		this.subject = subject;
+	}
+
+	public String getTemplateName() {
+		return templateName;
+	}
+
+	public void setTemplateName(String templateName) {
+		this.templateName = templateName;
+	}
+
+	public Map<String, String> getTemplateTokens() {
+		return templateTokens;
+	}
+
+	public void setTemplateTokens(Map<String, String> templateTokens) {
+		this.templateTokens = templateTokens;
+	}
+
+	public void setFromEmail(String fromEmail) {
+		this.fromEmail = fromEmail;
+	}
+
+	public String getFromEmail() {
+		return fromEmail;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/email/EmailConfig.java b/sm-core/src/main/java/com/salesmanager/core/modules/email/EmailConfig.java
new file mode 100755
index 0000000..0820869
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/email/EmailConfig.java
@@ -0,0 +1,113 @@
+package com.salesmanager.core.modules.email;
+
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+public class EmailConfig implements JSONAware {
+
+	private String host;
+	private String port;
+	private String protocol;
+	private String username;
+	private String password;
+	private boolean smtpAuth = false;
+	private boolean starttls = false;
+	
+	private String emailTemplatesPath = null;
+	
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		JSONObject data = new JSONObject();
+		data.put("host", this.getHost());
+		data.put("port", this.getPort());
+		data.put("protocol", this.getProtocol());
+		data.put("username", this.getUsername());
+		data.put("smtpAuth", this.isSmtpAuth());
+		data.put("starttls", this.isStarttls());
+		data.put("password", this.getPassword());
+		return data.toJSONString();
+	}
+	
+	
+
+	public boolean isSmtpAuth() {
+		return smtpAuth;
+	}
+	public void setSmtpAuth(boolean smtpAuth) {
+		this.smtpAuth = smtpAuth;
+	}
+	public boolean isStarttls() {
+		return starttls;
+	}
+	public void setStarttls(boolean starttls) {
+		this.starttls = starttls;
+	}
+	public void setEmailTemplatesPath(String emailTemplatesPath) {
+		this.emailTemplatesPath = emailTemplatesPath;
+	}
+	public String getEmailTemplatesPath() {
+		return emailTemplatesPath;
+	}
+
+
+
+	public String getHost() {
+		return host;
+	}
+
+
+
+	public void setHost(String host) {
+		this.host = host;
+	}
+
+
+
+	public String getPort() {
+		return port;
+	}
+
+
+
+	public void setPort(String port) {
+		this.port = port;
+	}
+
+
+
+	public String getProtocol() {
+		return protocol;
+	}
+
+
+
+	public void setProtocol(String protocol) {
+		this.protocol = protocol;
+	}
+
+
+
+	public String getUsername() {
+		return username;
+	}
+
+
+
+	public void setUsername(String username) {
+		this.username = username;
+	}
+
+
+
+	public String getPassword() {
+		return password;
+	}
+
+
+
+	public void setPassword(String password) {
+		this.password = password;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/email/HtmlEmailSender.java b/sm-core/src/main/java/com/salesmanager/core/modules/email/HtmlEmailSender.java
new file mode 100755
index 0000000..388d01e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/email/HtmlEmailSender.java
@@ -0,0 +1,10 @@
+package com.salesmanager.core.modules.email;
+
+
+public interface HtmlEmailSender {
+	
+	public void send(final Email email) throws Exception;
+
+	public void setEmailConfig(EmailConfig emailConfig);
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/email/HtmlEmailSenderImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/email/HtmlEmailSenderImpl.java
new file mode 100755
index 0000000..1708523
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/email/HtmlEmailSenderImpl.java
@@ -0,0 +1,195 @@
+package com.salesmanager.core.modules.email;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringWriter;
+import java.util.Map;
+import java.util.Properties;
+
+import javax.mail.BodyPart;
+import javax.mail.Message;
+import javax.mail.MessagingException;
+import javax.mail.Multipart;
+import javax.mail.internet.InternetAddress;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+
+import org.springframework.mail.MailPreparationException;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.springframework.mail.javamail.MimeMessagePreparator;
+
+import freemarker.template.Configuration;
+import freemarker.template.Template;
+import freemarker.template.TemplateException;
+
+
+public class HtmlEmailSenderImpl implements HtmlEmailSender {
+	
+	private static final String CHARSET = "UTF-8";
+	private Configuration freemarkerMailConfiguration;
+	private JavaMailSender mailSender;
+	private EmailConfig emailConfig;
+	
+	private final static String TEMPLATE_PATH = "templates/email";
+	
+	@Override
+	public void send(Email email)
+			throws Exception {
+		
+		final String eml = email.getFrom();
+		final String from = email.getFromEmail();
+		final String to = email.getTo();
+		final String subject = email.getSubject();
+		final String tmpl = email.getTemplateName();
+		final Map<String,String> templateTokens = email.getTemplateTokens();
+
+		MimeMessagePreparator preparator = new MimeMessagePreparator() {
+			public void prepare(MimeMessage mimeMessage)
+					throws MessagingException, IOException {
+				
+				JavaMailSenderImpl impl = (JavaMailSenderImpl)mailSender;
+				// if email configuration is present in Database, use the same
+				if(emailConfig != null) {
+					impl.setProtocol(emailConfig.getProtocol());
+					impl.setHost(emailConfig.getHost());
+					impl.setPort(Integer.parseInt(emailConfig.getPort()));
+					impl.setUsername(emailConfig.getUsername());
+					impl.setPassword(emailConfig.getPassword());
+					
+					Properties prop = new Properties();
+					prop.put("mail.smtp.auth", emailConfig.isSmtpAuth());
+					prop.put("mail.smtp.starttls.enable", emailConfig.isStarttls());
+					impl.setJavaMailProperties(prop);
+				}
+				
+				mimeMessage.setRecipient(Message.RecipientType.TO, new InternetAddress(to));
+
+				InternetAddress inetAddress = new InternetAddress();
+
+				inetAddress.setPersonal(eml);
+				inetAddress.setAddress(from);
+
+				mimeMessage.setFrom(inetAddress);
+				mimeMessage.setSubject(subject);
+
+				Multipart mp = new MimeMultipart("alternative");
+
+				// Create a "text" Multipart message
+				BodyPart textPart = new MimeBodyPart();
+				freemarkerMailConfiguration.setClassForTemplateLoading(HtmlEmailSenderImpl.class, "/");
+				Template textTemplate = freemarkerMailConfiguration.getTemplate(new StringBuilder(TEMPLATE_PATH).append("").append("/").append(tmpl).toString());
+				final StringWriter textWriter = new StringWriter();
+				try {
+					textTemplate.process(templateTokens, textWriter);
+				} catch (TemplateException e) {
+					throw new MailPreparationException(
+							"Can't generate text mail", e);
+				}
+				textPart.setDataHandler(new javax.activation.DataHandler(
+						new javax.activation.DataSource() {
+							public InputStream getInputStream()
+									throws IOException {
+								//return new StringBufferInputStream(textWriter
+								//		.toString());
+								return new ByteArrayInputStream(textWriter
+										.toString().getBytes(CHARSET));
+							}
+
+							public OutputStream getOutputStream()
+									throws IOException {
+								throw new IOException("Read-only data");
+							}
+
+							public String getContentType() {
+								return "text/plain";
+							}
+
+							public String getName() {
+								return "main";
+							}
+						}));
+				mp.addBodyPart(textPart);
+
+				// Create a "HTML" Multipart message
+				Multipart htmlContent = new MimeMultipart("related");
+				BodyPart htmlPage = new MimeBodyPart();
+				freemarkerMailConfiguration.setClassForTemplateLoading(HtmlEmailSenderImpl.class, "/");
+				Template htmlTemplate = freemarkerMailConfiguration.getTemplate(new StringBuilder(TEMPLATE_PATH).append("").append("/").append(tmpl).toString());
+				final StringWriter htmlWriter = new StringWriter();
+				try {
+					htmlTemplate.process(templateTokens, htmlWriter);
+				} catch (TemplateException e) {
+					throw new MailPreparationException(
+							"Can't generate HTML mail", e);
+				}
+				htmlPage.setDataHandler(new javax.activation.DataHandler(
+						new javax.activation.DataSource() {
+							public InputStream getInputStream()
+									throws IOException {
+								//return new StringBufferInputStream(htmlWriter
+								//		.toString());
+								return new ByteArrayInputStream(textWriter
+										.toString().getBytes(CHARSET));
+							}
+
+							public OutputStream getOutputStream()
+									throws IOException {
+								throw new IOException("Read-only data");
+							}
+
+							public String getContentType() {
+								return "text/html";
+							}
+
+							public String getName() {
+								return "main";
+							}
+						}));
+				htmlContent.addBodyPart(htmlPage);
+				BodyPart htmlPart = new MimeBodyPart();
+				htmlPart.setContent(htmlContent);
+				mp.addBodyPart(htmlPart);
+
+				mimeMessage.setContent(mp);
+
+				// if(attachment!=null) {
+				// MimeMessageHelper messageHelper = new
+				// MimeMessageHelper(mimeMessage, true);
+				// messageHelper.addAttachment(attachmentFileName, attachment);
+				// }
+
+			}
+		};
+
+		mailSender.send(preparator);
+	}
+
+	public Configuration getFreemarkerMailConfiguration() {
+		return freemarkerMailConfiguration;
+	}
+
+	public void setFreemarkerMailConfiguration(Configuration freemarkerMailConfiguration) {
+		this.freemarkerMailConfiguration = freemarkerMailConfiguration;
+	}
+
+	public JavaMailSender getMailSender() {
+		return mailSender;
+	}
+
+	public void setMailSender(JavaMailSender mailSender) {
+		this.mailSender = mailSender;
+	}
+
+	public EmailConfig getEmailConfig() {
+		return emailConfig;
+	}
+
+	public void setEmailConfig(EmailConfig emailConfig) {
+		this.emailConfig = emailConfig;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/IntegrationException.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/IntegrationException.java
new file mode 100644
index 0000000..cc6cd9d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/IntegrationException.java
@@ -0,0 +1,61 @@
+package com.salesmanager.core.modules.integration;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+
+public class IntegrationException extends ServiceException {
+	
+
+	/**
+	 * 
+	 */
+	private static final long serialVersionUID = 1L;
+	
+	public static final int ERROR_VALIDATION_SAVE = 100;
+	public static final int TRANSACTION_EXCEPTION = 99;
+	
+	private List<String> errorFields;
+	
+	private int errorCode = 0;
+
+	public int getErrorCode() {
+		return errorCode;
+	}
+
+	public void setErrorCode(int errorCode) {
+		this.errorCode = errorCode;
+	}
+
+	public IntegrationException(Exception e) {
+		super(e);
+	}
+	
+	public IntegrationException(String message, Exception e) {
+		super(message,e);
+	}
+	
+	public IntegrationException(int code, String message) {
+		
+		super(message);
+		this.errorCode = code;
+	}
+	
+	public IntegrationException(int code) {
+		
+		this.errorCode = code;
+	}
+
+	public IntegrationException(String message) {
+		super(message);
+	}
+
+	public void setErrorFields(List<String> errorFields) {
+		this.errorFields = errorFields;
+	}
+
+	public List<String> getErrorFields() {
+		return errorFields;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/BeanStreamPayment.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/BeanStreamPayment.java
new file mode 100644
index 0000000..71bacf4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/BeanStreamPayment.java
@@ -0,0 +1,755 @@
+package com.salesmanager.core.modules.integration.payment.impl;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStreamReader;
+import java.math.BigDecimal;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.UUID;
+
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.CreditCardPayment;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.PaymentType;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.payments.model.TransactionType;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.zone.service.ZoneService;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.MerchantLog;
+import com.salesmanager.core.business.system.model.ModuleConfig;
+import com.salesmanager.core.business.system.service.MerchantLogService;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.payment.model.PaymentModule;
+import com.salesmanager.core.utils.CreditCardUtils;
+import com.salesmanager.core.utils.ProductPriceUtils;
+
+public class BeanStreamPayment implements PaymentModule {
+	
+	@Autowired
+	private ProductPriceUtils productPriceUtils;
+	
+	@Autowired
+	private MerchantLogService merchantLogService;
+	
+	@Autowired
+    private CountryService countryService;
+	
+	@Autowired
+	private ZoneService zoneService;
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(BeanStreamPayment.class);
+
+	@Override
+	public Transaction initTransaction(MerchantStore store, Customer customer,
+			BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public Transaction authorize(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		return processTransaction(store, customer, TransactionType.AUTHORIZE,
+				amount,
+				payment,
+				configuration,
+				module);
+	}
+
+	@Override
+	public Transaction capture(MerchantStore store, Customer customer,
+			Order order, Transaction capturableTransaction,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+
+
+			try {
+				
+
+				
+				//authorize a preauth 
+
+		
+				String trnID = capturableTransaction.getTransactionDetails().get("TRANSACTIONID");
+				
+				String amnt = productPriceUtils.getAdminFormatedAmount(store, order.getTotal());
+				
+				/**
+				merchant_id=123456789&requestType=BACKEND
+				&trnType=PAC&username=user1234&password=pass1234&trnID=1000
+				2115 --> requires also adjId [not documented]
+				**/
+				
+				StringBuilder messageString = new StringBuilder();
+				messageString.append("requestType=BACKEND&");
+				messageString.append("merchant_id=").append(configuration.getIntegrationKeys().get("merchantid")).append("&");
+				messageString.append("trnType=").append("PAC").append("&");
+				messageString.append("username=").append(configuration.getIntegrationKeys().get("username")).append("&");
+				messageString.append("password=").append(configuration.getIntegrationKeys().get("password")).append("&");
+				messageString.append("trnAmount=").append(amnt).append("&");
+				messageString.append("adjId=").append(trnID).append("&");
+				messageString.append("trnID=").append(trnID);
+				
+				LOGGER.debug("REQUEST SENT TO BEANSTREAM -> " + messageString.toString());
+		
+
+
+				Transaction response = this.sendTransaction(null, store, messageString.toString(), "PAC", TransactionType.CAPTURE, PaymentType.CREDITCARD, order.getTotal(), configuration, module);
+				
+				return response;
+				
+			} catch(Exception e) {
+				
+				if(e instanceof IntegrationException)
+					throw (IntegrationException)e;
+				throw new IntegrationException("Error while processing BeanStream transaction",e);
+	
+			} 
+
+	}
+
+	@Override
+	public Transaction authorizeAndCapture(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		return processTransaction(
+				store,
+				customer,
+				TransactionType.AUTHORIZECAPTURE,
+				amount,
+				payment,
+				configuration,
+				module);
+	}
+
+	@Override
+	public Transaction refund(boolean partial, MerchantStore store, Transaction transaction,
+			Order order, BigDecimal amount,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+
+		
+		
+		
+		HttpURLConnection conn = null;
+		
+		try {
+			
+			
+			boolean bSandbox = false;
+			if (configuration.getEnvironment().equals("TEST")) {// sandbox
+				bSandbox = true;
+			}
+
+			String server = "";
+
+
+			ModuleConfig configs = module.getModuleConfigs().get("PROD");
+
+			if (bSandbox == true) {
+				configs = module.getModuleConfigs().get("TEST");
+			} 
+			
+			if(configs==null) {
+				throw new IntegrationException("Module not configured for TEST or PROD");
+			}
+			
+
+			server = new StringBuffer().append(
+					
+					configs.getScheme()).append("://")
+					.append(configs.getHost())
+							.append(":")
+							.append(configs.getPort())
+							.append(configs.getUri()).toString();
+
+			String trnID = transaction.getTransactionDetails().get("TRANSACTIONID");
+			
+			String amnt = productPriceUtils.getAdminFormatedAmount(store, amount);
+			
+			/**
+			merchant_id=123456789&requestType=BACKEND
+			&trnType=R&username=user1234&password=pass1234
+			&trnOrderNumber=1234&trnAmount=1.00&adjId=1000
+			2115
+			**/
+			StringBuilder messageString = new StringBuilder();
+
+
+
+			messageString.append("requestType=BACKEND&");
+			messageString.append("merchant_id=").append(configuration.getIntegrationKeys().get("merchantid")).append("&");
+			messageString.append("trnType=").append("R").append("&");
+			messageString.append("username=").append(configuration.getIntegrationKeys().get("username")).append("&");
+			messageString.append("password=").append(configuration.getIntegrationKeys().get("password")).append("&");
+			messageString.append("trnOrderNumber=").append(transaction.getTransactionDetails().get("TRNORDERNUMBER")).append("&");
+			messageString.append("trnAmount=").append(amnt).append("&");
+			messageString.append("adjId=").append(trnID);
+			
+			LOGGER.debug("REQUEST SENT TO BEANSTREAM -> " + messageString.toString());
+	
+			
+		
+			
+			URL postURL = new URL(server.toString());
+			conn = (HttpURLConnection) postURL.openConnection();
+			
+
+
+			
+			Transaction response = this.sendTransaction(null, store, messageString.toString(), "R", TransactionType.REFUND, PaymentType.CREDITCARD, amount, configuration, module);
+			
+			return response;
+			
+		} catch(Exception e) {
+			
+			if(e instanceof IntegrationException)
+				throw (IntegrationException)e;
+			throw new IntegrationException("Error while processing BeanStream transaction",e);
+
+		} finally {
+			
+			
+			if (conn != null) {
+				try {
+					conn.disconnect();
+				} catch (Exception ignore) {
+					// TODO: handle exception
+				}
+			}
+		}
+		
+		
+		
+	}
+	
+	
+	private Transaction sendTransaction(
+			String orderNumber,
+			MerchantStore store,
+			String transaction, 
+			String beanstreamType, 
+			TransactionType transactionType,
+			PaymentType paymentType,
+			BigDecimal amount,
+			IntegrationConfiguration configuration,
+			IntegrationModule module
+			) throws IntegrationException {
+		
+		String agent = "Mozilla/4.0";
+		String respText = "";
+		Map<String,String> nvp = null;
+		DataOutputStream output = null;
+		DataInputStream in = null;
+		BufferedReader is = null;
+		HttpURLConnection conn =null;
+		try {
+			
+			//transaction = "requestType=BACKEND&merchant_id=300200260&trnType=P&username=carlito&password=shopizer001&orderNumber=caa71106-7e3f-4975-a657-a35904dc32a0&trnCardOwner=Carl Samson&trnCardNumber=5100000020002000&trnExpMonth=10&trnExpYear=14&trnCardCvd=123&trnAmount=77.01&ordName=Carl S&ordAddress1=358 Du Languedoc&ordCity=Victoria&ordProvince=BC&ordPostalCode=V8T2E7&ordCountry=CA&ordPhoneNumber=(444) 555-6666&ordEmailAddress=csamson777@yahoo.com";
+			/**
+			requestType=BACKEND&merchant_id=300200260
+			&trnType=P
+			&username=carlito&password=shopizer001
+			&orderNumber=caa71106-7e3f-4975-a657-a35904dc32a0
+			&trnCardOwner=Carl Samson
+			&trnCardNumber=5100000020002000
+			&trnExpMonth=10
+			&trnExpYear=14
+			&trnCardCvd=123
+			&trnAmount=77.01
+			&ordName=Carl S
+			&ordAddress1=378 Du Languedoc
+			&ordCity=Boucherville
+			&ordProvince=QC
+			&ordPostalCode=J4B8J9
+			&ordCountry=CA
+			&ordPhoneNumber=(444) 555-6666
+			&ordEmailAddress=test@yahoo.com
+			**/
+			
+			/**
+			merchant_id=123456789&requestType=BACKEND
+			&trnType=P&trnOrderNumber=1234TEST&trnAmount=5.00&trnCardOwner=Joe+Test
+					&trnCardNumber=4030000010001234
+					&trnExpMonth=10
+					&trnExpYear=16
+					&ordName=Joe+Test
+					&ordAddress1=123+Test+Street
+					&ordCity=Victoria
+					&ordProvince=BC
+					&ordCountry=CA
+					&ordPostalCode=V8T2E7
+					&ordPhoneNumber=5555555555
+					&ordEmailAddress=joe%40testemail.com
+			**/
+			
+			
+			
+			boolean bSandbox = false;
+			if (configuration.getEnvironment().equals("TEST")) {// sandbox
+				bSandbox = true;
+			}
+
+			String server = "";
+			
+			ModuleConfig configs = module.getModuleConfigs().get("PROD");
+
+			if (bSandbox == true) {
+				configs = module.getModuleConfigs().get("TEST");
+			} 
+			
+			if(configs==null) {
+				throw new IntegrationException("Module not configured for TEST or PROD");
+			}
+			
+
+			server = new StringBuffer().append(
+					
+					configs.getScheme()).append("://")
+					.append(configs.getHost())
+							.append(":")
+							.append(configs.getPort())
+							.append(configs.getUri()).toString();
+			
+	
+			
+			URL postURL = new URL(server.toString());
+			conn = (HttpURLConnection) postURL.openConnection();
+			
+
+			// Set connection parameters. We need to perform input and output,
+			// so set both as true.
+			conn.setDoInput(true);
+			conn.setDoOutput(true);
+
+			// Set the content type we are POSTing. We impersonate it as
+			// encoded form data
+			conn.setRequestProperty("Content-Type",
+					"application/x-www-form-urlencoded");
+			conn.setRequestProperty("User-Agent", agent);
+
+			conn.setRequestProperty("Content-Length", String
+					.valueOf(transaction.length()));
+			conn.setRequestMethod("POST");
+
+			// get the output stream to POST to.
+			output = new DataOutputStream(conn.getOutputStream());
+			output.writeBytes(transaction);
+			output.flush();
+
+
+			// Read input from the input stream.
+			in = new DataInputStream(conn.getInputStream());
+			int rc = conn.getResponseCode();
+			if (rc != -1) {
+				is = new BufferedReader(new InputStreamReader(conn
+						.getInputStream()));
+				String _line = null;
+				while (((_line = is.readLine()) != null)) {
+					respText = respText + _line;
+				}
+				
+				LOGGER.debug("BeanStream response -> " + respText.trim());
+				
+				nvp = formatUrlResponse(respText.trim());
+			} else {
+				throw new IntegrationException("Invalid response from BeanStream, return code is " + rc);
+			}
+			
+			//check
+			//trnApproved=1&trnId=10003067&messageId=1&messageText=Approved&trnOrderNumber=E40089&authCode=TEST&errorType=N&errorFields=
+
+			String transactionApproved = (String)nvp.get("TRNAPPROVED");
+			String transactionId = (String)nvp.get("TRNID");
+			String messageId = (String)nvp.get("MESSAGEID");
+			String messageText = (String)nvp.get("MESSAGETEXT");
+			String orderId = (String)nvp.get("TRNORDERNUMBER");
+			String authCode = (String)nvp.get("AUTHCODE");
+			String errorType = (String)nvp.get("ERRORTYPE");
+			String errorFields = (String)nvp.get("ERRORFIELDS");
+			if(!StringUtils.isBlank(orderNumber)) {
+				nvp.put("INTERNALORDERID", orderNumber);
+			}
+			
+			if(StringUtils.isBlank(transactionApproved)) {
+				throw new IntegrationException("Required field transactionApproved missing from BeanStream response");
+			}
+			
+			//errors
+			if(transactionApproved.equals("0")) {
+
+				merchantLogService.save(
+						new MerchantLog(store,
+						"Can't process BeanStream message "
+								 + messageText + " return code id " + messageId));
+	
+				IntegrationException te = new IntegrationException(
+						"Can't process BeanStream message " + messageText);
+				te.setExceptionType(IntegrationException.EXCEPTION_PAYMENT_DECLINED);
+				te.setMessageCode("message.payment.beanstream." + messageId);
+				te.setErrorCode(IntegrationException.TRANSACTION_EXCEPTION);
+				throw te;
+			}
+			
+			//create transaction object
+
+			//return parseResponse(type,transaction,respText,nvp,order);
+			return this.parseResponse(transactionType, paymentType, nvp, amount);
+			
+			
+		} catch(Exception e) {
+			if(e instanceof IntegrationException) {
+				throw (IntegrationException)e;
+			}
+			
+			throw new IntegrationException("Error while processing BeanStream transaction",e);
+
+		} finally {
+			if (is != null) {
+				try {
+					is.close();
+				} catch (Exception ignore) {
+					// TODO: handle exception
+				}
+			}
+
+			if (in != null) {
+				try {
+					in.close();
+				} catch (Exception ignore) {
+					// TODO: handle exception
+				}
+			}
+
+			if (output != null) {
+				try {
+					output.close();
+				} catch (Exception ignore) {
+					// TODO: handle exception
+				}
+			}
+			
+			if (conn != null) {
+				try {
+					conn.disconnect();
+				} catch (Exception ignore) {
+					// TODO: handle exception
+				}
+			}
+
+		}
+
+		
+	}
+	
+	
+	
+	private Transaction processTransaction(MerchantStore store, Customer customer, TransactionType type,
+			BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module) throws IntegrationException {
+		
+
+		
+		
+		
+		boolean bSandbox = false;
+		if (configuration.getEnvironment().equals("TEST")) {// sandbox
+			bSandbox = true;
+		}
+
+		String server = "";
+
+		ModuleConfig configs = module.getModuleConfigs().get("PROD");
+
+		if (bSandbox == true) {
+			configs = module.getModuleConfigs().get("TEST");
+		} 
+		
+		if(configs==null) {
+			throw new IntegrationException("Module not configured for TEST or PROD");
+		}
+		
+
+		server = new StringBuffer().append(
+				
+				configs.getScheme()).append("://")
+				.append(configs.getHost())
+						.append(":")
+						.append(configs.getPort())
+						.append(configs.getUri()).toString();
+		
+		HttpURLConnection conn = null;
+		
+		try {
+			
+		String uniqueId = UUID.randomUUID().toString();//TODO
+			
+		String orderNumber = uniqueId;
+		
+		String amnt = productPriceUtils.getAdminFormatedAmount(store, amount);
+		
+		
+		StringBuilder messageString = new StringBuilder();
+		
+		String transactionType = "P";
+		if(type == TransactionType.AUTHORIZE) {
+			transactionType = "PA";
+		} else if(type == TransactionType.AUTHORIZECAPTURE) {
+			transactionType = "P";
+		} 
+		
+		CreditCardPayment creditCardPayment = (CreditCardPayment)payment;
+
+		messageString.append("requestType=BACKEND&");
+		messageString.append("merchant_id=").append(configuration.getIntegrationKeys().get("merchantid")).append("&");
+		messageString.append("trnType=").append(transactionType).append("&");
+		messageString.append("username=").append(configuration.getIntegrationKeys().get("username")).append("&");
+		messageString.append("password=").append(configuration.getIntegrationKeys().get("password")).append("&");
+		messageString.append("orderNumber=").append(orderNumber).append("&");
+		messageString.append("trnCardOwner=").append(creditCardPayment.getCardOwner()).append("&");
+		messageString.append("trnCardNumber=").append(creditCardPayment.getCreditCardNumber()).append("&");
+		messageString.append("trnExpMonth=").append(creditCardPayment.getExpirationMonth()).append("&");
+		messageString.append("trnExpYear=").append(creditCardPayment.getExpirationYear().substring(2)).append("&");
+		messageString.append("trnCardCvd=").append(creditCardPayment.getCredidCardValidationNumber()).append("&");
+		messageString.append("trnAmount=").append(amnt).append("&");
+		
+		StringBuilder nm = new StringBuilder();
+		nm.append(customer.getBilling().getFirstName()).append(" ").append(customer.getBilling().getLastName());
+		
+		
+		messageString.append("ordName=").append(nm.toString()).append("&");
+		messageString.append("ordAddress1=").append(customer.getBilling().getAddress()).append("&");
+		messageString.append("ordCity=").append(customer.getBilling().getCity()).append("&");
+		
+		String stateProvince = customer.getBilling().getState();
+		if(customer.getBilling().getZone()!=null) {
+			stateProvince = customer.getBilling().getZone().getCode();
+		}
+		
+		String countryName = customer.getBilling().getCountry().getIsoCode();
+		
+		messageString.append("ordProvince=").append(stateProvince).append("&");
+		messageString.append("ordPostalCode=").append(customer.getBilling().getPostalCode().replaceAll("\\s","")).append("&");
+		messageString.append("ordCountry=").append(countryName).append("&");
+		messageString.append("ordPhoneNumber=").append(customer.getBilling().getTelephone()).append("&");
+		messageString.append("ordEmailAddress=").append(customer.getEmailAddress());
+		
+		
+		
+		
+		/**
+		 * 	purchase (P)
+		 *  -----------
+				REQUEST -> merchant_id=123456789&requestType=BACKEND&trnType=P&trnOrderNumber=1234TEST&trnAmount=5.00&trnCardOwner=Joe+Test&trnCardNumber=4030000010001234&trnExpMonth=10&trnExpYear=10&ordName=Joe+Test&ordAddress1=123+Test+Street&ordCity=Victoria&ordProvince=BC&ordCountry=CA&ordPostalCode=V8T2E7&ordPhoneNumber=5555555555&ordEmailAddress=joe%40testemail.com
+				RESPONSE-> trnApproved=1&trnId=10003067&messageId=1&messageText=Approved&trnOrderNumber=E40089&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=10%2E00&trnDate=1%2F17%2F2008+11%3A36%3A34+AM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&rspCodeCav=0&rspCavResult=0&rspCodeCredit1=0&rspCodeCredit2=0&rspCodeCredit3=0&rspCodeCredit4=0&rspCodeAddr1=0&rspCodeAddr2=0&rspCodeAddr3=0&rspCodeAddr4=0&rspCodeDob=0&rspCustomerDec=&trnType=P&paymentMethod=CC&ref1=&ref2=&ref3=&ref4=&ref5=
+		
+			pre authorization (PA)
+			----------------------
+
+			Prior to processing a pre-authorization through the API, you must modify the transaction settings in your Beanstream merchant member area to allow for this transaction type.
+			- Log in to the Beanstream online member area at www.beanstream.com/admin/sDefault.asp.
+			- Navigate to administration - account admin - order settings in the left menu.
+			Under the heading �Restrict Internet Transaction Processing Types,� select either of the last two options. The �Purchases or Pre-Authorization Only� option will allow you to process both types of transaction through your web interface. De-selecting the �Restrict Internet Transaction Processing Types� checkbox will allow you to process all types of transactions including returns, voids and pre-auth completions.
+		
+			capture (PAC) -> requires trnId
+			-------------
+		
+			refund (R)
+			-------------
+				REQUEST -> merchant_id=123456789&requestType=BACKEND&trnType=R&username=user1234&password=pass1234&trnOrderNumber=1234&trnAmount=1.00&adjId=10002115
+				RESPONSE-> trnApproved=1&trnId=10002118&messageId=1&messageText=Approved&trnOrderNumber=1234R&authCode=TEST&errorType=N&errorFields=&responseType=T&trnAmount=1%2E00&trnDate=8%2F17%2F2009+1%3A44%3A56+PM&avsProcessed=0&avsId=0&avsResult=0&avsAddrMatch=0&avsPostalMatch=0&avsMessage=Address+Verification+not+performed+for+this+transaction%2E&cardType=VI&trnType=R&paymentMethod=CC&ref1=&ref2=&ref3=&ref4=&ref5=
+		
+
+			//notes
+			//On receipt of the transaction response, the merchant must display order amount, transaction ID number, bank authorization code (authCode), currency, date and �messageText� to the customer on a confirmation page.
+		*/
+		
+
+		//String agent = "Mozilla/4.0";
+		//String respText = "";
+		//Map nvp = null;
+		
+		
+		/** debug **/
+		
+		
+
+			StringBuffer messageLogString = new StringBuffer();
+			
+			
+			messageLogString.append("requestType=BACKEND&");
+			messageLogString.append("merchant_id=").append(configuration.getIntegrationKeys().get("merchantid")).append("&");
+			messageLogString.append("trnType=").append(type).append("&");
+			messageLogString.append("orderNumber=").append(orderNumber).append("&");
+			messageLogString.append("trnCardOwner=").append(creditCardPayment.getCardOwner()).append("&");
+			messageLogString.append("trnCardNumber=").append(CreditCardUtils.maskCardNumber(creditCardPayment.getCreditCardNumber())).append("&");
+			messageLogString.append("trnExpMonth=").append(creditCardPayment.getExpirationMonth()).append("&");
+			messageLogString.append("trnExpYear=").append(creditCardPayment.getExpirationYear()).append("&");
+			messageLogString.append("trnCardCvd=").append(creditCardPayment.getCredidCardValidationNumber()).append("&");
+			messageLogString.append("trnAmount=").append(amnt).append("&");
+
+			messageLogString.append("ordName=").append(nm.toString()).append("&");
+			messageLogString.append("ordAddress1=").append(customer.getBilling().getAddress()).append("&");
+			messageLogString.append("ordCity=").append(customer.getBilling().getCity()).append("&");
+			
+
+			
+			messageLogString.append("ordProvince=").append(stateProvince).append("&");
+			messageLogString.append("ordPostalCode=").append(customer.getBilling().getPostalCode()).append("&");
+			messageLogString.append("ordCountry=").append(customer.getBilling().getCountry().getName()).append("&");
+			messageLogString.append("ordPhoneNumber=").append(customer.getBilling().getTelephone()).append("&");
+			messageLogString.append("ordEmailAddress=").append(customer.getEmailAddress());
+			
+			
+
+
+			/** debug **/
+	
+	
+			LOGGER.debug("REQUEST SENT TO BEANSTREAM -> " + messageLogString.toString());
+
+			
+			URL postURL = new URL(server.toString());
+			conn = (HttpURLConnection) postURL.openConnection();
+			
+
+			
+			Transaction response = this.sendTransaction(orderNumber, store, messageString.toString(), transactionType, type, payment.getPaymentType(), amount, configuration, module);
+			
+			return response;
+
+
+			
+		} catch(Exception e) {
+			
+			if(e instanceof IntegrationException)
+				throw (IntegrationException)e;
+			throw new IntegrationException("Error while processing BeanStream transaction",e);
+
+		} finally {
+			
+			
+			if (conn != null) {
+				try {
+					conn.disconnect();
+				} catch (Exception ignore) {}
+			}
+		}
+
+	}
+	
+	
+	
+	private Transaction parseResponse(TransactionType transactionType,
+			PaymentType paymentType, Map<String,String> nvp,
+			BigDecimal amount) throws Exception {
+		
+		
+		Transaction transaction = new Transaction();
+		transaction.setAmount(amount);
+		//transaction.setOrder(order);
+		transaction.setTransactionDate(new Date());
+		transaction.setTransactionType(transactionType);
+		transaction.setPaymentType(PaymentType.CREDITCARD);
+		transaction.getTransactionDetails().put("TRANSACTIONID", (String)nvp.get("TRNID"));
+		transaction.getTransactionDetails().put("TRNAPPROVED", (String)nvp.get("TRNAPPROVED"));
+		transaction.getTransactionDetails().put("TRNORDERNUMBER", (String)nvp.get("TRNORDERNUMBER"));
+		transaction.getTransactionDetails().put("MESSAGETEXT", (String)nvp.get("MESSAGETEXT"));
+		if(nvp.get("INTERNALORDERID")!=null) {
+			transaction.getTransactionDetails().put("INTERNALORDERID", (String)nvp.get("INTERNALORDERID"));
+		}
+		return transaction;
+		
+	}
+
+	private Map formatUrlResponse(String payload) throws Exception {
+		HashMap<String,String> nvp = new HashMap<String,String> ();
+		StringTokenizer stTok = new StringTokenizer(payload, "&");
+		while (stTok.hasMoreTokens()) {
+			StringTokenizer stInternalTokenizer = new StringTokenizer(stTok
+					.nextToken(), "=");
+			if (stInternalTokenizer.countTokens() == 2) {
+				String key = URLDecoder.decode(stInternalTokenizer.nextToken(),
+						"UTF-8");
+				String value = URLDecoder.decode(stInternalTokenizer
+						.nextToken(), "UTF-8");
+				nvp.put(key.toUpperCase(), value);
+			}
+		}
+		return nvp;
+	}
+
+	@Override
+	public void validateModuleConfiguration(
+			IntegrationConfiguration integrationConfiguration,
+			MerchantStore store) throws IntegrationException {
+		
+		
+		List<String> errorFields = null;
+		
+		
+		Map<String,String> keys = integrationConfiguration.getIntegrationKeys();
+		
+		//validate integrationKeys['merchantid']
+		if(keys==null || StringUtils.isBlank(keys.get("merchantid"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("merchantid");
+		}
+		
+		//validate integrationKeys['username']
+		if(keys==null || StringUtils.isBlank(keys.get("username"))) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("username");
+		}
+		
+		
+		//validate integrationKeys['password']
+		if(keys==null || StringUtils.isBlank(keys.get("password"))) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("password");
+		}
+
+
+		
+		if(errorFields!=null) {
+			IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
+			ex.setErrorFields(errorFields);
+			throw ex;
+			
+		}
+		
+		
+		
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/MoneyOrderPayment.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/MoneyOrderPayment.java
new file mode 100644
index 0000000..0877a68
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/MoneyOrderPayment.java
@@ -0,0 +1,119 @@
+package com.salesmanager.core.modules.integration.payment.impl;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.PaymentType;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.payments.model.TransactionType;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.payment.model.PaymentModule;
+
+public class MoneyOrderPayment implements PaymentModule {
+
+	@Override
+	public void validateModuleConfiguration(
+			IntegrationConfiguration integrationConfiguration,
+			MerchantStore store) throws IntegrationException {
+		
+		List<String> errorFields = null;
+		
+		
+		Map<String,String> keys = integrationConfiguration.getIntegrationKeys();
+		
+		//validate integrationKeys['address']
+		if(keys==null || StringUtils.isBlank(keys.get("address"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("address");
+		}
+		
+		if(errorFields!=null) {
+			IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
+			ex.setErrorFields(errorFields);
+			throw ex;
+			
+		}
+		
+		
+		
+			return;
+
+	}
+
+	@Override
+	public Transaction initTransaction(MerchantStore store, Customer customer,
+			BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		//NOT REQUIRED
+		return null;
+	}
+
+	@Override
+	public Transaction authorize(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		//NOT REQUIRED
+		return null;
+	}
+
+/*	@Override
+	public Transaction capture(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment, Transaction transaction,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		//NOT REQUIRED
+		return null;
+	}*/
+
+	@Override
+	public Transaction authorizeAndCapture(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		
+		
+		Transaction transaction = new Transaction();
+		transaction.setAmount(amount);
+		transaction.setTransactionDate(new Date());
+		transaction.setTransactionType(TransactionType.AUTHORIZECAPTURE);
+		transaction.setPaymentType(PaymentType.MONEYORDER);
+
+		
+		return transaction;
+		
+		
+		
+	}
+
+	@Override
+	public Transaction refund(boolean partial, MerchantStore store, Transaction transaction,
+			Order order, BigDecimal amount, 
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		throw new IntegrationException("Transaction not supported");
+	}
+
+	@Override
+	public Transaction capture(MerchantStore store, Customer customer,
+			Order order, Transaction capturableTransaction,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/PayPalExpressCheckoutPayment.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/PayPalExpressCheckoutPayment.java
new file mode 100644
index 0000000..58b6132
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/PayPalExpressCheckoutPayment.java
@@ -0,0 +1,653 @@
+package com.salesmanager.core.modules.integration.payment.impl;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang.Validate;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import urn.ebay.api.PayPalAPI.DoCaptureReq;
+import urn.ebay.api.PayPalAPI.DoCaptureRequestType;
+import urn.ebay.api.PayPalAPI.DoCaptureResponseType;
+import urn.ebay.api.PayPalAPI.DoExpressCheckoutPaymentReq;
+import urn.ebay.api.PayPalAPI.DoExpressCheckoutPaymentRequestType;
+import urn.ebay.api.PayPalAPI.DoExpressCheckoutPaymentResponseType;
+import urn.ebay.api.PayPalAPI.GetExpressCheckoutDetailsReq;
+import urn.ebay.api.PayPalAPI.GetExpressCheckoutDetailsRequestType;
+import urn.ebay.api.PayPalAPI.GetExpressCheckoutDetailsResponseType;
+import urn.ebay.api.PayPalAPI.PayPalAPIInterfaceServiceService;
+import urn.ebay.api.PayPalAPI.RefundTransactionReq;
+import urn.ebay.api.PayPalAPI.RefundTransactionRequestType;
+import urn.ebay.api.PayPalAPI.RefundTransactionResponseType;
+import urn.ebay.api.PayPalAPI.SetExpressCheckoutReq;
+import urn.ebay.api.PayPalAPI.SetExpressCheckoutRequestType;
+import urn.ebay.api.PayPalAPI.SetExpressCheckoutResponseType;
+import urn.ebay.apis.CoreComponentTypes.BasicAmountType;
+import urn.ebay.apis.eBLBaseComponents.CompleteCodeType;
+import urn.ebay.apis.eBLBaseComponents.DoExpressCheckoutPaymentRequestDetailsType;
+import urn.ebay.apis.eBLBaseComponents.PaymentDetailsItemType;
+import urn.ebay.apis.eBLBaseComponents.PaymentDetailsType;
+import urn.ebay.apis.eBLBaseComponents.PaymentInfoType;
+import urn.ebay.apis.eBLBaseComponents.RefundType;
+import urn.ebay.apis.eBLBaseComponents.SetExpressCheckoutRequestDetailsType;
+
+import com.salesmanager.core.business.catalog.product.service.PricingService;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderTotal;
+import com.salesmanager.core.business.order.model.OrderTotalSummary;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.PaymentType;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.payments.model.TransactionType;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.payment.model.PaymentModule;
+import com.salesmanager.core.utils.CoreConfiguration;
+
+public class PayPalExpressCheckoutPayment implements PaymentModule {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(PayPalExpressCheckoutPayment.class);
+	
+	
+	@Autowired
+	private PricingService pricingService;
+	
+	@Autowired
+	private CoreConfiguration coreConfiguration;
+
+	@Override
+	public void validateModuleConfiguration(
+			IntegrationConfiguration integrationConfiguration,
+			MerchantStore store) throws IntegrationException {
+		
+		
+		List<String> errorFields = null;
+		
+		//validate integrationKeys['account']
+		Map<String,String> keys = integrationConfiguration.getIntegrationKeys();
+		if(keys==null || StringUtils.isBlank(keys.get("api"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("api");
+		}
+		
+		if(keys==null || StringUtils.isBlank(keys.get("username"))) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("username");
+		}
+		
+		if(keys==null || StringUtils.isBlank(keys.get("signature"))) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("signature");
+		}
+		
+
+		if(errorFields!=null) {
+			IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
+			ex.setErrorFields(errorFields);
+			throw ex;
+			
+		}
+		
+		
+	}
+
+	@Override
+	public Transaction initTransaction(MerchantStore store, Customer customer,
+			BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		
+			throw new IntegrationException("Not imlemented");
+	}
+
+	@Override
+	public Transaction authorize(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+
+		
+		com.salesmanager.core.business.payments.model.PaypalPayment paypalPayment = (com.salesmanager.core.business.payments.model.PaypalPayment)payment;
+		Validate.notNull(paypalPayment.getPaymentToken(), "A paypal payment token is required to process this transaction");
+		
+		return processTransaction(store, customer, items, amount, paypalPayment, configuration, module);
+		
+		
+	}
+
+/*	@Override
+	public Transaction capture(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment, Transaction transaction,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		
+		com.salesmanager.core.business.payments.model.PaypalPayment paypalPayment = (com.salesmanager.core.business.payments.model.PaypalPayment)payment;
+		Validate.notNull(paypalPayment.getPaymentToken(), "A paypal payment token is required to process this transaction");
+		
+		return processTransaction(store, customer, items, amount, paypalPayment, configuration, module);
+		
+	}*/
+	
+	public Transaction initPaypalTransaction(MerchantStore store,
+			List<ShoppingCartItem> items, OrderTotalSummary summary, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		
+		
+
+		try {
+			
+			
+			PaymentDetailsType paymentDetails = new PaymentDetailsType();
+			if(configuration.getIntegrationKeys().get("transaction").equalsIgnoreCase(TransactionType.AUTHORIZECAPTURE.name())) {
+				paymentDetails.setPaymentAction(urn.ebay.apis.eBLBaseComponents.PaymentActionCodeType.SALE);
+			} else {
+				paymentDetails.setPaymentAction(urn.ebay.apis.eBLBaseComponents.PaymentActionCodeType.AUTHORIZATION);
+			}
+			
+
+			List<PaymentDetailsItemType> lineItems = new ArrayList<PaymentDetailsItemType>();
+			
+			for(ShoppingCartItem cartItem : items) {
+			
+				PaymentDetailsItemType item = new PaymentDetailsItemType();
+				BasicAmountType amt = new BasicAmountType();
+				amt.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(payment.getCurrency().getCode()));
+				amt.setValue(pricingService.getStringAmount(cartItem.getFinalPrice().getFinalPrice(), store));
+				//itemsTotal = itemsTotal.add(cartItem.getSubTotal());
+				int itemQuantity = cartItem.getQuantity();
+				item.setQuantity(itemQuantity);
+				item.setName(cartItem.getProduct().getProductDescription().getName());
+				item.setAmount(amt);
+				//System.out.println(pricingService.getStringAmount(cartItem.getSubTotal(), store));
+				lineItems.add(item);
+			
+			}
+			
+			
+			List<OrderTotal> orderTotals = summary.getTotals();
+			BigDecimal tax = null;
+			for(OrderTotal total : orderTotals) {
+				
+				if(total.getModule().equals(Constants.OT_SHIPPING_MODULE_CODE)) {
+					BasicAmountType shipping = new BasicAmountType();
+					shipping.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(store.getCurrency().getCode()));
+					shipping.setValue(pricingService.getStringAmount(total.getValue(), store));
+					//System.out.println(pricingService.getStringAmount(total.getValue(), store));
+					paymentDetails.setShippingTotal(shipping);
+				}
+				
+				if(total.getModule().equals(Constants.OT_HANDLING_MODULE_CODE)) {
+					BasicAmountType handling = new BasicAmountType();
+					handling.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(store.getCurrency().getCode()));
+					handling.setValue(pricingService.getStringAmount(total.getValue(), store));
+					//System.out.println(pricingService.getStringAmount(total.getValue(), store));
+					paymentDetails.setHandlingTotal(handling);
+				}
+				
+				if(total.getModule().equals(Constants.OT_TAX_MODULE_CODE)) {
+					if(tax==null) {
+						tax = new BigDecimal("0");
+					}
+					tax = tax.add(total.getValue());
+				}
+				
+			}
+			
+			if(tax!=null) {
+				BasicAmountType taxAmnt = new BasicAmountType();
+				taxAmnt.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(store.getCurrency().getCode()));
+				taxAmnt.setValue(pricingService.getStringAmount(tax, store));
+				//System.out.println(pricingService.getStringAmount(tax, store));
+				paymentDetails.setTaxTotal(taxAmnt);
+			}
+			
+			
+
+			BasicAmountType itemTotal = new BasicAmountType();
+			itemTotal.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(store.getCurrency().getCode()));
+			itemTotal.setValue(pricingService.getStringAmount(summary.getSubTotal(), store));
+			paymentDetails.setItemTotal(itemTotal);
+			
+			paymentDetails.setPaymentDetailsItem(lineItems);
+			BasicAmountType orderTotal = new BasicAmountType();
+			orderTotal.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(store.getCurrency().getCode()));
+			orderTotal.setValue(pricingService.getStringAmount(summary.getTotal(), store));
+			//System.out.println(pricingService.getStringAmount(itemsTotal, store));
+			paymentDetails.setOrderTotal(orderTotal);
+			List<PaymentDetailsType> paymentDetailsList = new ArrayList<PaymentDetailsType>();
+			paymentDetailsList.add(paymentDetails);
+			
+			StringBuilder RETURN_URL = new StringBuilder().append(
+					coreConfiguration.getProperty("ORDER_SCHEME", "http")).append("://")
+					.append(store.getDomainName()).append("/")
+					.append(coreConfiguration.getProperty("CONTEXT_PATH", "sm-shop"));
+					
+
+
+			SetExpressCheckoutRequestDetailsType setExpressCheckoutRequestDetails = new SetExpressCheckoutRequestDetailsType();
+			String returnUrl = RETURN_URL.toString() + new StringBuilder().append(Constants.SHOP_URI).append("/paypal/checkout").append(coreConfiguration.getProperty("URL_EXTENSION", ".html")).append("/success").toString();
+			String cancelUrl = RETURN_URL.toString() + new StringBuilder().append(Constants.SHOP_URI).append("/paypal/checkout").append(coreConfiguration.getProperty("URL_EXTENSION", ".html")).append("/cancel").toString();
+			
+			setExpressCheckoutRequestDetails.setReturnURL(returnUrl);
+			setExpressCheckoutRequestDetails.setCancelURL(cancelUrl);
+
+			
+			setExpressCheckoutRequestDetails.setPaymentDetails(paymentDetailsList);
+
+			SetExpressCheckoutRequestType setExpressCheckoutRequest = new SetExpressCheckoutRequestType(setExpressCheckoutRequestDetails);
+			setExpressCheckoutRequest.setVersion("104.0");
+
+			SetExpressCheckoutReq setExpressCheckoutReq = new SetExpressCheckoutReq();
+			setExpressCheckoutReq.setSetExpressCheckoutRequest(setExpressCheckoutRequest);
+
+			
+			String mode = "sandbox";
+			String env = configuration.getEnvironment();
+			if(Constants.PRODUCTION_ENVIRONMENT.equals(env)) {
+				mode = "production";
+			}
+
+			Map<String,String> configurationMap = new HashMap<String,String>();
+			configurationMap.put("mode", mode);
+			configurationMap.put("acct1.UserName", configuration.getIntegrationKeys().get("username"));
+			configurationMap.put("acct1.Password", configuration.getIntegrationKeys().get("api"));
+			configurationMap.put("acct1.Signature", configuration.getIntegrationKeys().get("signature"));
+			
+			PayPalAPIInterfaceServiceService service = new PayPalAPIInterfaceServiceService(configurationMap);
+			SetExpressCheckoutResponseType setExpressCheckoutResponse = service.setExpressCheckout(setExpressCheckoutReq);
+			
+			String token = setExpressCheckoutResponse.getToken();
+			String correlationID = setExpressCheckoutResponse.getCorrelationID();
+			String ack = setExpressCheckoutResponse.getAck().getValue();
+			
+			if(!"Success".equals(ack)) {
+				LOGGER.error("Wrong value from init transaction " + ack);
+				throw new IntegrationException("Wrong paypal ack from init transaction " + ack);
+			}
+			
+			Transaction transaction = new Transaction();
+			transaction.setAmount(summary.getTotal());
+			//transaction.setOrder(order);
+			transaction.setTransactionDate(new Date());
+			transaction.setTransactionType(TransactionType.INIT);
+			transaction.setPaymentType(PaymentType.PAYPAL);
+			transaction.getTransactionDetails().put("TOKEN", token);
+			transaction.getTransactionDetails().put("CORRELATION", correlationID);
+			
+
+			return transaction;
+			
+			//redirect user to 
+			//https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=EC-5LL13394G30048922
+			
+		} catch(Exception e) {
+			e.printStackTrace();
+			throw new IntegrationException(e);
+		}
+		
+		
+	}
+
+	@Override
+	public Transaction authorizeAndCapture(MerchantStore store,
+			Customer customer, List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+
+		com.salesmanager.core.business.payments.model.PaypalPayment paypalPayment = (com.salesmanager.core.business.payments.model.PaypalPayment)payment;
+		Validate.notNull(paypalPayment.getPaymentToken(), "A paypal payment token is required to process this transaction");
+		
+		return processTransaction(store, customer, items, amount, paypalPayment, configuration, module);
+
+		
+	}
+
+	@Override
+	public Transaction refund(boolean partial, MerchantStore store,
+			Transaction transaction, Order order, BigDecimal amount,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+
+
+		try {
+			
+			
+			
+			Validate.notNull(transaction,"Transaction cannot be null");
+			Validate.notNull((String)transaction.getTransactionDetails().get("TRANSACTIONID"), "Transaction details must contain a TRANSACTIONID");
+			Validate.notNull(order,"Order must not be null");
+			Validate.notNull(order.getCurrency(),"Order nust contain Currency object");
+			
+			String mode = "sandbox";
+			String env = configuration.getEnvironment();
+			if(Constants.PRODUCTION_ENVIRONMENT.equals(env)) {
+				mode = "production";
+			}
+
+			
+			 RefundTransactionRequestType refundTransactionRequest = new RefundTransactionRequestType();
+			 refundTransactionRequest.setVersion("104.0");
+
+			 RefundTransactionReq refundRequest = new RefundTransactionReq();
+			 refundRequest.setRefundTransactionRequest(refundTransactionRequest);
+
+
+			 Map<String,String> configurationMap = new HashMap<String,String>();
+			 configurationMap.put("mode", mode);
+			 configurationMap.put("acct1.UserName", configuration.getIntegrationKeys().get("username"));
+			 configurationMap.put("acct1.Password", configuration.getIntegrationKeys().get("api"));
+			 configurationMap.put("acct1.Signature", configuration.getIntegrationKeys().get("signature"));
+				
+			 
+			 PayPalAPIInterfaceServiceService service = new PayPalAPIInterfaceServiceService(configurationMap);
+			 
+			 
+
+			 RefundType refundType = RefundType.FULL;
+			 if(partial) {
+				 refundType = RefundType.PARTIAL;
+			 }
+			 
+			 refundTransactionRequest.setRefundType(refundType);
+			 
+			 BasicAmountType refundAmount = new BasicAmountType();
+			 refundAmount.setValue(pricingService.getStringAmount(amount, store));
+			 refundAmount.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(order.getCurrency().getCode()));
+
+			 refundTransactionRequest.setAmount(refundAmount);
+			 refundTransactionRequest.setTransactionID(transaction.getTransactionDetails().get("TRANSACTIONID"));
+			 
+			 RefundTransactionResponseType refundTransactionResponse = service.refundTransaction(refundRequest);
+			 
+			 String refundAck = refundTransactionResponse.getAck().getValue();
+			 
+			 
+			 if(!"Success".equals(refundAck)) {
+				LOGGER.error("Wrong value from transaction commit " + refundAck);
+				throw new IntegrationException(ServiceException.EXCEPTION_TRANSACTION_DECLINED,"Paypal refund transaction code [" + refundTransactionResponse.getErrors().get(0).getErrorCode() + "], message-> " + refundTransactionResponse.getErrors().get(0).getShortMessage());
+			 }
+
+			 
+			 Transaction newTransaction = new Transaction();
+			 newTransaction.setAmount(amount);
+			 newTransaction.setTransactionDate(new Date());
+			 newTransaction.setTransactionType(TransactionType.REFUND);
+			 newTransaction.setPaymentType(PaymentType.PAYPAL);
+			 newTransaction.getTransactionDetails().put("TRANSACTIONID", refundTransactionResponse.getRefundTransactionID());
+			 transaction.getTransactionDetails().put("CORRELATION", refundTransactionResponse.getCorrelationID());
+							
+			
+
+			return newTransaction;
+			
+			
+		} catch(Exception e) {
+			if(e instanceof IntegrationException) {
+				throw (IntegrationException)e;
+			} else {
+				throw new IntegrationException(e);
+			}
+		}
+
+		
+		
+		
+		
+		
+	}
+	
+	private Transaction processTransaction(MerchantStore store,
+			Customer customer, List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		
+		
+		com.salesmanager.core.business.payments.model.PaypalPayment paypalPayment = (com.salesmanager.core.business.payments.model.PaypalPayment)payment;
+		
+		try {
+			
+			
+			String mode = "sandbox";
+			String env = configuration.getEnvironment();
+			if(Constants.PRODUCTION_ENVIRONMENT.equals(env)) {
+				mode = "production";
+			}
+			
+	  
+			 //get token from url and return the user to generate a payerid
+			   
+			 GetExpressCheckoutDetailsRequestType getExpressCheckoutDetailsRequest = new GetExpressCheckoutDetailsRequestType(paypalPayment.getPaymentToken());
+			 getExpressCheckoutDetailsRequest.setVersion("104.0");
+
+			 GetExpressCheckoutDetailsReq getExpressCheckoutDetailsReq = new GetExpressCheckoutDetailsReq();
+			 getExpressCheckoutDetailsReq.setGetExpressCheckoutDetailsRequest(getExpressCheckoutDetailsRequest);
+
+			 Map<String,String> configurationMap = new HashMap<String,String>();
+			 configurationMap.put("mode", mode);
+			 configurationMap.put("acct1.UserName", configuration.getIntegrationKeys().get("username"));
+			 configurationMap.put("acct1.Password", configuration.getIntegrationKeys().get("api"));
+			 configurationMap.put("acct1.Signature", configuration.getIntegrationKeys().get("signature"));
+				
+			 
+			 PayPalAPIInterfaceServiceService service = new PayPalAPIInterfaceServiceService(configurationMap);
+			 GetExpressCheckoutDetailsResponseType getExpressCheckoutDetailsResponse = service.getExpressCheckoutDetails(getExpressCheckoutDetailsReq);
+
+				
+			 String token = getExpressCheckoutDetailsResponse.getGetExpressCheckoutDetailsResponseDetails().getToken();
+			 String correlationID = getExpressCheckoutDetailsResponse.getCorrelationID();
+			 String ack = getExpressCheckoutDetailsResponse.getAck().getValue();
+			 String payerId = getExpressCheckoutDetailsResponse.getGetExpressCheckoutDetailsResponseDetails().getPayerInfo().getPayerID();
+			 
+			//TOKEN=EC-9VT64354BS889423P&CHECKOUTSTATUS=PaymentActionNotInitiated&TIMESTAMP=2014-01-26T17:30:17Z&CORRELATIONID=84dfe1d0939cc&ACK=Success&VERSION=104.0&BUILD=9285531&EMAIL=csamson777-facilitator@yahoo.com&PAYERID=XURV79Z6URDV4&PAYERSTATUS=verified&BUSINESS=facilitator account's Test Store&FIRSTNAME=facilitator&LASTNAME=account&COUNTRYCODE=US&SHIPTONAME=facilitator account's Test Store&SHIPTOSTREET=1 Main St&SHIPTOCITY=San Jose&SHIPTOSTATE=CA&SHIPTOZIP=95131&SHIPTOCOUNTRYCODE=US&SHIPTOCOUNTRYNAME=United States&ADDRESSSTATUS=Confirmed&CURRENCYCODE=USD&AMT=1.00&ITEMAMT=1.00&SHIPPINGAMT=0.00&HANDLINGAMT=0.00&TAXAMT=0.00&INSURANCEAMT=0.00&SHIPDISCAMT=0.00&L_NAME0=item&L_QTY0=1&L_TAXAMT0=0.00&L_AMT0=1.00&L_ITEMWEIGHTVALUE0=   0.00000&L_ITEMLENGTHVALUE0=   0.00000&L_ITEMWIDTHVALUE0=   0.00000&L_ITEMHEIGHTVALUE0=   0.00000&PAYMENTREQUEST_0_CURRENCYCODE=USD&PAYMENTREQUEST_0_AMT=1.00&PAYMENTREQUEST_0_ITEMAMT=1.00&PAYMENTREQUEST_0_SHIPPINGAMT=0.00&PAYMENTREQUEST_0_HANDLINGAMT=0.00&PAYMENTREQUEST_0_TAXAMT=0.00&PAYMENTREQUEST_0_INSURANCEAMT=0.00&PAYMENTREQUEST_0_SHIPDISCAMT=0.00&PAYMENTREQUEST_0_INSURANCEOPTIONOFFERED=false&PAYMENTREQUEST_0_SHIPTONAME=facilitator account's Test Store&PAYMENTREQUEST_0_SHIPTOSTREET=1 Main St&PAYMENTREQUEST_0_SHIPTOCITY=San Jose&PAYMENTREQUEST_0_SHIPTOSTATE=CA&PAYMENTREQUEST_0_SHIPTOZIP=95131&PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE=US&PAYMENTREQUEST_0_SHIPTOCOUNTRYNAME=United States&PAYMENTREQUEST_0_ADDRESSSTATUS=Confirmed&PAYMENTREQUEST_0_ADDRESSNORMALIZATIONSTATUS=None&L_PAYMENTREQUEST_0_NAME0=item&L_PAYMENTREQUEST_0_QTY0=1&L_PAYMENTREQUEST_0_TAXAMT0=0.00&L_PAYMENTREQUEST_0_AMT0=1.00&L_PAYMENTREQUEST_0_ITEMWEIGHTVALUE0=   0.00000&L_PAYMENTREQUEST_0_ITEMLENGTHVALUE0=   0.00000&L_PAYMENTREQUEST_0_ITEMWIDTHVALUE0=   0.00000&L_PAYMENTREQUEST_0_ITEMHEIGHTVALUE0=   0.00000&PAYMENTREQUESTINFO_0_ERRORCODE=0
+				
+			 if(!"Success".equals(ack)) {
+				LOGGER.error("Wrong value from anthorize and capture transaction " + ack);
+				throw new IntegrationException("Wrong paypal ack from init transaction " + ack);
+			 }
+			
+ 
+			 PaymentDetailsType paymentDetail = new PaymentDetailsType();
+			 /** IPN **/
+			 //paymentDetail.setNotifyURL("http://replaceIpnUrl.com");
+			 BasicAmountType orderTotal = new BasicAmountType();
+			 orderTotal.setValue(pricingService.getStringAmount(amount, store));
+			 orderTotal.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(payment.getCurrency().getCode()));
+			 paymentDetail.setOrderTotal(orderTotal);
+			 paymentDetail.setButtonSource("Shopizer_Cart_AP");
+			 /** sale or pre-auth **/
+			 if(payment.getTransactionType().name().equals(TransactionType.AUTHORIZE.name())) {
+				 paymentDetail.setPaymentAction(urn.ebay.apis.eBLBaseComponents.PaymentActionCodeType.AUTHORIZATION);
+			 } else {
+				 paymentDetail.setPaymentAction(urn.ebay.apis.eBLBaseComponents.PaymentActionCodeType.SALE);
+			 }
+			 
+			 List<PaymentDetailsType> paymentDetails = new ArrayList<PaymentDetailsType>();
+			 paymentDetails.add(paymentDetail);
+								
+			 DoExpressCheckoutPaymentRequestDetailsType doExpressCheckoutPaymentRequestDetails = new DoExpressCheckoutPaymentRequestDetailsType();
+			 doExpressCheckoutPaymentRequestDetails.setToken(token);
+			 doExpressCheckoutPaymentRequestDetails.setPayerID(payerId);
+			 doExpressCheckoutPaymentRequestDetails.setPaymentDetails(paymentDetails);
+				
+			 DoExpressCheckoutPaymentRequestType doExpressCheckoutPaymentRequest = new DoExpressCheckoutPaymentRequestType(doExpressCheckoutPaymentRequestDetails);
+			 doExpressCheckoutPaymentRequest.setVersion("104.0");
+				
+			 DoExpressCheckoutPaymentReq doExpressCheckoutPaymentReq = new DoExpressCheckoutPaymentReq();
+			 doExpressCheckoutPaymentReq.setDoExpressCheckoutPaymentRequest(doExpressCheckoutPaymentRequest);
+				
+
+			 DoExpressCheckoutPaymentResponseType doExpressCheckoutPaymentResponse = service.doExpressCheckoutPayment(doExpressCheckoutPaymentReq); 
+			 String commitAck = doExpressCheckoutPaymentResponse.getAck().getValue();
+			 
+			 
+			 if(!"Success".equals(commitAck)) {
+				LOGGER.error("Wrong value from transaction commit " + ack);
+				throw new IntegrationException("Wrong paypal ack from init transaction " + ack);
+			 }
+			 
+			 
+			 List<PaymentInfoType> paymentInfoList =  doExpressCheckoutPaymentResponse.getDoExpressCheckoutPaymentResponseDetails().getPaymentInfo();
+			 String transactionId = null;
+			 
+			 for(PaymentInfoType paymentInfo : paymentInfoList) {
+				 transactionId = paymentInfo.getTransactionID();
+			 }
+			 
+			 
+			 
+			 
+			 //TOKEN=EC-90U93956LU4997256&SUCCESSPAGEREDIRECTREQUESTED=false&TIMESTAMP=2014-02-16T15:41:03Z&CORRELATIONID=39d4ab666c1d7&ACK=Success&VERSION=104.0&BUILD=9720069&INSURANCEOPTIONSELECTED=false&SHIPPINGOPTIONISDEFAULT=false&PAYMENTINFO_0_TRANSACTIONID=4YA742984J1256935&PAYMENTINFO_0_TRANSACTIONTYPE=expresscheckout&PAYMENTINFO_0_PAYMENTTYPE=instant&PAYMENTINFO_0_ORDERTIME=2014-02-16T15:41:03Z&PAYMENTINFO_0_AMT=1.00&PAYMENTINFO_0_FEEAMT=0.33&PAYMENTINFO_0_TAXAMT=0.00&PAYMENTINFO_0_CURRENCYCODE=USD&PAYMENTINFO_0_PAYMENTSTATUS=Completed&PAYMENTINFO_0_PENDINGREASON=None&PAYMENTINFO_0_REASONCODE=None&PAYMENTINFO_0_PROTECTIONELIGIBILITY=Eligible&PAYMENTINFO_0_PROTECTIONELIGIBILITYTYPE=ItemNotReceivedEligible,UnauthorizedPaymentEligible&PAYMENTINFO_0_SECUREMERCHANTACCOUNTID=TWLK53YN7GDM6&PAYMENTINFO_0_ERRORCODE=0&PAYMENTINFO_0_ACK=Success
+			 
+			 Transaction transaction = new Transaction();
+			 transaction.setAmount(amount);
+			 transaction.setTransactionDate(new Date());
+			 transaction.setTransactionType(payment.getTransactionType());
+			 transaction.setPaymentType(PaymentType.PAYPAL);
+			 transaction.getTransactionDetails().put("TOKEN", token);
+			 transaction.getTransactionDetails().put("PAYERID", payerId);
+			 transaction.getTransactionDetails().put("TRANSACTIONID", transactionId);
+			 transaction.getTransactionDetails().put("CORRELATION", correlationID);
+				
+			
+
+			return transaction;
+			
+			
+		} catch(Exception e) {
+			throw new IntegrationException(e);
+		}
+
+		
+		
+	}
+
+	@Override
+	public Transaction capture(MerchantStore store, Customer customer,
+			Order order, Transaction capturableTransaction,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+
+		
+
+		try {
+			
+			
+			
+			Validate.notNull(capturableTransaction,"Transaction cannot be null");
+			Validate.notNull((String)capturableTransaction.getTransactionDetails().get("TRANSACTIONID"), "Transaction details must contain a TRANSACTIONID");
+			Validate.notNull(order,"Order must not be null");
+			Validate.notNull(order.getCurrency(),"Order nust contain Currency object");
+			
+			String mode = "sandbox";
+			String env = configuration.getEnvironment();
+			if(Constants.PRODUCTION_ENVIRONMENT.equals(env)) {
+				mode = "production";
+			}
+
+
+			 Map<String,String> configurationMap = new HashMap<String,String>();
+			 configurationMap.put("mode", mode);
+			 configurationMap.put("acct1.UserName", configuration.getIntegrationKeys().get("username"));
+			 configurationMap.put("acct1.Password", configuration.getIntegrationKeys().get("api"));
+			 configurationMap.put("acct1.Signature", configuration.getIntegrationKeys().get("signature"));
+				
+			 
+			 DoCaptureReq doCaptureReq = new DoCaptureReq();
+
+
+
+				
+				 BasicAmountType amount = new BasicAmountType();
+				 amount.setValue(pricingService.getStringAmount(order.getTotal(), store));
+				 amount.setCurrencyID(urn.ebay.apis.eBLBaseComponents.CurrencyCodeType.fromValue(order.getCurrency().getCode()));
+
+				// DoCaptureRequest which takes mandatory params:
+				// 
+				// Authorization ID - Authorization identification number of the
+				// payment you want to capture. This is the transaction ID
+				DoCaptureRequestType doCaptureRequest = new DoCaptureRequestType(
+						(String)capturableTransaction.getTransactionDetails().get("TRANSACTIONID"), amount, CompleteCodeType.NOTCOMPLETE);
+
+				doCaptureReq.setDoCaptureRequest(doCaptureRequest);
+
+				// ## Creating service wrapper object
+				// Creating service wrapper object to make API call and loading
+				// configuration file for your credentials and endpoint
+				PayPalAPIInterfaceServiceService service = new PayPalAPIInterfaceServiceService(configurationMap);
+				
+				DoCaptureResponseType doCaptureResponse = null;
+
+					// ## Making API call
+					// Invoke the appropriate method corresponding to API in service
+					// wrapper object
+					 doCaptureResponse = service
+							.doCapture(doCaptureReq);
+
+
+				// ## Accessing response parameters
+				// You can access the response parameters using getter methods in
+				// response object as shown below
+				// ### Success values
+				if(!"Success".equals(doCaptureResponse.getAck().getValue())) {
+							LOGGER.error("Wrong value from transaction commit " + doCaptureResponse.getAck().getValue());
+							throw new IntegrationException("Wrong paypal ack from refund transaction " + doCaptureResponse.getAck().getValue());
+				}
+				//if (doCaptureResponse.getAck().getValue()
+				//		.equalsIgnoreCase("success")) {
+					
+					// Authorization identification number
+					//logger.info("Authorization ID:"
+					//		+ doCaptureResponse.getDoCaptureResponseDetails()
+					//				.getAuthorizationID());
+				//}
+				// ### Error Values
+				// Access error values from error list using getter methods
+				//else {
+				//	List<ErrorType> errorList = doCaptureResponse.getErrors();
+				//	logger.severe("API Error Message : "
+				//			+ errorList.get(0).getLongMessage());
+				//}
+
+				//String refundAck = refundTransactionResponse.getAck().getValue();
+			 
+			 
+
+
+			 
+			 Transaction newTransaction = new Transaction();
+			 newTransaction.setAmount(order.getTotal());
+			 newTransaction.setTransactionDate(new Date());
+			 newTransaction.setTransactionType(TransactionType.CAPTURE);
+			 newTransaction.setPaymentType(PaymentType.PAYPAL);
+			 newTransaction.getTransactionDetails().put("AUTHORIZATIONID", doCaptureResponse.getDoCaptureResponseDetails().getAuthorizationID());
+			 newTransaction.getTransactionDetails().put("TRANSACTIONID", (String)capturableTransaction.getTransactionDetails().get("TRANSACTIONID"));
+
+			return newTransaction;
+			
+			
+		} catch(Exception e) {
+			throw new IntegrationException(e);
+		}
+		
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/PayPalRestPayment.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/PayPalRestPayment.java
new file mode 100644
index 0000000..54e4b23
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/impl/PayPalRestPayment.java
@@ -0,0 +1,262 @@
+package com.salesmanager.core.modules.integration.payment.impl;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+
+//import com.paypal.core.rest.OAuthTokenCredential;
+//import com.paypal.core.rest.PayPalRESTException;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.service.MerchantConfigurationService;
+import com.salesmanager.core.business.system.service.MerchantLogService;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.payment.model.PaymentModule;
+import com.salesmanager.core.utils.ProductPriceUtils;
+
+public class PayPalRestPayment implements PaymentModule {
+	
+	@Autowired
+	private ProductPriceUtils productPriceUtils;
+	
+	@Autowired
+	private MerchantConfigurationService merchantConfigurationService;
+	
+	@Autowired
+	private MerchantLogService merchantLogService;
+
+	@Override
+	public void validateModuleConfiguration(
+			IntegrationConfiguration integrationConfiguration,
+			MerchantStore store) throws IntegrationException {
+		
+		
+		List<String> errorFields = null;
+		
+		//validate integrationKeys['account']
+		Map<String,String> keys = integrationConfiguration.getIntegrationKeys();
+		if(keys==null || StringUtils.isBlank(keys.get("client"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("client");
+		}
+		
+		if(keys==null || StringUtils.isBlank(keys.get("secret"))) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("secret");
+		}
+		
+
+		if(errorFields!=null) {
+			IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
+			ex.setErrorFields(errorFields);
+			throw ex;
+			
+		}
+
+	}
+
+	@Override
+	public Transaction initTransaction(MerchantStore store, Customer customer,
+			BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public Transaction authorize(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		
+		return null;
+
+/*		
+		// ###AccessToken
+		// Retrieve the access token from
+		// OAuthTokenCredential by passing in
+		// ClientID and ClientSecret
+		APIContext apiContext = null;
+		String accessToken = null;
+		
+		try {
+			
+			String clientID = configuration.getIntegrationKeys().get("client");
+			String secret = configuration.getIntegrationKeys().get("secret");
+			
+			accessToken = getAccessToken(clientID, secret);
+
+			// ### Api Context
+			// Pass in a `ApiContext` object to authenticate
+			// the call and to send a unique request id
+			// (that ensures idempotency). The SDK generates
+			// a request id if you do not pass one explicitly.
+			apiContext = new APIContext(accessToken);
+			// Use this variant if you want to pass in a request id
+			// that is meaningful in your application, ideally
+			// a order id.
+			
+			 * String requestId = Long.toString(System.nanoTime(); APIContext
+			 * apiContext = new APIContext(accessToken, requestId ));
+			 
+
+			// ###Authorization
+			// Retrieve an Authorization Id
+			// by making a Payment with intent
+			// as 'authorize' and parsing through
+			// the Payment object
+			
+			
+			String authorizationID = null;
+
+			// ###Details
+			// Let's you specify details of a payment amount.
+			//Details details = new Details();
+			//details.setShipping("0.03");
+			//details.setSubtotal("107.41");
+			//details.setTax("0.03");
+
+			// ###Amount
+			// Let's you specify a payment amount.
+			
+			String sAmount = productPriceUtils.getAdminFormatedAmount(store, amount);
+			
+			
+			Amount amnt = new Amount();
+			amnt.setCurrency(store.getCurrency().getCode());
+			amnt.setTotal(sAmount);
+			//amnt.setDetails(details);
+
+			// ###Transaction
+			// A transaction defines the contract of a
+			// payment - what is the payment for and who
+			// is fulfilling it. Transaction is created with
+			// a `Payee` and `Amount` types
+			com.paypal.api.payments.Transaction transaction = new com.paypal.api.payments.Transaction();
+			transaction.setAmount(amnt);
+			//TODO change description
+			transaction.setDescription("This is the payment transaction description.");
+
+			// The Payment creation API requires a list of
+			// Transaction; add the created `Transaction`
+			// to a List
+			List<com.paypal.api.payments.Transaction> transactions = new ArrayList<com.paypal.api.payments.Transaction>();
+			transactions.add(transaction);
+
+			// ###Payer
+			// A resource representing a Payer that funds a payment
+			// Payment Method
+			// as 'paypal'
+			Payer payer = new Payer();
+			payer.setPaymentMethod("paypal");
+
+			// ###Payment
+			// A Payment Resource; create one using
+			// the above types and intent as 'sale'
+			com.paypal.api.payments.Payment ppayment = new com.paypal.api.payments.Payment();
+			ppayment.setIntent("sale");
+			ppayment.setPayer(payer);
+			ppayment.setTransactions(transactions);
+
+			// ###Redirect URLs
+			RedirectUrls redirectUrls = new RedirectUrls();
+			String guid = UUID.randomUUID().toString().replaceAll("-", "");
+			redirectUrls.setCancelUrl(req.getScheme() + "://"
+					+ req.getServerName() + ":" + req.getServerPort()
+					+ req.getContextPath() + "/paymentwithpaypal?guid=" + guid);
+			redirectUrls.setReturnUrl(req.getScheme() + "://"
+					+ req.getServerName() + ":" + req.getServerPort()
+					+ req.getContextPath() + "/paymentwithpaypal?guid=" + guid);
+			payment.setRedirectUrls(redirectUrls);
+
+			// Create a payment by posting to the APIService
+			// using a valid AccessToken
+			// The return object contains the status;
+			try {
+				Payment createdPayment = payment.create(apiContext);
+				LOGGER.info("Created payment with id = "
+						+ createdPayment.getId() + " and status = "
+						+ createdPayment.getState());
+				// ###Payment Approval Url
+				Iterator<Links> links = createdPayment.getLinks().iterator();
+				while (links.hasNext()) {
+					Links link = links.next();
+					if (link.getRel().equalsIgnoreCase("approval_url")) {
+						req.setAttribute("redirectURL", link.getHref());
+					}
+				}
+				req.setAttribute("response", Payment.getLastResponse());
+				map.put(guid, createdPayment.getId());
+			} catch (PayPalRESTException e) {
+				req.setAttribute("error", e.getMessage());
+			}
+		} catch (PayPalRESTException e) {
+			throw new IntegrationException(e);
+		}
+*/		
+		
+		
+	}
+
+/*	@Override
+	public Transaction capture(MerchantStore store, Customer customer,
+			List<ShoppingCartItem> items, BigDecimal amount, Payment payment, Transaction transaction,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		// TODO Auto-generated method stub
+		return null;
+	}*/
+
+	@Override
+	public Transaction authorizeAndCapture(MerchantStore store,
+			Customer customer, List<ShoppingCartItem> items, BigDecimal amount, Payment payment,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public Transaction refund(boolean partial, MerchantStore store,
+			Transaction transaction, Order order, BigDecimal amount,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+	
+	private String getAccessToken(String clientID, String clientSecret) throws Exception {
+
+		// ###AccessToken
+		// Retrieve the access token from
+		// OAuthTokenCredential by passing in
+		// ClientID and ClientSecret
+
+		return null;
+		//return new OAuthTokenCredential(clientID, clientSecret)
+		//		.getAccessToken();
+	}
+
+	@Override
+	public Transaction capture(MerchantStore store, Customer customer,
+			Order order, Transaction capturableTransaction,
+			IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/model/PaymentModule.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/model/PaymentModule.java
new file mode 100644
index 0000000..a6790bd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/payment/model/PaymentModule.java
@@ -0,0 +1,49 @@
+package com.salesmanager.core.modules.integration.payment.model;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.Payment;
+import com.salesmanager.core.business.payments.model.Transaction;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.modules.integration.IntegrationException;
+
+public interface PaymentModule {
+	
+	public void validateModuleConfiguration(IntegrationConfiguration integrationConfiguration, MerchantStore store) throws IntegrationException;
+	
+	/**
+	 * Returns token-value related to the initialization of the transaction This
+	 * method is invoked for paypal express checkout
+	 * @param customer
+	 * @param order
+	 * @return
+	 * @throws IntegrationException
+	 */
+	public Transaction initTransaction(
+			MerchantStore store, Customer customer, BigDecimal amount, Payment payment, IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException;
+	
+	public Transaction authorize(
+			MerchantStore store, Customer customer, List<ShoppingCartItem> items, BigDecimal amount, Payment payment, IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException;
+
+	
+	public Transaction capture(
+			MerchantStore store, Customer customer, Order order, Transaction capturableTransaction, IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException;
+	
+	public Transaction authorizeAndCapture(
+			MerchantStore store, Customer customer, List<ShoppingCartItem> items, BigDecimal amount, Payment payment, IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException;
+	
+	public Transaction refund(
+			boolean partial, MerchantStore store, Transaction transaction, Order order, BigDecimal amount, IntegrationConfiguration configuration, IntegrationModule module)
+			throws IntegrationException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/CanadaPostShippingQuote.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/CanadaPostShippingQuote.java
new file mode 100644
index 0000000..3eeabea
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/CanadaPostShippingQuote.java
@@ -0,0 +1,563 @@
+package com.salesmanager.core.modules.integration.shipping.impl;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+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.Validate;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingOption;
+import com.salesmanager.core.business.system.model.CustomIntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.MerchantLog;
+import com.salesmanager.core.business.system.model.ModuleConfig;
+import com.salesmanager.core.business.system.service.MerchantLogService;
+import com.salesmanager.core.constants.MeasureUnit;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.shipping.model.ShippingQuoteModule;
+import com.salesmanager.core.utils.DataUtils;
+import com.salesmanager.core.utils.ProductPriceUtils;
+
+/**
+ * Integrates with Canada Post sell online API
+ * @author casams1
+ *
+ */
+public class CanadaPostShippingQuote implements ShippingQuoteModule {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(CanadaPostShippingQuote.class);
+
+	
+	private final static String SHIPPING_TURN_AROUND_TIME = "24";
+
+
+	@Autowired
+	private ProductPriceUtils productPriceUtils;
+	
+	@Autowired
+	private MerchantLogService merchantLogService;
+
+	@Override
+	public void validateModuleConfiguration(
+			IntegrationConfiguration integrationConfiguration,
+			MerchantStore store) throws IntegrationException {
+		
+		
+		
+		
+		List<String> errorFields = null;
+		
+		//validate integrationKeys['account']
+		Map<String,String> keys = integrationConfiguration.getIntegrationKeys();
+		if(keys==null || StringUtils.isBlank(keys.get("account"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("identifier");
+		}
+
+		//validate at least one integrationOptions['packages']
+		Map<String,List<String>> options = integrationConfiguration.getIntegrationOptions();
+		if(options==null) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("identifier");
+		}
+		
+		List<String> packages = options.get("packages");
+		if(packages==null || packages.size()==0) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("packages");
+		}
+		
+		if(errorFields!=null) {
+			IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
+			ex.setErrorFields(errorFields);
+			throw ex;
+			
+		}
+
+	}
+	
+	@Override
+	public List<ShippingOption> getShippingQuotes(List<PackageDetails> packages, BigDecimal orderTotal, Delivery delivery, MerchantStore store, IntegrationConfiguration configuration, IntegrationModule module, ShippingConfiguration shippingConfiguration, Locale locale) throws IntegrationException {
+		BigDecimal total = orderTotal;
+
+
+		Validate.notNull(packages, "Packages are null");
+		Validate.notNull(delivery.getPostalCode(), "Delivery postal code is null");
+		
+		List<ShippingOption> options = 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());
+		}
+
+		// supports en and fr
+		String language = locale.getLanguage();
+		if (!language.equals(Locale.FRENCH.getLanguage())
+				&& !language.equals(Locale.ENGLISH.getLanguage())) {
+			language = Locale.ENGLISH.getLanguage();
+		}
+		
+
+		// if store is not CAD /** maintained in the currency **/
+/*		if (!store.getCurrency().equals(Constants.CURRENCY_CODE_CAD)) {
+			total = CurrencyUtil.convertToCurrency(total, store.getCurrency(),
+					Constants.CURRENCY_CODE_CAD);
+		}*/
+
+		
+		PostMethod httppost = null;
+		CanadaPostParsedElements canadaPost = null;
+
+		try {
+			
+			Map<String,String> keys = configuration.getIntegrationKeys();
+			if(keys==null || StringUtils.isBlank(keys.get("account"))) {
+				throw new IntegrationException("Canadapost missing configuration key account");
+			}
+
+			
+			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<String, ModuleConfig> 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();
+				}
+			}
+			
+
+
+			// accept KG and CM
+
+			StringBuilder request = new StringBuilder();
+
+			request.append("<?xml version=\"1.0\" ?>");
+			request.append("<eparcel>");
+			request.append("<language>").append(language).append("</language>");
+
+			request.append("<ratesAndServicesRequest>");
+			request.append("<merchantCPCID>").append(keys.get("account")).append(
+					"</merchantCPCID>");
+			request.append("<fromPostalCode>").append(
+					DataUtils
+							.trimPostalCode(store.getStorepostalcode()))
+					.append("</fromPostalCode>");
+			request.append("<turnAroundTime>").append(SHIPPING_TURN_AROUND_TIME).append(
+					"</turnAroundTime>");
+			request.append("<itemsPrice>").append(
+					productPriceUtils.getFormatedAmountWithCurrency(store,total, locale))
+					.append("</itemsPrice>");
+			request.append("<lineItems>");
+
+
+			for(PackageDetails pack : packages) {
+				request.append("<item>");
+				request.append("<quantity>").append(pack.getShippingQuantity())
+						.append("</quantity>");
+				request.append("<weight>").append(
+						String.valueOf(DataUtils.getWeight(pack
+								.getShippingWeight(), store,
+								MeasureUnit.KG.name()))).append("</weight>");
+				request.append("<length>").append(
+						String.valueOf(DataUtils.getMeasure(pack
+								.getShippingLength(), store,
+								MeasureUnit.CM.name()))).append("</length>");
+				request.append("<width>").append(
+						String.valueOf(DataUtils.getMeasure(pack
+								.getShippingWidth(), store,
+								MeasureUnit.CM.name()))).append("</width>");
+				request.append("<height>").append(
+						String.valueOf(DataUtils.getMeasure(pack
+								.getShippingHeight(), store,
+								MeasureUnit.CM.name()))).append("</height>");
+				request.append("<description>").append(pack.getItemName())
+						.append("</description>");
+				request.append("<readyToShip/>");//item is properly packed
+				request.append("</item>");
+			}
+			
+			request.append("</lineItems>");
+			
+			request.append("<city>").append(delivery.getCity()).append(
+					"</city>");
+			if(delivery.getZone()!=null) {
+				request.append("<provOrState>").append(delivery.getZone().getCode())
+					.append("</provOrState>");
+			} else {
+				request.append("<provOrState>").append(delivery.getZone())
+				.append("</provOrState>");				
+			}
+			request.append("<country>")
+					.append(delivery.getCountry().getIsoCode()).append(
+							"</country>");
+			request.append("<postalCode>").append(
+					DataUtils
+					.trimPostalCode(delivery.getPostalCode()))
+					.append("</postalCode>");
+			request.append("</ratesAndServicesRequest>");
+			request.append("</eparcel>");
+
+
+			/**
+			 * <?xml version="1.0" ?> <eparcel>
+			 * <!--********************************--> <!-- Prefered language
+			 * for the --> <!-- response (FR/EN) (optional) -->
+			 * <!--********************************--> <language>en</language>
+			 * 
+			 * <ratesAndServicesRequest>
+			 * <!--**********************************--> <!-- Merchant
+			 * Identification assigned --> <!-- by Canada Post --> <!-- --> <!--
+			 * Note: Use 'CPC_DEMO_HTML' or ask --> <!-- our Help Desk to change
+			 * your --> <!-- profile if you want HTML to be --> <!-- returned to
+			 * you --> <!--**********************************--> <merchantCPCID>
+			 * CPC_DEMO_XML </merchantCPCID>
+			 * 
+			 * <!--*********************************--> <!--Origin Postal Code
+			 * --> <!--This parameter is optional -->
+			 * <!--*********************************-->
+			 * <fromPostalCode>m1p1c0</fromPostalCode>
+			 * 
+			 * <!--**********************************--> <!-- Turn Around Time
+			 * (hours) --> <!-- This parameter is optional -->
+			 * <!--**********************************--> <turnAroundTime> 24
+			 * </turnAroundTime>
+			 * 
+			 * <!--**********************************--> <!-- Total amount in $
+			 * of the items --> <!-- for insurance calculation --> <!-- This
+			 * parameter is optional -->
+			 * <!--**********************************-->
+			 * <itemsPrice>0.00</itemsPrice>
+			 * 
+			 * <!--**********************************--> <!-- List of items in
+			 * the shopping --> <!-- cart --> <!-- Each item is defined by : -->
+			 * <!-- - quantity (mandatory) --> <!-- - size (mandatory) --> <!--
+			 * - weight (mandatory) --> <!-- - description (mandatory) --> <!--
+			 * - ready to ship (optional) -->
+			 * <!--**********************************--> <lineItems> <item>
+			 * <quantity> 1 </quantity> <weight> 1.491 </weight> <length> 1
+			 * </length> <width> 1 </width> <height> 1 </height> <description>
+			 * KAO Diskettes </description> </item>
+			 * 
+			 * <item> <quantity> 1 </quantity> <weight> 1.5 </weight> <length>
+			 * 20 </length> <width> 30 </width> <height> 20 </height>
+			 * <description> My Ready To Ship Item</description>
+			 * <!--**********************************************--> <!-- By
+			 * adding the 'readyToShip' tag, Sell Online --> <!-- will not pack
+			 * this item in the boxes --> <!-- defined in the merchant profile.
+			 * --> <!-- Instead, this item will be shipped in its --> <!--
+			 * original box: 1.5 kg and 20x30x20 cm -->
+			 * <!--**********************************************-->
+			 * <readyToShip/> </item> </lineItems>
+			 * 
+			 * <!--********************************--> <!-- City where the
+			 * parcel will be --> <!-- shipped to -->
+			 * <!--********************************--> <city> </city>
+			 * 
+			 * <!--********************************--> <!-- Province (Canada) or
+			 * State (US)--> <!-- where the parcel will be --> <!-- shipped to
+			 * --> <!--********************************--> <provOrState>
+			 * Wisconsin </provOrState>
+			 * 
+			 * <!--********************************--> <!-- Country or ISO
+			 * Country code --> <!-- where the parcel will be --> <!-- shipped
+			 * to --> <!--********************************--> <country> CANADA
+			 * </country>
+			 * 
+			 * <!--********************************--> <!-- Postal Code (or ZIP)
+			 * where the --> <!-- parcel will be shipped to -->
+			 * <!--********************************--> <postalCode>
+			 * H3K1E5</postalCode> </ratesAndServicesRequest> </eparcel>
+			 **/
+			
+
+			LOGGER.debug("canadapost request " + request.toString());
+
+			HttpClient client = new HttpClient();
+			
+			StringBuilder u = new StringBuilder().append(protocol).append("://").append(host).append(":").append(port);
+			if(!StringUtils.isBlank(url)) {
+				u.append(url);
+			}
+			
+			LOGGER.debug("Canadapost URL " + u.toString());
+
+			httppost = new PostMethod(u.toString());
+			RequestEntity entity = new StringRequestEntity(request.toString(),
+					"text/plain", "UTF-8");
+			httppost.setRequestEntity(entity);
+
+			int result = client.executeMethod(httppost);
+
+			if (result != 200) {
+				LOGGER.error("Communication Error with canadapost " + protocol
+						+ "://" + host + ":" + port + url);
+				throw new Exception("Communication Error with canadapost "
+						+ protocol + "://" + host + ":" + port + url);
+			}
+			String stringresult = httppost.getResponseBodyAsString();
+			LOGGER.debug("canadapost response " + stringresult);
+			
+			
+/*			<eparcel>
+			<error>
+			<statusCode>-3001</statusCode>
+			<statusMessage>Destination Postal Code/State Name/ Country is illegal. </statusMessage>
+			<requestID>2773909</requestID>
+			</error>
+			</eparcel>*/
+
+			canadaPost = new CanadaPostParsedElements();
+			Digester digester = new Digester();
+			digester.push(canadaPost);
+			
+			digester.addCallMethod(
+					"eparcel/error/statusCode",
+					"setStatusCode", 0);
+			
+			digester.addCallMethod(
+					"eparcel/error/statusMessage",
+					"setStatusMessage", 0);
+
+			digester.addCallMethod(
+					"eparcel/ratesAndServicesResponse/statusCode",
+					"setStatusCode", 0);
+			digester.addCallMethod(
+					"eparcel/ratesAndServicesResponse/statusMessage",
+					"setStatusMessage", 0);
+			digester.addObjectCreate(
+					"eparcel/ratesAndServicesResponse/product",
+					ShippingOption.class);
+			digester.addSetProperties(
+					"eparcel/ratesAndServicesResponse/product", "sequence",
+					"optionId");
+			digester.addCallMethod(
+					"eparcel/ratesAndServicesResponse/product/shippingDate",
+					"setOptionShippingDate", 0);
+			digester.addCallMethod(
+					"eparcel/ratesAndServicesResponse/product/deliveryDate",
+					"setOptionDeliveryDate", 0);
+			digester.addCallMethod(
+					"eparcel/ratesAndServicesResponse/product/name",
+					"setOptionName", 0);
+			digester.addCallMethod(
+					"eparcel/ratesAndServicesResponse/product/rate",
+					"setOptionPriceText", 0);
+			
+			digester.addSetNext("eparcel/ratesAndServicesResponse/product",
+					"addOption");
+
+			/**
+			 * response
+			 * 
+			 * <?xml version="1.0" ?> <!DOCTYPE eparcel (View Source for full
+			 * doctype...)> - <eparcel> - <ratesAndServicesResponse>
+			 * <statusCode>1</statusCode> <statusMessage>OK</statusMessage>
+			 * <requestID>1769506</requestID> <handling>0.0</handling>
+			 * <language>0</language> - <product id="1040" sequence="1">
+			 * <name>Priority Courier</name> <rate>38.44</rate>
+			 * <shippingDate>2008-12-22</shippingDate>
+			 * <deliveryDate>2008-12-23</deliveryDate>
+			 * <deliveryDayOfWeek>3</deliveryDayOfWeek>
+			 * <nextDayAM>true</nextDayAM> <packingID>P_0</packingID> </product>
+			 * - <product id="1020" sequence="2"> <name>Expedited</name>
+			 * <rate>16.08</rate> <shippingDate>2008-12-22</shippingDate>
+			 * <deliveryDate>2008-12-23</deliveryDate>
+			 * <deliveryDayOfWeek>3</deliveryDayOfWeek>
+			 * <nextDayAM>false</nextDayAM> <packingID>P_0</packingID>
+			 * </product> - <product id="1010" sequence="3">
+			 * <name>Regular</name> <rate>16.08</rate>
+			 * <shippingDate>2008-12-22</shippingDate>
+			 * <deliveryDate>2008-12-29</deliveryDate>
+			 * <deliveryDayOfWeek>2</deliveryDayOfWeek>
+			 * <nextDayAM>false</nextDayAM> <packingID>P_0</packingID>
+			 * </product> - <packing> <packingID>P_0</packingID> - <box>
+			 * <name>Small Box</name> <weight>1.691</weight>
+			 * <expediterWeight>1.691</expediterWeight> <length>25.0</length>
+			 * <width>17.0</width> <height>16.0</height> - <packedItem>
+			 * <quantity>1</quantity> <description>KAO Diskettes</description>
+			 * </packedItem> </box> - <box> <name>My Ready To Ship Item</name>
+			 * <weight>2.0</weight> <expediterWeight>1.5</expediterWeight>
+			 * <length>30.0</length> <width>20.0</width> <height>20.0</height> -
+			 * <packedItem> <quantity>1</quantity> <description>My Ready To Ship
+			 * Item</description> </packedItem> </box> </packing> -
+			 * <shippingOptions> <insurance>No</insurance>
+			 * <deliveryConfirmation>Yes</deliveryConfirmation>
+			 * <signature>No</signature> </shippingOptions> <comment />
+			 * </ratesAndServicesResponse> </eparcel> - <!-- END_OF_EPARCEL -->
+			 **/
+			
+			Reader reader = new StringReader(stringresult);
+			
+			digester.parse(reader);
+
+		
+			if (canadaPost == null || canadaPost.getStatusCode() == null) {
+				LOGGER.error("Nothing received from CanadaPost");
+				return null;
+			}
+			
+			System.out.println(canadaPost.getStatusCode());
+	
+			if (canadaPost.getStatusCode().equals("-6")
+					|| canadaPost.getStatusCode().equals("-7")) {
+				merchantLogService.save(
+						new MerchantLog(store,
+						"Can't process CanadaPost statusCode="
+								+ canadaPost.getStatusCode() + " message= "
+								+ canadaPost.getStatusMessage()));
+			}
+			
+			if (canadaPost.getStatusCode().equals("-5000")) {
+				merchantLogService.save(
+						new MerchantLog(store,("An error occured with canadapost request (code-> "
+						+ canadaPost.getStatusCode() + " message-> "
+						+ canadaPost.getStatusMessage() )));
+				throw new IntegrationException("Error with post canada service " + canadaPost.getStatusMessage());
+			}
+	
+			if (!canadaPost.getStatusCode().equals("1")) {
+				merchantLogService.save(
+						new MerchantLog(store,("An error occured with canadapost request (code-> "
+						+ canadaPost.getStatusCode() + " message-> "
+						+ canadaPost.getStatusMessage() )));
+				throw new IntegrationException("Error with post canada service " + canadaPost.getStatusMessage());
+			}
+
+		//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;
+		}*/
+		
+		
+		
+
+
+
+/*			options = canadaPost.getOptions();
+			for(ShippingOption option : options) {
+					StringBuilder description = new StringBuilder();
+					description.append(option.getOptionName());
+					if (shippingConfiguration.getShippingDescription()==ShippingDescription.LONG_DESCRIPTION) {
+						description.append(" (").append(option.getOptionDeliveryDate())
+								.append(")");
+					}
+					option.setDescription(description.toString());
+						if (requiresCurrencyConversion) {
+						option.setOptionPrice(CurrencyUtil.convertToCurrency(option
+								.getOptionPrice(), Constants.CURRENCY_CODE_CAD,
+								store.getCurrency()));
+					}
+					// System.out.println(option.getOptionPrice().toString());
+
+			}*/
+
+		
+		
+		} catch (Exception e) {
+			LOGGER.error("Canadapost getShippingQuote", e);
+			throw new IntegrationException(e);
+		} finally {
+				if (httppost != null) {
+					httppost.releaseConnection();
+				}
+		}
+
+		
+
+		return options;
+	}
+
+
+
+	@Override
+	public CustomIntegrationConfiguration getCustomModuleConfiguration(
+			MerchantStore store) throws IntegrationException {
+		//nothing to do
+		return null;
+	}
+	
+
+
+
+
+
+}
+
+class CanadaPostParsedElements {
+
+	private String statusCode;
+	private String statusMessage;
+	private List<ShippingOption> options = new ArrayList<ShippingOption>();
+
+	public void addOption(ShippingOption option) {
+		options.add(option);
+	}
+
+	public List<ShippingOption> 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;
+	}
+
+}
+
+
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/CustomWeightBasedShippingQuote.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/CustomWeightBasedShippingQuote.java
new file mode 100644
index 0000000..e80cf72
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/CustomWeightBasedShippingQuote.java
@@ -0,0 +1,153 @@
+package com.salesmanager.core.modules.integration.shipping.impl;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingBasisType;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingOption;
+import com.salesmanager.core.business.system.model.CustomIntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.MerchantConfiguration;
+import com.salesmanager.core.business.system.service.MerchantConfigurationService;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.shipping.model.CustomShippingQuoteWeightItem;
+import com.salesmanager.core.modules.integration.shipping.model.CustomShippingQuotesConfiguration;
+import com.salesmanager.core.modules.integration.shipping.model.CustomShippingQuotesRegion;
+import com.salesmanager.core.modules.integration.shipping.model.ShippingQuoteModule;
+import com.salesmanager.core.utils.ProductPriceUtils;
+
+public class CustomWeightBasedShippingQuote implements ShippingQuoteModule {
+	
+	public final static String MODULE_CODE = "weightBased";
+	private final static String CUSTOM_WEIGHT = "CUSTOM_WEIGHT";
+	
+	@Autowired
+	private MerchantConfigurationService merchantConfigurationService;
+	
+	@Autowired
+	private ProductPriceUtils productPriceUtils;
+
+
+	@Override
+	public void validateModuleConfiguration(
+			IntegrationConfiguration integrationConfiguration,
+			MerchantStore store) throws IntegrationException {
+		
+		
+		//not used, it has its own controller with complex validators
+
+	}
+	
+
+	@Override
+	public CustomIntegrationConfiguration getCustomModuleConfiguration(
+			MerchantStore store) throws IntegrationException {
+
+		try {
+
+			MerchantConfiguration configuration = merchantConfigurationService.getMerchantConfiguration(MODULE_CODE, store);
+	
+			if(configuration!=null) {
+				String value = configuration.getValue();
+				ObjectMapper mapper = new ObjectMapper();
+				try {
+					CustomShippingQuotesConfiguration config = mapper.readValue(value, CustomShippingQuotesConfiguration.class);
+					return config;
+				} catch(Exception e) {
+					throw new ServiceException("Cannot parse json string " + value);
+				}
+	
+			} else {
+				CustomShippingQuotesConfiguration custom = new CustomShippingQuotesConfiguration();
+				custom.setModuleCode(MODULE_CODE);
+				return custom;
+			}
+		
+		} catch (Exception e) {
+			throw new IntegrationException(e);
+		}
+		
+		
+	}
+
+	@Override
+	public List<ShippingOption> getShippingQuotes(
+			List<PackageDetails> packages, BigDecimal orderTotal,
+			Delivery delivery, MerchantStore store,
+			IntegrationConfiguration configuration, IntegrationModule module,
+			ShippingConfiguration shippingConfiguration, Locale locale)
+			throws IntegrationException {
+
+		
+		
+		//get configuration
+		CustomShippingQuotesConfiguration customConfiguration = (CustomShippingQuotesConfiguration)this.getCustomModuleConfiguration(store);
+		
+		
+		List<CustomShippingQuotesRegion> regions = customConfiguration.getRegions();
+		
+		ShippingBasisType shippingType =  shippingConfiguration.getShippingBasisType();
+		ShippingOption shippingOption = null;
+		try {
+			
+
+			for(CustomShippingQuotesRegion region : customConfiguration.getRegions()) {
+	
+				for(String countryCode : region.getCountries()) {
+					if(countryCode.equals(delivery.getCountry().getIsoCode())) {
+						
+						
+						//determine shipping weight
+						double weight = 0;
+						for(PackageDetails packageDetail : packages) {
+							weight = weight + packageDetail.getShippingWeight();
+						}
+						
+						//see the price associated with the width
+						List<CustomShippingQuoteWeightItem> quoteItems = region.getQuoteItems();
+						for(CustomShippingQuoteWeightItem quoteItem : quoteItems) {
+							if(weight<= quoteItem.getMaximumWeight()) {
+								shippingOption = new ShippingOption();
+								shippingOption.setOptionCode(new StringBuilder().append(CUSTOM_WEIGHT).toString());
+								shippingOption.setOptionId(new StringBuilder().append(CUSTOM_WEIGHT).append("_").append(region.getCustomRegionName()).toString());
+								shippingOption.setOptionPrice(quoteItem.getPrice());
+								shippingOption.setOptionPriceText(productPriceUtils.getStoreFormatedAmountWithCurrency(store, quoteItem.getPrice()));
+								break;
+							}
+						}
+						
+					}
+					
+					
+				}
+				
+			}
+			
+			if(shippingOption!=null) {
+				List<ShippingOption> options = new ArrayList<ShippingOption>();
+				options.add(shippingOption);
+				return options;
+			}
+			
+			return null;
+		
+		} catch (Exception e) {
+			throw new IntegrationException(e);
+		}
+
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/DefaultPackagingImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/DefaultPackagingImpl.java
new file mode 100644
index 0000000..1a95a72
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/DefaultPackagingImpl.java
@@ -0,0 +1,436 @@
+package com.salesmanager.core.modules.integration.shipping.impl;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingProduct;
+import com.salesmanager.core.business.shipping.service.ShippingService;
+import com.salesmanager.core.business.system.model.MerchantLog;
+import com.salesmanager.core.business.system.service.MerchantLogService;
+import com.salesmanager.core.modules.integration.shipping.model.Packaging;
+
+public class DefaultPackagingImpl implements Packaging {
+
+	
+	@Autowired
+	private ShippingService shippingService;
+	
+	@Autowired
+	private MerchantLogService merchantLogService;
+	
+	/** default dimensions **/
+	private final static Double defaultWeight = 1D;
+	private final static Double defaultHeight = 4D;
+	private final static Double defaultLength = 4D;
+	private final static Double defaultWidth = 4D;
+	
+	@Override
+	public List<PackageDetails> getBoxPackagesDetails(
+			List<ShippingProduct> products, MerchantStore store)
+			throws ServiceException {
+
+		
+		if (products == null) {
+			throw new ServiceException("Product list cannot be null !!");
+		}
+
+		double width = 0;
+		double length = 0;
+		double height = 0;
+		double weight = 0;
+		double maxweight = 0;
+
+		//int treshold = 0;
+		
+		
+		ShippingConfiguration shippingConfiguration = shippingService.getShippingConfiguration(store);
+		if(shippingConfiguration==null) {
+			throw new ServiceException("ShippingConfiguration not found for merchant " + store.getCode());
+		}
+		
+		width = new Double(shippingConfiguration.getBoxWidth()).doubleValue();
+		length = new Double(shippingConfiguration.getBoxLength()).doubleValue();
+		height = new Double(shippingConfiguration.getBoxHeight()).doubleValue();
+		weight = new Double(shippingConfiguration.getBoxWeight()).doubleValue();
+		maxweight = new Double(shippingConfiguration.getMaxWeight()).doubleValue();
+		
+
+
+		List<PackageDetails> boxes = new ArrayList<PackageDetails>();
+
+		// maximum number of boxes
+		int maxBox = 100;
+		int iterCount = 0;
+
+		List<Product> individualProducts = new ArrayList<Product>();
+
+		// need to put items individually
+		for(ShippingProduct shippingProduct : products){
+
+			Product product = shippingProduct.getProduct();
+			if (product.isProductVirtual()) {
+				continue;
+			}
+
+			int qty = shippingProduct.getQuantity();
+
+			Set<ProductAttribute> attrs = shippingProduct.getProduct().getAttributes();
+
+			// set attributes values
+			BigDecimal w = product.getProductWeight();
+			BigDecimal h = product.getProductHeight();
+			BigDecimal l = product.getProductLength();
+			BigDecimal wd = product.getProductWidth();
+			if(w==null) {
+				w = new BigDecimal(defaultWeight);
+			}
+			if(h==null) {
+				h = new BigDecimal(defaultHeight);
+			}
+			if(l==null) {
+				l = new BigDecimal(defaultLength);
+			}
+			if(wd==null) {
+				wd = new BigDecimal(defaultWidth);
+			}
+			if (attrs != null && attrs.size() > 0) {
+				for(ProductAttribute attribute : attrs) {
+					if(attribute.getProductAttributeWeight()!=null) {
+						w = w.add(attribute.getProductAttributeWeight());
+					}
+				}
+			}
+			
+
+
+			if (qty > 1) {
+
+				for (int i = 1; i <= qty; i++) {
+					Product temp = new Product();
+					temp.setProductHeight(h);
+					temp.setProductLength(l);
+					temp.setProductWidth(wd);
+					temp.setProductWeight(w);
+					temp.setAttributes(product.getAttributes());
+					temp.setDescriptions(product.getDescriptions());
+					individualProducts.add(temp);
+				}
+			} else {
+				Product temp = new Product();
+				temp.setProductHeight(h);
+				temp.setProductLength(l);
+				temp.setProductWidth(wd);
+				temp.setProductWeight(w);
+				temp.setAttributes(product.getAttributes());
+				temp.setDescriptions(product.getDescriptions());
+				individualProducts.add(temp);
+			}
+			iterCount++;
+		}
+
+		if (iterCount == 0) {
+			return null;
+		}
+
+		int productCount = individualProducts.size();
+
+		List<PackingBox> boxesList = new ArrayList<PackingBox>();
+
+		//start the creation of boxes
+		PackingBox box = new PackingBox();
+		// set box max volume
+		double maxVolume = width * length * height;
+
+		if (maxVolume == 0 || maxweight == 0) {
+			
+			merchantLogService.save(new MerchantLog(store,"shipping","Check shipping box configuration, it has a volume of "
+							+ maxVolume + " and a maximum weight of "
+							+ maxweight
+							+ ". Those values must be greater than 0."));
+			
+			throw new ServiceException("Product configuration exceeds box configuraton");
+			
+
+		}
+		
+		
+		box.setVolumeLeft(maxVolume);
+		box.setWeightLeft(maxweight);
+
+		boxesList.add(box);//assign first box
+
+		//int boxCount = 1;
+		List<Product> assignedProducts = new ArrayList<Product>();
+
+		// calculate the volume for the next object
+		if (assignedProducts.size() > 0) {
+			individualProducts.removeAll(assignedProducts);
+			assignedProducts = new ArrayList<Product>();
+		}
+
+		boolean productAssigned = false;
+
+		for(Product p : individualProducts) {
+
+			//Set<ProductAttribute> attributes = p.getAttributes();
+			productAssigned = false;
+
+			double productWeight = p.getProductWeight().doubleValue();
+
+
+			// validate if product fits in the box
+			if (p.getProductWidth().doubleValue() > width
+					|| p.getProductHeight().doubleValue() > height
+					|| p.getProductLength().doubleValue() > length) {
+				// log message to customer
+				merchantLogService.save(new MerchantLog(store,"shipping","Product "
+						+ p.getSku()
+						+ " has a demension larger than the box size specified. Will use per item calculation."));
+				throw new ServiceException("Product configuration exceeds box configuraton");
+
+			}
+
+			if (productWeight > maxweight) {
+				merchantLogService.save(new MerchantLog(store,"shipping","Product "
+						+ p.getSku()
+						+ " has a weight larger than the box maximum weight specified. Will use per item calculation."));
+				
+				throw new ServiceException("Product configuration exceeds box configuraton");
+
+			}
+
+			double productVolume = (p.getProductWidth().doubleValue()
+					* p.getProductHeight().doubleValue() * p
+					.getProductLength().doubleValue());
+
+			if (productVolume == 0) {
+				
+				merchantLogService.save(new MerchantLog(store,"shipping","Product "
+						+ p.getSku()
+						+ " has one of the dimension set to 0 and therefore cannot calculate the volume"));
+				
+				throw new ServiceException("Product configuration exceeds box configuraton");
+				
+
+			}
+			
+			if (productVolume > maxVolume) {
+				
+				throw new ServiceException("Product configuration exceeds box configuraton");
+				
+			}
+
+			//List boxesList = boxesList;
+
+			// try each box
+			//Iterator boxIter = boxesList.iterator();
+			for (PackingBox pbox : boxesList) {
+				double volumeLeft = pbox.getVolumeLeft();
+				double weightLeft = pbox.getWeightLeft();
+
+				if ((volumeLeft * .75) >= productVolume
+						&& pbox.getWeightLeft() >= productWeight) {// fit the item
+																	// in this
+																	// box
+					// fit in the current box
+					volumeLeft = volumeLeft - productVolume;
+					pbox.setVolumeLeft(volumeLeft);
+					weightLeft = weightLeft - productWeight;
+					pbox.setWeightLeft(weightLeft);
+
+					assignedProducts.add(p);
+					productCount--;
+
+					double w = pbox.getWeight();
+					w = w + productWeight;
+					pbox.setWeight(w);
+					productAssigned = true;
+					maxBox--;
+					break;
+
+				}
+
+			}
+
+			if (!productAssigned) {// create a new box
+
+				box = new PackingBox();
+				// set box max volume
+				box.setVolumeLeft(maxVolume);
+				box.setWeightLeft(maxweight);
+
+				boxesList.add(box);
+
+				double volumeLeft = box.getVolumeLeft() - productVolume;
+				box.setVolumeLeft(volumeLeft);
+				double weightLeft = box.getWeightLeft() - productWeight;
+				box.setWeightLeft(weightLeft);
+				assignedProducts.add(p);
+				productCount--;
+				double w = box.getWeight();
+				w = w + productWeight;
+				box.setWeight(w);
+				maxBox--;
+			}
+
+		}
+
+		// now prepare the shipping info
+
+		// number of boxes
+
+		//Iterator ubIt = usedBoxesList.iterator();
+
+		System.out.println("###################################");
+		System.out.println("Number of boxes " + boxesList.size());
+		System.out.println("###################################");
+
+		for(PackingBox pb : boxesList) {
+			PackageDetails details = new PackageDetails();
+			details.setShippingHeight(height);
+			details.setShippingLength(length);
+			details.setShippingWeight(weight + box.getWeight());
+			details.setShippingWidth(width);
+			details.setItemName(store.getCode());
+			boxes.add(details);
+		}
+
+		return boxes;
+
+	}
+
+	@Override
+	public List<PackageDetails> getItemPackagesDetails(
+			List<ShippingProduct> products, MerchantStore store)
+			throws ServiceException {
+		
+		
+		List<PackageDetails> packages = new ArrayList<PackageDetails>();
+		for(ShippingProduct shippingProduct : products) {
+			Product product = shippingProduct.getProduct();
+
+			if (product.isProductVirtual()) {
+				continue;
+			}
+
+			//BigDecimal weight = product.getProductWeight();
+			Set<ProductAttribute> attributes = product.getAttributes();
+			// set attributes values
+			BigDecimal w = product.getProductWeight();
+			BigDecimal h = product.getProductHeight();
+			BigDecimal l = product.getProductLength();
+			BigDecimal wd = product.getProductWidth();
+			if(w==null) {
+				w = new BigDecimal(defaultWeight);
+			}
+			if(h==null) {
+				h = new BigDecimal(defaultHeight);
+			}
+			if(l==null) {
+				l = new BigDecimal(defaultLength);
+			}
+			if(wd==null) {
+				wd = new BigDecimal(defaultWidth);
+			}
+			if (attributes != null && attributes.size() > 0) {
+				for(ProductAttribute attribute : attributes) {
+					if(attribute.getAttributeAdditionalWeight()!=null) {
+						w = w.add(attribute.getProductAttributeWeight());
+					}
+				}
+			}
+			
+			
+
+			if (shippingProduct.getQuantity() == 1) {
+				PackageDetails detail = new PackageDetails();
+
+	
+				detail.setShippingHeight(h
+						.doubleValue());
+				detail.setShippingLength(l
+						.doubleValue());
+				detail.setShippingWeight(w.doubleValue());
+				detail.setShippingWidth(wd.doubleValue());
+				detail.setShippingQuantity(shippingProduct.getQuantity());
+				String description = "item";
+				if(product.getDescriptions().size()>0) {
+					description = product.getDescriptions().iterator().next().getName();
+				}
+				detail.setItemName(description);
+	
+				packages.add(detail);
+			} else if (shippingProduct.getQuantity() > 1) {
+				for (int i = 0; i < shippingProduct.getQuantity(); i++) {
+					PackageDetails detail = new PackageDetails();
+					detail.setShippingHeight(h
+							.doubleValue());
+					detail.setShippingLength(l
+							.doubleValue());
+					detail.setShippingWeight(w.doubleValue());
+					detail.setShippingWidth(wd
+							.doubleValue());
+					detail.setShippingQuantity(shippingProduct.getQuantity());
+					String description = "item";
+					if(product.getDescriptions().size()>0) {
+						description = product.getDescriptions().iterator().next().getName();
+					}
+					detail.setItemName(description);
+					
+					packages.add(detail);
+				}
+			}
+		}
+		
+		return packages;
+		
+		
+		
+	}
+
+
+}
+
+
+class PackingBox {
+
+	private double volumeLeft;
+	private double weightLeft;
+	private double weight;
+
+	public double getVolumeLeft() {
+		return volumeLeft;
+	}
+
+	public void setVolumeLeft(double volumeLeft) {
+		this.volumeLeft = volumeLeft;
+	}
+
+	public double getWeight() {
+		return weight;
+	}
+
+	public void setWeight(double weight) {
+		this.weight = weight;
+	}
+
+	public double getWeightLeft() {
+		return weightLeft;
+	}
+
+	public void setWeightLeft(double weightLeft) {
+		this.weightLeft = weightLeft;
+	}
+
+}
+
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/UPSShippingQuote.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/UPSShippingQuote.java
new file mode 100644
index 0000000..89cec30
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/UPSShippingQuote.java
@@ -0,0 +1,681 @@
+package com.salesmanager.core.modules.integration.shipping.impl;
+
+import java.io.BufferedReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+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.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingOption;
+import com.salesmanager.core.business.system.model.CustomIntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.ModuleConfig;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.shipping.model.ShippingQuoteModule;
+import com.salesmanager.core.utils.DataUtils;
+
+/**
+ * Integrates with UPS online API
+ * @author casams1
+ *
+ */
+public class UPSShippingQuote implements ShippingQuoteModule {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(UPSShippingQuote.class);
+
+
+	@Override
+	public void validateModuleConfiguration(
+			IntegrationConfiguration integrationConfiguration,
+			MerchantStore store) throws IntegrationException {
+		
+		
+		List<String> errorFields = null;
+		
+		//validate integrationKeys['accessKey']
+		Map<String,String> keys = integrationConfiguration.getIntegrationKeys();
+		if(keys==null || StringUtils.isBlank(keys.get("accessKey"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("accessKey");
+		}
+		
+		if(keys==null || StringUtils.isBlank(keys.get("userId"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("userId");
+		}
+		
+		if(keys==null || StringUtils.isBlank(keys.get("password"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("password");
+		}
+
+		//validate at least one integrationOptions['packages']
+		Map<String,List<String>> options = integrationConfiguration.getIntegrationOptions();
+		if(options==null) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("packages");
+		}
+		
+		List<String> packages = options.get("packages");
+		if(packages==null || packages.size()==0) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("packages");
+		}
+		
+/*		List<String> services = options.get("services");
+		if(services==null || services.size()==0) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("services");
+		}
+		
+		if(services!=null && services.size()>3) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("services");
+		}*/
+		
+		if(errorFields!=null) {
+			IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
+			ex.setErrorFields(errorFields);
+			throw ex;
+			
+		}
+		
+		
+
+	}
+
+	@Override
+	public List<ShippingOption> getShippingQuotes(
+			List<PackageDetails> packages, BigDecimal orderTotal,
+			Delivery delivery, MerchantStore store,
+			IntegrationConfiguration configuration, IntegrationModule module,
+			ShippingConfiguration shippingConfiguration, Locale locale)
+			throws IntegrationException {
+
+		
+		
+		BigDecimal total = orderTotal;
+
+		if (packages == null) {
+			return null;
+		}
+		
+		List<ShippingOption> options = null;
+
+		// only applies to Canada and US
+		Country country = delivery.getCountry();
+		
+
+		
+		if(!(country.getIsoCode().equals("US") || country.getIsoCode().equals("CA"))) {
+			return null;
+			//throw new IntegrationException("UPS Not configured for shipping in country " + country.getIsoCode());
+		}
+
+		// supports en and fr
+		String language = locale.getLanguage();
+		if (!language.equals(Locale.FRENCH.getLanguage())
+				&& !language.equals(Locale.ENGLISH.getLanguage())) {
+			language = Locale.ENGLISH.getLanguage();
+		}
+		
+		String pack = configuration.getIntegrationOptions().get("packages").get(0);
+		Map<String,String> keys = configuration.getIntegrationKeys();
+		
+		String accessKey = keys.get("accessKey");
+		String userId = keys.get("userId");
+		String password = keys.get("password");
+		
+		
+		String host = null;
+		String protocol = null;
+		String port = null;
+		String url = null;
+		
+		StringBuilder xmlbuffer = new StringBuilder();
+		PostMethod httppost = null;
+		BufferedReader reader = null;
+
+		try {
+			String env = configuration.getEnvironment();
+			
+			Set<String> regions = module.getRegionsSet();
+			if(!regions.contains(store.getCountry().getIsoCode())) {
+				throw new IntegrationException("Can't use the service for store country code ");
+			}
+			
+			Map<String, ModuleConfig> 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();
+				}
+			}
+
+			
+			StringBuilder xmlreqbuffer = new StringBuilder();
+			xmlreqbuffer.append("<?xml version=\"1.0\"?>");
+			xmlreqbuffer.append("<AccessRequest>");
+			xmlreqbuffer.append("<AccessLicenseNumber>");
+			xmlreqbuffer.append(accessKey);
+			xmlreqbuffer.append("</AccessLicenseNumber>");
+			xmlreqbuffer.append("<UserId>");
+			xmlreqbuffer.append(userId);
+			xmlreqbuffer.append("</UserId>");
+			xmlreqbuffer.append("<Password>");
+			xmlreqbuffer.append(password);
+			xmlreqbuffer.append("</Password>");
+			xmlreqbuffer.append("</AccessRequest>");
+			
+			String xmlhead = xmlreqbuffer.toString();
+			
+
+			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>Shopizer</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 (store.getZone() != null) {
+				xmldatabuffer.append("<StateProvinceCode>");
+				xmldatabuffer.append(store.getZone().getCode());// zone code
+				xmldatabuffer.append("</StateProvinceCode>");
+			}
+			xmldatabuffer.append("<CountryCode>");
+			xmldatabuffer.append(store.getCountry().getIsoCode());
+			xmldatabuffer.append("</CountryCode>");
+			xmldatabuffer.append("<PostalCode>");
+			xmldatabuffer.append(DataUtils
+					.trimPostalCode(store.getStorepostalcode()));
+			xmldatabuffer.append("</PostalCode></Address></Shipper>");
+
+			// ship to
+			xmldatabuffer.append("<ShipTo>");
+			xmldatabuffer.append("<Address>");
+			xmldatabuffer.append("<City>");
+			xmldatabuffer.append(delivery.getCity());
+			xmldatabuffer.append("</City>");
+			// if(!StringUtils.isBlank(customer.getCustomerState())) {
+			if (delivery.getZone() != null) {
+				xmldatabuffer.append("<StateProvinceCode>");
+				xmldatabuffer.append(delivery.getZone().getCode());// zone code
+				xmldatabuffer.append("</StateProvinceCode>");
+			}
+			xmldatabuffer.append("<CountryCode>");
+			xmldatabuffer.append(delivery.getCountry().getIsoCode());
+			xmldatabuffer.append("</CountryCode>");
+			xmldatabuffer.append("<PostalCode>");
+			xmldatabuffer.append(DataUtils
+					.trimPostalCode(delivery.getPostalCode()));
+			xmldatabuffer.append("</PostalCode></Address></ShipTo>");
+			// xmldatabuffer.append("<Service><Code>11</Code></Service>");//TODO service codes (next day ...)
+
+
+			for(PackageDetails packageDetail : packages){
+
+				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(packageDetail.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(packageDetail.getShippingLength())
+						.setScale(2, BigDecimal.ROUND_HALF_UP));
+				xmldatabuffer.append("</Length>");
+				xmldatabuffer.append("<Width>");
+				xmldatabuffer.append(new BigDecimal(packageDetail.getShippingWidth())
+						.setScale(2, BigDecimal.ROUND_HALF_UP));
+				xmldatabuffer.append("</Width>");
+				xmldatabuffer.append("<Height>");
+				xmldatabuffer.append(new BigDecimal(packageDetail.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());
+			
+
+
+			LOGGER.debug("UPS QUOTE REQUEST " + xmlbuffer.toString());
+
+			String data = "";
+
+
+			HttpClient client = new HttpClient();
+			httppost = new PostMethod(protocol + "://" + host + ":" + port
+					+ url);
+			RequestEntity entity = new StringRequestEntity(
+					xmlbuffer.toString(), "text/plain", "UTF-8");
+			httppost.setRequestEntity(entity);
+
+			int result = client.executeMethod(httppost);
+			if (result != 200) {
+				LOGGER.error("Communication Error with ups quote " + result + " "
+						+ protocol + "://" + host + ":" + port + url);
+				throw new Exception("UPS quote communication error " + result);
+			}
+			data = httppost.getResponseBodyAsString();
+			LOGGER.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",
+					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())) {
+
+				
+					LOGGER.error("Can't process UPS statusCode="
+							+ parsed.getErrorCode() + " message= "
+							+ parsed.getError());
+				throw new IntegrationException(parsed.getError());
+			}
+			if (!StringUtils.isBlank(parsed.getStatusCode())
+					&& !parsed.getStatusCode().equals("1")) {
+
+				throw new IntegrationException(parsed.getError());
+			}
+
+			if (parsed.getOptions() == null || parsed.getOptions().size() == 0) {
+
+				throw new IntegrationException("No shipping options available for the configuration");
+			}
+
+			/*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() + "]");
+					}
+				}
+			}*/
+			
+
+			List<ShippingOption> shippingOptions = parsed.getOptions();
+			
+			if(shippingOptions!=null) {
+				
+				Map<String,String> details = module.getDetails();
+				
+				for(ShippingOption option : shippingOptions) {
+					
+					String name = details.get(option.getOptionCode());
+					option.setOptionName(name);
+					if(option.getOptionPrice()==null) {
+						String priceText = option.getOptionPriceText();
+						if(StringUtils.isBlank(priceText)) {
+							throw new IntegrationException("Price text is null for option " + name);
+						}
+						
+						try {
+							BigDecimal price = new BigDecimal(priceText);
+							option.setOptionPrice(price);
+						} catch(Exception e) {
+							throw new IntegrationException("Can't convert to numeric price " + priceText);
+						}
+						
+					}
+					
+					
+				}
+				
+				
+			}
+			
+/*			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 shippingOptions;
+
+		} catch (Exception e1) {
+			LOGGER.error("UPS quote error",e1);
+			throw new IntegrationException(e1);
+		} finally {
+			if (reader != null) {
+				try {
+					reader.close();
+				} catch (Exception ignore) {
+				}
+			}
+
+			if (httppost != null) {
+				httppost.releaseConnection();
+			}
+		}
+}
+
+
+	@Override
+	public CustomIntegrationConfiguration getCustomModuleConfiguration(
+			MerchantStore store) throws IntegrationException {
+		//nothing to do
+		return null;
+	}}
+
+
+class UPSParsedElements  {
+
+	private String statusCode;
+	private String statusMessage;
+	private String error = "";
+	private String errorCode = "";
+	private List<ShippingOption> options = new ArrayList<ShippingOption>();
+
+	public void addOption(ShippingOption option) {
+		options.add(option);
+	}
+
+	public List<ShippingOption> 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;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/USPSShippingQuote.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/USPSShippingQuote.java
new file mode 100644
index 0000000..9cedbb4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/impl/USPSShippingQuote.java
@@ -0,0 +1,721 @@
+package com.salesmanager.core.modules.integration.shipping.impl;
+
+import java.io.Reader;
+import java.io.StringReader;
+import java.math.BigDecimal;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.commons.digester.Digester;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingOption;
+import com.salesmanager.core.business.system.model.CustomIntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.MerchantLog;
+import com.salesmanager.core.business.system.model.ModuleConfig;
+import com.salesmanager.core.business.system.service.MerchantLogService;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.constants.MeasureUnit;
+import com.salesmanager.core.modules.integration.IntegrationException;
+import com.salesmanager.core.modules.integration.shipping.model.ShippingQuoteModule;
+import com.salesmanager.core.utils.DataUtils;
+import com.salesmanager.core.utils.ProductPriceUtils;
+
+/**
+ * Integrates with USPS online API
+ * @author casams1
+ *
+ */
+public class USPSShippingQuote implements ShippingQuoteModule {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(USPSShippingQuote.class);
+
+	
+	@Autowired
+	private ProductPriceUtils productPriceUtils;
+	
+	@Autowired
+	private CountryService countryService;
+	
+
+	@Override
+	public void validateModuleConfiguration(
+			IntegrationConfiguration integrationConfiguration,
+			MerchantStore store) throws IntegrationException {
+		
+		
+		List<String> errorFields = null;
+		
+		//validate integrationKeys['account']
+		Map<String,String> keys = integrationConfiguration.getIntegrationKeys();
+		if(keys==null || StringUtils.isBlank(keys.get("account"))) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("identifier");
+		}
+
+		//validate at least one integrationOptions['packages']
+		Map<String,List<String>> options = integrationConfiguration.getIntegrationOptions();
+		if(options==null) {
+			errorFields = new ArrayList<String>();
+			errorFields.add("identifier");
+		}
+		
+		List<String> packages = options.get("packages");
+		if(packages==null || packages.size()==0) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("packages");
+		}
+		
+/*		List<String> services = options.get("services");
+		if(services==null || services.size()==0) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("services");
+		}
+		
+		if(services!=null && services.size()>3) {
+			if(errorFields==null) {
+				errorFields = new ArrayList<String>();
+			}
+			errorFields.add("services");
+		}*/
+		
+		if(errorFields!=null) {
+			IntegrationException ex = new IntegrationException(IntegrationException.ERROR_VALIDATION_SAVE);
+			ex.setErrorFields(errorFields);
+			throw ex;
+			
+		}
+		
+		
+
+	}
+
+	@Override
+	public List<ShippingOption> getShippingQuotes(
+			List<PackageDetails> packages, BigDecimal orderTotal,
+			Delivery delivery, MerchantStore store,
+			IntegrationConfiguration configuration, IntegrationModule module,
+			ShippingConfiguration shippingConfiguration, Locale locale)
+			throws IntegrationException {
+
+	
+
+		if (packages == null) {
+			return null;
+		}
+		
+
+
+		// only applies to Canada and US
+/*		Country country = delivery.getCountry();
+		if(!country.getIsoCode().equals("US") || !country.getIsoCode().equals("US")){
+			throw new IntegrationException("USPS Not configured for shipping in country " + country.getIsoCode());
+		}*/
+		
+
+
+		// supports en and fr
+		String language = locale.getLanguage();
+		if (!language.equals(Locale.FRENCH.getLanguage())
+				&& !language.equals(Locale.ENGLISH.getLanguage())) {
+			language = Locale.ENGLISH.getLanguage();
+		}
+		
+
+		// if store is not CAD /** maintained in the currency **/
+/*		if (!store.getCurrency().equals(Constants.CURRENCY_CODE_CAD)) {
+			total = CurrencyUtil.convertToCurrency(total, store.getCurrency(),
+					Constants.CURRENCY_CODE_CAD);
+		}*/
+		
+		Language lang = store.getDefaultLanguage();
+		
+
+		
+		GetMethod httpget = null;
+		Reader xmlreader = null;
+		String pack = configuration.getIntegrationOptions().get("packages").get(0);
+
+		try {
+			
+			Map<String,Country> countries = countryService.getCountriesMap(lang);
+
+			Country destination = countries.get(delivery.getCountry().getIsoCode());
+			
+		
+			
+			Map<String,String> keys = configuration.getIntegrationKeys();
+			if(keys==null || StringUtils.isBlank(keys.get("account"))) {
+				return null;//TODO can we return null
+			}
+
+			
+			String host = null;
+			String protocol = null;
+			String port = null;
+			String url = null;
+		
+			
+			
+			//against which environment are we using the service
+			String env = configuration.getEnvironment();
+
+			//must be US
+			if(!store.getCountry().getIsoCode().equals("US")) {
+				throw new IntegrationException("Can't use the service for store country code ");
+			}
+
+			Map<String, ModuleConfig> 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();
+				}
+			}
+			
+
+			StringBuilder xmlheader = new StringBuilder();
+			if(store.getCountry().getIsoCode().equals(delivery.getCountry().getIsoCode())) {
+				xmlheader.append("<RateV3Request USERID=\"").append(keys.get("account")).append("\">");
+			} else {
+				xmlheader.append("<IntlRateRequest USERID=\"").append(keys.get("account")).append("\">");
+			}
+
+
+
+			StringBuilder xmldatabuffer = new StringBuilder();
+
+
+			double totalW = 0;
+			double totalH = 0;
+			double totalL = 0;
+			double totalG = 0;
+			double totalP = 0;
+
+			for (PackageDetails detail : packages) {
+
+
+				// need size in inch
+				double w = DataUtils.getMeasure(detail.getShippingWidth(),
+						store, MeasureUnit.IN.name());
+				double h = DataUtils.getMeasure(detail.getShippingHeight(),
+						store, MeasureUnit.IN.name());
+				double l = DataUtils.getMeasure(detail.getShippingLength(),
+						store, MeasureUnit.IN.name());
+	
+				totalW = totalW + w;
+				totalH = totalH + h;
+				totalL = totalL + l;
+	
+				// Girth = Length + (Width x 2) + (Height x 2)
+				double girth = l + (w * 2) + (h * 2);
+		
+				totalG = totalG + girth;
+	
+				// need weight in pounds
+				double p = DataUtils.getWeight(detail.getShippingWeight(), store, MeasureUnit.LB.name());
+	
+				totalP = totalP + p;
+
+			}
+
+/*			BigDecimal convertedOrderTotal = CurrencyUtil.convertToCurrency(
+					orderTotal, store.getCurrency(),
+					Constants.CURRENCY_CODE_USD);*/
+
+			// calculate total shipping volume
+
+			// ship date is 3 days from here
+
+			Calendar c = Calendar.getInstance();
+			c.setTime(new Date());
+			c.add(Calendar.DATE, 3);
+			Date newDate = c.getTime();
+			
+			SimpleDateFormat format = new SimpleDateFormat(Constants.DEFAULT_DATE_FORMAT);
+			String shipDate = format.format(newDate);
+			
+
+
+			int i = 1;
+
+			// need pounds and ounces
+			int pounds = (int) totalP;
+			String ouncesString = String.valueOf(totalP - pounds);
+			int ouncesIndex = ouncesString.indexOf(".");
+			String ounces = "00";
+			if (ouncesIndex > -1) {
+				ounces = ouncesString.substring(ouncesIndex + 1);
+			}
+
+			String size = "REGULAR";
+		
+			if (totalL + totalG <= 64) {
+				size = "REGULAR";
+			} else if (totalL + totalG <= 108) {
+				size = "LARGE";
+			} else {
+				size = "OVERSIZE";
+			}
+
+			/**
+			 * Domestic <Package ID="1ST"> <Service>ALL</Service>
+			 * <ZipOrigination>90210</ZipOrigination>
+			 * <ZipDestination>96698</ZipDestination> <Pounds>8</Pounds>
+			 * <Ounces>32</Ounces> <Container/> <Size>REGULAR</Size>
+			 * <Machinable>true</Machinable> </Package>
+			 * 
+			 * //MAXWEIGHT=70 lbs
+			 * 
+			 * 
+			 * //domestic container default=VARIABLE whiteSpace=collapse
+			 * enumeration=VARIABLE enumeration=FLAT RATE BOX enumeration=FLAT
+			 * RATE ENVELOPE enumeration=LG FLAT RATE BOX
+			 * enumeration=RECTANGULAR enumeration=NONRECTANGULAR
+			 * 
+			 * //INTL enumeration=Package enumeration=Postcards or aerogrammes
+			 * enumeration=Matter for the blind enumeration=Envelope
+			 * 
+			 * Size May be left blank in situations that do not Size. Defined as
+			 * follows: REGULAR: package plus girth is 84 inches or less; LARGE:
+			 * package length plus girth measure more than 84 inches not more
+			 * than 108 inches; OVERSIZE: package length plus girth is more than
+			 * 108 but not 130 inches. For example: <Size>REGULAR</Size>
+			 * 
+			 * International <Package ID="1ST"> <Machinable>true</Machinable>
+			 * <MailType>Envelope</MailType> <Country>Canada</Country>
+			 * <Length>0</Length> <Width>0</Width> <Height>0</Height>
+			 * <ValueOfContents>250</ValueOfContents> </Package>
+			 * 
+			 * <Package ID="2ND"> <Pounds>4</Pounds> <Ounces>3</Ounces>
+			 * <MailType>Package</MailType> <GXG> <Length>46</Length>
+			 * <Width>14</Width> <Height>15</Height> <POBoxFlag>N</POBoxFlag>
+			 * <GiftFlag>N</GiftFlag> </GXG>
+			 * <ValueOfContents>250</ValueOfContents> <Country>Japan</Country>
+			 * </Package>
+			 */
+
+			xmldatabuffer.append("<Package ID=\"").append(i).append("\">");
+
+
+			if(store.getCountry().getIsoCode().equals(delivery.getCountry().getIsoCode())) {
+
+				xmldatabuffer.append("<Service>");
+				xmldatabuffer.append("ALL");
+				xmldatabuffer.append("</Service>");
+				xmldatabuffer.append("<ZipOrigination>");
+				xmldatabuffer.append(DataUtils
+						.trimPostalCode(store.getStorepostalcode()));
+				xmldatabuffer.append("</ZipOrigination>");
+				xmldatabuffer.append("<ZipDestination>");
+				xmldatabuffer.append(DataUtils
+						.trimPostalCode(delivery.getPostalCode()));
+				xmldatabuffer.append("</ZipDestination>");
+				xmldatabuffer.append("<Pounds>");
+				xmldatabuffer.append(pounds);
+				xmldatabuffer.append("</Pounds>");
+				xmldatabuffer.append("<Ounces>");
+				xmldatabuffer.append(ounces);
+				xmldatabuffer.append("</Ounces>");
+				xmldatabuffer.append("<Container>");
+				xmldatabuffer.append(pack);
+				xmldatabuffer.append("</Container>");
+				xmldatabuffer.append("<Size>");
+				xmldatabuffer.append(size);
+				xmldatabuffer.append("</Size>");
+				xmldatabuffer.append("<Machinable>true</Machinable>");//TODO must be changed if not machinable
+				xmldatabuffer.append("<ShipDate>");
+				xmldatabuffer.append(shipDate);
+				xmldatabuffer.append("</ShipDate>");
+			} else {
+				// if international
+				xmldatabuffer.append("<Pounds>");
+				xmldatabuffer.append(pounds);
+				xmldatabuffer.append("</Pounds>");
+				xmldatabuffer.append("<Ounces>");
+				xmldatabuffer.append(ounces);
+				xmldatabuffer.append("</Ounces>");
+				xmldatabuffer.append("<MailType>");
+				xmldatabuffer.append(pack);
+				xmldatabuffer.append("</MailType>");
+				xmldatabuffer.append("<ValueOfContents>");
+				xmldatabuffer.append(productPriceUtils.getAdminFormatedAmount(store, orderTotal));
+				xmldatabuffer.append("</ValueOfContents>");
+				xmldatabuffer.append("<Country>");
+				xmldatabuffer.append(destination.getName());
+				xmldatabuffer.append("</Country>");
+			}
+
+			// if international & CXG
+			/*
+			 * xmldatabuffer.append("<CXG>"); xmldatabuffer.append("<Length>");
+			 * xmldatabuffer.append(""); xmldatabuffer.append("</Length>");
+			 * xmldatabuffer.append("<Width>"); xmldatabuffer.append("");
+			 * xmldatabuffer.append("</Width>");
+			 * xmldatabuffer.append("<Height>"); xmldatabuffer.append("");
+			 * xmldatabuffer.append("</Height>");
+			 * xmldatabuffer.append("<POBoxFlag>"); xmldatabuffer.append("");
+			 * xmldatabuffer.append("</POBoxFlag>");
+			 * xmldatabuffer.append("<GiftFlag>"); xmldatabuffer.append("");
+			 * xmldatabuffer.append("</GiftFlag>");
+			 * xmldatabuffer.append("</CXG>");
+			 */
+		
+			/*
+			 * xmldatabuffer.append("<Width>"); xmldatabuffer.append(totalW);
+			 * xmldatabuffer.append("</Width>");
+			 * xmldatabuffer.append("<Length>"); xmldatabuffer.append(totalL);
+			 * xmldatabuffer.append("</Length>");
+			 * xmldatabuffer.append("<Height>"); xmldatabuffer.append(totalH);
+			 * xmldatabuffer.append("</Height>");
+			 * xmldatabuffer.append("<Girth>"); xmldatabuffer.append(totalG);
+			 * xmldatabuffer.append("</Girth>");
+			 */
+
+			xmldatabuffer.append("</Package>");
+
+			String xmlfooter = "</RateV3Request>";
+			if(!store.getCountry().getIsoCode().equals(delivery.getCountry().getIsoCode())) {
+				xmlfooter = "</IntlRateRequest>";
+			}
+
+			StringBuilder xmlbuffer = new StringBuilder().append(xmlheader.toString()).append(
+					xmldatabuffer.toString()).append(xmlfooter.toString());
+
+			LOGGER.debug("USPS QUOTE REQUEST " + xmlbuffer.toString());
+
+			String data = "";
+
+
+			HttpClient client = new HttpClient();
+		
+			@SuppressWarnings("deprecation")
+			String encoded = java.net.URLEncoder.encode(xmlbuffer.toString());
+		
+			String completeUri = url + "?API=RateV3&XML=" + encoded;
+			if(!store.getCountry().getIsoCode().equals(delivery.getCountry().getIsoCode())) {
+				completeUri = url + "?API=IntlRate&XML=" + encoded;
+			}
+		
+			// ?API=RateV3
+		
+			httpget = new GetMethod(protocol + "://" + host + ":" + port
+					+ completeUri);
+			// RequestEntity entity = new
+			// StringRequestEntity(xmlbuffer.toString(),"text/plain","UTF-8");
+			// httpget.setRequestEntity(entity);
+		
+			int result = client.executeMethod(httpget);
+			if (result != 200) {
+				LOGGER.error("Communication Error with usps quote " + result + " "
+						+ protocol + "://" + host + ":" + port + url);
+				throw new Exception("USPS quote communication error " + result);
+			}
+			data = httpget.getResponseBodyAsString();
+			LOGGER.debug("usps quote response " + data);
+
+			USPSParsedElements parsed = new USPSParsedElements();
+
+			/**
+			 * <RateV3Response> <Package ID="1ST">
+			 * <ZipOrigination>44106</ZipOrigination>
+			 * <ZipDestination>20770</ZipDestination>
+			 */
+
+			Digester digester = new Digester();
+			digester.push(parsed);
+
+			if(store.getCountry().getIsoCode().equals(delivery.getCountry().getIsoCode())) {
+
+				digester.addCallMethod("Error/Description",
+						"setError", 0);
+				digester.addCallMethod("RateV3Response/Package/Error/Description",
+						"setError", 0);
+				digester
+						.addObjectCreate(
+								"RateV3Response/Package/Postage",
+								ShippingOption.class);
+				digester.addSetProperties("RateV3Response/Package/Postage",
+						"CLASSID", "optionId");
+				digester.addCallMethod(
+						"RateV3Response/Package/Postage/MailService",
+						"setOptionName", 0);
+				digester.addCallMethod(
+						"RateV3Response/Package/Postage/MailService",
+						"setOptionCode", 0);
+				digester.addCallMethod("RateV3Response/Package/Postage/Rate",
+						"setOptionPriceText", 0);
+				//digester
+				//		.addCallMethod(
+				//				"RateV3Response/Package/Postage/Commitment/CommitmentDate",
+				//				"estimatedNumberOfDays", 0);
+				digester.addSetNext("RateV3Response/Package/Postage",
+						"addOption");
+
+			} else {
+	
+				digester.addCallMethod("Error/Description",
+						"setError", 0);
+				digester.addCallMethod("IntlRateResponse/Package/Error/Description",
+						"setError", 0);
+				digester
+						.addObjectCreate(
+								"IntlRateResponse/Package/Service",
+								ShippingOption.class);
+				digester.addSetProperties("IntlRateResponse/Package/Service",
+						"ID", "optionId");
+				digester.addCallMethod(
+						"IntlRateResponse/Package/Service/SvcDescription",
+						"setOptionName", 0);
+				digester.addCallMethod(
+						"IntlRateResponse/Package/Service/SvcDescription",
+						"setOptionCode", 0);
+				digester.addCallMethod(
+						"IntlRateResponse/Package/Service/Postage",
+						"setOptionPriceText", 0);
+				//digester.addCallMethod(
+				//		"IntlRateResponse/Package/Service/SvcCommitments",
+				//		"setEstimatedNumberOfDays", 0);
+				digester.addSetNext("IntlRateResponse/Package/Service",
+						"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>
+
+			
+			//<?xml version="1.0"?>
+			//<IntlRateResponse><Package ID="1"><Error><Number>-2147218046</Number>
+			//<Source>IntlPostage;clsIntlPostage.GetCountryAndRestirctedServiceId;clsIntlPostage.CalcAllPostageDimensionsXML;IntlRate.ProcessRequest</Source>
+			//<Description>Invalid Country Name</Description><HelpFile></HelpFile><HelpContext>1000440</HelpContext></Error></Package></IntlRateResponse>
+			
+			
+			xmlreader = new StringReader(data);
+			digester.parse(xmlreader);
+
+			if (!StringUtils.isBlank(parsed.getError())) {
+				LOGGER.error("Can't process USPS message= "
+						+ parsed.getError());
+				throw new IntegrationException(parsed.getError());
+			}
+			if (!StringUtils.isBlank(parsed.getStatusCode())
+					&& !parsed.getStatusCode().equals("1")) {
+				LOGGER.error("Can't process USPS statusCode="
+						+ parsed.getStatusCode() + " message= "
+						+ parsed.getError());
+				throw new IntegrationException(parsed.getError());
+			}
+		
+			if (parsed.getOptions() == null || parsed.getOptions().size() == 0) {
+				LOGGER.warn("No options returned from USPS");
+				throw new IntegrationException(parsed.getError());
+			}
+
+	
+			
+/*			String carrier = getShippingMethodDescription(locale);
+			// cost is in USD, need to do conversion
+		
+			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() + "]");
+					}
+				}
+			}
+		
+			LabelUtil labelUtil = LabelUtil.getInstance();*/
+			// Map serviceMap =
+			// com.salesmanager.core.util.ShippingUtil.buildServiceMap("usps",locale);
+		
+			@SuppressWarnings("unchecked")
+			List<ShippingOption> shippingOptions = parsed.getOptions();
+		
+/*			List<ShippingOption> returnOptions = null;
+		
+			if (shippingOptions != null && shippingOptions.size() > 0) {
+		
+				returnOptions = new ArrayList<ShippingOption>();
+				// Map selectedintlservices =
+				// (Map)config.getConfiguration("service-global-usps");
+				// need to create a Map of LABEL - LABLEL
+				// Iterator servicesIterator =
+				// selectedintlservices.keySet().iterator();
+				// Map services = new HashMap();
+		
+				// ResourceBundle bundle = ResourceBundle.getBundle("usps",
+				// locale);
+		
+				// while(servicesIterator.hasNext()) {
+				// String key = (String)servicesIterator.next();
+				// String value =
+				// bundle.getString("shipping.quote.services.label." + key);
+				// services.put(value, key);
+				// }
+		
+				for(ShippingOption option : shippingOptions) {
+
+					StringBuilder description = new StringBuilder();
+					description.append(option.getOptionName());
+					//if (displayQuoteDeliveryTime == ShippingConstants.DISPLAY_RT_QUOTE_TIME) {
+					if (shippingConfiguration.getShippingDescription()==ShippingDescription.LONG_DESCRIPTION) {
+						if (option.getEstimatedNumberOfDays()>0) {
+							description.append(" (").append(
+									option.getEstimatedNumberOfDays()).append(
+									" ").append(
+									" d")
+									.append(")");
+						}
+					}
+					option.setDescription(description.toString());
+		
+					// get currency
+					if (!option.getCurrency().equals(store.getCurrency())) {
+						option.setOptionPrice(CurrencyUtil.convertToCurrency(
+								option.getOptionPrice(), option.getCurrency(),
+								store.getCurrency()));
+					}
+		
+					// if(!services.containsKey(option.getOptionCode())) {
+					// if(returnColl==null) {
+					// returnColl = new ArrayList();
+					// }
+					// returnColl.add(option);
+					// }
+					returnOptions.add(option);
+				}
+		
+				// if(options.size()==0) {
+				// CommonService.logServiceMessage(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 shippingOptions;
+		
+		} catch (Exception e1) {
+			LOGGER.error("Error in USPS shipping quote ",e1);
+			throw new IntegrationException(e1);
+		} finally {
+			if (xmlreader != null) {
+				try {
+					xmlreader.close();
+				} catch (Exception ignore) {
+				}
+			}
+			if (httpget != null) {
+				httpget.releaseConnection();
+			}
+		}
+
+		
+	}
+
+
+
+	@Override
+	public CustomIntegrationConfiguration getCustomModuleConfiguration(
+			MerchantStore store) throws IntegrationException {
+		//nothing to do
+		return null;
+	}
+
+}
+
+
+class USPSParsedElements {
+
+	private String statusCode;
+	private String statusMessage;
+	private String error = "";
+	private String errorCode = "";
+	private List<ShippingOption> options = new ArrayList<ShippingOption>();
+
+	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;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuoteItem.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuoteItem.java
new file mode 100644
index 0000000..4881db7
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuoteItem.java
@@ -0,0 +1,22 @@
+package com.salesmanager.core.modules.integration.shipping.model;
+
+import java.math.BigDecimal;
+
+public abstract class CustomShippingQuoteItem {
+	
+	private String priceText;
+	private BigDecimal price;
+	public void setPriceText(String priceText) {
+		this.priceText = priceText;
+	}
+	public String getPriceText() {
+		return priceText;
+	}
+	public void setPrice(BigDecimal price) {
+		this.price = price;
+	}
+	public BigDecimal getPrice() {
+		return price;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuotesConfiguration.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuotesConfiguration.java
new file mode 100644
index 0000000..93be6df
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuotesConfiguration.java
@@ -0,0 +1,87 @@
+package com.salesmanager.core.modules.integration.shipping.model;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.json.simple.JSONObject;
+
+import com.salesmanager.core.business.system.model.CustomIntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+
+public class CustomShippingQuotesConfiguration extends IntegrationConfiguration implements CustomIntegrationConfiguration, Serializable {
+	
+	/**
+	 * 
+	 */
+	private String moduleCode;
+	
+	private List<CustomShippingQuotesRegion> regions = new ArrayList<CustomShippingQuotesRegion>();
+	
+	
+	private static final long serialVersionUID = 1L;
+
+	
+	@SuppressWarnings("unchecked")
+	public String toJSONString() {
+		//JSONObject data = new JSONObject();
+		
+		//data.put("active", super.isActive());
+		//data.put("moduleCode", this.getModuleCode());
+		
+		
+		StringBuilder returnString = new StringBuilder();
+		returnString.append("{");
+		returnString.append("\"moduleCode\"").append(":\"").append(this.getModuleCode()).append("\"");
+		returnString.append(",");
+		returnString.append("\"active\"").append(":").append(this.isActive());
+		
+
+
+		if(regions!=null && regions.size()>0) {
+			
+			returnString.append(",");
+			//org.json.simple.JSONArray array=new org.json.simple.JSONArray();
+			StringBuilder regionsList = new StringBuilder();
+			int countRegion = 0;
+			regionsList.append("[");
+			for(CustomShippingQuotesRegion region : regions) {
+				regionsList.append(region.toJSONString());
+				countRegion ++;
+				if(countRegion<regions.size()) {
+					regionsList.append(",");
+				}
+			}
+			regionsList.append("]");
+			returnString.append("\"regions\"").append(":").append(regionsList.toString());
+		}
+
+		//return data.toJSONString();
+		returnString.append("}");
+		return returnString.toString();
+		
+		
+		
+
+	}
+
+	@Override
+	public String getModuleCode() {
+		return moduleCode;
+	}
+
+	@Override
+	public void setModuleCode(String moduleCode) {
+		this.moduleCode = moduleCode;
+		
+	}
+
+	public void setRegions(List<CustomShippingQuotesRegion> regions) {
+		this.regions = regions;
+	}
+
+	public List<CustomShippingQuotesRegion> getRegions() {
+		return regions;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuotesRegion.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuotesRegion.java
new file mode 100644
index 0000000..c37f279
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuotesRegion.java
@@ -0,0 +1,88 @@
+package com.salesmanager.core.modules.integration.shipping.model;
+
+import java.util.List;
+
+import org.json.simple.JSONAware;
+
+public class CustomShippingQuotesRegion implements JSONAware {
+	
+	private String customRegionName;//a name given by the merchant for this custom region
+	private List<String> countries;//a list of country code for this region
+	
+	private List<CustomShippingQuoteWeightItem> quoteItems;//price max weight
+
+	public void setQuoteItems(List<CustomShippingQuoteWeightItem> quoteItems) {
+		this.quoteItems = quoteItems;
+	}
+
+	public List<CustomShippingQuoteWeightItem> getQuoteItems() {
+		return quoteItems;
+	}
+
+	public void setCountries(List<String> countries) {
+		this.countries = countries;
+	}
+
+	public List<String> getCountries() {
+		return countries;
+	}
+
+	public void setCustomRegionName(String customRegionName) {
+		this.customRegionName = customRegionName;
+	}
+
+	public String getCustomRegionName() {
+		return customRegionName;
+	}
+	
+
+	public String toJSONString() {
+		
+
+		StringBuilder returnString = new StringBuilder();
+		returnString.append("{");
+		returnString.append("\"customRegionName\"").append(":\"").append(this.getCustomRegionName()).append("\"");
+		
+		
+		
+		if(countries!=null) {
+			returnString.append(",");
+			StringBuilder coutriesList = new StringBuilder();
+			int countCountry = 0;
+			coutriesList.append("[");
+			for(String country : countries) {
+				coutriesList.append("\"").append(country).append("\"");
+				countCountry ++;
+				if(countCountry<countries.size()) {
+					coutriesList.append(",");
+				}
+			}
+			
+			coutriesList.append("]");
+			returnString.append("\"countries\"").append(":").append(coutriesList.toString());
+		}
+		
+		if(quoteItems!=null) {
+			returnString.append(",");
+			StringBuilder quotesList = new StringBuilder();
+			int countQuotes = 0;
+			quotesList.append("[");
+			for(CustomShippingQuoteWeightItem quote : quoteItems) {
+				quotesList.append(quote.toJSONString());
+				countQuotes ++;
+				if(countQuotes<quoteItems.size()) {
+					quotesList.append(",");
+				}
+			}
+			quotesList.append("]");
+
+			returnString.append("\"quoteItems\"").append(":").append(quotesList.toString());
+		}
+		returnString.append("}");
+		return returnString.toString();
+		
+		
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuoteWeightItem.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuoteWeightItem.java
new file mode 100644
index 0000000..ee5b087
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/CustomShippingQuoteWeightItem.java
@@ -0,0 +1,40 @@
+package com.salesmanager.core.modules.integration.shipping.model;
+
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+public class CustomShippingQuoteWeightItem extends CustomShippingQuoteItem implements JSONAware {
+	
+	private int maximumWeight;
+	
+	private String priceText;
+
+	public String getPriceText() {
+		return priceText;
+	}
+
+	public void setPriceText(String priceText) {
+		this.priceText = priceText;
+	}
+
+	public void setMaximumWeight(int maximumWeight) {
+		this.maximumWeight = maximumWeight;
+	}
+
+	public int getMaximumWeight() {
+		return maximumWeight;
+	}
+
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		JSONObject data = new JSONObject();
+		data.put("price", super.getPrice());
+		data.put("maximumWeight", this.getMaximumWeight());
+		
+		return data.toJSONString();
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/Packaging.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/Packaging.java
new file mode 100644
index 0000000..fe54e27
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/Packaging.java
@@ -0,0 +1,18 @@
+package com.salesmanager.core.modules.integration.shipping.model;
+
+import java.util.List;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingProduct;
+
+public interface Packaging {
+	
+	public List<PackageDetails> getBoxPackagesDetails(
+			List<ShippingProduct> products, MerchantStore store) throws ServiceException;
+	
+	public List<PackageDetails> getItemPackagesDetails(
+			List<ShippingProduct> products, MerchantStore store) throws ServiceException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/ShippingQuoteModule.java b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/ShippingQuoteModule.java
new file mode 100644
index 0000000..691a722
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/integration/shipping/model/ShippingQuoteModule.java
@@ -0,0 +1,24 @@
+package com.salesmanager.core.modules.integration.shipping.model;
+
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Locale;
+
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingOption;
+import com.salesmanager.core.business.system.model.CustomIntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.modules.integration.IntegrationException;
+
+public interface ShippingQuoteModule {
+	
+	public void validateModuleConfiguration(IntegrationConfiguration integrationConfiguration, MerchantStore store) throws IntegrationException;
+	public CustomIntegrationConfiguration getCustomModuleConfiguration(MerchantStore store) throws IntegrationException;
+	
+	public List<ShippingOption> getShippingQuotes(List<PackageDetails> packages, BigDecimal orderTotal, Delivery delivery, MerchantStore store, IntegrationConfiguration configuration, IntegrationModule module, ShippingConfiguration shippingConfiguration, Locale locale) throws IntegrationException;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/order/InvoiceModule.java b/sm-core/src/main/java/com/salesmanager/core/modules/order/InvoiceModule.java
new file mode 100644
index 0000000..d715a50
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/order/InvoiceModule.java
@@ -0,0 +1,13 @@
+package com.salesmanager.core.modules.order;
+
+import java.io.ByteArrayOutputStream;
+
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+public interface InvoiceModule {
+	
+	public ByteArrayOutputStream createInvoice(MerchantStore store, Order order, Language language) throws Exception;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/order/ODSInvoiceModule.java b/sm-core/src/main/java/com/salesmanager/core/modules/order/ODSInvoiceModule.java
new file mode 100644
index 0000000..bc33e98
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/order/ODSInvoiceModule.java
@@ -0,0 +1,404 @@
+package com.salesmanager.core.modules.order;
+
+import java.awt.Graphics2D;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jopendocument.dom.OOUtils;
+import org.jopendocument.dom.spreadsheet.Sheet;
+import org.jopendocument.dom.spreadsheet.SpreadSheet;
+import org.jopendocument.model.OpenDocument;
+import org.jopendocument.renderer.ODTRenderer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.PageSize;
+import com.lowagie.text.Rectangle;
+import com.lowagie.text.pdf.PdfContentByte;
+import com.lowagie.text.pdf.PdfDocument;
+import com.lowagie.text.pdf.PdfTemplate;
+import com.lowagie.text.pdf.PdfWriter;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderTotal;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.reference.zone.service.ZoneService;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.utils.ProductPriceUtils;
+import com.salesmanager.core.utils.ProductUtils;
+
+public class ODSInvoiceModule implements InvoiceModule {
+	
+	private final static String INVOICE_TEMPLATE = "templates/invoice/Invoice";
+	private final static String INVOICE_TEMPLATE_EXTENSION = ".ods";
+	private final static String TEMP_INVOICE_SUFFIX_NAME = "_invoice.ods";
+	private final static int ADDRESS_ROW_START = 2;
+	private final static int ADDRESS_ROW_END = 5;
+	
+	private final static int BILLTO_ROW_START = 8;
+	private final static int BILLTO_ROW_END = 13;
+	
+	private final static int PRODUCT_ROW_START = 16;
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger( ODSInvoiceModule.class );
+	
+	@Autowired
+	private ZoneService zoneService;
+	
+	@Autowired
+	private CountryService countryService;
+	
+	@Autowired
+	private ProductPriceUtils priceUtil;
+	
+
+	@Override
+	public ByteArrayOutputStream createInvoice(MerchantStore store, Order order, Language language) throws Exception {
+		
+		
+
+			
+			List<Zone> zones = zoneService.getZones(store.getCountry(), language);
+			Map<String,Country> countries = countryService.getCountriesMap(language);
+			
+			//get default template
+			String template = new StringBuilder().append(INVOICE_TEMPLATE).append("_").append(language.getCode().toLowerCase()).append(INVOICE_TEMPLATE_EXTENSION).toString();
+			
+			//try by language
+			InputStream is = null;
+			try {
+				is = getClass().getClassLoader().getResourceAsStream(template);
+			} catch (Exception e) {
+				LOGGER.warn("Cannot open template " + template);
+				throw new Exception("Cannot open " + template);
+			}
+			
+			if(is==null) {
+				try {
+					is = getClass().getClassLoader().getResourceAsStream(new StringBuilder().append(INVOICE_TEMPLATE).append(INVOICE_TEMPLATE_EXTENSION).toString());
+				} catch (Exception e) {
+					LOGGER.warn("Cannot open template " + template);
+					throw new Exception("Cannot open " + new StringBuilder().append(INVOICE_TEMPLATE).append(INVOICE_TEMPLATE_EXTENSION).toString());
+				}
+			}
+			
+			if(is==null) {
+				LOGGER.warn("Cannot open template " + template);
+				throw new Exception("Cannot open " + new StringBuilder().append(INVOICE_TEMPLATE).append(INVOICE_TEMPLATE_EXTENSION).toString());
+			}
+			
+			File file = new File(order.getId() + "_working");
+			OutputStream os = new FileOutputStream(file);
+			IOUtils.copy(is, os);
+			os.close();
+			//File file = new File(resource.toURI().toURL());
+		
+			Sheet sheet = SpreadSheet.createFromFile(file).getSheet(0);
+			
+			
+			//Store name 
+			sheet.setValueAt(store.getStorename(), 0, 0);
+			
+			
+			
+			//Address
+			//count store address cell
+			int storeAddressCell = ADDRESS_ROW_START;
+			
+			Map<String,Zone> zns = zoneService.getZones(language);
+
+			
+			//3
+			StringBuilder storeAddress = null;
+			if(!StringUtils.isBlank(store.getStoreaddress())) {
+				storeAddress = new StringBuilder();
+				storeAddress.append(store.getStoreaddress());
+			}
+			if(!StringUtils.isBlank(store.getStorecity())) {
+				if(storeAddress==null) {
+					storeAddress = new StringBuilder();
+				} else {
+					storeAddress.append(", ");
+				}
+				storeAddress.append(store.getStorecity());
+			}
+			if(storeAddress!=null) {
+				sheet.setValueAt(storeAddress.toString(), 0, storeAddressCell);
+				storeAddressCell ++;
+			}
+			
+			//4
+			StringBuilder storeProvince = null;
+			if(store.getZone()!=null) {
+				storeProvince = new StringBuilder();
+				
+				for(Zone z : zones) {
+					if(z.getCode().equals(store.getZone().getCode())) {
+						storeProvince.append(z.getName());
+						break;
+					}
+				}
+				
+			} else {
+				if(!StringUtils.isBlank(store.getStorestateprovince())) {
+					storeProvince = new StringBuilder();
+					storeProvince.append(store.getStorestateprovince());
+				}
+			}
+			if(store.getCountry()!=null) {
+				if(storeProvince==null) {
+					storeProvince = new StringBuilder();
+				} else {
+					storeProvince.append(", ");
+				}
+				
+				Country c = countries.get(store.getCountry().getIsoCode());
+				if(c!=null) {
+					storeProvince.append(c.getName());
+				} else {
+					storeProvince.append(store.getCountry().getIsoCode());
+				}
+				
+			}
+			if(storeProvince!=null) {
+				sheet.setValueAt(storeProvince.toString(), 0, storeAddressCell);
+				storeAddressCell ++;
+			}
+			
+			//5
+			if(!StringUtils.isBlank(store.getStorepostalcode())) {
+				sheet.setValueAt(store.getStorepostalcode(), 0, storeAddressCell);
+				storeAddressCell ++;
+			}
+			
+			//6
+			if(!StringUtils.isBlank(store.getStorephone())) {
+				sheet.setValueAt(store.getStorephone(), 0, storeAddressCell);
+			}
+			
+			//delete address blank lines
+			for(int i = storeAddressCell; i<ADDRESS_ROW_END; i++) {
+				sheet.setValueAt("", 0, i);
+			}
+
+			//invoice date
+			SimpleDateFormat format = new SimpleDateFormat(Constants.DEFAULT_DATE_FORMAT);
+			sheet.setValueAt(format.format(order.getDatePurchased()), 3, 2);
+			
+			//invoice number
+			sheet.setValueAt(order.getId(), 3, 3);
+			
+			//bill to
+			//count bill to address cell
+			int billToCell = BILLTO_ROW_START;
+			if(!StringUtils.isBlank(order.getBilling().getFirstName())) {
+				StringBuilder nm = new StringBuilder();
+				nm.append(order.getBilling().getFirstName()).append(" ").append(order.getBilling().getLastName());
+				sheet.setValueAt(nm.toString(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//9
+			if(!StringUtils.isBlank(order.getBilling().getCompany())) {
+				sheet.setValueAt(order.getBilling().getCompany(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//10
+			StringBuilder billToAddress = null;
+			if(!StringUtils.isBlank(order.getBilling().getAddress())) {
+				billToAddress = new StringBuilder();
+				billToAddress.append(order.getBilling().getAddress());
+			}
+			if(!StringUtils.isBlank(order.getBilling().getCity())) {
+				if(billToAddress==null) {
+					billToAddress = new StringBuilder();
+				} else {
+					billToAddress.append(", ");
+				}
+				billToAddress.append(order.getBilling().getCity());
+			}
+			if(billToAddress!=null) {
+				sheet.setValueAt(billToAddress.toString(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//11
+			StringBuilder billToProvince = null;
+			if(order.getBilling().getZone()!=null) {
+				billToProvince = new StringBuilder();
+				
+				Zone billingZone = zns.get(order.getBilling().getZone().getCode());
+				if(billingZone!=null) {
+						billToProvince.append(billingZone.getName());
+				}
+				
+			} else {
+				if(!StringUtils.isBlank(order.getBilling().getState())) {
+					billToProvince = new StringBuilder();
+					billToProvince.append(order.getBilling().getState());
+				}
+			}
+			if(order.getBilling().getCountry()!=null) {
+				if(billToProvince==null) {
+					billToProvince = new StringBuilder();
+				} else {
+					billToProvince.append(", ");
+				}
+				Country c = countries.get(order.getBilling().getCountry().getIsoCode());
+				if(c!=null) {
+					billToProvince.append(c.getName());
+				} else {
+					billToProvince.append(order.getBilling().getCountry().getIsoCode());
+				}
+				
+			}
+			if(billToProvince!=null) {
+				sheet.setValueAt(billToProvince.toString(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//12
+			if(!StringUtils.isBlank(order.getBilling().getPostalCode())) {
+				billToCell ++;
+				sheet.setValueAt(order.getBilling().getPostalCode(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//13
+			if(!StringUtils.isBlank(order.getBilling().getTelephone())) {
+				sheet.setValueAt(order.getBilling().getTelephone(), 0, billToCell);
+			}
+			
+			//delete address blank lines
+			for(int i = billToCell; i<BILLTO_ROW_END; i++) {
+				sheet.setValueAt("", 0, i);
+			}
+			
+			//products
+			Set<OrderProduct> orderProducts = order.getOrderProducts();
+			int productCell = PRODUCT_ROW_START;
+			for(OrderProduct orderProduct : orderProducts) {
+				
+
+				String orderProductName = ProductUtils.buildOrderProductDisplayName(orderProduct);
+				
+				sheet.setValueAt(orderProductName.toString(), 0, productCell);
+				
+				int quantity = orderProduct.getProductQuantity();
+				sheet.setValueAt(quantity, 1, productCell);
+				String amount = priceUtil.getStoreFormatedAmountWithCurrency(store, orderProduct.getOneTimeCharge());
+				sheet.setValueAt(amount, 2, productCell);
+				String t = priceUtil.getStoreFormatedAmountWithCurrency(store, priceUtil.getOrderProductTotalPrice(store, orderProduct));
+				sheet.setValueAt(t, 3, productCell);
+
+				productCell++;
+				
+			}
+			
+			//print totals
+			productCell++;
+			Set<OrderTotal> totals = order.getOrderTotal();
+			for(OrderTotal orderTotal : totals) {
+				
+				String totalName = orderTotal.getText();
+				if(totalName.contains(".")) {
+					totalName = orderTotal.getTitle();
+				}
+				String totalValue = priceUtil.getStoreFormatedAmountWithCurrency(store,orderTotal.getValue());
+				sheet.setValueAt(totalName, 2, productCell);
+				sheet.setValueAt(totalValue, 3, productCell);
+				productCell++;
+			}
+			
+			//sheet.getCellAt(0, 0).setImage(arg0)
+			//sheet.getCellAt(0, 0).setStyleName(arg0)
+			//sheet.getCellAt(0, 0).getStyle().
+			
+			
+			//generate invoice file
+			StringBuilder tempInvoiceName = new StringBuilder();
+			tempInvoiceName.append(order.getId()).append(TEMP_INVOICE_SUFFIX_NAME);
+			File outputFile = new File(tempInvoiceName.toString());
+			OOUtils.open(sheet.getSpreadSheet().saveAs(outputFile));
+			
+			
+			
+			final OpenDocument doc = new OpenDocument();
+			doc.loadFrom(tempInvoiceName.toString());
+
+			 // Open the PDF document
+			 Document document = new Document(PageSize.A4);
+			 
+			 
+			 //File outFile = new File("invoice.pdf");
+
+			 PdfDocument pdf = new PdfDocument();
+
+			 document.addDocListener(pdf);
+
+			 //FileOutputStream fileOutputStream = new FileOutputStream(outFile);
+			 ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+
+			 
+			 PdfWriter writer = PdfWriter.getInstance(pdf, outputStream);
+			 pdf.addWriter(writer);
+
+			 document.open();
+
+			 // Create a template and a Graphics2D object 
+			 Rectangle pageSize = document.getPageSize();
+			 int w = (int) (pageSize.getWidth() * 0.9);
+			 int h = (int) (pageSize.getHeight() * 0.95);
+			 PdfContentByte cb = writer.getDirectContent();
+			 PdfTemplate tp = cb.createTemplate(w, h);
+
+			 Graphics2D g2 = tp.createPrinterGraphics(w, h, null);
+			 // If you want to prevent copy/paste, you can use
+			 // g2 = tp.createGraphicsShapes(w, h, true, 0.9f);
+			            
+			 tp.setWidth(w);
+			 tp.setHeight(h);
+
+			 // Configure the renderer
+			 ODTRenderer renderer = new ODTRenderer(doc);
+			 renderer.setIgnoreMargins(true);
+			 renderer.setPaintMaxResolution(true);
+			            
+			 // Scale the renderer to fit width
+			 renderer.setResizeFactor(renderer.getPrintWidth() / w);
+			 // Render
+			 renderer.paintComponent(g2);
+			 g2.dispose();
+
+			 // Add our spreadsheet in the middle of the page
+			 float offsetX = (pageSize.getWidth() - w) / 2;
+			 float offsetY = (pageSize.getHeight() - h) / 2;
+			 cb.addTemplate(tp, offsetX, offsetY);
+			 // Close the PDF document
+			 document.close();
+			 outputFile.delete();//remove temp file
+			 file.delete();//remove spreadsheet file
+			 is.close();
+			 return outputStream;
+		
+		
+
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/utils/Encryption.java b/sm-core/src/main/java/com/salesmanager/core/modules/utils/Encryption.java
new file mode 100644
index 0000000..e665d8c
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/utils/Encryption.java
@@ -0,0 +1,30 @@
+package com.salesmanager.core.modules.utils;
+
+/**
+ * Can be used to encrypt block or information that has to
+ * be maintained secret
+ * @author Carl Samson
+ *
+ */
+public interface Encryption {
+	
+
+	/**
+	 * Encrypts a string value
+	 * @param key
+	 * @param value
+	 * @return
+	 * @throws Exception
+	 */
+	public String encrypt(String value) throws Exception;
+	
+	/**
+	 * Decrypts a string value
+	 * @param key
+	 * @param value
+	 * @return
+	 * @throws Exception
+	 */
+	public String decrypt(String value) throws Exception;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/utils/EncryptionImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/utils/EncryptionImpl.java
new file mode 100644
index 0000000..43c44e4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/utils/EncryptionImpl.java
@@ -0,0 +1,105 @@
+package com.salesmanager.core.modules.utils;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import org.apache.commons.lang3.StringUtils;
+
+public final class EncryptionImpl implements Encryption {
+	
+	private final static String IV_P = "fedcba9876543210";
+	private final static String KEY_SPEC = "AES";
+	private final static String CYPHER_SPEC = "AES/CBC/PKCS5Padding";
+	
+
+
+    private String  secretKey;
+
+
+
+	@Override
+	public String encrypt(String value) throws Exception {
+
+		
+		// value = StringUtils.rightPad(value, 16,"*");
+		// Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+		// NEED TO UNDERSTAND WHY PKCS5Padding DOES NOT WORK
+		Cipher cipher = Cipher.getInstance(CYPHER_SPEC);
+		SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), KEY_SPEC);
+		IvParameterSpec ivSpec = new IvParameterSpec(IV_P
+				.getBytes());
+		cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
+		byte[] inpbytes = value.getBytes();
+		byte[] encrypted = cipher.doFinal(inpbytes);
+		return new String(bytesToHex(encrypted));
+		
+		
+	}
+
+	@Override
+	public String decrypt(String value) throws Exception {
+
+		
+		if (StringUtils.isBlank(value))
+			throw new Exception("Nothing to encrypt");
+
+		// NEED TO UNDERSTAND WHY PKCS5Padding DOES NOT WORK
+		// Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+		Cipher cipher = Cipher.getInstance(CYPHER_SPEC);
+		SecretKeySpec keySpec = new SecretKeySpec(secretKey.getBytes(), KEY_SPEC);
+		IvParameterSpec ivSpec = new IvParameterSpec(IV_P
+				.getBytes());
+		cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
+		byte[] outText;
+		outText = cipher.doFinal(hexToBytes(value));
+		return new String(outText);
+		
+		
+	}
+	
+	
+	private String bytesToHex(byte[] data) {
+		if (data == null) {
+			return null;
+		} else {
+			int len = data.length;
+			String str = "";
+			for (int i = 0; i < len; i++) {
+				if ((data[i] & 0xFF) < 16) {
+					str = str + "0"
+							+ java.lang.Integer.toHexString(data[i] & 0xFF);
+				} else {
+					str = str + java.lang.Integer.toHexString(data[i] & 0xFF);
+				}
+
+			}
+			return str;
+		}
+	}
+
+	private static byte[] hexToBytes(String str) {
+		if (str == null) {
+			return null;
+		} else if (str.length() < 2) {
+			return null;
+		} else {
+			int len = str.length() / 2;
+			byte[] buffer = new byte[len];
+			for (int i = 0; i < len; i++) {
+				buffer[i] = (byte) Integer.parseInt(str.substring(i * 2,
+						i * 2 + 2), 16);
+			}
+			return buffer;
+		}
+	}
+	
+	public String getSecretKey() {
+		return secretKey;
+	}
+
+	public void setSecretKey(String secretKey) {
+		this.secretKey = secretKey;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/utils/GeoLocation.java b/sm-core/src/main/java/com/salesmanager/core/modules/utils/GeoLocation.java
new file mode 100644
index 0000000..716330a
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/utils/GeoLocation.java
@@ -0,0 +1,9 @@
+package com.salesmanager.core.modules.utils;
+
+import com.salesmanager.core.business.common.model.Address;
+
+public interface GeoLocation {
+	
+	Address getAddress(String ipAddress) throws Exception;
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/modules/utils/GeoLocationImpl.java b/sm-core/src/main/java/com/salesmanager/core/modules/utils/GeoLocationImpl.java
new file mode 100644
index 0000000..7bd4ebc
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/modules/utils/GeoLocationImpl.java
@@ -0,0 +1,57 @@
+package com.salesmanager.core.modules.utils;
+
+import java.net.InetAddress;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.maxmind.geoip2.DatabaseReader;
+import com.maxmind.geoip2.model.CityResponse;
+import com.salesmanager.core.business.common.model.Address;
+
+
+public class GeoLocationImpl implements GeoLocation {
+	
+	private DatabaseReader reader = null;
+	private static final Logger LOGGER = LoggerFactory.getLogger( GeoLocationImpl.class );
+	//@Value("${dbPath:classpath:/reference/GeoLite2-Country.mmdb}")
+	//private Resource db;
+
+	
+
+
+	@Override
+	public Address getAddress(String ipAddress) throws Exception {
+		
+			if(reader==null) {
+				//if(db!=null) {
+					//File file = db.getFile();
+					try {
+						java.io.InputStream inputFile = GeoLocationImpl.class.getClassLoader().getResourceAsStream("reference/GeoLite2-Country.mmdb");
+						reader = new DatabaseReader.Builder(inputFile).build();
+					} catch(Exception e) {
+						LOGGER.error("Cannot instantiate IP database",e);
+					}
+				//}
+			}
+		
+			Address address = new Address();
+
+			
+			CityResponse response = reader.city(InetAddress.getByName(ipAddress));
+
+			address.setCountry(response.getCountry().getIsoCode());
+			address.setPostalCode(response.getPostal().getCode());
+			address.setZone(response.getMostSpecificSubdivision().getIsoCode());
+			address.setCity(response.getCity().getName());
+			
+
+
+		
+			return address;
+		
+		
+	}
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/AbstractDataPopulator.java b/sm-core/src/main/java/com/salesmanager/core/utils/AbstractDataPopulator.java
new file mode 100644
index 0000000..edd967d
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/AbstractDataPopulator.java
@@ -0,0 +1,41 @@
+/**
+ * 
+ */
+package com.salesmanager.core.utils;
+
+import java.util.Locale;
+
+import com.salesmanager.core.business.generic.exception.ConversionException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+
+/**
+ * @author Umesh A
+ *
+ */
+public abstract class AbstractDataPopulator<Source,Target> implements DataPopulator<Source, Target>
+{
+
+ 
+   
+    private Locale locale;
+
+	public void setLocale(Locale locale) {
+		this.locale = locale;
+	}
+	public Locale getLocale() {
+		return locale;
+	}
+	
+
+	@Override
+	public Target populate(Source source, MerchantStore store, Language language) throws ConversionException{
+	   return populate(source,createTarget(), store, language);
+	}
+	
+	protected abstract Target createTarget();
+
+   
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/ajax/AjaxPageableResponse.java b/sm-core/src/main/java/com/salesmanager/core/utils/ajax/AjaxPageableResponse.java
new file mode 100644
index 0000000..cde51e6
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/ajax/AjaxPageableResponse.java
@@ -0,0 +1,108 @@
+package com.salesmanager.core.utils.ajax;
+
+import java.util.Map;
+import java.util.Set;
+
+import org.json.simple.JSONObject;
+
+public class AjaxPageableResponse extends AjaxResponse {
+	
+	
+	private int startRow;
+	public int getStartRow() {
+		return startRow;
+	}
+
+
+
+	public void setStartRow(int startRow) {
+		this.startRow = startRow;
+	}
+
+
+
+	private int endRow;
+	private int totalRow;
+	
+	protected String getPageInfo() {
+		
+		StringBuilder returnString = new StringBuilder();
+		returnString.append("\"startRow\"").append(":");
+		returnString.append(this.startRow).append(",");
+		returnString.append("\"endRow\"").append(":").append(this.endRow).append(",");
+		returnString.append("\"totalRows\"").append(":").append(super.getData().size());
+		return returnString.toString();
+		
+	}
+	
+	
+	
+	@SuppressWarnings("unchecked")
+	@Override
+	public String toJSONString() {
+		
+		StringBuilder returnString = new StringBuilder();
+		
+		returnString.append(getJsonInfo()).append(",");
+		returnString.append(getPageInfo());
+
+		if(this.getData().size()>0) {
+			StringBuilder dataEntries = null;
+			int count = 0;
+			for(Map keyValue : this.getData()) {
+				if(dataEntries == null) {
+					dataEntries = new StringBuilder();
+				}
+				JSONObject data = new JSONObject();
+				Set<String> keys = keyValue.keySet();
+				for(String key : keys) {
+					data.put(key, keyValue.get(key));
+				}
+				String dataField = data.toJSONString();
+				dataEntries.append(dataField);
+				if(count<super.getData().size()-1) {
+					dataEntries.append(",");
+				}
+				count ++;
+			}
+			
+			returnString.append(",").append("\"data\"").append(":[");
+			if(dataEntries!=null) {
+				returnString.append(dataEntries.toString());
+			}
+			returnString.append("]");
+		}
+		returnString.append("}}");
+
+		
+		return returnString.toString();
+		
+		
+		
+	}
+
+
+
+	public int getEndRow() {
+		return endRow;
+	}
+
+
+
+	public void setEndRow(int endRow) {
+		this.endRow = endRow;
+	}
+
+
+
+	public int getTotalRow() {
+		return totalRow;
+	}
+
+
+
+	public void setTotalRow(int totalRow) {
+		this.totalRow = totalRow;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/ajax/AjaxResponse.java b/sm-core/src/main/java/com/salesmanager/core/utils/ajax/AjaxResponse.java
new file mode 100644
index 0000000..e020f2f
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/ajax/AjaxResponse.java
@@ -0,0 +1,186 @@
+package com.salesmanager.core.utils.ajax;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.json.simple.JSONAware;
+import org.json.simple.JSONObject;
+
+public class AjaxResponse implements JSONAware {
+	
+	public final static int RESPONSE_STATUS_SUCCESS=0;
+	public final static int RESPONSE_STATUS_FAIURE=-1;
+	public final static int RESPONSE_STATUS_VALIDATION_FAILED=-2;
+	public final static int RESPONSE_OPERATION_COMPLETED=9999;
+	public final static int CODE_ALREADY_EXIST=9998;
+	
+	private int status;
+	private List<Map<String,String>> data = new ArrayList<Map<String,String>>();
+	private Map<String,String> dataMap = new HashMap<String,String>();
+	private Map<String,String> validationMessages = new HashMap<String,String>();
+	public Map<String, String> getValidationMessages() {
+		return validationMessages;
+	}
+	public void setValidationMessages(Map<String, String> validationMessages) {
+		this.validationMessages = validationMessages;
+	}
+	public int getStatus() {
+		return status;
+	}
+	public void setStatus(int status) {
+		this.status = status;
+	}
+	protected List<Map<String,String>> getData() {
+		return data;
+	}
+	
+	public void addDataEntry(Map<String,String> dataEntry) {
+		this.data.add(dataEntry);
+	}
+	
+	public void addEntry(String key, String value) {
+		dataMap.put(key, value);
+	}
+	
+	
+	public void setErrorMessage(Throwable t) {
+		this.setStatusMessage(t.getMessage());
+	}
+	
+	public void setErrorString(String t) {
+		this.setStatusMessage(t);
+	}
+	
+
+	public void addValidationMessage(String fieldName, String message) {
+		this.validationMessages.put(fieldName, message);
+	}
+	
+	private String statusMessage = null;
+	
+	
+	public String getStatusMessage() {
+		return statusMessage;
+	}
+	public void setStatusMessage(String statusMessage) {
+		this.statusMessage = statusMessage;
+	}
+	
+	
+	protected String getJsonInfo() {
+		
+		StringBuilder returnString = new StringBuilder();
+		returnString.append("{");
+		returnString.append("\"response\"").append(":");
+		returnString.append("{");
+		returnString.append("\"status\"").append(":").append(this.getStatus());
+		if(this.getStatusMessage()!=null && this.getStatus()!=0) {
+			returnString.append(",").append("\"statusMessage\"").append(":\"").append(JSONObject.escape(this.getStatusMessage())).append("\"");
+		}
+		return returnString.toString();
+		
+	}
+	
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	@Override
+	public String toJSONString() {
+		StringBuilder returnString = new StringBuilder();
+		
+		returnString.append(getJsonInfo());
+
+		if(this.getData().size()>0) {
+			StringBuilder dataEntries = null;
+			int count = 0;
+			for(Map keyValue : this.getData()) {
+				if(dataEntries == null) {
+					dataEntries = new StringBuilder();
+				}
+				JSONObject data = new JSONObject();
+				Set<String> keys = keyValue.keySet();
+				for(String key : keys) {
+					data.put(key, keyValue.get(key));
+				}
+				String dataField = data.toJSONString();
+				dataEntries.append(dataField);
+				if(count<this.data.size()-1) {
+					dataEntries.append(",");
+				}
+				count ++;
+			}
+			
+			returnString.append(",").append("\"data\"").append(":[");
+			if(dataEntries!=null) {
+				returnString.append(dataEntries.toString());
+			}
+			returnString.append("]");
+		}
+		
+		if(this.getDataMap().size()>0) {
+			StringBuilder dataEntries = null;
+			int count = 0;
+			for(String key : this.getDataMap().keySet()) {
+				if(dataEntries == null) {
+					dataEntries = new StringBuilder();
+				}
+				
+				dataEntries.append("\"").append(key).append("\"");
+				dataEntries.append(":");
+				dataEntries.append("\"").append(this.getDataMap().get(key)).append("\"");
+
+				if(count<this.getDataMap().size()-1) {
+					dataEntries.append(",");
+				}
+				count ++;
+			}
+
+			if(dataEntries!=null) {
+				returnString.append(",").append(dataEntries.toString());
+			}
+		}
+		
+		if(CollectionUtils.isNotEmpty(this.getValidationMessages().values())) {
+			StringBuilder dataEntries = null;
+			int count = 0;
+			for(String key : this.getValidationMessages().keySet()) {
+				if(dataEntries == null) {
+					dataEntries = new StringBuilder();
+				}
+				dataEntries.append("{");
+				dataEntries.append("\"field\":\"").append(key).append("\"");
+				dataEntries.append(",");
+				dataEntries.append("\"message\":\"").append(this.getValidationMessages().get(key)).append("\"");
+				dataEntries.append("}");
+
+				if(count<this.getValidationMessages().size()-1) {
+					dataEntries.append(",");
+				}
+				count ++;
+			}
+			
+			returnString.append(",").append("\"validations\"").append(":[");
+			if(dataEntries!=null) {
+				returnString.append(dataEntries.toString());
+			}
+			returnString.append("]");
+
+		}
+		
+		returnString.append("}}");
+
+		
+		return returnString.toString();
+
+		
+	}
+	public Map<String,String> getDataMap() {
+		return dataMap;
+	}
+	public void setDataMap(Map<String,String> dataMap) {
+		this.dataMap = dataMap;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/ApplicationContextListenerUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/ApplicationContextListenerUtils.java
new file mode 100644
index 0000000..4ee0584
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/ApplicationContextListenerUtils.java
@@ -0,0 +1,20 @@
+package com.salesmanager.core.utils;
+
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextStartedEvent;
+
+import com.salesmanager.core.business.search.service.SearchService;
+
+public class ApplicationContextListenerUtils implements ApplicationListener<ContextStartedEvent> {
+
+	@Override
+	public void onApplicationEvent(ContextStartedEvent event) {
+		 ApplicationContext applicationContext = event.getApplicationContext();
+		 /** init search service **/
+		 SearchService searchService = (SearchService)applicationContext.getBean("productSearchService");
+		 searchService.initService();
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/CacheUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/CacheUtils.java
new file mode 100644
index 0000000..e23ed25
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/CacheUtils.java
@@ -0,0 +1,112 @@
+package com.salesmanager.core.utils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.cache.Cache;
+import org.springframework.cache.Cache.ValueWrapper;
+import org.springframework.stereotype.Component;
+
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+@Component("cache")
+public class CacheUtils {
+	
+	
+    @Inject
+    @Qualifier("serviceCache")
+    private Cache cache;
+	
+	
+	public final static String REFERENCE_CACHE = "REF";
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(CacheUtils.class);
+
+	private final static String KEY_DELIMITER = "_";
+	
+
+
+	public void putInCache(Object object, String keyName) throws Exception {
+
+		cache.put(keyName, object);
+		
+	}
+	
+
+	public Object getFromCache(String keyName) throws Exception {
+
+		ValueWrapper vw = cache.get(keyName);
+		if(vw!=null) {
+			return vw.get();
+		}
+		
+		return null;
+		
+	}
+	
+	public List<String> getCacheKeys(MerchantStore store) throws Exception {
+		
+		  net.sf.ehcache.Cache cacheImpl = (net.sf.ehcache.Cache) cache.getNativeCache();
+		  List<String> returnKeys = new ArrayList<String>();
+		  for (Object key: cacheImpl.getKeys()) {
+		    
+			  
+				try {
+					String sKey = (String)key;
+					
+					// a key should be <storeId>_<rest of the key>
+					int delimiterPosition = sKey.indexOf(KEY_DELIMITER);
+					
+					if(delimiterPosition>0 && Character.isDigit(sKey.charAt(0))) {
+					
+						String keyRemaining = sKey.substring(delimiterPosition+1);
+						returnKeys.add(keyRemaining);
+					
+					}
+
+				} catch (Exception e) {
+					LOGGER.equals("key " + key + " cannot be converted to a String or parsed");
+				}  
+		  }
+
+		return returnKeys;
+	}
+	
+	public void shutDownCache() throws Exception {
+		
+	}
+	
+	public void removeFromCache(String keyName) throws Exception {
+		cache.evict(keyName);
+	}
+	
+	public void removeAllFromCache(MerchantStore store) throws Exception {
+		  net.sf.ehcache.Cache cacheImpl = (net.sf.ehcache.Cache) cache.getNativeCache();
+		  for (Object key: cacheImpl.getKeys()) {
+				try {
+					String sKey = (String)key;
+					
+					// a key should be <storeId>_<rest of the key>
+					int delimiterPosition = sKey.indexOf(KEY_DELIMITER);
+					
+					if(delimiterPosition>0 && Character.isDigit(sKey.charAt(0))) {
+					
+
+						cache.evict(key);
+					
+					}
+
+				} catch (Exception e) {
+					LOGGER.equals("key " + key + " cannot be converted to a String or parsed");
+				}  
+		  }
+	}
+	
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/CloneUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/CloneUtils.java
new file mode 100644
index 0000000..6377078
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/CloneUtils.java
@@ -0,0 +1,16 @@
+package com.salesmanager.core.utils;
+
+import java.util.Date;
+
+public class CloneUtils {
+	
+	private CloneUtils() {};
+	
+	public static Date clone(Date date) {
+		if (date != null) {
+			return (Date) date.clone();
+		}
+		return null;
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/CoreConfiguration.java b/sm-core/src/main/java/com/salesmanager/core/utils/CoreConfiguration.java
new file mode 100644
index 0000000..cbcd4ca
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/CoreConfiguration.java
@@ -0,0 +1,46 @@
+package com.salesmanager.core.utils;
+
+import java.util.Properties;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+@Component
+public class CoreConfiguration {
+	
+
+	public Properties properties = new Properties();
+	private static final Logger LOGGER = LoggerFactory.getLogger(CoreConfiguration.class);
+	
+	public Properties getProperties() {
+		return properties;
+	}
+
+	public void setProperties(Properties properties) {
+		this.properties = properties;
+	}
+
+	public CoreConfiguration() {}
+	
+	public String getProperty(String propertyKey) {
+		
+		return properties.getProperty(propertyKey);
+		
+		
+	}
+	
+	public String getProperty(String propertyKey, String defaultValue) {
+		
+		String prop = defaultValue;
+		try {
+			prop = properties.getProperty(propertyKey);
+		} catch(Exception e) {
+			LOGGER.warn("Cannot find property " + propertyKey);
+		}
+		return prop;
+		
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/CreditCardUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/CreditCardUtils.java
new file mode 100644
index 0000000..162ef2b
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/CreditCardUtils.java
@@ -0,0 +1,32 @@
+package com.salesmanager.core.utils;
+
+
+public class CreditCardUtils {
+	
+	
+	public static final int MASTERCARD = 0, VISA = 1;
+	public static final int AMEX = 2, DISCOVER = 3, DINERS = 4;
+
+	public static String maskCardNumber(String clearcardnumber)
+			throws Exception {
+
+		if (clearcardnumber.length() < 10) {
+			throw new Exception("Invalid number of digits");
+		}
+
+		int length = clearcardnumber.length();
+
+		String prefix = clearcardnumber.substring(0, 4);
+		String suffix = clearcardnumber.substring(length - 4);
+
+		StringBuffer mask = new StringBuffer();
+		mask.append(prefix).append("XXXXXXXXXX").append(suffix);
+
+		return mask.toString();
+	}
+
+	
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/DataPopulator.java b/sm-core/src/main/java/com/salesmanager/core/utils/DataPopulator.java
new file mode 100644
index 0000000..e075809
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/DataPopulator.java
@@ -0,0 +1,22 @@
+/**
+ * 
+ */
+package com.salesmanager.core.utils;
+
+import com.salesmanager.core.business.generic.exception.ConversionException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+/**
+ * @author Umesh A
+ *
+ */
+public interface DataPopulator<Source,Target>
+{
+
+
+    public Target populate(Source source,Target target, MerchantStore store, Language language) throws ConversionException;
+    public Target populate(Source source, MerchantStore store, Language language) throws ConversionException;
+
+   
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/DataUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/DataUtils.java
new file mode 100644
index 0000000..fd411dd
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/DataUtils.java
@@ -0,0 +1,102 @@
+package com.salesmanager.core.utils;
+
+import java.math.BigDecimal;
+
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.constants.MeasureUnit;
+
+public class DataUtils {
+	
+	/**
+	 * Removes dashes
+	 * @param postalCode
+	 * @return
+	 */
+	public static String trimPostalCode(String postalCode) {
+
+		String pc = postalCode.replaceAll("[^a-zA-Z0-9]", "");
+
+		return pc;
+
+	}
+	
+	
+	/**
+	 * Get the measure according to the appropriate measure base. If the measure
+	 * configured in store is LB and it needs KG then the appropriate
+	 * calculation is done
+	 * 
+	 * @param weight
+	 * @param store
+	 * @param base
+	 * @return
+	 */
+	public static double getWeight(double weight, MerchantStore store,
+			String base) {
+
+		double weightConstant = 2.2;
+		if (base.equals(MeasureUnit.LB.name())) {
+			if (store.getWeightunitcode().equals(MeasureUnit.LB.name())) {
+				return new BigDecimal(String.valueOf(weight)).setScale(2,
+						BigDecimal.ROUND_HALF_UP).doubleValue();
+			} else {// pound = kilogram
+				double answer = weight * weightConstant;
+				BigDecimal w = new BigDecimal(answer);
+				return w.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+			}
+		} else {// need KG
+			if (store.getWeightunitcode().equals(MeasureUnit.KG.name())) {
+				return new BigDecimal(String.valueOf(weight)).setScale(2,
+						BigDecimal.ROUND_HALF_UP).doubleValue();
+			} else {
+
+				double answer = weight / weightConstant;
+				BigDecimal w = new BigDecimal(answer);
+				return w.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+
+			}
+		}
+	}
+	
+	/**
+	 * Get the measure according to the appropriate measure base. If the measure
+	 * configured in store is IN and it needs CM or vise versa then the
+	 * appropriate calculation is done
+	 * 
+	 * @param weight
+	 * @param store
+	 * @param base
+	 * @return
+	 */
+	public static double getMeasure(double measure, MerchantStore store,
+			String base) {
+
+		if (base.equals(MeasureUnit.IN.name())) {
+			if (store.getSeizeunitcode().equals(MeasureUnit.IN.name())) {
+				return new BigDecimal(String.valueOf(measure)).setScale(2,
+						BigDecimal.ROUND_HALF_UP).doubleValue();
+			} else {// centimeter (inch to centimeter)
+				double measureConstant = 2.54;
+
+				double answer = measure * measureConstant;
+				BigDecimal w = new BigDecimal(answer);
+				return w.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+
+			}
+		} else {// need CM
+			if (store.getSeizeunitcode().equals(MeasureUnit.CM.name())) {
+				return new BigDecimal(String.valueOf(measure)).setScale(2)
+						.doubleValue();
+			} else {// in (centimeter to inch)
+				double measureConstant = 0.39;
+
+				double answer = measure * measureConstant;
+				BigDecimal w = new BigDecimal(answer);
+				return w.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
+
+			}
+		}
+
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/EntityPopulator.java b/sm-core/src/main/java/com/salesmanager/core/utils/EntityPopulator.java
new file mode 100644
index 0000000..9071474
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/EntityPopulator.java
@@ -0,0 +1,18 @@
+/**
+ * 
+ */
+package com.salesmanager.core.utils;
+
+import com.salesmanager.core.business.generic.exception.ConversionException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+
+/**
+ * @author Umesh A
+ *
+ */
+public interface EntityPopulator<Source,Target>
+{
+
+    public Target populateToEntity(Source source, Target target, MerchantStore store)  throws ConversionException;
+    public Target populateToEntity(Source source) throws ConversionException;
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/ProductImageCropUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/ProductImageCropUtils.java
new file mode 100755
index 0000000..68d295e
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/ProductImageCropUtils.java
@@ -0,0 +1,232 @@
+package com.salesmanager.core.utils;
+
+import java.awt.Rectangle;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.net.FileNameMap;
+import java.net.URLConnection;
+
+import javax.imageio.ImageIO;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class ProductImageCropUtils {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ProductImageCropUtils.class);
+	
+	private boolean cropeable = true;
+
+	private int cropeBaseline = 0;// o is width, 1 is height
+
+	private int getCropeBaseline() {
+		return cropeBaseline;
+	}
+
+
+
+	private double cropAreaWidth = 0;
+	private double cropAreaHeight = 0;
+	
+	//private InputStream originalFile = null;
+	private BufferedImage originalFile = null;
+
+
+
+	public ProductImageCropUtils(BufferedImage file, int largeImageWidth, int largeImageHeight) {
+		
+		
+	
+			try {
+				
+			
+				this.originalFile = file;
+				
+				/** Original Image **/
+				// get original image size
+
+				int width = originalFile.getWidth();
+				int height = originalFile.getHeight();
+		
+				/*** determine if image can be cropped ***/
+				determineCropeable(width, largeImageWidth, height, largeImageHeight);
+		
+				/*** determine crop area calculation baseline ***/
+				//this.determineBaseline(width, height);
+		
+				determineCropArea(width, largeImageWidth, height, largeImageHeight);
+			
+			} catch (Exception e) {
+				LOGGER.error("Image Utils error in constructor", e);
+			}
+		
+
+
+		
+		
+		
+	}
+	
+	
+	private void determineCropeable(int width, int specificationsWidth,
+			int height, int specificationsHeight) {
+		/*** determine if image can be cropped ***/
+		// height
+		int y = height - specificationsHeight;
+		// width
+		int x = width - specificationsWidth;
+
+		if (x < 0 || y < 0) {
+			setCropeable(false);
+		}
+
+		if (x == 0 && y == 0) {
+			setCropeable(false);
+		}
+		
+		
+		if((height % specificationsHeight) == 0 && (width % specificationsWidth) == 0 ) {
+			setCropeable(false);
+		}
+
+		
+		
+	}
+
+
+	private void determineCropArea(int width, int specificationsWidth,
+			int height, int specificationsHeight) {
+
+		cropAreaWidth = specificationsWidth;
+		cropAreaHeight = specificationsHeight;
+		
+		
+		double factorWidth = new Integer(width).doubleValue() / new Integer(specificationsWidth).doubleValue();
+		double factorHeight = new Integer(height).doubleValue() / new Integer(specificationsHeight).doubleValue();
+
+		double factor = factorWidth;
+		
+		if(factorWidth>factorHeight) {
+			factor = factorHeight;
+		}
+		
+		
+		// crop factor
+/*		double factor = 1;
+		if (this.getCropeBaseline() == 0) {// width
+			factor = new Integer(width).doubleValue()
+					/ new Integer(specificationsWidth).doubleValue();
+		} else {// height
+			factor = new Integer(height).doubleValue()
+					/ new Integer(specificationsHeight).doubleValue();
+		}*/
+
+		double w = factor * specificationsWidth;
+		double h = factor * specificationsHeight;
+		
+		if(w==h) {
+			setCropeable(false);
+		}
+		
+
+		cropAreaWidth = w;
+		
+		if(cropAreaWidth > width)
+			cropAreaWidth = width;
+		
+		cropAreaHeight = h;
+		
+		if(cropAreaHeight > height)
+			cropAreaHeight = height;
+
+		/*
+		 * if(factor>1) { //determine croping section for(double
+		 * i=factor;i>1;i--) { //multiply specifications by factor int newWidth
+		 * = (int)(i * specificationsWidth); int newHeight = (int)(i *
+		 * specificationsHeight); //check if new size >= original image
+		 * if(width>=newWidth && height>=newHeight) { cropAreaWidth = newWidth;
+		 * cropAreaHeight = newHeight; break; } } }
+		 */
+
+	}
+	
+	
+	public File getCroppedImage(File originalFile, int x1, int y1, int width,
+			int height) throws Exception {
+		
+		if(!this.cropeable) {
+			return originalFile;
+		}
+
+		FileNameMap fileNameMap = URLConnection.getFileNameMap();
+		String contentType = fileNameMap.getContentTypeFor(originalFile.getName());
+		
+		String extension = contentType.substring(contentType.indexOf("/"),contentType.length());
+		
+		BufferedImage image = ImageIO.read(originalFile);
+		BufferedImage out = image.getSubimage(x1, y1, width, height);
+		File tempFile = File.createTempFile("temp", "." + extension );
+		tempFile.deleteOnExit();
+		ImageIO.write(out, extension, tempFile);
+		return tempFile;
+	}
+	
+	public BufferedImage getCroppedImage() throws IOException {
+		
+
+			//out if croppedArea == 0 or file is null
+		
+
+
+		
+			Rectangle goal = new Rectangle( (int)this.getCropAreaWidth(), (int) this.getCropAreaHeight()); 
+			
+			//Then intersect it with the dimensions of your image:
+
+			Rectangle clip = goal.intersection(new Rectangle(originalFile.getWidth(), originalFile.getHeight())); 
+			
+			//Now, clip corresponds to the portion of bi that will fit within your goal. In this case 100 x50.
+
+			//Now get the subImage using the value of clip.
+
+			BufferedImage clippedImg = originalFile.getSubimage(clip.x, clip.y, clip.width, clip.height); 
+			
+
+			return clippedImg;
+
+		
+		
+		
+	}
+	
+
+
+	
+	public double getCropAreaWidth() {
+		return cropAreaWidth;
+	}
+
+	public void setCropAreaWidth(int cropAreaWidth) {
+		this.cropAreaWidth = cropAreaWidth;
+	}
+
+	public double getCropAreaHeight() {
+		return cropAreaHeight;
+	}
+
+	public void setCropAreaHeight(int cropAreaHeight) {
+		this.cropAreaHeight = cropAreaHeight;
+	}
+
+	public void setCropeable(boolean cropeable) {
+		this.cropeable = cropeable;
+	}
+
+	public boolean isCropeable() {
+		return cropeable;
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/ProductImageSizeUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/ProductImageSizeUtils.java
new file mode 100755
index 0000000..1bf19f4
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/ProductImageSizeUtils.java
@@ -0,0 +1,151 @@
+package com.salesmanager.core.utils;
+
+import java.awt.AlphaComposite;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Transparency;
+import java.awt.image.BufferedImage;
+
+/**
+ * Utility class for image resize functions
+ * @author Carl Samson
+ *
+ */
+public class ProductImageSizeUtils {
+	
+
+	private ProductImageSizeUtils() {
+
+	}
+	
+
+	/**
+	 * Simple resize, does not maintain aspect ratio
+	 * @param image
+	 * @param width
+	 * @param height
+	 * @return
+	 */
+	
+	public static BufferedImage resize(BufferedImage image, int width, int height) {
+		int type = image.getType() == 0 ? BufferedImage.TYPE_INT_ARGB : image
+				.getType();
+		BufferedImage resizedImage = new BufferedImage(width, height, type);
+		Graphics2D g = resizedImage.createGraphics();
+		g.setComposite(AlphaComposite.Src);
+		g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+				RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+		g.setRenderingHint(RenderingHints.KEY_RENDERING,
+				RenderingHints.VALUE_RENDER_QUALITY);
+		g.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
+				RenderingHints.VALUE_ANTIALIAS_ON);
+		g.drawImage(image, 0, 0, width, height, null);
+		g.dispose();
+		return resizedImage;
+	}
+	
+	/**
+	 * 
+	 * @param img
+	 * @param targetWidth
+	 * @param targetHeight
+	 * @param hint
+	 * 	{@code RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR},
+     *  {@code RenderingHints.VALUE_INTERPOLATION_BILINEAR},
+     *  {@code RenderingHints.VALUE_INTERPOLATION_BICUBIC})
+	 * @param higherQuality
+	 * @return
+	 */
+	public static BufferedImage resizeWithHint(BufferedImage img,
+			int targetWidth, int targetHeight, Object hint,
+			boolean higherQuality) {
+		int type = (img.getTransparency() == Transparency.OPAQUE) ? BufferedImage.TYPE_INT_RGB
+				: BufferedImage.TYPE_INT_ARGB;
+		BufferedImage ret = (BufferedImage) img;
+		int w, h;
+		if (higherQuality) {
+			// Use multi-step technique: start with original size, then
+			// scale down in multiple passes with drawImage()
+			// until the target size is reached
+			w = img.getWidth();
+			h = img.getHeight();
+		} else {
+			// Use one-step technique: scale directly from original
+			// size to target size with a single drawImage() call
+			w = targetWidth;
+			h = targetHeight;
+		}
+
+		do {
+			if (higherQuality && w > targetWidth) {
+				w /= 2;
+				if (w < targetWidth) {
+					w = targetWidth;
+				}
+			}
+
+			if (higherQuality && h > targetHeight) {
+				h /= 2;
+				if (h < targetHeight) {
+					h = targetHeight;
+				}
+			}
+
+			BufferedImage tmp = new BufferedImage(w, h, type);
+			Graphics2D g2 = tmp.createGraphics();
+			g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, hint);
+			g2.drawImage(ret, 0, 0, w, h, null);
+			g2.dispose();
+
+			ret = tmp;
+		} while (w != targetWidth || h != targetHeight);
+
+		return ret;
+	}
+	
+	
+	public static BufferedImage resizeWithRatio(BufferedImage image, int destinationWidth, int destinationHeight) {
+
+            int type = image.getType() == 0? BufferedImage.TYPE_INT_ARGB : image.getType();
+
+            //*Special* if the width or height is 0 use image src dimensions
+            if (destinationWidth == 0) {
+            	destinationWidth = image.getWidth();
+            }
+            if (destinationHeight == 0) {
+            	destinationHeight = image.getHeight();
+            }
+
+            int fHeight = destinationHeight;
+            int fWidth = destinationWidth;
+
+            //Work out the resized width/height
+            if (image.getHeight() > destinationHeight || image.getWidth() > destinationWidth) {
+                fHeight = destinationHeight;
+                int wid = destinationWidth;
+                float sum = (float)image.getWidth() / (float)image.getHeight();
+                fWidth = Math.round(fHeight * sum);
+
+                if (fWidth > wid) {
+                    //rezise again for the width this time
+                    fHeight = Math.round(wid/sum);
+                    fWidth = wid;
+                }
+            }
+
+            BufferedImage resizedImage = new BufferedImage(fWidth, fHeight, type);
+            Graphics2D g = resizedImage.createGraphics();
+            g.setComposite(AlphaComposite.Src);
+
+            g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+            g.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+            g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+            g.drawImage(image, 0, 0, fWidth, fHeight, null);
+            g.dispose();
+
+            return resizedImage;
+	}
+	
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/ProductPriceUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/ProductPriceUtils.java
new file mode 100755
index 0000000..6eee5f9
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/ProductPriceUtils.java
@@ -0,0 +1,614 @@
+package com.salesmanager.core.utils;
+
+import java.math.BigDecimal;
+import java.text.NumberFormat;
+import java.util.ArrayList;
+import java.util.Currency;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.commons.lang.Validate;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.validator.routines.BigDecimalValidator;
+import org.apache.commons.validator.routines.CurrencyValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+import com.salesmanager.core.constants.Constants;
+
+
+/**
+ * This class determines the price that is displayed in the catalogue for a given item. 
+ * It does not calculate the total price for a given item
+ * @author casams1
+ *
+ */
+@Component("priceUtil")
+public class ProductPriceUtils {
+	
+	private final static char DECIMALCOUNT = '2';
+	private final static char DECIMALPOINT = '.';
+	private final static char THOUSANDPOINT = ',';
+	
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ProductPriceUtils.class);
+
+	
+	
+	/**
+	 * Get the price without discount
+	 * @param store
+	 * @param product
+	 * @param locale
+	 * @return
+	 */
+	public BigDecimal getPrice(MerchantStore store, Product product, Locale locale) {
+		
+		BigDecimal defaultPrice = new BigDecimal(0);
+
+		Set<ProductAvailability> availabilities = product.getAvailabilities();
+		for(ProductAvailability availability : availabilities) {
+			
+			Set<ProductPrice> prices = availability.getPrices();
+			for(ProductPrice price : prices) {
+				
+				if(price.isDefaultPrice()) {
+					defaultPrice = price.getProductPriceAmount();
+				}
+			}
+		}
+		
+		return defaultPrice;
+	}
+	
+	/**
+	 * This method calculates the final price taking into account
+	 * all attributes included having a specified default attribute with an attribute price gt 0
+	 * in the product object. The calculation is based
+	 * on the default price.
+	 * Attributes may be null
+	 * @param Product
+	 * @param List<ProductAttribute>
+	 * @return FinalPrice
+	 */
+	public FinalPrice getFinalProductPrice(Product product, List<ProductAttribute> attributes) {
+
+
+		FinalPrice finalPrice = calculateFinalPrice(product);
+		
+		//attributes
+		BigDecimal attributePrice = null;
+		if(attributes!=null && attributes.size()>0) {
+			for(ProductAttribute attribute : attributes) {
+					if(attribute.getProductAttributePrice()!=null && attribute.getProductAttributePrice().doubleValue()>0) {
+						if(attributePrice==null) {
+							attributePrice = new BigDecimal(0);
+						}
+						attributePrice = attributePrice.add(attribute.getProductAttributePrice());
+					}
+			}
+			
+			if(attributePrice!=null && attributePrice.doubleValue()>0) {
+				BigDecimal fp = finalPrice.getFinalPrice();
+				fp = fp.add(attributePrice);
+				finalPrice.setFinalPrice(fp);
+				
+				BigDecimal op = finalPrice.getOriginalPrice();
+				op = op.add(attributePrice);
+				finalPrice.setOriginalPrice(op);
+				
+				BigDecimal dp = finalPrice.getDiscountedPrice();
+				if(dp!=null) {
+					dp = dp.add(attributePrice);
+					finalPrice.setDiscountedPrice(dp);
+				}
+				
+			}
+		}
+		
+
+		return finalPrice;
+
+	}
+
+	
+	/**
+	 * This is the final price calculated from all configured prices
+	 * and all possibles discounts. This price does not calculate the attributes
+	 * or other prices than the default one
+	 * @param store
+	 * @param product
+	 * @param locale
+	 * @return
+	 */
+	public FinalPrice getFinalPrice(Product product) {
+
+
+
+		FinalPrice finalPrice = calculateFinalPrice(product);
+		
+		//attributes
+		BigDecimal attributePrice = null;
+		if(product.getAttributes()!=null && product.getAttributes().size()>0) {
+			for(ProductAttribute attribute : product.getAttributes()) {
+					if(attribute.getAttributeDefault()) {
+						if(attribute.getProductAttributePrice()!=null && attribute.getProductAttributePrice().doubleValue()>0) {
+							if(attributePrice==null) {
+								attributePrice = new BigDecimal(0);
+							}
+							attributePrice = attributePrice.add(attribute.getProductAttributePrice());
+						}
+					}
+			}
+			
+			if(attributePrice!=null && attributePrice.doubleValue()>0) {
+				BigDecimal fp = finalPrice.getFinalPrice();
+				fp = fp.add(attributePrice);
+				finalPrice.setFinalPrice(fp);
+				
+				BigDecimal op = finalPrice.getOriginalPrice();
+				op = op.add(attributePrice);
+				finalPrice.setOriginalPrice(op);
+			}
+		}
+
+		return finalPrice;
+
+	}
+	
+
+	
+
+	/**
+	 * This is the format that will be displayed
+	 * in the admin input text fields when editing
+	 * an entity having a BigDecimal to be displayed
+	 * as a raw amount 1,299.99
+	 * The admin user will also be force to input
+	 * the amount using that format	
+	 * @param store
+	 * @param amount
+	 * @return
+	 * @throws Exception
+	 */
+	public String getAdminFormatedAmount(MerchantStore store, BigDecimal amount) throws Exception {
+			
+		if(amount==null) {
+			return "";
+		}
+		
+		NumberFormat nf = null;
+
+			
+		nf = NumberFormat.getInstance(Constants.DEFAULT_LOCALE);
+
+		nf.setMaximumFractionDigits(Integer.parseInt(Character
+					.toString(DECIMALCOUNT)));
+		nf.setMinimumFractionDigits(Integer.parseInt(Character
+					.toString(DECIMALCOUNT)));
+
+		return nf.format(amount);
+	}
+	
+	
+	/**
+	 * This method has to be used to format store front amounts
+	 * It will display national format amount ex:
+	 * $1,345.99
+	 * Rs.1.345.99
+	 * or international format
+	 * USD1,345.79
+	 * INR1,345.79
+	 * @param store
+	 * @param amount
+	 * @return String
+	 * @throws Exception
+	 */
+	public String getStoreFormatedAmountWithCurrency(MerchantStore store, BigDecimal amount) throws Exception {
+		if(amount==null) {
+			return "";
+		}
+		
+		
+		
+		Currency currency = Constants.DEFAULT_CURRENCY;
+		Locale locale = Constants.DEFAULT_LOCALE; 
+		
+		try {
+
+			currency = store.getCurrency().getCurrency();
+			locale = new Locale(store.getDefaultLanguage().getCode(),store.getCountry().getIsoCode());
+		} catch (Exception e) {
+			LOGGER.error("Cannot create currency or locale instance for store " + store.getCode());
+		}
+
+		
+		NumberFormat currencyInstance = null;
+		
+		
+		if(store.isCurrencyFormatNational()) {
+			currencyInstance = NumberFormat.getCurrencyInstance(locale);//national
+		} else {
+			currencyInstance = NumberFormat.getCurrencyInstance();//international
+		}
+	    currencyInstance.setCurrency(currency);
+		
+	    
+	    return currencyInstance.format(amount.doubleValue());
+		
+
+    }
+	
+	
+	public String getFormatedAmountWithCurrency(Locale locale, com.salesmanager.core.business.reference.currency.model.Currency currency, BigDecimal amount) throws Exception {
+		if(amount==null) {
+			return "";
+		}
+
+		Currency curr = currency.getCurrency();
+
+
+		
+		NumberFormat currencyInstance = null;
+
+		currencyInstance = NumberFormat.getCurrencyInstance(locale);
+		currencyInstance.setCurrency(curr);
+	    return currencyInstance.format(amount.doubleValue());
+		
+
+    }
+	
+
+	
+	/**
+	 * This method will return the required formated amount
+	 * with the appropriate currency
+	 * @param store
+	 * @param amount
+	 * @return
+	 * @throws Exception
+	 */
+	public String getAdminFormatedAmountWithCurrency(MerchantStore store, BigDecimal amount) throws Exception {
+		if(amount==null) {
+			return "";
+		}
+		
+		
+		
+		
+		NumberFormat nf = null;
+
+		
+		Currency currency = store.getCurrency().getCurrency();
+		nf = NumberFormat.getInstance(Constants.DEFAULT_LOCALE);
+		nf.setMaximumFractionDigits(Integer.parseInt(Character
+				.toString(DECIMALCOUNT)));
+		nf.setMinimumFractionDigits(Integer.parseInt(Character
+				.toString(DECIMALCOUNT)));
+		nf.setCurrency(currency);
+
+
+		return nf.format(amount);
+	}
+	
+	/**
+	 * Returns a formatted amount using Shopizer Currency
+	 * requires internal java.util.Currency populated
+	 * @param currency
+	 * @param amount
+	 * @return
+	 * @throws Exception
+	 */
+	public String getFormatedAmountWithCurrency(com.salesmanager.core.business.reference.currency.model.Currency currency, BigDecimal amount) throws Exception {
+		if(amount==null) {
+			return "";
+		}
+		
+		Validate.notNull(currency.getCurrency(),"Currency must be populated with java.util.Currency");
+		
+		NumberFormat nf = null;
+
+		
+		Currency curr = currency.getCurrency();
+		nf = NumberFormat.getInstance(Constants.DEFAULT_LOCALE);
+		nf.setMaximumFractionDigits(Integer.parseInt(Character
+				.toString(DECIMALCOUNT)));
+		nf.setMinimumFractionDigits(Integer.parseInt(Character
+				.toString(DECIMALCOUNT)));
+		nf.setCurrency(curr);
+
+
+		String stringNumber = nf.format(amount);
+		
+		return stringNumber;
+	}
+
+	/**
+	 * This amount will be displayed to the end user
+	 * @param store
+	 * @param amount
+	 * @param locale
+	 * @return
+	 * @throws Exception
+	 */
+	public String getFormatedAmountWithCurrency(MerchantStore store, BigDecimal amount, Locale locale)
+				throws Exception {
+		
+			NumberFormat nf = null;
+
+			Currency currency = store.getCurrency().getCurrency();
+			
+			nf = NumberFormat.getInstance(locale);
+			nf.setCurrency(currency);
+			nf.setMaximumFractionDigits(Integer.parseInt(Character
+					.toString(DECIMALCOUNT)));
+			nf.setMinimumFractionDigits(Integer.parseInt(Character
+					.toString(DECIMALCOUNT)));
+	
+
+	
+			return nf.format(amount);
+
+	}
+	
+	/**
+	 * Transformation of an amount of money submited by the admin
+	 * user to be inserted as a BigDecimal in the database
+	 * @param amount
+	 * @param locale
+	 * @return
+	 * @throws Exception
+	 */
+	public BigDecimal getAmount(String amount) throws Exception {
+
+		// validations
+		/**
+		 * 1) remove decimal and thousand
+		 * 
+		 * String.replaceAll(decimalPoint, ""); String.replaceAll(thousandPoint,
+		 * "");
+		 * 
+		 * Should be able to parse to Integer
+		 */
+		StringBuffer newAmount = new StringBuffer();
+		for (int i = 0; i < amount.length(); i++) {
+			if (amount.charAt(i) != DECIMALPOINT
+					&& amount.charAt(i) != THOUSANDPOINT) {
+				newAmount.append(amount.charAt(i));
+			}
+		}
+
+		try {
+			Integer.parseInt(newAmount.toString());
+		} catch (Exception e) {
+			throw new Exception("Cannot parse " + amount);
+		}
+
+		if (!amount.contains(Character.toString(DECIMALPOINT))
+				&& !amount.contains(Character.toString(THOUSANDPOINT))
+				&& !amount.contains(" ")) {
+
+			if (matchPositiveInteger(amount)) {
+				BigDecimalValidator validator = CurrencyValidator.getInstance();
+				BigDecimal bdamount = validator.validate(amount, Locale.US);
+				if (bdamount == null) {
+					throw new Exception("Cannot parse " + amount);
+				} else {
+					return bdamount;
+				}
+			} else {
+				throw new Exception("Not a positive integer "
+						+ amount);
+			}
+
+		} else {
+			//TODO should not go this path in this current release
+			StringBuffer pat = new StringBuffer();
+
+			if (!StringUtils.isBlank(Character.toString(THOUSANDPOINT))) {
+				pat.append("\\d{1,3}(" + THOUSANDPOINT + "?\\d{3})*");
+			}
+
+			pat.append("(\\" + DECIMALPOINT + "\\d{1," + DECIMALCOUNT + "})");
+
+			Pattern pattern = Pattern.compile(pat.toString());
+			Matcher matcher = pattern.matcher(amount);
+
+			if (matcher.matches()) {
+
+				Locale locale = Constants.DEFAULT_LOCALE;
+				//TODO validate amount using old test case
+				if (DECIMALPOINT == ',') {
+					locale = Locale.GERMAN;
+				}
+
+				BigDecimalValidator validator = CurrencyValidator.getInstance();
+				BigDecimal bdamount = validator.validate(amount, locale);
+
+				return bdamount;
+			} else {
+				throw new Exception("Cannot parse " + amount);
+			}
+		}
+
+	}
+	
+	public BigDecimal getOrderProductTotalPrice(MerchantStore store, OrderProduct orderProduct) {
+		
+		BigDecimal finalPrice = orderProduct.getOneTimeCharge();
+		finalPrice = finalPrice.multiply(new BigDecimal(orderProduct.getProductQuantity()));
+		return finalPrice;
+	}
+	
+	/**
+	 * Determines if a ProductPrice has a discount
+	 * @param productPrice
+	 * @return
+	 */
+	public boolean hasDiscount(ProductPrice productPrice) {
+		
+		
+		Date today = new Date();
+
+		//calculate discount price
+		boolean hasDiscount = false;
+		if(productPrice.getProductPriceSpecialStartDate()!=null
+				|| productPrice.getProductPriceSpecialEndDate()!=null) {
+			
+			
+			if(productPrice.getProductPriceSpecialStartDate()!=null) {
+				if(productPrice.getProductPriceSpecialStartDate().before(today)) {
+					if(productPrice.getProductPriceSpecialEndDate()!=null) {
+							if(productPrice.getProductPriceSpecialEndDate().after(today)) {
+								hasDiscount = true;
+							}
+					} 
+				}
+			}
+		}
+		
+		return hasDiscount;
+		
+		
+		
+	}
+	
+	private boolean matchPositiveInteger(String amount) {
+
+		Pattern pattern = Pattern.compile("^[+]?\\d*$");
+		Matcher matcher = pattern.matcher(amount);
+		if (matcher.matches()) {
+			return true;
+
+		} else {
+			return false;
+		}
+	}
+	
+	private FinalPrice calculateFinalPrice(Product product) {
+
+		FinalPrice finalPrice = null;;
+		List<FinalPrice> otherPrices = null;
+		
+
+		Set<ProductAvailability> availabilities = product.getAvailabilities();
+		for(ProductAvailability availability : availabilities) {
+			if(availability.getRegion().equals(Constants.ALL_REGIONS)) {//TODO REL 2.1 accept a region
+				Set<ProductPrice> prices = availability.getPrices();
+				for(ProductPrice price : prices) {
+					
+					FinalPrice p = finalPrice(price);
+					if(price.isDefaultPrice()) {
+						finalPrice = p;
+					} else {
+						if(otherPrices==null) {
+							otherPrices = new ArrayList<FinalPrice>();
+						}
+						otherPrices.add(p);
+					}
+				}
+			}
+		}
+
+		
+		if(finalPrice!=null) {
+			finalPrice.setAdditionalPrices(otherPrices);
+		} else {
+			if(otherPrices!=null) {
+				finalPrice = otherPrices.get(0);
+			}
+		}
+		
+		return finalPrice;
+		
+		
+	}
+	
+	private FinalPrice finalPrice(ProductPrice price) {
+		
+		FinalPrice finalPrice = new FinalPrice();
+		BigDecimal fPrice = price.getProductPriceAmount();
+		BigDecimal oPrice = price.getProductPriceAmount();
+
+		Date today = new Date();
+		//calculate discount price
+		boolean hasDiscount = false;
+		if(price.getProductPriceSpecialStartDate()!=null
+				|| price.getProductPriceSpecialEndDate()!=null) {
+			
+			
+			if(price.getProductPriceSpecialStartDate()!=null) {
+				if(price.getProductPriceSpecialStartDate().before(today)) {
+					if(price.getProductPriceSpecialEndDate()!=null) {
+							if(price.getProductPriceSpecialEndDate().after(today)) {
+								hasDiscount = true;
+								fPrice = price.getProductPriceSpecialAmount();
+								finalPrice.setDiscountEndDate(price.getProductPriceSpecialEndDate());
+							}
+					} 
+						
+				}
+			}
+			
+			
+			if(!hasDiscount && price.getProductPriceSpecialStartDate()==null && price.getProductPriceSpecialEndDate()!=null) {
+				if(price.getProductPriceSpecialEndDate().after(today)) {
+					hasDiscount = true;
+					fPrice = price.getProductPriceSpecialAmount();
+					finalPrice.setDiscountEndDate(price.getProductPriceSpecialEndDate());
+				}
+			}
+		} else {
+			if(price.getProductPriceSpecialAmount()!=null && price.getProductPriceSpecialAmount().doubleValue()>0) {
+				hasDiscount = true;
+				fPrice = price.getProductPriceSpecialAmount();
+				finalPrice.setDiscountEndDate(price.getProductPriceSpecialEndDate());
+			}
+		}
+		
+		finalPrice.setProductPrice(price);
+		finalPrice.setFinalPrice(fPrice);
+		finalPrice.setOriginalPrice(oPrice);
+		
+		
+		if(price.isDefaultPrice()) {
+			finalPrice.setDefaultPrice(true);
+		}
+		if(hasDiscount) {
+			discountPrice(finalPrice);
+		}
+
+		
+		return finalPrice;
+	}
+	
+	private void discountPrice(FinalPrice finalPrice) {
+		
+		finalPrice.setDiscounted(true);
+		
+		double arith = finalPrice.getProductPrice().getProductPriceSpecialAmount().doubleValue() / finalPrice.getProductPrice().getProductPriceAmount().doubleValue();
+		double fsdiscount = 100 - (arith * 100);
+		Float percentagediscount = new Float(fsdiscount);
+		int percent = percentagediscount.intValue();
+		finalPrice.setDiscountPercent(percent);
+		
+		//calculate percent
+		BigDecimal price = finalPrice.getOriginalPrice();
+		finalPrice.setDiscountedPrice(finalPrice.getProductPrice().getProductPriceSpecialAmount());
+	}
+
+
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/ProductUtils.java b/sm-core/src/main/java/com/salesmanager/core/utils/ProductUtils.java
new file mode 100644
index 0000000..60950fa
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/ProductUtils.java
@@ -0,0 +1,42 @@
+package com.salesmanager.core.utils;
+
+import java.util.Set;
+
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductAttribute;
+
+public class ProductUtils {
+	
+	public static String buildOrderProductDisplayName(OrderProduct orderProduct) {
+		
+		String pName = orderProduct.getProductName();
+		Set<OrderProductAttribute> oAttributes = orderProduct.getOrderAttributes();
+		StringBuilder attributeName = null;
+		for(OrderProductAttribute oProductAttribute : oAttributes) {
+			if(attributeName == null) {
+				attributeName = new StringBuilder();
+				attributeName.append("[");
+			} else {
+				attributeName.append(", ");
+			}
+			attributeName.append(oProductAttribute.getProductAttributeName())
+			.append(": ")
+			.append(oProductAttribute.getProductAttributeValueName());
+			
+		}
+		
+		
+		StringBuilder productName = new StringBuilder();
+		productName.append(pName);
+		
+		if(attributeName!=null) {
+			attributeName.append("]");
+			productName.append(" ").append(attributeName.toString());
+		}
+		
+		return productName.toString();
+		
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/reference/ConfigurationModulesLoader.java b/sm-core/src/main/java/com/salesmanager/core/utils/reference/ConfigurationModulesLoader.java
new file mode 100644
index 0000000..64e7bad
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/reference/ConfigurationModulesLoader.java
@@ -0,0 +1,103 @@
+package com.salesmanager.core.utils.reference;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+
+
+public class ConfigurationModulesLoader {
+	
+	@SuppressWarnings("unused")
+	private static final Logger LOGGER = LoggerFactory.getLogger(ConfigurationModulesLoader.class);
+	
+
+	
+	public static String toJSONString(Map<String,IntegrationConfiguration> configurations) throws Exception {
+		
+		StringBuilder jsonModules = new StringBuilder();
+		jsonModules.append("[");
+		int count = 0;
+		for(Object key : configurations.keySet()) {
+			
+			String k = (String)key;
+			IntegrationConfiguration c = (IntegrationConfiguration)configurations.get(k);
+			
+			String jsonString = c.toJSONString();
+			jsonModules.append(jsonString);
+			
+			count ++;
+			if(count<configurations.size()) {
+				jsonModules.append(",");
+			}
+		}
+		jsonModules.append("]");
+		return jsonModules.toString();
+		
+		
+	}
+	
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	public static Map<String,IntegrationConfiguration> loadIntegrationConfigurations(String value) throws Exception {
+		
+		
+		Map<String,IntegrationConfiguration> modules = new HashMap<String,IntegrationConfiguration>();
+		
+		ObjectMapper mapper = new ObjectMapper();
+		
+		try {
+			
+
+            Map[] objects = mapper.readValue(value, Map[].class);
+            
+            for(int i = 0; i < objects.length; i++) {
+            	
+            	
+            	Map object = objects[i];
+            	
+            	IntegrationConfiguration configuration = new IntegrationConfiguration();
+            	
+            	String moduleCode = (String)object.get("moduleCode");
+            	if(object.get("active")!=null) {
+            		configuration.setActive((Boolean)object.get("active"));
+            	}
+            	if(object.get("defaultSelected")!=null) {
+            		configuration.setDefaultSelected((Boolean)object.get("defaultSelected"));
+            	}
+            	if(object.get("environment")!=null) {
+            		configuration.setEnvironment((String)object.get("environment"));
+            	}
+            	configuration.setModuleCode(moduleCode);
+            	
+            	modules.put(moduleCode, configuration);
+
+            	if(object.get("integrationKeys")!=null) {
+            		Map<String,String> confs = (Map<String,String> )object.get("integrationKeys");
+            		configuration.setIntegrationKeys(confs);
+            	}
+            	
+            	if(object.get("integrationKeys")!=null) {
+            		Map<String,List<String>> options = (Map<String,List<String>> )object.get("integrationOptions");
+            		configuration.setIntegrationOptions(options);
+            	}
+
+            	
+            }
+            
+            return modules;
+
+  		} catch (Exception e) {
+  			throw new ServiceException(e);
+  		}
+  		
+
+	
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/reference/IntegrationModulesLoader.java b/sm-core/src/main/java/com/salesmanager/core/utils/reference/IntegrationModulesLoader.java
new file mode 100755
index 0000000..48ef1ff
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/reference/IntegrationModulesLoader.java
@@ -0,0 +1,190 @@
+package com.salesmanager.core.utils.reference;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.model.ModuleConfig;
+
+@Component
+public class IntegrationModulesLoader {
+	
+
+	private static final Logger LOGGER = LoggerFactory.getLogger(IntegrationModulesLoader.class);
+	
+
+	public List<IntegrationModule> loadIntegrationModules(String jsonFilePath) throws Exception {
+		
+		
+		List<IntegrationModule> modules = new ArrayList<IntegrationModule>();
+		
+		ObjectMapper mapper = new ObjectMapper();
+		
+		try {
+			
+            InputStream in =
+                this.getClass().getClassLoader().getResourceAsStream(jsonFilePath);
+			
+            
+            @SuppressWarnings("rawtypes")
+			Map[] objects = mapper.readValue(in, Map[].class);
+            
+            for(int i = 0; i < objects.length; i++) {
+            	
+            	modules.add(this.loadModule(objects[i]));
+            }
+            
+            return modules;
+
+  		} catch (Exception e) {
+  			throw new ServiceException(e);
+  		}
+  		
+  		
+
+		
+	
+	
+	
+	}
+	
+	@SuppressWarnings({ "rawtypes", "unchecked" })
+	public IntegrationModule loadModule(Map object) throws Exception {
+		
+			ObjectMapper mapper = new ObjectMapper();
+	    	IntegrationModule module = new IntegrationModule();
+	    	module.setModule((String)object.get("module"));
+	    	module.setCode((String)object.get("code"));
+	    	module.setImage((String)object.get("image"));
+	    	
+	    	if(object.get("type")!=null) {
+	    		module.setType((String)object.get("type"));
+	    	}
+	    	
+	    	if(object.get("customModule")!=null) {
+	    		Object o = object.get("customModule");
+	    		Boolean b = false;
+	    		if(o instanceof Boolean) {
+	    			b = (Boolean)object.get("customModule");
+	    		} else {
+	    			try {
+	    				b = new Boolean((String)object.get("customModule"));
+	    			} catch(Exception e) {
+	    				LOGGER.error("Cannot cast " + o.getClass() + " tp a boolean value");
+	    			}
+	    		}
+	    		module.setCustomModule(b);
+	    	}
+	    	//module.setRegions(regions)
+	    	if(object.get("details")!=null) {
+	    		
+	    		Map<String,String> details = (Map<String,String>)object.get("details");
+	    		module.setDetails(details);
+	    		
+	    		//maintain the original json structure
+	    		StringBuilder detailsStructure = new StringBuilder();
+	    		int count = 0;
+	    		detailsStructure.append("{");
+	    		for(String key : details.keySet()) {
+	    			String jsonKeyString = mapper.writeValueAsString(key);
+	    			detailsStructure.append(jsonKeyString);
+	    			detailsStructure.append(":");
+	    			String jsonValueString = mapper.writeValueAsString(details.get(key));
+	    			detailsStructure.append(jsonValueString);
+	        		if(count<(details.size()-1)) {
+	        			detailsStructure.append(",");
+	        		}
+	        		count++;
+	    		}
+	    		detailsStructure.append("}");
+	    		module.setConfigDetails(detailsStructure.toString());
+	    		
+	    	}
+	    	
+	    	
+	    	List confs = (List)object.get("configuration");
+	    	
+	    	//convert to json
+	    	
+	    	
+	    	
+	    	if(confs!=null) {
+	    		StringBuilder configString = new StringBuilder();
+	    		configString.append("[");
+	    		Map<String,ModuleConfig> moduleConfigs = new HashMap<String,ModuleConfig>();
+	        	int count=0;
+	    		for(Object oo : confs) {
+	        		
+	        		Map values = (Map)oo;
+	        		
+	        		String env = (String)values.get("env");
+	        		
+	        		ModuleConfig config = new ModuleConfig();
+	        		config.setScheme((String)values.get("scheme"));
+	        		config.setHost((String)values.get("host"));
+	        		config.setPort((String)values.get("port"));
+	        		config.setUri((String)values.get("uri"));
+	        		config.setEnv((String)values.get("env"));
+	        		if((String)values.get("config1")!=null) {
+	        			config.setConfig1((String)values.get("config1"));
+	        		}
+	        		if((String)values.get("config2")!=null) {
+	        			config.setConfig2((String)values.get("config2"));
+	        		}
+	        		
+	        		String jsonConfigString = mapper.writeValueAsString(config);
+	        		configString.append(jsonConfigString);
+	        		
+	        		moduleConfigs.put(env, config);
+	        		
+	        		if(count<(confs.size()-1)) {
+	        			configString.append(",");
+	        		}
+	        		count++;
+	        		
+	        		
+	        	}
+	        	configString.append("]");
+	        	module.setConfiguration(configString.toString());
+	        	module.setModuleConfigs(moduleConfigs);
+	    	}
+	    	
+	    	List<String> regions = (List<String>)object.get("regions");
+	    	if(regions!=null) {
+	    		
+	
+	    		StringBuilder configString = new StringBuilder();
+	    		configString.append("[");
+	    		int count=0;
+	    		for(String region : regions) {
+	    			
+	    			module.getRegionsSet().add(region);
+	    			String jsonConfigString = mapper.writeValueAsString(region);
+	    			configString.append(jsonConfigString);
+	    			
+	        		if(count<(regions.size()-1)) {
+	        			configString.append(",");
+	        		}
+	        		count++;
+	
+	    		}
+	    		configString.append("]");
+	    		module.setRegions(configString.toString());
+	
+	    	}
+	    	
+	    	return module;
+    	
+		
+	}
+
+}
diff --git a/sm-core/src/main/java/com/salesmanager/core/utils/reference/ZonesLoader.java b/sm-core/src/main/java/com/salesmanager/core/utils/reference/ZonesLoader.java
new file mode 100755
index 0000000..6df0953
--- /dev/null
+++ b/sm-core/src/main/java/com/salesmanager/core/utils/reference/ZonesLoader.java
@@ -0,0 +1,142 @@
+package com.salesmanager.core.utils.reference;
+
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.reference.zone.model.ZoneDescription;
+
+@Component
+public class ZonesLoader {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(ZonesLoader.class);
+	
+	@Autowired
+	private LanguageService languageService;
+	
+	@Autowired
+	private CountryService countryService;
+	
+	public Map<String, Zone> loadZones(String jsonFilePath) throws Exception {
+		
+		
+		
+List<Language> languages = languageService.list();
+		
+		List<Country> countries = countryService.list();
+		Map<String,Country> countriesMap = new HashMap<String,Country>();
+		for(Country country : countries) {
+			
+			countriesMap.put(country.getIsoCode(), country);
+			
+		}
+		
+		ObjectMapper mapper = new ObjectMapper();
+
+        try {
+
+              InputStream in =
+                    this.getClass().getClassLoader().getResourceAsStream(jsonFilePath);
+
+              @SuppressWarnings("unchecked")
+              Map<String,Object> data = mapper.readValue(in, Map.class);
+              
+              Map<String,Zone> zonesMap = new HashMap<String,Zone>();
+              Map<String,List<ZoneDescription>> zonesDescriptionsMap = new HashMap<String,List<ZoneDescription>>();
+              Map<String,String> zonesMark = new HashMap<String,String>();
+              
+              for(Language l : languages) {
+	              @SuppressWarnings("rawtypes")
+	              List langList = (List)data.get(l.getCode());
+	              if(langList!=null) {
+		              for(Object z : langList) {
+		                    @SuppressWarnings("unchecked")
+							Map<String,String> e = (Map<String,String>)z;
+		                    String zoneCode = e.get("zoneCode");
+		                    ZoneDescription zoneDescription = new ZoneDescription();
+		                    zoneDescription.setLanguage(l);
+		                    zoneDescription.setName(e.get("zoneName"));
+		                    Zone zone = null;
+		                    List<ZoneDescription> descriptions = null;
+		                    if(!zonesMap.containsKey(zoneCode)) {
+		                    	zone = new Zone();
+		                    	Country country = countriesMap.get(e.get("countryCode"));
+		                    	if(country==null) {
+		                    		LOGGER.warn("Country is null for " + zoneCode + " and country code " + e.get("countryCode"));
+		                    		continue;
+		                    	}
+			                    zone.setCountry(country);
+		                    	zonesMap.put(zoneCode, zone);
+		                    	zone.setCode(zoneCode);
+
+		                    }
+		                    
+		                    
+		                    if(zonesMark.containsKey(l.getCode() + "_" + zoneCode)) {
+	                    		LOGGER.warn("This zone seems to be a duplicate !  " + zoneCode + " and language code " + l.getCode());
+	                    		continue;
+		                    }
+		                    
+		                    zonesMark.put(l.getCode() + "_" + zoneCode, l.getCode() + "_" + zoneCode);
+		                    
+		                    if(zonesDescriptionsMap.containsKey(zoneCode)) {
+		                    	descriptions = zonesDescriptionsMap.get(zoneCode);
+		                    } else {
+		                    	descriptions = new ArrayList<ZoneDescription>();
+		                    	zonesDescriptionsMap.put(zoneCode, descriptions);
+		                    }
+		                    
+		                    descriptions.add(zoneDescription);
+
+		                }
+		             }
+
+              }
+              
+              
+              for (Map.Entry<String, Zone> entry : zonesMap.entrySet()) {
+          	    String key = entry.getKey();
+          	    Zone value = entry.getValue();
+          	    
+          	    //if(value.getDescriptions()==null) {
+          	    //	LOGGER.warn("This zone " + key + " has no descriptions");
+          	    //	continue;
+          	    //}
+
+          	    //get descriptions
+          	    List<ZoneDescription> descriptions = zonesDescriptionsMap.get(key);
+          	    if(descriptions!=null) {
+          	    	value.setDescriptons(descriptions);
+          	    }
+            }
+
+              return zonesMap;
+              
+  			
+  		} catch (Exception e) {
+  			throw new ServiceException(e);
+  		}
+  		
+  		
+
+		
+	
+	
+	
+	}
+
+}
diff --git a/sm-core/src/main/resources/cms/infinispan_configuration.xml b/sm-core/src/main/resources/cms/infinispan_configuration.xml
new file mode 100755
index 0000000..c3f4cd0
--- /dev/null
+++ b/sm-core/src/main/resources/cms/infinispan_configuration.xml
@@ -0,0 +1,99 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+
+	xsi:schemaLocation="urn:infinispan:config:5.1 http://www.infinispan.org/schemas/infinispan-config-5.1.xsd"
+
+	xmlns="urn:infinispan:config:5.1">
+
+	<global>
+	
+		 <globalJmxStatistics enabled="false" jmxDomain="infinispan"/>
+	
+	</global>
+
+	<default />
+
+	<namedCache name="StoreRepository">
+		<invocationBatching enabled="true"/>
+		<!-- disable jmx in prod -->
+		<jmxStatistics enabled="false"/>
+		<loaders passivation="false" shared="false" preload="false">		
+<!-- 		<loader class="org.infinispan.loaders.jdbc.mixed.JdbcMixedCacheStore"
+                fetchPersistentState="false" ignoreModifications="false"
+                purgeOnStartup="false">
+                <properties>
+                    <property name="tableNamePrefixForStrings" value="ISPN_MIXED_STR_TABLE" />
+                    <property name="tableNamePrefixForBinary" value="ISPN_MIXED_BINARY_TABLE" />
+                    <property name="idColumnNameForStrings" value="ID_COLUMN" />
+                    <property name="idColumnNameForBinary" value="ID_COLUMN" />
+                    <property name="dataColumnNameForStrings" value="DATA_COLUMN" />
+                    <property name="dataColumnNameForBinary" value="DATA_COLUMN" />
+                    <property name="timestampColumnNameForStrings" value="TIMESTAMP_COLUMN" />
+                    <property name="timestampColumnNameForBinary" value="TIMESTAMP_COLUMN" />
+                    <property name="timestampColumnTypeForStrings" value="BIGINT" />
+                    <property name="timestampColumnTypeForBinary" value="BIGINT" />
+                    <property name="connectionFactoryClass"
+                        value="org.infinispan.loaders.jdbc.connectionfactory.PooledConnectionFactory" />
+                    <property name="connectionUrl"
+                        value="jdbc:mysql://localhost:3306/salesmanager_cms" />
+                    <property name="userName" value="username" />
+                    <property name="password" value="password" />
+                    <property name="driverClass" value="com.mysql.jdbc.Driver" />
+                    <property name="idColumnTypeForStrings" value="VARCHAR(255)" />
+                    <property name="idColumnTypeForBinary" value="VARCHAR(255)" />
+                    <property name="dataColumnTypeForStrings" value="LONGBLOB" />
+                    <property name="dataColumnTypeForBinary" value="LONGBLOB" />
+                    <property name="dropTableOnExitForStrings" value="false" />
+                    <property name="dropTableOnExitForBinary" value="false" />
+                    <property name="createTableOnStartForStrings" value="true" />
+                    <property name="createTableOnStartForBinary" value="true" />
+                    <property name="createTableOnStartForStrings" value="true" />
+                    <property name="createTableOnStartForBinary" value="true" />
+                </properties>
+          </loader> -->
+
+
+			  
+			  <loader class="org.infinispan.loaders.file.FileCacheStore" fetchPersistentState="false"
+	               ignoreModifications="false" purgeOnStartup="false">
+	               <properties>
+	                 <property name="location" value="./infinispan/store"/>
+	               </properties>
+	          </loader>
+	          
+		
+			</loaders>
+		
+		    <eviction maxEntries="10" strategy="LRU"/>
+
+		<transaction
+			transactionManagerLookupClass="org.infinispan.transaction.lookup.DummyTransactionManagerLookup"
+			transactionMode="TRANSACTIONAL" lockingMode="OPTIMISTIC" />
+
+	</namedCache>
+	
+	<namedCache name="FilesRepository">
+		 <invocationBatching enabled="true"/>
+		 <!-- disable jmx in prod -->
+		 <jmxStatistics enabled="true"/>
+	     <loaders passivation="false" shared="false" preload="false">
+	          <loader class="org.infinispan.loaders.file.FileCacheStore" fetchPersistentState="false"
+	               ignoreModifications="false" purgeOnStartup="false">
+	            <properties>
+	                 <property name="location" value="./infinispan/files"/>
+	               </properties>
+	          </loader>
+	     </loaders>
+	     
+	     <transaction
+
+			transactionManagerLookupClass="org.infinispan.transaction.lookup.DummyTransactionManagerLookup"
+			transactionMode="TRANSACTIONAL" lockingMode="OPTIMISTIC" />
+	     
+	</namedCache>
+	
+	
+
+</infinispan>
+
diff --git a/sm-core/src/main/resources/configs.properties b/sm-core/src/main/resources/configs.properties
new file mode 100644
index 0000000..531c3ef
--- /dev/null
+++ b/sm-core/src/main/resources/configs.properties
@@ -0,0 +1,2 @@
+#Must be 16 digits (replace with your own creation !)
+secretKey=7070200000000007
\ No newline at end of file
diff --git a/sm-core/src/main/resources/ehcache/smcore-ehcache.xml b/sm-core/src/main/resources/ehcache/smcore-ehcache.xml
new file mode 100644
index 0000000..4a78203
--- /dev/null
+++ b/sm-core/src/main/resources/ehcache/smcore-ehcache.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ehcache name="com.shopizer.core.cache" 
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd">
+	
+    <defaultCache
+            maxElementsInMemory="10000"
+            eternal="false"
+            timeToIdleSeconds="120"
+            timeToLiveSeconds="120"
+            overflowToDisk="false"
+            diskSpoolBufferSizeMB="30"
+            maxElementsOnDisk="10000000"
+            diskPersistent="false"
+            diskExpiryThreadIntervalSeconds="120"
+            memoryStoreEvictionPolicy="LRU" />
+            
+            
+     <cache name="com.shopizer.OBJECT_CACHE"
+           maxElementsInMemory="10000"
+           eternal="false"
+           overflowToDisk="false"
+           timeToIdleSeconds="1200"
+           timeToLiveSeconds="1200"
+           memoryStoreEvictionPolicy="LFU" />
+
+</ehcache>
\ No newline at end of file
diff --git a/sm-core/src/main/resources/email.properties b/sm-core/src/main/resources/email.properties
new file mode 100644
index 0000000..60d6551
--- /dev/null
+++ b/sm-core/src/main/resources/email.properties
@@ -0,0 +1,9 @@
+#GMail sample configuration
+#May require a keystore for certificates
+mailSender.protocol=smtps
+mailSender.host=smtp.gmail.com
+mailSender.port=465
+mailSender.username=test@gmail.com
+mailSender.password=test
+mailSender.mail.smtp.auth=true
+mail.smtp.starttls.enable=true
\ No newline at end of file
diff --git a/sm-core/src/main/resources/log4j.properties b/sm-core/src/main/resources/log4j.properties
new file mode 100644
index 0000000..2f9c9f6
--- /dev/null
+++ b/sm-core/src/main/resources/log4j.properties
@@ -0,0 +1,13 @@
+log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.Stdout.layout.ConversionPattern=[%d{ISO8601}] %-5p - %-26.26c{1} - %m\n
+
+log4j.rootLogger=WARN,Stdout
+
+
+# hibernate queries
+#log4j.logger.org.hibernate.SQL=DEBUG
+#log4j.logger.org.hibernate.type=INFO
+
+# schema initialization
+#log4j.logger.org.hibernate.tool.hbm2ddl=DEBUG
\ No newline at end of file
diff --git a/sm-core/src/main/resources/META-INF/sm-persistence.xml b/sm-core/src/main/resources/META-INF/sm-persistence.xml
new file mode 100644
index 0000000..c96807f
--- /dev/null
+++ b/sm-core/src/main/resources/META-INF/sm-persistence.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
+	version="2.0">
+	<persistence-unit name="sm-unit">
+	    <class>com.salesmanager.core.business.merchant.model.MerchantStore</class>
+		<class>com.salesmanager.core.business.reference.country.model.Country</class>
+		<class>com.salesmanager.core.business.reference.country.model.CountryDescription</class>
+		<class>com.salesmanager.core.business.reference.zone.model.Zone</class>
+		<class>com.salesmanager.core.business.reference.zone.model.ZoneDescription</class>
+		<class>com.salesmanager.core.business.reference.language.model.Language</class>
+		<class>com.salesmanager.core.business.reference.currency.model.Currency</class>
+		<class>com.salesmanager.core.business.reference.geozone.model.GeoZone</class>
+		<class>com.salesmanager.core.business.reference.geozone.model.GeoZoneDescription</class>
+		
+		
+		<class>com.salesmanager.core.business.tax.model.taxclass.TaxClass</class>
+		<class>com.salesmanager.core.business.tax.model.taxrate.TaxRate</class>
+		<class>com.salesmanager.core.business.tax.model.taxrate.TaxRateDescription</class>
+		<class>com.salesmanager.core.business.system.model.SystemConfiguration</class>
+		<class>com.salesmanager.core.business.system.model.IntegrationModule</class>
+		<class>com.salesmanager.core.business.system.model.MerchantConfiguration</class>
+		<class>com.salesmanager.core.business.system.model.SystemNotification</class>
+		<class>com.salesmanager.core.business.system.model.MerchantLog</class>
+		
+		<class>com.salesmanager.core.business.order.model.filehistory.FileHistory</class>
+		<class>com.salesmanager.core.business.order.model.orderproduct.OrderProduct</class>
+		<class>com.salesmanager.core.business.order.model.orderproduct.OrderProductAttribute</class>
+		<class>com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload</class>
+		<class>com.salesmanager.core.business.order.model.orderproduct.OrderProductPrice</class>
+		<class>com.salesmanager.core.business.order.model.orderstatus.OrderStatus</class>
+		<class>com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory</class>
+		<class>com.salesmanager.core.business.order.model.Order</class>
+		<class>com.salesmanager.core.business.order.model.OrderTotal</class>
+		
+		<class>com.salesmanager.core.business.customer.model.Customer</class>
+		<class>com.salesmanager.core.business.customer.model.attribute.CustomerAttribute</class>
+		<class>com.salesmanager.core.business.customer.model.attribute.CustomerOption</class>
+		<class>com.salesmanager.core.business.customer.model.attribute.CustomerOptionDescription</class>
+		<class>com.salesmanager.core.business.customer.model.attribute.CustomerOptionValue</class>
+		<class>com.salesmanager.core.business.customer.model.attribute.CustomerOptionSet</class>
+		<class>com.salesmanager.core.business.customer.model.attribute.CustomerOptionValueDescription</class>
+		
+		<class>com.salesmanager.core.business.catalog.category.model.Category</class>
+		<class>com.salesmanager.core.business.catalog.category.model.CategoryDescription</class>
+			   
+		<class>com.salesmanager.core.business.content.model.Content</class>
+		<class>com.salesmanager.core.business.content.model.ContentDescription</class>
+		
+		<class>com.salesmanager.core.business.catalog.product.model.Product</class>
+		<class>com.salesmanager.core.business.catalog.product.model.description.ProductDescription</class>
+		<class>com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute</class>
+		<class>com.salesmanager.core.business.catalog.product.model.attribute.ProductOption</class>
+		<class>com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionDescription</class>
+		<class>com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue</class>
+		<class>com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValueDescription</class>
+		
+		<class>com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability</class>
+		<class>com.salesmanager.core.business.catalog.product.model.file.DigitalProduct</class>
+		<class>com.salesmanager.core.business.catalog.product.model.image.ProductImage</class>
+		<class>com.salesmanager.core.business.catalog.product.model.image.ProductImageDescription</class>
+		<class>com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer</class>
+		<class>com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription</class>
+		<class>com.salesmanager.core.business.catalog.product.model.price.ProductPrice</class>
+		<class>com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription</class>
+		
+		<class>com.salesmanager.core.business.catalog.product.model.relationship.ProductRelationship</class>
+		<class>com.salesmanager.core.business.catalog.product.model.review.ProductReview</class>
+		<class>com.salesmanager.core.business.catalog.product.model.review.ProductReviewDescription</class>
+		
+		<class>com.salesmanager.core.business.catalog.product.model.type.ProductType</class>
+		
+		<class>com.salesmanager.core.business.user.model.User</class>
+		<class>com.salesmanager.core.business.user.model.Group</class>
+		<class>com.salesmanager.core.business.user.model.Permission</class>
+		
+		<class>com.salesmanager.core.business.shoppingcart.model.ShoppingCart</class>
+		<class>com.salesmanager.core.business.shoppingcart.model.ShoppingCartAttributeItem</class>
+		<class>com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem</class>
+		
+		
+	</persistence-unit>
+</persistence>
diff --git a/sm-core/src/main/resources/reference/GeoLite2-Country.mmdb b/sm-core/src/main/resources/reference/GeoLite2-Country.mmdb
new file mode 100644
index 0000000..1a25eb5
Binary files /dev/null and b/sm-core/src/main/resources/reference/GeoLite2-Country.mmdb differ
diff --git a/sm-core/src/main/resources/reference/integrationmodules.json b/sm-core/src/main/resources/reference/integrationmodules.json
new file mode 100755
index 0000000..cffa8e5
--- /dev/null
+++ b/sm-core/src/main/resources/reference/integrationmodules.json
@@ -0,0 +1,60 @@
+[
+	{
+		"module": "SHIPPING",
+		"code": "usps",
+		"version":"",
+		"regions": ["US"],
+		"image":"usps.jpg",
+		"configuration":[{"env":"TEST","scheme":"http","host":"testing.shippingapis.com","port":"80","uri":"/ShippingAPI.dll"},{"env":"PROD","scheme":"http","host":"production.shippingapis.com","port":"80","uri":"/ShippingAPI.dll"}]
+
+	},
+	{
+		"module": "SHIPPING",
+		"code": "ups",
+		"version":"",
+		"regions": ["US","CA","FR","GB"],
+		"image":"ups.jpg",
+		"configuration":[{"env":"TEST","scheme":"https","host":"wwwcie.ups.com","port":"443","uri":"/ups.app/xml/Rate"},{"env":"PROD","scheme":"https","host":"onlinetools.ups.com","port":"443","uri":"/xml/Rate"}],
+		"details":{"01":"UPS Next Day Air","02":"UPS Second Day Air","03":"UPS Ground","07":"UPS Worldwide Express","08":"UPS Worldwide Expedited","11":"UPS Standard","12":"UPS Three-Day Select","13":"UPS Next Day Air Saver","14":"UPS Next Day Air Early A.M.","54":"UPS Worldwide Express Plus","59":"UPS Second Day Air A.M.","69":"UPS Saver"}
+
+	},
+	{
+		"module": "SHIPPING",
+		"code": "weightBased",
+		"customModule":"true",
+		"version":"1.0",
+		"regions": ["*"]
+	},
+	{
+		"module": "PAYMENT",
+		"code": "moneyorder",
+		"type":"moneyorder",
+		"version":"",
+		"regions": ["*"],
+		"image":"moneyorder.gif"
+	},
+	{
+		"module": "PAYMENT",
+		"code": "paypal-express-checkout",
+		"type":"paypal",
+		"version":"104.0",
+		"regions": ["*"],
+		"image":"icon-paypal.png",
+		"configuration":[{"env":"TEST","scheme":"","host":"","port":"","uri":"","config1":"https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token="},{"env":"PROD","scheme":"","host":"","port":"","uri":"","config1":"https://www.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token="}]
+
+	},
+	
+	
+	{
+		"module": "PAYMENT",
+		"code": "beanstream",
+		"type":"creditcard",
+		"version":"",
+		"regions": ["US","CA","GB"],
+		"image":"beanstream.gif",
+		"configuration":[{"env":"TEST","scheme":"https","host":"www.beanstream.com","port":"443","uri":"/scripts/process_transaction.asp"},{"env":"PROD","scheme":"https","host":"www.beanstream.com","port":"443","uri":"/scripts/process_transaction.asp"}]
+
+	}
+
+] 
+
diff --git a/sm-core/src/main/resources/reference/zoneconfig.json b/sm-core/src/main/resources/reference/zoneconfig.json
new file mode 100644
index 0000000..3350c43
--- /dev/null
+++ b/sm-core/src/main/resources/reference/zoneconfig.json
@@ -0,0 +1,1888 @@
+{
+  "en":[
+	{
+		"zoneCode": "AL",
+		"zoneName": "Alabama",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AK",
+		"zoneName": "Alaska",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AS",
+		"zoneName": "American Samoa",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AZ",
+		"zoneName": "Arizona",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AR",
+		"zoneName": "Arkansas",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AF",
+		"zoneName": "Armed Forces Africa",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AA",
+		"zoneName": "Armed Forces Americas",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AC",
+		"zoneName": "Armed Forces Canada",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AE",
+		"zoneName": "Armed Forces Europe",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AM",
+		"zoneName": "Armed Forces Middle East",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AP",
+		"zoneName": "Armed Forces Pacific",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "CA",
+		"zoneName": "California",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "CO",
+		"zoneName": "Colorado",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "CT",
+		"zoneName": "Connecticut",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "DE",
+		"zoneName": "Delaware",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "DC",
+		"zoneName": "District of Columbia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "FM",
+		"zoneName": "Federated States Of Micronesia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "FL",
+		"zoneName": "Florida",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "GA",
+		"zoneName": "Georgia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "GU",
+		"zoneName": "Guam",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "HI",
+		"zoneName": "Hawaii",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "ID",
+		"zoneName": "Idaho",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "IL",
+		"zoneName": "Illinois",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "IN",
+		"zoneName": "Indiana",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "IA",
+		"zoneName": "Iowa",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "KS",
+		"zoneName": "Kansas",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "KY",
+		"zoneName": "Kentucky",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "LA",
+		"zoneName": "Louisiana",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "ME",
+		"zoneName": "Maine",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MH",
+		"zoneName": "Marshall Islands",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MD",
+		"zoneName": "Maryland",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MA",
+		"zoneName": "Massachusetts",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MI",
+		"zoneName": "Michigan",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MN",
+		"zoneName": "Minnesota",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MS",
+		"zoneName": "Mississippi",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MO",
+		"zoneName": "Missouri",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MT",
+		"zoneName": "Montana",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NE",
+		"zoneName": "Nebraska",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NV",
+		"zoneName": "Nevada",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NH",
+		"zoneName": "New Hampshire",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NJ",
+		"zoneName": "New Jersey",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NM",
+		"zoneName": "New Mexico",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NY",
+		"zoneName": "New York",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NC",
+		"zoneName": "North Carolina",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "ND",
+		"zoneName": "North Dakota",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MP",
+		"zoneName": "Northern Mariana Islands",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "OH",
+		"zoneName": "Ohio",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "OK",
+		"zoneName": "Oklahoma",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "OR",
+		"zoneName": "Oregon",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "PA",
+		"zoneName": "Pennsylvania",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "PR",
+		"zoneName": "Puerto Rico",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "RI",
+		"zoneName": "Rhode Island",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "SC",
+		"zoneName": "South Carolina",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "SD",
+		"zoneName": "South Dakota",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "TN",
+		"zoneName": "Tennessee",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "TX",
+		"zoneName": "Texas",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "UT",
+		"zoneName": "Utah",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "VT",
+		"zoneName": "Vermont",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "VI",
+		"zoneName": "Virgin Islands",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "VA",
+		"zoneName": "Virginia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "WA",
+		"zoneName": "Washington",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "WV",
+		"zoneName": "West Virginia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "WI",
+		"zoneName": "Wisconsin",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "WY",
+		"zoneName": "Wyoming",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AB",
+		"zoneName": "Alberta",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "BC",
+		"zoneName": "British Columbia",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "MB",
+		"zoneName": "Manitoba",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NF",
+		"zoneName": "Newfoundland - Labrador",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NB",
+		"zoneName": "New Brunswick",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NS",
+		"zoneName": "Nova Scotia",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NT",
+		"zoneName": "Northwest Territories",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NU",
+		"zoneName": "Nunavut",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "ON",
+		"zoneName": "Ontario",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "PE",
+		"zoneName": "Prince Edward Island",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "QC",
+		"zoneName": "Quebec",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "SK",
+		"zoneName": "Saskatchewan",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "YT",
+		"zoneName": "Yukon Territory",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NDS",
+		"zoneName": "Niedersachsen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BAW",
+		"zoneName": "Baden-Wrttemberg",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BAY",
+		"zoneName": "Bayern",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BER",
+		"zoneName": "Berlin",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BRG",
+		"zoneName": "Brandenburg",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BRE",
+		"zoneName": "Bremen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "HAM",
+		"zoneName": "Hamburg",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "HES",
+		"zoneName": "Hessen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "MEC",
+		"zoneName": "Mecklenburg-Vorpommern",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "NRW",
+		"zoneName": "Nordrhein-Westfalen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "RHE",
+		"zoneName": "Rheinland-Pfalz",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "SAR",
+		"zoneName": "Saarland",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "SAS",
+		"zoneName": "Sachsen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "SAC",
+		"zoneName": "Sachsen-Anhalt",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "SCN",
+		"zoneName": "Schleswig-Holstein",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "THE",
+		"zoneName": "Thringen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "WIAT",
+		"zoneName": "Wien",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "NO",
+		"zoneName": "Niederosterreich",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "OO",
+		"zoneName": "Oberosterreich",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "SB",
+		"zoneName": "Salzburg",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "KN",
+		"zoneName": "Katen",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "ST",
+		"zoneName": "Steiermark",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "TIAT",
+		"zoneName": "Tirol",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "BLAT",
+		"zoneName": "Burgenland",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "VB",
+		"zoneName": "Voralberg",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "AG",
+		"zoneName": "Aargau",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "AI",
+		"zoneName": "Appenzell Innerrhoden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "ARCH",
+		"zoneName": "Appenzell Ausserrhoden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "BE",
+		"zoneName": "Bern",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "BL",
+		"zoneName": "Basel-Landschaft",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "BS",
+		"zoneName": "Basel-Stadt",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "FR",
+		"zoneName": "Freiburg",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "GE",
+		"zoneName": "Genf",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "GL",
+		"zoneName": "Glarus",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "GR",
+		"zoneName": "Graubnden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "JU",
+		"zoneName": "Jura",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "LU",
+		"zoneName": "Luzern",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "NECH",
+		"zoneName": "Neuenburg",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "NW",
+		"zoneName": "Nidwalden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "OW",
+		"zoneName": "Obwalden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "SG",
+		"zoneName": "St. Gallen",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "SH",
+		"zoneName": "Schaffhausen",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "SO",
+		"zoneName": "Solothurn",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "SZ",
+		"zoneName": "Schwyz",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "TG",
+		"zoneName": "Thurgau",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "TI",
+		"zoneName": "Tessin",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "UR",
+		"zoneName": "Uri",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "VD",
+		"zoneName": "Waadt",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "VS",
+		"zoneName": "Wallis",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "ZG",
+		"zoneName": "Zug",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "ZH",
+		"zoneName": "Zrich",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "ACorua",
+		"zoneName": "A Corua",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Alava",
+		"zoneName": "Alava",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Albacete",
+		"zoneName": "Albacete",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Alicante",
+		"zoneName": "Alicante",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Almeria",
+		"zoneName": "Almeria",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Asturias",
+		"zoneName": "Asturias",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Avila",
+		"zoneName": "Avila",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Badajoz",
+		"zoneName": "Badajoz",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Baleares",
+		"zoneName": "Baleares",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Barcelona",
+		"zoneName": "Barcelona",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Burgos",
+		"zoneName": "Burgos",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Caceres",
+		"zoneName": "Caceres",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Cadiz",
+		"zoneName": "Cadiz",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Cantabria",
+		"zoneName": "Cantabria",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Castellon",
+		"zoneName": "Castellon",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Ceuta",
+		"zoneName": "Ceuta",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "CiudadReal",
+		"zoneName": "Ciudad Real",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Cordoba",
+		"zoneName": "Cordoba",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Cuenca",
+		"zoneName": "Cuenca",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Girona",
+		"zoneName": "Girona",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Granada",
+		"zoneName": "Granada",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Guadalajara",
+		"zoneName": "Guadalajara",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Guipuzcoa",
+		"zoneName": "Guipuzcoa",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Huelva",
+		"zoneName": "Huelva",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Huesca",
+		"zoneName": "Huesca",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Jaen",
+		"zoneName": "Jaen",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "LaRioja",
+		"zoneName": "La Rioja",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "LasPalmas",
+		"zoneName": "Las Palmas",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Leon",
+		"zoneName": "Leon",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Lleida",
+		"zoneName": "Lleida",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Lugo",
+		"zoneName": "Lugo",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Madrid",
+		"zoneName": "Madrid",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Malaga",
+		"zoneName": "Malaga",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Melilla",
+		"zoneName": "Melilla",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Murcia",
+		"zoneName": "Murcia",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Navarra",
+		"zoneName": "Navarra",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Ourense",
+		"zoneName": "Ourense",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Palencia",
+		"zoneName": "Palencia",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Pontevedra",
+		"zoneName": "Pontevedra",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Salamanca",
+		"zoneName": "Salamanca",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "SantaCruzdeTenerife",
+		"zoneName": "Santa Cruz de Tenerife",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Segovia",
+		"zoneName": "Segovia",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Sevilla",
+		"zoneName": "Sevilla",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Soria",
+		"zoneName": "Soria",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Tarragona",
+		"zoneName": "Tarragona",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Teruel",
+		"zoneName": "Teruel",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Toledo",
+		"zoneName": "Toledo",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Valencia",
+		"zoneName": "Valencia",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Valladolid",
+		"zoneName": "Valladolid",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Vizcaya",
+		"zoneName": "Vizcaya",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Zamora",
+		"zoneName": "Zamora",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Zaragoza",
+		"zoneName": "Zaragoza",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "ACT",
+		"zoneName": "Australian Capital Territory",
+		"countryCode": "AU"
+	},
+	{
+		"zoneCode": "NSW",
+		"zoneName": "New South Wales",
+		"countryCode": "AU"
+	},
+	{
+		"zoneCode": "NTAU",
+		"zoneName": "Northern Territory",
+		"countryCode": "AU"
+	},
+	{
+		"zoneCode": "QLD",
+		"zoneName": "Queensland",
+		"countryCode": "AU"
+	},
+	{
+		"zoneCode": "SA",
+		"zoneName": "South Australia",
+		"countryCode": "AU"
+	},
+	{
+		"zoneCode": "TAS",
+		"zoneName": "Tasmania",
+		"countryCode": "AU"
+	},
+	{
+		"zoneCode": "VIC",
+		"zoneName": "Victoria",
+		"countryCode": "AU"
+	},
+	{
+		"zoneCode": "WAAU",
+		"zoneName": "Western Australia",
+		"countryCode": "AU"
+	} 
+]  ,
+
+  "fr":[
+	{
+		"zoneCode": "AL",
+		"zoneName": "Alabama",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AK",
+		"zoneName": "Alaska",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AS",
+		"zoneName": "American Samoa",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AZ",
+		"zoneName": "Arizona",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AR",
+		"zoneName": "Arkansas",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AF",
+		"zoneName": "Armed Forces Africa",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AA",
+		"zoneName": "Armed Forces Americas",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AC",
+		"zoneName": "Armed Forces Canada",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AE",
+		"zoneName": "Armed Forces Europe",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AM",
+		"zoneName": "Armed Forces Middle East",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AP",
+		"zoneName": "Armed Forces Pacific",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "CA",
+		"zoneName": "California",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "CO",
+		"zoneName": "Colorado",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "CT",
+		"zoneName": "Connecticut",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "DE",
+		"zoneName": "Delaware",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "DC",
+		"zoneName": "District of Columbia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "FM",
+		"zoneName": "Federated States Of Micronesia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "FL",
+		"zoneName": "Florida",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "GA",
+		"zoneName": "Georgia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "GU",
+		"zoneName": "Guam",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "HI",
+		"zoneName": "Hawaii",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "ID",
+		"zoneName": "Idaho",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "IL",
+		"zoneName": "Illinois",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "IN",
+		"zoneName": "Indiana",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "IA",
+		"zoneName": "Iowa",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "KS",
+		"zoneName": "Kansas",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "KY",
+		"zoneName": "Kentucky",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "LA",
+		"zoneName": "Louisiana",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "ME",
+		"zoneName": "Maine",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MH",
+		"zoneName": "Marshall Islands",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MD",
+		"zoneName": "Maryland",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MA",
+		"zoneName": "Massachusetts",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MI",
+		"zoneName": "Michigan",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MN",
+		"zoneName": "Minnesota",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MS",
+		"zoneName": "Mississippi",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MO",
+		"zoneName": "Missouri",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MT",
+		"zoneName": "Montana",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NE",
+		"zoneName": "Nebraska",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NV",
+		"zoneName": "Nevada",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NH",
+		"zoneName": "New Hampshire",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NJ",
+		"zoneName": "New Jersey",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NM",
+		"zoneName": "New Mexico",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NY",
+		"zoneName": "New York",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "NC",
+		"zoneName": "North Carolina",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "ND",
+		"zoneName": "North Dakota",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "MP",
+		"zoneName": "Northern Mariana Islands",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "OH",
+		"zoneName": "Ohio",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "OK",
+		"zoneName": "Oklahoma",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "OR",
+		"zoneName": "Oregon",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "PA",
+		"zoneName": "Pennsylvania",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "PR",
+		"zoneName": "Puerto Rico",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "RI",
+		"zoneName": "Rhode Island",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "SC",
+		"zoneName": "South Carolina",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "SD",
+		"zoneName": "South Dakota",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "TN",
+		"zoneName": "Tennessee",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "TX",
+		"zoneName": "Texas",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "UT",
+		"zoneName": "Utah",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "VT",
+		"zoneName": "Vermont",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "VI",
+		"zoneName": "Virgin Islands",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "VA",
+		"zoneName": "Virginia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "WA",
+		"zoneName": "Washington",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "WV",
+		"zoneName": "West Virginia",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "WI",
+		"zoneName": "Wisconsin",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "WY",
+		"zoneName": "Wyoming",
+		"countryCode": "US"
+	},
+	{
+		"zoneCode": "AB",
+		"zoneName": "Alberta",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "BC",
+		"zoneName": "British Columbia",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "MB",
+		"zoneName": "Manitoba",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NF",
+		"zoneName": "Newfoundland - Labrador",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NB",
+		"zoneName": "New Brunswick",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NS",
+		"zoneName": "Nova Scotia",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NT",
+		"zoneName": "Northwest Territories",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NU",
+		"zoneName": "Nunavut",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "ON",
+		"zoneName": "Ontario",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "PE",
+		"zoneName": "Prince Edward Island",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "QC",
+		"zoneName": "Quebec",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "SK",
+		"zoneName": "Saskatchewan",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "YT",
+		"zoneName": "Yukon Territory",
+		"countryCode": "CA"
+	},
+	{
+		"zoneCode": "NDS",
+		"zoneName": "Niedersachsen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BAW",
+		"zoneName": "Baden-Wrttemberg",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BAY",
+		"zoneName": "Bayern",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BER",
+		"zoneName": "Berlin",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BRG",
+		"zoneName": "Brandenburg",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "BRE",
+		"zoneName": "Bremen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "HAM",
+		"zoneName": "Hamburg",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "HES",
+		"zoneName": "Hessen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "MEC",
+		"zoneName": "Mecklenburg-Vorpommern",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "NRW",
+		"zoneName": "Nordrhein-Westfalen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "RHE",
+		"zoneName": "Rheinland-Pfalz",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "SAR",
+		"zoneName": "Saarland",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "SAS",
+		"zoneName": "Sachsen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "SAC",
+		"zoneName": "Sachsen-Anhalt",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "SCN",
+		"zoneName": "Schleswig-Holstein",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "THE",
+		"zoneName": "Thringen",
+		"countryCode": "DE"
+	},
+	{
+		"zoneCode": "WIAT",
+		"zoneName": "Wien",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "NO",
+		"zoneName": "Niederosterreich",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "OO",
+		"zoneName": "Oberosterreich",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "SB",
+		"zoneName": "Salzburg",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "KN",
+		"zoneName": "Karten",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "ST",
+		"zoneName": "Steiermark",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "TIAT",
+		"zoneName": "Tirol",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "BLAT",
+		"zoneName": "Burgenland",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "VB",
+		"zoneName": "Voralberg",
+		"countryCode": "AT"
+	},
+	{
+		"zoneCode": "AG",
+		"zoneName": "Aargau",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "AI",
+		"zoneName": "Appenzell Innerrhoden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "ARCH",
+		"zoneName": "Appenzell Ausserrhoden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "BE",
+		"zoneName": "Bern",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "BL",
+		"zoneName": "Basel-Landschaft",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "BS",
+		"zoneName": "Basel-Stadt",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "FR",
+		"zoneName": "Freiburg",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "GE",
+		"zoneName": "Genf",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "GL",
+		"zoneName": "Glarus",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "GR",
+		"zoneName": "Graubnden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "JU",
+		"zoneName": "Jura",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "LU",
+		"zoneName": "Luzern",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "NECH",
+		"zoneName": "Neuenburg",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "NW",
+		"zoneName": "Nidwalden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "OW",
+		"zoneName": "Obwalden",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "SG",
+		"zoneName": "St. Gallen",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "SH",
+		"zoneName": "Schaffhausen",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "SO",
+		"zoneName": "Solothurn",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "SZ",
+		"zoneName": "Schwyz",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "TG",
+		"zoneName": "Thurgau",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "TI",
+		"zoneName": "Tessin",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "UR",
+		"zoneName": "Uri",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "VD",
+		"zoneName": "Waadt",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "VS",
+		"zoneName": "Wallis",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "ZG",
+		"zoneName": "Zug",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "ZH",
+		"zoneName": "Zrich",
+		"countryCode": "CH"
+	},
+	{
+		"zoneCode": "A Corua",
+		"zoneName": "A Corua",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Alava",
+		"zoneName": "Alava",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Albacete",
+		"zoneName": "Albacete",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Alicante",
+		"zoneName": "Alicante",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Almeria",
+		"zoneName": "Almeria",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Asturias",
+		"zoneName": "Asturias",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Avila",
+		"zoneName": "Avila",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Badajoz",
+		"zoneName": "Badajoz",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Baleares",
+		"zoneName": "Baleares",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Barcelona",
+		"zoneName": "Barcelona",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Burgos",
+		"zoneName": "Burgos",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Caceres",
+		"zoneName": "Caceres",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Cadiz",
+		"zoneName": "Cadiz",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Cantabria",
+		"zoneName": "Cantabria",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Castellon",
+		"zoneName": "Castellon",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Ceuta",
+		"zoneName": "Ceuta",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "CiudadReal",
+		"zoneName": "Ciudad Real",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Cordoba",
+		"zoneName": "Cordoba",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Cuenca",
+		"zoneName": "Cuenca",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Girona",
+		"zoneName": "Girona",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Granada",
+		"zoneName": "Granada",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Guadalajara",
+		"zoneName": "Guadalajara",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Guipuzcoa",
+		"zoneName": "Guipuzcoa",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Huelva",
+		"zoneName": "Huelva",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Huesca",
+		"zoneName": "Huesca",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Jaen",
+		"zoneName": "Jaen",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "LaRioja",
+		"zoneName": "La Rioja",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "LasPalmas",
+		"zoneName": "Las Palmas",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Leon",
+		"zoneName": "Leon",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Lleida",
+		"zoneName": "Lleida",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Lugo",
+		"zoneName": "Lugo",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Madrid",
+		"zoneName": "Madrid",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Malaga",
+		"zoneName": "Malaga",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Melilla",
+		"zoneName": "Melilla",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Murcia",
+		"zoneName": "Murcia",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Navarra",
+		"zoneName": "Navarra",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Ourense",
+		"zoneName": "Ourense",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Palencia",
+		"zoneName": "Palencia",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Pontevedra",
+		"zoneName": "Pontevedra",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Salamanca",
+		"zoneName": "Salamanca",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "SantaCruzdeTenerife",
+		"zoneName": "Santa Cruz de Tenerife",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Segovia",
+		"zoneName": "Segovia",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Sevilla",
+		"zoneName": "Sevilla",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Soria",
+		"zoneName": "Soria",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Tarragona",
+		"zoneName": "Tarragona",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Teruel",
+		"zoneName": "Teruel",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Toledo",
+		"zoneName": "Toledo",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Valencia",
+		"zoneName": "Valencia",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Valladolid",
+		"zoneName": "Valladolid",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Vizcaya",
+		"zoneName": "Vizcaya",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Zamora",
+		"zoneName": "Zamora",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode": "Zaragoza",
+		"zoneName": "Zaragoza",
+		"countryCode": "ES"
+	},
+	{
+		"zoneCode":"ACT",
+		"zoneName":"Territoire de la capitale australienne",
+		"countryCode":"AU"
+	},
+	{
+		"zoneCode":"WAAU",
+		"zoneName":"Australie-Occidentale",
+		"countryCode":"AU"
+	},
+	{
+		"zoneCode":"SA",
+		"zoneName":"Australie-Mridionale",
+		"countryCode":"AU"
+	},
+	{
+		"zoneCode":"NTAU",
+		"zoneName":"Territoire du Nord",
+		"countryCode":"AU"
+	},
+	{
+		"zoneCode":"VIC",
+		"zoneName":"Victoria",
+		"countryCode":"AU"
+	},
+	{
+		"zoneCode":"TAS",
+		"zoneName":"Tasmanie",
+		"countryCode":"AU"
+	},
+	{
+		"zoneCode":"QLD",
+		"zoneName":"Queensland",
+		"countryCode":"AU"
+	},
+	{
+		"zoneCode":"NSW",
+		"zoneName":"Nouvelle-Galles du Sud",
+		"countryCode":"AU"
+	}
+
+] 
+}
\ No newline at end of file
diff --git a/sm-core/src/main/resources/search/product.json b/sm-core/src/main/resources/search/product.json
new file mode 100755
index 0000000..0b2704a
--- /dev/null
+++ b/sm-core/src/main/resources/search/product.json
@@ -0,0 +1,15 @@
+{"product_en": {
+						"properties" :  {
+							"name": {"type": "multi_field","fields": {"name_original":{"type":"string","index":"not_analyzed"},"name_searchable":{"type":"string","index":"analyzed","store":"no"}}},
+							"price" : {"type":"string","index":"not_analyzed"},
+							"categories" : {"type":"string","index":"not_analyzed"},
+							"lang" : {"type":"string","index":"not_analyzed"},
+							"store" : {"type":"string","index":"not_analyzed"},
+							"availability" : {"type":"string","index":"not_analyzed"},
+							"manufacturer" : {"type":"string","index":"not_analyzed"},
+							"available" : {"type":"string","index":"not_analyzed"},
+							"description" : {"type":"string","index":"analyzed","index_analyzer":"english"}, 
+							"tags" : {"type":"string","index":"not_analyzed"} 
+						 } 
+			}
+}
\ No newline at end of file
diff --git a/sm-core/src/main/resources/search/product_fr.json b/sm-core/src/main/resources/search/product_fr.json
new file mode 100644
index 0000000..c7171b4
--- /dev/null
+++ b/sm-core/src/main/resources/search/product_fr.json
@@ -0,0 +1,15 @@
+{"product_fr": {
+						"properties" :  {
+							"name": {"type": "multi_field","fields": {"name_original":{"type":"string","index":"not_analyzed"},"name_searchable":{"type":"string","index":"analyzed","store":"no"}}},
+							"price" : {"type":"string","index":"not_analyzed"},
+							"categories" : {"type":"string","index":"not_analyzed"},
+							"lang" : {"type":"string","index":"not_analyzed"},
+							"store" : {"type":"string","index":"not_analyzed"},
+							"availability" : {"type":"string","index":"not_analyzed"},
+							"manufacturer" : {"type":"string","index":"not_analyzed"},
+							"available" : {"type":"string","index":"not_analyzed"},
+							"description" : {"type":"string","index":"analyzed","index_analyzer":"french"}, 
+							"tags" : {"type":"string","index":"not_analyzed"} 
+						 } 
+			}
+}
\ No newline at end of file
diff --git a/sm-core/src/main/resources/search/settings_product.json b/sm-core/src/main/resources/search/settings_product.json
new file mode 100644
index 0000000..452a01e
--- /dev/null
+++ b/sm-core/src/main/resources/search/settings_product.json
@@ -0,0 +1,11 @@
+        {"index": {
+            "analysis": {
+                "analyzer": {
+                    "custom_analyzer": {
+                        "type": "snowball",
+                        "language": "English"
+                    }
+                }
+            }
+        }
+        }
\ No newline at end of file
diff --git a/sm-core/src/main/resources/search/settings_product_fr.json b/sm-core/src/main/resources/search/settings_product_fr.json
new file mode 100644
index 0000000..452a01e
--- /dev/null
+++ b/sm-core/src/main/resources/search/settings_product_fr.json
@@ -0,0 +1,11 @@
+        {"index": {
+            "analysis": {
+                "analyzer": {
+                    "custom_analyzer": {
+                        "type": "snowball",
+                        "language": "English"
+                    }
+                }
+            }
+        }
+        }
\ No newline at end of file
diff --git a/sm-core/src/main/resources/spring/datasource-c3p0.xml b/sm-core/src/main/resources/spring/datasource-c3p0.xml
new file mode 100644
index 0000000..89d2af9
--- /dev/null
+++ b/sm-core/src/main/resources/spring/datasource-c3p0.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
+	
+	<bean id="datasource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
+		p:driverClass="${db.driverClass}" p:jdbcUrl="${db.jdbcUrl}" p:user="${db.user}"
+		p:password="${db.password}" p:initialPoolSize="${db.initialPoolSize}"
+		p:minPoolSize="${db.minPoolSize}" p:maxPoolSize="${db.maxPoolSize}"
+		p:preferredTestQuery="${db.preferredTestQuery}" p:testConnectionOnCheckin="true"
+		p:idleConnectionTestPeriod="300" destroy-method="close" />
+		
+</beans>
diff --git a/sm-core/src/main/resources/spring/shopizer-core-config.xml b/sm-core/src/main/resources/spring/shopizer-core-config.xml
new file mode 100644
index 0000000..6b99f37
--- /dev/null
+++ b/sm-core/src/main/resources/spring/shopizer-core-config.xml
@@ -0,0 +1,35 @@
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
+	xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="
+   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
+   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
+   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
+   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
+
+	
+	
+
+   	<bean id="coreConfiguration" class="com.salesmanager.core.utils.CoreConfiguration">
+		<property name="properties" ref="shopizer-properties"/>
+	</bean>
+	
+	<!-- JDBC User -->
+	<bean id="userService" class="com.salesmanager.core.business.user.service.UserServiceImpl"/>
+	
+	
+	<bean id="secretKey" class="java.lang.String">
+  		<constructor-arg value="${secretKey}"/>
+	</bean>
+	
+	<bean id="applicationContextListenerUtils" class="com.salesmanager.core.utils.ApplicationContextListenerUtils" />
+	
+	<!-- Get the secret key from JNDI -->
+	<!--
+	<jee:jndi-lookup id="secretKey"
+		jndi-name="java:comp/env/secretKey" />	
+	-->
+</beans>
\ No newline at end of file
diff --git a/sm-core/src/main/resources/spring/shopizer-core-ehcache.xml b/sm-core/src/main/resources/spring/shopizer-core-ehcache.xml
new file mode 100644
index 0000000..9178535
--- /dev/null
+++ b/sm-core/src/main/resources/spring/shopizer-core-ehcache.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
+	xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="
+   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
+   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
+   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
+   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
+   http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring http://ehcache-spring-annotations.googlecode.com/svn/schema/ehcache-spring/ehcache-spring-1.2.xsd">
+
+
+	<bean id="springCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
+		<property name="configLocation" value="classpath:/ehcache/smcore-ehcache.xml" />
+		<property name="shared" value="false" />
+	</bean>
+
+	<bean id="serviceCacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
+		<property name="cacheManager">
+			<ref local="springCacheManager" />
+		</property>
+	</bean>
+
+    <bean id="serviceCache" factory-bean="serviceCacheManager" factory-method="getCache">
+        <constructor-arg value="com.shopizer.OBJECT_CACHE" />
+    </bean>
+
+</beans>
\ No newline at end of file
diff --git a/sm-core/src/main/resources/spring/shopizer-core-modules.xml b/sm-core/src/main/resources/spring/shopizer-core-modules.xml
new file mode 100755
index 0000000..3a3dfd6
--- /dev/null
+++ b/sm-core/src/main/resources/spring/shopizer-core-modules.xml
@@ -0,0 +1,239 @@
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
+	xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="
+   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
+   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
+   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
+   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
+
+
+	<!-- Shipping integration modules -->
+	<util:map id="shippingModules" map-class="java.util.HashMap" key-type="java.lang.String" value-type="com.salesmanager.core.modules.integration.shipping.model.ShippingQuoteModule">
+    			<entry key="canadapost" value-ref="canadapost"/>
+    			<entry key="usps" value-ref="usps"/>
+    			<entry key="ups" value-ref="ups"/>
+    			<entry key="weightBased" value-ref="weightBased"/>
+    </util:map>
+    
+    <!-- Payment integration modules -->
+	<util:map id="paymentModules" map-class="java.util.HashMap" key-type="java.lang.String" value-type="com.salesmanager.core.modules.integration.payment.model.PaymentModule">
+    			<entry key="beanstream" value-ref="beanstream"/>
+    			<entry key="paypal-express-checkout" value-ref="paypal-ec"/>
+    			<entry key="moneyorder" value-ref="moneyorder"/>
+    </util:map>
+
+
+	<!-- Shipping -->
+	<bean id="canadapost"
+		class="com.salesmanager.core.modules.integration.shipping.impl.CanadaPostShippingQuote"/>
+	<bean id="usps"
+		class="com.salesmanager.core.modules.integration.shipping.impl.USPSShippingQuote"/>
+	<bean id="ups"
+		class="com.salesmanager.core.modules.integration.shipping.impl.UPSShippingQuote"/>
+	<bean id="weightBased"
+		class="com.salesmanager.core.modules.integration.shipping.impl.CustomWeightBasedShippingQuote"/>
+
+	<!-- Default packaging -->
+	<bean id="boxPackaging"
+		class="com.salesmanager.core.modules.integration.shipping.impl.DefaultPackagingImpl"/>
+	
+	<!-- Payment -->
+	<bean id="beanstream"
+		class="com.salesmanager.core.modules.integration.payment.impl.BeanStreamPayment"/>
+	<bean id="moneyorder"
+		class="com.salesmanager.core.modules.integration.payment.impl.MoneyOrderPayment"/>
+	<bean id="paypal-ec"
+		class="com.salesmanager.core.modules.integration.payment.impl.PayPalExpressCheckoutPayment"/>
+
+	<!--     -->
+	<!-- CMS -->
+	<!--     -->
+	
+	<!-- Product images manager-->
+	<bean id="productFileManager"
+		class="com.salesmanager.core.modules.cms.product.ProductFileManagerImpl">
+		<property name="uploadImage">
+				<ref bean="cmsProductImage" />
+		</property>
+		<property name="getImage">
+				<ref bean="cmsProductImage" />
+		</property>
+		<property name="removeImage">
+				<ref bean="cmsProductImage" />
+		</property>
+		<property name="configuration">
+				<ref bean="coreConfiguration" />
+		</property>
+	</bean>
+	
+	<!-- CMS implementation for product images-->
+	<bean id="cmsProductImage"
+				class="com.salesmanager.core.modules.cms.product.CmsImageFileManagerInfinispanImpl" factory-method="getInstance" >
+				<property name="cacheManager">
+						<ref bean="storeCacheManager" />
+				</property>
+				<property name="rootName" value="product-merchant"/>
+	</bean>
+	
+
+	
+	<!-- Content images manager (logo, other store artifacts)-->
+	<bean id="contentFileManager"
+		class="com.salesmanager.core.modules.cms.content.StaticContentFileManagerImpl">
+		<property name="uploadFile">
+				<ref bean="cmsStoreFile" />
+		</property>
+		<property name="getFile">
+				<ref bean="cmsStoreFile" />
+		</property>
+		<property name="removeFile">
+				<ref bean="cmsStoreFile" />
+		</property>
+	</bean>
+	
+
+	<bean id="cmsStoreFile"
+				class="com.salesmanager.core.modules.cms.content.CmsStaticContentFileManagerInfinispanImpl" factory-method="getInstance" >
+				<property name="cacheManager">
+						<ref bean="storeCacheManager" />
+				</property>
+				<property name="rootName" value="store-merchant"/>
+	</bean>
+	
+	
+
+	
+	<!-- Static content files manager (images, pdf...) -->
+	<bean id="staticContentFileManager"	class="com.salesmanager.core.modules.cms.content.StaticContentFileManagerImpl">
+		<property name="uploadFile">
+				<ref bean="cmsStaticFile" />
+		</property>
+		<property name="getFile">
+			<ref bean="cmsStaticFile" />
+		</property>
+		<property name="removeFile">
+			<ref bean="cmsStaticFile" />
+		</property>
+	</bean>
+	<!--  end of CMS implementation for static content data -->
+	
+	
+	<!-- CMS implementation for static content data -->
+	<bean id="cmsStaticFile" class="com.salesmanager.core.modules.cms.content.CmsStaticContentFileManagerInfinispanImpl" factory-method="getInstance">
+		<property name="cacheManager">
+			<ref bean="filesCacheManager" />
+		</property>
+		<property name="rootName" value="store-merchant"/>
+	</bean>
+	
+	
+	
+	
+	<!-- product downloads -->
+	<bean id="productDownloadsFileManager"	class="com.salesmanager.core.modules.cms.content.StaticContentFileManagerImpl">
+		<property name="uploadFile">
+				<ref bean="cmsProductFile" />
+		</property>
+		<property name="getFile">
+			<ref bean="cmsProductFile" />
+		</property>
+		<property name="removeFile">
+			<ref bean="cmsProductFile" />
+		</property>
+	</bean>
+	<!--  end of CMS implementation for static content data -->
+	
+	
+	<!-- CMS implementation for static content data -->
+	<bean id="cmsProductFile" class="com.salesmanager.core.modules.cms.content.CmsStaticContentFileManagerInfinispanImpl" factory-method="getInstance">
+		<property name="cacheManager">
+			<ref bean="storeCacheManager" />
+		</property>
+		<property name="rootName" value="product-file"/>
+	</bean>
+	
+	
+
+	
+	<!-- Store Cache Manager -->
+	<bean id="storeCacheManager"
+				class="com.salesmanager.core.modules.cms.impl.StoreCacheManagerImpl" factory-method="getInstance" >
+	</bean>
+	
+	<!-- Invoice -->
+	<bean id="invoiceModule"
+				class="com.salesmanager.core.modules.order.ODSInvoiceModule" >
+	</bean>
+
+	
+	<!-- 
+	 Cache manager to handle static content data which includes
+	 1. CSS Files
+	 2. JS Files
+	 2. Digital data
+	 -->
+	 
+	<bean id="filesCacheManager" 
+		class="com.salesmanager.core.modules.cms.impl.StaticContentCacheManagerImpl" factory-method="getInstance" >
+	</bean>
+	
+	<!-- Encryption -->
+	<bean id="encryption"
+		class="com.salesmanager.core.modules.utils.EncryptionImpl">
+		<property name="secretKey" ref="secretKey"/>
+	</bean>
+	
+	<!-- Geo Location -->
+	<bean id="geoLocation"
+		class="com.salesmanager.core.modules.utils.GeoLocationImpl">
+	</bean>
+	
+	<!-- Email -->
+	<bean id="freemarkerMailConfiguration" class="org.springframework.ui.freemarker.FreeMarkerConfigurationFactoryBean">
+                 <!-- Uses HTML with templates and freemarker template engine -->
+                 <property name="templateLoaderPath" value="/templates/email"/>
+    </bean>
+
+
+	<bean id="mailSender"
+		class="org.springframework.mail.javamail.JavaMailSenderImpl">
+
+		<!-- configured in systems.properties -->
+		<property name="protocol" value="${mailSender.protocol}" />
+		<property name="host" value="${mailSender.host}" />
+		<property name="port" value="${mailSender.port}" />
+
+		<property name="username">
+			<value>${mailSender.username}</value>
+		</property>
+
+		<property name="password">
+			<value>${mailSender.password}</value>
+		</property>
+		<property name="javaMailProperties">
+			<props>
+				<prop key="mail.smtp.auth">${mailSender.mail.smtp.auth}</prop>
+				<prop key="mail.smtp.starttls.enable">${mail.smtp.starttls.enable}</prop>
+			</props>
+		</property>
+	</bean>
+	
+	<bean id="htmlEmailSender" class="com.salesmanager.core.modules.email.HtmlEmailSenderImpl" >
+             <property name="mailSender" ref="mailSender"/>
+             <property name="freemarkerMailConfiguration" ref="freemarkerMailConfiguration"/>
+ 	</bean>
+ 
+	
+ 
+ 
+ 
+	
+ 
+
+	
+	
+</beans>
\ No newline at end of file
diff --git a/sm-core/src/main/resources/spring/shopizer-search.xml b/sm-core/src/main/resources/spring/shopizer-search.xml
new file mode 100755
index 0000000..63027f1
--- /dev/null
+++ b/sm-core/src/main/resources/spring/shopizer-search.xml
@@ -0,0 +1,184 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
+
+	<!-- can have different search client for indexing & searching -->
+	<bean id="searchClient" class="com.shopizer.search.utils.SearchClient">
+		<property name="serverConfiguration">
+				<ref bean="serverConfiguration" />
+		</property>
+	</bean>
+	
+	<!-- Server configuration -->
+	<bean id="serverConfiguration" class="com.shopizer.search.utils.ServerConfiguration">
+		<property name="clusterName" value="shopizer"/>
+		<!-- local (embedded version, will create new indexes in the working directory) or remote (requires existing server) -->
+		<property name="mode" value="local"/>
+		<!-- those properties are used when configured for remote -->
+		<property name="clusterHost" value="127.0.0.1"/>
+		<property name="clusterPort" value="9300"/>
+	</bean>
+	
+	<bean id="searchDelegate" class="com.shopizer.search.services.impl.SearchDelegateImpl">
+		<property name="searchClient">
+				<ref bean="searchClient" />
+		</property>
+	</bean>
+
+
+	<!--
+	This file contains flow definitions for indexing and searching
+	-->
+	
+	<bean id="searchService" class="com.shopizer.search.services.SearchService"/>
+
+
+	
+	<bean id="searchWorkflow" class="com.shopizer.search.services.workflow.SearchWorkflow">
+		<property name="searchFlow">
+			<list>
+				<bean id="search" class="com.shopizer.search.services.worker.SearchWorkerImpl"/>
+			</list>
+		</property>
+		<property name="searchKeywordWorkflow">
+			<list>
+				<bean id="searchKeyword" class="com.shopizer.search.services.worker.KeywordSearchWorkerImpl"/>
+			</list>
+		</property>
+		<property name="searchClient">
+				<ref bean="searchClient" />
+		</property>
+	</bean>
+
+	<bean id="indexWorkflow" class="com.shopizer.search.services.workflow.IndexWorkflow">
+		<property name="indexWorkflow">
+			<list>
+				<ref bean="index" />
+				<ref bean="keyword" />
+			</list>
+		</property>
+		<property name="searchClient">
+				<ref bean="searchClient" />
+		</property>
+	</bean>
+	
+	<bean id="deleteWorkflow" class="com.shopizer.search.services.workflow.DeleteObjectWorkflow">
+		<property name="deleteObjectWorkflow">
+			<list>
+				<bean id="deleteObject" class="com.shopizer.search.services.worker.DeleteObjectImpl"/>
+				<ref bean="deleteKeywords" />
+			</list>
+		</property>
+		<property name="searchClient">
+				<ref bean="searchClient" />
+		</property>
+	</bean>
+	
+	<!--<bean id="getWorkflow" class="com.shopizer.search.services.workflow.SearchWorkflow">-->
+	<bean id="getWorkflow" class="com.shopizer.search.services.workflow.GetWorkflow">
+		<property name="searchClient">
+				<ref bean="searchClient" />
+		</property>
+	</bean>
+	
+	<bean id="deleteKeywords" class="com.shopizer.search.services.worker.DeleteKeywordsImpl">
+		<property name="indexConfigurations">
+			<list>
+				<ref bean="keywordindex_en" />
+				<ref bean="keywordindex_fr" />
+			</list>
+		</property>
+	</bean>
+	
+	<bean id="index" class="com.shopizer.search.services.worker.ObjectIndexerImpl">
+		<property name="indexConfigurations">
+			<list>
+				<ref bean="productindex_en_defaultstore" />
+				<ref bean="productindex_fr_defaultstore" />
+			</list>
+		</property>
+	</bean>
+	
+
+	
+	<!-- The presence of those properties will allow the creation of mapping files -->
+	<bean id="productindex_en_defaultstore" class="com.shopizer.search.utils.IndexConfiguration">
+		<property name="collectionName" value="product_en_default"/>
+		<property name="indexName" value="product_en"/>
+		<property name="mappingFileName" value="search/product.json"/>
+		<property name="settingsFileName" value="search/settings_product.json"/>
+	</bean>
+	
+	<bean id="productindex_fr_defaultstore" class="com.shopizer.search.utils.IndexConfiguration">
+		<property name="collectionName" value="product_fr_default"/>
+		<property name="indexName" value="product_fr"/>
+		<property name="mappingFileName" value="search/product_fr.json"/>
+		<property name="settingsFileName" value="search/settings_product_fr.json"/>
+	</bean>
+		
+	<bean id="keyword" class="com.shopizer.search.services.worker.KeywordIndexerImpl">
+		<property name="indexConfigurations">
+			<list>
+				<ref bean="keywordindex_en" />
+				<ref bean="keywordindex_fr" />
+			</list>
+		</property>
+	</bean>
+	
+	<bean id="keywordindex_en" class="com.shopizer.search.utils.CustomIndexConfiguration">
+		<property name="collectionName" value="keyword_en_%store%"/>
+		<property name="createOnIndexName" value="product_en"/>
+		<property name="fields">
+			<list>
+				<ref bean="field1" />
+				<ref bean="field2" />
+			</list>
+		</property>
+		<!-- NO FILTERS
+		<property name="filters">
+			<list>
+				<ref bean="filter1" />
+			</list>
+		</property>
+		 -->
+	</bean>
+
+
+	<bean id="keywordindex_fr" class="com.shopizer.search.utils.CustomIndexConfiguration">
+		<property name="collectionName" value="keyword_fr_%store%"/>
+		<property name="createOnIndexName" value="product_fr"/>
+		<property name="fields">
+			<list>
+				<ref bean="field1" />
+				<ref bean="field2" />
+			</list>
+		</property>
+		<!-- NO FILTERS
+		<property name="filters">
+			<list>
+				<ref bean="filter1" />
+			</list>
+		</property>
+		-->
+	</bean>	
+	
+	
+	<!-- supported field types List, Integer, Double, Boolean, String -->
+	<bean id="field1" class="com.shopizer.search.utils.CustomIndexFieldConfiguration">
+		<property name="fieldName" value="tags"/>
+		<property name="fieldType" value="List"/>
+	</bean>
+	<bean id="field2" class="com.shopizer.search.utils.CustomIndexFieldConfiguration">
+		<property name="fieldName" value="name"/>
+		<property name="fieldType" value="String"/>
+	</bean>
+	<!--
+	<bean id="filter1" class="com.shopizer.search.utils.CustomIndexFieldConfiguration">
+		<property name="fieldName" value="price"/>
+		<property name="fieldType" value="Double"/>
+	</bean>
+	-->
+
+</beans>
\ No newline at end of file
diff --git a/sm-core/src/main/resources/spring/spring-context.xml b/sm-core/src/main/resources/spring/spring-context.xml
new file mode 100644
index 0000000..bc05b2a
--- /dev/null
+++ b/sm-core/src/main/resources/spring/spring-context.xml
@@ -0,0 +1,120 @@
+<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:aop="http://www.springframework.org/schema/aop"
+	xmlns:context="http://www.springframework.org/schema/context" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="
+   http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
+   http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
+   http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
+   http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
+   http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
+   http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
+   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
+
+	<context:annotation-config />
+	<context:component-scan base-package="com.salesmanager.core.business" />
+	<context:component-scan base-package="com.salesmanager.core.utils" />
+	<context:component-scan base-package="com.salesmanager.core.modules" />
+
+	<!-- datasource -->
+	<import resource="classpath:/spring/datasource-c3p0.xml" />
+	<!-- cache -->
+	<import resource="classpath:/spring/shopizer-core-ehcache.xml" />
+	<!-- properties -->
+	<import resource="classpath:/spring/shopizer-core-config.xml" />
+	<!-- modules -->
+	<import resource="classpath:/spring/shopizer-core-modules.xml" />
+	<!-- search -->
+	<import resource="classpath:/spring/shopizer-search.xml" />
+
+	<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
+		<property name="persistenceUnitName" value="sm-unit" />
+		<property name="dataSource" ref="datasource" />
+		<property name="persistenceXmlLocation" value="classpath:META-INF/sm-persistence.xml" />
+		
+		<!--
+		<property name="namingStrategy">
+      		<bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
+    	</property>
+    	-->
+		
+
+		<property name="jpaVendorAdapter">
+			<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
+				<property name="showSql" value="true" />
+				<property name="generateDdl" value="false" />
+				<property name="databasePlatform" value="${hibernate.dialect}" />
+			</bean>
+		</property>
+		<property name="jpaProperties">
+			<util:map>
+				<entry key="hibernate.default_schema" value="${db.schema}" />
+				<entry key="hibernate.hbm2ddl.auto" value="${hibernate.hbm2ddl.auto}" />
+				<entry key="hibernate.show_sql" value="true" />
+				<entry key="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
+				<entry key="hibernate.cache.use_second_level_cache" value="true" />
+			</util:map>
+		</property>
+
+		<property name="loadTimeWeaver">
+			<bean class="org.springframework.instrument.classloading.InstrumentationLoadTimeWeaver" />
+		</property>
+	</bean>
+
+	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
+
+	
+	
+	<!-- MBeans statistics [disable in production] only one definition per web app-->
+<!-- 	<bean id="jmxExporter" class="org.springframework.jmx.export.MBeanExporter">
+	    <property name="beans">
+	        <map>
+	            <entry key="Hibernate:application=Statistics" value-ref="hibernateStatisticsBean"/>
+	        </map>
+	    </property>
+	</bean>
+
+	<bean id="hibernateStatisticsBean" class="org.hibernate.jmx.StatisticsService">
+	    <property name="statisticsEnabled" value="true"/>
+	    <property name="sessionFactory">
+	        <util:property-path path="entityManagerFactory.sessionFactory" />
+	    </property>
+	</bean> -->
+	
+
+	<!-- Définition de la gestion des transactions -->
+	<tx:annotation-driven />
+	<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"
+		p:entityManagerFactory-ref="entityManagerFactory">
+	</bean>
+
+ 	<aop:config>
+		<aop:pointcut id="txPointCutDef" expression="this(com.salesmanager.core.business.generic.service.TransactionalAspectAwareService)" />
+		<aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCutDef" />
+	</aop:config>
+
+	<tx:advice id="txAdvice" transaction-manager="transactionManager">
+		<tx:attributes>
+			<tx:method name="get*" read-only="true" />
+			<tx:method name="list*" read-only="true" />
+			<tx:method name="search*" read-only="true" />
+			<tx:method name="*" read-only="false" rollback-for="com.salesmanager.core.business.generic.exception.ServiceException" />
+		</tx:attributes>
+	</tx:advice> 
+
+	<!-- traduction des exceptions -->
+	<bean class="org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor" />
+
+	<!-- persistence -->
+	<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
+
+	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
+		<property name="ignoreUnresolvablePlaceholders" value="false"/>
+		<property name="locations">
+			<list>
+		    	<value>classpath:database.properties</value>
+				<value>classpath:email.properties</value>
+				<value>classpath:configs.properties</value>
+			</list>
+		</property>
+	</bean>
+</beans>
\ No newline at end of file
diff --git a/sm-core/src/main/resources/templates/email/email_template_checkout.ftl b/sm-core/src/main/resources/templates/email/email_template_checkout.ftl
new file mode 100644
index 0000000..0a17d7f
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_checkout.ftl
@@ -0,0 +1,417 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html>
+<head>
+<!-- If you delete this meta tag, Earth will fall into the sun. -->
+<meta name="viewport" content="width=device-width" />
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title></title>
+	
+<style type="text/css">
+
+/* ------------------------------------- 
+		GLOBAL 
+------------------------------------- */
+* { 
+	margin:0;
+	padding:0;
+}
+* { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; }
+
+img { 
+	max-width: 100%; 
+}
+.collapse {
+	margin:0;
+	padding:0;
+}
+body {
+	-webkit-font-smoothing:antialiased; 
+	-webkit-text-size-adjust:none; 
+	width: 100%!important; 
+	height: 100%;
+}
+
+
+/* ------------------------------------- 
+		ELEMENTS 
+------------------------------------- */
+a { color: #2BA6CB;}
+
+.btn {
+	text-decoration:none;
+	color: #FFF;
+	background-color: #666;
+	padding:10px 16px;
+	font-weight:bold;
+	margin-right:10px;
+	text-align:center;
+	cursor:pointer;
+	display: inline-block;
+}
+
+p.callout {
+	padding:15px;
+	background-color:#ECF8FF;
+	margin-bottom: 15px;
+}
+.callout a {
+	font-weight:bold;
+	color: #2BA6CB;
+}
+
+table.social {
+/* 	padding:15px; */
+	background-color: #ebebeb;
+	
+}
+.social .soc-btn {
+	padding: 3px 7px;
+	font-size:12px;
+	margin-bottom:10px;
+	text-decoration:none;
+	color: #FFF;font-weight:bold;
+	display:block;
+	text-align:center;
+}
+a.fb { background-color: #3B5998!important; }
+a.tw { background-color: #1daced!important; }
+a.gp { background-color: #DB4A39!important; }
+a.ms { background-color: #000!important; }
+
+.sidebar .soc-btn { 
+	display:block;
+	width:100%;
+}
+
+/* ------------------------------------- 
+		HEADER 
+------------------------------------- */
+table.head-wrap { width: 100%;}
+
+.header.container table td.logo { padding: 2px; }
+.header.container table td.label { padding: 10fpx; padding-left:0px;}
+
+
+/* ------------------------------------- 
+		BODY 
+------------------------------------- */
+table.body-wrap { width: 100%;}
+
+
+/* ------------------------------------- 
+		FOOTER 
+------------------------------------- */
+table.footer-wrap { width: 100%;	clear:both!important;
+}
+.footer-wrap .container td.content  p { border-top: 1px solid rgb(215,215,215); padding-top:15px;}
+.footer-wrap .container td.content p {
+	font-size:10px;
+	font-weight: bold;
+	
+}
+
+
+/* ------------------------------------- 
+		TYPOGRAPHY 
+------------------------------------- */
+h1,h2,h3,h4,h5,h6 {
+font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; line-height: 1.1; margin-bottom:15px; color:#000;
+}
+h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 60%; color: #6f6f6f; line-height: 0; text-transform: none; }
+
+h1 { font-weight:200; font-size: 44px;}
+h2 { font-weight:200; font-size: 37px;}
+h3 { font-weight:500; font-size: 27px;}
+h4 { font-weight:500; font-size: 23px;}
+h5 { font-weight:900; font-size: 17px;}
+h6 { font-weight:900; font-size: 14px; text-transform: uppercase; color:#444;}
+
+.collapse { margin:0!important;}
+
+p, ul { 
+	margin-bottom: 10px; 
+	font-weight: normal; 
+	font-size:14px; 
+	line-height:1.6;
+}
+p.lead { font-size:17px; }
+p.last { margin-bottom:0px;}
+
+ul li {
+	margin-left:5px;
+	list-style-position: inside;
+}
+
+/* ------------------------------------- 
+		SIDEBAR 
+------------------------------------- */
+ul.sidebar {
+	display:block;
+	list-style-type: none;
+}
+ul.sidebar li { display: block; margin:0;}
+ul.sidebar li a {
+	text-decoration:none;
+	color: #666;
+	padding:10px 16px;
+/* 	font-weight:bold; */
+	margin-right:10px;
+/* 	text-align:center; */
+	cursor:pointer;
+/**	border-bottom: 1px solid #777777;**/
+/**	border-top: 1px solid #FFFFFF;**/
+	display:block;
+	margin:0;
+}
+ul.sidebar li a.last { border-bottom-width:0px;}
+ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.sidebar li a h5,ul.sidebar li a h6,ul.sidebar li a p { margin-bottom:0!important;}
+
+
+
+/* --------------------------------------------------- 
+		RESPONSIVENESS
+		Nuke it from orbit. It's the only way to be sure. 
+------------------------------------------------------ */
+
+/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
+.container {
+	display:block!important;
+	max-width:600px!important;
+	margin:0 auto!important; /* makes it centered */
+	clear:both!important;
+}
+
+/* This should also be a block element, so that it will fill 100% of the .container */
+.content {
+	padding:15px;
+	max-width:600px;
+	margin:0 auto;
+	display:block; 
+}
+
+/* Let's make sure tables in the content area are 100% wide */
+.content table { width: 100%; }
+
+
+/* Odds and ends */
+.column {
+	width: 300px;
+	float:left;
+}
+.column tr td { padding: 15px; }
+.column-wrap { 
+	padding:0!important; 
+	margin:0 auto; 
+	max-width:600px!important;
+}
+.column table { width:100%;}
+.social .column {
+	width: 280px;
+	min-width: 279px;
+	float:left;
+}
+
+/* Be sure to place a .clear element after each set of columns, just to be safe */
+.clear { display: block; clear: both; }
+
+.border {border:1px solid}
+
+/* ------------------------------------------- 
+		PHONE
+		For clients that support media queries.
+		Nothing fancy. 
+-------------------------------------------- */
+@media only screen and (max-width: 600px) {
+	
+	a[class="btn"] { display:block!important; margin-bottom:10px!important; background-image:none!important; margin-right:0!important;}
+
+	div[class="column"] { width: auto!important; float:none!important;}
+	
+	table.social div[class="column"] {
+		width:auto!important;
+	}
+
+}
+
+</style>
+
+</head>
+ 
+<body bgcolor="#FFFFFF" topmargin="0" leftmargin="0" marginheight="0" marginwidth="0">
+
+<!-- HEADER -->
+<table class="head-wrap">
+	<tr>
+		<td></td>
+		<td class="header container" >
+				
+				<p>
+				<table>
+					<tr>
+						<td>
+							${LOGOPATH}
+						</td>
+					</tr>
+				</table>
+				</p>
+				
+		</td>
+		<td></td>
+	</tr>
+</table>
+<!-- /HEADER -->
+
+<!-- BODY -->
+<table class="body-wrap">
+
+	<tr>
+		<td colspan="2">
+			<div class="content">
+			<table>
+				<tr>
+					<td>
+						<h4>${LABEL_HI} ${EMAIL_CUSTOMER_FIRSTNAME} ${EMAIL_CUSTOMER_LASTNAME}<br/></h4>
+						<p class="lead">
+							${EMAIL_ORDER_NUMBER}
+						</p>
+						<br>
+						<p>
+							${EMAIL_ORDER_DATE}<br/>
+							${EMAIL_ORDER_THANKS}
+						</p>
+					</td>
+				</tr>
+			</table>
+			</div><!-- /content -->
+		</td>
+	</tr>
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+			
+				
+						<p>
+							<h4>${EMAIL_ORDER_DETAILS_TITLE}</h4> 
+						</p>
+						<p>
+							${ORDER_PRODUCTS_DETAILS}
+						</p>
+		</td>
+		<td></td>
+	</tr>
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+
+				<table>
+				<tr>
+					<td valign="top">											
+						<ul class="sidebar">
+							<li>
+								<a>
+									<h5>${ADDRESS_BILLING_TITLE} &raquo;</h5>
+									<p>
+										${ADDRESS_BILLING}
+									</p>
+								</a>
+							</li>
+						  </ul>
+					  </td>
+					  <td valign="top">											
+						<ul class="sidebar">
+							<li>
+								<a>
+									<h5>${ADDRESS_DELIVERY_TITLE} &raquo;</h5>
+									<p>
+										${ADDRESS_DELIVERY}
+									</p>
+								</a>
+							</li>
+						  </ul>
+					  </td>
+				</tr>
+				<tr>
+					<td>
+						<ul class="sidebar">
+							<li>
+								<a>
+								<strong>${PAYMENT_METHOD_TITLE}</strong><br>
+								${PAYMENT_METHOD_DETAILS}
+								</a>
+							</li>
+
+						</ul>
+					</td>
+					<td>
+						<ul class="sidebar">
+							<li>
+								<a>
+								<strong>${SHIPPING_METHOD_TITLE}</strong><br>
+								${SHIPPING_METHOD_DETAILS}
+								</a>
+							</li>
+						</ul>
+					</td>
+				</tr>
+				</table>
+				<div class="clear"></div>
+				
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /BODY -->
+
+<table class="body-wrap">
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+			<div class="content">
+						<!-- Callout Panel -->
+						<p class="callout">
+							${ORDER_STATUS}
+						</p><!-- /Callout Panel -->
+			</div>
+		</td>
+		<td></td>
+	</tr>
+</table>
+
+<!-- FOOTER -->
+<table class="footer-wrap">
+	<tr>
+		<td></td>
+		<td class="container">
+			
+				<!-- content -->
+				<div class="content">
+				<p>
+				<table>
+				<tr>
+					<td align="center">
+						<p>
+							${EMAIL_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_SPAM_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_FOOTER_COPYRIGHT}
+						</p>
+					</td>
+				</tr>
+				</table>
+				</p>
+				</div><!-- /content -->
+				
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /FOOTER -->
+
+</body>
+</html>
+
+
+
+
diff --git a/sm-core/src/main/resources/templates/email/email_template_checkout_download.ftl b/sm-core/src/main/resources/templates/email/email_template_checkout_download.ftl
new file mode 100644
index 0000000..69de9d4
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_checkout_download.ftl
@@ -0,0 +1,329 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<!-- If you delete this meta tag, Half Life 3 will never be released. -->
+<meta name="viewport" content="width=device-width" />
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title></title>
+
+<style type="text/css">
+
+
+/* ------------------------------------- 
+		GLOBAL 
+------------------------------------- */
+* { 
+	margin:0;
+	padding:0;
+}
+* { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; }
+
+img { 
+	max-width: 100%; 
+}
+.collapse {
+	margin:0;
+	padding:0;
+}
+body {
+	-webkit-font-smoothing:antialiased; 
+	-webkit-text-size-adjust:none; 
+	width: 100%!important; 
+	height: 100%;
+}
+
+
+/* ------------------------------------- 
+		ELEMENTS 
+------------------------------------- */
+a { color: #2BA6CB;}
+
+.btn {
+	text-decoration:none;
+	color: #FFF;
+	background-color: #666;
+	padding:10px 16px;
+	font-weight:bold;
+	margin-right:10px;
+	text-align:center;
+	cursor:pointer;
+	display: inline-block;
+}
+
+p.callout {
+	padding:15px;
+	background-color:#ECF8FF;
+	margin-bottom: 15px;
+}
+.callout a {
+	font-weight:bold;
+	color: #2BA6CB;
+}
+
+table.social {
+/* 	padding:15px; */
+	background-color: #ebebeb;
+	
+}
+.social .soc-btn {
+	padding: 3px 7px;
+	font-size:12px;
+	margin-bottom:10px;
+	text-decoration:none;
+	color: #FFF;font-weight:bold;
+	display:block;
+	text-align:center;
+}
+a.fb { background-color: #3B5998!important; }
+a.tw { background-color: #1daced!important; }
+a.gp { background-color: #DB4A39!important; }
+a.ms { background-color: #000!important; }
+
+.sidebar .soc-btn { 
+	display:block;
+	width:100%;
+}
+
+/* ------------------------------------- 
+		HEADER 
+------------------------------------- */
+table.head-wrap { width: 100%;}
+
+.header.container table td.logo { padding: 15px; }
+.header.container table td.label { padding: 15px; padding-left:0px;}
+
+
+/* ------------------------------------- 
+		BODY 
+------------------------------------- */
+table.body-wrap { width: 100%;}
+
+
+/* ------------------------------------- 
+		FOOTER 
+------------------------------------- */
+table.footer-wrap { width: 100%;	clear:both!important;
+}
+.footer-wrap .container td.content  p { border-top: 1px solid rgb(215,215,215); padding-top:15px;}
+.footer-wrap .container td.content p {
+	font-size:10px;
+	font-weight: bold;
+	
+}
+
+
+/* ------------------------------------- 
+		TYPOGRAPHY 
+------------------------------------- */
+h1,h2,h3,h4,h5,h6 {
+font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; line-height: 1.1; margin-bottom:15px; color:#000;
+}
+h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 60%; color: #6f6f6f; line-height: 0; text-transform: none; }
+
+h1 { font-weight:200; font-size: 44px;}
+h2 { font-weight:200; font-size: 37px;}
+h3 { font-weight:500; font-size: 27px;}
+h4 { font-weight:500; font-size: 23px;}
+h5 { font-weight:900; font-size: 17px;}
+h6 { font-weight:900; font-size: 14px; text-transform: uppercase; color:#444;}
+
+.collapse { margin:0!important;}
+
+p, ul { 
+	margin-bottom: 10px; 
+	font-weight: normal; 
+	font-size:14px; 
+	line-height:1.6;
+}
+p.lead { font-size:17px; }
+p.last { margin-bottom:0px;}
+
+ul li {
+	margin-left:5px;
+	list-style-position: inside;
+}
+
+/* ------------------------------------- 
+		SIDEBAR 
+------------------------------------- */
+ul.sidebar {
+	background:#ebebeb;
+	display:block;
+	list-style-type: none;
+}
+ul.sidebar li { display: block; margin:0;}
+ul.sidebar li a {
+	text-decoration:none;
+	color: #666;
+	padding:10px 16px;
+/* 	font-weight:bold; */
+	margin-right:10px;
+/* 	text-align:center; */
+	cursor:pointer;
+	border-bottom: 1px solid #777777;
+	border-top: 1px solid #FFFFFF;
+	display:block;
+	margin:0;
+}
+ul.sidebar li a.last { border-bottom-width:0px;}
+ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.sidebar li a h5,ul.sidebar li a h6,ul.sidebar li a p { margin-bottom:0!important;}
+
+
+
+/* --------------------------------------------------- 
+		RESPONSIVENESS
+		Nuke it from orbit. It's the only way to be sure. 
+------------------------------------------------------ */
+
+/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
+.container {
+	display:block!important;
+	max-width:600px!important;
+	margin:0 auto!important; /* makes it centered */
+	clear:both!important;
+}
+
+/* This should also be a block element, so that it will fill 100% of the .container */
+.content {
+	padding:15px;
+	max-width:600px;
+	margin:0 auto;
+	display:block; 
+}
+
+/* Let's make sure tables in the content area are 100% wide */
+.content table { width: 100%; }
+
+
+/* Odds and ends */
+.column {
+	width: 300px;
+	float:left;
+}
+.column tr td { padding: 15px; }
+.column-wrap { 
+	padding:0!important; 
+	margin:0 auto; 
+	max-width:600px!important;
+}
+.column table { width:100%;}
+.social .column {
+	width: 280px;
+	min-width: 279px;
+	float:left;
+}
+
+/* Be sure to place a .clear element after each set of columns, just to be safe */
+.clear { display: block; clear: both; }
+
+
+/* ------------------------------------------- 
+		PHONE
+		For clients that support media queries.
+		Nothing fancy. 
+-------------------------------------------- */
+@media only screen and (max-width: 600px) {
+	
+	a[class="btn"] { display:block!important; margin-bottom:10px!important; background-image:none!important; margin-right:0!important;}
+
+	div[class="column"] { width: auto!important; float:none!important;}
+	
+	table.social div[class="column"] {
+		width:auto!important;
+	}
+
+}
+
+</style>
+
+</head>
+<body bgcolor="#FFFFFF">
+
+<!-- HEADER -->
+<table class="head-wrap">
+	<tr>
+		<td></td>
+		<td class="header container" >
+				
+				<p>
+				<table>
+					<tr>
+						<td>
+							<h3>${LOGOPATH}</h3>
+						</td>
+					</tr>
+				</table>
+				</p>
+				
+		</td>
+		<td></td>
+	</tr>
+</table>
+<!-- /HEADER -->
+
+
+<!-- BODY -->
+<table class="body-wrap">
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+
+			<div class="content">
+			<table>
+				<tr>
+					<td>
+						<h4>${LABEL_HI} ${EMAIL_CUSTOMER_FIRSTNAME} ${EMAIL_CUSTOMER_LASTNAME}<br/></h4>
+						<p class="lead">
+							${EMAIL_ORDER_DOWNLOAD}
+						</p>
+						<!-- Callout Panel -->
+						<p class="callout">
+							${CUSTOMER_ACCESS_LABEL}&nbsp;<a href="${CUSTOMER_ACCESS_URL}">${ACCESS_NOW_LABEL} &raquo;</a>
+						</p><!-- /Callout Panel -->					
+												
+
+					</td>
+				</tr>
+			</table>
+			</div><!-- /content -->
+									
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /BODY -->
+
+<!-- FOOTER -->
+<table class="footer-wrap">
+	<tr>
+		<td></td>
+		<td class="container">
+			
+				<!-- content -->
+				<div class="content">
+				<p>
+				<table>
+				<tr>
+					<td align="center">
+						<p>
+							${EMAIL_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_SPAM_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_FOOTER_COPYRIGHT}
+						</p>
+					</td>
+				</tr>
+				</table>
+				</p>
+				</div><!-- /content -->
+				
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /FOOTER -->
+
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_contact.ftl b/sm-core/src/main/resources/templates/email/email_template_contact.ftl
new file mode 100644
index 0000000..816b793
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_contact.ftl
@@ -0,0 +1,333 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<!-- If you delete this meta tag, Half Life 3 will never be released. -->
+<meta name="viewport" content="width=device-width" />
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title></title>
+
+<style type="text/css">
+
+
+/* ------------------------------------- 
+		GLOBAL 
+------------------------------------- */
+* { 
+	margin:0;
+	padding:0;
+}
+* { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; }
+
+img { 
+	max-width: 100%; 
+}
+.collapse {
+	margin:0;
+	padding:0;
+}
+body {
+	-webkit-font-smoothing:antialiased; 
+	-webkit-text-size-adjust:none; 
+	width: 100%!important; 
+	height: 100%;
+}
+
+
+/* ------------------------------------- 
+		ELEMENTS 
+------------------------------------- */
+a { color: #2BA6CB;}
+
+.btn {
+	text-decoration:none;
+	color: #FFF;
+	background-color: #666;
+	padding:10px 16px;
+	font-weight:bold;
+	margin-right:10px;
+	text-align:center;
+	cursor:pointer;
+	display: inline-block;
+}
+
+p.callout {
+	padding:15px;
+	background-color:#ECF8FF;
+	margin-bottom: 15px;
+}
+.callout a {
+	font-weight:bold;
+	color: #2BA6CB;
+}
+
+table.social {
+/* 	padding:15px; */
+	background-color: #ebebeb;
+	
+}
+.social .soc-btn {
+	padding: 3px 7px;
+	font-size:12px;
+	margin-bottom:10px;
+	text-decoration:none;
+	color: #FFF;font-weight:bold;
+	display:block;
+	text-align:center;
+}
+a.fb { background-color: #3B5998!important; }
+a.tw { background-color: #1daced!important; }
+a.gp { background-color: #DB4A39!important; }
+a.ms { background-color: #000!important; }
+
+.sidebar .soc-btn { 
+	display:block;
+	width:100%;
+}
+
+/* ------------------------------------- 
+		HEADER 
+------------------------------------- */
+table.head-wrap { width: 100%;}
+
+.header.container table td.logo { padding: 15px; }
+.header.container table td.label { padding: 15px; padding-left:0px;}
+
+
+/* ------------------------------------- 
+		BODY 
+------------------------------------- */
+table.body-wrap { width: 100%;}
+
+
+/* ------------------------------------- 
+		FOOTER 
+------------------------------------- */
+table.footer-wrap { width: 100%;	clear:both!important;
+}
+.footer-wrap .container td.content  p { border-top: 1px solid rgb(215,215,215); padding-top:15px;}
+.footer-wrap .container td.content p {
+	font-size:10px;
+	font-weight: bold;
+	
+}
+
+
+/* ------------------------------------- 
+		TYPOGRAPHY 
+------------------------------------- */
+h1,h2,h3,h4,h5,h6 {
+font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; line-height: 1.1; margin-bottom:15px; color:#000;
+}
+h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 60%; color: #6f6f6f; line-height: 0; text-transform: none; }
+
+h1 { font-weight:200; font-size: 44px;}
+h2 { font-weight:200; font-size: 37px;}
+h3 { font-weight:500; font-size: 27px;}
+h4 { font-weight:500; font-size: 23px;}
+h5 { font-weight:900; font-size: 17px;}
+h6 { font-weight:900; font-size: 14px; text-transform: uppercase; color:#444;}
+
+.collapse { margin:0!important;}
+
+p, ul { 
+	margin-bottom: 10px; 
+	font-weight: normal; 
+	font-size:14px; 
+	line-height:1.6;
+}
+p.lead { font-size:17px; }
+p.last { margin-bottom:0px;}
+
+ul li {
+	margin-left:5px;
+	list-style-position: inside;
+}
+
+/* ------------------------------------- 
+		SIDEBAR 
+------------------------------------- */
+ul.sidebar {
+	background:#ebebeb;
+	display:block;
+	list-style-type: none;
+}
+ul.sidebar li { display: block; margin:0;}
+ul.sidebar li a {
+	text-decoration:none;
+	color: #666;
+	padding:10px 16px;
+/* 	font-weight:bold; */
+	margin-right:10px;
+/* 	text-align:center; */
+	cursor:pointer;
+	border-bottom: 1px solid #777777;
+	border-top: 1px solid #FFFFFF;
+	display:block;
+	margin:0;
+}
+ul.sidebar li a.last { border-bottom-width:0px;}
+ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.sidebar li a h5,ul.sidebar li a h6,ul.sidebar li a p { margin-bottom:0!important;}
+
+
+
+/* --------------------------------------------------- 
+		RESPONSIVENESS
+		Nuke it from orbit. It's the only way to be sure. 
+------------------------------------------------------ */
+
+/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
+.container {
+	display:block!important;
+	max-width:600px!important;
+	margin:0 auto!important; /* makes it centered */
+	clear:both!important;
+}
+
+/* This should also be a block element, so that it will fill 100% of the .container */
+.content {
+	padding:15px;
+	max-width:600px;
+	margin:0 auto;
+	display:block; 
+}
+
+/* Let's make sure tables in the content area are 100% wide */
+.content table { width: 100%; }
+
+
+/* Odds and ends */
+.column {
+	width: 300px;
+	float:left;
+}
+.column tr td { padding: 15px; }
+.column-wrap { 
+	padding:0!important; 
+	margin:0 auto; 
+	max-width:600px!important;
+}
+.column table { width:100%;}
+.social .column {
+	width: 280px;
+	min-width: 279px;
+	float:left;
+}
+
+/* Be sure to place a .clear element after each set of columns, just to be safe */
+.clear { display: block; clear: both; }
+
+
+/* ------------------------------------------- 
+		PHONE
+		For clients that support media queries.
+		Nothing fancy. 
+-------------------------------------------- */
+@media only screen and (max-width: 600px) {
+	
+	a[class="btn"] { display:block!important; margin-bottom:10px!important; background-image:none!important; margin-right:0!important;}
+
+	div[class="column"] { width: auto!important; float:none!important;}
+	
+	table.social div[class="column"] {
+		width:auto!important;
+	}
+
+}
+
+</style>
+
+</head>
+<body bgcolor="#FFFFFF">
+
+<!-- HEADER -->
+<table class="head-wrap">
+	<tr>
+		<td></td>
+		<td class="header container" >
+				
+				<p>
+				<table>
+					<tr>
+						<td>
+							<h3>${LOGOPATH}</h3>
+						</td>
+					</tr>
+				</table>
+				</p>
+				
+		</td>
+		<td></td>
+	</tr>
+</table>
+<!-- /HEADER -->
+
+
+<!-- BODY -->
+<table class="body-wrap">
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+
+			<div class="content">
+			<table>
+				<tr>
+					<td>
+						<p class="lead">
+							${EMAIL_CUSTOMER_CONTACT}
+						</p>
+						<p>
+    							${EMAIL_CONTACT_NAME_LABEL}: ${EMAIL_CONTACT_NAME}<br />
+    							${EMAIL_CONTACT_EMAIL_LABEL}: ${EMAIL_CONTACT_EMAIL}<br />
+
+						</p>
+						<!-- Callout Panel -->
+						<p class="callout">
+							${EMAIL_CONTACT_CONTENT}
+						</p><!-- /Callout Panel -->					
+												
+
+					</td>
+				</tr>
+			</table>
+			</div><!-- /content -->
+									
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /BODY -->
+
+<!-- FOOTER -->
+<table class="footer-wrap">
+	<tr>
+		<td></td>
+		<td class="container">
+			
+				<!-- content -->
+				<div class="content">
+				<p>
+				<table>
+				<tr>
+					<td align="center">
+						<p>
+							${EMAIL_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_SPAM_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_FOOTER_COPYRIGHT}
+						</p>
+					</td>
+				</tr>
+				</table>
+				</p>
+				</div><!-- /content -->
+				
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /FOOTER -->
+
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_customer.ftl b/sm-core/src/main/resources/templates/email/email_template_customer.ftl
new file mode 100644
index 0000000..d87d27c
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_customer.ftl
@@ -0,0 +1,334 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<!-- If you delete this meta tag, Half Life 3 will never be released. -->
+<meta name="viewport" content="width=device-width" />
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title></title>
+
+<style type="text/css">
+
+
+/* ------------------------------------- 
+		GLOBAL 
+------------------------------------- */
+* { 
+	margin:0;
+	padding:0;
+}
+* { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; }
+
+img { 
+	max-width: 100%; 
+}
+.collapse {
+	margin:0;
+	padding:0;
+}
+body {
+	-webkit-font-smoothing:antialiased; 
+	-webkit-text-size-adjust:none; 
+	width: 100%!important; 
+	height: 100%;
+}
+
+
+/* ------------------------------------- 
+		ELEMENTS 
+------------------------------------- */
+a { color: #2BA6CB;}
+
+.btn {
+	text-decoration:none;
+	color: #FFF;
+	background-color: #666;
+	padding:10px 16px;
+	font-weight:bold;
+	margin-right:10px;
+	text-align:center;
+	cursor:pointer;
+	display: inline-block;
+}
+
+p.callout {
+	padding:15px;
+	background-color:#ECF8FF;
+	margin-bottom: 15px;
+}
+.callout a {
+	font-weight:bold;
+	color: #2BA6CB;
+}
+
+table.social {
+/* 	padding:15px; */
+	background-color: #ebebeb;
+	
+}
+.social .soc-btn {
+	padding: 3px 7px;
+	font-size:12px;
+	margin-bottom:10px;
+	text-decoration:none;
+	color: #FFF;font-weight:bold;
+	display:block;
+	text-align:center;
+}
+a.fb { background-color: #3B5998!important; }
+a.tw { background-color: #1daced!important; }
+a.gp { background-color: #DB4A39!important; }
+a.ms { background-color: #000!important; }
+
+.sidebar .soc-btn { 
+	display:block;
+	width:100%;
+}
+
+/* ------------------------------------- 
+		HEADER 
+------------------------------------- */
+table.head-wrap { width: 100%;}
+
+.header.container table td.logo { padding: 15px; }
+.header.container table td.label { padding: 15px; padding-left:0px;}
+
+
+/* ------------------------------------- 
+		BODY 
+------------------------------------- */
+table.body-wrap { width: 100%;}
+
+
+/* ------------------------------------- 
+		FOOTER 
+------------------------------------- */
+table.footer-wrap { width: 100%;	clear:both!important;
+}
+.footer-wrap .container td.content  p { border-top: 1px solid rgb(215,215,215); padding-top:15px;}
+.footer-wrap .container td.content p {
+	font-size:10px;
+	font-weight: bold;
+	
+}
+
+
+/* ------------------------------------- 
+		TYPOGRAPHY 
+------------------------------------- */
+h1,h2,h3,h4,h5,h6 {
+font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; line-height: 1.1; margin-bottom:15px; color:#000;
+}
+h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 60%; color: #6f6f6f; line-height: 0; text-transform: none; }
+
+h1 { font-weight:200; font-size: 44px;}
+h2 { font-weight:200; font-size: 37px;}
+h3 { font-weight:500; font-size: 27px;}
+h4 { font-weight:500; font-size: 23px;}
+h5 { font-weight:900; font-size: 17px;}
+h6 { font-weight:900; font-size: 14px; text-transform: uppercase; color:#444;}
+
+.collapse { margin:0!important;}
+
+p, ul { 
+	margin-bottom: 10px; 
+	font-weight: normal; 
+	font-size:14px; 
+	line-height:1.6;
+}
+p.lead { font-size:17px; }
+p.last { margin-bottom:0px;}
+
+ul li {
+	margin-left:5px;
+	list-style-position: inside;
+}
+
+/* ------------------------------------- 
+		SIDEBAR 
+------------------------------------- */
+ul.sidebar {
+	background:#ebebeb;
+	display:block;
+	list-style-type: none;
+}
+ul.sidebar li { display: block; margin:0;}
+ul.sidebar li a {
+	text-decoration:none;
+	color: #666;
+	padding:10px 16px;
+/* 	font-weight:bold; */
+	margin-right:10px;
+/* 	text-align:center; */
+	cursor:pointer;
+	border-bottom: 1px solid #777777;
+	border-top: 1px solid #FFFFFF;
+	display:block;
+	margin:0;
+}
+ul.sidebar li a.last { border-bottom-width:0px;}
+ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.sidebar li a h5,ul.sidebar li a h6,ul.sidebar li a p { margin-bottom:0!important;}
+
+
+
+/* --------------------------------------------------- 
+		RESPONSIVENESS
+		Nuke it from orbit. It's the only way to be sure. 
+------------------------------------------------------ */
+
+/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
+.container {
+	display:block!important;
+	max-width:600px!important;
+	margin:0 auto!important; /* makes it centered */
+	clear:both!important;
+}
+
+/* This should also be a block element, so that it will fill 100% of the .container */
+.content {
+	padding:15px;
+	max-width:600px;
+	margin:0 auto;
+	display:block; 
+}
+
+/* Let's make sure tables in the content area are 100% wide */
+.content table { width: 100%; }
+
+
+/* Odds and ends */
+.column {
+	width: 300px;
+	float:left;
+}
+.column tr td { padding: 15px; }
+.column-wrap { 
+	padding:0!important; 
+	margin:0 auto; 
+	max-width:600px!important;
+}
+.column table { width:100%;}
+.social .column {
+	width: 280px;
+	min-width: 279px;
+	float:left;
+}
+
+/* Be sure to place a .clear element after each set of columns, just to be safe */
+.clear { display: block; clear: both; }
+
+
+/* ------------------------------------------- 
+		PHONE
+		For clients that support media queries.
+		Nothing fancy. 
+-------------------------------------------- */
+@media only screen and (max-width: 600px) {
+	
+	a[class="btn"] { display:block!important; margin-bottom:10px!important; background-image:none!important; margin-right:0!important;}
+
+	div[class="column"] { width: auto!important; float:none!important;}
+	
+	table.social div[class="column"] {
+		width:auto!important;
+	}
+
+}
+
+</style>
+
+</head>
+<body bgcolor="#FFFFFF">
+
+<!-- HEADER -->
+<table class="head-wrap">
+	<tr>
+		<td></td>
+		<td class="header container" >
+				
+				<p>
+				<table>
+					<tr>
+						<td>
+							<h3>${LOGOPATH}</h3>
+						</td>
+					</tr>
+				</table>
+				</p>
+				
+		</td>
+		<td></td>
+	</tr>
+</table>
+<!-- /HEADER -->
+
+
+<!-- BODY -->
+<table class="body-wrap">
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+
+			<div class="content">
+			<table>
+				<tr>
+					<td>
+						<h4>${LABEL_HI} ${EMAIL_CUSTOMER_FIRSTNAME} ${EMAIL_CUSTOMER_LASTNAME}<br/></h4>
+						<p class="lead">
+							${EMAIL_CUSTOMER_GREETING}
+						</p>
+						<p>
+    							${EMAIL_USERNAME_LABEL}: ${EMAIL_USER_NAME}<br />
+    							${EMAIL_PASSWORD_LABEL}: ${EMAIL_CUSTOMER_PASSWORD}<br />
+
+						</p>
+						<!-- Callout Panel -->
+						<p class="callout">
+							${CUSTOMER_ACCESS_LABEL}&nbsp;<a href="${CUSTOMER_ACCESS_URL}">${ACCESS_NOW_LABEL} &raquo;</a>
+						</p><!-- /Callout Panel -->					
+												
+
+					</td>
+				</tr>
+			</table>
+			</div><!-- /content -->
+									
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /BODY -->
+
+<!-- FOOTER -->
+<table class="footer-wrap">
+	<tr>
+		<td></td>
+		<td class="container">
+			
+				<!-- content -->
+				<div class="content">
+				<p>
+				<table>
+				<tr>
+					<td align="center">
+						<p>
+							${EMAIL_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_SPAM_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_FOOTER_COPYRIGHT}
+						</p>
+					</td>
+				</tr>
+				</table>
+				</p>
+				</div><!-- /content -->
+				
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /FOOTER -->
+
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_lowstock.ftl b/sm-core/src/main/resources/templates/email/email_template_lowstock.ftl
new file mode 100644
index 0000000..e0924e3
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_lowstock.ftl
@@ -0,0 +1,50 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+
+
+<style type="text/css">
+body {background-color:#ffffff; color:#000000; font-family:Verdana, Arial, Helvetica, sans-serif; text-align:center;}
+a:link {color:#0066cc;}
+a:hover {background-color:#eeeecc; color:#0066cc;}
+a:visited {color:#0066cc;}
+.holder {background-color:#f9f9f9; border:1px solid #9a9a9a; font-size:9px; text-align:left; width:550px;}
+.header {font-size:10px; padding:0px; width:550px;}
+.content {font-size:10px; padding:5px; width:550px;}
+.footer {font-size:9px; margin-top:10px; text-align:center; width:550px;}
+.disclaimer {background-color:#f9f9f9; border:1px solid #cccccc; font-size:10px; margin-top:10px; padding:5px; width:550px;}
+.disclaimer1 {color:#666666; padding:5px;}
+.disclaimer1 a:link {color:#666666;}
+.disclaimer1 a:visited {color:#666666;}
+.disclaimer2 {color:#666666; padding:5px;}
+.copyright {border-bottom:0px solid #9a9a9a; padding:5px;}
+</style>
+
+</head>
+
+<body>
+<div class="holder">
+
+
+  <!-- Content Section -->
+  <div class="content">
+    <div class="content-line">
+    	${EMAIL_STORE_NAME}<br /><br />
+    	${EMAIL_PRODUCT_TEXT}<br/>
+    </div>
+</div>
+
+</div>
+
+  <!-- Footer Section -->
+  <div class="footer">
+    <div class="copyright">${EMAIL_FOOTER_COPYRIGHT}</div>
+  </div>
+
+<div class="disclaimer">
+  <div class="disclaimer1">${EMAIL_DISCLAIMER}</div>
+  <div class="disclaimer2">${EMAIL_SPAM_DISCLAIMER}</div>
+</div>
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_new_review.ftl b/sm-core/src/main/resources/templates/email/email_template_new_review.ftl
new file mode 100644
index 0000000..32ba63f
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_new_review.ftl
@@ -0,0 +1,52 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+
+<style type="text/css">
+body {background-color:#ffffff; color:#000000; font-family:Verdana, Arial, Helvetica, sans-serif; text-align:center;}
+a:link {color:#0066cc;}
+a:hover {background-color:#eeeecc; color:#0066cc;}
+a:visited {color:#0066cc;}
+.holder {background-color:#f9f9f9; border:1px solid #9a9a9a; font-size:9px; text-align:left; width:550px;}
+.header {font-size:10px; padding:0px; width:550px;}
+.content {font-size:10px; padding:5px; width:550px;}
+.footer {font-size:9px; margin-top:10px; text-align:center; width:550px;}
+.disclaimer {background-color:#f9f9f9; border:1px solid #cccccc; font-size:10px; margin-top:10px; padding:5px; width:550px;}
+.disclaimer1 {color:#666666; padding:5px;}
+.disclaimer1 a:link {color:#666666;}
+.disclaimer1 a:visited {color:#666666;}
+.disclaimer2 {color:#666666; padding:5px;}
+.copyright {border-bottom:0px solid #9a9a9a; padding:5px;}
+</style>
+
+</head>
+
+<body>
+<div class="holder">
+
+
+  <!-- Content Section -->
+  <div class="content">
+    <div class="content-line">
+    	${EMAIL_STORE_NAME}<br /><br /><br/>
+        ${EMAIL_SUBJECT} - ${EMAIL_PRODUCT_NAME}<br/>
+	${EMAIL_CUSTOMER_REVIEW}<br/><br />
+    	${EMAIL_REVIEW_RATING}<br/><br/>
+	${EMAIL_REVIEW_TEXT}<br/>
+    </div>
+</div>
+
+</div>
+
+  <!-- Footer Section -->
+  <div class="footer">
+    <div class="copyright">${EMAIL_FOOTER_COPYRIGHT}</div>
+  </div>
+
+<div class="disclaimer">
+  <div class="disclaimer1">${EMAIL_DISCLAIMER}</div>
+  <div class="disclaimer2">${EMAIL_SPAM_DISCLAIMER}</div>
+</div>
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_new_store.ftl b/sm-core/src/main/resources/templates/email/email_template_new_store.ftl
new file mode 100644
index 0000000..c1c8f29
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_new_store.ftl
@@ -0,0 +1,50 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+
+<style type="text/css">
+body {background-color:#ffffff; color:#000000; font-family:Verdana, Arial, Helvetica, sans-serif; text-align:center;}
+a:link {color:#0066cc;}
+a:hover {background-color:#eeeecc; color:#0066cc;}
+a:visited {color:#0066cc;}
+.holder {background-color:#f9f9f9; border:1px solid #9a9a9a; font-size:9px; text-align:left; width:550px;}
+.header {font-size:10px; padding:0px; width:550px;}
+.content {font-size:10px; padding:5px; width:550px;}
+.footer {font-size:9px; margin-top:10px; text-align:center; width:550px;}
+.disclaimer {background-color:#f9f9f9; border:1px solid #cccccc; font-size:10px; margin-top:10px; padding:5px; width:550px;}
+.disclaimer1 {color:#666666; padding:5px;}
+.disclaimer1 a:link {color:#666666;}
+.disclaimer1 a:visited {color:#666666;}
+.disclaimer2 {color:#666666; padding:5px;}
+.copyright {border-bottom:0px solid #9a9a9a; padding:5px;}
+</style>
+
+</head>
+
+<body>
+<div class="holder">
+
+  <!-- Content Section -->
+  <div class="content">
+    <div class="content-line">
+    	${EMAIL_NEW_STORE_TEXT}<br /><br /><br />
+    	${EMAIL_STORE_NAME}<br /><br />
+    	${EMAIL_ADMIN_STORE_INFO_LABEL}<br/>
+    	${EMAIL_ADMIN_URL_LABEL}<br /><br />
+    </div>
+</div>
+
+</div>
+
+  <!-- Footer Section -->
+  <div class="footer">
+    <div class="copyright">${EMAIL_FOOTER_COPYRIGHT}</div>
+  </div>
+
+<div class="disclaimer">
+  <div class="disclaimer1">${EMAIL_DISCLAIMER}</div>
+  <div class="disclaimer2">${EMAIL_SPAM_DISCLAIMER}</div>
+</div>
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_new_user.ftl b/sm-core/src/main/resources/templates/email/email_template_new_user.ftl
new file mode 100644
index 0000000..bda8dab
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_new_user.ftl
@@ -0,0 +1,52 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+
+<style type="text/css">
+body {background-color:#ffffff; color:#000000; font-family:Verdana, Arial, Helvetica, sans-serif; text-align:center;}
+a:link {color:#0066cc;}
+a:hover {background-color:#eeeecc; color:#0066cc;}
+a:visited {color:#0066cc;}
+.holder {background-color:#f9f9f9; border:1px solid #9a9a9a; font-size:9px; text-align:left; width:550px;}
+.header {font-size:10px; padding:0px; width:550px;}
+.content {font-size:10px; padding:5px; width:550px;}
+.footer {font-size:9px; margin-top:10px; text-align:center; width:550px;}
+.disclaimer {background-color:#f9f9f9; border:1px solid #cccccc; font-size:10px; margin-top:10px; padding:5px; width:550px;}
+.disclaimer1 {color:#666666; padding:5px;}
+.disclaimer1 a:link {color:#666666;}
+.disclaimer1 a:visited {color:#666666;}
+.disclaimer2 {color:#666666; padding:5px;}
+.copyright {border-bottom:0px solid #9a9a9a; padding:5px;}
+</style>
+
+</head>
+
+<body>
+<div class="holder">
+
+  <!-- Content Section -->
+  <div class="content">
+    <div class="content-line">
+    	${EMAIL_NEW_USER_TEXT}<br /><br />
+    	${EMAIL_STORE_NAME}<br /><br />
+    	${EMAIL_TEXT_NEW_USER_CREATED}<br/>
+    	${EMAIL_ADMIN_USERNAME_LABEL}: ${EMAIL_ADMIN_NAME}<br />
+    	${EMAIL_ADMIN_PASSWORD_LABEL}: ${EMAIL_ADMIN_PASSWORD}</br>
+    	${EMAIL_ADMIN_URL_LABEL}: ${EMAIL_ADMIN_URL}<br /><br />
+    </div>
+</div>
+
+</div>
+
+  <!-- Footer Section -->
+  <div class="footer">
+    <div class="copyright">${EMAIL_FOOTER_COPYRIGHT}</div>
+  </div>
+
+<div class="disclaimer">
+  <div class="disclaimer1">${EMAIL_DISCLAIMER}</div>
+  <div class="disclaimer2">${EMAIL_SPAM_DISCLAIMER}</div>
+</div>
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_notification.ftl b/sm-core/src/main/resources/templates/email/email_template_notification.ftl
new file mode 100644
index 0000000..939f97a
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_notification.ftl
@@ -0,0 +1,326 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<!-- If you delete this meta tag, Half Life 3 will never be released. -->
+<meta name="viewport" content="width=device-width" />
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title></title>
+
+<style type="text/css">
+
+
+/* ------------------------------------- 
+		GLOBAL 
+------------------------------------- */
+* { 
+	margin:0;
+	padding:0;
+}
+* { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; }
+
+img { 
+	max-width: 100%; 
+}
+.collapse {
+	margin:0;
+	padding:0;
+}
+body {
+	-webkit-font-smoothing:antialiased; 
+	-webkit-text-size-adjust:none; 
+	width: 100%!important; 
+	height: 100%;
+}
+
+
+/* ------------------------------------- 
+		ELEMENTS 
+------------------------------------- */
+a { color: #2BA6CB;}
+
+.btn {
+	text-decoration:none;
+	color: #FFF;
+	background-color: #666;
+	padding:10px 16px;
+	font-weight:bold;
+	margin-right:10px;
+	text-align:center;
+	cursor:pointer;
+	display: inline-block;
+}
+
+p.callout {
+	padding:15px;
+	background-color:#ECF8FF;
+	margin-bottom: 15px;
+}
+.callout a {
+	font-weight:bold;
+	color: #2BA6CB;
+}
+
+table.social {
+/* 	padding:15px; */
+	background-color: #ebebeb;
+	
+}
+.social .soc-btn {
+	padding: 3px 7px;
+	font-size:12px;
+	margin-bottom:10px;
+	text-decoration:none;
+	color: #FFF;font-weight:bold;
+	display:block;
+	text-align:center;
+}
+a.fb { background-color: #3B5998!important; }
+a.tw { background-color: #1daced!important; }
+a.gp { background-color: #DB4A39!important; }
+a.ms { background-color: #000!important; }
+
+.sidebar .soc-btn { 
+	display:block;
+	width:100%;
+}
+
+/* ------------------------------------- 
+		HEADER 
+------------------------------------- */
+table.head-wrap { width: 100%;}
+
+.header.container table td.logo { padding: 15px; }
+.header.container table td.label { padding: 15px; padding-left:0px;}
+
+
+/* ------------------------------------- 
+		BODY 
+------------------------------------- */
+table.body-wrap { width: 100%;}
+
+
+/* ------------------------------------- 
+		FOOTER 
+------------------------------------- */
+table.footer-wrap { width: 100%;	clear:both!important;
+}
+.footer-wrap .container td.content  p { border-top: 1px solid rgb(215,215,215); padding-top:15px;}
+.footer-wrap .container td.content p {
+	font-size:10px;
+	font-weight: bold;
+	
+}
+
+
+/* ------------------------------------- 
+		TYPOGRAPHY 
+------------------------------------- */
+h1,h2,h3,h4,h5,h6 {
+font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; line-height: 1.1; margin-bottom:15px; color:#000;
+}
+h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 60%; color: #6f6f6f; line-height: 0; text-transform: none; }
+
+h1 { font-weight:200; font-size: 44px;}
+h2 { font-weight:200; font-size: 37px;}
+h3 { font-weight:500; font-size: 27px;}
+h4 { font-weight:500; font-size: 23px;}
+h5 { font-weight:900; font-size: 17px;}
+h6 { font-weight:900; font-size: 14px; text-transform: uppercase; color:#444;}
+
+.collapse { margin:0!important;}
+
+p, ul { 
+	margin-bottom: 10px; 
+	font-weight: normal; 
+	font-size:14px; 
+	line-height:1.6;
+}
+p.lead { font-size:17px; }
+p.last { margin-bottom:0px;}
+
+ul li {
+	margin-left:5px;
+	list-style-position: inside;
+}
+
+/* ------------------------------------- 
+		SIDEBAR 
+------------------------------------- */
+ul.sidebar {
+	background:#ebebeb;
+	display:block;
+	list-style-type: none;
+}
+ul.sidebar li { display: block; margin:0;}
+ul.sidebar li a {
+	text-decoration:none;
+	color: #666;
+	padding:10px 16px;
+/* 	font-weight:bold; */
+	margin-right:10px;
+/* 	text-align:center; */
+	cursor:pointer;
+	border-bottom: 1px solid #777777;
+	border-top: 1px solid #FFFFFF;
+	display:block;
+	margin:0;
+}
+ul.sidebar li a.last { border-bottom-width:0px;}
+ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.sidebar li a h5,ul.sidebar li a h6,ul.sidebar li a p { margin-bottom:0!important;}
+
+
+
+/* --------------------------------------------------- 
+		RESPONSIVENESS
+		Nuke it from orbit. It's the only way to be sure. 
+------------------------------------------------------ */
+
+/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
+.container {
+	display:block!important;
+	max-width:600px!important;
+	margin:0 auto!important; /* makes it centered */
+	clear:both!important;
+}
+
+/* This should also be a block element, so that it will fill 100% of the .container */
+.content {
+	padding:15px;
+	max-width:600px;
+	margin:0 auto;
+	display:block; 
+}
+
+/* Let's make sure tables in the content area are 100% wide */
+.content table { width: 100%; }
+
+
+/* Odds and ends */
+.column {
+	width: 300px;
+	float:left;
+}
+.column tr td { padding: 15px; }
+.column-wrap { 
+	padding:0!important; 
+	margin:0 auto; 
+	max-width:600px!important;
+}
+.column table { width:100%;}
+.social .column {
+	width: 280px;
+	min-width: 279px;
+	float:left;
+}
+
+/* Be sure to place a .clear element after each set of columns, just to be safe */
+.clear { display: block; clear: both; }
+
+
+/* ------------------------------------------- 
+		PHONE
+		For clients that support media queries.
+		Nothing fancy. 
+-------------------------------------------- */
+@media only screen and (max-width: 600px) {
+	
+	a[class="btn"] { display:block!important; margin-bottom:10px!important; background-image:none!important; margin-right:0!important;}
+
+	div[class="column"] { width: auto!important; float:none!important;}
+	
+	table.social div[class="column"] {
+		width:auto!important;
+	}
+
+}
+
+</style>
+
+</head>
+<body bgcolor="#FFFFFF">
+
+<!-- HEADER -->
+<table class="head-wrap">
+	<tr>
+		<td></td>
+		<td class="header container" >
+				
+				<p>
+				<table>
+					<tr>
+						<td>
+							<h3>${LOGOPATH}</h3>
+						</td>
+					</tr>
+				</table>
+				</p>
+				
+		</td>
+		<td></td>
+	</tr>
+</table>
+<!-- /HEADER -->
+
+
+<!-- BODY -->
+<table class="body-wrap">
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+
+			<div class="content">
+			<table>
+				<tr>
+					<td>
+						<p class="lead">
+							<h4>${LABEL_HI} ${EMAIL_CUSTOMER_FIRSTNAME} ${EMAIL_CUSTOMER_LASTNAME}<br/></h4>
+						</p>
+						<p>
+    							${EMAIL_NOTIFICATION_MESSAGE}<br />
+
+						</p>
+					</td>
+				</tr>
+			</table>
+			</div><!-- /content -->
+									
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /BODY -->
+
+<!-- FOOTER -->
+<table class="footer-wrap">
+	<tr>
+		<td></td>
+		<td class="container">
+			
+				<!-- content -->
+				<div class="content">
+				<p>
+				<table>
+				<tr>
+					<td align="center">
+						<p>
+							${EMAIL_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_SPAM_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_FOOTER_COPYRIGHT}
+						</p>
+					</td>
+				</tr>
+				</table>
+				</p>
+				</div><!-- /content -->
+				
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /FOOTER -->
+
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_order_status.ftl b/sm-core/src/main/resources/templates/email/email_template_order_status.ftl
new file mode 100644
index 0000000..27dc2a8
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_order_status.ftl
@@ -0,0 +1,332 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<!-- If you delete this meta tag, Half Life 3 will never be released. -->
+<meta name="viewport" content="width=device-width" />
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title></title>
+
+<style type="text/css">
+
+
+/* ------------------------------------- 
+		GLOBAL 
+------------------------------------- */
+* { 
+	margin:0;
+	padding:0;
+}
+* { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; }
+
+img { 
+	max-width: 100%; 
+}
+.collapse {
+	margin:0;
+	padding:0;
+}
+body {
+	-webkit-font-smoothing:antialiased; 
+	-webkit-text-size-adjust:none; 
+	width: 100%!important; 
+	height: 100%;
+}
+
+
+/* ------------------------------------- 
+		ELEMENTS 
+------------------------------------- */
+a { color: #2BA6CB;}
+
+.btn {
+	text-decoration:none;
+	color: #FFF;
+	background-color: #666;
+	padding:10px 16px;
+	font-weight:bold;
+	margin-right:10px;
+	text-align:center;
+	cursor:pointer;
+	display: inline-block;
+}
+
+p.callout {
+	padding:15px;
+	background-color:#ECF8FF;
+	margin-bottom: 15px;
+}
+.callout a {
+	font-weight:bold;
+	color: #2BA6CB;
+}
+
+table.social {
+/* 	padding:15px; */
+	background-color: #ebebeb;
+	
+}
+.social .soc-btn {
+	padding: 3px 7px;
+	font-size:12px;
+	margin-bottom:10px;
+	text-decoration:none;
+	color: #FFF;font-weight:bold;
+	display:block;
+	text-align:center;
+}
+a.fb { background-color: #3B5998!important; }
+a.tw { background-color: #1daced!important; }
+a.gp { background-color: #DB4A39!important; }
+a.ms { background-color: #000!important; }
+
+.sidebar .soc-btn { 
+	display:block;
+	width:100%;
+}
+
+/* ------------------------------------- 
+		HEADER 
+------------------------------------- */
+table.head-wrap { width: 100%;}
+
+.header.container table td.logo { padding: 15px; }
+.header.container table td.label { padding: 15px; padding-left:0px;}
+
+
+/* ------------------------------------- 
+		BODY 
+------------------------------------- */
+table.body-wrap { width: 100%;}
+
+
+/* ------------------------------------- 
+		FOOTER 
+------------------------------------- */
+table.footer-wrap { width: 100%;	clear:both!important;
+}
+.footer-wrap .container td.content  p { border-top: 1px solid rgb(215,215,215); padding-top:15px;}
+.footer-wrap .container td.content p {
+	font-size:10px;
+	font-weight: bold;
+	
+}
+
+
+/* ------------------------------------- 
+		TYPOGRAPHY 
+------------------------------------- */
+h1,h2,h3,h4,h5,h6 {
+font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; line-height: 1.1; margin-bottom:15px; color:#000;
+}
+h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 60%; color: #6f6f6f; line-height: 0; text-transform: none; }
+
+h1 { font-weight:200; font-size: 44px;}
+h2 { font-weight:200; font-size: 37px;}
+h3 { font-weight:500; font-size: 27px;}
+h4 { font-weight:500; font-size: 23px;}
+h5 { font-weight:900; font-size: 17px;}
+h6 { font-weight:900; font-size: 14px; text-transform: uppercase; color:#444;}
+
+.collapse { margin:0!important;}
+
+p, ul { 
+	margin-bottom: 10px; 
+	font-weight: normal; 
+	font-size:14px; 
+	line-height:1.6;
+}
+p.lead { font-size:17px; }
+p.last { margin-bottom:0px;}
+
+ul li {
+	margin-left:5px;
+	list-style-position: inside;
+}
+
+/* ------------------------------------- 
+		SIDEBAR 
+------------------------------------- */
+ul.sidebar {
+	background:#ebebeb;
+	display:block;
+	list-style-type: none;
+}
+ul.sidebar li { display: block; margin:0;}
+ul.sidebar li a {
+	text-decoration:none;
+	color: #666;
+	padding:10px 16px;
+/* 	font-weight:bold; */
+	margin-right:10px;
+/* 	text-align:center; */
+	cursor:pointer;
+	border-bottom: 1px solid #777777;
+	border-top: 1px solid #FFFFFF;
+	display:block;
+	margin:0;
+}
+ul.sidebar li a.last { border-bottom-width:0px;}
+ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.sidebar li a h5,ul.sidebar li a h6,ul.sidebar li a p { margin-bottom:0!important;}
+
+
+
+/* --------------------------------------------------- 
+		RESPONSIVENESS
+		Nuke it from orbit. It's the only way to be sure. 
+------------------------------------------------------ */
+
+/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
+.container {
+	display:block!important;
+	max-width:600px!important;
+	margin:0 auto!important; /* makes it centered */
+	clear:both!important;
+}
+
+/* This should also be a block element, so that it will fill 100% of the .container */
+.content {
+	padding:15px;
+	max-width:600px;
+	margin:0 auto;
+	display:block; 
+}
+
+/* Let's make sure tables in the content area are 100% wide */
+.content table { width: 100%; }
+
+
+/* Odds and ends */
+.column {
+	width: 300px;
+	float:left;
+}
+.column tr td { padding: 15px; }
+.column-wrap { 
+	padding:0!important; 
+	margin:0 auto; 
+	max-width:600px!important;
+}
+.column table { width:100%;}
+.social .column {
+	width: 280px;
+	min-width: 279px;
+	float:left;
+}
+
+/* Be sure to place a .clear element after each set of columns, just to be safe */
+.clear { display: block; clear: both; }
+
+
+/* ------------------------------------------- 
+		PHONE
+		For clients that support media queries.
+		Nothing fancy. 
+-------------------------------------------- */
+@media only screen and (max-width: 600px) {
+	
+	a[class="btn"] { display:block!important; margin-bottom:10px!important; background-image:none!important; margin-right:0!important;}
+
+	div[class="column"] { width: auto!important; float:none!important;}
+	
+	table.social div[class="column"] {
+		width:auto!important;
+	}
+
+}
+
+</style>
+
+</head>
+<body bgcolor="#FFFFFF">
+
+<!-- HEADER -->
+<table class="head-wrap">
+	<tr>
+		<td></td>
+		<td class="header container" >
+				
+				<p>
+				<table>
+					<tr>
+						<td>
+							<h3>${LOGOPATH}</h3>
+						</td>
+					</tr>
+				</table>
+				</p>
+				
+		</td>
+		<td></td>
+	</tr>
+</table>
+<!-- /HEADER -->
+
+
+<!-- BODY -->
+<table class="body-wrap">
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+
+			<div class="content">
+			<table>
+				<tr>
+					<td>
+						<h4>${LABEL_HI} ${EMAIL_CUSTOMER_FIRSTNAME} ${EMAIL_CUSTOMER_LASTNAME}<br/></h4>
+						<p class="lead">
+							${EMAIL_ORDER_STATUS_TEXT}
+						</p>
+						<p>
+							${EMAIL_ORDER_STATUS}
+						</p>
+						<!-- Callout Panel -->
+						<p class="callout">
+							${EMAIL_TEXT_STATUS_COMMENTS}
+						</p><!-- /Callout Panel -->					
+												
+
+					</td>
+				</tr>
+			</table>
+			</div><!-- /content -->
+									
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /BODY -->
+
+<!-- FOOTER -->
+<table class="footer-wrap">
+	<tr>
+		<td></td>
+		<td class="container">
+			
+				<!-- content -->
+				<div class="content">
+				<p>
+				<table>
+				<tr>
+					<td align="center">
+						<p>
+							${EMAIL_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_SPAM_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_FOOTER_COPYRIGHT}
+						</p>
+					</td>
+				</tr>
+				</table>
+				</p>
+				</div><!-- /content -->
+				
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /FOOTER -->
+
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_outofstock.ftl b/sm-core/src/main/resources/templates/email/email_template_outofstock.ftl
new file mode 100644
index 0000000..bd9957f
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_outofstock.ftl
@@ -0,0 +1,49 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+
+<style type="text/css">
+body {background-color:#ffffff; color:#000000; font-family:Verdana, Arial, Helvetica, sans-serif; text-align:center;}
+a:link {color:#0066cc;}
+a:hover {background-color:#eeeecc; color:#0066cc;}
+a:visited {color:#0066cc;}
+.holder {background-color:#f9f9f9; border:1px solid #9a9a9a; font-size:9px; text-align:left; width:550px;}
+.header {font-size:10px; padding:0px; width:550px;}
+.content {font-size:10px; padding:5px; width:550px;}
+.footer {font-size:9px; margin-top:10px; text-align:center; width:550px;}
+.disclaimer {background-color:#f9f9f9; border:1px solid #cccccc; font-size:10px; margin-top:10px; padding:5px; width:550px;}
+.disclaimer1 {color:#666666; padding:5px;}
+.disclaimer1 a:link {color:#666666;}
+.disclaimer1 a:visited {color:#666666;}
+.disclaimer2 {color:#666666; padding:5px;}
+.copyright {border-bottom:0px solid #9a9a9a; padding:5px;}
+</style>
+
+</head>
+
+<body>
+<div class="holder">
+
+
+  <!-- Content Section -->
+  <div class="content">
+    <div class="content-line">
+    	${EMAIL_STORE_NAME}<br /><br />
+    	${EMAIL_PRODUCT_TEXT}<br/>
+    </div>
+</div>
+
+</div>
+
+  <!-- Footer Section -->
+  <div class="footer">
+    <div class="copyright">${EMAIL_FOOTER_COPYRIGHT}</div>
+  </div>
+
+<div class="disclaimer">
+  <div class="disclaimer1">${EMAIL_DISCLAIMER}</div>
+  <div class="disclaimer2">${EMAIL_SPAM_DISCLAIMER}</div>
+</div>
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_password_reset_customer.ftl b/sm-core/src/main/resources/templates/email/email_template_password_reset_customer.ftl
new file mode 100644
index 0000000..467fdf0
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_password_reset_customer.ftl
@@ -0,0 +1,334 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<!-- If you delete this meta tag, Half Life 3 will never be released. -->
+<meta name="viewport" content="width=device-width" />
+
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+<title></title>
+
+<style type="text/css">
+
+
+/* ------------------------------------- 
+		GLOBAL 
+------------------------------------- */
+* { 
+	margin:0;
+	padding:0;
+}
+* { font-family: "Helvetica Neue", "Helvetica", Helvetica, Arial, sans-serif; }
+
+img { 
+	max-width: 100%; 
+}
+.collapse {
+	margin:0;
+	padding:0;
+}
+body {
+	-webkit-font-smoothing:antialiased; 
+	-webkit-text-size-adjust:none; 
+	width: 100%!important; 
+	height: 100%;
+}
+
+
+/* ------------------------------------- 
+		ELEMENTS 
+------------------------------------- */
+a { color: #2BA6CB;}
+
+.btn {
+	text-decoration:none;
+	color: #FFF;
+	background-color: #666;
+	padding:10px 16px;
+	font-weight:bold;
+	margin-right:10px;
+	text-align:center;
+	cursor:pointer;
+	display: inline-block;
+}
+
+p.callout {
+	padding:15px;
+	background-color:#ECF8FF;
+	margin-bottom: 15px;
+}
+.callout a {
+	font-weight:bold;
+	color: #2BA6CB;
+}
+
+table.social {
+/* 	padding:15px; */
+	background-color: #ebebeb;
+	
+}
+.social .soc-btn {
+	padding: 3px 7px;
+	font-size:12px;
+	margin-bottom:10px;
+	text-decoration:none;
+	color: #FFF;font-weight:bold;
+	display:block;
+	text-align:center;
+}
+a.fb { background-color: #3B5998!important; }
+a.tw { background-color: #1daced!important; }
+a.gp { background-color: #DB4A39!important; }
+a.ms { background-color: #000!important; }
+
+.sidebar .soc-btn { 
+	display:block;
+	width:100%;
+}
+
+/* ------------------------------------- 
+		HEADER 
+------------------------------------- */
+table.head-wrap { width: 100%;}
+
+.header.container table td.logo { padding: 15px; }
+.header.container table td.label { padding: 15px; padding-left:0px;}
+
+
+/* ------------------------------------- 
+		BODY 
+------------------------------------- */
+table.body-wrap { width: 100%;}
+
+
+/* ------------------------------------- 
+		FOOTER 
+------------------------------------- */
+table.footer-wrap { width: 100%;	clear:both!important;
+}
+.footer-wrap .container td.content  p { border-top: 1px solid rgb(215,215,215); padding-top:15px;}
+.footer-wrap .container td.content p {
+	font-size:10px;
+	font-weight: bold;
+	
+}
+
+
+/* ------------------------------------- 
+		TYPOGRAPHY 
+------------------------------------- */
+h1,h2,h3,h4,h5,h6 {
+font-family: "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; line-height: 1.1; margin-bottom:15px; color:#000;
+}
+h1 small, h2 small, h3 small, h4 small, h5 small, h6 small { font-size: 60%; color: #6f6f6f; line-height: 0; text-transform: none; }
+
+h1 { font-weight:200; font-size: 44px;}
+h2 { font-weight:200; font-size: 37px;}
+h3 { font-weight:500; font-size: 27px;}
+h4 { font-weight:500; font-size: 23px;}
+h5 { font-weight:900; font-size: 17px;}
+h6 { font-weight:900; font-size: 14px; text-transform: uppercase; color:#444;}
+
+.collapse { margin:0!important;}
+
+p, ul { 
+	margin-bottom: 10px; 
+	font-weight: normal; 
+	font-size:14px; 
+	line-height:1.6;
+}
+p.lead { font-size:17px; }
+p.last { margin-bottom:0px;}
+
+ul li {
+	margin-left:5px;
+	list-style-position: inside;
+}
+
+/* ------------------------------------- 
+		SIDEBAR 
+------------------------------------- */
+ul.sidebar {
+	background:#ebebeb;
+	display:block;
+	list-style-type: none;
+}
+ul.sidebar li { display: block; margin:0;}
+ul.sidebar li a {
+	text-decoration:none;
+	color: #666;
+	padding:10px 16px;
+/* 	font-weight:bold; */
+	margin-right:10px;
+/* 	text-align:center; */
+	cursor:pointer;
+	border-bottom: 1px solid #777777;
+	border-top: 1px solid #FFFFFF;
+	display:block;
+	margin:0;
+}
+ul.sidebar li a.last { border-bottom-width:0px;}
+ul.sidebar li a h1,ul.sidebar li a h2,ul.sidebar li a h3,ul.sidebar li a h4,ul.sidebar li a h5,ul.sidebar li a h6,ul.sidebar li a p { margin-bottom:0!important;}
+
+
+
+/* --------------------------------------------------- 
+		RESPONSIVENESS
+		Nuke it from orbit. It's the only way to be sure. 
+------------------------------------------------------ */
+
+/* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */
+.container {
+	display:block!important;
+	max-width:600px!important;
+	margin:0 auto!important; /* makes it centered */
+	clear:both!important;
+}
+
+/* This should also be a block element, so that it will fill 100% of the .container */
+.content {
+	padding:15px;
+	max-width:600px;
+	margin:0 auto;
+	display:block; 
+}
+
+/* Let's make sure tables in the content area are 100% wide */
+.content table { width: 100%; }
+
+
+/* Odds and ends */
+.column {
+	width: 300px;
+	float:left;
+}
+.column tr td { padding: 15px; }
+.column-wrap { 
+	padding:0!important; 
+	margin:0 auto; 
+	max-width:600px!important;
+}
+.column table { width:100%;}
+.social .column {
+	width: 280px;
+	min-width: 279px;
+	float:left;
+}
+
+/* Be sure to place a .clear element after each set of columns, just to be safe */
+.clear { display: block; clear: both; }
+
+
+/* ------------------------------------------- 
+		PHONE
+		For clients that support media queries.
+		Nothing fancy. 
+-------------------------------------------- */
+@media only screen and (max-width: 600px) {
+	
+	a[class="btn"] { display:block!important; margin-bottom:10px!important; background-image:none!important; margin-right:0!important;}
+
+	div[class="column"] { width: auto!important; float:none!important;}
+	
+	table.social div[class="column"] {
+		width:auto!important;
+	}
+
+}
+
+</style>
+
+</head>
+
+
+<body bgcolor="#FFFFFF">
+
+<!-- HEADER -->
+<table class="head-wrap">
+	<tr>
+		<td></td>
+		<td class="header container" >
+				
+				<p>
+				<table>
+					<tr>
+						<td>
+							${LOGOPATH}
+						</td>
+					</tr>
+				</table>
+				</p>
+				
+		</td>
+		<td></td>
+	</tr>
+</table>
+<!-- /HEADER -->
+
+<!-- BODY -->
+<table class="body-wrap">
+	<tr>
+		<td></td>
+		<td class="container" bgcolor="#FFFFFF">
+
+			<div class="content">
+			<table>
+				<tr>
+					<td>
+						<h4>${LABEL_HI} ${EMAIL_CUSTOMER_FIRSTNAME} ${EMAIL_CUSTOMER_LASTNAME}<br/></h4>
+						<p class="lead">
+							${EMAIL_RESET_PASSWORD_TXT}
+						</p>
+						<p>
+    							${EMAIL_PASSWORD_LABEL}: ${EMAIL_CUSTOMER_PASSWORD}<br />
+
+						</p>
+						<!-- Callout Panel -->
+						<p class="callout">
+							${EMAIL_CONTACT_OWNER}
+						</p><!-- /Callout Panel -->					
+												
+
+					</td>
+				</tr>
+			</table>
+			</div><!-- /content -->
+									
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /BODY -->
+
+<!-- FOOTER -->
+<table class="footer-wrap">
+	<tr>
+		<td></td>
+		<td class="container">
+			
+				<!-- content -->
+				<div class="content">
+				<p>
+				<table>
+				<tr>
+					<td align="center">
+						<p>
+							${EMAIL_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_SPAM_DISCLAIMER}
+						</p>
+						<p>
+							${EMAIL_FOOTER_COPYRIGHT}
+						</p>
+					</td>
+				</tr>
+				</table>
+				</p>
+				</div><!-- /content -->
+				
+		</td>
+		<td></td>
+	</tr>
+</table><!-- /FOOTER -->
+
+</body>
+</html>
\ No newline at end of file
diff --git a/sm-core/src/main/resources/templates/email/email_template_password_reset_user.ftl b/sm-core/src/main/resources/templates/email/email_template_password_reset_user.ftl
new file mode 100644
index 0000000..57cfaa3
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_password_reset_user.ftl
@@ -0,0 +1,54 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+
+<style type="text/css">
+body {background-color:#ffffff; color:#000000; font-family:Verdana, Arial, Helvetica, sans-serif; text-align:center;}
+a:link {color:#0066cc;}
+a:hover {background-color:#eeeecc; color:#0066cc;}
+a:visited {color:#0066cc;}
+.holder {background-color:#f9f9f9; border:1px solid #9a9a9a; font-size:9px; text-align:left; width:550px;}
+.header {font-size:10px; padding:0px; width:550px;}
+.content {font-size:10px; padding:5px; width:550px;}
+.footer {font-size:9px; margin-top:10px; text-align:center; width:550px;}
+.disclaimer {background-color:#f9f9f9; border:1px solid #cccccc; font-size:10px; margin-top:10px; padding:5px; width:550px;}
+.disclaimer1 {color:#666666; padding:5px;}
+.disclaimer1 a:link {color:#666666;}
+.disclaimer1 a:visited {color:#666666;}
+.disclaimer2 {color:#666666; padding:5px;}
+.copyright {border-bottom:0px solid #9a9a9a; padding:5px;}
+</style>
+
+</head>
+
+<body>
+<div class="holder">
+
+  <!-- Header Section -->
+  ${LOGOPATH}
+
+
+  <!-- Content Section -->
+  <div class="content">
+    <div class="content-line">
+    	${EMAIL_STORE_NAME}<br /><br />
+    	<p>${EMAIL_RESET_PASSWORD_TXT}</p><br/>
+    	${EMAIL_PASSWORD_LABEL}: ${EMAIL_USER_PASSWORD}<br /><br />
+    	${EMAIL_CONTACT_OWNER}
+  	</div>
+</div>
+
+</div>
+
+  <!-- Footer Section -->
+  <div class="footer">
+    <div class="copyright">${EMAIL_FOOTER_COPYRIGHT}</div>
+  </div>
+
+<div class="disclaimer">
+  <div class="disclaimer1">${EMAIL_DISCLAIMER}</div>
+  <div class="disclaimer2">${EMAIL_SPAM_DISCLAIMER}</div>
+</div>
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_sentinvoice.ftl b/sm-core/src/main/resources/templates/email/email_template_sentinvoice.ftl
new file mode 100644
index 0000000..ba563a3
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_sentinvoice.ftl
@@ -0,0 +1,55 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+
+<style type="text/css">
+body {background-color:#ffffff; color:#000000; font-family:Verdana, Arial, Helvetica, sans-serif; text-align:center;}
+a:link {color:#0066cc;}
+a:hover {background-color:#eeeecc; color:#0066cc;}
+a:visited {color:#0066cc;}
+.holder {background-color:#f9f9f9; border:1px solid #9a9a9a; font-size:9px; text-align:left; width:550px;}
+.header {font-size:10px; padding:0px; width:550px;}
+.content {font-size:10px; padding:5px; width:550px;}
+.footer {font-size:9px; margin-top:10px; text-align:center; width:550px;}
+.disclaimer {background-color:#f9f9f9; border:1px solid #cccccc; font-size:10px; margin-top:10px; padding:5px; width:550px;}
+.disclaimer1 {color:#666666; padding:5px;}
+.disclaimer1 a:link {color:#666666;}
+.disclaimer1 a:visited {color:#666666;}
+.disclaimer2 {color:#666666; padding:5px;}
+.copyright {border-bottom:0px solid #9a9a9a; padding:5px;}
+</style>
+
+</head>
+
+<body>
+<div class="holder">
+
+  <!-- Header Section -->
+  ${LOGOPATH}
+
+
+  <!-- Content Section -->
+  <div class="content">
+    <div class="content-line">
+    	${EMAIL_STORE_NAME}<br /><br />
+	${EMAIL_GREETING} ${EMAIL_CUSTOMER_NAME}<br/><br/>
+    	${EMAIL_INVOICE_MESSAGE}<br /><br />
+    	${EMAIL_INVOICE_PAYMENT_URL}<br /><br />
+    	${EMAIL_CONTACT_OWNER}
+    </div>
+</div>
+
+</div>
+
+  <!-- Footer Section -->
+  <div class="footer">
+    <div class="copyright">${EMAIL_FOOTER_COPYRIGHT}</div>
+  </div>
+
+<div class="disclaimer">
+  <div class="disclaimer1">${EMAIL_DISCLAIMER}</div>
+  <div class="disclaimer2">${EMAIL_SPAM_DISCLAIMER}</div>
+</div>
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/email/email_template_user_password_link.ftl b/sm-core/src/main/resources/templates/email/email_template_user_password_link.ftl
new file mode 100644
index 0000000..02cef50
--- /dev/null
+++ b/sm-core/src/main/resources/templates/email/email_template_user_password_link.ftl
@@ -0,0 +1,49 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+
+
+<style type="text/css">
+body {background-color:#ffffff; color:#000000; font-family:Verdana, Arial, Helvetica, sans-serif; text-align:center;}
+a:link {color:#0066cc;}
+a:hover {background-color:#eeeecc; color:#0066cc;}
+a:visited {color:#0066cc;}
+.holder {background-color:#f9f9f9; border:1px solid #9a9a9a; font-size:9px; text-align:left; width:550px;}
+.header {font-size:10px; padding:0px; width:550px;}
+.content {font-size:10px; padding:5px; width:550px;}
+.footer {font-size:9px; margin-top:10px; text-align:center; width:550px;}
+.disclaimer {background-color:#f9f9f9; border:1px solid #cccccc; font-size:10px; margin-top:10px; padding:5px; width:550px;}
+.disclaimer1 {color:#666666; padding:5px;}
+.disclaimer1 a:link {color:#666666;}
+.disclaimer1 a:visited {color:#666666;}
+.disclaimer2 {color:#666666; padding:5px;}
+.copyright {border-bottom:0px solid #9a9a9a; padding:5px;}
+</style>
+
+</head>
+
+<body>
+<div class="holder">
+
+  <!-- Content Section -->
+  <div class="content">
+    <div class="content-line">
+    	${EMAIL_PASSWORD_TEXT}<br /><br /><br />
+    	${EMAIL_PASSWORD_LINK}<br /><br />
+		<br /><br />
+    </div>
+</div>
+
+</div>
+
+  <!-- Footer Section -->
+  <div class="footer">
+    <div class="copyright">${EMAIL_FOOTER_COPYRIGHT}</div>
+  </div>
+
+<div class="disclaimer">
+  <div class="disclaimer1">${EMAIL_DISCLAIMER}</div>
+  <div class="disclaimer2">${EMAIL_SPAM_DISCLAIMER}</div>
+</div>
+</body>
+</html>
diff --git a/sm-core/src/main/resources/templates/invoice/Invoice.ods b/sm-core/src/main/resources/templates/invoice/Invoice.ods
new file mode 100755
index 0000000..f936419
Binary files /dev/null and b/sm-core/src/main/resources/templates/invoice/Invoice.ods differ
diff --git a/sm-core/src/main/resources/templates/invoice/Invoice_fr.ods b/sm-core/src/main/resources/templates/invoice/Invoice_fr.ods
new file mode 100644
index 0000000..6c453a5
Binary files /dev/null and b/sm-core/src/main/resources/templates/invoice/Invoice_fr.ods differ
diff --git a/sm-core/src/test/java/com/salesmanager/test/catalog/CatalogSalesManagerTestCase.java b/sm-core/src/test/java/com/salesmanager/test/catalog/CatalogSalesManagerTestCase.java
new file mode 100644
index 0000000..32cb331
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/catalog/CatalogSalesManagerTestCase.java
@@ -0,0 +1,708 @@
+package com.salesmanager.test.catalog;
+
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionDescription;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionType;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValueDescription;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.review.ProductReview;
+import com.salesmanager.core.business.catalog.product.model.review.ProductReviewDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class CatalogSalesManagerTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+
+	/**
+	 * This method creates multiple products using multiple catelog APIs
+	 * @throws ServiceException
+	 */
+	@Test
+	public void testCreateProduct() throws ServiceException {
+
+	    Language en = languageService.getByCode("en");
+	    Language fr = languageService.getByCode("fr");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+
+	    Category book = new Category();
+	    book.setMerchantStore(store);
+	    book.setCode("book");
+
+	    CategoryDescription bookEnglishDescription = new CategoryDescription();
+	    bookEnglishDescription.setName("Book");
+	    bookEnglishDescription.setCategory(book);
+	    bookEnglishDescription.setLanguage(en);
+
+	    CategoryDescription bookFrenchDescription = new CategoryDescription();
+	    bookFrenchDescription.setName("Livre");
+	    bookFrenchDescription.setCategory(book);
+	    bookFrenchDescription.setLanguage(fr);
+
+	    List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+	    descriptions.add(bookEnglishDescription);
+	    descriptions.add(bookFrenchDescription);
+
+	    book.setDescriptions(descriptions);
+
+	    categoryService.create(book);
+
+	    Category music = new Category();
+	    music.setMerchantStore(store);
+	    music.setCode("music");
+
+	    CategoryDescription musicEnglishDescription = new CategoryDescription();
+	    musicEnglishDescription.setName("Music");
+	    musicEnglishDescription.setCategory(music);
+	    musicEnglishDescription.setLanguage(en);
+
+	    CategoryDescription musicFrenchDescription = new CategoryDescription();
+	    musicFrenchDescription.setName("Musique");
+	    musicFrenchDescription.setCategory(music);
+	    musicFrenchDescription.setLanguage(fr);
+
+	    List<CategoryDescription> descriptions2 = new ArrayList<CategoryDescription>();
+	    descriptions2.add(musicEnglishDescription);
+	    descriptions2.add(musicFrenchDescription);
+
+	    music.setDescriptions(descriptions2);
+
+	    categoryService.create(music);
+
+	    Category novell = new Category();
+	    novell.setMerchantStore(store);
+	    novell.setCode("novell");
+
+	    CategoryDescription novellEnglishDescription = new CategoryDescription();
+	    novellEnglishDescription.setName("Novell");
+	    novellEnglishDescription.setCategory(novell);
+	    novellEnglishDescription.setLanguage(en);
+
+	    CategoryDescription novellFrenchDescription = new CategoryDescription();
+	    novellFrenchDescription.setName("Roman");
+	    novellFrenchDescription.setCategory(novell);
+	    novellFrenchDescription.setLanguage(fr);
+
+	    List<CategoryDescription> descriptions3 = new ArrayList<CategoryDescription>();
+	    descriptions3.add(novellEnglishDescription);
+	    descriptions3.add(novellFrenchDescription);
+
+	    novell.setDescriptions(descriptions3);
+	    
+	    novell.setParent(book);
+
+	    categoryService.create(novell);
+	    categoryService.addChild(book, novell);
+
+	    Category tech = new Category();
+	    tech.setMerchantStore(store);
+	    tech.setCode("tech");
+
+	    CategoryDescription techEnglishDescription = new CategoryDescription();
+	    techEnglishDescription.setName("Technology");
+	    techEnglishDescription.setCategory(tech);
+	    techEnglishDescription.setLanguage(en);
+
+	    CategoryDescription techFrenchDescription = new CategoryDescription();
+	    techFrenchDescription.setName("Technologie");
+	    techFrenchDescription.setCategory(tech);
+	    techFrenchDescription.setLanguage(fr);
+
+	    List<CategoryDescription> descriptions4 = new ArrayList<CategoryDescription>();
+	    descriptions4.add(techFrenchDescription);
+	    descriptions4.add(techFrenchDescription);
+
+	    tech.setDescriptions(descriptions4);
+	    
+	    tech.setParent(book);
+
+	    categoryService.create(tech);
+	    categoryService.addChild(book, tech);
+
+	    Category fiction = new Category();
+	    fiction.setMerchantStore(store);
+	    fiction.setCode("fiction");
+
+	    CategoryDescription fictionEnglishDescription = new CategoryDescription();
+	    fictionEnglishDescription.setName("Fiction");
+	    fictionEnglishDescription.setCategory(fiction);
+	    fictionEnglishDescription.setLanguage(en);
+
+	    CategoryDescription fictionFrenchDescription = new CategoryDescription();
+	    fictionFrenchDescription.setName("Sc Fiction");
+	    fictionFrenchDescription.setCategory(fiction);
+	    fictionFrenchDescription.setLanguage(fr);
+
+	    List<CategoryDescription> fictiondescriptions = new ArrayList<CategoryDescription>();
+	    fictiondescriptions.add(fictionEnglishDescription);
+	    fictiondescriptions.add(fictionFrenchDescription);
+
+	    fiction.setDescriptions(fictiondescriptions);
+	    
+	    fiction.setParent(novell);
+
+	    categoryService.create(fiction);
+	    categoryService.addChild(book, fiction);
+
+	    Manufacturer oreilley = new Manufacturer();
+	    oreilley.setMerchantStore(store);
+
+	    ManufacturerDescription oreilleyd = new ManufacturerDescription();
+	    oreilleyd.setLanguage(en);
+	    oreilleyd.setName("O\'reilley");
+	    oreilleyd.setManufacturer(oreilley);
+	    oreilley.getDescriptions().add(oreilleyd);
+
+	    manufacturerService.create(oreilley);
+
+	    Manufacturer packed = new Manufacturer();
+	    packed.setMerchantStore(store);
+
+	    ManufacturerDescription packedd = new ManufacturerDescription();
+	    packedd.setLanguage(en);
+	    packedd.setManufacturer(packed);
+	    packedd.setName("Packed publishing");
+	    packed.getDescriptions().add(packedd);
+
+	    manufacturerService.create(packed);
+
+	    Manufacturer novells = new Manufacturer();
+	    novells.setMerchantStore(store);
+
+	    ManufacturerDescription novellsd = new ManufacturerDescription();
+	    novellsd.setLanguage(en);
+	    novellsd.setManufacturer(novells);
+	    novellsd.setName("Novells publishing");
+	    novells.getDescriptions().add(novellsd);
+
+	    manufacturerService.create(novells);
+
+	    // PRODUCT 1
+
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(1));
+	    product.setSku("TB12345");
+	    product.setManufacturer(oreilley);
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Spring in Action");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+
+	    product.getCategories().add(tech);
+
+	    productService.create(product);
+
+	    // Availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(date);
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+
+	    productAvailabilityService.create(availability);
+
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice);
+	    
+	    ProductReview review = new ProductReview();
+	    review.setProduct(product);
+	    review.setReviewRating(new Double(4));
+	    
+	    ProductReviewDescription reviewDescription = new ProductReviewDescription();
+	    reviewDescription.setLanguage(en);
+	    reviewDescription.setDescription("This is a product review");
+	    reviewDescription.setProductReview(review);
+	    review.getDescriptions().add(reviewDescription);
+	    
+	    productReviewService.create(review);
+	    
+	    review = new ProductReview();
+	    review.setProduct(product);
+	    review.setReviewRating(new Double(5));
+	    
+	    reviewDescription = new ProductReviewDescription();
+	    reviewDescription.setLanguage(en);
+	    reviewDescription.setDescription("This is a second product review");
+	    reviewDescription.setProductReview(review);
+	    review.getDescriptions().add(reviewDescription);
+	    
+	    productReviewService.create(review);
+	    
+
+	    // PRODUCT 2
+
+	    Product product2 = new Product();
+	    product2.setProductHeight(new BigDecimal(4));
+	    product2.setProductLength(new BigDecimal(3));
+	    product2.setProductWidth(new BigDecimal(1));
+	    product2.setSku("TB2468");
+	    product2.setManufacturer(packed);
+	    product2.setType(generalType);
+	    product2.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("This is Node.js");
+	    description.setLanguage(en);
+	    description.setProduct(product2);
+
+	    product2.getDescriptions().add(description);
+
+	    product2.getCategories().add(tech);
+	    productService.create(product2);
+
+	    // Availability
+	    ProductAvailability availability2 = new ProductAvailability();
+	    availability2.setProductDateAvailable(date);
+	    availability2.setProductQuantity(100);
+	    availability2.setRegion("*");
+	    availability2.setProduct(product2);// associate with product
+
+	    productAvailabilityService.create(availability2);
+
+	    ProductPrice dprice2 = new ProductPrice();
+	    dprice2.setDefaultPrice(true);
+	    dprice2.setProductPriceAmount(new BigDecimal(39.99));
+	    dprice2.setProductAvailability(availability2);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice2);
+	    dpd.setLanguage(en);
+
+	    dprice2.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice2);
+
+	    // PRODUCT 3
+
+	    Product product3 = new Product();
+	    product3.setProductHeight(new BigDecimal(4));
+	    product3.setProductLength(new BigDecimal(3));
+	    product3.setProductWidth(new BigDecimal(1));
+	    product3.setSku("NB1111");
+	    product3.setManufacturer(packed);
+	    product3.setType(generalType);
+	    product3.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("A nice book for you");
+	    description.setLanguage(en);
+	    description.setProduct(product3);
+
+	    product3.getDescriptions().add(description);
+
+	    product3.getCategories().add(novell);
+	    productService.create(product3);
+
+	    // Availability
+	    ProductAvailability availability3 = new ProductAvailability();
+	    availability3.setProductDateAvailable(date);
+	    availability3.setProductQuantity(100);
+	    availability3.setRegion("*");
+	    availability3.setProduct(product3);// associate with product
+
+	    productAvailabilityService.create(availability3);
+
+	    ProductPrice dprice3 = new ProductPrice();
+	    dprice3.setDefaultPrice(true);
+	    dprice3.setProductPriceAmount(new BigDecimal(19.99));
+	    dprice3.setProductAvailability(availability3);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice3);
+	    dpd.setLanguage(en);
+
+	    dprice3.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice3);
+
+	    // PRODUCT 4
+
+	    Product product4 = new Product();
+	    product4.setProductHeight(new BigDecimal(4));
+	    product4.setProductLength(new BigDecimal(3));
+	    product4.setProductWidth(new BigDecimal(1));
+	    product4.setSku("SF333345");
+	    product4.setManufacturer(packed);
+	    product4.setType(generalType);
+	    product4.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("Battle of the worlds");
+	    description.setLanguage(en);
+	    description.setProduct(product4);
+
+	    product4.getDescriptions().add(description);
+
+	    product4.getCategories().add(fiction);
+	    productService.create(product4);
+
+	    // Availability
+	    ProductAvailability availability4 = new ProductAvailability();
+	    availability4.setProductDateAvailable(date);
+	    availability4.setProductQuantity(100);
+	    availability4.setRegion("*");
+	    availability4.setProduct(product4);// associate with product
+
+	    productAvailabilityService.create(availability4);
+
+	    ProductPrice dprice4 = new ProductPrice();
+	    dprice4.setDefaultPrice(true);
+	    dprice4.setProductPriceAmount(new BigDecimal(18.99));
+	    dprice4.setProductAvailability(availability4);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice4);
+	    dpd.setLanguage(en);
+
+	    dprice4.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice4);
+
+	    // PRODUCT 5
+
+	    Product product5 = new Product();
+	    product5.setProductHeight(new BigDecimal(4));
+	    product5.setProductLength(new BigDecimal(3));
+	    product5.setProductWidth(new BigDecimal(1));
+	    product5.setSku("SF333346");
+	    product5.setManufacturer(packed);
+	    product5.setType(generalType);
+	    product5.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("Battle of the worlds 2");
+	    description.setLanguage(en);
+	    description.setProduct(product5);
+
+	    product5.getDescriptions().add(description);
+
+	    product5.getCategories().add(fiction);
+	    productService.create(product5);
+
+	    // Availability
+	    ProductAvailability availability5 = new ProductAvailability();
+	    availability5.setProductDateAvailable(date);
+	    availability5.setProductQuantity(100);
+	    availability5.setRegion("*");
+	    availability5.setProduct(product5);// associate with product
+
+	    productAvailabilityService.create(availability5);
+
+	    ProductPrice dprice5 = new ProductPrice();
+	    dprice5.setDefaultPrice(true);
+	    dprice5.setProductPriceAmount(new BigDecimal(18.99));
+	    dprice5.setProductAvailability(availability5);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice5);
+	    dpd.setLanguage(en);
+
+	    dprice5.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice5);
+
+	    // PRODUCT 6
+
+	    Product product6 = new Product();
+	    product6.setProductHeight(new BigDecimal(4));
+	    product6.setProductLength(new BigDecimal(3));
+	    product6.setProductWidth(new BigDecimal(1));
+	    product6.setSku("LL333444");
+	    product6.setManufacturer(packed);
+	    product6.setType(generalType);
+	    product6.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("Life book");
+	    description.setLanguage(en);
+	    description.setProduct(product6);
+
+	    product6.getDescriptions().add(description);
+
+	    product6.getCategories().add(novell);
+	    productService.create(product6);
+
+	    // Availability
+	    ProductAvailability availability6 = new ProductAvailability();
+	    availability6.setProductDateAvailable(date);
+	    availability6.setProductQuantity(100);
+	    availability6.setRegion("*");
+	    availability6.setProduct(product6);// associate with product
+
+	    productAvailabilityService.create(availability6);
+
+	    ProductPrice dprice6 = new ProductPrice();
+	    dprice6.setDefaultPrice(true);
+	    dprice6.setProductPriceAmount(new BigDecimal(18.99));
+	    dprice6.setProductAvailability(availability6);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice6);
+	    dpd.setLanguage(en);
+
+	    dprice6.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice6);
+	    
+	    //count products by category
+		String lineage = new StringBuilder().append(book.getLineage()).toString();
+		
+		List<Category> categories = categoryService.listByLineage(store, lineage);
+		
+		List<Long> ids = new ArrayList<Long>();
+		if(categories!=null && categories.size()>0) {
+			for(Category c : categories) {
+				ids.add(c.getId());
+			}
+		} 
+		
+		List<Object[]> objs = categoryService.countProductsByCategories(store, ids);
+		
+		System.out.println(objs.size());
+		
+		//get manufacturer for given categories
+		List<Manufacturer> manufacturers = manufacturerService.listByProductsByCategoriesId(store, ids, en);
+	    
+		System.out.println(manufacturers.size());
+	    
+	}
+	
+	
+	/**
+	 * This method creates a product and uses the saveOrUpdate on a complex graph object
+	 * @throws ServiceException
+	 */
+	@Test
+	@Ignore
+	public void testCreateSimpleProduct() throws ServiceException {
+		
+		
+	    Language en = languageService.getByCode("en");
+	    Language fr = languageService.getByCode("fr");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+
+	    /**
+	     * Create the category
+	     */
+	    Category book = new Category();
+	    book.setMerchantStore(store);
+	    book.setCode("book");
+
+	    CategoryDescription bookEnglishDescription = new CategoryDescription();
+	    bookEnglishDescription.setName("Book");
+	    bookEnglishDescription.setCategory(book);
+	    bookEnglishDescription.setLanguage(en);
+
+	    CategoryDescription bookFrenchDescription = new CategoryDescription();
+	    bookFrenchDescription.setName("Livre");
+	    bookFrenchDescription.setCategory(book);
+	    bookFrenchDescription.setLanguage(fr);
+
+	    List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+	    descriptions.add(bookEnglishDescription);
+	    descriptions.add(bookFrenchDescription);
+
+	    book.setDescriptions(descriptions);
+
+	    categoryService.create(book);
+	    
+	    
+	    /**
+	     * Create a manufacturer
+	     */
+	    Manufacturer packed = new Manufacturer();
+	    packed.setMerchantStore(store);
+
+	    ManufacturerDescription packedd = new ManufacturerDescription();
+	    packedd.setLanguage(en);
+	    packedd.setManufacturer(packed);
+	    packedd.setName("Packed publishing");
+	    packed.getDescriptions().add(packedd);
+
+	    manufacturerService.create(packed);
+	    
+	    /**
+	     * Create an option
+	     */
+	    ProductOption option = new ProductOption();
+	    option.setMerchantStore(store);
+	    option.setCode("copy");
+	    option.setProductOptionType(ProductOptionType.Radio.name());
+	    
+	    ProductOptionDescription optionDescription = new ProductOptionDescription();
+	    optionDescription.setLanguage(en);
+	    optionDescription.setName("Book type");
+	    optionDescription.setDescription("Offered in hard and soft copy");
+	    optionDescription.setProductOption(option);
+	    
+	    option.getDescriptions().add(optionDescription);
+	    
+	    productOptionService.saveOrUpdate(option);
+	    
+	    ProductOptionValue soft = new ProductOptionValue();
+	    soft.setMerchantStore(store);
+	    soft.setCode("soft");
+	    
+	    ProductOptionValueDescription softDescription = new ProductOptionValueDescription();
+	    softDescription.setLanguage(en);
+	    softDescription.setName("Soft");
+	    softDescription.setDescription("Soft copy");
+	    softDescription.setProductOptionValue(soft);
+	    
+	    soft.getDescriptions().add(softDescription);
+	    
+	    productOptionValueService.saveOrUpdate(soft);
+	    
+	    
+	    ProductOptionValue hard = new ProductOptionValue();
+	    hard.setMerchantStore(store);
+	    hard.setCode("hard");
+	    
+	    ProductOptionValueDescription hardDescription = new ProductOptionValueDescription();
+	    hardDescription.setLanguage(en);
+	    hardDescription.setName("Hard");
+	    hardDescription.setDescription("Hard copy");
+	    hardDescription.setProductOptionValue(hard);
+	    
+	    hard.getDescriptions().add(hardDescription);
+
+	    productOptionValueService.saveOrUpdate(hard);
+	    
+	    
+	    /**
+	     * Create a complex product
+	     */
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(1));
+	    product.setSku("TB12345");
+	    product.setManufacturer(packed);
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Spring in Action");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    product.getCategories().add(book);
+	    
+	    
+	    //availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(date);
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+	    
+	    //price
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+	    
+	    
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    availability.getPrices().add(dprice);
+	    
+	    
+	    
+	    //attributes
+	    ProductAttribute attribute = new ProductAttribute();
+	    attribute.setProduct(product);
+	    attribute.setProductOption(option);
+	    attribute.setAttributeDefault(true);
+	    attribute.setProductAttributePrice(new BigDecimal(0));//no price variation
+	    attribute.setProductAttributeWeight(new BigDecimal(1));//weight variation
+	    attribute.setProductOption(option);
+	    attribute.setProductOptionValue(hard);
+	    
+	    product.getAttributes().add(attribute);
+	    
+	    attribute = new ProductAttribute();
+	    attribute.setProduct(product);
+	    attribute.setProductOption(option);
+	    attribute.setProductAttributePrice(new BigDecimal(0));//no price variation
+	    attribute.setProductAttributeWeight(new BigDecimal(0));//no weight variation
+	    attribute.setProductOption(option);
+	    attribute.setProductOptionValue(soft);
+	    
+	    product.getAttributes().add(attribute);
+
+	    //relationships
+	    
+	    
+	  
+	    productService.create(product);
+
+		
+		
+	}
+	
+
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/catalog/ProductImagesTestCase.java b/sm-core/src/test/java/com/salesmanager/test/catalog/ProductImagesTestCase.java
new file mode 100644
index 0000000..46eb244
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/catalog/ProductImagesTestCase.java
@@ -0,0 +1,214 @@
+package com.salesmanager.test.catalog;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.file.ProductImageSize;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.ImageContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.content.service.ContentService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class ProductImagesTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+	@Autowired
+	private ContentService contentService;
+
+	@Test
+	public void testCreateProductImage() throws ServiceException, FileNotFoundException, IOException {
+		
+	    Language en = languageService.getByCode("en");
+	    Country country = countryService.getByCode("CA");
+	    Zone zone = zoneService.getByCode("QC");
+
+
+    	
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        
+        
+        
+        
+	    /**
+	     * Create the category
+	     */
+	    Category book = new Category();
+	    book.setMerchantStore(store);
+	    book.setCode("book");
+
+	    CategoryDescription bookEnglishDescription = new CategoryDescription();
+	    bookEnglishDescription.setName("Book");
+	    bookEnglishDescription.setCategory(book);
+	    bookEnglishDescription.setLanguage(en);
+
+
+
+	    List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+	    descriptions.add(bookEnglishDescription);
+
+
+	    book.setDescriptions(descriptions);
+
+	    categoryService.create(book);
+	    
+	    
+	    /**
+	     * Create a manufacturer
+	     */
+	    Manufacturer packed = new Manufacturer();
+	    packed.setMerchantStore(store);
+
+	    ManufacturerDescription packedd = new ManufacturerDescription();
+	    packedd.setLanguage(en);
+	    packedd.setManufacturer(packed);
+	    packedd.setName("Packed publishing");
+	    packed.getDescriptions().add(packedd);
+
+	    manufacturerService.create(packed);
+	    
+
+	    
+	    
+	    /**
+	     * Create the product
+	     */
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(1));
+	    product.setSku("TB12345");
+	    product.setManufacturer(packed);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Spring in Action");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    product.getCategories().add(book);
+	    
+	    
+	    //availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(date);
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+	    
+	    //price
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+	    
+	    
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    availability.getPrices().add(dprice);
+
+	  
+	    productService.create(product);
+        
+        
+   
+        
+        
+        final File file1 = new File( "/Users/csamson777/Documents/workspace2/files/images/watch.jpg" );
+
+        if ( !file1.exists() || !file1.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file1.getAbsolutePath() );
+        }
+
+        final byte[] is = IOUtils.toByteArray( new FileInputStream( file1 ) );
+        final ByteArrayInputStream inputStream = new ByteArrayInputStream( is );
+        final ImageContentFile cmsContentImage = new ImageContentFile();
+        cmsContentImage.setFileName( file1.getName() );
+        cmsContentImage.setFile( inputStream );
+        cmsContentImage.setFileContentType(FileContentType.PRODUCT);
+        
+
+        ProductImage productImage = new ProductImage();
+        productImage.setProductImage(file1.getName());
+        productImage.setProduct(product);
+
+        
+        productImageService.addProductImage(product, productImage, cmsContentImage);
+
+        //get productImage
+        productImage = productImageService.getById(productImage.getId());
+        
+        //get physical small image
+        OutputContentFile contentFile = productImageService.getProductImage(store.getCode(), product.getSku(), productImage.getProductImage(), ProductImageSize.SMALL);
+        
+        Assert.assertNotNull(contentFile);
+        
+        //print image
+   	 	OutputStream outputStream = new FileOutputStream ("/Users/csamson777/Documents/workspace2/files/images/small_" + contentFile.getFileName()); 
+
+   	 	ByteArrayOutputStream baos =  contentFile.getFile();
+   	 	baos.writeTo(outputStream);
+   	 	
+   	 	
+   	 	//get physical original image
+        contentFile = productImageService.getProductImage(store.getCode(), product.getSku(), productImage.getProductImage(), ProductImageSize.LARGE);
+        
+        Assert.assertNotNull(contentFile);
+        
+        //print image
+   	 	outputStream = new FileOutputStream ("/Users/csamson777/Documents/workspace2/files/images/large_" + contentFile.getFileName()); 
+
+   	 	baos =  contentFile.getFile();
+   	 	baos.writeTo(outputStream);
+   	 	
+   	 	//remove productImage
+   	 	productImageService.removeProductImage(productImage);
+   	 	
+   	 	
+
+	    
+	    
+
+	}
+	
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/catalog/ProductPriceTestCase.java b/sm-core/src/test/java/com/salesmanager/test/catalog/ProductPriceTestCase.java
new file mode 100644
index 0000000..cb39d19
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/catalog/ProductPriceTestCase.java
@@ -0,0 +1,60 @@
+package com.salesmanager.test.catalog;
+
+import java.math.BigDecimal;
+import java.util.Currency;
+import java.util.Date;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.utils.ProductPriceUtils;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class ProductPriceTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+	@Autowired
+	private ProductPriceUtils productPriceUtils;
+	
+	@Test
+	public void testPriceWithCurrency() throws Exception {
+		
+		
+		MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+		
+		/** specify currencies **/
+		
+		List<com.salesmanager.core.business.reference.currency.model.Currency> currencies = currencyService.list();
+		//countries iso codes -> http://userpage.chemie.fu-berlin.de/diverse/doc/ISO_3166.html
+		Country country = new Country();
+		country.setIsoCode("IN");
+		
+		
+		//iso languages codes -> http://www.loc.gov/standards/iso639-2/php/code_list.php
+		Language language = new Language();
+		language.setCode("en");
+		
+		store = new MerchantStore();
+		store.setCountry(country);
+		store.setDefaultLanguage(language);
+		
+		//all codes and examples -> http://www.xe.com/iso4217.php
+		Currency currency = Currency.getInstance("INR");
+		com.salesmanager.core.business.reference.currency.model.Currency c = new com.salesmanager.core.business.reference.currency.model.Currency();
+		c.setCurrency(currency);
+		store.setCurrency(c);
+		
+		String amount = productPriceUtils.getStoreFormatedAmountWithCurrency(store, new BigDecimal("12345"));
+		
+		Assert.assertNotNull(amount);
+		System.out.println(amount);
+		
+	}
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/catalog/SearchByProductAttributeTestCase.java b/sm-core/src/test/java/com/salesmanager/test/catalog/SearchByProductAttributeTestCase.java
new file mode 100644
index 0000000..b0ccfff
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/catalog/SearchByProductAttributeTestCase.java
@@ -0,0 +1,442 @@
+package com.salesmanager.test.catalog;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.ProductCriteria;
+import com.salesmanager.core.business.catalog.product.model.ProductList;
+import com.salesmanager.core.business.catalog.product.model.attribute.AttributeCriteria;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionDescription;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionType;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValueDescription;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class SearchByProductAttributeTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+
+	@Test
+	public void testFetchProductByAttribute() throws Exception {
+
+	    Language en = languageService.getByCode("en");
+
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+
+	    
+	    /** Categories **/
+	    
+	    Category book = new Category();
+	    book.setMerchantStore(store);
+	    book.setCode("book");
+
+	    CategoryDescription bookEnglishDescription = new CategoryDescription();
+	    bookEnglishDescription.setName("Book");
+	    bookEnglishDescription.setCategory(book);
+	    bookEnglishDescription.setLanguage(en);
+
+	    List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+	    descriptions.add(bookEnglishDescription);
+
+	    book.setDescriptions(descriptions);
+
+	    categoryService.create(book);
+
+
+	    Category novell = new Category();
+	    novell.setMerchantStore(store);
+	    novell.setCode("novell");
+
+	    CategoryDescription novellEnglishDescription = new CategoryDescription();
+	    novellEnglishDescription.setName("Novell");
+	    novellEnglishDescription.setCategory(novell);
+	    novellEnglishDescription.setLanguage(en);
+
+	    List<CategoryDescription> descriptions3 = new ArrayList<CategoryDescription>();
+	    descriptions3.add(novellEnglishDescription);
+
+	    novell.setDescriptions(descriptions3);
+	    
+	    novell.setParent(book);
+
+	    categoryService.create(novell);
+	    categoryService.addChild(book, novell);
+
+	    Category tech = new Category();
+	    tech.setMerchantStore(store);
+	    tech.setCode("tech");
+
+	    CategoryDescription techEnglishDescription = new CategoryDescription();
+	    techEnglishDescription.setName("Technology");
+	    techEnglishDescription.setCategory(tech);
+	    techEnglishDescription.setLanguage(en);
+
+	    List<CategoryDescription> descriptions4 = new ArrayList<CategoryDescription>();
+	    descriptions4.add(techEnglishDescription);
+
+	    tech.setDescriptions(descriptions4);
+	    
+	    tech.setParent(book);
+
+	    categoryService.create(tech);
+	    categoryService.addChild(book, tech);
+
+	    /** Manufacturers **/
+
+	    Manufacturer novells = new Manufacturer();
+	    novells.setMerchantStore(store);
+
+	    ManufacturerDescription novellsd = new ManufacturerDescription();
+	    novellsd.setLanguage(en);
+	    novellsd.setManufacturer(novells);
+	    novellsd.setName("Novells publishing");
+	    novells.getDescriptions().add(novellsd);
+
+	    manufacturerService.create(novells);
+	    
+	    
+	    Manufacturer manning = new Manufacturer();
+	    manning.setMerchantStore(store);
+
+	    ManufacturerDescription manningd = new ManufacturerDescription();
+	    manningd.setLanguage(en);
+	    manningd.setManufacturer(manning);
+	    manningd.setName("Manning publishing");
+	    manning.getDescriptions().add(manningd);
+
+	    manufacturerService.create(manning);
+	    
+	    //Author attribute
+	    ProductOption author = new ProductOption();
+	    author.setCode("author");
+	    author.setMerchantStore(store);
+	    author.setReadOnly(true);
+	    author.setProductOptionType(ProductOptionType.Text.name());
+	    
+	    
+	    ProductOptionDescription authorEnglishDescription = new ProductOptionDescription();
+	    authorEnglishDescription.setLanguage(en);
+	    authorEnglishDescription.setName("Author");
+	    authorEnglishDescription.setProductOption(author);
+	    
+	    author.getDescriptions().add(authorEnglishDescription);
+	    
+	    productOptionService.create(author);
+	    
+	    //Author name - Jimmy Jones
+	    ProductOptionValue jimmyjones = new ProductOptionValue();
+	    jimmyjones.setMerchantStore(store);
+	    jimmyjones.setCode("jimmyjones");
+	    jimmyjones.setProductOptionDisplayOnly(true);
+	    
+	    ProductOptionValueDescription jimmyjonesd = new ProductOptionValueDescription();
+	    jimmyjonesd.setLanguage(en);
+	    jimmyjonesd.setName("Jimmy Jones");//mandatory
+	    jimmyjonesd.setDescription("Jimmy Jones");//query is based on description
+	    jimmyjonesd.setProductOptionValue(jimmyjones);
+	    jimmyjones.getDescriptions().add(jimmyjonesd);
+	    
+	    productOptionValueService.create(jimmyjones);
+	    
+	    
+	    //Author name - Lucy Scott
+	    ProductOptionValue lucyscott = new ProductOptionValue();
+	    lucyscott.setMerchantStore(store);
+	    lucyscott.setCode("lucyscott");
+	    lucyscott.setProductOptionDisplayOnly(true);
+	    
+	    ProductOptionValueDescription lucyscottd = new ProductOptionValueDescription();
+	    lucyscottd.setLanguage(en);
+	    lucyscottd.setName("Lucy Scott");//mandatory
+	    lucyscottd.setDescription("Lucy Scott");//query is based on description
+	    lucyscottd.setProductOptionValue(lucyscott);
+	    lucyscott.getDescriptions().add(lucyscottd);
+	    
+	    productOptionValueService.create(lucyscott);
+	    
+	    //Author name - Carlos Santana Scott
+	    ProductOptionValue carlossantana = new ProductOptionValue();
+	    carlossantana.setMerchantStore(store);
+	    carlossantana.setCode("carlossantana");
+	    carlossantana.setProductOptionDisplayOnly(true);
+	    
+	    ProductOptionValueDescription carlossantanad = new ProductOptionValueDescription();
+	    carlossantanad.setLanguage(en);
+	    carlossantanad.setName("Carlos Santana");
+	    carlossantanad.setDescription("Carlos Santana");
+	    carlossantanad.setProductOptionValue(carlossantana);
+	    carlossantana.getDescriptions().add(carlossantanad);
+	    
+	    productOptionValueService.create(carlossantana);
+	    
+	    
+	    // PRODUCT 1 - technical book
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(1));
+	    product.setSku("TB12345");
+	    product.setManufacturer(manning);
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Spring in Action");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+
+	    product.getCategories().add(tech);
+
+	    productService.create(product);
+
+	    // Availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(date);
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+
+	    productAvailabilityService.create(availability);
+
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice);
+	    
+
+	    //set author attribute
+	    ProductAttribute product1Author = new ProductAttribute();
+	    product1Author.setAttributeDisplayOnly(true);
+	    product1Author.setProduct(product);
+	    product1Author.setProductOption(author);
+	    product1Author.setProductOptionValue(jimmyjones);
+	    
+	    productAttributeService.create(product1Author);
+	    
+	    
+
+	    // PRODUCT 2 - technical book
+
+	    Product product2 = new Product();
+	    product2.setProductHeight(new BigDecimal(4));
+	    product2.setProductLength(new BigDecimal(3));
+	    product2.setProductWidth(new BigDecimal(1));
+	    product2.setSku("TB2468");
+	    product2.setManufacturer(manning);
+	    product2.setType(generalType);
+	    product2.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("This is Node.js");
+	    description.setLanguage(en);
+	    description.setProduct(product2);
+
+	    product2.getDescriptions().add(description);
+
+	    product2.getCategories().add(tech);
+	    productService.create(product2);
+
+	    // Availability
+	    ProductAvailability availability2 = new ProductAvailability();
+	    availability2.setProductDateAvailable(date);
+	    availability2.setProductQuantity(100);
+	    availability2.setRegion("*");
+	    availability2.setProduct(product2);// associate with product
+
+	    productAvailabilityService.create(availability2);
+
+	    ProductPrice dprice2 = new ProductPrice();
+	    dprice2.setDefaultPrice(true);
+	    dprice2.setProductPriceAmount(new BigDecimal(39.99));
+	    dprice2.setProductAvailability(availability2);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice2);
+	    dpd.setLanguage(en);
+
+	    dprice2.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice2);
+	    
+	    //set author attribute
+	    ProductAttribute product2Author = new ProductAttribute();
+	    product2Author.setAttributeDisplayOnly(true);
+	    product2Author.setProduct(product2);
+	    product2Author.setProductOption(author);
+	    product2Author.setProductOptionValue(jimmyjones);
+	    
+	    productAttributeService.create(product2Author);
+
+	    // PRODUCT 3 - Novell
+
+	    Product product3 = new Product();
+	    product3.setProductHeight(new BigDecimal(4));
+	    product3.setProductLength(new BigDecimal(3));
+	    product3.setProductWidth(new BigDecimal(1));
+	    product3.setSku("NB1111");
+	    product3.setManufacturer(novells);
+	    product3.setType(generalType);
+	    product3.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("A nice book for you");
+	    description.setLanguage(en);
+	    description.setProduct(product3);
+
+	    product3.getDescriptions().add(description);
+
+	    product3.getCategories().add(novell);
+	    productService.create(product3);
+
+	    // Availability
+	    ProductAvailability availability3 = new ProductAvailability();
+	    availability3.setProductDateAvailable(date);
+	    availability3.setProductQuantity(100);
+	    availability3.setRegion("*");
+	    availability3.setProduct(product3);// associate with product
+
+	    productAvailabilityService.create(availability3);
+
+	    ProductPrice dprice3 = new ProductPrice();
+	    dprice3.setDefaultPrice(true);
+	    dprice3.setProductPriceAmount(new BigDecimal(19.99));
+	    dprice3.setProductAvailability(availability3);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice3);
+	    dpd.setLanguage(en);
+
+	    dprice3.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice3);
+	    
+	    //set author attribute
+	    ProductAttribute product3Author = new ProductAttribute();
+	    product3Author.setAttributeDisplayOnly(true);
+	    product3Author.setProduct(product3);
+	    product3Author.setProductOption(author);
+	    product3Author.setProductOptionValue(lucyscott);
+	    
+	    productAttributeService.create(product3Author);
+	    
+	    
+	    // PRODUCT 4 - Novell
+
+	    Product product4 = new Product();
+	    product4.setProductHeight(new BigDecimal(4));
+	    product4.setProductLength(new BigDecimal(3));
+	    product4.setProductWidth(new BigDecimal(1));
+	    product4.setSku("NB1111678");
+	    product4.setManufacturer(novells);
+	    product4.setType(generalType);
+	    product4.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("Look at the sky");
+	    description.setLanguage(en);
+	    description.setProduct(product4);
+
+	    product4.getDescriptions().add(description);
+
+	    product4.getCategories().add(novell);
+	    productService.create(product4);
+
+	    // Availability
+	    ProductAvailability availability4 = new ProductAvailability();
+	    availability4.setProductDateAvailable(date);
+	    availability4.setProductQuantity(100);
+	    availability4.setRegion("*");
+	    availability4.setProduct(product4);// associate with product
+
+	    productAvailabilityService.create(availability4);
+
+	    ProductPrice dprice4 = new ProductPrice();
+	    dprice4.setDefaultPrice(true);
+	    dprice4.setProductPriceAmount(new BigDecimal(17.99));
+	    dprice4.setProductAvailability(availability4);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice4);
+	    dpd.setLanguage(en);
+
+	    dprice4.getDescriptions().add(dpd);
+
+	    productPriceService.create(dprice4);
+	    
+	    //set author attribute
+	    ProductAttribute product4Author = new ProductAttribute();
+	    product4Author.setAttributeDisplayOnly(true);
+	    product4Author.setProduct(product4);
+	    product4Author.setProductOption(author);
+	    product4Author.setProductOptionValue(carlossantana);
+	    
+	    productAttributeService.create(product4Author);
+	    
+	    
+	    
+	    //get product by author Jimmy Jones
+	    ProductCriteria fetchCriteria = new ProductCriteria();
+	    //fetchCriteria.setCode("TB1234");
+	    
+	    List<AttributeCriteria> attributesCriteriaList = new ArrayList<AttributeCriteria>();
+	    
+	    AttributeCriteria fetchAttributeCriteria = new AttributeCriteria();
+	    fetchAttributeCriteria.setAttributeCode("author");
+	    fetchAttributeCriteria.setAttributeValue("Jimmy Jones");
+
+	    attributesCriteriaList.add(fetchAttributeCriteria);
+ 
+	    
+	    fetchCriteria.setAttributeCriteria(attributesCriteriaList);
+	    
+	    ProductList productList = productService.listByStore(store, en, fetchCriteria);
+	    
+	    Assert.assertNotNull(productList.getProducts());
+	    
+	    System.out.println(productList.getProducts().size());//should be 2
+	    
+	    
+		
+	}
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/content/ContentImagesTestCase.java b/sm-core/src/test/java/com/salesmanager/test/content/ContentImagesTestCase.java
new file mode 100644
index 0000000..921d9df
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/content/ContentImagesTestCase.java
@@ -0,0 +1,220 @@
+package com.salesmanager.test.content;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Date;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.content.service.ContentService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+
+
+
+/**
+ * Test 
+ * store logo
+ * @author Carl Samson
+ *
+ */
+
+public class ContentImagesTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+	@Autowired
+	private ContentService contentService;
+	
+
+	
+    @Test
+    public void createStoreLogo()
+        throws ServiceException, FileNotFoundException, IOException
+    {
+
+        MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final File file1 = new File( "/Users/csamson777/Pictures/peavey.jpg" );
+
+        if ( !file1.exists() || !file1.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file1.getAbsolutePath() );
+        }
+
+        byte[] is = IOUtils.toByteArray( new FileInputStream( file1 ) );
+        ByteArrayInputStream inputStream = new ByteArrayInputStream( is );
+        InputContentFile cmsContentImage = new InputContentFile();
+
+        cmsContentImage.setFileName( file1.getName() );
+        cmsContentImage.setFile(inputStream);
+ 
+		
+        //logo as a content
+        contentService.addLogo(store.getCode(), cmsContentImage);
+        
+        store.setStoreLogo(file1.getName() );
+        merchantService.update(store);
+        
+        //query the store
+        store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        
+        
+        
+        //get the logo
+        String logo = store.getStoreLogo();
+
+		OutputContentFile image =contentService.getContentFile(store.getCode(), FileContentType.LOGO, logo);
+
+        //print image
+   	 	OutputStream outputStream = new FileOutputStream ("/Users/csamson777/Pictures/mexique" + image.getFileName()); 
+
+   	 	ByteArrayOutputStream baos =  image.getFile();
+   	 	baos.writeTo(outputStream);
+		
+		
+		//remove image
+   	 	contentService.removeFile(store.getCode(), FileContentType.LOGO, store.getStoreLogo());
+		
+
+
+    }
+	
+	
+
+/*    
+    @Test
+    public void createContentImages()
+        throws ServiceException, FileNotFoundException, IOException
+    {
+
+        final List<CMSContentImage> contentImagesList=new ArrayList<CMSContentImage>();
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final File file1 = new File( "/Umesh/contentimage/destination.png" );
+
+        if ( !file1.exists() || !file1.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file1.getAbsolutePath() );
+        }
+
+        final byte[] is = IOUtils.toByteArray( new FileInputStream( file1 ) );
+        final ByteArrayInputStream inputStream = new ByteArrayInputStream( is );
+        final CMSContentImage cmsContentImage = new CMSContentImage();
+        cmsContentImage.setImageName( "demoCmsImage3" );
+        cmsContentImage.setFile( inputStream );
+        contentImagesList.add( cmsContentImage);
+        
+        final CMSContentImage cmsContentImage1 = new CMSContentImage();
+        cmsContentImage1.setImageName( "demoCmsImage4" );
+        cmsContentImage1.setFile( inputStream );
+        
+        contentImagesList.add( cmsContentImage1);
+        
+        //contentService.addContentImages( store.getCode(), contentImagesList );
+
+    }
+
+    @Test
+    public void getContentImage()
+        throws ServiceException, FileNotFoundException, IOException
+    {
+
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final String imageName = "demoCmsImage";
+
+        final OutputContentFile outputContentImage = contentService.getContentImage(store.getCode(), FileContentType.IMAGE, imageName );
+        //final OutputContentImage outputContentImage = contentService.getContentImage( store, "" );
+        System.out.println( outputContentImage.getFile() );
+        System.out.println( outputContentImage.getFileName() );
+
+    }
+    
+    @Test
+    public void getAllContentImages() throws ServiceException{
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final List<OutputContentFile> contentImagesList= contentService.getContentImages(store.getCode(), null );
+        if(CollectionUtils.isNotEmpty( contentImagesList )){
+            System.out.println("Total " + contentImagesList.size()+ " Images found");
+           for(final OutputContentFile outputContentImage :contentImagesList){
+               System.out.println(outputContentImage.getFileName());
+           }
+        }
+        else{
+            System.out.println("No image found for given merchant store");
+        }
+    }
+    
+    @Test
+    public void removeContentImage() throws ServiceException{
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final InputContentFile contentImage = new InputContentFile( );
+        contentImage.setFileContentType(FileContentType.IMAGE );
+        contentImage.setFileName("demoCmsImage");
+        //contentService.removeImage( store.getCode(), contentImage );
+        
+    }
+    
+    @Test
+    public void removeAllContentImages() throws ServiceException{
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        contentService.removeImages( store.getCode());
+    }
+    
+
+    @Test
+    public void getContentImagesNames() throws Exception{
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final List<String> imageNames = contentService.getContentImagesNames(store.getCode(),FileContentType.IMAGE);
+        for(final String imageName:imageNames){
+            System.out.println(imageName);
+        }
+    }
+    
+    @Test
+    public void testGetImages()
+        throws ServiceException
+    {
+
+        final Product product = productService.getById( 1L );
+
+        final List<OutputContentFile> images = productImageService.getProductImages( product );
+
+        for ( final OutputContentFile image : images )
+        {
+
+            System.out.println( image.getFileName() );
+            System.out.println( image.getFileContentType() );
+        }
+
+    }
+	
+	
+	
+	
+	@Test
+	public void testCreateContentImage() throws ServiceException {
+		
+	    Language en = languageService.getByCode("en");
+	    Country country = countryService.getByCode("CA");
+	    Zone zone = zoneService.getByCode("QC");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+	    
+
+	}
+	*/
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/content/StaticContentTestCase.java b/sm-core/src/test/java/com/salesmanager/test/content/StaticContentTestCase.java
new file mode 100644
index 0000000..3b56cc0
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/content/StaticContentTestCase.java
@@ -0,0 +1,190 @@
+package com.salesmanager.test.content;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.content.model.FileContentType;
+import com.salesmanager.core.business.content.model.InputContentFile;
+import com.salesmanager.core.business.content.model.OutputContentFile;
+import com.salesmanager.core.business.content.service.ContentService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+/**
+ * Test 
+ * 
+ * - static content files (.js, .pdf etc)
+ * - static content images (jpg, gig ...)
+ * @author Carl Samson
+ *
+ */
+public class StaticContentTestCase extends AbstractSalesManagerCoreTestCase {
+	
+
+	@Autowired
+	private ContentService contentService;
+	
+	
+    @Test
+    public void createImage()
+        throws ServiceException, FileNotFoundException, IOException
+    {
+
+        MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final File file1 = new File( "c:/doc/carl/shirt3.jpg" );
+
+        if ( !file1.exists() || !file1.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file1.getAbsolutePath() );
+        }
+
+        final byte[] is = IOUtils.toByteArray( new FileInputStream( file1 ) );
+        final ByteArrayInputStream inputStream = new ByteArrayInputStream( is );
+        final InputContentFile cmsContentImage = new InputContentFile();
+        cmsContentImage.setFileName( file1.getName() );
+        cmsContentImage.setFile( inputStream );
+        cmsContentImage.setFileContentType(FileContentType.IMAGE);
+        
+        //Add image
+        contentService.addContentFile(store.getCode(), cmsContentImage);
+
+    
+        //get image
+		OutputContentFile image = contentService.getContentFile(store.getCode(), FileContentType.IMAGE, file1.getName());
+
+        //print image
+   	 	OutputStream outputStream = new FileOutputStream ("c:/TEMP/" + image.getFileName()); 
+
+   	 	ByteArrayOutputStream baos =  image.getFile();
+   	 	baos.writeTo(outputStream);
+		
+		
+		//remove image
+   	 	contentService.removeFile(store.getCode(), FileContentType.IMAGE, file1.getName());
+		
+
+
+    }
+	
+	@Test
+	public void testCreateStaticContent() throws Exception {
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+        final File file = new File( "c:/doc/carl/cdbaby.zip" );
+
+        if ( !file.exists() || !file.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file.getAbsolutePath() );
+        }
+
+        byte[] is;
+        ByteArrayInputStream inputStream = null;
+
+		is = IOUtils.toByteArray( new FileInputStream( file ) );
+		inputStream = new ByteArrayInputStream( is );
+
+	     InputContentFile staticContent = new InputContentFile();
+	     staticContent.setFile(inputStream);
+	     staticContent.setFileName(file.getName());
+	     staticContent.setFileContentType(FileContentType.STATIC_FILE);//default to static data
+        
+	     contentService.addContentFile(store.getCode(), staticContent);
+	     
+	     //staticContentService.getFile(store, FileContentType.STATIC_FILE, file.getName());
+
+        //now get the file
+	     
+/*	     OutputStaticContentData getData = staticContentService.getStaticContentData(store, StaticContentType.STATIC_DATA ,file.getName());
+	     Assert.assertNotNull(getData);
+	     if(getData != null) {
+	    	 
+	    	 System.out.println(getData.getFileName());
+	    	 System.out.println(getData.getFileContentType());
+	    	 
+	    	 OutputStream outputStream = new FileOutputStream ("c:/tmp/" + getData.getFileName()); 
+
+	    	 ByteArrayOutputStream baos =  getData.getFile();
+	    	 baos.writeTo(outputStream);
+	    	 
+	     }*/
+	     
+	     //remove the file
+	     
+	     //staticContentService.removeFile(store, FileContentType.STATIC_FILE, file.getName());
+
+	}
+	
+	@Test
+	public void testCreateMultipleStaticContent() throws Exception {
+		
+		
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+	    
+	    // FILE 1
+        final File file = new File( "c:/doc/carl/cdbaby.zip" );
+
+        if ( !file.exists() || !file.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file.getAbsolutePath() );
+        }
+
+        byte[] is;
+        ByteArrayInputStream inputStream = null;
+
+		is = IOUtils.toByteArray( new FileInputStream( file ) );
+		inputStream = new ByteArrayInputStream( is );
+
+	    InputContentFile staticContent = new InputContentFile();
+	    staticContent.setFile(inputStream);
+	    staticContent.setFileName(file.getName());
+	    staticContent.setFileContentType(FileContentType.STATIC_FILE);//default to static data
+	    
+	    
+	    // FILE 2
+        final File file2 = new File( "c:/doc/carl/Cocoa - Requirements.doc" );
+
+        if ( !file2.exists() || !file2.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file2.getAbsolutePath() );
+        }
+
+        byte[] is2;
+        ByteArrayInputStream inputStream2 = null;
+
+		is2 = IOUtils.toByteArray( new FileInputStream( file2 ) );
+		inputStream2 = new ByteArrayInputStream( is2 );
+
+		InputContentFile staticContent2 = new InputContentFile();
+	    staticContent2.setFile(inputStream2);
+	    staticContent2.setFileName(file2.getName());
+	    staticContent2.setFileContentType(FileContentType.STATIC_FILE);//default to static data
+	    
+	    List<InputContentFile> staticFiles = new ArrayList<InputContentFile>();
+	    staticFiles.add(staticContent);
+	    staticFiles.add(staticContent2);
+		
+	    contentService.addContentFiles(store.getCode(), staticFiles);
+	    
+	    //get file names
+	    //staticContentService.get
+		
+		
+	}
+	
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/content/WebsiteContentTestCase.java b/sm-core/src/test/java/com/salesmanager/test/content/WebsiteContentTestCase.java
new file mode 100644
index 0000000..e7483f5
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/content/WebsiteContentTestCase.java
@@ -0,0 +1,55 @@
+package com.salesmanager.test.content;
+
+import java.util.Date;
+
+
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.content.service.ContentService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+
+
+
+
+public class WebsiteContentTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+	@Autowired
+	private ContentService contentService;
+	
+	@Test
+	public void testCreateContentPage() throws ServiceException {
+		
+	    Language en = languageService.getByCode("en");
+	    Country country = countryService.getByCode("CA");
+	    Zone zone = zoneService.getByCode("QC");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+	    
+
+	}
+	
+	public void testCreateContentBox() throws ServiceException {
+		
+	    Language en = languageService.getByCode("en");
+	    Country country = countryService.getByCode("CA");
+	    Zone zone = zoneService.getByCode("QC");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+	    
+
+	}
+	
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/core/AbstractSalesManagerCoreTestCase.java b/sm-core/src/test/java/com/salesmanager/test/core/AbstractSalesManagerCoreTestCase.java
new file mode 100644
index 0000000..08fbc81
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/core/AbstractSalesManagerCoreTestCase.java
@@ -0,0 +1,178 @@
+package com.salesmanager.test.core;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+
+import com.salesmanager.core.business.catalog.category.service.CategoryService;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.catalog.product.service.ProductService;
+import com.salesmanager.core.business.catalog.product.service.attribute.ProductAttributeService;
+import com.salesmanager.core.business.catalog.product.service.attribute.ProductOptionService;
+import com.salesmanager.core.business.catalog.product.service.attribute.ProductOptionValueService;
+import com.salesmanager.core.business.catalog.product.service.availability.ProductAvailabilityService;
+import com.salesmanager.core.business.catalog.product.service.image.ProductImageService;
+import com.salesmanager.core.business.catalog.product.service.manufacturer.ManufacturerService;
+import com.salesmanager.core.business.catalog.product.service.price.ProductPriceService;
+import com.salesmanager.core.business.catalog.product.service.review.ProductReviewService;
+import com.salesmanager.core.business.catalog.product.service.type.ProductTypeService;
+import com.salesmanager.core.business.customer.service.CustomerService;
+import com.salesmanager.core.business.customer.service.attribute.CustomerOptionService;
+import com.salesmanager.core.business.customer.service.attribute.CustomerOptionSetService;
+import com.salesmanager.core.business.customer.service.attribute.CustomerOptionValueService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.util.EntityManagerUtils;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.merchant.service.MerchantStoreService;
+import com.salesmanager.core.business.order.service.OrderService;
+import com.salesmanager.core.business.payments.service.PaymentService;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.currency.service.CurrencyService;
+import com.salesmanager.core.business.reference.init.service.InitializationDatabase;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.reference.zone.service.ZoneService;
+import com.salesmanager.core.business.shoppingcart.service.ShoppingCartService;
+import com.salesmanager.core.business.system.service.EmailService;
+
+@ContextConfiguration(locations = {
+		"classpath:spring/test-spring-context.xml"
+})
+@RunWith(SpringJUnit4ClassRunner.class)
+@TestExecutionListeners({
+	DependencyInjectionTestExecutionListener.class,
+	SalesManagerCoreTestExecutionListener.class
+})
+public abstract class AbstractSalesManagerCoreTestCase {
+	
+	
+	@Autowired
+	protected InitializationDatabase                initializationDatabase;
+	  
+	
+	protected static final String ENGLISH_LANGUAGE_CODE = "en";
+	
+	protected static final String FRENCH_LANGUAGE_CODE = "fr";
+	
+	protected static final String EURO_CURRENCY_CODE = "EUR";
+	
+	protected static final String FR_COUNTRY_CODE = "FR";
+	
+	protected static final String CAD_CURRENCY_CODE = "CAD";
+	
+	protected static final String CA_COUNTRY_CODE = "CA";
+	
+	protected static final String VT_ZONE_CODE = "VT";
+	
+	@Autowired
+	private EntityManagerUtils entityManagerUtils;
+	
+	@Autowired
+	protected ProductService productService;
+
+	
+	@Autowired
+	protected ProductPriceService productPriceService;
+	
+	@Autowired
+	protected ProductAttributeService productAttributeService;
+	
+	@Autowired
+	protected ProductOptionService productOptionService;
+	
+	@Autowired
+	protected ProductOptionValueService productOptionValueService;
+	
+	@Autowired
+	protected ProductAvailabilityService productAvailabilityService;
+	
+	@Autowired
+	protected ProductReviewService productReviewService;
+	
+	@Autowired
+	protected ProductImageService productImageService;
+	
+	@Autowired
+	protected CategoryService categoryService;
+	
+	@Autowired
+	protected MerchantStoreService merchantService;
+	
+	@Autowired
+	protected ProductTypeService productTypeService;
+	
+	@Autowired
+	protected LanguageService languageService;
+	
+	@Autowired
+	protected CountryService countryService;
+	
+	@Autowired
+	protected CurrencyService currencyService;
+	
+	@Autowired
+	protected ManufacturerService manufacturerService;
+	
+	@Autowired
+	protected ZoneService zoneService;
+	
+	@Autowired
+	protected CustomerService customerService;
+	
+	@Autowired
+	protected CustomerOptionService customerOptionService;
+	
+	@Autowired
+	protected CustomerOptionValueService customerOptionValueService;
+	
+	@Autowired
+	protected CustomerOptionSetService customerOptionSetService;
+	
+	@Autowired
+	protected OrderService orderService;
+	
+	@Autowired
+	protected PaymentService paymentService;
+	
+	@Autowired
+	protected ShoppingCartService shoppingCartService;
+	
+	@Autowired
+	protected EmailService emailService;
+
+
+	@Before
+	public void init() throws ServiceException {
+		
+		populate();
+
+	}
+	
+	@After
+	public void close() throws ServiceException {
+
+	}
+	
+
+	
+	private void populate() throws ServiceException {
+		
+		
+		initializationDatabase.populate("TEST");
+		
+
+	}
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/core/SalesManagerCoreTestExecutionListener.java b/sm-core/src/test/java/com/salesmanager/test/core/SalesManagerCoreTestExecutionListener.java
new file mode 100644
index 0000000..a7ea63e
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/core/SalesManagerCoreTestExecutionListener.java
@@ -0,0 +1,29 @@
+package com.salesmanager.test.core;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.TestContext;
+import org.springframework.test.context.support.AbstractTestExecutionListener;
+
+import com.salesmanager.core.business.generic.util.EntityManagerUtils;
+
+public class SalesManagerCoreTestExecutionListener extends AbstractTestExecutionListener {
+	
+	@Autowired
+	private EntityManagerUtils entityManagerUtils;
+	
+	@Override
+	public void beforeTestClass(TestContext testContext) throws Exception {
+		testContext.getApplicationContext().getAutowireCapableBeanFactory().autowireBean(this);
+	}
+
+	@Override
+	public void beforeTestMethod(TestContext testContext) throws Exception {
+		entityManagerUtils.openEntityManager();
+	}
+
+	@Override
+	public void afterTestMethod(TestContext testContext) throws Exception {
+		entityManagerUtils.closeEntityManager();
+	}
+
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/customer/CustomerOptionsTestCase.java b/sm-core/src/test/java/com/salesmanager/test/customer/CustomerOptionsTestCase.java
new file mode 100644
index 0000000..d50facb
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/customer/CustomerOptionsTestCase.java
@@ -0,0 +1,198 @@
+package com.salesmanager.test.customer;
+
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import com.salesmanager.core.business.common.model.Billing;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerGender;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOption;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionDescription;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionSet;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionValue;
+import com.salesmanager.core.business.customer.model.attribute.CustomerOptionValueDescription;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class CustomerOptionsTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	@Test
+	public void testCreateAndGetCustomerOptions() throws ServiceException {
+		
+		
+		MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+		Country country = countryService.getByCode("CA");
+		Zone zone = zoneService.getByCode("VT");
+		Language en = languageService.getByCode("en");
+		
+		Customer customer = new Customer();
+		customer.setMerchantStore(store);
+		customer.setEmailAddress("test@test.com");
+		customer.setGender(CustomerGender.M);
+
+		customer.setAnonymous(true);
+		customer.setCompany("ifactory");
+		customer.setDateOfBirth(new Date());
+		customer.setNick("My nick");
+		customer.setPassword("123456");
+
+		customer.setDefaultLanguage(store.getDefaultLanguage());
+		
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("Shipping address");
+	    delivery.setCountry(country);
+	    delivery.setZone(zone);
+	    
+	    
+	    Billing billing = new Billing();
+	    billing.setAddress("Billing address");
+	    billing.setCountry(country);
+	    billing.setZone(zone);
+	    
+	    customer.setBilling(billing);
+	    customer.setDelivery(delivery);
+		
+		customerService.create(customer);
+		customer = customerService.getById(customer.getId());
+
+		
+		//create option value
+		CustomerOptionValue yes = new CustomerOptionValue();
+		yes.setCode("yes");
+		yes.setMerchantStore(store);
+		CustomerOptionValueDescription yesDescription = new CustomerOptionValueDescription();
+		yesDescription.setLanguage(en);
+		yesDescription.setCustomerOptionValue(yes);
+		
+		customerOptionValueService.create(yes);
+		
+		CustomerOptionValue no = new CustomerOptionValue();
+		no.setCode("no");
+		no.setMerchantStore(store);
+		CustomerOptionValueDescription noDescription = new CustomerOptionValueDescription();
+		noDescription.setLanguage(en);
+		noDescription.setCustomerOptionValue(no);
+		
+		customerOptionValueService.create(no);
+		
+		CustomerOption subscribedToMailingList = new CustomerOption();
+		subscribedToMailingList.setActive(true);
+		subscribedToMailingList.setPublicOption(true);
+		subscribedToMailingList.setCode("subscribedToMailingList");
+		subscribedToMailingList.setMerchantStore(store);
+		
+		CustomerOptionDescription mailingListDesciption= new CustomerOptionDescription();
+		mailingListDesciption.setName("Subscribed to mailing list");
+		mailingListDesciption.setDescription("Subscribed to mailing list");
+		mailingListDesciption.setLanguage(en);
+		mailingListDesciption.setCustomerOption(subscribedToMailingList);
+		
+		Set<CustomerOptionDescription> mailingListDesciptionList = new HashSet<CustomerOptionDescription>();
+		mailingListDesciptionList.add(mailingListDesciption);
+		subscribedToMailingList.setDescriptions(mailingListDesciptionList);
+		
+		customerOptionService.create(subscribedToMailingList);
+		
+		
+		
+		CustomerOption hasReturnedItems = new CustomerOption();
+		hasReturnedItems.setActive(true);
+		hasReturnedItems.setPublicOption(true);
+		hasReturnedItems.setCode("hasReturnedItems");
+		hasReturnedItems.setMerchantStore(store);
+		
+		CustomerOptionDescription hasReturnedItemsDesciption= new CustomerOptionDescription();
+		hasReturnedItemsDesciption.setName("Has returned items");
+		hasReturnedItemsDesciption.setDescription("Has returned items");
+		hasReturnedItemsDesciption.setLanguage(en);
+		hasReturnedItemsDesciption.setCustomerOption(hasReturnedItems);
+		
+		Set<CustomerOptionDescription> hasReturnedItemsList = new HashSet<CustomerOptionDescription>();
+		hasReturnedItemsList.add(hasReturnedItemsDesciption);
+		hasReturnedItems.setDescriptions(hasReturnedItemsList);
+
+		customerOptionService.create(hasReturnedItems);
+		
+		subscribedToMailingList.setSortOrder(3);
+		
+		customerOptionService.update(subscribedToMailingList);
+		
+		
+/*		CustomerOptionSetId mailingListSetYesId = new CustomerOptionSetId();
+		mailingListSetYesId.setCustomerOption(subscribedToMailingList);
+		mailingListSetYesId.setCustomerOptionValue(yes);*/
+		
+		CustomerOptionSet mailingListSetYes = new CustomerOptionSet();
+		
+		//mailingListSetYes.setPk(mailingListSetYesId);
+		mailingListSetYes.setSortOrder(0);
+		mailingListSetYes.setCustomerOption(subscribedToMailingList);
+		mailingListSetYes.setCustomerOptionValue(yes);
+		
+		customerOptionSetService.create(mailingListSetYes);
+		//subscribedToMailingList.getCustomerOptions().add(mailingListSetYes);
+		//customerOptionService.update(subscribedToMailingList);
+		
+/*		CustomerOptionSetId mailingListSetNoId = new CustomerOptionSetId();
+		mailingListSetNoId.setCustomerOption(subscribedToMailingList);
+		mailingListSetNoId.setCustomerOptionValue(no);*/
+		
+		CustomerOptionSet mailingListSetNo = new CustomerOptionSet();
+		//mailingListSetNo.setPk(mailingListSetNoId);
+		mailingListSetNo.setSortOrder(1);
+		mailingListSetNo.setCustomerOption(subscribedToMailingList);
+		mailingListSetNo.setCustomerOptionValue(no);
+		
+		customerOptionSetService.create(mailingListSetNo);
+		
+		//subscribedToMailingList.getCustomerOptions().add(mailingListSetNo);
+		//customerOptionService.update(subscribedToMailingList);
+		
+		
+/*		CustomerOptionSetId hasReturnedItemsYesId = new CustomerOptionSetId();
+		hasReturnedItemsYesId.setCustomerOption(hasReturnedItems);
+		hasReturnedItemsYesId.setCustomerOptionValue(yes);*/
+		
+		CustomerOptionSet hasReturnedItemsYes = new CustomerOptionSet();
+		//hasReturnedItemsYes.setPk(hasReturnedItemsYesId);
+		hasReturnedItemsYes.setSortOrder(0);
+		hasReturnedItemsYes.setCustomerOption(hasReturnedItems);
+		hasReturnedItemsYes.setCustomerOptionValue(yes);
+		
+		customerOptionSetService.create(hasReturnedItemsYes);
+		
+		
+		//hasReturnedItems.getCustomerOptions().add(hasReturnedItemsYes);
+		//customerOptionService.update(hasReturnedItems);
+		
+		subscribedToMailingList.setSortOrder(2);
+		customerOptionService.update(subscribedToMailingList);
+		
+		CustomerOption option = customerOptionService.getById(subscribedToMailingList.getId());
+		
+		option.setSortOrder(4);
+		customerOptionService.update(option);
+		
+		List<CustomerOptionSet> optionSetList = customerOptionSetService.listByStore(store, en);
+		
+		//Assert.assertEquals(3, optionSetList.size());
+		System.out.println("Size of options : " + optionSetList.size());
+		
+
+		
+		
+		
+		
+	}
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/customer/CustomerSalesManagerTestCase.java b/sm-core/src/test/java/com/salesmanager/test/customer/CustomerSalesManagerTestCase.java
new file mode 100644
index 0000000..d686c8e
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/customer/CustomerSalesManagerTestCase.java
@@ -0,0 +1,69 @@
+package com.salesmanager.test.customer;
+
+import java.util.Date;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import com.salesmanager.core.business.common.model.Billing;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerGender;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class CustomerSalesManagerTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	@Test
+	public void createCustomer() throws ServiceException {
+		
+		
+		MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+		Country country = countryService.getByCode("CA");
+		Zone zone = zoneService.getByCode("VT");
+		
+		Customer customer = new Customer();
+		customer.setMerchantStore(store);
+		customer.setEmailAddress("test@test.com");
+		customer.setGender(CustomerGender.M);
+
+		customer.setAnonymous(true);
+		customer.setCompany("ifactory");
+		customer.setDateOfBirth(new Date());
+		customer.setNick("My nick");
+		customer.setPassword("123456");
+		customer.setDefaultLanguage(store.getDefaultLanguage());
+		
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("Shipping address");
+	    delivery.setCountry(country);
+	    delivery.setZone(zone);
+	    
+	    
+	    Billing billing = new Billing();
+	    billing.setFirstName("John");
+	    billing.setLastName("Bossanova");
+	    billing.setAddress("Billing address");
+	    billing.setCountry(country);
+	    billing.setZone(zone);
+	    
+	    customer.setBilling(billing);
+	    customer.setDelivery(delivery);
+		
+		customerService.create(customer);
+		customer = customerService.getById(customer.getId());
+		String countryCode = customer.getBilling().getCountry().getIsoCode();
+		String zoneCode = customer.getBilling().getZone().getCode();
+		System.out.println(countryCode + zoneCode);
+		
+		Assert.assertEquals(countryCode, "CA");
+		Assert.assertEquals(zoneCode, "VT");
+		Assert.assertTrue(customerService.count() == 1);
+		Assert.assertNotNull(customerService.getByName("Leonardo"));
+		
+	}
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/email/EmailTestCase.java b/sm-core/src/test/java/com/salesmanager/test/email/EmailTestCase.java
new file mode 100644
index 0000000..500d211
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/email/EmailTestCase.java
@@ -0,0 +1,47 @@
+package com.salesmanager.test.email;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.modules.email.Email;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class EmailTestCase extends AbstractSalesManagerCoreTestCase {
+
+	@Test
+	public void sendHtmlEmail() throws Exception {
+		
+		Map<String, String> templateTokens = new HashMap<String, String>();
+		templateTokens.put("EMAIL_NEW_USER_TEXT", "Hi My Friend,");
+		templateTokens.put("EMAIL_STORE_NAME", "Shopizer Store");
+		templateTokens.put("EMAIL_ADMIN_LABEL", "Adminstrator:");
+		templateTokens.put("EMAIL_TEXT_NEW_USER_CREATED", "New user created");
+		templateTokens.put("EMAIL_CUSTOMER_FIRSTNAME", "The");
+		templateTokens.put("EMAIL_CUSTOMER_LAST", "Rock");
+		templateTokens.put("EMAIL_ADMIN_USERNAME_LABEL", "UserName:");
+		templateTokens.put("EMAIL_ADMIN_NAME", "Admin");
+		templateTokens.put("EMAIL_ADMIN_PASSWORD_LABEL", "Password:");
+		templateTokens.put("EMAIL_ADMIN_PASSWORD", "12345");
+		templateTokens.put("EMAIL_ADMIN_URL_LABEL", "URL:");
+		templateTokens.put("EMAIL_ADMIN_URL", "http://www.shopizer.com");
+		templateTokens.put("EMAIL_FOOTER_COPYRIGHT", "Copyright @ Shopizer 2013, All Rights Reserved!");
+		templateTokens.put("EMAIL_DISCLAIMER", "Disclaimer text goes here...");
+		templateTokens.put("EMAIL_SPAM_DISCLAIMER", "Spam Disclaimer text goes here...");
+		
+		
+		Email email = new Email();
+		email.setFrom("Shopizer");
+		email.setFromEmail("admin@shopizer.com");
+		email.setSubject("HTML Test Mail");
+		email.setTo("carl@csticonsulting.com");
+		email.setTemplateName("email_template_new_user.ftl");
+		email.setTemplateTokens(templateTokens);
+		
+		MerchantStore store = merchantService.getById(1);
+
+		emailService.sendHtmlEmail(store, email);
+	}
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/init/AbstractInitSalesManagerCore.java b/sm-core/src/test/java/com/salesmanager/test/init/AbstractInitSalesManagerCore.java
new file mode 100644
index 0000000..26a047f
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/init/AbstractInitSalesManagerCore.java
@@ -0,0 +1,204 @@
+package com.salesmanager.test.init;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.metamodel.EntityType;
+
+import org.codehaus.jackson.JsonParseException;
+import org.codehaus.jackson.map.JsonMappingException;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.util.EntityManagerUtils;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.model.CountryDescription;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.currency.service.CurrencyService;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.reference.zone.imports.ZoneLoader;
+import com.salesmanager.core.business.reference.zone.imports.ZoneTransient;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.reference.zone.model.ZoneDescription;
+import com.salesmanager.core.business.reference.zone.service.ZoneService;
+import com.salesmanager.core.constants.SchemaConstant;
+import com.salesmanager.test.core.SalesManagerCoreTestExecutionListener;
+
+@ContextConfiguration(locations = {
+		"classpath:spring/test-spring-context.xml"
+})
+@TestExecutionListeners({
+	DependencyInjectionTestExecutionListener.class,
+	SalesManagerCoreTestExecutionListener.class
+})
+@RunWith(SpringJUnit4ClassRunner.class)
+public class AbstractInitSalesManagerCore {
+	
+	private static final Logger LOGGER = LoggerFactory.getLogger(AbstractInitSalesManagerCore.class);
+	
+	@Autowired
+	private EntityManagerUtils entityManagerUtils;
+	
+	@Autowired
+	protected LanguageService languageService;
+	
+	@Autowired
+	protected CountryService countryService;
+	
+	@Autowired
+	protected ZoneService zoneService;
+	
+	@Autowired
+	protected CurrencyService currencyService;
+	
+	@Before
+	public void clean() throws ServiceException {
+		cleanAll();
+		checkEmptyDatabase();
+	}
+	
+	@Test
+	public void init() throws ServiceException, JsonParseException, JsonMappingException, IOException {
+		initLanguages();
+		initCountries();
+//		initCurrencies();
+		initZones();
+	}
+	
+	private void initZones() throws JsonParseException, JsonMappingException, IOException, ServiceException {
+		Map<String, List<ZoneTransient>> loadZones =  new ZoneLoader().loadZoneConfigurations();
+		for(String languageCode : loadZones.keySet()) {
+			Language language = languageService.getByCode(languageCode);
+			List<ZoneTransient> transients = loadZones.get(languageCode);
+			
+			for(ZoneTransient zoneTransient : transients) {
+				String code = zoneTransient.getZoneCode();
+				String name = zoneTransient.getZoneName();
+				Country country = countryService.getByCode(zoneTransient.getCountryCode());
+				
+				if (country != null) {
+					Zone zone = zoneService.getByCode(code);
+					if (zone == null) {
+						zone = new Zone(country, name, code);
+						zoneService.create(zone);
+					}
+					
+					ZoneDescription description = new ZoneDescription(zone, language, name);
+					zoneService.addDescription(zone, description);
+				} else {
+					LOGGER.info("Import Zone : bad country code");
+				}
+			}
+		}
+	}
+
+	public void initCountries() throws ServiceException {
+		for(String code : SchemaConstant.COUNTRY_ISO_CODE) {
+			Locale locale = SchemaConstant.LOCALES.get(code);
+			if (locale != null) {
+				Country country = new Country(locale.getCountry());
+				countryService.create(country);
+				
+				for (Language language : languageService.list()) {
+					String name = locale.getDisplayCountry(new Locale(language.getCode()));
+					CountryDescription description = new CountryDescription(language, name);
+					countryService.addCountryDescription(country, description);
+				}
+			}
+		}
+	}
+	
+	public void initLanguages() throws ServiceException {
+		for(String code : SchemaConstant.LANGUAGE_ISO_CODE) {
+			Language language = new Language(code);
+			languageService.create(language);
+		}
+	}
+	
+	private void initCurrencies() throws ServiceException {
+		for (String code : SchemaConstant.CURRENCY_MAP.keySet()) {
+			Currency currency = new Currency();
+			try {
+				currency.setCurrency(java.util.Currency.getInstance(code));
+				currency.setName(SchemaConstant.CURRENCY_MAP.get(code));
+				currencyService.create(currency);
+			} catch (IllegalArgumentException e) {
+				LOGGER.info("Import Currency : bad currency code" + code);
+			}
+			
+		}
+	}
+
+	private void cleanAll() throws ServiceException {
+		cleanCurrency();
+		cleanCountry();
+		cleanLanguage();
+		cleanZone();
+	}
+	
+	private void cleanZone() throws ServiceException {
+		for(Zone zone : zoneService.list()) {
+			zoneService.delete(zone);
+		}
+	}
+
+	private void cleanCurrency() throws ServiceException {
+		for(Currency currency : currencyService.list()) {
+			currencyService.delete(currency);
+		}
+	}
+
+	private void cleanCountry() throws ServiceException {
+		for(Country country : countryService.list()) {
+			countryService.delete(country);
+		}
+	}
+
+	private void cleanLanguage() throws ServiceException {
+		List<Language> languages = languageService.list();
+		for (Language language : languages) {
+			languageService.delete(language);
+		}
+	}
+
+	private void checkEmptyDatabase() {
+		Set<EntityType<?>> entityTypes = getEntityManager().getEntityManagerFactory().getMetamodel().getEntities();
+		for (EntityType<?> entityType : entityTypes) {
+			List<?> entities = listEntities(entityType.getBindableJavaType());
+			
+			if (entities.size() > 0) {
+				Assert.fail(String.format("Remaining objects of type %1$s ", entities.get(0).getClass().getSimpleName()));
+			}
+		}
+	}
+	
+	protected <E> List<E> listEntities(Class<E> clazz) {
+		CriteriaBuilder cb = getEntityManager().getCriteriaBuilder();
+		CriteriaQuery<E> cq = cb.createQuery(clazz);
+		cq.from(clazz);
+		
+		return entityManagerUtils.getEntityManager().createQuery(cq).getResultList();
+	}
+	
+	private EntityManager getEntityManager() {
+		return entityManagerUtils.getEntityManager();
+	}
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/isolated/IsolatedTestCase.java b/sm-core/src/test/java/com/salesmanager/test/isolated/IsolatedTestCase.java
new file mode 100644
index 0000000..6967f23
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/isolated/IsolatedTestCase.java
@@ -0,0 +1,1378 @@
+package com.salesmanager.test.isolated;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.sql.Date;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.io.IOUtils;
+import org.apache.log4j.Logger;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.catalog.category.service.CategoryService;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.ProductCriteria;
+import com.salesmanager.core.business.catalog.product.model.ProductList;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImage;
+import com.salesmanager.core.business.catalog.product.model.image.ProductImageDescription;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.catalog.product.service.ProductService;
+import com.salesmanager.core.business.catalog.product.service.attribute.ProductAttributeService;
+import com.salesmanager.core.business.catalog.product.service.attribute.ProductOptionService;
+import com.salesmanager.core.business.catalog.product.service.attribute.ProductOptionValueService;
+import com.salesmanager.core.business.catalog.product.service.availability.ProductAvailabilityService;
+import com.salesmanager.core.business.catalog.product.service.image.ProductImageService;
+import com.salesmanager.core.business.catalog.product.service.manufacturer.ManufacturerService;
+import com.salesmanager.core.business.catalog.product.service.price.ProductPriceService;
+import com.salesmanager.core.business.catalog.product.service.type.ProductTypeService;
+import com.salesmanager.core.business.content.service.ContentService;
+import com.salesmanager.core.business.customer.service.CustomerService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.generic.util.EntityManagerUtils;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.merchant.service.MerchantStoreService;
+import com.salesmanager.core.business.order.service.OrderService;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.currency.service.CurrencyService;
+import com.salesmanager.core.business.reference.init.service.InitializationDatabase;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.reference.zone.service.ZoneService;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.service.ModuleConfigurationService;
+import com.salesmanager.core.business.user.model.Group;
+import com.salesmanager.core.business.user.model.Permission;
+import com.salesmanager.core.business.user.service.GroupService;
+import com.salesmanager.core.business.user.service.PermissionService;
+import com.salesmanager.core.business.user.service.UserService;
+import com.salesmanager.core.utils.reference.ConfigurationModulesLoader;
+import com.salesmanager.test.core.SalesManagerCoreTestExecutionListener;
+
+@ContextConfiguration( locations = { "classpath:spring/test-spring-context.xml" } )
+@RunWith( SpringJUnit4ClassRunner.class )
+@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class, SalesManagerCoreTestExecutionListener.class } )
+public class IsolatedTestCase
+{
+
+    private static final Logger log = Logger.getLogger( IsolatedTestCase.class );
+
+    private static final Date date = new Date( System.currentTimeMillis() );
+
+    @Autowired
+    private EntityManagerUtils entityManagerUtils;
+
+    @Autowired
+    protected ProductService productService;
+
+    @Autowired
+    protected ProductPriceService productPriceService;
+
+    @Autowired
+    protected ProductAttributeService productAttributeService;
+
+    @Autowired
+    protected ProductOptionService productOptionService;
+    
+
+    @Autowired
+    protected ProductOptionValueService productOptionValueService;
+
+    @Autowired
+    protected ProductAvailabilityService productAvailabilityService;
+
+    @Autowired
+    protected ProductImageService productImageService;
+
+    @Autowired
+    protected ContentService contentService;
+
+    @Autowired
+    protected CategoryService categoryService;
+
+    @Autowired
+    protected MerchantStoreService merchantService;
+
+    @Autowired
+    protected ProductTypeService productTypeService;
+
+    @Autowired
+    protected LanguageService languageService;
+
+    @Autowired
+    protected CountryService countryService;
+
+    @Autowired
+    protected ZoneService zoneService;
+
+    @Autowired
+    protected CustomerService customerService;
+
+    @Autowired
+    protected ManufacturerService manufacturerService;
+
+    @Autowired
+    protected CurrencyService currencyService;
+
+    @Autowired
+    protected OrderService orderService;
+
+    @Autowired
+    protected GroupService groupService;
+
+    @Autowired
+    protected PermissionService permissionService;
+
+    @Autowired
+    protected UserService userService;
+
+    @Autowired
+    protected InitializationDatabase initializationDatabase;
+
+    @Autowired
+    protected ModuleConfigurationService moduleConfigurationService;
+    
+
+
+    // @Autowired
+    protected TestSupportFactory testSupportFactory;
+
+    @Test
+    public void test1CreateReferences()
+        throws ServiceException
+    {
+
+        initializationDatabase.populate( "TEST" );
+
+
+
+    }
+
+    @Test
+    public void testSearchProduct()
+        throws ServiceException
+    {
+
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final Language en = languageService.getByCode( "en" );
+
+        final ProductCriteria criteria = new ProductCriteria();
+        criteria.setStartIndex( 0 );
+        criteria.setMaxCount( 75 );
+
+        final List<Long> categoryIds = new ArrayList<Long>();
+        categoryIds.add( 1L );
+        categoryIds.add( 2L );
+        categoryIds.add( 3L );
+        categoryIds.add( 5L );
+        categoryIds.add( 4L );
+
+        criteria.setAvailable( new Boolean( false ) );
+
+        criteria.setCategoryIds( categoryIds );
+
+        final ProductList l = productService.listByStore( store, en, criteria );
+
+        System.out.println( "done" );
+
+    }
+
+    @Test
+    public void testGetMerchant()
+        throws ServiceException
+    {
+
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        System.out.println( "done" );
+
+    }
+
+    @Test
+    public void testCreateProductWithImage()
+        throws ServiceException, IOException
+    {
+
+        final Language en = languageService.getByCode( "en" );
+        final Language fr = languageService.getByCode( "fr" );
+        final Country ca = countryService.getByCode( "CA" );
+        final Currency currency = currencyService.getByCode( "CAD" );
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        
+        final ProductType generalType = productTypeService.getProductType( ProductType.GENERAL_TYPE );
+
+        final Category book = categoryService.getByCode( store, "book" );
+        final Product product = productService.getById( 1L );
+
+
+        final File file1 = new File( "/Users/csamson777/Documents/csti/cocoacart/ktm.png" );
+        if ( !file1.exists() || !file1.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file1.getAbsolutePath() );
+        }
+
+        // FileInputStream is1 = new FileInputStream(file1);
+        // FileInputStream is2 = new FileInputStream(file2);
+
+        final byte[] is = IOUtils.toByteArray( new FileInputStream( file1 ) );
+        final ByteArrayInputStream is1 = new ByteArrayInputStream( is );
+
+        final ProductImage productImage1 = new ProductImage();
+        productImage1.setDefaultImage( true );
+        productImage1.setProductImage( file1.getName() );
+
+        final ProductImageDescription desc1 = new ProductImageDescription();
+        desc1.setLanguage( en );
+        desc1.setAltTag( "ALT IMAGE 1 en" );
+        desc1.setName( "A beautifill Thing" );
+        desc1.setProductImage( productImage1 );
+
+        final ProductImageDescription desc2 = new ProductImageDescription();
+        desc2.setLanguage( fr );
+        desc2.setAltTag( "ALT IMAGE 1 fr" );
+        desc2.setName( "Superbe chose" );
+        desc2.setProductImage( productImage1 );
+
+        final List image1descriptions = new ArrayList();
+        image1descriptions.add( desc1 );
+        image1descriptions.add( desc2 );
+
+        productImage1.setDescriptions( image1descriptions );
+        productImage1.setImage( is1 );
+
+        //productImageService.addProductImage( product, productImage1 );
+
+    }
+
+    @Test
+    public void createProduct()
+        throws Exception
+    {
+
+        final Language en = languageService.getByCode( "en" );
+        final Language fr = languageService.getByCode( "fr" );
+        final Country ca = countryService.getByCode( "CA" );
+        final Currency currency = currencyService.getByCode( "CAD" );
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final ProductType generalType = productTypeService.getProductType( ProductType.GENERAL_TYPE );
+
+        // Category book = categoryService.getByCode(store, "book");
+
+        // Manufacturer manufacturer = manufacturerService.getById(1L);
+
+        // PRODUCT 1
+
+        final Product product = new Product();
+        product.setProductHeight( new BigDecimal( 4 ) );
+        product.setProductLength( new BigDecimal( 3 ) );
+        product.setProductWidth( new BigDecimal( 1 ) );
+        product.setSku( "XYZTEST" );
+        // product.setManufacturer(manufacturer);
+        product.setType( generalType );
+        product.setMerchantStore( store );
+
+        // Product description
+        final ProductDescription description = new ProductDescription();
+        description.setName( "Test with image" );
+        description.setLanguage( en );
+        description.setProduct( product );
+
+        product.getDescriptions().add( description );
+        // product.getCategories().add(book);
+
+        final Set<ProductAvailability> availabilities = new HashSet<ProductAvailability>();
+
+        final ProductPrice dprice = new ProductPrice();
+        dprice.setDefaultPrice( true );
+        dprice.setProductPriceAmount( new BigDecimal( 29.99 ) );
+
+        final Set<ProductPrice> prices = new HashSet<ProductPrice>();
+        prices.add( dprice );
+
+        // Availability
+        final ProductAvailability availability = new ProductAvailability();
+        availability.setProductDateAvailable( date );
+        availability.setProductQuantity( 100 );
+        availability.setRegion( "*" );
+
+        availability.setPrices( prices );
+
+        availabilities.add( availability );
+
+        product.setAvailabilities( availabilities );
+
+        final File file1 = new File( "/Users/csamson777/Documents/csti/cocoacart/ktm.png" );
+        if ( !file1.exists() || !file1.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file1.getAbsolutePath() );
+        }
+
+        // FileInputStream is1 = new FileInputStream(file1);
+
+        final byte[] is = IOUtils.toByteArray( new FileInputStream( file1 ) );
+        final ByteArrayInputStream is1 = new ByteArrayInputStream( is );
+
+        final ProductImage productImage = new ProductImage();
+        productImage.setDefaultImage( true );
+        productImage.setProductImage( file1.getName() );
+
+        final ProductImageDescription desc1 = new ProductImageDescription();
+        desc1.setLanguage( en );
+        desc1.setAltTag( "ALT IMAGE 1 en" );
+        desc1.setName( "Product image" );
+
+        final ProductImageDescription desc2 = new ProductImageDescription();
+        desc2.setLanguage( fr );
+        desc2.setAltTag( "ALT IMAGE 1 fr" );
+        desc2.setName( "Image du produit" );
+
+        final List<ProductImageDescription> imagedescriptions = new ArrayList<ProductImageDescription>();
+        imagedescriptions.add( desc1 );
+        imagedescriptions.add( desc2 );
+
+        productImage.setDescriptions( imagedescriptions );
+        productImage.setImage( is1 );
+
+        product.getImages().add( productImage );
+
+        productService.saveOrUpdate( product );
+
+    }
+
+
+    
+/*    @Test
+    public void addStaticContentData() throws ServiceException, FileNotFoundException{
+        
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final File file1 = new File( "D:/wamp/www/travellingrants/wp-content/themes/TravelPro/style.css" );
+
+        if ( !file1.exists() || !file1.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file1.getAbsolutePath() );
+        }
+
+        InputStaticContentData staticData=new InputStaticContentData();
+        staticData.setFileName( file1.getName() );
+        staticData.setFile( new FileInputStream( file1 ) );
+        staticData.setContentType( StaticContentType.STATIC_DATA );
+        staticContentService.addStaticContentData( store.getCode(), staticData );
+        
+       
+       
+    }
+    
+    @Test
+    public void addStaticContentDataFiles() throws ServiceException, FileNotFoundException{
+      
+        List<InputStaticContentData> inputStaticContentDataList=new ArrayList<InputStaticContentData>();
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final File file1 = new File( "D:/wamp/www/travellingrants/wp-content/themes/TravelPro/style.css" );
+
+        if ( !file1.exists() || !file1.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file1.getAbsolutePath() );
+        }
+
+        InputStaticContentData staticData=new InputStaticContentData();
+        staticData.setFileName( file1.getName() );
+        staticData.setFile( new FileInputStream( file1 ) );
+        staticData.setContentType( StaticContentType.STATIC_DATA );
+        inputStaticContentDataList.add( staticData );
+        
+        final File file2= new File( "D:/personal/songs/Bahut der kardi.mp3" );
+
+        if ( !file2.exists() || !file2.canRead() )
+        {
+            throw new ServiceException( "Can't read" + file2.getAbsolutePath() );
+        }
+
+        InputStaticContentData staticData1=new InputStaticContentData();
+        staticData1.setFileName( file2.getName() );
+        staticData1.setFile( new FileInputStream( file2 ) );
+        staticData1.setContentType( StaticContentType.DIGITAL_DATA );
+        inputStaticContentDataList.add( staticData1 );
+        staticContentService.addStaticContentDataFiles( store.getCode(), inputStaticContentDataList );
+       
+    }
+    
+    @Test
+    public void getStaticContentData() throws ServiceException{
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        String fileName="style.css";
+        OutputStaticContentData data=staticContentService.getStaticContentData( store.getCode(), fileName );
+        System.out.println(data.getContentType());
+        //System.out.println(data.getFile().);
+        
+    }*/
+    
+/*    @Test
+    public void testGetUser() throws Exception {
+    	
+    	List<Integer> groups = new ArrayList<Integer>();
+    	User user = userService.getByUserName("admin");
+    	for(Group group : user.getGroups()) {
+    		
+    		System.out.println(group.getGroupName());
+    		groups.add(group.getId());
+    		for(Permission permission : group.getPermissions()) {
+    			
+    			System.out.println(permission.getPermissionName());
+    			
+    			
+    		}
+    		
+    	}
+    	
+    	List<Permission> permissions = permissionService.getPermissions(groups);
+    	for(Permission permission : permissions) {
+    		System.out.println(permission.getPermissionName());
+    	}
+    	
+    }*/
+
+    @Test
+    public void test2CreateProducts()
+        throws ServiceException
+    {
+
+        final Language en = languageService.getByCode( "en" );
+        final Language fr = languageService.getByCode( "fr" );
+        final Country ca = countryService.getByCode( "CA" );
+        final Currency currency = currencyService.getByCode( "CAD" );
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        final ProductType generalType = productTypeService.getProductType( ProductType.GENERAL_TYPE );
+
+        final Category book = new Category();
+        book.setMerchantStore( store );
+        book.setCode( "book" );
+
+        final CategoryDescription bookEnglishDescription = new CategoryDescription();
+        bookEnglishDescription.setName( "Book" );
+        bookEnglishDescription.setCategory( book );
+        bookEnglishDescription.setLanguage( en );
+
+        final CategoryDescription bookFrenchDescription = new CategoryDescription();
+        bookFrenchDescription.setName( "Livre" );
+        bookFrenchDescription.setCategory( book );
+        bookFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+        descriptions.add( bookEnglishDescription );
+        descriptions.add( bookFrenchDescription );
+
+        book.setDescriptions( descriptions );
+
+        categoryService.create( book );
+
+        final Category music = new Category();
+        music.setMerchantStore( store );
+        music.setCode( "music" );
+
+        final CategoryDescription musicEnglishDescription = new CategoryDescription();
+        musicEnglishDescription.setName( "Music" );
+        musicEnglishDescription.setCategory( music );
+        musicEnglishDescription.setLanguage( en );
+
+        final CategoryDescription musicFrenchDescription = new CategoryDescription();
+        musicFrenchDescription.setName( "Musique" );
+        musicFrenchDescription.setCategory( music );
+        musicFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> descriptions2 = new ArrayList<CategoryDescription>();
+        descriptions2.add( musicEnglishDescription );
+        descriptions2.add( musicFrenchDescription );
+
+        music.setDescriptions( descriptions2 );
+
+        categoryService.create( music );
+
+        final Category novell = new Category();
+        novell.setMerchantStore( store );
+        novell.setCode( "novell" );
+
+        final CategoryDescription novellEnglishDescription = new CategoryDescription();
+        novellEnglishDescription.setName( "Novell" );
+        novellEnglishDescription.setCategory( novell );
+        novellEnglishDescription.setLanguage( en );
+
+        final CategoryDescription novellFrenchDescription = new CategoryDescription();
+        novellFrenchDescription.setName( "Roman" );
+        novellFrenchDescription.setCategory( novell );
+        novellFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> descriptions3 = new ArrayList<CategoryDescription>();
+        descriptions3.add( novellEnglishDescription );
+        descriptions3.add( novellFrenchDescription );
+
+        novell.setDescriptions( descriptions3 );
+
+        novell.setParent( book );
+
+        categoryService.create( novell );
+        categoryService.addChild( book, novell );
+
+        final Category tech = new Category();
+        tech.setMerchantStore( store );
+        tech.setCode( "tech" );
+
+        final CategoryDescription techEnglishDescription = new CategoryDescription();
+        techEnglishDescription.setName( "Technology" );
+        techEnglishDescription.setCategory( tech );
+        techEnglishDescription.setLanguage( en );
+
+        final CategoryDescription techFrenchDescription = new CategoryDescription();
+        techFrenchDescription.setName( "Technologie" );
+        techFrenchDescription.setCategory( tech );
+        techFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> descriptions4 = new ArrayList<CategoryDescription>();
+        descriptions4.add( techFrenchDescription );
+        descriptions4.add( techFrenchDescription );
+
+        tech.setDescriptions( descriptions4 );
+
+        tech.setParent( book );
+
+        categoryService.create( tech );
+        categoryService.addChild( book, tech );
+
+        final Category fiction = new Category();
+        fiction.setMerchantStore( store );
+        fiction.setCode( "fiction" );
+
+        final CategoryDescription fictionEnglishDescription = new CategoryDescription();
+        fictionEnglishDescription.setName( "Fiction" );
+        fictionEnglishDescription.setCategory( fiction );
+        fictionEnglishDescription.setLanguage( en );
+
+        final CategoryDescription fictionFrenchDescription = new CategoryDescription();
+        fictionFrenchDescription.setName( "Sc Fiction" );
+        fictionFrenchDescription.setCategory( fiction );
+        fictionFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> fictiondescriptions = new ArrayList<CategoryDescription>();
+        fictiondescriptions.add( fictionEnglishDescription );
+        fictiondescriptions.add( fictionFrenchDescription );
+
+        fiction.setDescriptions( fictiondescriptions );
+
+        fiction.setParent( novell );
+
+        categoryService.create( fiction );
+        categoryService.addChild( book, fiction );
+
+        // Add products
+        // ProductType generalType = productTypeService.
+
+        final Manufacturer oreilley = new Manufacturer();
+        oreilley.setMerchantStore( store );
+
+        final ManufacturerDescription oreilleyd = new ManufacturerDescription();
+        oreilleyd.setLanguage( en );
+        oreilleyd.setName( "O\'reilley" );
+        oreilleyd.setManufacturer( oreilley );
+        oreilley.getDescriptions().add( oreilleyd );
+
+        manufacturerService.create( oreilley );
+
+        final Manufacturer packed = new Manufacturer();
+        packed.setMerchantStore( store );
+
+        final ManufacturerDescription packedd = new ManufacturerDescription();
+        packedd.setLanguage( en );
+        packedd.setManufacturer( packed );
+        packedd.setName( "Packed publishing" );
+        packed.getDescriptions().add( packedd );
+
+        manufacturerService.create( packed );
+
+        final Manufacturer novells = new Manufacturer();
+        novells.setMerchantStore( store );
+
+        final ManufacturerDescription novellsd = new ManufacturerDescription();
+        novellsd.setLanguage( en );
+        novellsd.setManufacturer( novells );
+        novellsd.setName( "Novells publishing" );
+        novells.getDescriptions().add( novellsd );
+
+        manufacturerService.create( novells );
+
+        // PRODUCT 1
+
+        final Product product = new Product();
+        product.setProductHeight( new BigDecimal( 4 ) );
+        product.setProductLength( new BigDecimal( 3 ) );
+        product.setProductWidth( new BigDecimal( 1 ) );
+        product.setSku( "TB12345" );
+        product.setManufacturer( oreilley );
+        product.setType( generalType );
+        product.setMerchantStore( store );
+
+        // Product description
+        ProductDescription description = new ProductDescription();
+        description.setName( "Spring in Action" );
+        description.setLanguage( en );
+        description.setProduct( product );
+
+        product.getDescriptions().add( description );
+
+        product.getCategories().add( tech );
+
+        productService.create( product );
+
+        // Availability
+        final ProductAvailability availability = new ProductAvailability();
+        availability.setProductDateAvailable( date );
+        availability.setProductQuantity( 100 );
+        availability.setRegion( "*" );
+        availability.setProduct( product );// associate with product
+
+        productAvailabilityService.create( availability );
+
+        final ProductPrice dprice = new ProductPrice();
+        dprice.setDefaultPrice( true );
+        dprice.setProductPriceAmount( new BigDecimal( 29.99 ) );
+        dprice.setProductAvailability( availability );
+
+        ProductPriceDescription dpd = new ProductPriceDescription();
+        dpd.setName( "Base price" );
+        dpd.setProductPrice( dprice );
+        dpd.setLanguage( en );
+
+        dprice.getDescriptions().add( dpd );
+
+        productPriceService.create( dprice );
+
+        // PRODUCT 2
+
+        final Product product2 = new Product();
+        product2.setProductHeight( new BigDecimal( 4 ) );
+        product2.setProductLength( new BigDecimal( 3 ) );
+        product2.setProductWidth( new BigDecimal( 1 ) );
+        product2.setSku( "TB2468" );
+        product2.setManufacturer( packed );
+        product2.setType( generalType );
+        product2.setMerchantStore( store );
+
+        // Product description
+        description = new ProductDescription();
+        description.setName( "This is Node.js" );
+        description.setLanguage( en );
+        description.setProduct( product2 );
+
+        product2.getDescriptions().add( description );
+
+        product2.getCategories().add( tech );
+        productService.create( product2 );
+
+        // Availability
+        final ProductAvailability availability2 = new ProductAvailability();
+        availability2.setProductDateAvailable( date );
+        availability2.setProductQuantity( 100 );
+        availability2.setRegion( "*" );
+        availability2.setProduct( product2 );// associate with product
+
+        productAvailabilityService.create( availability2 );
+
+        final ProductPrice dprice2 = new ProductPrice();
+        dprice2.setDefaultPrice( true );
+        dprice2.setProductPriceAmount( new BigDecimal( 39.99 ) );
+        dprice2.setProductAvailability( availability2 );
+
+        dpd = new ProductPriceDescription();
+        dpd.setName( "Base price" );
+        dpd.setProductPrice( dprice2 );
+        dpd.setLanguage( en );
+
+        dprice2.getDescriptions().add( dpd );
+
+        productPriceService.create( dprice2 );
+
+        // PRODUCT 3
+
+        final Product product3 = new Product();
+        product3.setProductHeight( new BigDecimal( 4 ) );
+        product3.setProductLength( new BigDecimal( 3 ) );
+        product3.setProductWidth( new BigDecimal( 1 ) );
+        product3.setSku( "NB1111" );
+        product3.setManufacturer( packed );
+        product3.setType( generalType );
+        product3.setMerchantStore( store );
+
+        // Product description
+        description = new ProductDescription();
+        description.setName( "A nice book for you" );
+        description.setLanguage( en );
+        description.setProduct( product3 );
+
+        product3.getDescriptions().add( description );
+
+        product3.getCategories().add( novell );
+        productService.create( product3 );
+
+        // Availability
+        final ProductAvailability availability3 = new ProductAvailability();
+        availability3.setProductDateAvailable( date );
+        availability3.setProductQuantity( 100 );
+        availability3.setRegion( "*" );
+        availability3.setProduct( product3 );// associate with product
+
+        productAvailabilityService.create( availability3 );
+
+        final ProductPrice dprice3 = new ProductPrice();
+        dprice3.setDefaultPrice( true );
+        dprice3.setProductPriceAmount( new BigDecimal( 19.99 ) );
+        dprice3.setProductAvailability( availability3 );
+
+        dpd = new ProductPriceDescription();
+        dpd.setName( "Base price" );
+        dpd.setProductPrice( dprice3 );
+        dpd.setLanguage( en );
+
+        dprice3.getDescriptions().add( dpd );
+
+        productPriceService.create( dprice3 );
+
+        // PRODUCT 4
+
+        final Product product4 = new Product();
+        product4.setProductHeight( new BigDecimal( 4 ) );
+        product4.setProductLength( new BigDecimal( 3 ) );
+        product4.setProductWidth( new BigDecimal( 1 ) );
+        product4.setSku( "SF333345" );
+        product4.setManufacturer( packed );
+        product4.setType( generalType );
+        product4.setMerchantStore( store );
+
+        // Product description
+        description = new ProductDescription();
+        description.setName( "Battle of the worlds" );
+        description.setLanguage( en );
+        description.setProduct( product4 );
+
+        product4.getDescriptions().add( description );
+
+        product4.getCategories().add( fiction );
+        productService.create( product4 );
+
+        // Availability
+        final ProductAvailability availability4 = new ProductAvailability();
+        availability4.setProductDateAvailable( date );
+        availability4.setProductQuantity( 100 );
+        availability4.setRegion( "*" );
+        availability4.setProduct( product4 );// associate with product
+
+        productAvailabilityService.create( availability4 );
+
+        final ProductPrice dprice4 = new ProductPrice();
+        dprice4.setDefaultPrice( true );
+        dprice4.setProductPriceAmount( new BigDecimal( 18.99 ) );
+        dprice4.setProductAvailability( availability4 );
+
+        dpd = new ProductPriceDescription();
+        dpd.setName( "Base price" );
+        dpd.setProductPrice( dprice4 );
+        dpd.setLanguage( en );
+
+        dprice4.getDescriptions().add( dpd );
+
+        productPriceService.create( dprice4 );
+
+        // PRODUCT 5
+
+        final Product product5 = new Product();
+        product5.setProductHeight( new BigDecimal( 4 ) );
+        product5.setProductLength( new BigDecimal( 3 ) );
+        product5.setProductWidth( new BigDecimal( 1 ) );
+        product5.setSku( "SF333346" );
+        product5.setManufacturer( packed );
+        product5.setType( generalType );
+        product5.setMerchantStore( store );
+
+        // Product description
+        description = new ProductDescription();
+        description.setName( "Battle of the worlds 2" );
+        description.setLanguage( en );
+        description.setProduct( product5 );
+
+        product5.getDescriptions().add( description );
+
+        product5.getCategories().add( fiction );
+        productService.create( product5 );
+
+        // Availability
+        final ProductAvailability availability5 = new ProductAvailability();
+        availability5.setProductDateAvailable( date );
+        availability5.setProductQuantity( 100 );
+        availability5.setRegion( "*" );
+        availability5.setProduct( product5 );// associate with product
+
+        productAvailabilityService.create( availability5 );
+
+        final ProductPrice dprice5 = new ProductPrice();
+        dprice5.setDefaultPrice( true );
+        dprice5.setProductPriceAmount( new BigDecimal( 18.99 ) );
+        dprice5.setProductAvailability( availability5 );
+
+        dpd = new ProductPriceDescription();
+        dpd.setName( "Base price" );
+        dpd.setProductPrice( dprice5 );
+        dpd.setLanguage( en );
+
+        dprice5.getDescriptions().add( dpd );
+
+        productPriceService.create( dprice5 );
+
+        // PRODUCT 6
+
+        final Product product6 = new Product();
+        product6.setProductHeight( new BigDecimal( 4 ) );
+        product6.setProductLength( new BigDecimal( 3 ) );
+        product6.setProductWidth( new BigDecimal( 1 ) );
+        product6.setSku( "LL333444" );
+        product6.setManufacturer( packed );
+        product6.setType( generalType );
+        product6.setMerchantStore( store );
+
+        // Product description
+        description = new ProductDescription();
+        description.setName( "Life book" );
+        description.setLanguage( en );
+        description.setProduct( product6 );
+
+        product6.getDescriptions().add( description );
+
+        product6.getCategories().add( novell );
+        productService.create( product6 );
+
+        // Availability
+        final ProductAvailability availability6 = new ProductAvailability();
+        availability6.setProductDateAvailable( date );
+        availability6.setProductQuantity( 100 );
+        availability6.setRegion( "*" );
+        availability6.setProduct( product6 );// associate with product
+
+        productAvailabilityService.create( availability6 );
+
+        final ProductPrice dprice6 = new ProductPrice();
+        dprice6.setDefaultPrice( true );
+        dprice6.setProductPriceAmount( new BigDecimal( 18.99 ) );
+        dprice6.setProductAvailability( availability6 );
+
+        dpd = new ProductPriceDescription();
+        dpd.setName( "Base price" );
+        dpd.setProductPrice( dprice6 );
+        dpd.setLanguage( en );
+
+        dprice6.getDescriptions().add( dpd );
+
+        productPriceService.create( dprice6 );
+
+    }
+
+    @Test
+    public void test3CreateUser()
+        throws ServiceException
+    {
+
+		  final MerchantStore store = merchantService.getMerchantStore(MerchantStore.DEFAULT_STORE);
+
+		  final Group gsuperadmin = new Group("SUPERADMIN");
+		  final Group gadmin = new Group("ADMIN");
+		  final Group gcatalogue = new Group("GROUP_CATALOGUE");
+		  final Group gstore = new Group("GROUP_STORE");
+		  final Group gorder = new Group("GROUP_ORDER");
+
+		  groupService.create(gsuperadmin);
+		  groupService.create(gadmin);
+		  groupService.create(gcatalogue);
+		  groupService.create(gstore);
+		  groupService.create(gorder);
+
+		  groupService.create(gsuperadmin);
+		  groupService.create(gadmin);
+		  groupService.create(gcatalogue);
+		  groupService.create(gstore);
+		  groupService.create(gorder);
+		  
+		  final Permission auth = new Permission("AUTH");//Authenticated
+		  auth.getGroups().add(gsuperadmin);
+		  auth.getGroups().add(gadmin);
+		  permissionService.create(auth);
+		  
+		  final Permission categories = new Permission("CATEGORIES");
+		  categories.getGroups().add(gsuperadmin);
+		  categories.getGroups().add(gadmin);
+		  permissionService.create(categories);
+		  
+		  final Permission products = new Permission("PRODUCTS");
+		  products.getGroups().add(gsuperadmin);
+		  products.getGroups().add(gadmin);
+		  permissionService.create(products);
+		  
+		  final Permission attributes = new Permission("ATTRIBUTES");
+		  attributes.getGroups().add(gsuperadmin);
+		  permissionService.create(attributes);
+		  
+		  final Permission featured = new Permission("FEATURED");
+		  featured.getGroups().add(gsuperadmin);
+		  permissionService.create(featured);
+		  
+		  final Permission order = new Permission("ORDER");
+		  order.getGroups().add(gsuperadmin);
+		  permissionService.create(order);
+		  
+		  final Permission content = new Permission("CONTENT");
+		  content.getGroups().add(gsuperadmin);
+		  permissionService.create(content);
+		  final Permission pstore = new Permission("STORE");
+		  pstore.getGroups().add(gsuperadmin);
+		  permissionService.create(pstore);
+		  
+		  final Permission tax = new Permission("TAX");
+		  tax.getGroups().add(gsuperadmin);
+		  permissionService.create(tax);
+		  final Permission payment = new Permission("PAYMENT");
+		  payment.getGroups().add(gsuperadmin);
+		  permissionService.create(payment);
+		  final Permission shipping = new Permission("SHIPPING");
+		  shipping.getGroups().add(gsuperadmin);
+		  permissionService.create(shipping);
+		  
+
+
+    }
+
+    @Test
+    public void testGetProduct()
+        throws ServiceException
+    {
+
+        final Language language = languageService.getByCode( "en" );
+
+        final Locale locale = new Locale( "en", "CA" );
+
+
+        final Product p = productService.getById(50L);
+
+        //final Product p = productService.getProductForLocale( 1L, language, locale );
+
+
+        if ( p != null )
+        {
+
+            System.out.println( p.getDescriptions().size() );
+
+        }
+
+    }
+
+    @Test
+    public void testGetProducts()
+        throws ServiceException
+    {
+        final Language language = languageService.getByCode( "en" );
+        final Locale locale = new Locale( "en", "CA" );
+
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+
+        final Category category = categoryService.getByCode( store, "book" );
+
+        final int nrOfIterations = 1;
+
+        for ( int i = 1; i <= nrOfIterations; i++ )
+        {
+            final List<Product> products = productService.getProductsForLocale( category, language, locale );
+            for ( final Product product : products )
+            {
+                log.info( MessageFormat.format( "product found:{0}:iteration{1}", product.getId(), i ) );
+            }
+        }
+    }
+
+    @Test
+    public void testGetProductsByCategories()
+        throws ServiceException
+    {
+        final Language language = languageService.getByCode( "en" );
+        final Locale locale = new Locale( "en", "CA" );
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+
+        // Category category = categoryService.getByCode(store, "novell");
+
+        final Category category = categoryService.getByCode( store, "book" );
+
+        categoryService.delete( category );
+
+        System.out.println( "done" );
+
+        /*
+         * List<Long> ids = new ArrayList<Long>(); ids.add(1L); ids.add(2L); ids.add(3L); List<Product> products =
+         * productService.getProducts(ids); System.out.println(products.size());
+         */
+
+    }
+
+    @Test
+    public void testCategory()
+        throws ServiceException
+    {
+
+        /**
+         * Creates a category hierarchy Music Books Novell Science-Fiction Technology Business
+         */
+
+        final Language en = languageService.getByCode( "en" );
+        final Language fr = languageService.getByCode( "fr" );
+        final Country ca = countryService.getByCode( "CA" );
+        final Currency currency = currencyService.getByCode( "CAD" );
+        final MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+
+        final Category book = new Category();
+        book.setDepth( 0 );
+        book.setLineage( "/" );
+        book.setMerchantStore( store );
+        book.setCode( "book" );
+
+        final CategoryDescription bookEnglishDescription = new CategoryDescription();
+        bookEnglishDescription.setName( "Book" );
+        bookEnglishDescription.setCategory( book );
+        bookEnglishDescription.setLanguage( en );
+
+        final CategoryDescription bookFrenchDescription = new CategoryDescription();
+        bookFrenchDescription.setName( "Livre" );
+        bookFrenchDescription.setCategory( book );
+        bookFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+        descriptions.add( bookEnglishDescription );
+        descriptions.add( bookFrenchDescription );
+
+        book.setDescriptions( descriptions );
+
+        categoryService.create( book );
+
+        final Category music = new Category();
+        music.setDepth( 0 );
+        music.setLineage( "/" );
+        music.setMerchantStore( store );
+        music.setCode( "music" );
+
+        final CategoryDescription musicEnglishDescription = new CategoryDescription();
+        musicEnglishDescription.setName( "Music" );
+        musicEnglishDescription.setCategory( music );
+        musicEnglishDescription.setLanguage( en );
+
+        final CategoryDescription musicFrenchDescription = new CategoryDescription();
+        musicFrenchDescription.setName( "Musique" );
+        musicFrenchDescription.setCategory( music );
+        musicFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> descriptions2 = new ArrayList<CategoryDescription>();
+        descriptions2.add( musicEnglishDescription );
+        descriptions2.add( musicFrenchDescription );
+
+        music.setDescriptions( descriptions2 );
+
+        categoryService.create( music );
+
+        final Category novell = new Category();
+        novell.setDepth( 1 );
+        novell.setLineage( "/" + book.getId() + "/" );
+        novell.setMerchantStore( store );
+        novell.setCode( "novell" );
+
+        final CategoryDescription novellEnglishDescription = new CategoryDescription();
+        novellEnglishDescription.setName( "Novell" );
+        novellEnglishDescription.setCategory( novell );
+        novellEnglishDescription.setLanguage( en );
+
+        final CategoryDescription novellFrenchDescription = new CategoryDescription();
+        novellFrenchDescription.setName( "Roman" );
+        novellFrenchDescription.setCategory( novell );
+        novellFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> descriptions3 = new ArrayList<CategoryDescription>();
+        descriptions3.add( novellEnglishDescription );
+        descriptions3.add( novellFrenchDescription );
+
+        novell.setDescriptions( descriptions3 );
+
+        categoryService.create( novell );
+        categoryService.addChild( book, novell );
+
+        final Category tech = new Category();
+        tech.setDepth( 1 );
+        tech.setLineage( "/" + book.getId() + "/" );
+        tech.setMerchantStore( store );
+        tech.setCode( "tech" );
+
+        final CategoryDescription techEnglishDescription = new CategoryDescription();
+        techEnglishDescription.setName( "Technology" );
+        techEnglishDescription.setCategory( tech );
+        techEnglishDescription.setLanguage( en );
+
+        final CategoryDescription techFrenchDescription = new CategoryDescription();
+        techFrenchDescription.setName( "Technologie" );
+        techFrenchDescription.setCategory( tech );
+        techFrenchDescription.setLanguage( fr );
+
+        final List<CategoryDescription> descriptions4 = new ArrayList<CategoryDescription>();
+        descriptions4.add( techFrenchDescription );
+        descriptions4.add( techFrenchDescription );
+
+        tech.setDescriptions( descriptions4 );
+
+        categoryService.create( tech );
+        categoryService.addChild( book, tech );
+
+    }
+
+    @Test
+    public void testGetModules()
+        throws ServiceException
+    {
+
+        final List<IntegrationModule> shippingModules = moduleConfigurationService.getIntegrationModules( "SHIPPING" );
+
+        for ( final IntegrationModule module : shippingModules )
+        {
+
+            System.out.println( module.getCode() );
+        }
+        System.out.println( "Done" );
+
+    }
+    
+    
+    @Test
+    public void testCreateModules()
+        throws ServiceException
+    {
+
+        Map<String,IntegrationConfiguration> modules = new HashMap<String,IntegrationConfiguration>();
+    	
+    	IntegrationConfiguration canadaPost = new IntegrationConfiguration();
+    	canadaPost.setActive(true);
+    	canadaPost.setModuleCode("canadapost");
+    	
+    	Map<String,String> integrationKeys= new HashMap<String,String>();
+    	integrationKeys.put("userName", "cpUserName");
+    	integrationKeys.put("password", "cpPassword");
+    	
+    	canadaPost.setIntegrationKeys(integrationKeys);
+    	
+    	//String cpOptions[] = {"A","B"};
+    	
+    	List<String> cpOptions = new ArrayList<String>();
+    	cpOptions.add("A");
+    	cpOptions.add("B");
+    	
+    	//String cpOptions = "A,B";
+    	
+    	Map<String,List<String>> integrationOptions= new HashMap<String,List<String>>();
+    	integrationOptions.put("cpExpress", cpOptions);
+    	
+    	canadaPost.setIntegrationOptions(integrationOptions);
+    	modules.put("canadapost", canadaPost);
+    	
+    	
+    	
+    	IntegrationConfiguration usps = new IntegrationConfiguration();
+    	usps.setActive(false);
+    	usps.setModuleCode("usps");
+    	
+    	integrationKeys= new HashMap<String,String>();
+    	integrationKeys.put("userName", "uspsUserName");
+    	integrationKeys.put("password", "uspsPassword");
+    	
+    	usps.setIntegrationKeys(integrationKeys);
+    	
+    	//String uspsOptions[] = {"X","Y"};
+    	List<String> uspsOptions = new ArrayList<String>();
+    	uspsOptions.add("X");
+    	uspsOptions.add("Y");
+    	
+    	//String uspsOptions = "X,Y";
+    	
+    	integrationOptions= new HashMap<String,List<String>>();
+    	integrationOptions.put("uspsExpress", uspsOptions);
+    	
+    	usps.setIntegrationOptions(integrationOptions);
+    	modules.put("usps", usps);
+    	
+    	
+
+		try {
+			String json = ConfigurationModulesLoader.toJSONString(modules);
+
+    	
+    	
+			System.out.println(json);
+    	
+    	
+			//re-create object
+			Map<String,IntegrationConfiguration> configs = ConfigurationModulesLoader.loadIntegrationConfigurations(json);
+    	
+			for(String key : configs.keySet()) {
+				
+				IntegrationConfiguration c = (IntegrationConfiguration)configs.get(key);
+				System.out.println(c.getModuleCode());
+				
+				
+			}
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+    }
+
+    @Test
+    public void testCreateManufacturer()
+        throws ServiceException
+    {
+
+        final Language english = new Language();
+        english.setCode( "en" );
+        languageService.create( english );
+
+        final Language french = new Language();
+        french.setCode( "fr" );
+        languageService.create( french );
+
+        final Currency euro = new Currency();
+        euro.setCurrency( java.util.Currency.getInstance( "EUR" ) );
+        currencyService.create( euro );
+
+        final Currency cad = new Currency();
+        cad.setCurrency( java.util.Currency.getInstance( "CAD" ) );
+        currencyService.create( cad );
+
+        final Country fr = new Country( "FR" );
+        countryService.create( fr );
+
+        final Country ca = new Country( "CA" );
+        countryService.create( ca );
+
+        final Language DEFAULT_LANGUAGE = languageService.getByCode( "en" );
+        final Language FRENCH = languageService.getByCode( "fr" );
+        final Currency currency = currencyService.getByCode( "CAD" );
+
+        // create a merchant
+        final MerchantStore store = new MerchantStore();
+        store.setCountry( ca );
+        store.setCurrency( currency );
+        store.setDefaultLanguage( DEFAULT_LANGUAGE );
+        store.setInBusinessSince( date );
+        store.setStorename( "store name" );
+        store.setStoreEmailAddress( "test@test.com" );
+        merchantService.create( store );
+
+        final Manufacturer manufacturer = new Manufacturer();
+        // store.getManufacturers().add(manufacturer);
+
+        // merchantService.update(store);
+
+        // Manufacturer manufacturer = new Manufacturer();
+        manufacturer.setMerchantStore( store );
+
+        final ManufacturerDescription fd = new ManufacturerDescription();
+        fd.setLanguage( FRENCH );
+        fd.setName( "Sony french" );
+        fd.setManufacturer( manufacturer );
+
+        final ManufacturerDescription ed = new ManufacturerDescription();
+        ed.setLanguage( DEFAULT_LANGUAGE );
+        ed.setName( "Sony english" );
+        ed.setManufacturer( manufacturer );
+
+        final Set descriptions = new HashSet();
+        descriptions.add( fd );
+        descriptions.add( ed );
+
+        manufacturer.setDescriptions( descriptions );
+
+        manufacturerService.create( manufacturer );
+
+        // manufacturerService.delete(manufacturer);
+        // merchantService.delete(store);
+
+    }
+
+    @Test
+    public void testDeleteManufacturerService()
+        throws ServiceException
+    {
+
+        final Manufacturer manufacturer = manufacturerService.getById( 1L );
+        manufacturerService.delete( manufacturer );
+
+    }
+
+    @Test
+    public void testStoreRandomProducts()
+        throws ServiceException
+    {
+
+        final Language en = testSupportFactory.createLanguage( "en" );
+        languageService.save( en );
+
+        final Language fr = testSupportFactory.createLanguage( "fr" );
+        languageService.save( fr );
+
+        final Language[] languages = { en, fr };
+
+        final ProductType generalType = testSupportFactory.createProductType();
+        productTypeService.save( generalType );
+
+        final Country country = testSupportFactory.createCountry( en );
+        countryService.save( country );
+
+        final Currency currency = testSupportFactory.createCurrency();
+        currencyService.save( currency );
+
+        final MerchantStore store =
+            testSupportFactory.createMerchantStore( MerchantStore.DEFAULT_STORE, country, currency, en );
+        merchantService.save( store );
+
+        final Manufacturer manufacturer = testSupportFactory.createRandomManufacturer( store, en );
+        manufacturerService.save( manufacturer );
+
+        final Category category = testSupportFactory.createCategory( null, store, languages );
+        categoryService.save( category );
+
+        final int nrOfProducts = 300;
+
+        for ( int i = 1; i <= nrOfProducts; i++ )
+        {
+            log.info( MessageFormat.format( "adding product nr:{0}", i ) );
+            testSupportFactory.createAndStoreRandomProduct( manufacturer, generalType, category, store, en );
+        }
+    }
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/isolated/TestSupportFactory.java b/sm-core/src/test/java/com/salesmanager/test/isolated/TestSupportFactory.java
new file mode 100644
index 0000000..8fd449e
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/isolated/TestSupportFactory.java
@@ -0,0 +1,213 @@
+package com.salesmanager.test.isolated;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+import java.util.Random;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.catalog.product.service.ProductService;
+import com.salesmanager.core.business.catalog.product.service.availability.ProductAvailabilityService;
+import com.salesmanager.core.business.catalog.product.service.manufacturer.ManufacturerService;
+import com.salesmanager.core.business.catalog.product.service.price.ProductPriceService;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.merchant.service.MerchantStoreService;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.country.model.CountryDescription;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.currency.service.CurrencyService;
+import com.salesmanager.core.business.reference.language.model.Language;
+
+@Component
+public class TestSupportFactory {
+
+  @Autowired
+  protected ProductService             productService;
+
+  @Autowired
+  protected ProductAvailabilityService productAvailabilityService;
+
+  @Autowired
+  protected ProductPriceService        productPriceService;
+
+  @Autowired
+  protected ManufacturerService        manufacturerService;
+
+  @Autowired
+  protected MerchantStoreService       merchantStoreService;
+
+  @Autowired
+  protected CountryService             countryService;
+
+  @Autowired
+  protected CurrencyService            currencyService;
+
+  public Product createAndStoreRandomProduct(Manufacturer manufacturer, ProductType type, Category category, MerchantStore store,
+      Language language) throws ServiceException {
+    Random rnd = new Random();
+
+    String[] descriptions = { "Live Book", "Nature Book", "Science Book", "Mathematics Book", "Physics Book" };
+
+    Product product = new Product();
+    product.setProductHeight(new BigDecimal(rnd.nextInt(100000)));
+    product.setProductLength(new BigDecimal(rnd.nextInt(100000)));
+    product.setProductWidth(new BigDecimal(rnd.nextInt(100000)));
+    product.setSku("LL" + rnd.nextLong());
+    product.setManufacturer(manufacturer);
+    product.setType(type);
+    product.setMerchantStore(store);
+
+    // Product description
+    ProductDescription description = new ProductDescription();
+    description.setName(getRandomString(descriptions));
+    description.setLanguage(language);
+    description.setProduct(product);
+
+    product.getDescriptions().add(description);
+
+    product.getCategories().add(category);
+    productService.create(product);
+
+    // Availability
+    ProductAvailability availability = new ProductAvailability();
+    availability.setProductDateAvailable(new Date());
+    availability.setProductQuantity(rnd.nextInt(200));
+    availability.setRegion("*");
+    availability.setProduct(product);// associate with product
+
+    productAvailabilityService.create(availability);
+
+    ProductPrice price = new ProductPrice();
+    price.setDefaultPrice(true);
+    price.setProductPriceAmount(new BigDecimal(18.99));
+    price.setProductAvailability(availability);
+
+    ProductPriceDescription dpd = new ProductPriceDescription();
+    dpd.setName("Base price");
+    dpd.setProductPrice(price);
+    dpd.setLanguage(language);
+
+    price.getDescriptions().add(dpd);
+
+    productPriceService.create(price);
+
+    return product;
+  }
+
+  public Category createCategory(Category parent, MerchantStore store, Language[] languages) {
+
+    String[] categoryDescriptions = { "Novell", "Roman", "Thriller", "Comedy", "Fantasy", "Horror", "Comics" };
+
+    Category cat = new Category();
+    if (parent == null) {
+      cat.setDepth(0);
+      cat.setLineage("/");
+    } else {
+      cat.setDepth(parent.getDepth());
+      cat.setLineage("/" + parent.getId() + "/");
+    }
+
+    cat.setMerchantStore(store);
+
+    List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+
+    String name = getRandomString(categoryDescriptions);
+    cat.setCode(name);
+    
+    for (Language language : languages) {
+     
+      CategoryDescription desc = new CategoryDescription();
+      desc.setName(name);
+      desc.setCategory(cat);
+      desc.setLanguage(language);
+      descriptions.add(desc);
+
+    }
+    cat.setDescriptions(descriptions);
+    return cat;
+  }
+
+  public Country createCountry(Language language) throws ServiceException {
+    Country ca = new Country();
+    ca.setIsoCode("CA");
+
+    CountryDescription countryDescription = new CountryDescription();
+    countryDescription.setCountry(ca);
+    countryDescription.setLanguage(language);
+    countryDescription.setName("Canada");
+    countryDescription.setDescription("Canada Country");
+
+    List<CountryDescription> descriptions = new ArrayList<CountryDescription>();
+    descriptions.add(countryDescription);
+    ca.setDescriptions(descriptions);
+
+    return ca;
+  }
+
+  public Currency createCurrency() throws ServiceException {
+    Currency currency = new Currency();
+    currency.setCurrency(java.util.Currency.getInstance(Locale.CANADA));
+    currency.setSupported(true);
+    return currency;
+  }
+
+  public Language createLanguage(String code) {
+    Language language = new Language();
+    language.setCode(code);
+    return language;
+  }
+
+  public MerchantStore createMerchantStore(String storeName, Country ca, Currency currency, Language language)
+      throws ServiceException {
+    MerchantStore store = new MerchantStore();
+    store.setCountry(ca);
+    store.setCurrency(currency);
+    store.setDefaultLanguage(language);
+    store.setInBusinessSince(new Date());
+    store.setStorename(storeName);
+    store.setCode(storeName);
+    store.setStoreEmailAddress("test@test.com");
+    return store;
+  }
+
+  public ProductType createProductType() {
+    ProductType generalType = new ProductType();
+    generalType.setCode(ProductType.GENERAL_TYPE);
+    return generalType;
+  }
+
+  public Manufacturer createRandomManufacturer(MerchantStore store, Language language) throws ServiceException {
+    String[] manufacturers = { "O\'reilley", "Hueber", "Langenscheidt", "Readers Digest", "Klett Verlag" };
+
+    Manufacturer manufacturer = new Manufacturer();
+    manufacturer.setMerchantStore(store);
+
+    ManufacturerDescription oreilleyd = new ManufacturerDescription();
+    oreilleyd.setLanguage(language);
+    oreilleyd.setName(getRandomString(manufacturers));
+    oreilleyd.setManufacturer(manufacturer);
+    manufacturer.getDescriptions().add(oreilleyd);
+
+    return manufacturer;
+  }
+
+  private String getRandomString(String[] strings) {
+    return strings[new Random().nextInt(strings.length)];
+  }
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/manufacturer/ManufacturerTestCase.java b/sm-core/src/test/java/com/salesmanager/test/manufacturer/ManufacturerTestCase.java
new file mode 100644
index 0000000..f8e5a9d
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/manufacturer/ManufacturerTestCase.java
@@ -0,0 +1,78 @@
+package com.salesmanager.test.manufacturer;
+
+import java.sql.Date;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Test;
+
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+
+
+public class ManufacturerTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+
+	
+	@Test
+	public void testCreateManufacturerService() throws ServiceException {
+		
+
+		
+		
+		Language DEFAULT_LANGUAGE = languageService.getByCode("en");
+		Language FRENCH = languageService.getByCode("fr");
+		Currency currency = currencyService.getByCode("CAD");
+		Country ca = super.countryService.getByCode("CA");
+		
+
+		
+		//create a merchant
+		MerchantStore store = new MerchantStore();
+		store.setCountry(ca);
+		store.setCurrency(currency);
+		store.setDefaultLanguage(DEFAULT_LANGUAGE);
+		store.setInBusinessSince(date);
+		store.setStorename("store name");
+		store.setStoreEmailAddress("test@test.com");
+		merchantService.create(store);
+		
+		Manufacturer manufacturer = new Manufacturer();
+		manufacturer.setMerchantStore(store);
+		
+		ManufacturerDescription fd = new ManufacturerDescription();
+		fd.setLanguage(FRENCH);
+		fd.setName("Sony french");
+		fd.setManufacturer(manufacturer);
+		
+		ManufacturerDescription ed = new ManufacturerDescription();
+		ed.setLanguage(DEFAULT_LANGUAGE);
+		ed.setName("Sony english");
+		ed.setManufacturer(manufacturer);
+		
+		Set descriptions = new HashSet();
+		descriptions.add(fd);
+		descriptions.add(ed);
+		
+		manufacturer.setDescriptions(descriptions);
+		
+		
+		manufacturerService.create(manufacturer);
+		
+		manufacturerService.delete(manufacturer);
+		//merchantService.delete(store);
+		
+	}
+	
+
+
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/merchant/MerchantSalesManagerTestCase.java b/sm-core/src/test/java/com/salesmanager/test/merchant/MerchantSalesManagerTestCase.java
new file mode 100644
index 0000000..e7e2206
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/merchant/MerchantSalesManagerTestCase.java
@@ -0,0 +1,41 @@
+package com.salesmanager.test.merchant;
+
+import java.util.Date;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class MerchantSalesManagerTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	@Test
+	public void createMerchant() throws Exception {
+		Country country = countryService.getByCode("CA");
+		Language lang = languageService.getByCode("en");
+		List<Language> langs = languageService.list();
+		
+		//create a merchant
+		MerchantStore store = new MerchantStore();
+		store.setCountry(country);
+		store.setCurrency(currencyService.getByCode("CAD"));
+		store.setDefaultLanguage(lang);
+		store.setInBusinessSince(new Date());
+		store.setStorename("store name");
+		store.setCode("STORE");
+		store.setLanguages(langs);
+		store.setStoreEmailAddress("test@test.com");
+
+		merchantService.create(store);
+		store = merchantService.getById(store.getId());
+		Assert.assertTrue(store!=null);
+		System.out.println(store.getId());
+		System.out.println(store.getDomainName());
+		System.out.println(store.getDefaultLanguage().getId());
+		System.out.println(store.getLanguages().size());
+	}
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/order/InvoiceTestCase.java b/sm-core/src/test/java/com/salesmanager/test/order/InvoiceTestCase.java
new file mode 100644
index 0000000..a001e95
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/order/InvoiceTestCase.java
@@ -0,0 +1,698 @@
+package com.salesmanager.test.order;
+
+import java.awt.Graphics2D;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.math.BigDecimal;
+import java.net.URL;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jopendocument.dom.OOUtils;
+import org.jopendocument.dom.spreadsheet.Sheet;
+import org.jopendocument.dom.spreadsheet.SpreadSheet;
+import org.jopendocument.model.OpenDocument;
+import org.jopendocument.renderer.ODTRenderer;
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.PageSize;
+import com.lowagie.text.Rectangle;
+import com.lowagie.text.pdf.PdfContentByte;
+import com.lowagie.text.pdf.PdfDocument;
+import com.lowagie.text.pdf.PdfTemplate;
+import com.lowagie.text.pdf.PdfWriter;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionDescription;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValueDescription;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.common.model.Billing;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerGender;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderTotal;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductAttribute;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductPrice;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatus;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory;
+import com.salesmanager.core.business.payments.model.PaymentType;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.constants.Constants;
+import com.salesmanager.core.utils.ProductPriceUtils;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+
+public class InvoiceTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	@Autowired
+	private ProductPriceUtils priceUtil;
+
+
+	@Test
+	public void createInvoice() throws ServiceException {
+		
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+		//create a product
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+	    
+	    Language en = languageService.getByCode("en");
+	    
+	    
+	    /**
+	     * 1) Create an order
+	     * 
+	     */
+	    
+	    //1.1 create a product
+	    
+	    //create an option
+	    ProductOption color = new ProductOption();
+	    color.setMerchantStore(store);
+	    color.setCode("color");
+	    color.setProductOptionType("SELECT");
+	    
+	    ProductOptionDescription colorDescription = new ProductOptionDescription();
+	    colorDescription.setDescription("Color");
+	    colorDescription.setName("Color");
+	    colorDescription.setLanguage(en);
+	    colorDescription.setProductOption(color);
+	    
+	    Set<ProductOptionDescription> colorDescriptions = new HashSet<ProductOptionDescription>();
+	    colorDescriptions.add(colorDescription);
+	    
+	    color.setDescriptions(colorDescriptions);
+	    
+	    productOptionService.create(color);
+	    
+	    //create an option value
+	    ProductOptionValue red = new ProductOptionValue();
+	    red.setMerchantStore(store);
+	    red.setCode("red");
+	    
+	    ProductOptionValueDescription redDescription = new ProductOptionValueDescription();
+	    redDescription.setDescription("Red");
+	    redDescription.setLanguage(en);
+	    redDescription.setName("Red");
+	    redDescription.setProductOptionValue(red);
+	    
+	    Set<ProductOptionValueDescription> redDescriptions = new HashSet<ProductOptionValueDescription>();
+	    redDescriptions.add(redDescription);
+	    
+	    red.setDescriptions(redDescriptions);
+	    
+	    productOptionValueService.create(red);
+
+	    //create a product
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(5));
+	    product.setProductWeight(new BigDecimal(8));
+	    product.setSku("TESTSKU");
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Product 1");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    
+
+	    // Availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(new Date());
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+
+	    //price
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    
+	    
+	    //create an attribute
+	    ProductAttribute colorAttribute = new ProductAttribute();
+	    colorAttribute.setProduct(product);
+	    colorAttribute.setProductAttributePrice(new BigDecimal(5));
+	    colorAttribute.setProductOption(color);
+	    colorAttribute.setProductOptionValue(red);
+	    
+	    Set<ProductAttribute> productAttributes = new HashSet<ProductAttribute>();
+	    productAttributes.add(colorAttribute);
+	    
+	    product.setAttributes(productAttributes);
+	    
+	    productService.saveOrUpdate(product);
+	    
+
+	    //1.2 create a Customer
+		Country country = countryService.getByCode("CA");
+		Zone zone = zoneService.getByCode("QC");
+		
+		Customer customer = new Customer();
+		customer.setMerchantStore(store);
+		customer.setEmailAddress("test@test.com");
+		customer.setGender(CustomerGender.M);				
+		customer.setAnonymous(true);
+		customer.setCompany("ifactory");
+		customer.setDateOfBirth(new Date());
+		customer.setNick("My nick");
+		customer.setDefaultLanguage(en);
+		
+		
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("358 Du Languadoc");
+	    delivery.setCity( "Boucherville" );
+	    delivery.setCountry(country);
+//	    delivery.setCountryCode(CA_COUNTRY_CODE);
+	    delivery.setFirstName("First" );
+	    delivery.setLastName("Last" );
+	    delivery.setPostalCode("J4B-8J9" );
+	    delivery.setZone(zone);	    
+	    
+	    Billing billing = new Billing();
+	    billing.setAddress("358 Du Languadoc");
+	    billing.setCity("Boucherville");
+	    billing.setCompany("CSTI Consulting");
+	    billing.setCountry(country);
+//	    billing.setCountryCode(CA_COUNTRY_CODE);
+	    billing.setFirstName("Carl" );
+	    billing.setLastName("Samson" );
+	    billing.setPostalCode("J4B-8J9");
+	    billing.setZone(zone);
+	    
+	    customer.setBilling(billing);
+	    customer.setDelivery(delivery);		
+		customerService.create(customer);
+		
+		Currency currency = currencyService.getByCode(CAD_CURRENCY_CODE);
+		
+		//1.3 create an order
+		OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
+		
+		
+		Order order = new Order();
+		order.setDatePurchased(new Date());
+		order.setCurrency(currency);
+		order.setLastModified(new Date());
+		order.setBilling(billing);
+		
+		Locale l = Locale.CANADA;
+		order.setLocale(l);
+
+
+		order.setCurrencyValue(new BigDecimal(0.98));//compared to based currency (not necessary)
+		order.setCustomerId(customer.getId());
+		order.setDelivery(delivery);
+		order.setIpAddress("ipAddress" );
+		order.setMerchant(store);
+		order.setCustomerEmailAddress(customer.getEmailAddress());
+		order.setOrderDateFinished(new Date());//committed date
+		
+		orderStatusHistory.setComments("We received your order");
+		orderStatusHistory.setCustomerNotified(1);
+		orderStatusHistory.setStatus(OrderStatus.ORDERED);
+		orderStatusHistory.setDateAdded(new Date() );
+		orderStatusHistory.setOrder(order);
+		order.getOrderHistory().add( orderStatusHistory );		
+		
+
+		order.setPaymentType(PaymentType.PAYPAL);
+		order.setPaymentModuleCode("paypal");
+		order.setStatus( OrderStatus.DELIVERED);
+		order.setTotal(new BigDecimal(23.99));
+		
+		
+		//OrderProductDownload - Digital download
+		OrderProductDownload orderProductDownload = new OrderProductDownload();
+		orderProductDownload.setDownloadCount(1);
+		orderProductDownload.setMaxdays(31);		
+		orderProductDownload.setOrderProductFilename("Your digital file name");
+		
+		//OrderProductPrice
+		OrderProductPrice oproductprice = new OrderProductPrice();
+		oproductprice.setDefaultPrice(true);	
+		oproductprice.setProductPrice(new BigDecimal(19.99) );
+		oproductprice.setProductPriceCode("baseprice" );
+		oproductprice.setProductPriceName("Base Price" );
+
+		//OrderProduct
+		OrderProduct oproduct = new OrderProduct();
+		oproduct.getDownloads().add( orderProductDownload);
+		oproduct.setOneTimeCharge( new BigDecimal(19.99) );
+		oproduct.setOrder(order);		
+		oproduct.setProductName( "Product name" );
+		oproduct.setProductQuantity(2);
+		oproduct.setSku("TB12345" );		
+		oproduct.getPrices().add(oproductprice ) ;
+		
+		
+		//an attribute to the OrderProduct
+		OrderProductAttribute orderAttribute = new OrderProductAttribute();
+		orderAttribute.setOrderProduct(oproduct);
+		orderAttribute.setProductAttributeName(colorDescription.getName());
+		orderAttribute.setProductAttributeValueName(redDescription.getName());
+		orderAttribute.setProductOptionId(color.getId());
+		orderAttribute.setProductOptionValueId(red.getId());
+		orderAttribute.setProductAttributePrice(colorAttribute.getProductAttributePrice());
+		
+		Set<OrderProductAttribute> orderAttributes = new HashSet<OrderProductAttribute>();
+		orderAttributes.add(orderAttribute);
+		
+		oproduct.setOrderAttributes(orderAttributes);
+		
+		oproductprice.setOrderProduct(oproduct);		
+		orderProductDownload.setOrderProduct(oproduct);
+		order.getOrderProducts().add(oproduct);
+		
+		
+		//product #2
+		OrderProductPrice oproductprice2 = new OrderProductPrice();
+		oproductprice2.setDefaultPrice(true);	
+		oproductprice2.setProductPrice(new BigDecimal(9.99) );
+		oproductprice2.setProductPriceCode("baseprice" );
+		oproductprice2.setProductPriceName("Base Price" );
+
+		//OrderProduct
+		OrderProduct oproduct2 = new OrderProduct();
+		oproduct2.setOneTimeCharge( new BigDecimal(9.99) );
+		oproduct2.setOrder(order);		
+		oproduct2.setProductName( "Additional item name" );
+		oproduct2.setProductQuantity(1);
+		oproduct2.setSku("TB12346" );		
+		oproduct2.getPrices().add(oproductprice2 ) ;
+		
+		oproductprice2.setOrderProduct(oproduct2);		
+		order.getOrderProducts().add(oproduct2);
+		
+		
+		
+		
+
+		//requires 
+		//OrderProduct
+		//OrderProductPrice
+		//OrderTotal
+		
+
+		
+		//OrderTotal
+		OrderTotal subtotal = new OrderTotal();	
+		subtotal.setModule("summary" );		
+		subtotal.setSortOrder(0);
+		subtotal.setText("Summary" );
+		subtotal.setTitle("Summary" );
+		subtotal.setValue(new BigDecimal(19.99 ) );
+		subtotal.setOrder(order);
+		
+		order.getOrderTotal().add(subtotal);
+		
+		OrderTotal tax = new OrderTotal();	
+		tax.setModule("tax" );		
+		tax.setSortOrder(1);
+		tax.setText("Tax" );
+		tax.setTitle("Tax" );
+		tax.setValue(new BigDecimal(4) );
+		tax.setOrder(order);
+		
+		order.getOrderTotal().add(tax);
+		
+		OrderTotal total = new OrderTotal();	
+		total.setModule("total" );		
+		total.setSortOrder(2);
+		total.setText("Total" );
+		total.setTitle("Total" );
+		total.setValue(new BigDecimal(23.99) );
+		total.setOrder(order);
+		
+		order.getOrderTotal().add(total);
+		
+		orderService.create(order);
+		Assert.assertTrue(orderService.count() == 1);
+		
+		Locale locale = Locale.ENGLISH;
+		
+		
+		order = orderService.getById(order.getId());
+		
+		/**
+		 * 2 Create an invoice
+		 */
+		try {
+			URL resource = getClass().getResource("/templates/invoice/invoice.ods");
+			File file = new File(resource.toURI());
+			//File file = new File("templates/invoice/invoice.ods");
+		
+			Sheet sheet = SpreadSheet.createFromFile(file).getSheet(0);
+			
+			
+			//Store name 
+			sheet.setValueAt(store.getStorename(), 0, 0);
+			
+			store.setStoreaddress("2001 zoo avenue");
+			store.setCurrencyFormatNational(true);//use $ instead of USD
+			
+			
+			//Address
+			//count store address cell
+			int storeAddressCell = 2;
+			//if(!StringUtils.isBlank(store.getStoreaddress())) {
+			//	sheet.setValueAt(store.getStoreaddress(), 0, storeAddressCell);
+			//	storeAddressCell ++;
+			//}
+			
+			//3
+			StringBuilder storeAddress = null;
+			if(!StringUtils.isBlank(store.getStoreaddress())) {
+				storeAddress = new StringBuilder();
+				storeAddress.append(store.getStoreaddress());
+			}
+			if(!StringUtils.isBlank(store.getStorecity())) {
+				if(storeAddress==null) {
+					storeAddress = new StringBuilder();
+				} else {
+					storeAddress.append(", ");
+				}
+				storeAddress.append(store.getStorecity());
+			}
+			if(storeAddress!=null) {
+				sheet.setValueAt(storeAddress.toString(), 0, storeAddressCell);
+				storeAddressCell ++;
+			}
+			
+			//4
+			StringBuilder storeProvince = null;
+			if(store.getZone()!=null) {
+				storeProvince = new StringBuilder();
+				List<Zone> zones = zoneService.getZones(store.getCountry(), en);
+				for(Zone z : zones) {
+					if(z.getCode().equals(store.getZone().getCode())) {
+						storeProvince.append(store.getZone().getName());
+						break;
+					}
+				}
+				
+			} else {
+				if(!StringUtils.isBlank(store.getStorestateprovince())) {
+					storeProvince = new StringBuilder();
+					storeProvince.append(store.getStorestateprovince());
+				}
+			}
+			if(store.getCountry()!=null) {
+				if(storeProvince==null) {
+					storeProvince = new StringBuilder();
+				} else {
+					storeProvince.append(", ");
+				}
+				Map<String,Country> countries = countryService.getCountriesMap(en);
+				Country c = countries.get(store.getCountry().getIsoCode());
+				if(c!=null) {
+					storeProvince.append(c.getName());
+				} else {
+					storeProvince.append(store.getCountry().getIsoCode());
+				}
+				
+			}
+			if(storeProvince!=null) {
+				sheet.setValueAt(storeProvince.toString(), 0, storeAddressCell);
+				storeAddressCell ++;
+			}
+			
+			//5
+			if(!StringUtils.isBlank(store.getStorepostalcode())) {
+				sheet.setValueAt(store.getStorepostalcode(), 0, storeAddressCell);
+				storeAddressCell ++;
+			}
+			
+			//6
+			if(!StringUtils.isBlank(store.getStorephone())) {
+				sheet.setValueAt(store.getStorephone(), 0, storeAddressCell);
+			}
+			
+			//delete address blank lines
+			for(int i = storeAddressCell; i<5; i++) {
+				sheet.setValueAt("", 0, i);
+			}
+
+			//invoice date
+			SimpleDateFormat format = new SimpleDateFormat(Constants.DEFAULT_DATE_FORMAT);
+			sheet.setValueAt(format.format(order.getDatePurchased()), 3, 2);
+			
+			//invoice number
+			sheet.setValueAt(order.getId(), 3, 3);
+			
+			//bill to
+			//count bill to address cell
+			int billToCell = 8;
+			if(!StringUtils.isBlank(customer.getBilling().getFirstName())) {
+				sheet.setValueAt(customer.getBilling().getFirstName() + " " + customer.getBilling().getLastName(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//9
+			if(!StringUtils.isBlank(customer.getBilling().getCompany())) {
+				sheet.setValueAt(customer.getBilling().getCompany(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//10
+			StringBuilder billToAddress = null;
+			if(!StringUtils.isBlank(customer.getBilling().getAddress())) {
+				billToAddress = new StringBuilder();
+				billToAddress.append(customer.getBilling().getAddress());
+			}
+			if(!StringUtils.isBlank(customer.getBilling().getCity())) {
+				if(billToAddress==null) {
+					billToAddress = new StringBuilder();
+				} else {
+					billToAddress.append(", ");
+				}
+				billToAddress.append(customer.getBilling().getCity());
+			}
+			if(billToAddress!=null) {
+				sheet.setValueAt(billToAddress.toString(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//11
+			StringBuilder billToProvince = null;
+			if(customer.getBilling().getZone()!=null) {
+				billToProvince = new StringBuilder();
+				List<Zone> zones = zoneService.getZones(customer.getBilling().getCountry(), en);
+				for(Zone z : zones) {
+					if(z.getCode().equals(customer.getBilling().getZone().getCode())) {
+						billToProvince.append(customer.getBilling().getZone().getName());
+						break;
+					}
+				}
+				
+			} else {
+				if(!StringUtils.isBlank(customer.getBilling().getState())) {
+					billToProvince = new StringBuilder();
+					billToProvince.append(customer.getBilling().getState());
+				}
+			}
+			if(customer.getBilling().getCountry()!=null) {
+				if(billToProvince==null) {
+					billToProvince = new StringBuilder();
+				} else {
+					billToProvince.append(", ");
+				}
+				Map<String,Country> countries = countryService.getCountriesMap(en);
+				Country c = countries.get(customer.getBilling().getCountry().getIsoCode());
+				if(c!=null) {
+					billToProvince.append(c.getName());
+				} else {
+					billToProvince.append(customer.getBilling().getCountry().getIsoCode());
+				}
+				
+			}
+			if(billToProvince!=null) {
+				sheet.setValueAt(billToProvince.toString(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//12
+			if(!StringUtils.isBlank(customer.getBilling().getPostalCode())) {
+				sheet.setValueAt(customer.getBilling().getPostalCode(), 0, billToCell);
+				billToCell ++;
+			}
+			
+			//13
+			if(!StringUtils.isBlank(customer.getBilling().getTelephone())) {
+				sheet.setValueAt(customer.getBilling().getTelephone(), 0, billToCell);
+			}
+			
+			//delete address blank lines
+			for(int i = billToCell; i<13; i++) {
+				sheet.setValueAt("", 0, i);
+			}
+			
+			//products
+			Set<OrderProduct> orderProducts = order.getOrderProducts();
+			int productCell = 16;
+			for(OrderProduct orderProduct : orderProducts) {
+				
+				//product name
+				String pName = orderProduct.getProductName();
+				Set<OrderProductAttribute> oAttributes = orderProduct.getOrderAttributes();
+				StringBuilder attributeName = null;
+				for(OrderProductAttribute oProductAttribute : oAttributes) {
+					if(attributeName == null) {
+						attributeName = new StringBuilder();
+						attributeName.append("[");
+					} else {
+						attributeName.append(", ");
+					}
+					attributeName.append(oProductAttribute.getProductAttributeName())
+					.append(": ")
+					.append(oProductAttribute.getProductAttributeValueName());
+					
+				}
+				
+				
+				StringBuilder productName = new StringBuilder();
+				productName.append(pName);
+				
+				if(attributeName!=null) {
+					attributeName.append("]");
+					productName.append(" ").append(attributeName.toString());
+				}
+				
+				
+				
+				
+				sheet.setValueAt(productName.toString(), 0, productCell);
+				
+				int quantity = orderProduct.getProductQuantity();
+				sheet.setValueAt(quantity, 1, productCell);
+				String amount = priceUtil.getStoreFormatedAmountWithCurrency(store, orderProduct.getOneTimeCharge());
+				sheet.setValueAt(amount, 2, productCell);
+				String t = priceUtil.getStoreFormatedAmountWithCurrency(store, priceUtil.getOrderProductTotalPrice(store, orderProduct));
+				sheet.setValueAt(t, 3, productCell);
+
+				productCell++;
+				
+			}
+			
+			//print totals
+			productCell++;
+			Set<OrderTotal> totals = order.getOrderTotal();
+			for(OrderTotal orderTotal : totals) {
+				
+				String totalName = orderTotal.getText();
+				String totalValue = priceUtil.getStoreFormatedAmountWithCurrency(store,orderTotal.getValue());
+				sheet.setValueAt(totalName, 2, productCell);
+				sheet.setValueAt(totalValue, 3, productCell);
+				productCell++;
+			}
+			
+			//sheet.getCellAt(0, 0).setImage(arg0)
+			//sheet.getCellAt(0, 0).setStyleName(arg0)
+			//sheet.getCellAt(0, 0).getStyle().
+			
+			
+			
+			File outputFile = new File(order.getId() + "_invoice.ods");
+			OOUtils.open(sheet.getSpreadSheet().saveAs(outputFile));
+			
+			
+			final OpenDocument doc = new OpenDocument();
+			doc.loadFrom(order.getId() + "_invoice.ods");
+
+			 // Open the PDF document
+			 Document document = new Document(PageSize.A4);
+			 File outFile = new File("invoice.pdf");
+
+			 PdfDocument pdf = new PdfDocument();
+
+			 document.addDocListener(pdf);
+
+			 FileOutputStream fileOutputStream = new FileOutputStream(outFile);
+			 PdfWriter writer = PdfWriter.getInstance(pdf, fileOutputStream);
+			 pdf.addWriter(writer);
+
+			 document.open();
+
+			 // Create a template and a Graphics2D object 
+			 Rectangle pageSize = document.getPageSize();
+			 int w = (int) (pageSize.getWidth() * 0.9);
+			 int h = (int) (pageSize.getHeight() * 0.95);
+			 PdfContentByte cb = writer.getDirectContent();
+			 PdfTemplate tp = cb.createTemplate(w, h);
+
+			 Graphics2D g2 = tp.createPrinterGraphics(w, h, null);
+			 // If you want to prevent copy/paste, you can use
+			 // g2 = tp.createGraphicsShapes(w, h, true, 0.9f);
+			            
+			 tp.setWidth(w);
+			 tp.setHeight(h);
+
+			 // Configure the renderer
+			 ODTRenderer renderer = new ODTRenderer(doc);
+			 renderer.setIgnoreMargins(true);
+			 renderer.setPaintMaxResolution(true);
+			            
+			 // Scale the renderer to fit width
+			 renderer.setResizeFactor(renderer.getPrintWidth() / w);
+			 // Render
+			 renderer.paintComponent(g2);
+			 g2.dispose();
+
+			 // Add our spreadsheet in the middle of the page
+			 float offsetX = (pageSize.getWidth() - w) / 2;
+			 float offsetY = (pageSize.getHeight() - h) / 2;
+			 cb.addTemplate(tp, offsetX, offsetY);
+			 // Close the PDF document
+			 document.close();
+			 
+			 outputFile.delete();//remove temp file
+			
+		} catch (Exception e) {
+			// TODO Auto-generated catch block
+			e.printStackTrace();
+		}
+		
+		
+	}
+	
+	
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/order/OrderSalesManagerTestCase.java b/sm-core/src/test/java/com/salesmanager/test/order/OrderSalesManagerTestCase.java
new file mode 100644
index 0000000..3d5c166
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/order/OrderSalesManagerTestCase.java
@@ -0,0 +1,550 @@
+package com.salesmanager.test.order;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import org.junit.Assert;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.common.model.Billing;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerGender;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.order.model.OrderCriteria;
+import com.salesmanager.core.business.order.model.OrderList;
+import com.salesmanager.core.business.order.model.OrderTotal;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProduct;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductDownload;
+import com.salesmanager.core.business.order.model.orderproduct.OrderProductPrice;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatus;
+import com.salesmanager.core.business.order.model.orderstatus.OrderStatusHistory;
+import com.salesmanager.core.business.order.model.payment.CreditCard;
+import com.salesmanager.core.business.payments.model.CreditCardType;
+import com.salesmanager.core.business.payments.model.PaymentType;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class OrderSalesManagerTestCase extends AbstractSalesManagerCoreTestCase {
+
+//	@Ignore
+	@Test
+	public void createOrder() throws ServiceException {
+		
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+		//create a product
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+	    
+	    Language en = languageService.getByCode("en");
+
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(5));
+	    product.setProductWeight(new BigDecimal(8));
+	    product.setSku("TESTSKU");
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Product 1");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    
+
+	    // Availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(new Date());
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+	    
+	    product.getAvailabilities().add(availability);
+
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+	    
+	    availability.getPrices().add(dprice);
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    
+	    productService.saveOrUpdate(product);
+	    
+	    //create a Customer
+		Country country = countryService.getByCode("CA");
+		Zone zone = zoneService.getByCode("QC");
+		
+		Customer customer = new Customer();
+		customer.setMerchantStore(store);
+		customer.setEmailAddress("test@test.com");
+		customer.setGender(CustomerGender.M);						
+		customer.setAnonymous(true);
+		customer.setCompany("ifactory");
+		customer.setDateOfBirth(new Date());
+		customer.setNick("My nick");
+		customer.setDefaultLanguage(en);
+		
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("358 Du Languadoc");
+	    delivery.setCity( "Boucherville" );
+	    delivery.setCountry(country);
+//	    delivery.setCountryCode(CA_COUNTRY_CODE);
+	    delivery.setPostalCode("J4B-8J9" );
+	    delivery.setFirstName("Carl");
+	    delivery.setLastName("Samson");
+	    delivery.setZone(zone);	    
+	    
+	    Billing billing = new Billing();
+	    billing.setAddress("358 Du Languadoc");
+	    billing.setCity("Boucherville");
+	    billing.setCompany("CSTI Consulting");
+	    billing.setCountry(country);
+//	    billing.setCountryCode(CA_COUNTRY_CODE);
+	    billing.setFirstName("Carl");
+	    billing.setLastName("Samson");
+	    billing.setPostalCode("J4B-8J9");
+	    billing.setZone(zone);
+	    
+	    customer.setBilling(billing);
+	    customer.setDelivery(delivery);		
+		customerService.create(customer);
+		
+		Currency currency = currencyService.getByCode(CAD_CURRENCY_CODE);
+
+		OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
+		
+		
+		
+		
+		Order order = new Order();
+		order.setDatePurchased(new Date());
+		order.setCurrency(currency);
+		order.setLastModified(new Date());
+		order.setBilling(billing);
+		
+		Locale l = Locale.CANADA;
+		order.setLocale(l);
+
+
+		order.setCurrencyValue(new BigDecimal(0.98));//compared to based currency (not necessary)
+		order.setCustomerId(customer.getId());
+		order.setDelivery(delivery);
+		order.setIpAddress("ipAddress" );
+		order.setMerchant(store);
+		order.setCustomerEmailAddress(customer.getEmailAddress());
+
+		order.setOrderDateFinished(new Date());//committed date
+
+		orderStatusHistory.setComments("We received your order");
+		orderStatusHistory.setCustomerNotified(1);
+		orderStatusHistory.setStatus(OrderStatus.ORDERED);
+		orderStatusHistory.setDateAdded(new Date() );
+		orderStatusHistory.setOrder(order);
+		order.getOrderHistory().add( orderStatusHistory );		
+
+		order.setPaymentType(PaymentType.PAYPAL);
+		order.setPaymentModuleCode("paypal");
+		order.setStatus( OrderStatus.DELIVERED);
+		order.setTotal(new BigDecimal(23.99));
+		
+		
+		//OrderProductDownload - Digital download
+		OrderProductDownload orderProductDownload = new OrderProductDownload();
+		orderProductDownload.setDownloadCount(1);
+		orderProductDownload.setMaxdays(31);		
+		orderProductDownload.setOrderProductFilename("Your digital file name");
+		
+		//OrderProductPrice
+		OrderProductPrice oproductprice = new OrderProductPrice();
+		oproductprice.setDefaultPrice(true);	
+		oproductprice.setProductPrice(new BigDecimal(19.99) );
+		oproductprice.setProductPriceCode("baseprice" );
+		oproductprice.setProductPriceName("Base Price" );
+
+		//OrderProduct
+		OrderProduct oproduct = new OrderProduct();
+		oproduct.getDownloads().add( orderProductDownload);
+		oproduct.setOneTimeCharge( new BigDecimal(19.99) );
+		oproduct.setOrder(order);		
+		oproduct.setProductName( "Product name" );
+		oproduct.setProductQuantity(1);
+		oproduct.setSku("TB12345" );		
+		oproduct.getPrices().add(oproductprice ) ;
+		
+		oproductprice.setOrderProduct(oproduct);		
+		orderProductDownload.setOrderProduct(oproduct);
+		order.getOrderProducts().add(oproduct);
+
+		//requires 
+		//OrderProduct
+		//OrderProductPrice
+		//OrderTotal
+		
+
+		
+		//OrderTotal
+		OrderTotal subtotal = new OrderTotal();	
+		subtotal.setModule("summary" );		
+		subtotal.setSortOrder(0);
+		subtotal.setText("Summary" );
+		subtotal.setTitle("Summary" );
+		subtotal.setOrderTotalCode("summary");
+		subtotal.setValue(new BigDecimal(19.99 ) );
+		subtotal.setOrder(order);
+		
+		order.getOrderTotal().add(subtotal);
+		
+		OrderTotal tax = new OrderTotal();	
+		tax.setModule("tax" );		
+		tax.setSortOrder(1);
+		tax.setText("Tax" );
+		tax.setTitle("Tax" );
+		tax.setOrderTotalCode("tax");
+		tax.setValue(new BigDecimal(4) );
+		tax.setOrder(order);
+		
+		order.getOrderTotal().add(tax);
+		
+		OrderTotal total = new OrderTotal();	
+		total.setModule("total" );		
+		total.setSortOrder(2);
+		total.setText("Total" );
+		total.setTitle("Total" );
+		total.setOrderTotalCode("total");
+		total.setValue(new BigDecimal(23.99) );
+		total.setOrder(order);
+		
+		order.getOrderTotal().add(total);
+		
+		orderService.create(order);
+		Assert.assertTrue(orderService.count() == 1);
+	}
+	
+	@Ignore
+	@Test
+	public void getMerchantOrders() throws ServiceException {
+		
+		List<Order> merchantOrders= new ArrayList<Order>();
+		
+		Language language = languageService.getByCode(ENGLISH_LANGUAGE_CODE);
+		Currency currency = currencyService.getByCode(EURO_CURRENCY_CODE);
+		Country country = countryService.getByCode(FR_COUNTRY_CODE);
+		Zone zone = zoneService.getByCode("VT");
+		
+		MerchantStore merchant = new MerchantStore();		
+		merchant.setCurrency(currency);
+		merchant.setStorename("Test Store");
+		merchant.setCountry(country);
+		merchant.setDefaultLanguage(language);		
+		merchant.setStorecity("Test Store City");
+		merchant.setCode( merchantService.count()+"");
+		Language en = languageService.getByCode("en");
+		Language fr = languageService.getByCode("fr");
+		List<Language> supportedLanguages = new ArrayList<Language>();
+		supportedLanguages.add(en);
+		supportedLanguages.add(fr);
+		merchant.setLanguages( supportedLanguages );
+		merchant.setStoreEmailAddress("store_email@email.com");
+		merchant.setStorephone("Merchant Store Phone");
+		merchant.setStorepostalcode("12061");		
+		merchantService.create(merchant);	
+		
+		
+		Customer customer = new Customer();	
+		customer.setMerchantStore(merchant);
+		customer.setEmailAddress("email@email.com");
+		customer.setPassword("-1999");
+		customer.setNick("My New nick");
+		customer.setCompany(" Apple");	
+		customer.setGender(CustomerGender.M);
+		customer.setDateOfBirth(new Date());		
+		
+		Billing billing = new Billing();
+	    billing.setAddress("Billing address");
+	    billing.setCity("Billing city");
+	    billing.setCompany("Billing company");
+	    billing.setCountry(country);
+//	    billing.setCountryCode(CA_COUNTRY_CODE);
+	    billing.setFirstName("Carl");
+	    billing.setLastName("Samson");
+	    billing.setPostalCode("Billing postal code");
+	    billing.setState("Billing state");
+	    billing.setZone(zone);
+	    
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("Shipping address");
+	    delivery.setCountry(country);
+	    delivery.setZone(zone);	    
+	    
+	    customer.setBilling(billing);
+	    customer.setDelivery(delivery);
+	    
+		customerService.create(customer);		
+				
+		OrderStatusHistory orderStatusHistory = new OrderStatusHistory();
+		Order order = new Order();
+		order.setDatePurchased(new Date());
+		order.setCurrency(currency);
+		order.setMerchant(merchant);
+		order.setLastModified(new Date());
+		
+		CreditCard creditCard = new CreditCard();
+		creditCard.setCardType(CreditCardType.VISA);
+
+		creditCard.setCcCvv("123");
+		creditCard.setCcExpires("12/30/2020" );
+		creditCard.setCcNumber( "123456789");
+		creditCard.setCcOwner("ccOwner" );
+
+		order.setCreditCard(creditCard);
+		
+		order.setCurrencyValue(new BigDecimal(19.99));
+		order.setCustomerId(new Long(1) );
+		order.setDelivery(delivery);
+		order.setIpAddress("ipAddress" );
+		order.setMerchant(merchant);
+		order.setOrderDateFinished(new Date());		
+		orderStatusHistory.setDateAdded(new Date() );
+		orderStatusHistory.setOrder(order);
+		order.setPaymentType(PaymentType.CREDITCARD);
+		order.setPaymentModuleCode("payment Module Code");
+		order.setShippingModuleCode("UPS" );
+		order.setStatus( OrderStatus.ORDERED);
+		order.setTotal(new BigDecimal(23.99));
+		
+		//OrderProduct
+		OrderProduct oproduct = new OrderProduct();
+		oproduct.setDownloads(null);
+		oproduct.setOneTimeCharge( new BigDecimal(16.99) );
+		oproduct.setOrder(order);		
+		oproduct.setProductName( "Order Product Name" );
+		oproduct.setProductQuantity(5);
+		oproduct.setSku("Order Product sku" );		
+
+
+		orderService.create(order);
+
+	
+		merchantOrders = orderService.listByStore(merchant);
+
+		
+		Assert.assertTrue("Merchant Orders are null." , merchantOrders != null);
+		Assert.assertTrue("Merchant Orders count is not one." , (merchantOrders != null && merchantOrders.size() == 1) );
+	}
+	
+	
+	@Test
+	public void testSearchOrders() throws ServiceException {
+		
+		MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+		Country country = countryService.getByCode("CA");
+		Zone zone = zoneService.getByCode("VT");
+		
+		//create 3 customers
+		Customer firstCustomer = new Customer();
+		firstCustomer.setMerchantStore(store);
+		firstCustomer.setEmailAddress("test@test.com");
+		firstCustomer.setGender(CustomerGender.M);
+		firstCustomer.setAnonymous(true);
+		firstCustomer.setCompany("ifactory");
+		firstCustomer.setDateOfBirth(new Date());
+		firstCustomer.setNick("My nick");
+		firstCustomer.setPassword("123456");
+
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("Shipping address");
+	    delivery.setCountry(country);
+	    delivery.setZone(zone);
+	    
+	    
+	    Billing billing = new Billing();
+	    billing.setAddress("Billing address");
+	    billing.setCountry(country);
+	    billing.setZone(zone);
+	    
+	    firstCustomer.setBilling(billing);
+	    firstCustomer.setDelivery(delivery);
+		
+		customerService.create(firstCustomer);
+		
+		Customer secondCustomer = new Customer();
+		secondCustomer.setMerchantStore(store);
+		secondCustomer.setEmailAddress("test@test.com");
+		secondCustomer.setGender(CustomerGender.M);
+		secondCustomer.setDateOfBirth(new Date());
+		secondCustomer.setPassword("123456");
+
+		
+		secondCustomer.setBilling(billing);
+		secondCustomer.setDelivery(delivery);
+		
+		customerService.create(secondCustomer);
+		
+		Customer thirdCustomer = new Customer();
+		thirdCustomer.setMerchantStore(store);
+		thirdCustomer.setEmailAddress("test@test.com");
+		thirdCustomer.setGender(CustomerGender.M);
+		thirdCustomer.setDateOfBirth(new Date());
+		thirdCustomer.setPassword("123456");
+
+		
+		thirdCustomer.setBilling(billing);
+		thirdCustomer.setDelivery(delivery);
+		
+		customerService.create(thirdCustomer);
+		
+		//create a few orders
+		Order order = new Order();
+		order.setDatePurchased(new Date());
+		order.setCurrency(store.getCurrency());
+		order.setMerchant(store);
+		order.setLastModified(new Date());
+		
+		CreditCard creditCard = new CreditCard();
+		creditCard.setCardType(CreditCardType.VISA);
+
+		creditCard.setCcCvv("123");
+		creditCard.setCcExpires("12/30/2020" );
+		creditCard.setCcNumber( "123456789");
+		creditCard.setCcOwner("ccOwner" );
+
+		order.setCreditCard(creditCard);
+		order.setCurrencyValue(new BigDecimal(19.99));
+		order.setCustomerId(new Long(1) );
+		order.setDelivery(delivery);
+		order.setIpAddress("ipAddress" );
+
+		order.setPaymentType(PaymentType.CREDITCARD);
+		order.setPaymentModuleCode("beanstream");
+		order.setShippingModuleCode("ups" );
+		order.setStatus( OrderStatus.ORDERED);
+		order.setTotal(new BigDecimal(23.99));
+		
+		OrderProductPrice oproductprice = new OrderProductPrice();
+		oproductprice.setDefaultPrice(true);	
+		oproductprice.setProductPrice(new BigDecimal(19.99) );
+		oproductprice.setProductPriceCode("baseprice" );
+		oproductprice.setProductPriceName("Base Price" );
+
+		//OrderProduct
+		OrderProduct oproduct = new OrderProduct();
+		oproduct.setOneTimeCharge( new BigDecimal(19.99) );
+		oproduct.setOrder(order);		
+		oproduct.setProductName( "Product name" );
+		oproduct.setProductQuantity(1);
+		oproduct.setSku("TB12345" );		
+		oproduct.getPrices().add(oproductprice ) ;
+		
+		oproductprice.setOrderProduct(oproduct);		
+		order.getOrderProducts().add(oproduct);
+
+		OrderTotal orderTotal = new OrderTotal();
+		orderTotal.setModule("total");
+		orderTotal.setOrder(order);
+		orderTotal.setText("Total");
+		orderTotal.setTitle("total");
+		orderTotal.setValue(new BigDecimal(23.99));
+		
+		order.getOrderTotal().add(orderTotal);
+		
+		orderService.create(order);
+		
+		
+		Order secondOrder = new Order();
+		secondOrder.setDatePurchased(new Date());
+		secondOrder.setCurrency(store.getCurrency());
+		secondOrder.setMerchant(store);
+		secondOrder.setLastModified(new Date());
+		
+		creditCard = new CreditCard();
+		creditCard.setCardType(CreditCardType.VISA);
+
+		creditCard.setCcCvv("123");
+		creditCard.setCcExpires("12/30/2020" );
+		creditCard.setCcNumber( "123456789");
+		creditCard.setCcOwner("ccOwner" );
+
+		order.setCreditCard(creditCard);
+		secondOrder.setCurrencyValue(new BigDecimal(19.99));
+		secondOrder.setCustomerId(secondCustomer.getId() );
+		secondOrder.setDelivery(delivery);
+		secondOrder.setIpAddress("ipAddress" );
+		order.setPaymentType(PaymentType.CREDITCARD);
+		order.setPaymentModuleCode("beanstream");
+		order.setShippingModuleCode("ups" );
+		secondOrder.setShippingModuleCode("ups" );
+		secondOrder.setStatus( OrderStatus.ORDERED);
+		secondOrder.setTotal(new BigDecimal(23.99));
+		
+		oproductprice = new OrderProductPrice();
+		oproductprice.setDefaultPrice(true);	
+		oproductprice.setProductPrice(new BigDecimal(19.99) );
+		oproductprice.setProductPriceCode("baseprice" );
+		oproductprice.setProductPriceName("Base Price" );
+		
+		//OrderProduct
+		oproduct = new OrderProduct();
+		oproduct.setOneTimeCharge( new BigDecimal(19.99) );
+		oproduct.setOrder(secondOrder);		
+		oproduct.setProductName( "Product name" );
+		oproduct.setProductQuantity(1);
+		oproduct.setSku("TB12345" );		
+		oproduct.getPrices().add(oproductprice ) ;
+		
+		oproductprice.setOrderProduct(oproduct);		
+		secondOrder.getOrderProducts().add(oproduct);
+
+		orderTotal = new OrderTotal();
+		orderTotal.setModule("total");
+		orderTotal.setOrder(secondOrder);
+		orderTotal.setText("Total");
+		orderTotal.setTitle("total");
+		orderTotal.setValue(new BigDecimal(23.99));
+		
+		order.getOrderTotal().add(orderTotal);
+
+		
+		orderService.create(secondOrder);
+		
+		OrderCriteria orderCriteria = new OrderCriteria();
+		orderCriteria.setCustomerName("Cruise");
+		orderCriteria.setStartIndex(0);
+		orderCriteria.setMaxCount(5);
+		
+		OrderList orderList = orderService.listByStore(store, orderCriteria);
+		
+		Assert.assertNotNull(orderList);
+		
+		System.out.println("Total count " + orderList.getTotalCount());
+		
+		
+	}
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/payment/PaymentTestCase.java b/sm-core/src/test/java/com/salesmanager/test/payment/PaymentTestCase.java
new file mode 100644
index 0000000..19e2dcc
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/payment/PaymentTestCase.java
@@ -0,0 +1,113 @@
+package com.salesmanager.test.payment;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import com.salesmanager.core.business.common.model.Billing;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerGender;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.Order;
+import com.salesmanager.core.business.payments.model.CreditCardType;
+import com.salesmanager.core.business.payments.model.CreditCardPayment;
+import com.salesmanager.core.business.payments.model.PaymentType;
+import com.salesmanager.core.business.payments.model.TransactionType;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class PaymentTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+
+	
+	@Test
+	public void testBeanStreamPayment() throws ServiceException {
+		
+	    Language en = languageService.getByCode("en");
+	    Country country = countryService.getByCode("CA");
+	    Zone zone = zoneService.getByCode("QC");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+	    
+	    //create customer
+		Customer customer = new Customer();
+		customer.setMerchantStore(store);
+		customer.setEmailAddress("test@test.com");
+		customer.setGender(CustomerGender.M);
+		customer.setAnonymous(true);
+		customer.setCompany("ifactory");
+		customer.setDateOfBirth(new Date());
+		customer.setNick("My nick");
+		customer.setPassword("123456");
+
+		
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("Shipping address");
+	    delivery.setCity("Boucherville");
+	    delivery.setCountry(country);
+	    delivery.setZone(zone);
+	    delivery.setPostalCode("J4B-8J9");
+
+	    Billing billing = new Billing();
+	    billing.setAddress("Billing address");
+	    billing.setCountry(country);
+	    billing.setZone(zone);
+	    billing.setPostalCode("J4B-8J9");
+	    
+	    customer.setBilling(billing);
+	    customer.setDelivery(delivery);
+	    
+
+	    
+	    //create Payment
+	    CreditCardPayment payment = new CreditCardPayment();
+	    payment.setModuleName("beanstream");
+	    payment.setPaymentType(PaymentType.CREDITCARD);
+		payment.setCardOwner("Test User");
+		payment.setCredidCardValidationNumber("0421");
+		payment.setCreditCardNumber("545412345678");
+		payment.setExpirationMonth("04");
+		payment.setExpirationYear("16");
+		payment.setCreditCard(CreditCardType.MASTERCARD);
+		payment.setTransactionType(TransactionType.AUTHORIZECAPTURE);
+	    
+		
+		IntegrationConfiguration paymentConfiguration = new IntegrationConfiguration();
+		
+		paymentConfiguration.setActive(true);
+		paymentConfiguration.setEnvironment(IntegrationConfiguration.TEST_ENVIRONMENT);
+		paymentConfiguration.setModuleCode("beanstream");
+		
+		Map<String,String> integrationKeys = new HashMap<String,String>();
+		integrationKeys.put("merchantid", "123456");
+		integrationKeys.put("username", "accnt");
+		integrationKeys.put("password", "pass123");
+		integrationKeys.put("transaction", "CAPTURE");
+		
+		paymentConfiguration.setIntegrationKeys(integrationKeys);
+		
+		paymentService.savePaymentModuleConfiguration(paymentConfiguration, store);
+		
+		Order order = new Order();
+		order.setTotal(new BigDecimal(20));
+		
+		//paypal requires item list List<ShoppinCartItem> for the rest i set null
+		paymentService.processPayment(customer, store, payment, null, order);
+
+		
+		
+	}
+	
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/search/IndexProductTestCase.java b/sm-core/src/test/java/com/salesmanager/test/search/IndexProductTestCase.java
new file mode 100644
index 0000000..d189d5c
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/search/IndexProductTestCase.java
@@ -0,0 +1,153 @@
+package com.salesmanager.test.search;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import org.junit.Test;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionDescription;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionType;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValueDescription;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class IndexProductTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+
+	
+	@Test
+	public void testIndexProduct() throws ServiceException {
+		
+	    Language en = languageService.getByCode("en");
+	    Language fr = languageService.getByCode("fr");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+
+	    /**
+	     * Create the category
+	     */
+	    Category book = new Category();
+	    book.setMerchantStore(store);
+	    book.setCode("book");
+
+	    CategoryDescription bookEnglishDescription = new CategoryDescription();
+	    bookEnglishDescription.setName("Book");
+	    bookEnglishDescription.setCategory(book);
+	    bookEnglishDescription.setLanguage(en);
+
+	    CategoryDescription bookFrenchDescription = new CategoryDescription();
+	    bookFrenchDescription.setName("Livre");
+	    bookFrenchDescription.setCategory(book);
+	    bookFrenchDescription.setLanguage(fr);
+
+	    List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+	    descriptions.add(bookEnglishDescription);
+	    descriptions.add(bookFrenchDescription);
+
+	    book.setDescriptions(descriptions);
+
+	    categoryService.create(book);
+	    
+	    
+	    /**
+	     * Create a manufacturer
+	     */
+	    Manufacturer packed = new Manufacturer();
+	    packed.setMerchantStore(store);
+
+	    ManufacturerDescription packedd = new ManufacturerDescription();
+	    packedd.setLanguage(en);
+	    packedd.setManufacturer(packed);
+	    packedd.setName("Packed publishing");
+	    packed.getDescriptions().add(packedd);
+
+	    manufacturerService.create(packed);
+	    
+
+	    
+
+	    
+	    
+	    /**
+	     * Create a simple product
+	     */
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(1));
+	    product.setSku("TB12345");
+	    product.setManufacturer(packed);
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Spring in Action");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+	    
+	    product.getDescriptions().add(description);
+	    
+	    ProductDescription descriptionF = new ProductDescription();
+	    descriptionF.setName("Spring en plein action");
+	    descriptionF.setLanguage(fr);
+	    descriptionF.setProduct(product);
+
+	    product.getDescriptions().add(descriptionF);
+	    product.getCategories().add(book);
+	    
+	    
+	    //availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(date);
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+	    
+	    //price
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+	    
+	    
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    availability.getPrices().add(dprice);
+	    
+
+	    productService.create(product);//this will index the product
+	    
+	    
+	    
+	    
+	    
+	}
+	
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/shipping/ShippingTestCase.java b/sm-core/src/test/java/com/salesmanager/test/shipping/ShippingTestCase.java
new file mode 100644
index 0000000..e73281f
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/shipping/ShippingTestCase.java
@@ -0,0 +1,568 @@
+package com.salesmanager.test.shipping;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Locale;
+
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.Assert;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.common.model.Billing;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerGender;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.language.service.LanguageService;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.shipping.model.PackageDetails;
+import com.salesmanager.core.business.shipping.model.ShippingBasisType;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingPackageType;
+import com.salesmanager.core.business.shipping.model.ShippingProduct;
+import com.salesmanager.core.business.shipping.model.ShippingQuote;
+import com.salesmanager.core.business.shipping.model.ShippingType;
+import com.salesmanager.core.business.shipping.service.ShippingService;
+import com.salesmanager.core.business.system.model.Environment;
+import com.salesmanager.core.business.system.model.IntegrationConfiguration;
+import com.salesmanager.core.modules.integration.shipping.model.CustomShippingQuoteWeightItem;
+import com.salesmanager.core.modules.integration.shipping.model.CustomShippingQuotesConfiguration;
+import com.salesmanager.core.modules.integration.shipping.model.CustomShippingQuotesRegion;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class ShippingTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+	@Autowired
+	private ShippingService shippingService;
+	
+	@Autowired
+	private LanguageService languageService;
+	
+	/**
+	 * This test will invoke a shipping module to get real time shipping quotes
+	 * @throws ServiceException
+	 */
+	@Test
+	public void testGetShippingPackages() throws ServiceException {
+
+	    Language en = languageService.getByCode("en");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+	    
+	    //generate 2 products
+	    
+	    // PRODUCT 1 (height 4 inches x 3 inches length + 5 inches width) 1 pound
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(5));
+	    product.setProductWeight(new BigDecimal(8));
+	    product.setSku("TB12345");
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Product 1");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    //productService.create(product);
+
+	    // Availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(date);
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+
+	    //productAvailabilityService.create(availability);
+
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+
+
+	    // PRODUCT 2  (height 3 inches x 4 inches length x 5 inches width) 2 pounds
+
+	    Product product2 = new Product();
+	    product2.setProductHeight(new BigDecimal(3));
+	    product2.setProductLength(new BigDecimal(4));
+	    product2.setProductWidth(new BigDecimal(5));
+	    product2.setProductWeight(new BigDecimal(2));
+	    product2.setSku("TB2468");
+	    product2.setType(generalType);
+	    product2.setMerchantStore(store);
+
+	    // Product description
+	    description = new ProductDescription();
+	    description.setName("Product 2");
+	    description.setLanguage(en);
+	    description.setProduct(product2);
+
+	    product2.getDescriptions().add(description);
+
+
+	    // Availability
+	    ProductAvailability availability2 = new ProductAvailability();
+	    availability2.setProductDateAvailable(date);
+	    availability2.setProductQuantity(100);
+	    availability2.setRegion("*");
+	    availability2.setProduct(product2);// associate with product
+
+	    //productAvailabilityService.create(availability2);
+
+	    ProductPrice dprice2 = new ProductPrice();
+	    dprice2.setDefaultPrice(true);
+	    dprice2.setProductPriceAmount(new BigDecimal(39.99));
+	    dprice2.setProductAvailability(availability2);
+
+	    dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice2);
+	    dpd.setLanguage(en);
+
+	    dprice2.getDescriptions().add(dpd);
+
+	    //add an attribute to product 2 that will augment weight of 1 pound
+	    ProductAttribute attribute = new ProductAttribute();
+	    attribute.setProduct(product2);
+	    attribute.setAttributeDefault(true);
+	    attribute.setProductAttributePrice(new BigDecimal(0));//no price variation
+	    attribute.setProductAttributeWeight(new BigDecimal(1));//weight variation
+
+	    
+	    product2.getAttributes().add(attribute);
+	    
+	    //create an integration configuration
+	    IntegrationConfiguration configuration = new IntegrationConfiguration();
+	    configuration.setActive(true);
+	    configuration.setEnvironment(Environment.TEST.name());
+	    configuration.setModuleCode("canadapost");
+	    
+	    //configure shipping
+	    ShippingConfiguration shippingConfiguration = new ShippingConfiguration();
+	    shippingConfiguration.setShippingBasisType(ShippingBasisType.SHIPPING);
+	    shippingConfiguration.setShippingType(ShippingType.INTERNATIONAL);
+	    shippingConfiguration.setShippingPackageType(ShippingPackageType.ITEM);
+	    shippingConfiguration.setBoxHeight(5);
+	    shippingConfiguration.setBoxLength(5);
+	    shippingConfiguration.setBoxWidth(5);
+	    shippingConfiguration.setBoxWeight(1);
+	    shippingConfiguration.setMaxWeight(10);
+	    
+	    //configure module
+	    List<String> options = new ArrayList<String>();
+	    options.add("PACKAGE");
+	    configuration.getIntegrationKeys().put("account", "CPC_CS_TI_INC");
+	    configuration.getIntegrationOptions().put("packages",options);
+	    
+	    shippingService.saveShippingConfiguration(shippingConfiguration, store);
+	    shippingService.saveShippingQuoteModuleConfiguration(configuration, store);
+	    
+	    //now create ShippingProduct
+	    ShippingProduct shippingProduct1 = new ShippingProduct(product);
+	    ShippingProduct shippingProduct2 = new ShippingProduct(product2);
+	    List<ShippingProduct> shippingProducts = new ArrayList<ShippingProduct>();
+	    shippingProducts.add(shippingProduct1);
+	    shippingProducts.add(shippingProduct2);
+	    
+	    List<PackageDetails> details = shippingService.getPackagesDetails(shippingProducts, store);
+	    
+	    Assert.notNull(details);
+	    
+	    for(PackageDetails pack : details) {
+	    	System.out.println("Height " + pack.getShippingHeight());
+	    	System.out.println("Length " + pack.getShippingLength());
+	    	System.out.println("Width " + pack.getShippingWidth());
+	    	System.out.println("Weight " + pack.getShippingWeight());
+	    }
+
+	    
+	}
+	
+	@Test
+	public void testGetShippingQuotes() throws ServiceException {
+
+	    Language en = languageService.getByCode("en");
+	    Country country = countryService.getByCode("CA");
+	    Zone zone = zoneService.getByCode("QC");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+	    
+	    //set valid store postal code
+	    store.setStorepostalcode("J4B-9J9");
+
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(5));
+	    product.setProductWeight(new BigDecimal(8));
+	    product.setSku("TESTSKU");
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Product 1");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    
+
+	    // Availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(new Date());
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    availability.getPrices().add(dprice);
+	    
+	    product.getAvailabilities().add(availability);
+	    
+	    productService.saveOrUpdate(product);
+	    
+	    
+
+	    
+	    //configure shipping
+	    ShippingConfiguration shippingConfiguration = new ShippingConfiguration();
+	    shippingConfiguration.setShippingBasisType(ShippingBasisType.SHIPPING);//based on shipping or billing address
+	    shippingConfiguration.setShippingType(ShippingType.INTERNATIONAL);
+	    shippingConfiguration.setShippingPackageType(ShippingPackageType.ITEM);//individual item pricing or box packaging (see unit test above)
+	    //only if package type is package
+	    shippingConfiguration.setBoxHeight(5);
+	    shippingConfiguration.setBoxLength(5);
+	    shippingConfiguration.setBoxWidth(5);
+	    shippingConfiguration.setBoxWeight(1);
+	    shippingConfiguration.setMaxWeight(10);
+	    
+	    List<String> supportedCountries = new ArrayList<String>();
+	    supportedCountries.add("CA");
+	    supportedCountries.add("US");
+	    supportedCountries.add("UK");
+	    supportedCountries.add("FR");
+	    
+	    shippingService.setSupportedCountries(store, supportedCountries);
+	    
+	    //create an integration configuration - CANADA POST
+	    /*
+	    IntegrationConfiguration configuration = new IntegrationConfiguration();
+	    configuration.setActive(true);
+	    configuration.setEnvironment(Environment.TEST.name());
+	    configuration.setModuleCode("canadapost");
+	    
+	    //configure module
+	    List<String> options = new ArrayList<String>();
+	    options.add("PACKAGE");//PACKAGE or ENVELOPE (supported by Canadapost)
+	    configuration.getIntegrationKeys().put("account", "CPC_CS_TI_INC");//CPC_DEMO_HTML
+	    configuration.getIntegrationOptions().put("packages",options);*/
+	    
+	    //create an integration configuration - USPS
+	    
+	    //overwrite shipping US
+/*	    Country us = countryService.getByCode("US");
+	    Zone NY = zoneService.getByCode("NY");//store (origin) has to be in the US
+	    store.setCountry(us);
+	    store.setZone(NY);
+	    store.setStorepostalcode("10451");*/
+	    
+/*	    IntegrationConfiguration configuration = new IntegrationConfiguration();
+	    configuration.setActive(true);
+	    configuration.setEnvironment(Environment.TEST.name());
+	    configuration.setModuleCode("usps");
+	    
+	    //configure module
+	    List<String> options = new ArrayList<String>();
+	    options.add("Package");//Package or Envelope (supported by USPS)
+	    configuration.getIntegrationKeys().put("account", "636CSTIC6187");
+	    configuration.getIntegrationOptions().put("packages",options);*/
+	    
+	    
+	    //create an integration configuration - USPS
+	    
+	    IntegrationConfiguration configuration = new IntegrationConfiguration();
+	    configuration.setActive(true);
+	    configuration.setEnvironment(Environment.TEST.name());
+	    configuration.setModuleCode("ups");
+	    
+	    //configure module
+
+	    configuration.getIntegrationKeys().put("userId", "csamson777");
+	    configuration.getIntegrationKeys().put("accessKey", "AC66279FF8020AE0");
+	    configuration.getIntegrationKeys().put("password", "william");
+	    
+	    List<String> options = new ArrayList<String>();
+	    options.add("21");
+	    configuration.getIntegrationOptions().put("packages",options);
+
+	    shippingService.saveShippingConfiguration(shippingConfiguration, store);
+	    shippingService.saveShippingQuoteModuleConfiguration(configuration, store);
+	    
+	    //now create ShippingProduct
+	    ShippingProduct shippingProduct1 = new ShippingProduct(product);
+	    List<ShippingProduct> shippingProducts = new ArrayList<ShippingProduct>();
+	    shippingProducts.add(shippingProduct1);
+	    
+		Customer customer = new Customer();
+		customer.setMerchantStore(store);
+		customer.setEmailAddress("test@test.com");
+		customer.setGender(CustomerGender.M);
+		customer.setAnonymous(true);
+		customer.setCompany("ifactory");
+		customer.setDateOfBirth(new Date());
+		customer.setNick("My nick");
+		customer.setPassword("123456");
+
+		
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("Shipping address");
+	    delivery.setCity("Boucherville");
+	    delivery.setCountry(country);
+	    delivery.setZone(zone);
+	    delivery.setPostalCode("J4B-8J9");
+	    
+	    //overwrite delivery to US (USPS)
+/*	    delivery.setPostalCode("90002");
+	    delivery.setCountry(us);
+	    Zone california = zoneService.getByCode("CA");
+	    delivery.setZone(california);*/
+	    
+	    
+	    Billing billing = new Billing();
+	    billing.setAddress("Billing address");
+	    billing.setCountry(country);
+	    billing.setZone(zone);
+	    billing.setPostalCode("J4B-8J9");
+	    
+	    customer.setBilling(billing);
+	    customer.setDelivery(delivery);
+		
+		customerService.create(customer);
+	    
+	    ShippingQuote shippingQuote = shippingService.getShippingQuote(store, delivery, shippingProducts, en);
+
+	    Assert.notNull(shippingQuote);
+	    
+	}
+
+	
+	
+	
+	
+	
+	@Test
+	public void testGetCustomShippingQuotesByWeight() throws ServiceException {
+
+	    Language en = languageService.getByCode("en");
+	    Country country = countryService.getByCode("CA");
+	    Zone zone = zoneService.getByCode("QC");
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+	    
+	    //set valid store postal code
+	    store.setStorepostalcode("J4B-9J9");
+
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(5));
+	    product.setProductWeight(new BigDecimal(8));
+	    product.setSku("TESTSKU");
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Product 1");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    
+
+	    // Availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(new Date());
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    availability.getPrices().add(dprice);
+	    
+	    product.getAvailabilities().add(availability);
+	    
+	    productService.saveOrUpdate(product);
+	    
+	    
+
+	    
+	    //configure shipping
+	    ShippingConfiguration shippingConfiguration = new ShippingConfiguration();
+	    shippingConfiguration.setShippingBasisType(ShippingBasisType.SHIPPING);//based on shipping or billing address
+	    shippingConfiguration.setShippingType(ShippingType.INTERNATIONAL);
+	    shippingConfiguration.setShippingPackageType(ShippingPackageType.ITEM);//individual item pricing or box packaging (see unit test above)
+	    //only if package type is package
+	    shippingConfiguration.setBoxHeight(5);
+	    shippingConfiguration.setBoxLength(5);
+	    shippingConfiguration.setBoxWidth(5);
+	    shippingConfiguration.setBoxWeight(1);
+	    shippingConfiguration.setMaxWeight(10);
+	    
+	    List<String> supportedCountries = new ArrayList<String>();
+	    supportedCountries.add("CA");
+	    supportedCountries.add("US");
+	    supportedCountries.add("UK");
+	    supportedCountries.add("FR");
+	    
+	    shippingService.setSupportedCountries(store, supportedCountries);
+	    
+
+	    CustomShippingQuotesConfiguration customConfiguration = new CustomShippingQuotesConfiguration();
+		customConfiguration.setModuleCode("weightBased");
+		customConfiguration.setActive(true);
+		
+		CustomShippingQuotesRegion northRegion = new CustomShippingQuotesRegion();
+		northRegion.setCustomRegionName("NORTH");
+		
+		List<String> countries = new ArrayList<String>();
+		countries.add("CA");
+		countries.add("US");
+		
+		northRegion.setCountries(countries);
+		
+		CustomShippingQuoteWeightItem caQuote4 = new CustomShippingQuoteWeightItem();
+		caQuote4.setMaximumWeight(4);
+		caQuote4.setPrice(new BigDecimal(20));
+		CustomShippingQuoteWeightItem caQuote10 = new CustomShippingQuoteWeightItem();
+		caQuote10.setMaximumWeight(10);
+		caQuote10.setPrice(new BigDecimal(50));
+		CustomShippingQuoteWeightItem caQuote100 = new CustomShippingQuoteWeightItem();
+		caQuote100.setMaximumWeight(100);
+		caQuote100.setPrice(new BigDecimal(120));
+		List<CustomShippingQuoteWeightItem> quotes = new ArrayList<CustomShippingQuoteWeightItem>();
+		quotes.add(caQuote4);
+		quotes.add(caQuote10);
+		quotes.add(caQuote100);
+		
+		northRegion.setQuoteItems(quotes);
+		
+		customConfiguration.getRegions().add(northRegion);
+	    
+	    
+	    //create an integration configuration - USPS
+	    
+	    IntegrationConfiguration configuration = new IntegrationConfiguration();
+	    configuration.setActive(true);
+	    configuration.setEnvironment(Environment.TEST.name());
+	    configuration.setModuleCode("weightBased");
+	    
+	    //configure module
+
+
+
+	    shippingService.saveShippingConfiguration(shippingConfiguration, store);
+	    shippingService.saveShippingQuoteModuleConfiguration(configuration, store);//create the basic configuration
+	    shippingService.saveCustomShippingConfiguration("weightBased", customConfiguration, store);//and the custom configuration
+	    
+	    //now create ShippingProduct
+	    ShippingProduct shippingProduct1 = new ShippingProduct(product);
+	    List<ShippingProduct> shippingProducts = new ArrayList<ShippingProduct>();
+	    shippingProducts.add(shippingProduct1);
+	    
+		Customer customer = new Customer();
+		customer.setMerchantStore(store);
+		customer.setEmailAddress("test@test.com");
+		customer.setGender(CustomerGender.M);
+
+		customer.setAnonymous(true);
+		customer.setCompany("ifactory");
+		customer.setDateOfBirth(new Date());
+		customer.setNick("My nick");
+		customer.setPassword("123456");
+
+		
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("Shipping address");
+	    delivery.setCity("Boucherville");
+	    delivery.setCountry(country);
+	    delivery.setZone(zone);
+	    delivery.setPostalCode("J4B-8J9");
+	    
+	    //overwrite delivery to US
+/*	    delivery.setPostalCode("90002");
+	    delivery.setCountry(us);
+	    Zone california = zoneService.getByCode("CA");
+	    delivery.setZone(california);*/
+	    
+	    
+	    Billing billing = new Billing();
+	    billing.setAddress("Billing address");
+	    billing.setCountry(country);
+	    billing.setZone(zone);
+	    billing.setPostalCode("J4B-8J9");
+	    
+	    customer.setBilling(billing);
+	    customer.setDelivery(delivery);
+		
+		customerService.create(customer);
+	    
+	    ShippingQuote shippingQuote = shippingService.getShippingQuote(store, delivery, shippingProducts, en);
+
+	    Assert.notNull(shippingQuote);
+	    
+	}
+
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/shoppingcart/ShoppingCartTestCase.java b/sm-core/src/test/java/com/salesmanager/test/shoppingcart/ShoppingCartTestCase.java
new file mode 100644
index 0000000..a67a394
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/shoppingcart/ShoppingCartTestCase.java
@@ -0,0 +1,481 @@
+package com.salesmanager.test.shoppingcart;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+import java.util.UUID;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.catalog.category.model.Category;
+import com.salesmanager.core.business.catalog.category.model.CategoryDescription;
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductAttribute;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOption;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionDescription;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionType;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValue;
+import com.salesmanager.core.business.catalog.product.model.attribute.ProductOptionValueDescription;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.Manufacturer;
+import com.salesmanager.core.business.catalog.product.model.manufacturer.ManufacturerDescription;
+import com.salesmanager.core.business.catalog.product.model.price.FinalPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.catalog.product.model.type.ProductType;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartAttributeItem;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.utils.ProductPriceUtils;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+/**
+ * Test 
+ * 
+ * - Add a product to persistent shopping cart
+ * - Retrieve an item from the persistent shopping cart
+ * - Rebuild a shopping cart item after the product definition has been modified
+ * @author Carl Samson
+ *
+ */
+public class ShoppingCartTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	@Autowired
+	private ProductPriceUtils productPriceUtil;
+	
+    @Test
+    public void createShoppingCart()
+        throws ServiceException
+    {
+
+        MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        
+		
+	    Language en = languageService.getByCode("en");
+
+
+	    /** CATALOG CREATION **/
+	    
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+
+	    /**
+	     * Create the category
+	     */
+	    Category shirts = new Category();
+	    shirts.setMerchantStore(store);
+	    shirts.setCode("shirts");
+
+	    CategoryDescription shirtsEnglishDescription = new CategoryDescription();
+	    shirtsEnglishDescription.setName("Shirts");
+	    shirtsEnglishDescription.setCategory(shirts);
+	    shirtsEnglishDescription.setLanguage(en);
+
+	    List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+	    descriptions.add(shirtsEnglishDescription);
+
+
+	    shirts.setDescriptions(descriptions);
+	    categoryService.create(shirts);
+	    
+	    
+	    /**
+	     * Create a manufacturer
+	     */
+	    Manufacturer addidas = new Manufacturer();
+	    addidas.setMerchantStore(store);
+
+	    ManufacturerDescription addidasDesc = new ManufacturerDescription();
+	    addidasDesc.setLanguage(en);
+	    addidasDesc.setManufacturer(addidas);
+	    addidasDesc.setName("Addidas");
+	    addidas.getDescriptions().add(addidasDesc);
+
+	    manufacturerService.create(addidas);
+	    
+	    /**
+	     * Create an option
+	     */
+	    ProductOption option = new ProductOption();
+	    option.setMerchantStore(store);
+	    option.setCode("color");
+	    option.setProductOptionType(ProductOptionType.Radio.name());
+	    
+	    ProductOptionDescription optionDescription = new ProductOptionDescription();
+	    optionDescription.setLanguage(en);
+	    optionDescription.setName("Color");
+	    optionDescription.setDescription("Item color");
+	    optionDescription.setProductOption(option);
+	    
+	    option.getDescriptions().add(optionDescription);
+	    
+	    productOptionService.saveOrUpdate(option);
+	    
+	    
+	    /** first option value **/
+	    ProductOptionValue white = new ProductOptionValue();
+	    white.setMerchantStore(store);
+	    white.setCode("white");
+	    
+	    ProductOptionValueDescription whiteDescription = new ProductOptionValueDescription();
+	    whiteDescription.setLanguage(en);
+	    whiteDescription.setName("White");
+	    whiteDescription.setDescription("White color");
+	    whiteDescription.setProductOptionValue(white);
+	    
+	    white.getDescriptions().add(whiteDescription);
+	    
+	    productOptionValueService.saveOrUpdate(white);
+	    
+	    
+	    ProductOptionValue black = new ProductOptionValue();
+	    black.setMerchantStore(store);
+	    black.setCode("black");
+	    
+	    /** second option value **/
+	    ProductOptionValueDescription blackDesc = new ProductOptionValueDescription();
+	    blackDesc.setLanguage(en);
+	    blackDesc.setName("Black");
+	    blackDesc.setDescription("Black color");
+	    blackDesc.setProductOptionValue(black);
+	    
+	    black.getDescriptions().add(blackDesc);
+
+	    productOptionValueService.saveOrUpdate(black);
+	    
+	    
+	    /**
+	     * Create a complex product
+	     */
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(1));
+	    product.setSku("TB12345");
+	    product.setManufacturer(addidas);
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Short sleeves shirt");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    product.getCategories().add(shirts);
+	    
+	    
+	    //availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(new Date());
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+	    
+	    //price
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+	    
+	    
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    availability.getPrices().add(dprice);
+	    product.getAvailabilities().add(availability);
+	    
+	    
+	    //attributes
+	    //white
+	    ProductAttribute whiteAttribute = new ProductAttribute();
+	    whiteAttribute.setProduct(product);
+	    whiteAttribute.setProductOption(option);
+	    whiteAttribute.setAttributeDefault(true);
+	    whiteAttribute.setProductAttributePrice(new BigDecimal(0));//no price variation
+	    whiteAttribute.setProductAttributeWeight(new BigDecimal(0));//no weight variation
+	    whiteAttribute.setProductOption(option);
+	    whiteAttribute.setProductOptionValue(white);
+	    
+	    product.getAttributes().add(whiteAttribute);
+	    //black
+	    ProductAttribute blackAttribute = new ProductAttribute();
+	    blackAttribute.setProduct(product);
+	    blackAttribute.setProductOption(option);
+	    blackAttribute.setProductAttributePrice(new BigDecimal(5));//5 + dollars
+	    blackAttribute.setProductAttributeWeight(new BigDecimal(0));//no weight variation
+	    blackAttribute.setProductOption(option);
+	    blackAttribute.setProductOptionValue(black);
+	    
+	    product.getAttributes().add(blackAttribute);
+
+	    productService.saveOrUpdate(product);
+	    
+	    /** Create Shopping cart **/
+	    
+	    ShoppingCart shoppingCart = new ShoppingCart();
+	    shoppingCart.setMerchantStore(store);
+	    
+	    UUID cartCode = UUID.randomUUID();
+	    shoppingCart.setShoppingCartCode(cartCode.toString());
+
+	    ShoppingCartItem item = new ShoppingCartItem(shoppingCart,product);
+	    item.setShoppingCart(shoppingCart);
+	    FinalPrice price = productPriceUtil.getFinalPrice(product);
+	    
+	    item.setItemPrice(price.getFinalPrice());
+	    item.setQuantity(1);
+	    
+	    /** user selects black **/
+	    ShoppingCartAttributeItem attributeItem = new ShoppingCartAttributeItem(item,blackAttribute);
+	    item.getAttributes().add(attributeItem);
+	    
+	    shoppingCart.getLineItems().add(item);
+	    
+	    
+	    shoppingCartService.create(shoppingCart);
+	    
+	    /** Retrieve cart **/
+	    
+	    ShoppingCart retrievedCart = shoppingCartService.getByCode(cartCode.toString(), store);
+	    
+	    Assert.assertNotNull(retrievedCart);
+	    
+	    
+	    
+	    
+    }
+	
+	@Test
+	public void retrieveAlteredShoppingCart() throws Exception {
+
+        MerchantStore store = merchantService.getByCode( MerchantStore.DEFAULT_STORE );
+        
+		
+	    Language en = languageService.getByCode("en");
+
+
+	    /** CATALOG CREATION **/
+	    
+	    ProductType generalType = productTypeService.getProductType(ProductType.GENERAL_TYPE);
+
+	    /**
+	     * Create the category
+	     */
+	    Category shirts = new Category();
+	    shirts.setMerchantStore(store);
+	    shirts.setCode("shirts");
+
+	    CategoryDescription shirtsEnglishDescription = new CategoryDescription();
+	    shirtsEnglishDescription.setName("Shirts");
+	    shirtsEnglishDescription.setCategory(shirts);
+	    shirtsEnglishDescription.setLanguage(en);
+
+	    List<CategoryDescription> descriptions = new ArrayList<CategoryDescription>();
+	    descriptions.add(shirtsEnglishDescription);
+
+
+	    shirts.setDescriptions(descriptions);
+	    categoryService.create(shirts);
+	    
+	    
+	    /**
+	     * Create a manufacturer
+	     */
+	    Manufacturer addidas = new Manufacturer();
+	    addidas.setMerchantStore(store);
+
+	    ManufacturerDescription addidasDesc = new ManufacturerDescription();
+	    addidasDesc.setLanguage(en);
+	    addidasDesc.setManufacturer(addidas);
+	    addidasDesc.setName("Addidas");
+	    addidas.getDescriptions().add(addidasDesc);
+
+	    manufacturerService.create(addidas);
+	    
+	    /**
+	     * Create an option
+	     */
+	    ProductOption option = new ProductOption();
+	    option.setMerchantStore(store);
+	    option.setCode("color");
+	    option.setProductOptionType(ProductOptionType.Radio.name());
+	    
+	    ProductOptionDescription optionDescription = new ProductOptionDescription();
+	    optionDescription.setLanguage(en);
+	    optionDescription.setName("Color");
+	    optionDescription.setDescription("Item color");
+	    optionDescription.setProductOption(option);
+	    
+	    option.getDescriptions().add(optionDescription);
+	    
+	    productOptionService.saveOrUpdate(option);
+	    
+	    
+	    /** first option value **/
+	    ProductOptionValue white = new ProductOptionValue();
+	    white.setMerchantStore(store);
+	    white.setCode("white");
+	    
+	    ProductOptionValueDescription whiteDescription = new ProductOptionValueDescription();
+	    whiteDescription.setLanguage(en);
+	    whiteDescription.setName("White");
+	    whiteDescription.setDescription("White color");
+	    whiteDescription.setProductOptionValue(white);
+	    
+	    white.getDescriptions().add(whiteDescription);
+	    
+	    productOptionValueService.saveOrUpdate(white);
+	    
+	    
+	    ProductOptionValue black = new ProductOptionValue();
+	    black.setMerchantStore(store);
+	    black.setCode("black");
+	    
+	    /** second option value **/
+	    ProductOptionValueDescription blackDesc = new ProductOptionValueDescription();
+	    blackDesc.setLanguage(en);
+	    blackDesc.setName("Black");
+	    blackDesc.setDescription("Black color");
+	    blackDesc.setProductOptionValue(black);
+	    
+	    black.getDescriptions().add(blackDesc);
+
+	    productOptionValueService.saveOrUpdate(black);
+	    
+	    
+	    /**
+	     * Create a complex product
+	     */
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(1));
+	    product.setSku("TB12345");
+	    product.setManufacturer(addidas);
+	    product.setType(generalType);
+	    product.setMerchantStore(store);
+
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Short sleeves shirt");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    product.getCategories().add(shirts);
+	    
+	    
+	    //availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(new Date());
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+	    
+	    //price
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+	    
+	    
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    availability.getPrices().add(dprice);
+	    product.getAvailabilities().add(availability);
+	    
+	    
+	    //attributes
+	    //white
+	    ProductAttribute whiteAttribute = new ProductAttribute();
+	    whiteAttribute.setProduct(product);
+	    whiteAttribute.setProductOption(option);
+	    whiteAttribute.setAttributeDefault(true);
+	    whiteAttribute.setProductAttributePrice(new BigDecimal(0));//no price variation
+	    whiteAttribute.setProductAttributeWeight(new BigDecimal(0));//no weight variation
+	    whiteAttribute.setProductOption(option);
+	    whiteAttribute.setProductOptionValue(white);
+	    
+	    product.getAttributes().add(whiteAttribute);
+	    //black
+	    ProductAttribute blackAttribute = new ProductAttribute();
+	    blackAttribute.setProduct(product);
+	    blackAttribute.setProductOption(option);
+	    blackAttribute.setProductAttributePrice(new BigDecimal(5));//5 + dollars
+	    blackAttribute.setProductAttributeWeight(new BigDecimal(0));//no weight variation
+	    blackAttribute.setProductOption(option);
+	    blackAttribute.setProductOptionValue(black);
+	    
+	    product.getAttributes().add(blackAttribute);
+
+	    productService.saveOrUpdate(product);
+	    
+	    /** Create Shopping cart **/
+	    
+	    ShoppingCart shoppingCart = new ShoppingCart();
+	    shoppingCart.setMerchantStore(store);
+	    
+	    UUID cartCode = UUID.randomUUID();
+	    shoppingCart.setShoppingCartCode(cartCode.toString());
+
+	    ShoppingCartItem item = new ShoppingCartItem(shoppingCart,product);
+	    item.setShoppingCart(shoppingCart);
+	    FinalPrice price = productPriceUtil.getFinalPrice(product);
+	    
+	    item.setItemPrice(price.getFinalPrice());
+	    item.setQuantity(1);
+	    
+	    /** user selects black **/
+	    ShoppingCartAttributeItem attributeItem = new ShoppingCartAttributeItem(item,blackAttribute);
+	    item.getAttributes().add(attributeItem);
+	    
+	    shoppingCart.getLineItems().add(item);
+	    
+	    
+	    shoppingCartService.create(shoppingCart);
+	    
+	    
+	    /** Modify product definition **/
+	    
+	    Product retrievedProduct = productService.getById(product.getId());
+	    
+	    Set<ProductAttribute> attributes = retrievedProduct.getAttributes();
+	    
+	    Assert.assertNotNull(attributes);
+	    
+	    for(ProductAttribute attr : attributes) {
+	    	productAttributeService.delete(attr);
+	    }
+	    
+	    
+	    
+	    /** Retrieve cart **/
+	    
+	    ShoppingCart retrievedCart = shoppingCartService.getByCode(cartCode.toString(), store);
+	    
+	    Assert.assertNotNull(retrievedCart);
+	    
+  
+
+	}
+	
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/tax/TaxTestCase.java b/sm-core/src/test/java/com/salesmanager/test/tax/TaxTestCase.java
new file mode 100644
index 0000000..b8194cb
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/tax/TaxTestCase.java
@@ -0,0 +1,235 @@
+package com.salesmanager.test.tax;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.catalog.product.model.Product;
+import com.salesmanager.core.business.catalog.product.model.availability.ProductAvailability;
+import com.salesmanager.core.business.catalog.product.model.description.ProductDescription;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPrice;
+import com.salesmanager.core.business.catalog.product.model.price.ProductPriceDescription;
+import com.salesmanager.core.business.common.model.Delivery;
+import com.salesmanager.core.business.customer.model.Customer;
+import com.salesmanager.core.business.customer.model.CustomerGender;
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.merchant.model.MerchantStore;
+import com.salesmanager.core.business.order.model.OrderSummary;
+import com.salesmanager.core.business.reference.country.model.Country;
+import com.salesmanager.core.business.reference.language.model.Language;
+import com.salesmanager.core.business.reference.zone.model.Zone;
+import com.salesmanager.core.business.shipping.model.ShippingConfiguration;
+import com.salesmanager.core.business.shipping.model.ShippingSummary;
+import com.salesmanager.core.business.shipping.service.ShippingService;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCart;
+import com.salesmanager.core.business.shoppingcart.model.ShoppingCartItem;
+import com.salesmanager.core.business.tax.model.TaxBasisCalculation;
+import com.salesmanager.core.business.tax.model.TaxConfiguration;
+import com.salesmanager.core.business.tax.model.TaxItem;
+import com.salesmanager.core.business.tax.model.taxclass.TaxClass;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRate;
+import com.salesmanager.core.business.tax.model.taxrate.TaxRateDescription;
+import com.salesmanager.core.business.tax.service.TaxClassService;
+import com.salesmanager.core.business.tax.service.TaxRateService;
+import com.salesmanager.core.business.tax.service.TaxService;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class TaxTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	private static final Date date = new Date(System.currentTimeMillis());
+	
+	@Autowired
+	private TaxService taxService;
+	
+	@Autowired
+	private TaxRateService taxRateService;
+	
+	@Autowired
+	private ShippingService shippingService;
+	
+	@Autowired
+	private TaxClassService taxClassService;
+	
+	/**
+	 * Test tax calculation
+	 * @throws ServiceException
+	 */
+	@Test
+	public void testCanadianSalesTax() throws ServiceException {
+
+	    Language en = languageService.getByCode("en");
+	    Country country = countryService.getByCode("CA");
+	    Zone zone = zoneService.getByCode("QC");
+	    Zone on = zoneService.getByCode("ON");
+	    TaxClass defaultTaxClass = taxClassService.getByCode(TaxClass.DEFAULT_TAX_CLASS);
+
+	    MerchantStore store = merchantService.getByCode(MerchantStore.DEFAULT_STORE);
+	    
+	    //create tax configuration based on store location in the admin
+	    
+	    TaxConfiguration taxConfiguration = new TaxConfiguration();
+	    taxConfiguration.setTaxBasisCalculation(TaxBasisCalculation.STOREADDRESS);
+	    
+	    taxService.saveTaxConfiguration(taxConfiguration, store);
+	    
+	    //tax on shipping
+	    ShippingConfiguration shippingConfiguration = new ShippingConfiguration();
+	    shippingConfiguration.setTaxOnShipping(true);
+	    shippingService.saveShippingConfiguration(shippingConfiguration, store);
+	    
+	    OrderSummary orderSummary = new OrderSummary();
+	    
+	    ShippingSummary shippingSummary = new ShippingSummary();
+	    shippingSummary.setShipping(new BigDecimal(10));
+	    
+	    orderSummary.setShippingSummary(shippingSummary);
+	    
+	    
+	    
+	    Product product = new Product();
+	    product.setProductHeight(new BigDecimal(4));
+	    product.setProductLength(new BigDecimal(3));
+	    product.setProductWidth(new BigDecimal(5));
+	    product.setProductWeight(new BigDecimal(8));
+	    product.setSku("TB12345");
+	    product.setMerchantStore(store);
+	    product.setTaxClass(defaultTaxClass);
+	    
+	    // Product description
+	    ProductDescription description = new ProductDescription();
+	    description.setName("Product 1");
+	    description.setLanguage(en);
+	    description.setProduct(product);
+
+	    product.getDescriptions().add(description);
+	    //productService.create(product);
+
+	    // Availability
+	    ProductAvailability availability = new ProductAvailability();
+	    availability.setProductDateAvailable(date);
+	    availability.setProductQuantity(100);
+	    availability.setRegion("*");
+	    availability.setProduct(product);// associate with product
+
+	    //productAvailabilityService.create(availability);
+
+	    ProductPrice dprice = new ProductPrice();
+	    dprice.setDefaultPrice(true);
+	    dprice.setProductPriceAmount(new BigDecimal(29.99));
+	    dprice.setProductAvailability(availability);
+
+	    ProductPriceDescription dpd = new ProductPriceDescription();
+	    dpd.setName("Base price");
+	    dpd.setProductPrice(dprice);
+	    dpd.setLanguage(en);
+
+	    dprice.getDescriptions().add(dpd);
+	    
+	    ShoppingCartItem shoppingCartItem = new ShoppingCartItem(new ShoppingCart(),product);
+	    
+	    shoppingCartItem.setItemPrice(new BigDecimal(29.99));
+	    shoppingCartItem.setProduct(product);
+	    
+	    orderSummary.getProducts().add(shoppingCartItem);
+	    
+	    //create tax rates in the admin for QC - CA
+	    TaxRate tps = new TaxRate();
+	    tps.setCode("TPS");
+	    tps.setCountry(country);
+	    tps.setZone(zone);
+	    tps.setMerchantStore(store);
+	    tps.setTaxClass(defaultTaxClass);
+	    tps.setTaxPriority(0);
+	    tps.setTaxRate(new BigDecimal(5));
+	    
+	    TaxRateDescription tpsDescription = new TaxRateDescription();
+	    tpsDescription.setName("TPS");
+	    tpsDescription.setDescription("TPS Sales Tax");
+	    tpsDescription.setLanguage(en);
+	    tpsDescription.setTaxRate(tps);
+	    
+	    tps.getDescriptions().add(tpsDescription);
+	    
+	    taxRateService.create(tps);
+	    
+	    
+	    TaxRate tvq = new TaxRate();
+	    tvq.setCode("TVQ");
+	    tvq.setCountry(country);
+	    tvq.setZone(zone);
+	    tvq.setMerchantStore(store);
+	    tvq.setTaxClass(defaultTaxClass);
+	    tvq.setTaxPriority(1);
+	    tvq.setTaxRate(new BigDecimal(7));
+	    tvq.setPiggyback(true);
+	    tvq.setParent(tps);
+	    
+	    TaxRateDescription tvqDescription = new TaxRateDescription();
+	    tvqDescription.setName("TVQ");
+	    tvqDescription.setDescription("TVQ Sales Tax");
+	    tvqDescription.setLanguage(en);
+	    tvqDescription.setTaxRate(tvq);
+	    
+	    tvq.getDescriptions().add(tvqDescription);
+	    
+	    taxRateService.create(tvq);
+	    
+	    
+	    TaxRate hst = new TaxRate();
+	    hst.setCode("HST");
+	    hst.setCountry(country);
+	    hst.setZone(on);
+	    hst.setMerchantStore(store);
+	    hst.setTaxClass(defaultTaxClass);
+	    hst.setTaxPriority(0);
+	    hst.setTaxRate(new BigDecimal(14));
+
+	    
+	    TaxRateDescription hstDescription = new TaxRateDescription();
+	    hstDescription.setName("HST");
+	    hstDescription.setDescription("Harmonized Sales Tax");
+	    hstDescription.setLanguage(en);
+	    hstDescription.setTaxRate(hst);
+	    
+	    hst.getDescriptions().add(hstDescription);
+	    
+	    taxRateService.create(hst);
+	    
+	    //create a Customer with origin QC - CA
+		Customer customer = new Customer();
+		customer.setMerchantStore(store);
+		customer.setEmailAddress("test@test.com");
+		customer.setGender(CustomerGender.M);
+		customer.setAnonymous(true);
+		customer.setCompany("ifactory");
+		customer.setDateOfBirth(new Date());
+		customer.setNick("My nick");
+		customer.setPassword("123456");
+
+		
+	    Delivery delivery = new Delivery();
+	    delivery.setAddress("Shipping address");
+	    delivery.setCity("Boucherville");
+	    delivery.setCountry(country);
+	    delivery.setZone(on);
+	    delivery.setPostalCode("J4B-8J9");
+	    
+	    List<TaxItem> taxLines = taxService.calculateTax(orderSummary, customer, store, en);
+	    
+	    Assert.assertNotNull(taxLines);
+	    
+	    for(TaxItem taxItem : taxLines) {
+	    	
+	    	System.out.println(taxItem.getLabel() + " " + taxItem.getItemPrice().toPlainString());
+	    	
+	    }
+	    
+	}
+
+
+
+}
\ No newline at end of file
diff --git a/sm-core/src/test/java/com/salesmanager/test/utils/ExportSchema.java b/sm-core/src/test/java/com/salesmanager/test/utils/ExportSchema.java
new file mode 100644
index 0000000..ba1a1ea
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/utils/ExportSchema.java
@@ -0,0 +1,50 @@
+package com.salesmanager.test.utils;
+
+import java.util.Map;
+
+import javax.persistence.spi.PersistenceUnitInfo;
+
+import org.hibernate.ejb.Ejb3Configuration;
+import org.hibernate.tool.hbm2ddl.SchemaExport;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
+
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+
+
+
+public class ExportSchema extends AbstractSalesManagerCoreTestCase {
+
+	@Autowired
+	private LocalContainerEntityManagerFactoryBean entityManagerFactory;
+	
+	/**
+	 * Create a sql script with create tables, indexes and fk
+	 * from annotated POJOs
+	 * You must copy resources/META-INF/sm-persistence.xml to persistence.xml
+	 * before you run this class
+	 * Once generated, remove the persistence.xml copy from META-INF
+	 * @throws Exception
+	 */
+	@Test
+	@Ignore
+	public void createSchema() throws Exception {
+		
+
+	    PersistenceUnitInfo persistenceUnitInfo = entityManagerFactory.getPersistenceUnitInfo();
+	    Map jpaPropertyMap = entityManagerFactory.getJpaPropertyMap();
+
+	    @SuppressWarnings("deprecation")
+		org.hibernate.cfg.Configuration configuration = new Ejb3Configuration().configure( persistenceUnitInfo, jpaPropertyMap ).getHibernateConfiguration();
+
+	    SchemaExport schema = new SchemaExport(configuration);
+	    schema.setOutputFile("c:/schema.sql");
+	    schema.create(true, false);
+
+		
+	}
+
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/utils/ImportIntegrationModule.java b/sm-core/src/test/java/com/salesmanager/test/utils/ImportIntegrationModule.java
new file mode 100644
index 0000000..1e388bc
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/utils/ImportIntegrationModule.java
@@ -0,0 +1,101 @@
+package com.salesmanager.test.utils;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Map;
+
+import org.codehaus.jackson.map.ObjectMapper;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.test.context.ContextConfiguration;
+import org.springframework.test.context.TestExecutionListeners;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.support.DependencyInjectionTestExecutionListener;
+
+import com.salesmanager.core.business.generic.exception.ServiceException;
+import com.salesmanager.core.business.system.model.IntegrationModule;
+import com.salesmanager.core.business.system.service.ModuleConfigurationService;
+import com.salesmanager.core.utils.reference.IntegrationModulesLoader;
+
+
+
+
+@ContextConfiguration( locations = { "classpath:spring/test-spring-context.xml" } )
+@RunWith( SpringJUnit4ClassRunner.class )
+@TestExecutionListeners( { DependencyInjectionTestExecutionListener.class } )
+public class ImportIntegrationModule  {
+
+	@Autowired
+	private IntegrationModulesLoader integrationModulesLoader;
+	
+	
+	@Autowired
+	private ModuleConfigurationService moduleCongigurationService;
+	
+	/**
+	 * Import an integration module 
+	 * @throws Exception
+	 */
+	@Ignore
+	public void importIntegrationModule() throws Exception {
+		
+
+			ObjectMapper mapper = new ObjectMapper();
+			File file = new File("/Users/csamson777/Documents/workspace2/sm-core/src/main/resources/reference/integrationmodules.json");
+			
+			InputStream in = null;
+			
+			
+			try {
+				
+
+				
+				
+	            in = new FileInputStream(file);
+
+	            if(in==null) {
+	            	throw new Exception("File not found");
+	            }
+	            @SuppressWarnings("rawtypes")
+	    		Map[] objects = mapper.readValue(in, Map[].class);
+	            
+	            IntegrationModule module = null;
+	            //get the module to be loaded
+	            for(int i = 0; i < objects.length; i++) {
+	            	@SuppressWarnings("rawtypes")
+					Map o = objects[i];
+	            	//load that specific module
+	            	if(o.get("code").equals("beanstream")) {
+	            		//get module object
+	            		module = integrationModulesLoader.loadModule(o);
+	            		break;
+	            	}
+	            }
+	            
+	            if(module!=null) {
+	            	IntegrationModule m = moduleCongigurationService.getByCode(module.getCode());
+	            	if(m!=null) {
+	            		moduleCongigurationService.delete(m);
+	            	}
+	            	
+	            	moduleCongigurationService.create(module);
+	            }
+
+	  		} catch (Exception e) {
+	  			throw new ServiceException(e);
+	  		} finally {
+	  			if(in !=null) {
+	  				try {
+	  					in.close();
+	  				} catch(Exception ignore) {}
+	  			}
+	  		}
+
+
+		
+	}
+
+}
diff --git a/sm-core/src/test/java/com/salesmanager/test/utils/UtilsTestCase.java b/sm-core/src/test/java/com/salesmanager/test/utils/UtilsTestCase.java
new file mode 100644
index 0000000..627a142
--- /dev/null
+++ b/sm-core/src/test/java/com/salesmanager/test/utils/UtilsTestCase.java
@@ -0,0 +1,90 @@
+package com.salesmanager.test.utils;
+
+
+
+import java.text.NumberFormat;
+import java.util.List;
+import java.util.Locale;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.salesmanager.core.business.common.model.Address;
+import com.salesmanager.core.business.reference.country.service.CountryService;
+import com.salesmanager.core.business.reference.currency.model.Currency;
+import com.salesmanager.core.business.reference.currency.service.CurrencyService;
+import com.salesmanager.core.modules.utils.Encryption;
+import com.salesmanager.core.modules.utils.GeoLocation;
+import com.salesmanager.core.utils.CacheUtils;
+import com.salesmanager.test.core.AbstractSalesManagerCoreTestCase;
+
+public class UtilsTestCase extends AbstractSalesManagerCoreTestCase {
+	
+	
+	@Autowired
+	private CountryService countryService;
+	
+	
+	
+	@Autowired
+	private CurrencyService currencyService;
+	
+	@Autowired
+	private Encryption encryption;
+	
+	@Autowired
+	private CacheUtils cache;
+	
+	@Autowired
+	private GeoLocation geoLoaction;
+	
+
+	
+	@Test
+	public void testCache() throws Exception {
+		
+
+		
+		@SuppressWarnings("rawtypes")
+		List countries = countryService.list();
+		
+
+
+		
+		//CacheUtils cache = CacheUtils.getInstance();
+		cache.putInCache(countries, "COUNTRIES");
+		
+		@SuppressWarnings("rawtypes")
+		List objects = (List) cache.getFromCache("COUNTRIES");
+		
+		Assert.assertNotNull(objects);
+		
+	}
+	
+	@Test
+	public void testCurrency() throws Exception {
+		
+		Currency currency = currencyService.getByCode("BGN");
+		
+		java.util.Currency c = currency.getCurrency();
+		
+		NumberFormat numberFormat = NumberFormat.getCurrencyInstance(Locale.US);
+		numberFormat.setCurrency(c);
+		
+		System.out.println("Done");
+		
+	}
+	
+	@Test
+	public void testGeoLocation() throws Exception {
+		
+		Address address = geoLoaction.getAddress("96.21.132.0");
+		if(address!=null) {
+			System.out.println(address.getCountry());
+		}
+		
+	}
+	
+
+}
diff --git a/sm-core/src/test/resources/database.properties b/sm-core/src/test/resources/database.properties
new file mode 100644
index 0000000..798fdab
--- /dev/null
+++ b/sm-core/src/test/resources/database.properties
@@ -0,0 +1,29 @@
+##
+## db configuration for test
+##
+db.jdbcUrl=jdbc\:h2\:file\:SALESMANAGER-TEST;AUTOCOMMIT=OFF;INIT\=RUNSCRIPT FROM 'src/test/resources/sql/create_schema.sql'
+db.user=test
+db.password=password
+db.driverClass=org.h2.Driver
+#hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
+hibernate.dialect=org.hibernate.dialect.H2Dialect
+
+#db.jdbcUrl=jdbc:mysql://localhost:3306/SALESMANAGER?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8
+#db.user=carlito
+#db.password=ninetrails
+#hibernate.hbm2ddl.auto=create
+#db.driverClass=com.mysql.jdbc.Driver
+#hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
+db.preferredTestQuery=SELECT 1
+db.schema=SALESMANAGER
+hibernate.hbm2ddl.auto=update
+
+
+
+
+##
+## configuration pooling base de donn�es
+##
+db.initialPoolSize=10
+db.minPoolSize=5
+db.maxPoolSize=50
\ No newline at end of file
diff --git a/sm-core/src/test/resources/hbm2dll.properties b/sm-core/src/test/resources/hbm2dll.properties
new file mode 100755
index 0000000..13a3da4
--- /dev/null
+++ b/sm-core/src/test/resources/hbm2dll.properties
@@ -0,0 +1 @@
+hibernate.dialect=org.hibernate.dialect.Oracle10gDialect
\ No newline at end of file
diff --git a/sm-core/src/test/resources/log4j.properties b/sm-core/src/test/resources/log4j.properties
new file mode 100644
index 0000000..38d6d36
--- /dev/null
+++ b/sm-core/src/test/resources/log4j.properties
@@ -0,0 +1,14 @@
+log4j.appender.Stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.Stdout.layout.ConversionPattern=[%d{ISO8601}] %-5p - %-26.26c{1} - %m\n
+
+log4j.rootLogger=WARN,Stdout
+
+# hibernate queries
+log4j.logger.org.hibernate.SQL=DEBUG
+log4j.logger.org.hibernate.type=INFO
+
+# schema initialization
+log4j.logger.org.hibernate.tool.hbm2ddl=DEBUG
+
+log4j.logger.org.springframework.transaction=DEBUG
diff --git a/sm-core/src/test/resources/spring/test-datasource.xml b/sm-core/src/test/resources/spring/test-datasource.xml
new file mode 100644
index 0000000..55dbe6a
--- /dev/null
+++ b/sm-core/src/test/resources/spring/test-datasource.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
+	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
+
+	<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+		<property name="driverClassName" value="${db.driverClass}" />
+		<property name="url" value="${db.jdbcUrl}" />
+		<property name="username" value="${db.user}" />
+		<property name="password" value="${db.password}" />
+	</bean> 
+		
+</beans>
diff --git a/sm-core/src/test/resources/spring/test-spring-context.xml b/sm-core/src/test/resources/spring/test-spring-context.xml
new file mode 100644
index 0000000..a672df3
--- /dev/null
+++ b/sm-core/src/test/resources/spring/test-spring-context.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans xmlns="http://www.springframework.org/schema/beans"
+	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
+	xmlns:context="http://www.springframework.org/schema/context"
+	xmlns:util="http://www.springframework.org/schema/util"
+	xsi:schemaLocation="
+        http://www.springframework.org/schema/beans
+        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+        http://www.springframework.org/schema/context
+        http://www.springframework.org/schema/context/spring-context-3.0.xsd
+        http://www.springframework.org/schema/util
+        http://www.springframework.org/schema/util/spring-util-3.0.xsd
+        ">
+
+  <import resource="classpath:/spring/spring-context.xml" />
+
+
+  <bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
+    <property name="driverClassName" value="${db.driverClass}" />
+    <property name="url" value="${db.jdbcUrl}" />
+    <property name="username" value="${db.user}" />
+    <property name="password" value="${db.password}" />
+  </bean>
+
+
+  <context:component-scan base-package="com.salesmanager.test" />
+
+  <util:properties id="shopizer-properties">
+    			<prop key="MULTIPLE_PRICE_AVAILABILITY">false</prop>
+    			<prop key="INDEX_PRODUCTS">false</prop>
+				<!-- Images -->
+				<prop key="PRODUCT_IMAGE_WIDTH_SIZE">350</prop>
+				<prop key="PRODUCT_IMAGE_HEIGHT_SIZE">375</prop>
+				<prop key="CROP_UPLOADED_IMAGES">false</prop>
+				
+				<!-- upload image validations -->
+				<prop key="PRODUCT_IMAGE_MAX_HEIGHT_SIZE">2000</prop>
+				<prop key="PRODUCT_IMAGE_MAX_WIDTH_SIZE">4000</prop>
+				<prop key="PRODUCT_IMAGE_MAX_SIZE">9000000</prop>
+				<prop key="IMAGE_FORMATS">jpg|png|gif</prop>
+				
+				<prop key="POPULATE_TEST_DATA">true</prop>
+
+  </util:properties>
+
+</beans>