use of org.killbill.billing.payment.dao.PaymentTransactionModelDao in project killbill by killbill.
the class InvoicePaymentControlPluginApi method onSuccessCall.
@Override
public OnSuccessPaymentControlResult onSuccessCall(final PaymentControlContext paymentControlContext, final Iterable<PluginProperty> pluginProperties) throws PaymentControlApiException {
final TransactionType transactionType = paymentControlContext.getTransactionType();
Preconditions.checkArgument(transactionType == TransactionType.PURCHASE || transactionType == TransactionType.REFUND || transactionType == TransactionType.CHARGEBACK || transactionType == TransactionType.CREDIT);
final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
try {
final InvoicePayment existingInvoicePayment;
switch(transactionType) {
case PURCHASE:
final UUID invoiceId = getInvoiceId(pluginProperties);
existingInvoicePayment = invoiceApi.getInvoicePaymentForAttempt(paymentControlContext.getPaymentId(), internalContext);
if (existingInvoicePayment != null && existingInvoicePayment.isSuccess()) {
// Only one successful purchase per payment (the invoice could be linked to multiple successful payments though)
log.info("onSuccessCall was already completed for purchase paymentId='{}'", paymentControlContext.getPaymentId());
} else {
final BigDecimal invoicePaymentAmount;
if (paymentControlContext.getCurrency() == paymentControlContext.getProcessedCurrency()) {
invoicePaymentAmount = paymentControlContext.getProcessedAmount();
} else {
log.warn("processedCurrency='{}' of invoice paymentId='{}' doesn't match invoice currency='{}', assuming it is a full payment", paymentControlContext.getProcessedCurrency(), paymentControlContext.getPaymentId(), paymentControlContext.getCurrency());
invoicePaymentAmount = paymentControlContext.getAmount();
}
final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(paymentControlContext.getTransactionId(), internalContext);
// If it's not SUCCESS, it is PENDING
final boolean success = paymentTransactionModelDao.getTransactionStatus() == TransactionStatus.SUCCESS;
log.debug("Notifying invoice of {} paymentId='{}', amount='{}', currency='{}', invoiceId='{}'", success ? "successful" : "pending", paymentControlContext.getPaymentId(), invoicePaymentAmount, paymentControlContext.getCurrency(), invoiceId);
// For PENDING payments, the attempt will be kept as unsuccessful and an InvoicePaymentErrorInternalEvent sent on the bus (e.g. for Overdue)
invoiceApi.recordPaymentAttemptCompletion(invoiceId, invoicePaymentAmount, paymentControlContext.getCurrency(), paymentControlContext.getProcessedCurrency(), paymentControlContext.getPaymentId(), paymentControlContext.getTransactionExternalKey(), paymentControlContext.getCreatedDate(), success, internalContext);
}
break;
case REFUND:
final Map<UUID, BigDecimal> idWithAmount = extractIdsWithAmountFromProperties(pluginProperties);
final PluginProperty prop = getPluginProperty(pluginProperties, PROP_IPCD_REFUND_WITH_ADJUSTMENTS);
final boolean isAdjusted = prop != null ? Boolean.valueOf((String) prop.getValue()) : false;
invoiceApi.recordRefund(paymentControlContext.getPaymentId(), paymentControlContext.getAmount(), isAdjusted, idWithAmount, paymentControlContext.getTransactionExternalKey(), internalContext);
break;
case CHARGEBACK:
existingInvoicePayment = invoiceApi.getInvoicePaymentForChargeback(paymentControlContext.getPaymentId(), internalContext);
if (existingInvoicePayment != null) {
// We don't support partial chargebacks (yet?)
log.info("onSuccessCall was already completed for chargeback paymentId='{}'", paymentControlContext.getPaymentId());
} else {
final InvoicePayment linkedInvoicePayment = invoiceApi.getInvoicePaymentForAttempt(paymentControlContext.getPaymentId(), internalContext);
final BigDecimal amount;
final Currency currency;
if (linkedInvoicePayment.getCurrency().equals(paymentControlContext.getProcessedCurrency()) && paymentControlContext.getProcessedAmount() != null) {
amount = paymentControlContext.getProcessedAmount();
currency = paymentControlContext.getProcessedCurrency();
} else if (linkedInvoicePayment.getCurrency().equals(paymentControlContext.getCurrency()) && paymentControlContext.getAmount() != null) {
amount = paymentControlContext.getAmount();
currency = paymentControlContext.getCurrency();
} else {
amount = linkedInvoicePayment.getAmount();
currency = linkedInvoicePayment.getCurrency();
}
invoiceApi.recordChargeback(paymentControlContext.getPaymentId(), paymentControlContext.getTransactionExternalKey(), amount, currency, internalContext);
}
break;
case CREDIT:
final Map<UUID, BigDecimal> idWithAmountMap = extractIdsWithAmountFromProperties(pluginProperties);
final PluginProperty properties = getPluginProperty(pluginProperties, PROP_IPCD_REFUND_WITH_ADJUSTMENTS);
final boolean isInvoiceAdjusted = properties != null ? Boolean.valueOf((String) properties.getValue()) : false;
final PluginProperty legacyPayment = getPluginProperty(pluginProperties, PROP_IPCD_PAYMENT_ID);
final UUID paymentId = legacyPayment != null ? (UUID) legacyPayment.getValue() : paymentControlContext.getPaymentId();
invoiceApi.recordRefund(paymentId, paymentControlContext.getAmount(), isInvoiceAdjusted, idWithAmountMap, paymentControlContext.getTransactionExternalKey(), internalContext);
break;
default:
throw new IllegalStateException("Unexpected transactionType " + transactionType);
}
} catch (final InvoiceApiException e) {
log.warn("onSuccessCall failed for attemptId='{}', transactionType='{}'", paymentControlContext.getAttemptPaymentId(), transactionType, e);
}
return new DefaultOnSuccessPaymentControlResult();
}
use of org.killbill.billing.payment.dao.PaymentTransactionModelDao in project killbill by killbill.
the class InvoicePaymentControlPluginApi method getPurchasedTransactions.
private List<PaymentTransactionModelDao> getPurchasedTransactions(final String paymentExternalKey, final InternalCallContext internalContext) {
final PaymentModelDao payment = paymentDao.getPaymentByExternalKey(paymentExternalKey, internalContext);
if (payment == null) {
return Collections.emptyList();
}
final List<PaymentTransactionModelDao> transactions = paymentDao.getTransactionsForPayment(payment.getId(), internalContext);
if (transactions == null || transactions.size() == 0) {
return Collections.emptyList();
}
return ImmutableList.copyOf(Iterables.filter(transactions, new Predicate<PaymentTransactionModelDao>() {
@Override
public boolean apply(final PaymentTransactionModelDao input) {
return input.getTransactionType() == TransactionType.PURCHASE;
}
}));
}
use of org.killbill.billing.payment.dao.PaymentTransactionModelDao in project killbill by killbill.
the class TestPaymentEnteringStateCallback method testEnterStateAndProcessPaymentTransactionInfoPlugin.
@Test(groups = "slow")
public void testEnterStateAndProcessPaymentTransactionInfoPlugin() throws Exception {
// Create the payment and first transaction (would be done by PaymentLeavingStateCallback)
daoHelper.createNewPaymentTransaction();
Assert.assertEquals(paymentDao.getPaymentTransaction(paymentStateContext.getPaymentTransactionModelDao().getId(), internalCallContext).getTransactionStatus(), TransactionStatus.UNKNOWN);
// Mock the plugin result
final PaymentTransactionInfoPlugin paymentInfoPlugin = Mockito.mock(PaymentTransactionInfoPlugin.class);
Mockito.when(paymentInfoPlugin.getAmount()).thenReturn(new BigDecimal("82010.222"));
Mockito.when(paymentInfoPlugin.getCurrency()).thenReturn(Currency.CAD);
Mockito.when(paymentInfoPlugin.getStatus()).thenReturn(PaymentPluginStatus.PENDING);
Mockito.when(paymentInfoPlugin.getGatewayErrorCode()).thenReturn(UUID.randomUUID().toString().substring(0, 5));
Mockito.when(paymentInfoPlugin.getGatewayError()).thenReturn(UUID.randomUUID().toString());
paymentStateContext.setPaymentTransactionInfoPlugin(paymentInfoPlugin);
// Process the plugin result
callback.enteringState(state, operationCallback, operationResult, leavingStateCallback);
// Verify the updated transaction
final PaymentTransactionModelDao paymentTransaction = paymentDao.getPaymentTransaction(paymentStateContext.getPaymentTransactionModelDao().getId(), internalCallContext);
Assert.assertEquals(paymentTransaction.getAmount().compareTo(paymentStateContext.getAmount()), 0);
Assert.assertEquals(paymentTransaction.getCurrency(), paymentStateContext.getCurrency());
Assert.assertEquals(paymentTransaction.getProcessedAmount().compareTo(paymentInfoPlugin.getAmount()), 0);
Assert.assertEquals(paymentTransaction.getProcessedCurrency(), paymentInfoPlugin.getCurrency());
Assert.assertEquals(paymentTransaction.getTransactionStatus(), TransactionStatus.PENDING);
Assert.assertEquals(paymentTransaction.getGatewayErrorCode(), paymentInfoPlugin.getGatewayErrorCode());
Assert.assertEquals(paymentTransaction.getGatewayErrorMsg(), paymentInfoPlugin.getGatewayError());
}
use of org.killbill.billing.payment.dao.PaymentTransactionModelDao in project killbill by killbill.
the class TestPaymentLeavingStateCallback method testLeaveStateForExistingPayment.
@Test(groups = "slow")
public void testLeaveStateForExistingPayment() throws Exception {
final UUID paymentId = UUID.randomUUID();
setUp(paymentId);
// Verify the payment has only one transaction
final List<PaymentTransactionModelDao> transactions = paymentDao.getTransactionsForPayment(paymentId, internalCallContext);
Assert.assertEquals(transactions.size(), 1);
// Reset paymentExternalKey to something else
paymentStateContext.setPaymentTransactionExternalKey(UUID.randomUUID().toString());
callback.leavingState(state);
// Verify a new transaction was created
verifyPaymentTransaction();
// Verify the payment has now two transactions
Assert.assertEquals(paymentDao.getTransactionsForPayment(paymentId, internalCallContext).size(), 2);
}
Aggregations