Michael, I have lot of improvement to share with your commit (groovy
syntax, code simplification) Do you prefer keep the hand, or I commit directly ? You can find some diff on my starting work hereĀ [1] Cheers, Nicolas [1] https://github.com/nmalin/ApacheOFBiz/compare/ProductService.groovy?expand=1 On 21/02/2020 17:51, [hidden email] wrote: > This is an automated email from the ASF dual-hosted git repository. > > mbrohl pushed a commit to branch trunk > in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git > > > The following commit(s) were added to refs/heads/trunk by this push: > new e0a26fc Improved: Convert ProductServices.xml mini lang to groovy (OFBIZ-10231) > e0a26fc is described below > > commit e0a26fce43eec7c84d87c0d5055ff0a87f2af796 > Author: Michael Brohl <[hidden email]> > AuthorDate: Fri Feb 21 16:59:37 2020 +0100 > > Improved: Convert ProductServices.xml mini lang to groovy > (OFBIZ-10231) > > Thanks Dennis Balkir for reporting and Sebastian Berg for the implementation. > --- > .../product/product/ProductServices.groovy | 1095 ++++++++++++++++++++ > .../minilang/product/product/ProductServices.xml | 1051 ------------------- > applications/product/servicedef/services.xml | 112 +- > 3 files changed, 1151 insertions(+), 1107 deletions(-) > > diff --git a/applications/product/groovyScripts/product/product/ProductServices.groovy b/applications/product/groovyScripts/product/product/ProductServices.groovy > new file mode 100644 > index 0000000..b4be894 > --- /dev/null > +++ b/applications/product/groovyScripts/product/product/ProductServices.groovy > @@ -0,0 +1,1095 @@ > +/* > + * 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 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.serialize.XmlSerializer > +import org.apache.ofbiz.entity.util.EntityUtil > +import org.apache.ofbiz.product.product.KeywordIndex > +import org.apache.ofbiz.product.product.ProductWorker > +import org.apache.ofbiz.service.ServiceUtil > + > + > + > + module = "ProductServices.groovy" // this is used for logging > + > + /** > + * Create a Product > + */ > + def createProduct() { > + Map result = success() > + if (!(security.hasEntityPermission("CATALOG", "_CREATE", parameters.userLogin) > + || security.hasEntityPermission("CATALOG_ROLE", "_CREATE", parameters.userLogin))) { > + return error(UtilProperties.getMessage("ProductUiLabels", "ProductCatalogCreatePermissionError", parameters.locale)) > + } > + > + GenericValue newEntity = makeValue("Product") > + newEntity.setNonPKFields(parameters) > + > + newEntity.productId = parameters.productId > + > + if (UtilValidate.isEmpty(newEntity.productId)) { > + newEntity.productId = delegator.getNextSeqId("Product") > + } else { > + String errorMessage = UtilValidate.checkValidDatabaseId(newEntity.productId) > + if(errorMessage != null) { > + logError(errorMessage) > + return error(errorMessage) > + } > + GenericValue dummyProduct = findOne("Product", ["productId": parameters.productId], false) > + if (UtilValidate.isNotEmpty(dummyProduct)) { > + errorMessage = UtilProperties.getMessage("CommonErrorUiLabels", CommonErrorDuplicateKey, parameters.locale) > + logError(errorMessage) > + return error(errorMessage) > + } > + } > + result.productId = newEntity.productId > + > + Timestamp nowTimestamp = UtilDateTime.nowTimestamp() > + > + newEntity.createdDate = nowTimestamp > + newEntity.lastModifiedDate = nowTimestamp > + newEntity.lastModifiedByUserLogin = userLogin.userLoginId > + newEntity.createdByUserLogin = userLogin.userLoginId > + > + if (UtilValidate.isEmpty(newEntity.isVariant)) { > + newEntity.isVariant = "N" > + } > + if (UtilValidate.isEmpty(newEntity.isVirtual)) { > + newEntity.isVirtual = "N" > + } > + if (UtilValidate.isEmpty(newEntity.billOfMaterialLevel)) { > + newEntity.billOfMaterialLevel = (Long) 0 > + } > + > + newEntity.create() > + > + /* > + * if setting the primaryProductCategoryId create a member entity too > + * THIS IS REMOVED BECAUSE IT CAUSES PROBLEMS FOR WORKING ON PRODUCTION SITES > + * <if-not-empty field="newEntity.primaryProductCategoryId"> > + * <make-value entity-name="ProductCategoryMember" value-field="newMember"/> > + * <set from-field="productId" map-name="newEntity" to-field-name="productId" to-map-name="newMember"/> > + * <set from-field="primaryProductCategoryId" map-name="newEntity" to-field-name="productCategoryId" to-map-name="newMember"/> > + * <now-timestamp field="nowStamp"/> > + * <set from-field="nowStamp" field="newMember.fromDate"/> > + * <create-value value-field="newMember"/> > + * </if-not-empty> > + */ > + > + // if the user has the role limited position, add this product to the limit category/ies > + > + > + if (security.hasEntityPermission("CATALOG_ROLE","_CREATE", parameters.userLogin)) { > + List productCategoryRoles = from("ProductCategoryRole").where("partyId": userLogin.partyId, "roleTypeId": "LTD_ADMIN").queryList() > + > + for (GenericValue productCategoryRole : productCategoryRoles) { > + // add this new product to the category > + GenericValue newLimitMember = makeValue("ProductCategoryMember") > + newLimitMember.productId = newEntity.productId > + newLimitMember.productCateogryId = productCategoryRole.productCategoryId > + newLimitMember.fromDate = nowTimestamp > + newLimitMember.create() > + } > + } > + > + return result > +} > + > +/** > + * Update a product > + */ > +def updateProduct() { > + Map res = checkProductRelatedPermission("updateProduct", "UPDATE") > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + GenericValue lookedUpValue = findOne("Product", ["productId": parameters.productId], false) > + // save this value before overwriting it so we can compare it later > + Map saveIdMap = ["primaryProductCategoryId": lookedUpValue.primaryProductCategoryId] > + > + lookedUpValue.setNonPKFields(parameters) > + lookedUpValue.lastModifiedDate = UtilDateTime.nowTimestamp() > + lookedUpValue.lastModifiedByUserLogin = userLogin.userLoginId > + lookedUpValue.store() > + > + return success() > + } > + > + /** > + * Update a Product Name from quick admin > + */ > +def updateProductQuickAdminName() { > + Map res = checkProductRelatedPermission("updateQuickAdminName", "UPDATE") > + > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + > + GenericValue lookedUpValue = findOne("Product", ["productId": parameters.productId], false) > + lookedUpValue.productName = parameters.productName > + if ("Y".equals(lookedUpValue.isVirtual)) { > + lookedUpValue.internalName = lookedUpValue.productName > + } > + > + lookedUpValue.lastModifiedDate = UtilDateTime.nowTimestamp(); > + lookedUpValue.lastModifiedByUserLogin = userLogin.userLoginId > + > + lookedUpValue.store() > + > + if ("Y".equals(lookedUpValue.isVirtual)) { > + // get all variant products, to update their productNames > + Map variantProductAssocMap = ["productId": parameters.productId, "productAssocTypeId": "PRODUCT_VARIANT"] > + > + // get all productAssocs, then get the actual product to update > + List variantProductAssocs = from("ProductAssoc").where(variantProductAssocMap).queryList() > + variantProductAssocs = EntityUtil.filterByDate(variantProductAssocs) > + for(GenericValue variantProductAssoc : variantProductAssocs) { > + GenericValue variantProduct = null > + variantProduct = findOne("Product", ["productId": variantProductAssoc.productIdTo], false) > + > + variantProduct.productName = parameters.productName > + variantProduct.lastModifiedDate = UtilDateTime.nowTimestamp() > + variantProduct.lastModifiedByUserLogin = userLogin.userLoginId > + variantProduct.store() > + } > + } > + return success() > +} > + > +/** > + * Duplicate a Product > + */ > +def duplicateProduct() { > + String callingMethodName = "duplicateProduct" > + String checkAction = "CREATE" > + Map res = checkProductRelatedPermission(callingMethodName, checkAction) > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + checkAction = "DELETE" > + res = checkProductRelatedPermission(callingMethodName, checkAction) > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + GenericValue dummyProduct = findOne("Product", ["productId": parameters.productId], false) > + if (UtilValidate.isNotEmpty(dummyProduct)) { > + String errorMessage = UtilProperties.getMessage("CommonErrorUiLabels", CommonErrorDuplicateKey, parameters.locale) > + logError(errorMessage) > + return error(errorMessage) > + } > + > + // look up the old product and clone it > + GenericValue oldProduct = findOne("Product", ["productId": parameters.oldProductId], false) > + GenericValue newProduct = oldProduct.clone() > + > + // set the productId, and write it to the datasource > + newProduct.productId = parameters.productId > + > + // if requested, set the new internalName field > + if (UtilValidate.isNotEmpty(parameters.newInternalName)) { > + newProduct.internalName = parameters.newInternalName > + } > + > + // if requested, set the new productName field > + if (UtilValidate.isNotEmpty(parameters.newProductName)) { > + newProduct.productName = parameters.newProductName > + } > + > + // if requested, set the new description field > + if (UtilValidate.isNotEmpty(parameters.newDescription)) { > + newProduct.description = parameters.newDescription > + } > + > + // if requested, set the new longDescription field > + if (UtilValidate.isNotEmpty(parameters.newLongDescription)) { > + newProduct.longDescription = parameters.newLongDescription > + } > + > + newProduct.create() > + > + // set up entity filter > + Map productFindContext = ["productId": parameters.oldProductId] > + Map reverseProductFindContext = ["productIdTo": parameters.oldProductId] > + > + // if requested, duplicate related data as well > + if (UtilValidate.isNotEmpty(parameters.duplicatePrices)) { > + List foundValues = from("ProductPrice").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = parameters.productId > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateIDs)) { > + List foundValues = from("GoodIdentification").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = parameters.productId > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateContent)) { > + List foundValues = from("ProductContent").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = parameters.productId > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateCategoryMembers)) { > + List foundValues = from("ProductCategoryMember").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = parameters.productId > + > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateAssocs)) { > + List foundValues = from("ProductAssoc").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = parameters.productId > + newTempValue.create() > + } > + > + // small difference here, also do the reverse assocs... > + foundValues = from("ProductAssoc").where("productIdTo": parameters.oldProductId).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productIdTo = parameters.productId > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateAttributes)) { > + List foundValues = from("ProductAttribute").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = parameters.productId > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateFeatureAppls)) { > + List foundValues = from("ProductFeatureAppl").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = parameters.productId > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateInventoryItems)) { > + List foundValues = from("InventoryItem").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + /* > + * NOTE: new inventory items should always be created calling the > + * createInventoryItem service because in this way we are sure > + * that all the relevant fields are filled with default values. > + * However, the code here should work fine because all the values > + * for the new inventory item are inerited from the existing item. > + * TODO: is this code correct? What is the meaning of duplicating inventory items? > + * What about the InventoryItemDetail entries? > + */ > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = parameters.productId > + // this one is slightly different because it needs a new sequenced inventoryItemId > + newTempValue.inventoryItemId = delegator.getNextSeqId("InventoryItem") > + newTempValue.create() > + } > + } > + > + // if requested, remove related data as well > + if (UtilValidate.isNotEmpty(parameters.removePrices)) { > + delegator.removeByAnd("ProductPrice", productFindContext) > + } > + if (UtilValidate.isNotEmpty(parameters.removeIDs)) { > + delegator.removeByAnd("GoodIdentification", productFindContext) > + } > + if (UtilValidate.isNotEmpty(parameters.removeContent)) { > + delegator.removeByAnd("ProductContent", productFindContext) > + } > + if (UtilValidate.isNotEmpty(parameters.removeCategoryMembers)) { > + delegator.removeByAnd("ProductCategoryMember", productFindContext) > + } > + if (UtilValidate.isNotEmpty(parameters.removeAssocs)) { > + delegator.removeByAnd("ProductAssoc", productFindContext) > + // small difference here, also do the reverse assocs... > + delegator.removeByAnd("ProductAssoc", reverseProductFindContext) > + } > + if (UtilValidate.isNotEmpty(parameters.removeAttributes)) { > + delegator.removeByAnd("ProductAttribute", productFindContext) > + } > + if (UtilValidate.isNotEmpty(parameters.removeFeatureAppls)) { > + delegator.removeByAnd("ProductFeatureAppl", productFindContext) > + } > + if (UtilValidate.isNotEmpty(parameters.removeInventoryItems)) { > + delegator.removeByAnd("InventoryItem", productFindContext) > + } > + return success() > +} > + > +// Product Keyword Services > + > +/** > + * induce all the keywords of a product > + */ > +def forceIndexProductKeywords() { > + GenericValue product = findOne("Product", [productId: parameters.productId], false) > + KeywordIndex.forceIndexKeywords(product) > + return success() > +} > + > +/** > + * delete all the keywords of a produc > + */ > +def deleteProductKeywords() { > + GenericValue product = findOne("Product", [productId: parameters.productId], false) > + delegator.removeRelated("ProductKeyword", product) > + return success() > +} > + > +/** > + * Index the Keywords for a Product > + */ > +def indexProductKeywords() { > + //this service is meant to be called from an entity ECA for entities that include a productId > + //if it is the Product entity itself triggering this action, then a [productInstance] parameter > + //will be passed and we can save a few cycles looking that up > + GenericValue productInstance = parameters.productInstance > + if (productInstance == null) { > + Map findProductMap = [productId: parameters.productId] > + productInstance = findOne("Product", findProductMap, false) > + } > + //induce keywords if autoCreateKeywords is empty or Y > + if (UtilValidate.isEmpty(productInstance.autoCreateKeywords) || "Y".equals(productInstance.autoCreateKeywords)) { > + KeywordIndex.indexKeywords(productInstance) > + } > + return success() > +} > + > +/** > + * Discontinue Product Sales > + * set sales discontinuation date to now > + */ > +def discontinueProductSales() { > + // set sales discontinuation date to now > + Timestamp nowTimestamp = UtilDateTime.nowTimestamp() > + GenericValue product = findOne("Product", parameters, false) > + product.salesDiscontinuationDate = nowTimestamp > + product.store() > + > + // expire product from all categories > + List productCategoryMembers = delegator.getRelated("ProductCategoryMember", null, null, product, false) > + for (GenericValue productCategoryMember : productCategoryMembers) { > + if (UtilValidate.isEmpty(productCategoryMember.thruDate)) { > + productCategoryMember.thruDate = UtilDateTime.nowTimestamp() > + productCategoryMember.store() > + } > + } > + // expire product from all associations going to it > + List assocProductAssocs = delegator.getRelated("AssocProductAssoc", null, null, product, false) > + for (GenericValue assocProductAssoc : assocProductAssocs) { > + if (UtilValidate.isEmpty(assocProductAssoc.thruDate)) { > + assocProductAssoc.thruDate = UtilDateTime.nowTimestamp() > + assocProductAssoc.store() > + } > + } > + return success() > +} > + > + > +def countProductView() { > + if (UtilValidate.isEmpty(parameters.weight)) { > + parameters.weight = (Long) 1 > + } > + GenericValue productCalculatedInfo = findOne("ProductCalculatedInfo", ["productId": parameters.productId], false) > + if (UtilValidate.isEmpty(productCalculatedInfo)) { > + // go ahead and create it > + productCalculatedInfo = makeValue("ProductCalculatedInfo") > + productCalculatedInfo.productId = parameters.productId > + productCalculatedInfo.totalTimesViewed = parameters.weight > + productCalculatedInfo.create() > + } else { > + productCalculatedInfo.totalTimesViewed = productCalculatedInfo.totalTimesViewed + parameters.weight > + productCalculatedInfo.store() > + } > + > + // do the same for the virtual product... > + GenericValue product = findOne("Product", ["productId": parameters.productId], true) > + ProductWorker productWorker = new ProductWorker() > + String virtualProductId = productWorker.getVariantVirtualId(product) > + if (UtilValidate.isNotEmpty(virtualProductId)) { > + Map callSubMap = ["productId": virtualProductId, "weight": parameters.weight] > + run service: "countProductView", with: callSubMap > + } > + return success() > + > +} > + > +/** > + * Create a ProductReview > + */ > +def createProductReview() { > + GenericValue newEntity = makeValue("ProductReview", parameters) > + newEntity.userLoginId = userLogin.userLoginId > + newEntity.statusId = "PRR_PENDING" > + > + // code to check for auto-approved reviews (store setting) > + GenericValue productStore = findOne("ProductStore", ["productStoreId": parameters.productStoreId], false) > + > + if (!UtilValidate.isEmpty(productStore)) { > + if ("Y".equals(productStore.autoApproveReviews)) { > + newEntity.statusId = "PRR_APPROVED" > + } > + } > + > + // create the new ProductReview > + newEntity.productReviewId = delegator.getNextSeqId("ProductReview") > + Map result = success() > + result.productReviewId = newEntity.productReviewId > + > + if (UtilValidate.isEmpty(newEntity.postedDateTime)) { > + newEntity.postedDateTime = UtilDateTime.nowTimestamp() > + } > + > + newEntity.create() > + > + String productId = newEntity.productId > + String successMessage = UtilProperties.getMessage("ProductUiLabels", "ProductCreateProductReviewSuccess", parameters.locale) > + updateProductWithReviewRatingAvg(productId) > + > + return result > +} > + > +/** > + * Update ProductReview > + */ > +def updateProductReview() { > + Map res = checkProductRelatedPermission("updateProductReview", "UPDATE") > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + > + GenericValue lookupPKMap = makeValue("ProductReview") > + lookupPKMap.setPKFields(parameters) > + GenericValue lookedUpValue = findOne("ProductReview", lookupPKMap, false) > + lookupPKMap.setNonPKFields(parameters) > + lookupPKMap.store() > + > + String productId = lookedUpValue.productId > + updateProductWithReviewRatingAvg(productId) > + > + return success() > +} > + > +/** > + * change the product review Status > + */ > +def setProductReviewStatus(){ > + Map res = checkProductRelatedPermission("setProductReviewStatus", "UPDATE") > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + > + GenericValue productReview = findOne("ProductReview", parameters, false) > + if (UtilValidate.isNotEmpty(productReview)) { > + if (!productReview.statusId.equals(parameters.statusId)) { > + GenericValue statusChange = from("StatusValidChange") > + .where("statusId", productReview.statusId, "statusIdTo", parameters.statusId) > + .queryOne() > + if (UtilValidate.isEmpty(statusChange)) { > + String msg = "Status is not a valid change: from " + productReview.statusId + " to " + parameters.statusId > + logError(msg) > + String errorMessage = UtilProperties.getMessage("ProductErrorUiLabels", ProductReviewErrorCouldNotChangeOrderStatusFromTo, parameters.locale) > + logError(errorMessage) > + return error(errorMessage) > + } > + } > + } > + > + productReview.statusId = parameters.statusId > + productReview.store() > + Map result = success() > + result.productReviewId = productReview.productReviewId > + > + return result > +} > + > +/** > + * Update Product with new Review Rating Avg > + * this method is meant to be called in-line and depends in a productId parameter > + */ > +def updateProductWithReviewRatingAvg(String productId) { > + ProductWorker productWorker = new ProductWorker() > + BigDecimal averageCustomerRating = productWorker.getAverageProductRating(delegator, productId) > + logInfo("Got new average customer rating "+ averageCustomerRating) > + > + if (averageCustomerRating == 0) { > + return success() > + } > + > + // update the review average on the ProductCalculatedInfo entity > + GenericValue productCalculatedInfo = findOne("ProductCalculatedInfo", parameters, false) > + if (UtilValidate.isEmpty(productCalculatedInfo)) { > + // go ahead and create it > + productCalculatedInfo = makeValue("ProductCalculatedInfo") > + productCalculatedInfo.productId = productId > + productCalculatedInfo.averageCustomerRating = averageCustomerRating > + productCalculatedInfo.create() > + } else { > + productCalculatedInfo.averageCustomerRating = averageCustomerRating > + productCalculatedInfo.store() > + } > + > + return success() > +} > + > +/** > + * Updates the Product's Variants > + */ > +def copyToProductVariants() { > + String callingMethodName = "copyToProductVariants" > + String checkAction = "CREATE" > + Map res = checkProductRelatedPermission(callingMethodName, checkAction) > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + checkAction = "DELETE" > + res = checkProductRelatedPermission(callingMethodName, checkAction) > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + > + Map productFindContext = ["productId": parameters.virtualProductId] > + GenericValue oldProduct = findOne("Product", productFindContext, false) > + > + Map variantsFindContext = ["productId": parameters.virtualProductId, "productAssocTypeId": "PRODUCT_VARIANT"] > + > + List variants = from("ProductAssoc").where(variantsFindContext).filterByDate().queryList() > + List foundVariantValues = [] > + List foundValues = [] > + for (GenericValue newProduct : variants) { > + Map productVariantContext = ["productId": newProduct.productIdTo] > + // if requested, duplicate related data > + if (UtilValidate.isNotEmpty(parameters.duplicatePrices)) { > + if (UtilValidate.isNotEmpty(parameters.removeBefore)) { > + foundVariantValues = from("ProductPrice").where(productVariantContext).queryList() > + for (GenericValue foundVariantValue : foundVariantValues) { > + foundVariantValue.remove() > + } > + } > + foundValues = from("ProductPrice").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = newProduct.productIdTo > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateIDs)) { > + if (UtilValidate.isNotEmpty(parameters.removeBefore)) { > + foundVariantValues = from("GoodIdentification").where(productVariantContext).queryList() > + for (GenericValue foundVariantValue : foundVariantValues) { > + foundVariantValue.remove() > + } > + } > + foundValues = from("GoodIdentification").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = newProduct.productIdTo > + newTempValue.create() > + } > + > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateContent)) { > + if (UtilValidate.isNotEmpty(parameters.removeBefore)) { > + foundVariantValues = from("ProductContent").where(productVariantContext).queryList() > + for (GenericValue foundVariantValue : foundVariantValues) { > + foundVariantValue.remove() > + } > + } > + foundValues = from("ProductContent").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = newProduct.productIdTo > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateCategoryMembers)) { > + if (UtilValidate.isNotEmpty(parameters.removeBefore)) { > + foundVariantValues = from("ProductCategoryMember").where(productVariantContext).queryList() > + for (GenericValue foundVariantValue : foundVariantValues) { > + foundVariantValue.remove() > + } > + } > + foundValues = from("ProductCategoryMember").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = newProduct.productIdTo > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateAttributes)) { > + if (UtilValidate.isNotEmpty(parameters.removeBefore)) { > + foundVariantValues = from("ProductAttribute").where(productVariantContext).queryList() > + for (GenericValue foundVariantValue : foundVariantValues) { > + foundVariantValue.remove() > + } > + } > + foundValues = from("ProductAttribute").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = newProduct.productIdTo > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateFacilities)) { > + if (UtilValidate.isNotEmpty(parameters.removeBefore)) { > + foundVariantValues = from("ProductFacility").where(productVariantContext).queryList() > + for (GenericValue foundVariantValue : foundVariantValues) { > + foundVariantValue.remove() > + } > + } > + foundValues = from("ProductFacility").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = newProduct.productIdTo > + newTempValue.create() > + } > + } > + if (UtilValidate.isNotEmpty(parameters.duplicateLocations)) { > + if (UtilValidate.isNotEmpty(parameters.removeBefore)) { > + foundVariantValues = from("ProductFacilityLocation").where(productVariantContext).queryList() > + for (GenericValue foundVariantValue : foundVariantValues) { > + foundVariantValue.remove() > + } > + } > + foundValues = from("ProductFacilityLocation").where(productFindContext).queryList() > + for (GenericValue foundValue : foundValues) { > + GenericValue newTempValue = foundValue.clone() > + newTempValue.productId = newProduct.productIdTo > + newTempValue.create() > + } > + } > + } > + return success() > +} > + > +/** > + * Check Product Related Permission > + * a method 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 > + */ > +def checkProductRelatedPermission (String callingMethodName, String checkAction){ > + if (UtilValidate.isEmpty(callingMethodName)) { > + callingMethodName = UtilProperties.getMessage("CommonUiLabels", "CommonPermissionThisOperation", parameters.locale) > + } > + if (UtilValidate.isEmpty(checkAction)) { > + checkAction = "UPDATE" > + } > + List roleCategories = [] > + // find all role-categories that this product is a member of > + if (!security.hasEntityPermission("CATALOG", "_${checkAction}", parameters.userLogin)) { > + Map lookupRoleCategoriesMap = ["productId": parameters.productId, "partyId": userLogin.partyId, "roleTypeId": "LTD_ADMIN"] > + roleCategories = from("ProductCategoryMemberAndRole").where(lookupRoleCategoriesMap).filterByDate("roleFromDate", "roleThruDate").queryList() > + } > + > + if (! ((security.hasEntityPermission("CATALOG", "_${checkAction}", parameters.userLogin)) > + || (security.hasEntityPermission("CATALOG_ROLE", "_${checkAction}", parameters.userLogin) && !UtilValidate.isEmpty(roleCategories)) > + || (!UtilValidate.isEmpty(parameters.alternatePermissionRoot) && security.hasEntityPermission(parameters.alternatePermissionRoot, checkAction, parameters.userLogin)))) { > + String checkActionLabel = "ProductCatalog" + checkAction.charAt(0) + checkAction.substring(1).toLowerCase() + "PermissionError" > + String resourceDescription = callingMethodName > + > + String errorMessage = UtilProperties.getMessage("ProductUiLabels", checkActionLabel, parameters.locale) > + logError(errorMessage) > + return error(errorMessage) > + } > + return success() > +} > + > +/** > + * Main permission logic > + */ > +def productGenericPermission(){ > + String mainAction = parameters.mainAction > + Map result = success() > + if (UtilValidate.isEmpty(mainAction)) { > + String errorMessage = UtilProperties.getMessage("ProductUiLabels", "ProductMissingMainActionInPermissionService", parameters.locale) > + logError(errorMessage) > + return error(errorMessage) > + } > + Map res = checkProductRelatedPermission(parameters.resourceDescription, parameters.mainAction) > + if (!ServiceUtil.isSuccess(res)) { > + String failMessage = UtilProperties.getMessage("ProductUiLabels", "ProductPermissionError", parameters.locale) > + Boolean hasPermission = false > + result = fail(failMessage) > + result.hasPermission = hasPermission > + } else { > + Boolean hasPermission = true > + result.hasPermission = hasPermission > + } > + return result > +} > + > +/** > + * product price permission logic > + */ > +def productPriceGenericPermission(){ > + String mainAction = parameters.mainAction > + if (UtilValidate.isEmpty(mainAction)) { > + String errorMessage = UtilProperties.getMessage("ProductUiLabels", "ProductMissingMainActionInPermissionService", parameters.locale) > + logError(errorMessage) > + return error(errorMessage) > + } > + Map result = success() > + if (!security.hasEntityPermission("CATALOG_PRICE_MAINT", null, parameters.userLogin)) { > + String errorMessage = UtilProperties.getMessage("ProductUiLabels", "ProductPriceMaintPermissionError", parameters.locale) > + logError(errorMessage) > + result = error(errorMessage) > + } > + Map res = checkProductRelatedPermission(null, null) > + if (ServiceUtil.isSuccess(result) && ServiceUtil.isSuccess(res)) { > + result.hasPermission = true > + } else { > + String failMessage = UtilProperties.getMessage("ProductUiLabels", "ProductPermissionError", parameters.locale) > + result = fail(failMessage) > + result.hasPermission = false > + } > + return result > +} > + > +/** > + * ================================================================ > + * ProductRole Services > + * ================================================================ > + */ > + > + > +/** > + * Add Party to Product > + */ > +def addPartyToProduct(){ > + Map result = checkProductRelatedPermission("addPartyToProduct", "CREATE") > + if (!ServiceUtil.isSuccess(result)) { > + return result > + } > + GenericValue newEntity = makeValue("ProductRole", parameters) > + > + if (UtilValidate.isEmpty(newEntity.fromDate)) { > + newEntity.fromDate = UtilDateTime.nowTimestamp() > + } > + newEntity.create() > + return success() > +} > + > +/** > + * Update Party to Product > + */ > +def updatePartyToProduct(){ > + Map result = checkProductRelatedPermission("updatePartyToProduct", "UPDATE") > + if (!ServiceUtil.isSuccess(result)) { > + return result > + } > + GenericValue lookupPKMap = makeValue("ProductRole") > + lookupPKMap.setPKFields(parameters) > + GenericValue lookedUpValue = findOne("ProductRole", lookupPKMap, false) > + lookedUpValue.setNonPKFields(parameters) > + lookedUpValue.store() > + return success() > +} > + > +/** > + * Remove Party From Product > + */ > +def removePartyFromProduct(){ > + Map res = checkProductRelatedPermission("removePartyFromProduct", "DELETE") > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + Map lookupPKMap = makeValue("ProductRole") > + lookupPKMap.setPKFields(parameters) > + GenericValue lookedUpValue = findOne("ProductRole", lookupPKMap, false) > + lookedUpValue.remove() > + > + return success() > +} > + > +// ProductCategoryGlAccount methods > + /** > + * Create a ProductCategoryGlAccount > + */ > +def createProductCategoryGlAccount(){ > + Map res = checkProductRelatedPermission("createProductCategoryGlAccount", "CREATE") > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + > + GenericValue newEntity = makeValue("ProductCategoryGlAccount", parameters) > + newEntity.create() > + > + return success() > +} > + > +/** > + * Update a ProductCategoryGlAccount > + */ > +def updateProductCategoryGlAccount(){ > + Map res = checkProductRelatedPermission("updateProductCategoryGlAccount", "UPDATE") > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + > + GenericValue lookedUpValue = findOne("ProductCategoryGlAccount", parameters, false) > + lookedUpValue.setNonPKFields(parameters) > + lookedUpValue.store() > + > + return success() > +} > + > +/** > + * Delete a ProductCategoryGlAccount > + */ > +def deleteProductCategoryGlAccount(){ > + Map res = checkProductRelatedPermission("deleteProductCategorGLAccount", "DELETE") > + if (!ServiceUtil.isSuccess(res)) { > + return res > + } > + GenericValue lookedUpValue = findOne("ProductCategoryGlAccount", parameters, false) > + lookedUpValue.remove() > + > + return success() > +} > + > +// Product GroupOrder Services --> > + > +/** > + * Create ProductGroupOrder > + */ > +def createProductGroupOrder(){ > + GenericValue newEntity = makeValue("ProductGroupOrder") > + delegator.setNextSubSeqId(newEntity, "groupOrderId", 5, 1) > + Map result = success() > + result.groupOrderId = newEntity.groupOrderId > + newEntity.setNonPKFields(parameters) > + newEntity.create() > + > + return result > +} > + > +/** > + * Update ProductGroupOrder > + */ > +def updateProductGroupOrder(){ > + GenericValue productGroupOrder = findOne("ProductGroupOrder", ["groupOrderId": parameters.groupOrderId], false) > + productGroupOrder.setNonPKFields(parameters) > + productGroupOrder.store() > + > + if ("GO_CREATED".equals(productGroupOrder.statusId)) { > + GenericValue jobSandbox = findOne("JobSandbox", ["jobId": productGroupOrder.jobId], false) > + if (UtilValidate.isNotEmpty(jobSandbox)) { > + jobSandbox.runTime = parameters.thruDate > + jobSandbox.store() > + } > + } > + return success() > +} > + > +/** > + * Delete ProductGroupOrder > + */ > +def deleteProductGroupOrder(){ > + List orderItemGroupOrders = from("OrderItemGroupOrder").where("groupOrderId": parameters.groupOrderId).queryList() > + for (GenericValue orderItemGroupOrder : orderItemGroupOrders) { > + orderItemGroupOrder.remove() > + } > + GenericValue productGroupOrder = findOne("ProductGroupOrder", ["groupOrderId": parameters.groupOrderId], false) > + if (UtilValidate.isEmpty(productGroupOrder)) { > + return error("Entity value not found with name: " + productGroupOrder) > + } > + productGroupOrder.remove() > + > + GenericValue jobSandbox = findOne("JobSandbox", ["jobId": productGroupOrder.jobId], false) > + if (UtilValidate.isEmpty(jobSandbox)) { > + return error("Entity value not found with name: " + jobSandbox) > + } > + jobSandbox.remove() > + > + List jobSandboxList = from("JobSandbox").where("runtimeDataId": jobSandbox.runtimeDataId).queryList() > + for (GenericValue jobSandboxRelatedRuntimeData : jobSandboxList) { > + jobSandboxRelatedRuntimeData.remove() > + } > + > + GenericValue runtimeData = findOne("RuntimeData", ["runtimeDataId": jobSandbox.runtimeDataId], false) > + if (UtilValidate.isEmpty(runtimeData)) { > + return error("Entity value not found with name: " + runtimeData) > + } > + runtimeData.remove() > + > + return success() > +} > + > +/** > + * Create ProductGroupOrder > + */ > +def createJobForProductGroupOrder(){ > + GenericValue productGroupOrder = findOne("ProductGroupOrder", ["groupOrderId": parameters.groupOrderId], false) > + if (UtilValidate.isEmpty(productGroupOrder.jobId)) { > + // Create RuntimeData For ProductGroupOrder > + Map runtimeDataMap = ["groupOrderId": parameters.groupOrderId] > + XmlSerializer xmlSerializer = new XmlSerializer() > + String runtimeInfo = xmlSerializer.serialize(runtimeDataMap) > + > + GenericValue runtimeData = makeValue("RuntimeData") > + runtimeData.runtimeDataId = delegator.getNextSeqId("RuntimeData") > + String runtimeDataId = runtimeData.runtimeDataId > + runtimeData.runtimeInfo = runtimeInfo > + runtimeData.create() > + > + // Create Job For ProductGroupOrder > + // FIXME: Jobs should not be manually created > + GenericValue jobSandbox = makeValue("JobSandbox") > + jobSandbox.jobId = delegator.getNextSeqId("JobSandbox") > + String jobId = jobSandbox.jobId > + jobSandbox.jobName = "Check ProductGroupOrder Expired" > + jobSandbox.runTime = parameters.thruDate > + jobSandbox.poolId = "pool" > + jobSandbox.statusId = "SERVICE_PENDING" > + jobSandbox.serviceName = "checkProductGroupOrderExpired" > + jobSandbox.runAsUser = "system" > + jobSandbox.runtimeDataId = runtimeDataId > + jobSandbox.maxRecurrenceCount = (Long) 1 > + jobSandbox.priority = (Long) 50 > + jobSandbox.create() > + > + productGroupOrder.jobId = jobId > + productGroupOrder.store() > + } > + return success() > +} > + > +/** > + * Check OrderItem For ProductGroupOrder > + */ > +def checkOrderItemForProductGroupOrder(){ > + List orderItems = from("OrderItem").where("orderId": parameters.orderId).queryList() > + for (GenericValue orderItem : orderItems) { > + String productId = orderItem.productId > + GenericValue product = findOne("Product", ["productId": orderItem.productId], false) > + if ("Y".equals(product.isVariant)) { > + List variantProductAssocs = from("ProductAssoc").where("productIdTo": orderItem.productId, "productAssocTypeId": "PRODUCT_VARIANT").queryList() > + variantProductAssocs = EntityUtil.filterByDate(variantProductAssocs) > + GenericValue variantProductAssoc = variantProductAssocs.get(0) > + productId = variantProductAssoc.productId > + } > + List productGroupOrders = from("ProductGroupOrder").where("productId": productId).queryList() > + if (UtilValidate.isNotEmpty(productGroupOrders)) { > + productGroupOrders = EntityUtil.filterByDate(productGroupOrders) > + GenericValue productGroupOrder = productGroupOrders.get(0) > + if (UtilValidate.isEmpty(productGroupOrder.soldOrderQty)) { > + productGroupOrder.soldOrderQty = orderItem.quantity > + } else { > + productGroupOrder.soldOrderQty = productGroupOrder.soldOrderQty + orderItem.quantity > + } > + productGroupOrder.store() > + > + Map createOrderItemGroupOrderMap = ["orderId": orderItem.orderId, "orderItemSeqId": orderItem.orderItemSeqId, "groupOrderId": productGroupOrder.groupOrderId] > + > + run service: "createOrderItemGroupOrder", with: createOrderItemGroupOrderMap > + } > + } > + return success() > +} > + > +/** > + * Cancle OrderItemGroupOrder > + */ > +def cancleOrderItemGroupOrder(){ > + List orderItems = [] > + if (UtilValidate.isNotEmpty(parameters.orderItemSeqId)) { > + orderItems = from("OrderItem") > + .where("orderId", parameters.orderId, "orderItemSeqId", parameters.orderItemSeqId) > + .queryList() > + } else { > + orderItems = from("OrderItem") > + .where("orderId", parameters.orderId) > + .queryList() > + } > + for(GenericValue orderItem : orderItems) { > + List orderItemGroupOrders = from("OrderItemGroupOrder") > + .where("orderId", orderItem.orderId, "orderItemSeqId", orderItem.orderItemSeqId) > + .queryList() > + if (UtilValidate.isNotEmpty(orderItemGroupOrders)) { > + GenericValue orderItemGroupOrder = orderItemGroupOrders.get(0) > + GenericValue productGroupOrder = findOne("ProductGroupOrder", [groupOrderId: orderItemGroupOrder.groupOrderId], false) > + > + if (UtilValidate.isNotEmpty(productGroupOrder)) { > + if ("GO_CREATED".equals(productGroupOrder.statusId)) { > + if ("ITEM_CANCELLED".equals(orderItem.statusId)) { > + BigDecimal cancelQuantity > + if (UtilValidate.isNotEmpty(orderItem.cancelQuantity)) { > + cancelQuantity = orderItem.cancelQuantity > + } else { > + cancelQuantity = orderItem.quantity > + } > + productGroupOrder.soldOrderQty = productGroupOrder.soldOrderQty - cancelQuantity > + } > + productGroupOrder.store() > + orderItemGroupOrder.remove() > + } > + } > + } > + } > + return success() > +} > + > +/** > + * Check ProductGroupOrder Expired > + */ > +def checkProductGroupOrderExpired(){ > + GenericValue productGroupOrder = findOne("ProductGroupOrder", parameters, false) > + if (UtilValidate.isNotEmpty(productGroupOrder)) { > + String groupOrderStatusId > + String newItemStatusId > + if (productGroupOrder.soldOrderQty >= productGroupOrder.reqOrderQty) { > + newItemStatusId = "ITEM_APPROVED" > + groupOrderStatusId = "GO_SUCCESS" > + } else { > + newItemStatusId = "ITEM_CANCELLED" > + groupOrderStatusId = "GO_CANCELLED" > + } > + Map updateProductGroupOrderMap = [:] > + updateProductGroupOrderMap.groupOrderId = productGroupOrder.groupOrderId > + updateProductGroupOrderMap.statusId = groupOrderStatusId > + run service: "updateProductGroupOrder", with: updateProductGroupOrderMap > + > + List orderItemGroupOrders = from("OrderItemGroupOrder") > + .where("groupOrderId", productGroupOrder.groupOrderId) > + .queryList() > + for(GenericValue orderItemGroupOrder : orderItemGroupOrders) { > + Map changeOrderItemStatusMap = ["orderId": orderItemGroupOrder.orderId, "orderItemSeqId": orderItemGroupOrder.orderItemSeqId, "statusId": newItemStatusId] > + run service: "changeOrderItemStatus", with: changeOrderItemStatusMap > + } > + return success() > + } > +} > + > diff --git a/applications/product/minilang/product/product/ProductServices.xml b/applications/product/minilang/product/product/ProductServices.xml > deleted file mode 100644 > index b331b32..0000000 > --- a/applications/product/minilang/product/product/ProductServices.xml > +++ /dev/null > @@ -1,1051 +0,0 @@ > -<?xml version="1.0" encoding="UTF-8"?> > -<!-- > -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. > ---> > - > -<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"> > - <simple-method method-name="createProduct" short-description="Create a Product"> > - <check-permission permission="CATALOG" action="_CREATE"> > - <alt-permission permission="CATALOG_ROLE" action="_CREATE"/> > - <fail-property resource="ProductUiLabels" property="ProductCatalogCreatePermissionError"/> > - </check-permission> > - <check-errors/> > - > - <make-value entity-name="Product" value-field="newEntity"/> > - <set-nonpk-fields map="parameters" value-field="newEntity"/> > - > - <set from-field="parameters.productId" field="newEntity.productId"/> > - <if-empty field="newEntity.productId"> > - <sequenced-id sequence-name="Product" field="newEntity.productId"/> > - <else> > - <check-id field="newEntity.productId"/> > - <check-errors /> > - <entity-one entity-name="Product" value-field="dummyProduct"><field-map field-name="productId" from-field="parameters.productId"/></entity-one> > - <if-not-empty field="dummyProduct"> > - <add-error ><fail-property resource="CommonErrorUiLabels" property="CommonErrorDuplicateKey" /></add-error> > - </if-not-empty> > - <check-errors /> > - </else> > - </if-empty> > - <field-to-result field="newEntity.productId" result-name="productId"/> > - > - <now-timestamp field="nowTimestamp"/> > - <set from-field="nowTimestamp" field="newEntity.createdDate"/> > - <set from-field="nowTimestamp" field="newEntity.lastModifiedDate"/> > - <set from-field="userLogin.userLoginId" field="newEntity.lastModifiedByUserLogin"/> > - <set from-field="userLogin.userLoginId" field="newEntity.createdByUserLogin"/> > - <if-empty field="newEntity.isVariant"> > - <set field="newEntity.isVariant" value="N"/> > - </if-empty> > - <if-empty field="newEntity.isVirtual"> > - <set field="newEntity.isVirtual" value="N"/> > - </if-empty> > - <if-empty field="newEntity.billOfMaterialLevel"> > - <set field="newEntity.billOfMaterialLevel" value="0" type="Long"/> > - </if-empty> > - > - <create-value value-field="newEntity"/> > - > - <!-- if setting the primaryProductCategoryId create a member entity too --> > - <!-- THIS IS REMOVED BECAUSE IT CAUSES PROBLEMS FOR WORKING ON PRODUCTION SITES > - <if-not-empty field="newEntity.primaryProductCategoryId"> > - <make-value entity-name="ProductCategoryMember" value-field="newMember"/> > - <set from-field="productId" map-name="newEntity" to-field-name="productId" to-map-name="newMember"/> > - <set from-field="primaryProductCategoryId" map-name="newEntity" to-field-name="productCategoryId" to-map-name="newMember"/> > - <now-timestamp field="nowStamp"/> > - <set from-field="nowStamp" field="newMember.fromDate"/> > - <create-value value-field="newMember"/> > - </if-not-empty> > - --> > - > - <!-- if the user has the role limited position, add this product 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="ProductCategoryMember" value-field="newLimitMember"/> > - <set from-field="newEntity.productId" field="newLimitMember.productId"/> > - <set from-field="productCategoryRole.productCategoryId" field="newLimitMember.productCategoryId"/> > - <set from-field="nowTimestamp" field="newLimitMember.fromDate"/> > - <create-value value-field="newLimitMember"/> > - </iterate> > - </if-has-permission> > - </simple-method> > - <simple-method method-name="updateProduct" short-description="Update a Product"> > - <set value="updateProduct" field="callingMethodName"/> > - <set value="UPDATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <entity-one entity-name="Product" value-field="lookedUpValue"/> > - <!-- save this value before overwriting it so we can compare it later --> > - <set from-field="lookedUpValue.primaryProductCategoryId" field="saveIdMap.primaryProductCategoryId"/> > - <set-nonpk-fields map="parameters" value-field="lookedUpValue"/> > - > - <now-timestamp field="lookedUpValue.lastModifiedDate"/> > - <set from-field="userLogin.userLoginId" field="lookedUpValue.lastModifiedByUserLogin"/> > - > - <store-value value-field="lookedUpValue"/> > - > - <!-- if setting the primaryParentCategoryId, create a rollup entity too --> > - <!-- THIS IS REMOVED BECAUSE IT CAUSES PROBLEMS FOR WORKING ON PRODUCTION SITES > - <if-not-empty field="lookedUpValue.primaryProductCategoryId"> > - <if-compare-field to-field="saveIdMap.primaryProductCategoryId" field="lookedUpValue.primaryProductCategoryId" operator="equals"> > - <make-value entity-name="ProductCategoryMember" value-field="newMember"/> > - <set from-field="productId" map-name="newEntity" to-field-name="productId" to-map-name="newMember"/> > - <set from-field="primaryProductCategoryId" map-name="newEntity" to-field-name="productCategoryId" to-map-name="newMember"/> > - <now-timestamp field="newMember.fromDate"/> > - <create-value value-field="newMember"/> > - </if-compare-field> > - </if-not-empty> > - --> > - </simple-method> > - > - <!-- update the name of a product - handles real , virtual and variant products --> > - <simple-method method-name="updateProductQuickAdminName" short-description="Update a Product Name from quick admin"> > - <set value="updateProductQuickAdminName" field="callingMethodName"/> > - <set value="UPDATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <entity-one entity-name="Product" value-field="lookedUpValue"/> > - <set from-field="parameters.productName" field="lookedUpValue.productName"/> > - <if-compare field="lookedUpValue.isVirtual" operator="equals" value="Y"> > - <set from-field="lookedUpValue.productName" field="lookedUpValue.internalName"/> > - </if-compare> > - > - <now-timestamp field="lookedUpValue.lastModifiedDate"/> > - <set from-field="userLogin.userLoginId" field="lookedUpValue.lastModifiedByUserLogin"/> > - > - <store-value value-field="lookedUpValue"/> > - > - <if-compare field="lookedUpValue.isVirtual" operator="equals" value="Y"> > - <!-- get all variant products, to update their productNames --> > - <set from-field="parameters.productId" field="variantProductAssocMap.productId"/> > - <set value="PRODUCT_VARIANT" field="variantProductAssocMap.productAssocTypeId"/> > - > - <!-- get all productAssocs, then get the actual product to update --> > - <find-by-and entity-name="ProductAssoc" map="variantProductAssocMap" list="variantProductAssocs"/> > - <filter-list-by-date list="variantProductAssocs"/> > - <iterate list="variantProductAssocs" entry="variantProductAssoc"> > - <clear-field field="variantProduct"/> > - <entity-one entity-name="Product" value-field="variantProduct" auto-field-map="false"> > - <field-map field-name="productId" from-field="variantProductAssoc.productIdTo"/> > - </entity-one> > - > - <set from-field="parameters.productName" field="variantProduct.productName"/> > - <now-timestamp field="variantProduct.lastModifiedDate"/> > - <set from-field="userLogin.userLoginId" field="variantProduct.lastModifiedByUserLogin"/> > - <store-value value-field="variantProduct"/> > - </iterate> > - </if-compare> > - </simple-method> > - > - <simple-method method-name="duplicateProduct" short-description="Duplicate a Product"> > - <set value="duplicateProduct" field="callingMethodName"/> > - <set value="CREATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <set value="DELETE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <entity-one entity-name="Product" value-field="dummyProduct"> > - <field-map field-name="productId" from-field="parameters.productId"/> > - </entity-one> > - <if-not-empty field="dummyProduct"> > - <add-error ><fail-property resource="CommonErrorUiLabels" property="CommonErrorDuplicateKey" /></add-error> > - </if-not-empty> > - <check-errors/> > - > - <!-- look up the old product and clone it --> > - <entity-one entity-name="Product" value-field="oldProduct" auto-field-map="false"> > - <field-map field-name="productId" from-field="parameters.oldProductId"/> > - </entity-one> > - <clone-value value-field="oldProduct" new-value-field="newProduct"/> > - > - <!-- set the productId, and write it to the datasource --> > - <set from-field="parameters.productId" field="newProduct.productId"/> > - > - <!-- if requested, set the new internalName field --> > - <if-not-empty field="parameters.newInternalName"> > - <set from-field="parameters.newInternalName" field="newProduct.internalName"/> > - </if-not-empty> > - > - <!-- if requested, set the new productName field --> > - <if-not-empty field="parameters.newProductName"> > - <set from-field="parameters.newProductName" field="newProduct.productName"/> > - </if-not-empty> > - > - <!-- if requested, set the new description field --> > - <if-not-empty field="parameters.newDescription"> > - <set from-field="parameters.newDescription" field="newProduct.description"/> > - </if-not-empty> > - > - <!-- if requested, set the new longDescription field --> > - <if-not-empty field="parameters.newLongDescription"> > - <set from-field="parameters.newLongDescription" field="newProduct.longDescription"/> > - </if-not-empty> > - > - <create-value value-field="newProduct"/> > - > - <!-- set up entity filter --> > - <set field="productFindContext.productId" from-field="parameters.oldProductId"/> > - <set field="reverseProductFindContext.productIdTo" from-field="parameters.oldProductId"/> > - > - <!-- if requested, duplicate related data as well --> > - <if-not-empty field="parameters.duplicatePrices"> > - <find-by-and entity-name="ProductPrice" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateIDs"> > - <find-by-and entity-name="GoodIdentification" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateContent"> > - <find-by-and entity-name="ProductContent" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateCategoryMembers"> > - <find-by-and entity-name="ProductCategoryMember" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productId"/> > - <!-- Clone Content --> > - <sequenced-id sequence-name="Content" field="newContentId"/> > - <entity-one entity-name="Content" value-field="oldContent" use-cache="false"> > - <field-map field-name="contentId" value="${newTempValue.contentId}"/> > - </entity-one> > - <if-not-empty field="oldContent"> > - <clone-value value-field="oldContent" new-value-field="clonedContent"/> > - <set from-field="newContentId" field="clonedContent.contentId"/> > - <set from-field="newContentId" field="newTempValue.contentId"/> > - <!-- Clone DataResource --> > - <entity-one entity-name="DataResource" value-field="oldDataResource" use-cache="false"> > - <field-map field-name="dataResourceId" value="${clonedContent.dataResourceId}"/> > - </entity-one> > - <if-not-empty field="oldDataResource"> > - <sequenced-id sequence-name="DataResource" field="newDataResourceId"/> > - <clone-value new-value-field="clonedDataresource" value-field="oldDataResource"/> > - <set from-field="newDataResourceId" field="clonedDataresource.dataResourceId"/> > - <!-- set new data resource id in cloned content --> > - <set from-field="newDataResourceId" field="clonedContent.dataResourceId"/> > - <create-value value-field="clonedDataresource"/> > - <!-- Clone Electronic Text if exists --> > - <get-related-one value-field="oldDataResource" relation-name="ElectronicText" to-value-field="oldElectronicText"/> > - <if-not-empty field="oldElectronicText"> > - <clone-value value-field="oldElectronicText" new-value-field="clonedElectronicText"/> > - <set from-field="newDataResourceId" field="clonedElectronicText.dataResourceId"/> > - <create-value value-field="clonedElectronicText"/> > - </if-not-empty> > - </if-not-empty> > - <create-value value-field="clonedContent"/> > - </if-not-empty> > - <!-- End Clone Contet --> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateAssocs"> > - <find-by-and entity-name="ProductAssoc" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - > - <!-- small difference here, also do the reverse assocs... --> > - <entity-and entity-name="ProductAssoc" list="foundValues"> > - <field-map field-name="productIdTo" from-field="parameters.oldProductId"/> > - </entity-and> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productIdTo"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateAttributes"> > - <find-by-and entity-name="ProductAttribute" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateFeatureAppls"> > - <find-by-and entity-name="ProductFeatureAppl" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateInventoryItems"> > - <find-by-and entity-name="InventoryItem" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <!-- > - NOTE: new inventory items should always be created calling the > - createInventoryItem service because in this way we are sure > - that all the relevant fields are filled with default values. > - However, the code here should work fine because all the values > - for the new inventory item are inerited from the existing item. > - TODO: is this code correct? What is the meaning of duplicating inventory items? > - What about the InventoryItemDetail entries? > - --> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="parameters.productId" field="newTempValue.productId"/> > - <!-- this one is slightly different because it needs a new sequenced inventoryItemId --> > - <sequenced-id sequence-name="InventoryItem" field="newTempValue.inventoryItemId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - > - <!-- if requested, remove related data as well --> > - <if-not-empty field="parameters.removePrices"> > - <remove-by-and entity-name="ProductPrice" map="productFindContext"/> > - </if-not-empty> > - <if-not-empty field="parameters.removeIDs"> > - <remove-by-and entity-name="GoodIdentification" map="productFindContext"/> > - </if-not-empty> > - <if-not-empty field="parameters.removeContent"> > - <remove-by-and entity-name="ProductContent" map="productFindContext"/> > - </if-not-empty> > - <if-not-empty field="parameters.removeCategoryMembers"> > - <remove-by-and entity-name="ProductCategoryMember" map="productFindContext"/> > - </if-not-empty> > - <if-not-empty field="parameters.removeAssocs"> > - <remove-by-and entity-name="ProductAssoc" map="productFindContext"/> > - <!-- small difference here, also do the reverse assocs... --> > - <remove-by-and entity-name="ProductAssoc" map="reverseProductFindContext"/> > - </if-not-empty> > - <if-not-empty field="parameters.removeAttributes"> > - <remove-by-and entity-name="ProductAttribute" map="productFindContext"/> > - </if-not-empty> > - <if-not-empty field="parameters.removeFeatureAppls"> > - <remove-by-and entity-name="ProductFeatureAppl" map="productFindContext"/> > - </if-not-empty> > - <if-not-empty field="parameters.removeInventoryItems"> > - <remove-by-and entity-name="InventoryItem" map="productFindContext"/> > - </if-not-empty> > - </simple-method> > - > - <!-- Product Keyword Services --> > - <simple-method method-name="forceIndexProductKeywords" short-description="induce all the keywords of a product"> > - <entity-one entity-name="Product" value-field="product"/> > - <call-class-method class-name="org.apache.ofbiz.product.product.KeywordIndex" method-name="forceIndexKeywords"> > - <field field="product" type="org.apache.ofbiz.entity.GenericValue"/> > - </call-class-method> > - </simple-method> > - <simple-method method-name="deleteProductKeywords" short-description="delete all the keywords of a product"> > - <entity-one entity-name="Product" value-field="product"/> > - <remove-related value-field="product" relation-name="ProductKeyword"/> > - </simple-method> > - > - <simple-method method-name="indexProductKeywords" short-description="Index the Keywords for a Product" login-required="false"> > - <!-- this service is meant to be called from an entity ECA for entities that include a productId --> > - <!-- if it is the Product entity itself triggering this action, then a [productInstance] parameter > - will be passed and we can save a few cycles looking that up --> > - <set from-field="parameters.productInstance" field="productInstance"/> > - <if-empty field="productInstance"> > - <set from-field="parameters.productId" field="findProductMap.productId"/> > - <find-by-primary-key entity-name="Product" map="findProductMap" value-field="productInstance"/> > - </if-empty> > - > - <!-- induce keywords if autoCreateKeywords is emtpy or Y--> > - <if> > - <condition> > - <or> > - <if-empty field="productInstance.autoCreateKeywords"/> > - <if-compare field="productInstance.autoCreateKeywords" operator="equals" value="Y"/> > - </or> > - </condition> > - <then> > - <call-class-method class-name="org.apache.ofbiz.product.product.KeywordIndex" method-name="indexKeywords"> > - <field field="productInstance" type="org.apache.ofbiz.entity.GenericValue"/> > - </call-class-method> > - </then> > - </if> > - </simple-method> > - > - <simple-method method-name="discontinueProductSales" short-description="Discontinue Product Sales" login-required="false"> > - <!-- set sales discontinuation date to now --> > - <now-timestamp field="nowTimestamp"/> > - <entity-one entity-name="Product" value-field="product"/> > - <set from-field="nowTimestamp" field="product.salesDiscontinuationDate"/> > - <store-value value-field="product"/> > - <!-- expire product from all categories --> > - <get-related value-field="product" relation-name="ProductCategoryMember" list="productCategoryMembers"/> > - <iterate list="productCategoryMembers" entry="productCategoryMember"> > - <if-empty field="productCategoryMember.thruDate"> > - <set from-field="nowTimestamp" field="productCategoryMember.thruDate"/> > - <store-value value-field="productCategoryMember"/> > - </if-empty> > - </iterate> > - <!-- expire product from all associations going to it --> > - <get-related value-field="product" relation-name="AssocProductAssoc" list="assocProductAssocs"/> > - <iterate list="assocProductAssocs" entry="assocProductAssoc"> > - <if-empty field="assocProductAssoc.thruDate"> > - <set from-field="nowTimestamp" field="assocProductAssoc.thruDate"/> > - <store-value value-field="assocProductAssoc"/> > - </if-empty> > - </iterate> > - </simple-method> > - > - <simple-method method-name="countProductView" short-description="Count Product View" login-required="false"> > - <if-empty field="parameters.weight"> > - <calculate field="parameters.weight" type="Long"><number value="1"/></calculate> > - </if-empty> > - <entity-one entity-name="ProductCalculatedInfo" value-field="productCalculatedInfo"/> > - <if-empty field="productCalculatedInfo"> > - <!-- go ahead and create it --> > - <make-value entity-name="ProductCalculatedInfo" value-field="productCalculatedInfo"/> > - <set from-field="parameters.productId" field="productCalculatedInfo.productId"/> > - <set from-field="parameters.weight" field="productCalculatedInfo.totalTimesViewed"/> > - <create-value value-field="productCalculatedInfo"/> > - <else> > - <calculate field="productCalculatedInfo.totalTimesViewed" type="Long"> > - <calcop operator="add" field="productCalculatedInfo.totalTimesViewed"> > - <calcop operator="get" field="parameters.weight"></calcop> > - </calcop> > - </calculate> > - <store-value value-field="productCalculatedInfo"/> > - </else> > - </if-empty> > - > - <!-- do the same for the virtual product... --> > - <entity-one entity-name="Product" value-field="product" use-cache="true"/> > - <call-class-method class-name="org.apache.ofbiz.product.product.ProductWorker" method-name="getVariantVirtualId" ret-field="virtualProductId"> > - <field field="product" type="GenericValue"/> > - </call-class-method> > - <if-not-empty field="virtualProductId"> > - <set from-field="virtualProductId" field="callSubMap.productId"/> > - <set from-field="parameters.weight" field="callSubMap.weight"/> > - <call-service service-name="countProductView" in-map-name="callSubMap"></call-service> > - </if-not-empty> > - </simple-method> > - > - <simple-method method-name="createProductReview" short-description="Create a ProductReview" login-required="false"> > - <make-value entity-name="ProductReview" value-field="newEntity"/> > - <set-nonpk-fields map="parameters" value-field="newEntity"/> > - <set from-field="userLogin.userLoginId" field="newEntity.userLoginId"/> > - <set value="PRR_PENDING" field="newEntity.statusId"/> > - > - <!-- code to check for auto-approved reviews (store setting) --> > - <entity-one entity-name="ProductStore" value-field="productStore"/> > - > - <if-not-empty field="productStore"> > - <if-compare field="productStore.autoApproveReviews" operator="equals" value="Y"> > - <set value="PRR_APPROVED" field="newEntity.statusId"/> > - </if-compare> > - </if-not-empty> > - > - <!-- auto approve the review if it is just a rating and has no review text --> > - <if-empty field="parameters.productReview"> > - <set value="PRR_APPROVED" field="newEntity.statusId"/> > - </if-empty> > - > - <!-- create the new ProductReview --> > - <sequenced-id sequence-name="ProductReview" field="newEntity.productReviewId"/> > - <field-to-result field="newEntity.productReviewId" result-name="productReviewId"/> > - > - <if-empty field="newEntity.postedDateTime"> > - <now-timestamp field="newEntity.postedDateTime"/> > - </if-empty> > - > - <create-value value-field="newEntity"/> > - > - <set from-field="newEntity.productId" field="productId"/> > - <property-to-field resource="ProductUiLabels" property="ProductCreateProductReviewSuccess" field="successMessage"/> > - <call-simple-method method-name="updateProductWithReviewRatingAvg"/> > - </simple-method> > - <simple-method method-name="updateProductReview" short-description="Update ProductReview"> > - <set value="updateProductReview" field="callingMethodName"/> > - <set value="UPDATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <make-value entity-name="ProductReview" value-field="lookupPKMap"/> > - <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"/> > - > - <set from-field="lookedUpValue.productId" field="productId"/> > - <call-simple-method method-name="updateProductWithReviewRatingAvg"/> > - </simple-method> > - <simple-method method-name="updateProductWithReviewRatingAvg" short-description="Update Product with new Review Rating Avg" login-required="false"> > - <!-- this method is meant to be called in-line and depends in a productId parameter --> > - <call-class-method class-name="org.apache.ofbiz.product.product.ProductWorker" method-name="getAverageProductRating" ret-field="averageCustomerRating"> > - <field field="delegator" type="org.apache.ofbiz.entity.Delegator"/> > - <field field="productId" type="java.lang.String"/> > - </call-class-method> > - <log level="info" message="Got new average customer rating ${averageCustomerRating}"/> > - <if-compare field="averageCustomerRating" operator="equals" value="0" type="BigDecimal"> > - <return/> > - </if-compare> > - <!-- update the review average on the ProductCalculatedInfo entity --> > - <entity-one entity-name="ProductCalculatedInfo" value-field="productCalculatedInfo"/> > - <if-empty field="productCalculatedInfo"> > - <!-- go ahead and create it --> > - <make-value entity-name="ProductCalculatedInfo" value-field="productCalculatedInfo"/> > - <set from-field="productId" field="productCalculatedInfo.productId"/> > - <set from-field="averageCustomerRating" field="productCalculatedInfo.averageCustomerRating"/> > - <create-value value-field="productCalculatedInfo"/> > - <else> > - <set from-field="averageCustomerRating" field="productCalculatedInfo.averageCustomerRating"/> > - <store-value value-field="productCalculatedInfo"/> > - </else> > - </if-empty> > - </simple-method> > - <simple-method method-name="copyToProductVariants" short-description="Updates the Product's Variants"> > - <set value="copyToProductVariants" field="callingMethodName"/> > - <set value="CREATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <set value="DELETE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <set from-field="parameters.virtualProductId" field="productFindContext.productId"/> > - <find-by-primary-key entity-name="Product" map="productFindContext" value-field="oldProduct"/> > - > - <set from-field="parameters.virtualProductId" field="variantsFindContext.productId"/> > - <set value="PRODUCT_VARIANT" field="variantsFindContext.productAssocTypeId"/> > - <find-by-and entity-name="ProductAssoc" map="variantsFindContext" list="variants"/> > - <filter-list-by-date list="variants"/> > - <iterate list="variants" entry="newProduct"> > - <set from-field="newProduct.productIdTo" field="productVariantContext.productId"/> > - <!-- if requested, duplicate related data --> > - <if-not-empty field="parameters.duplicatePrices"> > - <if-not-empty field="parameters.removeBefore"> > - <find-by-and entity-name="ProductPrice" map="productVariantContext" list="foundVariantValues"/> > - <iterate list="foundVariantValues" entry="foundVariantValue"> > - <remove-value value-field="foundVariantValue"/> > - </iterate> > - </if-not-empty> > - <find-by-and entity-name="ProductPrice" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="newProduct.productIdTo" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateIDs"> > - <if-not-empty field="parameters.removeBefore"> > - <find-by-and entity-name="GoodIdentification" map="productVariantContext" list="foundVariantValues"/> > - <iterate list="foundVariantValues" entry="foundVariantValue"> > - <remove-value value-field="foundVariantValue"/> > - </iterate> > - </if-not-empty> > - <find-by-and entity-name="GoodIdentification" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="newProduct.productIdTo" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateContent"> > - <if-not-empty field="parameters.removeBefore"> > - <find-by-and entity-name="ProductContent" map="productVariantContext" list="foundVariantValues"/> > - <iterate list="foundVariantValues" entry="foundVariantValue"> > - <remove-value value-field="foundVariantValue"/> > - </iterate> > - </if-not-empty> > - <find-by-and entity-name="ProductContent" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="newProduct.productIdTo" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateCategoryMembers"> > - <if-not-empty field="parameters.removeBefore"> > - <find-by-and entity-name="ProductCategoryMember" map="productVariantContext" list="foundVariantValues"/> > - <iterate list="foundVariantValues" entry="foundVariantValue"> > - <remove-value value-field="foundVariantValue"/> > - </iterate> > - </if-not-empty> > - <find-by-and entity-name="ProductCategoryMember" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="newProduct.productIdTo" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateAttributes"> > - <if-not-empty field="parameters.removeBefore"> > - <find-by-and entity-name="ProductAttribute" map="productVariantContext" list="foundVariantValues"/> > - <iterate list="foundVariantValues" entry="foundVariantValue"> > - <remove-value value-field="foundVariantValue"/> > - </iterate> > - </if-not-empty> > - <find-by-and entity-name="ProductAttribute" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="newProduct.productIdTo" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateFacilities"> > - <if-not-empty field="parameters.removeBefore"> > - <find-by-and entity-name="ProductFacility" map="productVariantContext" list="foundVariantValues"/> > - <iterate list="foundVariantValues" entry="foundVariantValue"> > - <remove-value value-field="foundVariantValue"/> > - </iterate> > - </if-not-empty> > - <find-by-and entity-name="ProductFacility" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="newProduct.productIdTo" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - <if-not-empty field="parameters.duplicateLocations"> > - <if-not-empty field="parameters.removeBefore"> > - <find-by-and entity-name="ProductFacilityLocation" map="productVariantContext" list="foundVariantValues"/> > - <iterate list="foundVariantValues" entry="foundVariantValue"> > - <remove-value value-field="foundVariantValue"/> > - </iterate> > - </if-not-empty> > - <find-by-and entity-name="ProductFacilityLocation" map="productFindContext" list="foundValues"/> > - <iterate list="foundValues" entry="foundValue"> > - <clone-value value-field="foundValue" new-value-field="newTempValue"/> > - <set from-field="newProduct.productIdTo" field="newTempValue.productId"/> > - <create-value value-field="newTempValue"/> > - </iterate> > - </if-not-empty> > - </iterate> > - </simple-method> > - > - <!-- a method 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="checkProductRelatedPermission" short-description="Check Product Related Permission"> > - <if-empty field="callingMethodName"> > - <property-to-field resource="CommonUiLabels" property="CommonPermissionThisOperation" field="callingMethodName"/> > - </if-empty> > - <if-empty field="checkAction"> > - <set value="UPDATE" field="checkAction"/> > - </if-empty> > - > - <!-- find all role-categories that this product is a member of --> > - <if> > - <condition> > - <not><if-has-permission permission="CATALOG" action="_${checkAction}"/></not> > - </condition> > - <then> > - <set from-field="parameters.productId" field="lookupRoleCategoriesMap.productId"/> > - <set from-field="userLogin.partyId" field="lookupRoleCategoriesMap.partyId"/> > - <set value="LTD_ADMIN" field="lookupRoleCategoriesMap.roleTypeId"/> > - <find-by-and entity-name="ProductCategoryMemberAndRole" map="lookupRoleCategoriesMap" list="roleCategories"/> > - <filter-list-by-date list="roleCategories"/> > - <filter-list-by-date list="roleCategories" from-field-name="roleFromDate" thru-field-name="roleThruDate"/> > - </then> > - </if> > - <if> > - <condition> > - <not> > - <or> > - <if-has-permission permission="CATALOG" action="_${checkAction}"/> > - <and> > - <if-has-permission permission="CATALOG_ROLE" action="_${checkAction}"/> > - <not><if-empty field="roleCategories"/></not> > - </and> > - <and> > - <not><if-empty field="alternatePermissionRoot"/></not> > - <if-has-permission permission="${alternatePermissionRoot}" action="_${checkAction}"/> > - </and> > - </or> > - </not> > - </condition> > - <then> > - <set field="checkActionLabel" value="${groovy: 'ProductCatalog' + checkAction.charAt(0) + checkAction.substring(1).toLowerCase() + 'PermissionError'}"/> > - <set field="resourceDescription" from-field="callingMethodName"/> > - <add-error> > - <fail-property resource="ProductUiLabels" property="${checkActionLabel}"/> > - </add-error> > - </then> > - </if> > - </simple-method> > - <simple-method method-name="productGenericPermission" 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="checkProductRelatedPermission"/> > - > - <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> > - <simple-method method-name="productPriceGenericPermission" short-description="product price 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> > - <check-permission permission="CATALOG_PRICE_MAINT"> > - <fail-property resource="ProductUiLabels" property="ProductPriceMaintPermissionError"/> > - </check-permission> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <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> > - > - <!-- ================================================================ --> > - <!-- ProductRole Services --> > - <!-- ================================================================ --> > - > - <simple-method method-name="addPartyToProduct" short-description="Add Party to Product"> > - <set value="addPartyToProduct" field="callingMethodName"/> > - <set value="CREATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <make-value entity-name="ProductRole" 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="updatePartyToProduct" short-description="Update Party to Product"> > - <set value="updatePartyToProduct" field="callingMethodName"/> > - <set value="UPDATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <make-value entity-name="ProductRole" value-field="lookupPKMap"/> > - <set-pk-fields map="parameters" value-field="lookupPKMap"/> > - <find-by-primary-key entity-name="ProductRole" map="lookupPKMap" value-field="lookedUpValue"/> > - <set-nonpk-fields map="parameters" value-field="lookedUpValue"/> > - <store-value value-field="lookedUpValue"/> > - </simple-method> > - <simple-method method-name="removePartyFromProduct" short-description="Remove Party From Product"> > - <set value="removePartyFromProduct" field="callingMethodName"/> > - <set value="DELETE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <make-value entity-name="ProductRole" value-field="lookupPKMap"/> > - <set-pk-fields map="parameters" value-field="lookupPKMap"/> > - <find-by-primary-key entity-name="ProductRole" map="lookupPKMap" value-field="lookedUpValue"/> > - <remove-value value-field="lookedUpValue"/> > - </simple-method> > - > - <!-- ProductCategoryGlAccount methods --> > - <simple-method method-name="createProductCategoryGlAccount" short-description="Create a ProductCategoryGlAccount"> > - <set value="createProductCategoryGlAccount" field="callingMethodName"/> > - <set value="CREATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <make-value entity-name="ProductCategoryGlAccount" 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="updateProductCategoryGlAccount" short-description="Update a ProductCategoryGlAccount"> > - <set value="updateProductCategoryGlAccount" field="callingMethodName"/> > - <set value="UPDATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <entity-one entity-name="ProductCategoryGlAccount" value-field="lookedUpValue"/> > - <set-nonpk-fields map="parameters" value-field="lookedUpValue"/> > - <store-value value-field="lookedUpValue"/> > - </simple-method> > - > - <simple-method method-name="deleteProductCategoryGlAccount" short-description="Delete a ProductCategoryGlAccount"> > - <set value="deleteProductCategoryGlAccount" field="callingMethodName"/> > - <set value="DELETE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <entity-one entity-name="ProductCategoryGlAccount" value-field="lookedUpValue"/> > - <remove-value value-field="lookedUpValue"/> > - </simple-method> > - > - <!-- Product GroupOrder Services --> > - <simple-method method-name="createProductGroupOrder" short-description="Create ProductGroupOrder"> > - <make-value entity-name="ProductGroupOrder" value-field="newEntity"/> > - <make-next-seq-id value-field="newEntity" seq-field-name="groupOrderId"/> > - <field-to-result field="newEntity.groupOrderId" result-name="groupOrderId"/> > - <set-nonpk-fields map="parameters" value-field="newEntity"/> > - <create-value value-field="newEntity"/> > - </simple-method> > - > - <simple-method method-name="updateProductGroupOrder" short-description="Update ProductGroupOrder"> > - <entity-one entity-name="ProductGroupOrder" value-field="productGroupOrder"/> > - <set-nonpk-fields map="parameters" value-field="productGroupOrder"/> > - <store-value value-field="productGroupOrder"/> > - > - <if-compare field="productGroupOrder.statusId" operator="equals" value="GO_CREATED"> > - <entity-one entity-name="JobSandbox" value-field="jobSandbox"> > - <field-map field-name="jobId" from-field="productGroupOrder.jobId"/> > - </entity-one> > - <if-not-empty field="jobSandbox"> > - <set field="jobSandbox.runTime" from-field="parameters.thruDate"/> > - <store-value value-field="jobSandbox"/> > - </if-not-empty> > - </if-compare> > - </simple-method> > - > - <simple-method method-name="deleteProductGroupOrder" short-description="Delete ProductGroupOrder"> > - <entity-and entity-name="OrderItemGroupOrder" list="orderItemGroupOrders"> > - <field-map field-name="groupOrderId" from-field="parameters.groupOrderId"/> > - </entity-and> > - <iterate list="orderItemGroupOrders" entry="orderItemGroupOrder"> > - <remove-value value-field="orderItemGroupOrder"/> > - </iterate> > - > - <entity-one entity-name="ProductGroupOrder" value-field="productGroupOrder"/> > - <remove-value value-field="productGroupOrder"/> > - > - <entity-one entity-name="JobSandbox" value-field="jobSandbox"> > - <field-map field-name="jobId" from-field="productGroupOrder.jobId"/> > - </entity-one> > - <remove-value value-field="jobSandbox"/> > - > - <entity-and entity-name="JobSandbox" list="jobSandboxList"> > - <field-map field-name="runtimeDataId" from-field="jobSandbox.runtimeDataId"/> > - </entity-and> > - <iterate list="jobSandboxList" entry="jobSandboxRelatedRuntimeData"> > - <remove-value value-field="jobSandboxRelatedRuntimeData"/> > - </iterate> > - > - <entity-one entity-name="RuntimeData" value-field="runtimeData"> > - <field-map field-name="runtimeDataId" from-field="jobSandbox.runtimeDataId"/> > - </entity-one> > - <remove-value value-field="runtimeData"/> > - </simple-method> > - > - <simple-method method-name="createJobForProductGroupOrder" short-description="Create ProductGroupOrder"> > - <entity-one entity-name="ProductGroupOrder" value-field="productGroupOrder"/> > - <if-empty field="productGroupOrder.jobId"> > - <!-- Create RuntimeData For ProductGroupOrder --> > - <set field="runtimeDataMap.groupOrderId" from-field="parameters.groupOrderId"/> > - <call-class-method class-name="org.apache.ofbiz.entity.serialize.XmlSerializer" method-name="serialize" ret-field="runtimeInfo"> > - <field field="runtimeDataMap" type="Object"/> > - </call-class-method> > - <make-value entity-name="RuntimeData" value-field="runtimeData"/> > - <sequenced-id sequence-name="RuntimeData" field="runtimeData.runtimeDataId"/> > - <set field="runtimeDataId" from-field="runtimeData.runtimeDataId"/> > - <set field="runtimeData.runtimeInfo" from-field="runtimeInfo"/> > - <create-value value-field="runtimeData"/> > - > - <!-- Create Job For ProductGroupOrder --> > - <!-- FIXME: Jobs should not be manually created --> > - <make-value entity-name="JobSandbox" value-field="jobSandbox"/> > - <sequenced-id sequence-name="JobSandbox" field="jobSandbox.jobId"/> > - <set field="jobId" from-field="jobSandbox.jobId"/> > - <set field="jobSandbox.jobName" value="Check ProductGroupOrder Expired"/> > - <set field="jobSandbox.runTime" from-field="parameters.thruDate"/> > - <set field="jobSandbox.poolId" value="pool"/> > - <set field="jobSandbox.statusId" value="SERVICE_PENDING"/> > - <set field="jobSandbox.serviceName" value="checkProductGroupOrderExpired"/> > - <set field="jobSandbox.runAsUser" value="system"/> > - <set field="jobSandbox.runtimeDataId" from-field="runtimeDataId"/> > - <set field="jobSandbox.maxRecurrenceCount" value="1" type="Long"/> > - <set field="jobSandbox.priority" value="50" type="Long"/> > - <create-value value-field="jobSandbox"/> > - > - <set field="productGroupOrder.jobId" from-field="jobId"/> > - <store-value value-field="productGroupOrder"/> > - </if-empty> > - </simple-method> > - > - <simple-method method-name="checkOrderItemForProductGroupOrder" short-description="Check OrderItem For ProductGroupOrder"> > - <entity-and entity-name="OrderItem" list="orderItems"> > - <field-map field-name="orderId" from-field="parameters.orderId"/> > - </entity-and> > - <iterate list="orderItems" entry="orderItem"> > - <set field="productId" from-field="orderItem.productId"/> > - <entity-one entity-name="Product" value-field="product"> > - <field-map field-name="productId" from-field="orderItem.productId"/> > - </entity-one> > - <if-compare field="product.isVariant" operator="equals" value="Y"> > - <entity-and entity-name="ProductAssoc" list="variantProductAssocs" filter-by-date="true"> > - <field-map field-name="productIdTo" from-field="orderItem.productId"/> > - <field-map field-name="productAssocTypeId" value="PRODUCT_VARIANT"/> > - </entity-and> > - <first-from-list list="variantProductAssocs" entry="variantProductAssoc"/> > - <set field="productId" from-field="variantProductAssoc.productId"/> > - </if-compare> > - > - <entity-and entity-name="ProductGroupOrder" list="productGroupOrders" filter-by-date="true"> > - <field-map field-name="productId" from-field="productId"/> > - </entity-and> > - <if-not-empty field="productGroupOrders"> > - <first-from-list list="productGroupOrders" entry="productGroupOrder"/> > - <calculate field="productGroupOrder.soldOrderQty"> > - <calcop operator="add" field="productGroupOrder.soldOrderQty"> > - <calcop operator="get" field="orderItem.quantity"/> > - </calcop> > - </calculate> > - <store-value value-field="productGroupOrder"/> > - > - <set field="createOrderItemGroupOrderMap.orderId" from-field="orderItem.orderId"/> > - <set field="createOrderItemGroupOrderMap.orderItemSeqId" from-field="orderItem.orderItemSeqId"/> > - <set field="createOrderItemGroupOrderMap.groupOrderId" from-field="productGroupOrder.groupOrderId"/> > - <call-service service-name="createOrderItemGroupOrder" in-map-name="createOrderItemGroupOrderMap"/> > - </if-not-empty> > - </iterate> > - </simple-method> > - > - <simple-method method-name="cancleOrderItemGroupOrder" short-description="Cancle OrderItemGroupOrder"> > - <if-not-empty field="parameters.orderItemSeqId"> > - <entity-and entity-name="OrderItem" list="orderItems"> > - <field-map field-name="orderId" from-field="parameters.orderId"/> > - <field-map field-name="orderItemSeqId" from-field="parameters.orderItemSeqId" /> > - </entity-and> > - <else> > - <entity-and entity-name="OrderItem" list="orderItems"> > - <field-map field-name="orderId" from-field="parameters.orderId"/> > - </entity-and> > - </else> > - </if-not-empty> > - <iterate list="orderItems" entry="orderItem"> > - <entity-and entity-name="OrderItemGroupOrder" list="orderItemGroupOrders"> > - <field-map field-name="orderId" from-field="orderItem.orderId"/> > - <field-map field-name="orderItemSeqId" from-field="orderItem.orderItemSeqId"/> > - </entity-and> > - <if-not-empty field="orderItemGroupOrders"> > - <first-from-list list="orderItemGroupOrders" entry="orderItemGroupOrder"/> > - <entity-one entity-name="ProductGroupOrder" value-field="productGroupOrder"> > - <field-map field-name="groupOrderId" from-field="orderItemGroupOrder.groupOrderId"/> > - </entity-one> > - <if-not-empty field="productGroupOrder"> > - <if-compare field="productGroupOrder.statusId" operator="equals" value="GO_CREATED"> > - <if-compare field="orderItem.statusId" operator="equals" value="ITEM_CANCELLED"> > - <if-not-empty field="orderItem.cancelQuantity"> > - <set field="cancelQuantity" from-field="orderItem.cancelQuantity"/> > - <else> > - <set field="cancelQuantity" from-field="orderItem.quantity"/> > - </else> > - </if-not-empty> > - <calculate field="productGroupOrder.soldOrderQty"> > - <calcop operator="subtract" field="productGroupOrder.soldOrderQty"> > - <calcop operator="get" field="cancelQuantity"/> > - </calcop> > - </calculate> > - </if-compare> > - <store-value value-field="productGroupOrder"/> > - <remove-value value-field="orderItemGroupOrder"/> > - </if-compare> > - </if-not-empty> > - </if-not-empty> > - </iterate> > - </simple-method> > - > - <simple-method method-name="checkProductGroupOrderExpired" short-description="Check ProductGroupOrder Expired"> > - <entity-one entity-name="ProductGroupOrder" value-field="productGroupOrder"/> > - <if-not-empty field="productGroupOrder"> > - <if-compare field="productGroupOrder.soldOrderQty" operator="greater-equals" value="${productGroupOrder.reqOrderQty}"> > - <set field="newItemStatusId" value="ITEM_APPROVED"/> > - <set field="groupOrderStatusId" value="GO_SUCCESS"/> > - <else> > - <set field="newItemStatusId" value="ITEM_CANCELLED"/> > - <set field="groupOrderStatusId" value="GO_CANCELLED"/> > - </else> > - </if-compare> > - > - <set field="updateProductGroupOrderMap.groupOrderId" from-field="productGroupOrder.groupOrderId"/> > - <set field="updateProductGroupOrderMap.statusId" from-field="groupOrderStatusId"/> > - <call-service service-name="updateProductGroupOrder" in-map-name="updateProductGroupOrderMap"/> > - > - <entity-and entity-name="OrderItemGroupOrder" list="orderItemGroupOrders"> > - <field-map field-name="groupOrderId" from-field="productGroupOrder.groupOrderId"/> > - </entity-and> > - <iterate list="orderItemGroupOrders" entry="orderItemGroupOrder"> > - <set field="changeOrderItemStatusMap.orderId" from-field="orderItemGroupOrder.orderId"/> > - <set field="changeOrderItemStatusMap.orderItemSeqId" from-field="orderItemGroupOrder.orderItemSeqId"/> > - <set field="changeOrderItemStatusMap.statusId" from-field="newItemStatusId"/> > - <call-service service-name="changeOrderItemStatus" in-map-name="changeOrderItemStatusMap"/> > - </iterate> > - </if-not-empty> > - </simple-method> > - > - <simple-method method-name="setProductReviewStatus" short-description="change the product review Status"> > - <set value="setProductReviewStatus" field="callingMethodName"/> > - <set value="UPDATE" field="checkAction"/> > - <call-simple-method method-name="checkProductRelatedPermission"/> > - <check-errors/> > - > - <entity-one entity-name="ProductReview" value-field="productReview"/> > - <if-not-empty field="productReview"> > - <if-compare-field field="productReview.statusId" to-field="parameters.statusId" operator="not-equals"> > - <entity-one entity-name="StatusValidChange" value-field="statusChange"> > - <field-map field-name="statusId" from-field="productReview.statusId"/> > - <field-map field-name="statusIdTo" from-field="parameters.statusId"/> > - </entity-one> > - <if-empty field="statusChange"> > - <set field="msg" value="Status is not a valid change: from ${productReview.statusId} to ${parameters.statusId}"/> > - <log level="error" message="${msg}"/> > - <add-error> > - <fail-property resource="ProductErrorUiLabels" property="ProductReviewErrorCouldNotChangeOrderStatusFromTo"/> > - </add-error> > - </if-empty> > - </if-compare-field> > - </if-not-empty> > - <check-errors/> > - > - <set field="productReview.statusId" from-field="parameters.statusId"/> > - <store-value value-field="productReview"/> > - <field-to-result field="productReview.productReviewId" result-name="productReviewId"/> > - </simple-method> > -</simple-methods> > diff --git a/applications/product/servicedef/services.xml b/applications/product/servicedef/services.xml > index 4e821b4..b44cba7 100644 > --- a/applications/product/servicedef/services.xml > +++ b/applications/product/servicedef/services.xml > @@ -37,22 +37,22 @@ under the License. > <override name="description" allow-html="safe"/> > <override name="longDescription" allow-html="safe"/> > </service> > - <service name="createProduct" default-entity-name="Product" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="createProduct" auth="true"> > + <service name="createProduct" default-entity-name="Product" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="createProduct" auth="true"> > <description>Create a Product</description> > <implements service="interfaceProduct"/> > <auto-attributes include="pk" mode="INOUT" optional="true"/> > <override name="productTypeId" optional="false"/> > <override name="internalName" optional="false"/> > </service> > - <service name="updateProduct" default-entity-name="Product" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="updateProduct" auth="true"> > + <service name="updateProduct" default-entity-name="Product" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="updateProduct" auth="true"> > <description>Update a Product</description> > <implements service="interfaceProduct"/> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > - <service name="updateProductQuickAdminName" default-entity-name="Product" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="updateProductQuickAdminName" auth="true"> > + <service name="updateProductQuickAdminName" default-entity-name="Product" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="updateProductQuickAdminName" auth="true"> > <description>Update a Product from Quick Admin</description> > <implements service="interfaceProduct"/> > <auto-attributes include="pk" mode="IN" optional="false"/> > @@ -63,8 +63,8 @@ under the License. > <implements service="interfaceProduct"/> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > - <service name="duplicateProduct" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="duplicateProduct" auth="true"> > + <service name="duplicateProduct" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="duplicateProduct" auth="true"> > <description>Duplicate a Product using a new productId</description> > <attribute name="productId" type="String" mode="IN" optional="false"/> > <attribute name="oldProductId" type="String" mode="IN" optional="false"/> > @@ -89,8 +89,8 @@ under the License. > <attribute name="removeFeatureAppls" type="String" mode="IN" optional="true"/> > <attribute name="removeInventoryItems" type="String" mode="IN" optional="true"/> > </service> > - <service name="copyToProductVariants" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="copyToProductVariants" auth="true"> > + <service name="copyToProductVariants" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="copyToProductVariants" auth="true"> > <description>Copy Virtual Product's data to the Variant Products</description> > <attribute name="virtualProductId" type="String" mode="IN" optional="false"/> > <attribute name="removeBefore" type="String" mode="IN" optional="true"/> > @@ -151,40 +151,40 @@ under the License. > <permission-service service-name="productGenericPermission" main-action="DELETE"/> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > - <service name="deleteProductKeywords" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="deleteProductKeywords" auth="true"> > + <service name="deleteProductKeywords" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="deleteProductKeywords" auth="true"> > <description>Delete all the keywords of a product</description> > <permission-service service-name="productGenericPermission" main-action="DELETE"/> > <attribute name="productId" type="String" mode="IN" optional="false"/> > </service> > - <service name="indexProductKeywords" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="indexProductKeywords" auth="false"> > + <service name="indexProductKeywords" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="indexProductKeywords" auth="false"> > <description>Index the Keywords for a Product</description> > <attribute name="productId" type="String" mode="IN" optional="false"/> > <attribute name="productInstance" type="org.apache.ofbiz.entity.GenericValue" mode="IN" optional="true"/> > </service> > - <service name="forceIndexProductKeywords" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="forceIndexProductKeywords" auth="true"> > + <service name="forceIndexProductKeywords" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="forceIndexProductKeywords" auth="true"> > <description>Induce all the keywords of a product, ignoring the flag in the Product.autoCreateKeywords flag</description> > <permission-service service-name="productGenericPermission" main-action="CREATE"/> > <attribute name="productId" type="String" mode="IN" optional="false"/> > </service> > > - <service name="discontinueProductSales" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="discontinueProductSales" auth="false"> > + <service name="discontinueProductSales" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="discontinueProductSales" auth="false"> > <description>Discontinue Product Sales</description> > <attribute name="productId" type="String" mode="IN" optional="false"/> > </service> > > - <service name="countProductView" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="countProductView" auth="false"> > + <service name="countProductView" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="countProductView" auth="false"> > <description>count Product View</description> > <attribute name="productId" type="String" mode="IN" optional="false"/> > <attribute name="weight" type="Long" mode="IN" optional="true"/> > </service> > > - <service name="createProductReview" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="createProductReview" auth="true"> > + <service name="createProductReview" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="createProductReview" auth="true"> > <description>Create a product review entity</description> > <auto-attributes entity-name="ProductReview" mode="IN" include="nonpk" optional="true"/> > <attribute name="productReviewId" type="String" mode="OUT" optional="false"/> > @@ -192,8 +192,8 @@ under the License. > <override name="productId" optional="false"/> > <override name="productRating" optional="false"/> > </service> > - <service name="updateProductReview" engine="simple" default-entity-name="ProductReview" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="updateProductReview" auth="true"> > + <service name="updateProductReview" engine="groovy" default-entity-name="ProductReview" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="updateProductReview" auth="true"> > <description>Updates a product review record</description> > <required-permissions join-type="OR"> > <check-permission permission="CATALOG_UPDATE"/> > @@ -202,8 +202,8 @@ under the License. > <auto-attributes mode="IN" include="pk" optional="false"/> > <auto-attributes mode="IN" include="nonpk" optional="true"/> > </service> > - <service name="setProductReviewStatus" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="setProductReviewStatus" auth="true"> > + <service name="setProductReviewStatus" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="setProductReviewStatus" auth="true"> > <description>Updates a product review record</description> > <required-permissions join-type="OR"> > <check-permission permission="CATALOG_UPDATE"/> > @@ -784,8 +784,8 @@ under the License. > <attribute name="fromDate" type="Timestamp" mode="IN" optional="false"/> > </service> > > - <service name="addPartyToProduct" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="addPartyToProduct" auth="true"> > + <service name="addPartyToProduct" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="addPartyToProduct" auth="true"> > <description>Add Party To Product</description> > <attribute name="productId" type="String" mode="IN" optional="false"/> > <attribute name="partyId" type="String" mode="IN" optional="false"/> > @@ -795,8 +795,8 @@ under the License. > <attribute name="sequenceNum" type="Long" mode="IN" optional="true"/> > <attribute name="comments" type="String" mode="IN" optional="true"/> > </service> > - <service name="updatePartyToProduct" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="updatePartyToProduct" auth="true"> > + <service name="updatePartyToProduct" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="updatePartyToProduct" auth="true"> > <description>Update Party To Product</description> > <attribute name="productId" type="String" mode="IN" optional="false"/> > <attribute name="partyId" type="String" mode="IN" optional="false"/> > @@ -806,8 +806,8 @@ under the License. > <attribute name="sequenceNum" type="Long" mode="IN" optional="true"/> > <attribute name="comments" type="String" mode="IN" optional="true"/> > </service> > - <service name="removePartyFromProduct" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="removePartyFromProduct" auth="true"> > + <service name="removePartyFromProduct" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="removePartyFromProduct" auth="true"> > <description>Remove Party From Product</description> > <attribute name="productId" type="String" mode="IN" optional="false"/> > <attribute name="partyId" type="String" mode="IN" optional="false"/> > @@ -1240,16 +1240,16 @@ under the License. > </service> > > <!-- Permission Services --> > - <service name="productGenericPermission" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="productGenericPermission"> > + <service name="productGenericPermission" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="productGenericPermission"> > <implements service="permissionInterface"/> > </service> > <service name="productCategoryGenericPermission" engine="groovy" > location="component://product/groovyScripts/product/category/CategoryServices.groovy" invoke="productCategoryGenericPermission"> > <implements service="permissionInterface"/> > </service> > - <service name="productPriceGenericPermission" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="productPriceGenericPermission"> > + <service name="productPriceGenericPermission" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="productPriceGenericPermission"> > <implements service="permissionInterface"/> > </service> > <service name="checkCategoryPermissionWithViewPurchaseAllow" engine="groovy" > @@ -1285,20 +1285,20 @@ under the License. > </service> > > <!-- ProductCategoryGlAccount Services --> > - <service name="createProductCategoryGlAccount" default-entity-name="ProductCategoryGlAccount" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="createProductCategoryGlAccount" auth="true"> > + <service name="createProductCategoryGlAccount" default-entity-name="ProductCategoryGlAccount" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="createProductCategoryGlAccount" auth="true"> > <description>Create a ProductCategoryGlAccount</description> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="false"/> > </service> > - <service name="updateProductCategoryGlAccount" default-entity-name="ProductCategoryGlAccount" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="updateProductCategoryGlAccount" auth="true"> > + <service name="updateProductCategoryGlAccount" default-entity-name="ProductCategoryGlAccount" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="updateProductCategoryGlAccount" auth="true"> > <description>Update a ProductCategoryGlAccount</description> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="false"/> > </service> > - <service name="deleteProductCategoryGlAccount" default-entity-name="ProductCategoryGlAccount" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="deleteProductCategoryGlAccount" auth="true"> > + <service name="deleteProductCategoryGlAccount" default-entity-name="ProductCategoryGlAccount" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="deleteProductCategoryGlAccount" auth="true"> > <description>Delete a ProductCategoryGlAccount</description> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > @@ -1608,48 +1608,48 @@ under the License. > </service> > > <!-- Product GroupOrder Services --> > - <service name="createProductGroupOrder" default-entity-name="ProductGroupOrder" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="createProductGroupOrder" auth="true"> > + <service name="createProductGroupOrder" default-entity-name="ProductGroupOrder" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="createProductGroupOrder" auth="true"> > <description>Create ProductGroupOrder</description> > <auto-attributes include="pk" mode="OUT" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > </service> > > - <service name="updateProductGroupOrder" default-entity-name="ProductGroupOrder" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="updateProductGroupOrder" auth="true"> > + <service name="updateProductGroupOrder" default-entity-name="ProductGroupOrder" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="updateProductGroupOrder" auth="true"> > <description>Update ProductGroupOrder</description> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > </service> > > - <service name="deleteProductGroupOrder" default-entity-name="ProductGroupOrder" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="deleteProductGroupOrder" auth="true"> > + <service name="deleteProductGroupOrder" default-entity-name="ProductGroupOrder" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="deleteProductGroupOrder" auth="true"> > <description>Delete ProductGroupOrder</description> > <auto-attributes include="pk" mode="IN" optional="false"/> > </service> > > - <service name="createJobForProductGroupOrder" default-entity-name="ProductGroupOrder" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="createJobForProductGroupOrder" auth="true"> > + <service name="createJobForProductGroupOrder" default-entity-name="ProductGroupOrder" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="createJobForProductGroupOrder" auth="true"> > <description>Create Job For ProductGroupOrder</description> > <auto-attributes include="pk" mode="IN" optional="false"/> > <auto-attributes include="nonpk" mode="IN" optional="true"/> > </service> > > - <service name="checkOrderItemForProductGroupOrder" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="checkOrderItemForProductGroupOrder" auth="true"> > + <service name="checkOrderItemForProductGroupOrder" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="checkOrderItemForProductGroupOrder" auth="true"> > <description>Check OrderItem For ProductGroupOrder</description> > <attribute name="orderId" mode="IN" type="String" optional="false"/> > </service> > > - <service name="cancleOrderItemGroupOrder" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="cancleOrderItemGroupOrder" auth="true"> > + <service name="cancleOrderItemGroupOrder" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="cancleOrderItemGroupOrder" auth="true"> > <description>Cancle OrderItemGroupOrder</description> > <attribute name="orderId" mode="IN" type="String" optional="false"/> > <attribute name="orderItemSeqId" type="String" mode="IN" optional="true"/> > </service> > > - <service name="checkProductGroupOrderExpired" engine="simple" > - location="component://product/minilang/product/product/ProductServices.xml" invoke="checkProductGroupOrderExpired" auth="true"> > + <service name="checkProductGroupOrderExpired" engine="groovy" > + location="component://product/groovyScripts/product/product/ProductServices.groovy" invoke="checkProductGroupOrderExpired" auth="true"> > <description>Check ProductGroupOrder Expired</description> > <attribute name="groupOrderId" mode="IN" type="String" optional="false"/> > </service> > pEpkey.asc (2K) Download Attachment |
Hi Nicolas,
great, thanks for reviewing and improving the code! Please go ahead and commit, thanks, Michael Brohl ecomify GmbH - www.ecomify.de Am 27.02.20 um 16:22 schrieb Nicolas Malin: > Michael, I have lot of improvement to share with your commit (groovy > syntax, code simplification) > > Do you prefer keep the hand, or I commit directly ? > > You can find some diff on my starting work hereĀ [1] > > Cheers, > > Nicolas > > [1] > https://github.com/nmalin/ApacheOFBiz/compare/ProductService.groovy?expand=1 > > On 21/02/2020 17:51, [hidden email] wrote: >> This is an automated email from the ASF dual-hosted git repository. >> >> mbrohl pushed a commit to branch trunk >> in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git >> >> >> The following commit(s) were added to refs/heads/trunk by this push: >> new e0a26fc Improved: Convert ProductServices.xml mini lang to groovy (OFBIZ-10231) >> e0a26fc is described below >> >> commit e0a26fce43eec7c84d87c0d5055ff0a87f2af796 >> Author: Michael Brohl <[hidden email]> >> AuthorDate: Fri Feb 21 16:59:37 2020 +0100 >> >> Improved: Convert ProductServices.xml mini lang to groovy >> (OFBIZ-10231) >> >> Thanks Dennis Balkir for reporting and Sebastian Berg for the implementation. smime.p7s (5K) Download Attachment |
Free forum by Nabble | Edit this page |