Search in sources :

Example 11 with InvoicePayment

use of org.killbill.billing.invoice.api.InvoicePayment in project killbill by killbill.

the class DefaultInvoiceInternalApi method recordPaymentAttemptCompletion.

@Override
public void recordPaymentAttemptCompletion(final UUID invoiceId, final BigDecimal amount, final Currency currency, final Currency processedCurrency, final UUID paymentId, final String transactionExternalKey, final DateTime paymentDate, final boolean success, final InternalCallContext context) throws InvoiceApiException {
    final InvoicePayment invoicePayment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentId, invoiceId, paymentDate, amount, currency, processedCurrency, transactionExternalKey, success);
    dao.notifyOfPaymentCompletion(new InvoicePaymentModelDao(invoicePayment), context);
}
Also used : DefaultInvoicePayment(org.killbill.billing.invoice.model.DefaultInvoicePayment) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) InvoicePaymentModelDao(org.killbill.billing.invoice.dao.InvoicePaymentModelDao) DefaultInvoicePayment(org.killbill.billing.invoice.model.DefaultInvoicePayment)

Example 12 with InvoicePayment

use of org.killbill.billing.invoice.api.InvoicePayment in project killbill by killbill.

the class DefaultInvoiceInternalApi method recordPaymentAttemptInit.

@Override
public void recordPaymentAttemptInit(final UUID invoiceId, final BigDecimal amount, final Currency currency, final Currency processedCurrency, final UUID paymentId, final String transactionExternalKey, final DateTime paymentDate, final InternalCallContext context) throws InvoiceApiException {
    final InvoicePayment invoicePayment = new DefaultInvoicePayment(InvoicePaymentType.ATTEMPT, paymentId, invoiceId, paymentDate, amount, currency, processedCurrency, transactionExternalKey, false);
    dao.notifyOfPaymentInit(new InvoicePaymentModelDao(invoicePayment), context);
}
Also used : DefaultInvoicePayment(org.killbill.billing.invoice.model.DefaultInvoicePayment) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) InvoicePaymentModelDao(org.killbill.billing.invoice.dao.InvoicePaymentModelDao) DefaultInvoicePayment(org.killbill.billing.invoice.model.DefaultInvoicePayment)

Example 13 with InvoicePayment

use of org.killbill.billing.invoice.api.InvoicePayment in project killbill by killbill.

the class RefundChecker method checkRefund.

public PaymentTransaction checkRefund(final UUID paymentId, final CallContext context, ExpectedRefundCheck expected) throws PaymentApiException {
    final Payment payment = paymentApi.getPayment(paymentId, false, false, ImmutableList.<PluginProperty>of(), context);
    final PaymentTransaction refund = Iterables.tryFind(payment.getTransactions(), new Predicate<PaymentTransaction>() {

        @Override
        public boolean apply(final PaymentTransaction input) {
            return input.getTransactionType() == TransactionType.REFUND;
        }
    }).orNull();
    Assert.assertNotNull(refund);
    final InvoicePayment refundInvoicePayment = getInvoicePaymentEntry(paymentId, InvoicePaymentType.REFUND, context);
    final InvoicePayment invoicePayment = getInvoicePaymentEntry(paymentId, InvoicePaymentType.ATTEMPT, context);
    Assert.assertEquals(refund.getPaymentId(), expected.getPaymentId());
    Assert.assertEquals(refund.getCurrency(), expected.getCurrency());
    Assert.assertEquals(refund.getAmount().compareTo(expected.getRefundAmount()), 0);
    Assert.assertEquals(refundInvoicePayment.getPaymentId(), paymentId);
    Assert.assertEquals(refundInvoicePayment.getLinkedInvoicePaymentId(), invoicePayment.getId());
    Assert.assertEquals(refundInvoicePayment.getPaymentCookieId(), refund.getExternalKey());
    Assert.assertEquals(refundInvoicePayment.getInvoiceId(), invoicePayment.getInvoiceId());
    Assert.assertEquals(refundInvoicePayment.getAmount().compareTo(expected.getRefundAmount().negate()), 0);
    Assert.assertEquals(refundInvoicePayment.getCurrency(), expected.getCurrency());
    return refund;
}
Also used : PaymentTransaction(org.killbill.billing.payment.api.PaymentTransaction) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) Payment(org.killbill.billing.payment.api.Payment) Predicate(com.google.common.base.Predicate)

Example 14 with InvoicePayment

use of org.killbill.billing.invoice.api.InvoicePayment 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 15 with InvoicePayment

use of org.killbill.billing.invoice.api.InvoicePayment in project killbill by killbill.

the class InvoiceResource method getPayments.

@TimedResource
@GET
@Path("/{invoiceId:" + UUID_PATTERN + "}/" + PAYMENTS)
@Produces(APPLICATION_JSON)
@ApiOperation(value = "Retrieve payments associated with an invoice", response = InvoicePaymentJson.class, responseContainer = "List")
@ApiResponses(value = { @ApiResponse(code = 400, message = "Invalid invoice id supplied"), @ApiResponse(code = 404, message = "Invoice not found") })
public Response getPayments(@PathParam("invoiceId") final String invoiceId, @QueryParam(QUERY_AUDIT) @DefaultValue("NONE") final AuditMode auditMode, @QueryParam(QUERY_WITH_PLUGIN_INFO) @DefaultValue("false") final Boolean withPluginInfo, @QueryParam(QUERY_WITH_ATTEMPTS) @DefaultValue("false") final Boolean withAttempts, @javax.ws.rs.core.Context final HttpServletRequest request) throws PaymentApiException, InvoiceApiException {
    final TenantContext tenantContext = context.createContext(request);
    final Invoice invoice = invoiceApi.getInvoice(UUID.fromString(invoiceId), tenantContext);
    // Extract unique set of paymentId for this invoice
    final Set<UUID> invoicePaymentIds = ImmutableSet.copyOf(Iterables.transform(invoice.getPayments(), new Function<InvoicePayment, UUID>() {

        @Override
        public UUID apply(final InvoicePayment input) {
            return input.getPaymentId();
        }
    }));
    if (invoicePaymentIds.isEmpty()) {
        return Response.status(Status.OK).entity(ImmutableList.<InvoicePaymentJson>of()).build();
    }
    final List<Payment> payments = new ArrayList<Payment>();
    for (final UUID paymentId : invoicePaymentIds) {
        final Payment payment = paymentApi.getPayment(paymentId, withPluginInfo, withAttempts, ImmutableList.<PluginProperty>of(), tenantContext);
        payments.add(payment);
    }
    final Iterable<InvoicePaymentJson> result = INVOICE_PAYMENT_ORDERING.sortedCopy(Iterables.transform(payments, new Function<Payment, InvoicePaymentJson>() {

        @Override
        public InvoicePaymentJson apply(final Payment input) {
            return new InvoicePaymentJson(input, invoice.getId(), null);
        }
    }));
    return Response.status(Status.OK).entity(result).build();
}
Also used : Function(com.google.common.base.Function) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) InvoicePayment(org.killbill.billing.invoice.api.InvoicePayment) Payment(org.killbill.billing.payment.api.Payment) Invoice(org.killbill.billing.invoice.api.Invoice) InvoicePaymentJson(org.killbill.billing.jaxrs.json.InvoicePaymentJson) ArrayList(java.util.ArrayList) TenantContext(org.killbill.billing.util.callcontext.TenantContext) UUID(java.util.UUID) Path(javax.ws.rs.Path) TimedResource(org.killbill.commons.metrics.TimedResource) Produces(javax.ws.rs.Produces) GET(javax.ws.rs.GET) ApiOperation(io.swagger.annotations.ApiOperation) ApiResponses(io.swagger.annotations.ApiResponses)

Aggregations

InvoicePayment (org.killbill.billing.invoice.api.InvoicePayment)20 UUID (java.util.UUID)11 BigDecimal (java.math.BigDecimal)9 DateTime (org.joda.time.DateTime)8 Invoice (org.killbill.billing.invoice.api.Invoice)8 DefaultInvoicePayment (org.killbill.billing.invoice.model.DefaultInvoicePayment)8 LocalDate (org.joda.time.LocalDate)7 DefaultInvoice (org.killbill.billing.invoice.model.DefaultInvoice)6 Payment (org.killbill.billing.payment.api.Payment)6 RecurringInvoiceItem (org.killbill.billing.invoice.model.RecurringInvoiceItem)5 ApiOperation (io.swagger.annotations.ApiOperation)4 ApiResponses (io.swagger.annotations.ApiResponses)4 GET (javax.ws.rs.GET)4 Path (javax.ws.rs.Path)4 Produces (javax.ws.rs.Produces)4 TenantContext (org.killbill.billing.util.callcontext.TenantContext)4 TimedResource (org.killbill.commons.metrics.TimedResource)4 Predicate (com.google.common.base.Predicate)3 ArrayList (java.util.ArrayList)3 CreditBalanceAdjInvoiceItem (org.killbill.billing.invoice.model.CreditBalanceAdjInvoiceItem)3