Search in sources :

Example 11 with TransactionType

use of org.killbill.billing.payment.api.TransactionType in project killbill by killbill.

the class AccountResource method processPayment.

private Response processPayment(final PaymentTransactionJson json, final Account account, final String paymentMethodIdStr, final List<String> paymentControlPluginNames, final List<String> pluginPropertiesString, final UriInfo uriInfo, final CallContext callContext, final HttpServletRequest request) throws PaymentApiException {
    verifyNonNullOrEmpty(json, "PaymentTransactionJson body should be specified");
    verifyNonNullOrEmpty(json.getTransactionType(), "PaymentTransactionJson transactionType needs to be set", json.getAmount(), "PaymentTransactionJson amount needs to be set");
    final Iterable<PluginProperty> pluginProperties = extractPluginProperties(pluginPropertiesString);
    final Currency currency = json.getCurrency() == null ? account.getCurrency() : Currency.valueOf(json.getCurrency());
    final UUID paymentId = json.getPaymentId() == null ? null : UUID.fromString(json.getPaymentId());
    //
    // If paymentId was specified, it means we are attempting a payment completion. The preferred way is to use the PaymentResource
    // (PUT /1.0/kb/payments/{paymentId}/completeTransaction), but for backward compatibility we still allow the call to proceed
    // as long as the request/existing state is healthy (i.e there is a matching PENDING transaction)
    //
    final UUID paymentMethodId;
    if (paymentId != null) {
        final Payment initialPayment = paymentApi.getPayment(paymentId, false, false, pluginProperties, callContext);
        final PaymentTransaction pendingOrSuccessTransaction = lookupPendingOrSuccessTransaction(initialPayment, json != null ? json.getTransactionId() : null, json != null ? json.getTransactionExternalKey() : null, json != null ? json.getTransactionType() : null);
        // If transaction was already completed, return early (See #626)
        if (pendingOrSuccessTransaction.getTransactionStatus() == TransactionStatus.SUCCESS) {
            return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", pendingOrSuccessTransaction.getPaymentId(), request);
        }
        paymentMethodId = initialPayment.getPaymentMethodId();
    } else {
        paymentMethodId = paymentMethodIdStr == null ? account.getPaymentMethodId() : UUID.fromString(paymentMethodIdStr);
    }
    validatePaymentMethodForAccount(account.getId(), paymentMethodId, callContext);
    final TransactionType transactionType = TransactionType.valueOf(json.getTransactionType());
    final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
    final Payment result;
    switch(transactionType) {
        case AUTHORIZE:
            result = paymentApi.createAuthorizationWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency, json.getPaymentExternalKey(), json.getTransactionExternalKey(), pluginProperties, paymentOptions, callContext);
            break;
        case PURCHASE:
            result = paymentApi.createPurchaseWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency, json.getPaymentExternalKey(), json.getTransactionExternalKey(), pluginProperties, paymentOptions, callContext);
            break;
        case CREDIT:
            result = paymentApi.createCreditWithPaymentControl(account, paymentMethodId, paymentId, json.getAmount(), currency, json.getPaymentExternalKey(), json.getTransactionExternalKey(), pluginProperties, paymentOptions, callContext);
            break;
        default:
            return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + transactionType + " is not allowed for an account").build();
    }
    return createPaymentResponse(uriInfo, result, transactionType, json.getTransactionExternalKey(), request);
}
Also used : PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) PluginProperty(org.killbill.billing.payment.api.PluginProperty) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) Payment(org.killbill.billing.payment.api.Payment) TransactionType(org.killbill.billing.payment.api.TransactionType) Currency(org.killbill.billing.catalog.api.Currency) UUID(java.util.UUID) PaymentOptions(org.killbill.billing.payment.api.PaymentOptions)

Example 12 with TransactionType

use of org.killbill.billing.payment.api.TransactionType 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 13 with TransactionType

use of org.killbill.billing.payment.api.TransactionType in project killbill by killbill.

the class InvoicePaymentControlPluginApi method priorCall.

@Override
public PriorPaymentControlResult priorCall(final PaymentControlContext paymentControlContext, final Iterable<PluginProperty> pluginProperties) throws PaymentControlApiException {
    final TransactionType transactionType = paymentControlContext.getTransactionType();
    Preconditions.checkArgument(paymentControlContext.getPaymentApiType() == PaymentApiType.PAYMENT_TRANSACTION);
    Preconditions.checkArgument(transactionType == TransactionType.PURCHASE || transactionType == TransactionType.REFUND || transactionType == TransactionType.CHARGEBACK || transactionType == TransactionType.CREDIT);
    final InternalCallContext internalContext = internalCallContextFactory.createInternalCallContext(paymentControlContext.getAccountId(), paymentControlContext);
    switch(transactionType) {
        case PURCHASE:
            return getPluginPurchaseResult(paymentControlContext, pluginProperties, internalContext);
        case REFUND:
            return getPluginRefundResult(paymentControlContext, pluginProperties, internalContext);
        case CHARGEBACK:
            return new DefaultPriorPaymentControlResult(false, paymentControlContext.getAmount());
        case CREDIT:
            return getPluginCreditResult(paymentControlContext, pluginProperties, internalContext);
        default:
            throw new IllegalStateException("Unexpected transactionType " + transactionType);
    }
}
Also used : TransactionType(org.killbill.billing.payment.api.TransactionType) InternalCallContext(org.killbill.billing.callcontext.InternalCallContext) DefaultPriorPaymentControlResult(org.killbill.billing.payment.retry.DefaultPriorPaymentControlResult)

Example 14 with TransactionType

use of org.killbill.billing.payment.api.TransactionType in project killbill by killbill.

the class TestPaymentDao method testPaymentAttempt.

@Test(groups = "slow")
public void testPaymentAttempt() throws PluginPropertySerializerException {
    final UUID transactionId = UUID.randomUUID();
    final String paymentExternalKey = "vraiment?";
    final String transactionExternalKey = "tduteuqweq";
    final String stateName = "INIT";
    final TransactionType transactionType = TransactionType.AUTHORIZE;
    final String pluginName = "superPlugin";
    final List<PluginProperty> properties = new ArrayList<PluginProperty>();
    properties.add(new PluginProperty("key1", "value1", false));
    properties.add(new PluginProperty("key2", "value2", false));
    final byte[] serialized = PluginPropertySerializer.serialize(properties);
    final PaymentAttemptModelDao attempt = new PaymentAttemptModelDao(UUID.randomUUID(), UUID.randomUUID(), clock.getUTCNow(), clock.getUTCNow(), paymentExternalKey, transactionId, transactionExternalKey, transactionType, stateName, BigDecimal.ZERO, Currency.ALL, ImmutableList.<String>of(pluginName), serialized);
    PaymentAttemptModelDao savedAttempt = paymentDao.insertPaymentAttemptWithProperties(attempt, internalCallContext);
    assertEquals(savedAttempt.getTransactionExternalKey(), transactionExternalKey);
    assertEquals(savedAttempt.getTransactionType(), transactionType);
    assertEquals(savedAttempt.getStateName(), stateName);
    assertEquals(savedAttempt.getPluginName(), pluginName);
    final Iterable<PluginProperty> deserialized = PluginPropertySerializer.deserialize(savedAttempt.getPluginProperties());
    int i = 0;
    for (PluginProperty cur : deserialized) {
        Assert.assertEquals(cur, properties.get(i++));
    }
    final PaymentAttemptModelDao retrievedAttempt1 = paymentDao.getPaymentAttempt(attempt.getId(), internalCallContext);
    assertEquals(retrievedAttempt1.getTransactionExternalKey(), transactionExternalKey);
    assertEquals(retrievedAttempt1.getTransactionType(), transactionType);
    assertEquals(retrievedAttempt1.getStateName(), stateName);
    assertEquals(retrievedAttempt1.getPluginName(), pluginName);
    final List<PaymentAttemptModelDao> retrievedAttempts = paymentDao.getPaymentAttemptByTransactionExternalKey(transactionExternalKey, internalCallContext);
    assertEquals(retrievedAttempts.size(), 1);
    assertEquals(retrievedAttempts.get(0).getTransactionExternalKey(), transactionExternalKey);
    assertEquals(retrievedAttempts.get(0).getTransactionType(), transactionType);
    assertEquals(retrievedAttempts.get(0).getStateName(), stateName);
    assertEquals(retrievedAttempts.get(0).getPluginName(), pluginName);
}
Also used : PluginProperty(org.killbill.billing.payment.api.PluginProperty) TransactionType(org.killbill.billing.payment.api.TransactionType) ArrayList(java.util.ArrayList) UUID(java.util.UUID) Test(org.testng.annotations.Test)

Aggregations

TransactionType (org.killbill.billing.payment.api.TransactionType)14 UUID (java.util.UUID)13 BigDecimal (java.math.BigDecimal)9 Account (org.killbill.billing.client.model.Account)8 Payment (org.killbill.billing.client.model.Payment)8 PaymentTransaction (org.killbill.billing.client.model.PaymentTransaction)8 Test (org.testng.annotations.Test)8 ComboPaymentTransaction (org.killbill.billing.client.model.ComboPaymentTransaction)7 PluginProperty (org.killbill.billing.payment.api.PluginProperty)4 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)3 Currency (org.killbill.billing.catalog.api.Currency)3 KillBillClientException (org.killbill.billing.client.KillBillClientException)3 InvoiceApiException (org.killbill.billing.invoice.api.InvoiceApiException)2 InvoicePayment (org.killbill.billing.invoice.api.InvoicePayment)2 Payment (org.killbill.billing.payment.api.Payment)2 PaymentOptions (org.killbill.billing.payment.api.PaymentOptions)2 ApiOperation (io.swagger.annotations.ApiOperation)1 ApiResponses (io.swagger.annotations.ApiResponses)1 ArrayList (java.util.ArrayList)1 Consumes (javax.ws.rs.Consumes)1