Initial commit

This commit is contained in:
user
2026-07-12 14:34:52 +04:00
commit 3abf6bd9c2
557 changed files with 68706 additions and 0 deletions
+219
View File
@@ -0,0 +1,219 @@
#include "ticket_generator.h"
#include "create_ticket_request.h"
#include "hall_dto.h"
#include "halls_repository.h"
#include "repository_manager.h"
#include "repository_result.h"
#include "schema_metadata.h"
#include "session_dto.h"
#include "sessions_repository.h"
#include "tickets_repository.h"
#include <QDebug>
#include <QStack>
#include <numeric>
#include "repository_result.h"
std::random_device TicketGenerator::rd_;
std::mt19937 TicketGenerator::generator_(rd_());
TicketGenerator::TicketGenerator(
const QPair<qint32, qint32> &dayRange, const QPair<QTime, QTime> &timeRange,
const QPair<double, double> &fillRatioPerSessionRange)
: BaseGenerator("Ticket"), DateTimeGenerator(dayRange, timeRange) {
if (!setFillRatioPerSessionRange(fillRatioPerSessionRange)) {
qFatal() << "Failed to set fill ratio per session range";
}
initializeRepositories();
initializeSessionIdToAvailableSeatMap(); // After initializing repositories
initializeSessionIdToBeginAtMap(); // After initializing repositories
initializeRemainingCapacity(); // After initializing sessionToAvailableSeats
qInfo() << "Number of sessions:" << sessionIdToAvailableSeatNumbers_.size();
}
void TicketGenerator::initializeRepositories() {
RepositoryManager &repositoryManager = RepositoryManager::instance();
SchemaMetadata metadata = SchemaMetadata::defaultSchema();
hallsRepository_ = repositoryManager.getRepositoryAs<HallsRepository>(
metadata.repositoryTableName("halls"));
sessionsRepository_ = repositoryManager.getRepositoryAs<SessionsRepository>(
metadata.repositoryTableName("sessions"));
ticketsRepository_ = repositoryManager.getRepositoryAs<TicketsRepository>(
metadata.repositoryTableName("tickets"));
if (!bool(ticketsRepository_ && sessionsRepository_)) {
qFatal() << "Failed to initialize repositories";
}
}
void TicketGenerator::initializeSessionIdToAvailableSeatMap() {
QVector<HallDTO> halls;
RepositoryResult resultGetAllHalls = hallsRepository_->getAllHalls(halls);
if (!resultGetAllHalls.success) {
qFatal() << "Failed to retrieve halls";
}
QVector<SessionDTO> sessions;
RepositoryResult resultGetAllSessions =
sessionsRepository_->getAllSessions(sessions);
if (!resultGetAllSessions.success) {
qFatal() << "Failed to retrieve sessions";
}
QMap<qint32 /* sessionId */, QSet<qint32> /* availableSeatNumbers */>
hallIdToAvailableSeatNumbers;
for (const HallDTO &hall : halls) {
qint32 targetCapacity =
std::ceil(hall.capacity() * generateFillRatioPerSession());
QVector<qint32> availableSeats(targetCapacity);
std::iota(availableSeats.begin(), availableSeats.end(), 1);
std::shuffle(availableSeats.begin(), availableSeats.end(), generator_);
QSet<qint32> buffer;
for (qint32 i = 0; i < targetCapacity; ++i) {
buffer.insert(availableSeats[i]);
}
hallIdToAvailableSeatNumbers[hall.hallId()] = std::move(buffer);
}
for (const SessionDTO &session : sessions) {
sessionIdToAvailableSeatNumbers_[session.sessionId()] =
hallIdToAvailableSeatNumbers[session.hallId()];
}
}
void TicketGenerator::initializeSessionIdToBeginAtMap() {
QVector<SessionDTO> sessions;
RepositoryResult resultGetAllSessions =
sessionsRepository_->getAllSessions(sessions);
if (!resultGetAllSessions.success) {
qFatal() << "Failed to retrieve sessions";
}
for (const SessionDTO &session : sessions) {
sessionIdToBeginAt_[session.sessionId()] = session.beginAt();
}
}
bool TicketGenerator::setFillRatioPerSessionRange(
const QPair<double, double> &range) {
const auto &[minValue, maxValue] = range;
if (minValue > maxValue) {
return false;
}
auto &[minFillRatioPerSession, maxFillRatioPerSession] =
fillRatioPerSessionRange_;
minFillRatioPerSession = std::max(minValue, 0.0);
maxFillRatioPerSession = std::min(maxValue, 1.0);
return true;
}
double TicketGenerator::generateFillRatioPerSession() const {
const auto &[min, max] = fillRatioPerSessionRange_;
std::uniform_real_distribution<double> distribution(min, max);
return distribution(generator_);
}
void TicketGenerator::initializeRemainingCapacity() {
remainingCapacity_ =
std::accumulate(sessionIdToAvailableSeatNumbers_.cbegin(),
sessionIdToAvailableSeatNumbers_.cend(), 0,
[&](qsizetype sum, const QSet<qint32> &availableSeats) {
return sum + availableSeats.size();
});
}
QString
TicketGenerator::createFailureMessage(const QString &errorMessage) const {
QString additionalInfo =
QString("Additional info: Session id: %1 Seat number: %2 Sold at: %3 "
"Begin at: %4")
.arg(reservationContext_.sessionId)
.arg(reservationContext_.seatNumber)
.arg(reservationContext_.soldAt.toString("yyyy-MM-dd hh:mm:ss"))
.arg(reservationContext_.beginAt.toString("yyyy-MM-dd hh:mm:ss"));
QString failureMessage = "Failure:\n\t%1\n\tError message: %2";
return failureMessage.arg(additionalInfo).arg(errorMessage);
}
QString TicketGenerator::createSuccessMessage() const {
return QString("Success: EId: %1 SN: %2")
.arg(reservationContext_.sessionId)
.arg(reservationContext_.seatNumber);
}
qsizetype TicketGenerator::calculateRemainingCapacity() const {
return remainingCapacity_;
}
RepositoryResult TicketGenerator::createRecord() {
CreateTicketRequest request;
request.setSessionId(reservationContext_.sessionId);
request.setSeatNumber(reservationContext_.seatNumber);
request.setSoldAt(reservationContext_.soldAt);
RepositoryResult result = ticketsRepository_->createTicket(request);
if (result.success) {
--remainingCapacity_;
}
return result;
}
bool TicketGenerator::prepareData() {
if (remainingCapacity_ <= 0) {
qInfo() << "All tickets have been sold";
return false;
}
qsizetype deltaIndex =
bounded<qsizetype>(0, sessionIdToAvailableSeatNumbers_.size());
auto it = sessionIdToAvailableSeatNumbers_.begin();
std::advance(it, deltaIndex);
const qint32 sessionId = it.key();
QSet<qint32> &availableSeatNumbers = it.value(); // Not empty
const QDateTime &beginAt = sessionIdToBeginAt_[sessionId];
constexpr qint32 minus20MinutesMs = -20 * 1000 * 60;
// soldAt < beginAt || soldAt + 20 minute <= beginAt
QDateTime soldAt = generate(beginAt.addMSecs(minus20MinutesMs));
qsizetype seatNumberIndex =
bounded<qsizetype>(0, availableSeatNumbers.size());
auto seatNumberIt = availableSeatNumbers.cbegin();
std::advance(seatNumberIt, seatNumberIndex);
qint32 seatNumber = *seatNumberIt;
ReservationContext context{beginAt, soldAt, seatNumber, sessionId};
reservationContext_ = std::move(context);
return true;
}
void TicketGenerator::clearStaleData() {
qint32 sessionId = reservationContext_.sessionId;
qint32 seatNumber = reservationContext_.seatNumber;
QSet<qint32> &availableSeatNumbers =
sessionIdToAvailableSeatNumbers_[sessionId];
availableSeatNumbers.remove(seatNumber);
if (availableSeatNumbers.empty()) {
qWarning() << "All tickets for session with id" << sessionId
<< "have been sold";
sessionIdToAvailableSeatNumbers_.remove(sessionId);
sessionIdToBeginAt_.remove(sessionId);
}
}