public static Map<String, Object> updateContact(
      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("partyId");

    // make sure userLogin has CRMSFA_CONTACT_UPDATE permission for this contact
    if (!CrmsfaSecurity.hasPartyRelationSecurity(
        security, "CRMSFA_CONTACT", "_UPDATE", userLogin, contactPartyId)) {
      return UtilMessage.createAndLogServiceError("CrmErrorPermissionDenied", locale, MODULE);
    }
    try {
      // update the Party and Person
      Map<String, Object> input =
          UtilMisc.<String, Object>toMap(
              "partyId",
              contactPartyId,
              "firstName",
              context.get("firstName"),
              "lastName",
              context.get("lastName"));
      input.put("firstNameLocal", context.get("firstNameLocal"));
      input.put("lastNameLocal", context.get("lastNameLocal"));
      input.put("personalTitle", context.get("personalTitle"));
      input.put("preferredCurrencyUomId", context.get("preferredCurrencyUomId"));
      input.put("description", context.get("description"));
      input.put("birthDate", context.get("birthDate"));
      input.put("userLogin", userLogin);
      Map<String, Object> serviceResults = dispatcher.runSync("updatePerson", input);
      if (ServiceUtil.isError(serviceResults)) {
        return UtilMessage.createAndLogServiceError(
            serviceResults, "CrmErrorUpdateContactFail", locale, MODULE);
      }

      // update PartySupplementalData
      GenericValue partyData =
          delegator.findByPrimaryKey(
              "PartySupplementalData", UtilMisc.toMap("partyId", contactPartyId));
      if (partyData == null) {
        // create a new one
        partyData =
            delegator.makeValue("PartySupplementalData", UtilMisc.toMap("partyId", contactPartyId));
        partyData.create();
      }
      partyData.setNonPKFields(context);
      partyData.store();

    } catch (GenericServiceException e) {
      return UtilMessage.createAndLogServiceError(e, "CrmErrorUpdateContactFail", locale, MODULE);
    } catch (GenericEntityException e) {
      return UtilMessage.createAndLogServiceError(e, "CrmErrorUpdateContactFail", locale, MODULE);
    }
    return ServiceUtil.returnSuccess();
  }
  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();
  }
  public static Map<String, Object> deactivateContact(
      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);

    // what contact we're expiring
    String contactPartyId = (String) context.get("partyId");

    // check that userLogin has CRMSFA_CONTACT_DEACTIVATE permission for this contact
    if (!CrmsfaSecurity.hasPartyRelationSecurity(
        security, "CRMSFA_CONTACT", "_DEACTIVATE", userLogin, contactPartyId)) {
      return UtilMessage.createAndLogServiceError("CrmErrorPermissionDenied", locale, MODULE);
    }

    // when to expire the contact
    Timestamp expireDate = (Timestamp) context.get("expireDate");
    if (expireDate == null) {
      expireDate = UtilDateTime.nowTimestamp();
    }

    // in order to deactivate a contact, we expire all party relationships on the expire date
    try {
      List<GenericValue> partyRelationships =
          delegator.findByAnd(
              "PartyRelationship",
              UtilMisc.toMap("partyIdFrom", contactPartyId, "roleTypeIdFrom", "CONTACT"));
      PartyHelper.expirePartyRelationships(partyRelationships, expireDate, dispatcher, userLogin);
    } catch (GenericEntityException e) {
      return UtilMessage.createAndLogServiceError(
          e, "CrmErrorDeactivateContactFail", locale, MODULE);
    } catch (GenericServiceException e) {
      return UtilMessage.createAndLogServiceError(
          e, "CrmErrorDeactivateContactFail", locale, MODULE);
    }

    // set the party statusId to PARTY_DISABLED and register the PartyDeactivation
    try {
      GenericValue contactParty =
          delegator.findByPrimaryKey("Party", UtilMisc.toMap("partyId", contactPartyId));
      contactParty.put("statusId", "PARTY_DISABLED");
      contactParty.store();

      delegator.create(
          "PartyDeactivation",
          UtilMisc.toMap("partyId", contactPartyId, "deactivationTimestamp", expireDate));
    } catch (GenericEntityException e) {
      return UtilMessage.createAndLogServiceError(
          e, "CrmErrorDeactivateAccountFail", locale, MODULE);
    }
    return ServiceUtil.returnSuccess();
  }
  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();
  }
  public static Map<String, Object> removeContactFromAccount(
      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");

    // ensure update permission on account
    if (!CrmsfaSecurity.hasPartyRelationSecurity(
        security, "CRMSFA_ACCOUNT", "_UPDATE", userLogin, accountPartyId)) {
      return UtilMessage.createAndLogServiceError("CrmErrorPermissionDenied", locale, MODULE);
    }
    try {
      // find and expire all contact relationships between the contact and account
      List<GenericValue> relations =
          delegator.findByAnd(
              "PartyRelationship",
              UtilMisc.toMap(
                  "partyIdTo",
                  accountPartyId,
                  "partyIdFrom",
                  contactPartyId,
                  "partyRelationshipTypeId",
                  PartyRelationshipTypeConstants.CONTACT_REL_INV));
      PartyHelper.expirePartyRelationships(
          relations, UtilDateTime.nowTimestamp(), dispatcher, userLogin);
    } catch (GenericServiceException e) {
      return UtilMessage.createAndLogServiceError(e, "CrmErrorRemoveContactFail", locale, MODULE);
    } catch (GenericEntityException e) {
      return UtilMessage.createAndLogServiceError(e, "CrmErrorRemoveContactFail", locale, MODULE);
    }
    return ServiceUtil.returnSuccess();
  }
  @SuppressWarnings("unchecked")
  public static Map<String, Object> sendCrmNotificationEmails(
      DispatchContext dctx, Map<String, Object> context) {
    Delegator delegator = dctx.getDelegator();
    LocalDispatcher dispatcher = dctx.getDispatcher();
    String eventType = (String) context.get("eventType");
    String subject = (String) context.get("subject");
    Map<String, Object> bodyParameters = (Map<String, Object>) context.get("bodyParameters");
    List<String> notifyPartyIds = (List<String>) context.get("notifyPartyIds");
    Set<String> uniquePartyIds = new HashSet<String>(notifyPartyIds);
    GenericValue userLogin = (GenericValue) context.get("userLogin");
    Locale locale = UtilCommon.getLocale(context);

    try {

      // Try the specific case first - EG: screen.location.task.add=...
      String bodyScreenUri =
          UtilProperties.getMessage(notificationResource, "screen.location." + eventType, locale);
      if (UtilValidate.isEmpty(bodyScreenUri)) {

        // Failing that, try the more general case - EG: screen.location.task=...
        String[] propertyElements = eventType.split(".");
        if (propertyElements.length > 0) {
          bodyScreenUri =
              UtilProperties.getMessage(
                  notificationResource, "screen.location." + propertyElements[0], locale);
        }
      }

      String fromProperty = "from." + eventType;
      String sendFrom = UtilProperties.getMessage(notificationResource, fromProperty, locale);
      if (UtilValidate.isEmpty(sendFrom) || fromProperty.equals(sendFrom)) {
        sendFrom = UtilProperties.getMessage(notificationResource, "from", locale);
      }

      for (String notifyPartyId : uniquePartyIds) {

        try {

          // Get the party's primary email address
          String sendTo = PartyHelper.getPrimaryEmailForParty(notifyPartyId, delegator);

          if (sendTo == null) {
            Debug.logError(
                UtilProperties.getMessage(
                    resource,
                    "crmsfa.sendCrmNotificationEmailsErrorNoAddress",
                    UtilMisc.toMap("partyId", notifyPartyId, "subject", subject),
                    locale),
                MODULE);
            continue;
          }

          Map<String, Object> sendMailContext = new HashMap<String, Object>();
          sendMailContext.put("bodyScreenUri", bodyScreenUri);
          sendMailContext.put("bodyParameters", bodyParameters);
          sendMailContext.put("sendTo", sendTo);
          sendMailContext.put("sendFrom", sendFrom);
          sendMailContext.put("subject", subject);
          sendMailContext.put("contentType", "text/html");
          sendMailContext.put("userLogin", userLogin);

          // Call sendMailFromScreen async so that failed emails are retried
          dispatcher.runAsync("sendMailFromScreen", sendMailContext);

        } catch (GenericServiceException e) {
          TransactionUtil.rollback();
          Debug.logError(
              e,
              UtilProperties.getMessage(
                  resource,
                  "crmsfa.sendCrmNotificationEmailsError",
                  UtilMisc.toMap("partyId", notifyPartyId, "subject", subject),
                  locale),
              MODULE);
        }
      }

    } catch (GenericEntityException e) {
      return UtilMessage.createAndLogServiceError(
          e, "CrmErrorSendCrmNotificationEmailsFail", locale, MODULE);
    }
    return ServiceUtil.returnSuccess();
  }
  public static Map<String, Object> sendCatalogRequestNotificationEmail(
      DispatchContext dctx, Map<String, Object> context) {

    LocalDispatcher dispatcher = dctx.getDispatcher();
    Delegator delegator = dctx.getDelegator();

    Locale locale = UtilCommon.getLocale(context);
    GenericValue userLogin = (GenericValue) context.get("userLogin");
    String custRequestId = (String) context.get("custRequestId");

    boolean sendEmail =
        "true"
            .equalsIgnoreCase(
                UtilProperties.getMessage(
                        notificationResource,
                        "email.marketing.catalog.sendCatalogRequestEmails",
                        locale)
                    .trim());
    if (!sendEmail) {
      Debug.logInfo(
          UtilProperties.getMessage(
              resource,
              "crmsfa.sendCrmNotificationEmailsCatRqTurnedOff",
              UtilMisc.toMap("custRequestId", custRequestId),
              locale),
          MODULE);
      return ServiceUtil.returnSuccess();
    }

    String mailToPartyId = (String) context.get("fromPartyId");

    try {
      Map<String, Object> paramsMap = FastMap.newInstance();

      paramsMap.put("eventType", "marketing.catalog");
      paramsMap.put(
          "subject",
          UtilProperties.getMessage(notificationResource, "subject.marketing.catalog", locale));
      paramsMap.put("locale", locale);
      paramsMap.put("userLogin", userLogin);
      paramsMap.put("notifyPartyIds", UtilMisc.toList(mailToPartyId));

      Map<String, Object> bodyParameters = FastMap.newInstance();

      GenericValue custRequest =
          delegator.findByPrimaryKey("CustRequest", UtilMisc.toMap("custRequestId", custRequestId));
      GenericValue contactMech = custRequest.getRelatedOne("FulfillContactMech");
      GenericValue postalAddress = contactMech.getRelatedOne("PostalAddress");
      String address1 = (String) postalAddress.get("address1");
      String address2 = (String) postalAddress.get("address2");
      String city = (String) postalAddress.get("city");
      String postalCode = (String) postalAddress.get("postalCode");
      String stateProvinceGeoId = (String) postalAddress.get("stateProvinceGeoId");
      GenericValue country = postalAddress.getRelatedOne("CountryGeo");
      String countryName = (String) country.get("geoName");
      GenericValue party =
          delegator.findByPrimaryKey(
              "PartySummaryCRMView", UtilMisc.toMap("partyId", custRequest.get("fromPartyId")));

      bodyParameters.put("firstName", party.get("firstName"));
      bodyParameters.put("lastName", party.get("lastName"));
      bodyParameters.put("address1", address1);
      bodyParameters.put("address2", address2);
      bodyParameters.put("city", city);
      bodyParameters.put("postalCode", postalCode);
      bodyParameters.put("stateProvinceGeoId", stateProvinceGeoId);
      bodyParameters.put("countryName", countryName);

      paramsMap.put("bodyParameters", bodyParameters);

      dispatcher.runSync("crmsfa.sendCrmNotificationEmails", paramsMap);

    } catch (GenericServiceException gse) {
      return UtilMessage.createAndLogServiceError(gse, MODULE);
    } catch (GenericEntityException gee) {
      return UtilMessage.createAndLogServiceError(gee, MODULE);
    }

    return ServiceUtil.returnSuccess();
  }
  /**
   * Wrapper service for the OFBiz completePack service, plus additional warehouse-app-specific
   * logic. Uses an org.opentaps.warehouse.shipment.packing.PackingSession object which extends the
   * OFBiz PackingSession class.
   *
   * @param dctx the service <code>DispatchContext</code>
   * @param context the service context <code>Map</code>
   * @return the service result <code>Map</code>
   */
  @SuppressWarnings("unchecked")
  public static Map<String, Object> warehouseCompletePack(
      DispatchContext dctx, Map<String, Object> context) {
    LocalDispatcher dispatcher = dctx.getDispatcher();
    Locale locale = UtilCommon.getLocale(context);
    GenericValue userLogin = (GenericValue) context.get("userLogin");
    org.opentaps.warehouse.shipment.packing.PackingSession session =
        (PackingSession) context.get("packingSession");

    DomainsDirectory dd =
        new DomainsLoader(new Infrastructure(dispatcher), new User(userLogin))
            .loadDomainsDirectory();
    ShippingRepositoryInterface repo;
    Facility facility;
    try {
      repo = dd.getShippingDomain().getShippingRepository();
      facility =
          repo.findOneNotNullCache(
              Facility.class, repo.map(Facility.Fields.facilityId, session.getFacilityId()));
    } catch (FoundationException e) {
      return UtilMessage.createAndLogServiceError(e, MODULE);
    }
    context.put("orderId", session.getPrimaryOrderId());
    Map<String, String> packageWeights = (Map<String, String>) context.get("packageWeights");
    org.ofbiz.shipment.packing.PackingServices.setSessionPackageWeights(session, packageWeights);
    context.remove("packageWeights");

    Map<String, String> packageTrackingCodes =
        (Map<String, String>) context.get("packageTrackingCodes");
    setSessionPackageTrackingCodes(session, packageTrackingCodes);
    context.remove("packageTrackingCodes");

    Map<String, String> packageBoxTypeIds = (Map<String, String>) context.get("packageBoxTypeIds");
    setSessionPackageBoxTypeIds(session, packageBoxTypeIds);
    context.remove("packageBoxTypeIds");

    String additionalShippingChargeDescription =
        (String) context.get("additionalShippingChargeDescription");
    session.setAdditionalShippingChargeDescription(additionalShippingChargeDescription);
    context.remove("additionalShippingChargeDescription");

    session.setHandlingInstructions((String) context.get("handlingInstructions"));

    Boolean force = (Boolean) context.get("forceComplete");
    if ("Y".equals(facility.getSkipPackOrderInventoryCheck())) {
      force = true;
      // passing it to the ofbiz service will also skip reservation checks
      context.put("forceComplete", Boolean.TRUE);
    }

    if (force == null || !force.booleanValue()) {
      List<String> errMsgs = FastList.newInstance();
      Map<String, BigDecimal> productQuantities = session.getProductQuantities();
      Set<String> keySet = productQuantities.keySet();
      for (String productId : keySet) {
        BigDecimal quantity = productQuantities.get(productId);
        Map<String, Object> serviceResult = null;
        try {
          serviceResult =
              dispatcher.runSync(
                  "getInventoryAvailableByFacility",
                  UtilMisc.toMap(
                      "productId",
                      productId,
                      "facilityId",
                      session.getFacilityId(),
                      "userLogin",
                      userLogin));
          if (ServiceUtil.isError(serviceResult)) {
            return serviceResult;
          }
        } catch (GenericServiceException e) {
          return UtilMessage.createAndLogServiceError(e, MODULE);
        }
        BigDecimal quantityOnHandTotal = (BigDecimal) serviceResult.get("quantityOnHandTotal");
        if ((UtilValidate.isNotEmpty(quantityOnHandTotal))
            && quantityOnHandTotal.subtract(quantity).signum() < 0) {
          errMsgs.add(
              UtilMessage.expandLabel(
                  "WarehouseErrorInventoryItemProductQOHUnderZero",
                  locale,
                  UtilMisc.toMap("productId", productId)));
        }
      }
      if (UtilValidate.isNotEmpty(errMsgs)) {
        return ServiceUtil.returnError(errMsgs);
      }
    }

    // Call the OFBiz completePack service. The PackingSession object passed is an opentaps
    // PackingSession, so that when
    // PackingSession.complete() is called by completePack, the overridden method is used instead,
    // and additional steps are performed.
    Map<String, Object> completePackResult = null;
    try {
      completePackResult = dispatcher.runSync("completePack", context);
    } catch (GenericServiceException e) {
      Debug.logError("Error calling completePack service in warehouseCompletePack", MODULE);
    }
    if (ServiceUtil.isError(completePackResult)) {
      return completePackResult;
    }

    Map<String, Object> result = ServiceUtil.returnSuccess();
    result.put("shipmentId", completePackResult.get("shipmentId"));
    return result;
  }
  public static Map<String, Object> createContact(
      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);

    if (!security.hasPermission("CRMSFA_CONTACT_CREATE", userLogin)) {
      return UtilMessage.createAndLogServiceError("CrmErrorPermissionDenied", locale, MODULE);
    }

    // the net result of creating an contact is the generation of a Contact partyId
    String contactPartyId = (String) context.get("partyId");
    try {
      // make sure user has the right crmsfa roles defined.  otherwise the contact will be created
      // as deactivated.
      if (UtilValidate.isEmpty(
          PartyHelper.getFirstValidTeamMemberRoleTypeId(
              userLogin.getString("partyId"), delegator))) {
        return UtilMessage.createAndLogServiceError(
            "CrmError_NoRoleForCreateParty",
            UtilMisc.toMap(
                "userPartyName",
                org.ofbiz.party.party.PartyHelper.getPartyName(
                    delegator, userLogin.getString("partyId"), false),
                "requiredRoleTypes",
                PartyHelper.TEAM_MEMBER_ROLES),
            locale,
            MODULE);
      }

      // if we're given the partyId to create, then verify it is free to use
      if (contactPartyId != null) {
        Map<String, Object> findMap = UtilMisc.<String, Object>toMap("partyId", contactPartyId);
        GenericValue party = delegator.findByPrimaryKey("Party", findMap);
        if (party != null) {
          return UtilMessage.createAndLogServiceError(
              "person.create.person_exists", findMap, locale, MODULE);
        }
      }

      // create the Party and Person, which results in a partyId
      Map<String, Object> input =
          UtilMisc.<String, Object>toMap(
              "firstName", context.get("firstName"), "lastName", context.get("lastName"));
      if (contactPartyId != null) {
        input.put("partyId", contactPartyId);
      }
      input.put("firstNameLocal", context.get("firstNameLocal"));
      input.put("lastNameLocal", context.get("lastNameLocal"));
      input.put("personalTitle", context.get("personalTitle"));
      input.put("preferredCurrencyUomId", context.get("preferredCurrencyUomId"));
      input.put("description", context.get("description"));
      input.put("birthDate", context.get("birthDate"));
      Map<String, Object> serviceResults = dispatcher.runSync("createPerson", input);
      if (ServiceUtil.isError(serviceResults)) {
        return UtilMessage.createAndLogServiceError(
            serviceResults, "CrmErrorCreateContactFail", locale, MODULE);
      }
      contactPartyId = (String) serviceResults.get("partyId");

      // create a PartyRole for the resulting Contact partyId with roleTypeId = CONTACT
      serviceResults =
          dispatcher.runSync(
              "createPartyRole",
              UtilMisc.toMap(
                  "partyId", contactPartyId, "roleTypeId", "CONTACT", "userLogin", userLogin));
      if (ServiceUtil.isError(serviceResults)) {
        return UtilMessage.createAndLogServiceError(
            serviceResults, "CrmErrorCreateContactFail", locale, MODULE);
      }

      // create PartySupplementalData
      GenericValue partyData =
          delegator.makeValue("PartySupplementalData", UtilMisc.toMap("partyId", contactPartyId));
      partyData.setNonPKFields(context);
      partyData.create();

      // create a party relationship between the userLogin and the Contact with
      // partyRelationshipTypeId RESPONSIBLE_FOR
      createResponsibleContactRelationshipForParty(
          userLogin.getString("partyId"), contactPartyId, userLogin, delegator, dispatcher);

      // if initial marketing campaign is provided, add it
      String marketingCampaignId = (String) context.get("marketingCampaignId");
      if (marketingCampaignId != null) {
        serviceResults =
            dispatcher.runSync(
                "crmsfa.addContactMarketingCampaign",
                UtilMisc.toMap(
                    "partyId",
                    contactPartyId,
                    "marketingCampaignId",
                    marketingCampaignId,
                    "userLogin",
                    userLogin));
        if (ServiceUtil.isError(serviceResults)) {
          return UtilMessage.createAndLogServiceError(
              serviceResults, "CrmErrorCreateContactFail", locale, MODULE);
        }
      }

      // create basic contact info
      ModelService service = dctx.getModelService("crmsfa.createBasicContactInfoForParty");
      input = service.makeValid(context, "IN");
      input.put("partyId", contactPartyId);
      serviceResults = dispatcher.runSync(service.name, input);
      if (ServiceUtil.isError(serviceResults)) {
        return UtilMessage.createAndLogServiceError(
            serviceResults, "CrmErrorCreateContactFail", locale, MODULE);
      }

      // Sumit:  priority of warehouse for the specified party..
      String priorityOne = (String) context.get("warehousePriorityOne");
      String priorityTwo = (String) context.get("warehousePriorityTwo");
      String priorityThree = (String) context.get("warehousePriorityThree");
      String priorityFour = (String) context.get("warehousePriorityFour");

      if (UtilValidate.isNotEmpty(priorityOne)
          && UtilValidate.isNotEmpty(priorityTwo)
          && UtilValidate.isNotEmpty(priorityThree)
          && UtilValidate.isNotEmpty(priorityFour)) {
        Set<String> priorityList = new LinkedHashSet<String>();
        priorityList.add(priorityOne);
        priorityList.add(priorityTwo);
        priorityList.add(priorityThree);
        priorityList.add(priorityFour);
        List<GenericValue> warehousePriority = new ArrayList<GenericValue>();

        GenericValue facilityPriorityOne = delegator.makeValue("FacilityPartyPriority");
        Long count = 0L;
        for (String priority : priorityList) {
          count++;
          facilityPriorityOne.set("facilityId", priority);
          facilityPriorityOne.set("partyId", contactPartyId);
          facilityPriorityOne.set("priority", count);
          facilityPriorityOne.set("thruDate", UtilDateTime.nowTimestamp());
          warehousePriority.add(facilityPriorityOne);
        }
        delegator.storeAll(warehousePriority);
      }

    } catch (GenericServiceException e) {
      return UtilMessage.createAndLogServiceError(e, "CrmErrorCreateContactFail", locale, MODULE);
    } catch (GenericEntityException e) {
      return UtilMessage.createAndLogServiceError(e, "CrmErrorCreateContactFail", locale, MODULE);
    }

    // return the partyId of the newly created Contact
    Map<String, Object> results = ServiceUtil.returnSuccess();
    results.put("partyId", contactPartyId);
    results.put("contactPartyId", contactPartyId);
    return results;
  }