Search in sources :

Example 36 with PaymentTransactionModelDao

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();
}
Also used : InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) TransactionType(org.killbill.billing.payment.api.TransactionType) DefaultOnSuccessPaymentControlResult(org.killbill.billing.payment.retry.DefaultOnSuccessPaymentControlResult) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) BigDecimal(java.math.BigDecimal) PluginProperty(org.killbill.billing.payment.api.PluginProperty) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) Currency(org.killbill.billing.catalog.api.Currency) UUID(java.util.UUID)

Example 37 with PaymentTransactionModelDao

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;
        }
    }));
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) Predicate(com.google.common.base.Predicate)

Example 38 with PaymentTransactionModelDao

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());
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) BigDecimal(java.math.BigDecimal) Test(org.testng.annotations.Test)

Example 39 with PaymentTransactionModelDao

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);
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) UUID(java.util.UUID) Test(org.testng.annotations.Test)

Aggregations

PaymentTransactionModelDao (org.killbill.billing.payment.dao.PaymentTransactionModelDao)39 PaymentModelDao (org.killbill.billing.payment.dao.PaymentModelDao)17 PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)16 Test (org.testng.annotations.Test)16 UUID (java.util.UUID)12 BigDecimal (java.math.BigDecimal)10 PaymentAttemptModelDao (org.killbill.billing.payment.dao.PaymentAttemptModelDao)10 Predicate (com.google.common.base.Predicate)8 Payment (org.killbill.billing.payment.api.Payment)7 Account (org.killbill.billing.account.api.Account)6 PaymentTransactionInfoPlugin (org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin)6 ImmutableList (com.google.common.collect.ImmutableList)5 List (java.util.List)5 LinkedList (java.util.LinkedList)4 LocalDate (org.joda.time.LocalDate)4 Invoice (org.killbill.billing.invoice.api.Invoice)4 PluginProperty (org.killbill.billing.payment.api.PluginProperty)4 ArrayList (java.util.ArrayList)3 TimeoutException (java.util.concurrent.TimeoutException)3 OperationException (org.killbill.automaton.OperationException)3