use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.
the class TestRetryablePayment method testInitToSuccessWithResFailure.
@Test(groups = "fast")
public void testInitToSuccessWithResFailure() throws PaymentApiException {
mockRetryProviderPlugin.setAborted(false).setNextRetryDate(null);
mockRetryAuthorizeOperationCallback.setResult(OperationResult.FAILURE).setException(null);
runner.setOperationCallback(mockRetryAuthorizeOperationCallback).setContext(paymentStateContext);
runner.run(true, TransactionType.AUTHORIZE, ControlOperation.AUTHORIZE, account, paymentMethodId, null, paymentExternalKey, paymentTransactionExternalKey, amount, currency, null, emptyProperties, null, callContext, internalCallContext);
final PaymentAttemptModelDao pa = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionExternalKey, internalCallContext).get(0);
assertEquals(pa.getTransactionExternalKey(), paymentTransactionExternalKey);
assertEquals(pa.getStateName(), "SUCCESS");
assertEquals(pa.getTransactionType(), TransactionType.AUTHORIZE);
}
use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.
the class TestRetryablePayment method testRetryLogicFromRetriedStateWithSuccess.
@Test(groups = "fast")
public void testRetryLogicFromRetriedStateWithSuccess() throws PaymentApiException {
mockRetryProviderPlugin.setAborted(false).setNextRetryDate(null);
mockRetryAuthorizeOperationCallback.setResult(OperationResult.SUCCESS).setException(null);
runner.setOperationCallback(mockRetryAuthorizeOperationCallback).setContext(paymentStateContext);
final State state = retrySMHelper.getRetriedState();
final UUID transactionId = UUID.randomUUID();
final UUID paymentId = UUID.randomUUID();
final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(account.getId(), paymentMethodId, utcNow, utcNow, paymentExternalKey, transactionId, paymentTransactionExternalKey, TransactionType.AUTHORIZE, state.getName(), amount, currency, null, EMPTY_PROPERTIES);
paymentDao.insertPaymentAttemptWithProperties(attempt, internalCallContext);
paymentDao.insertPaymentWithFirstTransaction(new PaymentModelDao(paymentId, utcNow, utcNow, account.getId(), paymentMethodId, -1, paymentExternalKey), new PaymentTransactionModelDao(transactionId, attempt.getId(), paymentTransactionExternalKey, utcNow, utcNow, paymentId, TransactionType.AUTHORIZE, utcNow, TransactionStatus.PAYMENT_FAILURE, amount, currency, "bla", "foo"), internalCallContext);
processor.retryPaymentTransaction(attempt.getId(), ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME), internalCallContext);
final List<PaymentAttemptModelDao> pas = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionExternalKey, internalCallContext);
assertEquals(pas.size(), 2);
final PaymentAttemptModelDao successfulAttempt = Iterables.tryFind(pas, new Predicate<PaymentAttemptModelDao>() {
@Override
public boolean apply(final PaymentAttemptModelDao input) {
return input.getTransactionType() == TransactionType.AUTHORIZE && input.getStateName().equals("SUCCESS");
}
}).orNull();
assertNotNull(successfulAttempt);
}
use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.
the class TestInvoicePayment method testWithoutDefaultPaymentMethodAndAUTO_PAY_OFF.
@Test(groups = "slow")
public void testWithoutDefaultPaymentMethodAndAUTO_PAY_OFF() throws Exception {
// 2012-05-01T00:03:42.000Z
clock.setTime(new DateTime(2012, 5, 1, 0, 3, 42, 0));
final AccountData accountData = getAccountData(0);
final Account account = createAccount(accountData);
accountChecker.checkAccount(account.getId(), accountData, callContext);
final DefaultEntitlement baseEntitlement = createBaseEntitlementAndCheckForCompletion(account.getId(), "externalKey", "Shotgun", ProductCategory.BASE, BillingPeriod.MONTHLY, NextEvent.CREATE, NextEvent.BLOCK, NextEvent.INVOICE);
final Invoice invoice1 = invoiceChecker.checkInvoice(account.getId(), 1, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 1), null, InvoiceItemType.FIXED, new BigDecimal("0")));
invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 5, 1), callContext);
// No invoice payment
Assert.assertEquals(invoice1.getPayments().size(), 0);
// There is one dangling payment attempt (not easy to get to...)
final List<AuditLog> paymentAttemptsAuditLogs1 = new ArrayList<AuditLog>();
for (final AuditLog auditLog : auditUserApi.getAccountAuditLogs(account.getId(), AuditLevel.FULL, callContext).getAuditLogs()) {
if (auditLog.getAuditedObjectType() == ObjectType.PAYMENT_ATTEMPT) {
paymentAttemptsAuditLogs1.add(auditLog);
}
}
// One INSERT and one UPDATE
Assert.assertEquals(paymentAttemptsAuditLogs1.size(), 2);
final PaymentAttemptModelDao paymentAttempt1 = paymentDao.getPaymentAttempt(paymentAttemptsAuditLogs1.get(0).getAuditedEntityId(), internalCallContext);
Assert.assertEquals(paymentAttempt1.getStateName(), "ABORTED");
// Put the account in AUTO_PAY_OFF
add_AUTO_PAY_OFF_Tag(account.getId(), ObjectType.ACCOUNT);
// 2012-05-31 => DAY 30 have to get out of trial {I0, P0}
addDaysAndCheckForCompletion(30, NextEvent.PHASE, NextEvent.INVOICE);
Invoice invoice2 = invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
invoiceChecker.checkChargedThroughDate(baseEntitlement.getId(), new LocalDate(2012, 6, 30), callContext);
// Invoice is not paid
Assert.assertEquals(paymentApi.getAccountPayments(account.getId(), false, false, ImmutableList.<PluginProperty>of(), callContext).size(), 0);
Assert.assertEquals(invoice2.getBalance().compareTo(new BigDecimal("249.95")), 0);
Assert.assertEquals(invoiceUserApi.getAccountBalance(account.getId(), callContext).compareTo(invoice2.getBalance()), 0);
// There is no invoice payment
Assert.assertEquals(invoice2.getPayments().size(), 0);
// There is another dangling payment attempt (not easy to get to...)
final List<AuditLog> paymentAttemptsAuditLogs2 = new ArrayList<AuditLog>();
for (final AuditLog auditLog : auditUserApi.getAccountAuditLogs(account.getId(), AuditLevel.FULL, callContext).getAuditLogs()) {
if (auditLog.getAuditedObjectType() == ObjectType.PAYMENT_ATTEMPT && !paymentAttemptsAuditLogs1.contains(auditLog)) {
paymentAttemptsAuditLogs2.add(auditLog);
}
}
// One INSERT and one UPDATE
Assert.assertEquals(paymentAttemptsAuditLogs2.size(), 2);
final PaymentAttemptModelDao paymentAttempt2 = paymentDao.getPaymentAttempt(paymentAttemptsAuditLogs2.get(0).getAuditedEntityId(), internalCallContext);
Assert.assertEquals(paymentAttempt2.getStateName(), "ABORTED");
// Just verify we've found the right one
Assert.assertNotEquals(paymentAttempt2.getId(), paymentAttempt1.getId());
}
use of org.killbill.billing.payment.dao.PaymentAttemptModelDao in project killbill by killbill.
the class PluginControlPaymentProcessor method notifyPendingPaymentOfStateChanged.
public Payment notifyPendingPaymentOfStateChanged(final boolean isApiPayment, final Account account, final UUID paymentTransactionId, final boolean isSuccess, final List<String> paymentControlPluginNames, final CallContext callContext, final InternalCallContext internalCallContext) throws PaymentApiException {
final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(paymentTransactionId, internalCallContext);
final List<PaymentAttemptModelDao> attempts = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey(), internalCallContext);
final PaymentAttemptModelDao attempt = Iterables.find(attempts, new Predicate<PaymentAttemptModelDao>() {
@Override
public boolean apply(final PaymentAttemptModelDao input) {
return input.getTransactionId().equals(paymentTransactionId);
}
});
final Iterable<PluginProperty> pluginProperties;
try {
pluginProperties = PluginPropertySerializer.deserialize(attempt.getPluginProperties());
} catch (final PluginPropertySerializerException e) {
throw new PaymentApiException(e, ErrorCode.PAYMENT_INTERNAL_ERROR, String.format("Unable to deserialize payment attemptId='%s' properties", attempt.getId()));
}
return pluginControlledPaymentAutomatonRunner.run(isApiPayment, isSuccess, paymentTransactionModelDao.getTransactionType(), ControlOperation.NOTIFICATION_OF_STATE_CHANGE, account, attempt.getPaymentMethodId(), paymentTransactionModelDao.getPaymentId(), attempt.getPaymentExternalKey(), paymentTransactionId, paymentTransactionModelDao.getTransactionExternalKey(), paymentTransactionModelDao.getAmount(), paymentTransactionModelDao.getCurrency(), null, pluginProperties, paymentControlPluginNames, callContext, internalCallContext);
}
use of org.killbill.billing.payment.dao.PaymentAttemptModelDao 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);
}
}
Aggregations