/** Prepares the parameters for a payment. The resulting status is null when no problem found */
  private PrepareParametersResult prepareParameters(final PaymentParameters params) {

    final Member restricted = WebServiceContext.getMember();
    final boolean fromSystem = params.isFromSystem();
    final boolean toSystem = params.isToSystem();
    PaymentStatus status = null;
    Member fromMember = null;
    Member toMember = null;
    // Load the from member
    if (!fromSystem) {
      try {
        fromMember = paymentHelper.resolveFromMember(params);
      } catch (final EntityNotFoundException e) {
        webServiceHelper.error(e);
        status = PaymentStatus.FROM_NOT_FOUND;
      }
    }
    // Load the to member
    if (!toSystem) {
      try {
        toMember = paymentHelper.resolveToMember(params);
      } catch (final EntityNotFoundException e) {
        webServiceHelper.error(e);
        status = PaymentStatus.TO_NOT_FOUND;
      }
    }

    if (status == null) {
      if (restricted == null) {
        // Ensure has the do payment permission
        if (!WebServiceContext.hasPermission(ServiceOperation.DO_PAYMENT)) {
          throw new PermissionDeniedException(
              "The service client doesn't have the following permission: "
                  + ServiceOperation.DO_PAYMENT);
        }
        // Check the channel immediately, as needed by SMS controller
        if (fromMember != null
            && !accessService.isChannelEnabledForMember(channelHelper.restricted(), fromMember)) {
          status = PaymentStatus.INVALID_CHANNEL;
        }
      } else {
        // Enforce the restricted to member parameters
        if (fromSystem) {
          // Restricted to member can't perform payment from system
          status = PaymentStatus.FROM_NOT_FOUND;
        } else {
          if (fromMember == null) {
            fromMember = restricted;
          } else if (toMember == null && !toSystem) {
            toMember = restricted;
          }
        }
        if (status == null) {
          // Check make / receive payment permissions
          if (fromMember.equals(restricted)) {
            if (!WebServiceContext.hasPermission(ServiceOperation.DO_PAYMENT)) {
              throw new PermissionDeniedException(
                  "The service client doesn't have the following permission: "
                      + ServiceOperation.DO_PAYMENT);
            }
          } else {
            if (!WebServiceContext.hasPermission(ServiceOperation.RECEIVE_PAYMENT)) {
              throw new PermissionDeniedException(
                  "The service client doesn't have the following permission: "
                      + ServiceOperation.RECEIVE_PAYMENT);
            }
          }
          // Ensure that either from or to member is the restricted one
          if (!fromMember.equals(restricted) && !toMember.equals(restricted)) {
            status = PaymentStatus.INVALID_PARAMETERS;
            webServiceHelper.trace(
                status
                    + ". Reason: Neither the origin nor the destination members are equal to the restricted: "
                    + restricted);
          }
        }
        if (status == null) {
          // Enforce the permissions
          if (restricted.equals(fromMember)
              && !WebServiceContext.hasPermission(ServiceOperation.DO_PAYMENT)) {
            throw new PermissionDeniedException(
                "The service client doesn't have the following permission: "
                    + ServiceOperation.DO_PAYMENT);
          } else if (restricted.equals(toMember)
              && !WebServiceContext.hasPermission(ServiceOperation.RECEIVE_PAYMENT)) {
            throw new PermissionDeniedException(
                "The service client doesn't have the following permission: "
                    + ServiceOperation.RECEIVE_PAYMENT);
          }
        }
      }
    }

    // Ensure both from and to member are present
    if (status == null) {
      if (fromMember == null && !fromSystem) {
        status = PaymentStatus.FROM_NOT_FOUND;
      } else if (toMember == null && !toSystem) {
        status = PaymentStatus.TO_NOT_FOUND;
      }
    }

    if (status == null) {
      // Check the channel
      if (fromMember != null
          && !accessService.isChannelEnabledForMember(channelHelper.restricted(), fromMember)) {
        status = PaymentStatus.INVALID_CHANNEL;
      }
    }
    if (status == null) {
      // Check the credentials
      boolean checkCredentials;
      if (restricted != null) {
        checkCredentials = !fromMember.equals(restricted);
      } else {
        checkCredentials = !fromSystem && WebServiceContext.getClient().isCredentialsRequired();
      }
      if (checkCredentials) {
        try {
          checkCredentials(fromMember, WebServiceContext.getChannel(), params.getCredentials());
        } catch (final InvalidCredentialsException e) {
          status = PaymentStatus.INVALID_CREDENTIALS;
        } catch (final BlockedCredentialsException e) {
          status = PaymentStatus.BLOCKED_CREDENTIALS;
        }
      }
    }

    // No error
    final AccountOwner fromOwner = fromSystem ? SystemAccountOwner.instance() : fromMember;
    final AccountOwner toOwner = toSystem ? SystemAccountOwner.instance() : toMember;
    return new PrepareParametersResult(status, fromOwner, toOwner);
  }
  public RequestPaymentResult requestPaymentConfirmation(final RequestPaymentParameters params) {
    Exception errorException = null;
    PaymentRequestStatus status = null;
    // Get the to member
    Member toMember = null;
    final Member restricted = WebServiceContext.getMember();
    if (restricted != null) {
      // When restricted to a member, he is always the to
      toMember = restricted;
    } else {
      try {
        toMember = paymentHelper.resolveToMember(params);
      } catch (final EntityNotFoundException e) {
        status = PaymentRequestStatus.TO_NOT_FOUND;
      }
      // When not restricted to a member, check the channel access of the payment receiver
      if (status == null && !memberHelper.isChannelEnabledForMember(toMember)) {
        status = PaymentRequestStatus.TO_INVALID_CHANNEL;
      }
    }
    // Get the from member
    Member fromMember = null;
    if (status == null) {
      try {
        fromMember = paymentHelper.resolveFromMember(params);
      } catch (final EntityNotFoundException e) {
        status = PaymentRequestStatus.FROM_NOT_FOUND;
      }
    }

    // Generate the ticket if no error so far
    PaymentRequestTicket ticket = null;
    if (status == null) {
      try {
        ticket = paymentHelper.toTicket(params, null);
        ticket.setFrom(fromMember);
        ticket.setTo(toMember);
        ticket = ticketService.generate(ticket);
        status = PaymentRequestStatus.REQUEST_RECEIVED;
      } catch (final InvalidChannelException e) {
        status = PaymentRequestStatus.FROM_INVALID_CHANNEL;
      } catch (final Exception e) {
        errorException = e;
        final PaymentStatus paymentStatus = paymentHelper.toStatus(e);
        try {
          // Probably it's a payment status also present on payment request status
          status = PaymentRequestStatus.valueOf(paymentStatus.name());
        } catch (final Exception e1) {
          e1.initCause(e);
          errorException = e1;
          status = PaymentRequestStatus.UNKNOWN_ERROR;
        }
      }
    }

    if (!status.isSuccessful()) {
      webServiceHelper.error(
          errorException != null
              ? errorException
              : new Exception("Request payment confirmation status: " + status));
    }

    // Build a result
    final RequestPaymentResult result = new RequestPaymentResult();
    result.setStatus(status);
    if (ticket != null) {
      result.setTicket(ticket.getTicket());
    }
    return result;
  }