public PaymentSimulationResult simulatePayment(final PaymentParameters params) {

    PaymentStatus status;
    AccountHistoryTransferVO transferVO = null;

    try {
      final PrepareParametersResult result = prepareParameters(params);
      status = result.getStatus();

      if (status == null) {
        final DoExternalPaymentDTO dto =
            paymentHelper.toExternalPaymentDTO(params, result.getFrom(), result.getTo());
        if (!validateTransferType(dto)) {
          webServiceHelper.trace(
              PaymentStatus.INVALID_PARAMETERS
                  + ". Reason: The service client doesn't have permission to the specified transfer type: "
                  + dto.getTransferType());
          status = PaymentStatus.INVALID_PARAMETERS;
        } else {
          // Simulate the payment
          final Transfer transfer = (Transfer) paymentService.simulatePayment(dto);
          transferVO = accountHelper.toVO(WebServiceContext.getMember(), transfer, null);
          status = paymentHelper.toStatus(transfer);
        }
      }
    } catch (final Exception e) {
      webServiceHelper.error(e);
      status = paymentHelper.toStatus(e);
    }

    if (!status.isSuccessful()) {
      webServiceHelper.error("Simulate payment status: " + status);
    }
    return new PaymentSimulationResult(status, transferVO);
  }
  private ChargebackResult doChargeback(final Transfer transfer) {
    ChargebackStatus status = null;
    Transfer chargebackTransfer = null;

    // Check if the transfer can be charged back
    if (!paymentService.canChargeback(transfer, false)) {
      if (transfer.getChargedBackBy() != null) {
        chargebackTransfer = transfer.getChargedBackBy();
        status = ChargebackStatus.TRANSFER_ALREADY_CHARGEDBACK;
      } else {
        if (transfer.getStatus() == Payment.Status.PENDING) {
          final TransferAuthorizationDTO transferAuthorizationDto = new TransferAuthorizationDTO();
          transferAuthorizationDto.setTransfer(transfer);
          transferAuthorizationDto.setShowToMember(false);
          chargebackTransfer =
              transferAuthorizationService.cancelFromMemberAsReceiver(transferAuthorizationDto);
          status = ChargebackStatus.SUCCESS;
        } else {
          status = ChargebackStatus.TRANSFER_CANNOT_BE_CHARGEDBACK;
        }
      }
    }

    // Do the chargeback
    if (status == null) {
      chargebackTransfer =
          paymentService.chargeback(transfer, WebServiceContext.getClient().getId());
      status = ChargebackStatus.SUCCESS;
    }

    if (!status.isSuccessful()) {
      webServiceHelper.error("Chargeback result: " + status);
    }

    final Member member = WebServiceContext.getMember();
    // Build the result
    if (status == ChargebackStatus.SUCCESS
        || status == ChargebackStatus.TRANSFER_ALREADY_CHARGEDBACK) {
      final AccountOwner owner = member == null ? transfer.getToOwner() : member;
      final AccountHistoryTransferVO originalVO = accountHelper.toVO(owner, transfer, null);
      final AccountHistoryTransferVO chargebackVO =
          accountHelper.toVO(owner, chargebackTransfer, null);
      return new ChargebackResult(status, originalVO, chargebackVO);
    } else {
      return new ChargebackResult(status, null, null);
    }
  }
  public PaymentResult doPayment(final PaymentParameters params) {
    AccountHistoryTransferVO transferVO = null;
    PaymentStatus status;
    AccountStatus fromMemberStatus = null;
    AccountStatus toMemberStatus = null;
    try {
      final PrepareParametersResult result = prepareParameters(params);
      status = result.getStatus();

      if (status == null) {
        // Status null means no "pre-payment" errors (like validation, pin, channel...)
        // Perform the payment
        final DoExternalPaymentDTO dto =
            paymentHelper.toExternalPaymentDTO(params, result.getFrom(), result.getTo());

        // Validate the transfer type
        if (!validateTransferType(dto)) {
          status = PaymentStatus.INVALID_PARAMETERS;
          webServiceHelper.trace(
              status
                  + ". Reason: The service client doesn't have permission to the specified transfer type: "
                  + dto.getTransferType());
        } else {
          final Transfer transfer = (Transfer) paymentService.insertExternalPayment(dto);
          status = paymentHelper.toStatus(transfer);
          transferVO = accountHelper.toVO(WebServiceContext.getMember(), transfer, null);

          if (WebServiceContext.getClient()
                  .getPermissions()
                  .contains(ServiceOperation.ACCOUNT_DETAILS)
              && params.isReturnStatus()) {
            if (WebServiceContext.getMember() == null) {
              fromMemberStatus =
                  accountService.getStatus(
                      new GetTransactionsDTO(dto.getFrom(), dto.getTransferType().getFrom()));
              toMemberStatus =
                  accountService.getStatus(
                      new GetTransactionsDTO(dto.getTo(), dto.getTransferType().getTo()));
            } else if (WebServiceContext.getMember()
                .equals(paymentHelper.resolveFromMember(params))) {
              fromMemberStatus =
                  accountService.getStatus(
                      new GetTransactionsDTO(dto.getFrom(), dto.getTransferType().getFrom()));
            } else {
              toMemberStatus =
                  accountService.getStatus(
                      new GetTransactionsDTO(dto.getTo(), dto.getTransferType().getTo()));
            }
          }
        }
      }
    } catch (final Exception e) {
      webServiceHelper.error(e);
      status = paymentHelper.toStatus(e);
    }

    if (!status.isSuccessful()) {
      webServiceHelper.error("Payment status: " + status);
    }

    return new PaymentResult(
        status,
        transferVO,
        accountHelper.toVO(fromMemberStatus),
        accountHelper.toVO(toMemberStatus));
  }
  public PaymentResult confirmPayment(final ConfirmPaymentParameters params) {
    Exception errorException = null;
    AccountStatus fromMemberStatus = null;
    AccountStatus toMemberStatus = null;
    Member fromMember = null;
    Member toMember = null;

    // It's nonsense to use this if restricted to a member
    if (WebServiceContext.getMember() != null) {
      throw new PermissionDeniedException();
    }
    final Channel channel = WebServiceContext.getChannel();
    final String channelName = channel == null ? null : channel.getInternalName();

    PaymentStatus status = null;
    AccountHistoryTransferVO transferVO = null;

    // Get the ticket
    PaymentRequestTicket ticket = null;
    try {
      // Check that the ticket is valid
      final Ticket t = ticketService.load(params.getTicket());
      fromMember = t.getFrom();
      toMember = t.getTo();

      if (!(t instanceof PaymentRequestTicket) || t.getStatus() != Ticket.Status.PENDING) {
        throw new Exception(
            "Invalid ticket and/or status: "
                + t.getClass().getName()
                + ", status: "
                + t.getStatus());
      }
      // Check that the channel is the expected one
      ticket = (PaymentRequestTicket) t;
      if (!ticket.getToChannel().getInternalName().equals(channelName)) {
        throw new Exception(
            "The ticket's destination channel is not the expected one (expected="
                + channelName
                + "): "
                + ticket.getToChannel().getInternalName());
      }
    } catch (final Exception e) {
      errorException = e;
      status = PaymentStatus.INVALID_PARAMETERS;
    }

    // Validate the Channel and credentials
    Member member = null;
    if (status == null) {
      member = ticket.getFrom();
      if (!accessService.isChannelEnabledForMember(channelName, member)) {
        status = PaymentStatus.INVALID_CHANNEL;
      }
      if (status == null && WebServiceContext.getClient().isCredentialsRequired()) {
        try {
          checkCredentials(member, channel, params.getCredentials());
        } catch (final InvalidCredentialsException e) {
          status = PaymentStatus.INVALID_CREDENTIALS;
        } catch (final BlockedCredentialsException e) {
          status = PaymentStatus.BLOCKED_CREDENTIALS;
        }
      }
    }
    // Confirm the payment
    if (status == null) {
      try {
        final Transfer transfer = (Transfer) paymentService.confirmPayment(ticket.getTicket());
        transferVO = accountHelper.toVO(member, transfer, null);
        status = paymentHelper.toStatus(transfer);

        if (WebServiceContext.getClient()
            .getPermissions()
            .contains(ServiceOperation.ACCOUNT_DETAILS)) {
          if (WebServiceContext.getMember() == null) {
            fromMemberStatus =
                accountService.getStatus(
                    new GetTransactionsDTO(fromMember, transfer.getFrom().getType()));
            toMemberStatus =
                accountService.getStatus(
                    new GetTransactionsDTO(toMember, transfer.getTo().getType()));
          } else if (WebServiceContext.getMember().equals(fromMember)) {
            fromMemberStatus =
                accountService.getStatus(
                    new GetTransactionsDTO(fromMember, transfer.getFrom().getType()));
          } else {
            toMemberStatus =
                accountService.getStatus(
                    new GetTransactionsDTO(toMember, transfer.getTo().getType()));
          }
        }
      } catch (final Exception e) {
        errorException = e;
        status = paymentHelper.toStatus(e);
      }
    }

    if (!status.isSuccessful()) {
      webServiceHelper.error(
          errorException != null
              ? errorException
              : new Exception("Confirm payment status: " + status));
    }
    // Build the result
    return new PaymentResult(
        status,
        transferVO,
        accountHelper.toVO(fromMemberStatus),
        accountHelper.toVO(toMemberStatus));
  }