/******************************************************************************* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. *******************************************************************************/ package org.apache.ofbiz.product.subscription; import java.math.BigDecimal; import java.sql.Timestamp; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; import org.apache.ofbiz.base.util.Debug; import org.apache.ofbiz.base.util.UtilDateTime; 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.common.uom.UomWorker; 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.util.EntityQuery; import org.apache.ofbiz.entity.util.EntityUtil; import org.apache.ofbiz.service.DispatchContext; import org.apache.ofbiz.service.GenericServiceException; import org.apache.ofbiz.service.LocalDispatcher; import org.apache.ofbiz.service.ModelService; import org.apache.ofbiz.service.ServiceUtil; import com.ibm.icu.util.Calendar; /** * Subscription Services */ public class SubscriptionServices { public static final String module = SubscriptionServices.class.getName(); public static final String resource = "ProductUiLabels"; public static final String resourceError = "ProductErrorUiLabels"; public static final String resourceOrderError = "OrderErrorUiLabels"; public static Map<String, Object> processExtendSubscription(DispatchContext dctx, Map<String, ? extends Object> context) { Delegator delegator = dctx.getDelegator(); LocalDispatcher dispatcher = dctx.getDispatcher(); Timestamp nowTimestamp = UtilDateTime.nowTimestamp(); String partyId = (String) context.get("partyId"); String subscriptionResourceId = (String) context.get("subscriptionResourceId"); String inventoryItemId = (String) context.get("inventoryItemId"); String roleTypeId = (String) context.get("useRoleTypeId"); GenericValue userLogin = (GenericValue) context.get("userLogin"); Integer useTime = (Integer) context.get("useTime"); String useTimeUomId = (String) context.get("useTimeUomId"); String alwaysCreateNewRecordStr = (String) context.get("alwaysCreateNewRecord"); Locale locale = (Locale) context.get("locale"); boolean alwaysCreateNewRecord = !"N".equals(alwaysCreateNewRecordStr); GenericValue lastSubscription = null; try { Map<String, String> subscriptionFindMap = UtilMisc.toMap("partyId", partyId, "subscriptionResourceId", subscriptionResourceId); // if this subscription is attached to something the customer owns, filter by that too if (UtilValidate.isNotEmpty(inventoryItemId)) subscriptionFindMap.put("inventoryItemId", inventoryItemId); List<GenericValue> subscriptionList = EntityQuery.use(delegator).from("Subscription").where(subscriptionFindMap).queryList(); // DEJ20070718 DON'T filter by date, we want to consider all subscriptions: List listFiltered = EntityUtil.filterByDate(subscriptionList, true); List<GenericValue> listOrdered = EntityUtil.orderBy(subscriptionList, UtilMisc.toList("-fromDate")); if (listOrdered.size() > 0) { lastSubscription = listOrdered.get(0); } } catch (GenericEntityException e) { return ServiceUtil.returnError(e.toString()); } GenericValue newSubscription = null; if (lastSubscription == null || alwaysCreateNewRecord) { newSubscription = delegator.makeValue("Subscription"); newSubscription.set("subscriptionResourceId", subscriptionResourceId); newSubscription.set("partyId", partyId); newSubscription.set("roleTypeId", roleTypeId); newSubscription.set("productId", context.get("productId")); newSubscription.set("orderId", context.get("orderId")); newSubscription.set("orderItemSeqId", context.get("orderItemSeqId")); newSubscription.set("automaticExtend", context.get("automaticExtend")); newSubscription.set("canclAutmExtTimeUomId", context.get("canclAutmExtTimeUomId")); newSubscription.set("canclAutmExtTime", context.get("canclAutmExtTime")); } else { newSubscription = lastSubscription; } newSubscription.set("inventoryItemId", inventoryItemId); Timestamp thruDate = lastSubscription != null ? (Timestamp) lastSubscription.get("thruDate") : null; // set the fromDate, one way or another if (thruDate == null) { // no thruDate? start with NOW thruDate = nowTimestamp; newSubscription.set("fromDate", nowTimestamp); } else { // there is a thru date... if it is in the past, bring it up to NOW before adding on the time period // don't want to penalize for skipping time, in other words if they had a subscription last year for a // month and buy another month, we want that second month to start now and not last year if (thruDate.before(nowTimestamp)) { thruDate = nowTimestamp; } newSubscription.set("fromDate", thruDate); } Calendar calendar = Calendar.getInstance(); calendar.setTime(thruDate); int[] times = UomWorker.uomTimeToCalTime(useTimeUomId); if (times != null) { calendar.add(times[0], (useTime.intValue() * times[1])); } else { Debug.logWarning("Don't know anything about useTimeUomId [" + useTimeUomId + "], defaulting to month", module); calendar.add(Calendar.MONTH, useTime); } thruDate = new Timestamp(calendar.getTimeInMillis()); newSubscription.set("thruDate", thruDate); Map<String, Object> result = ServiceUtil.returnSuccess(); try { if (lastSubscription != null && !alwaysCreateNewRecord) { Map<String, Object> updateSubscriptionMap = dctx.getModelService("updateSubscription").makeValid(newSubscription, ModelService.IN_PARAM); updateSubscriptionMap.put("userLogin", EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").queryOne()); Map<String, Object> updateSubscriptionResult = dispatcher.runSync("updateSubscription", updateSubscriptionMap); result.put("subscriptionId", updateSubscriptionMap.get("subscriptionId")); if (ServiceUtil.isError(updateSubscriptionResult)) { return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ProductSubscriptionUpdateError", UtilMisc.toMap("subscriptionId", updateSubscriptionMap.get("subscriptionId")), locale), null, null, updateSubscriptionResult); } } else { Map<String, Object> ensurePartyRoleMap = new HashMap<String, Object>(); if (UtilValidate.isNotEmpty(roleTypeId)) { ensurePartyRoleMap.put("partyId", partyId); ensurePartyRoleMap.put("roleTypeId", roleTypeId); ensurePartyRoleMap.put("userLogin", userLogin); Map<String, Object> createPartyRoleResult = dispatcher.runSync("ensurePartyRole", ensurePartyRoleMap); if (ServiceUtil.isError(createPartyRoleResult)) { return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ProductSubscriptionPartyRoleCreationError", UtilMisc.toMap("subscriptionResourceId", subscriptionResourceId), locale), null, null, createPartyRoleResult); } } Map<String, Object> createSubscriptionMap = dctx.getModelService("createSubscription").makeValid(newSubscription, ModelService.IN_PARAM); createSubscriptionMap.put("userLogin", EntityQuery.use(delegator).from("UserLogin").where("userLoginId", "system").queryOne()); Map<String, Object> createSubscriptionResult = dispatcher.runSync("createSubscription", createSubscriptionMap); if (ServiceUtil.isError(createSubscriptionResult)) { return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ProductSubscriptionCreateError", UtilMisc.toMap("subscriptionResourceId", subscriptionResourceId), locale), null, null, createSubscriptionResult); } result.put("subscriptionId", createSubscriptionResult.get("subscriptionId")); } } catch (GenericEntityException e) { return ServiceUtil.returnError(e.toString()); } catch (GenericServiceException e) { return ServiceUtil.returnError(e.toString()); } return result; } public static Map<String, Object> processExtendSubscriptionByProduct(DispatchContext dctx, Map<String, ? extends Object> context) throws GenericServiceException{ Delegator delegator = dctx.getDelegator(); LocalDispatcher dispatcher = dctx.getDispatcher(); String productId = (String) context.get("productId"); Integer qty = (Integer) context.get("quantity"); Locale locale = (Locale) context.get("locale"); if (qty == null) { qty = Integer.valueOf(1); } Timestamp orderCreatedDate = (Timestamp) context.get("orderCreatedDate"); if (orderCreatedDate == null) { orderCreatedDate = UtilDateTime.nowTimestamp(); } try { List<GenericValue> productSubscriptionResourceList = EntityQuery.use(delegator).from("ProductSubscriptionResource") .where("productId", productId) .cache(true) .filterByDate(orderCreatedDate, "fromDate", "thruDate", "purchaseFromDate", "purchaseThruDate") .queryList(); if (productSubscriptionResourceList.size() == 0) { Debug.logError("No ProductSubscriptionResource found for productId: " + productId, module); return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ProductSubscriptionResourceNotFound", UtilMisc.toMap("productId", productId), locale)); } for (GenericValue productSubscriptionResource: productSubscriptionResourceList) { Long useTime = productSubscriptionResource.getLong("useTime"); Integer newUseTime = Integer.valueOf(0); if (useTime != null) { newUseTime = Integer.valueOf(useTime.intValue() * qty.intValue()); } Map<String, Object> subContext = UtilMisc.makeMapWritable(context); subContext.put("useTime", newUseTime); subContext.put("useTimeUomId", productSubscriptionResource.get("useTimeUomId")); subContext.put("useRoleTypeId", productSubscriptionResource.get("useRoleTypeId")); subContext.put("subscriptionResourceId", productSubscriptionResource.get("subscriptionResourceId")); subContext.put("automaticExtend", productSubscriptionResource.get("automaticExtend")); subContext.put("canclAutmExtTime", productSubscriptionResource.get("canclAutmExtTime")); subContext.put("canclAutmExtTimeUomId", productSubscriptionResource.get("canclAutmExtTimeUomId")); subContext.put("gracePeriodOnExpiry", productSubscriptionResource.get("gracePeriodOnExpiry")); subContext.put("gracePeriodOnExpiryUomId", productSubscriptionResource.get("gracePeriodOnExpiryUomId")); Map<String, Object> ctx = dctx.getModelService("processExtendSubscription").makeValid(subContext, ModelService.IN_PARAM); Map<String, Object> processExtendSubscriptionResult = dispatcher.runSync("processExtendSubscription", ctx); if (ServiceUtil.isError(processExtendSubscriptionResult)) { return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ProductSubscriptionByProductError", UtilMisc.toMap("productId", productId), locale), null, null, processExtendSubscriptionResult); } } } catch (GenericEntityException e) { Debug.logError(e, e.toString(), module); return ServiceUtil.returnError(e.toString()); } return ServiceUtil.returnSuccess(); } public static Map<String, Object> processExtendSubscriptionByOrder(DispatchContext dctx, Map<String, ? extends Object> context) throws GenericServiceException{ Delegator delegator = dctx.getDelegator(); LocalDispatcher dispatcher = dctx.getDispatcher(); Map<String, Object> subContext = UtilMisc.makeMapWritable(context); String orderId = (String) context.get("orderId"); Locale locale = (Locale) context.get("locale"); Debug.logInfo("In processExtendSubscriptionByOrder service with orderId: " + orderId, module); GenericValue orderHeader = null; try { List<GenericValue> orderRoleList = EntityQuery.use(delegator).from("OrderRole").where("orderId", orderId, "roleTypeId", "END_USER_CUSTOMER").queryList(); if (orderRoleList.size() > 0) { GenericValue orderRole = orderRoleList.get(0); String partyId = (String) orderRole.get("partyId"); subContext.put("partyId", partyId); } else { return ServiceUtil.returnFailure(UtilProperties.getMessage(resourceOrderError, "OrderErrorCannotGetOrderRoleEntity", UtilMisc.toMap("itemMsgInfo", orderId), locale)); } orderHeader = EntityQuery.use(delegator).from("OrderHeader").where("orderId", orderId).queryOne(); if (orderHeader == null) { return ServiceUtil.returnError(UtilProperties.getMessage(resourceOrderError, "OrderErrorNoValidOrderHeaderFoundForOrderId", UtilMisc.toMap("orderId", orderId), locale)); } Timestamp orderCreatedDate = (Timestamp) orderHeader.get("orderDate"); subContext.put("orderCreatedDate", orderCreatedDate); List<GenericValue> orderItemList = orderHeader.getRelated("OrderItem", null, null, false); for (GenericValue orderItem: orderItemList) { BigDecimal qty = orderItem.getBigDecimal("quantity"); String productId = orderItem.getString("productId"); if (UtilValidate.isEmpty(productId)) { continue; } List<GenericValue> productSubscriptionResourceListFiltered = EntityQuery.use(delegator).from("ProductSubscriptionResource").where("productId", productId).cache(true).filterByDate().queryList(); if (productSubscriptionResourceListFiltered.size() > 0) { subContext.put("subscriptionTypeId", "PRODUCT_SUBSCR"); subContext.put("productId", productId); subContext.put("orderId", orderId); subContext.put("orderItemSeqId", orderItem.get("orderItemSeqId")); subContext.put("inventoryItemId", orderItem.get("fromInventoryItemId")); subContext.put("quantity", Integer.valueOf(qty.intValue())); Map<String, Object> ctx = dctx.getModelService("processExtendSubscriptionByProduct").makeValid(subContext, ModelService.IN_PARAM); Map<String, Object> thisResult = dispatcher.runSync("processExtendSubscriptionByProduct", ctx); if (ServiceUtil.isError(thisResult)) { return ServiceUtil.returnError(UtilProperties.getMessage(resource, "ProductSubscriptionByOrderError", UtilMisc.toMap("orderId", orderId), locale), null, null, thisResult); } } } } catch (GenericEntityException e) { Debug.logError(e.toString(), module); return ServiceUtil.returnError(e.toString()); } return ServiceUtil.returnSuccess(); } public static Map<String, Object> runServiceOnSubscriptionExpiry( DispatchContext dctx, Map<String, ? extends Object> context) { LocalDispatcher dispatcher = dctx.getDispatcher(); Delegator delegator = dctx.getDelegator(); Locale locale =(Locale)context.get("locale"); GenericValue userLogin = (GenericValue) context.get("userLogin"); Map<String, Object> result = new HashMap<String, Object>(); Map<String, Object> expiryMap = new HashMap<String, Object>(); String gracePeriodOnExpiry = null; String gracePeriodOnExpiryUomId = null; String subscriptionId = null; Timestamp expirationCompletedDate = null; try { EntityCondition cond1 = EntityCondition.makeCondition("automaticExtend", EntityOperator.EQUALS, "N"); EntityCondition cond2 = EntityCondition.makeCondition("automaticExtend", EntityOperator.EQUALS, null); EntityCondition cond = EntityCondition.makeCondition(UtilMisc.toList(cond1, cond2), EntityOperator.OR); List<GenericValue> subscriptionList = null; subscriptionList = EntityQuery.use(delegator).from("Subscription").where(cond).queryList(); if (subscriptionList != null) { for (GenericValue subscription : subscriptionList) { expirationCompletedDate = subscription.getTimestamp("expirationCompletedDate"); if (expirationCompletedDate == null) { Calendar currentDate = Calendar.getInstance(); currentDate.setTime(UtilDateTime.nowTimestamp()); // check if the thruDate + grace period (if provided) is earlier than today's date Calendar endDateSubscription = Calendar.getInstance(); int field = Calendar.MONTH; String subscriptionResourceId = subscription.getString("subscriptionResourceId"); GenericValue subscriptionResource = null; subscriptionResource = EntityQuery.use(delegator).from("SubscriptionResource").where("subscriptionResourceId", subscriptionResourceId).queryOne(); subscriptionId = subscription.getString("subscriptionId"); gracePeriodOnExpiry = subscription.getString("gracePeriodOnExpiry"); gracePeriodOnExpiryUomId = subscription.getString("gracePeriodOnExpiryUomId"); String serviceNameOnExpiry = subscriptionResource.getString("serviceNameOnExpiry"); endDateSubscription.setTime(subscription.getTimestamp("thruDate")); if (gracePeriodOnExpiry != null && gracePeriodOnExpiryUomId != null) { if ("TF_day".equals(gracePeriodOnExpiryUomId)) { field = Calendar.DAY_OF_YEAR; } else if ("TF_wk".equals(gracePeriodOnExpiryUomId)) { field = Calendar.WEEK_OF_YEAR; } else if ("TF_mon".equals(gracePeriodOnExpiryUomId)) { field = Calendar.MONTH; } else if ("TF_yr".equals(gracePeriodOnExpiryUomId)) { field = Calendar.YEAR; } else { Debug.logWarning("Don't know anything about gracePeriodOnExpiryUomId [" + gracePeriodOnExpiryUomId + "], defaulting to month", module); } endDateSubscription.add(field, Integer.valueOf(gracePeriodOnExpiry).intValue()); } if ((currentDate.after(endDateSubscription) || currentDate.equals(endDateSubscription)) && serviceNameOnExpiry != null) { if (userLogin != null) { expiryMap.put("userLogin", userLogin); } if (subscriptionId != null) { expiryMap.put("subscriptionId", subscriptionId); } result = dispatcher.runSync(serviceNameOnExpiry, expiryMap); if (ServiceUtil.isSuccess(result)) { subscription.set("expirationCompletedDate", UtilDateTime.nowTimestamp()); delegator.store(subscription); Debug.logInfo("Subscription expired successfully for subscription ID:" + subscriptionId, module); } else if (ServiceUtil.isError(result)) { result = null; Debug.logError("Error expiring subscription while processing with subscriptionId: " + subscriptionId, module); } if (result != null && subscriptionId != null) { Debug.logInfo("Service mentioned in serviceNameOnExpiry called with result: " + result.get("successMessage"), module); } else if (result == null && subscriptionId != null) { Debug.logError("Subscription couldn't be expired for subscriptionId: " + subscriptionId, module); return ServiceUtil.returnError(UtilProperties.getMessage(resourceError, "ProductSubscriptionCouldntBeExpired", UtilMisc.toMap("subscriptionId", subscriptionId), locale)); } } } } } } catch (GenericServiceException e) { Debug.logError("Error while calling service specified in serviceNameOnExpiry", module); return ServiceUtil.returnError(e.toString()); } catch (GenericEntityException e) { Debug.logError(e, module); } return result; } public static Map<String, Object> runSubscriptionExpired( DispatchContext dctx, Map<String, ? extends Object> context) { Locale locale = (Locale)context.get("locale"); String subscriptionId = (String) context.get("subscriptionId"); Map<String, Object> result = new HashMap<String, Object>(); if (subscriptionId != null) { return ServiceUtil.returnSuccess(UtilProperties.getMessage(resource, "ProductRunSubscriptionExpiredServiceCalledSuccessfully", locale)); } return result; } }