svn commit: r1822912 [1/2] - in /ofbiz/ofbiz-framework/trunk: applications/product/groovyScripts/product/ applications/product/groovyScripts/product/category/ applications/product/minilang/product/category/ applications/product/servicedef/ framework/co...

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

svn commit: r1822912 [1/2] - in /ofbiz/ofbiz-framework/trunk: applications/product/groovyScripts/product/ applications/product/groovyScripts/product/category/ applications/product/minilang/product/category/ applications/product/servicedef/ framework/co...

nmalin
Author: nmalin
Date: Thu Feb  1 22:33:59 2018
New Revision: 1822912

URL: http://svn.apache.org/viewvc?rev=1822912&view=rev
Log:
Improved: Convert CategoryServices.xml mini lang to groovy (OFBIZ-10031)
thanks to Dennis Balkir for this help to minilang conversion

Added:
    ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/
    ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/
    ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/CategoryServices.groovy   (with props)
Modified:
    ofbiz/ofbiz-framework/trunk/applications/product/minilang/product/category/CategoryServices.xml
    ofbiz/ofbiz-framework/trunk/applications/product/servicedef/services.xml
    ofbiz/ofbiz-framework/trunk/applications/product/servicedef/services_maint.xml
    ofbiz/ofbiz-framework/trunk/applications/product/servicedef/services_view.xml
    ofbiz/ofbiz-framework/trunk/framework/common/config/CommonUiLabels.xml

Added: ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/CategoryServices.groovy
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/CategoryServices.groovy?rev=1822912&view=auto
==============================================================================
--- ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/CategoryServices.groovy (added)
+++ ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/CategoryServices.groovy Thu Feb  1 22:33:59 2018
@@ -0,0 +1,808 @@
+/*
+ * 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.
+ */
+
+
+import org.apache.ofbiz.entity.util.EntityUtilProperties
+
+import java.sql.Timestamp
+
+import org.apache.ofbiz.base.util.UtilDateTime
+import org.apache.ofbiz.base.util.UtilProperties
+import org.apache.ofbiz.base.util.UtilValidate
+import org.apache.ofbiz.entity.GenericValue
+import org.apache.ofbiz.entity.condition.EntityCondition
+import org.apache.ofbiz.entity.condition.EntityOperator
+import org.apache.ofbiz.entity.util.EntityUtil
+import org.apache.ofbiz.service.ModelService
+import org.apache.ofbiz.service.ServiceUtil
+
+
+/*
+ * ================================================================
+ * ProductCategory Services
+ * ================================================================
+ */
+
+/**
+ * Create an ProductCategory
+ */
+def createProductCategory() {
+    def resourceDescription = parameters.rescourceDescription ?: "createProductCategory"
+    if (!(security.hasEntityPermission("CATALOG", "_CREATE", parameters.userLogin)
+        || security.hasEntityPermission("CATALOG_ROLE", "_CREATE", parameters.userLogin))) {
+        return error(UtilProperties.getMessage("ProductUiLabels", "ProductCatalogCreatePermissionError",
+            [resourceDescription: resourceDescription], parameters.locale))
+    }
+
+    Timestamp nowTimestamp = UtilDateTime.nowTimestamp()
+    GenericValue newEntity = makeValue("ProductCategory", parameters)
+
+    if (!parameters.productCategoryId) {
+        newEntity.productCategoryId = delegator.getNextSeqId("ProductCategory")
+    } else {
+        newEntity.productCategoryId = parameters.productCategoryId
+        def errorMessage = UtilValidate.checkValidDatabaseId(newEntity.productCategoryId)
+        if (errorMessage != null) {
+            return error(errorMessage)
+        }
+    }
+    Map result = success()
+    result.productCategoryId = newEntity.productCategoryId
+    newEntity.create()
+
+    if (security.hasEntityPermission("CATALOG_ROLE", "_CREATE", parameters.userLogin)) {
+        List productCategoryRoles = from("ProductCategoryRole")
+            .where("partyId", parameters.userLogin.partyId, "roleTypeId", "LTD_ADMIN")
+            .filterByDate()
+            .queryList()
+        for (def productCategoryRole : productCategoryRoles) {
+            // add this new product to the category
+            GenericValue newLimitRollup = makeValue("ProductCategoryRollup", [
+                productCategoryId: newEntity.productCategoryId,
+                parentProductCategoryId: productCategoryRole.productCategoryId,
+                fromDate: nowTimestamp
+            ])
+            newLimitRollup.create()
+        }
+    }
+    return result
+}
+
+/**
+ * Update an ProductCategory
+ */
+def updateProductCategory() {
+    Map res = checkCategoryRelatedPermission("updateProductCategory", "UPDATE", null, null)
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+    GenericValue lookedUpValue = from("ProductCategory").where(parameters).queryOne()
+    lookedUpValue.setNonPKFields(parameters)
+    lookedUpValue.store()
+    return success()
+}
+
+/*
+ * ================================================================
+ * ProductCategoryMember Services
+ * ================================================================
+ */
+
+/**
+ * Add Product to Multiple Categories
+ */
+def addProductToCategories() {
+    Map addProductToCategoryMap = dispatcher.dispatchContext.makeValidContext("addProductToCategory", ModelService.IN_PARAM, parameters)
+    if (parameters.categories instanceof java.util.List) {
+        for (def category : parameters.categories) {
+            addProductToCategoryMap.productCategoryId = category
+            run service: "addProductToCategory", with: addProductToCategoryMap
+        }
+    } else {
+        /* Note that the security semantics require the user to have the general admin permission,
+           or the role limited permission and association with the category, not the product */
+        Map res = checkCategoryRelatedPermission("addProductToCategories", "CREATE", parameters.categories, null)
+        if (!ServiceUtil.isSuccess(res)) {
+            return res
+        }
+
+        addProductToCategoryMap.productCategoryId = parameters.categories
+        run service: "addProductToCategory", with: addProductToCategoryMap
+    }
+    return success()
+}
+
+/**
+ * Remove Product From Category
+ */
+def removeProductFromCategory() {
+    // If the associated category was the primary category for the product, clear that field
+    GenericValue product = from("Product").where(parameters).queryOne()
+    if (UtilValidate.areEqual(product?.primaryProductCategoryId, parameters.productCategoryId)) {
+        product.primaryProductCategoryId = null
+        product.store()
+    }
+    Map lookupPKMap = makeValue("ProductCategoryMember", parameters)
+    GenericValue lookedUpValue = findOne("ProductCategoryMember", lookupPKMap, false)
+    lookedUpValue.remove()
+    return success()
+}
+
+/*
+ * ================================================================
+ * ProductCategoryRole Services
+ * ================================================================
+ */
+
+/**
+ * Add Party to Category
+ */
+def addPartyToCategory() {
+    Map res = checkCategoryRelatedPermission("addPartyToCategory", "CREATE", null, null)
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+    GenericValue newEntity = makeValue("ProductCategoryRole", parameters)
+    if (!newEntity.fromDate) {
+        newEntity.fromDate = UtilDateTime.nowTimestamp()
+    }
+    newEntity.create()
+    return success()
+}
+
+/**
+ * Update Party to Category Application
+ */
+def updatePartyToCategory() {
+    Map res = checkCategoryRelatedPermission("updatePartyToCategory", "UPDATE", null, null)
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+    GenericValue lookedUpValue = from("ProductCategoryRole").where(parameters).queryOne()
+    lookedUpValue.setNonPKFields(parameters)
+    lookedUpValue.store()
+    return success()
+}
+
+/**
+ * Remove Party From Category
+ */
+def removePartyFromCategory() {
+    Map res = checkCategoryRelatedPermission("removePartyFromCategory", "DELETE", null, null)
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+    GenericValue lookedUpValue = from("ProductCategoryRole").where(parameters).queryOne()
+    lookedUpValue.remove()
+    return success()
+}
+
+/*
+ * ================================================================
+ * ProductCategoryRollup Services
+ * ================================================================
+ */
+
+/**
+ * Add ProductCategory to Category
+ */
+def addProductCategoryToCategory() {
+    Map res = checkCategoryRelatedPermission("addProductCategoryToCategory", "CREATE", null, "parentProductCategoryId")
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+    GenericValue newEntity = makeValue("ProductCategoryRollup", parameters)
+
+    if (!newEntity.fromDate) {
+        newEntity.fromDate = UtilDateTime.nowTimestamp()
+    }
+
+    newEntity.create()
+    return success()
+}
+
+/**
+ * Add ProductCategory to Categories
+ */
+def addProductCategoryToCategories() {
+    if (parameters.categories instanceof java.util.List) {
+        for (def category : parameters.categories) {
+            // note the the user must be associated with the parent category with the role limited permission
+            Map res = checkCategoryRelatedPermission("addProductCategoryToCategories", "CREATE", category, null)
+            if (!ServiceUtil.isSuccess(res)) {
+                return res
+            }
+            GenericValue newEntity = makeValue("ProductCategoryRollup", parameters)
+            newEntity.parentProductCategoryId = category
+
+            if (!newEntity.fromDate) {
+                newEntity.fromDate = UtilDateTime.nowTimestamp()
+            }
+            newEntity.create()
+        }
+    } else {
+        // note the the user must be associated with the parent category with the role limited permission
+        Map res = checkCategoryRelatedPermission("addProductCategoryToCategories", "CREATE", "parameters.categories", null)
+        if (!ServiceUtil.isSuccess(res)) {
+            return res
+        }
+        GenericValue newEntity = makeValue("ProductCategoryRollup", parameters)
+        newEntity.parentProductCategoryId = parameters.categories
+
+        if (!newEntity.fromDate) {
+            newEntity.fromDate = UtilDateTime.nowTimestamp()
+        }
+
+        newEntity.create()
+    }
+    return success()
+}
+
+/**
+ * Update ProductCategory to Category Application
+ */
+def updateProductCategoryToCategory() {
+    // note the the user must be associated with the parent category with the role limited permission
+    Map res = checkCategoryRelatedPermission("updateProductCategoryToCategory", "UPDATE", null, "parentProductCategoryId")
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+
+    GenericValue lookedUpValue = from("ProductCategoryRollup").where(parameters).queryOne()
+    lookedUpValue.setNonPKFields(parameters)
+    lookedUpValue.store()
+    Map result = success()
+    result.productCategoryId = parameters.productCategoryId
+    return result
+}
+
+/**
+ * Remove ProductCategory From Category
+ */
+def removeProductCategoryFromCategory() {
+    // note the the user must be associated with the parent category with the role limited permission
+    Map res = checkCategoryRelatedPermission("removeProductCategoryFromCategory", "DELETE", null, "parentProductCategoryId")
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+
+    GenericValue lookedUpValue = from("ProductCategoryRollup").where(parameters).queryOne()
+    lookedUpValue.remove()
+    return success()
+}
+
+/*
+ * ================================================================
+ * Special Category Function Services
+ * ================================================================
+ */
+
+/**
+ * copy CategoryProduct Members to a CategoryProductTo
+ */
+def copyCategoryProductMembers() {
+    Map res = checkCategoryRelatedPermission("copyCategoryProductMembers", "CREATE", null, "productCategoryIdTo")
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+
+    def query = from("ProductCategoryMember").where("productCategoryId", parameters.productCategoryId)
+    if (parameters.validDate) {
+        query.filterByDate()
+    }
+    List productCategoryMembers = query.queryList()
+
+    // add each to a list to store and then store all and let the entity engine do inserts or updates as needed; much more reliable/useful
+    List pcmsToStore = []
+    for (def productCategoryMember : productCategoryMembers) {
+        def newProductCategoryMember = productCategoryMember.clone()
+        parameters.productCategoryIdTo = newProductCategoryMember.productCategoryId
+        pcmsToStore.add(newProductCategoryMember)
+    }
+    delegator.storeAll(pcmsToStore)
+
+    if (parameters.recurse == "Y") {
+        // call this service for each sub-category in the rollup with the same productCategoryIdTo
+        Map lookupChildrenMap = [parentProductCategoryId: parameters.productCategoryId]
+        query = from("ProductCategoryRollup").where(lookupChildrenMap)
+
+        if (parameters.validDate) {
+            query.filterByDate()
+        }
+        List productCategoryRollups = query.queryList()
+
+        Map callServiceMap = [:]
+        for (def productCategoryRollup : productCategoryRollups) {
+            callServiceMap = [
+                productCategoryId: productCategoryRollup.productCategoryId,
+                productCategoryIdTo: parameters.productCategoryIdTo,
+                validDate: parameters.validDate,
+                recurse: parameters.recurse
+            ]
+            run service: "copyCategoryProductMembers", with: callServiceMap
+        }
+    }
+    return success()
+}
+
+/**
+ * a service wrapper for copyCategoryEntities
+ */
+def duplicateCategoryEntities() {
+    def resourceDescription = parameters.resourceDescription ?: "duplicateCategoryEntities"
+    if (!(security.hasEntityPermission("CATALOG", "_CREATE", parameters.userLogin)
+        || security.hasEntityPermission("CATALOG_ROLE", "_CREATE", parameters.userLogin))) {
+        return error(UtilProperties.getMessage("ProductUiLabels", "ProductCatalogCreatePermissionError", [resourceDescription: resourceDescription], parameters.locale))
+    }
+
+    copyCategoryEntities(parameters.entityName, parameters.productCategoryId, parameters.productCategoryIdTo, parameters.validDate)
+    return success()
+}
+
+/**
+ * copies all entities of entityName with a productCategoryId to a new entity with a productCategoryIdTo,
+ * filtering them by a timestamp passed in to validDate if necessary
+ * @param entityName
+ * @param productCategoryId
+ * @param productCategoryIdTo
+ * @param validDate
+ */
+def copyCategoryEntities(entityName, productCategoryId, productCategoryIdTo, validDate) {
+    def query = from(entityName).where("productCategoryId", productCategoryId)
+    if (validDate) {
+        query.filterByDate()
+    }
+    List categoryEntities = query.queryList()
+
+    // add each to a list to store and then store all and let the entity engine do inserts or updates as needed; much more reliable/useful
+    List entitiesToStore = []
+    for (def categoryEntity : categoryEntities) {
+        def newCategoryEntity = categoryEntity.clone()
+        newCategoryEntity.productCategoryId = productCategoryIdTo
+        entitiesToStore.add(newCategoryEntity)
+    }
+    delegator.storeAll(entitiesToStore)
+}
+
+/**
+ * Remove ProductCategory From Category
+ */
+def expireAllCategoryProductMembers() {
+    Map res = checkCategoryRelatedPermission("expireAllCategoryProductMembers", "UPDATE", null, null)
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+
+    Timestamp expireTimestamp = null
+    if (parameters.thruDate) {
+        expireTimestamp = parameters.thruDate
+    } else {
+        expireTimestamp = UtilDateTime.nowTimestamp()
+    }
+
+    List productCategoryMembers = from("ProductCategoryMember").where("productCategoryId", parameters.productCategoryId).queryList()
+
+    for (GenericValue productCategoryMember : productCategoryMembers) {
+        productCategoryMember.thruDate = expireTimestamp
+        productCategoryMember.store()
+    }
+    return success()
+}
+
+/**
+ * Remove ProductCategory From Category
+ */
+def removeExpiredCategoryProductMembers() {
+    Map res = checkCategoryRelatedPermission("removeExpiredCategoryProductMembers", "DELETE", null, null)
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+
+    Timestamp expireTimestamp = null
+    if (parameters.validDate) {
+        expireTimestamp = parameters.validDate
+    } else {
+        expireTimestamp = UtilDateTime.nowTimestamp()
+    }
+
+    List productCategoryMembers = from("ProductCategoryMember").where("productCategoryId", parameters.productCategoryId).queryList()
+
+    for (GenericValue productCategoryMember : productCategoryMembers) {
+        Timestamp thruDate = productCategoryMember.thruDate
+        if (thruDate && thruDate.before(expireTimestamp)) {
+            productCategoryMember.remove()
+        }
+    }
+    return success()
+}
+
+/*
+ * ================================================================
+ * Special Category Related Create Services
+ * ================================================================
+ */
+
+/**
+ * Create a Product in a Category along with special information such as features
+ *
+ */
+def createProductInCategory() {
+    Map res = checkCategoryRelatedPermission("createProductInCategory", "CREATE", null, null)
+    if (!ServiceUtil.isSuccess(res)) {
+        return res
+    }
+
+    if (!parameters.currencyUomId) {
+        parameters.currencyUomId = EntityUtilProperties.getPropertyValue("general", "currency.uom.id.default", "USD", delegator)
+    }
+
+    // create product
+    if (!parameters.productTypeId) {
+        parameters.productTypeId = "FINISHED_GOOD"
+    }
+    Map cPRes = run service: "createProduct", with: parameters
+    def productId = cPRes.productId
+    Map result = success()
+    result.productId = productId
+
+    // create ProductCategoryMember
+    Map callCreateProductCategoryMemberMap = [
+        productId: productId,
+        productCategoryId: parameters.productCategoryId
+    ]
+    run service: "addProductToCategory", with: callCreateProductCategoryMemberMap
+
+    // create defaultPrice and averageCost ProductPrice
+    if (parameters.defaultPrice) {
+        Map createDefaultPriceMap = [
+            productId: productId,
+            currencyUomId: parameters.currencyUomId,
+            price: parameters.defaultPrice,
+            productStoreGroupId: "_NA_",
+            productPriceTypeId: "DEFAULT_PRICE",
+            productPricePurposeId: "PURCHASE",
+        ]
+        run service: "createProductPrice", with: createDefaultPriceMap
+    }
+
+    if (parameters.averageCost) {
+        Map createAverageCostMap = [
+            productId: productId,
+            currencyUomId: parameters.currencyUomId,
+            price: parameters.averageCost,
+            productStoreGroupId: "_NA_",
+            productPriceTypeId: "AVERAGE_COST",
+            productPricePurposeId: "PURCHASE",
+        ]
+        run service: "createProductPrice", with: createAverageCostMap
+    }
+
+    // create ProductFeatureAppl(s)
+    String hasSelectableFeatures = "N"
+    for (Map entry : parameters.productFeatureIdByType.entrySet()) {
+        def productFeatureTypeId = entry.getKey()
+        def productFeatureId = entry.getValue()
+        logInfo("Applying feature [${productFeatureId}] of type [${productFeatureTypeId}] to product [${productId}]")
+        Map createPfaMap = [productId: productId, productFeatureId: productFeatureId]
+        if (parameters.productFeatureSelectableByType[productFeatureTypeId].equals("Y")) {
+            createPfaMap.productFeatureApplTypeId = "SELECTABLE_FEATURE"
+            hasSelectableFeatures = "Y"
+        } else {
+            createPfaMap.productFeatureApplTypeId = "STANDARD_FEATURE"
+        }
+        run service: "applyFeatureToProduct", with: createPfaMap
+        createPfaMap = null
+    }
+
+    // set isVirtual based on hasSelectableFeatures
+    if (hasSelectableFeatures.equals("Y")) {
+        GenericValue newProduct = from("Product").where(parameters).queryOne()
+        newProduct.isVirtual = "Y"
+        newProduct.store()
+    }
+    return result
+}
+
+/**
+ * Duplicate a ProductCategory
+ */
+def duplicateProductCategory() {
+    def resourceDescription = parameters.resourceDescription ?: "duplicateProductCategory"
+    if (!(security.hasEntityPermission("CATALOG", "_CREATE", parameters.userLogin)
+        || security.hasEntityPermission("CATALOG_ROLE", "_CREATE", parameters.userLogin))) {
+        return error(UtilProperties.getMessage("ProductUiLabels", "ProductCatalogCreatePermissionError",
+                [resourceDescription: resourceDescription], parameters.locale))
+    }
+
+    // look up the old product category and clone it
+    GenericValue oldCategory = findOne("ProductCategory", [productCategoryId: parameters.oldProductCategoryId], false)
+    GenericValue newCategory = oldCategory.clone()
+
+    // set the new product category id, and write it to the datasource
+    newCategory.productCategoryId = parameters.productCategoryId
+    newCategory.create()
+    def productCategoryId = parameters.oldProductCategoryId
+    def productCategoryIdTo = parameters.productCategoryId
+
+    // if requested, duplicate related data as well
+    if (parameters.duplicateMembers) {
+        copyCategoryEntities("ProductCategoryMember", productCategoryId, productCategoryIdTo, null)
+    }
+    if (parameters.duplicateContent) {
+        copyCategoryEntities("ProductCategoryContent", productCategoryId, productCategoryIdTo, null)
+    }
+    if (parameters.duplicateRoles) {
+        copyCategoryEntities("ProductCategoryRole", productCategoryId, productCategoryIdTo, null)
+    }
+    if (parameters.duplicateAttributes) {
+        copyCategoryEntities("ProductCategoryAttribute", productCategoryId, productCategoryIdTo, null)
+    }
+    if (parameters.duplicateFeatureCategories) {
+        copyCategoryEntities("ProductFeatureCategoryAppl", productCategoryId, productCategoryIdTo, null)
+    }
+    if (parameters.duplicateFeatureGroups) {
+        copyCategoryEntities("ProductFeatureCatGrpAppl", productCategoryId, productCategoryIdTo, null)
+    }
+    if (parameters.duplicateCatalogs) {
+        copyCategoryEntities("ProdCatalogCategory", productCategoryId, productCategoryIdTo, null)
+    }
+
+    /* Parent rollups are where oldProductCategoryId = ProductCategoryRollup.productCategoryId,
+     * but the child roll up is where oldProductCategoryId = ProductCategoryRollup.parentProductCategoryId
+     * and hence requires a new find-by map */
+    def foundValues = []
+    if (parameters.duplicateParentRollup) {
+        foundValues = from("ProductCategoryRollup").where("productCategoryId", parameters.oldProductCategoryId).queryList()
+        for (GenericValue foundValue : foundValues) {
+            GenericValue newTempValue = foundValue.clone()
+            newTempValue.productCategoryId = parameters.productCategoryId
+            newTempValue.create()
+        }
+    }
+    if (parameters.duplicateChildRollup) {
+        foundValues = from("ProductCategoryRollup").where("parentProductCategoryId", parameters.oldProductCategoryId).queryList()
+        for (GenericValue foundValue : foundValues) {
+            GenericValue newTempValue = foundValue.clone()
+            newTempValue.parentProductCategoryId = parameters.productCategoryId
+            newTempValue.create()
+        }
+    }
+    return success()
+}
+
+/*
+ * ================================================================
+ * Product Category Attribute Services
+ * ================================================================
+ */
+
+/**
+ * Create an attribute for a product category
+ */
+def createProductCategoryAttribute() {
+    def resourceDescription = parameters.resourceDescription ?: "createProductCategoryAttribute"
+    if (!(security.hasEntityPermission("CATALOG", "_CREATE", parameters.userLogin))) {
+        return error(UtilProperties.getMessage("ProductUiLabels", "ProductCatalogCreatePermissionError",
+            [resourceDescription: resourceDescription], parameters.locale))
+    }
+
+    GenericValue newEntity = makeValue("ProductCategoryAttribute", parameters)
+    newEntity.create()
+    return success()
+}
+
+/**
+ * Update an association between two product categories
+ */
+def updateProductCategoryAttribute() {
+    def resourceDescription = parameters.resourceDescription ?: "updateProductCategoryAttribute"
+    if (!(security.hasEntityPermission("CATALOG", "_UPDATE", parameters.userLogin))) {
+        return error(UtilProperties.getMessage("ProductUiLabels", "ProductCatalogUpdatePermissionError",
+            [resourceDescription: resourceDescription], parameters.locale))
+    }
+
+    GenericValue productCategoryAttributeInstance = from("ProductCategoryAttribute").where(parameters).queryOne()
+    productCategoryAttributeInstance.setNonPKFields(parameters)
+    productCategoryAttributeInstance.store()
+    return success()
+}
+
+/**
+ * Delete an association between two product categories
+ */
+def deleteProductCategoryAttribute() {
+    def resourceDescription = parameters.resourceDescription ?: "deleteProductCategoryAttribute"
+    if (!(security.hasEntityPermission("CATALOG", "_DELETE", parameters.userLogin))) {
+        return error(UtilProperties.getMessage("ProductUiLabels", "ProductCatalogDeletePermissionError",
+            [resourceDescription: resourceDescription], parameters.locale))
+    }
+
+    GenericValue productCategoryAttributeInstance = from("ProductCategoryAttribute").where(parameters).queryOne()
+    productCategoryAttributeInstance.remove()
+    return success()
+}
+
+// ProductCategoryLink Create/Update/Delete
+/**
+ * create a ProductCategoryLink
+ */
+def createProductCategoryLink() {
+    GenericValue newEntity = makeValue("ProductCategoryLink", parameters)
+    newEntity.productCategoryId = parameters.productCategoryId
+
+    // don't set the fromDate yet; let's get the seq ID first
+    if(!parameters.linkSeqId) {
+        newEntity.linkSeqId = delegator.getNextSeqId("newEntity")
+    }
+
+    // now set the rest of the PK fields (should just be fromDate now; unless linkSeqId is not empty)
+    if (!newEntity.fromDate) {
+        newEntity.fromDate = UtilDateTime.nowTimestamp()
+    }
+    newEntity.create()
+    return success()
+}
+
+/*
+ * ================================================================
+ * Permission Methods
+ * ================================================================
+ */
+
+/**
+ * Check Product Category Related Permission
+ */
+def checkCategoryRelatedPermission(callingMethodName, checkAction, productCategoryIdToCheck, productCategoryIdName) {
+    if (!callingMethodName) {
+        callingMethodName = UtilProperties.getMessage("CommonUiLabels", "CommonPermissionThisOperation", parameters.locale)
+    }
+    if (!checkAction) {
+        checkAction = "UPDATE"
+    }
+    if (!productCategoryIdName) {
+        productCategoryIdName = "productCategoryId"
+    }
+    if (!productCategoryIdToCheck) {
+        productCategoryIdToCheck = parameters."${productCategoryIdName}"
+    }
+
+    // find all role-categories that this category is a member of
+    List roleCategories = []
+    if (!(security.hasEntityPermission("CATALOG", "_${checkAction}", parameters.userLogin))) {
+        roleCategories = from("ProductCategoryRollupAndRole")
+            .where("productCategoryId", productCategoryIdToCheck, "partyId", parameters.userLogin.partyId, "roleTypeId", "LTD_ADMIN")
+            .filterByDate()
+            .queryList()
+        roleCategories = EntityUtil.filterByDate(roleCategories, UtilDateTime.nowTimestamp(), "roleFromDate", "roleThruDate", true)
+    }
+    logInfo("Checking category permission, roleCategories=${roleCategories}")
+    Map result = success()
+    result.hasPermission = true
+    if (!(security.hasEntityPermission("CATALOG", "_${checkAction}", parameters.userLogin)
+        || (security.hasEntityPermission("CATALOG_ROLE", "_${checkAction}", parameters.userLogin)
+        && roleCategories))) {
+        logVerbose("Permission check failed, user does not have the correct permission.")
+        result = error(UtilProperties.getMessage("ProductUiLabels", "ProductCatalogCreatePermissionError",
+            [resourceDescription: callingMethodName], parameters.locale))
+    }
+    return result
+}
+
+/**
+ * Main permission logic
+ */
+def productCategoryGenericPermission() {
+    if (!parameters.mainAction) {
+        return error(UtilProperties.getMessage("ProductUiLabels", "ProductMissingMainActionInPermissionService", parameters.locale))
+    }
+
+    Map result = success()
+    Map res = checkCategoryRelatedPermission(parameters.resourceDescription, parameters.mainAction, null, null)
+    if (ServiceUtil.isSuccess(res)) {
+        result.hasPermission = true
+    } else {
+        result.failMessage = UtilProperties
+            .getMessage("ProductUiLabels", "ProductPermissionError",
+                [resourceDescription: parameters.resourceDescription, mainAction: parameters.mainAction],
+                parameters.locale)
+        result.hasPermission = false
+    }
+    return result
+}
+
+// A service version of checkCategoryRelatedPermission, only with purchase/viewAllowPermReqd taken into account
+/**
+ * Check Product Category Permission With View and Purchase Allow
+ */
+def checkCategoryPermissionWithViewPurchaseAllow() {
+    Map genericResult = run service: "productCategoryGenericPermission", with: parameters
+    if (genericResult.hasPermission.equals(false)) {
+        Map result = [
+            hasPermission: genericResult.hasPermission,
+            failMessage: genericResult.failMessage
+        ]
+        return result
+    }
+
+    // If the generic permission test passed, carry on
+    boolean hasPermission = true
+
+    // Set up for a call to ckeckCategoryRelatedPermission below, but callingMethodName is needed sooner
+    String resourceDescription = parameters.resourceDescription
+    if (!resourceDescription) {
+        resourceDescription = UtilProperties.getMessage("CommonUiLabels", "CommonPermissionThisOperation", parameters.locale)
+    }
+    String callingMethodName = resourceDescription
+    String checkAction = parameters.mainAction ?: "UPDATE"
+
+    EntityCondition condition = EntityCondition.makeCondition([
+        EntityCondition.makeCondition([
+            EntityCondition.makeCondition("prodCatalogCategoryTypeId", "PCCT_VIEW_ALLW"),
+            EntityCondition.makeCondition("prodCatalogCategoryTypeId", "PCCT_PURCH_ALLW")
+        ], EntityOperator.OR),
+        EntityCondition.makeCondition("productCategoryId", parameters.productCategoryId)
+    ])
+    List prodCatalogCategoryList = from("ProdCatalogCategory").where(condition).filterByDate().queryList()
+    String failMessage = ""
+    for (Map prodCatalogCategory : prodCatalogCategoryList) {
+        // Do not do a permission check, unless the ProdCatalog requires it
+        def prodCatalog = findOne("ProdCatalog", [prodCatalogId: prodCatalogCategory.prodCatalogId], false)
+        if (prodCatalog.viewAllowPermReqd.equals("Y")
+            && !security.hasEntityPermission("CATALOG_VIEW", "_ALLOW", parameters.userLogin)) {
+            logVerbose("Permission check failed, user does not have permission")
+            failMessage = UtilProperties.getMessage("CommonUiLabels", "CommmonCallingMethodPermissionError", [callingMethodName, "CATALOG_VIEW_ALLOW"], parameters.locale)
+            hasPermission = false
+        }
+        if (prodCatalog.purchaseAllowPermReqd.equals("Y")
+            && !security.hasEntityPermission("CATALOG_PURCHASE", "_ALLOW", parameters.userLogin)) {
+            logVerbose("Permission check failed, user does not have permission")
+            failMessage = UtilProperties.getMessage("CommonUiLabels", "CommonCallingMethodPermissionError", [callingMethodName, "CATALOG_PURCHASE_ALLOW"], parameters.locale)
+            hasPermission = false
+        }
+    }
+
+    Map result = success()
+    result.failMessage = failMessage
+    result.hasPermission = hasPermission
+    return result
+}
+
+// To help dynamically populate a products dropdown given a product category id from a change in another dropdown, possibly sorted on sequenceNum
+/**
+ * Set the product options for selected product category, mostly used by getDependentDropdownValues
+ */
+def getAssociatedProductsList() {
+    parameters.categoryId = parameters.productCategoryId
+    Map getProductCategoryMembersMap = dispatcher.dispatchContext.makeValidContext("getProductCategoryMembers", ModelService.IN_PARAM, parameters)
+    Map res = run service: "getProductCategoryMembers", with: getProductCategoryMembersMap
+    List productsList = res.categoryMembers
+    productsList = EntityUtil.orderBy(productsList, ["sequenceNum"])
+    List products = []
+    for (Map productMember : productsList) {
+        GenericValue product = findOne("Product", [productId: productMember.productId], false)
+        String productName = "${product.internalName}: ${product.productId}"
+        products.add(productName)
+    }
+    if (!products) {
+        products.add(UtilProperties.getMessage("ProductUiLabels", "ProductNoProducts", parameters.locale))
+    }
+    Map result = success()
+    result.products = products
+    return result
+}
\ No newline at end of file

Propchange: ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/CategoryServices.groovy
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/CategoryServices.groovy
------------------------------------------------------------------------------
    svn:keywords = Date Rev Author URL Id

Propchange: ofbiz/ofbiz-framework/trunk/applications/product/groovyScripts/product/category/CategoryServices.groovy
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: ofbiz/ofbiz-framework/trunk/applications/product/minilang/product/category/CategoryServices.xml
URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/applications/product/minilang/product/category/CategoryServices.xml?rev=1822912&r1=1822911&r2=1822912&view=diff
==============================================================================
--- ofbiz/ofbiz-framework/trunk/applications/product/minilang/product/category/CategoryServices.xml (original)
+++ ofbiz/ofbiz-framework/trunk/applications/product/minilang/product/category/CategoryServices.xml Thu Feb  1 22:33:59 2018
@@ -20,628 +20,6 @@ under the License.
 
 <simple-methods xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://ofbiz.apache.org/Simple-Method" xsi:schemaLocation="http://ofbiz.apache.org/Simple-Method http://ofbiz.apache.org/dtds/simple-methods.xsd">
-
-    <!-- ================================================================ -->
-    <!-- ProductCategory Services -->
-    <!-- ================================================================ -->
-
-    <simple-method method-name="createProductCategory" short-description="Create an ProductCategory">
-        <check-permission permission="CATALOG" action="_CREATE">
-            <alt-permission permission="CATALOG_ROLE" action="_CREATE"/>
-            <fail-property resource="ProductUiLabels" property="ProductCatalogCreatePermissionError"/>
-        </check-permission>
-        <check-errors/>
-
-        <now-timestamp field="nowTimestamp"/>
-        <make-value entity-name="ProductCategory" value-field="newEntity"/>
-        <set-nonpk-fields map="parameters" value-field="newEntity"/>
-
-        <if-empty field="parameters.productCategoryId">
-            <sequenced-id sequence-name="ProductCategory" field="newEntity.productCategoryId"/>
-        <else>
-            <set field="newEntity.productCategoryId" from-field="parameters.productCategoryId"/>
-            <check-id field="newEntity.productCategoryId"/>
-            <check-errors/>
-        </else>
-        </if-empty>
-        <field-to-result field="newEntity.productCategoryId" result-name="productCategoryId"/>
-
-        <create-value value-field="newEntity"/>
-
-        <!-- if setting the primaryParentCategoryId, create a rollup entity too -->
-        <!-- NOTE: this is commented out to disable because it is dangerous to add category rollups on a live site without being able to specify a fromDate
-        <if-not-empty field="newEntity.primaryParentCategoryId">
-            <make-value entity-name="ProductCategoryRollup" value-field="newRollup"/>
-            <field-to-field field-name="productCategoryId" map-name="newEntity" to-field-name="productCategoryId" to-map-name="newRollup"/>
-            <field-to-field field-name="primaryParentCategoryId" map-name="newEntity" to-field-name="parentProductCategoryId" to-map-name="newRollup"/>
-            <env-to-field env-name="nowTimestamp" field-name="fromDate" map-name="newRollup"/>
-            <create-value value-field="newRollup"/>
-        </if-not-empty>
-        -->
-
-        <!-- if the user has the role limited position, add this category to the limit category/ies -->
-        <if-has-permission permission="CATALOG_ROLE" action="_CREATE">
-            <entity-and entity-name="ProductCategoryRole" list="productCategoryRoles" filter-by-date="true">
-                <field-map field-name="partyId" from-field="userLogin.partyId"/>
-                <field-map field-name="roleTypeId" value="LTD_ADMIN"/>
-            </entity-and>
-            <iterate list="productCategoryRoles" entry="productCategoryRole">
-                <!-- add this new product to the category -->
-                <make-value entity-name="ProductCategoryRollup" value-field="newLimitRollup"/>
-                <set field="newLimitRollup.productCategoryId" from-field="newEntity.productCategoryId"/>
-                <set field="newLimitRollup.parentProductCategoryId" from-field="productCategoryRole.productCategoryId"/>
-                <set field="newLimitRollup.fromDate" from-field="nowTimestamp"/>
-                <create-value value-field="newLimitRollup"/>
-            </iterate>
-        </if-has-permission>
-    </simple-method>
-    <simple-method method-name="updateProductCategory" short-description="Update an ProductCategory">
-        <set field="callingMethodName" value="updateProductCategory"/>
-        <set field="checkAction" value="UPDATE"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <entity-one entity-name="ProductCategory" value-field="lookedUpValue"/>
-        <!-- save this value before overwriting it so we can compare it later -->
-        <!-- <field-to-field field-name="primaryParentCategoryId" map-name="lookedUpValue" to-map-name="saveIdMap"/> -->
-        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
-        <store-value value-field="lookedUpValue"/>
-
-        <!-- if setting the primaryParentCategoryId, create a rollup entity too -->
-        <!-- NOTE: this is commented out to disable because it is dangerous to add category rollups on a live site without being able to specify a fromDate
-        <if-not-empty field="lookedUpValue.primaryParentCategoryId">
-            <if-compare-field to-field="saveIdMap.primaryParentCategoryId" field="lookedUpValue.primaryParentCategoryId" operator="not-equals">
-                <make-value entity-name="ProductCategoryRollup" value-field="newRollup"/>
-                <field-to-field field-name="productCategoryId" map-name="lookedUpValue" to-field-name="productCategoryId" to-map-name="newRollup"/>
-                <field-to-field field-name="primaryParentCategoryId" map-name="lookedUpValue" to-field-name="parentProductCategoryId" to-map-name="newRollup"/>
-                <now-timestamp field="nowTimestamp"/>
-                <env-to-field env-name="nowTimestamp" field-name="fromDate" map-name="newRollup"/>
-                <create-value value-field="newRollup"/>
-            </if-compare-field>
-        </if-not-empty>
-        -->
-    </simple-method>
-
-    <!-- ================================================================ -->
-    <!-- ProductCategoryMember Services -->
-    <!-- ================================================================ -->
-
-    <simple-method method-name="addProductToCategories" short-description="Add Product to Multiple Categories">
-        <set-service-fields service-name="addProductToCategory" map="parameters" to-map="addProductToCategoryMap"/>
-        <if-instance-of field="parameters.categories" class="java.util.List">
-            <iterate list="parameters.categories" entry="category">
-                <set field="addProductToCategoryMap.productCategoryId" from-field="category"/>
-                <call-service service-name="addProductToCategory" in-map-name="addProductToCategoryMap"/>
-            </iterate>
-            <else>
-                <!-- note that the security semantics require the user to have the general admin permission,
-                    or the role limited permission and association with the category, not the product -->
-                <set from-field="parameters.categories" field="productCategoryIdToCheck"/>
-                <set field="callingMethodName" value="addProductToCategories"/>
-                <set field="checkAction" value="CREATE"/>
-                <call-simple-method method-name="checkCategoryRelatedPermission"/>
-                <check-errors/>
-
-                <set field="addProductToCategoryMap.productCategoryId" from-field="productCategoryIdToCheck"/>
-                <call-service service-name="addProductToCategory" in-map-name="addProductToCategoryMap"/>
-            </else>
-        </if-instance-of>
-    </simple-method>
-
-    <simple-method method-name="removeProductFromCategory" short-description="Remove Product From Category">
-        <!-- note that the security semantics require the user to have the general admin permission,
-            or the role limited permission and association with the category, not the product -->
-        <!--
-        <set value="removeProductFromCategory" field="callingMethodName"/>
-        <set value="DELETE" field="checkAction"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-         -->
-
-        <!-- If the associated category was the primary category for the product, clear that field -->
-        <entity-one entity-name="Product" value-field="product" auto-field-map="true"/>
-        <if-compare-field field="product.primaryProductCategoryId" to-field="parameters.productCategoryId" operator="equals">
-            <clear-field field="product.primaryProductCategoryId"/>
-            <store-value value-field="product"/>
-        </if-compare-field>
-
-        <make-value entity-name="ProductCategoryMember" value-field="lookupPKMap"/>
-        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
-        <find-by-primary-key entity-name="ProductCategoryMember" map="lookupPKMap" value-field="lookedUpValue"/>
-        <remove-value value-field="lookedUpValue"/>
-    </simple-method>
-
-    <!-- ================================================================ -->
-    <!-- ProductCategoryRole Services -->
-    <!-- ================================================================ -->
-
-    <simple-method method-name="addPartyToCategory" short-description="Add Party to Category">
-        <set value="addPartyToCategory" field="callingMethodName"/>
-        <set value="CREATE" field="checkAction"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryRole" value-field="newEntity"/>
-        <set-pk-fields map="parameters" value-field="newEntity"/>
-        <set-nonpk-fields map="parameters" value-field="newEntity"/>
-
-        <if-empty field="newEntity.fromDate">
-            <now-timestamp field="newEntity.fromDate"/>
-        </if-empty>
-
-        <create-value value-field="newEntity"/>
-    </simple-method>
-    <simple-method method-name="updatePartyToCategory" short-description="Update Party to Category Application">
-        <set value="updatePartyToCategory" field="callingMethodName"/>
-        <set value="UPDATE" field="checkAction"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryRole" value-field="lookupPKMap"/>
-        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
-        <find-by-primary-key entity-name="ProductCategoryRole" map="lookupPKMap" value-field="lookedUpValue"/>
-        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
-        <store-value value-field="lookedUpValue"/>
-    </simple-method>
-    <simple-method method-name="removePartyFromCategory" short-description="Remove Party From Category">
-        <set value="removePartyFromCategory" field="callingMethodName"/>
-        <set value="DELETE" field="checkAction"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryRole" value-field="lookupPKMap"/>
-        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
-        <find-by-primary-key entity-name="ProductCategoryRole" map="lookupPKMap" value-field="lookedUpValue"/>
-        <remove-value value-field="lookedUpValue"/>
-    </simple-method>
-
-    <!-- ================================================================ -->
-    <!-- ProductCategoryRollup Services -->
-    <!-- ================================================================ -->
-
-    <simple-method method-name="addProductCategoryToCategory" short-description="Add ProductCategory to Category">
-        <set value="addProductCategoryToCategory" field="callingMethodName"/>
-        <set value="CREATE" field="checkAction"/>
-        <!-- note the the user must be associated with the parent category with the role limited permission -->
-        <set value="parentProductCategoryId" field="productCategoryIdName"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryRollup" value-field="newEntity"/>
-        <set-pk-fields map="parameters" value-field="newEntity"/>
-        <set-nonpk-fields map="parameters" value-field="newEntity"/>
-
-        <if-empty field="newEntity.fromDate">
-            <now-timestamp field="newEntity.fromDate"/>
-        </if-empty>
-
-        <create-value value-field="newEntity"/>
-    </simple-method>
-    <simple-method method-name="addProductCategoryToCategories" short-description="Add ProductCategory to Categories">
-        <if-instance-of field="parameters.categories" class="java.util.List">
-            <iterate list="parameters.categories" entry="category">
-                <set field="callingMethodName" value="addProductCategoryToCategories"/>
-                <set field="checkAction" value="CREATE"/>
-                <!-- note the the user must be associated with the parent category with the role limited permission -->
-                <set field="productCategoryIdToCheck" from-field="category"/>
-                <call-simple-method method-name="checkCategoryRelatedPermission"/>
-                <check-errors/>
-
-                <make-value entity-name="ProductCategoryRollup" value-field="newEntity"/>
-                <set field="newEntity.parentProductCategoryId" from-field="category"/>
-                <set-pk-fields map="parameters" value-field="newEntity"/>
-                <set-nonpk-fields map="parameters" value-field="newEntity"/>
-
-                <if-empty field="newEntity.fromDate">
-                    <now-timestamp field="newEntity.fromDate"/>
-                </if-empty>
-
-                <create-value value-field="newEntity"/>
-            </iterate>
-            <else>
-                <set value="addProductCategoryToCategories" field="callingMethodName"/>
-                <set value="CREATE" field="checkAction"/>
-                <!-- note the the user must be associated with the parent category with the role limited permission -->
-                <set field="productCategoryIdToCheck" from-field="parameters.categories"/>
-                <call-simple-method method-name="checkCategoryRelatedPermission"/>
-                <check-errors/>
-
-                <make-value entity-name="ProductCategoryRollup" value-field="newEntity"/>
-                <set field="newEntity.parentProductCategoryId" from-field="parameters.categories"/>
-                <set-pk-fields map="parameters" value-field="newEntity"/>
-                <set-nonpk-fields map="parameters" value-field="newEntity"/>
-
-                <if-empty field="newEntity.fromDate">
-                    <now-timestamp field="newEntity.fromDate"/>
-                </if-empty>
-
-                <create-value value-field="newEntity"/>
-            </else>
-        </if-instance-of>
-    </simple-method>
-    <simple-method method-name="updateProductCategoryToCategory" short-description="Update ProductCategory to Category Application">
-        <set value="updateProductCategoryToCategory" field="callingMethodName"/>
-        <set value="UPDATE" field="checkAction"/>
-        <!-- note the the user must be associated with the parent category with the role limited permission -->
-        <set value="parentProductCategoryId" field="productCategoryIdName"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryRollup" value-field="lookupPKMap"/>
-        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
-        <find-by-primary-key entity-name="ProductCategoryRollup" map="lookupPKMap" value-field="lookedUpValue"/>
-        <set-nonpk-fields map="parameters" value-field="lookedUpValue"/>
-        <store-value value-field="lookedUpValue"/>
-        <field-to-result field="parameters.productCategoryId" result-name="productCategoryId"/>
-    </simple-method>
-    <simple-method method-name="removeProductCategoryFromCategory" short-description="Remove ProductCategory From Category">
-        <set value="removeProductCategoryFromCategory" field="callingMethodName"/>
-        <set value="DELETE" field="checkAction"/>
-        <!-- note the the user must be associated with the parent category with the role limited permission -->
-        <set value="parentProductCategoryId" field="productCategoryIdName"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryRollup" value-field="lookupPKMap"/>
-        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
-        <find-by-primary-key entity-name="ProductCategoryRollup" map="lookupPKMap" value-field="lookedUpValue"/>
-        <remove-value value-field="lookedUpValue"/>
-    </simple-method>
-
-    <!-- ================================================================ -->
-    <!-- Special Category Function Services -->
-    <!-- ================================================================ -->
-
-    <simple-method method-name="copyCategoryProductMembers" short-description="copy CategoryProduct Members to a CategoryProductTo">
-        <set value="copyCategoryProductMembers" field="callingMethodName"/>
-        <set value="CREATE" field="checkAction"/>
-        <!-- note the the user must be associated with the target category with the role limited permission -->
-        <set value="productCategoryIdTo" field="productCategoryIdName"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <entity-and entity-name="ProductCategoryMember" list="productCategoryMembers">
-            <field-map field-name="productCategoryId" from-field="parameters.productCategoryId"/>
-        </entity-and>
-
-        <set field="validDate" from-field="parameters.validDate"/>
-        <if-not-empty field="validDate">
-            <filter-list-by-date list="productCategoryMembers" valid-date="validDate"/>
-        </if-not-empty>
-
-        <!-- add each to a list to store and then store all and let the entity engine do inserts or updates as needed; much more reliable/useful -->
-        <iterate list="productCategoryMembers" entry="productCategoryMember">
-            <clone-value value-field="productCategoryMember" new-value-field="newProductCategoryMember"/>
-            <set field="newProductCategoryMember.productCategoryId" from-field="parameters.productCategoryIdTo"/>
-            <field-to-list field="newProductCategoryMember" list="pcmsToStore"/>
-        </iterate>
-        <store-list list="pcmsToStore"/>
-
-        <if-compare field="parameters.recurse" operator="equals" value="Y">
-            <!-- call this service for each sub-category in the rollup with the same productCategoryIdTo -->
-            <set field="lookupChildrenMap.parentProductCategoryId" from-field="parameters.productCategoryId"/>
-            <find-by-and entity-name="ProductCategoryRollup" map="lookupChildrenMap" list="productCategoryRollups"/>
-
-            <if-not-empty field="validDate">
-                <filter-list-by-date list="productCategoryRollups" valid-date="validDate"/>
-            </if-not-empty>
-
-            <iterate list="productCategoryRollups" entry="productCategoryRollup">
-                <set field="callServiceMap.productCategoryId" from-field="productCategoryRollup.productCategoryId"/>
-                <set field="callServiceMap.productCategoryIdTo" from-field="parameters.productCategoryIdTo"/>
-                <set field="callServiceMap.validDate" from-field="parameters.validDate"/>
-                <set field="callServiceMap.recurse" from-field="parameters.recurse"/>
-                <call-service service-name="copyCategoryProductMembers" in-map-name="callServiceMap"/>
-            </iterate>
-        </if-compare>
-    </simple-method>
-
-    <simple-method method-name="duplicateCategoryEntities" short-description="a service wrapper for copyCategoryEntities">
-        <set value="duplicateCategoryEntities" field="callingMethodName"/>
-        <check-permission permission="CATALOG" action="_CREATE">
-            <alt-permission permission="CATALOG_ROLE" action="_CREATE"/>
-            <fail-property resource="ProductUiLabels" property="ProductCatalogCreatePermissionError"/>
-        </check-permission>
-        <check-errors/>
-
-        <set field="entityName" from-field="parameters.entityName"/>
-        <set field="productCategoryId" from-field="parameters.productCategoryId"/>
-        <set field="productCategoryIdTo" from-field="parameters.productCategoryIdTo"/>
-        <set field="validDate" from-field="parameters.validDate"/>
-        <call-simple-method method-name="copyCategoryEntities"/>
-    </simple-method>
-
-    <simple-method method-name="copyCategoryEntities" short-description="copies all entities of entityName with a productCategoryId to a new entity with a productCategoryIdTo,
-            filtering them by a timestamp passed in to validDate if necessary">
-        <entity-and entity-name="${entityName}" list="categoryEntities">
-            <field-map field-name="productCategoryId" from-field="productCategoryId"/>
-        </entity-and>
-
-        <if-not-empty field="validDate">
-            <filter-list-by-date list="categoryEntities" valid-date="validDate"/>
-        </if-not-empty>
-
-        <!-- add each to a list to store and then store all and let the entity engine do inserts or updates as needed; much more reliable/useful -->
-        <iterate list="categoryEntities" entry="categoryEntity">
-            <clone-value value-field="categoryEntity" new-value-field="newCategoryEntity"/>
-            <set field="newCategoryEntity.productCategoryId" from-field="productCategoryIdTo"/>
-            <field-to-list field="newCategoryEntity" list="entitiesToStore"/>
-        </iterate>
-        <store-list list="entitiesToStore"/>
-      </simple-method>
-
-    <simple-method method-name="expireAllCategoryProductMembers" short-description="Remove ProductCategory From Category">
-        <set value="expireAllCategoryProductMembers" field="callingMethodName"/>
-        <set value="UPDATE" field="checkAction"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <if-not-empty field="parameters.thruDate">
-            <set field="expireTimestamp" from-field="parameters.thruDate"/>
-            <else>
-                <now-timestamp field="expireTimestamp"/>
-            </else>
-        </if-not-empty>
-
-        <entity-and entity-name="ProductCategoryMember" list="productCategoryMembers">
-            <field-map field-name="productCategoryId" from-field="parameters.productCategoryId"/>
-        </entity-and>
-
-        <iterate list="productCategoryMembers" entry="productCategoryMember">
-            <set field="productCategoryMember.thruDate" from-field="expireTimestamp"/>
-            <store-value value-field="productCategoryMember"/>
-        </iterate>
-    </simple-method>
-    <simple-method method-name="removeExpiredCategoryProductMembers" short-description="Remove ProductCategory From Category">
-        <set value="removeExpiredCategoryProductMembers" field="callingMethodName"/>
-        <set value="DELETE" field="checkAction"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <if-not-empty field="parameters.validDate">
-            <set field="expireTimestamp" from-field="parameters.validDate"/>
-            <else>
-                <now-timestamp field="expireTimestamp"/>
-            </else>
-        </if-not-empty>
-
-        <entity-and entity-name="ProductCategoryMember" list="productCategoryMembers">
-            <field-map field-name="productCategoryId" from-field="parameters.productCategoryId"/>
-        </entity-and>
-
-        <iterate list="productCategoryMembers" entry="productCategoryMember">
-            <if-compare-field field="productCategoryMember.thruDate" to-field="expireTimestamp" operator="less" type="Timestamp">
-                <remove-value value-field="productCategoryMember"/>
-            </if-compare-field>
-        </iterate>
-    </simple-method>
-
-    <!-- ================================================================ -->
-    <!-- Special Category Related Create Services -->
-    <!-- ================================================================ -->
-    <simple-method method-name="createProductInCategory" short-description="Create a Product in a Category along with special information such as features">
-        <set value="createProductInCategory" field="callingMethodName"/>
-        <set value="CREATE" field="checkAction"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-        <check-errors/>
-
-        <if-empty field="parameters.currencyUomId">
-            <!-- default to USD for lack of a better alternative, for now anyway... -->
-            <set field="parameters.currencyUomId" value="USD"/>
-        </if-empty>
-
-        <!-- create Product -->
-        <set-service-fields service-name="createProduct" map="parameters" to-map="callCreateProductMap"/>
-        <if-empty field="callCreateProductMap.productTypeId">
-            <set field="callCreateProductMap.productTypeId" value="FINISHED_GOOD"/>
-        </if-empty>
-        <call-service service-name="createProduct" in-map-name="callCreateProductMap">
-            <result-to-field result-name="productId"/>
-        </call-service>
-        <field-to-result field="productId"/>
-
-        <!-- create ProductCategoryMember -->
-        <set field="callCreateProductCategoryMemberMap.productId" from-field="productId"/>
-        <set field="callCreateProductCategoryMemberMap.productCategoryId" from-field="parameters.productCategoryId"/>
-        <call-service service-name="addProductToCategory" in-map-name="callCreateProductCategoryMemberMap"/>
-
-        <!-- create defaultPrice and averageCost ProductPrice -->
-        <if-not-empty field="parameters.defaultPrice">
-            <set field="createDefaultPriceMap.productId" from-field="productId"/>
-            <set field="createDefaultPriceMap.currencyUomId" from-field="parameters.currencyUomId"/>
-            <set field="createDefaultPriceMap.price" from-field="parameters.defaultPrice"/>
-            <set field="createDefaultPriceMap.productStoreGroupId" value="_NA_"/>
-            <set field="createDefaultPriceMap.productPriceTypeId" value="DEFAULT_PRICE"/>
-            <set field="createDefaultPriceMap.productPricePurposeId" value="PURCHASE"/>
-            <call-service service-name="createProductPrice" in-map-name="createDefaultPriceMap"/>
-        </if-not-empty>
-
-        <if-not-empty field="parameters.averageCost">
-            <set field="createAverageCostMap.productId" from-field="productId"/>
-            <set field="createAverageCostMap.currencyUomId" from-field="parameters.currencyUomId"/>
-            <set field="createAverageCostMap.price" from-field="parameters.averageCost"/>
-            <set field="createAverageCostMap.productStoreGroupId" value="_NA_"/>
-            <set field="createAverageCostMap.productPriceTypeId" value="AVERAGE_COST"/>
-            <set field="createAverageCostMap.productPricePurposeId" value="PURCHASE"/>
-            <call-service service-name="createProductPrice" in-map-name="createAverageCostMap"/>
-        </if-not-empty>
-
-        <!-- create ProductFeatureAppl(s) -->
-        <set field="hasSelectableFeatures" value="N"/>
-        <iterate-map map="parameters.productFeatureIdByType" key="productFeatureTypeId" value="productFeatureId">
-            <log level="info" message="Applying feature [${productFeatureId}] of type [${productFeatureTypeId}] to product [${productId}]"/>
-            <set field="createPfaMap.productId" from-field="productId"/>
-            <set field="createPfaMap.productFeatureId" from-field="productFeatureId"/>
-            <if-compare field="parameters.productFeatureSelectableByType[productFeatureTypeId]" operator="equals" value="Y">
-                <set field="createPfaMap.productFeatureApplTypeId" value="SELECTABLE_FEATURE"/>
-                <set field="hasSelectableFeatures" value="Y"/>
-            <else>
-                <set field="createPfaMap.productFeatureApplTypeId" value="STANDARD_FEATURE"/>
-            </else>
-            </if-compare>
-            <call-service service-name="applyFeatureToProduct" in-map-name="createPfaMap"/>
-            <clear-field field="createPfaMap"/>
-        </iterate-map>
-
-        <!-- set isVirtual based on hasSelectableFeatures -->
-        <if-compare field="hasSelectableFeatures" operator="equals" value="Y">
-            <entity-one entity-name="Product" value-field="newProduct"/>
-            <set field="newProduct.isVirtual" value="Y"/>
-            <store-value value-field="newProduct"/>
-        </if-compare>
-    </simple-method>
-
-    <simple-method method-name="duplicateProductCategory" short-description="Duplicate a ProductCategory">
-        <set value="duplicateProductCategory" field="callingMethodName"/>
-        <check-permission permission="CATALOG" action="_CREATE">
-            <alt-permission permission="CATALOG_ROLE" action="_CREATE"/>
-            <fail-property resource="ProductUiLabels" property="ProductCatalogCreatePermissionError"/>
-        </check-permission>
-        <check-errors/>
-
-        <!-- look up the old product category and clone it -->
-        <entity-one entity-name="ProductCategory" value-field="oldCategory">
-            <field-map field-name="productCategoryId" from-field="parameters.oldProductCategoryId"/>
-        </entity-one>
-        <clone-value value-field="oldCategory" new-value-field="newCategory"/>
-
-        <!-- set the new product category id, and write it to the datasource -->
-        <set field="newCategory.productCategoryId" from-field="parameters.productCategoryId"/>
-        <create-value value-field="newCategory"/>
-        <set field="productCategoryId" from-field="parameters.oldProductCategoryId"/>
-        <set field="productCategoryIdTo" from-field="parameters.productCategoryId"/>
-
-        <!-- if requested, duplicate related data as well -->
-        <if-not-empty field="parameters.duplicateMembers">
-            <set field="entityName" value="ProductCategoryMember"/>
-            <call-simple-method method-name="copyCategoryEntities"/>
-        </if-not-empty>
-        <if-not-empty field="parameters.duplicateContent">
-            <set field="entityName" value="ProductCategoryContent"/>
-            <call-simple-method method-name="copyCategoryEntities"/>
-        </if-not-empty>
-        <if-not-empty field="parameters.duplicateRoles">
-            <set field="entityName" value="ProductCategoryRole"/>
-            <call-simple-method method-name="copyCategoryEntities"/>
-        </if-not-empty>
-        <if-not-empty field="parameters.duplicateAttributes">
-            <set field="entityName" value="ProductCategoryAttribute"/>
-            <call-simple-method method-name="copyCategoryEntities"/>
-        </if-not-empty>
-        <if-not-empty field="parameters.duplicateFeatureCategories">
-            <set field="entityName" value="ProductFeatureCategoryAppl"/>
-            <call-simple-method method-name="copyCategoryEntities"/>
-        </if-not-empty>
-        <if-not-empty field="parameters.duplicateFeatureGroups">
-            <set field="entityName" value="ProductFeatureCatGrpAppl"/>
-            <call-simple-method method-name="copyCategoryEntities"/>
-        </if-not-empty>
-        <if-not-empty field="parameters.duplicateCatalogs">
-            <set field="entityName" value="ProdCatalogCategory"/>
-            <call-simple-method method-name="copyCategoryEntities"/>
-        </if-not-empty>
-
-          <!-- parent rollups are where oldProductCategoryId = ProductCategoryRollup.productCategoryId, but the
-            child roll up is where oldProductCategoryId = ProductCategoryRollup.parentProductCategoryId and hence
-            requires a new find-by map -->
-        <if-not-empty field="parameters.duplicateParentRollup">
-            <entity-and entity-name="ProductCategoryRollup" list="foundValues">
-                <field-map field-name="productCategoryId" from-field="parameters.oldProductCategoryId"/>
-            </entity-and>
-            <iterate list="foundValues" entry="foundValue">
-                <clone-value value-field="foundValue" new-value-field="newTempValue"/>
-                <set field="newTempValue.productCategoryId" from-field="parameters.productCategoryId"/>
-                <create-value value-field="newTempValue"/>
-            </iterate>
-        </if-not-empty>
-        <if-not-empty field="parameters.duplicateChildRollup">
-            <entity-and entity-name="ProductCategoryRollup" list="foundValues">
-                <field-map field-name="parentProductCategoryId" from-field="parameters.oldProductCategoryId"/>
-            </entity-and>
-            <iterate list="foundValues" entry="foundValue">
-                <clone-value value-field="foundValue" new-value-field="newTempValue"/>
-                <set field="newTempValue.parentProductCategoryId" from-field="parameters.productCategoryId"/>
-                <create-value value-field="newTempValue"/>
-            </iterate>
-        </if-not-empty>
-    </simple-method>
-
-    <!-- ================================================================ -->
-    <!-- Product Category Attribute Services -->
-    <!-- ================================================================ -->
-
-    <simple-method method-name="createProductCategoryAttribute"
-        short-description="Create an attribute for a product category">
-        <check-permission permission="CATALOG" action="_CREATE">
-            <fail-property resource="ProductUiLabels" property="ProductCatalogCreatePermissionError"/>
-        </check-permission>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryAttribute" value-field="newEntity"/>
-        <set-nonpk-fields map="parameters" value-field="newEntity"/>
-        <set-pk-fields map="parameters" value-field="newEntity"/>
-
-        <create-value value-field="newEntity"/>
-    </simple-method>
-    <simple-method method-name="updateProductCategoryAttribute"
-        short-description="Update an association between two product categories">
-        <check-permission permission="CATALOG" action="_UPDATE">
-            <fail-property resource="ProductUiLabels" property="ProductCatalogUpdatePermissionError"/>
-        </check-permission>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryAttribute" value-field="lookupPKMap"/>
-        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
-        <find-by-primary-key entity-name="ProductCategoryAttribute" map="lookupPKMap" value-field="ProductCategoryAttributeInstance"/>
-        <set-nonpk-fields map="parameters" value-field="ProductCategoryAttributeInstance"/>
-        <store-value value-field="ProductCategoryAttributeInstance"/>
-    </simple-method>
-    <simple-method method-name="deleteProductCategoryAttribute"
-        short-description="Delete an association between two product categories">
-        <check-permission permission="CATALOG" action="_DELETE">
-            <fail-property resource="ProductUiLabels" property="ProductCatalogDeletePermissionError"/>
-        </check-permission>
-        <check-errors/>
-
-        <make-value entity-name="ProductCategoryAttribute" value-field="lookupPKMap"/>
-        <set-pk-fields map="parameters" value-field="lookupPKMap"/>
-        <find-by-primary-key entity-name="ProductCategoryAttribute" map="lookupPKMap" value-field="ProductCategoryAttributeInstance"/>
-        <remove-value value-field="ProductCategoryAttributeInstance"/>
-    </simple-method>
-
-
-    <!-- ProductCategoryLink Create/Update/Delete"-->
-    <simple-method method-name="createProductCategoryLink" short-description="create a ProductCategoryLink">
-        <make-value entity-name="ProductCategoryLink" value-field="newEntity"/>
-        <set field="newEntity.productCategoryId" from-field="parameters.productCategoryId"/>
-
-        <!-- don't set the fromDate yet; let's get the seq ID first -->
-        <if-empty field="parameters.linkSeqId">
-            <make-next-seq-id value-field="newEntity" seq-field-name="linkSeqId"/> <!-- this finds the next sub-sequence ID -->
-            <set from-field="linkSeqId" field="newEntity.linkSeqId"/>
-        </if-empty>
-
-        <!-- now set the rest of the PK fields (should just be fromDate now; unless linkSeqId is not empty -->
-        <set-pk-fields value-field="newEntity" map="parameters"/>
-        <if-empty field="newEntity.fromDate">
-            <now-timestamp field="newEntity.fromDate"/>
-        </if-empty>
-
-        <set-nonpk-fields map="parameters" value-field="newEntity"/>
-        <create-value value-field="newEntity"/>
-    </simple-method>
-
-    <simple-method method-name="deleteProductCategoryLink" short-description="delete a ProductCategoryLink">
-        <entity-one entity-name="ProductCategoryLink" value-field="lookedUpValue"/>
-        <remove-value value-field="lookedUpValue"/>
-    </simple-method>
-
-    <!-- ============================= -->
-    <!-- Permission Methods -->
-    <!-- ============================= -->
-
-    <!-- a methods to centralize product security code, meant to be called in-line with
-        call-simple-method, and the checkAction and callingMethodName attributes should be in the method context -->
     <simple-method method-name="checkCategoryRelatedPermission" short-description="Check Product Category Related Permission">
         <if-empty field="callingMethodName">
             <property-to-field resource="CommonUiLabels" property="CommonPermissionThisOperation" field="callingMethodName"/>
@@ -692,125 +70,7 @@ under the License.
             </then>
         </if>
     </simple-method>
-    <simple-method method-name="productCategoryGenericPermission" short-description="Main permission logic">
-        <set field="mainAction" from-field="parameters.mainAction"/>
-        <if-empty field="mainAction">
-            <add-error>
-                <fail-property resource="ProductUiLabels" property="ProductMissingMainActionInPermissionService"/>
-            </add-error>
-            <check-errors/>
-        </if-empty>
-
-        <set field="callingMethodName" from-field="parameters.resourceDescription"/>
-        <set field="checkAction" from-field="parameters.mainAction"/>
-        <call-simple-method method-name="checkCategoryRelatedPermission"/>
-
-        <if-empty field="error_list">
-            <set field="hasPermission" type="Boolean" value="true"/>
-            <field-to-result field="hasPermission"/>
-
-            <else>
-                <property-to-field resource="ProductUiLabels" property="ProductPermissionError" field="failMessage"/>
-                <set field="hasPermission" type="Boolean" value="false"/>
-                <field-to-result field="hasPermission"/>
-                <field-to-result field="failMessage"/>
-            </else>
-        </if-empty>
-    </simple-method>
-
-    <!-- a service verion of checkCategoryRelatedPermission, only with purchase/viewAllowPermReqd taken into account -->
-    <simple-method method-name="checkCategoryPermissionWithViewPurchaseAllow" short-description="Check Product Category Permission With View and Purchase Allow">
-        <set-service-fields service-name="productCategoryGenericPermission" map="parameters" to-map="productCategoryGenericPermissionMap"/>
-        <call-service service-name="productCategoryGenericPermission" in-map-name="productCategoryGenericPermissionMap">
-            <results-to-map map-name="genericResult"/>
-        </call-service>
-        <if-compare field="genericResult.hasPermission" operator="equals" value="false" type="Boolean">
-            <field-to-result field="genericResult.hasPermission" result-name="hasPermission"/>
-            <field-to-result field="failMessage.genericResult.failMessage" result-name="genericResult.failMessage"/>
-            <return/>
-        </if-compare>
-
-        <!-- if the generic permission test passed, carry on -->
-        <set field="hasPermission" type="Boolean" value="true"/>
-
-        <!--  Set up for a call to checkCategoryRelatedPermission below, but callingMethodName is needed sooner -->
-        <set field="resourceDescription" from-field="parameters.resourceDescription"/>
-        <if-empty field="resourceDescription">
-            <property-to-field resource="CommonUiLabels" property="CommonPermissionThisOperation" field="resourceDescription"/>
-        </if-empty>
-        <set field="callingMethodName" from-field="resourceDescription"/>
-        <set field="checkAction" from-field="parameters.mainAction" default-value="UPDATE"/>
-
-        <entity-condition entity-name="ProdCatalogCategory" list="prodCatalogCategoryList" filter-by-date="true">
-            <condition-list combine="and">
-                <condition-expr field-name="productCategoryId" from-field="parameters.productCategoryId"/>
-                <condition-list combine="or">
-                    <condition-expr field-name="prodCatalogCategoryTypeId" value="PCCT_VIEW_ALLW"/>
-                    <condition-expr field-name="prodCatalogCategoryTypeId" value="PCCT_PURCH_ALLW"/>
-                </condition-list>
-            </condition-list>
-        </entity-condition>
-        <iterate list="prodCatalogCategoryList" entry="prodCatalogCategory">
-            <!-- Do not do a permission check unless the ProdCatalog requires it -->
-            <entity-one entity-name="ProdCatalog" value-field="prodCatalog" auto-field-map="false">
-                <field-map field-name="prodCatalogId" from-field="prodCatalogCategory.prodCatalogId"/>
-            </entity-one>
-            <if>
-                <condition>
-                    <and>
-                        <if-compare field="prodCatalog.viewAllowPermReqd" operator="equals" value="Y"/>
-                        <not><if-has-permission permission="CATALOG_VIEW_ALLOW"/></not>
-                    </and>
-                </condition>
-                <then>
-                    <log level="verbose" message="Permission check failed, user does not have permission"/>
-                    <set field="failMessage" value="Security Error: to run ${callingMethodName} you must have the CATALOG_VIEW_ALLOW permission."/>
-                    <set field="hasPermission" type="Boolean" value="false"/>
-                </then>
-            </if>
-            <if>
-                <condition>
-                    <and>
-                        <if-compare field="prodCatalog.purchaseAllowPermReqd" operator="equals" value="Y"/>
-                        <not><if-has-permission permission="CATALOG_PURCHASE_ALLOW"/></not>
-                    </and>
-                </condition>
-                <then>
-                    <log level="verbose" message="Permission check failed, user does not have permission"/>
-                    <set field="failMessage" value="Security Error: to run ${callingMethodName} you must have the CATALOG_PURCHASE_ALLOW permission."/>
-                    <set field="hasPermission" type="Boolean" value="false"/>
-                </then>
-            </if>
-        </iterate>
-
-        <field-to-result field="hasPermission"/>
-        <field-to-result field="failMessage"/>
-    </simple-method>
 
-    <!-- To help dynamically populate a products dropdown given a product category id from a change in another dropdown, possibly sorted on sequenceNum -->    
-    <simple-method method-name="getAssociatedProductsList" short-description="Set the product options for selected product category, mostly used by getDependentDropdownValues" login-required="false">
-        <set field="parameters.categoryId" from-field="parameters.productCategoryId"/>
-        <set-service-fields service-name="getProductCategoryMembers" map="parameters" to-map="getProductCategoryMembersMap"/>        
-        <call-service service-name="getProductCategoryMembers" in-map-name="getProductCategoryMembersMap">
-            <result-to-field result-name="categoryMembers" field="productsList"/>
-        </call-service>
-        <order-map-list list="productsList">
-            <order-by field-name="sequenceNum"/>
-        </order-map-list>
-        <iterate list="productsList" entry="productMember">
-            <entity-one entity-name="Product" value-field="product">
-                <field-map field-name="productId" from-field="productMember.productId"/>
-            </entity-one>
-            <set field="productName" value="${product.internalName}: ${product.productId}"/>
-            <field-to-list list="products" field="productName"/>
-        </iterate>
-        <if-empty field="products">
-            <property-to-field resource="ProductUiLabels" property="ProductNoProducts" field="noOption"/>
-            <field-to-list list="products" field="noOption"/>
-        </if-empty>
-        <field-to-result field="products"/>
-    </simple-method>
-    
     <!-- Load data of best selling category -->
     <simple-method method-name="loadBestSellingCategory" short-description="Load data of best selling category by week.">
         <now-date-to-env field="nowDate"/>
@@ -840,7 +100,7 @@ under the License.
             </if-compare>
         </else>
         </if-compare>
-        
+
         <entity-and entity-name="ProductStoreCatalog" list="productStoreCatalogs" filter-by-date="true">
             <field-map field-name="productStoreId" from-field="parameters.productStoreId"/>
         </entity-and>
@@ -848,7 +108,7 @@ under the License.
             <first-from-list list="productStoreCatalogs" entry="productStoreCatalog"/>
             <set field="callRemoveProductMap.prodCatalogId" from-field="productStoreCatalog.prodCatalogId"/>
             <call-service service-name="RemoveProductFromBestSellCategory" in-map-name="callRemoveProductMap"/>
-            
+
             <set field="callAddProductMap.productStoreId" from-field="parameters.productStoreId"/>
             <set field="callAddProductMap.prodCatalogId" from-field="productStoreCatalog.prodCatalogId"/>
             <set field="callAddProductMap.week" from-field="week" type="Long"/>
@@ -856,7 +116,7 @@ under the License.
             <call-service service-name="AddProductToBestSellCategory" in-map-name="callAddProductMap"/>
         </if-not-empty>
     </simple-method>
-    
+
     <simple-method method-name="RemoveProductFromBestSellCategory" short-description="Remove products from best selling category.">
         <entity-and entity-name="ProdCatalogCategory" list="prodCatalogCategorys">
             <field-map field-name="prodCatalogId" from-field="parameters.prodCatalogId"/>
@@ -876,7 +136,7 @@ under the License.
             </iterate>
         </iterate>
     </simple-method>
-    
+
     <simple-method method-name="AddProductToBestSellCategory" short-description="Add products to best selling category.">
         <entity-and entity-name="ProdCatalogCategory" list="prodCatalogCategorys">
             <field-map field-name="prodCatalogId" from-field="parameters.prodCatalogId"/>
@@ -893,7 +153,7 @@ under the License.
             <call-service service-name="FindCategoryChild" in-map-name="CategoryChildMap"/>
         </iterate>
     </simple-method>
-    
+
     <simple-method method-name="FindCategoryChild" short-description="Find category child.">
         <entity-and entity-name="ProductCategoryRollup" list="productCategoryRollupList">
             <field-map field-name="parentProductCategoryId" from-field="parameters.productCategoryId"/>
@@ -911,7 +171,7 @@ under the License.
         </else>
         </if-empty>
     </simple-method>
-    
+
     <simple-method method-name="FindBestSellingProduct" short-description="Find best selling product.">
         <now-timestamp field="nowTimestamp"/>
         <entity-and entity-name="ProductCategoryMember" list="productCategoryMembers" filter-by-date="true">