#include "refund_generator.h" #include "create_refund_request.h" #include "refunds_repository.h" #include "repository_manager.h" #include "repository_result.h" #include "schema_metadata.h" #include "session_dto.h" #include "sessions_repository.h" #include "ticket_dto.h" #include "tickets_repository.h" #include RefundGenerator::RefundGenerator(const QPair &refundRatioRange, const QPair &dayRange, const QPair &timeRange) : BaseGenerator("Refund"), DateTimeGenerator(dayRange, timeRange), refundRatioRange_(refundRatioRange) { auto &[lowest, highest] = refundRatioRange_; if (lowest > highest) { qCritical() << "Lowest refund ratio is greater than the highest refund, " "values will be swapped"; std::swap(lowest, highest); } initializeRepositories(); // First initializeTicketIdToCacheValueMap(); // After initializing // repositories initializeRemainingCapacity(); // After initializing ticketIdToCacheValue } void RefundGenerator::initializeRepositories() { RepositoryManager &repositoryManager = RepositoryManager::instance(); SchemaMetadata metadata = SchemaMetadata::defaultSchema(); ticketsRepository_ = repositoryManager.getRepositoryAs( metadata.repositoryTableName("tickets")); refundsRepository_ = repositoryManager.getRepositoryAs( metadata.repositoryTableName("refunds")); sessionsRepository_ = repositoryManager.getRepositoryAs( metadata.repositoryTableName("sessions")); if (!bool(ticketsRepository_ && refundsRepository_ && sessionsRepository_)) { qFatal() << "Failed to initialize repositories"; } } void RefundGenerator::initializeTicketIdToCacheValueMap() { QVector sessions; RepositoryResult resultGetAllSessions = sessionsRepository_->getAllSessions(sessions); if (!resultGetAllSessions.success) { qFatal() << "Failed to retrieve sessions"; } QMap> sessionIdToBeginAtAndTicketPrice; for (const SessionDTO &session : sessions) { sessionIdToBeginAtAndTicketPrice[session.sessionId()] = qMakePair(session.beginAt(), session.ticketPrice()); } QVector tickets; RepositoryResult resultGetAllTickets = ticketsRepository_->getAllTickets(tickets); if (!resultGetAllTickets.success) { qFatal() << "Failed to retrieve tickets"; } for (const auto &ticket : tickets) { const auto &[beginAt, ticketPrice] = sessionIdToBeginAtAndTicketPrice[ticket.sessionId()]; CacheValue cacheValue{beginAt, ticket.soldAt(), ticketPrice}; if (calculateDurationMs(cacheValue) < 2) { continue; } ticketIdToCacheValue_[ticket.ticketId()] = cacheValue; } } QString RefundGenerator::createFailureMessage(const QString &errorMessage) const { const QString dateTimeFormat = "yyyy-MM-dd hh:mm:ss.zzz"; QString additionalInfo = QString("Additional info: Ticket id: %1 Refund amount: %2 Sold at: %3 " "Refund at: %4 Begin at: %5") .arg(reservationContext_.ticketId) .arg(reservationContext_.refundAmount) .arg(reservationContext_.soldAt.toString(dateTimeFormat)) .arg(reservationContext_.refundAt.toString(dateTimeFormat)) .arg(reservationContext_.beginAt.toString(dateTimeFormat)); QString failureMessage = "Failure:\n\t%1\n\tError message: %2"; return failureMessage.arg(additionalInfo).arg(errorMessage); } QString RefundGenerator::createSuccessMessage() const { return QString("Success: EId: %1 RAm: %2 RAt: %3") .arg(reservationContext_.ticketId) .arg(reservationContext_.refundAmount) .arg(reservationContext_.refundAt.toString("yyyy-MM-dd hh:mm:ss")); } qsizetype RefundGenerator::calculateRemainingCapacity() const { return remainingCapacity_; } RepositoryResult RefundGenerator::createRecord() { CreateRefundRequest request; request.setRefundAmount(reservationContext_.refundAmount); request.setRefundAt(reservationContext_.refundAt); request.setTicketId(reservationContext_.ticketId); RepositoryResult result = refundsRepository_->createRefund(request); if (result.success) { --remainingCapacity_; } return result; } bool RefundGenerator::prepareData() { if (ticketIdToCacheValue_.isEmpty()) { qInfo() << "No tickets to refund"; return false; } qsizetype ticketIdIndex = bounded(0, ticketIdToCacheValue_.size()); auto ticketIdIt = ticketIdToCacheValue_.cbegin(); std::advance(ticketIdIt, ticketIdIndex); qint32 ticketId = ticketIdIt.key(); CacheValue cacheValue = ticketIdIt.value(); constexpr qint32 fiveMinutesMs = 5 * 1000 * 60; qint64 deltaBoundMs = calculateDurationMs(cacheValue) / 2; if (deltaBoundMs > fiveMinutesMs) { deltaBoundMs = fiveMinutesMs; } const QDateTime refundAt = // SoldAt < RefundAt < BeginAt // SoldAt + n minute <= RefundAt <= BeginAt - n minute generate(cacheValue.soldAt.addMSecs(+deltaBoundMs), cacheValue.beginAt.addMSecs(-deltaBoundMs)); const auto [refundRatioLowest, refundRatioHighest] = refundRatioRange_; int lowest = refundRatioLowest * 100; int highest = refundRatioHighest * 100; int numerator = bounded(lowest, highest); double refundAmount = std::floor(numerator * cacheValue.ticketPrice) / 100.0; ReservationContext context{cacheValue.beginAt, refundAt, cacheValue.soldAt, refundAmount, ticketId}; reservationContext_ = std::move(context); return true; } void RefundGenerator::clearStaleData() { qint32 ticketId = reservationContext_.ticketId; ticketIdToCacheValue_.remove(ticketId); }