diff --git a/applications/product/groovyScripts/product/catalog/CatalogServices.groovy b/applications/product/groovyScripts/product/catalog/CatalogServices.groovy new file mode 100644 index 00000000000..67dcf7fc458 --- /dev/null +++ b/applications/product/groovyScripts/product/catalog/CatalogServices.groovy @@ -0,0 +1,421 @@ +/* + * 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.UtilURL +import org.apache.ofbiz.entity.GenericValue +import org.apache.ofbiz.entity.util.EntityUtilProperties +import org.apache.ofbiz.service.ServiceUtil + +/** + * get All categories + */ +def getAllCategories() { + String defaultTopCategoryId = parameters.topCategory ?: EntityUtilProperties.getPropertyValue("catalog", "top.category.default", delegator) + Map serviceRes = run service: "getRelatedCategories", with: [parentProductCategoryId: defaultTopCategoryId] + return serviceRes +} + +def getRelatedCategories() { + Map result = success() + List categories = [] + List rollups = from("ProductCategoryRollup") + .where("parentProductCategoryId", parameters.parentProductCategoryId) + .orderBy("sequenceNum") + .queryList() + if (parameters.categories) { + categories.addAll(parameters.categories) + } + if (rollups) { + List subCategories = [] + for (GenericValue parent: rollups) { + subCategories << parent.getRelatedOne("CurrentProductCategory", true) + } + if (subCategories) { + Set distinctCategories = categories? [*categories] as Set: [] as Set + Map relatedCategoryContext = [categories: subCategories] + for (Map subCategory: subCategories) { + relatedCategoryContext.parentProductCategoryId = subCategory.productCategoryId + Map res = run service: "getRelatedCategories", with: relatedCategoryContext + if (res.categories) { + distinctCategories.addAll(res.categories) + } + } + categories = distinctCategories as List + } + } else { + GenericValue productCategory = from("ProductCategory") + .where("productCategoryId", parameters.parentProductCategoryId) + .queryOne() + categories << productCategory + } + result.categories = categories + return result +} + + +/** + * Check if image url exists or not for all categories + */ +def checkImageUrlForAllCategories() { + Map result = success() + Map gacRes = run service: "getAllCategories", with: parameters + List categories = gacRes.categories + if (categories) { + Map categoriesMap = [:] + // get the category from categories + for (Map category : categories) { + Map ciufcapRes = run service: "checkImageUrlForCategoryAndProduct", with: [categoryId: category.productCategoryId] + Map fileStatusMap = [fileExists: ciufcapRes.fileExists, fileNotExists: ciufcapRes.fileNotExists] + String categoryId = category.productCategoryId + categoriesMap[categoryId] = fileStatusMap + } + result.categoriesMap = categoriesMap + } + return result +} + + +/** + * Check if image url exists or not for category and product + */ +def checkImageUrlForCategoryAndProduct() { + Map result = success() + Map gpcmRes = run service: "getProductCategoryMembers", with: parameters + List categoryMembers = gpcmRes.categoryMembers + Map category = gpcmRes.category + + List fileExists = [] + List fileNotExists = [] + Map filesImageMap = [:] + // Get category images and check it exists or not + if (category) { + Map ciufcRes = run service: "checkImageUrlForCategory", with: [categoryId: category.productCategoryId] + filesImageMap = ciufcRes.filesImageMap + + if (filesImageMap) { + fileImageExists("categoryImageUrlMap", "categoryImageUrl", filesImageMap, fileExists, fileNotExists) + fileImageExists("linkOneImageUrlMap", "linkOneImageUrl", filesImageMap, fileExists, fileNotExists) + fileImageExists("linkTwoImageUrlMap", "linkTwoImageUrl", filesImageMap, fileExists, fileNotExists) + } + } + + if (categoryMembers) { + for (GenericValue productCategoryMember : categoryMembers) { + Map ciufpRes = run service: "checkImageUrlForProduct", with: [productId: productCategoryMember.productId] + filesImageMap = ciufpRes.filesImageMap + + if (filesImageMap) { + fileImageExists("smallImageUrlMap", "smallImageUrl", filesImageMap, fileExists, fileNotExists) + fileImageExists("mediumImageUrlMap", "mediumImageUrl", filesImageMap, fileExists, fileNotExists) + fileImageExists("largeImageUrlMap", "largeImageUrl", filesImageMap, fileExists, fileNotExists) + fileImageExists("detailImageUrlMap", "detailImageUrl", filesImageMap, fileExists, fileNotExists) + } + + /* Case for virtual product + get related assoc product */ + Map product = productCategoryMember.getRelatedOne("Product", false) + if ("Y" == product.isVirtual) { + Map virtualProductContext = [ + productId: product.productId, + productAssocTypeId: "PRODUCT_VARIANT" + ] + List variantProducts = from("ProductAssoc") + .where(virtualProductContext) + .filterByDate() + .queryList() + if (variantProducts) { + for (Map variantProduct : variantProducts) { + Map res = run service: "checkImageUrlForProduct", with: [productId: variantProduct.productIdTo] + filesImageMap = res.filesImageMap + if (filesImageMap) { + fileImageExists("smallImageUrlMap", "smallImageUrl", filesImageMap, fileExists, fileNotExists) + fileImageExists("mediumImageUrlMap", "mediumImageUrl", filesImageMap, fileExists, fileNotExists) + fileImageExists("largeImageUrlMap", "largeImageUrl", filesImageMap, fileExists, fileNotExists) + fileImageExists("detailImageUrlMap", "detailImageUrl", filesImageMap, fileExists, fileNotExists) + } + } + } + } + } + result.fileExists = fileExists + result.fileNotExists = fileNotExists + } + return result +} + +/** + * This Method checks if the images exist and puts them into + * the lists filesExist and filesNotExist. + *

+ * The lists filesExist and filesNotExist are filled with the new values. + * @param map + * @param key + * @param filesImageMap + * @param fileExists + * @param fileNotExists + */ +def fileImageExists(map, key, filesImageMap, fileExists, fileNotExists) { + if (filesImageMap."${map}"?."${key}") { + if ("Y" == filesImageMap."${map}".isExists) { + fileExists.add(filesImageMap."${map}"."${key}") + } else { + fileNotExists.add(filesImageMap."${map}"."${key}") + } + } +} + +/** + * This service gets the category id and checks if + * all the images of category exists or not + */ +def checkImageUrlForCategory() { + Map result = success() + Map filesImageMap = [:] + GenericValue category = from("ProductCategory") + .where("productCategoryId", parameters.categoryId) + .queryOne() + if (category) { + // check for category image url + imageUrlCheck(category, "categoryImageUrl", filesImageMap) + // check for link image url + imageUrlCheck(category, "linkOneImageUrl", filesImageMap) + // check for link two image url + imageUrlCheck(category, "linkTwoImageUrl", filesImageMap) + category.store() + if (filesImageMap) { + result.filesImageMap = filesImageMap + } + } + return result +} + +/** + * Check if image url exists or not for product + */ +def checkImageUrlForProduct() { + Map result = success() + Map filesImageMap = [:] + if (parameters.productId) { + Map product = from("Product").where(parameters).queryOne() + // check for small image url + imageUrlCheck(product, "smallImageUrl", filesImageMap) + // check for medium image url + imageUrlCheck(product, "mediumImageUrl", filesImageMap) + // check for large image url + imageUrlCheck(product, "largeImageUrl", filesImageMap) + // check for detail image url + imageUrlCheck(product, "detailImageUrl", filesImageMap) + if (filesImageMap) { + result.filesImageMap = filesImageMap + } + product.store() + } + return result +} + +/** + * This method fills filesImageMap with the needed content and sets the relevant type in + * the prodOrCat (product or category) map to null, if there is no image existent for this type + * @param prodOrCat + * @param filesImageMap + * @param imageType + * @return + */ +def imageUrlCheck(prodOrCat, imageType, filesImageMap) { + if (prodOrCat."${imageType}") { + Map res = run service: "checkImageUrl", with: [imageUrl: prodOrCat."${imageType}"] + String isExists = res.isExists + filesImageMap."${imageType}Map" = [:] + filesImageMap."${imageType}Map"."${imageType}" = prodOrCat."${imageType}" + filesImageMap."${imageType}Map".isExists = isExists + if (isExists == "N") { + prodOrCat."${imageType}" = null + } + } +} + +/** + * Check if image url exists or not + */ +def checkImageUrl() { + def imageUrl = parameters.imageUrl + boolean httpFlag = imageUrl.startsWith("http") + boolean ftpFlag = imageUrl.startsWith("ftp") + String url = httpFlag || ftpFlag + ? UtilURL.fromUrlString(imageUrl) + : UtilURL.fromOfbizHomePath("/themes/common-theme/webapp" + imageUrl) + Map result = success() + result.isExists = url ? "Y" : "N" + return result +} + +/** + * Catalog permission logic + */ +def catalogPermissionCheck() { + parameters.primaryPermission = "CATALOG" + Map result = run service: "genericBasePermissionCheck", with: parameters + return result +} + +/** + * ProdCatalogToParty permission logic + */ +def prodCatalogToPartyPermissionCheck() { + parameters.altPermission = "PARTYMGR" + return catalogPermissionCheck() +} + +/** + * create missing category and product alternative urls + */ +def createMissingCategoryAndProductAltUrls() { + Timestamp now = UtilDateTime.nowTimestamp() + Map result = success() + result.prodCatalogId = parameters.prodCatalogId + int categoriesNotUpdated = 0 + int categoriesUpdated = 0 + int productsNotUpdated = 0 + int productsUpdated = 0 + String checkProduct = parameters.product + String checkCategory = parameters.category + List prodCatalogCategoryList = from("ProdCatalogCategory").where("prodCatalogId", parameters.prodCatalogId).queryList() + + // get all categories + List productCategories = [] + for (GenericValue prodCatalog: prodCatalogCategoryList) { + productCategories.addAll(createMissingCategoryAltUrlInline(prodCatalog.productCategoryId)) + } + + for (Map productCategoryList : productCategories) { + // create product category alternative URLs + if (checkCategory) { + List productCategoryContentAndInfoList = from("ProductCategoryContentAndInfo") + .where("productCategoryId", productCategoryList.productCategoryId, + "prodCatContentTypeId", "ALTERNATIVE_URL") + .filterByDate() + .orderBy("-fromDate") + .cache() + .queryList() + if (!productCategoryContentAndInfoList) { + Map createSimpleTextContentForCategoryCtx = [ + fromDate: now, + prodCatContentTypeId: "ALTERNATIVE_URL", + localeString: "en", + productCategoryId: productCategoryList.productCategoryId + ] + if (!productCategoryList.categoryName) { + GenericValue productCategoryContent = from("ProductCategoryContentAndInfo") + .where("productCategoryId", productCategoryList.productCategoryId, + "prodCatContentTypeId", "CATEGORY_NAME") + .filterByDate() + .orderBy("-fromDate") + .cache() + .queryFirst() + if (productCategoryContent) { + Map gcadrRes = run service: "getContentAndDataResource", with: [contentId: productCategoryContent.contentId] + Map resultMap = gcadrRes.resultData + createSimpleTextContentForCategoryCtx.text = resultMap.electronicText.textData + } + } else { + createSimpleTextContentForCategoryCtx.text = productCategoryList.categoryName + } + if (createSimpleTextContentForCategoryCtx.text) { + Map res = run service: "createSimpleTextContentForCategory", with: createSimpleTextContentForCategoryCtx + if (ServiceUtil.isError(res)) { + return res + } + categoriesUpdated += 1 + } + } else { + categoriesNotUpdated += 1 + } + } + + // create product alternative URLs + if (checkProduct) { + List productCategoryMemberList = from("ProductCategoryMember") + .where("productCategoryId", productCategoryList.productCategoryId) + .filterByDate() + .orderBy("-fromDate") + .cache() + .queryList() + for (Map productCategoryMember: productCategoryMemberList) { + String memberProductId = productCategoryMember.productId + List productContentAndInfoList = from("ProductContentAndInfo") + .where("productId", memberProductId, "productContentTypeId", "ALTERNATIVE_URL") + .cache().orderBy("-fromDate") + .filterByDate() + .queryList() + if (!productContentAndInfoList) { + GenericValue product = from("Product").where("productId", memberProductId).queryOne() + Map createSimpleTextContentForProductCtx = [ + fromDate: now, + productContentTypeId: "ALTERNATIVE_URL", + localeString: "en", + productId: memberProductId + ] + createSimpleTextContentForProductCtx.text = product.internalName ?: product.productName + if (createSimpleTextContentForProductCtx.text) { + Map res = run service: "createSimpleTextContentForProduct", with: createSimpleTextContentForProductCtx + if (ServiceUtil.isError(res)) { + return res + } + productsUpdated += 1 + } + } else { + productsNotUpdated += 1 + } + } + } + } + result.successMessageList = [ + "Categories updated: ${categoriesUpdated}", + "Products updated: ${productsUpdated}" + ] + result.categoriesNotUpdated = categoriesNotUpdated + result.productsNotUpdated = productsNotUpdated + result.categoriesUpdated = categoriesUpdated + result.productsUpdated = productsUpdated + return result +} + +def createMissingCategoryAltUrlInline(parentProductCategoryId) { + List productCategoryRollupIds = from("ProductCategoryRollup") + .where("parentProductCategoryId", parentProductCategoryId) + .filterByDate() + .cache() + .getFieldList("productCategoryId") + List productCategories = [] + for (String productCategoryId : productCategoryRollupIds) { + + // append product category to list + productCategories << from("ProductCategory") + .where("productCategoryId", productCategoryId) + .cache() + .queryOne() + + // find rollup product categories + productCategories.addAll(createMissingCategoryAltUrlInline(productCategoryId)) + } + return productCategories +} \ No newline at end of file diff --git a/applications/product/minilang/product/catalog/CatalogServices.xml b/applications/product/minilang/product/catalog/CatalogServices.xml deleted file mode 100644 index 45d6eaac265..00000000000 --- a/applications/product/minilang/product/catalog/CatalogServices.xml +++ /dev/null @@ -1,595 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/applications/product/servicedef/services.xml b/applications/product/servicedef/services.xml index 3458698725f..4e821b4814a 100644 --- a/applications/product/servicedef/services.xml +++ b/applications/product/servicedef/services.xml @@ -182,7 +182,7 @@ under the License. - + Create a product review entity @@ -245,14 +245,14 @@ under the License. - Create a Product Price. - - If taxAuthGeoId and taxAuthPartyId are passed in then the price will be considered a price + Create a Product Price. + + If taxAuthGeoId and taxAuthPartyId are passed in then the price will be considered a price with tax included (the priceWithoutTax, priceWithTax, taxAmount, and taxPercentage fields will also be populated). - + If the taxInPrice field is 'Y' then the price field will be left with the tax included (price will be equal to priceWithTax), otherwise tax will be removed from the passed in price and the price field will be equal to the priceWithoutTax field. - + If taxAuthGeoId or taxAuthPartyId empty then the taxInPrice field will be ignored. @@ -1303,14 +1303,14 @@ under the License. - + Catalog Permission Checking Logic - + ProdCatalogToParty Permission Checking Logic @@ -1320,7 +1320,7 @@ under the License. Create product and inventory item - + Create a WebAnalyticsConfig @@ -1336,7 +1336,7 @@ under the License. Delete a WebAnalyticsConfig - + Create a WebAnalyticsType @@ -1351,7 +1351,7 @@ under the License. Delete a WebAnalyticsType - + Create Product Promo Content @@ -1517,12 +1517,12 @@ under the License. location="component://product/minilang/product/imagemanagement/ImageManagementServices.xml" invoke="createImageContentApproval" auth="true"> - + - + Resize Images. @@ -1530,7 +1530,7 @@ under the License. - + Resize Image Of Product. @@ -1538,7 +1538,7 @@ under the License. - + Create New Image Thumbnail. @@ -1548,14 +1548,14 @@ under the License. - + Remove Image By Size. - + Resize Image Of Product. @@ -1565,7 +1565,7 @@ under the License. - + Rename Image. @@ -1573,10 +1573,10 @@ under the License. - + - + Create missing Category and Product Alternative URLs @@ -1593,7 +1593,7 @@ under the License. - + Update a Market Interest diff --git a/applications/product/servicedef/services_maint.xml b/applications/product/servicedef/services_maint.xml index ef40320d5cd..72198a6ede3 100644 --- a/applications/product/servicedef/services_maint.xml +++ b/applications/product/servicedef/services_maint.xml @@ -93,64 +93,64 @@ under the License. - + check For Image Urls exists or not for all categories - + Get all categories of a category - + Get all related categories of a category - + - Returns a complete category trail - can be used for exporting proper category trees. - This is mostly useful when used in combination with breadcrumbs, for building a facetted index tree, + Returns a complete category trail - can be used for exporting proper category trees. + This is mostly useful when used in combination with breadcrumbs, for building a facetted index tree, or to export a category tree for migration to another system. - Will create the tree from root point to categoryId. - + Will create the tree from root point to categoryId. + This service is not meant to be run on every request. - Its best use is to generate the trail every so often and store somewhere (a lucene/solr tree, entities, cache or so). + Its best use is to generate the trail every so often and store somewhere (a lucene/solr tree, entities, cache or so). - + check For Image Urls exists or not for category - + check For Image Urls exists or not For Product - + check For Image Urls exists or not For Product - + check For Image Urls exists or not