Skip to content

Commit

Permalink
#24 - do not send reminder e-mail for expired events
Browse files Browse the repository at this point in the history
  • Loading branch information
cbellone committed Apr 3, 2015
1 parent 3d2a4ad commit 0ed7b29
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 12 deletions.
24 changes: 14 additions & 10 deletions src/main/java/alfio/manager/TicketReservationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import org.springframework.transaction.support.TransactionTemplate;

import java.math.BigDecimal;
import java.time.Period;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.temporal.ChronoUnit;
Expand Down Expand Up @@ -305,8 +306,8 @@ public void deleteOfflinePayment(Event event, String reservationId) {
String subject = messageSource.getMessage("reservation-email-expired-subject", new Object[]{getShortReservationID(reservationId), event.getShortName()}, reservationLanguage);
cancelReservation(reservationId);
notificationManager.sendSimpleEmail(event, reservation.getEmail(), subject, () -> {
return templateManager.renderClassPathResource("/alfio/templates/offline-reservation-expired-email-txt.ms", emailModel, reservationLanguage, TemplateOutput.TEXT);
});
return templateManager.renderClassPathResource("/alfio/templates/offline-reservation-expired-email-txt.ms", emailModel, reservationLanguage, TemplateOutput.TEXT);
});
}

@Transactional(readOnly = true)
Expand All @@ -330,10 +331,10 @@ public Map<String, Object> prepareModelForReservationEmail(Event event, TicketRe

private void transitionToInPayment(String reservationId, String email, String fullName, String billingAddress) {
requiresNewTransactionTemplate.execute(status -> {
int updatedReservation = ticketReservationRepository.updateTicketReservation(reservationId, IN_PAYMENT.toString(), email, fullName, billingAddress, null, PaymentProxy.STRIPE.toString());
Validate.isTrue(updatedReservation == 1, "expected exactly one updated reservation, got "+updatedReservation);
return null;
});
int updatedReservation = ticketReservationRepository.updateTicketReservation(reservationId, IN_PAYMENT.toString(), email, fullName, billingAddress, null, PaymentProxy.STRIPE.toString());
Validate.isTrue(updatedReservation == 1, "expected exactly one updated reservation, got " + updatedReservation);
return null;
});
}

private void transitionToOfflinePayment(Event event, String reservationId, String email, String fullName, String billingAddress) {
Expand Down Expand Up @@ -717,7 +718,7 @@ public Optional<Triple<Event, TicketReservation, Ticket>> fetchComplete(String e
*/
public Optional<Triple<Event, TicketReservation, Ticket>> fetchCompleteAndAssigned(String eventName, String reservationId, String ticketIdentifier) {
return fetchComplete(eventName, reservationId, ticketIdentifier).flatMap((t) -> {
if(t.getRight().getAssigned()) {
if (t.getRight().getAssigned()) {
return Optional.of(t);
} else {
return Optional.empty();
Expand Down Expand Up @@ -750,14 +751,17 @@ void sendReminderForOfflinePayments() {
model.put("expirationDate", ZonedDateTime.ofInstant(reservation.getValidity().toInstant(), event.getZoneId()));
Locale locale = p.getRight();
ticketReservationRepository.flagAsOfflinePaymentReminderSent(reservation.getId());
notificationManager.sendSimpleEmail(event, reservation.getEmail(), messageSource.getMessage("reservation.reminder.mail.subject", new Object[]{ getShortReservationID(reservation.getId()) }, locale), () -> templateManager.renderClassPathResource("/alfio/templates/reminder-email-txt.ms", model, locale, TemplateOutput.TEXT));
notificationManager.sendSimpleEmail(event, reservation.getEmail(), messageSource.getMessage("reservation.reminder.mail.subject", new Object[]{getShortReservationID(reservation.getId())}, locale), () -> templateManager.renderClassPathResource("/alfio/templates/reminder-email-txt.ms", model, locale, TemplateOutput.TEXT));
});
}

void sendReminderForTicketAssignment() {
int daysBeforeStart = configurationManager.getIntConfigValue(ASSIGNMENT_REMINDER_START, 10);
eventRepository.findAll().stream()
.filter(e -> ZonedDateTime.now(e.getZoneId()).truncatedTo(ChronoUnit.DAYS).plusDays(daysBeforeStart).isAfter(e.getBegin().truncatedTo(ChronoUnit.DAYS)))
eventRepository.findAll().stream()
.filter(e -> {
int days = Period.between(ZonedDateTime.now(e.getZoneId()).toLocalDate(), e.getBegin().toLocalDate()).getDays();
return days > 0 && days <= daysBeforeStart;
})
.map(e -> Pair.of(e, ticketRepository.findAllReservationsConfirmedButNotAssigned(e.getId())))
.filter(p -> !p.getRight().isEmpty())
.forEach(this::sendAssignmentReminder);
Expand Down
91 changes: 89 additions & 2 deletions src/test/java/alfio/manager/TicketReservationManagerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,32 @@

import alfio.controller.form.UpdateTicketOwnerForm;
import alfio.manager.support.PartialTicketTextGenerator;
import alfio.manager.support.TextTemplateGenerator;
import alfio.manager.system.ConfigurationManager;
import alfio.model.Event;
import alfio.model.Ticket;
import alfio.model.TicketReservation;
import alfio.repository.EventRepository;
import alfio.repository.PromoCodeDiscountRepository;
import alfio.repository.TicketRepository;
import alfio.repository.TicketReservationRepository;
import alfio.repository.user.AuthorityRepository;
import alfio.repository.user.OrganizationRepository;
import com.insightfullogic.lambdabehave.JunitSuiteRunner;
import org.junit.runner.RunWith;
import org.springframework.context.MessageSource;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.transaction.PlatformTransactionManager;

import java.util.Arrays;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.Locale;
import java.util.Optional;

import static alfio.model.system.ConfigurationKeys.ASSIGNMENT_REMINDER_START;
import static com.insightfullogic.lambdabehave.Suite.describe;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.*;
Expand Down Expand Up @@ -70,7 +79,7 @@ public class TicketReservationManagerTest {{
TicketReservation reservation = mock(TicketReservation.class);
when(original.getTicketsReservationId()).thenReturn(ticketReservationId);
when(ticketReservationRepository.findReservationById(eq(ticketReservationId))).thenReturn(reservation);
UserDetails userDetails = new User("user", "password", Arrays.asList(new SimpleGrantedAuthority(AuthorityRepository.ROLE_ADMIN)));
UserDetails userDetails = new User("user", "password", Collections.singletonList(new SimpleGrantedAuthority(AuthorityRepository.ROLE_ADMIN)));
trm.updateTicketOwner(original, Locale.ENGLISH, event, form, (a) -> null,(b) -> null, (c) -> null, Optional.of(userDetails));
verify(messageSource, never()).getMessage(eq("ticket-has-changed-owner-subject"), eq(new Object[] {"short-name"}), eq(Locale.ENGLISH));
});
Expand All @@ -83,4 +92,82 @@ public class TicketReservationManagerTest {{
verify(notificationManager, times(1)).sendSimpleEmail(eq(event), eq(originalEmail), anyString(), eq("Hello, world"));
});
});

describe("sendReminderForTicketAssignment", it -> {
ConfigurationManager configurationManager = it.usesMock(ConfigurationManager.class);
TicketRepository ticketRepository = it.usesMock(TicketRepository.class);
EventRepository eventRepository = it.usesMock(EventRepository.class);
TicketReservationRepository ticketReservationRepository = it.usesMock(TicketReservationRepository.class);
TicketReservation reservation = it.usesMock(TicketReservation.class);
PlatformTransactionManager transactionManager = it.usesMock(PlatformTransactionManager.class);
OrganizationRepository organizationRepository = it.usesMock(OrganizationRepository.class);
PromoCodeDiscountRepository promoCodeDiscountRepository = it.usesMock(PromoCodeDiscountRepository.class);
NotificationManager notificationManager = mock(NotificationManager.class);
MessageSource messageSource = it.usesMock(MessageSource.class);
TicketReservationManager trm = new TicketReservationManager(eventRepository, organizationRepository, ticketRepository, ticketReservationRepository, null, configurationManager, null, promoCodeDiscountRepository, null, null, notificationManager, messageSource, null, transactionManager);
it.initializesWith(() -> reset(notificationManager, eventRepository, organizationRepository, ticketRepository, ticketReservationRepository, configurationManager, promoCodeDiscountRepository, messageSource, transactionManager));
it.should("send the reminder before event end", expect -> {
when(configurationManager.getIntConfigValue(eq(ASSIGNMENT_REMINDER_START), anyInt())).thenReturn(10);
when(configurationManager.getStringConfigValue(any())).thenReturn(Optional.empty());
when(reservation.latestNotificationTimestamp(any())).thenReturn(Optional.empty());
when(reservation.getId()).thenReturn("abcd");
when(ticketReservationRepository.findReservationById(eq("abcd"))).thenReturn(reservation);
Event event = it.usesMock(Event.class);
when(eventRepository.findByReservationId("abcd")).thenReturn(event);
when(event.getZoneId()).thenReturn(ZoneId.systemDefault());
when(event.getBegin()).thenReturn(ZonedDateTime.now().plusDays(1));
when(eventRepository.findAll()).thenReturn(Collections.singletonList(event));
when(ticketRepository.findAllReservationsConfirmedButNotAssigned(anyInt())).thenReturn(Collections.singletonList("abcd"));
trm.sendReminderForTicketAssignment();
verify(notificationManager, times(1)).sendSimpleEmail(eq(event), anyString(), anyString(), any(TextTemplateGenerator.class));
});

it.should("not send the reminder after event end", expect -> {
when(configurationManager.getIntConfigValue(eq(ASSIGNMENT_REMINDER_START), anyInt())).thenReturn(10);
when(configurationManager.getStringConfigValue(any())).thenReturn(Optional.empty());
when(reservation.latestNotificationTimestamp(any())).thenReturn(Optional.empty());
when(reservation.getId()).thenReturn("abcd");
when(ticketReservationRepository.findReservationById(eq("abcd"))).thenReturn(reservation);
Event event = it.usesMock(Event.class);
when(eventRepository.findByReservationId("abcd")).thenReturn(event);
when(event.getZoneId()).thenReturn(ZoneId.systemDefault());
when(event.getBegin()).thenReturn(ZonedDateTime.now().minusDays(1));
when(eventRepository.findAll()).thenReturn(Collections.singletonList(event));
when(ticketRepository.findAllReservationsConfirmedButNotAssigned(anyInt())).thenReturn(Collections.singletonList("abcd"));
trm.sendReminderForTicketAssignment();
verify(notificationManager, never()).sendSimpleEmail(eq(event), anyString(), anyString(), any(TextTemplateGenerator.class));
});

it.should("consider ZoneId while checking (valid)", expect -> {
when(configurationManager.getIntConfigValue(eq(ASSIGNMENT_REMINDER_START), anyInt())).thenReturn(10);
when(configurationManager.getStringConfigValue(any())).thenReturn(Optional.empty());
when(reservation.latestNotificationTimestamp(any())).thenReturn(Optional.empty());
when(reservation.getId()).thenReturn("abcd");
when(ticketReservationRepository.findReservationById(eq("abcd"))).thenReturn(reservation);
Event event = it.usesMock(Event.class);
when(eventRepository.findByReservationId("abcd")).thenReturn(event);
when(event.getZoneId()).thenReturn(ZoneId.of("GMT-4"));
when(event.getBegin()).thenReturn(ZonedDateTime.now(ZoneId.of("GMT-4")).plusDays(1));
when(eventRepository.findAll()).thenReturn(Collections.singletonList(event));
when(ticketRepository.findAllReservationsConfirmedButNotAssigned(anyInt())).thenReturn(Collections.singletonList("abcd"));
trm.sendReminderForTicketAssignment();
verify(notificationManager, times(1)).sendSimpleEmail(eq(event), anyString(), anyString(), any(TextTemplateGenerator.class));
});

it.should("consider ZoneId while checking (expired)", expect -> {
when(configurationManager.getIntConfigValue(eq(ASSIGNMENT_REMINDER_START), anyInt())).thenReturn(10);
when(configurationManager.getStringConfigValue(any())).thenReturn(Optional.empty());
when(reservation.latestNotificationTimestamp(any())).thenReturn(Optional.empty());
when(reservation.getId()).thenReturn("abcd");
when(ticketReservationRepository.findReservationById(eq("abcd"))).thenReturn(reservation);
Event event = it.usesMock(Event.class);
when(eventRepository.findByReservationId("abcd")).thenReturn(event);
when(event.getZoneId()).thenReturn(ZoneId.of("UTC-8"));
when(event.getBegin()).thenReturn(ZonedDateTime.now(ZoneId.of("UTC-8")));//same day
when(eventRepository.findAll()).thenReturn(Collections.singletonList(event));
when(ticketRepository.findAllReservationsConfirmedButNotAssigned(anyInt())).thenReturn(Collections.singletonList("abcd"));
trm.sendReminderForTicketAssignment();
verify(notificationManager, never()).sendSimpleEmail(eq(event), anyString(), anyString(), any(TextTemplateGenerator.class));
});
});
}}

0 comments on commit 0ed7b29

Please sign in to comment.