Search in sources :

Example 1 with PurchaseContext

use of alfio.model.PurchaseContext in project alf.io by alfio-event.

the class BankTransferManager method getModelOptions.

@Override
public Map<String, ?> getModelOptions(PaymentContext context) {
    OptionalInt delay = getOfflinePaymentWaitingPeriod(context, configurationManager);
    PurchaseContext purchaseContext = context.getPurchaseContext();
    if (delay.isEmpty()) {
        log.error("Already started event {} has been found with OFFLINE payment enabled", purchaseContext.getDisplayName());
    }
    Map<String, Object> model = new HashMap<>();
    model.put("delayForOfflinePayment", Math.max(1, delay.orElse(0)));
    boolean recaptchaEnabled = configurationManager.isRecaptchaForOfflinePaymentAndFreeEnabled(purchaseContext.getConfigurationLevel());
    model.put("captchaRequestedForOffline", recaptchaEnabled);
    if (recaptchaEnabled) {
        model.put("recaptchaApiKey", configurationManager.getForSystem(RECAPTCHA_API_KEY).getValue().orElse(null));
    }
    return model;
}
Also used : PurchaseContext(alfio.model.PurchaseContext)

Example 2 with PurchaseContext

use of alfio.model.PurchaseContext in project alf.io by alfio-event.

the class StripeWebhookPaymentManager method forceTransactionCheck.

@Override
public PaymentWebhookResult forceTransactionCheck(TicketReservation reservation, Transaction transaction, PaymentContext paymentContext) {
    Validate.isTrue(transaction.getPaymentProxy() == PaymentProxy.STRIPE, "invalid transaction");
    try {
        PurchaseContext purchaseContext = paymentContext.getPurchaseContext();
        var options = baseStripeManager.options(purchaseContext, builder -> builder.setIdempotencyKey(reservation.getId())).orElseThrow();
        var intent = PaymentIntent.retrieve(transaction.getPaymentId(), options);
        switch(intent.getStatus()) {
            case "processing":
            case "requires_action":
            case "requires_confirmation":
                return PaymentWebhookResult.pending();
            case "succeeded":
                return processSuccessfulPaymentIntent(transaction, intent, reservation, purchaseContext);
            case REQUIRES_PAYMENT_METHOD:
                // payment is failed.
                return processFailedPaymentIntent(transaction, reservation, purchaseContext);
            default:
                return null;
        }
    } catch (Exception ex) {
        log.error("Error trying to check PaymentIntent status", ex);
        return PaymentWebhookResult.error("failed");
    }
}
Also used : alfio.repository(alfio.repository) java.util(java.util) ConfigurationLevel(alfio.manager.system.ConfigurationLevel) ZonedDateTime(java.time.ZonedDateTime) PaymentResult(alfio.manager.support.PaymentResult) PurchaseContext(alfio.model.PurchaseContext) ConfigurationManager(alfio.manager.system.ConfigurationManager) JsonParser(com.google.gson.JsonParser) PaymentInformation(alfio.model.PaymentInformation) Charge(com.stripe.model.Charge) alfio.model.transaction.capabilities(alfio.model.transaction.capabilities) PaymentIntent(com.stripe.model.PaymentIntent) alfio.model.transaction(alfio.model.transaction) StripeChargeTransactionWebhookPayload(alfio.model.transaction.webhook.StripeChargeTransactionWebhookPayload) StripePaymentIntentWebhookPayload(alfio.model.transaction.webhook.StripePaymentIntentWebhookPayload) StripeException(com.stripe.exception.StripeException) Stripe(com.stripe.Stripe) ConfigurationRepository(alfio.repository.system.ConfigurationRepository) Audit(alfio.model.Audit) Component(org.springframework.stereotype.Component) Validate(org.apache.commons.lang3.Validate) StringReader(java.io.StringReader) StripeSCACreditCardToken(alfio.model.transaction.token.StripeSCACreditCardToken) Environment(org.springframework.core.env.Environment) STRIPE_MANAGER_TYPE_KEY(alfio.manager.payment.BaseStripeManager.STRIPE_MANAGER_TYPE_KEY) TicketReservation(alfio.model.TicketReservation) Log4j2(lombok.extern.log4j.Log4j2) PaymentWebhookResult(alfio.manager.support.PaymentWebhookResult) StripeObject(com.stripe.model.StripeObject) ClockProvider(alfio.util.ClockProvider) EXTERNAL_PROCESSING_PAYMENT(alfio.model.TicketReservation.TicketReservationStatus.EXTERNAL_PROCESSING_PAYMENT) ConfigurationKeys(alfio.model.system.ConfigurationKeys) WAITING_EXTERNAL_CONFIRMATION(alfio.model.TicketReservation.TicketReservationStatus.WAITING_EXTERNAL_CONFIRMATION) BalanceTransaction(com.stripe.model.BalanceTransaction) Webhook(com.stripe.net.Webhook) Transactional(org.springframework.transaction.annotation.Transactional) PurchaseContext(alfio.model.PurchaseContext) StripeException(com.stripe.exception.StripeException)

Example 3 with PurchaseContext

use of alfio.model.PurchaseContext in project alf.io by alfio-event.

the class BaseStripeManager method refund.

// https://stripe.com/docs/api#create_refund
boolean refund(Transaction transaction, PurchaseContext purchaseContext, Integer amountToRefund) {
    Optional<Integer> amount = Optional.ofNullable(amountToRefund);
    String chargeId = transaction.getTransactionId();
    try {
        String amountOrFull = amount.map(p -> MonetaryUtil.formatCents(p, transaction.getCurrency())).orElse("full");
        log.info("Stripe: trying to do a refund for payment {} with amount: {}", chargeId, amountOrFull);
        Map<String, Object> params = new HashMap<>();
        params.put("charge", chargeId);
        amount.ifPresent(a -> params.put("amount", a));
        if (transaction.getPlatformFee() > 0 && isConnectEnabled(new PaymentContext(purchaseContext))) {
            params.put("refund_application_fee", true);
        }
        Optional<RequestOptions> requestOptionsOptional = options(purchaseContext);
        if (requestOptionsOptional.isPresent()) {
            RequestOptions options = requestOptionsOptional.get();
            Refund r = Refund.create(params, options);
            boolean pending = PENDING.equals(r.getStatus());
            if (SUCCEEDED.equals(r.getStatus()) || pending) {
                log.info("Stripe: refund for payment {} {} for amount: {}", chargeId, pending ? "registered" : "executed with success", amountOrFull);
                return true;
            } else {
                log.warn("Stripe: was not able to refund payment with id {}, returned status is not 'succeded' but {}", chargeId, r.getStatus());
                return false;
            }
        }
        return false;
    } catch (StripeException e) {
        log.warn("Stripe: was not able to refund payment with id " + chargeId, e);
        return false;
    }
}
Also used : Transaction(alfio.model.transaction.Transaction) RequestOptions(com.stripe.net.RequestOptions) java.util(java.util) PaymentProxy(alfio.model.transaction.PaymentProxy) PaymentResult(alfio.manager.support.PaymentResult) PurchaseContext(alfio.model.PurchaseContext) PurchaseContextType(alfio.model.PurchaseContext.PurchaseContextType) UnaryOperator(java.util.function.UnaryOperator) ConfigurationManager(alfio.manager.system.ConfigurationManager) PaymentInformation(alfio.model.PaymentInformation) Charge(com.stripe.model.Charge) Profiles(org.springframework.core.env.Profiles) Configurable(alfio.model.Configurable) Refund(com.stripe.model.Refund) TicketRepository(alfio.repository.TicketRepository) Predicate(java.util.function.Predicate) FeeCalculator(alfio.manager.support.FeeCalculator) PaymentMethod(alfio.model.transaction.PaymentMethod) Stripe(com.stripe.Stripe) ErrorsCode(alfio.util.ErrorsCode) ConfigurationRepository(alfio.repository.system.ConfigurationRepository) PaymentContext(alfio.model.transaction.PaymentContext) MonetaryUtil(alfio.util.MonetaryUtil) Environment(org.springframework.core.env.Environment) UserManager(alfio.manager.user.UserManager) Log4j2(lombok.extern.log4j.Log4j2) ConfigurationPathLevel(alfio.model.system.ConfigurationPathLevel) com.stripe.exception(com.stripe.exception) AllArgsConstructor(lombok.AllArgsConstructor) ConfigurationKeys(alfio.model.system.ConfigurationKeys) BalanceTransaction(com.stripe.model.BalanceTransaction) Webhook(com.stripe.net.Webhook) RequestOptions(com.stripe.net.RequestOptions) PaymentContext(alfio.model.transaction.PaymentContext) Refund(com.stripe.model.Refund)

Example 4 with PurchaseContext

use of alfio.model.PurchaseContext in project alf.io by alfio-event.

the class MollieWebhookPaymentManager method initPayment.

private PaymentResult initPayment(TicketReservation reservation, PaymentSpecification spec, String baseUrl, Map<ConfigurationKeys, ConfigurationManager.MaybeConfiguration> configuration) throws IOException, InterruptedException {
    var purchaseContext = spec.getPurchaseContext();
    var purchaseContextUrlComponent = purchaseContext.getType().getUrlComponent();
    var publicIdentifier = purchaseContext.getPublicIdentifier();
    var reservationId = reservation.getId();
    String bookUrl = baseUrl + "/" + purchaseContextUrlComponent + "/" + publicIdentifier + "/reservation/" + reservationId + "/book";
    final int items;
    if (spec.getPurchaseContext().getType() == PurchaseContext.PurchaseContextType.event) {
        items = ticketRepository.countTicketsInReservation(spec.getReservationId());
    } else {
        items = 1;
    }
    Map<String, Object> payload = new HashMap<>();
    payload.put(AMOUNT, Map.of(VALUE, spec.getOrderSummary().getTotalPrice(), CURRENCY, spec.getPurchaseContext().getCurrency()));
    var description = purchaseContext.ofType(PurchaseContext.PurchaseContextType.event) ? "ticket(s) for event" : "x subscription";
    payload.put("description", String.format("%s - %d %s %s", configurationManager.getShortReservationID(spec.getPurchaseContext(), reservation), items, description, spec.getPurchaseContext().getDisplayName()));
    payload.put("redirectUrl", bookUrl);
    payload.put("webhookUrl", baseUrl + UriComponentsBuilder.fromPath(WEBHOOK_URL_TEMPLATE).buildAndExpand(reservationId).toUriString());
    payload.put("metadata", MetadataBuilder.buildMetadata(spec, Map.of()));
    if (configuration.get(PLATFORM_MODE_ENABLED).getValueAsBooleanOrDefault()) {
        payload.put("profileId", configuration.get(MOLLIE_CONNECT_PROFILE_ID).getRequiredValue());
        payload.put("testmode", !configuration.get(MOLLIE_CONNECT_LIVE_MODE).getValueAsBooleanOrDefault());
        String currencyCode = spec.getCurrencyCode();
        FeeCalculator.getCalculator(spec.getPurchaseContext(), configurationManager, currencyCode).apply(items, (long) spec.getPriceWithVAT()).filter(// minimum fee for Mollie is 0.01
        fee -> fee > 1L).map(fee -> MonetaryUtil.formatCents(fee, currencyCode)).ifPresent(fee -> payload.put("applicationFee", Map.of(AMOUNT, Map.of(CURRENCY, currencyCode, VALUE, fee), "description", "Reservation" + reservationId)));
    }
    HttpRequest request = requestFor(PAYMENTS_ENDPOINT, configuration, spec.getPurchaseContext().getConfigurationLevel()).header(HttpUtils.CONTENT_TYPE, HttpUtils.APPLICATION_JSON).POST(HttpRequest.BodyPublishers.ofString(Json.GSON.toJson(payload))).build();
    HttpResponse<InputStream> response = client.send(request, HttpResponse.BodyHandlers.ofInputStream());
    if (HttpUtils.callSuccessful(response)) {
        try (var responseReader = new InputStreamReader(response.body(), UTF_8)) {
            var body = new MolliePaymentDetails(JsonParser.parseReader(responseReader).getAsJsonObject());
            var paymentId = body.getPaymentId();
            var checkoutLink = body.getCheckoutLink();
            // we give an additional slack to process the payment
            var expiration = body.getExpiresAt().orElseThrow().plusMinutes(5);
            ticketReservationRepository.updateReservationStatus(reservationId, EXTERNAL_PROCESSING_PAYMENT.toString());
            ticketReservationRepository.updateValidity(reservationId, Date.from(expiration.toInstant()));
            invalidateExistingTransactions(reservationId, transactionRepository);
            transactionRepository.insert(paymentId, paymentId, reservationId, ZonedDateTime.now(clockProvider.withZone(spec.getPurchaseContext().getZoneId())), spec.getPriceWithVAT(), spec.getPurchaseContext().getCurrency(), "Mollie Payment", PaymentProxy.MOLLIE.name(), 0L, 0L, Transaction.Status.PENDING, Map.of());
            return PaymentResult.redirect(checkoutLink);
        }
    } else {
        log.warn("was not able to create a payment for reservation id " + reservationId);
        return PaymentResult.failed(ErrorsCode.STEP_2_PAYMENT_REQUEST_CREATION);
    }
}
Also used : JsonObject(com.google.gson.JsonObject) UriComponentsBuilder(org.springframework.web.util.UriComponentsBuilder) ZonedDateTime(java.time.ZonedDateTime) PaymentResult(alfio.manager.support.PaymentResult) PurchaseContext(alfio.model.PurchaseContext) StringUtils(org.apache.commons.lang3.StringUtils) PaymentInformation(alfio.model.PaymentInformation) MonetaryUtil.formatCents(alfio.util.MonetaryUtil.formatCents) PurchaseContextManager(alfio.manager.PurchaseContextManager) Duration(java.time.Duration) URI(java.net.URI) AccessTokenResponseDetails(alfio.util.oauth2.AccessTokenResponseDetails) RefundRequest(alfio.model.transaction.capabilities.RefundRequest) MollieToken(alfio.model.transaction.token.MollieToken) HttpResponse(java.net.http.HttpResponse) FeeCalculator(alfio.manager.support.FeeCalculator) EXTERNAL_PROCESSING_PAYMENT(alfio.model.TicketReservation.TicketReservationStatus.EXTERNAL_PROCESSING_PAYMENT) java.util(java.util) ConfigurationLevel(alfio.manager.system.ConfigurationLevel) MaybeConfiguration(alfio.manager.system.ConfigurationManager.MaybeConfiguration) TicketReservationRepository(alfio.repository.TicketReservationRepository) ConfigurationManager(alfio.manager.system.ConfigurationManager) Cache(com.github.benmanes.caffeine.cache.Cache) JsonParser(com.google.gson.JsonParser) alfio.util(alfio.util) HttpRequest(java.net.http.HttpRequest) MollieWebhookPayload(alfio.model.transaction.webhook.MollieWebhookPayload) alfio.model.transaction(alfio.model.transaction) TransactionRepository(alfio.repository.TransactionRepository) HttpClient(java.net.http.HttpClient) Caffeine(com.github.benmanes.caffeine.cache.Caffeine) TicketRepository(alfio.repository.TicketRepository) UTF_8(java.nio.charset.StandardCharsets.UTF_8) IOException(java.io.IOException) PaymentInfo(alfio.model.transaction.capabilities.PaymentInfo) WebhookHandler(alfio.model.transaction.capabilities.WebhookHandler) InputStreamReader(java.io.InputStreamReader) Component(org.springframework.stereotype.Component) Validate(org.apache.commons.lang3.Validate) StringReader(java.io.StringReader) TicketReservation(alfio.model.TicketReservation) Data(lombok.Data) Log4j2(lombok.extern.log4j.Log4j2) PaymentWebhookResult(alfio.manager.support.PaymentWebhookResult) PaymentManagerUtils.invalidateExistingTransactions(alfio.manager.payment.PaymentManagerUtils.invalidateExistingTransactions) AllArgsConstructor(lombok.AllArgsConstructor) ConfigurationKeys(alfio.model.system.ConfigurationKeys) WAITING_EXTERNAL_CONFIRMATION(alfio.model.TicketReservation.TicketReservationStatus.WAITING_EXTERNAL_CONFIRMATION) InputStream(java.io.InputStream) HttpRequest(java.net.http.HttpRequest) InputStreamReader(java.io.InputStreamReader) InputStream(java.io.InputStream) JsonObject(com.google.gson.JsonObject)

Example 5 with PurchaseContext

use of alfio.model.PurchaseContext in project alf.io by alfio-event.

the class BankTransferManager method getOfflinePaymentDeadline.

public static ZonedDateTime getOfflinePaymentDeadline(PaymentContext context, ConfigurationManager configurationManager) {
    PurchaseContext purchaseContext = context.getPurchaseContext();
    ZonedDateTime now = purchaseContext.now(ClockProvider.clock());
    int waitingPeriod = getOfflinePaymentWaitingPeriod(context, configurationManager).orElse(0);
    if (waitingPeriod == 0) {
        log.warn("accepting offline payments the same day is a very bad practice and should be avoided. Please set cash payment as payment method next time");
        // TODO Maybe should we avoid this wrong behavior upfront, in the admin area?
        return now.plusHours(2);
    }
    return now.plusDays(waitingPeriod).truncatedTo(ChronoUnit.HALF_DAYS).with(WorkingDaysAdjusters.defaultWorkingDays());
}
Also used : PurchaseContext(alfio.model.PurchaseContext) ZonedDateTime(java.time.ZonedDateTime)

Aggregations

PurchaseContext (alfio.model.PurchaseContext)6 java.util (java.util)4 PaymentResult (alfio.manager.support.PaymentResult)3 ConfigurationManager (alfio.manager.system.ConfigurationManager)3 PaymentInformation (alfio.model.PaymentInformation)3 ConfigurationKeys (alfio.model.system.ConfigurationKeys)3 ZonedDateTime (java.time.ZonedDateTime)3 AllArgsConstructor (lombok.AllArgsConstructor)3 Log4j2 (lombok.extern.log4j.Log4j2)3 Validate (org.apache.commons.lang3.Validate)3 Component (org.springframework.stereotype.Component)3 FeeCalculator (alfio.manager.support.FeeCalculator)2 PaymentWebhookResult (alfio.manager.support.PaymentWebhookResult)2 ConfigurationLevel (alfio.manager.system.ConfigurationLevel)2 TicketReservation (alfio.model.TicketReservation)2 EXTERNAL_PROCESSING_PAYMENT (alfio.model.TicketReservation.TicketReservationStatus.EXTERNAL_PROCESSING_PAYMENT)2 WAITING_EXTERNAL_CONFIRMATION (alfio.model.TicketReservation.TicketReservationStatus.WAITING_EXTERNAL_CONFIRMATION)2 alfio.model.transaction (alfio.model.transaction)2 TicketRepository (alfio.repository.TicketRepository)2 OpenIdAlfioAuthentication (alfio.config.authentication.support.OpenIdAlfioAuthentication)1