alfio.manager.TicketReservationManagerIntegrationTest.java Source code

Java tutorial

Introduction

Here is the source code for alfio.manager.TicketReservationManagerIntegrationTest.java

Source

/**
 * This file is part of alf.io.
 *
 * alf.io is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * alf.io is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with alf.io.  If not, see <http://www.gnu.org/licenses/>.
 */
package alfio.manager;

import alfio.TestConfiguration;
import alfio.config.DataSourceConfiguration;
import alfio.config.Initializer;
import alfio.config.RepositoryConfiguration;
import alfio.manager.support.PaymentResult;
import alfio.manager.user.UserManager;
import alfio.model.*;
import alfio.model.modification.DateTimeModification;
import alfio.model.modification.TicketCategoryModification;
import alfio.model.modification.TicketReservationModification;
import alfio.model.modification.TicketReservationWithOptionalCodeModification;
import alfio.model.transaction.PaymentProxy;
import alfio.repository.EventRepository;
import alfio.repository.TicketCategoryRepository;
import alfio.repository.TicketRepository;
import alfio.repository.TicketReservationRepository;
import alfio.repository.system.ConfigurationRepository;
import alfio.repository.user.OrganizationRepository;
import alfio.test.util.IntegrationTestUtil;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;

import static alfio.test.util.IntegrationTestUtil.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { RepositoryConfiguration.class, DataSourceConfiguration.class,
        TestConfiguration.class })
@ActiveProfiles({ Initializer.PROFILE_DEV, Initializer.PROFILE_DISABLE_JOBS })
@Transactional
public class TicketReservationManagerIntegrationTest {

    private static final Map<String, String> DESCRIPTION = Collections.singletonMap("en", "desc");

    @BeforeClass
    public static void initEnv() {
        initSystemProperties();
    }

    @Autowired
    private EventManager eventManager;

    @Autowired
    private OrganizationRepository organizationRepository;
    @Autowired
    private UserManager userManager;
    @Autowired
    private TicketRepository ticketRepository;
    @Autowired
    private TicketCategoryRepository ticketCategoryRepository;
    @Autowired
    private TicketReservationManager ticketReservationManager;
    @Autowired
    private TicketReservationRepository ticketReservationRepository;
    @Autowired
    private EventStatisticsManager eventStatisticsManager;

    @Autowired
    private ConfigurationRepository configurationRepository;
    @Autowired
    private WaitingQueueManager waitingQueueManager;
    @Autowired
    private EventRepository eventRepository;

    @Before
    public void ensureConfiguration() {
        IntegrationTestUtil.ensureMinimalConfiguration(configurationRepository);
    }

    @Test
    public void testPriceIsOverridden() {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        Event event = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository)
                .getKey();

        TicketReservationModification tr = new TicketReservationModification();
        tr.setAmount(2);
        TicketCategory category = ticketCategoryRepository.findByEventId(event.getId()).get(0);
        tr.setTicketCategoryId(category.getId());
        TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr,
                Optional.empty());
        ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod),
                Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(),
                Locale.ENGLISH, false);
        List<Ticket> pendingTickets = ticketRepository
                .findPendingTicketsInCategories(Collections.singletonList(category.getId()));
        assertEquals(2, pendingTickets.size());
        pendingTickets.forEach(t -> assertEquals(1000, t.getFinalPriceCts()));
        List<Ticket> tickets = ticketRepository.findFreeByEventId(event.getId());
        assertEquals(18, tickets.size());
        assertTrue(tickets.stream().allMatch(t -> t.getCategoryId() == null));
    }

    @Test
    public void testTicketSelection() {
        List<TicketCategoryModification> categories = Arrays.asList(
                new TicketCategoryModification(null, "default", AVAILABLE_SEATS,
                        new DateTimeModification(LocalDate.now(), LocalTime.now()),
                        new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN,
                        false, "", false, null, null, null, null, null),
                new TicketCategoryModification(null, "default", 10,
                        new DateTimeModification(LocalDate.now(), LocalTime.now()),
                        new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN,
                        false, "", true, null, null, null, null, null));
        Pair<Event, String> eventAndUsername = initEvent(categories, organizationRepository, userManager,
                eventManager, eventRepository);
        Event event = eventAndUsername.getKey();

        TicketCategory bounded = ticketCategoryRepository.findByEventId(event.getId()).stream()
                .filter(TicketCategory::isBounded).findFirst().orElseThrow(IllegalStateException::new);
        TicketCategory unbounded = ticketCategoryRepository.findByEventId(event.getId()).stream()
                .filter(t -> !t.isBounded()).findFirst().orElseThrow(IllegalStateException::new);

        assertEquals(0, eventStatisticsManager.loadModifiedTickets(event.getId(), bounded.getId(), 0, null).size());
        assertEquals(Integer.valueOf(0),
                eventStatisticsManager.countModifiedTicket(event.getId(), bounded.getId(), null));
        assertEquals(0,
                eventStatisticsManager.loadModifiedTickets(event.getId(), unbounded.getId(), 0, null).size());

        TicketReservationModification tr = new TicketReservationModification();
        tr.setAmount(10);
        tr.setTicketCategoryId(bounded.getId());

        TicketReservationModification tr2 = new TicketReservationModification();
        tr2.setAmount(9);
        tr2.setTicketCategoryId(unbounded.getId());

        TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr,
                Optional.empty());
        TicketReservationWithOptionalCodeModification mod2 = new TicketReservationWithOptionalCodeModification(tr2,
                Optional.empty());
        String reservationId = ticketReservationManager.createTicketReservation(event, Arrays.asList(mod, mod2),
                Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(),
                Locale.ENGLISH, false);

        List<TicketReservation> reservations = ticketReservationManager
                .findAllReservationsInEvent(event.getId(), 0, null, null).getKey();
        assertTrue(reservations.size() == 1);
        assertEquals(reservationId, reservations.get(0).getId());

        List<Ticket> pendingTickets = ticketRepository
                .findPendingTicketsInCategories(Arrays.asList(bounded.getId(), unbounded.getId()));
        assertEquals(19, pendingTickets.size());
        pendingTickets.forEach(t -> assertEquals(1000, t.getFinalPriceCts()));
        List<Ticket> tickets = ticketRepository.findFreeByEventId(event.getId());
        assertEquals(1, tickets.size());
        assertTrue(tickets.stream().allMatch(t -> t.getCategoryId() == null));

        TotalPrice totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId);

        assertEquals(0, ticketReservationManager.getPendingPayments(event).size());

        PaymentResult confirm = ticketReservationManager.confirm(null, null, event, reservationId,
                "email@example.com", new CustomerName("full name", "full", "name", event), Locale.ENGLISH,
                "billing address", totalPrice, Optional.empty(), Optional.of(PaymentProxy.OFFLINE), false, null,
                null, null);

        assertTrue(confirm.isSuccessful());

        assertEquals(TicketReservation.TicketReservationStatus.OFFLINE_PAYMENT,
                ticketReservationManager.findById(reservationId).get().getStatus());

        assertEquals(1, ticketReservationManager.getPendingPayments(event).size());

        Date now = new Date();
        Date from = DateUtils.addDays(now, -1);
        Date to = DateUtils.addDays(now, 1);

        assertTrue(ticketReservationRepository.getSoldStatistic(event.getId(), from, to).isEmpty()); // -> no reservations
        ticketReservationManager.validateAndConfirmOfflinePayment(reservationId, event, new BigDecimal("190.00"),
                eventAndUsername.getValue());

        assertEquals(19,
                ticketReservationRepository.getSoldStatistic(event.getId(), from, to).get(0).getTicketSoldCount()); // -> 19 tickets reserved

        assertEquals(10,
                eventStatisticsManager.loadModifiedTickets(event.getId(), bounded.getId(), 0, null).size());
        assertEquals(Integer.valueOf(10),
                eventStatisticsManager.countModifiedTicket(event.getId(), bounded.getId(), null));
        assertEquals(9,
                eventStatisticsManager.loadModifiedTickets(event.getId(), unbounded.getId(), 0, null).size());
        assertEquals(Integer.valueOf(9),
                eventStatisticsManager.countModifiedTicket(event.getId(), unbounded.getId(), null));

        assertEquals(TicketReservation.TicketReservationStatus.COMPLETE,
                ticketReservationManager.findById(reservationId).get().getStatus());

        //-------------------

        TicketReservationModification trForDelete = new TicketReservationModification();
        trForDelete.setAmount(1);
        trForDelete.setTicketCategoryId(unbounded.getId());
        TicketReservationWithOptionalCodeModification modForDelete = new TicketReservationWithOptionalCodeModification(
                trForDelete, Optional.empty());
        String reservationId2 = ticketReservationManager.createTicketReservation(event,
                Collections.singletonList(modForDelete), Collections.emptyList(), DateUtils.addDays(new Date(), 1),
                Optional.empty(), Optional.empty(), Locale.ENGLISH, false);

        ticketReservationManager.confirm(null, null, event, reservationId2, "email@example.com",
                new CustomerName("full name", "full", "name", event), Locale.ENGLISH, "billing address", totalPrice,
                Optional.empty(), Optional.of(PaymentProxy.OFFLINE), false, null, null, null);

        assertTrue(ticketReservationManager.findById(reservationId2).isPresent());

        ticketReservationManager.deleteOfflinePayment(event, reservationId2, false);

        Assert.assertFalse(ticketReservationManager.findById(reservationId2).isPresent());
    }

    @Test
    public void testTicketWithDiscount() {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        Event event = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository)
                .getKey();

        TicketCategory unbounded = ticketCategoryRepository.findByEventId(event.getId()).stream()
                .filter(t -> !t.isBounded()).findFirst().orElseThrow(IllegalStateException::new);

        //promo code at event level
        eventManager.addPromoCode("MYPROMOCODE", event.getId(), null, event.getBegin(), event.getEnd(), 10,
                PromoCodeDiscount.DiscountType.PERCENTAGE, null);

        //promo code at organization level
        eventManager.addPromoCode("MYFIXEDPROMO", null, event.getOrganizationId(), event.getBegin(), event.getEnd(),
                5, PromoCodeDiscount.DiscountType.FIXED_AMOUNT, null);

        TicketReservationModification tr = new TicketReservationModification();
        tr.setAmount(3);
        tr.setTicketCategoryId(unbounded.getId());
        TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr,
                Optional.empty());

        String reservationId = ticketReservationManager.createTicketReservation(event,
                Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1),
                Optional.empty(), Optional.of("MYPROMOCODE"), Locale.ENGLISH, false);

        TotalPrice totalPrice = ticketReservationManager.totalReservationCostWithVAT(reservationId);

        // 3 * 10 chf is the normal price, 10% discount -> 300 discount
        Assert.assertEquals(2700, totalPrice.getPriceWithVAT());
        Assert.assertEquals(27, totalPrice.getVAT());
        Assert.assertEquals(-300, totalPrice.getDiscount());
        Assert.assertEquals(1, totalPrice.getDiscountAppliedCount());

        OrderSummary orderSummary = ticketReservationManager.orderSummaryForReservationId(reservationId, event,
                Locale.ENGLISH);
        Assert.assertEquals("27.00", orderSummary.getTotalPrice());
        Assert.assertEquals("0.27", orderSummary.getTotalVAT());
        Assert.assertEquals(3, orderSummary.getTicketAmount());

        TicketReservationModification trFixed = new TicketReservationModification();
        trFixed.setAmount(3);
        trFixed.setTicketCategoryId(unbounded.getId());
        TicketReservationWithOptionalCodeModification modFixed = new TicketReservationWithOptionalCodeModification(
                trFixed, Optional.empty());

        String reservationIdFixed = ticketReservationManager.createTicketReservation(event,
                Collections.singletonList(modFixed), Collections.emptyList(), DateUtils.addDays(new Date(), 1),
                Optional.empty(), Optional.of("MYFIXEDPROMO"), Locale.ENGLISH, false);

        TotalPrice totalPriceFixed = ticketReservationManager.totalReservationCostWithVAT(reservationIdFixed);

        // 3 * 10 chf is the normal price, 3 * 5 is the discount
        Assert.assertEquals(2985, totalPriceFixed.getPriceWithVAT());
        Assert.assertEquals(30, totalPriceFixed.getVAT());
        Assert.assertEquals(-15, totalPriceFixed.getDiscount());
        Assert.assertEquals(3, totalPriceFixed.getDiscountAppliedCount());

        OrderSummary orderSummaryFixed = ticketReservationManager.orderSummaryForReservationId(reservationIdFixed,
                event, Locale.ENGLISH);
        Assert.assertEquals("29.85", orderSummaryFixed.getTotalPrice());
        Assert.assertEquals("0.30", orderSummaryFixed.getTotalVAT());
        Assert.assertEquals(3, orderSummaryFixed.getTicketAmount());

    }

    @Test(expected = TicketReservationManager.NotEnoughTicketsException.class)
    public void testTicketSelectionNotEnoughTicketsAvailable() {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        Event event = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository)
                .getKey();

        TicketCategory unbounded = ticketCategoryRepository.findByEventId(event.getId()).stream()
                .filter(t -> !t.isBounded()).findFirst().orElseThrow(IllegalStateException::new);

        TicketReservationModification tr = new TicketReservationModification();
        tr.setAmount(AVAILABLE_SEATS + 1);
        tr.setTicketCategoryId(unbounded.getId());
        TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr,
                Optional.empty());

        ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod),
                Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(),
                Locale.ENGLISH, false);
    }

    @Test
    public void testDeletePendingPaymentUnboundedCategory() {
        List<TicketCategoryModification> categories = Collections.singletonList(new TicketCategoryModification(null,
                "default", AVAILABLE_SEATS, new DateTimeModification(LocalDate.now(), LocalTime.now()),
                new DateTimeModification(LocalDate.now(), LocalTime.now()), DESCRIPTION, BigDecimal.TEN, false, "",
                false, null, null, null, null, null));
        Event event = initEvent(categories, organizationRepository, userManager, eventManager, eventRepository)
                .getKey();

        TicketCategory unbounded = ticketCategoryRepository.findByEventId(event.getId()).get(0);

        TicketReservationModification tr = new TicketReservationModification();
        tr.setAmount(AVAILABLE_SEATS / 2 + 1);
        tr.setTicketCategoryId(unbounded.getId());

        TicketReservationWithOptionalCodeModification mod = new TicketReservationWithOptionalCodeModification(tr,
                Optional.empty());
        String reservationId = ticketReservationManager.createTicketReservation(event,
                Collections.singletonList(mod), Collections.emptyList(), DateUtils.addDays(new Date(), 1),
                Optional.empty(), Optional.empty(), Locale.ENGLISH, false);
        TotalPrice reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId);
        PaymentResult result = ticketReservationManager.confirm("", null, event, reservationId, "test@test.ch",
                new CustomerName("full name", "full", "name", event), Locale.ENGLISH, "", reservationCost,
                Optional.empty(), Optional.of(PaymentProxy.OFFLINE), false, null, null, null);
        assertTrue(result.isSuccessful());
        ticketReservationManager.deleteOfflinePayment(event, reservationId, false);
        waitingQueueManager.distributeSeats(event);

        mod = new TicketReservationWithOptionalCodeModification(tr, Optional.empty());
        reservationId = ticketReservationManager.createTicketReservation(event, Collections.singletonList(mod),
                Collections.emptyList(), DateUtils.addDays(new Date(), 1), Optional.empty(), Optional.empty(),
                Locale.ENGLISH, false);
        reservationCost = ticketReservationManager.totalReservationCostWithVAT(reservationId);
        result = ticketReservationManager.confirm("", null, event, reservationId, "test@test.ch",
                new CustomerName("full name", "full", "name", event), Locale.ENGLISH, "", reservationCost,
                Optional.empty(), Optional.of(PaymentProxy.OFFLINE), false, null, null, null);
        assertTrue(result.isSuccessful());
    }
}