Search in sources :

Example 6 with PaymentTransaction

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

the class AdminResource method updatePaymentTransactionState.

@PUT
@Consumes(APPLICATION_JSON)
@Produces(APPLICATION_JSON)
@Path("/payments/{paymentId:" + UUID_PATTERN + "}/transactions/{paymentTransactionId:" + UUID_PATTERN + "}")
@ApiOperation(value = "Update existing paymentTransaction and associated payment state")
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid account data supplied") })
public Response updatePaymentTransactionState(final AdminPaymentJson json, @PathParam("paymentId") final String paymentIdStr, @PathParam("paymentTransactionId") final String paymentTransactionIdStr, @HeaderParam(HDR_CREATED_BY) final String createdBy, @HeaderParam(HDR_REASON) final String reason, @HeaderParam(HDR_COMMENT) final String comment, @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException {
    final CallContext callContext = context.createContext(createdBy, reason, comment, request);
    final Payment payment = paymentApi.getPayment(UUID.fromString(paymentIdStr), false, false, ImmutableList.<PluginProperty>of(), callContext);
    final UUID paymentTransactionId = UUID.fromString(paymentTransactionIdStr);
    final PaymentTransaction paymentTransaction = Iterables.tryFind(payment.getTransactions(), new Predicate<PaymentTransaction>() {

        @Override
        public boolean apply(final PaymentTransaction input) {
            return input.getId().equals(paymentTransactionId);
        }
    }).orNull();
    adminPaymentApi.fixPaymentTransactionState(payment, paymentTransaction, TransactionStatus.valueOf(json.getTransactionStatus()), json.getLastSuccessPaymentState(), json.getCurrentPaymentStateName(), ImmutableList.<PluginProperty>of(), callContext);
    return Response.status(Status.OK).build();
}
Also used : PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) Payment(org.killbill.billing.payment.api.Payment) UUID(java.util.UUID) CallContext(org.killbill.billing.util.callcontext.CallContext) Predicate(com.google.common.base.Predicate) Path(javax.ws.rs.Path) Consumes(javax.ws.rs.Consumes) Produces(javax.ws.rs.Produces) ApiOperation(io.swagger.annotations.ApiOperation) PUT(javax.ws.rs.PUT) ApiResponses(io.swagger.annotations.ApiResponses)

Example 7 with PaymentTransaction

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

the class JaxRsResourceBase method createPaymentResponse.

protected Response createPaymentResponse(final UriInfo uriInfo, final Payment payment, final TransactionType transactionType, @Nullable final String transactionExternalKey, final HttpServletRequest request) {
    final PaymentTransaction createdTransaction = findCreatedTransaction(payment, transactionType, transactionExternalKey);
    Preconditions.checkNotNull(createdTransaction, "No transaction of type '%s' found", transactionType);
    final ResponseBuilder responseBuilder;
    final BillingExceptionJson exception;
    switch(createdTransaction.getTransactionStatus()) {
        case PENDING:
        case SUCCESS:
            return uriBuilder.buildResponse(uriInfo, PaymentResource.class, "getPayment", payment.getId(), request);
        case PAYMENT_FAILURE:
            // 402 - Payment Required
            responseBuilder = Response.status(402);
            exception = createBillingException(String.format("Payment decline by gateway. Error message: %s", createdTransaction.getGatewayErrorMsg()));
            break;
        case PAYMENT_SYSTEM_OFF:
            // 503 - Service Unavailable
            responseBuilder = Response.status(Status.SERVICE_UNAVAILABLE);
            exception = createBillingException("Payment system is off.");
            break;
        case UNKNOWN:
            // 503 - Service Unavailable
            responseBuilder = Response.status(Status.SERVICE_UNAVAILABLE);
            exception = createBillingException("Payment in unknown status, failed to receive gateway response.");
            break;
        case PLUGIN_FAILURE:
            // 502 - Bad Gateway
            responseBuilder = Response.status(502);
            exception = createBillingException("Failed to submit payment transaction");
            break;
        default:
            // Should never happen
            responseBuilder = Response.serverError();
            exception = createBillingException("This should never have happened!!!");
    }
    addExceptionToResponse(responseBuilder, exception);
    return uriBuilder.buildResponse(responseBuilder, uriInfo, PaymentResource.class, "getPayment", payment.getId(), request);
}
Also used : PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) BillingExceptionJson(org.killbill.billing.jaxrs.json.BillingExceptionJson) ResponseBuilder(javax.ws.rs.core.Response.ResponseBuilder)

Example 8 with PaymentTransaction

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

the class PaymentResource method completeTransactionInternal.

private Response completeTransactionInternal(final PaymentTransactionJson json, @Nullable final String paymentIdStr, final List<String> paymentControlPluginNames, final Iterable<String> pluginPropertiesString, final String createdBy, final String reason, final String comment, final UriInfo uriInfo, final HttpServletRequest request) throws PaymentApiException, AccountApiException {
    final Iterable<PluginProperty> pluginPropertiesFromBody = extractPluginProperties(json.getProperties());
    final Iterable<PluginProperty> pluginPropertiesFromQuery = extractPluginProperties(pluginPropertiesString);
    final Iterable<PluginProperty> pluginProperties = Iterables.concat(pluginPropertiesFromQuery, pluginPropertiesFromBody);
    final CallContext callContext = context.createContext(createdBy, reason, comment, request);
    final Payment initialPayment = getPaymentByIdOrKey(paymentIdStr, json == null ? null : json.getPaymentExternalKey(), pluginProperties, callContext);
    final Account account = accountUserApi.getAccountById(initialPayment.getAccountId(), callContext);
    final BigDecimal amount = json == null ? null : json.getAmount();
    final Currency currency = json == null || json.getCurrency() == null ? null : Currency.valueOf(json.getCurrency());
    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);
    }
    final PaymentTransaction pendingTransaction = pendingOrSuccessTransaction;
    final PaymentOptions paymentOptions = createControlPluginApiPaymentOptions(paymentControlPluginNames);
    final Payment result;
    switch(pendingTransaction.getTransactionType()) {
        case AUTHORIZE:
            result = paymentApi.createAuthorizationWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, initialPayment.getExternalKey(), pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
            break;
        case CAPTURE:
            result = paymentApi.createCaptureWithPaymentControl(account, initialPayment.getId(), amount, currency, pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
            break;
        case PURCHASE:
            result = paymentApi.createPurchaseWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, initialPayment.getExternalKey(), pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
            break;
        case CREDIT:
            result = paymentApi.createCreditWithPaymentControl(account, initialPayment.getPaymentMethodId(), initialPayment.getId(), amount, currency, initialPayment.getExternalKey(), pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
            break;
        case REFUND:
            result = paymentApi.createRefundWithPaymentControl(account, initialPayment.getId(), amount, currency, pendingTransaction.getExternalKey(), pluginProperties, paymentOptions, callContext);
            break;
        default:
            return Response.status(Status.PRECONDITION_FAILED).entity("TransactionType " + pendingTransaction.getTransactionType() + " cannot be completed").build();
    }
    return createPaymentResponse(uriInfo, result, pendingTransaction.getTransactionType(), pendingTransaction.getExternalKey(), request);
}
Also used : PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) PluginProperty(org.killbill.billing.payment.api.PluginProperty) Account(org.killbill.billing.account.api.Account) Payment(org.killbill.billing.payment.api.Payment) Currency(org.killbill.billing.catalog.api.Currency) PaymentOptions(org.killbill.billing.payment.api.PaymentOptions) CallContext(org.killbill.billing.util.callcontext.CallContext) BigDecimal(java.math.BigDecimal)

Example 9 with PaymentTransaction

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

the class TestInvoicePayment method testWithIncompletePaymentAttempt.

@Test(groups = "slow")
public void testWithIncompletePaymentAttempt() 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 = createAccountWithNonOsgiPaymentMethod(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);
    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);
    // 2012-05-31 => DAY 30 have to get out of trial {I0, P0}
    addDaysAndCheckForCompletion(30, NextEvent.PHASE, NextEvent.INVOICE, NextEvent.PAYMENT, NextEvent.INVOICE_PAYMENT);
    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 fully paid
    final Payment originalPayment = paymentChecker.checkPayment(account.getId(), 1, callContext, new ExpectedPaymentCheck(new LocalDate(2012, 5, 31), new BigDecimal("249.95"), TransactionStatus.SUCCESS, invoice2.getId(), Currency.USD));
    Assert.assertEquals(originalPayment.getPurchasedAmount().compareTo(new BigDecimal("249.95")), 0);
    Assert.assertEquals(originalPayment.getRefundedAmount().compareTo(BigDecimal.ZERO), 0);
    Assert.assertEquals(originalPayment.getTransactions().get(0).getProcessedAmount().compareTo(new BigDecimal("249.95")), 0);
    Assert.assertEquals(invoice2.getBalance().compareTo(BigDecimal.ZERO), 0);
    Assert.assertEquals(invoiceUserApi.getAccountBalance(account.getId(), callContext).compareTo(invoice2.getBalance()), 0);
    final PaymentTransaction originalTransaction = originalPayment.getTransactions().get(0);
    // Let 's hack invoice_payment table by hand to simulate a non completion of the payment (onSuccessCall was never called)
    dbi.withHandle(new HandleCallback<Void>() {

        @Override
        public Void withHandle(final Handle handle) throws Exception {
            handle.execute("update invoice_payments set success = false where payment_cookie_id = ?", originalTransaction.getExternalKey());
            return null;
        }
    });
    final Invoice updateInvoice2 = invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
    // Invoice now shows as unpaid
    Assert.assertEquals(updateInvoice2.getBalance().compareTo(originalPayment.getPurchasedAmount()), 0);
    Assert.assertEquals(updateInvoice2.getPayments().size(), 1);
    Assert.assertEquals(updateInvoice2.getPayments().get(0).getPaymentCookieId(), originalTransaction.getExternalKey());
    //
    // Now trigger invoice payment again (no new payment should be made as code should detect broken state and fix it by itself)
    // We expect an INVOICE_PAYMENT that indicates the invoice was repaired, and also an exception because plugin aborts payment call since there is nothing to do.
    //
    busHandler.pushExpectedEvents(NextEvent.INVOICE_PAYMENT);
    final List<PluginProperty> properties = new ArrayList<PluginProperty>();
    final PluginProperty prop1 = new PluginProperty(InvoicePaymentControlPluginApi.PROP_IPCD_INVOICE_ID, updateInvoice2.getId().toString(), false);
    properties.add(prop1);
    try {
        paymentApi.createPurchaseWithPaymentControl(account, account.getPaymentMethodId(), null, updateInvoice2.getBalance(), updateInvoice2.getCurrency(), UUID.randomUUID().toString(), UUID.randomUUID().toString(), properties, PAYMENT_OPTIONS, callContext);
        Assert.fail("The payment should not succeed (and yet it will repair the broken state....)");
    } catch (final PaymentApiException expected) {
        Assert.assertEquals(expected.getCode(), ErrorCode.PAYMENT_PLUGIN_EXCEPTION.getCode());
    }
    assertListenerStatus();
    final Invoice updateInvoice3 = invoiceChecker.checkInvoice(account.getId(), 2, callContext, new ExpectedInvoiceItemCheck(new LocalDate(2012, 5, 31), new LocalDate(2012, 6, 30), InvoiceItemType.RECURRING, new BigDecimal("249.95")));
    Assert.assertEquals(updateInvoice3.getBalance().compareTo(BigDecimal.ZERO), 0);
    Assert.assertEquals(updateInvoice3.getPayments().size(), 1);
    Assert.assertEquals(updateInvoice3.getPayments().get(0).getPaymentCookieId(), originalTransaction.getExternalKey());
    Assert.assertTrue(updateInvoice3.getPayments().get(0).isSuccess());
    Assert.assertEquals(invoiceUserApi.getAccountBalance(account.getId(), callContext).compareTo(invoice2.getBalance()), 0);
    final List<Payment> payments = paymentApi.getAccountPayments(account.getId(), false, false, ImmutableList.<PluginProperty>of(), callContext);
    Assert.assertEquals(payments.size(), 1);
    Assert.assertEquals(payments.get(0).getTransactions().size(), 1);
}
Also used : Account(org.killbill.billing.account.api.Account) Invoice(org.killbill.billing.invoice.api.Invoice) ArrayList(java.util.ArrayList) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) ExpectedInvoiceItemCheck(org.killbill.billing.beatrix.util.InvoiceChecker.ExpectedInvoiceItemCheck) LocalDate(org.joda.time.LocalDate) DateTime(org.joda.time.DateTime) BigDecimal(java.math.BigDecimal) ExpectedPaymentCheck(org.killbill.billing.beatrix.util.PaymentChecker.ExpectedPaymentCheck) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException) Handle(org.skife.jdbi.v2.Handle) PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) PluginProperty(org.killbill.billing.payment.api.PluginProperty) Payment(org.killbill.billing.payment.api.Payment) AccountData(org.killbill.billing.account.api.AccountData) DefaultEntitlement(org.killbill.billing.entitlement.api.DefaultEntitlement) Test(org.testng.annotations.Test)

Example 10 with PaymentTransaction

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

the class MockRetryAuthorizeOperationCallback method doCallSpecificOperationCallback.

@Override
protected Payment doCallSpecificOperationCallback() throws PaymentApiException {
    if (exception != null) {
        if (exception instanceof PaymentApiException) {
            throw (PaymentApiException) exception;
        } else if (exception instanceof RuntimeException) {
            throw (RuntimeException) exception;
        } else {
            throw new RuntimeException(exception);
        }
    }
    final PaymentModelDao payment = new PaymentModelDao(clock.getUTCNow(), clock.getUTCNow(), paymentStateContext.getAccount().getId(), paymentStateContext.getPaymentMethodId(), paymentStateContext.getPaymentExternalKey());
    final PaymentTransactionModelDao transaction = new PaymentTransactionModelDao(clock.getUTCNow(), clock.getUTCNow(), paymentStateContext.getAttemptId(), paymentStateContext.getPaymentTransactionExternalKey(), paymentStateContext.getPaymentId(), paymentStateContext.getTransactionType(), clock.getUTCNow(), TransactionStatus.SUCCESS, paymentStateContext.getAmount(), paymentStateContext.getCurrency(), "", "");
    final PaymentModelDao paymentModelDao = paymentDao.insertPaymentWithFirstTransaction(payment, transaction, paymentStateContext.getInternalCallContext());
    final PaymentTransaction convertedTransaction = new DefaultPaymentTransaction(transaction.getId(), paymentStateContext.getAttemptId(), transaction.getTransactionExternalKey(), transaction.getCreatedDate(), transaction.getUpdatedDate(), transaction.getPaymentId(), transaction.getTransactionType(), transaction.getEffectiveDate(), transaction.getTransactionStatus(), transaction.getAmount(), transaction.getCurrency(), transaction.getProcessedAmount(), transaction.getProcessedCurrency(), transaction.getGatewayErrorCode(), transaction.getGatewayErrorMsg(), null);
    return new DefaultPayment(paymentModelDao.getId(), paymentModelDao.getCreatedDate(), paymentModelDao.getUpdatedDate(), paymentModelDao.getAccountId(), paymentModelDao.getPaymentMethodId(), paymentModelDao.getPaymentNumber(), paymentModelDao.getExternalKey(), Collections.singletonList(convertedTransaction), null);
}
Also used : DefaultPaymentTransaction(org.killbill.billing.payment.api.DefaultPaymentTransaction) PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) DefaultPayment(org.killbill.billing.payment.api.DefaultPayment) PaymentTransactionModelDao(org.killbill.billing.payment.dao.PaymentTransactionModelDao) PaymentModelDao(org.killbill.billing.payment.dao.PaymentModelDao) DefaultPaymentTransaction(org.killbill.billing.payment.api.DefaultPaymentTransaction) PaymentApiException(org.killbill.billing.payment.api.PaymentApiException)

Aggregations

PaymentTransaction (org.killbill.billing.payment.api.PaymentTransaction)20 Payment (org.killbill.billing.payment.api.Payment)12 PluginProperty (org.killbill.billing.payment.api.PluginProperty)7 PaymentApiException (org.killbill.billing.payment.api.PaymentApiException)6 BigDecimal (java.math.BigDecimal)5 UUID (java.util.UUID)5 Account (org.killbill.billing.account.api.Account)5 InvoicePayment (org.killbill.billing.invoice.api.InvoicePayment)4 CallContext (org.killbill.billing.util.callcontext.CallContext)4 Predicate (com.google.common.base.Predicate)3 ArrayList (java.util.ArrayList)3 LocalDate (org.joda.time.LocalDate)3 Invoice (org.killbill.billing.invoice.api.Invoice)3 Test (org.testng.annotations.Test)3 AccountApiException (org.killbill.billing.account.api.AccountApiException)2 AccountData (org.killbill.billing.account.api.AccountData)2 InternalCallContext (org.killbill.billing.callcontext.InternalCallContext)2 Currency (org.killbill.billing.catalog.api.Currency)2 DefaultEntitlement (org.killbill.billing.entitlement.api.DefaultEntitlement)2 DefaultPayment (org.killbill.billing.payment.api.DefaultPayment)2