svn commit: r922506 - in /ofbiz/trunk/applications/product: config/ entitydef/ script/org/ofbiz/product/product/ servicedef/ src/org/ofbiz/product/product/ webapp/catalog/WEB-INF/ widget/catalog/

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

svn commit: r922506 - in /ofbiz/trunk/applications/product: config/ entitydef/ script/org/ofbiz/product/product/ servicedef/ src/org/ofbiz/product/product/ webapp/catalog/WEB-INF/ widget/catalog/

ashish-18
Author: ashish
Date: Sat Mar 13 08:46:57 2010
New Revision: 922506

URL: http://svn.apache.org/viewvc?rev=922506&view=rev
Log:
Applied patch from OFBIZ-3533 - Associate Image functionality with ProductPromo using content driven.
Associate Image functionality with ProductPromo using content driven.

Following work will be covered: -

   1. Add new entity "ProductPromoContent" entity having composite primary key:
         1. productPromoId
         2. contentId
         3. productPromoContentTypeId
         4. fromDate
   2. CRUD services for ProductPromoContent Entity.
   3. Create wrapper ProductPromoContentWrapper
   4. Add content tab at catalog -> promo
   5. List and edit form for associating images to specific productPromoId.
   6. Implement service addImageForProductPromo.

Thanks Amit for the contribution.
Special thanks to Scott for his valuable comments.

PS: Scott regarding to you point # 2 in the last comment, I think it would be fine if we keep association as it in the current patch. Because all the ContentType already exists in the ProductContentType entity. In general we can associate Image, PDF or word document with any promotion so reusing existing entity will be fine IMO.

Added:
    ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductPromoContentWrapper.java   (with props)
Modified:
    ofbiz/trunk/applications/product/config/ProductUiLabels.xml
    ofbiz/trunk/applications/product/entitydef/entitymodel.xml
    ofbiz/trunk/applications/product/script/org/ofbiz/product/product/ProductContentServices.xml
    ofbiz/trunk/applications/product/servicedef/services.xml
    ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductServices.java
    ofbiz/trunk/applications/product/webapp/catalog/WEB-INF/controller.xml
    ofbiz/trunk/applications/product/widget/catalog/CatalogMenus.xml
    ofbiz/trunk/applications/product/widget/catalog/PromoForms.xml
    ofbiz/trunk/applications/product/widget/catalog/PromoScreens.xml

Modified: ofbiz/trunk/applications/product/config/ProductUiLabels.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/config/ProductUiLabels.xml?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/config/ProductUiLabels.xml (original)
+++ ofbiz/trunk/applications/product/config/ProductUiLabels.xml Sat Mar 13 08:46:57 2010
@@ -5467,6 +5467,9 @@
         <value xml:lang="th">แก้ไขราคาสินค้า</value>
         <value xml:lang="zh">编辑产品价格</value>
     </property>
+    <property key="PageTitleEditProductPromoContent">
+        <value xml:lang="en">Edit Product Promo Content</value>
+    </property>
     <property key="PageTitleEditProductPromoRules">
         <value xml:lang="de">Produkt Aktionsregeln bearbeiten</value>
         <value xml:lang="en">Edit Promo Rules</value>
@@ -16388,6 +16391,12 @@
         <value xml:lang="th">หน้าสินค้า</value>
         <value xml:lang="zh">产品页面</value>
     </property>
+    <property key="ProductProductPromoContentList">
+        <value xml:lang="en">Product Promo Content List</value>
+    </property>
+    <property key="ProductProductPromoContentType">
+        <value xml:lang="en">Product Promo Content Type</value>
+    </property>
     <property key="ProductProductPromotionsList">
         <value xml:lang="de">Produkt Aktionsliste</value>
         <value xml:lang="en">Product Promotions List</value>

Modified: ofbiz/trunk/applications/product/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/entitydef/entitymodel.xml?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/applications/product/entitydef/entitymodel.xml Sat Mar 13 08:46:57 2010
@@ -4746,5 +4746,27 @@ under the License.
             <key-map field-name="parentTypeId" rel-field-name="webAnalyticsTypeId"/>
         </relation>
     </entity>
-    
+
+    <entity entity-name="ProductPromoContent"
+            package-name="org.ofbiz.product.promo"
+            title="Product Promo Content Entity">
+      <field name="productPromoId" type="id-ne"/>
+      <field name="contentId" type="id-ne"/>
+      <field name="productPromoContentTypeId" type="id-ne"/>
+      <field name="fromDate" type="date-time"/>
+      <field name="thruDate" type="date-time"/>
+      <prim-key field="productPromoId"/>
+      <prim-key field="contentId"/>
+      <prim-key field="productPromoContentTypeId"/>
+      <prim-key field="fromDate"/>
+      <relation type="one" fk-name="PRODPR_CNT_PROD_PR" rel-entity-name="ProductPromo">
+        <key-map field-name="productPromoId"/>
+      </relation>
+      <relation type="one" fk-name="PRODPR_CNT_CNT" rel-entity-name="Content">
+        <key-map field-name="contentId"/>
+      </relation>
+      <relation type="one" fk-name="PRODPR_CNT_TYPE" rel-entity-name="ProductContentType">
+        <key-map field-name="productPromoContentTypeId" rel-field-name="productContentTypeId"/>
+      </relation>
+    </entity>
 </entitymodel>

Modified: ofbiz/trunk/applications/product/script/org/ofbiz/product/product/ProductContentServices.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/script/org/ofbiz/product/product/ProductContentServices.xml?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/script/org/ofbiz/product/product/ProductContentServices.xml (original)
+++ ofbiz/trunk/applications/product/script/org/ofbiz/product/product/ProductContentServices.xml Sat Mar 13 08:46:57 2010
@@ -167,4 +167,39 @@ under the License.
         </if-not-empty>
         <field-to-result field="parameters.productId" result-name="productId"/>
     </simple-method>
+
+    <!-- ProductPromoContent -->
+    <simple-method method-name="createProductPromoContent" short-description="Create Content For Product Promo">
+        <make-value value-field="newEntity" entity-name="ProductPromoContent"/>
+        <set-pk-fields map="parameters" value-field="newEntity"/>
+        <set-nonpk-fields map="parameters" value-field="newEntity"/>
+        <if-empty field="newEntity.fromDate">
+            <now-timestamp field="nowTimestamp"/>
+            <set field="newEntity.fromDate" from-field="nowTimestamp"/>
+        </if-empty>
+        <create-value value-field="newEntity"/>
+        <field-to-result field="newEntity.contentId" result-name="contentId"/>
+        <field-to-result field="newEntity.productPromoId" result-name="productPromoId"/>
+        <field-to-result field="newEntity.productPromoContentTypeId" result-name="productPromoContentTypeId"/>
+    </simple-method>
+
+    <simple-method method-name="updateProductPromoContent" short-description="Update Content For Product Promo">
+        <make-value value-field="lookupPKMap" entity-name="ProductPromoContent"/>
+        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
+        <find-by-primary-key map="lookupPKMap" value-field="lookedUpValue"/>
+        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
+        <store-value value-field="lookedUpValue"/>
+    </simple-method>
+
+    <simple-method method-name="removeProductPromoContent" short-description="Remove Content From Product Promo">
+        <make-value value-field="lookupPKMap" entity-name="ProductPromoContent"/>
+        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
+        <find-by-primary-key map="lookupPKMap" value-field="lookedUpValue"/>
+        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
+        <if-empty field="lookedUpValue.thruDate">
+            <now-timestamp field="nowTimestamp"/>
+            <set from-field="nowTimestamp" field="lookedUpValue.thruDate"/>
+        </if-empty>
+        <store-value value-field="lookedUpValue"/>
+    </simple-method>
 </simple-methods>

Modified: ofbiz/trunk/applications/product/servicedef/services.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/servicedef/services.xml?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/servicedef/services.xml (original)
+++ ofbiz/trunk/applications/product/servicedef/services.xml Sat Mar 13 08:46:57 2010
@@ -1289,4 +1289,33 @@ under the License.
         <auto-attributes include="pk" mode="IN" optional="false"/>
     </service>
     
+    <!-- Product Promo Content services -->
+    <service name="createProductPromoContent" default-entity-name="ProductPromoContent" engine="simple"
+            location="component://product/script/org/ofbiz/product/product/ProductContentServices.xml" invoke="createProductPromoContent" auth="true">
+        <description>Create Product Promo Content</description>
+        <auto-attributes include="pk" mode="INOUT" optional="false"/>
+        <auto-attributes include="nonpk" mode="IN" optional="true"/>
+        <override name="fromDate" optional="true"/>
+    </service>
+    <service name="updateProductPromoContent" default-entity-name="ProductPromoContent" engine="simple"
+            location="component://product/script/org/ofbiz/product/product/ProductContentServices.xml" invoke="updateProductPromoContent" auth="true">
+        <description>Update Product Promo Content</description>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+        <auto-attributes include="nonpk" mode="IN" optional="true"/>
+    </service>
+    <service name="removeProductPromoContent" default-entity-name="ProductPromoContent" engine="simple"
+            location="component://product/script/org/ofbiz/product/product/ProductContentServices.xml" invoke="removeProductPromoContent" auth="true">
+        <description>Remove Product Promo Content</description>
+        <auto-attributes include="pk" mode="IN" optional="false"/>
+        <auto-attributes include="nonpk" mode="IN" optional="true"/>
+    </service>
+    <service name="addImageForProductPromo" default-entity-name="ProductPromoContent" engine="java"
+            location="org.ofbiz.product.product.ProductServices" invoke="addImageForProductPromo" auth="true">
+        <implements service="uploadFileInterface"/>
+        <auto-attributes include="pk" mode="IN" optional="true"/>
+        <auto-attributes include="nonpk" mode="IN" optional="true"/>
+        <attribute name="contentId" mode="IN" optional="true" type="String"/>
+        <override name="productPromoContentTypeId" optional="false"/>
+        <override name="productPromoId" optional="false"/>
+    </service>
 </services>

Added: ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductPromoContentWrapper.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductPromoContentWrapper.java?rev=922506&view=auto
==============================================================================
--- ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductPromoContentWrapper.java (added)
+++ ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductPromoContentWrapper.java Sat Mar 13 08:46:57 2010
@@ -0,0 +1,192 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *******************************************************************************/
+package org.ofbiz.product.product;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import javolution.util.FastList;
+import javolution.util.FastMap;
+
+import org.ofbiz.base.util.Debug;
+import org.ofbiz.base.util.GeneralException;
+import org.ofbiz.base.util.StringUtil;
+import org.ofbiz.base.util.UtilHttp;
+import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.base.util.GeneralRuntimeException;
+import org.ofbiz.base.util.cache.UtilCache;
+import org.ofbiz.content.content.ContentWorker;
+import org.ofbiz.content.content.ContentWrapper;
+import org.ofbiz.entity.Delegator;
+import org.ofbiz.entity.GenericValue;
+import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.condition.EntityExpr;
+import org.ofbiz.entity.condition.EntityOperator;
+import org.ofbiz.entity.model.ModelEntity;
+import org.ofbiz.entity.model.ModelUtil;
+import org.ofbiz.entity.util.EntityUtil;
+import org.ofbiz.service.LocalDispatcher;
+
+/**
+ * Product Promo Content Worker: gets product promo content to display
+ */
+public class ProductPromoContentWrapper implements ContentWrapper {
+
+    public static final String module = ProductPromoContentWrapper.class.getName();
+    public static final String SEPARATOR = "::";    // cache key separator
+
+    public static UtilCache<String, String> productPromoContentCache = UtilCache.createUtilCache("product.promo.content.rendered", true);
+
+    public static ProductPromoContentWrapper makeProductPromoContentWrapper(GenericValue productPromo, HttpServletRequest request) {
+        return new ProductPromoContentWrapper(productPromo, request);
+    }
+
+    LocalDispatcher dispatcher;
+    protected GenericValue productPromo;
+    protected Locale locale;
+    protected String mimeTypeId;
+
+    public ProductPromoContentWrapper(LocalDispatcher dispatcher, GenericValue productPromo, Locale locale, String mimeTypeId) {
+        this.dispatcher = dispatcher;
+        this.productPromo = productPromo;
+        this.locale = locale;
+        this.mimeTypeId = mimeTypeId;
+    }
+
+    public ProductPromoContentWrapper(GenericValue productPromo, HttpServletRequest request) {
+        this.dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
+        this.productPromo = productPromo;
+        this.locale = UtilHttp.getLocale(request);
+        this.mimeTypeId = "text/html";
+    }
+
+    public StringUtil.StringWrapper get(String productPromoContentTypeId) {
+        if (UtilValidate.isEmpty(this.productPromo)) {
+            Debug.logWarning("Tried to get ProductPromoContent for type [" + productPromoContentTypeId + "] but the productPromo field in the ProductPromoContentWrapper is null", module);
+            return null;
+        }
+        return StringUtil.makeStringWrapper(getProductPromoContentAsText(this.productPromo, productPromoContentTypeId, locale, mimeTypeId, null, null, this.productPromo.getDelegator(), dispatcher));
+    }
+
+    public static String getProductPromoContentAsText(GenericValue productPromo, String productPromoContentTypeId, HttpServletRequest request) {
+        LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher");
+        return getProductPromoContentAsText(productPromo, productPromoContentTypeId, UtilHttp.getLocale(request), "text/html", null, null, productPromo.getDelegator(), dispatcher);
+    }
+
+    public static String getProductContentAsText(GenericValue productPromo, String productPromoContentTypeId, Locale locale, LocalDispatcher dispatcher) {
+        return getProductPromoContentAsText(productPromo, productPromoContentTypeId, locale, null, null, null, null, dispatcher);
+    }
+
+    public static String getProductPromoContentAsText(GenericValue productPromo, String productPromoContentTypeId, Locale locale, String mimeTypeId, String partyId, String roleTypeId, Delegator delegator, LocalDispatcher dispatcher) {
+        if (UtilValidate.isEmpty(productPromo)) {
+            return null;
+        }
+
+        String candidateFieldName = ModelUtil.dbNameToVarName(productPromoContentTypeId);
+        /* caching: there is one cache created, "product.promo.content"  Each productPromo's content is cached with a key of
+         * contentTypeId::locale::mimeType::productPromoId, or whatever the SEPARATOR is defined above to be.
+         */
+        String cacheKey = productPromoContentTypeId + SEPARATOR + locale + SEPARATOR + mimeTypeId + SEPARATOR + productPromo.get("productPromoId");
+        try {
+            if (productPromoContentCache.get(cacheKey) != null) {
+                return productPromoContentCache.get(cacheKey);
+            }
+
+            Writer outWriter = new StringWriter();
+            getProductPromoContentAsText(null, productPromo, productPromoContentTypeId, locale, mimeTypeId, partyId, roleTypeId, delegator, dispatcher, outWriter);
+            String outString = outWriter.toString();
+            if (outString.length() > 0) {
+                if (productPromoContentCache != null) {
+                    productPromoContentCache.put(cacheKey, outString);
+                }
+                return outString;
+            } else {
+                String candidateOut = productPromo.getModelEntity().isField(candidateFieldName) ? productPromo.getString(candidateFieldName): "";
+                return candidateOut == null? "" : candidateOut;
+            }
+        } catch (GeneralException e) {
+            Debug.logError(e, "Error rendering ProductPromoContent, inserting empty String", module);
+            String candidateOut = productPromo.getModelEntity().isField(candidateFieldName) ? productPromo.getString(candidateFieldName): "";
+            return candidateOut == null? "" : candidateOut;
+        } catch (IOException e) {
+            Debug.logError(e, "Error rendering ProductPromoContent, inserting empty String", module);
+            String candidateOut = productPromo.getModelEntity().isField(candidateFieldName) ? productPromo.getString(candidateFieldName): "";
+            return candidateOut == null? "" : candidateOut;
+        }
+    }
+
+    public static void getProductPromoContentAsText(String productPromoId, GenericValue productPromo, String productPromoContentTypeId, Locale locale, String mimeTypeId, String partyId, String roleTypeId, Delegator delegator, LocalDispatcher dispatcher, Writer outWriter) throws GeneralException, IOException {
+        if (UtilValidate.isEmpty(productPromoId) && UtilValidate.isNotEmpty(productPromo)) {
+            productPromoId = productPromo.getString("productPromoId");
+        }
+
+        if (UtilValidate.isEmpty(delegator) && UtilValidate.isNotEmpty(productPromo)) {
+            delegator = productPromo.getDelegator();
+        }
+
+        if (UtilValidate.isEmpty(mimeTypeId)) {
+            mimeTypeId = "text/html";
+        }
+
+        if (UtilValidate.isEmpty(delegator)) {
+            throw new GeneralRuntimeException("Unable to find a delegator to use!");
+        }
+
+        String candidateFieldName = ModelUtil.dbNameToVarName(productPromoContentTypeId);
+        ModelEntity productModel = delegator.getModelEntity("ProductPromo");
+        if (productModel.isField(candidateFieldName)) {
+            if (UtilValidate.isEmpty(productPromo)) {
+                productPromo = delegator.findByPrimaryKeyCache("ProductPromo", UtilMisc.toMap("productPromoId", productPromoId));
+            }
+            if (UtilValidate.isNotEmpty(productPromo)) {
+                String candidateValue = productPromo.getString(candidateFieldName);
+                if (UtilValidate.isNotEmpty(candidateValue)) {
+                    outWriter.write(candidateValue);
+                    return;
+                }
+            }
+        }
+
+        List<EntityExpr> exprs = FastList.newInstance();
+        exprs.add(EntityCondition.makeCondition("productPromoId", EntityOperator.EQUALS, productPromoId));
+        exprs.add(EntityCondition.makeCondition("productPromoContentTypeId", EntityOperator.EQUALS, productPromoContentTypeId));
+        List<String> orderBy = UtilMisc.toList("-fromDate");
+
+        List<GenericValue> productPromoContentList = delegator.findList("ProductPromoContent", EntityCondition.makeCondition(exprs, EntityOperator.AND), null, orderBy, null, false);
+        GenericValue productPromoContent = null;
+        if (UtilValidate.isNotEmpty(productPromoContentList)) {
+            productPromoContent = EntityUtil.getFirst(EntityUtil.filterByDate(productPromoContentList));
+        }
+
+        if (UtilValidate.isNotEmpty(productPromoContent)) {
+            // when rendering the product promo content, always include the ProductPromo and ProductPromoContent records that this comes from
+            Map<String, Object> inContext = FastMap.newInstance();
+            inContext.put("productPromo", productPromo);
+            inContext.put("productPromoContent", productPromoContent);
+            ContentWorker.renderContentAsText(dispatcher, delegator, productPromoContent.getString("contentId"), outWriter, inContext, locale, mimeTypeId, partyId, roleTypeId, false);
+        }
+    }
+}

Propchange: ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductPromoContentWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductPromoContentWrapper.java
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductPromoContentWrapper.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductServices.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductServices.java?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductServices.java (original)
+++ ofbiz/trunk/applications/product/src/org/ofbiz/product/product/ProductServices.java Sat Mar 13 08:46:57 2010
@@ -44,7 +44,9 @@ import org.ofbiz.entity.Delegator;
 import org.ofbiz.entity.GenericEntityException;
 import org.ofbiz.entity.GenericValue;
 import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.condition.EntityExpr;
 import org.ofbiz.entity.condition.EntityJoinOperator;
+import org.ofbiz.entity.condition.EntityOperator;
 import org.ofbiz.entity.util.EntityUtil;
 import org.ofbiz.product.image.ScaleImage;
 import org.ofbiz.product.catalog.CatalogWorker;
@@ -1164,5 +1166,183 @@ public class ProductServices {
 
         return result;
     }
-}
 
+    public static Map<String, Object> addImageForProductPromo(DispatchContext dctx, Map<String, ? extends Object> context)
+            throws IOException, JDOMException {
+        LocalDispatcher dispatcher = dctx.getDispatcher();
+        Delegator delegator = dctx.getDelegator();
+        GenericValue userLogin = (GenericValue) context.get("userLogin");
+        String productPromoId = (String) context.get("productPromoId");
+        String productPromoContentTypeId = (String) context.get("productPromoContentTypeId");
+        ByteBuffer imageData = (ByteBuffer) context.get("uploadedFile");
+        String contentId = (String) context.get("contentId");
+
+        if (UtilValidate.isNotEmpty(context.get("_uploadedFile_fileName"))) {
+            String imageFilenameFormat = UtilProperties.getPropertyValue("catalog", "image.filename.format");
+            String imageServerPath = FlexibleStringExpander.expandString(UtilProperties.getPropertyValue("catalog", "image.server.path"), context);
+            String imageUrlPrefix = UtilProperties.getPropertyValue("catalog", "image.url.prefix");
+
+            FlexibleStringExpander filenameExpander = FlexibleStringExpander.getInstance(imageFilenameFormat);
+            String id = productPromoId + "_Image_" + productPromoContentTypeId.charAt(productPromoContentTypeId.length() - 1);
+            String fileLocation = filenameExpander.expandString(UtilMisc.toMap("location", "products", "type", "promo", "id", id));
+            String filePathPrefix = "";
+            String filenameToUse = fileLocation;
+            if (fileLocation.lastIndexOf("/") != -1) {
+                filePathPrefix = fileLocation.substring(0, fileLocation.lastIndexOf("/") + 1); // adding 1 to include the trailing slash
+                filenameToUse = fileLocation.substring(fileLocation.lastIndexOf("/") + 1);
+            }
+
+            List<GenericValue> fileExtension = FastList.newInstance();
+            try {
+                fileExtension = delegator.findList("FileExtension", EntityCondition.makeCondition("mimeTypeId", EntityOperator.EQUALS, (String) context.get("_uploadedFile_contentType")), null, null, null, false);
+            } catch (GenericEntityException e) {
+                Debug.logError(e, module);
+                ServiceUtil.returnError(e.getMessage());
+            }
+
+            GenericValue extension = EntityUtil.getFirst(fileExtension);
+            if (extension != null) {
+                filenameToUse += "." + extension.getString("fileExtensionId");
+            }
+
+            File makeResourceDirectory  = new File(imageServerPath + "/" + filePathPrefix);
+            if (!makeResourceDirectory.exists()) {
+                makeResourceDirectory.mkdirs();
+            }
+
+            File file = new File(imageServerPath + "/" + filePathPrefix + filenameToUse);
+
+            try {
+                RandomAccessFile out = new RandomAccessFile(file, "rw");
+                out.write(imageData.array());
+                out.close();
+            } catch (FileNotFoundException e) {
+                Debug.logError(e, module);
+                return ServiceUtil.returnError("Unable to open file for writing: " + file.getAbsolutePath());
+            } catch (IOException e) {
+                Debug.logError(e, module);
+                return ServiceUtil.returnError("Unable to write binary data to: " + file.getAbsolutePath());
+            }
+
+            String imageUrl = imageUrlPrefix + "/" + filePathPrefix + filenameToUse;
+
+            if (UtilValidate.isNotEmpty(imageUrl) && imageUrl.length() > 0) {
+                Map<String, Object> dataResourceCtx = FastMap.newInstance();
+                dataResourceCtx.put("objectInfo", imageUrl);
+                dataResourceCtx.put("dataResourceName", (String) context.get("_uploadedFile_fileName"));
+                dataResourceCtx.put("userLogin", userLogin);
+
+                Map<String, Object> productPromoContentCtx = FastMap.newInstance();
+                productPromoContentCtx.put("productPromoId", productPromoId);
+                productPromoContentCtx.put("productPromoContentTypeId", productPromoContentTypeId);
+                productPromoContentCtx.put("fromDate", (Timestamp) context.get("fromDate"));
+                productPromoContentCtx.put("thruDate", (Timestamp) context.get("thruDate"));
+                productPromoContentCtx.put("userLogin", userLogin);
+
+                if (UtilValidate.isNotEmpty(contentId)) {
+                    GenericValue content = null;
+                    try {
+                        content = delegator.findOne("Content", UtilMisc.toMap("contentId", contentId), false);
+                    } catch (GenericEntityException e) {
+                        Debug.logError(e, module);
+                        ServiceUtil.returnError(e.getMessage());
+                    }
+
+                    if (UtilValidate.isNotEmpty(content)) {
+                        GenericValue dataResource = null;
+                        try {
+                            dataResource = content.getRelatedOne("DataResource");
+                        } catch (GenericEntityException e) {
+                            Debug.logError(e, module);
+                            ServiceUtil.returnError(e.getMessage());
+                        }
+
+                        if (UtilValidate.isNotEmpty(dataResource)) {
+                            dataResourceCtx.put("dataResourceId", dataResource.getString("dataResourceId"));
+                            try {
+                                dispatcher.runSync("updateDataResource", dataResourceCtx);
+                            } catch (GenericServiceException e) {
+                                Debug.logError(e, module);
+                                ServiceUtil.returnError(e.getMessage());
+                            }
+                        } else {
+                            dataResourceCtx.put("dataResourceTypeId", "SHORT_TEXT");
+                            dataResourceCtx.put("mimeTypeId", "text/html");
+                            Map<String, Object> dataResourceResult = FastMap.newInstance();
+                            try {
+                                dataResourceResult = dispatcher.runSync("createDataResource", dataResourceCtx);
+                            } catch (GenericServiceException e) {
+                                Debug.logError(e, module);
+                                ServiceUtil.returnError(e.getMessage());
+                            }
+
+                            Map<String, Object> contentCtx = FastMap.newInstance();
+                            contentCtx.put("contentId", contentId);
+                            contentCtx.put("dataResourceId", dataResourceResult.get("dataResourceId"));
+                            contentCtx.put("userLogin", userLogin);
+                            try {
+                                dispatcher.runSync("updateContent", contentCtx);
+                            } catch (GenericServiceException e) {
+                                Debug.logError(e, module);
+                                ServiceUtil.returnError(e.getMessage());
+                            }
+                        }
+
+                        productPromoContentCtx.put("contentId", contentId);
+                        try {
+                            dispatcher.runSync("updateProductPromoContent", productPromoContentCtx);
+                        } catch (GenericServiceException e) {
+                            Debug.logError(e, module);
+                            ServiceUtil.returnError(e.getMessage());
+                        }
+                    }
+                } else {
+                    dataResourceCtx.put("dataResourceTypeId", "SHORT_TEXT");
+                    dataResourceCtx.put("mimeTypeId", "text/html");
+                    Map<String, Object> dataResourceResult = FastMap.newInstance();
+                    try {
+                        dataResourceResult = dispatcher.runSync("createDataResource", dataResourceCtx);
+                    } catch (GenericServiceException e) {
+                        Debug.logError(e, module);
+                        ServiceUtil.returnError(e.getMessage());
+                    }
+
+                    Map<String, Object> contentCtx = FastMap.newInstance();
+                    contentCtx.put("contentTypeId", "DOCUMENT");
+                    contentCtx.put("dataResourceId", dataResourceResult.get("dataResourceId"));
+                    contentCtx.put("userLogin", userLogin);
+                    Map<String, Object> contentResult = FastMap.newInstance();
+                    try {
+                        contentResult = dispatcher.runSync("createContent", contentCtx);
+                    } catch (GenericServiceException e) {
+                        Debug.logError(e, module);
+                        ServiceUtil.returnError(e.getMessage());
+                    }
+
+                    productPromoContentCtx.put("contentId", contentResult.get("contentId"));
+                    try {
+                        dispatcher.runSync("createProductPromoContent", productPromoContentCtx);
+                    } catch (GenericServiceException e) {
+                        Debug.logError(e, module);
+                        ServiceUtil.returnError(e.getMessage());
+                    }
+                }
+            }
+        } else {
+            Map<String, Object> productPromoContentCtx = FastMap.newInstance();
+            productPromoContentCtx.put("productPromoId", productPromoId);
+            productPromoContentCtx.put("productPromoContentTypeId", productPromoContentTypeId);
+            productPromoContentCtx.put("contentId", contentId);
+            productPromoContentCtx.put("fromDate", (Timestamp) context.get("fromDate"));
+            productPromoContentCtx.put("thruDate", (Timestamp) context.get("thruDate"));
+            productPromoContentCtx.put("userLogin", userLogin);
+            try {
+                dispatcher.runSync("updateProductPromoContent", productPromoContentCtx);
+            } catch (GenericServiceException e) {
+                Debug.logError(e, module);
+                ServiceUtil.returnError(e.getMessage());
+            }
+        }
+        return ServiceUtil.returnSuccess();
+    }
+}

Modified: ofbiz/trunk/applications/product/webapp/catalog/WEB-INF/controller.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/webapp/catalog/WEB-INF/controller.xml?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/webapp/catalog/WEB-INF/controller.xml (original)
+++ ofbiz/trunk/applications/product/webapp/catalog/WEB-INF/controller.xml Sat Mar 13 08:46:57 2010
@@ -2672,6 +2672,25 @@ under the License.
     </request-map>
 
     <!-- end of request mappings -->
+    
+    <!-- ================ Product Promo Content Requests ================= -->
+    <request-map uri="EditProductPromoContent">
+        <security https="true" auth="true"/>
+        <response name="success" type="view" value="EditProductPromoContent"/>
+        <response name="error" type="view" value="EditProductPromoContent"/>
+    </request-map>    
+    <request-map uri="removeContentFromProductPromo">
+        <security https="true" auth="true"/>
+        <event type="service" invoke="removeProductPromoContent"/>
+        <response name="success" type="view" value="EditProductPromoContent"/>
+        <response name="error" type="view" value="EditProductPromoContent"/>
+    </request-map>
+    <request-map uri="addImageContentForProductPromo">
+        <security https="true" auth="true"/>
+        <event type="service" invoke="addImageForProductPromo"/>
+        <response name="success" type="view" value="EditProductPromoContent"/>
+        <response name="error" type="view" value="EditProductPromoContent"/>
+    </request-map>
 
     <!-- View Mappings -->
     <view-map name="main" type="screen" page="component://product/widget/catalog/CommonScreens.xml#main"/>
@@ -2771,6 +2790,7 @@ under the License.
     <view-map name="EditProductPromoStores" type="screen" page="component://product/widget/catalog/PromoScreens.xml#EditProductPromoStores"/>
     <view-map name="FindProductPromoCode" type="screen" page="component://product/widget/catalog/PromoScreens.xml#FindProductPromoCode"/>
     <view-map name="EditProductPromoCode" type="screen" page="component://product/widget/catalog/PromoScreens.xml#EditProductPromoCode"/>
+    <view-map name="EditProductPromoContent" type="screen" page="component://product/widget/catalog/PromoScreens.xml#EditProductPromoContent"/>
 
     <view-map name="FindPriceRules" type="screen" page="component://product/widget/catalog/PriceScreens.xml#FindProductPriceRule"/>
     <view-map name="EditProductPriceRules" type="screen" page="component://product/widget/catalog/PriceScreens.xml#EditProductPriceRules"/>

Modified: ofbiz/trunk/applications/product/widget/catalog/CatalogMenus.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/widget/catalog/CatalogMenus.xml?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/widget/catalog/CatalogMenus.xml (original)
+++ ofbiz/trunk/applications/product/widget/catalog/CatalogMenus.xml Sat Mar 13 08:46:57 2010
@@ -235,6 +235,11 @@ under the License.
                 <parameter param-name="productPromoId"/>
             </link>
         </menu-item>
+        <menu-item name="EditProductPromoContent" title="${uiLabelMap.CommonContent}">
+            <link target="EditProductPromoContent">
+                <parameter param-name="productPromoId"/>
+            </link>
+        </menu-item>
     </menu>
 
     <menu name="ProductTabBar" extends="CommonTabBarMenu" extends-resource="component://common/widget/CommonMenus.xml">

Modified: ofbiz/trunk/applications/product/widget/catalog/PromoForms.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/widget/catalog/PromoForms.xml?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/widget/catalog/PromoForms.xml (original)
+++ ofbiz/trunk/applications/product/widget/catalog/PromoForms.xml Sat Mar 13 08:46:57 2010
@@ -118,4 +118,46 @@ under the License.
             </hyperlink>
         </field>
     </form>
+    
+    <form name="EditProductPromoContentImage" type="upload" target="addImageContentForProductPromo" default-map-name="productPromoContent">
+        <field name="productPromoId"><hidden/></field>
+        <field use-when="productPromoContent != null" name="contentId"><display/></field>
+        <field name="productPromoContentTypeId"><hidden value="ORIGINAL_IMAGE_URL"/></field>
+        <field name="fromDate" use-when="productPromoContent == null" title="${uiLabelMap.CommonFromDate}"><date-time/></field>
+        <field name="fromDate" use-when="productPromoContent != null" title="${uiLabelMap.CommonFromDate}"><display/></field>
+        <field name="thruDate" title="${uiLabelMap.CommonThruDate}"><date-time/></field>
+        <field name="uploadedFile" title="${uiLabelMap.ProductFile}"><file/></field>
+        <field use-when="productPromoContent == null" name="submitButton" title="${uiLabelMap.CommonCreate}" widget-style="smallSubmit"><submit button-type="button"/></field>
+        <field use-when="productPromoContent != null" name="submitButton" title="${uiLabelMap.CommonUpdate}" widget-style="smallSubmit"><submit button-type="button"/></field>
+    </form>
+
+    <form name="ListProductPromoContent" type="list" list-name="productPromoContents"
+            odd-row-style="alternate-row" default-table-style="basic-table">
+        <field name="editProductPromoContent" title="${uiLabelMap.ProductContent}" widget-style="buttontext">
+            <hyperlink target="EditProductPromoContent" description="${description} [${contentId}]" also-hidden="false">
+                <parameter param-name="productPromoId"/>
+                <parameter param-name="contentId"/>
+                <parameter param-name="productPromoContentTypeId"/>
+                <parameter param-name="fromDate"/>
+            </hyperlink>
+        </field>
+        <field name="productPromoContentTypeId" title="${uiLabelMap.ProductProductPromoContentType}">
+            <display-entity entity-name="ProductContentType" key-field-name="productContentTypeId" also-hidden="false" description="${description}"/>
+        </field>
+        <field name="fromDate"><display/></field>
+        <field name="thruDate"><display/></field>
+        <field name="editContent" title="${uiLabelMap.ProductEditContent}" widget-style="buttontext">
+            <hyperlink target="/content/control/EditContent" target-type="inter-app" description="${contentId}" also-hidden="false">
+                <parameter param-name="contentId"/>
+            </hyperlink>
+        </field>
+        <field name="removeContent" title="${uiLabelMap.CommonEmptyHeader}" widget-style="buttontext">
+            <hyperlink target="removeContentFromProductPromo" description="${uiLabelMap.CommonDelete}" also-hidden="false">
+                <parameter param-name="productPromoId"/>
+                <parameter param-name="contentId"/>
+                <parameter param-name="productPromoContentTypeId"/>
+                <parameter param-name="fromDate"/>
+            </hyperlink>
+        </field>
+    </form>
 </forms>

Modified: ofbiz/trunk/applications/product/widget/catalog/PromoScreens.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/applications/product/widget/catalog/PromoScreens.xml?rev=922506&r1=922505&r2=922506&view=diff
==============================================================================
--- ofbiz/trunk/applications/product/widget/catalog/PromoScreens.xml (original)
+++ ofbiz/trunk/applications/product/widget/catalog/PromoScreens.xml Sat Mar 13 08:46:57 2010
@@ -330,4 +330,35 @@ under the License.
             </widgets>
         </section>
     </screen>
+
+    <screen name="EditProductPromoContent">
+        <section>
+            <actions>
+                <set field="titleProperty" value="PageTitleEditProductPromoContent"/>
+                <set field="headerItem" value="promos"/>
+                <set field="tabButtonItem" value="EditProductPromoContent"/>
+                <set field="labelTitleProperty" value="ProductPromoContents"/>
+                <set field="productPromoId" from-field="parameters.productPromoId"/>
+                <set field="parameters.fromDate" type="Timestamp" from-field="parameters.fromDate"/>
+                <set field="parameters.thruDate" type="Timestamp" from-field="parameters.thruDate"/>
+                <entity-one entity-name="ProductPromo" value-field="productPromo"/>
+                <entity-one entity-name="ProductPromoContent" value-field="productPromoContent"/>
+                <entity-and list="productPromoContents" entity-name="ProductPromoContent">
+                    <field-map field-name="productPromoId" from-field="productPromoId"/>
+                </entity-and>
+            </actions>
+            <widgets>
+                <decorator-screen name="CommonPromoDecorator">
+                    <decorator-section name="body">
+                        <screenlet title="${uiLabelMap.PageTitleEditProductPromoContent}">
+                            <include-form name="EditProductPromoContentImage" location="component://product/widget/catalog/PromoForms.xml"/>
+                        </screenlet>
+                        <screenlet title="${uiLabelMap.ProductProductPromoContentList}">
+                            <include-form name="ListProductPromoContent" location="component://product/widget/catalog/PromoForms.xml"/>
+                        </screenlet>
+                    </decorator-section>
+                </decorator-screen>
+            </widgets>
+        </section>
+    </screen>
 </screens>