Beispiel #1
0
  public static GenericValue getPaymentAddress(Delegator delegator, String partyId) {
    List<GenericValue> paymentAddresses = null;
    try {
      paymentAddresses =
          delegator.findByAnd(
              "PartyContactMechPurpose",
              UtilMisc.toMap("partyId", partyId, "contactMechPurposeTypeId", "PAYMENT_LOCATION"),
              UtilMisc.toList("-fromDate"));
      paymentAddresses = EntityUtil.filterByDate(paymentAddresses);
    } catch (GenericEntityException e) {
      Debug.logError(e, "Trouble getting PartyContactMechPurpose entity list", module);
    }

    // get the address for the primary contact mech
    GenericValue purpose = EntityUtil.getFirst(paymentAddresses);
    GenericValue postalAddress = null;
    if (purpose != null) {
      try {
        postalAddress =
            delegator.findByPrimaryKey(
                "PostalAddress",
                UtilMisc.toMap("contactMechId", purpose.getString("contactMechId")));
      } catch (GenericEntityException e) {
        Debug.logError(
            e,
            "Trouble getting PostalAddress record for contactMechId: "
                + purpose.getString("contactMechId"),
            module);
      }
    }

    return postalAddress;
  }
Beispiel #2
0
  public static String[] findFirstMatchingPartyAndContactMechId(
      Delegator delegator,
      String address1,
      String address2,
      String city,
      String stateProvinceGeoId,
      String postalCode,
      String postalCodeExt,
      String countryGeoId,
      String firstName,
      String middleName,
      String lastName)
      throws GeneralException {

    List<GenericValue> matching =
        findMatchingPersonPostalAddresses(
            delegator,
            address1,
            address2,
            city,
            stateProvinceGeoId,
            postalCode,
            postalCodeExt,
            countryGeoId,
            firstName,
            middleName,
            lastName);
    GenericValue v = EntityUtil.getFirst(matching);
    if (v != null) {
      return new String[] {v.getString("partyId"), v.getString("contactMechId")};
    }
    return null;
  }
Beispiel #3
0
 /** Checks if the given party with role is assigned to the user login. */
 public static boolean isAssignedToUserLogin(
     String partyId, String roleTypeId, GenericValue userLogin) throws GenericEntityException {
   Delegator delegator = userLogin.getDelegator();
   String roleTypeIdTo =
       getFirstValidTeamMemberRoleTypeId(userLogin.getString("partyId"), delegator);
   if (roleTypeIdTo == null) {
     return false;
   }
   List<GenericValue> activeRelationships =
       EntityUtil.filterByDate(
           delegator.findByAnd(
               "PartyRelationship",
               UtilMisc.toMap(
                   "partyIdFrom",
                   partyId,
                   "roleTypeIdFrom",
                   roleTypeId,
                   "partyIdTo",
                   userLogin.get("partyId"),
                   "roleTypeIdTo",
                   roleTypeIdTo,
                   "partyRelationshipTypeId",
                   "ASSIGNED_TO")));
   return activeRelationships.size() > 0;
 }
Beispiel #4
0
 public static GenericValue findParty(
     Delegator delegator, String idToFind, String partyIdentificationTypeId)
     throws GenericEntityException {
   List<GenericValue> parties = findPartiesById(delegator, idToFind, partyIdentificationTypeId);
   GenericValue party = EntityUtil.getFirst(parties);
   return party;
 }
  public static boolean isProductInCategory(
      Delegator delegator, String productId, String productCategoryId)
      throws GenericEntityException {
    if (productCategoryId == null) return false;
    if (UtilValidate.isEmpty(productId)) return false;

    List<GenericValue> productCategoryMembers =
        EntityUtil.filterByDate(
            delegator.findByAndCache(
                "ProductCategoryMember",
                UtilMisc.toMap("productCategoryId", productCategoryId, "productId", productId)),
            true);
    if (UtilValidate.isEmpty(productCategoryMembers)) {
      // before giving up see if this is a variant product, and if so look up the virtual product
      // and check it...
      GenericValue product =
          delegator.findByPrimaryKeyCache("Product", UtilMisc.toMap("productId", productId));
      List<GenericValue> productAssocs = ProductWorker.getVariantVirtualAssocs(product);
      // this does take into account that a product could be a variant of multiple products, but
      // this shouldn't ever really happen...
      if (productAssocs != null) {
        for (GenericValue productAssoc : productAssocs) {
          if (isProductInCategory(
              delegator, productAssoc.getString("productId"), productCategoryId)) {
            return true;
          }
        }
      }

      return false;
    } else {
      return true;
    }
  }
Beispiel #6
0
  public static List<Map<String, GenericValue>> getPartyPaymentMethodValueMaps(
      Delegator delegator, String partyId, Boolean showOld) {
    List<Map<String, GenericValue>> paymentMethodValueMaps = FastList.newInstance();
    try {
      List<GenericValue> paymentMethods =
          delegator.findByAnd("PaymentMethod", UtilMisc.toMap("partyId", partyId));

      if (!showOld) paymentMethods = EntityUtil.filterByDate(paymentMethods, true);

      for (GenericValue paymentMethod : paymentMethods) {
        Map<String, GenericValue> valueMap = FastMap.newInstance();

        paymentMethodValueMaps.add(valueMap);
        valueMap.put("paymentMethod", paymentMethod);
        if ("CREDIT_CARD".equals(paymentMethod.getString("paymentMethodTypeId"))) {
          GenericValue creditCard = paymentMethod.getRelatedOne("CreditCard");
          if (creditCard != null) valueMap.put("creditCard", creditCard);
        } else if ("GIFT_CARD".equals(paymentMethod.getString("paymentMethodTypeId"))) {
          GenericValue giftCard = paymentMethod.getRelatedOne("GiftCard");
          if (giftCard != null) valueMap.put("giftCard", giftCard);
        } else if ("EFT_ACCOUNT".equals(paymentMethod.getString("paymentMethodTypeId"))) {
          GenericValue eftAccount = paymentMethod.getRelatedOne("EftAccount");
          if (eftAccount != null) valueMap.put("eftAccount", eftAccount);
        }
      }
    } catch (GenericEntityException e) {
      Debug.logWarning(e, module);
    }
    return paymentMethodValueMaps;
  }
  /**
   * Finds or creates a specialized (auto-save) shopping list used to record shopping bag contents
   * between user visits.
   */
  public static String getAutoSaveListId(
      Delegator delegator,
      LocalDispatcher dispatcher,
      String partyId,
      GenericValue userLogin,
      String productStoreId)
      throws GenericEntityException, GenericServiceException {
    if (partyId == null && userLogin != null) {
      partyId = userLogin.getString("partyId");
    }

    String autoSaveListId = null;
    GenericValue list = null;
    // TODO: add sorting, just in case there are multiple...
    if (partyId != null) {
      Map<String, Object> findMap =
          UtilMisc.<String, Object>toMap(
              "partyId",
              partyId,
              "productStoreId",
              productStoreId,
              "shoppingListTypeId",
              "SLT_SPEC_PURP",
              "listName",
              PERSISTANT_LIST_NAME);
      List<GenericValue> existingLists =
          EntityQuery.use(delegator).from("ShoppingList").where(findMap).queryList();
      Debug.logInfo(
          "Finding existing auto-save shopping list with:  \nfindMap: "
              + findMap
              + "\nlists: "
              + existingLists,
          module);

      if (UtilValidate.isNotEmpty(existingLists)) {
        list = EntityUtil.getFirst(existingLists);
        autoSaveListId = list.getString("shoppingListId");
      }
    }
    if (list == null && dispatcher != null) {
      Map<String, Object> listFields =
          UtilMisc.<String, Object>toMap(
              "userLogin",
              userLogin,
              "productStoreId",
              productStoreId,
              "shoppingListTypeId",
              "SLT_SPEC_PURP",
              "listName",
              PERSISTANT_LIST_NAME);
      Map<String, Object> newListResult = dispatcher.runSync("createShoppingList", listFields);

      if (newListResult != null) {
        autoSaveListId = (String) newListResult.get("shoppingListId");
      }
    }

    return autoSaveListId;
  }
  public static Map<String, Object> assignContactToAccount(
      DispatchContext dctx, Map<String, Object> context) {
    Delegator delegator = dctx.getDelegator();
    LocalDispatcher dispatcher = dctx.getDispatcher();
    Security security = dctx.getSecurity();
    GenericValue userLogin = (GenericValue) context.get("userLogin");
    Locale locale = UtilCommon.getLocale(context);

    String contactPartyId = (String) context.get("contactPartyId");
    String accountPartyId = (String) context.get("accountPartyId");

    try {
      // check if this contact is already a contact of this account
      EntityCondition searchConditions =
          EntityCondition.makeCondition(
              EntityOperator.AND,
              EntityCondition.makeCondition("partyIdFrom", EntityOperator.EQUALS, contactPartyId),
              EntityCondition.makeCondition("partyIdTo", EntityOperator.EQUALS, accountPartyId),
              EntityCondition.makeCondition("roleTypeIdFrom", EntityOperator.EQUALS, "CONTACT"),
              EntityCondition.makeCondition("roleTypeIdTo", EntityOperator.EQUALS, "ACCOUNT"),
              EntityCondition.makeCondition(
                  "partyRelationshipTypeId", EntityOperator.EQUALS, "CONTACT_REL_INV"),
              EntityUtil.getFilterByDateExpr());
      List<GenericValue> existingRelationships =
          delegator.findByCondition("PartyRelationship", searchConditions, null, null);
      if (existingRelationships.size() > 0) {
        return UtilMessage.createAndLogServiceError(
            "CrmErrorContactAlreadyAssociatedToAccount", locale, MODULE);
      }

      // check if userLogin has CRMSFA_ACCOUNT_UPDATE permission for this account
      if (!CrmsfaSecurity.hasPartyRelationSecurity(
          security, "CRMSFA_ACCOUNT", "_UPDATE", userLogin, accountPartyId)) {
        return UtilMessage.createAndLogServiceError("CrmErrorPermissionDenied", locale, MODULE);
      }
      // create the party relationship between the Contact and the Account
      PartyHelper.createNewPartyToRelationship(
          accountPartyId,
          contactPartyId,
          "CONTACT",
          "CONTACT_REL_INV",
          null,
          UtilMisc.toList("ACCOUNT"),
          false,
          userLogin,
          delegator,
          dispatcher);

    } catch (GenericServiceException e) {
      return UtilMessage.createAndLogServiceError(
          e, "CrmErrorAssignContactToAccountFail", locale, MODULE);
    } catch (GenericEntityException e) {
      return UtilMessage.createAndLogServiceError(
          e, "CrmErrorAssignContactToAccountFail", locale, MODULE);
    }
    return ServiceUtil.returnSuccess();
  }
 /**
  * Returns a complete category trail - can be used for exporting proper category trees. This is
  * mostly useful when used in combination with bread-crumbs, for building a faceted index tree, or
  * to export a category tree for migration to another system. Will create the tree from root point
  * to categoryId.
  *
  * <p>This method is not meant to be run on every request. Its best use is to generate the trail
  * every so often and store somewhere (a lucene/solr tree, entities, cache or so).
  *
  * @param productCategoryId id of category the trail should be generated for
  * @returns List organized trail from root point to categoryId.
  */
 public static Map getCategoryTrail(DispatchContext dctx, Map context) {
   String productCategoryId = (String) context.get("productCategoryId");
   Map<String, Object> results = ServiceUtil.returnSuccess();
   GenericDelegator delegator = (GenericDelegator) dctx.getDelegator();
   List<String> trailElements = FastList.newInstance();
   trailElements.add(productCategoryId);
   String parentProductCategoryId = productCategoryId;
   while (UtilValidate.isNotEmpty(parentProductCategoryId)) {
     // find product category rollup
     try {
       List<EntityCondition> rolllupConds = FastList.newInstance();
       rolllupConds.add(
           EntityCondition.makeCondition("productCategoryId", parentProductCategoryId));
       rolllupConds.add(EntityUtil.getFilterByDateExpr());
       List<GenericValue> productCategoryRollups =
           delegator.findList(
               "ProductCategoryRollup",
               EntityCondition.makeCondition(rolllupConds),
               null,
               UtilMisc.toList("sequenceNum"),
               null,
               true);
       if (UtilValidate.isNotEmpty(productCategoryRollups)) {
         // add only categories that belong to the top category to trail
         for (GenericValue productCategoryRollup : productCategoryRollups) {
           String trailCategoryId = productCategoryRollup.getString("parentProductCategoryId");
           parentProductCategoryId = trailCategoryId;
           if (trailElements.contains(trailCategoryId)) {
             break;
           } else {
             trailElements.add(trailCategoryId);
           }
         }
       } else {
         parentProductCategoryId = null;
       }
     } catch (GenericEntityException e) {
       Map<String, String> messageMap =
           UtilMisc.toMap("errMessage", ". Cannot generate trail from product category. ");
       String errMsg =
           UtilProperties.getMessage(
               "CommonUiLabels",
               "CommonDatabaseProblem",
               messageMap,
               (Locale) context.get("locale"));
       Debug.logError(e, errMsg, module);
       return ServiceUtil.returnError(errMsg);
     }
   }
   Collections.reverse(trailElements);
   results.put("trail", trailElements);
   return results;
 }
  /**
   * Retrieves a single user preference from persistent storage. Call with userPrefTypeId and
   * optional userPrefLoginId. If userPrefLoginId isn't specified, then the currently logged-in
   * user's userLoginId will be used. The retrieved preference is contained in the
   * <b>userPrefMap</b> element.
   *
   * @param ctx The DispatchContext that this service is operating in.
   * @param context Map containing the input arguments.
   * @return Map with the result of the service, the output parameters.
   */
  public static Map<String, Object> getUserPreference(DispatchContext ctx, Map<String, ?> context) {
    Locale locale = (Locale) context.get("locale");
    if (!PreferenceWorker.isValidGetId(ctx, context)) {
      return ServiceUtil.returnError(
          UtilProperties.getMessage(resource, "getPreference.permissionError", locale));
    }
    Delegator delegator = ctx.getDelegator();

    String userPrefTypeId = (String) context.get("userPrefTypeId");
    if (UtilValidate.isEmpty(userPrefTypeId)) {
      return ServiceUtil.returnError(
          UtilProperties.getMessage(resource, "getPreference.invalidArgument", locale));
    }
    String userLoginId = PreferenceWorker.getUserLoginId(context, true);
    Map<String, String> fieldMap =
        UtilMisc.toMap("userLoginId", userLoginId, "userPrefTypeId", userPrefTypeId);
    String userPrefGroupTypeId = (String) context.get("userPrefGroupTypeId");
    if (UtilValidate.isNotEmpty(userPrefGroupTypeId)) {
      fieldMap.put("userPrefGroupTypeId", userPrefGroupTypeId);
    }

    Map<String, Object> userPrefMap = null;
    try {
      GenericValue preference =
          EntityUtil.getFirst(delegator.findByAnd("UserPreference", fieldMap));
      if (preference != null) {
        userPrefMap = PreferenceWorker.createUserPrefMap(preference);
      }
    } catch (GenericEntityException e) {
      Debug.logWarning(e.getMessage(), module);
      return ServiceUtil.returnError(
          UtilProperties.getMessage(
              resource, "getPreference.readFailure", new Object[] {e.getMessage()}, locale));
    } catch (GeneralException e) {
      Debug.logWarning(e.getMessage(), module);
      return ServiceUtil.returnError(
          UtilProperties.getMessage(
              resource, "getPreference.readFailure", new Object[] {e.getMessage()}, locale));
    }

    Map<String, Object> result = ServiceUtil.returnSuccess();
    result.put("userPrefMap", userPrefMap);
    if (userPrefMap != null) {
      // Put the value in the result Map too, makes access easier for calling methods.
      Object userPrefValue = userPrefMap.get(userPrefTypeId);
      if (userPrefValue != null) {
        result.put("userPrefValue", userPrefValue);
      }
    }
    return result;
  }
Beispiel #11
0
 public static GenericValue findPartyLatestContactMech(
     String partyId, String contactMechTypeId, Delegator delegator) {
   try {
     List<GenericValue> cmList =
         delegator.findByAnd(
             "PartyAndContactMech",
             UtilMisc.toMap("partyId", partyId, "contactMechTypeId", contactMechTypeId),
             UtilMisc.toList("-fromDate"));
     cmList = EntityUtil.filterByDate(cmList);
     return EntityUtil.getFirst(cmList);
   } catch (GenericEntityException e) {
     Debug.logError(
         e,
         "Error while finding latest ContactMech for party with ID ["
             + partyId
             + "] TYPE ["
             + contactMechTypeId
             + "]: "
             + e.toString(),
         module);
     return null;
   }
 }
  public static Map<String, Object> reassignContactResponsibleParty(
      DispatchContext dctx, Map<String, Object> context) {
    Delegator delegator = dctx.getDelegator();
    LocalDispatcher dispatcher = dctx.getDispatcher();
    Security security = dctx.getSecurity();
    GenericValue userLogin = (GenericValue) context.get("userLogin");
    Locale locale = UtilCommon.getLocale(context);

    String contactPartyId = (String) context.get("contactPartyId");
    String newPartyId = (String) context.get("newPartyId");

    // ensure reassign permission on this contact
    if (!CrmsfaSecurity.hasPartyRelationSecurity(
        security, "CRMSFA_CONTACT", "_REASSIGN", userLogin, contactPartyId)) {
      return UtilMessage.createAndLogServiceError("CrmErrorPermissionDenied", locale, MODULE);
    }
    try {
      // we need to expire all the active ASSIGNED_TO relationships from the contact party to the
      // new owner party
      List<GenericValue> activeAssignedToRelationships =
          EntityUtil.filterByDate(
              delegator.findByAnd(
                  "PartyRelationship",
                  UtilMisc.toMap(
                      "partyIdFrom",
                      contactPartyId,
                      "roleTypeIdFrom",
                      "CONTACT",
                      "partyIdTo",
                      newPartyId,
                      "partyRelationshipTypeId",
                      "ASSIGNED_TO")));
      PartyHelper.expirePartyRelationships(
          activeAssignedToRelationships, UtilDateTime.nowTimestamp(), dispatcher, userLogin);

      // reassign relationship using a helper method
      boolean result =
          createResponsibleContactRelationshipForParty(
              newPartyId, contactPartyId, userLogin, delegator, dispatcher);
      if (!result) {
        return UtilMessage.createAndLogServiceError("CrmErrorReassignFail", locale, MODULE);
      }
    } catch (GenericServiceException e) {
      return UtilMessage.createAndLogServiceError(e, "CrmErrorReassignFail", locale, MODULE);
    } catch (GenericEntityException e) {
      return UtilMessage.createAndLogServiceError(e, "CrmErrorReassignFail", locale, MODULE);
    }
    return ServiceUtil.returnSuccess();
  }
Beispiel #13
0
  public static void setRequestAttributes(
      ServletRequest request, Delegator delegator, ServletContext servletContext) {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    // check if multi tenant is enabled
    boolean useMultitenant = EntityUtil.isMultiTenantEnabled();
    if (useMultitenant) {
      // get tenant delegator by domain name
      String serverName = request.getServerName();
      try {
        // if tenant was specified, replace delegator with the new per-tenant delegator and set
        // tenantId to session attribute
        delegator = getDelegator(servletContext);

        // Use base delegator for fetching data from entity of entityGroup org.ofbiz.tenant
        Delegator baseDelegator = DelegatorFactory.getDelegator(delegator.getDelegatorBaseName());
        GenericValue tenantDomainName =
            EntityQuery.use(baseDelegator)
                .from("TenantDomainName")
                .where("domainName", serverName)
                .queryOne();

        if (UtilValidate.isNotEmpty(tenantDomainName)) {
          String tenantId = tenantDomainName.getString("tenantId");
          // make that tenant active, setup a new delegator and a new dispatcher
          String tenantDelegatorName = delegator.getDelegatorBaseName() + "#" + tenantId;
          httpRequest.getSession().setAttribute("delegatorName", tenantDelegatorName);

          // after this line the delegator is replaced with the new per-tenant delegator
          delegator = DelegatorFactory.getDelegator(tenantDelegatorName);
          servletContext.setAttribute("delegator", delegator);
        }

      } catch (GenericEntityException e) {
        Debug.logWarning(e, "Unable to get Tenant", module);
      }
    }

    // set the web context in the request for future use
    request.setAttribute("servletContext", httpRequest.getSession().getServletContext());
    request.setAttribute("delegator", delegator);

    // set the webSiteId in the session
    if (UtilValidate.isEmpty(httpRequest.getSession().getAttribute("webSiteId"))) {
      httpRequest
          .getSession()
          .setAttribute(
              "webSiteId", httpRequest.getSession().getServletContext().getAttribute("webSiteId"));
    }
  }
Beispiel #14
0
 /** Checks if the given party with role is unassigned. */
 public static boolean isUnassigned(Delegator delegator, String partyId, String roleTypeId)
     throws GenericEntityException {
   List<GenericValue> activeRelationships =
       EntityUtil.filterByDate(
           delegator.findByAnd(
               "PartyRelationship",
               UtilMisc.toMap(
                   "partyIdFrom",
                   partyId,
                   "roleTypeIdFrom",
                   roleTypeId,
                   "partyRelationshipTypeId",
                   "ASSIGNED_TO")));
   return activeRelationships.size() == 0;
 }
Beispiel #15
0
 /**
  * Find the active ASSIGNED_TO party relationships with given From and To party IDs, and the role
  * type ID of From party such as 'CONTACT'.
  *
  * @param delegator a Delegator instance
  * @param partyIdFrom a String object that represents the From party ID
  * @param roleTypeIdFrom a String object that represents the role type ID of From party
  * @param partyIdTo a String object that represents the To party ID
  * @return a List of GenericValue objects
  */
 public static List<GenericValue> findActiveAssignedToPartyRelationships(
     final Delegator delegator,
     final String partyIdFrom,
     final String roleTypeIdFrom,
     final String partyIdTo)
     throws GenericEntityException {
   EntityCondition conditions =
       EntityCondition.makeCondition(
           EntityOperator.AND,
           EntityCondition.makeCondition("partyIdFrom", partyIdFrom),
           EntityCondition.makeCondition("roleTypeIdFrom", roleTypeIdFrom),
           EntityCondition.makeCondition("partyIdTo", partyIdTo),
           EntityCondition.makeCondition("partyRelationshipTypeId", "ASSIGNED_TO"),
           EntityUtil.getFilterByDateExpr());
   return delegator.findByCondition("PartyRelationship", conditions, null, null);
 }
Beispiel #16
0
 public static GenericValue findPartyLatestUserLogin(String partyId, Delegator delegator) {
   try {
     List<GenericValue> userLoginList =
         delegator.findByAnd(
             "UserLogin",
             UtilMisc.toMap("partyId", partyId),
             UtilMisc.toList("-" + ModelEntity.STAMP_FIELD));
     return EntityUtil.getFirst(userLoginList);
   } catch (GenericEntityException e) {
     Debug.logError(
         e,
         "Error while finding latest UserLogin for party with ID ["
             + partyId
             + "]: "
             + e.toString(),
         module);
     return null;
   }
 }
 private boolean evalRoleMember(GenericValue userLogin) {
   if (nameOrRole == null) {
     Debug.logWarning("Null role type name passed for evaluation", module);
     return false;
   }
   List<GenericValue> partyRoles = null;
   /**
    * (jaz) THIS IS NOT SECURE AT ALL try { partyRoles = delegator.findByAnd("PartyRole",
    * "roleTypeId", nameOrRole, "partyId", userLogin.get("partyId")); } catch
    * (GenericEntityException e) { Debug.logError(e, "Unable to lookup PartyRole records", module);
    * }
    */
   if (UtilValidate.isNotEmpty(partyRoles)) {
     partyRoles = EntityUtil.filterByDate(partyRoles);
     if (UtilValidate.isNotEmpty(partyRoles)) {
       return true;
     }
   }
   return false;
 }
Beispiel #18
0
 public static List<String> getAssociatedPartyIdsByRelationshipType(
     Delegator delegator, String partyIdFrom, String partyRelationshipTypeId) {
   List<GenericValue> partyList = FastList.newInstance();
   List<String> partyIds = null;
   try {
     EntityConditionList<EntityExpr> baseExprs =
         EntityCondition.makeCondition(
             UtilMisc.toList(
                 EntityCondition.makeCondition("partyIdFrom", partyIdFrom),
                 EntityCondition.makeCondition(
                     "partyRelationshipTypeId", partyRelationshipTypeId)),
             EntityOperator.AND);
     List<GenericValue> associatedParties =
         delegator.findList("PartyRelationship", baseExprs, null, null, null, true);
     partyList.addAll(associatedParties);
     while (UtilValidate.isNotEmpty(associatedParties)) {
       List<GenericValue> currentAssociatedParties = FastList.newInstance();
       for (GenericValue associatedParty : associatedParties) {
         EntityConditionList<EntityExpr> innerExprs =
             EntityCondition.makeCondition(
                 UtilMisc.toList(
                     EntityCondition.makeCondition(
                         "partyIdFrom", associatedParty.get("partyIdTo")),
                     EntityCondition.makeCondition(
                         "partyRelationshipTypeId", partyRelationshipTypeId)),
                 EntityOperator.AND);
         List<GenericValue> associatedPartiesChilds =
             delegator.findList("PartyRelationship", innerExprs, null, null, null, true);
         if (UtilValidate.isNotEmpty(associatedPartiesChilds)) {
           currentAssociatedParties.addAll(associatedPartiesChilds);
         }
         partyList.add(associatedParty);
       }
       associatedParties = currentAssociatedParties;
     }
     partyIds = EntityUtil.getFieldListFromEntityList(partyList, "partyIdTo", true);
   } catch (GenericEntityException e) {
     Debug.logWarning(e, module);
   }
   return partyIds;
 }
Beispiel #19
0
 public static Timestamp findPartyLastLoginTime(String partyId, Delegator delegator) {
   try {
     List<GenericValue> loginHistory =
         delegator.findByAnd(
             "UserLoginHistory", UtilMisc.toMap("partyId", partyId), UtilMisc.toList("-fromDate"));
     GenericValue v = EntityUtil.getFirst(loginHistory);
     if (v != null) {
       return v.getTimestamp("fromDate");
     } else {
       return null;
     }
   } catch (GenericEntityException e) {
     Debug.logError(
         e,
         "Error while finding latest login time for party with ID ["
             + partyId
             + "]: "
             + e.toString(),
         module);
     return null;
   }
 }
  public static List<GenericValue> getRelatedCategoriesRet(
      Delegator delegator,
      String attributeName,
      String parentId,
      boolean limitView,
      boolean excludeEmpty,
      boolean recursive) {
    List<GenericValue> categories = FastList.newInstance();

    if (Debug.verboseOn())
      Debug.logVerbose("[CategoryWorker.getRelatedCategories] ParentID: " + parentId, module);

    List<GenericValue> rollups = null;

    try {
      rollups =
          delegator.findByAndCache(
              "ProductCategoryRollup",
              UtilMisc.toMap("parentProductCategoryId", parentId),
              UtilMisc.toList("sequenceNum"));
      if (limitView) {
        rollups = EntityUtil.filterByDate(rollups, true);
      }
    } catch (GenericEntityException e) {
      Debug.logWarning(e.getMessage(), module);
    }
    if (rollups != null) {
      // Debug.logInfo("Rollup size: " + rollups.size(), module);
      for (GenericValue parent : rollups) {
        // Debug.logInfo("Adding child of: " + parent.getString("parentProductCategoryId"), module);
        GenericValue cv = null;

        try {
          cv = parent.getRelatedOneCache("CurrentProductCategory");
        } catch (GenericEntityException e) {
          Debug.logWarning(e.getMessage(), module);
        }
        if (cv != null) {
          if (excludeEmpty) {
            if (!isCategoryEmpty(cv)) {
              // Debug.logInfo("Child : " + cv.getString("productCategoryId") + " is not empty.",
              // module);
              categories.add(cv);
              if (recursive) {
                categories.addAll(
                    getRelatedCategoriesRet(
                        delegator,
                        attributeName,
                        cv.getString("productCategoryId"),
                        limitView,
                        excludeEmpty,
                        recursive));
              }
            }
          } else {
            categories.add(cv);
            if (recursive) {
              categories.addAll(
                  getRelatedCategoriesRet(
                      delegator,
                      attributeName,
                      cv.getString("productCategoryId"),
                      limitView,
                      excludeEmpty,
                      recursive));
            }
          }
        }
      }
    }
    return categories;
  }
Beispiel #21
0
  public static Map<String, Object> assembleCrmsfaShipmentFormMergeContext(
      Delegator delegator,
      String orderId,
      String shipGroupSeqId,
      String shipmentId,
      Locale locale) {
    Map<String, Object> templateContext = new HashMap<String, Object>();

    try {

      // Prefer shipment data if shipmentId is provided
      if (UtilValidate.isNotEmpty(shipmentId)) {

        GenericValue shipment =
            delegator.findByPrimaryKey("Shipment", UtilMisc.toMap("shipmentId", shipmentId));
        if (UtilValidate.isNotEmpty(shipment)) {

          GenericValue shipLoc = shipment.getRelatedOne("DestinationPostalAddress");
          if (UtilValidate.isNotEmpty(shipLoc)) {
            templateContext.put("orderShippingAddress1", shipLoc.get("address1"));
            templateContext.put("orderShippingAddress2", shipLoc.get("address2"));
            templateContext.put("orderShippingCity", shipLoc.get("city"));
            templateContext.put("orderShippingPostalCode", shipLoc.get("postalCode"));

            GenericValue stateProvGeo = shipLoc.getRelatedOne("StateProvinceGeo");
            if (UtilValidate.isNotEmpty(stateProvGeo)) {
              templateContext.put("orderShippingStateProvince", stateProvGeo.get("geoName"));
            }
            GenericValue countryGeo = shipLoc.getRelatedOne("CountryGeo");
            if (UtilValidate.isNotEmpty(countryGeo)) {
              templateContext.put("orderShippingCountry", countryGeo.get("geoName"));
            }
          }

          GenericValue phoneNumber = shipment.getRelatedOne("DestinationTelecomNumber");
          if (UtilValidate.isNotEmpty(phoneNumber)) {

            String phoneNumberString =
                UtilValidate.isEmpty(phoneNumber.getString("countryCode"))
                    ? ""
                    : phoneNumber.getString("countryCode") + " ";
            if (UtilValidate.isNotEmpty(phoneNumber.getString("areaCode"))) {
              phoneNumberString += phoneNumber.getString("areaCode") + " ";
            }
            if (UtilValidate.isNotEmpty(phoneNumber.getString("contactNumber"))) {
              phoneNumberString += phoneNumber.getString("contactNumber");
            }
            templateContext.put("orderShippingPhone", phoneNumberString);
          }

          GenericValue statusItem = shipment.getRelatedOne("StatusItem");
          if (UtilValidate.isNotEmpty(statusItem)) {
            templateContext.put("shipmentStatus", statusItem.get("description", locale));
          }
        }

      } else if (UtilValidate.isNotEmpty(orderId)) {

        OrderReadHelper orh = new OrderReadHelper(delegator, orderId);
        GenericValue shipGroup = orh.getOrderItemShipGroup(shipGroupSeqId);
        if (UtilValidate.isEmpty(shipGroup)) {

          // Default to the first ship group if no shipGroupSeqId is provided
          List shipGroups = orh.getOrderItemShipGroups();
          if (UtilValidate.isNotEmpty(shipGroups)) {
            shipGroup = (GenericValue) shipGroups.get(0);
          }
        }

        if (UtilValidate.isNotEmpty(shipGroup)) {
          GenericValue shipLoc = shipGroup.getRelatedOne("PostalAddress");
          if (UtilValidate.isNotEmpty(shipLoc)) {
            templateContext.put("orderShippingAddress1", shipLoc.get("address1"));
            templateContext.put("orderShippingAddress2", shipLoc.get("address2"));
            templateContext.put("orderShippingCity", shipLoc.get("city"));
            templateContext.put("orderShippingPostalCode", shipLoc.get("postalCode"));

            GenericValue stateProvGeo = shipLoc.getRelatedOne("StateProvinceGeo");
            if (UtilValidate.isNotEmpty(stateProvGeo)) {
              templateContext.put("orderShippingStateProvince", stateProvGeo.get("geoName"));
            }
            GenericValue countryGeo = shipLoc.getRelatedOne("CountryGeo");
            if (UtilValidate.isNotEmpty(countryGeo)) {
              templateContext.put("orderShippingCountry", countryGeo.get("geoName"));
            }
          }

          GenericValue phoneNumber = shipGroup.getRelatedOne("TelecomTelecomNumber");
          if (UtilValidate.isNotEmpty(phoneNumber)) {

            String phoneNumberString =
                UtilValidate.isEmpty(phoneNumber.getString("countryCode"))
                    ? ""
                    : phoneNumber.getString("countryCode") + " ";
            if (UtilValidate.isNotEmpty(phoneNumber.getString("areaCode"))) {
              phoneNumberString += phoneNumber.getString("areaCode") + " ";
            }
            if (UtilValidate.isNotEmpty(phoneNumber.getString("contactNumber"))) {
              phoneNumberString += phoneNumber.getString("contactNumber");
            }
            templateContext.put("orderShippingPhone", phoneNumberString);
          }

          // Find any shipments relating to this ship group
          List<GenericValue> shipments =
              delegator.findByAnd(
                  "Shipment",
                  UtilMisc.toMap(
                      "primaryOrderId",
                      orderId,
                      "primaryShipGroupSeqId",
                      shipGroup.getString("shipGroupSeqId")),
                  UtilMisc.toList("createdStamp DESC"));
          GenericValue shipment = EntityUtil.getFirst(shipments);
          if (UtilValidate.isNotEmpty(shipment)) {
            GenericValue statusItem = shipment.getRelatedOne("StatusItem");
            if (UtilValidate.isNotEmpty(statusItem)) {
              templateContext.put("shipmentStatus", statusItem.get("description", locale));
            }
          }
        }
      }
    } catch (GenericEntityException e) {
      Debug.logError(e, MODULE);
    }
    return templateContext;
  }
Beispiel #22
0
  public static void indexKeywords(GenericValue product, boolean doAll)
      throws GenericEntityException {
    if (product == null) return;
    Timestamp nowTimestamp = UtilDateTime.nowTimestamp();

    if (!doAll) {
      if ("N".equals(product.getString("autoCreateKeywords"))) {
        return;
      }
      if ("Y".equals(product.getString("isVariant"))
          && "true"
              .equals(UtilProperties.getPropertyValue("prodsearch", "index.ignore.variants"))) {
        return;
      }
      Timestamp salesDiscontinuationDate = product.getTimestamp("salesDiscontinuationDate");
      if (salesDiscontinuationDate != null
          && salesDiscontinuationDate.before(nowTimestamp)
          && "true"
              .equals(
                  UtilProperties.getPropertyValue(
                      "prodsearch", "index.ignore.discontinued.sales"))) {
        return;
      }
    }

    Delegator delegator = product.getDelegator();
    if (delegator == null) return;
    String productId = product.getString("productId");

    // get these in advance just once since they will be used many times for the multiple strings to
    // index
    String separators = KeywordSearchUtil.getSeparators();
    String stopWordBagOr = KeywordSearchUtil.getStopWordBagOr();
    String stopWordBagAnd = KeywordSearchUtil.getStopWordBagAnd();
    boolean removeStems = KeywordSearchUtil.getRemoveStems();
    Set<String> stemSet = KeywordSearchUtil.getStemSet();

    Map<String, Long> keywords = new TreeMap<String, Long>();
    List<String> strings = FastList.newInstance();

    int pidWeight = 1;
    try {
      pidWeight =
          Integer.parseInt(
              UtilProperties.getPropertyValue("prodsearch", "index.weight.Product.productId", "0"));
    } catch (Exception e) {
      Debug.logWarning("Could not parse weight number: " + e.toString(), module);
    }
    keywords.put(product.getString("productId").toLowerCase(), Long.valueOf(pidWeight));

    // Product fields - default is 0 if not found in the properties file
    if (!"0"
        .equals(
            UtilProperties.getPropertyValue(
                "prodsearch", "index.weight.Product.productName", "0"))) {
      addWeightedKeywordSourceString(product, "productName", strings);
    }
    if (!"0"
        .equals(
            UtilProperties.getPropertyValue(
                "prodsearch", "index.weight.Product.internalName", "0"))) {
      addWeightedKeywordSourceString(product, "internalName", strings);
    }
    if (!"0"
        .equals(
            UtilProperties.getPropertyValue("prodsearch", "index.weight.Product.brandName", "0"))) {
      addWeightedKeywordSourceString(product, "brandName", strings);
    }
    if (!"0"
        .equals(
            UtilProperties.getPropertyValue(
                "prodsearch", "index.weight.Product.description", "0"))) {
      addWeightedKeywordSourceString(product, "description", strings);
    }
    if (!"0"
        .equals(
            UtilProperties.getPropertyValue(
                "prodsearch", "index.weight.Product.longDescription", "0"))) {
      addWeightedKeywordSourceString(product, "longDescription", strings);
    }

    // ProductFeatureAppl
    if (!"0"
            .equals(
                UtilProperties.getPropertyValue(
                    "prodsearch", "index.weight.ProductFeatureAndAppl.description", "0"))
        || !"0"
            .equals(
                UtilProperties.getPropertyValue(
                    "prodsearch", "index.weight.ProductFeatureAndAppl.abbrev", "0"))
        || !"0"
            .equals(
                UtilProperties.getPropertyValue(
                    "prodsearch", "index.weight.ProductFeatureAndAppl.idCode", "0"))) {
      // get strings from attributes and features
      List<GenericValue> productFeatureAndAppls =
          delegator.findByAnd("ProductFeatureAndAppl", UtilMisc.toMap("productId", productId));
      for (GenericValue productFeatureAndAppl : productFeatureAndAppls) {
        addWeightedKeywordSourceString(productFeatureAndAppl, "description", strings);
        addWeightedKeywordSourceString(productFeatureAndAppl, "abbrev", strings);
        addWeightedKeywordSourceString(productFeatureAndAppl, "idCode", strings);
      }
    }

    // ProductAttribute
    if (!"0"
            .equals(
                UtilProperties.getPropertyValue(
                    "prodsearch", "index.weight.ProductAttribute.attrName", "0"))
        || !"0"
            .equals(
                UtilProperties.getPropertyValue(
                    "prodsearch", "index.weight.ProductAttribute.attrValue", "0"))) {
      List<GenericValue> productAttributes =
          delegator.findByAnd("ProductAttribute", UtilMisc.toMap("productId", productId));
      for (GenericValue productAttribute : productAttributes) {
        addWeightedKeywordSourceString(productAttribute, "attrName", strings);
        addWeightedKeywordSourceString(productAttribute, "attrValue", strings);
      }
    }

    // GoodIdentification
    if (!"0"
        .equals(
            UtilProperties.getPropertyValue(
                "prodsearch", "index.weight.GoodIdentification.idValue", "0"))) {
      List<GenericValue> goodIdentifications =
          delegator.findByAnd("GoodIdentification", UtilMisc.toMap("productId", productId));
      for (GenericValue goodIdentification : goodIdentifications) {
        addWeightedKeywordSourceString(goodIdentification, "idValue", strings);
      }
    }

    // Variant Product IDs
    if ("Y".equals(product.getString("isVirtual"))) {
      if (!"0"
          .equals(
              UtilProperties.getPropertyValue(
                  "prodsearch", "index.weight.Variant.Product.productId", "0"))) {
        List<GenericValue> variantProductAssocs =
            delegator.findByAnd(
                "ProductAssoc",
                UtilMisc.toMap("productId", productId, "productAssocTypeId", "PRODUCT_VARIANT"));
        variantProductAssocs = EntityUtil.filterByDate(variantProductAssocs);
        for (GenericValue variantProductAssoc : variantProductAssocs) {
          int weight = 1;
          try {
            weight =
                Integer.parseInt(
                    UtilProperties.getPropertyValue(
                        "prodsearch", "index.weight.Variant.Product.productId", "0"));
          } catch (Exception e) {
            Debug.logWarning("Could not parse weight number: " + e.toString(), module);
          }
          for (int i = 0; i < weight; i++) {
            strings.add(variantProductAssoc.getString("productIdTo"));
          }
        }
      }
    }

    String productContentTypes =
        UtilProperties.getPropertyValue("prodsearch", "index.include.ProductContentTypes");
    for (String productContentTypeId : productContentTypes.split(",")) {
      int weight = 1;
      try {
        // this is defaulting to a weight of 1 because you specified you wanted to index this type
        weight =
            Integer.parseInt(
                UtilProperties.getPropertyValue(
                    "prodsearch", "index.weight.ProductContent." + productContentTypeId, "1"));
      } catch (Exception e) {
        Debug.logWarning("Could not parse weight number: " + e.toString(), module);
      }

      List<GenericValue> productContentAndInfos =
          delegator.findByAnd(
              "ProductContentAndInfo",
              UtilMisc.toMap("productId", productId, "productContentTypeId", productContentTypeId),
              null);
      for (GenericValue productContentAndInfo : productContentAndInfos) {
        addWeightedDataResourceString(productContentAndInfo, weight, strings, delegator, product);

        List<GenericValue> alternateViews =
            productContentAndInfo.getRelated(
                "ContentAssocDataResourceViewTo",
                UtilMisc.toMap("caContentAssocTypeId", "ALTERNATE_LOCALE"),
                UtilMisc.toList("-caFromDate"));
        alternateViews =
            EntityUtil.filterByDate(
                alternateViews, UtilDateTime.nowTimestamp(), "caFromDate", "caThruDate", true);
        for (GenericValue thisView : alternateViews) {
          addWeightedDataResourceString(thisView, weight, strings, delegator, product);
        }
      }
    }
    if (UtilValidate.isNotEmpty(strings)) {
      for (String str : strings) {
        // call process keywords method here
        KeywordSearchUtil.processKeywordsForIndex(
            str, keywords, separators, stopWordBagAnd, stopWordBagOr, removeStems, stemSet);
      }
    }

    List<GenericValue> toBeStored = FastList.newInstance();
    int keywordMaxLength =
        Integer.parseInt(
            UtilProperties.getPropertyValue("prodsearch", "product.keyword.max.length"));
    for (Map.Entry<String, Long> entry : keywords.entrySet()) {
      if (entry.getKey().length() <= keywordMaxLength) {
        GenericValue productKeyword =
            delegator.makeValue(
                "ProductKeyword",
                UtilMisc.toMap(
                    "productId",
                    product.getString("productId"),
                    "keyword",
                    entry.getKey(),
                    "keywordTypeId",
                    "KWT_KEYWORD",
                    "relevancyWeight",
                    entry.getValue()));
        toBeStored.add(productKeyword);
      }
    }
    if (toBeStored.size() > 0) {
      if (Debug.verboseOn())
        Debug.logVerbose(
            "[KeywordIndex.indexKeywords] Storing "
                + toBeStored.size()
                + " keywords for productId "
                + product.getString("productId"),
            module);

      if ("true"
          .equals(
              UtilProperties.getPropertyValue("prodsearch", "index.delete.on_index", "false"))) {
        // delete all keywords if the properties file says to
        delegator.removeByAnd(
            "ProductKeyword", UtilMisc.toMap("productId", product.getString("productId")));
      }

      delegator.storeAll(toBeStored);
    }
  }
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
      throws IOException, ServletException {
    HttpServletRequest httpRequest = (HttpServletRequest) request;
    HttpServletResponse httpResponse = (HttpServletResponse) response;
    Delegator delegator =
        (Delegator) httpRequest.getSession().getServletContext().getAttribute("delegator");

    // Get ServletContext
    ServletContext servletContext = config.getServletContext();

    ContextFilter.setCharacterEncoding(request);

    // Set request attribute and session
    UrlServletHelper.setRequestAttributes(request, delegator, servletContext);

    // set initial parameters
    String initDefaultLocalesString = config.getInitParameter("defaultLocaleString");
    String initRedirectUrl = config.getInitParameter("redirectUrl");
    defaultLocaleString =
        UtilValidate.isNotEmpty(initDefaultLocalesString) ? initDefaultLocalesString : "";
    redirectUrl = UtilValidate.isNotEmpty(initRedirectUrl) ? initRedirectUrl : "";

    String pathInfo = httpRequest.getServletPath();
    if (UtilValidate.isNotEmpty(pathInfo)) {
      List<String> pathElements = StringUtil.split(pathInfo, "/");
      String alternativeUrl = pathElements.get(0);

      String productId = null;
      String productCategoryId = null;
      String urlContentId = null;
      try {
        // look for productId
        if (alternativeUrl.endsWith("-p")) {
          List<EntityCondition> productContentConds = FastList.newInstance();
          productContentConds.add(
              EntityCondition.makeCondition("productContentTypeId", "ALTERNATIVE_URL"));
          productContentConds.add(EntityUtil.getFilterByDateExpr());
          List<GenericValue> productContentInfos =
              EntityQuery.use(delegator)
                  .from("ProductContentAndInfo")
                  .where(productContentConds)
                  .orderBy("-fromDate")
                  .cache(true)
                  .queryList();
          if (UtilValidate.isNotEmpty(productContentInfos)) {
            for (GenericValue productContentInfo : productContentInfos) {
              String contentId = (String) productContentInfo.get("contentId");
              List<GenericValue> ContentAssocDataResourceViewTos =
                  EntityQuery.use(delegator)
                      .from("ContentAssocDataResourceViewTo")
                      .where(
                          "contentIdStart",
                          contentId,
                          "caContentAssocTypeId",
                          "ALTERNATE_LOCALE",
                          "drDataResourceTypeId",
                          "ELECTRONIC_TEXT")
                      .cache(true)
                      .queryList();
              if (UtilValidate.isNotEmpty(ContentAssocDataResourceViewTos)) {
                for (GenericValue ContentAssocDataResourceViewTo :
                    ContentAssocDataResourceViewTos) {
                  GenericValue ElectronicText =
                      ContentAssocDataResourceViewTo.getRelatedOne("ElectronicText", true);
                  if (UtilValidate.isNotEmpty(ElectronicText)) {
                    String textData = (String) ElectronicText.get("textData");
                    textData = UrlServletHelper.invalidCharacter(textData);
                    if (alternativeUrl.matches(textData + ".+$")) {
                      String productIdStr = null;
                      productIdStr = alternativeUrl.replace(textData + "-", "");
                      productIdStr = productIdStr.replace("-p", "");
                      String checkProductId = (String) productContentInfo.get("productId");
                      if (productIdStr.equalsIgnoreCase(checkProductId)) {
                        productId = checkProductId;
                        break;
                      }
                    }
                  }
                }
              }
              if (UtilValidate.isEmpty(productId)) {
                List<GenericValue> contentDataResourceViews =
                    EntityQuery.use(delegator)
                        .from("ContentDataResourceView")
                        .where("contentId", contentId, "drDataResourceTypeId", "ELECTRONIC_TEXT")
                        .cache(true)
                        .queryList();
                for (GenericValue contentDataResourceView : contentDataResourceViews) {
                  GenericValue ElectronicText =
                      contentDataResourceView.getRelatedOne("ElectronicText", true);
                  if (UtilValidate.isNotEmpty(ElectronicText)) {
                    String textData = (String) ElectronicText.get("textData");
                    if (UtilValidate.isNotEmpty(textData)) {
                      textData = UrlServletHelper.invalidCharacter(textData);
                      if (alternativeUrl.matches(textData + ".+$")) {
                        String productIdStr = null;
                        productIdStr = alternativeUrl.replace(textData + "-", "");
                        productIdStr = productIdStr.replace("-p", "");
                        String checkProductId = (String) productContentInfo.get("productId");
                        if (productIdStr.equalsIgnoreCase(checkProductId)) {
                          productId = checkProductId;
                          break;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }

        // look for productCategoryId
        if (alternativeUrl.endsWith("-c")) {
          List<EntityCondition> productCategoryContentConds = FastList.newInstance();
          productCategoryContentConds.add(
              EntityCondition.makeCondition("prodCatContentTypeId", "ALTERNATIVE_URL"));
          productCategoryContentConds.add(EntityUtil.getFilterByDateExpr());
          List<GenericValue> productCategoryContentInfos =
              EntityQuery.use(delegator)
                  .from("ProductCategoryContentAndInfo")
                  .where(productCategoryContentConds)
                  .orderBy("-fromDate")
                  .cache(true)
                  .queryList();
          if (UtilValidate.isNotEmpty(productCategoryContentInfos)) {
            for (GenericValue productCategoryContentInfo : productCategoryContentInfos) {
              String contentId = (String) productCategoryContentInfo.get("contentId");
              List<GenericValue> ContentAssocDataResourceViewTos =
                  EntityQuery.use(delegator)
                      .from("ContentAssocDataResourceViewTo")
                      .where(
                          "contentIdStart",
                          contentId,
                          "caContentAssocTypeId",
                          "ALTERNATE_LOCALE",
                          "drDataResourceTypeId",
                          "ELECTRONIC_TEXT")
                      .cache(true)
                      .queryList();
              if (UtilValidate.isNotEmpty(ContentAssocDataResourceViewTos)) {
                for (GenericValue ContentAssocDataResourceViewTo :
                    ContentAssocDataResourceViewTos) {
                  GenericValue ElectronicText =
                      ContentAssocDataResourceViewTo.getRelatedOne("ElectronicText", true);
                  if (UtilValidate.isNotEmpty(ElectronicText)) {
                    String textData = (String) ElectronicText.get("textData");
                    if (UtilValidate.isNotEmpty(textData)) {
                      textData = UrlServletHelper.invalidCharacter(textData);
                      if (alternativeUrl.matches(textData + ".+$")) {
                        String productCategoryStr = null;
                        productCategoryStr = alternativeUrl.replace(textData + "-", "");
                        productCategoryStr = productCategoryStr.replace("-c", "");
                        String checkProductCategoryId =
                            (String) productCategoryContentInfo.get("productCategoryId");
                        if (productCategoryStr.equalsIgnoreCase(checkProductCategoryId)) {
                          productCategoryId = checkProductCategoryId;
                          break;
                        }
                      }
                    }
                  }
                }
              }
              if (UtilValidate.isEmpty(productCategoryId)) {
                List<GenericValue> contentDataResourceViews =
                    EntityQuery.use(delegator)
                        .from("ContentDataResourceView")
                        .where("contentId", contentId, "drDataResourceTypeId", "ELECTRONIC_TEXT")
                        .cache(true)
                        .queryList();
                for (GenericValue contentDataResourceView : contentDataResourceViews) {
                  GenericValue ElectronicText =
                      contentDataResourceView.getRelatedOne("ElectronicText", true);
                  if (UtilValidate.isNotEmpty(ElectronicText)) {
                    String textData = (String) ElectronicText.get("textData");
                    if (UtilValidate.isNotEmpty(textData)) {
                      textData = UrlServletHelper.invalidCharacter(textData);
                      if (alternativeUrl.matches(textData + ".+$")) {
                        String productCategoryStr = null;
                        productCategoryStr = alternativeUrl.replace(textData + "-", "");
                        productCategoryStr = productCategoryStr.replace("-c", "");
                        String checkProductCategoryId =
                            (String) productCategoryContentInfo.get("productCategoryId");
                        if (productCategoryStr.equalsIgnoreCase(checkProductCategoryId)) {
                          productCategoryId = checkProductCategoryId;
                          break;
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }

      } catch (GenericEntityException e) {
        Debug.logWarning("Cannot look for product and product category", module);
      }

      // generate forward URL
      StringBuilder urlBuilder = new StringBuilder();
      urlBuilder.append("/" + CONTROL_MOUNT_POINT);

      if (UtilValidate.isNotEmpty(productId)) {
        try {
          List<EntityCondition> conds = FastList.newInstance();
          conds.add(EntityCondition.makeCondition("productId", productId));
          conds.add(EntityUtil.getFilterByDateExpr());
          List<GenericValue> productCategoryMembers =
              EntityQuery.use(delegator)
                  .select("productCategoryId")
                  .from("ProductCategoryMember")
                  .where(conds)
                  .orderBy("-fromDate")
                  .cache(true)
                  .queryList();
          if (UtilValidate.isNotEmpty(productCategoryMembers)) {
            GenericValue productCategoryMember = EntityUtil.getFirst(productCategoryMembers);
            productCategoryId = productCategoryMember.getString("productCategoryId");
          }
        } catch (GenericEntityException e) {
          Debug.logError(e, "Cannot find product category for product: " + productId, module);
        }
        urlBuilder.append("/" + PRODUCT_REQUEST);

      } else {
        urlBuilder.append("/" + CATEGORY_REQUEST);
      }

      // generate trail belong to a top category
      String topCategoryId = CategoryWorker.getCatalogTopCategory(httpRequest, null);
      List<GenericValue> trailCategories =
          CategoryWorker.getRelatedCategoriesRet(
              httpRequest, "trailCategories", topCategoryId, false, false, true);
      List<String> trailCategoryIds =
          EntityUtil.getFieldListFromEntityList(trailCategories, "productCategoryId", true);

      // look for productCategoryId from productId
      if (UtilValidate.isNotEmpty(productId)) {
        try {
          List<EntityCondition> rolllupConds = FastList.newInstance();
          rolllupConds.add(EntityCondition.makeCondition("productId", productId));
          rolllupConds.add(EntityUtil.getFilterByDateExpr());
          List<GenericValue> productCategoryMembers =
              EntityQuery.use(delegator)
                  .from("ProductCategoryMember")
                  .where(rolllupConds)
                  .orderBy("-fromDate")
                  .cache(true)
                  .queryList();
          for (GenericValue productCategoryMember : productCategoryMembers) {
            String trailCategoryId = productCategoryMember.getString("productCategoryId");
            if (trailCategoryIds.contains(trailCategoryId)) {
              productCategoryId = trailCategoryId;
              break;
            }
          }
        } catch (GenericEntityException e) {
          Debug.logError(e, "Cannot generate trail from product category", module);
        }
      }

      // generate trail elements from productCategoryId
      if (UtilValidate.isNotEmpty(productCategoryId)) {
        List<String> trailElements = FastList.newInstance();
        trailElements.add(productCategoryId);
        String parentProductCategoryId = productCategoryId;
        while (UtilValidate.isNotEmpty(parentProductCategoryId)) {
          // find product category rollup
          try {
            List<EntityCondition> rolllupConds = FastList.newInstance();
            rolllupConds.add(
                EntityCondition.makeCondition("productCategoryId", parentProductCategoryId));
            rolllupConds.add(EntityUtil.getFilterByDateExpr());
            List<GenericValue> productCategoryRollups =
                EntityQuery.use(delegator)
                    .from("ProductCategoryRollup")
                    .where(rolllupConds)
                    .orderBy("-fromDate")
                    .cache(true)
                    .queryList();
            if (UtilValidate.isNotEmpty(productCategoryRollups)) {
              // add only categories that belong to the top category to trail
              for (GenericValue productCategoryRollup : productCategoryRollups) {
                String trailCategoryId = productCategoryRollup.getString("parentProductCategoryId");
                parentProductCategoryId = trailCategoryId;
                if (trailCategoryIds.contains(trailCategoryId)) {
                  trailElements.add(trailCategoryId);
                  break;
                }
              }
            } else {
              parentProductCategoryId = null;
            }
          } catch (GenericEntityException e) {
            Debug.logError(e, "Cannot generate trail from product category", module);
          }
        }
        Collections.reverse(trailElements);

        List<String> trail = CategoryWorker.getTrail(httpRequest);
        if (trail == null) {
          trail = FastList.newInstance();
        }

        // adjust trail
        String previousCategoryId = null;
        if (trail.size() > 0) {
          previousCategoryId = trail.get(trail.size() - 1);
        }
        trail = CategoryWorker.adjustTrail(trail, productCategoryId, previousCategoryId);

        if (trailElements.size() == 1) {
          CategoryWorker.setTrail(request, trailElements.get(0), null);
        } else if (trailElements.size() == 2) {
          CategoryWorker.setTrail(request, trailElements.get(1), trailElements.get(0));
        } else if (trailElements.size() > 2) {
          if (trail.contains(trailElements.get(0))) {
            // first category is in the trail, so remove it everything after that and fill it in
            // with the list from the pathInfo
            int firstElementIndex = trail.indexOf(trailElements.get(0));
            while (trail.size() > firstElementIndex) {
              trail.remove(firstElementIndex);
            }
            trail.addAll(trailElements);
          } else {
            // first category is NOT in the trail, so clear out the trail and use the trailElements
            // list
            trail.clear();
            trail.addAll(trailElements);
          }
          CategoryWorker.setTrail(request, trail);
        }

        request.setAttribute("productCategoryId", productCategoryId);

        if (productId != null) {
          request.setAttribute("product_id", productId);
          request.setAttribute("productId", productId);
        }
      }

      // Set view query parameters
      UrlServletHelper.setViewQueryParameters(request, urlBuilder);
      if (UtilValidate.isNotEmpty(productId)
          || UtilValidate.isNotEmpty(productCategoryId)
          || UtilValidate.isNotEmpty(urlContentId)) {
        Debug.logInfo("[Filtered request]: " + pathInfo + " (" + urlBuilder + ")", module);
        ContextFilter.setAttributesFromRequestBody(request);
        RequestDispatcher dispatch = request.getRequestDispatcher(urlBuilder.toString());
        dispatch.forward(request, response);
        return;
      }

      // Check path alias
      UrlServletHelper.checkPathAlias(request, httpResponse, delegator, pathInfo);
    }

    // we're done checking; continue on
    chain.doFilter(request, response);
  }
  /**
   * Creates and updates a PartyRelationship creating related PartyRoles if needed. A side of the
   * relationship is checked to maintain history
   *
   * @param ctx The DispatchContext that this service is operating in
   * @param context Map containing the input parameters
   * @return Map with the result of the service, the output parameters
   */
  public static Map<String, Object> createUpdatePartyRelationshipAndRoles(
      DispatchContext ctx, Map<String, ? extends Object> context) {
    Map<String, Object> result = FastMap.newInstance();
    Delegator delegator = ctx.getDelegator();
    LocalDispatcher dispatcher = ctx.getDispatcher();

    try {
      List<GenericValue> partyRelationShipList =
          PartyRelationshipHelper.getActivePartyRelationships(delegator, context);
      if (UtilValidate.isEmpty(
          partyRelationShipList)) { // If already exists and active nothing to do: keep the current
                                    // one
        String partyId = (String) context.get("partyId");
        String partyIdFrom = (String) context.get("partyIdFrom");
        String partyIdTo = (String) context.get("partyIdTo");
        String roleTypeIdFrom = (String) context.get("roleTypeIdFrom");
        String roleTypeIdTo = (String) context.get("roleTypeIdTo");
        String partyRelationshipTypeId = (String) context.get("partyRelationshipTypeId");

        // Before creating the partyRelationShip, create the partyRoles if they don't exist
        GenericValue partyToRole = null;
        partyToRole =
            delegator.findOne(
                "PartyRole",
                UtilMisc.toMap("partyId", partyIdTo, "roleTypeId", roleTypeIdTo),
                false);
        if (partyToRole == null) {
          partyToRole =
              delegator.makeValue(
                  "PartyRole", UtilMisc.toMap("partyId", partyIdTo, "roleTypeId", roleTypeIdTo));
          partyToRole.create();
        }

        GenericValue partyFromRole = null;
        partyFromRole =
            delegator.findOne(
                "PartyRole",
                UtilMisc.toMap("partyId", partyIdFrom, "roleTypeId", roleTypeIdFrom),
                false);
        if (partyFromRole == null) {
          partyFromRole =
              delegator.makeValue(
                  "PartyRole",
                  UtilMisc.toMap("partyId", partyIdFrom, "roleTypeId", roleTypeIdFrom));
          partyFromRole.create();
        }

        // Check if there is already a partyRelationship of that type with another party from the
        // side indicated
        String sideChecked = partyIdFrom.equals(partyId) ? "partyIdFrom" : "partyIdTo";
        partyRelationShipList =
            delegator.findByAnd(
                "PartyRelationship",
                UtilMisc.toMap(
                    sideChecked,
                    partyId,
                    "roleTypeIdFrom",
                    roleTypeIdFrom,
                    "roleTypeIdTo",
                    roleTypeIdTo,
                    "partyRelationshipTypeId",
                    partyRelationshipTypeId));
        // We consider the last one (in time) as sole active (we try to maintain a unique
        // relationship and keep changes history)
        partyRelationShipList = EntityUtil.filterByDate(partyRelationShipList);
        GenericValue oldPartyRelationShip = EntityUtil.getFirst(partyRelationShipList);
        if (UtilValidate.isNotEmpty(oldPartyRelationShip)) {
          oldPartyRelationShip.setFields(
              UtilMisc.toMap("thruDate", UtilDateTime.nowTimestamp())); // Current becomes inactive
          oldPartyRelationShip.store();
        }
        try {
          dispatcher.runSync("createPartyRelationship", context); // Create new one
        } catch (GenericServiceException e) {
          Debug.logWarning(e.getMessage(), module);
          return ServiceUtil.returnError(
              "Could not create party relationship (write failure): " + e.getMessage());
        }
      }
    } catch (GenericEntityException e) {
      Debug.logWarning(e.getMessage(), module);
      return ServiceUtil.returnError(
          "Could not create party relationship (write failure): " + e.getMessage());
    }
    result.put(ModelService.RESPONSE_MESSAGE, ModelService.RESPOND_SUCCESS);
    return result;
  }
  private static List<GenericValue> getTaxAdjustments(
      Delegator delegator,
      GenericValue product,
      GenericValue productStore,
      String payToPartyId,
      String billToPartyId,
      Set<GenericValue> taxAuthoritySet,
      BigDecimal itemPrice,
      BigDecimal itemQuantity,
      BigDecimal itemAmount,
      BigDecimal shippingAmount,
      BigDecimal orderPromotionsAmount) {
    Timestamp nowTimestamp = UtilDateTime.nowTimestamp();
    List<GenericValue> adjustments = FastList.newInstance();

    if (payToPartyId == null) {
      if (productStore != null) {
        payToPartyId = productStore.getString("payToPartyId");
      }
    }

    // store expr
    EntityCondition storeCond = null;
    if (productStore != null) {
      storeCond =
          EntityCondition.makeCondition(
              EntityCondition.makeCondition(
                  "productStoreId", EntityOperator.EQUALS, productStore.get("productStoreId")),
              EntityOperator.OR,
              EntityCondition.makeCondition("productStoreId", EntityOperator.EQUALS, null));
    } else {
      storeCond = EntityCondition.makeCondition("productStoreId", EntityOperator.EQUALS, null);
    }

    // build the TaxAuthority expressions (taxAuthGeoId, taxAuthPartyId)
    List<EntityCondition> taxAuthCondOrList = FastList.newInstance();
    // start with the _NA_ TaxAuthority...
    taxAuthCondOrList.add(
        EntityCondition.makeCondition(
            EntityCondition.makeCondition("taxAuthPartyId", EntityOperator.EQUALS, "_NA_"),
            EntityOperator.AND,
            EntityCondition.makeCondition("taxAuthGeoId", EntityOperator.EQUALS, "_NA_")));

    for (GenericValue taxAuthority : taxAuthoritySet) {
      EntityCondition taxAuthCond =
          EntityCondition.makeCondition(
              EntityCondition.makeCondition(
                  "taxAuthPartyId",
                  EntityOperator.EQUALS,
                  taxAuthority.getString("taxAuthPartyId")),
              EntityOperator.AND,
              EntityCondition.makeCondition(
                  "taxAuthGeoId", EntityOperator.EQUALS, taxAuthority.getString("taxAuthGeoId")));
      taxAuthCondOrList.add(taxAuthCond);
    }
    EntityCondition taxAuthoritiesCond =
        EntityCondition.makeCondition(taxAuthCondOrList, EntityOperator.OR);

    try {
      EntityCondition productCategoryCond = null;
      if (product != null) {
        // find the tax categories associated with the product and filter by those, with an IN
        // clause or some such
        // if this product is variant, find the virtual product id and consider also the categories
        // of the virtual
        // question: get all categories, or just a special type? for now let's do all categories...
        String virtualProductId = null;
        if ("Y".equals(product.getString("isVariant"))) {
          virtualProductId = ProductWorker.getVariantVirtualId(product);
        }
        Set<String> productCategoryIdSet = FastSet.newInstance();
        EntityCondition productIdCond = null;
        if (virtualProductId != null) {
          productIdCond =
              EntityCondition.makeCondition(
                  EntityCondition.makeCondition(
                      "productId", EntityOperator.EQUALS, product.getString("productId")),
                  EntityOperator.OR,
                  EntityCondition.makeCondition(
                      "productId", EntityOperator.EQUALS, virtualProductId));

        } else {
          productIdCond =
              EntityCondition.makeCondition(
                  "productId", EntityOperator.EQUALS, product.getString("productId"));
        }
        List<GenericValue> pcmList =
            delegator.findList(
                "ProductCategoryMember",
                productIdCond,
                UtilMisc.toSet("productCategoryId", "fromDate", "thruDate"),
                null,
                null,
                true);
        pcmList = EntityUtil.filterByDate(pcmList, true);
        for (GenericValue pcm : pcmList) {
          productCategoryIdSet.add(pcm.getString("productCategoryId"));
        }

        if (productCategoryIdSet.size() == 0) {
          productCategoryCond =
              EntityCondition.makeCondition("productCategoryId", EntityOperator.EQUALS, null);
        } else {
          productCategoryCond =
              EntityCondition.makeCondition(
                  EntityCondition.makeCondition("productCategoryId", EntityOperator.EQUALS, null),
                  EntityOperator.OR,
                  EntityCondition.makeCondition(
                      "productCategoryId", EntityOperator.IN, productCategoryIdSet));
        }
      } else {
        productCategoryCond =
            EntityCondition.makeCondition("productCategoryId", EntityOperator.EQUALS, null);
      }

      // FIXME handles shipping and promo tax. Simple solution, see
      // https://issues.apache.org/jira/browse/OFBIZ-4160 for a better one
      if (product == null && shippingAmount != null) {
        EntityCondition taxShippingCond =
            EntityCondition.makeCondition(
                EntityCondition.makeCondition("taxShipping", EntityOperator.EQUALS, null),
                EntityOperator.OR,
                EntityCondition.makeCondition("taxShipping", EntityOperator.EQUALS, "Y"));

        if (productCategoryCond != null) {
          productCategoryCond =
              EntityCondition.makeCondition(
                  productCategoryCond, EntityOperator.OR, taxShippingCond);
        }
      }

      if (product == null && orderPromotionsAmount != null) {
        EntityCondition taxOrderPromotionsCond =
            EntityCondition.makeCondition(
                EntityCondition.makeCondition("taxPromotions", EntityOperator.EQUALS, null),
                EntityOperator.OR,
                EntityCondition.makeCondition("taxPromotions", EntityOperator.EQUALS, "Y"));

        if (productCategoryCond != null) {
          productCategoryCond =
              EntityCondition.makeCondition(
                  productCategoryCond, EntityOperator.OR, taxOrderPromotionsCond);
        }
      }

      // build the main condition clause
      List<EntityCondition> mainExprs =
          UtilMisc.toList(storeCond, taxAuthoritiesCond, productCategoryCond);
      mainExprs.add(
          EntityCondition.makeCondition(
              EntityCondition.makeCondition("minItemPrice", EntityOperator.EQUALS, null),
              EntityOperator.OR,
              EntityCondition.makeCondition(
                  "minItemPrice", EntityOperator.LESS_THAN_EQUAL_TO, itemPrice)));
      mainExprs.add(
          EntityCondition.makeCondition(
              EntityCondition.makeCondition("minPurchase", EntityOperator.EQUALS, null),
              EntityOperator.OR,
              EntityCondition.makeCondition(
                  "minPurchase", EntityOperator.LESS_THAN_EQUAL_TO, itemAmount)));
      EntityCondition mainCondition = EntityCondition.makeCondition(mainExprs, EntityOperator.AND);

      // create the orderby clause
      List<String> orderList = UtilMisc.<String>toList("minItemPrice", "minPurchase", "fromDate");

      // finally ready... do the rate query
      List<GenericValue> lookupList =
          delegator.findList(
              "TaxAuthorityRateProduct", mainCondition, null, orderList, null, false);
      List<GenericValue> filteredList = EntityUtil.filterByDate(lookupList, true);

      if (filteredList.size() == 0) {
        Debug.logWarning(
            "In TaxAuthority Product Rate no records were found for condition:"
                + mainCondition.toString(),
            module);
        return adjustments;
      }

      // find the right entry(s) based on purchase amount
      for (GenericValue taxAuthorityRateProduct : filteredList) {
        BigDecimal taxRate =
            taxAuthorityRateProduct.get("taxPercentage") != null
                ? taxAuthorityRateProduct.getBigDecimal("taxPercentage")
                : ZERO_BASE;
        BigDecimal taxable = ZERO_BASE;

        if (product != null
            && (product.get("taxable") == null
                || (product.get("taxable") != null
                    && product.getBoolean("taxable").booleanValue()))) {
          taxable = taxable.add(itemAmount);
        }
        if (shippingAmount != null
            && taxAuthorityRateProduct != null
            && (taxAuthorityRateProduct.get("taxShipping") == null
                || (taxAuthorityRateProduct.get("taxShipping") != null
                    && taxAuthorityRateProduct.getBoolean("taxShipping").booleanValue()))) {
          taxable = taxable.add(shippingAmount);
        }
        if (orderPromotionsAmount != null
            && taxAuthorityRateProduct != null
            && (taxAuthorityRateProduct.get("taxPromotions") == null
                || (taxAuthorityRateProduct.get("taxPromotions") != null
                    && taxAuthorityRateProduct.getBoolean("taxPromotions").booleanValue()))) {
          taxable = taxable.add(orderPromotionsAmount);
        }

        if (taxable.compareTo(BigDecimal.ZERO) == 0) {
          // this should make it less confusing if the taxable flag on the product is not Y/true,
          // and there is no shipping and such
          continue;
        }

        // taxRate is in percentage, so needs to be divided by 100
        BigDecimal taxAmount =
            (taxable.multiply(taxRate))
                .divide(PERCENT_SCALE, salestaxCalcDecimals, salestaxRounding);

        String taxAuthGeoId = taxAuthorityRateProduct.getString("taxAuthGeoId");
        String taxAuthPartyId = taxAuthorityRateProduct.getString("taxAuthPartyId");

        // get glAccountId from TaxAuthorityGlAccount entity using the payToPartyId as the
        // organizationPartyId
        GenericValue taxAuthorityGlAccount =
            delegator.findByPrimaryKey(
                "TaxAuthorityGlAccount",
                UtilMisc.toMap(
                    "taxAuthPartyId",
                    taxAuthPartyId,
                    "taxAuthGeoId",
                    taxAuthGeoId,
                    "organizationPartyId",
                    payToPartyId));
        String taxAuthGlAccountId = null;
        if (taxAuthorityGlAccount != null) {
          taxAuthGlAccountId = taxAuthorityGlAccount.getString("glAccountId");
        } else {
          // TODO: what to do if no TaxAuthorityGlAccount found? Use some default, or is that done
          // elsewhere later on?
        }

        GenericValue productPrice = null;
        if (product != null && taxAuthPartyId != null && taxAuthGeoId != null) {
          // find a ProductPrice for the productId and taxAuth* valxues, and see if it has a
          // priceWithTax value
          Map<String, String> priceFindMap =
              UtilMisc.toMap(
                  "productId",
                  product.getString("productId"),
                  "taxAuthPartyId",
                  taxAuthPartyId,
                  "taxAuthGeoId",
                  taxAuthGeoId,
                  "productPricePurposeId",
                  "PURCHASE");
          List<GenericValue> productPriceList =
              delegator.findByAnd("ProductPrice", priceFindMap, UtilMisc.toList("-fromDate"));
          productPriceList = EntityUtil.filterByDate(productPriceList, true);
          productPrice =
              (productPriceList != null && productPriceList.size() > 0)
                  ? productPriceList.get(0)
                  : null;
          // Debug.logInfo("=================== productId=" + product.getString("productId"),
          // module);
          // Debug.logInfo("=================== productPrice=" + productPrice, module);

        }

        GenericValue taxAdjValue = delegator.makeValue("OrderAdjustment");

        if (productPrice != null && "Y".equals(productPrice.getString("taxInPrice"))) {
          // tax is in the price already, so we want the adjustment to be a VAT_TAX adjustment to be
          // subtracted instead of a SALES_TAX adjustment to be added
          taxAdjValue.set("orderAdjustmentTypeId", "VAT_TAX");

          // the amount will be different because we want to figure out how much of the price was
          // tax, and not how much tax needs to be added
          // the formula is: taxAmount = priceWithTax - (priceWithTax/(1+taxPercentage/100))
          BigDecimal taxAmountIncluded =
              itemAmount.subtract(
                  itemAmount.divide(
                      BigDecimal.ONE.add(
                          taxRate.divide(PERCENT_SCALE, 4, BigDecimal.ROUND_HALF_UP)),
                      3,
                      BigDecimal.ROUND_HALF_UP));
          taxAdjValue.set("amountAlreadyIncluded", taxAmountIncluded);
          taxAdjValue.set("amount", BigDecimal.ZERO);
        } else {
          taxAdjValue.set("orderAdjustmentTypeId", "SALES_TAX");
          taxAdjValue.set("amount", taxAmount);
        }

        taxAdjValue.set("sourcePercentage", taxRate);
        taxAdjValue.set(
            "taxAuthorityRateSeqId", taxAuthorityRateProduct.getString("taxAuthorityRateSeqId"));
        // the primary Geo should be the main jurisdiction that the tax is for, and the secondary
        // would just be to define a parent or wrapping jurisdiction of the primary
        taxAdjValue.set("primaryGeoId", taxAuthGeoId);
        taxAdjValue.set("comments", taxAuthorityRateProduct.getString("description"));
        if (taxAuthPartyId != null) taxAdjValue.set("taxAuthPartyId", taxAuthPartyId);
        if (taxAuthGlAccountId != null) taxAdjValue.set("overrideGlAccountId", taxAuthGlAccountId);
        if (taxAuthGeoId != null) taxAdjValue.set("taxAuthGeoId", taxAuthGeoId);

        // check to see if this party has a tax ID for this, and if the party is tax exempt in the
        // primary (most-local) jurisdiction
        if (UtilValidate.isNotEmpty(billToPartyId) && UtilValidate.isNotEmpty(taxAuthGeoId)) {
          // see if partyId is a member of any groups, if so honor their tax exemptions
          // look for PartyRelationship with partyRelationshipTypeId=GROUP_ROLLUP, the partyIdTo is
          // the group member, so the partyIdFrom is the groupPartyId
          Set<String> billToPartyIdSet = FastSet.newInstance();
          billToPartyIdSet.add(billToPartyId);
          List<GenericValue> partyRelationshipList =
              EntityUtil.filterByDate(
                  delegator.findByAndCache(
                      "PartyRelationship",
                      UtilMisc.toMap(
                          "partyIdTo", billToPartyId, "partyRelationshipTypeId", "GROUP_ROLLUP")),
                  true);
          for (GenericValue partyRelationship : partyRelationshipList) {
            billToPartyIdSet.add(partyRelationship.getString("partyIdFrom"));
          }
          handlePartyTaxExempt(
              taxAdjValue,
              billToPartyIdSet,
              taxAuthGeoId,
              taxAuthPartyId,
              taxAmount,
              nowTimestamp,
              delegator);
        } else {
          Debug.logInfo(
              "NOTE: A tax calculation was done without a billToPartyId or taxAuthGeoId, so no tax exemptions or tax IDs considered; billToPartyId=["
                  + billToPartyId
                  + "] taxAuthGeoId=["
                  + taxAuthGeoId
                  + "]",
              module);
        }

        adjustments.add(taxAdjValue);

        if (productPrice != null
            && itemQuantity != null
            && productPrice.getBigDecimal("priceWithTax") != null
            && !"Y".equals(productPrice.getString("taxInPrice"))) {
          BigDecimal priceWithTax = productPrice.getBigDecimal("priceWithTax");
          BigDecimal price = productPrice.getBigDecimal("price");
          BigDecimal baseSubtotal = price.multiply(itemQuantity);
          BigDecimal baseTaxAmount =
              (baseSubtotal.multiply(taxRate))
                  .divide(PERCENT_SCALE, salestaxCalcDecimals, salestaxRounding);
          // Debug.logInfo("=================== priceWithTax=" + priceWithTax, module);
          // Debug.logInfo("=================== enteredTotalPriceWithTax=" +
          // enteredTotalPriceWithTax, module);
          // Debug.logInfo("=================== calcedTotalPriceWithTax=" + calcedTotalPriceWithTax,
          // module);

          // tax is not already in price so we want to add it in, but this is a VAT situation so
          // adjust to make it as accurate as possible

          // for VAT taxes if the calculated total item price plus calculated taxes is different
          // from what would be
          // expected based on the original entered price with taxes (if the price was entered this
          // way), then create
          // an adjustment that corrects for the difference, and this correction will be effectively
          // subtracted from the
          // price and not from the tax (the tax is meant to be calculated based on Tax Authority
          // rules and so should
          // not be shorted)

          // TODO (don't think this is needed, but just to keep it in mind): get this to work with
          // multiple VAT tax authorities instead of just one (right now will get incorrect totals
          // if there are multiple taxes included in the price)
          // TODO add constraint to ProductPrice lookup by any productStoreGroupId associated with
          // the current productStore

          BigDecimal enteredTotalPriceWithTax = priceWithTax.multiply(itemQuantity);
          BigDecimal calcedTotalPriceWithTax = (baseSubtotal).add(baseTaxAmount);
          if (!enteredTotalPriceWithTax.equals(calcedTotalPriceWithTax)) {
            // if the calced amount is higher than the entered amount we want the value to be
            // negative
            //     to get it down to match the entered amount
            // so, subtract the calced amount from the entered amount (ie: correction = entered -
            // calced)
            BigDecimal correctionAmount =
                enteredTotalPriceWithTax.subtract(calcedTotalPriceWithTax);
            // Debug.logInfo("=================== correctionAmount=" + correctionAmount, module);

            GenericValue correctionAdjValue = delegator.makeValue("OrderAdjustment");
            correctionAdjValue.set(
                "taxAuthorityRateSeqId",
                taxAuthorityRateProduct.getString("taxAuthorityRateSeqId"));
            correctionAdjValue.set("amount", correctionAmount);
            // don't set this, causes a doubling of the tax rate because calling code adds up all
            // tax rates: correctionAdjValue.set("sourcePercentage", taxRate);
            correctionAdjValue.set("orderAdjustmentTypeId", "VAT_PRICE_CORRECT");
            // the primary Geo should be the main jurisdiction that the tax is for, and the
            // secondary would just be to define a parent or wrapping jurisdiction of the primary
            correctionAdjValue.set("primaryGeoId", taxAuthGeoId);
            correctionAdjValue.set("comments", taxAuthorityRateProduct.getString("description"));
            if (taxAuthPartyId != null) correctionAdjValue.set("taxAuthPartyId", taxAuthPartyId);
            if (taxAuthGlAccountId != null)
              correctionAdjValue.set("overrideGlAccountId", taxAuthGlAccountId);
            if (taxAuthGeoId != null) correctionAdjValue.set("taxAuthGeoId", taxAuthGeoId);
            adjustments.add(correctionAdjValue);
          }
        }
      }
    } catch (GenericEntityException e) {
      Debug.logError(e, "Problems looking up tax rates", module);
      return FastList.newInstance();
    }

    return adjustments;
  }
  private static void handlePartyTaxExempt(
      GenericValue adjValue,
      Set<String> billToPartyIdSet,
      String taxAuthGeoId,
      String taxAuthPartyId,
      BigDecimal taxAmount,
      Timestamp nowTimestamp,
      Delegator delegator)
      throws GenericEntityException {
    Debug.logInfo("Checking for tax exemption : " + taxAuthGeoId + " / " + taxAuthPartyId, module);
    List<EntityCondition> ptiConditionList =
        UtilMisc.<EntityCondition>toList(
            EntityCondition.makeCondition("partyId", EntityOperator.IN, billToPartyIdSet),
            EntityCondition.makeCondition("taxAuthGeoId", EntityOperator.EQUALS, taxAuthGeoId),
            EntityCondition.makeCondition("taxAuthPartyId", EntityOperator.EQUALS, taxAuthPartyId));
    ptiConditionList.add(
        EntityCondition.makeCondition("fromDate", EntityOperator.LESS_THAN_EQUAL_TO, nowTimestamp));
    ptiConditionList.add(
        EntityCondition.makeCondition(
            EntityCondition.makeCondition("thruDate", EntityOperator.EQUALS, null),
            EntityOperator.OR,
            EntityCondition.makeCondition("thruDate", EntityOperator.GREATER_THAN, nowTimestamp)));
    EntityCondition ptiCondition =
        EntityCondition.makeCondition(ptiConditionList, EntityOperator.AND);
    // sort by -fromDate to get the newest (largest) first, just in case there is more than one, we
    // only want the most recent valid one, should only be one per jurisdiction...
    List<GenericValue> partyTaxInfos =
        delegator.findList(
            "PartyTaxAuthInfo", ptiCondition, null, UtilMisc.toList("-fromDate"), null, false);

    boolean foundExemption = false;
    if (partyTaxInfos.size() > 0) {
      GenericValue partyTaxInfo = partyTaxInfos.get(0);
      adjValue.set("customerReferenceId", partyTaxInfo.get("partyTaxId"));
      if ("Y".equals(partyTaxInfo.getString("isExempt"))) {
        adjValue.set("amount", BigDecimal.ZERO);
        adjValue.set("exemptAmount", taxAmount);
        foundExemption = true;
      }
    }

    // if no exceptions were found for the current; try the parent
    if (!foundExemption) {
      // try the "parent" TaxAuthority
      List<GenericValue> taxAuthorityAssocList =
          delegator.findByAndCache(
              "TaxAuthorityAssoc",
              UtilMisc.toMap(
                  "toTaxAuthGeoId",
                  taxAuthGeoId,
                  "toTaxAuthPartyId",
                  taxAuthPartyId,
                  "taxAuthorityAssocTypeId",
                  "EXEMPT_INHER"),
              UtilMisc.toList("-fromDate"));
      taxAuthorityAssocList = EntityUtil.filterByDate(taxAuthorityAssocList, true);
      GenericValue taxAuthorityAssoc = EntityUtil.getFirst(taxAuthorityAssocList);
      // Debug.logInfo("Parent assoc to " + taxAuthGeoId + " : " + taxAuthorityAssoc, module);
      if (taxAuthorityAssoc != null) {
        handlePartyTaxExempt(
            adjValue,
            billToPartyIdSet,
            taxAuthorityAssoc.getString("taxAuthGeoId"),
            taxAuthorityAssoc.getString("taxAuthPartyId"),
            taxAmount,
            nowTimestamp,
            delegator);
      }
    }
  }
Beispiel #27
0
  /**
   * Finds all matching parties based on the values provided. Excludes party records with a statusId
   * of PARTY_DISABLED. Results are ordered by descending PartyContactMech.fromDate. 1. Candidate
   * addresses are found by querying PartyAndPostalAddress using the supplied city and if provided,
   * stateProvinceGeoId, postalCode, postalCodeExt and countryGeoId 2. In-memory address line
   * comparisons are then performed against the supplied address1 and if provided, address2. Address
   * lines are compared after the strings have been converted using {@link
   * #makeMatchingString(Delegator, String)}.
   *
   * @param delegator Delegator instance
   * @param address1 PostalAddress.address1 to match against (Required).
   * @param address2 Optional PostalAddress.address2 to match against.
   * @param city PostalAddress.city value to match against (Required).
   * @param stateProvinceGeoId Optional PostalAddress.stateProvinceGeoId value to match against. If
   *     null or "**" is passed then the value will be ignored during matching. "NA" can be passed
   *     in place of "_NA_".
   * @param postalCode PostalAddress.postalCode value to match against. Cannot be null but can be
   *     skipped by passing a value starting with an "*". If the length of the supplied string is 10
   *     characters and the string contains a "-" then the postal code will be split at the "-" and
   *     the second half will be used as the postalCodeExt.
   * @param postalCodeExt Optional PostalAddress.postalCodeExt value to match against. Will be
   *     overridden if a postalCodeExt value is retrieved from postalCode as described above.
   * @param countryGeoId Optional PostalAddress.countryGeoId value to match against.
   * @param partyTypeId Optional Party.partyTypeId to match against.
   * @return List of PartyAndPostalAddress GenericValue objects that match the supplied criteria.
   * @throws GenericEntityException
   */
  public static List<GenericValue> findMatchingPartyPostalAddress(
      Delegator delegator,
      String address1,
      String address2,
      String city,
      String stateProvinceGeoId,
      String postalCode,
      String postalCodeExt,
      String countryGeoId,
      String partyTypeId)
      throws GenericEntityException {

    if (address1 == null || city == null || postalCode == null) {
      throw new IllegalArgumentException();
    }

    List<EntityCondition> addrExprs = FastList.newInstance();
    if (stateProvinceGeoId != null) {
      if ("**".equals(stateProvinceGeoId)) {
        Debug.logWarning("Illegal state code passed!", module);
      } else if ("NA".equals(stateProvinceGeoId)) {
        addrExprs.add(
            EntityCondition.makeCondition("stateProvinceGeoId", EntityOperator.EQUALS, "_NA_"));
      } else {
        addrExprs.add(
            EntityCondition.makeCondition(
                "stateProvinceGeoId", EntityOperator.EQUALS, stateProvinceGeoId.toUpperCase()));
      }
    }

    if (!postalCode.startsWith("*")) {
      if (postalCode.length() == 10 && postalCode.indexOf("-") != -1) {
        String[] zipSplit = postalCode.split("-", 2);
        postalCode = zipSplit[0];
        postalCodeExt = zipSplit[1];
      }
      addrExprs.add(EntityCondition.makeCondition("postalCode", EntityOperator.EQUALS, postalCode));
    }

    if (postalCodeExt != null) {
      addrExprs.add(
          EntityCondition.makeCondition("postalCodeExt", EntityOperator.EQUALS, postalCodeExt));
    }

    addrExprs.add(
        EntityCondition.makeCondition(
            EntityFunction.UPPER_FIELD("city"), EntityOperator.EQUALS, EntityFunction.UPPER(city)));

    if (countryGeoId != null) {
      addrExprs.add(
          EntityCondition.makeCondition(
              "countryGeoId", EntityOperator.EQUALS, countryGeoId.toUpperCase()));
    }

    // limit to only non-disabled status
    addrExprs.add(
        EntityCondition.makeCondition(
            EntityCondition.makeCondition("statusId", EntityOperator.EQUALS, null),
            EntityOperator.OR,
            EntityCondition.makeCondition("statusId", EntityOperator.NOT_EQUAL, "PARTY_DISABLED")));

    if (partyTypeId != null) {
      addrExprs.add(
          EntityCondition.makeCondition("partyTypeId", EntityOperator.EQUALS, partyTypeId));
    }

    List<String> sort = UtilMisc.toList("-fromDate");
    EntityCondition addrCond = EntityCondition.makeCondition(addrExprs, EntityOperator.AND);
    List<GenericValue> addresses =
        EntityUtil.filterByDate(
            delegator.findList("PartyAndPostalAddress", addrCond, null, sort, null, false));
    // Debug.logInfo("Checking for matching address: " + addrCond.toString() + "[" +
    // addresses.size() + "]", module);

    if (UtilValidate.isEmpty(addresses)) {
      // No address matches, return an empty list
      return addresses;
    }

    List<GenericValue> validFound = FastList.newInstance();
    // check the address line
    for (GenericValue address : addresses) {
      // address 1 field
      String addr1Source = PartyWorker.makeMatchingString(delegator, address1);
      String addr1Target = PartyWorker.makeMatchingString(delegator, address.getString("address1"));

      if (addr1Target != null) {
        Debug.logInfo("Comparing address1 : " + addr1Source + " / " + addr1Target, module);
        if (addr1Target.equals(addr1Source)) {

          // address 2 field
          if (address2 != null) {
            String addr2Source = PartyWorker.makeMatchingString(delegator, address2);
            String addr2Target =
                PartyWorker.makeMatchingString(delegator, address.getString("address2"));
            if (addr2Target != null) {
              Debug.logInfo("Comparing address2 : " + addr2Source + " / " + addr2Target, module);

              if (addr2Source.equals(addr2Target)) {
                Debug.logInfo("Matching address2; adding valid address", module);
                validFound.add(address);
                // validParty.put(address.getString("partyId"), address.getString("contactMechId"));
              }
            }
          } else {
            if (address.get("address2") == null) {
              Debug.logInfo("No address2; adding valid address", module);
              validFound.add(address);
              // validParty.put(address.getString("partyId"), address.getString("contactMechId"));
            }
          }
        }
      }
    }
    return validFound;
  }
Beispiel #28
0
  public static Map<String, Object> getExpressCheckout(
      DispatchContext dctx, Map<String, Object> context) {
    Locale locale = (Locale) context.get("locale");
    LocalDispatcher dispatcher = dctx.getDispatcher();
    Delegator delegator = dctx.getDelegator();

    ShoppingCart cart = (ShoppingCart) context.get("cart");
    GenericValue payPalConfig = getPaymentMethodGatewayPayPal(dctx, context, null);
    if (payPalConfig == null) {
      return ServiceUtil.returnError(
          UtilProperties.getMessage(
              resource, "AccountingPayPalPaymentGatewayConfigCannotFind", locale));
    }

    NVPEncoder encoder = new NVPEncoder();
    encoder.add("METHOD", "GetExpressCheckoutDetails");
    String token = (String) cart.getAttribute("payPalCheckoutToken");
    if (UtilValidate.isNotEmpty(token)) {
      encoder.add("TOKEN", token);
    } else {
      return ServiceUtil.returnError(
          UtilProperties.getMessage(resource, "AccountingPayPalTokenNotFound", locale));
    }

    NVPDecoder decoder;
    try {
      decoder = sendNVPRequest(payPalConfig, encoder);
    } catch (PayPalException e) {
      Debug.logError(e, module);
      return ServiceUtil.returnError(e.getMessage());
    }

    if (UtilValidate.isNotEmpty(decoder.get("NOTE"))) {
      cart.addOrderNote(decoder.get("NOTE"));
    }

    if (cart.getUserLogin() == null) {
      try {
        GenericValue userLogin =
            EntityQuery.use(delegator)
                .from("UserLogin")
                .where("userLoginId", "anonymous")
                .queryOne();
        try {
          cart.setUserLogin(userLogin, dispatcher);
        } catch (CartItemModifyException e) {
          Debug.logError(e, module);
          return ServiceUtil.returnError(e.getMessage());
        }
      } catch (GenericEntityException e) {
        Debug.logError(e, module);
        return ServiceUtil.returnError(e.getMessage());
      }
    }
    boolean anon = "anonymous".equals(cart.getUserLogin().getString("userLoginId"));
    // Even if anon, a party could already have been created
    String partyId = cart.getOrderPartyId();
    if (partyId == null && anon) {
      // Check nothing has been set on the anon userLogin either
      partyId = cart.getUserLogin() != null ? cart.getUserLogin().getString("partyId") : null;
      cart.setOrderPartyId(partyId);
    }
    if (partyId != null) {
      GenericValue party = null;
      try {
        party = EntityQuery.use(delegator).from("Party").where("partyId", partyId).queryOne();
      } catch (GenericEntityException e) {
        Debug.logError(e, module);
      }
      if (party == null) {
        partyId = null;
      }
    }

    Map<String, Object> inMap = FastMap.newInstance();
    Map<String, Object> outMap = null;
    // Create the person if necessary
    boolean newParty = false;
    if (partyId == null) {
      newParty = true;
      inMap.put("userLogin", cart.getUserLogin());
      inMap.put("personalTitle", decoder.get("SALUTATION"));
      inMap.put("firstName", decoder.get("FIRSTNAME"));
      inMap.put("middleName", decoder.get("MIDDLENAME"));
      inMap.put("lastName", decoder.get("LASTNAME"));
      inMap.put("suffix", decoder.get("SUFFIX"));
      try {
        outMap = dispatcher.runSync("createPerson", inMap);
        partyId = (String) outMap.get("partyId");
        cart.setOrderPartyId(partyId);
        cart.getUserLogin().setString("partyId", partyId);
        inMap.clear();
        inMap.put("userLogin", cart.getUserLogin());
        inMap.put("partyId", partyId);
        inMap.put("roleTypeId", "CUSTOMER");
        dispatcher.runSync("createPartyRole", inMap);
      } catch (GenericServiceException e) {
        Debug.logError(e, module);
        return ServiceUtil.returnError(e.getMessage());
      }
    }
    // Create a new email address if necessary
    String emailContactMechId = null;
    String emailContactPurposeTypeId = "PRIMARY_EMAIL";
    String emailAddress = decoder.get("EMAIL");
    if (!newParty) {
      EntityCondition cond =
          EntityCondition.makeCondition(
              UtilMisc.toList(
                  EntityCondition.makeCondition(
                      UtilMisc.toMap("partyId", partyId, "contactMechTypeId", "EMAIL_ADDRESS")),
                  EntityCondition.makeCondition(
                      EntityFunction.UPPER_FIELD("infoString"),
                      EntityComparisonOperator.EQUALS,
                      EntityFunction.UPPER(emailAddress))));

      try {
        GenericValue matchingEmail =
            EntityQuery.use(delegator)
                .from("PartyAndContactMech")
                .where(cond)
                .orderBy("fromDate")
                .filterByDate()
                .queryFirst();
        if (matchingEmail != null) {
          emailContactMechId = matchingEmail.getString("contactMechId");
        } else {
          // No email found so we'll need to create one but first check if it should be PRIMARY or
          // just BILLING
          long primaryEmails =
              EntityQuery.use(delegator)
                  .from("PartyContactWithPurpose")
                  .where(
                      "partyId",
                      partyId,
                      "contactMechTypeId",
                      "EMAIL_ADDRESS",
                      "contactMechPurposeTypeId",
                      "PRIMARY_EMAIL")
                  .filterByDate(
                      "contactFromDate", "contactThruDate", "purposeFromDate", "purposeThruDate")
                  .queryCount();
          if (primaryEmails > 0) emailContactPurposeTypeId = "BILLING_EMAIL";
        }
      } catch (GenericEntityException e) {
        Debug.logError(e, module);
      }
    }
    if (emailContactMechId == null) {
      inMap.clear();
      inMap.put("userLogin", cart.getUserLogin());
      inMap.put("contactMechPurposeTypeId", emailContactPurposeTypeId);
      inMap.put("emailAddress", emailAddress);
      inMap.put("partyId", partyId);
      inMap.put("roleTypeId", "CUSTOMER");
      inMap.put("verified", "Y"); // Going to assume PayPal has taken care of this for us
      inMap.put("fromDate", UtilDateTime.nowTimestamp());
      try {
        outMap = dispatcher.runSync("createPartyEmailAddress", inMap);
        emailContactMechId = (String) outMap.get("contactMechId");
      } catch (GenericServiceException e) {
        Debug.logError(e, module);
        return ServiceUtil.returnError(e.getMessage());
      }
    }
    cart.addContactMech("ORDER_EMAIL", emailContactMechId);

    // Phone number
    String phoneNumber = decoder.get("PHONENUM");
    String phoneContactId = null;
    if (phoneNumber != null) {
      inMap.clear();
      if (phoneNumber.startsWith("+")) {
        // International, format is +XXX XXXXXXXX which we'll split into countryCode + contactNumber
        String[] phoneNumbers = phoneNumber.split(" ");
        inMap.put("countryCode", StringUtil.removeNonNumeric(phoneNumbers[0]));
        inMap.put("contactNumber", phoneNumbers[1]);
      } else {
        // U.S., format is XXX-XXX-XXXX which we'll split into areaCode + contactNumber
        inMap.put("countryCode", "1");
        String[] phoneNumbers = phoneNumber.split("-");
        inMap.put("areaCode", phoneNumbers[0]);
        inMap.put("contactNumber", phoneNumbers[1] + phoneNumbers[2]);
      }
      inMap.put("userLogin", cart.getUserLogin());
      inMap.put("partyId", partyId);
      try {
        outMap = dispatcher.runSync("createUpdatePartyTelecomNumber", inMap);
        phoneContactId = (String) outMap.get("contactMechId");
        cart.addContactMech("PHONE_BILLING", phoneContactId);
      } catch (GenericServiceException e) {
        Debug.logError(e, module);
      }
    }
    // Create a new Postal Address if necessary
    String postalContactId = null;
    boolean needsShippingPurpose = true;
    // if the cart for some reason already has a billing address, we'll leave it be
    boolean needsBillingPurpose = (cart.getContactMech("BILLING_LOCATION") == null);
    Map<String, Object> postalMap = FastMap.newInstance();
    postalMap.put("toName", decoder.get("SHIPTONAME"));
    postalMap.put("address1", decoder.get("SHIPTOSTREET"));
    postalMap.put("address2", decoder.get("SHIPTOSTREET2"));
    postalMap.put("city", decoder.get("SHIPTOCITY"));
    String countryGeoId =
        PayPalServices.getCountryGeoIdFromGeoCode(decoder.get("SHIPTOCOUNTRYCODE"), delegator);
    postalMap.put("countryGeoId", countryGeoId);
    postalMap.put(
        "stateProvinceGeoId",
        parseStateProvinceGeoId(decoder.get("SHIPTOSTATE"), countryGeoId, delegator));
    postalMap.put("postalCode", decoder.get("SHIPTOZIP"));
    if (!newParty) {
      // We want an exact match only
      EntityCondition cond =
          EntityCondition.makeCondition(
              UtilMisc.toList(
                  EntityCondition.makeCondition(postalMap),
                  EntityCondition.makeCondition(
                      UtilMisc.toMap(
                          "attnName",
                          null,
                          "directions",
                          null,
                          "postalCodeExt",
                          null,
                          "postalCodeGeoId",
                          null)),
                  EntityCondition.makeCondition("partyId", partyId)));
      try {
        GenericValue postalMatch =
            EntityQuery.use(delegator)
                .from("PartyAndPostalAddress")
                .where(cond)
                .orderBy("fromDate")
                .filterByDate()
                .queryFirst();
        if (postalMatch != null) {
          postalContactId = postalMatch.getString("contactMechId");
          List<GenericValue> postalPurposes =
              EntityQuery.use(delegator)
                  .from("PartyContactMechPurpose")
                  .where("partyId", partyId, "contactMechId", postalContactId)
                  .filterByDate()
                  .queryList();
          List<Object> purposeStrings =
              EntityUtil.getFieldListFromEntityList(
                  postalPurposes, "contactMechPurposeTypeId", false);
          if (UtilValidate.isNotEmpty(purposeStrings)
              && purposeStrings.contains("SHIPPING_LOCATION")) {
            needsShippingPurpose = false;
          }
          if (needsBillingPurpose
              && UtilValidate.isNotEmpty(purposeStrings)
              && purposeStrings.contains("BILLING_LOCATION")) {
            needsBillingPurpose = false;
          }
        }
      } catch (GenericEntityException e) {
        Debug.logError(e, module);
      }
    }
    if (postalContactId == null) {
      postalMap.put("userLogin", cart.getUserLogin());
      postalMap.put("fromDate", UtilDateTime.nowTimestamp());
      try {
        outMap = dispatcher.runSync("createPartyPostalAddress", postalMap);
        postalContactId = (String) outMap.get("contactMechId");
      } catch (GenericServiceException e) {
        Debug.logError(e, module);
        return ServiceUtil.returnError(e.getMessage());
      }
    }
    if (needsShippingPurpose || needsBillingPurpose) {
      inMap.clear();
      inMap.put("userLogin", cart.getUserLogin());
      inMap.put("contactMechId", postalContactId);
      inMap.put("partyId", partyId);
      try {
        if (needsShippingPurpose) {
          inMap.put("contactMechPurposeTypeId", "SHIPPING_LOCATION");
          dispatcher.runSync("createPartyContactMechPurpose", inMap);
        }
        if (needsBillingPurpose) {
          inMap.put("contactMechPurposeTypeId", "BILLING_LOCATION");
          dispatcher.runSync("createPartyContactMechPurpose", inMap);
        }
      } catch (GenericServiceException e) {
        // Not the end of the world, we'll carry on
        Debug.logInfo(e.getMessage(), module);
      }
    }

    // Load the selected shipping method - thanks to PayPal's less than sane API all we've to work
    // with is the shipping option label
    // that was shown to the customer
    String shipMethod = decoder.get("SHIPPINGOPTIONNAME");
    if ("Calculated Offline".equals(shipMethod)) {
      cart.setAllCarrierPartyId("_NA_");
      cart.setAllShipmentMethodTypeId("NO_SHIPPING");
    } else {
      String[] shipMethodSplit = shipMethod.split(" - ");
      cart.setAllCarrierPartyId(shipMethodSplit[0]);
      String shippingMethodTypeDesc =
          StringUtils.join(shipMethodSplit, " - ", 1, shipMethodSplit.length);
      try {
        GenericValue shipmentMethod =
            EntityQuery.use(delegator)
                .from("ProductStoreShipmentMethView")
                .where(
                    "productStoreId",
                    cart.getProductStoreId(),
                    "partyId",
                    shipMethodSplit[0],
                    "roleTypeId",
                    "CARRIER",
                    "description",
                    shippingMethodTypeDesc)
                .queryFirst();
        cart.setAllShipmentMethodTypeId(shipmentMethod.getString("shipmentMethodTypeId"));
      } catch (GenericEntityException e1) {
        Debug.logError(e1, module);
      }
    }
    // Get rid of any excess ship groups
    List<CartShipInfo> shipGroups = cart.getShipGroups();
    for (int i = 1; i < shipGroups.size(); i++) {
      Map<ShoppingCartItem, BigDecimal> items = cart.getShipGroupItems(i);
      for (Map.Entry<ShoppingCartItem, BigDecimal> entry : items.entrySet()) {
        cart.positionItemToGroup(entry.getKey(), entry.getValue(), i, 0, false);
      }
    }
    cart.cleanUpShipGroups();
    cart.setAllShippingContactMechId(postalContactId);
    Map<String, Object> result =
        ShippingEvents.getShipGroupEstimate(dispatcher, delegator, cart, 0);
    if (result.get(ModelService.RESPONSE_MESSAGE).equals(ModelService.RESPOND_ERROR)) {
      return ServiceUtil.returnError((String) result.get(ModelService.ERROR_MESSAGE));
    }

    BigDecimal shippingTotal = (BigDecimal) result.get("shippingTotal");
    if (shippingTotal == null) {
      shippingTotal = BigDecimal.ZERO;
    }
    cart.setItemShipGroupEstimate(shippingTotal, 0);
    CheckOutHelper cho = new CheckOutHelper(dispatcher, delegator, cart);
    try {
      cho.calcAndAddTax();
    } catch (GeneralException e) {
      Debug.logError(e, module);
      return ServiceUtil.returnError(e.getMessage());
    }

    // Create the PayPal payment method
    inMap.clear();
    inMap.put("userLogin", cart.getUserLogin());
    inMap.put("partyId", partyId);
    inMap.put("contactMechId", postalContactId);
    inMap.put("fromDate", UtilDateTime.nowTimestamp());
    inMap.put("payerId", decoder.get("PAYERID"));
    inMap.put("expressCheckoutToken", token);
    inMap.put("payerStatus", decoder.get("PAYERSTATUS"));

    try {
      outMap = dispatcher.runSync("createPayPalPaymentMethod", inMap);
    } catch (GenericServiceException e) {
      Debug.logError(e, module);
      return ServiceUtil.returnError(e.getMessage());
    }
    String paymentMethodId = (String) outMap.get("paymentMethodId");

    cart.clearPayments();
    BigDecimal maxAmount = cart.getGrandTotal().setScale(2, BigDecimal.ROUND_HALF_UP);
    cart.addPaymentAmount(paymentMethodId, maxAmount, true);

    return ServiceUtil.returnSuccess();
  }