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} - <#if (shownPrice > 0)>+<@ofbizCurrency amount=shownPrice isoCode=price.currencyUsed/> </#if> - <#if (shownPrice < 0)>-<@ofbizCurrency amount=(-1*shownPrice) isoCode=price.currencyUsed/> </#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} + <#if (shownPrice > 0)>+<@ofbizCurrency amount=shownPrice isoCode=price.currencyUsed/> </#if> + <#if (shownPrice < 0)>-<@ofbizCurrency amount=(-1*shownPrice) isoCode=price.currencyUsed/> </#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; + } } |
Free forum by Nabble | Edit this page |