Skip to content

Commit

Permalink
implement #333 checkin date category (#341)
Browse files Browse the repository at this point in the history
* #333 checkin date for ticket category: db changes

* #333 fix mysql

* #333 valid checkin from/to: add property in java model

* #333 valid checkin from/to: mysql fix take2

* #333 valid check-in from/to for ticket category: backend: add insert/update support

* #333 valid check-in from/to for ticket category: admin web ui: add support for set/update valid check in from/to

* #333 check-in: add date check range from ticket category

* #333 add UPDATE_TICKET_CATEGORY event for auditing

* #333 fix query for mysql/pgsql

* #333 add valid check in from/to to offline payload

* #333 fix conditions
  • Loading branch information
syjer committed Sep 22, 2017
1 parent ce04eb8 commit 426c92e
Show file tree
Hide file tree
Showing 40 changed files with 368 additions and 162 deletions.
8 changes: 4 additions & 4 deletions src/main/java/alfio/controller/TicketController.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ public String showTicketForUpdate(@PathVariable("eventName") String eventName,
}
Triple<Event, TicketReservation, Ticket> data = oData.get();
Event event = data.getLeft();
TicketCategory ticketCategory = ticketCategoryRepository.getById(data.getRight().getCategoryId(), event.getId());
TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(data.getRight().getCategoryId(), event.getId());
Organization organization = organizationRepository.getById(event.getOrganizationId());

boolean enableFreeCancellation = configurationManager.getBooleanConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ticketCategory.getId(), ALLOW_FREE_TICKETS_CANCELLATION), false);
Expand Down Expand Up @@ -176,7 +176,7 @@ private Ticket internalSendTicketByEmail(HttpServletRequest request, Triple<Even
Organization organization = organizationRepository.getById(event.getOrganizationId());
notificationManager.sendTicketByEmail(ticket,
event, locale, TemplateProcessor.buildPartialEmail(event, organization, reservation, templateManager, ticketReservationManager.ticketUpdateUrl(event, ticket.getUuid()), request),
reservation, ticketCategoryRepository.getById(ticket.getCategoryId(), event.getId()));
reservation, ticketCategoryRepository.getByIdAndActive(ticket.getCategoryId(), event.getId()));
return ticket;
}

Expand Down Expand Up @@ -234,7 +234,7 @@ public String cancelTicket(@PathVariable("eventName") String eventName,
}

private PartialTicketPDFGenerator preparePdfTicket(HttpServletRequest request, Event event, TicketReservation ticketReservation, Ticket ticket) throws WriterException, IOException {
TicketCategory ticketCategory = ticketCategoryRepository.getById(ticket.getCategoryId(), event.getId());
TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(ticket.getCategoryId(), event.getId());
Organization organization = organizationRepository.getById(event.getOrganizationId());
String reservationID = ticketReservationManager.getShortReservationID(event, ticketReservation.getId());
return TemplateProcessor.buildPartialPDFTicket(LocaleUtil.getTicketLanguage(ticket, request), event, ticketReservation,
Expand All @@ -249,7 +249,7 @@ private String internalShowTicket(String eventName, String ticketIdentifier, boo
Triple<Event, TicketReservation, Ticket> data = oData.get();


TicketCategory ticketCategory = ticketCategoryRepository.getById(data.getRight().getCategoryId(), data.getLeft().getId());
TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(data.getRight().getCategoryId(), data.getLeft().getId());
Organization organization = organizationRepository.getById(data.getLeft().getOrganizationId());
Event event = data.getLeft();

Expand Down
12 changes: 7 additions & 5 deletions src/main/java/alfio/manager/AdminReservationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -332,7 +332,7 @@ private Stream<Pair<TicketCategory, TicketsInfo>> flattenTicketsInfo(Event event
attendees.addAll(ti2.getAttendees());
return new TicketsInfo(ti1.getCategory(), attendees, ti1.isAddSeatsIfNotAvailable() && ti2.isAddSeatsIfNotAvailable(), ti1.isUpdateAttendees() && ti2.isUpdateAttendees());
}).orElse(empty);
return Pair.of(ticketCategoryRepository.getById(entry.getKey(), event.getId()), ticketsInfo);
return Pair.of(ticketCategoryRepository.getByIdAndActive(entry.getKey(), event.getId()), ticketsInfo);
});
}

Expand Down Expand Up @@ -371,11 +371,11 @@ private Result<TicketCategory> createCategory(TicketsInfo ti, Event event, Admin

int tickets = attendees.size();
TicketCategoryModification tcm = new TicketCategoryModification(category.getExistingCategoryId(), category.getName(), tickets,
inception, reservation.getExpiration(), Collections.emptyMap(), category.getPrice(), true, "", true, null);
inception, reservation.getExpiration(), Collections.emptyMap(), category.getPrice(), true, "", true, null, null, null);
int notAllocated = getNotAllocatedTickets(event);
int missingTickets = Math.max(tickets - notAllocated, 0);
Event modified = increaseSeatsIfNeeded(ti, event, missingTickets, event);
return eventManager.insertCategory(modified, tcm, username).map(id -> ticketCategoryRepository.getById(id, event.getId()));
return eventManager.insertCategory(modified, tcm, username).map(id -> ticketCategoryRepository.getByIdAndActive(id, event.getId()));
}

private Event increaseSeatsIfNeeded(TicketsInfo ti, Event event, int missingTickets, Event modified) {
Expand All @@ -398,7 +398,7 @@ private Result<TicketCategory> checkExistingCategory(TicketsInfo ti, Event event
List<Attendee> attendees = ti.getAttendees();
int tickets = attendees.size();
int eventId = event.getId();
TicketCategory existing = ticketCategoryRepository.getById(category.getExistingCategoryId(), eventId);
TicketCategory existing = ticketCategoryRepository.getByIdAndActive(category.getExistingCategoryId(), eventId);
int existingCategoryId = existing.getId();
int freeTicketsInCategory = ticketRepository.countFreeTickets(eventId, existingCategoryId);
int notAllocated = getNotAllocatedTickets(event);
Expand All @@ -408,7 +408,9 @@ private Result<TicketCategory> checkExistingCategory(TicketsInfo ti, Event event
int maxTickets = existing.getMaxTickets() + (tickets - freeTicketsInCategory);
TicketCategoryModification tcm = new TicketCategoryModification(existingCategoryId, existing.getName(), maxTickets,
DateTimeModification.fromZonedDateTime(existing.getInception(modified.getZoneId())), DateTimeModification.fromZonedDateTime(existing.getExpiration(event.getZoneId())),
Collections.emptyMap(), existing.getPrice(), existing.isAccessRestricted(), "", true, existing.getCode());
Collections.emptyMap(), existing.getPrice(), existing.isAccessRestricted(), "", true, existing.getCode(),
DateTimeModification.fromZonedDateTime(existing.getValidCheckInFrom(modified.getZoneId())),
DateTimeModification.fromZonedDateTime(existing.getValidCheckInTo(modified.getZoneId())));
return eventManager.updateCategory(existingCategoryId, modified, tcm, username);
}
return Result.success(existing);
Expand Down
30 changes: 29 additions & 1 deletion src/main/java/alfio/manager/CheckInManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.function.Predicate;
Expand All @@ -69,6 +70,7 @@ public class CheckInManager {
private final EventRepository eventRepository;
private final TicketReservationRepository ticketReservationRepository;
private final TicketFieldRepository ticketFieldRepository;
private final TicketCategoryRepository ticketCategoryRepository;
private final ScanAuditRepository scanAuditRepository;
private final AuditingRepository auditingRepository;
private final ConfigurationManager configurationManager;
Expand Down Expand Up @@ -185,6 +187,19 @@ private TicketAndCheckInResult extractStatus(Optional<Event> maybeEvent, Optiona
Event event = maybeEvent.get();
String code = ticketCode.get();

TicketCategory tc = ticketCategoryRepository.getById(ticket.getCategoryId());

ZonedDateTime now = ZonedDateTime.now(event.getZoneId());
if(!tc.hasValidCheckIn(now, event.getZoneId())) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy - hh:mm");
String from = tc.getValidCheckInFrom() == null ? ".." : formatter.format(tc.getValidCheckInFrom(event.getZoneId()));
String to = tc.getValidCheckInTo() == null ? ".." : formatter.format(tc.getValidCheckInTo(event.getZoneId()));
String formattedNow = formatter.format(now);
return new TicketAndCheckInResult(ticket, new DefaultCheckInResult(INVALID_TICKET_CATEGORY_CHECK_IN_DATE,
String.format("Invalid check-in date: valid range for category %s is from %s to %s, current time is: %s",
tc.getName(), from, to, formattedNow)));
}

log.trace("scanned code is {}", code);
log.trace("true code is {}", ticket.ticketCode(event.getPrivateKey()));

Expand Down Expand Up @@ -283,6 +298,9 @@ public Predicate<Event> isOfflineCheckInAndLabelPrintingEnabled() {
}

public Map<String,String> getEncryptedAttendeesInformation(Event ev, Set<String> additionalFields, List<Integer> ids) {

Map<Integer, TicketCategory> categories = ticketCategoryRepository.findByEventIdAsMap(ev.getId());

return Optional.ofNullable(ev).filter(isOfflineCheckInEnabled()).map(event -> {
String eventKey = event.getPrivateKey();

Expand All @@ -297,10 +315,20 @@ public Map<String,String> getEncryptedAttendeesInformation(Event ev, Set<String>
info.put("status", ticket.getStatus().toString());
info.put("uuid", ticket.getUuid());
info.put("category", ticket.getTicketCategory().getName());
if(!additionalFields.isEmpty()) {
if (!additionalFields.isEmpty()) {
Map<String, String> map = ticketFieldRepository.findValueForTicketId(ticket.getId(), additionalFields).stream().collect(Collectors.toMap(TicketFieldValue::getName, TicketFieldValue::getValue));
info.put("additionalInfoJson", Json.toJson(map));
}

//
TicketCategory tc = categories.get(ticket.getCategoryId());
if (tc.getValidCheckInFrom() != null) {
info.put("validCheckInFrom", Long.toString(tc.getValidCheckInFrom(event.getZoneId()).toEpochSecond()));
}
if (tc.getValidCheckInTo() != null) {
info.put("validCheckInTo", Long.toString(tc.getValidCheckInTo(event.getZoneId()).toEpochSecond()));
}
//
String key = ticket.ticketCode(eventKey);
return encrypt(key, Json.toJson(info));
};
Expand Down
36 changes: 22 additions & 14 deletions src/main/java/alfio/manager/EventManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,8 @@
import alfio.model.PromoCodeDiscount.DiscountType;
import alfio.model.Ticket.TicketStatus;
import alfio.model.TicketFieldConfiguration.Context;
import alfio.model.modification.EventModification;
import alfio.model.modification.*;
import alfio.model.modification.EventModification.AdditionalField;
import alfio.model.modification.PromoCodeDiscountWithFormattedTime;
import alfio.model.modification.TicketCategoryModification;
import alfio.model.modification.TicketFieldDescriptionModification;
import alfio.model.result.ErrorCode;
import alfio.model.result.Result;
import alfio.model.system.Configuration;
Expand Down Expand Up @@ -102,6 +99,7 @@ public class EventManager {
private final Flyway flyway;
private final Environment environment;
private final OrganizationRepository organizationRepository;
private final AuditingRepository auditingRepository;


public Event getSingleEvent(String eventName, String username) {
Expand Down Expand Up @@ -367,7 +365,7 @@ public Result<TicketCategory> updateCategory(int categoryId, Event event, Ticket
return categories.stream().filter(tc -> tc.getId() == categoryId).findFirst()
.map(existing -> new Result.Builder<>(() -> {
updateCategory(tcm, event.isFreeOfCharge(), event.getZoneId(), event);
return ticketCategoryRepository.getById(categoryId, eventId);
return ticketCategoryRepository.getByIdAndActive(categoryId, eventId);
})
.addValidation(() -> tcm.getExpiration().toZonedDateTime(event.getZoneId()).isBefore(event.getEnd()), ErrorCode.CategoryError.EXPIRATION_AFTER_EVENT_END)
.addValidation(() -> tcm.getMaxTickets() - existing.getMaxTickets() + ticketRepository.countAllocatedTicketsForEvent(eventId) <= eventRepository.countExistingTickets(eventId), ErrorCode.CategoryError.NOT_ENOUGH_SEATS)
Expand Down Expand Up @@ -405,7 +403,7 @@ private void fixTicketCategoryDates(ZonedDateTime end, TicketCategory tc, ZonedD

public void reallocateTickets(int srcCategoryId, int targetCategoryId, int eventId) {
Event event = eventRepository.findById(eventId);
reallocateTickets(ticketCategoryRepository.findStatisticWithId(srcCategoryId, eventId), Optional.of(ticketCategoryRepository.getById(targetCategoryId, event.getId())), event);
reallocateTickets(ticketCategoryRepository.findStatisticWithId(srcCategoryId, eventId), Optional.of(ticketCategoryRepository.getByIdAndActive(targetCategoryId, event.getId())), event);
}

void reallocateTickets(TicketCategoryStatisticView src, Optional<TicketCategory> target, Event event) {
Expand Down Expand Up @@ -493,12 +491,13 @@ private void createCategoriesForEvent(EventModification em, Event event) {
final int price = evaluatePrice(tc.getPriceInCents(), freeOfCharge);
final int maxTickets = tc.isBounded() ? tc.getMaxTickets() : 0;
final AffectedRowCountAndKey<Integer> category = ticketCategoryRepository.insert(tc.getInception().toZonedDateTime(zoneId),
tc.getExpiration().toZonedDateTime(zoneId), tc.getName(), maxTickets, tc.isTokenGenerationRequested(), eventId, tc.isBounded(), price, StringUtils.trimToNull(tc.getCode()));
tc.getExpiration().toZonedDateTime(zoneId), tc.getName(), maxTickets, tc.isTokenGenerationRequested(), eventId, tc.isBounded(), price, StringUtils.trimToNull(tc.getCode()),
DateTimeModification.toZonedDateTime(tc.getValidCheckInFrom(), zoneId), DateTimeModification.toZonedDateTime(tc.getValidCheckInTo(), zoneId));

insertOrUpdateTicketCategoryDescription(category.getKey(), tc, event);

if (tc.isTokenGenerationRequested()) {
final TicketCategory ticketCategory = ticketCategoryRepository.getById(category.getKey(), event.getId());
final TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(category.getKey(), event.getId());
final MapSqlParameterSource[] args = prepareTokenBulkInsertParameters(ticketCategory, ticketCategory.getMaxTickets());
jdbc.batchUpdate(specialPriceRepository.bulkInsert(), args);
}
Expand All @@ -510,8 +509,10 @@ private Integer insertCategory(TicketCategoryModification tc, Event event) {
int eventId = event.getId();
final int price = evaluatePrice(tc.getPriceInCents(), event.isFreeOfCharge());
final AffectedRowCountAndKey<Integer> category = ticketCategoryRepository.insert(tc.getInception().toZonedDateTime(zoneId),
tc.getExpiration().toZonedDateTime(zoneId), tc.getName(), tc.isBounded() ? tc.getMaxTickets() : 0, tc.isTokenGenerationRequested(), eventId, tc.isBounded(), price, StringUtils.trimToNull(tc.getCode()));
TicketCategory ticketCategory = ticketCategoryRepository.getById(category.getKey(), eventId);
tc.getExpiration().toZonedDateTime(zoneId), tc.getName(), tc.isBounded() ? tc.getMaxTickets() : 0, tc.isTokenGenerationRequested(), eventId, tc.isBounded(), price, StringUtils.trimToNull(tc.getCode()),
DateTimeModification.toZonedDateTime(tc.getValidCheckInFrom(), zoneId),
DateTimeModification.toZonedDateTime(tc.getValidCheckInTo(), zoneId));
TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(category.getKey(), eventId);
if(tc.isBounded()) {
List<Integer> lockedTickets = ticketRepository.selectNotAllocatedTicketsForUpdate(eventId, ticketCategory.getMaxTickets(), asList(TicketStatus.FREE.name(), TicketStatus.RELEASED.name()));
jdbc.batchUpdate(ticketRepository.bulkTicketUpdate(), lockedTickets.stream().map(id -> new MapSqlParameterSource("id", id).addValue("categoryId", ticketCategory.getId()).addValue("srcPriceCts", ticketCategory.getSrcPriceCts())).toArray(MapSqlParameterSource[]::new));
Expand Down Expand Up @@ -551,10 +552,12 @@ private void insertOrUpdateTicketCategoryDescription(int tcId, TicketCategoryMod
private void updateCategory(TicketCategoryModification tc, boolean freeOfCharge, ZoneId zoneId, Event event) {
int eventId = event.getId();
final int price = evaluatePrice(tc.getPriceInCents(), freeOfCharge);
TicketCategory original = ticketCategoryRepository.getById(tc.getId(), eventId);
TicketCategory original = ticketCategoryRepository.getByIdAndActive(tc.getId(), eventId);
ticketCategoryRepository.update(tc.getId(), tc.getName(), tc.getInception().toZonedDateTime(zoneId),
tc.getExpiration().toZonedDateTime(zoneId), tc.getMaxTickets(), tc.isTokenGenerationRequested(), price, StringUtils.trimToNull(tc.getCode()));
TicketCategory updated = ticketCategoryRepository.getById(tc.getId(), eventId);
tc.getExpiration().toZonedDateTime(zoneId), tc.getMaxTickets(), tc.isTokenGenerationRequested(), price, StringUtils.trimToNull(tc.getCode()),
DateTimeModification.toZonedDateTime(tc.getValidCheckInFrom(), zoneId),
DateTimeModification.toZonedDateTime(tc.getValidCheckInTo(), (zoneId)));
TicketCategory updated = ticketCategoryRepository.getByIdAndActive(tc.getId(), eventId);
int addedTickets = 0;
if(original.isBounded() ^ tc.isBounded()) {
handleTicketAllocationStrategyChange(event, original, tc);
Expand All @@ -566,6 +569,11 @@ private void updateCategory(TicketCategoryModification tc, boolean freeOfCharge,
handlePriceChange(event, original, updated);

insertOrUpdateTicketCategoryDescription(tc.getId(), tc, event);

//

auditingRepository.insertUpdateTicketInCategoryId(tc.getId());

}

private void handleTicketAllocationStrategyChange(Event event, TicketCategory original, TicketCategoryModification updated) {
Expand Down Expand Up @@ -687,7 +695,7 @@ private String collectPaymentProxies(EventModification em) {
}

public TicketCategory getTicketCategoryById(int id, int eventId) {
return ticketCategoryRepository.getById(id, eventId);
return ticketCategoryRepository.getByIdAndActive(id, eventId);
}

public AdditionalService getAdditionalServiceById(int id, int eventId) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ void generatePendingCodesForCategory(int categoryId) {

private void generateCode(SpecialPrice specialPrice) {

TicketCategory ticketCategory = ticketCategoryRepository.getById(specialPrice.getTicketCategoryId()).orElseThrow(IllegalStateException::new);
TicketCategory ticketCategory = ticketCategoryRepository.getByIdAndActive(specialPrice.getTicketCategoryId()).orElseThrow(IllegalStateException::new);
Event event = eventRepository.findById(ticketCategory.getEventId());
int maxLength = configurationManager.getIntConfigValue(Configuration.from(event.getOrganizationId(), event.getId(), ticketCategory.getId(), ConfigurationKeys.SPECIAL_PRICE_CODE_LENGTH), 6);

Expand Down

0 comments on commit 426c92e

Please sign in to comment.