/**
* 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.repository;
import alfio.model.FullTicketInfo;
import alfio.model.Ticket;
import alfio.model.TicketCSVInfo;
import ch.digitalfondue.npjt.*;
import java.util.List;
import java.util.Optional;
import java.util.Set;
@QueryRepository
public interface TicketRepository {
String CONFIRMED = "'ACQUIRED', 'CHECKED_IN', 'TO_BE_PAID'";
String FREE = "FREE";
String RELEASED = "RELEASED";
@Query(type = QueryType.TEMPLATE, value = "insert into ticket (uuid, creation, category_id, event_id, status, original_price_cts, paid_price_cts, src_price_cts)"
+ "values(:uuid, :creation, :categoryId, :eventId, :status, 0, 0, :srcPriceCts)")
String bulkTicketInitialization();
@Query(type = QueryType.TEMPLATE, value = "update ticket set category_id = :categoryId, src_price_cts = :srcPriceCts where id = :id")
String bulkTicketUpdate();
@Query("select id from ticket where status in (:requiredStatuses) and category_id = :categoryId and event_id = :eventId and tickets_reservation_id is null order by id limit :amount for update")
List<Integer> selectTicketInCategoryForUpdate(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId, @Bind("amount") int amount, @Bind("requiredStatuses") List<String> requiredStatus);
@Query("select id from ticket where status in(:requiredStatuses) and category_id is null and event_id = :eventId and tickets_reservation_id is null order by id limit :amount for update")
List<Integer> selectNotAllocatedTicketsForUpdate(@Bind("eventId") int eventId, @Bind("amount") int amount, @Bind("requiredStatuses") List<String> requiredStatuses);
@Query("select id from ticket where status = 'FREE' and category_id = :categoryId and event_id = :eventId and tickets_reservation_id is null order by id desc limit :amount for update")
List<Integer> lockTicketsToInvalidate(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId, @Bind("amount") int amount);
@Query("select count(*) from ticket where status in ("+CONFIRMED+") and category_id = :categoryId and event_id = :eventId and full_name is not null and email_address is not null")
Integer countAssignedTickets(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId);
@Query("select * from ticket where status in ('PENDING', 'ACQUIRED', 'TO_BE_PAID', 'CANCELLED', 'CHECKED_IN') and category_id = :categoryId and event_id = :eventId")
List<Ticket> findAllModifiedTickets(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId);
@Query("select count(*) from ticket where status in ("+CONFIRMED+", 'PENDING') and category_id = :categoryId and event_id = :eventId")
Integer countConfirmedAndPendingTickets(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId);
@Query("select count(*) from ticket where status in ("+CONFIRMED+") and category_id = :categoryId and event_id = :eventId")
Integer countConfirmedForCategory(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId);
@Query("select count(*) from ticket where status in ('PENDING', 'RELEASED') and category_id = :categoryId and event_id = :eventId")
Integer countPendingOrReleasedForCategory(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId);
@Query("select count(*) from ticket where status = 'FREE' and category_id = :categoryId and event_id = :eventId")
Integer countFreeTickets(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId);
@Query("select count(*) from ticket where status = 'FREE' and category_id is null and event_id = :eventId")
Integer countFreeTicketsForUnbounded(@Bind("eventId") int eventId);
@Query("select count(*) from ticket where status = 'RELEASED' and category_id is null and event_id = :eventId")
Integer countReleasedTickets(@Bind("eventId") int eventId);
@Query("update ticket set tickets_reservation_id = :reservationId, status = 'PENDING', category_id = :categoryId, user_language = :userLanguage, src_price_cts = :srcPriceCts where id in (:reservedForUpdate)")
int reserveTickets(@Bind("reservationId") String reservationId, @Bind("reservedForUpdate") List<Integer> reservedForUpdate, @Bind("categoryId") int categoryId, @Bind("userLanguage") String userLanguage, @Bind("srcPriceCts") int srcPriceCts);
@Query("update ticket set tickets_reservation_id = :reservationId, special_price_id_fk = :specialCodeId, user_language = :userLanguage, status = 'PENDING', src_price_cts = :srcPriceCts where id = :ticketId")
void reserveTicket(@Bind("reservationId")String transactionId, @Bind("ticketId") int ticketId, @Bind("specialCodeId") int specialCodeId, @Bind("userLanguage") String userLanguage, @Bind("srcPriceCts") int srcPriceCts);
@Query("update ticket set status = :status where tickets_reservation_id = :reservationId")
int updateTicketsStatusWithReservationId(@Bind("reservationId") String reservationId, @Bind("status") String status);
@Query("update ticket set status = :status where uuid = :uuid")
int updateTicketStatusWithUUID(@Bind("uuid") String uuid, @Bind("status") String status);
@Query("update ticket set status = 'INVALIDATED' where id in (:ids)")
int invalidateTickets(@Bind("ids") List<Integer> ids);
@Query("update ticket set src_price_cts = :srcPriceCts, final_price_cts = :finalPriceCts, vat_cts = :vatCts, discount_cts = :discountCts where event_id = :eventId and category_id = :categoryId")
int updateTicketPrice(@Bind("categoryId") int categoryId, @Bind("eventId") int eventId, @Bind("srcPriceCts") int srcPriceCts, @Bind("finalPriceCts") int finalPriceCts, @Bind("vatCts") int vatCts, @Bind("discountCts") int discountCts);
@Query("update ticket set src_price_cts = :srcPriceCts, final_price_cts = :finalPriceCts, vat_cts = :vatCts, discount_cts = :discountCts where event_id = :eventId and category_id = :categoryId and id in(:ids)")
int updateTicketPrice(@Bind("ids") List<Integer> ids, @Bind("categoryId") int categoryId, @Bind("eventId") int eventId, @Bind("srcPriceCts") int srcPriceCts, @Bind("finalPriceCts") int finalPriceCts, @Bind("vatCts") int vatCts, @Bind("discountCts") int discountCts);
@Query("update ticket set status = 'RELEASED', tickets_reservation_id = null, special_price_id_fk = null, first_name = null, last_name = null, full_name = null, email_address = null where status in ('PENDING', 'OFFLINE_PAYMENT') "
+ " and tickets_reservation_id in (:reservationIds)")
int freeFromReservation(@Bind("reservationIds") List<String> reservationIds);
@Query("update ticket set category_id = null where tickets_reservation_id in (:reservationIds) and status in ('PENDING', 'OFFLINE_PAYMENT') and category_id in (select tc.id from ticket_category tc, ticket t where t.tickets_reservation_id in (:reservationIds) and t.category_id = tc.id and tc.bounded = false)")
@QueriesOverride({
@QueryOverride(db = "MYSQL", value = "update ticket set category_id = null where tickets_reservation_id in (:reservationIds) and status in ('PENDING', 'OFFLINE_PAYMENT') and category_id in (select * from (select tc.id from ticket_category tc, ticket t where t.tickets_reservation_id in (:reservationIds) and t.category_id = tc.id and tc.bounded = false) as sq)")
})
int resetCategoryIdForUnboundedCategories(@Bind("reservationIds") List<String> reservationIds);
@Query("update ticket set category_id = null where id in (:ticketIds) and category_id in (select tc.id from ticket_category tc, ticket t where t.id in (:ticketIds) and t.category_id = tc.id and tc.bounded = false)")
@QueriesOverride({
@QueryOverride(db = "MYSQL", value = "update ticket set category_id = null where id in (:ticketIds) and category_id in (select * from (select tc.id from ticket_category tc, ticket t where t.id in (:ticketIds) and t.category_id = tc.id and tc.bounded = false) as sq)")
})
int resetCategoryIdForUnboundedCategoriesWithTicketIds(@Bind("ticketIds") List<Integer> ticketIds);
@Query("update ticket set category_id = null where event_id = :eventId and category_id = :categoryId and id in (:ticketIds)")
int unbindTicketsFromCategory(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId, @Bind("ticketIds") List<Integer> ids);
@Query("select * from ticket where tickets_reservation_id = :reservationId order by category_id asc, uuid asc")
List<Ticket> findTicketsInReservation(@Bind("reservationId") String reservationId);
@Query("select * from ticket where tickets_reservation_id = :reservationId order by category_id asc, uuid asc LIMIT 1 OFFSET 0")
Optional<Ticket> findFirstTicketInReservation(@Bind("reservationId") String reservationId);
@Query("select count(*) from ticket where tickets_reservation_id = :reservationId ")
Integer countTicketsInReservation(@Bind("reservationId") String reservationId);
@Query("select * from ticket where uuid = :uuid")
Ticket findByUUID(@Bind("uuid") String uuid);
@Query("select * from ticket where uuid = :uuid")
Optional<Ticket> findOptionalByUUID(@Bind("uuid") String uuid);
@Query("select * from ticket where uuid = :uuid for update")
Optional<Ticket> findByUUIDForUpdate(@Bind("uuid") String uuid);
@Query("update ticket set email_address = :email, full_name = :fullName, first_name = :firstName, last_name = :lastName where uuid = :ticketIdentifier")
int updateTicketOwner(@Bind("ticketIdentifier") String ticketIdentifier, @Bind("email") String email, @Bind("fullName") String fullName, @Bind("firstName") String firstName, @Bind("lastName") String lastName);
@Query("update ticket set email_address = :email, full_name = :fullName, first_name = :firstName, last_name = :lastName where id = :id")
int updateTicketOwnerById(@Bind("id") int id, @Bind("email") String email, @Bind("fullName") String fullName, @Bind("firstName") String firstName, @Bind("lastName") String lastName);
@Query("update ticket set locked_assignment = :lockedAssignment where id = :id and category_id = :categoryId")
int toggleTicketLocking(@Bind("id") int ticketId, @Bind("categoryId") int categoryId, @Bind("lockedAssignment") boolean locked);
@Query("update ticket set user_language = :userLanguage where uuid = :ticketIdentifier")
int updateOptionalTicketInfo(@Bind("ticketIdentifier") String ticketIdentifier, @Bind("userLanguage") String userLanguage);
@Query("select * from ticket where id = :id and category_id = :categoryId")
Ticket findById(@Bind("id") int ticketId, @Bind("categoryId") int categoryId);
@Query("select * from ticket where id in (:ids)")
List<Ticket> findByIds(@Bind("ids") List<Integer> ticketIds);
@Query("select * from ticket where special_price_id_fk = :specialPriceId")
Ticket findBySpecialPriceId(@Bind("specialPriceId") int specialPriceId);
@Query("update ticket set category_id = :targetCategoryId, src_price_cts = :srcPriceCts where id in (:ticketIds)")
int moveToAnotherCategory(@Bind("ticketIds") List<Integer> ticketIds, @Bind("targetCategoryId") int targetCategoryId, @Bind("srcPriceCts") int srcPriceCts);
@Query("select * from ticket where category_id in (:categories) and status = 'PENDING'")
List<Ticket> findPendingTicketsInCategories(@Bind("categories") List<Integer> categories);
@Query("select " +
" t.id t_id, t.uuid t_uuid, t.creation t_creation, t.category_id t_category_id, t.status t_status, t.event_id t_event_id," +
" t.src_price_cts t_src_price_cts, t.final_price_cts t_final_price_cts, t.vat_cts t_vat_cts, t.discount_cts t_discount_cts, t.tickets_reservation_id t_tickets_reservation_id," +
" t.full_name t_full_name, t.first_name t_first_name, t.last_name t_last_name, t.email_address t_email_address, t.locked_assignment t_locked_assignment," +
" t.user_language t_user_language," +
" tr.id tr_id, tr.validity tr_validity, tr.status tr_status, tr.full_name tr_full_name, tr.first_name tr_first_name, tr.last_name tr_last_name, tr.email_address tr_email_address, tr.billing_address tr_billing_address," +
" tr.confirmation_ts tr_confirmation_ts, tr.latest_reminder_ts tr_latest_reminder_ts, tr.payment_method tr_payment_method, " +
" tr.offline_payment_reminder_sent tr_offline_payment_reminder_sent, tr.promo_code_id_fk tr_promo_code_id_fk, tr.automatic tr_automatic, tr.user_language tr_user_language, tr.direct_assignment tr_direct_assignment, tr.invoice_number tr_invoice_number, tr.invoice_model tr_invoice_model, " +
" tc.id tc_id, tc.inception tc_inception, tc.expiration tc_expiration, tc.max_tickets tc_max_tickets, tc.name tc_name, tc.src_price_cts tc_src_price_cts, tc.access_restricted tc_access_restricted, tc.tc_status tc_tc_status, tc.event_id tc_event_id, tc.bounded tc_bounded" +
" from ticket t " +
" inner join tickets_reservation tr on t.tickets_reservation_id = tr.id " +
" inner join ticket_category tc on t.category_id = tc.id " +
" where t.event_id = :eventId and t.full_name is not null and t.email_address is not null")
List<FullTicketInfo> findAllFullTicketInfoAssignedByEventId(@Bind("eventId") int eventId);
@Query("select " +
" t.id t_id, t.uuid t_uuid, t.creation t_creation, t.category_id t_category_id, t.status t_status, t.event_id t_event_id," +
" t.src_price_cts t_src_price_cts, t.final_price_cts t_final_price_cts, t.vat_cts t_vat_cts, t.discount_cts t_discount_cts, t.tickets_reservation_id t_tickets_reservation_id," +
" t.full_name t_full_name, t.first_name t_first_name, t.last_name t_last_name, t.email_address t_email_address, t.locked_assignment t_locked_assignment," +
" t.user_language t_user_language," +
" tr.id tr_id, tr.validity tr_validity, tr.status tr_status, tr.full_name tr_full_name, tr.first_name tr_first_name, tr.last_name tr_last_name, tr.email_address tr_email_address, tr.billing_address tr_billing_address," +
" tr.confirmation_ts tr_confirmation_ts, tr.latest_reminder_ts tr_latest_reminder_ts, tr.payment_method tr_payment_method, tr.offline_payment_reminder_sent tr_offline_payment_reminder_sent, tr.promo_code_id_fk tr_promo_code_id_fk, tr.automatic tr_automatic, tr.user_language tr_user_language, tr.direct_assignment tr_direct_assignment, " +
" tr.invoice_number tr_invoice_number, tr.invoice_model tr_invoice_model from ticket t, tickets_reservation tr where t.event_id = :eventId and t.status in(" + CONFIRMED + ") and t.tickets_reservation_id = tr.id order by tr.confirmation_ts")
List<TicketCSVInfo> findAllConfirmedForCSV(@Bind("eventId") int eventId);
@Query("select a.*, b.confirmation_ts from ticket a, tickets_reservation b where a.event_id = :eventId and a.status in(" + CONFIRMED + ") and a.tickets_reservation_id = b.id order by b.confirmation_ts")
List<Ticket> findAllConfirmed(@Bind("eventId") int eventId);
@Query("select * from ticket where event_id = :eventId and status in(" + CONFIRMED + ") and category_id = :categoryId")
List<Ticket> findConfirmedByCategoryId(@Bind("eventId") int eventId, @Bind("categoryId") int categoryId);
@Query("select count(*) from ticket where event_id = :eventId and status in(" + CONFIRMED + ") and full_name is not null and email_address is not null")
Integer countAllAssigned(@Bind("eventId") int eventId);
@Query("select distinct tickets_reservation_id from ticket where event_id = :eventId and status in('ACQUIRED', 'TO_BE_PAID') and (full_name is null or email_address is null)")
List<String> findAllReservationsConfirmedButNotAssigned(@Bind("eventId") int eventId);
@Query("select * from ticket where event_id = :eventId and status in('ACQUIRED', 'TO_BE_PAID') and full_name is not null and email_address is not null and reminder_sent = false")
List<Ticket> findAllAssignedButNotYetNotified(@Bind("eventId") int eventId);
@Query("update ticket set reminder_sent = true where id = :id and reminder_sent = false")
int flagTicketAsReminderSent(@Bind("id") int ticketId);
String RESET_TICKET = " TICKETS_RESERVATION_ID = null, FULL_NAME = null, EMAIL_ADDRESS = null, SPECIAL_PRICE_ID_FK = null, LOCKED_ASSIGNMENT = false, USER_LANGUAGE = null, REMINDER_SENT = false, SRC_PRICE_CTS = 0, FINAL_PRICE_CTS = 0, VAT_CTS = 0, DISCOUNT_CTS = 0, FIRST_NAME = null, LAST_NAME = null ";
@Query("update ticket set status = 'RELEASED', " + RESET_TICKET + " where id = :ticketId and status = 'ACQUIRED' and tickets_reservation_id = :reservationId and event_id = :eventId")
int releaseTicket(@Bind("reservationId") String reservationId, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId);
@Query("update ticket set status = 'RELEASED', " + RESET_TICKET + " where id = :ticketId and status = 'PENDING' and tickets_reservation_id = :reservationId and event_id = :eventId")
int releaseExpiredTicket(@Bind("reservationId") String reservationId, @Bind("eventId") int eventId, @Bind("ticketId") int ticketId);
@Query("update ticket set status = 'FREE', " + RESET_TICKET + " where id in (:ticketIds)")
int resetTickets(@Bind("ticketIds") List<Integer> ticketIds);
@Query("select count(*) from ticket where status = 'RELEASED' and event_id = :eventId")
Integer countWaiting(@Bind("eventId") int eventId);
@Query("update ticket set status = 'FREE' where status = 'RELEASED' and event_id = :eventId")
int revertToFree(@Bind("eventId") int eventId);
@Query("select * from ticket where status = :status and event_id = :eventId order by id limit :amount for update")
List<Ticket> selectWaitingTicketsForUpdate(@Bind("eventId") int eventId, @Bind("status") String status, @Bind("amount") int amount);
@Query("select id from ticket where status = 'FREE' and event_id = :eventId and category_id = :categoryId order by id limit :amount for update")
List<Integer> selectFreeTicketsForPreReservation(@Bind("eventId") int eventId, @Bind("amount") int amount, @Bind("categoryId") int categoryId);
@Query("select id from ticket where status = 'FREE' and event_id = :eventId and category_id is null order by id limit :amount for update")
List<Integer> selectNotAllocatedFreeTicketsForPreReservation(@Bind("eventId") int eventId, @Bind("amount") int amount);
@Query("select count(*) from ticket where status = 'PRE_RESERVED'")
Integer countPreReservedTickets(@Bind("eventId") int eventId);
@Query(type = QueryType.TEMPLATE, value = "update ticket set status = 'PRE_RESERVED' where id = :id")
String preReserveTicket();
@Query("select * from ticket where status = 'FREE' and event_id = :eventId")
List<Ticket> findFreeByEventId(@Bind("eventId") int eventId);
@Query("select count(*) from ticket where event_id = :eventId and status <> 'INVALIDATED'")
Integer countExistingTicketsForEvent(@Bind("eventId") int eventId);
@Query("select count(*) from ticket where tickets_reservation_id = :reservationId and uuid in (:uuids)")
Integer countFoundTicketsInReservation(@Bind("reservationId") String reservationId, @Bind("uuids") Set<String> uuids);
default boolean checkTicketUUIDs(String reservationId, Set<String> uuids) {
return countFoundTicketsInReservation(reservationId, uuids) == uuids.size();
}
}