use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.
the class TestPaymentLeavingStateCallback method testLeaveStateForNewPayment.
@Test(groups = "slow")
public void testLeaveStateForNewPayment() throws Exception {
setUp(null);
callback.leavingState(state);
// Verify a new transaction was created
verifyPaymentTransaction();
// Verify a new payment was created
final PaymentModelDao payment = paymentDao.getPayment(paymentStateContext.getPaymentTransactionModelDao().getPaymentId(), internalCallContext);
Assert.assertEquals(payment.getExternalKey(), paymentStateContext.getPaymentExternalKey());
Assert.assertNull(payment.getStateName());
// Verify the payment has only one transaction
Assert.assertEquals(paymentDao.getTransactionsForPayment(payment.getId(), internalCallContext).size(), 1);
}
use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.
the class TestPaymentLeavingStateCallback method setUp.
private void setUp(@Nullable final UUID paymentId) throws Exception {
account = Mockito.mock(Account.class);
Mockito.when(account.getId()).thenReturn(UUID.randomUUID());
paymentStateContext = new PaymentStateContext(true, paymentId, null, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), TransactionType.CAPTURE, account, UUID.randomUUID(), new BigDecimal("192.3920111"), Currency.BRL, null, null, null, false, null, ImmutableList.<PluginProperty>of(), internalCallContext, callContext);
if (paymentId != null) {
// Create the first payment manually
final PaymentModelDao newPaymentModelDao = new PaymentModelDao(paymentId, clock.getUTCNow(), clock.getUTCNow(), paymentStateContext.getAccount().getId(), paymentStateContext.getPaymentMethodId(), 1, paymentStateContext.getPaymentExternalKey());
final PaymentTransactionModelDao newPaymentTransactionModelDao = new PaymentTransactionModelDao(clock.getUTCNow(), clock.getUTCNow(), null, paymentStateContext.getPaymentTransactionExternalKey(), paymentId, paymentStateContext.getTransactionType(), clock.getUTCNow(), TransactionStatus.UNKNOWN, paymentStateContext.getAmount(), paymentStateContext.getCurrency(), null, null);
paymentDao.insertPaymentWithFirstTransaction(newPaymentModelDao, newPaymentTransactionModelDao, internalCallContext);
}
final PaymentAutomatonDAOHelper daoHelper = new PaymentAutomatonDAOHelper(paymentStateContext, clock.getUTCNow(), paymentDao, paymentPluginServiceRegistration, internalCallContext, eventBus, paymentSMHelper);
callback = new PaymentLeavingStateTestCallback(daoHelper, paymentStateContext);
Mockito.when(state.getName()).thenReturn("NEW_STATE");
}
use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.
the class PaymentRefresher method invokeJanitor.
// Invoke the Janitor on-the-fly for all GET operations and for most payment operations (except notifyPendingPaymentOfStateChanged)
public PaymentModelDao invokeJanitor(final PaymentModelDao curPaymentModelDao, final Collection<PaymentTransactionModelDao> curTransactionsModelDao, @Nullable final Iterable<PaymentTransactionInfoPlugin> pluginTransactions, final boolean isApiPayment, final InternalTenantContext internalTenantContext) {
PaymentModelDao newPaymentModelDao = curPaymentModelDao;
final Collection<PaymentTransactionModelDao> transactionsModelDao = new LinkedList<PaymentTransactionModelDao>();
for (final PaymentTransactionModelDao curPaymentTransactionModelDao : curTransactionsModelDao) {
PaymentTransactionModelDao newPaymentTransactionModelDao = curPaymentTransactionModelDao;
final PaymentTransactionInfoPlugin paymentTransactionInfoPlugin = findPaymentTransactionInfoPlugin(newPaymentTransactionModelDao, pluginTransactions);
if (paymentTransactionInfoPlugin != null) {
// Make sure to invoke the Janitor task in case the plugin fixes its state on the fly
// See https://github.com/killbill/killbill/issues/341
final boolean hasChanged = invokeJanitor(newPaymentModelDao.getAccountId(), newPaymentTransactionModelDao, paymentTransactionInfoPlugin, isApiPayment, internalTenantContext);
if (hasChanged) {
newPaymentModelDao = paymentDao.getPayment(newPaymentModelDao.getId(), internalTenantContext);
newPaymentTransactionModelDao = paymentDao.getPaymentTransaction(newPaymentTransactionModelDao.getId(), internalTenantContext);
}
} else {
log.debug("Unable to find transaction={} from pluginTransactions={}", curPaymentTransactionModelDao, pluginTransactions);
}
transactionsModelDao.add(newPaymentTransactionModelDao);
}
curTransactionsModelDao.clear();
curTransactionsModelDao.addAll(transactionsModelDao);
return newPaymentModelDao;
}
use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.
the class PluginControlPaymentProcessor method retryPaymentTransaction.
public void retryPaymentTransaction(final UUID attemptId, final List<String> paymentControlPluginNames, final InternalCallContext internalCallContext) {
final PaymentAttemptModelDao attempt = paymentDao.getPaymentAttempt(attemptId, internalCallContext);
log.info("Retrying attemptId='{}', paymentExternalKey='{}', transactionExternalKey='{}'. paymentControlPluginNames='{}'", attemptId, attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), paymentControlPluginNames);
final PaymentModelDao paymentModelDao = paymentDao.getPaymentByExternalKey(attempt.getPaymentExternalKey(), internalCallContext);
final UUID paymentId = paymentModelDao != null ? paymentModelDao.getId() : null;
final CallContext callContext = buildCallContext(internalCallContext);
final String transactionType = TransactionType.PURCHASE.name();
Account account = null;
Payment payment = null;
PaymentTransaction paymentTransaction = null;
try {
account = accountInternalApi.getAccountById(attempt.getAccountId(), internalCallContext);
final State state = paymentControlStateMachineHelper.getState(attempt.getStateName());
final Iterable<PluginProperty> pluginProperties = PluginPropertySerializer.deserialize(attempt.getPluginProperties());
logEnterAPICall(log, transactionType, account, attempt.getPaymentMethodId(), paymentId, null, attempt.getAmount(), attempt.getCurrency(), attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), null, paymentControlPluginNames);
payment = pluginControlledPaymentAutomatonRunner.run(state, false, attempt.getTransactionType(), ControlOperation.valueOf(attempt.getTransactionType().toString()), account, attempt.getPaymentMethodId(), paymentId, attempt.getPaymentExternalKey(), attempt.getTransactionExternalKey(), // The amount on the payment attempt drives the amount of the new payment transaction
attempt.getAmount(), attempt.getCurrency(), null, pluginProperties, paymentControlPluginNames, callContext, internalCallContext);
log.debug("retryPaymentTransaction result: payment='{}'", payment);
paymentTransaction = Iterables.<PaymentTransaction>find(Lists.<PaymentTransaction>reverse(payment.getTransactions()), new Predicate<PaymentTransaction>() {
@Override
public boolean apply(final PaymentTransaction input) {
return attempt.getTransactionExternalKey().equals(input.getExternalKey());
}
});
} catch (final AccountApiException e) {
log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
} catch (final PaymentApiException e) {
// Log exception unless nothing left to be paid
if (e.getCode() == ErrorCode.PAYMENT_PLUGIN_API_ABORTED.getCode() && paymentControlPluginNames != null && paymentControlPluginNames.size() == 1 && InvoicePaymentControlPluginApi.PLUGIN_NAME.equals(paymentControlPluginNames.get(0))) {
log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames));
} else {
log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
}
} catch (final PluginPropertySerializerException e) {
log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
} catch (final MissingEntryException e) {
log.warn("Failed to retry attemptId='{}', paymentControlPlugins='{}'", attemptId, toPluginNamesOnError(paymentControlPluginNames), e);
} finally {
logExitAPICall(log, transactionType, account, payment != null ? payment.getPaymentMethodId() : null, payment != null ? payment.getId() : null, paymentTransaction != null ? paymentTransaction.getId() : null, paymentTransaction != null ? paymentTransaction.getProcessedAmount() : null, paymentTransaction != null ? paymentTransaction.getProcessedCurrency() : null, payment != null ? payment.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getExternalKey() : null, paymentTransaction != null ? paymentTransaction.getTransactionStatus() : null, paymentControlPluginNames, null);
}
}
use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.
the class PaymentAutomatonRunner method retrievePaymentId.
// TODO Could we cache these to avoid extra queries in PaymentAutomatonDAOHelper?
private UUID retrievePaymentId(@Nullable final String paymentExternalKey, @Nullable final String paymentTransactionExternalKey, final InternalCallContext internalCallContext) throws PaymentApiException {
if (paymentExternalKey != null) {
final PaymentModelDao payment = paymentDao.getPaymentByExternalKey(paymentExternalKey, internalCallContext);
if (payment != null) {
return payment.getId();
}
}
if (paymentTransactionExternalKey == null) {
return null;
}
final List<PaymentTransactionModelDao> paymentTransactionModelDaos = paymentDao.getPaymentTransactionsByExternalKey(paymentTransactionExternalKey, internalCallContext);
for (final PaymentTransactionModelDao paymentTransactionModelDao : paymentTransactionModelDaos) {
if (paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.SUCCESS || paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.PENDING || paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.UNKNOWN) {
return paymentTransactionModelDao.getPaymentId();
}
}
UUID paymentIdCandidate = null;
for (final PaymentTransactionModelDao paymentTransactionModelDao : paymentTransactionModelDaos) {
if (paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.PAYMENT_FAILURE || paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.PLUGIN_FAILURE) {
if (paymentIdCandidate == null) {
paymentIdCandidate = paymentTransactionModelDao.getPaymentId();
} else if (!paymentIdCandidate.equals(paymentTransactionModelDao.getPaymentId())) {
throw new PaymentApiException(ErrorCode.PAYMENT_INTERNAL_ERROR, "Multiple failed payments sharing the same transaction external key - this should never happen");
}
}
}
return paymentIdCandidate;
}
Aggregations