Search in sources :

Example 1 with PaymentModelDao

use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.

the class PaymentProcessor method invokeJanitor.

private PaymentModelDao invokeJanitor(final PaymentModelDao curPaymentModelDao, final Collection<PaymentTransactionModelDao> curTransactionsModelDao, @Nullable final Iterable<PaymentTransactionInfoPlugin> pluginTransactions, final InternalTenantContext internalTenantContext) {
    // Need to filter for optimized codepaths looking up by account_record_id
    final Iterable<PaymentTransactionModelDao> filteredTransactions = Iterables.filter(curTransactionsModelDao, new Predicate<PaymentTransactionModelDao>() {

        @Override
        public boolean apply(final PaymentTransactionModelDao curPaymentTransactionModelDao) {
            return curPaymentTransactionModelDao.getPaymentId().equals(curPaymentModelDao.getId());
        }
    });
    PaymentModelDao newPaymentModelDao = curPaymentModelDao;
    final Collection<PaymentTransactionModelDao> transactionsModelDao = new LinkedList<PaymentTransactionModelDao>();
    for (final PaymentTransactionModelDao curPaymentTransactionModelDao : filteredTransactions) {
        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 = incompletePaymentTransactionTask.updatePaymentAndTransactionIfNeededWithAccountLock(newPaymentModelDao, newPaymentTransactionModelDao, paymentTransactionInfoPlugin, internalTenantContext);
            if (hasChanged) {
                newPaymentModelDao = paymentDao.getPayment(newPaymentModelDao.getId(), internalTenantContext);
                newPaymentTransactionModelDao = paymentDao.getPaymentTransaction(newPaymentTransactionModelDao.getId(), internalTenantContext);
            }
        }
        transactionsModelDao.add(newPaymentTransactionModelDao);
    }
    curTransactionsModelDao.clear();
    curTransactionsModelDao.addAll(transactionsModelDao);
    return newPaymentModelDao;
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PaymentTransactionInfoPlugin(org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin) LinkedList(java.util.LinkedList)

Example 2 with PaymentModelDao

use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.

the class InvoicePaymentControlPluginApi method getPluginRefundResult.

private PriorPaymentControlResult getPluginRefundResult(final PaymentControlContext paymentControlPluginContext, final Iterable<PluginProperty> pluginProperties, final InternalCallContext internalContext) throws PaymentControlApiException {
    final Map<UUID, BigDecimal> idWithAmount = extractIdsWithAmountFromProperties(pluginProperties);
    if ((paymentControlPluginContext.getAmount() == null || paymentControlPluginContext.getAmount().compareTo(BigDecimal.ZERO) == 0) && idWithAmount.size() == 0) {
        throw new PaymentControlApiException("Abort refund call: ", new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION, String.format("Refund for payment, key = %s, aborted: requested refund amount is = %s", paymentControlPluginContext.getPaymentExternalKey(), paymentControlPluginContext.getAmount())));
    }
    final PaymentModelDao payment = paymentDao.getPayment(paymentControlPluginContext.getPaymentId(), internalContext);
    if (payment == null) {
        throw new PaymentControlApiException("Unexpected null payment");
    }
    // This will calculate the upper bound on the refund amount based on the invoice items associated with that payment.
    // Note that we are not checking that other (partial) refund occurred, but if the refund ends up being greater than what is allowed
    // the call to the gateway would fail; it would need noce to validate on our side though...
    final BigDecimal amountToBeRefunded = computeRefundAmount(payment.getId(), paymentControlPluginContext.getAmount(), idWithAmount, internalContext);
    final boolean isAborted = amountToBeRefunded.compareTo(BigDecimal.ZERO) == 0;
    if (paymentControlPluginContext.isApiPayment() && isAborted) {
        throw new PaymentControlApiException("Abort refund call: ", new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION, String.format("Refund for payment %s aborted : invoice item sum amount is %s, requested refund amount is = %s", payment.getId(), amountToBeRefunded, paymentControlPluginContext.getAmount())));
    }
    final PluginProperty prop = getPluginProperty(pluginProperties, PROP_IPCD_REFUND_WITH_ADJUSTMENTS);
    final boolean isAdjusted = prop != null && prop.getValue() != null ? Boolean.valueOf(prop.getValue().toString()) : false;
    if (isAdjusted) {
        try {
            invoiceApi.validateInvoiceItemAdjustments(paymentControlPluginContext.getPaymentId(), idWithAmount, internalContext);
        } catch (InvoiceApiException e) {
            throw new PaymentControlApiException(String.format("Refund for payment %s aborted", payment.getId()), new PaymentApiException(ErrorCode.PAYMENT_PLUGIN_EXCEPTION, e.getMessage()));
        }
    }
    return new DefaultPriorPaymentControlResult(isAborted, amountToBeRefunded);
}
Also used : PluginProperty(org.killbill.billing.payment.api.PluginProperty) InvoiceApiException(org.killbill.billing.invoice.api.InvoiceApiException) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) UUID(java.util.UUID) BigDecimal(java.math.BigDecimal) PaymentControlApiException(org.killbill.billing.control.plugin.api.PaymentControlApiException) DefaultPriorPaymentControlResult(org.killbill.billing.payment.retry.DefaultPriorPaymentControlResult)

Example 3 with PaymentModelDao

use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.

the class TestDefaultAdminPaymentApi method testFixPaymentTransactionState.

@Test(groups = "slow")
public void testFixPaymentTransactionState() throws PaymentApiException {
    final PaymentOptions paymentOptions = new PaymentOptions() {

        @Override
        public boolean isExternalPayment() {
            return false;
        }

        @Override
        public List<String> getPaymentControlPluginNames() {
            return ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME);
        }
    };
    final Payment payment = paymentApi.createAuthorizationWithPaymentControl(account, account.getPaymentMethodId(), null, BigDecimal.TEN, Currency.EUR, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), paymentOptions, callContext);
    Assert.assertEquals(payment.getTransactions().size(), 1);
    final PaymentModelDao paymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(payment.getTransactions().get(0).getId(), internalCallContext);
    Assert.assertEquals(paymentModelDao.getStateName(), "AUTH_SUCCESS");
    Assert.assertEquals(paymentModelDao.getLastSuccessStateName(), "AUTH_SUCCESS");
    Assert.assertEquals(paymentTransactionModelDao.getTransactionStatus(), TransactionStatus.SUCCESS);
    Assert.assertEquals(paymentTransactionModelDao.getProcessedAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(paymentTransactionModelDao.getProcessedCurrency(), Currency.EUR);
    Assert.assertEquals(paymentTransactionModelDao.getGatewayErrorCode(), "");
    Assert.assertEquals(paymentTransactionModelDao.getGatewayErrorMsg(), "");
    final List<PaymentAttemptModelDao> paymentAttemptModelDaos = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey(), internalCallContext);
    Assert.assertEquals(paymentAttemptModelDaos.size(), 1);
    Assert.assertEquals(paymentAttemptModelDaos.get(0).getStateName(), "SUCCESS");
    Assert.assertEquals(paymentAttemptModelDaos.get(0).getAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(paymentAttemptModelDaos.get(0).getCurrency(), Currency.EUR);
    adminPaymentApi.fixPaymentTransactionState(payment, payment.getTransactions().get(0), TransactionStatus.PAYMENT_FAILURE, null, "AUTH_ERRORED", ImmutableList.<PluginProperty>of(), callContext);
    Assert.assertEquals(paymentApi.getPayment(payment.getId(), false, false, ImmutableList.<PluginProperty>of(), callContext).getTransactions().size(), 1);
    final PaymentModelDao refreshedPaymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao refreshedPaymentTransactionModelDao = paymentDao.getPaymentTransaction(payment.getTransactions().get(0).getId(), internalCallContext);
    Assert.assertEquals(refreshedPaymentModelDao.getStateName(), "AUTH_ERRORED");
    Assert.assertNull(refreshedPaymentModelDao.getLastSuccessStateName());
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getProcessedAmount().compareTo(BigDecimal.ZERO), 0);
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getProcessedCurrency(), Currency.EUR);
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getGatewayErrorCode(), "");
    Assert.assertEquals(refreshedPaymentTransactionModelDao.getGatewayErrorMsg(), "");
    final List<PaymentAttemptModelDao> refreshedPaymentAttemptModelDaos = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey(), internalCallContext);
    Assert.assertEquals(refreshedPaymentAttemptModelDaos.size(), 1);
    Assert.assertEquals(refreshedPaymentAttemptModelDaos.get(0).getStateName(), "ABORTED");
    Assert.assertEquals(refreshedPaymentAttemptModelDaos.get(0).getAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(refreshedPaymentAttemptModelDaos.get(0).getCurrency(), Currency.EUR);
    // Advance the clock to make sure the effective date of the new transaction is after the first one
    clock.addDays(1);
    assertListenerStatus();
    // Verify subsequent payment retries work
    retryService.retryPaymentTransaction(refreshedPaymentTransactionModelDao.getAttemptId(), ImmutableList.<String>of(MockPaymentControlProviderPlugin.PLUGIN_NAME), internalCallContext);
    final Payment retriedPayment = paymentApi.getPayment(payment.getId(), false, false, ImmutableList.<PluginProperty>of(), callContext);
    Assert.assertEquals(retriedPayment.getTransactions().size(), 2);
    final PaymentModelDao retriedPaymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao retriedPaymentTransactionModelDao = paymentDao.getPaymentTransaction(retriedPayment.getTransactions().get(1).getId(), internalCallContext);
    Assert.assertEquals(retriedPaymentModelDao.getStateName(), "AUTH_SUCCESS");
    Assert.assertEquals(retriedPaymentModelDao.getLastSuccessStateName(), "AUTH_SUCCESS");
    Assert.assertEquals(retriedPaymentTransactionModelDao.getTransactionStatus(), TransactionStatus.SUCCESS);
    Assert.assertEquals(retriedPaymentTransactionModelDao.getProcessedAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(retriedPaymentTransactionModelDao.getProcessedCurrency(), Currency.EUR);
    Assert.assertEquals(retriedPaymentTransactionModelDao.getGatewayErrorCode(), "");
    Assert.assertEquals(retriedPaymentTransactionModelDao.getGatewayErrorMsg(), "");
    final List<PaymentAttemptModelDao> retriedPaymentAttemptModelDaos = paymentDao.getPaymentAttemptByTransactionExternalKey(paymentTransactionModelDao.getTransactionExternalKey(), internalCallContext);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.size(), 2);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(0).getStateName(), "ABORTED");
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(0).getAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(0).getCurrency(), Currency.EUR);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(1).getStateName(), "SUCCESS");
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(1).getAmount().compareTo(BigDecimal.TEN), 0);
    Assert.assertEquals(retriedPaymentAttemptModelDaos.get(1).getCurrency(), Currency.EUR);
}
Also used : PaymentAttemptModelDao(org.killbill.billing.payment.dao.PaymentAttemptModelDao) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) Test(org.testng.annotations.Test)

Example 4 with PaymentModelDao

use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.

the class TestDefaultAdminPaymentApi method testFixPaymentTransactionStateRefundFailedToRefundSuccess.

@Test(groups = "slow", description = "https://github.com/killbill/killbill-adyen-plugin/pull/60")
public void testFixPaymentTransactionStateRefundFailedToRefundSuccess() throws PaymentApiException {
    final Payment payment = paymentApi.createPurchase(account, account.getPaymentMethodId(), null, BigDecimal.TEN, Currency.EUR, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
    final PaymentModelDao paymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(payment.getTransactions().get(0).getId(), internalCallContext);
    Assert.assertEquals(paymentModelDao.getStateName(), "PURCHASE_SUCCESS");
    Assert.assertEquals(paymentModelDao.getLastSuccessStateName(), "PURCHASE_SUCCESS");
    Assert.assertEquals(paymentTransactionModelDao.getTransactionStatus(), TransactionStatus.SUCCESS);
    final Payment refund = paymentApi.createRefund(account, payment.getId(), payment.getPurchasedAmount(), payment.getCurrency(), null, UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(new PluginProperty(MockPaymentProviderPlugin.PLUGIN_PROPERTY_PAYMENT_PLUGIN_STATUS_OVERRIDE, PaymentPluginStatus.ERROR.toString(), false)), callContext);
    final PaymentModelDao paymentModelDao2 = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao paymentTransactionModelDao2 = paymentDao.getPaymentTransaction(refund.getTransactions().get(1).getId(), internalCallContext);
    Assert.assertEquals(paymentModelDao2.getStateName(), "REFUND_FAILED");
    Assert.assertEquals(paymentModelDao2.getLastSuccessStateName(), "PURCHASE_SUCCESS");
    Assert.assertEquals(paymentTransactionModelDao2.getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
    adminPaymentApi.fixPaymentTransactionState(refund, refund.getTransactions().get(1), TransactionStatus.SUCCESS, null, /* Let Kill Bill figure it out */
    null, /* Let Kill Bill figure it out */
    ImmutableList.<PluginProperty>of(), callContext);
    final PaymentModelDao paymentModelDao3 = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao paymentTransactionModelDao3 = paymentDao.getPaymentTransaction(refund.getTransactions().get(1).getId(), internalCallContext);
    Assert.assertEquals(paymentModelDao3.getStateName(), "REFUND_SUCCESS");
    Assert.assertEquals(paymentModelDao3.getLastSuccessStateName(), "REFUND_SUCCESS");
    Assert.assertEquals(paymentTransactionModelDao3.getTransactionStatus(), TransactionStatus.SUCCESS);
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) Test(org.testng.annotations.Test)

Example 5 with PaymentModelDao

use of org.killbill.billing.payment.dao.PaymentModelDao in project killbill by killbill.

the class TestDefaultAdminPaymentApi method testFixPaymentTransactionStateRefundSuccessToRefundFailed.

@Test(groups = "slow", description = "https://github.com/killbill/killbill-adyen-plugin/pull/60")
public void testFixPaymentTransactionStateRefundSuccessToRefundFailed() throws PaymentApiException {
    final Payment payment = paymentApi.createPurchase(account, account.getPaymentMethodId(), null, BigDecimal.TEN, Currency.EUR, null, UUID.randomUUID().toString(), UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
    final PaymentModelDao paymentModelDao = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao paymentTransactionModelDao = paymentDao.getPaymentTransaction(payment.getTransactions().get(0).getId(), internalCallContext);
    Assert.assertEquals(paymentModelDao.getStateName(), "PURCHASE_SUCCESS");
    Assert.assertEquals(paymentModelDao.getLastSuccessStateName(), "PURCHASE_SUCCESS");
    Assert.assertEquals(paymentTransactionModelDao.getTransactionStatus(), TransactionStatus.SUCCESS);
    final Payment refund = paymentApi.createRefund(account, payment.getId(), payment.getPurchasedAmount(), payment.getCurrency(), null, UUID.randomUUID().toString(), ImmutableList.<PluginProperty>of(), callContext);
    final PaymentModelDao paymentModelDao2 = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao paymentTransactionModelDao2 = paymentDao.getPaymentTransaction(refund.getTransactions().get(1).getId(), internalCallContext);
    Assert.assertEquals(paymentModelDao2.getStateName(), "REFUND_SUCCESS");
    Assert.assertEquals(paymentModelDao2.getLastSuccessStateName(), "REFUND_SUCCESS");
    Assert.assertEquals(paymentTransactionModelDao2.getTransactionStatus(), TransactionStatus.SUCCESS);
    adminPaymentApi.fixPaymentTransactionState(refund, refund.getTransactions().get(1), TransactionStatus.PAYMENT_FAILURE, null, /* Let Kill Bill figure it out */
    null, /* Let Kill Bill figure it out */
    ImmutableList.<PluginProperty>of(), callContext);
    final PaymentModelDao paymentModelDao3 = paymentDao.getPayment(payment.getId(), internalCallContext);
    final PaymentTransactionModelDao paymentTransactionModelDao3 = paymentDao.getPaymentTransaction(refund.getTransactions().get(1).getId(), internalCallContext);
    Assert.assertEquals(paymentModelDao3.getStateName(), "REFUND_FAILED");
    Assert.assertEquals(paymentModelDao3.getLastSuccessStateName(), "PURCHASE_SUCCESS");
    Assert.assertEquals(paymentTransactionModelDao3.getTransactionStatus(), TransactionStatus.PAYMENT_FAILURE);
}
Also used : PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) Test(org.testng.annotations.Test)

Aggregations

PaymentModelDao (org.killbill.billing.payment.dao.PaymentModelDao)28 PaymentTransactionModelDao (org.killbill.billing.payment.dao.PaymentTransactionModelDao)21 Test (org.testng.annotations.Test)11 UUID (java.util.UUID)10 PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)9 PaymentTransactionInfoPlugin (org.killbill.billing.payment.plugin.api.PaymentTransactionInfoPlugin)9 Predicate (com.google.common.base.Predicate)8 PaymentAttemptModelDao (org.killbill.billing.payment.dao.PaymentAttemptModelDao)6 PluginProperty (org.killbill.billing.payment.api.PluginProperty)5 LinkedList (java.util.LinkedList)4 State (org.killbill.automaton.State)4 PaymentPluginApi (org.killbill.billing.payment.plugin.api.PaymentPluginApi)4 DefaultNoOpPaymentInfoPlugin (org.killbill.billing.payment.provider.DefaultNoOpPaymentInfoPlugin)4 BigDecimal (java.math.BigDecimal)3 ImmutableList (com.google.common.collect.ImmutableList)2 List (java.util.List)2 DateTime (org.joda.time.DateTime)2 Account (org.killbill.billing.account.api.Account)2 AccountApiException (org.killbill.billing.account.api.AccountApiException)2 InternalTenantContext (org.killbill.billing.callcontext.InternalTenantContext)2