blob: 649aee8970b8f238af17d7bc695ee8ebf0d369e1 [file] [log] [blame]
/*
* 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.oagis;
import java.io.IOException;
import java.sql.Timestamp;
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 org.apache.ofbiz.base.util.Debug;
import org.apache.ofbiz.base.util.UtilDateTime;
import org.apache.ofbiz.base.util.UtilFormatOut;
import org.apache.ofbiz.base.util.UtilMisc;
import org.apache.ofbiz.base.util.UtilProperties;
import org.apache.ofbiz.base.util.UtilValidate;
import org.apache.ofbiz.base.util.UtilXml;
import org.apache.ofbiz.entity.Delegator;
import org.apache.ofbiz.entity.GenericEntityException;
import org.apache.ofbiz.entity.GenericValue;
import org.apache.ofbiz.entity.condition.EntityCondition;
import org.apache.ofbiz.entity.condition.EntityOperator;
import org.apache.ofbiz.entity.transaction.GenericTransactionException;
import org.apache.ofbiz.entity.transaction.TransactionUtil;
import org.apache.ofbiz.entity.util.EntityQuery;
import org.apache.ofbiz.entity.util.EntityUtil;
import org.apache.ofbiz.entity.util.EntityUtilProperties;
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.ServiceUtil;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
public class OagisInventoryServices {
public static final String module = OagisInventoryServices.class.getName();
public static final String resource = "OagisUiLabels";
public static final Double doubleZero = new Double(0.0);
public static final Double doubleOne = new Double(1.0);
public static Map<String, Object> oagisReceiveSyncInventory(DispatchContext ctx, Map<String, Object> context) {
Document doc = (Document) context.get("document");
boolean isErrorRetry = Boolean.TRUE.equals(context.get("isErrorRetry"));
Delegator delegator = ctx.getDelegator();
LocalDispatcher dispatcher = ctx.getDispatcher();
Locale locale = (Locale) context.get("locale");
List<Map<String, String>> errorMapList = new LinkedList<Map<String,String>>();
List<Map<String, Object>> inventoryMapList = new LinkedList<Map<String,Object>>();
final String syncInventoryFacilityId = EntityUtilProperties.getPropertyValue("oagis", "Oagis.Warehouse.SyncInventoryFacilityId", delegator);
GenericValue userLogin = null;
try {
userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").queryOne();
} catch (GenericEntityException e) {
String errMsg = "Error Getting UserLogin: " + e.toString();
Debug.logError(e, errMsg, module);
}
Element syncInventoryRootElement = doc.getDocumentElement();
syncInventoryRootElement.normalize();
Element docCtrlAreaElement = UtilXml.firstChildElement(syncInventoryRootElement, "os:CNTROLAREA");
Element docBsrElement = UtilXml.firstChildElement(docCtrlAreaElement, "os:BSR");
Element docSenderElement = UtilXml.firstChildElement(docCtrlAreaElement, "os:SENDER");
String bsrVerb = UtilXml.childElementValue(docBsrElement, "of:VERB");
String bsrNoun = UtilXml.childElementValue(docBsrElement, "of:NOUN");
String bsrRevision = UtilXml.childElementValue(docBsrElement, "of:REVISION");
String logicalId = UtilXml.childElementValue(docSenderElement, "of:LOGICALID");
String component = UtilXml.childElementValue(docSenderElement, "of:COMPONENT");
String task = UtilXml.childElementValue(docSenderElement, "of:TASK");
String referenceId = UtilXml.childElementValue(docSenderElement, "of:REFERENCEID");
String confirmation = UtilXml.childElementValue(docSenderElement, "of:CONFIRMATION");
String authId = UtilXml.childElementValue(docSenderElement, "of:AUTHID");
// create oagis message info
Map<String, Object> comiCtx = new HashMap<String, Object>();
comiCtx.put("logicalId", logicalId);
comiCtx.put("component", component);
comiCtx.put("task", task);
comiCtx.put("referenceId", referenceId);
comiCtx.put("confirmation", confirmation);
comiCtx.put("authId", authId);
comiCtx.put("bsrVerb", bsrVerb);
comiCtx.put("bsrNoun", bsrNoun);
comiCtx.put("bsrRevision", bsrRevision);
comiCtx.put("receivedDate", UtilDateTime.nowTimestamp());
comiCtx.put("outgoingMessage", "N");
comiCtx.put("processingStatusId", "OAGMP_RECEIVED");
comiCtx.put("userLogin", userLogin);
if (OagisServices.debugSaveXmlIn) {
try {
comiCtx.put("fullMessageXml", UtilXml.writeXmlDocument(doc));
} catch (IOException e) {
// this is just for debug info, so just log and otherwise ignore error
String errMsg = "Warning: error creating text from XML Document for saving to database: " + e.toString();
Debug.logWarning(errMsg, module);
}
}
try {
if (isErrorRetry) {
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} else {
dispatcher.runSync("createOagisMessageInfo", comiCtx, 60, true);
}
} catch (GenericServiceException e) {
String errMsg = "Error creating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
// data area elements
List<? extends Element> dataAreaList = UtilXml.childElementList(syncInventoryRootElement, "ns:DATAAREA");
if (UtilValidate.isNotEmpty(dataAreaList)) {
try {
for (Element dataAreaElement : dataAreaList) {
Element syncInventoryElement = UtilXml.firstChildElement(dataAreaElement, "ns:SYNC_INVENTORY");
Element inventoryElement = UtilXml.firstChildElement(syncInventoryElement, "ns:INVENTORY");
Element quantityElement = UtilXml.firstChildElement(inventoryElement, "os:QUANTITY");
String itemQtyStr = UtilXml.childElementValue(quantityElement, "of:VALUE");
double itemQty = Double.parseDouble(itemQtyStr);
/* TODO sign denoted whether quantity is accepted(+) or rejected(-), which plays role in receiving inventory
* In this message will it serve any purpose, since it is not handled.
*/
// TODOLATER: Not used now, Later we may need it
//String sign = UtilXml.childElementValue(quantityElement, "of:SIGN");
//String uom = UtilXml.childElementValue(quantityElement, "of:UOM");
String productId = UtilXml.childElementValue(inventoryElement, "of:ITEM");
String itemStatus = UtilXml.childElementValue(inventoryElement, "of:ITEMSTATUS");
// make sure productId is valid
GenericValue product = EntityQuery.use(delegator).from("Product").where("productId", productId).cache().queryOne();
if (product == null) {
String errMsg = "Product with ID [" + productId + "] not found (invalid Product ID).";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ProductIdNotValid", "description", errMsg));
Debug.logError(errMsg, module);
continue;
}
// if anything but "NOTAVAILABLE" set to available
boolean isAvailable = !"NOTAVAILABLE".equals(itemStatus);
String statusId = "INV_AVAILABLE";
if (!isAvailable) {
statusId = "INV_ON_HOLD";
}
String snapshotDateStr = UtilXml.childElementValue(inventoryElement, "os:DATETIMEISO");
//Parse this into a valid Timestamp Object
Timestamp snapshotDate = OagisServices.parseIsoDateString(snapshotDateStr, errorMapList);
// get quantity on hand diff
double quantityOnHandTotal = 0.0;
// only if looking for available inventory find the non-serialized QOH total
if (isAvailable) {
EntityCondition condition = EntityCondition.makeCondition(UtilMisc.toList(
EntityCondition.makeCondition("effectiveDate", EntityOperator.LESS_THAN_EQUAL_TO, snapshotDate),
EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId),
EntityCondition.makeCondition("inventoryItemTypeId", EntityOperator.EQUALS, "NON_SERIAL_INV_ITEM"),
EntityCondition.makeCondition("facilityId", EntityOperator.EQUALS, syncInventoryFacilityId)), EntityOperator.AND);
List<GenericValue> invItemAndDetails = EntityQuery.use(delegator).select("quantityOnHandSum").from("InventoryItemDetailForSum").where(condition).queryList();
for (GenericValue inventoryItemDetailForSum : invItemAndDetails) {
quantityOnHandTotal += inventoryItemDetailForSum.getDouble("quantityOnHandSum").doubleValue();
}
}
// now regardless of AVAILABLE or NOTAVAILABLE check serialized inventory, just use the corresponding statusId as set above
EntityCondition serInvCondition = EntityCondition.makeCondition(UtilMisc.toList(
EntityCondition.makeCondition("statusDatetime", EntityOperator.LESS_THAN_EQUAL_TO, snapshotDate),
EntityCondition.makeCondition(EntityCondition.makeCondition("statusEndDatetime", EntityOperator.GREATER_THAN, snapshotDate), EntityOperator.OR, EntityCondition.makeCondition("statusEndDatetime", EntityOperator.EQUALS, null)),
EntityCondition.makeCondition("productId", EntityOperator.EQUALS, productId),
EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, statusId),
EntityCondition.makeCondition("inventoryItemTypeId", EntityOperator.EQUALS, "SERIALIZED_INV_ITEM"),
EntityCondition.makeCondition("facilityId", EntityOperator.EQUALS, syncInventoryFacilityId)), EntityOperator.AND);
long invItemQuantCount = EntityQuery.use(delegator).from("InventoryItemStatusForCount").where(serInvCondition).queryCount();
quantityOnHandTotal += invItemQuantCount;
// check for mismatch in quantity
if (itemQty != quantityOnHandTotal) {
double quantityDiff = Math.abs((itemQty - quantityOnHandTotal));
inventoryMapList.add(UtilMisc.toMap("productId", (Object) productId, "statusId", statusId,
"quantityOnHandTotal", String.valueOf(quantityOnHandTotal), "quantityFromMessage", itemQtyStr,
"quantityDiff", String.valueOf(quantityDiff), "timestamp", snapshotDate));
}
}
} catch (Throwable t) {
String errMsg = "Error processing Sync Inventory message: " + t.toString();
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "Exception"));
Debug.logInfo(t, errMsg, module);
}
}
// send mail if mismatch(s) found
if (errorMapList.size() == 0 && inventoryMapList.size() > 0) {
try {
// prepare information to send mail
Map<String, Object> sendMap = new HashMap<String, Object>();
String sendToEmail = EntityUtilProperties.getPropertyValue("oagis", "oagis.notification.email.sendTo", delegator);
/* DEJ20070802 changed to get email address from properties file, should be way easier to manage
// get facility email address
List facilityContactMechs = null;
GenericValue contactMech = null;
try {
facilityContactMechs = delegator.findByAnd("FacilityContactMech", UtilMisc.toMap("facilityId", facilityId), null, false);
} catch (GenericEntityException e) {
String errMsg = "Error Getting FacilityContactMech: " + e.toString();
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "GenericEntityException", "description", errMsg));
Debug.logError(e, errMsg, module);
}
Iterator fcmIter = facilityContactMechs.iterator();
while (fcmIter.hasNext()) {
GenericValue facilityContactMech = (GenericValue) fcmIter.next();
String contactMechId = facilityContactMech.getString("contactMechId");
try {
contactMech = EntityQuery.use(delegator).from("ContactMech").where("contactMechId", contactMechId).queryOne();
} catch (GenericEntityException e) {
String errMsg = "Error Getting ContactMech: " + e.toString();
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "GenericEntityException", "description", errMsg));
Debug.logError(e, errMsg, module);
}
String contactMechTypeId = contactMech.getString("contactMechTypeId");
if (contactMechTypeId.equals("EMAIL_ADDRESS")) {
String emailString = contactMech.getString("infoString");
sendMap.put("sendTo", emailString);
}
}
*/
if (UtilValidate.isNotEmpty(sendToEmail)) {
String productStoreId = EntityUtilProperties.getPropertyValue("oagis", "Oagis.Warehouse.SyncInventoryProductStoreId", delegator);
GenericValue productStoreEmail = EntityQuery.use(delegator).from("ProductStoreEmailSetting").where("productStoreId", productStoreId, "emailType", "PRDS_OAGIS_CONFIRM").queryOne();
if (productStoreEmail != null) {
String bodyScreenLocation = productStoreEmail.getString("bodyScreenLocation");
sendMap.put("bodyScreenUri", bodyScreenLocation);
} else {
sendMap.put("bodyScreenUri", "component://oagis/widget/EmailOagisMessageScreens.xml#InventoryMismatchNotice");
}
if (locale == null) {
locale = Locale.getDefault();
}
sendMap.put("sendTo", sendToEmail);
sendMap.put("subject", productStoreEmail.getString("subject"));
sendMap.put("sendFrom", productStoreEmail.getString("fromAddress"));
sendMap.put("sendCc", productStoreEmail.getString("ccAddress"));
sendMap.put("sendBcc", productStoreEmail.getString("bccAddress"));
sendMap.put("contentType", productStoreEmail.getString("contentType"));
Map<String, Object> bodyParameters = UtilMisc.toMap("inventoryMapList", inventoryMapList, "locale", locale);
sendMap.put("bodyParameters", bodyParameters);
sendMap.put("userLogin", userLogin);
// send the notification
// run async so it will happen in the background AND so errors in sending won't mess this up
dispatcher.runAsync("sendMailFromScreen", sendMap, true);
} else {
// no send to email address, just log to file
Debug.logImportant("No sendTo email address found in process oagisReceiveSyncInventory service: inventoryMapList: " + inventoryMapList, module);
}
} catch (Throwable t) {
Debug.logInfo(t, "System Error processing Sync Inventory message: " + t.toString(), module);
// in this case we don't want to return a Confirm BOD, so return an error now
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "OagisErrorProcessingSyncInventory", UtilMisc.toMap("errorString", t.toString()), locale));
}
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("logicalId", logicalId);
result.put("component", component);
result.put("task", task);
result.put("referenceId", referenceId);
result.put("userLogin", userLogin);
if (errorMapList.size() > 0) {
try {
comiCtx.put("processingStatusId", "OAGMP_PROC_ERROR");
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
// call services createOagisMsgErrInfosFromErrMapList and for incoming messages oagisSendConfirmBod
Map<String, Object> saveErrorMapListCtx = new HashMap<String, Object>();
saveErrorMapListCtx.put("logicalId", logicalId);
saveErrorMapListCtx.put("component", component);
saveErrorMapListCtx.put("task", task);
saveErrorMapListCtx.put("referenceId", referenceId);
saveErrorMapListCtx.put("errorMapList", errorMapList);
saveErrorMapListCtx.put("userLogin", userLogin);
try {
dispatcher.runSync("createOagisMsgErrInfosFromErrMapList", saveErrorMapListCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
try {
Map<String, Object> sendConfirmBodCtx = new HashMap<String, Object>();
sendConfirmBodCtx.putAll(saveErrorMapListCtx);
// NOTE: this is different for each service, should be shipmentId or returnId or PO orderId or etc
// for sync inventory no such ID: sendConfirmBodCtx.put("origRefId", shipmentId);
// run async because this will send a message back to the other server and may take some time, and/or fail
dispatcher.runAsync("oagisSendConfirmBod", sendConfirmBodCtx, null, true, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error sending Confirm BOD: " + e.toString();
Debug.logError(e, errMsg, module);
}
// return success here so that the message won't be retried and the Confirm BOD, etc won't be sent multiple times
result.putAll(ServiceUtil.returnSuccess(UtilProperties.getMessage(resource, "OagisErrorProcessingMessage", locale)));
return result;
} else {
try {
comiCtx.put("processingStatusId", "OAGMP_PROC_SUCCESS");
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
// don't pass this back, nothing they can do about it: errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "GenericServiceException"));
Debug.logError(e, errMsg, module);
}
}
result.putAll(ServiceUtil.returnSuccess(UtilProperties.getMessage(resource, "OagisServiceCompletedSuccessfully", locale)));
return result;
}
public static Map<String, Object> oagisReceiveAcknowledgeDeliveryPo(DispatchContext ctx, Map<String, Object> context) {
Document doc = (Document) context.get("document");
boolean isErrorRetry = Boolean.TRUE.equals(context.get("isErrorRetry"));
Locale locale = (Locale) context.get("locale");
LocalDispatcher dispatcher = ctx.getDispatcher();
Delegator delegator = ctx.getDelegator();
List<Map<String, String>> errorMapList = new LinkedList<Map<String,String>>();
Map<String, Object> comiCtx = new HashMap<String, Object>();
GenericValue userLogin = null;
try {
userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").queryOne();
} catch (GenericEntityException e) {
String errMsg = "Error Getting UserLogin: " + e.toString();
Debug.logError(e, errMsg, module);
}
// parse the message
Element receivePoElement = doc.getDocumentElement();
receivePoElement.normalize();
Element docCtrlAreaElement = UtilXml.firstChildElement(receivePoElement, "os:CNTROLAREA");
Element docSenderElement = UtilXml.firstChildElement(docCtrlAreaElement, "os:SENDER");
Element docBsrElement = UtilXml.firstChildElement(docCtrlAreaElement, "os:BSR");
String bsrVerb = UtilXml.childElementValue(docBsrElement, "of:VERB");
String bsrNoun = UtilXml.childElementValue(docBsrElement, "of:NOUN");
String bsrRevision = UtilXml.childElementValue(docBsrElement, "of:REVISION");
String logicalId = UtilXml.childElementValue(docSenderElement, "of:LOGICALID");
String component = UtilXml.childElementValue(docSenderElement, "of:COMPONENT");
String task = UtilXml.childElementValue(docSenderElement, "of:TASK"); // This field should be Not more then 10 char long
String referenceId = UtilXml.childElementValue(docSenderElement, "of:REFERENCEID");
String confirmation = UtilXml.childElementValue(docSenderElement, "of:CONFIRMATION");
String authId = UtilXml.childElementValue(docSenderElement, "of:AUTHID");
String sentDate = UtilXml.childElementValue(docCtrlAreaElement, "os:DATETIMEISO");
Timestamp sentTimestamp = OagisServices.parseIsoDateString(sentDate, errorMapList);
Timestamp timestamp = UtilDateTime.nowTimestamp();
Map<String, Object> omiPkMap = UtilMisc.toMap("logicalId", (Object) logicalId, "component", component, "task", task, "referenceId", referenceId);
// always log this to make messages easier to find
Debug.logInfo("Processing oagisReceiveAcknowledgeDeliveryPo for message ID [" + omiPkMap + "]", module);
// before getting into this check to see if we've tried once and had an error, if so set isErrorRetry even if it wasn't passed in
GenericValue previousOagisMessageInfo = null;
try {
previousOagisMessageInfo = EntityQuery.use(delegator).from("OagisMessageInfo").where(omiPkMap).queryOne();
} catch (GenericEntityException e) {
String errMsg = "Error getting OagisMessageInfo from database for message ID [" + omiPkMap + "]: " + e.toString();
Debug.logInfo(e, errMsg, module);
// anything else to do about this? we don't really want to send the error back or anything...
}
if (previousOagisMessageInfo != null && !isErrorRetry) {
if ("OAGMP_SYS_ERROR".equals(previousOagisMessageInfo.getString("processingStatusId"))) {
isErrorRetry = true;
} else {
// message already in the db, but is not in a system error state...
Debug.logError("Message received for message ID [" + omiPkMap + "] was already partially processed but is not in a system error state, needs manual review; message ID: " + omiPkMap, module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "OagisErrorMessageAlreadyProcessed", UtilMisc.toMap("shipmentId", "", "omiPkMap", omiPkMap), locale));
}
}
comiCtx.putAll(omiPkMap);
comiCtx.put("authId", authId);
comiCtx.put("receivedDate", timestamp);
comiCtx.put("sentDate", sentTimestamp);
comiCtx.put("outgoingMessage", "N");
comiCtx.put("confirmation", confirmation);
comiCtx.put("bsrVerb", bsrVerb);
comiCtx.put("bsrNoun", bsrNoun);
comiCtx.put("bsrRevision", bsrRevision);
comiCtx.put("processingStatusId", "OAGMP_RECEIVED");
comiCtx.put("userLogin", userLogin);
if (OagisServices.debugSaveXmlIn) {
try {
comiCtx.put("fullMessageXml", UtilXml.writeXmlDocument(doc));
} catch (IOException e) {
// this is just for debug info, so just log and otherwise ignore error
String errMsg = "Warning: error creating text from XML Document for saving to database: " + e.toString();
Debug.logWarning(errMsg, module);
}
}
try {
if (isErrorRetry) {
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} else {
dispatcher.runSync("createOagisMessageInfo", comiCtx, 60, true);
}
} catch (GenericServiceException e) {
String errMsg = "Error creating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
Element dataAreaElement = UtilXml.firstChildElement(receivePoElement, "ns:DATAAREA");
Element acknowledgeDeliveryElement = UtilXml.firstChildElement(dataAreaElement, "ns:ACKNOWLEDGE_DELIVERY");
String facilityId = EntityUtilProperties.getPropertyValue("oagis", "Oagis.Warehouse.PoReceiptFacilityId", delegator);
String orderId = null;
// get RECEIPTLN elements from message
List<? extends Element> acknowledgeElementList = UtilXml.childElementList(acknowledgeDeliveryElement, "ns:RECEIPTLN");
if (UtilValidate.isNotEmpty(acknowledgeElementList)) {
try {
for (Element receiptLnElement : acknowledgeElementList) {
Map<String, Object> ripCtx = new HashMap<String, Object>();
Element qtyElement = UtilXml.firstChildElement(receiptLnElement, "os:QUANTITY");
String itemQtyStr = UtilXml.childElementValue(qtyElement, "of:VALUE");
double itemQty = Double.parseDouble(itemQtyStr);
String sign = UtilXml.childElementValue(qtyElement, "of:SIGN");
String productId = UtilXml.childElementValue(receiptLnElement, "of:ITEM");
// make sure productId is valid
GenericValue product = EntityQuery.use(delegator).from("Product").where("productId", productId).cache().queryOne();
if (product == null) {
String errMsg = "Product with ID [" + productId + "] not found (invalid Product ID).";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ProductIdNotValid", "description", errMsg));
Debug.logError(errMsg, module);
continue;
}
Element documentRefElement = UtilXml.firstChildElement(receiptLnElement, "os:DOCUMNTREF");
orderId = UtilXml.childElementValue(documentRefElement, "of:DOCUMENTID");
String orderTypeId = UtilXml.childElementValue(documentRefElement, "of:DOCTYPE");
if (orderTypeId.equals("PO")) {
orderTypeId = "PURCHASE_ORDER";
}
String datetimeReceived = UtilXml.childElementValue(receiptLnElement, "os:DATETIMEISO");
Timestamp timestampItemReceived = OagisServices.parseIsoDateString(datetimeReceived, errorMapList);
ripCtx.put("datetimeReceived", timestampItemReceived);
// Check reference to PO number, if exists
GenericValue orderHeader = null;
if (orderId != null) {
List<GenericValue> toStore = new LinkedList<GenericValue>();
orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne();
if (orderHeader != null) {
// Case : update the record
ripCtx.put("orderId", orderId);
comiCtx.put("orderId", orderId);
GenericValue orderItem = delegator.makeValue("OrderItem", UtilMisc.toMap("orderId", orderId, "productId",productId,"quantity",new Double(itemQtyStr)));
delegator.setNextSubSeqId(orderItem, "orderItemSeqId", 5, 1);
delegator.create(orderItem);
ripCtx.put("orderItemSeqId", orderItem.get("orderItemSeqId"));
} else {
// Case : New record entry when PO not exists in the Database
orderHeader = delegator.makeValue("OrderHeader", UtilMisc.toMap("orderId", orderId, "orderTypeId",orderTypeId ,
"orderDate", timestampItemReceived, "statusId", "ORDER_CREATED", "entryDate", UtilDateTime.nowTimestamp(),
"productStoreId", EntityUtilProperties.getPropertyValue("oagis", "Oagis.Warehouse.SyncInventoryProductStoreId","9001", delegator)));
toStore.add(orderHeader);
GenericValue orderItem = delegator.makeValue("OrderItem", UtilMisc.toMap("orderId", orderId,
"orderItemSeqId", UtilFormatOut.formatPaddedNumber(1L, 5),
"productId", productId, "quantity", new Double(itemQtyStr)));
toStore.add(orderItem);
delegator.storeAll(toStore);
}
}
/* NOTE DEJ20070813 this is only meant to be used in the Ack Delivery RMA message, so ignoring here and always settings status to AVAILABLE
// get inventory item status
String invItemStatus = UtilXml.childElementValue(receiptLnElement, "of:DISPOSITN");
if (invItemStatus.equals("ReceivedTOAvailable") || invItemStatus.equals("NotAvailableTOAvailable")) {
ripCtx.put("statusId","INV_AVAILABLE");
} else if (invItemStatus.equals("ReceivedTONotAvailable") || invItemStatus.equals("AvailableTONotAvailable")) {
ripCtx.put("statusId","INV_ON_HOLD");
}
*/
ripCtx.put("statusId","INV_AVAILABLE");
ripCtx.put("inventoryItemTypeId", "NON_SERIAL_INV_ITEM");
ripCtx.put("productId", productId);
ripCtx.put("facilityId",facilityId);
ripCtx.put("userLogin", userLogin);
// sign handling for items
double quantityAccepted = 0.0;
double quantityRejected = 0.0;
if (sign.equals("+")) {
quantityAccepted = itemQty;
quantityRejected= 0.0;
} else {
quantityRejected = itemQty;
quantityAccepted = 0.0;
}
ripCtx.put("quantityAccepted", new Double(quantityAccepted));
ripCtx.put("quantityRejected", new Double(quantityRejected));
Map<String, Object> ripResult = dispatcher.runSync("receiveInventoryProduct", ripCtx);
if (ServiceUtil.isError(ripResult)) {
String errMsg = ServiceUtil.getErrorMessage(ripResult);
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ReceiveInventoryServiceError", "description", errMsg));
}
}
} catch (Throwable t) {
String errMsg = UtilProperties.getMessage(resource, "OagisErrorDeliveryMessagePO", UtilMisc.toMap("omiPkMap", omiPkMap), locale) + t.toString();
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SystemError"));
try {
comiCtx.put("processingStatusId", "OAGMP_SYS_ERROR");
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
Map<String, Object> saveErrorMapListCtx = new HashMap<String, Object>();
saveErrorMapListCtx.putAll(omiPkMap);
saveErrorMapListCtx.put("errorMapList", errorMapList);
saveErrorMapListCtx.put("userLogin", userLogin);
dispatcher.runSync("createOagisMsgErrInfosFromErrMapList", saveErrorMapListCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg2 = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg2, module);
}
Debug.logInfo(t, errMsg, module);
// in this case we don't want to return a Confirm BOD, so return an error now
return ServiceUtil.returnError(errMsg);
}
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("logicalId", logicalId);
result.put("component", component);
result.put("task", task);
result.put("referenceId", referenceId);
result.put("userLogin", userLogin);
if (errorMapList.size() > 0) {
try {
comiCtx.put("processingStatusId", "OAGMP_PROC_ERROR");
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
// call services createOagisMsgErrInfosFromErrMapList and for incoming messages oagisSendConfirmBod
Map<String, Object> saveErrorMapListCtx = new HashMap<String, Object>();
saveErrorMapListCtx.put("logicalId", logicalId);
saveErrorMapListCtx.put("component", component);
saveErrorMapListCtx.put("task", task);
saveErrorMapListCtx.put("referenceId", referenceId);
saveErrorMapListCtx.put("errorMapList", errorMapList);
saveErrorMapListCtx.put("userLogin", userLogin);
try {
dispatcher.runSync("createOagisMsgErrInfosFromErrMapList", saveErrorMapListCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
try {
Map<String, Object> sendConfirmBodCtx = new HashMap<String, Object>();
sendConfirmBodCtx.putAll(saveErrorMapListCtx);
// NOTE: this is different for each service, should be shipmentId or returnId or PO orderId or etc
sendConfirmBodCtx.put("origRefId", orderId);
// run async because this will send a message back to the other server and may take some time, and/or fail
dispatcher.runAsync("oagisSendConfirmBod", sendConfirmBodCtx, null, true, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error sending Confirm BOD: " + e.toString();
Debug.logError(e, errMsg, module);
}
// return success here so that the message won't be retried and the Confirm BOD, etc won't be sent multiple times
String errMsg = UtilProperties.getMessage(resource, "OagisErrorBusinessLevel", UtilMisc.toMap("errorString", ""), locale) + errorMapList.get(0);
result.putAll(ServiceUtil.returnSuccess(errMsg));
// however, we still don't want to save the partial results, so set rollbackOnly
try {
TransactionUtil.setRollbackOnly(errMsg, null);
} catch (GenericTransactionException e) {
Debug.logError(e, "Error setting rollback only ", module);
}
return result;
} else {
comiCtx.put("processingStatusId", "OAGMP_PROC_SUCCESS");
try {
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
// don't pass this back, nothing they can do about it: errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "GenericServiceException"));
Debug.logError(e, errMsg, module);
}
}
result.putAll(ServiceUtil.returnSuccess(UtilProperties.getMessage(resource, "OagisServiceCompletedSuccessfully", locale)));
return result;
}
public static Map<String, Object> oagisReceiveAcknowledgeDeliveryRma(DispatchContext ctx, Map<String, Object> context) {
Document doc = (Document) context.get("document");
boolean isErrorRetry = Boolean.TRUE.equals(context.get("isErrorRetry"));
Locale locale = (Locale) context.get("locale");
LocalDispatcher dispatcher = ctx.getDispatcher();
Delegator delegator = ctx.getDelegator();
List<Map<String, String>> errorMapList = new LinkedList<Map<String,String>>();
GenericValue userLogin = null;
try {
userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").queryOne();
} catch (GenericEntityException e) {
Debug.logError(e, "Error Getting UserLogin: " + e.toString(), module);
}
// parse the message
Element receiveRmaElement = doc.getDocumentElement();
receiveRmaElement.normalize();
Element docCtrlAreaElement = UtilXml.firstChildElement(receiveRmaElement, "os:CNTROLAREA");
Element docSenderElement = UtilXml.firstChildElement(docCtrlAreaElement, "os:SENDER");
Element docBsrElement = UtilXml.firstChildElement(docCtrlAreaElement, "os:BSR");
String bsrVerb = UtilXml.childElementValue(docBsrElement, "of:VERB");
String bsrNoun = UtilXml.childElementValue(docBsrElement, "of:NOUN");
String bsrRevision = UtilXml.childElementValue(docBsrElement, "of:REVISION");
String logicalId = UtilXml.childElementValue(docSenderElement, "of:LOGICALID");
String component = UtilXml.childElementValue(docSenderElement, "of:COMPONENT");
String task = UtilXml.childElementValue(docSenderElement, "of:TASK");
String referenceId = UtilXml.childElementValue(docSenderElement, "of:REFERENCEID");
String confirmation = UtilXml.childElementValue(docSenderElement, "of:CONFIRMATION");
String authId = UtilXml.childElementValue(docSenderElement, "of:AUTHID");
String sentDate = UtilXml.childElementValue(docCtrlAreaElement, "os:DATETIMEISO");
Timestamp sentTimestamp = OagisServices.parseIsoDateString(sentDate, errorMapList);
Element dataAreaElement = UtilXml.firstChildElement(receiveRmaElement, "ns:DATAAREA");
Element acknowledgeDeliveryElement = UtilXml.firstChildElement(dataAreaElement, "ns:ACKNOWLEDGE_DELIVERY");
// get the first returnId from the list so we at least have something in the info record
Element firstReceiptlnElement = UtilXml.firstChildElement(acknowledgeDeliveryElement, "ns:RECEIPTLN");
Element firstDocRefElement = UtilXml.firstChildElement(firstReceiptlnElement, "os:DOCUMNTREF");
String firstReturnId = UtilXml.childElementValue(firstDocRefElement, "of:DOCUMENTID");
String facilityId = EntityUtilProperties.getPropertyValue("oagis", "Oagis.Warehouse.PoReceiptFacilityId", delegator);
String locationSeqId = EntityUtilProperties.getPropertyValue("oagis", "Oagis.Warehouse.ReturnReceiptLocationSeqId", delegator);
Timestamp timestamp = UtilDateTime.nowTimestamp();
Map<String, Object> comiCtx = new HashMap<String, Object>();
Map<String, Object> omiPkMap = UtilMisc.toMap("logicalId", (Object) logicalId, "component", component, "task", task, "referenceId", referenceId);
// always log this to make messages easier to find
Debug.logInfo("Processing oagisReceiveAcknowledgeDeliveryRma for message ID [" + omiPkMap + "]", module);
// before getting into this check to see if we've tried once and had an error, if so set isErrorRetry even if it wasn't passed in
GenericValue previousOagisMessageInfo = null;
try {
previousOagisMessageInfo = EntityQuery.use(delegator).from("OagisMessageInfo").where(omiPkMap).queryOne();
} catch (GenericEntityException e) {
String errMsg = "Error getting OagisMessageInfo from database for message ID [" + omiPkMap + "]: " + e.toString();
Debug.logInfo(e, errMsg, module);
// anything else to do about this? we don't really want to send the error back or anything...
}
if (previousOagisMessageInfo != null && !isErrorRetry) {
if ("OAGMP_SYS_ERROR".equals(previousOagisMessageInfo.getString("processingStatusId"))) {
isErrorRetry = true;
} else {
// message already in the db, but is not in a system error state...
Debug.logError("Message received for message ID [" + omiPkMap + "] was already partially processed but is not in a system error state, needs manual review; message ID: " + omiPkMap, module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "OagisErrorMessageAlreadyProcessed", UtilMisc.toMap("shipmentId", "", "omiPkMap", omiPkMap), locale));
}
}
comiCtx.putAll(omiPkMap);
comiCtx.put("authId", authId);
comiCtx.put("receivedDate", timestamp);
comiCtx.put("sentDate", sentTimestamp);
comiCtx.put("outgoingMessage", "N");
comiCtx.put("confirmation", confirmation);
comiCtx.put("bsrVerb", bsrVerb);
comiCtx.put("bsrNoun", bsrNoun);
comiCtx.put("bsrRevision", bsrRevision);
comiCtx.put("processingStatusId", "OAGMP_RECEIVED");
comiCtx.put("returnId", firstReturnId);
comiCtx.put("userLogin", userLogin);
if (OagisServices.debugSaveXmlIn) {
try {
comiCtx.put("fullMessageXml", UtilXml.writeXmlDocument(doc));
} catch (IOException e) {
// this is just for debug info, so just log and otherwise ignore error
String errMsg = "Warning: error creating text from XML Document for saving to database: " + e.toString();
Debug.logWarning(errMsg, module);
}
}
try {
if (isErrorRetry) {
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} else {
dispatcher.runSync("createOagisMessageInfo", comiCtx, 60, true);
}
} catch (GenericServiceException e) {
String errMsg = "Error creating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
String lastReturnId = null;
//String inventoryItemId = null;
List<String> invItemIds = new LinkedList<String>();
// get RECEIPTLN elements from message
List<? extends Element> receiptLineElementList = UtilXml.childElementList(acknowledgeDeliveryElement, "ns:RECEIPTLN");
if (UtilValidate.isNotEmpty(receiptLineElementList)) {
try {
Map<String, String> processedStatusIdByReturnIdMap = new HashMap<String, String>();
for (Element receiptLnElement : receiptLineElementList) {
Map<String, Object> ripCtx = new HashMap<String, Object>();
Element qtyElement = UtilXml.firstChildElement(receiptLnElement, "os:QUANTITY");
String itemQtyStr = UtilXml.childElementValue(qtyElement, "of:VALUE");
double itemQty = Double.parseDouble(itemQtyStr);
String sign = UtilXml.childElementValue(qtyElement, "of:SIGN");
String productId = UtilXml.childElementValue(receiptLnElement, "of:ITEM");
if (UtilValidate.isEmpty(productId)) {
String errMsg = "Product ID Missing";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ProductIdMissing", "description", errMsg));
Debug.logError(errMsg, module);
}
// make sure productId is valid
GenericValue product = EntityQuery.use(delegator).from("Product").where("productId", productId).cache().queryOne();
if (product == null) {
String errMsg = "Product with ID [" + productId + "] not found (invalid Product ID).";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ProductIdNotValid", "description", errMsg));
Debug.logError(errMsg, module);
continue;
}
Element documentRefElement = UtilXml.firstChildElement(receiptLnElement, "os:DOCUMNTREF");
String returnId = UtilXml.childElementValue(documentRefElement, "of:DOCUMENTID");
lastReturnId = returnId;
ripCtx.put("returnId", returnId);
String returnHeaderTypeId = UtilXml.childElementValue(documentRefElement, "of:DOCTYPE");
if (returnHeaderTypeId.equals("RMA")) {
returnHeaderTypeId = "CUSTOMER_RETURN";
}
String returnItemSeqId = UtilXml.childElementValue(documentRefElement, "of:LINENUM");
if (UtilValidate.isNotEmpty(returnItemSeqId)) {
// if there is a LINENUM/returnItemSeqId make sure it is valid
GenericValue returnItem = EntityQuery.use(delegator).from("ReturnItem").where("returnId", returnId, "returnItemSeqId", returnItemSeqId).cache().queryOne();
if (returnItem == null) {
String errMsg = "Return Item with ID [" + returnId + ":" + returnItemSeqId + "] not found (invalid Return/Item ID Combination).";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ReturnAndItemIdNotValid", "description", errMsg));
Debug.logError(errMsg, module);
continue;
}
} else {
String errMsg = "No Return Item ID (LINENUM) found in DOCUMNTREF for Return [" + returnId + "]; this is a required field.";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ReturnItemIdLinenumMissing", "description", errMsg));
Debug.logError(errMsg, module);
continue;
}
// getting inventory item status
String invItemStatusId = null;
String disposition = UtilXml.childElementValue(receiptLnElement, "of:DISPOSITN");
if ("ReceivedTOAvailable".equals(disposition)) {
invItemStatusId = "INV_AVAILABLE";
} else if ("ReceivedTONotAvailable".equals(disposition)) {
invItemStatusId = "INV_ON_HOLD";
} else if ("NotAvailableTOAvailable".equals(disposition) || "AvailableTONotAvailable".equals(disposition)) {
// for RMA we should only get the ReceivedTO* DISPOSITN values; if we get something else we should return an error
String errMsg = "Got DISPOSITN value [" + disposition + "] that is not valid for RMA, only for status change.";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "DispositnNotValidForRMA", "description", errMsg));
continue;
}
ripCtx.put("statusId", invItemStatusId);
// TODOLATER: get the returnItem associated with the product received and update the receivedQuantity
String datetimeReceived = UtilXml.childElementValue(receiptLnElement, "os:DATETIMEISO");
Timestamp timestampItemReceived = OagisServices.parseIsoDateString(datetimeReceived, errorMapList);
ripCtx.put("datetimeReceived", timestampItemReceived);
GenericValue returnHeader = EntityQuery.use(delegator).from("ReturnHeader").where("returnId", returnId).queryOne();
if (returnHeader != null) {
//getting ReturnHeader status
String statusId = returnHeader.get("statusId").toString();
// save this here so the status will be updated after all processed
processedStatusIdByReturnIdMap.put(returnId, statusId);
// getting the serial number(s)
List<String> serialNumsList = new LinkedList<String>();
List<? extends Element> invDetailList = UtilXml.childElementList(receiptLnElement, "ns:INVDETAIL");
if (UtilValidate.isNotEmpty(invDetailList)) {
for (Element invDetailElement : invDetailList) {
String serialNumber = UtilXml.childElementValue(invDetailElement, "of:SERIALNUM");
if (UtilValidate.isNotEmpty(serialNumber)) {
serialNumsList.add(serialNumber);
}
}
/* DEJ20070711 Commenting this out because it shouldn't happen, ie more likely the ITEM element will be filled
* than INVDETAIL->SERIALNUM, and this isn't a reliable way to look it up (may be more than 1 record for a given
* serialNumber for different products
// this is a Serialized Inventory Item. If the productId from the message is not valid then lets read it from InventoryItem in Ofbiz database.
if (productId == null || "".equals(productId)) {
try {
GenericValue inventoryItem = EntityUtil.getFirst(delegator.findByAnd("InventoryItem", UtilMisc.toMap("serialNumber", serialNumber), null, false));
if (inventoryItem !=null) {
productId = inventoryItem.getString("productId");
}
} catch (GenericEntityException e) {
String errMsg = "Error Getting Entity InventoryItem";
Debug.logError(e, errMsg, module);
} */
}
//do some validations
Integer messageQuantity = Integer.valueOf(itemQtyStr);
if (UtilValidate.isNotEmpty(serialNumsList)) {
if (messageQuantity.intValue() != serialNumsList.size()) {
String errMsg = "Not enough serial numbers [" + serialNumsList.size() + "] for the quantity [" + messageQuantity.intValue() + "].";
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SerialNumbersMissing"));
Debug.logInfo(errMsg, module);
continue;
}
}
ripCtx.put("facilityId",facilityId);
ripCtx.put("locationSeqId", locationSeqId);
ripCtx.put("userLogin", userLogin);
// sign handling for items
double quantityAccepted = 0.0;
if (sign.equals("+")) {
quantityAccepted = itemQty;
} else {
quantityAccepted = 0.0;
}
if (quantityAccepted > 0) {
if (serialNumsList.size() > 0) {
String inventoryItemTypeId = "SERIALIZED_INV_ITEM";
ripCtx.put("inventoryItemTypeId", inventoryItemTypeId);
for (String serialNum : serialNumsList) {
// also look at the productId, and associated refurb productId(s) (or other way around, we might get a refurb sku
//and need to look up by the non-refurb sku); serialNumbers may not be unique globally, but should be per product
Set<String> productIdSet = ProductWorker.getRefurbishedProductIdSet(productId, delegator);
productIdSet.add(productId);
List<GenericValue> inventoryItemsBySerialNumber = EntityQuery.use(delegator).from("InventoryItem").where(EntityCondition.makeCondition(EntityCondition.makeCondition("serialNumber", EntityOperator.EQUALS, serialNum),
EntityOperator.AND, EntityCondition.makeCondition("productId", EntityOperator.IN, productIdSet))).queryList();
if (OagisServices.requireSerialNumberExist != null) {
// according to requireSerialNumberExist make sure serialNumber does or does not exist in database, add an error message as needed
if (OagisServices.requireSerialNumberExist.booleanValue()) {
if (inventoryItemsBySerialNumber.size() == 0) {
String errMsg = "Referenced serial numbers must already exist, but serial number [" + serialNum + "] was not found.";
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SerialNumberRequiredButNotFound"));
continue;
}
} else {
if (inventoryItemsBySerialNumber.size() > 0) {
String errMsg = "Referenced serial numbers must NOT already exist, but serial number [" + serialNum + "] already exists.";
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SerialNumberRequiredNotExistButFound"));
continue;
}
}
}
// TODOLATER: another fun thing to check: see if the serial number matches a serial number attached to the original return (if possible!)
//clone the context as it may be changed in the call
Map<String, Object> localRipCtx = new HashMap<String, Object>();
localRipCtx.putAll(ripCtx);
localRipCtx.put("quantityAccepted", new Double(1.0));
// always set this to 0, if needed we'll handle the rejected quantity separately
localRipCtx.put("quantityRejected", new Double(0.0));
localRipCtx.put("serialNumber", serialNum);
localRipCtx.put("productId", productId);
localRipCtx.put("returnItemSeqId", returnItemSeqId);
GenericValue inventoryItem = EntityUtil.getFirst(inventoryItemsBySerialNumber);
if (inventoryItem != null) {
localRipCtx.put("currentInventoryItemId", inventoryItem.getString("inventoryItemId"));
}
Map<String, Object> ripResult = dispatcher.runSync("receiveInventoryProduct", localRipCtx);
if (ServiceUtil.isError(ripResult)) {
String errMsg = ServiceUtil.getErrorMessage(ripResult);
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ReceiveInventoryServiceError", "description", errMsg));
} else {
invItemIds.add((String) ripResult.get("inventoryItemId"));
}
}
} else {
String inventoryItemTypeId = "NON_SERIAL_INV_ITEM";
ripCtx.put("inventoryItemTypeId", inventoryItemTypeId);
// no serial numbers, just receive the quantity
// clone the context as it may be changted in the call
Map<String, Object> localRipCtx = new HashMap<String, Object>();
localRipCtx.putAll(ripCtx);
localRipCtx.put("quantityAccepted", new Double(quantityAccepted));
// always set this to 0, if needed we'll handle the rejected quantity separately
localRipCtx.put("quantityRejected", new Double(0.0));
localRipCtx.put("productId", productId);
localRipCtx.put("returnItemSeqId", returnItemSeqId);
String inventoryItemId = null;
Map<String, Object> ripResult = dispatcher.runSync("receiveInventoryProduct", localRipCtx);
if (ServiceUtil.isError(ripResult)) {
String errMsg = ServiceUtil.getErrorMessage(ripResult);
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ReceiveInventoryServiceError", "description", errMsg));
}
inventoryItemId = (String) ripResult.get("inventoryItemId");
invItemIds.add(inventoryItemId);
if (("INV_ON_HOLD").equals(invItemStatusId)) {
Map<String, Object> createPhysicalInvAndVarCtx = new HashMap<String, Object>();
createPhysicalInvAndVarCtx.put("inventoryItemId", inventoryItemId);
createPhysicalInvAndVarCtx.put("physicalInventoryDate", UtilDateTime.nowTimestamp());
// NOTE DEJ20070815: calling damaged for now as the only option so that all will feed into a check/repair process and go into the ON_HOLD status; we should at some point change OFBiz so these can go into the ON_HOLD status without having to call them damaged
createPhysicalInvAndVarCtx.put("generalComments", "Damaged, in repair");
createPhysicalInvAndVarCtx.put("varianceReasonId", "VAR_DAMAGED");
createPhysicalInvAndVarCtx.put("availableToPromiseVar", new Double(-quantityAccepted));
createPhysicalInvAndVarCtx.put("quantityOnHandVar", new Double(0.0));
createPhysicalInvAndVarCtx.put("userLogin", userLogin);
Map<String, Object> cpivResult = dispatcher.runSync("createPhysicalInventoryAndVariance", createPhysicalInvAndVarCtx);
if (ServiceUtil.isError(cpivResult)) {
String errMsg = ServiceUtil.getErrorMessage(cpivResult);
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "CreatePhysicalInventoryAndVarianceServiceError", "description", errMsg));
}
}
}
} else {
// TODOLATER: need to run service receiveInventoryProduct and updateInventoryItem when quantityRejected > 0
// NOTE DEJ20070711 this shouldn't happen for current needs, so save for later
}
} else {
String errMsg = "Return ID [" + returnId + "] Not Found";
Debug.logError(errMsg, module);
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ReturnIdNotFound", "description", errMsg));
}
}
for (Map.Entry<String, String> processedStatusIdByReturnIdEntry : processedStatusIdByReturnIdMap.entrySet()) {
String returnId = processedStatusIdByReturnIdEntry.getKey();
String statusId = processedStatusIdByReturnIdEntry.getValue();
if (UtilValidate.isNotEmpty(statusId) && statusId.equals("RETURN_ACCEPTED")) {
// check to see if all return items have been received, if so then set to received then completed
// NOTE: an alternative method would be to see if the total has been received for each
//ReturnItem (receivedQuantity vs returnQuantity), but we may have a hard time matching
//those up so that information is probably not as reliable; another note: as of 20070821
//the receipt processing code properly updates ReturnItem with receivedQuantity and status
//so we _could_ possibly move to that method if needed
// loop through ReturnItem records, get totals for each productId
Map<String, Double> returnQuantityByProductIdMap = new HashMap<String, Double>();
List<GenericValue> returnItemList = delegator.findByAnd("ReturnItem", UtilMisc.toMap("returnId", returnId), null, false);
for (GenericValue returnItem : returnItemList) {
String productId = returnItem.getString("productId");
Double returnQuantityDbl = returnItem.getDouble("returnQuantity");
if (UtilValidate.isNotEmpty(productId) && returnQuantityDbl != null) {
double newTotal = returnQuantityDbl.doubleValue();
Double existingTotal = returnQuantityByProductIdMap.get(productId);
if (existingTotal != null) newTotal += existingTotal.doubleValue();
returnQuantityByProductIdMap.put(productId, new Double(newTotal));
}
}
// set to true, if we find any that aren't fully received, will set to false
boolean fullReturnReceived = true;
// for each productId see if total received is equal to the total for that ID
for (Map.Entry<String, Double> returnQuantityByProductIdEntry : returnQuantityByProductIdMap.entrySet()) {
String productId = returnQuantityByProductIdEntry.getKey();
double returnQuantity = returnQuantityByProductIdEntry.getValue();
double receivedQuantity = 0;
// note no facilityId because we don't really care where the return items were received
List<GenericValue> shipmentReceiptList = delegator.findByAnd("ShipmentReceipt", UtilMisc.toMap("productId", productId, "returnId", returnId), null, false);
// NOTE only consider those with a quantityOnHandDiff > 0 so we just look at how many have been received, not what was actually done with them
for (GenericValue shipmentReceipt : shipmentReceiptList) {
Double quantityAccepted = shipmentReceipt.getDouble("quantityAccepted");
if (quantityAccepted != null && quantityAccepted.doubleValue() > 0) {
receivedQuantity += quantityAccepted.doubleValue();
}
}
if (receivedQuantity < returnQuantity) {
fullReturnReceived = false;
break;
} else if (receivedQuantity > returnQuantity) {
// TODOLATER: we received MORE than expected... what to do about that?!?
String warnMsg = "Received more [" + receivedQuantity + "] than were expected on return [" + returnQuantity + "] for Return ID [" + returnId + "] and Product ID [" + productId + "]";
warnMsg = warnMsg + "; still completing return, but something should be done with these extras!";
Debug.logWarning(warnMsg, module);
// even with that, allow it to go through and complete the return
}
}
if (fullReturnReceived) {
dispatcher.runSync("updateReturnHeader", UtilMisc.<String, Object>toMap("statusId", "RETURN_RECEIVED", "returnId", returnId, "userLogin", userLogin));
dispatcher.runSync("updateReturnHeader", UtilMisc.<String, Object>toMap("statusId", "RETURN_COMPLETED", "returnId", returnId, "userLogin", userLogin));
}
}
}
} catch (Throwable t) {
String errMsg = "System Error processing Acknowledge Delivery RMA message for message [" + omiPkMap + "]: " + t.toString();
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SystemError"));
try {
comiCtx.put("processingStatusId", "OAGMP_SYS_ERROR");
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
Map<String, Object> saveErrorMapListCtx = new HashMap<String, Object>();
saveErrorMapListCtx.putAll(omiPkMap);
saveErrorMapListCtx.put("errorMapList", errorMapList);
saveErrorMapListCtx.put("userLogin", userLogin);
dispatcher.runSync("createOagisMsgErrInfosFromErrMapList", saveErrorMapListCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg2 = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg2, module);
}
Debug.logInfo(t, errMsg, module);
// in this case we don't want to return a Confirm BOD, so return an error now
return ServiceUtil.returnError(errMsg);
}
}
Map<String, Object> result = new HashMap<String, Object>();
result.put("logicalId", logicalId);
result.put("component", component);
result.put("task", task);
result.put("referenceId", referenceId);
result.put("userLogin", userLogin);
if (errorMapList.size() > 0) {
try {
comiCtx.put("processingStatusId", "OAGMP_PROC_ERROR");
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
// call services createOagisMsgErrInfosFromErrMapList and for incoming messages oagisSendConfirmBod
Map<String, Object> saveErrorMapListCtx = new HashMap<String, Object>();
saveErrorMapListCtx.put("logicalId", logicalId);
saveErrorMapListCtx.put("component", component);
saveErrorMapListCtx.put("task", task);
saveErrorMapListCtx.put("referenceId", referenceId);
saveErrorMapListCtx.put("errorMapList", errorMapList);
saveErrorMapListCtx.put("userLogin", userLogin);
try {
dispatcher.runSync("createOagisMsgErrInfosFromErrMapList", saveErrorMapListCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
try {
Map<String, Object> sendConfirmBodCtx = new HashMap<String, Object>();
sendConfirmBodCtx.putAll(saveErrorMapListCtx);
// NOTE: this is different for each service, should be shipmentId or returnId or PO orderId or etc
// TODO: unfortunately there could be multiple returnIds for the message, so what to do...?
sendConfirmBodCtx.put("origRefId", lastReturnId);
// run async because this will send a message back to the other server and may take some time, and/or fail
dispatcher.runAsync("oagisSendConfirmBod", sendConfirmBodCtx, null, true, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error sending Confirm BOD: " + e.toString();
Debug.logError(e, errMsg, module);
}
String errMsg = "Found business level errors in message processing, not saving results; first error is: " + errorMapList.get(0);
// return success here so that the message won't be retried and the Confirm BOD, etc won't be sent multiple times
result.putAll(ServiceUtil.returnSuccess(errMsg));
// however, we still don't want to save the partial results, so set rollbackOnly
try {
TransactionUtil.setRollbackOnly(errMsg, null);
} catch (GenericTransactionException e) {
Debug.logError(e, "Error setting rollback only ", module);
}
return result;
} else {
comiCtx.put("processingStatusId", "OAGMP_PROC_SUCCESS");
try {
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
// don't pass this back, nothing they can do about it: errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "GenericServiceException"));
Debug.logError(e, errMsg, module);
}
}
result.putAll(ServiceUtil.returnSuccess(UtilProperties.getMessage(resource, "OagisServiceCompletedSuccessfully", locale)));
result.put("inventoryItemIdList", invItemIds);
return result;
}
public static Map<String, Object> oagisReceiveAcknowledgeDeliveryStatus(DispatchContext ctx, Map<String, Object> context) {
Document doc = (Document) context.get("document");
boolean isErrorRetry = Boolean.TRUE.equals(context.get("isErrorRetry"));
Locale locale = (Locale) context.get("locale");
LocalDispatcher dispatcher = ctx.getDispatcher();
Delegator delegator = ctx.getDelegator();
List<Map<String, String>> errorMapList = new LinkedList<Map<String,String>>();
GenericValue userLogin = null;
try {
userLogin = EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").queryOne();
} catch (GenericEntityException e) {
String errMsg = "Error Getting UserLogin: " + e.toString();
Debug.logError(e, errMsg, module);
}
// parse the message
Element receiveStatusElement = doc.getDocumentElement();
receiveStatusElement.normalize();
Element docCtrlAreaElement = UtilXml.firstChildElement(receiveStatusElement, "os:CNTROLAREA");
Element docSenderElement = UtilXml.firstChildElement(docCtrlAreaElement, "os:SENDER");
Element docBsrElement = UtilXml.firstChildElement(docCtrlAreaElement, "os:BSR");
String bsrVerb = UtilXml.childElementValue(docBsrElement, "of:VERB");
String bsrNoun = UtilXml.childElementValue(docBsrElement, "of:NOUN");
String bsrRevision = UtilXml.childElementValue(docBsrElement, "of:REVISION");
String logicalId = UtilXml.childElementValue(docSenderElement, "of:LOGICALID");
String component = UtilXml.childElementValue(docSenderElement, "of:COMPONENT");
String task = UtilXml.childElementValue(docSenderElement, "of:TASK");
String referenceId = UtilXml.childElementValue(docSenderElement, "of:REFERENCEID");
String confirmation = UtilXml.childElementValue(docSenderElement, "of:CONFIRMATION");
String authId = UtilXml.childElementValue(docSenderElement, "of:AUTHID");
String sentDate = UtilXml.childElementValue(docCtrlAreaElement, "os:DATETIMEISO");
Timestamp sentTimestamp = OagisServices.parseIsoDateString(sentDate, errorMapList);
Element dataAreaElement = UtilXml.firstChildElement(receiveStatusElement, "ns:DATAAREA");
Element acknowledgeDeliveryElement = UtilXml.firstChildElement(dataAreaElement, "ns:ACKNOWLEDGE_DELIVERY");
String facilityId = EntityUtilProperties.getPropertyValue("oagis", "Oagis.Warehouse.PoReceiptFacilityId", delegator);
String locationSeqId = EntityUtilProperties.getPropertyValue("oagis", "Oagis.Warehouse.ReturnReceiptLocationSeqId", delegator);
Timestamp timestamp = UtilDateTime.nowTimestamp();
Map<String, Object> comiCtx = new HashMap<String, Object>();
Map<String, Object> omiPkMap = UtilMisc.toMap("logicalId", (Object) logicalId, "component", component, "task", task, "referenceId", referenceId);
// always log this to make messages easier to find
Debug.logInfo("Processing oagisReceiveAcknowledgeDeliveryStatus for message ID [" + omiPkMap + "]", module);
// before getting into this check to see if we've tried once and had an error, if so set isErrorRetry even if it wasn't passed in
GenericValue previousOagisMessageInfo = null;
try {
previousOagisMessageInfo = delegator.findOne("OagisMessageInfo", omiPkMap, false);
} catch (GenericEntityException e) {
String errMsg = "Error getting OagisMessageInfo from database for message ID [" + omiPkMap + "]: " + e.toString();
Debug.logInfo(e, errMsg, module);
// anything else to do about this? we don't really want to send the error back or anything...
}
if (previousOagisMessageInfo != null && !isErrorRetry) {
if ("OAGMP_SYS_ERROR".equals(previousOagisMessageInfo.getString("processingStatusId"))) {
isErrorRetry = true;
} else {
// message already in the db, but is not in a system error state...
Debug.logError("Message received for message ID [" + omiPkMap + "] was already partially processed but is not in a system error state, needs manual review; message ID: " + omiPkMap, module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "OagisErrorMessageAlreadyProcessed", UtilMisc.toMap("shipmentId", "", "omiPkMap", omiPkMap), locale));
}
}
comiCtx.putAll(omiPkMap);
comiCtx.put("authId", authId);
comiCtx.put("receivedDate", timestamp);
comiCtx.put("sentDate", sentTimestamp);
comiCtx.put("outgoingMessage", "N");
comiCtx.put("confirmation", confirmation);
comiCtx.put("bsrVerb", bsrVerb);
comiCtx.put("bsrNoun", bsrNoun);
comiCtx.put("bsrRevision", bsrRevision);
comiCtx.put("processingStatusId", "OAGMP_RECEIVED");
comiCtx.put("userLogin", userLogin);
if (OagisServices.debugSaveXmlIn) {
try {
comiCtx.put("fullMessageXml", UtilXml.writeXmlDocument(doc));
} catch (IOException e) {
// this is just for debug info, so just log and otherwise ignore error
String errMsg = "Warning: error creating text from XML Document for saving to database: " + e.toString();
Debug.logWarning(errMsg, module);
}
}
try {
if (isErrorRetry) {
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} else {
dispatcher.runSync("createOagisMessageInfo", comiCtx, 60, true);
}
} catch (GenericServiceException e) {
String errMsg = "Error creating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
//String inventoryItemId = null;
List<String> invItemIds = new LinkedList<String>();
// get RECEIPTLN elements from message
List<? extends Element> receiptLineElementList = UtilXml.childElementList(acknowledgeDeliveryElement, "ns:RECEIPTLN");
if (UtilValidate.isNotEmpty(receiptLineElementList)) {
try {
for (Element receiptLnElement : receiptLineElementList) {
Map<String, Object> uiiCtx = new HashMap<String, Object>();
Element qtyElement = UtilXml.firstChildElement(receiptLnElement, "os:QUANTITY");
String itemQtyStr = UtilXml.childElementValue(qtyElement, "of:VALUE");
String sign = UtilXml.childElementValue(qtyElement, "of:SIGN");
String productId = UtilXml.childElementValue(receiptLnElement, "of:ITEM");
if (UtilValidate.isEmpty(productId)) {
String errMsg = "Product ID Missing";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ProductIdMissing", "description", errMsg));
Debug.logError(errMsg, module);
}
// make sure productId is valid
GenericValue product = EntityQuery.use(delegator).from("Product").where("productId", productId).cache().queryOne();
if (product == null) {
String errMsg = "Product with ID [" + productId + "] not found (invalid Product ID).";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "ProductIdNotValid", "description", errMsg));
Debug.logError(errMsg, module);
continue;
}
/* no place to put this in the InventoryItem update
String datetimeReceived = UtilXml.childElementValue(receiptLnElement, "os:DATETIMEISO");
Timestamp timestampItemReceived = OagisServices.parseIsoDateString(datetimeReceived, errorMapList);
uiiCtx.put("datetimeReceived", timestampItemReceived);
*/
String invItemStatusId = null;
String reqFromItemStatusId = null;
String disposition = UtilXml.childElementValue(receiptLnElement, "of:DISPOSITN");
if ("NotAvailableTOAvailable".equals(disposition)) {
invItemStatusId = "INV_AVAILABLE";
reqFromItemStatusId = "INV_ON_HOLD";
} else if ("AvailableTONotAvailable".equals(disposition)) {
invItemStatusId = "INV_ON_HOLD";
reqFromItemStatusId = "INV_AVAILABLE";
} else if ("ReceivedTOAvailable".equals(disposition) || "ReceivedTONotAvailable".equals(disposition)) {
String errMsg = "Got DISPOSITN value [" + disposition + "] that is not valid for Status Change, only for RMA/return.";
errorMapList.add(UtilMisc.<String, String>toMap("reasonCode", "DispositnNotValidForStatusChange", "description", errMsg));
continue;
}
uiiCtx.put("statusId", invItemStatusId);
// geting the serial number(s)
List<String> serialNumsList = new LinkedList<String>();
List<? extends Element> invDetailList = UtilXml.childElementList(receiptLnElement, "ns:INVDETAIL");
if (UtilValidate.isNotEmpty(invDetailList)) {
for (Element invDetailElement : invDetailList) {
String serialNumber = UtilXml.childElementValue(invDetailElement, "of:SERIALNUM");
if (UtilValidate.isNotEmpty(serialNumber)) {
serialNumsList.add(serialNumber);
}
}
}
//do some validations
Integer messageQuantity = Integer.valueOf(itemQtyStr);
if (UtilValidate.isNotEmpty(serialNumsList)) {
if (messageQuantity.intValue() != serialNumsList.size()) {
String errMsg = "Not enough serial numbers [" + serialNumsList.size() + "] for the quantity [" + messageQuantity.intValue() + "].";
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SerialNumbersMissing"));
Debug.logInfo(errMsg, module);
continue;
}
}
uiiCtx.put("facilityId",facilityId);
uiiCtx.put("locationSeqId", locationSeqId);
uiiCtx.put("userLogin", userLogin);
// sign handling for items
if (!"+".equals(sign)) {
String errMsg = "Got a sign [" + sign + "] that was not plus (+), this is not valid for a Status Change operation.";
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SignNotPlusForStatusChange"));
continue;
}
if (serialNumsList.size() > 0) {
String inventoryItemTypeId = "SERIALIZED_INV_ITEM";
uiiCtx.put("inventoryItemTypeId", inventoryItemTypeId);
for (String serialNum : serialNumsList) {
// also look at the productId, and associated refurb productId(s) (or other way around, we might get a refurb sku
//and need to look up by the non-refurb sku); serialNumbers may not be unique globally, but should be per product
Set<String> productIdSet = ProductWorker.getRefurbishedProductIdSet(productId, delegator);
productIdSet.add(productId);
List<GenericValue> inventoryItemsBySerialNumber = EntityQuery.use(delegator).from("InventoryItem").where(EntityCondition.makeCondition(EntityCondition.makeCondition("serialNumber", EntityOperator.EQUALS, serialNum),
EntityOperator.AND, EntityCondition.makeCondition("productId", EntityOperator.IN, productIdSet))).queryList();
// this is a status update, so referenced serial number MUST already exist
if (inventoryItemsBySerialNumber.size() == 0) {
String errMsg = "Referenced serial numbers must already exist, but serial number [" + serialNum + "] was not found.";
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SerialNumberRequiredButNotFound"));
continue;
}
GenericValue inventoryItem = EntityUtil.getFirst(inventoryItemsBySerialNumber);
if (UtilValidate.isNotEmpty(reqFromItemStatusId) && !reqFromItemStatusId.equals(inventoryItem.getString("statusId"))) {
String errMsg = "Referenced serial number [" + serialNum + "] has status [" + inventoryItem.getString("statusId") + "] but we were expecting [" + reqFromItemStatusId + "]; this may mean the Acknowledge Delivery RMA message has not yet come in for this item.";
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SerialNumberRequiredButNotFound"));
continue;
}
Map<String, Object> updateInvItmMap = new HashMap<String, Object>();
updateInvItmMap.put("inventoryItemId", inventoryItem.getString("inventoryItemId"));
updateInvItmMap.put("userLogin", userLogin);
updateInvItmMap.put("statusId", invItemStatusId);
String inventoryItemProductId = inventoryItem.getString("productId");
if (!inventoryItemProductId.equals(productId)) {
// got a new productId for the serial number; this may happen for refurbishment, etc
updateInvItmMap.put("productId",productId);
}
dispatcher.runSync("updateInventoryItem", updateInvItmMap);
invItemIds.add(inventoryItem.getString("inventoryItemId"));
}
} else {
String inventoryItemTypeId = "NON_SERIAL_INV_ITEM";
uiiCtx.put("inventoryItemTypeId", inventoryItemTypeId);
// TODO: later somehow do status changes for non-serialized inventory
// for now just return an error message
String errMsg = "No serial numbers were included in the message and right now this is not supported";
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "NoSerialNumbersInMessage"));
}
}
} catch (Throwable t) {
String errMsg = "System Error processing Acknowledge Delivery Status message for message [" + omiPkMap + "]: " + t.toString();
errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "SystemError"));
try {
comiCtx.put("processingStatusId", "OAGMP_SYS_ERROR");
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
Map<String, Object> saveErrorMapListCtx = new HashMap<String, Object>();
saveErrorMapListCtx.putAll(omiPkMap);
saveErrorMapListCtx.put("errorMapList", errorMapList);
saveErrorMapListCtx.put("userLogin", userLogin);
dispatcher.runSync("createOagisMsgErrInfosFromErrMapList", saveErrorMapListCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg2 = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg2, module);
}
Debug.logInfo(t, errMsg, module);
// in this case we don't want to return a Confirm BOD, so return an error now
return ServiceUtil.returnError(errMsg);
}
}
Map<String, Object> result = new HashMap<String, Object>();
result.putAll(omiPkMap);
result.put("userLogin", userLogin);
if (errorMapList.size() > 0) {
try {
comiCtx.put("processingStatusId", "OAGMP_PROC_ERROR");
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
// call services createOagisMsgErrInfosFromErrMapList and for incoming messages oagisSendConfirmBod
Map<String, Object> saveErrorMapListCtx = new HashMap<String, Object>();
saveErrorMapListCtx.putAll(omiPkMap);
saveErrorMapListCtx.put("errorMapList", errorMapList);
saveErrorMapListCtx.put("userLogin", userLogin);
try {
dispatcher.runSync("createOagisMsgErrInfosFromErrMapList", saveErrorMapListCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
Debug.logError(e, errMsg, module);
}
try {
Map<String, Object> sendConfirmBodCtx = new HashMap<String, Object>();
sendConfirmBodCtx.putAll(saveErrorMapListCtx);
// run async because this will send a message back to the other server and may take some time, and/or fail
dispatcher.runAsync("oagisSendConfirmBod", sendConfirmBodCtx, null, true, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error sending Confirm BOD: " + e.toString();
Debug.logError(e, errMsg, module);
}
String errMsg = "Found business level errors in message processing, not saving results; first error is: " + errorMapList.get(0);
// return success here so that the message won't be retried and the Confirm BOD, etc won't be sent multiple times
result.putAll(ServiceUtil.returnSuccess(errMsg));
// however, we still don't want to save the partial results, so set rollbackOnly
try {
TransactionUtil.setRollbackOnly(errMsg, null);
} catch (GenericTransactionException e) {
Debug.logError(e, "Error setting rollback only ", module);
}
return result;
} else {
comiCtx.put("processingStatusId", "OAGMP_PROC_SUCCESS");
try {
dispatcher.runSync("updateOagisMessageInfo", comiCtx, 60, true);
} catch (GenericServiceException e) {
String errMsg = "Error updating OagisMessageInfo for the Incoming Message: " + e.toString();
// don't pass this back, nothing they can do about it: errorMapList.add(UtilMisc.<String, String>toMap("description", errMsg, "reasonCode", "GenericServiceException"));
Debug.logError(e, errMsg, module);
}
}
result.putAll(ServiceUtil.returnSuccess(UtilProperties.getMessage(resource, "OagisServiceCompletedSuccessfully", locale)));
result.put("inventoryItemIdList", invItemIds);
return result;
}
}