KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > product > inventory > InventoryServices


1 /*
2  * $Id: InventoryServices.java 7053 2006-03-23 06:14:49Z jacopo $
3  *
4  * Copyright (c) 2001-2005 The Open For Business Project - www.ofbiz.org
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included
14  * in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT
21  * OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */

24 package org.ofbiz.product.inventory;
25
26 import java.sql.Timestamp JavaDoc;
27 import java.util.ArrayList JavaDoc;
28 import java.util.Calendar JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.Iterator JavaDoc;
31 import java.util.List JavaDoc;
32 import java.util.Map JavaDoc;
33 import java.util.Set JavaDoc;
34
35 import org.ofbiz.base.util.Debug;
36 import org.ofbiz.base.util.UtilDateTime;
37 import org.ofbiz.base.util.UtilMisc;
38 import org.ofbiz.entity.GenericDelegator;
39 import org.ofbiz.entity.GenericEntityException;
40 import org.ofbiz.entity.GenericValue;
41 import org.ofbiz.entity.condition.EntityExpr;
42 import org.ofbiz.entity.condition.EntityOperator;
43 import org.ofbiz.service.DispatchContext;
44 import org.ofbiz.service.GenericServiceException;
45 import org.ofbiz.service.LocalDispatcher;
46 import org.ofbiz.service.ServiceUtil;
47
48 /**
49  * Inventory Services
50  *
51  * @author <a HREF="mailto:jaz@ofbiz.org">Andy Zeneski</a>
52  * @author <a HREF="mailto:jonesde@ofbiz.org">David E. Jones</a>
53  * @author <a HREF="mailto:tiz@sastau.it">Jacopo Cappellato</a>
54  * @version $Rev: 7053 $
55  * @since 2.0
56  */

57 public class InventoryServices {
58     
59     public final static String JavaDoc module = InventoryServices.class.getName();
60     
61     public static Map JavaDoc prepareInventoryTransfer(DispatchContext dctx, Map JavaDoc context) {
62         GenericDelegator delegator = dctx.getDelegator();
63         String JavaDoc inventoryItemId = (String JavaDoc) context.get("inventoryItemId");
64         Double JavaDoc xferQty = (Double JavaDoc) context.get("xferQty");
65         GenericValue inventoryItem = null;
66         GenericValue newItem = null;
67         GenericValue userLogin = (GenericValue) context.get("userLogin");
68         
69         try {
70             inventoryItem = delegator.findByPrimaryKey("InventoryItem", UtilMisc.toMap("inventoryItemId", inventoryItemId));
71         } catch (GenericEntityException e) {
72             return ServiceUtil.returnError("Inventory item lookup problem [" + e.getMessage() + "]");
73         }
74         
75         if (inventoryItem == null) {
76             return ServiceUtil.returnError("Cannot locate inventory item.");
77         }
78
79         try {
80             Map JavaDoc results = ServiceUtil.returnSuccess();
81             
82             String JavaDoc inventoryType = inventoryItem.getString("inventoryItemTypeId");
83             if (inventoryType.equals("NON_SERIAL_INV_ITEM")) {
84                 Double JavaDoc atp = inventoryItem.getDouble("availableToPromiseTotal");
85                 Double JavaDoc qoh = inventoryItem.getDouble("quantityOnHandTotal");
86                 
87                 if (atp == null) {
88                     return ServiceUtil.returnError("The request transfer amount is not available, there is no available to promise on the Inventory Item with ID " + inventoryItem.getString("inventoryItemId"));
89                 }
90                 if (qoh == null) {
91                     qoh = atp;
92                 }
93                 
94                 // first make sure we have enough to cover the request transfer amount
95
if (xferQty.doubleValue() > atp.doubleValue()) {
96                     return ServiceUtil.returnError("The request transfer amount is not available, the available to promise [" + atp + "] is not sufficient for the desired transfer quantity [" + xferQty + "] on the Inventory Item with ID " + inventoryItem.getString("inventoryItemId"));
97                 }
98                             
99                 /*
100                  * atp < qoh - split and save the qoh - atp
101                  * xferQty < atp - split and save atp - xferQty
102                  * atp < qoh && xferQty < atp - split and save qoh - atp + atp - xferQty
103                  */

104     
105                 // at this point we have already made sure that the xferQty is less than or equals to the atp, so if less that just create a new inventory record for the quantity to be moved
106
// NOTE: atp should always be <= qoh, so if xfer < atp, then xfer < qoh, so no need to check/handle that
107
// however, if atp < qoh && atp == xferQty, then we still need to split; oh, but no need to check atp == xferQty in the second part because if it isn't greater and isn't less, then it is equal
108
if (xferQty.doubleValue() < atp.doubleValue() || atp.doubleValue() < qoh.doubleValue()) {
109                     Double JavaDoc negXferQty = new Double JavaDoc(-xferQty.doubleValue());
110                     // NOTE: new inventory items should always be created calling the
111
// createInventoryItem service because in this way we are sure
112
// that all the relevant fields are filled with default values.
113
// However, the code here should work fine because all the values
114
// for the new inventory item are inerited from the existing item.
115
newItem = GenericValue.create(inventoryItem);
116                     newItem.set("availableToPromiseTotal", new Double JavaDoc(0));
117                     newItem.set("quantityOnHandTotal", new Double JavaDoc(0));
118                     
119                     String JavaDoc newSeqId = null;
120                     try {
121                         newSeqId = delegator.getNextSeqId("InventoryItem");
122                     } catch (IllegalArgumentException JavaDoc e) {
123                         return ServiceUtil.returnError("ERROR: Could not get next sequence id for InventoryItem, cannot create item.");
124                     }
125                     
126                     newItem.set("inventoryItemId", newSeqId);
127                     newItem.create();
128                     
129                     results.put("inventoryItemId", newItem.get("inventoryItemId"));
130     
131                     // TODO: how do we get this here: "inventoryTransferId", inventoryTransferId
132
Map JavaDoc createNewDetailMap = UtilMisc.toMap("availableToPromiseDiff", xferQty, "quantityOnHandDiff", xferQty,
133                             "inventoryItemId", newItem.get("inventoryItemId"), "userLogin", userLogin);
134                     Map JavaDoc createUpdateDetailMap = UtilMisc.toMap("availableToPromiseDiff", negXferQty, "quantityOnHandDiff", negXferQty,
135                             "inventoryItemId", inventoryItem.get("inventoryItemId"), "userLogin", userLogin);
136                     
137                     try {
138                         Map JavaDoc resultNew = dctx.getDispatcher().runSync("createInventoryItemDetail", createNewDetailMap);
139                         if (ServiceUtil.isError(resultNew)) {
140                             return ServiceUtil.returnError("Inventory Item Detail create problem in prepare inventory transfer", null, null, resultNew);
141                         }
142                         Map JavaDoc resultUpdate = dctx.getDispatcher().runSync("createInventoryItemDetail", createUpdateDetailMap);
143                         if (ServiceUtil.isError(resultNew)) {
144                             return ServiceUtil.returnError("Inventory Item Detail create problem in prepare inventory transfer", null, null, resultUpdate);
145                         }
146                     } catch (GenericServiceException e1) {
147                         return ServiceUtil.returnError("Inventory Item Detail create problem in prepare inventory transfer: [" + e1.getMessage() + "]");
148                     }
149                 } else {
150                     results.put("inventoryItemId", inventoryItem.get("inventoryItemId"));
151                 }
152             } else if (inventoryType.equals("SERIALIZED_INV_ITEM")) {
153                 if (!"INV_AVAILABLE".equals(inventoryItem.getString("statusId"))) {
154                     return ServiceUtil.returnError("Serialized inventory is not available for transfer.");
155                 }
156             }
157                     
158             // setup values so that no one will grab the inventory during the move
159
// if newItem is not null, it is the item to be moved, otherwise the original inventoryItem is the one to be moved
160
if (inventoryType.equals("NON_SERIAL_INV_ITEM")) {
161                 // set the transfered inventory item's atp to 0 and the qoh to the xferQty; at this point atp and qoh will always be the same, so we can safely zero the atp for now
162
GenericValue inventoryItemToClear = newItem == null ? inventoryItem : newItem;
163
164                 inventoryItemToClear.refresh();
165                 double atp = inventoryItemToClear.get("availableToPromiseTotal") == null ? 0 : inventoryItemToClear.getDouble("availableToPromiseTotal").doubleValue();
166                 if (atp != 0) {
167                     Map JavaDoc createDetailMap = UtilMisc.toMap("availableToPromiseDiff", new Double JavaDoc(-atp),
168                             "inventoryItemId", inventoryItemToClear.get("inventoryItemId"), "userLogin", userLogin);
169                     try {
170                         Map JavaDoc result = dctx.getDispatcher().runSync("createInventoryItemDetail", createDetailMap);
171                         if (ServiceUtil.isError(result)) {
172                             return ServiceUtil.returnError("Inventory Item Detail create problem in complete inventory transfer", null, null, result);
173                         }
174                     } catch (GenericServiceException e1) {
175                         return ServiceUtil.returnError("Inventory Item Detail create problem in complete inventory transfer: [" + e1.getMessage() + "]");
176                     }
177                 }
178             } else if (inventoryType.equals("SERIALIZED_INV_ITEM")) {
179                 // set the status to avoid re-moving or something
180
if (newItem != null) {
181                     newItem.refresh();
182                     newItem.set("statusId", "INV_BEING_TRANSFERED");
183                     newItem.store();
184                     results.put("inventoryItemId", newItem.get("inventoryItemId"));
185               } else {
186                     inventoryItem.refresh();
187                     inventoryItem.set("statusId", "INV_BEING_TRANSFERED");
188                     inventoryItem.store();
189                     results.put("inventoryItemId", inventoryItem.get("inventoryItemId"));
190               }
191             }
192                                     
193             return results;
194         } catch (GenericEntityException e) {
195             return ServiceUtil.returnError("Inventory store/create problem [" + e.getMessage() + "]");
196         }
197     }
198     
199     public static Map JavaDoc completeInventoryTransfer(DispatchContext dctx, Map JavaDoc context) {
200         GenericDelegator delegator = dctx.getDelegator();
201         String JavaDoc inventoryTransferId = (String JavaDoc) context.get("inventoryTransferId");
202         GenericValue inventoryTransfer = null;
203         GenericValue inventoryItem = null;
204         GenericValue destinationFacility = null;
205         GenericValue userLogin = (GenericValue) context.get("userLogin");
206         
207         try {
208             inventoryTransfer = delegator.findByPrimaryKey("InventoryTransfer",
209                     UtilMisc.toMap("inventoryTransferId", inventoryTransferId));
210             inventoryItem = inventoryTransfer.getRelatedOne("InventoryItem");
211             destinationFacility = inventoryTransfer.getRelatedOne("ToFacility");
212         } catch (GenericEntityException e) {
213             return ServiceUtil.returnError("Inventory Item/Transfer lookup problem [" + e.getMessage() + "]");
214         }
215         
216         if (inventoryTransfer == null || inventoryItem == null) {
217             return ServiceUtil.returnError("ERROR: Lookup of InventoryTransfer and/or InventoryItem failed!");
218         }
219             
220         String JavaDoc inventoryType = inventoryItem.getString("inventoryItemTypeId");
221         
222         // set the fields on the transfer record
223
if (inventoryTransfer.get("receiveDate") == null) {
224             inventoryTransfer.set("receiveDate", UtilDateTime.nowTimestamp());
225         }
226             
227         if (inventoryType.equals("NON_SERIAL_INV_ITEM")) {
228             // add an adjusting InventoryItemDetail so set ATP back to QOH: ATP = ATP + (QOH - ATP), diff = QOH - ATP
229
double atp = inventoryItem.get("availableToPromiseTotal") == null ? 0 : inventoryItem.getDouble("availableToPromiseTotal").doubleValue();
230             double qoh = inventoryItem.get("quantityOnHandTotal") == null ? 0 : inventoryItem.getDouble("quantityOnHandTotal").doubleValue();
231             Map JavaDoc createDetailMap = UtilMisc.toMap("availableToPromiseDiff", new Double JavaDoc(qoh - atp),
232                     "inventoryItemId", inventoryItem.get("inventoryItemId"), "userLogin", userLogin);
233             try {
234                 Map JavaDoc result = dctx.getDispatcher().runSync("createInventoryItemDetail", createDetailMap);
235                 if (ServiceUtil.isError(result)) {
236                     return ServiceUtil.returnError("Inventory Item Detail create problem in complete inventory transfer", null, null, result);
237                 }
238             } catch (GenericServiceException e1) {
239                 return ServiceUtil.returnError("Inventory Item Detail create problem in complete inventory transfer: [" + e1.getMessage() + "]");
240             }
241             try {
242                 inventoryItem.refresh();
243             } catch (GenericEntityException e) {
244                 return ServiceUtil.returnError("Inventory refresh problem [" + e.getMessage() + "]");
245             }
246         } else if (inventoryType.equals("SERIALIZED_INV_ITEM")) {
247             inventoryItem.set("statusId", "INV_AVAILABLE");
248         }
249
250         // set the fields on the item
251
Map JavaDoc updateInventoryItemMap = UtilMisc.toMap("inventoryItemId", inventoryItem.getString("inventoryItemId"),
252                                                     "facilityId", inventoryTransfer.get("facilityIdTo"),
253                                                     "containerId", inventoryTransfer.get("containerIdTo"),
254                                                     "locationSeqId", inventoryTransfer.get("locationSeqIdTo"),
255                                                     "userLogin", userLogin);
256         // if the destination facility's owner is different
257
// from the inventory item's ownwer,
258
// the inventory item is assigned to the new owner.
259
if (destinationFacility != null && destinationFacility.get("ownerPartyId") != null) {
260             String JavaDoc fromPartyId = inventoryItem.getString("ownerPartyId");
261             String JavaDoc toPartyId = destinationFacility.getString("ownerPartyId");
262             if (fromPartyId == null || !fromPartyId.equals(toPartyId)) {
263                 updateInventoryItemMap.put("ownerPartyId", toPartyId);
264             }
265         }
266         try {
267             Map JavaDoc result = dctx.getDispatcher().runSync("updateInventoryItem", updateInventoryItemMap);
268             if (ServiceUtil.isError(result)) {
269                 return ServiceUtil.returnError("Inventory item store problem", null, null, result);
270             }
271         } catch (GenericServiceException exc) {
272             return ServiceUtil.returnError("Inventory item store problem [" + exc.getMessage() + "]");
273         }
274
275         // set the inventory transfer record to complete
276
inventoryTransfer.set("statusId", "IXF_COMPLETE");
277         
278         // store the entities
279
try {
280             inventoryTransfer.store();
281         } catch (GenericEntityException e) {
282             return ServiceUtil.returnError("Inventory store problem [" + e.getMessage() + "]");
283         }
284          
285         return ServiceUtil.returnSuccess();
286     }
287     
288     public static Map JavaDoc cancelInventoryTransfer(DispatchContext dctx, Map JavaDoc context) {
289         GenericDelegator delegator = dctx.getDelegator();
290         String JavaDoc inventoryTransferId = (String JavaDoc) context.get("inventoryTransferId");
291         GenericValue inventoryTransfer = null;
292         GenericValue inventoryItem = null;
293         GenericValue userLogin = (GenericValue) context.get("userLogin");
294
295         try {
296             inventoryTransfer = delegator.findByPrimaryKey("InventoryTransfer",
297                     UtilMisc.toMap("inventoryTransferId", inventoryTransferId));
298             inventoryItem = inventoryTransfer.getRelatedOne("InventoryItem");
299         } catch (GenericEntityException e) {
300             return ServiceUtil.returnError("Inventory Item/Transfer lookup problem [" + e.getMessage() + "]");
301         }
302
303         if (inventoryTransfer == null || inventoryItem == null) {
304             return ServiceUtil.returnError("ERROR: Lookup of InventoryTransfer and/or InventoryItem failed!");
305         }
306             
307         String JavaDoc inventoryType = inventoryItem.getString("inventoryItemTypeId");
308         
309         // re-set the fields on the item
310
if (inventoryType.equals("NON_SERIAL_INV_ITEM")) {
311             // add an adjusting InventoryItemDetail so set ATP back to QOH: ATP = ATP + (QOH - ATP), diff = QOH - ATP
312
double atp = inventoryItem.get("availableToPromiseTotal") == null ? 0 : inventoryItem.getDouble("availableToPromiseTotal").doubleValue();
313             double qoh = inventoryItem.get("quantityOnHandTotal") == null ? 0 : inventoryItem.getDouble("quantityOnHandTotal").doubleValue();
314             Map JavaDoc createDetailMap = UtilMisc.toMap("availableToPromiseDiff", new Double JavaDoc(qoh - atp),
315                                                  "inventoryItemId", inventoryItem.get("inventoryItemId"),
316                                                  "userLogin", userLogin);
317             try {
318                 Map JavaDoc result = dctx.getDispatcher().runSync("createInventoryItemDetail", createDetailMap);
319                 if (ServiceUtil.isError(result)) {
320                     return ServiceUtil.returnError("Inventory Item Detail create problem in cancel inventory transfer", null, null, result);
321                 }
322             } catch (GenericServiceException e1) {
323                 return ServiceUtil.returnError("Inventory Item Detail create problem in cancel inventory transfer: [" + e1.getMessage() + "]");
324             }
325         } else if (inventoryType.equals("SERIALIZED_INV_ITEM")) {
326             inventoryItem.set("statusId", "INV_AVAILABLE");
327             // store the entity
328
try {
329                 inventoryItem.store();
330             } catch (GenericEntityException e) {
331                 return ServiceUtil.returnError("Inventory item store problem in cancel inventory transfer: [" + e.getMessage() + "]");
332             }
333         }
334                                 
335         return ServiceUtil.returnSuccess();
336     }
337
338     /** In spite of the generic name this does the very specific task of checking availability of all back-ordered items and sends notices, etc */
339     public static Map JavaDoc checkInventoryAvailability(DispatchContext dctx, Map JavaDoc context) {
340         GenericDelegator delegator = dctx.getDelegator();
341         LocalDispatcher dispatcher = dctx.getDispatcher();
342         GenericValue userLogin = (GenericValue) context.get("userLogin");
343
344         /* TODO: NOTE: This method has been updated, but testing requires many eyes. See http://jira.undersunconsulting.com/browse/OFBIZ-662
345         boolean skipThisNeedsUpdating = true;
346         if (skipThisNeedsUpdating) {
347             Debug.logWarning("NOT Running the checkInventoryAvailability service, no backorders or such will be automatically created; the reason is that this serice needs to be updated to use OrderItemShipGroup instead of OrderShipmentPreference which it currently does.", module);
348             return ServiceUtil.returnSuccess();
349         }
350         */

351         
352         Map JavaDoc ordersToUpdate = new HashMap JavaDoc();
353         Map JavaDoc ordersToCancel = new HashMap JavaDoc();
354         
355         // find all inventory items w/ a negative ATP
356
List JavaDoc inventoryItems = null;
357         try {
358             List JavaDoc exprs = UtilMisc.toList(new EntityExpr("availableToPromiseTotal", EntityOperator.LESS_THAN, new Double JavaDoc(0)));
359             inventoryItems = delegator.findByAnd("InventoryItem", exprs);
360         } catch (GenericEntityException e) {
361             Debug.logError(e, "Trouble getting inventory items", module);
362             return ServiceUtil.returnError("Problem getting InventoryItem records");
363         }
364                         
365         if (inventoryItems == null) {
366             Debug.logInfo("No items out of stock; no backorders to worry about", module);
367             return ServiceUtil.returnSuccess();
368         }
369         
370         Debug.log("OOS Inventory Items: " + inventoryItems.size(), module);
371         
372         Iterator JavaDoc itemsIter = inventoryItems.iterator();
373         while (itemsIter.hasNext()) {
374             GenericValue inventoryItem = (GenericValue) itemsIter.next();
375             
376             // get the incomming shipment information for the item
377
List JavaDoc shipmentAndItems = null;
378             try {
379                 List JavaDoc exprs = new ArrayList JavaDoc();
380                 exprs.add(new EntityExpr("productId", EntityOperator.EQUALS, inventoryItem.get("productId")));
381                 exprs.add(new EntityExpr("destinationFacilityId", EntityOperator.EQUALS, inventoryItem.get("facilityId")));
382                 exprs.add(new EntityExpr("statusId", EntityOperator.NOT_EQUAL, "SHIPMENT_DELIVERED"));
383                 exprs.add(new EntityExpr("statusId", EntityOperator.NOT_EQUAL, "SHIPMENT_CANCELLED"));
384                 shipmentAndItems = delegator.findByAnd("ShipmentAndItem", exprs, UtilMisc.toList("estimatedArrivalDate"));
385             } catch (GenericEntityException e) {
386                 Debug.logError(e, "Problem getting ShipmentAndItem records", module);
387                 return ServiceUtil.returnError("Problem getting ShipmentAndItem records");
388             }
389             
390             // get the reservations in order of newest first
391
List JavaDoc reservations = null;
392             try {
393                 reservations = inventoryItem.getRelated("OrderItemShipGrpInvRes", null, UtilMisc.toList("-reservedDatetime"));
394             } catch (GenericEntityException e) {
395                 Debug.logError(e, "Problem getting related reservations", module);
396                 return ServiceUtil.returnError("Problem getting related reservations");
397             }
398             
399             if (reservations == null) {
400                 Debug.logWarning("No outstanding reservations for this inventory item, why is it negative then?", module);
401                 continue;
402             }
403             
404             Debug.log("Reservations for item: " + reservations.size(), module);
405             
406             // available at the time of order
407
double availableBeforeReserved = inventoryItem.getDouble("availableToPromiseTotal").doubleValue();
408             
409             // go through all the reservations in order
410
Iterator JavaDoc ri = reservations.iterator();
411             while (ri.hasNext()) {
412                 GenericValue reservation = (GenericValue) ri.next();
413                 String JavaDoc orderId = reservation.getString("orderId");
414                 String JavaDoc orderItemSeqId = reservation.getString("orderItemSeqId");
415                 Timestamp JavaDoc promisedDate = reservation.getTimestamp("promisedDatetime");
416                 Timestamp JavaDoc currentPromiseDate = reservation.getTimestamp("currentPromisedDate");
417                 Timestamp JavaDoc actualPromiseDate = currentPromiseDate;
418                 if (actualPromiseDate == null) {
419                     if (promisedDate != null) {
420                         actualPromiseDate = promisedDate;
421                     } else {
422                         // fall back if there is no promised date stored
423
actualPromiseDate = reservation.getTimestamp("reservedDatetime");
424                     }
425                 }
426                 
427                 Debug.log("Promised Date: " + actualPromiseDate, module);
428                                                                
429                 // find the next possible ship date
430
Timestamp JavaDoc nextShipDate = null;
431                 double availableAtTime = 0.00;
432                 Iterator JavaDoc si = shipmentAndItems.iterator();
433                 while (si.hasNext()) {
434                     GenericValue shipmentItem = (GenericValue) si.next();
435                     availableAtTime += shipmentItem.getDouble("quantity").doubleValue();
436                     if (availableAtTime >= availableBeforeReserved) {
437                         nextShipDate = shipmentItem.getTimestamp("estimatedArrivalDate");
438                         break;
439                     }
440                 }
441                 
442                 Debug.log("Next Ship Date: " + nextShipDate, module);
443                                                 
444                 // create a modified promise date (promise date - 1 day)
445
Calendar JavaDoc pCal = Calendar.getInstance();
446                 pCal.setTimeInMillis(actualPromiseDate.getTime());
447                 pCal.add(Calendar.DAY_OF_YEAR, -1);
448                 Timestamp JavaDoc modifiedPromisedDate = new Timestamp JavaDoc(pCal.getTimeInMillis());
449                 Timestamp JavaDoc now = UtilDateTime.nowTimestamp();
450                 
451                 Debug.log("Promised Date + 1: " + modifiedPromisedDate, module);
452                 Debug.log("Now: " + now, module);
453                              
454                 // check the promised date vs the next ship date
455
if (nextShipDate == null || nextShipDate.after(actualPromiseDate)) {
456                     if (nextShipDate == null && modifiedPromisedDate.after(now)) {
457                         // do nothing; we are okay to assume it will be shipped on time
458
Debug.log("No ship date known yet, but promised date hasn't approached, assuming it will be here on time", module);
459                     } else {
460                         // we cannot ship by the promised date; need to notify the customer
461
Debug.log("We won't ship on time, getting notification info", module);
462                         Map JavaDoc notifyItems = (Map JavaDoc) ordersToUpdate.get(orderId);
463                         if (notifyItems == null) {
464                             notifyItems = new HashMap JavaDoc();
465                         }
466                         notifyItems.put(orderItemSeqId, nextShipDate);
467                         ordersToUpdate.put(orderId, notifyItems);
468                         
469                         // need to know if nextShipDate is more then 30 days after promised
470
Calendar JavaDoc sCal = Calendar.getInstance();
471                         sCal.setTimeInMillis(actualPromiseDate.getTime());
472                         sCal.add(Calendar.DAY_OF_YEAR, 30);
473                         Timestamp JavaDoc farPastPromised = new Timestamp JavaDoc(sCal.getTimeInMillis());
474                         
475                         // check to see if this is >30 days or second run, if so flag to cancel
476
boolean needToCancel = false;
477                         if (nextShipDate == null || nextShipDate.after(farPastPromised)) {
478                             // we cannot ship until >30 days after promised; using cancel rule
479
Debug.log("Ship date is >30 past the promised date", module);
480                             needToCancel = true;
481                         } else if (currentPromiseDate != null && actualPromiseDate.equals(currentPromiseDate)) {
482                             // this is the second notification; using cancel rule
483
needToCancel = true;
484                         }
485                         
486                         // add the info to the cancel map if we need to schedule a cancel
487
if (needToCancel) {
488                             // queue the item to be cancelled
489
Debug.log("Flagging the item to auto-cancel", module);
490                             Map JavaDoc cancelItems = (Map JavaDoc) ordersToCancel.get(orderId);
491                             if (cancelItems == null) {
492                                 cancelItems = new HashMap JavaDoc();
493                             }
494                             cancelItems.put(orderItemSeqId, farPastPromised);
495                             ordersToCancel.put(orderId, cancelItems);
496                         }
497                         
498                         // store the updated promiseDate as the nextShipDate
499
try {
500                             reservation.set("currentPromisedDate", nextShipDate);
501                             reservation.store();
502                         } catch (GenericEntityException e) {
503                             Debug.logError(e, "Problem storing reservation : " + reservation, module);
504                         }
505                     }
506                 }
507                                 
508                 // subtract our qty from reserved to get the next value
509
availableBeforeReserved -= reservation.getDouble("quantity").doubleValue();
510             }
511         }
512                
513         // all items to cancel will also be in the notify list so start with that
514
List JavaDoc ordersToNotify = new ArrayList JavaDoc();
515         Set JavaDoc orderSet = ordersToUpdate.keySet();
516         Iterator JavaDoc orderIter = orderSet.iterator();
517         while (orderIter.hasNext()) {
518             String JavaDoc orderId = (String JavaDoc) orderIter.next();
519             Map JavaDoc backOrderedItems = (Map JavaDoc) ordersToUpdate.get(orderId);
520             Map JavaDoc cancelItems = (Map JavaDoc) ordersToCancel.get(orderId);
521             boolean cancelAll = false;
522             Timestamp JavaDoc cancelAllTime = null;
523             
524             List JavaDoc orderItemShipGroups = null;
525             try {
526                 orderItemShipGroups= delegator.findByAnd("OrderItemShipGroup",
527                         UtilMisc.toMap("orderId", orderId));
528             } catch (GenericEntityException e) {
529                 Debug.logError(e, "Cannot get OrderItemShipGroups from orderId" + orderId, module);
530             }
531             
532             Iterator JavaDoc orderItemShipGroupsIter = orderItemShipGroups.iterator();
533             while (orderItemShipGroupsIter.hasNext()) {
534                 GenericValue orderItemShipGroup = (GenericValue)orderItemShipGroupsIter.next();
535                 List JavaDoc orderItems = new java.util.Vector JavaDoc();
536                 List JavaDoc orderItemShipGroupAssoc = null;
537                 try {
538                     orderItemShipGroupAssoc =
539                         delegator.findByAnd("OrderItemShipGroupAssoc",
540                                 UtilMisc.toMap("shipGroupSeqId",
541                                         orderItemShipGroup.get("shipGroupSeqId"),
542                                         "orderId",
543                                         orderId));
544                     
545                     Iterator JavaDoc assocIter = orderItemShipGroupAssoc.iterator();
546                     while (assocIter.hasNext()) {
547                         GenericValue assoc = (GenericValue)assocIter.next();
548                         GenericValue orderItem = assoc.getRelatedOne("OrderItem");
549                         if (orderItem != null) {
550                             orderItems.add(orderItem);
551                         }
552                     }
553                 } catch (GenericEntityException e) {
554                      Debug.logError(e, "Problem fetching OrderItemShipGroupAssoc", module);
555                 }
556                 
557     
558                 /* Check the split preference. */
559                 boolean maySplit = false;
560                 if (orderItemShipGroup != null && orderItemShipGroup.get("maySplit") != null) {
561                     maySplit = orderItemShipGroup.getBoolean("maySplit").booleanValue();
562                 }
563                 
564                 /* Figure out if we must cancel all items. */
565                 if (!maySplit && cancelItems != null) {
566                     cancelAll = true;
567                     Set JavaDoc cancelSet = cancelItems.keySet();
568                     cancelAllTime = (Timestamp JavaDoc) cancelItems.get(cancelSet.iterator().next());
569                 }
570                 
571                 // if there are none to cancel just create an empty map
572
if (cancelItems == null) {
573                     cancelItems = new HashMap JavaDoc();
574                 }
575                 
576                 if (orderItems != null) {
577                     List JavaDoc toBeStored = new ArrayList JavaDoc();
578                     Iterator JavaDoc orderItemsIter = orderItems.iterator();
579                     while (orderItemsIter.hasNext()) {
580                         GenericValue orderItem = (GenericValue) orderItemsIter.next();
581                         String JavaDoc orderItemSeqId = orderItem.getString("orderItemSeqId");
582                         Timestamp JavaDoc shipDate = (Timestamp JavaDoc) backOrderedItems.get(orderItemSeqId);
583                         Timestamp JavaDoc cancelDate = (Timestamp JavaDoc) cancelItems.get(orderItemSeqId);
584                         Timestamp JavaDoc currentCancelDate = (Timestamp JavaDoc) orderItem.getTimestamp("autoCancelDate");
585                         
586                         Debug.logError("OI: " + orderId + " SEQID: "+ orderItemSeqId + " cancelAll: " + cancelAll + " cancelDate: " + cancelDate, module);
587                         if (backOrderedItems.containsKey(orderItemSeqId)) {
588                             orderItem.set("estimatedShipDate", shipDate);
589                             
590                             if (currentCancelDate == null) {
591                                 if (cancelAll || cancelDate != null) {
592                                     if (orderItem.get("dontCancelSetUserLogin") == null && orderItem.get("dontCancelSetDate") == null) {
593                                         if (cancelAllTime != null) {
594                                             orderItem.set("autoCancelDate", cancelAllTime);
595                                         } else {
596                                             orderItem.set("autoCancelDate", cancelDate);
597                                         }
598                                     }
599                                 }
600                                 // only notify orders which have not already sent the final notice
601
ordersToNotify.add(orderId);
602                             }
603                             toBeStored.add(orderItem);
604                         }
605                     }
606                     if (toBeStored.size() > 0) {
607                         try {
608                             delegator.storeAll(toBeStored);
609                         } catch (GenericEntityException e) {
610                             Debug.logError(e, "Problem storing order items", module);
611                         }
612                     }
613                 }
614                 
615                 
616             }
617         }
618         
619         // send off a notification for each order
620
Iterator JavaDoc orderNotifyIter = ordersToNotify.iterator();
621         while (orderNotifyIter.hasNext()) {
622             String JavaDoc orderId = (String JavaDoc) orderNotifyIter.next();
623             
624             try {
625                 dispatcher.runAsync("sendOrderBackorderNotification", UtilMisc.toMap("orderId", orderId, "userLogin", userLogin));
626             } catch (GenericServiceException e) {
627                 Debug.logError(e, "Problems sending off the notification", module);
628                 continue;
629             }
630         }
631         
632         return ServiceUtil.returnSuccess();
633     }
634     
635     /**
636      * Get Inventory Available for a Product based on the list of associated products. The final ATP and QOH will
637      * be the minimum of all the associated products' inventory divided by their ProductAssoc.quantity
638      * */

639     public static Map JavaDoc getProductInventoryAvailablefromAssocProducts(DispatchContext dctx, Map JavaDoc context) {
640         GenericDelegator delegator = dctx.getDelegator();
641         LocalDispatcher dispatcher = dctx.getDispatcher();
642         List JavaDoc productAssocList = (List JavaDoc) context.get("assocProducts");
643                 
644         Double JavaDoc availableToPromiseTotal = new Double JavaDoc(0);
645         Double JavaDoc quantityOnHandTotal = new Double JavaDoc(0);
646         
647         if (productAssocList != null && productAssocList.size() > 0) {
648             // minimum QOH and ATP encountered
649
double minQuantityOnHandTotal = Double.MAX_VALUE;
650            double minAvailableToPromiseTotal = Double.MAX_VALUE;
651            
652            // loop through each associated product.
653
for (int i = 0; productAssocList.size() > i; i++) {
654                GenericValue productAssoc = (GenericValue) productAssocList.get(i);
655                String JavaDoc productIdTo = productAssoc.getString("productIdTo");
656                Double JavaDoc assocQuantity = productAssoc.getDouble("quantity");
657                
658                // if there is no quantity for the associated product in ProductAssoc entity, default it to 1.0
659
if (assocQuantity == null) {
660                    Debug.logWarning("ProductAssoc from [" + productAssoc.getString("productId") + "] to [" + productAssoc.getString("productIdTo") + "] has no quantity, assuming 1.0", module);
661                    assocQuantity = new Double JavaDoc(1.0);
662                }
663                
664                // figure out the inventory available for this associated product
665
Map JavaDoc resultOutput = null;
666                try {
667                   resultOutput = dispatcher.runSync("getProductInventoryAvailable", UtilMisc.toMap("productId", productIdTo));
668                } catch (GenericServiceException e) {
669                   Debug.logError(e, "Problems getting inventory available by facility", module);
670                   return ServiceUtil.returnError(e.getMessage());
671                }
672                
673                // Figure out what the QOH and ATP inventory would be with this associated product
674
Double JavaDoc currentQuantityOnHandTotal = (Double JavaDoc) resultOutput.get("quantityOnHandTotal");
675                Double JavaDoc currentAvailableToPromiseTotal = (Double JavaDoc) resultOutput.get("availableToPromiseTotal");
676                double tmpQuantityOnHandTotal = currentQuantityOnHandTotal.doubleValue()/assocQuantity.doubleValue();
677                double tmpAvailableToPromiseTotal = currentAvailableToPromiseTotal.doubleValue()/assocQuantity.doubleValue();
678
679                // reset the minimum QOH and ATP quantities if those quantities for this product are less
680
if (tmpQuantityOnHandTotal < minQuantityOnHandTotal) {
681                    minQuantityOnHandTotal = tmpQuantityOnHandTotal;
682                }
683                if (tmpAvailableToPromiseTotal < minAvailableToPromiseTotal) {
684                    minAvailableToPromiseTotal = tmpAvailableToPromiseTotal;
685                }
686              
687                if (Debug.verboseOn()) {
688                    Debug.logVerbose("productIdTo = " + productIdTo + " assocQuantity = " + assocQuantity + "current QOH " + currentQuantityOnHandTotal +
689                         "currentATP = " + currentAvailableToPromiseTotal + " minQOH = " + minQuantityOnHandTotal + " minATP = " + minAvailableToPromiseTotal, module);
690                }
691            }
692           // the final QOH and ATP quantities are the minimum of all the products
693
quantityOnHandTotal = new Double JavaDoc(minQuantityOnHandTotal);
694           availableToPromiseTotal = new Double JavaDoc(minAvailableToPromiseTotal);
695         }
696         
697         Map JavaDoc result = ServiceUtil.returnSuccess();
698         result.put("availableToPromiseTotal", availableToPromiseTotal);
699         result.put("quantityOnHandTotal", quantityOnHandTotal);
700         return result;
701     }
702     
703     /**
704      * Given a set of order items, returns a hashmap with the ATP and QOH for each product. The default method is to sum
705      * inventories over all Facilities.
706      */

707     public static Map JavaDoc getProductInventorySummaryForItems(DispatchContext dctx, Map JavaDoc context) {
708         GenericDelegator delegator = dctx.getDelegator();
709         LocalDispatcher dispatcher = dctx.getDispatcher();
710         List JavaDoc orderItems = (List JavaDoc) context.get("orderItems");
711         Map JavaDoc atpMap = new HashMap JavaDoc();
712         Map JavaDoc qohMap = new HashMap JavaDoc();
713         Map JavaDoc results = ServiceUtil.returnSuccess();
714         results.put("availableToPromiseMap", atpMap);
715         results.put("quantityOnHandMap", qohMap);
716         
717         List JavaDoc facilities = null;
718         try {
719             facilities = delegator.findAll("Facility");
720         } catch (GenericEntityException e) {
721             Debug.logError(e, "Couldn't get list of facilities.", module);
722             return ServiceUtil.returnError("Unable to locate facilities.");
723         }
724                 
725         Iterator JavaDoc iter = orderItems.iterator();
726         while (iter.hasNext()) {
727             GenericValue orderItem = (GenericValue) iter.next();
728             String JavaDoc productId = orderItem.getString("productId");
729             
730             if ((productId == null) || productId.equals("")) continue;
731             
732             double atp = 0.0;
733             double qoh = 0.0;
734             Iterator JavaDoc facilityIter = facilities.iterator();
735             while (facilityIter.hasNext()) {
736                 GenericValue facility = (GenericValue) facilityIter.next();
737                 Map JavaDoc params = UtilMisc.toMap("productId", productId, "facilityId", facility.getString("facilityId"));
738                 Map JavaDoc invResult = null;
739                 try {
740                     invResult = dispatcher.runSync("getInventoryAvailableByFacility", params);
741                 } catch (GenericServiceException e) {
742                     String JavaDoc msg = "Could not find inventory for facility [" + facility.getString("facilityId") + "]";
743                     Debug.logError(e, msg, module);
744                     return ServiceUtil.returnError(msg);
745                 }
746                 Double JavaDoc fatp = (Double JavaDoc) invResult.get("availableToPromiseTotal");
747                 Double JavaDoc fqoh = (Double JavaDoc) invResult.get("quantityOnHandTotal");
748                 if (fatp != null) atp += fatp.doubleValue();
749                 if (fqoh != null) qoh += fqoh.doubleValue();
750             }
751             atpMap.put(productId, new Double JavaDoc(atp));
752             qohMap.put(productId, new Double JavaDoc(qoh));
753         }
754         return results;
755     }
756 }
757
Popular Tags