svn commit: r685807 - in /ofbiz/trunk/applications: ecommerce/data/ ecommerce/widget/ manufacturing/src/org/ofbiz/manufacturing/jobshopmgt/ order/src/org/ofbiz/order/shoppingcart/ order/webapp/ordermgr/entry/catalog/ order/widget/ordermgr/ product/enti...

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r685807 - in /ofbiz/trunk/applications: ecommerce/data/ ecommerce/widget/ manufacturing/src/org/ofbiz/manufacturing/jobshopmgt/ order/src/org/ofbiz/order/shoppingcart/ order/webapp/ordermgr/entry/catalog/ order/widget/ordermgr/ product/enti...

bibryam
Author: bibryam
Date: Thu Aug 14 01:30:07 2008
New Revision: 685807

URL: http://svn.apache.org/viewvc?rev=685807&view=rev
Log:
Applied the patch from JIRA Issue # OFBIZ-1912 "Configurable products with Virtual product options".
Added a new entity ConfigOptionProductOption to store selected variant products per configuration.
Moved a code snippet about products with VV_FEATURETREE from ShoppingCartEvents to ProductWorker.
Added a demo product PIZZA to test demonstrate Configurable products with Virtual product options.

Modified:
    ofbiz/trunk/applications/ecommerce/data/DemoConfigurator.xml
    ofbiz/trunk/applications/ecommerce/widget/CatalogScreens.xml
    ofbiz/trunk/applications/manufacturing/src/org/ofbiz/manufacturing/jobshopmgt/ProductionRunServices.java
    ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartEvents.java
    ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/configproductdetail.ftl
    ofbiz/trunk/applications/order/widget/ordermgr/OrderEntryCatalogScreens.xml
    ofbiz/trunk/applications/product/entitydef/entitymodel.xml
    ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWorker.java
    ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWrapper.java
    ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductWorker.java

Modified: ofbiz/trunk/applications/ecommerce/data/DemoConfigurator.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/ecommerce/data/DemoConfigurator.xml?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/ecommerce/data/DemoConfigurator.xml (original)
+++ ofbiz/trunk/applications/ecommerce/data/DemoConfigurator.xml Thu Aug 14 01:30:07 2008
@@ -110,4 +110,104 @@
     <ProductCategoryMember productCategoryId="FOOD-001" productId="ENCHILADAS" fromDate="2007-12-27 12:00:00.0"/>
     <ProductCategoryMember productCategoryId="CATALOG1_SEARCH" productId="ENCHILADAS" fromDate="2007-12-27 12:00:00.0"/>
     
+    <!-- Configurable product with virtual product options example -->
+    <Product productId="PIZZA" productTypeId="AGGREGATED" productName="Gold Pizza" internalName="Pizza" description="Create your own pizza" isVirtual="N" isVariant="N" billOfMaterialLevel="0" createdDate="2004-08-20 12:49:13.418" createdByUserLogin="admin"/>
+    <Product productId="DOUGH" productTypeId="FINISHED_GOOD" productName="Dough" internalName="Dough" description="Dough" isVirtual="N" isVariant="N" billOfMaterialLevel="0" createdDate="2004-08-20 12:50:54.794" createdByUserLogin="admin"/>
+    <Product productId="SAUCE" productTypeId="FINISHED_GOOD" productName="Sauce" internalName="Sauce" description="Sauce" isVirtual="Y" isVariant="N" billOfMaterialLevel="0" createdDate="2004-08-20 12:50:54.794" createdByUserLogin="admin"/>    
+    <Product productId="SAUCE-TM" productTypeId="FINISHED_GOOD" internalName="Tomato Sauce with Mozzarella" productName="Tomato Sauce with Mozzarella" description="Tomato Sauce with Mozzarella" returnable="N" includeInPromotions="N" taxable="N" chargeShipping="N" isVirtual="N" isVariant="Y" createdDate="2003-11-20 13:48:19.105" createdByUserLogin="admin" lastModifiedDate="2003-11-20 13:48:19.105" lastModifiedByUserLogin="admin"/>
+    <Product productId="SAUCE-CM" productTypeId="FINISHED_GOOD" internalName="Chili Sauce with Mozzarella" productName="Chili Sauce with Mozzarella" description="Chili Sauce with Mozzarella" returnable="N" includeInPromotions="N" taxable="N" chargeShipping="N" isVirtual="N" isVariant="Y" createdDate="2003-11-20 13:48:19.105" createdByUserLogin="admin" lastModifiedDate="2003-11-20 13:48:19.105" lastModifiedByUserLogin="admin"/>
+    <Product productId="SAUCE-TP" productTypeId="FINISHED_GOOD" internalName="Tomato Sauce with Parmesan" productName="Tomato Sauce with Parmesan" description="Tomato Sauce" returnable="N" includeInPromotions="N" taxable="N" chargeShipping="N" isVirtual="N" isVariant="Y" createdDate="2003-11-20 13:48:19.105" createdByUserLogin="admin" lastModifiedDate="2003-11-20 13:48:19.105" lastModifiedByUserLogin="admin"/>
+    <Product productId="SAUCE-CP" productTypeId="FINISHED_GOOD" internalName="Chili Sauce" productName="Chili Sauce with Parmesan" description="Chili Sauce with Parmesan" returnable="N" includeInPromotions="N" taxable="N" chargeShipping="N" isVirtual="N" isVariant="Y" createdDate="2003-11-20 13:48:19.105" createdByUserLogin="admin" lastModifiedDate="2003-11-20 13:48:19.105" lastModifiedByUserLogin="admin"/>
+    <Product productId="PEPPERS" productTypeId="FINISHED_GOOD" productName="Peppers" internalName="Pepper" description="Pepper" isVirtual="Y" isVariant="N" billOfMaterialLevel="0" createdDate="2004-08-20 12:50:54.794" createdByUserLogin="admin"/>    
+    <Product productId="PEPPERS-G" productTypeId="FINISHED_GOOD" internalName="Green Peppers" productName="Green Peppers" description="Green Peppers" returnable="N" includeInPromotions="N" taxable="N" chargeShipping="N" isVirtual="N" isVariant="Y" createdDate="2003-11-20 13:48:19.105" createdByUserLogin="admin" lastModifiedDate="2003-11-20 13:48:19.105" lastModifiedByUserLogin="admin"/>
+    <Product productId="PEPPERS-H" productTypeId="FINISHED_GOOD" internalName="Hot Peppers" productName="Hot Peppers" description="Hot Peppers" returnable="N" includeInPromotions="N" taxable="N" chargeShipping="N" isVirtual="N" isVariant="Y" createdDate="2003-11-20 13:48:19.105" createdByUserLogin="admin" lastModifiedDate="2003-11-20 13:48:19.105" lastModifiedByUserLogin="admin"/>
+    <Product productId="PEPPERS-R" productTypeId="FINISHED_GOOD" internalName="Roasted Peppers" productName="Roasted Peppers" description="Roasted Peppers" returnable="N" includeInPromotions="N" taxable="N" chargeShipping="N" isVirtual="N" isVariant="Y" createdDate="2003-11-20 13:48:19.105" createdByUserLogin="admin" lastModifiedDate="2003-11-20 13:48:19.105" lastModifiedByUserLogin="admin"/>
+
+    <ProductAssoc productId="PEPPERS" productIdTo="PEPPERS-G" productAssocTypeId="PRODUCT_VARIANT" fromDate="2001-05-13 12:00:00.0"/>
+    <ProductAssoc productId="PEPPERS" productIdTo="PEPPERS-H" productAssocTypeId="PRODUCT_VARIANT" fromDate="2001-05-13 12:00:00.0"/>
+    <ProductAssoc productId="PEPPERS" productIdTo="PEPPERS-R" productAssocTypeId="PRODUCT_VARIANT" fromDate="2001-05-13 12:00:00.0"/>
+
+    <ProductAssoc productId="SAUCE" productIdTo="SAUCE-TM" productAssocTypeId="PRODUCT_VARIANT" fromDate="2001-05-13 12:00:00.0"/>
+    <ProductAssoc productId="SAUCE" productIdTo="SAUCE-CM" productAssocTypeId="PRODUCT_VARIANT" fromDate="2001-05-13 12:00:00.0"/>
+    <ProductAssoc productId="SAUCE" productIdTo="SAUCE-TP" productAssocTypeId="PRODUCT_VARIANT" fromDate="2001-05-13 12:00:00.0"/>
+    <ProductAssoc productId="SAUCE" productIdTo="SAUCE-CP" productAssocTypeId="PRODUCT_VARIANT" fromDate="2001-05-13 12:00:00.0"/>
+
+    <ProductFeatureCategory productFeatureCategoryId="3000" description="Taste"/>
+    <ProductFeature productFeatureId="3001" productFeatureTypeId="TYPE" productFeatureCategoryId="3000" description="Tomato" defaultSequenceNum="1"/>
+    <ProductFeature productFeatureId="3002" productFeatureTypeId="TYPE" productFeatureCategoryId="3000" description="Chili" defaultSequenceNum="2"/>
+    <ProductFeature productFeatureId="3003" productFeatureTypeId="OTHER_FEATURE" productFeatureCategoryId="3000" description="Mozzarella" defaultSequenceNum="3"/>
+    <ProductFeature productFeatureId="3004" productFeatureTypeId="OTHER_FEATURE" productFeatureCategoryId="3000" description="Parmesan" defaultSequenceNum="4"/>  
+    
+    <ProductFeature productFeatureId="3010" productFeatureTypeId="TYPE" productFeatureCategoryId="3000" description="Green" defaultSequenceNum="1"/>
+    <ProductFeature productFeatureId="3011" productFeatureTypeId="TYPE" productFeatureCategoryId="3000" description="Hot" defaultSequenceNum="2"/>
+    <ProductFeature productFeatureId="3012" productFeatureTypeId="TYPE" productFeatureCategoryId="3000" description="Roasted" defaultSequenceNum="3"/>    
+
+    <ProductFeatureAppl productId="SAUCE" productFeatureId="3001" productFeatureApplTypeId="SELECTABLE_FEATURE" fromDate="2003-11-20 13:50:07.796" sequenceNum="1"/>
+    <ProductFeatureAppl productId="SAUCE" productFeatureId="3002" productFeatureApplTypeId="SELECTABLE_FEATURE" fromDate="2003-11-20 13:50:26.411" sequenceNum="2"/>
+    <ProductFeatureAppl productId="SAUCE" productFeatureId="3003" productFeatureApplTypeId="SELECTABLE_FEATURE" fromDate="2003-11-20 13:50:07.796" sequenceNum="3"/>
+    <ProductFeatureAppl productId="SAUCE" productFeatureId="3004" productFeatureApplTypeId="SELECTABLE_FEATURE" fromDate="2003-11-20 13:50:26.411" sequenceNum="4"/>
+
+    <ProductFeatureAppl productId="PEPPERS" productFeatureId="3010" productFeatureApplTypeId="SELECTABLE_FEATURE" fromDate="2003-11-20 13:50:07.796" sequenceNum="1"/>
+    <ProductFeatureAppl productId="PEPPERS" productFeatureId="3011" productFeatureApplTypeId="SELECTABLE_FEATURE" fromDate="2003-11-20 13:50:26.411" sequenceNum="2"/>
+    <ProductFeatureAppl productId="PEPPERS" productFeatureId="3012" productFeatureApplTypeId="SELECTABLE_FEATURE" fromDate="2003-11-20 13:50:07.796" sequenceNum="3"/>
+
+    <ProductFeatureAppl productId="SAUCE-TM" productFeatureId="3001" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="1"/>
+    <ProductFeatureAppl productId="SAUCE-TM" productFeatureId="3003" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="2"/>    
+    <ProductFeatureAppl productId="SAUCE-CM" productFeatureId="3002" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="1"/>
+    <ProductFeatureAppl productId="SAUCE-CM" productFeatureId="3003" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="2"/>    
+    <ProductFeatureAppl productId="SAUCE-TP" productFeatureId="3001" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="1"/>
+    <ProductFeatureAppl productId="SAUCE-TP" productFeatureId="3004" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="2"/>    
+    <ProductFeatureAppl productId="SAUCE-CP" productFeatureId="3002" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="1"/>
+    <ProductFeatureAppl productId="SAUCE-CP" productFeatureId="3004" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="2"/>    
+
+    <ProductFeatureAppl productId="PEPPERS-G" productFeatureId="3010" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="1"/>
+    <ProductFeatureAppl productId="PEPPERS-H" productFeatureId="3011" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="2"/>    
+    <ProductFeatureAppl productId="PEPPERS-R" productFeatureId="3012" productFeatureApplTypeId="STANDARD_FEATURE" fromDate="2003-11-20 13:51:53.35" sequenceNum="3"/>
+
+    <ProductPrice productId="PIZZA" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2004-08-20 12:55:53.223" price="5" createdDate="2004-08-20 12:55:53.223" createdByUserLogin="admin"/>
+    <ProductPrice productId="DOUGH" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2004-08-20 12:55:53.223" price="3" createdDate="2004-08-20 12:55:53.223" createdByUserLogin="admin"/>
+    <ProductPrice productId="SAUCE" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2004-08-20 12:55:36.479" price="1.5" createdDate="2004-08-20 12:55:36.479" createdByUserLogin="admin"/>
+    <ProductPrice productId="SAUCE" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2004-08-20 12:55:36.479" price="1.5" createdDate="2004-08-20 12:55:36.479" createdByUserLogin="admin"/>
+    <ProductPrice productId="SAUCE-TM" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="1.0" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>
+    <ProductPrice productId="SAUCE-TM" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="1.0" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>
+    <ProductPrice productId="SAUCE-CM" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="2.0" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>    
+    <ProductPrice productId="SAUCE-CM" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="2.0" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>    
+    <ProductPrice productId="SAUCE-TP" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="1.5" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>
+    <ProductPrice productId="SAUCE-TP" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="1.5" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>
+    <ProductPrice productId="SAUCE-CP" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="2.5" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>    
+    <ProductPrice productId="SAUCE-CP" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="2.5" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>    
+    <ProductPrice productId="PEPPERS-G" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="1.0" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>
+    <ProductPrice productId="PEPPERS-G" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="1.0" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>
+    <ProductPrice productId="PEPPERS-H" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="2.0" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>    
+    <ProductPrice productId="PEPPERS-H" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="2.0" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>    
+    <ProductPrice productId="PEPPERS-R" productPricePurposeId="COMPONENT_PRICE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="1.5" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>
+    <ProductPrice productId="PEPPERS-R" productPricePurposeId="PURCHASE" productPriceTypeId="DEFAULT_PRICE" currencyUomId="USD" productStoreGroupId="_NA_" fromDate="2001-05-13 12:00:00.0" price="1.5" createdDate="2001-05-13 12:00:00.0" createdByUserLogin="admin" lastModifiedDate="2001-05-13 12:00:00.0" lastModifiedByUserLogin="admin"/>
+    
+    <ProductConfigItem configItemId="PZ0000" configItemTypeId="SINGLE" configItemName="Dough" description="Select type:"/>
+    <ProductConfigItem configItemId="PZ0001" configItemTypeId="MULTIPLE" configItemName="Toppings" description="Select the Toppings:"/>
+
+    <ProductConfigOption configItemId="PZ0000" configOptionId="PZOP000" configOptionName="PZOPT001" description="Small Pizza" sequenceNum="10"/>
+    <ProductConfigOption configItemId="PZ0000" configOptionId="PZOP001" configOptionName="PZOPT002" description="Large Pizza" sequenceNum="20"/>
+    <ProductConfigOption configItemId="PZ0001" configOptionId="PZOP003" configOptionName="PZOPT002" description="Peppers" sequenceNum="10"/>    
+    <ProductConfigOption configItemId="PZ0001" configOptionId="PZOP002" configOptionName="PZOPT001" description="Sauce" sequenceNum="20"/>
+    
+    <ProductConfigProduct configItemId="PZ0000" configOptionId="PZOP000" productId="DOUGH" quantity="1"/>
+    <ProductConfigProduct configItemId="PZ0000" configOptionId="PZOP001" productId="DOUGH" quantity="2"/>
+    <ProductConfigProduct configItemId="PZ0001" configOptionId="PZOP003" productId="PEPPERS" quantity="1"/>
+    <ProductConfigProduct configItemId="PZ0001" configOptionId="PZOP002" productId="SAUCE" quantity="1"/>
+    
+    <ProductConfig productId="PIZZA" configItemId="PZ0000" sequenceNum="10" fromDate="2004-08-20 12:59:26.209" configTypeId="QUESTION" isMandatory="Y"/>
+    <ProductConfig productId="PIZZA" configItemId="PZ0001" sequenceNum="30" fromDate="2004-08-20 12:59:26.209" configTypeId="QUESTION" isMandatory="N"/>
+    
+    <WorkEffort workEffortId="PZTASK01" workEffortTypeId="ROU_TASK" workEffortPurposeTypeId="ROU_ASSEMBLING" currentStatusId="ROU_ACTIVE" workEffortName="Stock out" description="Components" revisionNumber="1" fixedAssetId="DEMO_FOOD_GROUP" estimatedMilliSeconds="600000" estimatedSetupMillis="0"/>
+    <WorkEffort workEffortId="PZTASK02" workEffortTypeId="ROU_TASK" workEffortPurposeTypeId="ROU_ASSEMBLING" currentStatusId="ROU_ACTIVE" workEffortName="Preparation" description="Preparation" revisionNumber="1" fixedAssetId="DEMO_FOOD_GROUP" estimatedMilliSeconds="900000" estimatedSetupMillis="0"/>
+    <WorkEffort workEffortId="PZROUT01" workEffortTypeId="ROUTING" currentStatusId="ROU_ACTIVE" workEffortName="Pizza preparation" description="Pizza preparation" revisionNumber="1" quantityToProduce="0"/>
+    <WorkEffortGoodStandard workEffortId="PZROUT01" productId="PIZZA" workEffortGoodStdTypeId="ROU_PROD_TEMPLATE" statusId="WEGS_CREATED" fromDate="2004-09-24 15:10:14.227"/>
+    <WorkEffortAssoc workEffortIdFrom="PZROUT01" workEffortIdTo="PZTASK01" workEffortAssocTypeId="ROUTING_COMPONENT" sequenceNum="10" fromDate="2004-09-24 15:09:38.736"/>
+    <WorkEffortAssoc workEffortIdFrom="PZROUT01" workEffortIdTo="PZTASK02" workEffortAssocTypeId="ROUTING_COMPONENT" sequenceNum="20" fromDate="2004-09-24 15:09:47.338"/>
+    
+    <ProductCategoryMember productCategoryId="FOOD-001" productId="PIZZA" fromDate="2004-09-24 15:09:47.338"/>
+    <ProductCategoryMember productCategoryId="CATALOG1_SEARCH" productId="PIZZA" fromDate="2004-09-24 15:09:47.338"/>
+    <ProductCategoryMember productCategoryId="PROMOTIONS" productId="PIZZA" fromDate="2004-09-24 15:09:47.338"/>
+    
 </entity-engine-xml>

Modified: ofbiz/trunk/applications/ecommerce/widget/CatalogScreens.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/ecommerce/widget/CatalogScreens.xml?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/ecommerce/widget/CatalogScreens.xml (original)
+++ ofbiz/trunk/applications/ecommerce/widget/CatalogScreens.xml Thu Aug 14 01:30:07 2008
@@ -283,12 +283,23 @@
             </widgets>
         </section>
     </screen>
+    
+    <screen name="inlineProductDetail">
+        <section>
+            <actions>
+                <script location="component://order/webapp/ordermgr/WEB-INF/actions/entry/catalog/InlineProductDetail.groovy"/>
+            </actions>
+            <widgets>
+                <platform-specific><html><html-template location="component://order/webapp/ordermgr/entry/catalog/inlineProductDetail.ftl"/></html></platform-specific>
+            </widgets>
+        </section>
+    </screen>    
 
     <screen name="configproductdetail">
         <section>
             <actions>
                 <set field="productsummaryScreen" value="component://ecommerce/widget/CatalogScreens.xml#productsummary"/>
-
+                <set field="inlineProductDetailScreen" value="component://ecommerce/widget/CatalogScreens.xml#inlineProductDetail"/>
                 <script location="component://order/webapp/ordermgr/WEB-INF/actions/entry/catalog/ProductDetail.groovy"/>
                 <script location="component://order/webapp/ordermgr/WEB-INF/actions/entry/catalog/PrepareConfigForm.groovy"/>
             </actions>

Modified: ofbiz/trunk/applications/manufacturing/src/org/ofbiz/manufacturing/jobshopmgt/ProductionRunServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/manufacturing/src/org/ofbiz/manufacturing/jobshopmgt/ProductionRunServices.java?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/manufacturing/src/org/ofbiz/manufacturing/jobshopmgt/ProductionRunServices.java (original)
+++ ofbiz/trunk/applications/manufacturing/src/org/ofbiz/manufacturing/jobshopmgt/ProductionRunServices.java Thu Aug 14 01:30:07 2008
@@ -2183,12 +2183,19 @@
                 if (componentQuantity == null) {
                     componentQuantity = new Double(1);
                 }
+                String componentProductId = selComponent.getString("productId");
+                if (co.isVirtualComponent(selComponent)) {      
+                    Map componentOptions = co.getComponentOptions();
+                    if (UtilValidate.isNotEmpty(componentOptions) && UtilValidate.isNotEmpty(componentOptions.get(componentProductId))) {
+                        componentProductId = (String)componentOptions.get(componentProductId);
+                    }
+                }
                 componentQuantity = new Double(quantity.doubleValue() * componentQuantity.doubleValue());
-                if (components.containsKey(selComponent.getString("productId"))) {
-                    Double totalQuantity = (Double)components.get(selComponent.getString("productId"));
+                if (components.containsKey(componentProductId)) {
+                    Double totalQuantity = (Double)components.get(componentProductId);
                     componentQuantity = new Double(totalQuantity.doubleValue() + componentQuantity.doubleValue());
                 }
-                components.put(selComponent.getString("productId"), componentQuantity);
+                components.put(componentProductId, componentQuantity);
             }
         }
         

Modified: ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartEvents.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartEvents.java?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartEvents.java (original)
+++ ofbiz/trunk/applications/order/src/org/ofbiz/order/shoppingcart/ShoppingCartEvents.java Thu Aug 14 01:30:07 2008
@@ -258,171 +258,16 @@
  request.setAttribute("_EVENT_MESSAGE_",UtilProperties.getMessage(resource,"cart.addToCart.chooseVariationBeforeAddingToCart",locale));
  return "product";
      }
-    
- try {
+
+                String variantProductId = ProductWorker.getVariantFromFeatureTree(productId, selectedFeatures, delegator);
+                if (UtilValidate.isNotEmpty(variantProductId)) {
+                    productId = variantProductId;
+                } else {
+                    request.setAttribute("product_id", productId);
+                    request.setAttribute("_EVENT_MESSAGE_",UtilProperties.getMessage(resource,"cart.addToCart.incompatibilityVariantFeature",locale));
+                    return "product";
+                }
 
- Iterator<String> featureIter = selectedFeatures.iterator();
- while (featureIter.hasNext()) {
- String paramValue = featureIter.next();
- // find incompatibilities..
- List<GenericValue> incompatibilityVariants = delegator.findByAndCache("ProductFeatureIactn", UtilMisc.toMap("productId", productId,
- "productFeatureIactnTypeId","FEATURE_IACTN_INCOMP"));
- Iterator<GenericValue> incompIter = incompatibilityVariants.iterator();
- while (incompIter.hasNext()) {
- GenericValue incompatibilityVariant = incompIter.next();
- String featur = incompatibilityVariant.getString("productFeatureId");
- if(paramValue.equals(featur)){
- String featurTo = incompatibilityVariant.getString("productFeatureIdTo");
- Iterator<String> featureToIter = selectedFeatures.iterator();
- while (featureToIter.hasNext()) {
- String paramValueTo = featureToIter.next();
- if(featurTo.equals(paramValueTo)){
- GenericValue featureFrom = (GenericValue) delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", featur));
- GenericValue featureTo = (GenericValue) delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", featurTo));
- String message = UtilProperties.getMessage(resource, "cart.addToCart.incompatibilityVariantFeature", locale) + ":/" + featureFrom.getString("description") + "/ => /" + featureTo.getString("description") +"/";
- request.setAttribute("_ERROR_MESSAGE_", message);
- return "incompatibilityVariantFeature";
- }
- }
-
- }
- }
- // find dependencies..
- List<GenericValue> dependenciesVariants = delegator.findByAndCache("ProductFeatureIactn", UtilMisc.toMap("productId", productId,
- "productFeatureIactnTypeId","FEATURE_IACTN_DEPEND"));
- Iterator<GenericValue> dpIter = dependenciesVariants.iterator();
- while (dpIter.hasNext()) {
- GenericValue dpVariant = dpIter.next();
- String featur = dpVariant.getString("productFeatureId");
- if(paramValue.equals(featur)){
- String featurTo = dpVariant.getString("productFeatureIdTo");
- Iterator<String> featureToIter = selectedFeatures.iterator();
- boolean found = false;
- while (featureToIter.hasNext()) {
- String paramValueTo = featureToIter.next();
- if(featurTo.equals(paramValueTo)){
- found = true;
- break;
- }
- }
- if (!found) {
- GenericValue featureFrom = (GenericValue) delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", featur));
- GenericValue featureTo = (GenericValue) delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", featurTo));
- String message = UtilProperties.getMessage(resource, "cart.addToCart.dependencyVariantFeature", locale) + ":/" + featureFrom.getString("description") + "/ => /" + featureTo.getString("description") +"/";
- request.setAttribute("_ERROR_MESSAGE_", message);
- return "dependencyVariantFeature";
- }
- }
- }
- }
- // find variant
- // Debug.log("=====try to find variant for product: " + productId + " and features: " + selectedFeatures);
- List  <GenericValue> productAssocs = EntityUtil.filterByDate(delegator.findByAnd("ProductAssoc", UtilMisc.toMap("productId", productId, "productAssocTypeId","PRODUCT_VARIANT")));
- Iterator <GenericValue> assocIter = productAssocs.iterator();
- boolean productFound = false;
- nextProd: while(assocIter.hasNext()) {
- GenericValue productAssoc = (GenericValue) assocIter.next();
- Iterator <String> fIter = selectedFeatures.iterator();
- while (fIter.hasNext()) {
- String featureId = (String) fIter.next();
- List <GenericValue> pAppls = delegator.findByAndCache("ProductFeatureAppl", UtilMisc.toMap("productId", productAssoc.getString("productIdTo"), "productFeatureId", featureId, "productFeatureApplTypeId","STANDARD_FEATURE"));
- if (UtilValidate.isEmpty(pAppls)) {
- continue nextProd;
- }
- }
- productFound = true;
- productId = productAssoc.getString("productIdTo");
- break;
- }
-// if (productFound)
-// Debug.log("=====product found:" + productId + " and features: " + selectedFeatures);
-
- /**
- * 1. variant not found so create new variant product and use the virtual product as basis, new one  is a variant type and not a virtual type.
- *    adjust the prices according the selected features
- */
- if (!productFound) {
- // copy product to be variant
- GenericValue product = delegator.findByPrimaryKey("Product", UtilMisc.toMap("productId",  productId));
- product.put("isVariant", "Y");
- product.put("isVirtual", "N");
- product.put("productId", delegator.getNextSeqId("Product"));
- product.remove("virtualVariantMethodEnum"); // not relevant for a non virtual product.
- product.create();
- // add the selected/standard features as 'standard features' to the 'ProductFeatureAppl' table
- GenericValue productFeatureAppl = delegator.makeValue("ProductFeatureAppl",
- UtilMisc.toMap("productId", product.getString("productId"), "productFeatureApplTypeId", "STANDARD_FEATURE"));
- productFeatureAppl.put("fromDate", UtilDateTime.nowTimestamp());                      
- Iterator <String> selectedFeatureIter = selectedFeatures.iterator();
- while (selectedFeatureIter.hasNext()) {
- String productFeatureId = selectedFeatureIter.next();
- productFeatureAppl.put("productFeatureId",  productFeatureId);
- productFeatureAppl.create();
- }
- //add standard features too
- List <GenericValue> stdFeaturesAppls = EntityUtil.filterByDate(delegator.findByAnd("ProductFeatureAppl", UtilMisc.toMap("productId", productId, "productFeatureApplTypeId", "STANDARD_FEATURE")));
- Iterator <GenericValue> stdFeatureIter = stdFeaturesAppls.iterator();
- while (stdFeatureIter.hasNext()) {
- GenericValue stdFeaturesAppl = stdFeatureIter.next();
- stdFeaturesAppl.put("productId",  product.getString("productId"));
- stdFeaturesAppl.create();
- }
- /* 3. use the price of the virtual product(Entity:ProductPrice) as a basis and adjust according the prices in the feature price table.
- *  take the default price from the vitual product, go to the productfeature table and retrieve all the prices for the difFerent features
- *  add these to the price of the virtual product, store the result as the default price on the variant you created.
- */
- List <GenericValue> productPrices = EntityUtil.filterByDate(delegator.findByAnd("ProductPrice", UtilMisc.toMap("productId", productId)));
- Iterator <GenericValue> ppIter = productPrices.iterator();
- while (ppIter.hasNext()) {
- GenericValue productPrice = ppIter.next();
- Iterator <String> sfIter = selectedFeatures.iterator();
- while (sfIter.hasNext()) {
- List <GenericValue> productFeaturePrices = EntityUtil.filterByDate(delegator.findByAnd("ProductFeaturePrice",
- UtilMisc.toMap("productFeatureId", sfIter.next(), "productPriceTypeId", productPrice.getString("productPriceTypeId"))));
- if (UtilValidate.isNotEmpty(productFeaturePrices)) {
- GenericValue productFeaturePrice = productFeaturePrices.get(0);
- if (UtilValidate.isNotEmpty(productFeaturePrice)) {
- productPrice.put("price", productPrice.getDouble("price").doubleValue() + productFeaturePrice.getDouble("price").doubleValue());
- }
- }
- }
- if (productPrice.get("price") == null) {
- productPrice.put("price", productPrice.getDouble("price").doubleValue());
- }
- productPrice.put("productId",  product.getString("productId"));
- productPrice.create();
- }
- // add the product association
- GenericValue productAssoc = delegator.makeValue("ProductAssoc", UtilMisc.toMap("productId", productId, "productIdTo", product.getString("productId"), "productAssocTypeId", "PRODUCT_VARIANT"));
- productAssoc.put("fromDate", UtilDateTime.nowTimestamp());
- productAssoc.create();
- Debug.log("set the productId to: " + product.getString("productId"));
-
- // copy the supplier
- List <GenericValue> supplierProducts = delegator.findByAndCache("SupplierProduct", UtilMisc.toMap("productId", productId));
- Iterator <GenericValue> SPite = supplierProducts.iterator();
- while (SPite.hasNext()) {
- GenericValue supplierProduct = SPite.next();
- supplierProduct.set("productId",  product.getString("productId"));
- supplierProduct.create();
- }
-
- // copy the content
- List <GenericValue> productContents = delegator.findByAndCache("ProductContent", UtilMisc.toMap("productId", productId));
- Iterator <GenericValue> productContentsTte = productContents.iterator();
- while (productContentsTte.hasNext()) {
- GenericValue productContent = productContentsTte.next();
- productContent.set("productId",  product.getString("productId"));  
- productContent.create();
- }
-
- // finally use the new productId to be added to the cart
- productId = product.getString("productId"); // set to the new product
- }
-
- } catch (GenericEntityException e) {
- Debug.logError(e, module);
- }
  } else {
  request.setAttribute("product_id", productId);
  request.setAttribute("_EVENT_MESSAGE_",UtilProperties.getMessage(resource,"cart.addToCart.chooseVariationBeforeAddingToCart",locale));

Modified: ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/configproductdetail.ftl
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/configproductdetail.ftl?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/configproductdetail.ftl (original)
+++ ofbiz/trunk/applications/order/webapp/ordermgr/entry/catalog/configproductdetail.ftl Thu Aug 14 01:30:07 2008
@@ -136,7 +136,7 @@
 <!--
 
 Event.observe(window, 'load', function() {
-  Event.observe($('configFormId'),'click',getConfigDetails);
+  Event.observe($('configFormId'),'change',getConfigDetails);
 });
 
 function getConfigDetails(event) {
@@ -503,20 +503,39 @@
                 <#if !question.isMandatory()>
                   <div><input type="radio" name='${counter}' value='<#if !question.isSelected()>checked</#if>'> No option</div>
                 </#if>
-                <#assign optionCounter = 0>
+                <#assign optionCounter = 0>              
                 <#list options as option>
+                  <#assign componentCounter = 0>                  
                   <#if showOffsetPrice?exists && "Y" == showOffsetPrice>
                     <#assign shownPrice = option.price - selectedPrice>
                   <#else>
                     <#assign shownPrice = option.price>
                   </#if>
-                  <div>
-                    <input type="radio" name='${counter}' value='${optionCounter}' <#if option.isSelected() || (!question.isSelected() && optionCounter == 0 && question.isMandatory())>checked</#if>>
-                    ${option.description}&nbsp;
-                    <#if (shownPrice > 0)>+<@ofbizCurrency amount=shownPrice isoCode=price.currencyUsed/>&nbsp;</#if>
-                    <#if (shownPrice < 0)>-<@ofbizCurrency amount=(-1*shownPrice) isoCode=price.currencyUsed/>&nbsp;</#if>
-                    <#if !option.isAvailable()>(*)</#if>
-                  </div>
+                    <#-- Render virtual compoennts -->
+                    <#if option.hasVirtualComponent()>
+                      <div >
+                        <input type='radio' name='${counter}' id="${counter}_${optionCounter}" value='${optionCounter}' onclick="javascript:checkOptionVariants('${counter}_${optionCounter}');">
+                        ${option.description} <#if !option.isAvailable()> (*)</#if>
+                        <#assign components = option.getComponents()>
+                        <#list components as component>
+                          <#if (option.isVirtualComponent(component))>
+                            ${setRequestAttribute("inlineProductId", component.productId)}
+                            ${setRequestAttribute("inlineCounter", counter+ "_" +optionCounter + "_"+componentCounter)}
+                            ${setRequestAttribute("addJavaScript", componentCounter)}
+                            ${screens.render(inlineProductDetailScreen)}
+                            <#assign componentCounter = componentCounter + 1>
+                          </#if>
+                        </#list>
+                      </div>
+                    <#else>
+                      <div>
+                        <input type="radio" name='${counter}' value='${optionCounter}' <#if option.isSelected() || (!question.isSelected() && optionCounter == 0 && question.isMandatory())>checked</#if>>
+                        ${option.description}&nbsp;
+                        <#if (shownPrice > 0)>+<@ofbizCurrency amount=shownPrice isoCode=price.currencyUsed/>&nbsp;</#if>
+                        <#if (shownPrice < 0)>-<@ofbizCurrency amount=(-1*shownPrice) isoCode=price.currencyUsed/>&nbsp;</#if>
+                        <#if !option.isAvailable()>(*)</#if>
+                      </div>
+                    </#if>
                   <#assign optionCounter = optionCounter + 1>
                 </#list>
                 <#else>
@@ -551,10 +570,29 @@
                 <#assign options = question.options>
                 <#assign optionCounter = 0>
                 <#list options as option>
-                  <div>
-                    <input type='CHECKBOX' name='${counter}' value='${optionCounter}' <#if option.isSelected()>checked</#if>>
-                    ${option.description} +<@ofbizCurrency amount=option.price isoCode=price.currencyUsed/><#if !option.isAvailable()> (*)</#if>
-                  </div>
+                    <#assign componentCounter = 0>                
+                    <#-- Render virtual compoennts -->
+                    <#if option.hasVirtualComponent()>
+                      <div >
+                        <input type='CHECKBOX' name='${counter}' id="${counter}_${optionCounter}" value='${optionCounter}' onclick="javascript:checkOptionVariants('${counter}_${optionCounter}');">
+                        ${option.description} <#if !option.isAvailable()> (*)</#if>
+                        <#assign components = option.getComponents()>
+                        <#list components as component>
+                          <#if (option.isVirtualComponent(component))>
+                            ${setRequestAttribute("inlineProductId", component.productId)}
+                            ${setRequestAttribute("inlineCounter", counter+ "_" +optionCounter + "_"+componentCounter)}
+                            ${setRequestAttribute("addJavaScript", componentCounter)}
+                            ${screens.render(inlineProductDetailScreen)}
+                            <#assign componentCounter = componentCounter + 1>
+                          </#if>
+                        </#list>
+                      </div>
+                    <#else>
+                    <div>
+                      <input type='CHECKBOX' name='${counter}' value='${optionCounter}' <#if option.isSelected()>checked</#if>>
+                      ${option.description} +<@ofbizCurrency amount=option.price isoCode=price.currencyUsed/><#if !option.isAvailable()> (*)</#if>
+                    </div>
+                    </#if>
                   <#assign optionCounter = optionCounter + 1>
                 </#list>
               </#if>

Modified: ofbiz/trunk/applications/order/widget/ordermgr/OrderEntryCatalogScreens.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/order/widget/ordermgr/OrderEntryCatalogScreens.xml?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/order/widget/ordermgr/OrderEntryCatalogScreens.xml (original)
+++ ofbiz/trunk/applications/order/widget/ordermgr/OrderEntryCatalogScreens.xml Thu Aug 14 01:30:07 2008
@@ -177,6 +177,7 @@
         <section>
             <actions>
                 <set field="productsummaryScreen" value="component://order/widget/ordermgr/OrderEntryCatalogScreens.xml#productsummary"/>
+                <set field="inlineProductDetailScreen" value="component://order/widget/ordermgr/OrderEntryCatalogScreens.xml#inlineProductDetail"/>
                 <script location="component://order/webapp/ordermgr/WEB-INF/actions/entry/catalog/ProductDetail.groovy"/>
                 <!--<script location="component://ecommerce/webapp/ecommerce/WEB-INF/actions/catalog/prepareconfigform.bsh"/>-->
                 <script location="component://order/webapp/ordermgr/WEB-INF/actions/entry/catalog/PrepareConfigForm.groovy"/>
@@ -189,6 +190,16 @@
             </widgets>
         </section>
     </screen>
+    <screen name="inlineProductDetail">
+        <section>
+            <actions>
+                <script location="component://order/webapp/ordermgr/WEB-INF/actions/entry/catalog/InlineProductDetail.groovy"/>                
+            </actions>
+            <widgets>
+                <platform-specific><html><html-template location="component://order/webapp/ordermgr/entry/catalog/inlineProductDetail.ftl"/></html></platform-specific>
+            </widgets>
+        </section>
+    </screen>    
     <screen name="keywordsearch">
         <section>
             <actions>

Modified: ofbiz/trunk/applications/product/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/entitydef/entitymodel.xml?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/applications/product/entitydef/entitymodel.xml Thu Aug 14 01:30:07 2008
@@ -731,6 +731,33 @@
             <key-map field-name="productId"/>
         </relation>
     </entity>
+    <entity entity-name="ConfigOptionProductOption"
+            package-name="org.ofbiz.product.config"
+            title="Config Option Product Options Entity">
+        <field name="configId" type="id-ne"></field>
+        <field name="configItemId" type="id-ne"></field>
+        <field name="sequenceNum" type="numeric"></field>
+        <field name="configOptionId" type="id-ne"></field>
+        <field name="productId" type="id-ne"></field>        
+        <field name="productOptionId" type="id-ne"></field>        
+        <field name="description" type="description"></field>
+        <prim-key field="configId"/>
+        <prim-key field="configItemId"/>
+        <prim-key field="configOptionId"/>
+        <prim-key field="sequenceNum"/>
+        <prim-key field="productId"/>        
+        <relation type="one" fk-name="PROD_OPTN_CONF" title="Config" rel-entity-name="ProductConfigConfig">
+            <key-map field-name="configId"/>
+            <key-map field-name="configItemId"/>
+            <key-map field-name="configOptionId"/>
+            <key-map field-name="sequenceNum"/>
+        </relation>
+        <relation type="one" fk-name="PROD_OPTN_PROD" title="Product" rel-entity-name="ProductConfigProduct">
+            <key-map field-name="configItemId"/>
+            <key-map field-name="configOptionId"/>        
+            <key-map field-name="productId"/>
+        </relation>        
+    </entity>
     
   <!-- ========================================================= -->
   <!-- org.ofbiz.product.cost -->

Modified: ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWorker.java?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWorker.java (original)
+++ ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWorker.java Thu Aug 14 01:30:07 2008
@@ -23,9 +23,9 @@
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
-
+import java.util.Map;
+import java.util.Enumeration;
 import javax.servlet.http.HttpServletRequest;
-import javax.servlet.jsp.tagext.TryCatchFinally;
 
 import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilHttp;
@@ -34,14 +34,12 @@
 import org.ofbiz.entity.GenericDelegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
-import org.ofbiz.entity.condition.EntityExpr;
-import org.ofbiz.entity.condition.EntityOperator;
 import org.ofbiz.product.catalog.CatalogWorker;
 import org.ofbiz.product.config.ProductConfigWrapper.ConfigItem;
 import org.ofbiz.product.config.ProductConfigWrapper.ConfigOption;
+import org.ofbiz.product.product.ProductWorker;
 import org.ofbiz.product.store.ProductStoreWorker;
 import org.ofbiz.service.LocalDispatcher;
-import org.ofbiz.service.ServiceUtil;
 import org.ofbiz.base.util.cache.UtilCache;
 
 /**
@@ -95,7 +93,53 @@
                 int cnt = -1;
                 try {
                     cnt = Integer.parseInt(opts[h]);
-                    configWrapper.setSelected(k, cnt);
+                    ProductConfigWrapper.ConfigOption option = configWrapper.getItemOtion(k, cnt);
+                    if (UtilValidate.isNotEmpty(option) && (option.hasVirtualComponent())) {
+                        List components = option.getComponents();
+                        int variantIndex = 0;
+                        for (int i = 0; i < components.size(); i++) {      
+                            GenericValue component = (GenericValue)components.get(i);
+                            if (option.isVirtualComponent(component)) {
+                                String productParamName = "add_product_id" + k + "_" + cnt + "_" + variantIndex;
+                                String selectedProdcutId = request.getParameter(productParamName);
+                                if (UtilValidate.isEmpty(selectedProdcutId)) {
+                                    Debug.logWarning("ERROR: Request param [" + productParamName + "] not found!", module);
+                                } else {
+                                    //  handle both types of virtual variant methods
+                                    if (ProductWorker.isVirtual((GenericDelegator)request.getAttribute("delegator"), selectedProdcutId)) {
+                                        if ("VV_FEATURETREE".equals(ProductWorker.getProductvirtualVariantMethod((GenericDelegator)request.getAttribute("delegator"), selectedProdcutId))) {
+                                            // get the selected features
+                                            List <String> selectedFeatures = new LinkedList<String>();
+                                            Enumeration paramNames = request.getParameterNames();
+                                            while(paramNames.hasMoreElements()) {
+                                                String paramName = (String)paramNames.nextElement();
+                                                if (paramName.startsWith("FT" + k + "_" + cnt + "_" + variantIndex)) {
+                                                    selectedFeatures.add(request.getParameterValues(paramName)[0]);
+                                                }
+                                            }
+                                            
+                                            // check if features are selected
+                                            if (UtilValidate.isEmpty(selectedFeatures)) {
+                                                Debug.logWarning("ERROR: No features selected for productId [" + selectedProdcutId+ "]", module);
+                                            }
+                            
+                                            String variantProductId = ProductWorker.getVariantFromFeatureTree(selectedProdcutId, selectedFeatures, (GenericDelegator)request.getAttribute("delegator"));
+                                            if (UtilValidate.isNotEmpty(variantProductId)) {
+                                                selectedProdcutId = variantProductId;
+                                            } else {
+                                                Debug.logWarning("ERROR: Variant product not found!", module);
+                                           }
+                                        }
+                                    }
+                                    configWrapper.setSelected(k, cnt, i, selectedProdcutId);
+                                }
+                                variantIndex ++;
+                            }
+                        }
+                    } else {
+                        configWrapper.setSelected(k, cnt);
+                    }
+
                 } catch(Exception e) {
                     Debug.logWarning(e.getMessage(), module);
                 }
@@ -166,10 +210,70 @@
                 String tempConfigId = productConfigConfig.getString("configId");
                 try {
                     List tempResult = delegator.findByAnd("ProductConfigConfig", UtilMisc.toMap("configId",tempConfigId));
-                    if (tempResult.size() == selectedOptionSize && configsToCheck.containsAll(tempResult)) {
+                    if (tempResult.size() == selectedOptionSize && configsToCheck.containsAll(tempResult)) {                        
+                        List<GenericValue> configOptionProductOptions = delegator.findByAnd("ConfigOptionProductOption", UtilMisc.toMap("configId",tempConfigId));
+                        if (UtilValidate.isNotEmpty(configOptionProductOptions)) {
+                            
+                            //  check for variant product equality
+                            for (int i = 0; i < questions.size(); i++) {
+                                String configItemId = null;
+                                Long sequenceNum = null;
+                                List <ProductConfigWrapper.ConfigOption> selectedOptions = new ArrayList <ProductConfigWrapper.ConfigOption>();        
+                                ConfigItem ci = (ConfigItem)questions.get(i);
+                                List options = ci.getOptions();
+                                if (ci.isStandard()) {
+                                    selectedOptions.addAll(options);
+                                } else {
+                                    Iterator availOptions = options.iterator();
+                                    while (availOptions.hasNext()) {
+                                        ConfigOption oneOption = (ConfigOption)availOptions.next();
+                                        if (oneOption.isSelected()) {
+                                            selectedOptions.add(oneOption);
+                                        }
+                                    }
+                                }        
+                                
+                                boolean match = true;
+                                for (ProductConfigWrapper.ConfigOption anOption : selectedOptions) {
+                                    if (match && anOption.hasVirtualComponent()) {                                        
+                                        List<GenericValue> components = anOption.getComponents();
+                                        for (GenericValue aComponent : components) {
+                                            if (anOption.isVirtualComponent(aComponent)) {
+                                                Map componentOptions = anOption.getComponentOptions();
+                                                String optionProductId = aComponent.getString("productId");
+                                                String optionProductOptionId = (String)componentOptions.get(optionProductId);
+                                                String configOptionId = anOption.configOption.getString("configOptionId");
+                                                configItemId = ci.getConfigItemAssoc().getString("configItemId");
+                                                sequenceNum = ci.getConfigItemAssoc().getLong("sequenceNum");
+                                                
+                                                GenericValue configOptionProductOption = delegator.makeValue("ConfigOptionProductOption");                            
+                                                configOptionProductOption.set("configId", tempConfigId);                                
+                                                configOptionProductOption.set("configItemId",configItemId);
+                                                configOptionProductOption.set("sequenceNum", sequenceNum);
+                                                configOptionProductOption.set("configOptionId", configOptionId);
+                                                configOptionProductOption.set("productId", optionProductId);
+                                                configOptionProductOption.set("productOptionId", optionProductOptionId);
+                                                if (!configOptionProductOptions.remove(configOptionProductOption)) {
+                                                    match = false;
+                                                    break;
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                                
+                                if (match && (UtilValidate.isEmpty(configOptionProductOptions))) {
+                                    configWrapper.configId = tempConfigId;
+                                    Debug.logInfo("Existing configuration found with configId:"+ tempConfigId,  module);
+                                    return;
+                                }
+                            }                          
+                            
+                        } else {
                             configWrapper.configId = tempConfigId;
                             Debug.logInfo("Existing configuration found with configId:"+ tempConfigId,  module);
                             return;
+                        }
                     }
                 } catch (GenericEntityException e) {
                     Debug.logError(e, module);
@@ -208,6 +312,7 @@
                 sequenceNum = ci.getConfigItemAssoc().getLong("sequenceNum");
                 Iterator selOpIt = selectedOptions.iterator();
                 while (selOpIt.hasNext()) {
+                    List toBeStored = new LinkedList();
                     ConfigOption oneOption = (ConfigOption)selOpIt.next();
                     String configOptionId = oneOption.configOption.getString("configOptionId");
                     GenericValue productConfigConfig = delegator.makeValue("ProductConfigConfig");
@@ -215,8 +320,27 @@
                     productConfigConfig.put("configItemId", configItemId);
                     productConfigConfig.put("sequenceNum", sequenceNum);
                     productConfigConfig.put("configOptionId", configOptionId);
-                    try {
-                        productConfigConfig.create();
+                    toBeStored.add(productConfigConfig);
+
+                    if (oneOption.hasVirtualComponent()) {                        
+                        List components = oneOption.getComponents();
+                        for (int j = 0; j < components.size(); j++) {      
+                            GenericValue component = (GenericValue)components.get(j);
+                            if (oneOption.isVirtualComponent(component)) {
+                                String componentOption = (String)oneOption.componentOptions.get(component.getString("productId"));                                
+                                GenericValue configOptionProductOption = delegator.makeValue("ConfigOptionProductOption");
+                                configOptionProductOption.put("configId", configId);
+                                configOptionProductOption.put("configItemId", configItemId);
+                                configOptionProductOption.put("sequenceNum", sequenceNum);
+                                configOptionProductOption.put("configOptionId", configOptionId);
+                                configOptionProductOption.put("productId", component.getString("productId"));
+                                configOptionProductOption.put("productOptionId", componentOption);
+                                toBeStored.add(configOptionProductOption);
+                            }
+                        }                      
+                    }
+                    try {                        
+                        delegator.storeAll(toBeStored);
                     } catch (GenericEntityException e) {
                         configId = null;
                         Debug.logWarning(e.getMessage(), module);

Modified: ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWrapper.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWrapper.java?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWrapper.java (original)
+++ ofbiz/trunk/applications/product/src/org/ofbiz/product/config/ProductConfigWrapper.java Thu Aug 14 01:30:07 2008
@@ -27,10 +27,13 @@
 import java.util.Map;
 import java.util.HashMap;
 import java.util.Locale;
+import javolution.util.FastMap;
 
+import org.ofbiz.base.util.Debug;
 import org.ofbiz.base.util.UtilMisc;
 import org.ofbiz.base.util.UtilValidate;
 import org.ofbiz.entity.GenericDelegator;
+import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
 import org.ofbiz.entity.util.EntityUtil;
 import org.ofbiz.service.LocalDispatcher;
@@ -45,7 +48,13 @@
     public static final String module = ProductConfigWrapper.class.getName();
 
     protected LocalDispatcher dispatcher;
+    protected String productStoreId;
+    protected String catalogId;
+    protected String webSiteId;
+    protected String currencyUomId;
+    protected GenericDelegator delegator;
     protected GenericValue product = null; // the aggregated product
+    protected GenericValue autoUserLogin = null;
     protected double basePrice = 0.0;
     protected double defaultPrice = 0.0;
     protected String configId = null; // Id of persisted ProductConfigWrapper
@@ -64,6 +73,13 @@
         basePrice = pcw.basePrice;
         defaultPrice = pcw.defaultPrice;
         questions = new ArrayList();
+        dispatcher = pcw.dispatcher;
+        productStoreId = pcw.productStoreId;
+        catalogId = pcw.catalogId;
+        webSiteId = pcw.webSiteId;
+        currencyUomId = pcw.currencyUomId;
+        delegator = pcw.delegator;
+        autoUserLogin = pcw.autoUserLogin;
         for (int i = 0; i < pcw.questions.size(); i++) {
             questions.add(new ConfigItem((ConfigItem)pcw.questions.get(i)));
         }
@@ -75,6 +91,12 @@
             throw new ProductConfigWrapperException("Product " + productId + " is not an AGGREGATED product.");
         }
         this.dispatcher = dispatcher;
+        this.productStoreId = productStoreId;
+        this.catalogId = catalogId;
+        this.webSiteId = webSiteId;
+        this.currencyUomId = currencyUomId;
+        this.delegator = delegator;
+        this.autoUserLogin = autoUserLogin;
         
         // get the base price
         Map priceContext = UtilMisc.toMap("product", product, "prodCatalogId", catalogId, "webSiteId", webSiteId, "productStoreId", productStoreId,
@@ -229,6 +251,24 @@
         }
     }
     
+    public void setSelected(int question, int option, int component, String componentOption) throws Exception {
+        setSelected(question, option);
+        //  set variant products
+        ConfigOption theOption = getItemOtion(question, option);
+        List components = theOption.getComponents();
+        GenericValue oneComponent = (GenericValue)components.get(component);
+        if (theOption.isVirtualComponent(oneComponent)) {
+            if (theOption.componentOptions == null) {
+                theOption.componentOptions = FastMap.newInstance();
+            }
+            theOption.componentOptions.put(oneComponent.getString("productId"), componentOption);
+            
+            //  recalculate option price
+            theOption.recalculateOptionPrice(this);
+            
+        }
+    }    
+    
     public List getSelectedOptions() {
         List selectedOptions = new ArrayList();
         for (int i = 0; i < questions.size(); i++) {
@@ -307,6 +347,19 @@
         return completed;
     }
     
+    public ConfigOption getItemOtion(int itemIndex, int optionIndex) {
+        if (questions.size() > itemIndex) {
+            ConfigItem ci = (ConfigItem)questions.get(itemIndex);
+            List options = ci.getOptions();
+            if (options.size() > optionIndex) {
+                ConfigOption co = (ConfigOption)options.get(optionIndex);
+                return co;
+            }            
+        }
+        
+        return null;
+    }
+    
     public class ConfigItem implements java.io.Serializable {
         GenericValue configItem = null;
         GenericValue configItemAssoc = null;
@@ -469,6 +522,7 @@
         double optionPrice = 0;
         Date availabilityDate = null;
         List componentList = null; // lists of ProductConfigProduct
+        Map componentOptions = null;
         GenericValue configOption = null;
         boolean selected = false;
         boolean available = true;
@@ -519,6 +573,45 @@
             available = co.available;
             selected = co.selected;
         }
+        
+        public void recalculateOptionPrice(ProductConfigWrapper pcw) throws Exception {
+            optionPrice = 0;
+            Iterator componentsIt = componentList.iterator();
+            while (componentsIt.hasNext()) {
+                double price = 0;
+                GenericValue oneComponent = (GenericValue)componentsIt.next();
+                GenericValue oneComponentProduct = oneComponent.getRelatedOne("ProductProduct");        
+                String variantProductId = (String)componentOptions.get(oneComponent.getString("productId"));        
+                
+                if (UtilValidate.isNotEmpty(variantProductId)) {
+                    oneComponentProduct = pcw.delegator.findByPrimaryKey("Product", UtilMisc.toMap("productId", variantProductId));                
+                }
+
+                // Get the component's price
+                Map fieldMap = UtilMisc.toMap("product", oneComponentProduct, "prodCatalogId", pcw.catalogId, "webSiteId", pcw.webSiteId,
+                        "currencyUomId", pcw.currencyUomId, "productPricePurposeId", "COMPONENT_PRICE", "autoUserLogin", pcw.autoUserLogin);
+                Map priceMap = dispatcher.runSync("calculateProductPrice", fieldMap);
+                Double componentPrice = (Double) priceMap.get("price");
+                double mult = 1;
+                if (oneComponent.getDouble("quantity") != null) {
+                    mult = oneComponent.getDouble("quantity").doubleValue();
+                }
+                if (mult == 0) {
+                    mult = 1;
+                }
+                if (componentPrice != null) {
+                    price = componentPrice.doubleValue();
+                } else {
+                    fieldMap.put("productPricePurposeId", "PURCHASE");
+                    Map purchasePriceResultMap = dispatcher.runSync("calculateProductPrice", fieldMap);
+                    Double purchasePrice = (Double) purchasePriceResultMap.get("price");
+                    if (purchasePrice != null) {
+                        price = purchasePrice.doubleValue();
+                    }
+                }
+                optionPrice += (price * mult);
+            }
+        }                
 
         public String getDescription() {
             return (configOption.getString("description") != null? configOption.getString("description"): "no description");
@@ -548,6 +641,32 @@
             }
             return false;
         }
+                
+        public boolean hasVirtualComponent () {
+           List <GenericValue> components = getComponents();
+           if (UtilValidate.isNotEmpty(components)) {
+               for (GenericValue component : components) {
+                   if (isVirtualComponent(component)) {
+                       return true;      
+                   }
+               }            
+           }
+
+           return false;
+       }
+        
+        public boolean isVirtualComponent (GenericValue component) {
+            int index = getComponents().indexOf(component);
+            if (index != -1) {
+                try {
+                    GenericValue product = component.getRelatedOne("ProductProduct");
+                    return "Y".equals(product.getString("isVirtual"));  
+                } catch (GenericEntityException e) {
+                    Debug.logWarning(e.getMessage(), module);
+                }            
+            }
+            return false;
+        }
         
         public boolean isSelected() {
             return selected;
@@ -567,6 +686,10 @@
 
         public List getComponents() {
             return componentList;
+        }        
+
+        public Map getComponentOptions() {
+            return componentOptions;
         }
         
         public boolean equals(Object obj) {

Modified: ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductWorker.java?rev=685807&r1=685806&r2=685807&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductWorker.java (original)
+++ ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductWorker.java Thu Aug 14 01:30:07 2008
@@ -987,4 +987,179 @@
         
         return productIdSet;
     }
+    
+    public static String getVariantFromFeatureTree(String productId, List selectedFeatures, GenericDelegator delegator) {
+        
+        //  all method code moved here from ShoppingCartEvents.addToCart event
+        String variantProductId = null;
+        try {
+
+            Iterator<String> featureIter = selectedFeatures.iterator();                
+            while (featureIter.hasNext()) {
+                String paramValue = featureIter.next();
+                // find incompatibilities..
+                List<GenericValue> incompatibilityVariants = delegator.findByAndCache("ProductFeatureIactn", UtilMisc.toMap("productId", productId,
+                        "productFeatureIactnTypeId","FEATURE_IACTN_INCOMP"));
+                Iterator<GenericValue> incompIter = incompatibilityVariants.iterator();
+                while (incompIter.hasNext()) {
+                    GenericValue incompatibilityVariant = incompIter.next();
+                    String featur = incompatibilityVariant.getString("productFeatureId");
+                    if(paramValue.equals(featur)){
+                        String featurTo = incompatibilityVariant.getString("productFeatureIdTo");
+                        Iterator<String> featureToIter = selectedFeatures.iterator();  
+                        while (featureToIter.hasNext()) {                              
+                            String paramValueTo = featureToIter.next();
+                            if(featurTo.equals(paramValueTo)){
+                                GenericValue featureFrom = (GenericValue) delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", featur));
+                                GenericValue featureTo = (GenericValue) delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", featurTo));
+                                //String message = UtilProperties.getMessage(resource, "cart.addToCart.incompatibilityVariantFeature", locale) + ":/" + featureFrom.getString("description") + "/ => /" + featureTo.getString("description") +"/";
+                                //request.setAttribute("_ERROR_MESSAGE_", message);
+                                //return "incompatibilityVariantFeature";
+                                Debug.logWarning("Incompatible features", module);
+                                return null;
+                            }
+                        }
+
+                    }
+                }
+                // find dependencies..
+                List<GenericValue> dependenciesVariants = delegator.findByAndCache("ProductFeatureIactn", UtilMisc.toMap("productId", productId,
+                        "productFeatureIactnTypeId","FEATURE_IACTN_DEPEND"));
+                Iterator<GenericValue> dpIter = dependenciesVariants.iterator();    
+                while (dpIter.hasNext()) {
+                    GenericValue dpVariant = dpIter.next();
+                    String featur = dpVariant.getString("productFeatureId");
+                    if(paramValue.equals(featur)){
+                        String featurTo = dpVariant.getString("productFeatureIdTo");
+                        Iterator<String> featureToIter = selectedFeatures.iterator();
+                        boolean found = false;
+                        while (featureToIter.hasNext()) {                              
+                            String paramValueTo = featureToIter.next();
+                            if(featurTo.equals(paramValueTo)){
+                                found = true;
+                                break;
+                            }
+                        }
+                        if (!found) {
+                            GenericValue featureFrom = (GenericValue) delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", featur));
+                            GenericValue featureTo = (GenericValue) delegator.findByPrimaryKey("ProductFeature", UtilMisc.toMap("productFeatureId", featurTo));
+                            //String message = UtilProperties.getMessage(resource, "cart.addToCart.dependencyVariantFeature", locale) + ":/" + featureFrom.getString("description") + "/ => /" + featureTo.getString("description") +"/";
+                            //request.setAttribute("_ERROR_MESSAGE_", message);
+                            Debug.logWarning("Dependancy features", module);
+                            return null;
+                        }
+                    }
+                }
+            }
+            // find variant
+            // Debug.log("=====try to find variant for product: " + productId + " and features: " + selectedFeatures);
+            List  <GenericValue> productAssocs = EntityUtil.filterByDate(delegator.findByAnd("ProductAssoc", UtilMisc.toMap("productId", productId, "productAssocTypeId","PRODUCT_VARIANT")));
+            Iterator <GenericValue> assocIter = productAssocs.iterator();
+            boolean productFound = false;
+nextProd:       while(assocIter.hasNext()) {
+                GenericValue productAssoc = (GenericValue) assocIter.next();
+                Iterator <String> fIter = selectedFeatures.iterator();
+                while (fIter.hasNext()) {
+                    String featureId = (String) fIter.next();
+                    List <GenericValue> pAppls = delegator.findByAndCache("ProductFeatureAppl", UtilMisc.toMap("productId", productAssoc.getString("productIdTo"), "productFeatureId", featureId, "productFeatureApplTypeId","STANDARD_FEATURE"));
+                    if (UtilValidate.isEmpty(pAppls)) {
+                        continue nextProd;
+                    }
+                }
+                productFound = true;
+                variantProductId = productAssoc.getString("productIdTo");
+                break;
+            }
+//          if (productFound)
+//              Debug.log("=====product found:" + productId + " and features: " + selectedFeatures);
+
+            /**
+             * 1. variant not found so create new variant product and use the virtual product as basis, new one  is a variant type and not a virtual type.
+             *    adjust the prices according the selected features
+             */                    
+            if (!productFound) {
+                // copy product to be variant
+                GenericValue product = delegator.findByPrimaryKey("Product", UtilMisc.toMap("productId",  productId));
+                product.put("isVariant", "Y");
+                product.put("isVirtual", "N");
+                product.put("productId", delegator.getNextSeqId("Product"));
+                product.remove("virtualVariantMethodEnum"); // not relevant for a non virtual product.
+                product.create();
+                // add the selected/standard features as 'standard features' to the 'ProductFeatureAppl' table
+                GenericValue productFeatureAppl = delegator.makeValue("ProductFeatureAppl",
+                        UtilMisc.toMap("productId", product.getString("productId"), "productFeatureApplTypeId", "STANDARD_FEATURE"));
+                productFeatureAppl.put("fromDate", UtilDateTime.nowTimestamp());                          
+                Iterator <String> selectedFeatureIter = selectedFeatures.iterator();                
+                while (selectedFeatureIter.hasNext()) {
+                    String productFeatureId = selectedFeatureIter.next();
+                    productFeatureAppl.put("productFeatureId",  productFeatureId);
+                    productFeatureAppl.create();
+                }
+                //add standard features too
+                List <GenericValue> stdFeaturesAppls = EntityUtil.filterByDate(delegator.findByAnd("ProductFeatureAppl", UtilMisc.toMap("productId", productId, "productFeatureApplTypeId", "STANDARD_FEATURE")));
+                Iterator <GenericValue> stdFeatureIter = stdFeaturesAppls.iterator();              
+                while (stdFeatureIter.hasNext()) {
+                    GenericValue stdFeaturesAppl = stdFeatureIter.next();
+                    stdFeaturesAppl.put("productId",  product.getString("productId"));
+                    stdFeaturesAppl.create();
+                }
+                /* 3. use the price of the virtual product(Entity:ProductPrice) as a basis and adjust according the prices in the feature price table.
+                 *  take the default price from the vitual product, go to the productfeature table and retrieve all the prices for the difFerent features
+                 *  add these to the price of the virtual product, store the result as the default price on the variant you created.
+                 */
+                List <GenericValue> productPrices = EntityUtil.filterByDate(delegator.findByAnd("ProductPrice", UtilMisc.toMap("productId", productId)));
+                Iterator <GenericValue> ppIter = productPrices.iterator();
+                while (ppIter.hasNext()) {
+                    GenericValue productPrice = ppIter.next();
+                    Iterator <String> sfIter = selectedFeatures.iterator();            
+                    while (sfIter.hasNext()) {
+                        List <GenericValue> productFeaturePrices = EntityUtil.filterByDate(delegator.findByAnd("ProductFeaturePrice",
+                                UtilMisc.toMap("productFeatureId", sfIter.next(), "productPriceTypeId", productPrice.getString("productPriceTypeId"))));
+                        if (UtilValidate.isNotEmpty(productFeaturePrices)) {
+                            GenericValue productFeaturePrice = productFeaturePrices.get(0);
+                            if (UtilValidate.isNotEmpty(productFeaturePrice)) {
+                                productPrice.put("price", productPrice.getDouble("price").doubleValue() + productFeaturePrice.getDouble("price").doubleValue());
+                            }
+                        }
+                    }
+                    if (productPrice.get("price") == null) {
+                        productPrice.put("price", productPrice.getDouble("price").doubleValue());
+                    }
+                    productPrice.put("productId",  product.getString("productId"));
+                    productPrice.create();
+                }
+                // add the product association
+                GenericValue productAssoc = delegator.makeValue("ProductAssoc", UtilMisc.toMap("productId", productId, "productIdTo", product.getString("productId"), "productAssocTypeId", "PRODUCT_VARIANT"));
+                productAssoc.put("fromDate", UtilDateTime.nowTimestamp());
+                productAssoc.create();
+                Debug.log("set the productId to: " + product.getString("productId"));
+                
+                // copy the supplier
+                List <GenericValue> supplierProducts = delegator.findByAndCache("SupplierProduct", UtilMisc.toMap("productId", productId));
+                Iterator <GenericValue> SPite = supplierProducts.iterator();
+                while (SPite.hasNext()) {
+                    GenericValue supplierProduct = SPite.next();
+                    supplierProduct.set("productId",  product.getString("productId"));  
+                    supplierProduct.create();
+                }
+                
+                // copy the content
+                List <GenericValue> productContents = delegator.findByAndCache("ProductContent", UtilMisc.toMap("productId", productId));
+                Iterator <GenericValue> productContentsTte = productContents.iterator();
+                while (productContentsTte.hasNext()) {
+                    GenericValue productContent = productContentsTte.next();
+                    productContent.set("productId",  product.getString("productId"));      
+                    productContent.create();
+                }                                          
+                
+                // finally use the new productId to be added to the cart
+                variantProductId = product.getString("productId"); // set to the new product
+            }
+
+        } catch (GenericEntityException e) {
+            Debug.logError(e, module);
+        }
+        
+        return variantProductId;
+    }    
 }