001: /*******************************************************************************
002: * Licensed to the Apache Software Foundation (ASF) under one
003: * or more contributor license agreements. See the NOTICE file
004: * distributed with this work for additional information
005: * regarding copyright ownership. The ASF licenses this file
006: * to you under the Apache License, Version 2.0 (the
007: * "License"); you may not use this file except in compliance
008: * with the License. You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing,
013: * software distributed under the License is distributed on an
014: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015: * KIND, either express or implied. See the License for the
016: * specific language governing permissions and limitations
017: * under the License.
018: *******************************************************************************/package org.ofbiz.order.order;
019:
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Map;
023:
024: import org.ofbiz.base.util.Debug;
025: import org.ofbiz.base.util.UtilDateTime;
026: import org.ofbiz.base.util.UtilMisc;
027: import org.ofbiz.entity.GenericDelegator;
028: import org.ofbiz.entity.GenericEntityException;
029: import org.ofbiz.entity.GenericValue;
030: import org.ofbiz.entity.util.EntityUtil;
031: import org.ofbiz.service.GenericServiceException;
032: import org.ofbiz.service.LocalDispatcher;
033: import org.ofbiz.service.ModelService;
034: import org.ofbiz.service.ServiceUtil;
035: import org.ofbiz.workflow.WfException;
036: import org.ofbiz.workflow.client.WorkflowClient;
037:
038: /**
039: * Order Helper - Helper Methods For Non-Read Actions
040: */
041: public class OrderChangeHelper {
042:
043: public static final String module = OrderChangeHelper.class
044: .getName();
045:
046: public static boolean approveOrder(LocalDispatcher dispatcher,
047: GenericValue userLogin, String orderId) {
048: return approveOrder(dispatcher, userLogin, orderId, false);
049: }
050:
051: public static boolean approveOrder(LocalDispatcher dispatcher,
052: GenericValue userLogin, String orderId, boolean holdOrder) {
053: GenericValue productStore = OrderReadHelper
054: .getProductStoreFromOrder(dispatcher.getDelegator(),
055: orderId);
056: if (productStore == null) {
057: throw new IllegalArgumentException(
058: "Could not find ProductStore for orderId ["
059: + orderId + "], cannot approve order.");
060: }
061:
062: // interal status for held orders
063: String HEADER_STATUS = "ORDER_PROCESSING";
064: String ITEM_STATUS = "ITEM_CREATED";
065: String DIGITAL_ITEM_STATUS = "ITEM_APPROVED";
066:
067: if (!holdOrder) {
068: if (productStore.get("headerApprovedStatus") != null) {
069: HEADER_STATUS = productStore
070: .getString("headerApprovedStatus");
071: }
072: if (productStore.get("itemApprovedStatus") != null) {
073: ITEM_STATUS = productStore
074: .getString("itemApprovedStatus");
075: }
076: if (productStore.get("digitalItemApprovedStatus") != null) {
077: DIGITAL_ITEM_STATUS = productStore
078: .getString("digitalItemApprovedStatus");
079: }
080: }
081:
082: try {
083: OrderChangeHelper.orderStatusChanges(dispatcher, userLogin,
084: orderId, HEADER_STATUS, "ITEM_CREATED",
085: ITEM_STATUS, DIGITAL_ITEM_STATUS);
086: OrderChangeHelper.releaseInitialOrderHold(dispatcher,
087: orderId);
088:
089: /*
090: // call the service to check/run digital fulfillment
091: Map checkDigi = dispatcher.runSync("checkDigitalItemFulfillment", UtilMisc.toMap("orderId", orderId, "userLogin", userLogin));
092: // this service will return a message with success if there were any problems. Get this message and return it to the user
093: String message = (String) checkDigi.get(ModelService.SUCCESS_MESSAGE);
094: if (UtilValidate.isNotEmpty(message)) {
095: throw new GeneralRuntimeException(message);
096: }
097: */
098: } catch (GenericServiceException e) {
099: Debug.logError(e,
100: "Service invocation error, status changes were not updated for order #"
101: + orderId, module);
102: return false;
103: }
104:
105: return true;
106: }
107:
108: public static boolean rejectOrder(LocalDispatcher dispatcher,
109: GenericValue userLogin, String orderId) {
110: GenericValue productStore = OrderReadHelper
111: .getProductStoreFromOrder(dispatcher.getDelegator(),
112: orderId);
113: String HEADER_STATUS = "ORDER_REJECTED";
114: String ITEM_STATUS = "ITEM_REJECTED";
115: if (productStore.get("headerDeclinedStatus") != null) {
116: HEADER_STATUS = productStore
117: .getString("headerDeclinedStatus");
118: }
119: if (productStore.get("itemDeclinedStatus") != null) {
120: ITEM_STATUS = productStore.getString("itemDeclinedStatus");
121: }
122:
123: try {
124: OrderChangeHelper.orderStatusChanges(dispatcher, userLogin,
125: orderId, HEADER_STATUS, null, ITEM_STATUS, null);
126: OrderChangeHelper.cancelInventoryReservations(dispatcher,
127: userLogin, orderId);
128: OrderChangeHelper.releasePaymentAuthorizations(dispatcher,
129: userLogin, orderId);
130: OrderChangeHelper.releaseInitialOrderHold(dispatcher,
131: orderId);
132: } catch (GenericServiceException e) {
133: Debug.logError(e,
134: "Service invocation error, status changes were not updated for order #"
135: + orderId, module);
136: return false;
137: }
138: return true;
139: }
140:
141: public static boolean completeOrder(LocalDispatcher dispatcher,
142: GenericValue userLogin, String orderId) {
143: try {
144: OrderChangeHelper.createReceivedPayments(dispatcher,
145: userLogin, orderId);
146: OrderChangeHelper.createOrderInvoice(dispatcher, userLogin,
147: orderId);
148: OrderChangeHelper.orderStatusChanges(dispatcher, userLogin,
149: orderId, "ORDER_COMPLETED", "ITEM_APPROVED",
150: "ITEM_COMPLETED", null);
151: } catch (GenericEntityException e) {
152: Debug.logError(e, module);
153: return false;
154: } catch (GenericServiceException e) {
155: Debug.logError(e, module);
156: return false;
157: }
158: return true;
159: }
160:
161: public static boolean cancelOrder(LocalDispatcher dispatcher,
162: GenericValue userLogin, String orderId) {
163: GenericValue productStore = OrderReadHelper
164: .getProductStoreFromOrder(dispatcher.getDelegator(),
165: orderId);
166: String HEADER_STATUS = "ORDER_CANCELLED";
167: String ITEM_STATUS = "ITEM_CANCELLED";
168: if (productStore.get("headerCancelStatus") != null) {
169: HEADER_STATUS = productStore
170: .getString("headerCancelStatus");
171: }
172: if (productStore.get("itemCancelStatus") != null) {
173: ITEM_STATUS = productStore.getString("itemCancelStatus");
174: }
175:
176: try {
177: OrderChangeHelper.orderStatusChanges(dispatcher, userLogin,
178: orderId, HEADER_STATUS, null, ITEM_STATUS, null);
179: OrderChangeHelper.cancelInventoryReservations(dispatcher,
180: userLogin, orderId);
181: OrderChangeHelper.releasePaymentAuthorizations(dispatcher,
182: userLogin, orderId);
183: OrderChangeHelper.releaseInitialOrderHold(dispatcher,
184: orderId);
185: } catch (GenericServiceException e) {
186: Debug.logError(e,
187: "Service invocation error, status changes were not updated for order #"
188: + orderId, module);
189: return false;
190: }
191: return true;
192: }
193:
194: public static void orderStatusChanges(LocalDispatcher dispatcher,
195: GenericValue userLogin, String orderId, String orderStatus,
196: String fromItemStatus, String toItemStatus,
197: String digitalItemStatus) throws GenericServiceException {
198: // set the status on the order header
199: Map statusFields = UtilMisc.toMap("orderId", orderId,
200: "statusId", orderStatus, "userLogin", userLogin);
201: Map statusResult = dispatcher.runSync("changeOrderStatus",
202: statusFields);
203: if (statusResult.containsKey(ModelService.ERROR_MESSAGE)) {
204: Debug.logError(
205: "Problems adjusting order header status for order #"
206: + orderId, module);
207: }
208:
209: // set the status on the order item(s)
210: Map itemStatusFields = UtilMisc.toMap("orderId", orderId,
211: "statusId", toItemStatus, "userLogin", userLogin);
212: if (fromItemStatus != null) {
213: itemStatusFields.put("fromStatusId", fromItemStatus);
214: }
215: Map itemStatusResult = dispatcher.runSync(
216: "changeOrderItemStatus", itemStatusFields);
217: if (itemStatusResult.containsKey(ModelService.ERROR_MESSAGE)) {
218: Debug.logError(
219: "Problems adjusting order item status for order #"
220: + orderId, module);
221: }
222:
223: // now set the status for digital items
224: if (digitalItemStatus != null
225: && !digitalItemStatus.equals(toItemStatus)) {
226: GenericDelegator delegator = dispatcher.getDelegator();
227: GenericValue orderHeader = null;
228: try {
229: orderHeader = delegator.findByPrimaryKey("OrderHeader",
230: UtilMisc.toMap("orderId", orderId));
231: } catch (GenericEntityException e) {
232: Debug.logError(e,
233: "ERROR: Unable to get OrderHeader for OrderID : "
234: + orderId, module);
235: }
236: if (orderHeader != null) {
237: List orderItems = null;
238: try {
239: orderItems = orderHeader.getRelated("OrderItem");
240: } catch (GenericEntityException e) {
241: Debug.logError(e,
242: "ERROR: Unable to get OrderItem records for OrderHeader : "
243: + orderId, module);
244: }
245: if (orderItems != null && orderItems.size() > 0) {
246: Iterator oii = orderItems.iterator();
247: while (oii.hasNext()) {
248: GenericValue orderItem = (GenericValue) oii
249: .next();
250: String orderItemSeqId = orderItem
251: .getString("orderItemSeqId");
252: GenericValue product = null;
253:
254: try {
255: product = orderItem
256: .getRelatedOne("Product");
257: } catch (GenericEntityException e) {
258: Debug.logError(e,
259: "ERROR: Unable to get Product record for OrderItem : "
260: + orderId + "/"
261: + orderItemSeqId, module);
262: }
263: if (product != null) {
264: GenericValue productType = null;
265: try {
266: productType = product
267: .getRelatedOne("ProductType");
268: } catch (GenericEntityException e) {
269: Debug.logError(e,
270: "ERROR: Unable to get ProductType from Product : "
271: + product, module);
272: }
273: if (productType != null) {
274: String isDigital = productType
275: .getString("isDigital");
276: if (isDigital != null
277: && "Y"
278: .equalsIgnoreCase(isDigital)) {
279: // update the status
280: Map digitalStatusFields = UtilMisc
281: .toMap("orderId", orderId,
282: "orderItemSeqId",
283: orderItemSeqId,
284: "statusId",
285: digitalItemStatus,
286: "userLogin",
287: userLogin);
288: Map digitalStatusChange = dispatcher
289: .runSync(
290: "changeOrderItemStatus",
291: digitalStatusFields);
292: if (ModelService.RESPOND_ERROR
293: .equals(digitalStatusChange
294: .get(ModelService.RESPONSE_MESSAGE))) {
295: Debug.logError(
296: "Problems with digital product status change : "
297: + product,
298: module);
299: }
300: }
301: }
302: } else {
303: String orderItemType = orderItem
304: .getString("orderItemTypeId");
305: if (!"PRODUCT_ORDER_ITEM"
306: .equals(orderItemType)) {
307: // non-product items don't ship; treat as a digital item
308: Map digitalStatusFields = UtilMisc
309: .toMap("orderId", orderId,
310: "orderItemSeqId",
311: orderItemSeqId,
312: "statusId",
313: digitalItemStatus,
314: "userLogin", userLogin);
315: Map digitalStatusChange = dispatcher
316: .runSync(
317: "changeOrderItemStatus",
318: digitalStatusFields);
319: if (ModelService.RESPOND_ERROR
320: .equals(digitalStatusChange
321: .get(ModelService.RESPONSE_MESSAGE))) {
322: Debug.logError(
323: "Problems with digital product status change : "
324: + product, module);
325: }
326: }
327: }
328: }
329: }
330: }
331: }
332: }
333:
334: public static void cancelInventoryReservations(
335: LocalDispatcher dispatcher, GenericValue userLogin,
336: String orderId) throws GenericServiceException {
337: // cancel the inventory reservations
338: Map cancelInvFields = UtilMisc.toMap("orderId", orderId,
339: "userLogin", userLogin);
340: Map cancelInvResult = dispatcher.runSync(
341: "cancelOrderInventoryReservation", cancelInvFields);
342: if (ModelService.RESPOND_ERROR.equals(cancelInvResult
343: .get(ModelService.RESPONSE_MESSAGE))) {
344: Debug.logError(
345: "Problems reversing inventory reservations for order #"
346: + orderId, module);
347: }
348: }
349:
350: public static void releasePaymentAuthorizations(
351: LocalDispatcher dispatcher, GenericValue userLogin,
352: String orderId) throws GenericServiceException {
353: Map releaseFields = UtilMisc.toMap("orderId", orderId,
354: "userLogin", userLogin);
355: Map releaseResult = dispatcher.runSync("releaseOrderPayments",
356: releaseFields);
357: if (ModelService.RESPOND_ERROR.equals(releaseResult
358: .get(ModelService.RESPONSE_MESSAGE))) {
359: Debug.logError(
360: "Problems releasing payment authorizations for order #"
361: + orderId, module);
362: }
363: }
364:
365: public static void createReceivedPayments(
366: LocalDispatcher dispatcher, GenericValue userLogin,
367: String orderId) throws GenericEntityException,
368: GenericServiceException {
369: GenericValue orderHeader = null;
370: try {
371: orderHeader = dispatcher.getDelegator().findByPrimaryKey(
372: "OrderHeader", UtilMisc.toMap("orderId", orderId));
373: } catch (GenericEntityException e) {
374: Debug.logError(e, module);
375: }
376: if (orderHeader != null) {
377: OrderReadHelper orh = new OrderReadHelper(orderHeader);
378: GenericValue btparty = orh.getBillToParty();
379: String partyId = "_NA_";
380: if (btparty != null) {
381: partyId = btparty.getString("partyId");
382: }
383:
384: List opps = orh.getPaymentPreferences();
385: Iterator oppi = opps.iterator();
386: while (oppi.hasNext()) {
387: GenericValue opp = (GenericValue) oppi.next();
388: if ("PAYMENT_RECEIVED"
389: .equals(opp.getString("statusId"))) {
390: List payments = orh.getOrderPayments(opp);
391: if (payments == null || payments.size() == 0) {
392: // only do this one time; if we have payment already for this pref ignore.
393: Map results = dispatcher
394: .runSync(
395: "createPaymentFromPreference",
396: UtilMisc
397: .toMap(
398: "userLogin",
399: userLogin,
400: "orderPaymentPreferenceId",
401: opp
402: .getString("orderPaymentPreferenceId"),
403: "paymentRefNum",
404: UtilDateTime
405: .nowTimestamp()
406: .toString(),
407: "paymentFromId",
408: partyId));
409: if (results.get(ModelService.RESPONSE_MESSAGE)
410: .equals(ModelService.RESPOND_ERROR)) {
411: Debug.logError((String) results
412: .get(ModelService.ERROR_MESSAGE),
413: module);
414: }
415: }
416: }
417: }
418: }
419: }
420:
421: public static void createOrderInvoice(LocalDispatcher dispatcher,
422: GenericValue userLogin, String orderId)
423: throws GenericServiceException {
424: GenericValue orderHeader = null;
425: try {
426: orderHeader = dispatcher.getDelegator().findByPrimaryKey(
427: "OrderHeader", UtilMisc.toMap("orderId", orderId));
428: } catch (GenericEntityException e) {
429: Debug.logError(e, module);
430: }
431: if (orderHeader != null) {
432: OrderReadHelper orh = new OrderReadHelper(orderHeader);
433: List items = orh.getOrderItems();
434:
435: Map serviceParam = UtilMisc.toMap("orderId", orderId,
436: "billItems", items, "userLogin", userLogin);
437: Map serviceRes = dispatcher.runSync(
438: "createInvoiceForOrder", serviceParam);
439: if (ServiceUtil.isError(serviceRes)) {
440: throw new GenericServiceException(ServiceUtil
441: .getErrorMessage(serviceRes));
442: }
443: }
444: }
445:
446: public static boolean releaseInitialOrderHold(
447: LocalDispatcher dispatcher, String orderId) {
448: // get the delegator from the dispatcher
449: GenericDelegator delegator = dispatcher.getDelegator();
450:
451: // find the workEffortId for this order
452: List workEfforts = null;
453: try {
454: workEfforts = delegator.findByAnd("WorkEffort", UtilMisc
455: .toMap("currentStatusId", "WF_SUSPENDED",
456: "sourceReferenceId", orderId));
457: } catch (GenericEntityException e) {
458: Debug.logError(e,
459: "Problems getting WorkEffort with order ref number: "
460: + orderId, module);
461: return false;
462: }
463:
464: if (workEfforts != null) {
465: // attempt to release the order workflow from 'Hold' status (resume workflow)
466: boolean allPass = true;
467: Iterator wei = workEfforts.iterator();
468: while (wei.hasNext()) {
469: GenericValue workEffort = (GenericValue) wei.next();
470: String workEffortId = workEffort
471: .getString("workEffortId");
472: try {
473: if (workEffort.getString("currentStatusId").equals(
474: "WF_SUSPENDED")) {
475: WorkflowClient client = new WorkflowClient(
476: dispatcher.getDispatchContext());
477: client.resume(workEffortId);
478: } else {
479: Debug.logVerbose("Current : --{" + workEffort
480: + "}-- not resuming", module);
481: }
482: } catch (WfException e) {
483: Debug.logError(e, "Problem resuming activity : "
484: + workEffortId, module);
485: allPass = false;
486: }
487: }
488: return allPass;
489: } else {
490: Debug.logWarning("No WF found for order ID : " + orderId,
491: module);
492: }
493: return false;
494: }
495:
496: public static boolean abortOrderProcessing(
497: LocalDispatcher dispatcher, String orderId) {
498: Debug.logInfo("Aborting workflow for order " + orderId, module);
499: GenericDelegator delegator = dispatcher.getDelegator();
500:
501: // find the workEffortId for this order
502: GenericValue workEffort = null;
503: try {
504: List workEfforts = delegator.findByAnd("WorkEffort",
505: UtilMisc.toMap("workEffortTypeId", "WORK_FLOW",
506: "sourceReferenceId", orderId));
507: if (workEfforts != null && workEfforts.size() > 1) {
508: Debug.logWarning(
509: "More then one workflow found for defined order: "
510: + orderId, module);
511: }
512: workEffort = EntityUtil.getFirst(workEfforts);
513: } catch (GenericEntityException e) {
514: Debug.logError(e,
515: "Problems getting WorkEffort with order ref number: "
516: + orderId, module);
517: return false;
518: }
519:
520: if (workEffort != null) {
521: String workEffortId = workEffort.getString("workEffortId");
522: if (workEffort.getString("currentStatusId").equals(
523: "WF_RUNNING")) {
524: Debug.logInfo("WF is running; trying to abort", module);
525: WorkflowClient client = new WorkflowClient(dispatcher
526: .getDispatchContext());
527: try {
528: client.abortProcess(workEffortId);
529: } catch (WfException e) {
530: Debug.logError(e, "Problem aborting workflow",
531: module);
532: return false;
533: }
534: return true;
535: }
536: }
537: return false;
538: }
539: }
|