From 14bd073c5dbb45e840b5858ef0576763411241c3 Mon Sep 17 00:00:00 2001 From: Yashwant Dhakad Date: Tue, 11 Feb 2020 17:45:27 +0530 Subject: [PATCH 1/4] Implemented: Added new inventory cycle count feature for warehouse. (OFBIZ-10577) Added new inventory cycle count and user can create new cycle count session from pending location, find the existing cycle count session and review the cycle count session and see progress report of the cycle count. Along with we have locked the facility location until cycle count is not completed and also updated inbound and outbound transaction services of inventory item if facility location is locked in any of active cycle count session. Thanks: Ankit Joshi for help --- .../datamodel/data/seed/ProductSeedData.xml | 15 + .../entitydef/product-entitymodel.xml | 112 ++- .../jobshopmgt/ProductionRunServices.xml | 9 + .../product/config/ProductUiLabels.xml | 69 +- .../cyclecount/FindCountReport.groovy | 213 ++++++ .../facility/cyclecount/FindCycleCount.groovy | 100 +++ .../cyclecount/FindPendingLocation.groovy | 159 ++++ .../facility/cyclecount/RecordCount.groovy | 96 +++ .../cyclecount/ReviewCountSession.groovy | 77 ++ .../product/inventory/InventoryServices.xml | 40 + .../shipment/issuance/IssuanceServices.xml | 18 + .../receipt/ShipmentReceiptServices.xml | 10 + .../product/servicedef/services_inventory.xml | 72 ++ .../product/inventory/InventoryEvents.java | 132 ++++ .../product/inventory/InventoryServices.java | 715 +++++++++++++++++- .../template/cyclecount/CountReport.ftl | 242 ++++++ .../template/cyclecount/FindCycleCount.ftl | 87 +++ .../cyclecount/FindPendingLocation.ftl | 81 ++ .../template/cyclecount/ListCycleCount.ftl | 71 ++ .../template/cyclecount/PendingLocations.ftl | 115 +++ .../template/cyclecount/RecordCount.ftl | 208 +++++ .../cyclecount/ReviewCountSession.ftl | 188 +++++ .../webapp/facility/WEB-INF/controller.xml | 89 +++ .../product/widget/facility/CommonScreens.xml | 1 + .../widget/facility/CycleCountScreens.xml | 192 +++++ .../product/widget/facility/FacilityMenus.xml | 17 + 26 files changed, 3115 insertions(+), 13 deletions(-) create mode 100644 applications/product/groovyScripts/facility/cyclecount/FindCountReport.groovy create mode 100644 applications/product/groovyScripts/facility/cyclecount/FindCycleCount.groovy create mode 100644 applications/product/groovyScripts/facility/cyclecount/FindPendingLocation.groovy create mode 100644 applications/product/groovyScripts/facility/cyclecount/RecordCount.groovy create mode 100644 applications/product/groovyScripts/facility/cyclecount/ReviewCountSession.groovy create mode 100644 applications/product/src/main/java/org/apache/ofbiz/product/inventory/InventoryEvents.java create mode 100644 applications/product/template/cyclecount/CountReport.ftl create mode 100644 applications/product/template/cyclecount/FindCycleCount.ftl create mode 100644 applications/product/template/cyclecount/FindPendingLocation.ftl create mode 100644 applications/product/template/cyclecount/ListCycleCount.ftl create mode 100644 applications/product/template/cyclecount/PendingLocations.ftl create mode 100644 applications/product/template/cyclecount/RecordCount.ftl create mode 100644 applications/product/template/cyclecount/ReviewCountSession.ftl create mode 100644 applications/product/widget/facility/CycleCountScreens.xml diff --git a/applications/datamodel/data/seed/ProductSeedData.xml b/applications/datamodel/data/seed/ProductSeedData.xml index 05d6f640343..d4054501763 100644 --- a/applications/datamodel/data/seed/ProductSeedData.xml +++ b/applications/datamodel/data/seed/ProductSeedData.xml @@ -588,6 +588,21 @@ under the License. + + + + + + + + + + + + + + + diff --git a/applications/datamodel/entitydef/product-entitymodel.xml b/applications/datamodel/entitydef/product-entitymodel.xml index 2ee09ecfdb8..3e16c6770a9 100644 --- a/applications/datamodel/entitydef/product-entitymodel.xml +++ b/applications/datamodel/entitydef/product-entitymodel.xml @@ -1288,7 +1288,10 @@ under the License. - + + + + @@ -1299,7 +1302,10 @@ under the License. - + + + + @@ -4994,4 +5000,106 @@ under the License. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/applications/manufacturing/minilang/jobshopmgt/ProductionRunServices.xml b/applications/manufacturing/minilang/jobshopmgt/ProductionRunServices.xml index c98d1880064..2bfb4868dfd 100644 --- a/applications/manufacturing/minilang/jobshopmgt/ProductionRunServices.xml +++ b/applications/manufacturing/minilang/jobshopmgt/ProductionRunServices.xml @@ -335,6 +335,15 @@ under the License. + + + + + + + + + diff --git a/applications/product/config/ProductUiLabels.xml b/applications/product/config/ProductUiLabels.xml index 142b6418a29..54329dc86d3 100644 --- a/applications/product/config/ProductUiLabels.xml +++ b/applications/product/config/ProductUiLabels.xml @@ -74,6 +74,9 @@ 网站分析类型 網站分析型態 + + Create Session + Neuen Merkmaltyp erstellen Create New Product Feature Type @@ -89,6 +92,12 @@ Crear Acuerdo de Ventas Contract aanmaken + + Counted Inventory Items + + + Count Progress + Aktuelle Lieferkosten Actual shipping charges @@ -476,6 +485,9 @@ 尝试接收一个已经序列化的库存明细,序列号(serialNumber)${parameters.serialNumber}或者传入的库存明细标识(inventoryItemId)${parameters.currentInventoryItemId},并且已接受数量 ${parameters.quantityAccepted} 大于1;我们不知道要做什么! 嘗試接收一個已經序列化的庫存細項,序號(serialNumber)${parameters.serialNumber}或者傳入的庫存細項標識(inventoryItemId)${parameters.currentInventoryItemId},並且已接受數量 ${parameters.quantityAccepted} 大於1;我們不知道要做什麼! + + Record Count + ${returnHeader.returnHeaderTypeId} wird nicht unterstützt ${returnHeader.returnHeaderTypeId} is not supported @@ -3801,6 +3813,9 @@ 送货费差异太大 送貨費差異太大 + + Find Session + Abkürzung Abbrev @@ -9339,7 +9354,13 @@ "Identificación de la instalación de inventario requerida" 必须有库存场所标识 - + + Inventory Items Counted + + + Item Variance + + Erlaubt Allowed @@ -9370,6 +9391,15 @@ 必须 必須 + + Location Counted + + + Locations not scanned in last + + + Location scheduled for scanning in next + Meta Beschreibung Meta Description @@ -13636,6 +13666,12 @@ 合同 合約 + + Find Pending Locations + + + Pending Locations + Verträge Agreements @@ -14212,7 +14248,7 @@ 关联 結合 - + Zurück Sendungsstatus Return Shipment Status @@ -16473,6 +16509,9 @@ 没有找到货运——标识 沒有找到貨運識別 + + Count Report + Country of Origin País de Origen @@ -17047,6 +17086,9 @@ 客户评级 客戶評級 + + Cycle Count + DL DL @@ -27567,6 +27609,9 @@ 现货数量 現貨數量 + + Qty Counted + Vorhandene Menge minus Minimalbestand Qty Offset @@ -27667,6 +27712,9 @@ 已拒绝的数量 已拒絕的數量 + + Qty Variance + Menge Quantity @@ -28954,6 +29002,9 @@ 评价这个产品! 評論這個產品! + + Review Count Session + Bewertungen Reviews @@ -31297,7 +31348,7 @@ Để kiểm soát cách nhìn và cảm quan và cửa hàng trực tuyến 用于控制一个网店的外观感受。 用於控制一個網店的外觀感受. - + Läden für Stores For @@ -33521,6 +33572,12 @@ 搜索结果 搜尋結果 + + Results + + + Review Session + Suche Lieferverfolgung Search of a tracking @@ -33530,6 +33587,12 @@ 搜索一个跟踪 搜尋一個追蹤 + + To Date + + + Total Projected Counts + Lieferverfolgung Tracking diff --git a/applications/product/groovyScripts/facility/cyclecount/FindCountReport.groovy b/applications/product/groovyScripts/facility/cyclecount/FindCountReport.groovy new file mode 100644 index 00000000000..14d8d7c9090 --- /dev/null +++ b/applications/product/groovyScripts/facility/cyclecount/FindCountReport.groovy @@ -0,0 +1,213 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.ofbiz.base.util.ObjectType +import org.apache.ofbiz.entity.condition.EntityConditionBuilder + +context.facilityIds = parameters.facilityIds; +context.statusIds = parameters.statusIds; +inventoryCountId = parameters.inventoryCountId; +context.inventoryCountId = inventoryCountId; +progressList = []; +inventoryCountItemsAndVariances = []; + +if (parameters.searchResult && parameters.searchResult == "Y") { + exprBldr = new EntityConditionBuilder(); + + cond = exprBldr.AND() { + if (parameters.facilityIds && "All" != parameters.facilityIds) + IN("facilityId": ObjectType.simpleTypeOrObjectConvert(parameters.facilityIds, "java.util.List" , null, null)) + if (parameters.locationSeqId) + LIKE("locationSeqId": parameters.locationSeqId) + if (parameters.fromDate) { + GREATER_THAN_EQUAL_TO("createdDate": ObjectType.simpleTypeOrObjectConvert(parameters.fromDate, "Timestamp", null, timeZone, locale, false)); + } + if (parameters.toDate) { + LESS_THAN_EQUAL_TO("createdDate": ObjectType.simpleTypeOrObjectConvert(parameters.toDate, "Timestamp", null, timeZone, locale, false)); + } + IN("itemStatusId": ["INV_COUNT_COMPLETED"]); + } + + inventoryCountItemsAndVarianceList = from("InventoryCountItemsAndVariance").where(cond).orderBy(["-createdDate"]).queryList(); + + countProgressMap = [:]; + + inventoryCountItemsAndVarianceList.each { inventoryCountItemsAndVariance -> + cycleCount = [:] + cycleCount.putAll(inventoryCountItemsAndVariance); + + inventoryCountId = inventoryCountItemsAndVariance.inventoryCountId; + + facility = from("Facility").where("facilityId", inventoryCountItemsAndVariance?.facilityId).queryOne(); + cycleCount.facilityName = facility?.facilityName; + + statusItem = from("StatusItem").where("statusId", inventoryCountItemsAndVariance?.statusId).queryOne(); + cycleCount.statusDescription = statusItem?.description; + + product = from("Product").where("productId", inventoryCountItemsAndVariance?.productId).queryOne(); + cycleCount.internalName = product?.internalName; + cycleCount.partDescription = product?.description; + + unitCost = BigDecimal.ZERO; + totalCost = BigDecimal.ZERO; + actualCost = BigDecimal.ZERO; + error = BigDecimal.ZERO; + unitCost = inventoryCountItemsAndVariance?.unitCost; + totalCost = inventoryCountItemsAndVariance?.totalCost; + actualCost = inventoryCountItemsAndVariance?.actualCost; + costVariance = inventoryCountItemsAndVariance?.costVariance; + + if (costVariance && totalCost != 0) { + error = costVariance.divide(totalCost, BigDecimal.ROUND_HALF_UP); + error = error * 100; + } + cycleCount.error = error?.setScale(2, BigDecimal.ROUND_HALF_UP); + cycleCount.unitCost = unitCost?.setScale(2, BigDecimal.ROUND_HALF_UP); + cycleCount.totalCost = totalCost?.setScale(2, BigDecimal.ROUND_HALF_UP); + cycleCount.costVariance = costVariance?.setScale(2, BigDecimal.ROUND_HALF_UP); + cycleCount.actualCost = actualCost?.setScale(2, BigDecimal.ROUND_HALF_UP); + + facilityLocation = from("FacilityLocation").where("facilityId", inventoryCountItemsAndVariance?.facilityId, "locationSeqId", inventoryCountItemsAndVariance?.locationSeqId).queryOne(); + cycleCount.areaId = facilityLocation?.areaId; + cycleCount.aisleId = facilityLocation?.aisleId; + cycleCount.sectionId = facilityLocation?.sectionId; + cycleCount.levelId = facilityLocation?.levelId + cycleCount.positionId = facilityLocation?.positionId + + description = "Cycle Count Session # " + inventoryCountId; + inventoryItemDetail = from("InventoryItemDetail").where("inventoryItemId", inventoryCountItemsAndVariance?.inventoryItemId, "description", description).queryFirst() + cycleCount.varianceCreatedOn = inventoryItemDetail?.effectiveDate + + facilityId = facility.facilityId; + if (countProgressMap && countProgressMap.containsKey(facilityId)) { + countProgressMap.each { key, value -> + if (key == facilityId) { + countProgress = [:]; + def locationSeqIds = [] as Set; + def inventoryItems = [] as Set; + locationSeqIds = value.locationSeqIds; + locationSeqIds.add(inventoryCountItemsAndVariance?.locationSeqId); + inventoryItems = value.inventoryItems; + inventoryItems.add(inventoryCountItemsAndVariance?.inventoryItemId); + countProgress.locationSeqIds = locationSeqIds; + countProgress.inventoryItems = inventoryItems; + countProgressMap.put(facilityId, countProgress); + inventoryCountItemsAndVariances.add(cycleCount); + } + } + } else { + countProgress = [:]; + def locationSeqIds = [] as Set; + def inventoryItems = [] as Set; + locationSeqIds.add(inventoryCountItemsAndVariance?.locationSeqId); + inventoryItems.add(inventoryCountItemsAndVariance?.inventoryItemId); + countProgress.locationSeqIds = locationSeqIds; + countProgress.inventoryItems = inventoryItems; + countProgressMap.put(facilityId, countProgress); + inventoryCountItemsAndVariances.add(cycleCount); + } + } + + grandTotalLocationCompleted = BigDecimal.ZERO; + grandTotalInventoryItemCompleted = BigDecimal.ZERO; + grandTotalLocationCounted = BigDecimal.ZERO; + grandTotalInventoryItemCounted = BigDecimal.ZERO; + grandTotalPerLocation = BigDecimal.ZERO; + grandTotalPerInventoryItem = BigDecimal.ZERO; + + countProgressMap.each { key, value -> + progress = [:]; + facility = from("Facility").where("facilityId", key).queryOne(); + progress.facilityName = facility?.facilityName; + progress.facilityId = key; + totalCountedInventoryItems = BigDecimal.ZERO; + countedLocations = BigDecimal.ZERO; + totalInventoryItems = BigDecimal.ZERO; + totalLocations = BigDecimal.ZERO; + + if (value.inventoryItems.size()) { + totalCountedInventoryItems = new BigDecimal(value.inventoryItems.size()); + totalCountedInventoryItems = totalCountedInventoryItems.setScale(2,BigDecimal.ROUND_HALF_UP); + grandTotalInventoryItemCounted = grandTotalInventoryItemCounted + totalCountedInventoryItems; + } + + if (value.locationSeqIds.size()) { + countedLocations = new BigDecimal(value.locationSeqIds.size()); + countedLocations = countedLocations.setScale(2,BigDecimal.ROUND_HALF_UP); + grandTotalLocationCounted = grandTotalLocationCounted + countedLocations; + } + progress.totalCountedInventoryItems = totalCountedInventoryItems; + progress.countedLocations = countedLocations; + inventoryItemCondition = exprBldr.AND() { + NOT_EQUAL("locationSeqId": null) + NOT_EQUAL("quantityOnHandTotal": 0.0) + EQUALS("facilityId": key) + } + + inventoryItemCount = from("InventoryItem").where(inventoryItemCondition).queryCount(); + totalInventories = from("InventoryItem").where(inventoryItemCondition).queryCount(); + if (totalInventories) { + totalInventoryItems = new BigDecimal(totalInventories); + totalInventoryItems = totalInventoryItems.setScale(2, BigDecimal.ROUND_HALF_UP); + grandTotalInventoryItemCompleted = grandTotalInventoryItemCompleted + totalInventoryItems; + } + progress.totalInventoryItems = totalInventoryItems; + + locations = from("FacilityLocation").where("facilityId", key).queryCount(); + if (locations) { + totalLocations = new BigDecimal(locations); + totalLocations = totalLocations.setScale(2, BigDecimal.ROUND_HALF_UP); + grandTotalLocationCompleted = grandTotalLocationCompleted + totalLocations; + } + progress.totalLocations = totalLocations; + + percentLocationCompleted = BigDecimal.ZERO; + percentInventoryItemCompleted = BigDecimal.ZERO; + + if (totalCountedInventoryItems && totalInventoryItems && totalInventoryItems != 0) { + percentInventoryItemCompleted = (totalCountedInventoryItems/totalInventoryItems) * 100; + percentInventoryItemCompleted = percentInventoryItemCompleted.setScale(2, BigDecimal.ROUND_HALF_UP); + } + + if (countedLocations && totalLocations && totalLocations != 0) { + percentLocationCompleted = (countedLocations/totalLocations) * 100; + percentLocationCompleted = percentLocationCompleted.setScale(2, BigDecimal.ROUND_HALF_UP); + } + progress.percentInventoryItemCompleted = percentInventoryItemCompleted; + progress.percentLocationCompleted = percentLocationCompleted; + + progressList.add(progress); + } + context.grandTotalLocationCompleted = grandTotalLocationCompleted; + context.grandTotalInventoryItemCompleted = grandTotalInventoryItemCompleted; + context.grandTotalLocationCounted = grandTotalLocationCounted; + context.grandTotalInventoryItemCounted = grandTotalInventoryItemCounted; + if (grandTotalLocationCompleted != 0) { + grandTotalPerLocation = (grandTotalLocationCounted/grandTotalLocationCompleted) * 100; + } + grandTotalPerLocation = grandTotalPerLocation.setScale(2, BigDecimal.ROUND_HALF_UP); + context.grandTotalPerLocation = grandTotalPerLocation; + if (grandTotalInventoryItemCompleted != 0) { + grandTotalPerInventoryItem = (grandTotalInventoryItemCounted/grandTotalInventoryItemCompleted) * 100; + } + grandTotalPerInventoryItem = grandTotalPerInventoryItem.setScale(2, BigDecimal.ROUND_HALF_UP); + context.grandTotalPerInventoryItem = grandTotalPerInventoryItem; +} +context.progressList = progressList; +context.inventoryCountItemsAndVariances = inventoryCountItemsAndVariances; \ No newline at end of file diff --git a/applications/product/groovyScripts/facility/cyclecount/FindCycleCount.groovy b/applications/product/groovyScripts/facility/cyclecount/FindCycleCount.groovy new file mode 100644 index 00000000000..51706d0862d --- /dev/null +++ b/applications/product/groovyScripts/facility/cyclecount/FindCycleCount.groovy @@ -0,0 +1,100 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.ofbiz.base.util.ObjectType +import org.apache.ofbiz.entity.condition.EntityConditionBuilder + +cycleCountMap = [:] +facilityId = parameters.facilityId +showCreateSession = "N" +if (parameters.statusIds && parameters.statusIds.contains("INV_COUNT_REJECTED")) { + showCreateSession = "Y" +} + +inventoryCountId = parameters.inventoryCountId + +exprBldr = new EntityConditionBuilder() +cond = exprBldr.AND() { + if (inventoryCountId) + LIKE(inventoryCountId: "%" + inventoryCountId.toUpperCase() + "%") + if (facilityId) + EQUALS(facilityId: facilityId) + if (parameters.statusIds) + IN(statusId: ObjectType.simpleTypeOrObjectConvert(parameters.statusIds, "List", null, null)) + else + EQUALS(statusId: "INV_COUNT_APPROVED") + if (parameters.locationSeqId) + LIKE(locationSeqId: parameters.locationSeqId) +} + +inventoryCountAndItems = from("InventoryCountAndItems").where(cond).orderBy("-createdDate").queryList() + +inventoryCountAndItems.each { inventoryCountAndItem -> + cycleCount = [:] + inventoryCountId = inventoryCountAndItem?.inventoryCountId + cycleCount.inventoryCountId = inventoryCountAndItem?.inventoryCountId + cycleCount.facilityId = inventoryCountAndItem?.facilityId + facility = from("Facility").where("facilityId", inventoryCountAndItem?.facilityId).queryOne() + cycleCount.facilityName = facility?.facilityName + statusItem = from("StatusItem").where("statusId", inventoryCountAndItem?.statusId).queryOne() + cycleCount.statusId = inventoryCountAndItem?.statusId + cycleCount.statusDescription = statusItem.description + if (inventoryCountAndItem?.inventoryItemId) { + if (cycleCountMap && cycleCountMap.containsKey(inventoryCountId)) { + oldCycleCountMap = cycleCountMap.get(inventoryCountId) + totalInventoryItems = oldCycleCountMap.totalInventoryItems + 1 + cycleCount.totalInventoryItems = totalInventoryItems + } else { + totalInventoryItems = 1 + cycleCount.totalInventoryItems = totalInventoryItems + } + } else { + if (cycleCountMap && cycleCountMap.containsKey(inventoryCountId)) { + oldCycleCountMap = cycleCountMap.get(inventoryCountId) + totalInventoryItems = oldCycleCountMap.totalInventoryItems + 0 + cycleCount.totalInventoryItems = totalInventoryItems + } else { + totalInventoryItems = 0 + cycleCount.totalInventoryItems = totalInventoryItems + } + } + + if (inventoryCountAndItem.locationSeqId) { + if (cycleCountMap && cycleCountMap.containsKey(inventoryCountId)) { + oldCycleCountMap = cycleCountMap.get(inventoryCountId) + locationSeqIds = [] as Set + locationSeqIds.addAll(oldCycleCountMap.locationSeqIds) + locationSeqIds.add(inventoryCountAndItem.locationSeqId) + cycleCount.locationSeqIds = locationSeqIds + } else { + locationSeqIds = [] as Set + locationSeqIds.add(inventoryCountAndItem.locationSeqId) + cycleCount.locationSeqIds = locationSeqIds + } + } else { + cycleCount.locationSeqIds = null + } + cycleCountMap.put(inventoryCountId, cycleCount) +} + +context.showCreateSession = showCreateSession +context.facilityId = facilityId +context.statusIds = parameters.statusIds +context.inventoryCountId = inventoryCountId +context.cycleCountMap = cycleCountMap \ No newline at end of file diff --git a/applications/product/groovyScripts/facility/cyclecount/FindPendingLocation.groovy b/applications/product/groovyScripts/facility/cyclecount/FindPendingLocation.groovy new file mode 100644 index 00000000000..d29d66cb8f8 --- /dev/null +++ b/applications/product/groovyScripts/facility/cyclecount/FindPendingLocation.groovy @@ -0,0 +1,159 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.ofbiz.base.util.UtilDateTime +import org.apache.ofbiz.base.util.UtilMisc +import org.apache.ofbiz.base.util.UtilValidate +import org.apache.ofbiz.entity.condition.EntityConditionBuilder + +import java.sql.Timestamp + +facilityId = parameters.facilityId; +if (!facilityId && facilities) { + facilityId = facilities[0].facilityId +} +context.facilityId = facilityId; +exprBldr = new EntityConditionBuilder(); + +Timestamp lastCountDate = null; +countDays = parameters.countDays; +if (countDays && UtilValidate.isInteger(countDays)) { + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, -(new Integer(parameters.countDays))); + lastCountDate = new Timestamp(cal.getTimeInMillis()); +} +Timestamp nextCountDate = null; +nextCountDays = parameters.nextCountDays; +if (nextCountDays && UtilValidate.isInteger(nextCountDays)) { + Calendar nextCountCal = Calendar.getInstance(); + nextCountCal.add(Calendar.DAY_OF_YEAR, (new Integer(parameters.nextCountDays))); + nextCountDate = new Timestamp(nextCountCal.getTimeInMillis()); +} + +cond = exprBldr.AND() { + if (facilityId) { + EQUALS("facilityId": facilityId) + } + OR { + NOT_EQUAL("locked": "Y") + EQUALS("locked": null) + } + if (parameters.locationSeqId) { + EQUALS("locationSeqId": parameters.locationSeqId) + } + if (parameters.areaId) { + LIKE("areaId": (parameters.areaId).toUpperCase() + "%") + } + if (parameters.aisleId) { + LIKE("aisleId": (parameters.aisleId).toUpperCase() + "%") + } + if (parameters.sectionId) { + LIKE("sectionId": (parameters.sectionId).toUpperCase() + "%") + } + if (parameters.levelId) { + LIKE("levelId": (parameters.levelId).toUpperCase() + "%") + } + if (parameters.positionId) { + LIKE("positionId": (parameters.positionId).toUpperCase() + "%") + } + if (countDays && UtilValidate.isInteger(countDays)) { + LESS_THAN_EQUAL_TO(lastCountDate: new java.sql.Date(lastCountDate.getTime())) + lastCountCond = " lastCountDate <= '" + new java.sql.Date(lastCountDate.getTime()) + "'" + } + if (nextCountDays && UtilValidate.isInteger(nextCountDays)) { + OR() { + LESS_THAN_EQUAL_TO(nextCountDate: new java.sql.Date(UtilDateTime.nowTimestamp().getTime())) + GREATER_THAN_EQUAL_TO(nextCountDate: new java.sql.Date(nextCountDate.getTime())) + } + } +} + +viewIndex = parameters.VIEW_INDEX ? Integer.valueOf(parameters.VIEW_INDEX) : 0 +viewSize = parameters.VIEW_SIZE ? Integer.valueOf(parameters.VIEW_SIZE) : 20 + +int lowIndex = viewIndex * viewSize + 1 +int highIndex = (viewIndex + 1) * viewSize + +context.viewIndexFirst = 0 +context.viewIndex = viewIndex +context.viewIndexPrevious = viewIndex-1 +context.viewIndexNext = viewIndex+1 + +listIt = from("FacilityLocation").where(cond).orderBy("nextCountDate").cursorScrollInsensitive().cache(true).queryIterator() +resultPartialList = listIt.getPartialList(lowIndex, highIndex - lowIndex + 1) + +listSize = listIt.getResultsSizeAfterPartialList() +if (listSize < highIndex) { + highIndex = listSize +} + +context.highIndex = highIndex +context.listSize = listSize +context.resultPartialList = resultPartialList +context.viewIndexLast = UtilMisc.getViewLastIndex(listSize, viewSize) + +def pendingLocations = []; +if (resultPartialList) { + resultPartialList.each { pendingLocation -> + def pendingLocationMap = [:]; + facilityId = pendingLocation?.facilityId; + locationSeqId = pendingLocation?.locationSeqId; + def facility = from("Facility").where("facilityId", facilityId).queryOne(); + pendingLocationMap.locationSeqId = locationSeqId; + + facilityLocation = from("FacilityLocation").where("facilityId", facilityId, "locationSeqId", locationSeqId).queryOne(); + pendingLocationMap.areaId = facilityLocation.areaId; + pendingLocationMap.aisleId = facilityLocation.aisleId; + pendingLocationMap.sectionId = facilityLocation.sectionId; + pendingLocationMap.levelId = facilityLocation.levelId + pendingLocationMap.positionId = facilityLocation.positionId; + pendingLocationMap.facilityId = facilityLocation.facilityId; + pendingLocationMap.facilityName = facility.facilityName; + pendingLocationMap.lastCountDate = pendingLocation?.lastCountDate; + pendingLocationMap.nextCountDate = pendingLocation?.nextCountDate; + long count = from("InventoryItem").where("facilityId", facilityId, "locationSeqId", locationSeqId).queryCount(); + pendingLocationMap.totalInventoryItems = count + if (pendingLocation?.lastCountDate) { + Calendar cal = Calendar.getInstance(); + cal.setTime(pendingLocation?.lastCountDate); + days = cal.get(Calendar.DAY_OF_YEAR); + + Calendar nowCal = Calendar.getInstance(); + nowCal.setTime(UtilDateTime.nowDate()); + nowDays = nowCal.get(Calendar.DAY_OF_YEAR); + if (days && nowDays) + pendingLocationMap.lastCountDay = (nowDays - days); + } + if (pendingLocation?.nextCountDate) { + Calendar cal = Calendar.getInstance(); + cal.setTime(pendingLocation?.nextCountDate); + days = cal.get(Calendar.DAY_OF_YEAR); + + Calendar nowCal = Calendar.getInstance(); + nowCal.setTime(UtilDateTime.nowDate()); + nowDays = nowCal.get(Calendar.DAY_OF_YEAR); + if (days && nowDays) + nextCountDay = (nowDays - days); + pendingLocationMap.nextCountDay = nextCountDay * -1; + } + pendingLocations.add(pendingLocationMap); + } +} + +context.pendingLocations = pendingLocations; \ No newline at end of file diff --git a/applications/product/groovyScripts/facility/cyclecount/RecordCount.groovy b/applications/product/groovyScripts/facility/cyclecount/RecordCount.groovy new file mode 100644 index 00000000000..37ef1278125 --- /dev/null +++ b/applications/product/groovyScripts/facility/cyclecount/RecordCount.groovy @@ -0,0 +1,96 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.ofbiz.entity.condition.EntityConditionBuilder + +countSession = from('InventoryCount').where("inventoryCountId", parameters.inventoryCountId).queryOne(); + +countSessionValue = [:]; +if (countSession) { + countSessionValue.inventoryCountId = countSession?.inventoryCountId; + statusItem = from("StatusItem").where("statusId", countSession?.statusId).queryOne(); + countSessionValue.statusId = countSession?.statusId; + countSessionValue.statusDescription = statusItem?.description; + countSessionValue.facilityId = countSession?.facilityId; + facility = from("Facility").where("facilityId", countSession?.facilityId).queryOne(); + countSessionValue.facilityName = facility?.facilityName; + countSessionValue.createdDate = countSession?.createdDate; + countSessionValue.createdBy = countSession?.createdByUserLogin; + context.inventoryCountId = countSession?.inventoryCountId; + context.facilityId = countSession?.facilityId; +} +context.countSessionValue = countSessionValue; + +exprBldr = new EntityConditionBuilder(); +cond = exprBldr.AND() { + if (parameters.inventoryCountId) + EQUALS("inventoryCountId": parameters.inventoryCountId) +} +inventoryCountItemAndVarList = from('InventoryCountItemsAndVariance').where(cond).orderBy("locationSeqId").queryList(); + +inventoryCountItemAndVariances = []; +inventoryCountItemAndVarList.each { inventoryCountItemAndVar -> + cycleCountMap = [:]; + cycleCountMap.inventoryCountId = inventoryCountItemAndVar.inventoryCountId; + cycleCountMap.inventoryCountItemSeqId = inventoryCountItemAndVar.inventoryCountItemSeqId; + cycleCountMap.locationSeqId = inventoryCountItemAndVar?.locationSeqId; + + facilityLocation = from("FacilityLocation").where("facilityId", inventoryCountItemAndVar?.facilityId, "locationSeqId", inventoryCountItemAndVar?.locationSeqId).queryOne(); + cycleCountMap.areaId = facilityLocation?.areaId; + cycleCountMap.aisleId = facilityLocation?.aisleId; + cycleCountMap.sectionId = facilityLocation?.sectionId; + cycleCountMap.levelId = facilityLocation?.levelId + cycleCountMap.positionId = facilityLocation?.positionId + + statusItem = from('StatusItem').where("statusId", inventoryCountItemAndVar.itemStatusId).queryOne(); + cycleCountMap.itemStatusId = inventoryCountItemAndVar.itemStatusId; + cycleCountMap.statusDescription = statusItem?.description; + + facility = from("Facility").where("facilityId", inventoryCountItemAndVar?.facilityId).queryOne(); + cycleCountMap.facilityId = inventoryCountItemAndVar.facilityId; + cycleCountMap.facilityName = facility?.facilityName; + + product = from("Product").where("productId", inventoryCountItemAndVar.productId).queryOne(); + cycleCountMap.internalName = product?.internalName; + cycleCountMap.partDescription = product?.description; + + cycleCountMap.inventoryItemId = inventoryCountItemAndVar?.inventoryItemId; + cycleCountMap.quantity = inventoryCountItemAndVar?.quantity; + inventoryCountItemAndVariances.add(cycleCountMap); +} + +inventoryValue = [:]; +errorMessage = ''; +if (parameters.inventoryItemId) { + inventoryItem = from("InventoryItem").where("inventoryItemId", parameters.inventoryItemId).queryOne(); + if (inventoryItem) { + inventoryValue.inventoryItemId = parameters.inventoryItemId; + inventoryValue.locationSeqId = inventoryItem.locationSeqId; + inventoryValue.quantity = parameters.quantity; + inventoryItem = from("Product").where("productId", parameters.productId).queryOne(); + inventoryValue.internalName = product.internalName; + inventoryValue.partDescription = product.description; + } else { + errorMessage = "Inventory item not found."; + } +} +context.errorMessage = errorMessage; +context.inventoryValue = inventoryValue; + +context.inventoryCountItemAndVariances = inventoryCountItemAndVariances; \ No newline at end of file diff --git a/applications/product/groovyScripts/facility/cyclecount/ReviewCountSession.groovy b/applications/product/groovyScripts/facility/cyclecount/ReviewCountSession.groovy new file mode 100644 index 00000000000..0faa38c2128 --- /dev/null +++ b/applications/product/groovyScripts/facility/cyclecount/ReviewCountSession.groovy @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.ofbiz.entity.condition.EntityConditionBuilder +import org.apache.ofbiz.party.party.PartyHelper + +countSession = from("InventoryCount").where("inventoryCountId", parameters.inventoryCountId).queryOne(); +countSessionValue = [:]; +if (countSession) { + countSessionValue.inventoryCountId = countSession.inventoryCountId; + statusItem = from("StatusItem").where("statusId", countSession.statusId).queryOne(); + countSessionValue.statusId = countSession.statusId; + countSessionValue.statusDescription = statusItem.description; + countSessionValue.createdDate = countSession.createdDate; + countSessionValue.createdBy = countSession.createdByUserLogin; + context.inventoryCountId = countSession.inventoryCountId; +} +context.countSessionValue = countSessionValue; + +exprBldr = new EntityConditionBuilder(); +cond = exprBldr.AND() { + if (parameters.inventoryCountId) + EQUALS("inventoryCountId": parameters.inventoryCountId) +} +inventoryCountItemAndVarList = from("InventoryCountItemsAndVariance").where(cond).orderBy(["locationSeqId ASC", "inventoryItemId ASC"]).queryList(); + +inventoryCountItemAndVariances = []; +inventoryCountItemAndVarList.each { inventoryCountItemAndVar -> + cycleCountMap = [:]; + exprBldr = new EntityConditionBuilder() + cycleCountMap.inventoryCountId = inventoryCountItemAndVar.inventoryCountId; + cycleCountMap.inventoryCountItemSeqId = inventoryCountItemAndVar.inventoryCountItemSeqId; + + cycleCountMap.locationSeqId = inventoryCountItemAndVar?.locationSeqId; + facilityLocation = from("FacilityLocation").where("facilityId", inventoryCountItemAndVar?.facilityId, "locationSeqId", inventoryCountItemAndVar?.locationSeqId).queryOne(); + cycleCountMap.areaId = facilityLocation?.areaId; + cycleCountMap.aisleId = facilityLocation?.aisleId; + cycleCountMap.sectionId = facilityLocation?.sectionId; + cycleCountMap.levelId = facilityLocation?.levelId + cycleCountMap.positionId = facilityLocation?.positionId + + statusItem = from("StatusItem").where("statusId", inventoryCountItemAndVar?.itemStatusId).queryOne(); + cycleCountMap.statusDescription = statusItem?.description; + cycleCountMap.itemStatusId = inventoryCountItemAndVar?.itemStatusId; + + cycleCountMap.facilityId = inventoryCountItemAndVar?.facilityId; + facility = from("Facility").where("facilityId", inventoryCountItemAndVar?.facilityId).queryOne(); + cycleCountMap.facilityName = facility?.facilityName; + + product = from("Product").where("productId", inventoryCountItemAndVar?.productId).queryOne(); + cycleCountMap.internalName = product?.internalName; + + cycleCountMap.inventoryItemId = inventoryCountItemAndVar?.inventoryItemId; + cycleCountMap.quantity = inventoryCountItemAndVar?.quantity; + cycleCountMap.varianceQuantityOnHand = inventoryCountItemAndVar?.varianceQuantityOnHand; + cycleCountMap.systemQuantityOnHand = inventoryCountItemAndVar?.systemQuantityOnHand; + cycleCountMap.createBy = PartyHelper.getPartyName(delegator, inventoryCountItemAndVar.createdByUserLogin, false); + inventoryCountItemAndVariances.add(cycleCountMap); +} + +context.inventoryCountItemAndVariances = inventoryCountItemAndVariances; \ No newline at end of file diff --git a/applications/product/minilang/product/inventory/InventoryServices.xml b/applications/product/minilang/product/inventory/InventoryServices.xml index 56d15a3b8f8..eb07c1d8ada 100644 --- a/applications/product/minilang/product/inventory/InventoryServices.xml +++ b/applications/product/minilang/product/inventory/InventoryServices.xml @@ -1005,6 +1005,27 @@ under the License. + + + + + + + + + + + + + + + + + + + + + @@ -1272,4 +1293,23 @@ under the License. + + + + + + + + + + + + + + + + + + + diff --git a/applications/product/minilang/shipment/issuance/IssuanceServices.xml b/applications/product/minilang/shipment/issuance/IssuanceServices.xml index 53f2322e1d0..1bee4f9d8d7 100644 --- a/applications/product/minilang/shipment/issuance/IssuanceServices.xml +++ b/applications/product/minilang/shipment/issuance/IssuanceServices.xml @@ -135,6 +135,15 @@ under the License. + + + + + + + + + @@ -610,6 +619,15 @@ under the License. + + + + + + + + + diff --git a/applications/product/minilang/shipment/receipt/ShipmentReceiptServices.xml b/applications/product/minilang/shipment/receipt/ShipmentReceiptServices.xml index 2dade39d926..b09733c5aa2 100644 --- a/applications/product/minilang/shipment/receipt/ShipmentReceiptServices.xml +++ b/applications/product/minilang/shipment/receipt/ShipmentReceiptServices.xml @@ -84,6 +84,16 @@ under the License. - if the type is SERIALIZED_INV_ITEM but there is not serial number (which is weird...) we'll create a bunch of individual InventoryItems - DEJ20070822: something to consider for the future: maybe instead of this funny looping maybe for serialized items we should only allow a quantity of 1, ie return an error if it is not 1 --> + + + + + + + + + + diff --git a/applications/product/servicedef/services_inventory.xml b/applications/product/servicedef/services_inventory.xml index a3fab48fb5d..b3435e9de77 100644 --- a/applications/product/servicedef/services_inventory.xml +++ b/applications/product/servicedef/services_inventory.xml @@ -84,4 +84,76 @@ under the License. + + + Create Inventory Count Record + + + + + Create Inventory Count Item Record + + + + + + + + + + + + + + + Update Inventory Count Record + + + + + Update Inventory Count Item Record + + + + + + + Create Inventory Count Variance Record + + + + + Update Inventory Count Variance Record + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/applications/product/src/main/java/org/apache/ofbiz/product/inventory/InventoryEvents.java b/applications/product/src/main/java/org/apache/ofbiz/product/inventory/InventoryEvents.java new file mode 100644 index 00000000000..358fe9ac82d --- /dev/null +++ b/applications/product/src/main/java/org/apache/ofbiz/product/inventory/InventoryEvents.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + *******************************************************************************/ +package org.apache.ofbiz.product.inventory; + +import org.apache.ofbiz.base.util.Debug; +import org.apache.ofbiz.base.util.UtilDateTime; +import org.apache.ofbiz.base.util.UtilHttp; +import org.apache.ofbiz.base.util.UtilProperties; +import org.apache.ofbiz.base.util.UtilValidate; +import org.apache.ofbiz.entity.Delegator; +import org.apache.ofbiz.entity.GenericEntityException; +import org.apache.ofbiz.entity.GenericValue; +import org.apache.ofbiz.entity.util.EntityQuery; +import org.apache.ofbiz.entity.util.EntityUtil; +import org.apache.ofbiz.service.GenericServiceException; +import org.apache.ofbiz.service.LocalDispatcher; +import org.apache.ofbiz.service.ServiceUtil; +import org.apache.ofbiz.webapp.control.ExternalLoginKeysManager; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import java.util.*; + +public class InventoryEvents { + public static final String module = InventoryEvents.class.getName(); + public static final String resource = "ProductUiLabels"; + + public static String createInventoryCountAndAddBulkLocations(HttpServletRequest request, HttpServletResponse response) { + HttpSession session = request.getSession(); + LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); + Delegator delegator = (Delegator) request.getAttribute("delegator"); + GenericValue userLogin = (GenericValue) session.getAttribute("userLogin"); + + String facilityId = request.getParameter("facilityId"); + if (UtilValidate.isEmpty(facilityId)) { + request.setAttribute("_ERROR_MESSAGE_", "Facility should not be empty."); + return "error"; + } + String inventoryCountId = null; + List locationSeqIds = new ArrayList(); + + Map serviceResult = new HashMap(); + Map paramMap = UtilHttp.getParameterMap(request); + int rowCount = UtilHttp.getMultiFormRowCount(paramMap); + + for(int i = 0; i < rowCount; ++i) { + String curSuffix = UtilHttp.getMultiRowDelimiter() + i; + boolean rowSelected = false; + if (UtilValidate.isNotEmpty(request.getAttribute(UtilHttp.getRowSubmitPrefix() + i))) { + rowSelected = request.getAttribute(UtilHttp.getRowSubmitPrefix() + i) == null ? false : + "Y".equalsIgnoreCase((String)request.getAttribute(UtilHttp.getRowSubmitPrefix() + i)); + } else { + rowSelected = request.getParameter(UtilHttp.getRowSubmitPrefix() + i) == null ? false : + "Y".equalsIgnoreCase(request.getParameter(UtilHttp.getRowSubmitPrefix() + i)); + } + + if (!rowSelected) { + continue; + } + String thisSuffix = UtilHttp.getMultiRowDelimiter() + i; // current suffix after each field id + if (paramMap.containsKey("locationSeqId" + thisSuffix)) { + String locationSeqId = (String) paramMap.remove("locationSeqId" + thisSuffix); + locationSeqIds.add(locationSeqId); + } + } + + try { + Map createInventoryCountCtx = new HashMap(); + createInventoryCountCtx.put("userLogin", userLogin); + createInventoryCountCtx.put("facilityId", facilityId); + createInventoryCountCtx.put("statusId", "INV_COUNT_CREATED"); + createInventoryCountCtx.put("createdByUserLogin", userLogin.getString("userLoginId")); + createInventoryCountCtx.put("createdDate", UtilDateTime.nowTimestamp()); + serviceResult = dispatcher.runSync("createInventoryCount", createInventoryCountCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return "error"; + } + inventoryCountId = (String) serviceResult.get("inventoryCountId"); + + for (String locationSeqId : locationSeqIds) { + GenericValue inventoryItemAndLocation = EntityQuery.use(delegator).from("FacilityLocation").where("facilityId", facilityId, "locationSeqId", locationSeqId, "locked", "Y").queryFirst(); + if (UtilValidate.isNotEmpty(inventoryItemAndLocation)) { + Debug.logError("Location #" + locationSeqId + " is currently locked under active counting session #" + inventoryItemAndLocation.getString("inventoryCountId") + " Please choose another location or wait till lock is released.", module); + request.setAttribute("_ERROR_MESSAGE_", "Location #" + locationSeqId + " is currently locked under active counting session #" + inventoryItemAndLocation.getString("inventoryCountId") + ", Please choose another location or wait till lock is released."); + return "error"; + } + Map serviceInCtx = new HashMap(); + serviceInCtx.put("inventoryCountId", inventoryCountId); + serviceInCtx.put("facilityId", facilityId); + serviceInCtx.put("locationSeqId", locationSeqId); + serviceInCtx.put("userLogin", userLogin); + serviceResult.clear(); + serviceResult = dispatcher.runSync("addLocationItemsToCycleCount", serviceInCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + request.setAttribute("_ERROR_MESSAGE_", ServiceUtil.getErrorMessage(serviceResult)); + return "error"; + } + } + request.setAttribute("inventoryCountId", inventoryCountId); + } catch (GenericServiceException e) { + Debug.logError(e, module); + request.setAttribute("_ERROR_MESSAGE_", e.getMessage()); + return "error"; + } catch (GenericEntityException e) { + Debug.logError(e, module); + request.setAttribute("_ERROR_MESSAGE_", e.getMessage()); + return "error"; + } + + request.setAttribute("_EVENT_MESSAGE_", "Session # " + inventoryCountId + " Created successfully."); + return "success"; + } +} \ No newline at end of file diff --git a/applications/product/src/main/java/org/apache/ofbiz/product/inventory/InventoryServices.java b/applications/product/src/main/java/org/apache/ofbiz/product/inventory/InventoryServices.java index 1ed4b26df15..70af41a4146 100644 --- a/applications/product/src/main/java/org/apache/ofbiz/product/inventory/InventoryServices.java +++ b/applications/product/src/main/java/org/apache/ofbiz/product/inventory/InventoryServices.java @@ -20,14 +20,9 @@ import java.math.BigDecimal; import java.math.MathContext; +import java.sql.Date; import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; +import java.util.*; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.GeneralException; @@ -47,9 +42,12 @@ import org.apache.ofbiz.entity.util.EntityListIterator; import org.apache.ofbiz.entity.util.EntityQuery; import org.apache.ofbiz.entity.util.EntityTypeUtil; +import org.apache.ofbiz.entity.util.EntityUtil; +import org.apache.ofbiz.product.product.ProductWorker; import org.apache.ofbiz.service.DispatchContext; import org.apache.ofbiz.service.GenericServiceException; import org.apache.ofbiz.service.LocalDispatcher; +import org.apache.ofbiz.service.ModelService; import org.apache.ofbiz.service.ServiceUtil; import com.ibm.icu.util.Calendar; @@ -1013,5 +1011,706 @@ public static Map getProductInventoryAndFacilitySummary(Dispatch } return result; } + + public static Map updateInventoryCountItemAndRecordVariance(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String inventoryCountId = (String) context.get("inventoryCountId"); + String nextCountDayStr = (String) context.get("nextCountDay"); + String inventoryCountItemSeqId = (String) context.get("inventoryCountItemSeqId"); + String statusId = (String) context.get("statusId"); + Map serviceResult = new HashMap(); + String successMessage = null; + int nextCountDay; + if (UtilValidate.isNotEmpty(nextCountDayStr) && UtilValidate.isInteger(nextCountDayStr)) { + nextCountDay = Integer.parseInt(nextCountDayStr); + } else { + return ServiceUtil.returnError("You have selected invalid count session."); + } + + try { + GenericValue inventoryCount = EntityQuery.use(delegator).from("InventoryCount").where("inventoryCountId",inventoryCountId).queryOne(); + GenericValue inventoryCountItem = EntityQuery.use(delegator).from("InventoryCountItem").where("inventoryCountId", inventoryCountId, "inventoryCountItemSeqId", inventoryCountItemSeqId).queryOne(); + + if (UtilValidate.isNotEmpty(inventoryCountItem)) { + GenericValue inventoryCountVariance = EntityQuery.use(delegator).from("InventoryCountVariance").where("inventoryCountId", inventoryCountId, "inventoryCountItemSeqId", inventoryCountItemSeqId).queryOne(); + if ("INV_COUNT_COMPLETED".equals(statusId) && UtilValidate.isNotEmpty(inventoryCountVariance)) { + Map recordProductVarianceCtx = new HashMap(); + recordProductVarianceCtx.put("userLogin", userLogin); + recordProductVarianceCtx.put("inventoryCountId", inventoryCountItem.getString("inventoryCountId")); + recordProductVarianceCtx.put("inventoryCountItemSeqId", inventoryCountItem.getString("inventoryCountItemSeqId")); + serviceResult = dispatcher.runSync("recordProductVariance", recordProductVarianceCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + + Map updateInventoryCountItemCtx = new HashMap(); + updateInventoryCountItemCtx.put("userLogin", userLogin); + updateInventoryCountItemCtx.put("inventoryCountId", inventoryCountId); + updateInventoryCountItemCtx.put("inventoryCountItemSeqId", inventoryCountItemSeqId); + updateInventoryCountItemCtx.put("itemStatusId", statusId); + serviceResult.clear(); + serviceResult = dispatcher.runSync("updateInventoryCountItem", updateInventoryCountItemCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + + if (UtilValidate.isNotEmpty(inventoryCount) && UtilValidate.isNotEmpty(inventoryCountItem)) { + List invCountItems = EntityQuery.use(delegator).from("InventoryCountItem").where("inventoryCountId", inventoryCountId, "itemStatusId", "INV_COUNT_APPROVED", "locationSeqId", inventoryCountItem.getString("locationSeqId")).queryList(); + if (UtilValidate.isEmpty(invCountItems)) { + GenericValue facilityLocation = EntityQuery.use(delegator).from("FacilityLocation").where("facilityId", inventoryCount.getString("facilityId"), "locationSeqId", inventoryCountItem.getString("locationSeqId")).queryOne(); + if (UtilValidate.isNotEmpty(facilityLocation)) { + Timestamp lastCountDate = UtilDateTime.nowTimestamp(); + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DAY_OF_YEAR, nextCountDay); + Timestamp nextCountDate = new Timestamp(cal.getTimeInMillis()); + Map facilityLocationCtx = dctx.getModelService("updateFacilityLocation").makeValid(facilityLocation, "IN"); + facilityLocationCtx.put("userLogin", userLogin); + facilityLocationCtx.put("locked", null); + if ("INV_COUNT_COMPLETED".equals(statusId)) { + facilityLocationCtx.put("lastCountDate", new Date(lastCountDate.getTime())); + facilityLocationCtx.put("nextCountDate", new Date(nextCountDate.getTime())); + } + serviceResult.clear(); + serviceResult = dispatcher.runSync("updateFacilityLocation", facilityLocationCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + } + } + if ("INV_COUNT_REJECTED".equals(statusId)) { + successMessage = "Inventory count item(s) rejected successfully."; + } else { + successMessage = "Inventory count item(s) accepted and variance recorded successfully."; + } + } else { + return ServiceUtil.returnError("Inventory count variance record not found."); + } + + boolean allRejected = true; + boolean allCompleted = true; + List inventoryCountItems = EntityQuery.use(delegator).from("InventoryCountItem").where("inventoryCountId", inventoryCountId).queryList(); + for (GenericValue inventoryCountItemValue: inventoryCountItems) { + String itmStatusId = inventoryCountItemValue.getString("itemStatusId"); + if (!"INV_COUNT_REJECTED".equals(itmStatusId)) { + allRejected = false; + if (!"INV_COUNT_COMPLETED".equals(itmStatusId)) { + allCompleted = false; + if (!"INV_COUNT_APPROVED".equals(itmStatusId)) { + break; + } + } + } + } + + String newStatus = null; + if (allRejected) { + newStatus = "INV_COUNT_REJECTED"; + } else if (allCompleted) { + newStatus = "INV_COUNT_COMPLETED"; + } + if (UtilValidate.isNotEmpty(newStatus)) { + Map updateInventoryCountCtx = new HashMap(); + updateInventoryCountCtx.put("userLogin", userLogin); + updateInventoryCountCtx.put("inventoryCountId", inventoryCountId); + updateInventoryCountCtx.put("statusId", newStatus); + serviceResult = dispatcher.runSync("updateInventoryCount", updateInventoryCountCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + } catch (GenericEntityException e) { + Debug.logError(e.getMessage(), module); + } catch (GenericServiceException e) { + Debug.logError(e.getMessage(), module); + } + Map result = ServiceUtil.returnSuccess(successMessage); + result.put("inventoryCountId", inventoryCountId); + return result; + } + + public static Map recordProductVariance(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String inventoryCountId = (String) context.get("inventoryCountId"); + String inventoryCountItemSeqId = (String) context.get("inventoryCountItemSeqId"); + Map serviceResult = new HashMap(); + + try { + + GenericValue inventoryCountVariance = EntityQuery.use(delegator).from("InventoryCountVariance").where("inventoryCountId", inventoryCountId, "inventoryCountItemSeqId", inventoryCountItemSeqId).queryOne(); + if (UtilValidate.isNotEmpty(inventoryCountVariance)) { + BigDecimal varianceQuantityOnHand = inventoryCountVariance.getBigDecimal("varianceQuantityOnHand"); + String varianceReasonId = "VAR_FOUND"; + if (varianceQuantityOnHand.compareTo(BigDecimal.ZERO) < 0) { + varianceReasonId = "VAR_LOST"; + } + if (varianceQuantityOnHand.compareTo(BigDecimal.ZERO) != 0) { + Map createPhysicalInventoryAndVarianceCtx = new HashMap(); + createPhysicalInventoryAndVarianceCtx.put("userLogin", userLogin); + createPhysicalInventoryAndVarianceCtx.put("quantityOnHandVar", varianceQuantityOnHand); + createPhysicalInventoryAndVarianceCtx.put("availableToPromiseVar", varianceQuantityOnHand); + createPhysicalInventoryAndVarianceCtx.put("inventoryItemId", inventoryCountVariance.getString("inventoryItemId")); + createPhysicalInventoryAndVarianceCtx.put("varianceReasonId", varianceReasonId); + createPhysicalInventoryAndVarianceCtx.put("comments", "Cycle Count Session # " + inventoryCountId); + serviceResult = dispatcher.runSync("createPhysicalInventoryAndVariance", createPhysicalInventoryAndVarianceCtx); + + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + GenericValue inventoryItem = EntityQuery.use(delegator).from("InventoryItem").where("inventoryItemId", inventoryCountVariance.getString("inventoryItemId")).queryOne(); + String varianceLocationSeqId = inventoryCountVariance.getString("locationSeqId"); + String inventoryLocationSeqId = inventoryItem.getString("locationSeqId"); + if (UtilValidate.isNotEmpty(varianceLocationSeqId) && UtilValidate.isNotEmpty(inventoryLocationSeqId) && !varianceLocationSeqId.equals(inventoryLocationSeqId)) { + ModelService createAccountService = dctx.getModelService("updateInventoryItem"); + Map updateInventoryItemCtx = createAccountService.makeValid(context, ModelService.IN_PARAM); + updateInventoryItemCtx.put("locationSeqId", varianceLocationSeqId); + updateInventoryItemCtx.put("userLogin", userLogin); + + serviceResult.clear(); + serviceResult = dispatcher.runSync("updateInventoryItem", updateInventoryItemCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + + } + } catch (GenericEntityException e) { + Debug.logError(e.getMessage(), module); + } catch (GenericServiceException e) { + Debug.logError(e.getMessage(), module); + } + return ServiceUtil.returnSuccess("Variance recorded successfully."); + } + public static Map addLocationItemsToCycleCount(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String inventoryCountId = (String) context.get("inventoryCountId"); + String locationSeqId = (String) context.get("locationSeqId"); + String facilityId = (String) context.get("facilityId"); + Map serviceResult = new HashMap(); + String successMessage; + String customerOwnedMessage = ""; + boolean itemAdded = false; + + try { + GenericValue inventoryCount = EntityQuery.use(delegator).from("InventoryCount").where("inventoryCountId", inventoryCountId).queryOne(); + if (inventoryCount != null) { + String currentStatusId = inventoryCount.getString("statusId"); + if (UtilValidate.isNotEmpty(currentStatusId) && "INV_COUNT_APPROVED".equals(currentStatusId)) { + Debug.logError("Session already in review status, You can not add more items in this session.", module); + return ServiceUtil.returnError("Session already in review status, You can not add more items in this session."); + } else if (UtilValidate.isNotEmpty(currentStatusId) && "INV_COUNT_COMPLETED".equals(currentStatusId)) { + Debug.logError("Session already completed, Please create new session or use created session.", module); + return ServiceUtil.returnError("Session already completed, Please create new session or use created session."); + } else if (UtilValidate.isNotEmpty(currentStatusId) && "INV_COUNT_REJECTED".equals(currentStatusId)) { + Debug.logError("Session already rejected, Please create new session or use created session.", module); + return ServiceUtil.returnError("Session already rejected, Please create new session or use created session."); + } + } + + GenericValue facilityLocation = EntityQuery.use(delegator).from("FacilityLocation").where("facilityId", facilityId, "locationSeqId", locationSeqId).queryOne(); + if (UtilValidate.isEmpty(facilityLocation)) { + Debug.logError("Facility location does not exist for facility " + facilityId + " and location " + locationSeqId, module); + return ServiceUtil.returnError("Facility location does not exist for facility " + facilityId + " and location " + locationSeqId); + } else { + String facilityIdString = facilityLocation.getString("facilityId"); + if (inventoryCount != null && UtilValidate.isNotEmpty(facilityIdString)) { + facilityId = inventoryCount.getString("facilityId"); + if (!facilityIdString.equals(facilityId)) { + return ServiceUtil.returnError("Location does not belong to existing session facility, Please scan another location."); + } + } + String locked = facilityLocation.getString("locked"); + if (UtilValidate.isNotEmpty(locked) && "Y".equals(locked)) { + Debug.logError("Location #" + locationSeqId + " is currently locked under active counting session. Please choose another location or wait till lock is released.", module); + return ServiceUtil.returnError("Location #" + locationSeqId + " is currently locked under active counting session. Please choose another location or wait till lock is released."); + } + + + EntityCondition cond = EntityCondition.makeCondition(UtilMisc.toList( + EntityCondition.makeCondition("facilityId", facilityId), + EntityCondition.makeCondition("locationSeqId", locationSeqId) + )); + List inventoryItems = EntityQuery.use(delegator).from("InventoryItem").where(cond).orderBy("quantityOnHandTotal DESC").queryList(); + for (GenericValue inventoryItem : inventoryItems) { + List inventoryCountItems = EntityQuery.use(delegator).from("InventoryCountItem").where("inventoryCountId", inventoryCountId, "inventoryItemId", inventoryItem.getString("inventoryItemId"), "locationSeqId", locationSeqId).queryList(); + if (UtilValidate.isNotEmpty(inventoryCountItems)) { + continue; + } + Map createInventoryCountItemCtx = new HashMap(); + createInventoryCountItemCtx.put("userLogin", userLogin); + createInventoryCountItemCtx.put("inventoryCountId", inventoryCountId); + createInventoryCountItemCtx.put("locationSeqId", locationSeqId); + createInventoryCountItemCtx.put("inventoryItemId", inventoryItem.getString("inventoryItemId")); + createInventoryCountItemCtx.put("productId", inventoryItem.getString("productId")); + createInventoryCountItemCtx.put("itemStatusId", "INV_COUNT_CREATED"); + serviceResult = dispatcher.runSync("createInventoryCountItem", createInventoryCountItemCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + itemAdded = true; + } + + if (itemAdded) { + Map facilityLocationCtx = dctx.getModelService("updateFacilityLocation").makeValid(facilityLocation, "IN"); + facilityLocationCtx.put("userLogin", userLogin); + facilityLocationCtx.put("locked", "Y"); + serviceResult.clear(); + serviceResult = dispatcher.runSync("updateFacilityLocation", facilityLocationCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + } + } catch (GenericEntityException e) { + Debug.logError(e.getMessage(), module); + } catch (GenericServiceException e) { + Debug.logError(e.getMessage(), module); + } + if (itemAdded) { + successMessage = "Items added successfully for location # " + locationSeqId + customerOwnedMessage; + } else if (UtilValidate.isNotEmpty(customerOwnedMessage)) { + successMessage = customerOwnedMessage; + } else { + successMessage = "Item not found for given location # " + locationSeqId; + } + Map result = ServiceUtil.returnSuccess(successMessage); + result.put("inventoryCountId", inventoryCountId); + + return result; + } + + public static Map createInventoryCountItem(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + String inventoryCountId = (String) context.get("inventoryCountId"); + String inventoryItemId = (String) context.get("inventoryItemId"); + String itemStatusId = (String) context.get("itemStatusId"); + String locationSeqId = (String) context.get("locationSeqId"); + String productIdentifier = (String) context.get("productIdentifier"); + String productId = (String) context.get("productId"); + BigDecimal quantity = (BigDecimal) context.get("quantity"); + List productList = new ArrayList(); + Map result = ServiceUtil.returnSuccess(); + try { + GenericValue product = EntityQuery.use(delegator).from("Product").where("productId", productId).queryOne(); + if(UtilValidate.isEmpty(product)) { + productIdentifier = productId; + productId = null; + } + if (UtilValidate.isEmpty(product) && UtilValidate.isNotEmpty(productIdentifier)) { + productList = ProductWorker.findProductsById(delegator, productIdentifier, null, true, true); + if(UtilValidate.isNotEmpty(productList) && UtilValidate.isEmpty(productId)) { + product = EntityUtil.getFirst(productList); + productId = product.getString("productId"); + } + } + GenericValue inventoryCountItem = delegator.makeValue("InventoryCountItem", UtilMisc.toMap("inventoryCountId", inventoryCountId, "inventoryItemId", inventoryItemId, "productId", productId, "itemStatusId", itemStatusId, "productIdentifier", productIdentifier, "locationSeqId", locationSeqId)); + if (UtilValidate.isNotEmpty(quantity)) { + inventoryCountItem.set("quantity", quantity); + } + String inventoryCountItemSeqId = delegator.getNextSeqId("InventoryCountItem"); + inventoryCountItem.set("inventoryCountItemSeqId", inventoryCountItemSeqId); + delegator.create(inventoryCountItem); + result.put("inventoryCountItemSeqId", inventoryCountItemSeqId); + } catch (GenericEntityException e) { + Debug.log(module, e.getMessage()); + } + return result; + } + + public static Map addInventoryItemToCycleCount(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String inventoryCountId = (String) context.get("inventoryCountId"); + String inventoryItemId = (String) context.get("inventoryItemId"); + + if (UtilValidate.isEmpty(inventoryItemId)) { + Debug.logError("Please enter inventoryItemId.", module); + return ServiceUtil.returnError("Please enter inventoryItemId."); + } + + Map result = ServiceUtil.returnSuccess("Inventory Item " + inventoryItemId + " added successfully."); + result.put("inventoryCountId", inventoryCountId); + Map serviceResult = new HashMap(); + + try { + GenericValue inventoryCount = EntityQuery.use(delegator).from("InventoryCount").where("inventoryCountId", inventoryCountId).queryOne(); + if (inventoryCount != null) { + String currentStatusId = inventoryCount.getString("statusId"); + if (UtilValidate.isNotEmpty(currentStatusId) && "INV_COUNT_APPROVED".equals(currentStatusId)) { + Debug.logError("Session already in review status, You can not add more items in this session.", module); + return ServiceUtil.returnError("Session already in review status, You can not add more items in this session."); + } else if (UtilValidate.isNotEmpty(currentStatusId) && "INV_COUNT_COMPLETED".equals(currentStatusId)) { + Debug.logError("Session already completed, Please create new session or use created session.", module); + return ServiceUtil.returnError("Session already completed, Please create new session or use created session."); + } else if (UtilValidate.isNotEmpty(currentStatusId) && "INV_COUNT_REJECTED".equals(currentStatusId)) { + Debug.logError("Session already rejected, Please create new session or use created session.", module); + return ServiceUtil.returnError("Session already rejected, Please create new session or use created session."); + } + } + + GenericValue inventoryItem = EntityQuery.use(delegator).from("InventoryItem").where("inventoryItemId", inventoryItemId).queryOne(); + if (inventoryCount != null && inventoryItem != null) { + String existingFacilityId = inventoryCount.getString("facilityId"); + String inventoryItemFacilityId = inventoryItem.getString("facilityId"); + if (UtilValidate.isNotEmpty(existingFacilityId) && UtilValidate.isNotEmpty(inventoryItemFacilityId) && !existingFacilityId.equals(inventoryItemFacilityId)) { + Debug.logError("Inventory Item belongs to a different facility " + inventoryItemFacilityId, module); + return ServiceUtil.returnError("Inventory Item belongs to a different facility " + inventoryItemFacilityId); + } + } else { + Debug.logError("Inventory Item doesn't exist.", module); + return ServiceUtil.returnError("Inventory Item doesn't exist"); + } + + GenericValue facilityLocation = EntityQuery.use(delegator).from("FacilityLocation").where("facilityId", inventoryItem.getString("facilityId"), "locationSeqId", inventoryItem.getString("locationSeqId")).queryOne(); + + List exprList = new ArrayList(); + exprList.add(EntityCondition.makeCondition("locationSeqId", EntityOperator.EQUALS, inventoryItem.getString("locationSeqId"))); + exprList.add(EntityCondition.makeCondition("inventoryItemId", EntityOperator.EQUALS, inventoryItemId)); + exprList.add(EntityCondition.makeCondition("itemStatusId", EntityOperator.IN, UtilMisc.toList("INV_COUNT_CREATED", "INV_COUNT_APPROVED"))); + GenericValue inventoryCountItem = EntityQuery.use(delegator).from("InventoryCountItem").where(EntityCondition.makeCondition(exprList)).queryFirst(); + + if (UtilValidate.isNotEmpty(inventoryCountItem)) { + Debug.logError("Inventory item already exist in session #" + inventoryCountItem.getString("inventoryCountId"), module); + return ServiceUtil.returnError("Inventory item already exist in session #" + inventoryCountItem.getString("inventoryCountId")); + } + Map createInventoryCountItemCtx = new HashMap(); + createInventoryCountItemCtx.put("userLogin", userLogin); + createInventoryCountItemCtx.put("inventoryCountId", inventoryCountId); + createInventoryCountItemCtx.put("locationSeqId", inventoryItem.getString("locationSeqId")); + createInventoryCountItemCtx.put("inventoryItemId", inventoryItemId); + createInventoryCountItemCtx.put("productId", inventoryItem.getString("productId")); + createInventoryCountItemCtx.put("itemStatusId", "INV_COUNT_CREATED"); + serviceResult = dispatcher.runSync("createInventoryCountItem", createInventoryCountItemCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + Map facilityLocationCtx = dctx.getModelService("updateFacilityLocation").makeValid(facilityLocation, "IN"); + facilityLocationCtx.put("userLogin", userLogin); + facilityLocationCtx.put("locked", "Y"); + serviceResult.clear(); + serviceResult = dispatcher.runSync("updateFacilityLocation", facilityLocationCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } catch (GenericEntityException e) { + Debug.logError(e.getMessage(), module); + return ServiceUtil.returnError(e.getMessage()); + } catch (GenericServiceException e) { + Debug.logError(e.getMessage(), module); + return ServiceUtil.returnError(e.getMessage()); + } + return result; + } + + public static Map approveInventoryCountAndItems(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String inventoryCountId = (String) context.get("inventoryCountId"); + String statusId = (String) context.get("statusId"); + String successMessage = "Session submitted successfully."; + if (UtilValidate.isNotEmpty(statusId) && "INV_COUNT_REJECTED".equals(statusId)) { + successMessage = "Session rejected successfully."; + } + Map result = ServiceUtil.returnSuccess(successMessage); + result.put("inventoryCountId", inventoryCountId); + Map serviceResult = new HashMap(); + List> facilityAndLocations = new ArrayList>(); + + try { + GenericValue inventoryCount = EntityQuery.use(delegator).from("InventoryCount").where("inventoryCountId", inventoryCountId).queryOne(); + if (UtilValidate.isNotEmpty(inventoryCount)) { + List inventoryCountItems = EntityQuery.use(delegator).from("InventoryCountItem").where("inventoryCountId", inventoryCountId).queryList(); + for (GenericValue inventoryCountItem : inventoryCountItems) { + Map facilityAndLocationMap = new HashMap(); + facilityAndLocationMap.put("facilityId", inventoryCount.getString("facilityId")); + facilityAndLocationMap.put("locationSeqId", inventoryCountItem.getString("locationSeqId")); + facilityAndLocations.add(facilityAndLocationMap); + Map updateInventoryCountItemCtx = new HashMap(); + updateInventoryCountItemCtx.put("userLogin", userLogin); + updateInventoryCountItemCtx.put("inventoryCountId", inventoryCountId); + updateInventoryCountItemCtx.put("inventoryCountItemSeqId", inventoryCountItem.getString("inventoryCountItemSeqId")); + if (UtilValidate.isNotEmpty(statusId)) { + updateInventoryCountItemCtx.put("itemStatusId", statusId); + } else { + updateInventoryCountItemCtx.put("itemStatusId", "INV_COUNT_APPROVED"); + } + + serviceResult = dispatcher.runSync("updateInventoryCountItem", updateInventoryCountItemCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + + Map updateInventoryCountCtx = new HashMap(); + updateInventoryCountCtx.put("userLogin", userLogin); + updateInventoryCountCtx.put("inventoryCountId", inventoryCountId); + if (UtilValidate.isNotEmpty(statusId)) { + updateInventoryCountCtx.put("statusId", statusId); + } else { + updateInventoryCountCtx.put("statusId", "INV_COUNT_APPROVED"); + } + serviceResult = dispatcher.runSync("updateInventoryCount", updateInventoryCountCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + + for (Map facilityAndLocation : facilityAndLocations) { + String facilityId = (String) facilityAndLocation.get("facilityId"); + String locationSeqId = (String) facilityAndLocation.get("locationSeqId"); + + List exprList = new ArrayList(); + exprList.add(EntityCondition.makeCondition("inventoryCountId", EntityOperator.EQUALS, inventoryCountId)); + exprList.add(EntityCondition.makeCondition("locationSeqId", EntityOperator.EQUALS, locationSeqId)); + exprList.add(EntityCondition.makeCondition("facilityId", EntityOperator.EQUALS, facilityId)); + exprList.add(EntityCondition.makeCondition("itemStatusId", EntityOperator.IN, UtilMisc.toList("INV_COUNT_APPROVED"))); + List invCountItems = EntityQuery.use(delegator).from("InventoryCountAndItems").where(EntityCondition.makeCondition(exprList)).queryList(); + + if (UtilValidate.isEmpty(invCountItems) && UtilValidate.isNotEmpty(facilityId) && UtilValidate.isNotEmpty(locationSeqId)) { + GenericValue facilityLocation = EntityQuery.use(delegator).from("FacilityLocation").where("facilityId", facilityId, "locationSeqId", locationSeqId).queryOne(); + Map facilityLocationCtx = dctx.getModelService("updateFacilityLocation").makeValid(facilityLocation, "IN"); + facilityLocationCtx.put("userLogin", userLogin); + facilityLocationCtx.put("locked", ""); + serviceResult.clear(); + serviceResult = dispatcher.runSync("updateFacilityLocation", facilityLocationCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + } + } else { + Debug.logError("Inventory count does not exist into system.", module); + return ServiceUtil.returnError("Inventory count does not exist into system."); + } + + } catch (GenericEntityException e) { + Debug.logError(e.getMessage(), module); + return ServiceUtil.returnError(e.getMessage()); + } catch (GenericServiceException e) { + Debug.logError(e.getMessage(), module); + return ServiceUtil.returnError(e.getMessage()); + } + return result; + } + + public static Map updateCountItemAndCreateCountVariance(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + LocalDispatcher dispatcher = dctx.getDispatcher(); + GenericValue userLogin = (GenericValue) context.get("userLogin"); + + String inventoryCountId = (String) context.get("inventoryCountId"); + String inventoryCountItemSeqId = (String) context.get("inventoryCountItemSeqId"); + BigDecimal quantity = (BigDecimal) context.get("quantity"); + Map result = ServiceUtil.returnSuccess(); + result.put("inventoryCountId", inventoryCountId); + Map serviceResult = new HashMap(); + + if (UtilValidate.isNotEmpty(quantity)) { + try { + GenericValue inventoryCountItem = EntityQuery.use(delegator).from("InventoryCountItem").where("inventoryCountId", inventoryCountId, "inventoryCountItemSeqId", inventoryCountItemSeqId).queryOne(); + if (UtilValidate.isEmpty(inventoryCountItem)) { + Debug.logError("Item doesn't exist", module); + return ServiceUtil.returnError("Item doesn't exist"); + } else { + Map updateInventoryCountItemCtx = dctx.getModelService("updateInventoryCountItem").makeValid(inventoryCountItem, "IN"); + updateInventoryCountItemCtx.put("userLogin", userLogin); + updateInventoryCountItemCtx.put("quantity", quantity); + serviceResult = dispatcher.runSync("updateInventoryCountItem", updateInventoryCountItemCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + + GenericValue inventoryCountVariance = EntityQuery.use(delegator).from("InventoryCountVariance").where("inventoryCountId", inventoryCountId, "inventoryCountItemSeqId", inventoryCountItemSeqId).queryOne(); + String productId = inventoryCountItem.getString("productId"); + String inventoryItemId = inventoryCountItem.getString("inventoryItemId"); + String locationSeqId = inventoryCountItem.getString("locationSeqId"); + BigDecimal actualQOH = quantity; + if (UtilValidate.isEmpty(quantity)) { + actualQOH = inventoryCountItem.getBigDecimal("quantity"); + } + if (UtilValidate.isNotEmpty(inventoryCountVariance) && UtilValidate.isNotEmpty(productId) && UtilValidate.isNotEmpty(inventoryItemId) && UtilValidate.isNotEmpty(locationSeqId)) { + GenericValue inventoryItem = EntityQuery.use(delegator).from("InventoryItem").where("inventoryItemId", inventoryItemId).queryOne(); + BigDecimal systemicQOH = BigDecimal.ZERO; + BigDecimal totalCost = BigDecimal.ZERO; + BigDecimal unitCost = BigDecimal.ZERO; + if (UtilValidate.isNotEmpty(inventoryItem)) { + if (UtilValidate.isNotEmpty(inventoryItem.getBigDecimal("unitCost"))) { + unitCost = inventoryItem.getBigDecimal("unitCost"); + } + if (UtilValidate.isNotEmpty(inventoryItem.getBigDecimal("quantityOnHandTotal"))) { + systemicQOH = inventoryItem.getBigDecimal("quantityOnHandTotal"); + } + totalCost = systemicQOH.multiply(unitCost); + } + + Map updateInventoryCountVarianceCtx = new HashMap(); + updateInventoryCountVarianceCtx.put("inventoryCountId", inventoryCountId); + updateInventoryCountVarianceCtx.put("inventoryCountItemSeqId", inventoryCountItemSeqId); + updateInventoryCountVarianceCtx.put("inventoryItemId", inventoryItemId); + updateInventoryCountVarianceCtx.put("productId", productId); + updateInventoryCountVarianceCtx.put("locationSeqId", locationSeqId); + updateInventoryCountVarianceCtx.put("systemQuantityOnHand", systemicQOH); + updateInventoryCountVarianceCtx.put("actualQuantityOnHand", actualQOH); + BigDecimal varianceQOH = actualQOH.subtract(systemicQOH); + updateInventoryCountVarianceCtx.put("varianceQuantityOnHand", varianceQOH); + BigDecimal actualCost = actualQOH.multiply(unitCost); + BigDecimal costVariance = varianceQOH.multiply(unitCost); + updateInventoryCountVarianceCtx.put("unitCost", unitCost); + updateInventoryCountVarianceCtx.put("totalCost", totalCost); + updateInventoryCountVarianceCtx.put("actualCost", actualCost); + updateInventoryCountVarianceCtx.put("costVariance", costVariance); + + GenericValue productPrice = EntityQuery.use(delegator).from("ProductPrice").where("productId", productId, "productPriceTypeId", "DEFAULT_PRICE").filterByDate().queryFirst(); + if (UtilValidate.isEmpty(productPrice)) { + GenericValue product = EntityQuery.use(delegator).from("Product").where("productId", productId).queryOne(); + if ("Y".equals(product.getString("isVariant"))) { + String virtualProductId = ProductWorker.getVariantVirtualId(product); + productPrice = EntityQuery.use(delegator).from("ProductPrice").where("productId", virtualProductId, "productPriceTypeId", "DEFAULT_PRICE").filterByDate().queryFirst(); + } + } + + BigDecimal actualValue = BigDecimal.ZERO; + BigDecimal totalValue = BigDecimal.ZERO; + BigDecimal valueVariance = BigDecimal.ZERO; + if (UtilValidate.isNotEmpty(productPrice)) { + actualValue = actualQOH.multiply(productPrice.getBigDecimal("price")); + totalValue = systemicQOH.multiply(productPrice.getBigDecimal("price")); + valueVariance = varianceQOH.multiply(productPrice.getBigDecimal("price")); + } + + updateInventoryCountVarianceCtx.put("totalValue", totalValue); + updateInventoryCountVarianceCtx.put("actualValue", actualValue); + updateInventoryCountVarianceCtx.put("valueVariance", valueVariance); + + updateInventoryCountVarianceCtx.put("userLogin", userLogin); + serviceResult = dispatcher.runSync("updateInventoryCountVariance", updateInventoryCountVarianceCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } else if(UtilValidate.isEmpty(inventoryCountVariance) && UtilValidate.isNotEmpty(productId) && UtilValidate.isNotEmpty(inventoryItemId) && UtilValidate.isNotEmpty(locationSeqId)) { + Map createInventoryCountVarianceCtx = dctx.getModelService("createInventoryCountVariance").makeValid(inventoryCountItem, "IN"); + createInventoryCountVarianceCtx.put("userLogin", userLogin); + createInventoryCountVarianceCtx.put("actualQuantityOnHand", quantity); + serviceResult.clear(); + serviceResult = dispatcher.runSync("createInventoryCountVariance", createInventoryCountVarianceCtx); + if (!ServiceUtil.isSuccess(serviceResult)) { + Debug.logError(ServiceUtil.getErrorMessage(serviceResult), module); + return ServiceUtil.returnError(ServiceUtil.getErrorMessage(serviceResult)); + } + } + } + } catch (GenericEntityException e) { + Debug.logError(e.getMessage(), module); + } catch (GenericServiceException e) { + Debug.logError(e.getMessage(), module); + } + } + + return result; + } + + public static Map createInventoryCountVariance(DispatchContext dctx, Map context) { + Delegator delegator = dctx.getDelegator(); + + String inventoryCountId = (String) context.get("inventoryCountId"); + String inventoryCountItemSeqId = (String) context.get("inventoryCountItemSeqId"); + String inventoryItemId = (String) context.get("inventoryItemId"); + String productId = (String) context.get("productId"); + + String productIdentifier = (String) context.get("productIdentifier"); + String locationSeqId = (String) context.get("locationSeqId"); + BigDecimal actualQOH = (BigDecimal) context.get("actualQuantityOnHand"); + + try { + GenericValue inventoryItem = EntityQuery.use(delegator).from("InventoryItem").where("inventoryItemId", inventoryItemId).queryOne(); + BigDecimal systemicQOH = BigDecimal.ZERO; + BigDecimal totalCost = BigDecimal.ZERO; + BigDecimal unitCost = BigDecimal.ZERO; + if (UtilValidate.isNotEmpty(inventoryItem)) { + if (UtilValidate.isNotEmpty(inventoryItem.getBigDecimal("unitCost"))) { + unitCost = inventoryItem.getBigDecimal("unitCost"); + } + if (UtilValidate.isNotEmpty(inventoryItem.getBigDecimal("quantityOnHandTotal"))) { + systemicQOH = inventoryItem.getBigDecimal("quantityOnHandTotal"); + } + totalCost = systemicQOH.multiply(unitCost); + } + + Map inventoryCountVarianceCtx = new HashMap(); + inventoryCountVarianceCtx.put("inventoryCountId", inventoryCountId); + inventoryCountVarianceCtx.put("inventoryItemId", inventoryItemId); + inventoryCountVarianceCtx.put("inventoryCountItemSeqId", inventoryCountItemSeqId); + inventoryCountVarianceCtx.put("productId", productId); + inventoryCountVarianceCtx.put("productIdentifier", productIdentifier); + inventoryCountVarianceCtx.put("locationSeqId", locationSeqId); + inventoryCountVarianceCtx.put("systemQuantityOnHand", systemicQOH); + inventoryCountVarianceCtx.put("actualQuantityOnHand", actualQOH); + BigDecimal varianceQOH = actualQOH.subtract(systemicQOH); + inventoryCountVarianceCtx.put("varianceQuantityOnHand", varianceQOH); + BigDecimal actualCost = actualQOH.multiply(unitCost); + BigDecimal costVariance = varianceQOH.multiply(unitCost); + inventoryCountVarianceCtx.put("unitCost", unitCost); + inventoryCountVarianceCtx.put("totalCost", totalCost); + inventoryCountVarianceCtx.put("actualCost", actualCost); + inventoryCountVarianceCtx.put("costVariance", costVariance); + + GenericValue productPrice = EntityQuery.use(delegator).from("ProductPrice").where("productId", productId, "productPriceTypeId", "DEFAULT_PRICE").filterByDate().queryFirst(); + if (UtilValidate.isEmpty(productPrice)) { + GenericValue product = EntityQuery.use(delegator).from("Product").where("productId", productId).queryOne(); + if ("Y".equals(product.getString("isVariant"))) { + String virtualProductId = ProductWorker.getVariantVirtualId(product); + productPrice = EntityQuery.use(delegator).from("ProductPrice").where("productId", virtualProductId, "productPriceTypeId", "DEFAULT_PRICE").filterByDate().queryFirst(); + } + } + + BigDecimal actualValue = BigDecimal.ZERO; + BigDecimal totalValue = BigDecimal.ZERO; + BigDecimal valueVariance = BigDecimal.ZERO; + if (UtilValidate.isNotEmpty(productPrice)) { + actualValue = actualQOH.multiply(productPrice.getBigDecimal("price")); + totalValue = systemicQOH.multiply(productPrice.getBigDecimal("price")); + valueVariance = varianceQOH.multiply(productPrice.getBigDecimal("price")); + } + + inventoryCountVarianceCtx.put("totalValue", totalValue); + inventoryCountVarianceCtx.put("actualValue", actualValue); + inventoryCountVarianceCtx.put("valueVariance", valueVariance); + + GenericValue inventoryCountVariance = delegator.makeValue("InventoryCountVariance", inventoryCountVarianceCtx); + delegator.create(inventoryCountVariance); + } catch (GenericEntityException e) { + Debug.log(e.getMessage(), module); + } + return ServiceUtil.returnSuccess("Inventory Count Variance record created successfully."); + } -} +} \ No newline at end of file diff --git a/applications/product/template/cyclecount/CountReport.ftl b/applications/product/template/cyclecount/CountReport.ftl new file mode 100644 index 00000000000..fcd1b4644c0 --- /dev/null +++ b/applications/product/template/cyclecount/CountReport.ftl @@ -0,0 +1,242 @@ +<#-- +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. +--> +
+
+
    +
  • ${uiLabelMap.ProductCountReport}
  • +
+
+ <#setting number_format=",##0.00;(,##0.00)"> +
+ + + + + + + + +
+
+
+
    +
  • ${uiLabelMap.CommonSearchOptions}/li> +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + +
+ <#if facilityIds?has_content && "All" != parameters.facilityIds> + <@htmlTemplate.lookupField value='${parameters.locationSeqId!}' formName="FindCycleCount" name="locationSeqId" id="locationSeqId" fieldFormName="LookupFacilityLocation?facilityId=${parameters.facilityIds!}"/> + <#else> + <@htmlTemplate.lookupField value='${parameters.locationSeqId!}' formName="FindCycleCount" name="locationSeqId" id="locationSeqId" fieldFormName="LookupFacilityLocation"/> + +
+
${uiLabelMap.CommonFromDate} + <@htmlTemplate.renderDateTimeField name="fromDate" event="" action="" className="${class!}" alert="" title="Format: yyyy-MM-dd HH:mm:ss.SSS" value="${(parameters.fromDate)!}" size="25" maxlength="30" id="fromDate" dateType="date" shortDateInput=false timeDropdownParamName="" defaultDateTimeString="" localizedIconTitle="" timeDropdown="" timeHourName="" classString="" hour1="" hour2="" timeMinutesName="" minutes="" isTwelveHour="" ampmName="" amSelected="" pmSelected="" compositeType="" formName=""/> +
${uiLabelMap.ToDate} + <@htmlTemplate.renderDateTimeField name="toDate" event="" action="" className="${class!}" alert="" title="Format: yyyy-MM-dd HH:mm:ss.SSS" value="${(parameters.toDate)!}" size="25" maxlength="30" id="toDate" dateType="date" shortDateInput=false timeDropdownParamName="" defaultDateTimeString="" localizedIconTitle="" timeDropdown="" timeHourName="" classString="" hour1="" hour2="" timeMinutesName="" minutes="" isTwelveHour="" ampmName="" amSelected="" pmSelected="" compositeType="" formName=""/> +
+ +
+
+
+
+
+
+
+
+
    +
  • ${uiLabelMap.CountProgress}
  • +
+
+
+ <#if inventoryCountItemsAndVariances?has_content> + + + + + + + + + + + + + + + + + + + <#list progressList as progress> + + + + + + + + + + + + + + + + + + + + + + +
${uiLabelMap.CountProgress}${uiLabelMap.TotalProjectedCounts}${uiLabelMap.WorkEffortPercentComplete}
${uiLabelMap.Facility}${uiLabelMap.LocationCounted}${uiLabelMap.InventoryItemsCounted}${uiLabelMap.ProductLocations}${uiLabelMap.ProductInventoryItems}${uiLabelMap.ProductLocations}${uiLabelMap.ProductInventoryItems}
${progress.facilityName!}${progress.countedLocations!}${progress.totalCountedInventoryItems!}${progress.totalLocations!}${progress.totalInventoryItems!}${progress.percentLocationCompleted!}%${progress.percentInventoryItemCompleted!}%
Grand Total${grandTotalLocationCounted!}${grandTotalInventoryItemCounted!}${grandTotalLocationCompleted!}${grandTotalInventoryItemCompleted!}${grandTotalPerLocation!}%${grandTotalPerInventoryItem!}%
+ <#else> + + +
+
+
+
+
+
    +
  • ${uiLabelMap.ItemVariance}
  • +
+
+
+ <#if inventoryCountItemsAndVariances?has_content> + + + + + + + + + + + + + + + + + + + + + <#list inventoryCountItemsAndVariances as inventoryCountItemsAndVariance> + + + + + + + + + + + + + + + + + + +
${uiLabelMap.Facility}${uiLabelMap.ProductLocation}Counted OnVariance Created On${uiLabelMap.ProductInventoryItem}${uiLabelMap.ProductProductName}${uiLabelMap.ProductProductDescription}Qty CountedSystem QOH${uiLabelMap.FormFieldTitle_unitCost}${uiLabelMap.ProductQtyVariance}Variance ValueInventory Value${uiLabelMap.WebtoolsErrorLogLevel}
${inventoryCountItemsAndVariance.facilityName!} + <#if inventoryCountItemsAndVariance.areaId?has_content>${inventoryCountItemsAndVariance.areaId!}: <#if inventoryCountItemsAndVariance.aisleId?has_content>${inventoryCountItemsAndVariance.aisleId!}:<#if inventoryCountItemsAndVariance.sectionId?has_content>${inventoryCountItemsAndVariance.sectionId!}:<#if inventoryCountItemsAndVariance.levelId?has_content>${inventoryCountItemsAndVariance.levelId!}:<#if inventoryCountItemsAndVariance.positionId?has_content>${inventoryCountItemsAndVariance.positionId!}
[${inventoryCountItemsAndVariance.locationSeqId!}]
+
<#if inventoryCountItemsAndVariance.createdDate?has_content>${inventoryCountItemsAndVariance.createdDate?string("MM/dd/yyyy")}<#if inventoryCountItemsAndVariance.varianceCreatedOn?has_content>${inventoryCountItemsAndVariance.varianceCreatedOn?string("MM/dd/yyyy")} + <#if inventoryCountItemsAndVariance.inventoryItemId?has_content> + ${inventoryCountItemsAndVariance.inventoryItemId!} + + + <#if inventoryCountItemsAndVariance.internalName?has_content && inventoryCountItemsAndVariance.internalName?length > 20> + ${inventoryCountItemsAndVariance.internalName?substring(0,20)} + <#else> + ${inventoryCountItemsAndVariance.internalName!} + + + <#if inventoryCountItemsAndVariance.partDescription?has_content && inventoryCountItemsAndVariance.partDescription?length > 20> + ${inventoryCountItemsAndVariance.partDescription?substring(0,20)} + <#else> + ${inventoryCountItemsAndVariance.partDescription!} + + title="${inventoryCountItemsAndVariance.quantity!}"> +
<#if inventoryCountItemsAndVariance.quantity?has_content && inventoryCountItemsAndVariance.quantity < 0> ${inventoryCountItemsAndVariance.quantity!}<#else>${inventoryCountItemsAndVariance.quantity!}
+
title="${inventoryCountItemsAndVariance.systemQuantityOnHand!}"> +
<#if inventoryCountItemsAndVariance.systemQuantityOnHand?has_content && inventoryCountItemsAndVariance.systemQuantityOnHand < 0> ${inventoryCountItemsAndVariance.systemQuantityOnHand!}<#else>${inventoryCountItemsAndVariance.systemQuantityOnHand!}
+
title="${inventoryCountItemsAndVariance.unitCost!}"> +
<#if inventoryCountItemsAndVariance.unitCost?has_content && inventoryCountItemsAndVariance.unitCost < 0> <@ofbizCurrency amount=inventoryCountItemsAndVariance.unitCost isoCode=currencyUomId/><#else><@ofbizCurrency amount=inventoryCountItemsAndVariance.unitCost isoCode=currencyUomId/>
+
title="${inventoryCountItemsAndVariance.varianceQuantityOnHand!}"> +
<#if inventoryCountItemsAndVariance.varianceQuantityOnHand?has_content && inventoryCountItemsAndVariance.varianceQuantityOnHand < 0> ${inventoryCountItemsAndVariance.varianceQuantityOnHand!}<#else>${inventoryCountItemsAndVariance.varianceQuantityOnHand!}
+
title="${inventoryCountItemsAndVariance.costVariance!}"> +
<#if inventoryCountItemsAndVariance.costVariance?has_content && inventoryCountItemsAndVariance.costVariance < 0> <@ofbizCurrency amount=inventoryCountItemsAndVariance.costVariance isoCode=currencyUomId/><#else><@ofbizCurrency amount=inventoryCountItemsAndVariance.costVariance isoCode=currencyUomId/>
+
title="${inventoryCountItemsAndVariance.totalCost!}"> +
<#if inventoryCountItemsAndVariance.totalCost?has_content && inventoryCountItemsAndVariance.totalCost < 0> <@ofbizCurrency amount=inventoryCountItemsAndVariance.totalCost isoCode=currencyUomId/><#else><@ofbizCurrency amount=inventoryCountItemsAndVariance.totalCost isoCode=currencyUomId/>
+
title="${inventoryCountItemsAndVariance.error!}"> +
<#if inventoryCountItemsAndVariance.error?has_content && inventoryCountItemsAndVariance.error < 0> ${inventoryCountItemsAndVariance.error!}%<#else>${inventoryCountItemsAndVariance.error!}%
+
+ <#else> + + +
+
+
+
diff --git a/applications/product/template/cyclecount/FindCycleCount.ftl b/applications/product/template/cyclecount/FindCycleCount.ftl new file mode 100644 index 00000000000..d1830a3e048 --- /dev/null +++ b/applications/product/template/cyclecount/FindCycleCount.ftl @@ -0,0 +1,87 @@ +<#-- +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. +--> +
+
+
    +
  • ${uiLabelMap.FindSession}
  • +
+
+
+
+
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + +
+ + +
+ <@htmlTemplate.lookupField value='${parameters.locationSeqId!}' formName="FindCycleCount" name="locationSeqId" id="locationSeqId" fieldFormName="LookupFacilityLocation?facilityId=${facilityId!}"/> +
+
+ + + <#list statusItems as statusItem> + checked="checked"<#elseif parameters.statusIds?has_content && statusItem.statusId == parameters.statusIds>checked="checked"<#elseif !parameters.statusIds?has_content && statusItem.statusId == "INV_COUNT_APPROVED">checked="checked"/> + + +
+ +
+
+
+
+
+
+
\ No newline at end of file diff --git a/applications/product/template/cyclecount/FindPendingLocation.ftl b/applications/product/template/cyclecount/FindPendingLocation.ftl new file mode 100644 index 00000000000..3b6b9b34518 --- /dev/null +++ b/applications/product/template/cyclecount/FindPendingLocation.ftl @@ -0,0 +1,81 @@ +<#-- +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. +--> +
+
+
    +
  • ${uiLabelMap.FindPendingLocations}
  • +
+
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + +
+ <@htmlTemplate.lookupField value='${parameters.locationSeqId!}' formName="FindCycleCount" name="locationSeqId" id="locationSeqId" fieldFormName="LookupFacilityLocation?facilityId=${facilityId!}"/> +
+ + + + + +
${uiLabelMap.LocationNotScanned} + ${uiLabelMap.CommonDays} +
${uiLabelMap.LocationScheduledForScanning} + ${uiLabelMap.CommonDays} +
+ +
+
+
+
+
\ No newline at end of file diff --git a/applications/product/template/cyclecount/ListCycleCount.ftl b/applications/product/template/cyclecount/ListCycleCount.ftl new file mode 100644 index 00000000000..30eb3f9de45 --- /dev/null +++ b/applications/product/template/cyclecount/ListCycleCount.ftl @@ -0,0 +1,71 @@ +<#-- +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. +--> +
+
+
    +
  • ${uiLabelMap.Results}
  • +
+
+
+ <#if cycleCountMap?has_content> +
+ + + + + + + + + + + + <#assign rowClass = "2"/> + <#assign rowCount = 0/> + <#list cycleCountMap.keySet() as key> + <#assign cycleCount = cycleCountMap.get(key)> + class="alternate-row"> + + + + + + + <#assign rowCount = rowCount + 1> + <#if rowClass == "2"> + <#assign rowClass = "1"> + <#else> + <#assign rowClass = "2"> + + + +
${uiLabelMap.Session}${uiLabelMap.ProductFacility}${uiLabelMap.ProductLocation}s${uiLabelMap.CommonStatus}${uiLabelMap.CountedInventoryItems}
+ <#if "INV_COUNT_CREATED" == cycleCount.statusId> + ${cycleCount.inventoryCountId!} + + <#if "INV_COUNT_CREATED" != cycleCount.statusId> + ${cycleCount.inventoryCountId!} + + ${cycleCount.facilityName!}<#if cycleCount.locationSeqIds?has_content><#list cycleCount.locationSeqIds as locationSeqId>${locationSeqId!}<#if locationSeqId_has_next>, ${cycleCount.statusDescription!}${cycleCount.totalInventoryItems!}
+
+ <#else> +

${uiLabelMap.CommonNoRecordFound}.

+ +
+
\ No newline at end of file diff --git a/applications/product/template/cyclecount/PendingLocations.ftl b/applications/product/template/cyclecount/PendingLocations.ftl new file mode 100644 index 00000000000..a271ebe5106 --- /dev/null +++ b/applications/product/template/cyclecount/PendingLocations.ftl @@ -0,0 +1,115 @@ +<#-- +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. +--> +
+
+
    +
  • ${uiLabelMap.PendingLocations}
  • +
  • +
+
+
+ <#if pendingLocations?has_content> + <#assign commonUrl> + <@ofbizUrl>RecordCount? + + <#if parameters.facilityId?has_content> + <#assign commonUrl=commonUrl?trim+'facilityId='+parameters.facilityId?default("")+'&'/> + + <#if parameters.locationSeqId?has_content> + <#assign commonUrl=commonUrl?trim+'locationSeqId='+parameters.locationSeqId?default("")+'&'/> + + <#if parameters.areaId?has_content> + <#assign commonUrl=commonUrl?trim+'areaId='+parameters.areaId?default("")+'&'/> + + <#if parameters.aisleId?has_content> + <#assign commonUrl=commonUrl?trim+'aisleId='+parameters.aisleId?default("")+'&'/> + + <#if parameters.sectionId?has_content> + <#assign commonUrl=commonUrl?trim+'sectionId='+parameters.sectionId?default("")+'&'/> + + <#if parameters.levelId?has_content> + <#assign commonUrl=commonUrl?trim+'levelId='+parameters.levelId?default("")+'&'/> + + <#if parameters.positionId?has_content> + <#assign commonUrl=commonUrl?trim+'positionId='+parameters.positionId?default("")+'&'/> + + <#if parameters.countDays?has_content> + <#assign commonUrl=commonUrl?trim+'countDays='+parameters.countDays?default("")+'&'/> + + <#if parameters.nextCountDays?has_content> + <#assign commonUrl=commonUrl?trim+'nextCountDays='+parameters.nextCountDays?default("")+'&'/> + + <@htmlTemplate.nextPrev commonUrl=commonUrl ajaxEnabled=false javaScriptEnabled=false paginateStyle="nav-pager" paginateFirstStyle="nav-first" viewIndex=viewIndex highIndex=highIndex listSize=listSize viewSize=viewSize ajaxFirstUrl="" firstUrl="" paginateFirstLabel="" paginatePreviousStyle="nav-previous" ajaxPreviousUrl="" previousUrl="" paginatePreviousLabel="" pageLabel="" ajaxSelectUrl="" selectUrl="" ajaxSelectSizeUrl="" selectSizeUrl="" commonDisplaying=commonDisplaying paginateNextStyle="nav-next" ajaxNextUrl="" nextUrl="" paginateNextLabel="" paginateLastStyle="nav-last" ajaxLastUrl="" lastUrl="" paginateLastLabel="" paginateViewSizeLabel="" /> + <#assign rowCount = 0/> +
+ + + + + + + + + + + + + + + + + + + + + <#assign rowCount = 0/> + <#list pendingLocations as pendingLocation> + + + + + + + + + + + + + + + + <#assign rowCount = rowCount + 1> + + +
${uiLabelMap.Facility}${uiLabelMap.ProductLocation}${uiLabelMap.ProductArea}${uiLabelMap.ProductAisle}${uiLabelMap.ProductSection}${uiLabelMap.ProductLevel}${uiLabelMap.ProductPosition}Last counted onDays since last countNext count dateDays to next count${uiLabelMap.CommonTotal} ${uiLabelMap.ProductInventoryItems}
${pendingLocation.facilityName!} + ${pendingLocation.areaId!} <#if pendingLocation.aisleId?has_content>:${pendingLocation.aisleId!}<#if pendingLocation.sectionId?has_content>:${pendingLocation.sectionId!}<#if pendingLocation.levelId?has_content>:${pendingLocation.levelId!}:${pendingLocation.positionId!} [${pendingLocation.locationSeqId!}] + ${pendingLocation.areaId!}${pendingLocation.aisleId!}${pendingLocation.sectionId!}${pendingLocation.levelId!}${pendingLocation.positionId!}<#if pendingLocation.lastCountDate?has_content>${pendingLocation.lastCountDate?string('MM/dd/yyyy')}${pendingLocation.lastCountDay!}<#if pendingLocation.nextCountDate?has_content>${pendingLocation.nextCountDate?string('MM/dd/yyyy')}${pendingLocation.nextCountDay!}${pendingLocation.totalInventoryItems!} + + +
+
+ <@htmlTemplate.nextPrev commonUrl=commonUrl ajaxEnabled=false javaScriptEnabled=false paginateStyle="nav-pager" paginateFirstStyle="nav-first" viewIndex=viewIndex highIndex=highIndex listSize=listSize viewSize=viewSize ajaxFirstUrl="" firstUrl="" paginateFirstLabel="" paginatePreviousStyle="nav-previous" ajaxPreviousUrl="" previousUrl="" paginatePreviousLabel="" pageLabel="" ajaxSelectUrl="" selectUrl="" ajaxSelectSizeUrl="" selectSizeUrl="" commonDisplaying=commonDisplaying paginateNextStyle="nav-next" ajaxNextUrl="" nextUrl="" paginateNextLabel="" paginateLastStyle="nav-last" ajaxLastUrl="" lastUrl="" paginateLastLabel="" paginateViewSizeLabel="" /> + <#else> + + +
+
\ No newline at end of file diff --git a/applications/product/template/cyclecount/RecordCount.ftl b/applications/product/template/cyclecount/RecordCount.ftl new file mode 100644 index 00000000000..516744cc573 --- /dev/null +++ b/applications/product/template/cyclecount/RecordCount.ftl @@ -0,0 +1,208 @@ +<#-- +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. +--> + + +<#if countSessionValue?has_content> +
+
+
    + <#if "INV_COUNT_CREATED" == countSessionValue.statusId> +
  • +
    + + +
    +
  • +
  • +
    + + + +
    +
  • + +
  • ${uiLabelMap.FacilityRecordCount}
  • +
+
+
+ + + + +
+
+
    +
  • Session Details
  • +
+
+
+ + + + + + + + + + + + + + + + + + <#if "INV_COUNT_CREATED" == countSessionValue.statusId> + + + + + + <#if "INV_COUNT_CREATED" == countSessionValue.statusId> + + + + + +
Session:${countSessionValue.inventoryCountId!}
${uiLabelMap.FacilityFacility}:${countSessionValue.facilityName!}
Status:${countSessionValue.statusDescription!}
Scanned By:${countSessionValue.createdBy!}
${uiLabelMap.ProductLocation}: +
+ + + <@htmlTemplate.lookupField value='${parameters.locationSeqId!}' formName="addItemFromLocation" name="locationSeqId" id="locationSeqId" fieldFormName="LookupFacilityLocation?facilityId=${facilityId!}" showDescription="N"/> + +
+
${uiLabelMap.ProductInventoryItem}: +
+ + <@htmlTemplate.lookupField value='${parameters.inventoryItemId!}' formName="addItemFromInventoryItem" name="inventoryItemId" id="inventoryItemId" fieldFormName="LookupInventoryItem?facilityId=${facilityId!}" showDescription="N"/> + +
+
+
+
+
+
    + <#if "INV_COUNT_CREATED" == countSessionValue.statusId>
  • +
  • Item Details
  • +
+
+
+ <#assign rowCount = 0/> +
+ + + + + + + + + + + <#if "INV_COUNT_CREATED" == countSessionValue.statusId> + + + + + + <#list inventoryCountItemAndVariances as inventoryCountItemAndVariance> + + + + + + + <#if "INV_COUNT_CREATED" == countSessionValue.statusId> + + + + <#assign rowCount = rowCount + 1> + + +
${uiLabelMap.FormFieldTitle_locationSeqId}${uiLabelMap.ProductInventoryItem}${uiLabelMap.ProductProductName}${uiLabelMap.ProductProductDescription}${uiLabelMap.ProductQtyCounted} + +
+ ${inventoryCountItemAndVariance.areaId!} <#if inventoryCountItemAndVariance.aisleId?has_content>:${inventoryCountItemAndVariance.aisleId!}<#if inventoryCountItemAndVariance.sectionId?has_content>:${inventoryCountItemAndVariance.sectionId!}<#if inventoryCountItemAndVariance.levelId?has_content>:${inventoryCountItemAndVariance.levelId!}:${inventoryCountItemAndVariance.positionId!} [${inventoryCountItemAndVariance.locationSeqId!}] + + <#if inventoryCountItemAndVariance.inventoryItemId?has_content> + ${inventoryCountItemAndVariance.inventoryItemId!} + + ${inventoryCountItemAndVariance.internalName!}${inventoryCountItemAndVariance.partDescription!} + <#if "INV_COUNT_CREATED" == countSessionValue.statusId> + + <#else> + ${inventoryCountItemAndVariance.quantity!} + + + + +
+
+
+
+
+<#else> + ${screens.render("component://product/widget/facility/CycleCountScreens.xml#PendingLocations")} + \ No newline at end of file diff --git a/applications/product/template/cyclecount/ReviewCountSession.ftl b/applications/product/template/cyclecount/ReviewCountSession.ftl new file mode 100644 index 00000000000..0cd9acd88a7 --- /dev/null +++ b/applications/product/template/cyclecount/ReviewCountSession.ftl @@ -0,0 +1,188 @@ +<#-- +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. +--> + +<#if countSessionValue?has_content> +
+
+
    +
  • ${uiLabelMap.ProductReviewCountSession}
  • +
+
+
+ + + + + + + + + + + + + + + + + +
Session:${countSessionValue.inventoryCountId!}
Status:${countSessionValue.statusDescription!}
Created By:${countSessionValue.createdBy!}
Created On:<#if countSessionValue.createdDate?has_content>${countSessionValue.createdDate?string("MM/dd/yyyy")}
+
+
    + <#if "INV_COUNT_APPROVED" == countSessionValue.statusId> +
  • +
  • + +
  • Item Details
  • +
+
+
+ <#assign rowCount = 0> +
+
+ + + + + + + + + + + + + + + + + + + + + + <#setting number_format=",##0;(,##0)"> + <#list inventoryCountItemAndVariances as inventoryCountItemAndVariance> + + + + + + + + + + + + + <#assign rowCount = rowCount + 1> + + +
${uiLabelMap.ProductFacility}${uiLabelMap.ProductLocation}${uiLabelMap.ProductInventoryItem}${uiLabelMap.ProductInternalName}${uiLabelMap.ProductQtyCounted}Systemic QOH${uiLabelMap.ProductQtyVariance}Counter User ID${uiLabelMap.CommonStatus}disabled="disabled" name="selectAll" id="selectAll" value="Y" onclick="javascript:toggleInventoryCount(this, 'selectAllForm');"/>
${inventoryCountItemAndVariance.facilityName!} + ${inventoryCountItemAndVariance.areaId!} <#if inventoryCountItemAndVariance.aisleId?has_content>:${inventoryCountItemAndVariance.aisleId!}<#if inventoryCountItemAndVariance.sectionId?has_content>:${inventoryCountItemAndVariance.sectionId!}<#if inventoryCountItemAndVariance.levelId?has_content>:${inventoryCountItemAndVariance.levelId!}:${inventoryCountItemAndVariance.positionId!} [${inventoryCountItemAndVariance.locationSeqId!}] + + <#if inventoryCountItemAndVariance.inventoryItemId?has_content> + ${inventoryCountItemAndVariance.inventoryItemId!} + + ${inventoryCountItemAndVariance.internalName!}<#if inventoryCountItemAndVariance.quantity?has_content && inventoryCountItemAndVariance.quantity < 0>${inventoryCountItemAndVariance.quantity!}<#else>${inventoryCountItemAndVariance.quantity!}<#if inventoryCountItemAndVariance.systemQuantityOnHand?has_content && inventoryCountItemAndVariance.systemQuantityOnHand < 0>${inventoryCountItemAndVariance.systemQuantityOnHand!}<#else>${inventoryCountItemAndVariance.systemQuantityOnHand!}<#if inventoryCountItemAndVariance.varianceQuantityOnHand?has_content && inventoryCountItemAndVariance.varianceQuantityOnHand < 0>${inventoryCountItemAndVariance.varianceQuantityOnHand!}<#else>${inventoryCountItemAndVariance.varianceQuantityOnHand!}${inventoryCountItemAndVariance.createBy!}${inventoryCountItemAndVariance.statusDescription!} + <#if "INV_COUNT_APPROVED" == inventoryCountItemAndVariance.itemStatusId> + + + +
+
+
+
+
+
+<#else> +
+
+
    +
  • ${uiLabelMap.ProductReviewCountSession}
  • +
+
+
+ ${screens.render("component://product/widget/facility/CycleCountScreens.xml#PendingCycleCountList")} +
+
+ \ No newline at end of file diff --git a/applications/product/webapp/facility/WEB-INF/controller.xml b/applications/product/webapp/facility/WEB-INF/controller.xml index 0ddf8e094d2..ac27df799aa 100644 --- a/applications/product/webapp/facility/WEB-INF/controller.xml +++ b/applications/product/webapp/facility/WEB-INF/controller.xml @@ -1342,6 +1342,88 @@ under the License. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -1472,5 +1554,12 @@ under the License. + + + + + + + diff --git a/applications/product/widget/facility/CommonScreens.xml b/applications/product/widget/facility/CommonScreens.xml index d46439f58d4..c075a68c5ee 100644 --- a/applications/product/widget/facility/CommonScreens.xml +++ b/applications/product/widget/facility/CommonScreens.xml @@ -30,6 +30,7 @@ under the License. + diff --git a/applications/product/widget/facility/CycleCountScreens.xml b/applications/product/widget/facility/CycleCountScreens.xml new file mode 100644 index 00000000000..afc0cefa582 --- /dev/null +++ b/applications/product/widget/facility/CycleCountScreens.xml @@ -0,0 +1,192 @@ + + + + + +
+ + + + + + + +
+ + + + + + + + + +
+
+
+
+
+
+ + +
+ + + + + + + + + + + + + + <#if countSessionValue?has_content> -
-
-
    -
  • ${uiLabelMap.ProductReviewCountSession}
  • -
-
-
- - - - - - - - - - - - - +
+
+
    +
  • ${uiLabelMap.ProductReviewCountSession}
  • +
+
+
+
Session:${countSessionValue.inventoryCountId!}
Status:${countSessionValue.statusDescription!}
Created By:${countSessionValue.createdBy!}
+ + + + + + + + + + + + + + + + +
Session:${countSessionValue.inventoryCountId!}
Status:${countSessionValue.statusDescription!}
Created By:${countSessionValue.createdBy!}
Created On:<#if countSessionValue.createdDate?has_content>${countSessionValue.createdDate?string("MM/dd/yyyy")}
+
+
    + <#if "INV_COUNT_APPROVED" == countSessionValue.statusId> +
  • +
  • + +
  • Item Details
  • +
+
+
+ <#assign rowCount = 0> +
+
+ + + + + + + + + + + + + + + + + + + + + + <#setting number_format=",##0;(,##0)"> + <#list inventoryCountItemAndVariances as inventoryCountItemAndVariance> - - + + + + + + + + + + -
${uiLabelMap.ProductFacility}${uiLabelMap.ProductLocation}${uiLabelMap.ProductInventoryItem}${uiLabelMap.ProductInternalName}${uiLabelMap.ProductQtyCounted}Systemic QOH${uiLabelMap.ProductQtyVariance}Counter User ID${uiLabelMap.CommonStatus}disabled="disabled" name="selectAll" id="selectAll" value="Y" onclick="javascript:toggleInventoryCount(this, 'selectAllForm');"/>
Created On:<#if countSessionValue.createdDate?has_content>${countSessionValue.createdDate?string("MM/dd/yyyy")}${inventoryCountItemAndVariance.facilityName!} + ${inventoryCountItemAndVariance.areaId!} <#if inventoryCountItemAndVariance.aisleId?has_content>:${inventoryCountItemAndVariance.aisleId!}<#if inventoryCountItemAndVariance.sectionId?has_content>:${inventoryCountItemAndVariance.sectionId!}<#if inventoryCountItemAndVariance.levelId?has_content>:${inventoryCountItemAndVariance.levelId!}:${inventoryCountItemAndVariance.positionId!} [${inventoryCountItemAndVariance.locationSeqId!}] + + <#if inventoryCountItemAndVariance.inventoryItemId?has_content> + ${inventoryCountItemAndVariance.inventoryItemId!} + + ${inventoryCountItemAndVariance.internalName!}<#if inventoryCountItemAndVariance.quantity?has_content && inventoryCountItemAndVariance.quantity < 0>${inventoryCountItemAndVariance.quantity!}<#else>${inventoryCountItemAndVariance.quantity!}<#if inventoryCountItemAndVariance.systemQuantityOnHand?has_content && inventoryCountItemAndVariance.systemQuantityOnHand < 0>${inventoryCountItemAndVariance.systemQuantityOnHand!}<#else>${inventoryCountItemAndVariance.systemQuantityOnHand!}<#if inventoryCountItemAndVariance.varianceQuantityOnHand?has_content && inventoryCountItemAndVariance.varianceQuantityOnHand < 0>${inventoryCountItemAndVariance.varianceQuantityOnHand!}<#else>${inventoryCountItemAndVariance.varianceQuantityOnHand!}${inventoryCountItemAndVariance.createBy!}${inventoryCountItemAndVariance.statusDescription!} + <#if "INV_COUNT_APPROVED" == inventoryCountItemAndVariance.itemStatusId> + + + +
-
-
    - <#if "INV_COUNT_APPROVED" == countSessionValue.statusId> -
  • -
  • - -
  • Item Details
  • -
-
-
- <#assign rowCount = 0> - -
- - - - - - - - - - - - - - - - - - - - - - <#setting number_format=",##0;(,##0)"> - <#list inventoryCountItemAndVariances as inventoryCountItemAndVariance> - - - - - - - - - - - - - <#assign rowCount = rowCount + 1> - - -
${uiLabelMap.ProductFacility}${uiLabelMap.ProductLocation}${uiLabelMap.ProductInventoryItem}${uiLabelMap.ProductInternalName}${uiLabelMap.ProductQtyCounted}Systemic QOH${uiLabelMap.ProductQtyVariance}Counter User ID${uiLabelMap.CommonStatus}disabled="disabled" name="selectAll" id="selectAll" value="Y" onclick="javascript:toggleInventoryCount(this, 'selectAllForm');"/>
${inventoryCountItemAndVariance.facilityName!} - ${inventoryCountItemAndVariance.areaId!} <#if inventoryCountItemAndVariance.aisleId?has_content>:${inventoryCountItemAndVariance.aisleId!}<#if inventoryCountItemAndVariance.sectionId?has_content>:${inventoryCountItemAndVariance.sectionId!}<#if inventoryCountItemAndVariance.levelId?has_content>:${inventoryCountItemAndVariance.levelId!}:${inventoryCountItemAndVariance.positionId!} [${inventoryCountItemAndVariance.locationSeqId!}] - - <#if inventoryCountItemAndVariance.inventoryItemId?has_content> - ${inventoryCountItemAndVariance.inventoryItemId!} - - ${inventoryCountItemAndVariance.internalName!}<#if inventoryCountItemAndVariance.quantity?has_content && inventoryCountItemAndVariance.quantity < 0>${inventoryCountItemAndVariance.quantity!}<#else>${inventoryCountItemAndVariance.quantity!}<#if inventoryCountItemAndVariance.systemQuantityOnHand?has_content && inventoryCountItemAndVariance.systemQuantityOnHand < 0>${inventoryCountItemAndVariance.systemQuantityOnHand!}<#else>${inventoryCountItemAndVariance.systemQuantityOnHand!}<#if inventoryCountItemAndVariance.varianceQuantityOnHand?has_content && inventoryCountItemAndVariance.varianceQuantityOnHand < 0>${inventoryCountItemAndVariance.varianceQuantityOnHand!}<#else>${inventoryCountItemAndVariance.varianceQuantityOnHand!}${inventoryCountItemAndVariance.createBy!}${inventoryCountItemAndVariance.statusDescription!} - <#if "INV_COUNT_APPROVED" == inventoryCountItemAndVariance.itemStatusId> - - - -
-
- -
-
+ <#assign rowCount = rowCount + 1> + + + + +
+
+ <#else> -
-
-
    -
  • ${uiLabelMap.ProductReviewCountSession}
  • -
-
-
- ${screens.render("component://product/widget/facility/CycleCountScreens.xml#PendingCycleCountList")} -
+
+
+
    +
  • ${uiLabelMap.ProductReviewCountSession}
  • +
+
+
+ ${screens.render("component://product/widget/facility/CycleCountScreens.xml#PendingCycleCountList")}
+
\ No newline at end of file diff --git a/applications/product/widget/facility/CycleCountScreens.xml b/applications/product/widget/facility/CycleCountScreens.xml index afc0cefa582..38d8d3698fb 100644 --- a/applications/product/widget/facility/CycleCountScreens.xml +++ b/applications/product/widget/facility/CycleCountScreens.xml @@ -178,7 +178,7 @@ under the License.