private void setUp(final PaymentPluginStatus paymentPluginStatus) throws Exception {
    final GlobalLocker locker = new MemoryGlobalLocker();
    final PluginDispatcher<OperationResult> paymentPluginDispatcher =
        new PluginDispatcher<OperationResult>(1, Executors.newCachedThreadPool());
    paymentStateContext =
        new PaymentStateContext(
            true,
            UUID.randomUUID(),
            null,
            null,
            UUID.randomUUID().toString(),
            UUID.randomUUID().toString(),
            TransactionType.CAPTURE,
            Mockito.mock(Account.class),
            UUID.randomUUID(),
            new BigDecimal("192.3920111"),
            Currency.BRL,
            false,
            null,
            ImmutableList.<PluginProperty>of(),
            internalCallContext,
            callContext);

    final PaymentMethodModelDao paymentMethodModelDao =
        new PaymentMethodModelDao(
            paymentStateContext.getPaymentMethodId(),
            UUID.randomUUID().toString(),
            clock.getUTCNow(),
            clock.getUTCNow(),
            paymentStateContext.getAccount().getId(),
            MockPaymentProviderPlugin.PLUGIN_NAME,
            true);
    final PaymentDao paymentDao = Mockito.mock(PaymentDao.class);
    Mockito.when(
            paymentDao.getPaymentMethodIncludedDeleted(
                paymentStateContext.getPaymentMethodId(), internalCallContext))
        .thenReturn(paymentMethodModelDao);

    final PaymentAutomatonDAOHelper daoHelper =
        new PaymentAutomatonDAOHelper(
            paymentStateContext,
            clock.getUTCNow(),
            paymentDao,
            registry,
            internalCallContext,
            eventBus,
            paymentSMHelper);
    paymentOperation =
        new PaymentOperationTest(
            paymentPluginStatus, daoHelper, locker, paymentPluginDispatcher, paymentStateContext);
  }
  @Override
  public void leavingState(final State state) throws OperationException {
    final DateTime utcNow = pluginControlPaymentAutomatonRunner.getClock().getUTCNow();

    // Retrieve the associated payment transaction, if any
    PaymentTransactionModelDao paymentTransactionModelDaoCandidate = null;
    if (stateContext.getTransactionId() != null) {
      paymentTransactionModelDaoCandidate =
          paymentDao.getPaymentTransaction(
              stateContext.getTransactionId(), stateContext.getInternalCallContext());
      Preconditions.checkNotNull(
          paymentTransactionModelDaoCandidate,
          "paymentTransaction cannot be null for id " + stateContext.getTransactionId());
    } else if (stateContext.getPaymentTransactionExternalKey() != null) {
      final List<PaymentTransactionModelDao> paymentTransactionModelDaos =
          paymentDao.getPaymentTransactionsByExternalKey(
              stateContext.getPaymentTransactionExternalKey(),
              stateContext.getInternalCallContext());
      if (!paymentTransactionModelDaos.isEmpty()) {
        paymentTransactionModelDaoCandidate =
            paymentTransactionModelDaos.get(paymentTransactionModelDaos.size() - 1);
      }
    }
    final PaymentTransactionModelDao paymentTransactionModelDao =
        paymentTransactionModelDaoCandidate != null
                && TRANSIENT_TRANSACTION_STATUSES.contains(
                    paymentTransactionModelDaoCandidate.getTransactionStatus())
            ? paymentTransactionModelDaoCandidate
            : null;

    if (stateContext.getPaymentId() != null && stateContext.getPaymentExternalKey() == null) {
      final PaymentModelDao payment =
          paymentDao.getPayment(stateContext.getPaymentId(), stateContext.getInternalCallContext());
      Preconditions.checkNotNull(
          payment, "payment cannot be null for id " + stateContext.getPaymentId());
      stateContext.setPaymentExternalKey(payment.getExternalKey());
      stateContext.setPaymentMethodId(payment.getPaymentMethodId());
    } else if (stateContext.getPaymentExternalKey() == null) {
      stateContext.setPaymentExternalKey(UUIDs.randomUUID().toString());
    }

    if (paymentTransactionModelDao != null) {
      stateContext.setPaymentTransactionExternalKey(
          paymentTransactionModelDao.getTransactionExternalKey());
    } else if (stateContext.getPaymentTransactionExternalKey() == null) {
      stateContext.setPaymentTransactionExternalKey(UUIDs.randomUUID().toString());
    }

    if (stateContext.getPaymentMethodId() == null) {
      // Similar logic in PaymentAutomatonRunner
      stateContext.setPaymentMethodId(stateContext.getAccount().getPaymentMethodId());
    }

    if (state.getName().equals(initialState.getName())
        || state.getName().equals(retriedState.getName())) {
      try {
        final PaymentAttemptModelDao attempt;
        if (paymentTransactionModelDao != null
            && paymentTransactionModelDao.getAttemptId() != null) {
          attempt =
              pluginControlPaymentAutomatonRunner
                  .getPaymentDao()
                  .getPaymentAttempt(
                      paymentTransactionModelDao.getAttemptId(),
                      stateContext.getInternalCallContext());
          Preconditions.checkNotNull(
              attempt,
              "attempt cannot be null for id " + paymentTransactionModelDao.getAttemptId());
        } else {
          //
          // We don't serialize any properties at this stage to avoid serializing sensitive
          // information.
          // However, if after going through the control plugins, the attempt end up in RETRIED
          // state,
          // the properties will be serialized in the enteringState callback (any plugin that sets a
          // retried date is responsible to correctly remove sensitive information such as CVV, ...)
          //
          final byte[] serializedProperties =
              PluginPropertySerializer.serialize(ImmutableList.<PluginProperty>of());

          attempt =
              new PaymentAttemptModelDao(
                  stateContext.getAccount().getId(),
                  stateContext.getPaymentMethodId(),
                  utcNow,
                  utcNow,
                  stateContext.getPaymentExternalKey(),
                  stateContext.getTransactionId(),
                  stateContext.getPaymentTransactionExternalKey(),
                  transactionType,
                  initialState.getName(),
                  stateContext.getAmount(),
                  stateContext.getCurrency(),
                  stateContext.getPaymentControlPluginNames(),
                  serializedProperties);
          pluginControlPaymentAutomatonRunner
              .getPaymentDao()
              .insertPaymentAttemptWithProperties(attempt, stateContext.getInternalCallContext());
        }

        stateContext.setAttemptId(attempt.getId());
      } catch (final PluginPropertySerializerException e) {
        throw new OperationException(e);
      }
    }
  }