Search in sources :

Example 1 with NOT_INCLUDED_NOT_CHARGED

use of alfio.model.PriceContainer.VatStatus.NOT_INCLUDED_NOT_CHARGED in project alf.io by alfio-event.

the class ReverseChargeManager method checkAndApplyVATRules.

public void checkAndApplyVATRules(PurchaseContext purchaseContext, String reservationId, ContactAndTicketsForm contactAndTicketsForm, BindingResult bindingResult) {
    String country = contactAndTicketsForm.getVatCountryCode();
    // validate VAT presence if Reverse Charge is enabled
    var reverseChargeConfiguration = EuVatChecker.loadConfigurationForReverseChargeCheck(configurationManager, purchaseContext);
    if (EuVatChecker.reverseChargeEnabled(reverseChargeConfiguration) && (country == null || isEUCountry(country))) {
        ValidationUtils.rejectIfEmptyOrWhitespace(bindingResult, "vatNr", "error.emptyField");
    }
    boolean isEvent = purchaseContext.ofType(PurchaseContext.PurchaseContextType.event);
    // we must take into account specific configuration only if the purchase context is an Event.
    // Otherwise, specific settings do not apply
    boolean reverseChargeInPerson = !isEvent || reverseChargeConfiguration.get(ENABLE_REVERSE_CHARGE_IN_PERSON).getValueAsBooleanOrDefault();
    boolean reverseChargeOnline = !isEvent || reverseChargeConfiguration.get(ENABLE_REVERSE_CHARGE_ONLINE).getValueAsBooleanOrDefault();
    try {
        var optionalReservation = ticketReservationRepository.findOptionalReservationById(reservationId);
        List<TicketCategory> categoriesList = optionalReservation.filter(// skip load if the current context is not "event"
        res -> isEvent).map(res -> ticketCategoryRepository.findCategoriesInReservation(res.getId())).orElse(List.of());
        Optional<VatDetail> vatDetail = optionalReservation.filter(e -> {
            if (purchaseContext.ofType(PurchaseContext.PurchaseContextType.event) && (!reverseChargeInPerson || !reverseChargeOnline)) {
                var eventFormat = purchaseContext.event().orElseThrow().getFormat();
                // if we find at least one category matching the criteria, then we can proceed
                return categoriesList.stream().anyMatch(findReverseChargeCategory(reverseChargeInPerson, reverseChargeOnline, eventFormat));
            }
            var vatStatus = purchaseContext.getVatStatus();
            return vatStatus == INCLUDED || vatStatus == NOT_INCLUDED;
        }).filter(e -> vatChecker.isReverseChargeEnabledFor(purchaseContext)).flatMap(e -> vatChecker.checkVat(contactAndTicketsForm.getVatNr(), country, purchaseContext));
        if (vatDetail.isPresent()) {
            var vatValidation = vatDetail.get();
            if (!vatValidation.isValid()) {
                bindingResult.rejectValue("vatNr", "error.STEP_2_INVALID_VAT");
            } else {
                var reservation = ticketReservationManager.findById(reservationId).orElseThrow();
                var currencyCode = reservation.getCurrencyCode();
                PriceContainer.VatStatus vatStatus = determineVatStatus(purchaseContext.getVatStatus(), vatValidation.isVatExempt());
                // standard case: Reverse Charge is applied to the entire reservation
                var discount = reservation.getPromoCodeDiscountId() != null ? promoCodeDiscountRepository.findById(reservation.getPromoCodeDiscountId()) : null;
                if (!isEvent || (reverseChargeOnline && reverseChargeInPerson)) {
                    if (isEvent) {
                        var event = purchaseContext.event().orElseThrow();
                        var priceContainers = mapPriceContainersByCategoryId(categoriesList, (a) -> true, currencyCode, vatStatus, discount, event);
                        // update all tickets in reservation to match the VAT_STATUS
                        ticketRepository.updateVatStatusForReservation(reservationId, vatStatus);
                        updateTicketPricesByCategory(reservationId, currencyCode, vatStatus, event, priceContainers);
                    }
                    updateBillingData(reservationId, contactAndTicketsForm, purchaseContext, country, trimToNull(vatValidation.getVatNr()), reservation, vatStatus);
                } else {
                    var event = purchaseContext.event().orElseThrow();
                    var eventFormat = event.getFormat();
                    var matchingCategories = mapPriceContainersByCategoryId(categoriesList, findReverseChargeCategory(reverseChargeInPerson, reverseChargeOnline, eventFormat), currencyCode, vatStatus, discount, event);
                    updateTicketPricesByCategory(reservationId, currencyCode, vatStatus, event, matchingCategories);
                    // update billing data for the reservation, using the original VatStatus from reservation
                    updateBillingData(reservationId, contactAndTicketsForm, purchaseContext, country, trimToNull(vatValidation.getVatNr()), reservation, reservation.getVatStatus());
                }
                vatChecker.logSuccessfulValidation(vatValidation, reservationId, purchaseContext);
            }
        } else if (optionalReservation.isPresent() && contactAndTicketsForm.isItalyEInvoicingSplitPayment()) {
            var reservation = optionalReservation.get();
            var vatStatus = purchaseContext.getVatStatus() == INCLUDED ? INCLUDED_NOT_CHARGED : NOT_INCLUDED_NOT_CHARGED;
            updateBillingData(reservationId, contactAndTicketsForm, purchaseContext, country, trimToNull(contactAndTicketsForm.getVatNr()), reservation, vatStatus);
        }
    } catch (IllegalStateException ise) {
        // vat checker failure
        bindingResult.rejectValue("vatNr", "error.vatVIESDown");
    }
}
Also used : alfio.repository(alfio.repository) NOT_INCLUDED_NOT_CHARGED(alfio.model.PriceContainer.VatStatus.NOT_INCLUDED_NOT_CHARGED) StringUtils.trimToNull(org.apache.commons.lang3.StringUtils.trimToNull) MonetaryUtil.unitToCents(alfio.util.MonetaryUtil.unitToCents) Predicate(java.util.function.Predicate) NamedParameterJdbcTemplate(org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate) MapSqlParameterSource(org.springframework.jdbc.core.namedparam.MapSqlParameterSource) BindingResult(org.springframework.validation.BindingResult) ConfigurationManager(alfio.manager.system.ConfigurationManager) Function(java.util.function.Function) ReservationPriceCalculator(alfio.manager.system.ReservationPriceCalculator) BigDecimal(java.math.BigDecimal) Component(org.springframework.stereotype.Component) List(java.util.List) ContactAndTicketsForm(alfio.controller.form.ContactAndTicketsForm) ValidationUtils(org.springframework.validation.ValidationUtils) Collectors.toMap(java.util.stream.Collectors.toMap) alfio.model(alfio.model) Map(java.util.Map) Optional(java.util.Optional) AllArgsConstructor(lombok.AllArgsConstructor) VatStatus(alfio.model.PriceContainer.VatStatus) ConfigurationKeys(alfio.model.system.ConfigurationKeys) VatStatus(alfio.model.PriceContainer.VatStatus)

Aggregations

ContactAndTicketsForm (alfio.controller.form.ContactAndTicketsForm)1 ConfigurationManager (alfio.manager.system.ConfigurationManager)1 ReservationPriceCalculator (alfio.manager.system.ReservationPriceCalculator)1 alfio.model (alfio.model)1 VatStatus (alfio.model.PriceContainer.VatStatus)1 NOT_INCLUDED_NOT_CHARGED (alfio.model.PriceContainer.VatStatus.NOT_INCLUDED_NOT_CHARGED)1 ConfigurationKeys (alfio.model.system.ConfigurationKeys)1 alfio.repository (alfio.repository)1 MonetaryUtil.unitToCents (alfio.util.MonetaryUtil.unitToCents)1 BigDecimal (java.math.BigDecimal)1 List (java.util.List)1 Map (java.util.Map)1 Optional (java.util.Optional)1 Function (java.util.function.Function)1 Predicate (java.util.function.Predicate)1 Collectors.toMap (java.util.stream.Collectors.toMap)1 AllArgsConstructor (lombok.AllArgsConstructor)1 StringUtils.trimToNull (org.apache.commons.lang3.StringUtils.trimToNull)1 MapSqlParameterSource (org.springframework.jdbc.core.namedparam.MapSqlParameterSource)1 NamedParameterJdbcTemplate (org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate)1