}
public static Map<String, Object> productionRunProduce(DispatchContext ctx, Map<String, ? extends Object> context) {
Map<String, Object> result = FastMap.newInstance();
Delegator delegator = ctx.getDelegator();
LocalDispatcher dispatcher = ctx.getDispatcher();
Locale locale = (Locale) context.get("locale");
GenericValue userLogin = (GenericValue) context.get("userLogin");
// Mandatory input fields
String productionRunId = (String)context.get("workEffortId");
// Optional input fields
BigDecimal quantity = (BigDecimal) context.get("quantity");
String inventoryItemTypeId = (String)context.get("inventoryItemTypeId");
String lotId = (String)context.get("lotId");
Boolean createLotIfNeeded = (Boolean)context.get("createLotIfNeeded");
Boolean autoCreateLot = (Boolean)context.get("autoCreateLot");
// The default is non-serialized inventory item
if (UtilValidate.isEmpty(inventoryItemTypeId)) {
inventoryItemTypeId = "NON_SERIAL_INV_ITEM";
}
// The default is to create a lot if the lotId is given, but the lot doesn't exist
if (createLotIfNeeded == null) {
createLotIfNeeded = Boolean.TRUE;
}
if (autoCreateLot == null) {
autoCreateLot = Boolean.FALSE;
}
List<String> inventoryItemIds = FastList.newInstance();
result.put("inventoryItemIds", inventoryItemIds);
// The production run is loaded
ProductionRun productionRun = new ProductionRun(productionRunId, delegator, dispatcher);
// The last task is loaded
GenericValue lastTask = productionRun.getLastProductionRunRoutingTask();
if (lastTask == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ManufacturingProductionRunTaskNotExists", locale));
}
if ("WIP".equals(productionRun.getProductProduced().getString("productTypeId"))) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ManufacturingProductIsWIP", locale));
}
BigDecimal quantityProduced = productionRun.getGenericValue().getBigDecimal("quantityProduced");
if (quantityProduced == null) {
quantityProduced = BigDecimal.ZERO;
}
BigDecimal quantityDeclared = lastTask.getBigDecimal("quantityProduced");
if (quantityDeclared == null) {
quantityDeclared = BigDecimal.ZERO;
}
// If the quantity already produced is not lower than the quantity declared, no inventory is created.
BigDecimal maxQuantity = quantityDeclared.subtract(quantityProduced);
if (maxQuantity.compareTo(BigDecimal.ZERO) <= 0) {
return result;
}
// If quantity was not passed, the max quantity is used
if (quantity == null) {
quantity = maxQuantity;
}
//
if (quantity.compareTo(maxQuantity) > 0) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ManufacturingProductionRunProductProducedNotStillAvailable", locale));
}
if (lotId == null && autoCreateLot.booleanValue()) {
lotId = delegator.getNextSeqId("Lot");
createLotIfNeeded = Boolean.TRUE;
}
if (UtilValidate.isNotEmpty(lotId)) {
try {
// Find the lot
GenericValue lot = delegator.findByPrimaryKey("Lot", UtilMisc.toMap("lotId", lotId));
if (lot == null) {
if (createLotIfNeeded.booleanValue()) {
lot = delegator.makeValue("Lot", UtilMisc.toMap("lotId", lotId, "creationDate", UtilDateTime.nowTimestamp()));
lot.create();
} else {
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ManufacturingLotNotExists", locale));
}
}
} catch (GenericEntityException e) {
Debug.logWarning(e.getMessage(), module);
return ServiceUtil.returnError(e.getMessage());
}
}
GenericValue orderItem = null;
try {
// Find the related order item (if exists)
List<GenericValue> orderItems = productionRun.getGenericValue().getRelated("WorkOrderItemFulfillment");
orderItem = EntityUtil.getFirst(orderItems);
} catch (GenericEntityException e) {
Debug.logWarning(e.getMessage(), module);
return ServiceUtil.returnError(e.getMessage());
}
// the inventory item unit cost is the product's standard cost
BigDecimal unitCost = ZERO;
try {
// get the currency
GenericValue facility = productionRun.getGenericValue().getRelatedOne("Facility");
Map<String, Object> outputMap = dispatcher.runSync("getPartyAccountingPreferences", UtilMisc.<String, Object>toMap("userLogin", userLogin, "organizationPartyId", facility.getString("ownerPartyId")));
GenericValue partyAccountingPreference = (GenericValue)outputMap.get("partyAccountingPreference");
if (partyAccountingPreference == null) {
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ManufacturingProductionRunUnableToFindCosts", locale));
}
outputMap = dispatcher.runSync("getProductCost", UtilMisc.<String, Object>toMap("userLogin", userLogin, "productId", productionRun.getProductProduced().getString("productId"), "currencyUomId", (String)partyAccountingPreference.get("baseCurrencyUomId"), "costComponentTypePrefix", "EST_STD"));
unitCost = (BigDecimal)outputMap.get("productCost");
if (unitCost == null) {
unitCost = ZERO;
}
} catch (Exception e) {
Debug.logWarning(e.getMessage(), module);
return ServiceUtil.returnError(e.getMessage());
}
if ("SERIALIZED_INV_ITEM".equals(inventoryItemTypeId)) {
try {
int numOfItems = quantity.intValue();
for (int i = 0; i < numOfItems; i++) {
Map<String, Object> serviceContext = UtilMisc.<String, Object>toMap("productId", productionRun.getProductProduced().getString("productId"),
"inventoryItemTypeId", "SERIALIZED_INV_ITEM",
"statusId", "INV_AVAILABLE");
serviceContext.put("facilityId", productionRun.getGenericValue().getString("facilityId"));
serviceContext.put("datetimeReceived", UtilDateTime.nowTimestamp());
serviceContext.put("comments", "Created by production run " + productionRunId);
if (unitCost.compareTo(ZERO) != 0) {
serviceContext.put("unitCost", unitCost);
}
//serviceContext.put("serialNumber", productionRunId);
serviceContext.put("lotId", lotId);
serviceContext.put("userLogin", userLogin);
Map<String, Object> resultService = dispatcher.runSync("createInventoryItem", serviceContext);
String inventoryItemId = (String)resultService.get("inventoryItemId");
inventoryItemIds.add(inventoryItemId);
serviceContext.clear();
serviceContext.put("inventoryItemId", inventoryItemId);
serviceContext.put("workEffortId", productionRunId);
serviceContext.put("availableToPromiseDiff", BigDecimal.ONE);
serviceContext.put("quantityOnHandDiff", BigDecimal.ONE);
serviceContext.put("userLogin", userLogin);
resultService = dispatcher.runSync("createInventoryItemDetail", serviceContext);
serviceContext.clear();
serviceContext.put("userLogin", userLogin);
serviceContext.put("workEffortId", productionRunId);
serviceContext.put("inventoryItemId", inventoryItemId);
resultService = dispatcher.runSync("createWorkEffortInventoryProduced", serviceContext);
// Recompute reservations
serviceContext = FastMap.newInstance();
serviceContext.put("inventoryItemId", inventoryItemId);
serviceContext.put("userLogin", userLogin);
resultService = dispatcher.runSync("balanceInventoryItems", serviceContext);
}
} catch (Exception exc) {
return ServiceUtil.returnError(exc.getMessage());
}
} else {
try {
Map<String, Object> serviceContext = UtilMisc.<String, Object>toMap("productId", productionRun.getProductProduced().getString("productId"),
"inventoryItemTypeId", "NON_SERIAL_INV_ITEM");
serviceContext.put("facilityId", productionRun.getGenericValue().getString("facilityId"));
serviceContext.put("datetimeReceived", UtilDateTime.nowTimestamp());
serviceContext.put("comments", "Created by production run " + productionRunId);
serviceContext.put("lotId", lotId);
if (unitCost.compareTo(ZERO) != 0) {
serviceContext.put("unitCost", unitCost);
}
serviceContext.put("userLogin", userLogin);
Map<String, Object> resultService = dispatcher.runSync("createInventoryItem", serviceContext);
String inventoryItemId = (String)resultService.get("inventoryItemId");
inventoryItemIds.add(inventoryItemId);
serviceContext.clear();
serviceContext.put("inventoryItemId", inventoryItemId);
serviceContext.put("workEffortId", productionRunId);
serviceContext.put("availableToPromiseDiff", quantity);
serviceContext.put("quantityOnHandDiff", quantity);
serviceContext.put("userLogin", userLogin);
resultService = dispatcher.runSync("createInventoryItemDetail", serviceContext);
serviceContext.clear();
serviceContext.put("userLogin", userLogin);
serviceContext.put("workEffortId", productionRunId);
serviceContext.put("inventoryItemId", inventoryItemId);
resultService = dispatcher.runSync("createWorkEffortInventoryProduced", serviceContext);
// Recompute reservations
serviceContext = FastMap.newInstance();
serviceContext.put("inventoryItemId", inventoryItemId);
serviceContext.put("userLogin", userLogin);
if (orderItem != null) {
// the reservations of this order item are privileged reservations
serviceContext.put("priorityOrderId", orderItem.getString("orderId"));
serviceContext.put("priorityOrderItemSeqId", orderItem.getString("orderItemSeqId"));
}
resultService = dispatcher.runSync("balanceInventoryItems", serviceContext);
} catch (Exception exc) {
return ServiceUtil.returnError(exc.getMessage());
}
}
// Now the production run's quantityProduced is updated
Map<String, Object> serviceContext = UtilMisc.<String, Object>toMap("workEffortId", productionRunId);
serviceContext.put("quantityProduced", quantityProduced.add(quantity));
serviceContext.put("actualCompletionDate", UtilDateTime.nowTimestamp());
serviceContext.put("userLogin", userLogin);
try {
dispatcher.runSync("updateWorkEffort", serviceContext);
} catch (GenericServiceException e) {
Debug.logError(e, "Problem calling the updateWorkEffort service", module);
return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ManufacturingProductionRunStatusNotChanged", locale));
}