7957 lines
840 KiB
HTML
7957 lines
840 KiB
HTML
|
|
<HTML><HEAD><TITLE>
|
||
|
|
source file
|
||
|
|
</TITLE>
|
||
|
|
</HEAD>
|
||
|
|
<BODY>
|
||
|
|
<TT>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/controllers/application_connector.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 1"> 1 </A>#include "application_connector.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "model_manager.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include <QObject><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 8"> 8 </A>ApplicationConnector::ApplicationConnector( QObject *rootObject )<BR>
|
||
|
|
: modelManager_( ModelManager::instance( ) ), <BR>
|
||
|
|
repositoryManager_( RepositoryManager::instance( ) ), <BR>
|
||
|
|
rootObject_( rootObject ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 13"> 13 </A>bool ApplicationConnector::connect( ) {<BR>
|
||
|
|
if ( !connectSelfReferenceTableLinks( ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connectTablePairLinks( ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connectUpdateDeleteRFLinks( ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connectDeleteRFLinks( ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector::RMLinkList<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 34"> 34 </A>ApplicationConnector::initializeSelfReferenceTableLinks( ) {<BR>
|
||
|
|
return {linkRepositoryToModel( "genres", "genres" ), <BR>
|
||
|
|
linkRepositoryToModel( "halls", "halls" ), <BR>
|
||
|
|
linkRepositoryToModel( "movies", "movies" ), <BR>
|
||
|
|
linkRepositoryToModel( "sessions", "sessions" ), <BR>
|
||
|
|
linkRepositoryToModel( "refunds", "refunds" ), <BR>
|
||
|
|
linkRepositoryToModel( "tickets", "tickets" )};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector::RMLinkList<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 44"> 44 </A>ApplicationConnector::initializeTablePairLinks( ) {<BR>
|
||
|
|
return {linkRepositoryToModel( "genres", "movies" ), <BR>
|
||
|
|
linkRepositoryToModel( "genres", "sessions" ), <BR>
|
||
|
|
linkRepositoryToModel( "genres", "tickets" ), <BR>
|
||
|
|
linkRepositoryToModel( "genres", "refunds" ), <BR>
|
||
|
|
linkRepositoryToModel( "halls", "sessions" ), <BR>
|
||
|
|
linkRepositoryToModel( "halls", "tickets" ), <BR>
|
||
|
|
linkRepositoryToModel( "halls", "refunds" ), <BR>
|
||
|
|
linkRepositoryToModel( "movies", "sessions" ), <BR>
|
||
|
|
linkRepositoryToModel( "movies", "tickets" ), <BR>
|
||
|
|
linkRepositoryToModel( "movies", "refunds" ), <BR>
|
||
|
|
linkRepositoryToModel( "sessions", "refunds" ), <BR>
|
||
|
|
linkRepositoryToModel( "tickets", "refunds" )};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector::RFLinkList<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 60"> 60 </A>ApplicationConnector::flattenLinkList( const QVector<RFLinkList> &linkLists ) {<BR>
|
||
|
|
RFLinkList result;<BR>
|
||
|
|
for ( const RFLinkList &currentList : linkLists ) {<BR>
|
||
|
|
std::move( currentList.cbegin( ), currentList.cend( ), <BR>
|
||
|
|
std::back_inserter( result ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector::RFLinkList<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 70"> 70 </A>ApplicationConnector::initializeUpdateDeleteCandidates( ) {<BR>
|
||
|
|
const QVector<RFLinkList> updateDeleteCandidates = {<BR>
|
||
|
|
linkRepositoryToFinder( "genres", "genreFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "genres", "movieFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "genres", "sessionFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "genres", "ticketFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "genres", "entityFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "halls", "hallFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "halls", "movieFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "halls", "sessionFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "halls", "ticketFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "halls", "entityFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "movies", "movieFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "movies", "sessionFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "movies", "ticketFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "movies", "entityFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "sessions", "sessionFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "sessions", "ticketFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "sessions", "entityFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "tickets", "ticketFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "tickets", "entityFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "refunds", "entityFinder" )};<BR>
|
||
|
|
<BR>
|
||
|
|
return flattenLinkList( updateDeleteCandidates );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector::RFLinkList<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 97"> 97 </A>ApplicationConnector::initializeDeleteCandidates( ) {<BR>
|
||
|
|
// foreignKeyFinder will reset to default on signal primaryKeyFinder<BR>
|
||
|
|
<BR>
|
||
|
|
const QVector<RFLinkList> deleteCandidates = {<BR>
|
||
|
|
linkRepositoryToFinder( "genres", "primaryKeyFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "halls", "primaryKeyFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "movies", "primaryKeyFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "sessions", "primaryKeyFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "tickets", "primaryKeyFinder" ), <BR>
|
||
|
|
linkRepositoryToFinder( "refunds", "primaryKeyFinder" )};<BR>
|
||
|
|
<BR>
|
||
|
|
return flattenLinkList( deleteCandidates );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 111"> 111 </A>bool ApplicationConnector::connectSelfReferenceTableLinks( ) {<BR>
|
||
|
|
const QList<RMLink> selfReferenceTableLinks =<BR>
|
||
|
|
initializeSelfReferenceTableLinks( );<BR>
|
||
|
|
qInfo( ) << "Connecting self-reference tables...";<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connect( selfReferenceTableLinks, singleTableConnections( ) ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to connect self-reference tables";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 123"> 123 </A>bool ApplicationConnector::connectTablePairLinks( ) {<BR>
|
||
|
|
const RMLinkList tablePairLinks = initializeTablePairLinks( );<BR>
|
||
|
|
qInfo( ) << "Connecting pair tables...";<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connect( tablePairLinks, pairTableConnections( ) ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to connect pair tables";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 134"> 134 </A>bool ApplicationConnector::connectUpdateDeleteRFLinks( ) {<BR>
|
||
|
|
const RFLinkList repositoryToFinderLinks = initializeUpdateDeleteCandidates( );<BR>
|
||
|
|
qInfo( ) << "Connecting repository to finder...";<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connect( repositoryToFinderLinks, repositoryToFinderConnections( ) ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to connect repository to finder";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 145"> 145 </A>bool ApplicationConnector::connectDeleteRFLinks( ) {<BR>
|
||
|
|
const RFLinkList repositoryToFinderLinks = initializeDeleteCandidates( );<BR>
|
||
|
|
qInfo( ) << "Connecting repository to finder...";<BR>
|
||
|
|
<BR>
|
||
|
|
using Signal = void ( Repository::* )( );<BR>
|
||
|
|
using Slot = void ( Finder::* )( );<BR>
|
||
|
|
RFConnectionList connections;<BR>
|
||
|
|
connections.append( Connection<Signal, Slot>( &Repository::dataDeleted, <BR>
|
||
|
|
&Finder::resetToDefault ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connect( repositoryToFinderLinks, connections ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to connect repository to finder";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector::RMConnectionList<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 163"> 163 </A>ApplicationConnector::pairTableConnections( ) {<BR>
|
||
|
|
using Signal = void ( Repository::* )( );<BR>
|
||
|
|
using Slot = bool ( Model::* )( );<BR>
|
||
|
|
<BR>
|
||
|
|
RMConnectionList result;<BR>
|
||
|
|
std::initializer_list<Connection<Signal, Slot>> initList = {<BR>
|
||
|
|
{&Repository::dataUpdated, &Model::refreshAll}, <BR>
|
||
|
|
{&Repository::dataDeleted, &Model::refreshAll}};<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &connection : initList ) {<BR>
|
||
|
|
result.append( connection );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector::RMConnectionList<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 180"> 180 </A>ApplicationConnector::singleTableConnections( ) {<BR>
|
||
|
|
using Signal = void ( Repository::* )( );<BR>
|
||
|
|
using Slot = bool ( Model::* )( );<BR>
|
||
|
|
<BR>
|
||
|
|
RMConnectionList result;<BR>
|
||
|
|
std::initializer_list<Connection<Signal, Slot>> initList = {<BR>
|
||
|
|
{&Repository::dataCreated, &Model::refreshAll}, <BR>
|
||
|
|
{&Repository::dataUpdated, &Model::refreshAll}, <BR>
|
||
|
|
{&Repository::dataDeleted, &Model::refreshAll}};<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &connection : initList ) {<BR>
|
||
|
|
result.append( connection );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 197"> 197 </A>ApplicationConnector::RMLink ApplicationConnector::linkRepositoryToModel( <BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 198"> 198 </A> const QString &senderDatabaseTableName, <BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 199"> 199 </A> const QString &receiverDatabaseTableName ) {<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
Repository *sender = repositoryManager_.getRepositoryAs<Repository>( <BR>
|
||
|
|
metadata.repositoryTableName( senderDatabaseTableName ) );<BR>
|
||
|
|
if ( !sender ) {<BR>
|
||
|
|
qWarning( ) << "Sender with type" << typeid( sender ).name( ) << "is null";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
Model *receiver = modelManager_.getModelAs<Model>( <BR>
|
||
|
|
metadata.modelTableName( receiverDatabaseTableName ) );<BR>
|
||
|
|
if ( !receiver ) {<BR>
|
||
|
|
qWarning( ) << "Receiver with type" << typeid( receiver ).name( ) << "is null";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !sender || !receiver ) {<BR>
|
||
|
|
return qMakePair( nullptr, nullptr );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return qMakePair( sender, receiver );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 221"> 221 </A>ApplicationConnector::RFLinkList ApplicationConnector::linkRepositoryToFinder( <BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 222"> 222 </A> const QString &senderDatabaseTableName, <BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 223"> 223 </A> const QString &receiverEntityFinderName ) {<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
Repository *sender = repositoryManager_.getRepositoryAs<Repository>( <BR>
|
||
|
|
metadata.repositoryTableName( senderDatabaseTableName ) );<BR>
|
||
|
|
if ( !sender ) {<BR>
|
||
|
|
qWarning( ) << "Sender with type" << typeid( sender ).name( ) << "is null";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QList<Finder *> receiver =<BR>
|
||
|
|
rootObject_->findChildren<Finder *>( receiverEntityFinderName );<BR>
|
||
|
|
if ( receiver.isEmpty( ) ) {<BR>
|
||
|
|
qWarning( ) << "Receivers with type" << typeid( receiver ).name( )<BR>
|
||
|
|
<< "there is not";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !sender || receiver.isEmpty( ) ) {<BR>
|
||
|
|
return QList<RFLink>( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RFLinkList result;<BR>
|
||
|
|
for ( Finder *currentReceiver : receiver ) {<BR>
|
||
|
|
result.append( qMakePair( sender, currentReceiver ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector::RFConnectionList<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 252"> 252 </A>ApplicationConnector::repositoryToFinderConnections( ) {<BR>
|
||
|
|
using Signal = void ( Repository::* )( );<BR>
|
||
|
|
using Slot = void ( Finder::* )( );<BR>
|
||
|
|
<BR>
|
||
|
|
RFConnectionList result;<BR>
|
||
|
|
std::initializer_list<Connection<Signal, Slot>> initList = {<BR>
|
||
|
|
{&Repository::dataDeleted, &Finder::resetToDefault}, <BR>
|
||
|
|
{&Repository::dataUpdated, &Finder::resetToDefault}};<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &connection : initList ) {<BR>
|
||
|
|
result.append( connection );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 268"> 268 </A>QString ApplicationConnector::getAddress( const QObject *object ) {<BR>
|
||
|
|
quintptr address = reinterpret_cast<quintptr>( object );<BR>
|
||
|
|
return object ? QString::number( address, 16 ) : "null";<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 273"> 273 </A>QString ApplicationConnector::getMetaClassName( const QMetaObject *meta ) {<BR>
|
||
|
|
return meta ? meta->className( ) : "Unknown";<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 277"> 277 </A>QString ApplicationConnector::getMethodSignature( const QMetaObject *meta, <BR>
|
||
|
|
const char *methodType, <BR>
|
||
|
|
<A NAME="./core/controllers/application_connector.cpp: 279"> 279 </A> bool isSignal ) {<BR>
|
||
|
|
if ( !meta ) {<BR>
|
||
|
|
return "Unknown";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QByteArray normalizedSignature = QMetaObject::normalizedSignature( methodType );<BR>
|
||
|
|
int methodIndex = isSignal ? meta->indexOfSignal( normalizedSignature )<BR>
|
||
|
|
: meta->indexOfSlot( normalizedSignature );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( methodIndex < 0 ) {<BR>
|
||
|
|
return normalizedSignature;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString result = meta->method( methodIndex ).methodSignature( );<BR>
|
||
|
|
return result;<BR>
|
||
|
|
};<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/controllers/application_controller.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 1"> 1 </A>#include "application_controller.h"<BR>
|
||
|
|
#include "config.h"<BR>
|
||
|
|
#include "database_manager.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// Translations<BR>
|
||
|
|
#include <QCoreApplication><BR>
|
||
|
|
#include <QLocale><BR>
|
||
|
|
#include <QTranslator><BR>
|
||
|
|
<BR>
|
||
|
|
// Generation of records<BR>
|
||
|
|
#include "refund_generator.h"<BR>
|
||
|
|
#include "session_generator.h"<BR>
|
||
|
|
#include "ticket_generator.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// Auntification<BR>
|
||
|
|
#include "auth_dialog.h"<BR>
|
||
|
|
<BR>
|
||
|
|
qint32 ApplicationController::userId_ = -1;<BR>
|
||
|
|
qint32 ApplicationController::accessLevel_ = 0;<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 21"> 21 </A>bool ApplicationController::setupApplication( ) {<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !ensureDatabaseExists( DATABASE_NAME ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connectToDatabase( DATABASE_NAME ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !loadTranslations( "ru", "app", "_", ":/translations" ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
AuthDialog authDialog;<BR>
|
||
|
|
<BR>
|
||
|
|
QObject::connect( &authDialog, &AuthDialog::loginSuccessful, <BR>
|
||
|
|
&ApplicationController::onLoginSuccessful );<BR>
|
||
|
|
<BR>
|
||
|
|
QObject::connect( &authDialog, &AuthDialog::loginFailed, <BR>
|
||
|
|
&ApplicationController::onLoginFailed );<BR>
|
||
|
|
<BR>
|
||
|
|
// if ( authDialog.exec( ) != QDialog::Accepted ) {<BR>
|
||
|
|
// return false; // User has not logged in<BR>
|
||
|
|
// }<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 50"> 50 </A>bool ApplicationController::ensureDatabaseExists( <BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 51"> 51 </A> const QString &databaseFileName ) {<BR>
|
||
|
|
DatabaseManager::CreateDatabaseResult result =<BR>
|
||
|
|
DatabaseManager::createDefaultDatabaseIfMissing( databaseFileName );<BR>
|
||
|
|
<BR>
|
||
|
|
switch ( result ) {<BR>
|
||
|
|
case DatabaseManager::CreateDatabaseResult::Success: {<BR>
|
||
|
|
<BR>
|
||
|
|
#ifndef NDEBUG<BR>
|
||
|
|
qInfo( ) << "Generating test data...";<BR>
|
||
|
|
<BR>
|
||
|
|
DayManager dayManager( QTime( 8, 0 ), QTime( 17, 0 ) );<BR>
|
||
|
|
dayManager.setMode( DayManager::SlotSelectionMode::Quick );<BR>
|
||
|
|
dayManager.setMode( DayManager::StartTimeMode::Random );<BR>
|
||
|
|
<BR>
|
||
|
|
const QDate begin = QDate( 2025, 1, 1 ); // Since 01-01-2025<BR>
|
||
|
|
const QDate end = begin.addDays( 5 );<BR>
|
||
|
|
ReservationManager reservationManager( 14, begin.daysTo( end ), <BR>
|
||
|
|
std::move( dayManager ) );<BR>
|
||
|
|
<BR>
|
||
|
|
SessionGenerator sessionGenerator( reservationManager );<BR>
|
||
|
|
<BR>
|
||
|
|
sessionGenerator.generateAll( <BR>
|
||
|
|
sessionGenerator.defaultShouldLog( 1 /* percent */, 60 /* seconds */ ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QPair<QTime, QTime> timeRange( QTime( 9, 30 ), QTime( 15, 30 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
TicketGenerator ticketsGenerator( <BR>
|
||
|
|
{0, 30} /* day range */, timeRange, <BR>
|
||
|
|
{0.0, 1.0} /* fill ratio per session range*/ );<BR>
|
||
|
|
GeneratorInterface::ShouldLogSuccess performOtherwise =<BR>
|
||
|
|
ticketsGenerator.shouldLogFirstAndLastPercent( );<BR>
|
||
|
|
ticketsGenerator.generateByFillRatio( <BR>
|
||
|
|
0.35, <BR>
|
||
|
|
ticketsGenerator.defaultShouldLog( 1 /* percent */, 600 /* seconds */ ) );<BR>
|
||
|
|
<BR>
|
||
|
|
RefundGenerator refundGenerator( {0.1, 0.5} /* refund ratio range */, <BR>
|
||
|
|
{0, 7} /* day range */, timeRange );<BR>
|
||
|
|
refundGenerator.generateByFillRatio( <BR>
|
||
|
|
0.1, <BR>
|
||
|
|
refundGenerator.defaultShouldLog( 1 /* percent */, 600 /* seconds<BR>
|
||
|
|
*/ ) );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Test data generated successfully";<BR>
|
||
|
|
#endif<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Database created and initialized successfully";<BR>
|
||
|
|
} break;<BR>
|
||
|
|
case DatabaseManager::CreateDatabaseResult::AlreadyExists:<BR>
|
||
|
|
break;<BR>
|
||
|
|
case DatabaseManager::CreateDatabaseResult::Error:<BR>
|
||
|
|
qCritical( ) << "Failed to create and connect to the database";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 108"> 108 </A>void ApplicationController::onLoginFailed( ) {<BR>
|
||
|
|
userId_ = -1;<BR>
|
||
|
|
accessLevel_ = 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 113"> 113 </A>void ApplicationController::onLoginSuccessful( qint32 userId, <BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 114"> 114 </A> qint32 accessLevel ) {<BR>
|
||
|
|
userId_ = userId;<BR>
|
||
|
|
accessLevel_ = accessLevel;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 119"> 119 </A>bool ApplicationController::connectToDatabase( const QString &databaseName ) {<BR>
|
||
|
|
if ( !DatabaseManager::connectToDefaultDatabase( databaseName ) ) {<BR>
|
||
|
|
qCritical( ) << "Failed to connect to the database";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Connected to database" << databaseName << "successfully";<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 129"> 129 </A>bool ApplicationController::loadTranslations( const QString &locale, <BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 130"> 130 </A> const QString &filename, <BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 131"> 131 </A> const QString &prefix, <BR>
|
||
|
|
<A NAME="./core/controllers/application_controller.cpp: 132"> 132 </A> const QString &directory ) {<BR>
|
||
|
|
QCoreApplication *app = QCoreApplication::instance( );<BR>
|
||
|
|
QTranslator *translator = new QTranslator( app );<BR>
|
||
|
|
<BR>
|
||
|
|
bool loaded = translator->load( QLocale( locale ), filename, prefix, directory );<BR>
|
||
|
|
if ( !loaded ) {<BR>
|
||
|
|
qWarning( ) << "Failed to load translations";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
bool installed = app->installTranslator( translator );<BR>
|
||
|
|
if ( !installed ) {<BR>
|
||
|
|
qWarning( ) << "Failed to install translations";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Translations are loaded successfully";<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/db/database_manager.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 1"> 1 </A>#include "database_manager.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "config.h"<BR>
|
||
|
|
#include "execute_sql_file.h"<BR>
|
||
|
|
#include <QFile><BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <qsqldatabase.h><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 9"> 9 </A>DatabaseManager::~DatabaseManager( ) {<BR>
|
||
|
|
disconnectDefaultDatabase( );<BR>
|
||
|
|
<BR>
|
||
|
|
QString defaultConnectionName = QSqlDatabase::database( ).connectionName( );<BR>
|
||
|
|
QSqlDatabase::removeDatabase( QSqlDatabase::database( ).connectionName( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Database with default connection name:" << defaultConnectionName<BR>
|
||
|
|
<< "was removed";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
DatabaseManager::CreateDatabaseResult<BR>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 20"> 20 </A>DatabaseManager::createDefaultDatabaseIfMissing( <BR>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 21"> 21 </A> const QString &databaseFileName ) {<BR>
|
||
|
|
if ( QFile::exists( databaseFileName ) ) {<BR>
|
||
|
|
qInfo( )<BR>
|
||
|
|
<< "Database file name already exists and will not be created again:"<BR>
|
||
|
|
<< databaseFileName;<BR>
|
||
|
|
return CreateDatabaseResult::AlreadyExists;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !connectToDefaultDatabase( databaseFileName ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to create and connect to the database";<BR>
|
||
|
|
return CreateDatabaseResult::Error;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Execute SQL files to initialize the database<BR>
|
||
|
|
QStringList sqlFiles = {":/sql/create_tables.sql", ":/sql/create_indexes.sql", <BR>
|
||
|
|
":/sql/create_views.sql", ":/sql/create_triggers.sql", <BR>
|
||
|
|
":/sql/insert_role.sql"};<BR>
|
||
|
|
<BR>
|
||
|
|
#ifndef NDEBUG<BR>
|
||
|
|
QStringList additionalSqlFiles = {<BR>
|
||
|
|
":/sql/insert_genre.sql", ":/sql/insert_hall.sql", <BR>
|
||
|
|
":/sql/insert_movie.sql", ":/sql/insert_user.sql"};<BR>
|
||
|
|
sqlFiles.append( additionalSqlFiles );<BR>
|
||
|
|
#endif<BR>
|
||
|
|
<BR>
|
||
|
|
QSqlDatabase defaultDatabase = QSqlDatabase::database( );<BR>
|
||
|
|
bool success = executeSqlFiles( sqlFiles, defaultDatabase );<BR>
|
||
|
|
disconnectDefaultDatabase( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( success ) {<BR>
|
||
|
|
qInfo( ) << "Database created and initialized successfully";<BR>
|
||
|
|
return CreateDatabaseResult::Success;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qWarning( ) << "Failed to execute initialization SQL files";<BR>
|
||
|
|
<BR>
|
||
|
|
if ( QFile::remove( databaseFileName ) ) {<BR>
|
||
|
|
qInfo( ) << "Database file deleted due to initialization failure:"<BR>
|
||
|
|
<< databaseFileName;<BR>
|
||
|
|
} else {<BR>
|
||
|
|
qWarning( ) << "Failed to delete database file:" << databaseFileName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return CreateDatabaseResult::Error;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 67"> 67 </A>bool DatabaseManager::connectToDefaultDatabase( <BR>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 68"> 68 </A> const QString &databaseFileName ) {<BR>
|
||
|
|
QSqlDatabase defaultDatabase = QSqlDatabase::database( );<BR>
|
||
|
|
<BR>
|
||
|
|
defaultDatabase.setDatabaseName( databaseFileName );<BR>
|
||
|
|
if ( defaultDatabase.isValid( ) && defaultDatabase.isOpen( ) ) {<BR>
|
||
|
|
qInfo( ) << "Database is already connected";<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Constructor does not open/close the connection<BR>
|
||
|
|
defaultDatabase = QSqlDatabase::addDatabase( DATABASE_DRIVER );<BR>
|
||
|
|
defaultDatabase.setDatabaseName( databaseFileName );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !defaultDatabase.open( ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to connect to the database:" << databaseFileName;<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qDebug( ) << "Database was connected successfully: Connection name:"<BR>
|
||
|
|
<< defaultDatabase.connectionName( );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 92"> 92 </A>void DatabaseManager::disconnectDefaultDatabase( ) {<BR>
|
||
|
|
QSqlDatabase defaultDatabase = QSqlDatabase::database( );<BR>
|
||
|
|
if ( defaultDatabase.isOpen( ) ) {<BR>
|
||
|
|
defaultDatabase.close( );<BR>
|
||
|
|
qInfo( ) << "Database disconnected";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 100"> 100 </A>bool DatabaseManager::executeSqlFiles( const QStringList &filePaths, <BR>
|
||
|
|
<A NAME="./core/db/database_manager.cpp: 101"> 101 </A> QSqlDatabase &database ) {<BR>
|
||
|
|
ExecuteSqlFile executor( database );<BR>
|
||
|
|
for ( const QString &filePath : filePaths ) {<BR>
|
||
|
|
qInfo( ) << "Executing SQL file:" << filePath;<BR>
|
||
|
|
if ( !executor( filePath ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to execute SQL file:" << filePath;<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/db/execute_sql_file.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/db/execute_sql_file.cpp: 1"> 1 </A>#include "execute_sql_file.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QRegularExpression><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/execute_sql_file.cpp: 5"> 5 </A>ExecuteSqlFile::ExecuteSqlFile( QSqlDatabase &db )<BR>
|
||
|
|
: db_( db ), delimiter_( ";" ) { // Default delimiter is ";"<BR>
|
||
|
|
// Constructor does not open/close the connection<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/execute_sql_file.cpp: 10"> 10 </A>bool ExecuteSqlFile::operator( )( const QString &filePath ) {<BR>
|
||
|
|
// Ensure the database connection is open<BR>
|
||
|
|
if ( !db_.isOpen( ) ) {<BR>
|
||
|
|
qWarning( ) << "Database connection is not open";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QFile file( filePath );<BR>
|
||
|
|
if ( !file.open( QIODevice::ReadOnly | QIODevice::Text ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to open file:" << filePath;<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QTextStream in( &file );<BR>
|
||
|
|
QString sqlContent = in.readAll( );<BR>
|
||
|
|
file.close( );<BR>
|
||
|
|
<BR>
|
||
|
|
QStringList statements = sqlContent.split( "\n", Qt::SkipEmptyParts );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Executing SQL file:" << filePath;<BR>
|
||
|
|
<BR>
|
||
|
|
return processStatements( statements );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/execute_sql_file.cpp: 34"> 34 </A>bool ExecuteSqlFile::processStatements( QStringList &statements ) {<BR>
|
||
|
|
QString currentStatement;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( QString &line : statements ) {<BR>
|
||
|
|
qInfo( ) << "Processing line:" << line;<BR>
|
||
|
|
if ( !processLine( line, currentStatement ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Execute any remaining statement<BR>
|
||
|
|
if ( !currentStatement.isEmpty( ) && !executeStatement( currentStatement ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/execute_sql_file.cpp: 52"> 52 </A>bool ExecuteSqlFile::processLine( QString &line, QString &currentStatement ) {<BR>
|
||
|
|
if ( !filterLine( line ) ) {<BR>
|
||
|
|
qInfo( ) << "Line is empty after filtering";<BR>
|
||
|
|
return true; // Line was empty after filtering<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( processDelimiterChange( line ) ) {<BR>
|
||
|
|
qInfo( ) << "Delimiter changed to:" << delimiter_;<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
currentStatement += line + " ";<BR>
|
||
|
|
<BR>
|
||
|
|
auto delimiterIndex = currentStatement.lastIndexOf( delimiter_ );<BR>
|
||
|
|
if ( delimiterIndex == -1 ) {<BR>
|
||
|
|
qInfo( ) << "Delimiter not found, current statement is not finished";<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
qInfo( ) << "Statement finished, delimiter found at index:" << delimiterIndex;<BR>
|
||
|
|
<BR>
|
||
|
|
// Execute the current statement<BR>
|
||
|
|
QString completedStatement =<BR>
|
||
|
|
currentStatement.replace( delimiter_, ";" ).trimmed( );<BR>
|
||
|
|
if ( !executeStatement( completedStatement ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to execute statement:" << completedStatement;<BR>
|
||
|
|
return false; // Execution failed<BR>
|
||
|
|
}<BR>
|
||
|
|
qInfo( ) << "Successfully executed statement:" << completedStatement;<BR>
|
||
|
|
<BR>
|
||
|
|
currentStatement.clear( );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/execute_sql_file.cpp: 86"> 86 </A>bool ExecuteSqlFile::processDelimiterChange( QString &line ) {<BR>
|
||
|
|
QRegularExpression regex( R"( ^DELIMITER\s+( \S+ ) )" );<BR>
|
||
|
|
QRegularExpressionMatch match = regex.match( line );<BR>
|
||
|
|
if ( !match.hasMatch( ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
delimiter_ = match.captured( 1 ); // Update the delimiter_<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/execute_sql_file.cpp: 96"> 96 </A>bool ExecuteSqlFile::filterLine( QString &line ) {<BR>
|
||
|
|
line = line.section( "--", 0, 0 ).trimmed( ); // Remove comments and trim<BR>
|
||
|
|
return !line.isEmpty( ); // Return true if line is not empty<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/db/execute_sql_file.cpp: 101"> 101 </A>bool ExecuteSqlFile::executeStatement( const QString &statement ) const {<BR>
|
||
|
|
QSqlQuery query( db_ );<BR>
|
||
|
|
if ( !query.exec( statement ) ) {<BR>
|
||
|
|
qWarning( ) << "Error:" << query.lastError( ).text( );<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/repositories/repository_result.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/repositories/repository_result.cpp: 1"> 1 </A>#include "repository_result.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/repositories/repository_result.cpp: 3"> 3 </A>RepositoryResult RepositoryResult::successResult( ) { return {"", true}; }<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/repositories/repository_result.cpp: 5"> 5 </A>RepositoryResult RepositoryResult::failureResult( const QString &error ) {<BR>
|
||
|
|
return {error, false};<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/base_generator.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
#include "base_generator.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QElapsedTimer><BR>
|
||
|
|
#include <QVariant><BR>
|
||
|
|
<BR>
|
||
|
|
BaseGenerator::ShouldLogSuccess<BR>
|
||
|
|
<A NAME="./core/services/base_generator.cpp: 7"> 7 </A>BaseGenerator::shouldLogAllSuccesses( ) const noexcept {<BR>
|
||
|
|
return [this]( ) { return true; };<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
BaseGenerator::ShouldLogSuccess<BR>
|
||
|
|
BaseGenerator::shouldLogEveryNPercent( int percent ) const noexcept {<BR>
|
||
|
|
if ( percent <= 0 ) {<BR>
|
||
|
|
return [this]( ) { return false; };<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
int oldLastPercentage = 0;<BR>
|
||
|
|
return [this, percent, oldLastPercentage]( ) mutable {<BR>
|
||
|
|
if ( oldLastPercentage == lastPercentage_ ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
oldLastPercentage = lastPercentage_;<BR>
|
||
|
|
return !bool( lastPercentage_ % percent );<BR>
|
||
|
|
};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
BaseGenerator::ShouldLogSuccess<BR>
|
||
|
|
BaseGenerator::shouldLogFirstAndLastPercent( ) const noexcept {<BR>
|
||
|
|
return [this]( ) { return createdRecords_ == 1 || lastPercentage_ == 100; };<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
BaseGenerator::ShouldLogSuccess BaseGenerator::shouldLogEveryNSeconds( <BR>
|
||
|
|
int seconds, const ShouldLogSuccess &performOtherwise ) const noexcept {<BR>
|
||
|
|
QElapsedTimer timer;<BR>
|
||
|
|
timer.start( );<BR>
|
||
|
|
<BR>
|
||
|
|
return [this, timer, seconds, performOtherwise]( ) mutable {<BR>
|
||
|
|
if ( timer.elapsed( ) >= seconds * 1000 ) {<BR>
|
||
|
|
timer.restart( );<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
return performOtherwise( );<BR>
|
||
|
|
};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
BaseGenerator::ShouldLogSuccess<BR>
|
||
|
|
BaseGenerator::defaultShouldLog( int percent, int seconds ) const noexcept {<BR>
|
||
|
|
ShouldLogSuccess first =<BR>
|
||
|
|
shouldLogEveryNSeconds( seconds, shouldLogFirstAndLastPercent( ) );<BR>
|
||
|
|
ShouldLogSuccess second = shouldLogEveryNPercent( percent );<BR>
|
||
|
|
<BR>
|
||
|
|
return [first, second]( ) { return first( ) || second( ); };<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void BaseGenerator::generateAll( const ShouldLogSuccess &shouldLogSuccess ) {<BR>
|
||
|
|
auto withoutLimit = []( ) { return true; };<BR>
|
||
|
|
<BR>
|
||
|
|
generateImplementation( withoutLimit, shouldLogSuccess );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void BaseGenerator::generateByFillRatio( <BR>
|
||
|
|
double fillRatio, const ShouldLogSuccess &shouldLogSuccess ) {<BR>
|
||
|
|
fillRatio >= 1.0 ? fillRatio = 1.0 : fillRatio;<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Limit fill ratio of records to create: " << fillRatio;<BR>
|
||
|
|
<BR>
|
||
|
|
auto shouldContinue = [this, fillRatio]( ) -> bool {<BR>
|
||
|
|
double currentFillRatio = lastPercentage_ / 100.0;<BR>
|
||
|
|
bool shouldContinue = currentFillRatio < fillRatio;<BR>
|
||
|
|
if ( !shouldContinue ) {<BR>
|
||
|
|
qInfo( ) << "Limit of records to create reached";<BR>
|
||
|
|
}<BR>
|
||
|
|
return shouldContinue;<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
generateImplementation( shouldContinue, shouldLogSuccess );<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
void BaseGenerator::generateByRecordCount( <BR>
|
||
|
|
qsizetype totalRecordsToCreate, const ShouldLogSuccess &shouldLogSuccess ) {<BR>
|
||
|
|
int limit = std::min( totalRecordsToCreate, calculateRemainingCapacity( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Limit of records to create: " << limit;<BR>
|
||
|
|
<BR>
|
||
|
|
auto shouldContinue = [this, limit]( ) -> bool {<BR>
|
||
|
|
bool shouldContinue = createdRecords_ < limit;<BR>
|
||
|
|
if ( !shouldContinue ) {<BR>
|
||
|
|
qInfo( ) << "Limit of records to create reached";<BR>
|
||
|
|
}<BR>
|
||
|
|
return shouldContinue;<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
generateImplementation( shouldContinue, shouldLogSuccess );<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
void BaseGenerator::generateImplementation( <BR>
|
||
|
|
std::function<bool( )> shouldContinue, <BR>
|
||
|
|
std::function<bool( )> shouldLogSuccess ) {<BR>
|
||
|
|
maximumRecords_ = calculateRemainingCapacity( );<BR>
|
||
|
|
qInfo( ) << "The number of records available for creation:" << maximumRecords_;<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ).noquote( ) << createTemplateMessage( ) << "Started";<BR>
|
||
|
|
<BR>
|
||
|
|
while ( shouldContinue( ) && prepareData( ) ) {<BR>
|
||
|
|
bool success;<BR>
|
||
|
|
RepositoryResult result = createRecord( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
qWarning( ).noquote( ) << createTemplateMessage( )<BR>
|
||
|
|
<< createFailureMessage( result.errorMessage );<BR>
|
||
|
|
continue;<BR>
|
||
|
|
}<BR>
|
||
|
|
++createdRecords_;<BR>
|
||
|
|
updatePercentage( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( shouldLogSuccess( ) ) {<BR>
|
||
|
|
qInfo( ).noquote( ) << createTemplateMessage( ) << createSuccessMessage( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
clearStaleData( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ).noquote( ) << createTemplateMessage( ) << "Completed";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void BaseGenerator::updatePercentage( ) {<BR>
|
||
|
|
int numerator = maximumRecords_ - calculateRemainingCapacity( );<BR>
|
||
|
|
int newPercentage = std::floor( numerator * 100.0 / maximumRecords_ );<BR>
|
||
|
|
lastPercentage_ = std::max( newPercentage, lastPercentage_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString BaseGenerator::createFailureMessage( const QString &errorMessage ) const {<BR>
|
||
|
|
QString failureMessage = "Failure: Error message:\n\t%1";<BR>
|
||
|
|
return failureMessage.arg( errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString BaseGenerator::createSuccessMessage( ) const { return "Success"; }<BR>
|
||
|
|
<BR>
|
||
|
|
QString BaseGenerator::createTemplateMessage( ) const {<BR>
|
||
|
|
auto digitCount = []( int number ) {<BR>
|
||
|
|
if ( number == 0 ) {<BR>
|
||
|
|
return 1;<BR>
|
||
|
|
}<BR>
|
||
|
|
return static_cast<int>( std::log10( std::abs( number ) ) ) + 1;<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
int maximumRecordsValue = calculateRemainingCapacity( );<BR>
|
||
|
|
int newFieldWidth =<BR>
|
||
|
|
std::max( digitCount( createdRecords_ ), digitCount( maximumRecordsValue ) );<BR>
|
||
|
|
fieldWidth_ = std::max( fieldWidth_, newFieldWidth );<BR>
|
||
|
|
<BR>
|
||
|
|
static constexpr int progressBarSize = 25;<BR>
|
||
|
|
static constexpr int progressBarStep = 100 / progressBarSize;<BR>
|
||
|
|
const QString progressBar( lastPercentage_ / progressBarStep, QChar( '#' ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return QString( "Creating records of entity %1 [ %2 <~ %3] [%4]:" )<BR>
|
||
|
|
.arg( entityName_ )<BR>
|
||
|
|
.arg( createdRecords_, fieldWidth_, 10, QChar( ' ' ) )<BR>
|
||
|
|
.arg( maximumRecordsValue, fieldWidth_, 10, QChar( ' ' ) )<BR>
|
||
|
|
.arg( progressBar.leftJustified( progressBarSize, QChar( ' ' ) ) );<BR>
|
||
|
|
};<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/date_time_generator.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/services/date_time_generator.cpp: 1"> 1 </A>#include "date_time_generator.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/date_time_generator.cpp: 3"> 3 </A>DateTimeGenerator::DateTimeGenerator( const QPair<qint64, qint64> &dayRange, <BR>
|
||
|
|
<A NAME="./core/services/date_time_generator.cpp: 4"> 4 </A> const QPair<QTime, QTime> &timeRange )<BR>
|
||
|
|
: dayRange_( dayRange ), timeRange_( timeRange ) {<BR>
|
||
|
|
auto &[lowestDate, highestDate] = dayRange_;<BR>
|
||
|
|
if ( lowestDate < 0 || highestDate < 0 ) {<BR>
|
||
|
|
qFatal( ) << "Lowest or highest date is negative";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( lowestDate > highestDate ) {<BR>
|
||
|
|
qCritical( ) << "Lowest date is greater than the highest date, values will "<BR>
|
||
|
|
"be swapped";<BR>
|
||
|
|
std::swap( lowestDate, highestDate );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
auto &[lowestTime, highestTime] = timeRange_;<BR>
|
||
|
|
if ( !lowestTime.isValid( ) || !highestTime.isValid( ) ) {<BR>
|
||
|
|
qFatal( ) << "Lowest or highest time is not valid";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( lowestTime > highestTime ) {<BR>
|
||
|
|
qCritical( ) << "Lowest time is greater than the highest time, values will "<BR>
|
||
|
|
"be swapped";<BR>
|
||
|
|
std::swap( lowestTime, highestTime );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/date_time_generator.cpp: 29"> 29 </A>QDateTime DateTimeGenerator::generate( const QDateTime &upperBoundInclusive ) {<BR>
|
||
|
|
auto [lowestDate, highestDate] = dayRange_;<BR>
|
||
|
|
auto [lowestTime, highestTime] = timeRange_;<BR>
|
||
|
|
const QDate &maxDateValue = upperBoundInclusive.date( );<BR>
|
||
|
|
const qint64 maxTimeValueMs =<BR>
|
||
|
|
upperBoundInclusive.time( ).msecsSinceStartOfDay( );<BR>
|
||
|
|
<BR>
|
||
|
|
QDate epochDate = QDateTime::fromMSecsSinceEpoch( 0 ).date( );<BR>
|
||
|
|
qint64 daysFromEpochDateToMaxDateValue = epochDate.daysTo( maxDateValue );<BR>
|
||
|
|
highestDate = std::min( highestDate, daysFromEpochDateToMaxDateValue );<BR>
|
||
|
|
<BR>
|
||
|
|
qint64 minusDeltaDays = -bounded( lowestDate, highestDate );<BR>
|
||
|
|
QDate dateSoldAt = maxDateValue.addDays( minusDeltaDays );<BR>
|
||
|
|
<BR>
|
||
|
|
qint64 lowestTimeMs = lowestTime.msecsSinceStartOfDay( );<BR>
|
||
|
|
qint64 highestTimeMs = highestTime.msecsSinceStartOfDay( ) + 1;<BR>
|
||
|
|
qint64 msecsSinceStartOfDay = bounded( lowestTimeMs, highestTimeMs );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( msecsSinceStartOfDay > maxTimeValueMs ) {<BR>
|
||
|
|
msecsSinceStartOfDay = maxTimeValueMs;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QTime timeSoldAt = QTime::fromMSecsSinceStartOfDay( msecsSinceStartOfDay );<BR>
|
||
|
|
<BR>
|
||
|
|
return {std::move( dateSoldAt ), std::move( timeSoldAt )};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/date_time_generator.cpp: 56"> 56 </A>QDateTime DateTimeGenerator::generate( const QDateTime &lowerBoundInclusive, <BR>
|
||
|
|
<A NAME="./core/services/date_time_generator.cpp: 57"> 57 </A> const QDateTime &upperBoundInclusive ) {<BR>
|
||
|
|
if ( lowerBoundInclusive > upperBoundInclusive ) {<BR>
|
||
|
|
qFatal( ) << "Lower bound date is greater than the upper bound date";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const QDate &minDateValue = lowerBoundInclusive.date( );<BR>
|
||
|
|
const QTime &minTimeValue = lowerBoundInclusive.time( );<BR>
|
||
|
|
<BR>
|
||
|
|
QDateTime unboundedLower = generate( upperBoundInclusive );<BR>
|
||
|
|
<BR>
|
||
|
|
QDate boundedDate = unboundedLower.date( ) <= minDateValue<BR>
|
||
|
|
? minDateValue<BR>
|
||
|
|
: unboundedLower.date( );<BR>
|
||
|
|
QTime boundedTime = unboundedLower.time( ) <= minTimeValue<BR>
|
||
|
|
? minTimeValue<BR>
|
||
|
|
: unboundedLower.time( );<BR>
|
||
|
|
<BR>
|
||
|
|
return {std::move( boundedDate ), std::move( boundedTime )};<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/model_manager.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 1"> 1 </A>#include "model_manager.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "genres_model.h"<BR>
|
||
|
|
#include "halls_model.h"<BR>
|
||
|
|
#include "movies_model.h"<BR>
|
||
|
|
#include "refunds_model.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "sessions_model.h"<BR>
|
||
|
|
#include "tickets_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 11"> 11 </A>ModelManager::ModelManager( ) {<BR>
|
||
|
|
// Get connection to the database<BR>
|
||
|
|
database_ = QSqlDatabase::database( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !database_.isOpen( ) ) {<BR>
|
||
|
|
qDebug( ) << "Database is not open. Cannot initialize models";<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
initialize( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 23"> 23 </A>ModelManager::~ModelManager( ) {<BR>
|
||
|
|
qInfo( ) << "Models manager is being destroyed";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 27"> 27 </A>ModelManager &ModelManager::instance( ) {<BR>
|
||
|
|
static ModelManager instance;<BR>
|
||
|
|
return instance;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 32"> 32 </A>QStringList ModelManager::registeredModelTableNames( ) const {<BR>
|
||
|
|
return models_.keys( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QStringList<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 37"> 37 </A>ModelManager::registeredModelTableNames( QString databaseTableName ) const {<BR>
|
||
|
|
QStringList registeredModelTableNames;<BR>
|
||
|
|
for ( const auto &modelTableName : models_.keys( ) ) {<BR>
|
||
|
|
QSqlTableModel *currentModel = getModelAs<QSqlTableModel>( modelTableName );<BR>
|
||
|
|
QString currentDatabaseTableName = currentModel->tableName( );<BR>
|
||
|
|
if ( currentDatabaseTableName == databaseTableName ) {<BR>
|
||
|
|
registeredModelTableNames.append( modelTableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return registeredModelTableNames;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 49"> 49 </A>void ModelManager::initialize( ) {<BR>
|
||
|
|
// clang-format off<BR>
|
||
|
|
<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
registerModel<GenresModel>( <BR>
|
||
|
|
metadata.modelTableName( "genres" ), database_ );<BR>
|
||
|
|
<BR>
|
||
|
|
registerModel<HallsModel>( <BR>
|
||
|
|
metadata.modelTableName( "halls" ), database_ );<BR>
|
||
|
|
<BR>
|
||
|
|
registerModel<MoviesModel>( <BR>
|
||
|
|
metadata.modelTableName( "movies" ), database_ );<BR>
|
||
|
|
<BR>
|
||
|
|
registerModel<RefundsModel>( <BR>
|
||
|
|
metadata.modelTableName( "refunds" ), database_ );<BR>
|
||
|
|
<BR>
|
||
|
|
registerModel<SessionsModel>( <BR>
|
||
|
|
metadata.modelTableName( "sessions" ), database_ );<BR>
|
||
|
|
<BR>
|
||
|
|
registerModel<TicketsModel>( <BR>
|
||
|
|
metadata.modelTableName( "tickets" ), database_ );<BR>
|
||
|
|
<BR>
|
||
|
|
// clang-format on<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 75"> 75 </A>QSqlTableModel *ModelManager::getModel( const QString &modelTableName ) const {<BR>
|
||
|
|
QSqlTableModel *model = models_.value( modelTableName, nullptr );<BR>
|
||
|
|
if ( model == nullptr ) {<BR>
|
||
|
|
qDebug( ) << "Model" << modelTableName << "is not registered";<BR>
|
||
|
|
return nullptr;<BR>
|
||
|
|
}<BR>
|
||
|
|
qDebug( ) << "Getting model" << modelTableName << "with value" << model;<BR>
|
||
|
|
<BR>
|
||
|
|
return model;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 86"> 86 </A>void ModelManager::resetFilter( const QString &modelTableName ) {<BR>
|
||
|
|
BaseSqlTableModel *model = getModelAs<BaseSqlTableModel>( modelTableName );<BR>
|
||
|
|
model->resetFilter( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 91"> 91 </A>void ModelManager::setMultiColumnFilter( const QString &modelTableName, <BR>
|
||
|
|
<A NAME="./core/services/model_manager.cpp: 92"> 92 </A> const QString &filter ) {<BR>
|
||
|
|
BaseSqlTableModel *model = getModelAs<BaseSqlTableModel>( modelTableName );<BR>
|
||
|
|
model->setMultiColumnFilter( filter );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/refund_generator.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 1"> 1 </A>#include "refund_generator.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_refund_request.h"<BR>
|
||
|
|
#include "refunds_repository.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "session_dto.h"<BR>
|
||
|
|
#include "sessions_repository.h"<BR>
|
||
|
|
#include "ticket_dto.h"<BR>
|
||
|
|
#include "tickets_repository.h"<BR>
|
||
|
|
#include <QRandomGenerator><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 14"> 14 </A>RefundGenerator::RefundGenerator( const QPair<double, double> &refundRatioRange, <BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 15"> 15 </A> const QPair<qint64, qint64> &dayRange, <BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 16"> 16 </A> const QPair<QTime, QTime> &timeRange )<BR>
|
||
|
|
: BaseGenerator( "Refund" ), DateTimeGenerator( dayRange, timeRange ), <BR>
|
||
|
|
refundRatioRange_( refundRatioRange ) {<BR>
|
||
|
|
auto &[lowest, highest] = refundRatioRange_;<BR>
|
||
|
|
if ( lowest > highest ) {<BR>
|
||
|
|
qCritical( ) << "Lowest refund ratio is greater than the highest refund, "<BR>
|
||
|
|
"values will be swapped";<BR>
|
||
|
|
std::swap( lowest, highest );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
initializeRepositories( ); // First<BR>
|
||
|
|
initializeTicketIdToCacheValueMap( ); // After initializing<BR>
|
||
|
|
// repositories<BR>
|
||
|
|
initializeRemainingCapacity( ); // After initializing ticketIdToCacheValue<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 32"> 32 </A>void RefundGenerator::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
ticketsRepository_ = repositoryManager.getRepositoryAs<TicketsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "tickets" ) );<BR>
|
||
|
|
refundsRepository_ = repositoryManager.getRepositoryAs<RefundsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "refunds" ) );<BR>
|
||
|
|
sessionsRepository_ = repositoryManager.getRepositoryAs<SessionsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "sessions" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( ticketsRepository_ && refundsRepository_ && sessionsRepository_ ) ) {<BR>
|
||
|
|
qFatal( ) << "Failed to initialize repositories";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 48"> 48 </A>void RefundGenerator::initializeTicketIdToCacheValueMap( ) {<BR>
|
||
|
|
QVector<SessionDTO> sessions;<BR>
|
||
|
|
RepositoryResult resultGetAllSessions =<BR>
|
||
|
|
sessionsRepository_->getAllSessions( sessions );<BR>
|
||
|
|
if ( !resultGetAllSessions.success ) {<BR>
|
||
|
|
qFatal( ) << "Failed to retrieve sessions";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QMap<qint32 /* sessionId */, <BR>
|
||
|
|
QPair<QDateTime /* beginAt */, double /* ticketPrice */>><BR>
|
||
|
|
sessionIdToBeginAtAndTicketPrice;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const SessionDTO &session : sessions ) {<BR>
|
||
|
|
sessionIdToBeginAtAndTicketPrice[session.sessionId( )] =<BR>
|
||
|
|
qMakePair( session.beginAt( ), session.ticketPrice( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QVector<TicketDTO> tickets;<BR>
|
||
|
|
RepositoryResult resultGetAllTickets =<BR>
|
||
|
|
ticketsRepository_->getAllTickets( tickets );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !resultGetAllTickets.success ) {<BR>
|
||
|
|
qFatal( ) << "Failed to retrieve tickets";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &ticket : tickets ) {<BR>
|
||
|
|
const auto &[beginAt, ticketPrice] =<BR>
|
||
|
|
sessionIdToBeginAtAndTicketPrice[ticket.sessionId( )];<BR>
|
||
|
|
CacheValue cacheValue{beginAt, ticket.soldAt( ), ticketPrice};<BR>
|
||
|
|
<BR>
|
||
|
|
if ( calculateDurationMs( cacheValue ) < 2 ) {<BR>
|
||
|
|
continue;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ticketIdToCacheValue_[ticket.ticketId( )] = cacheValue;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 87"> 87 </A>RefundGenerator::createFailureMessage( const QString &errorMessage ) const {<BR>
|
||
|
|
const QString dateTimeFormat = "yyyy-MM-dd hh:mm:ss.zzz";<BR>
|
||
|
|
QString additionalInfo =<BR>
|
||
|
|
QString( "Additional info: Ticket id: %1 Refund amount: %2 Sold at: %3 "<BR>
|
||
|
|
"Refund at: %4 Begin at: %5" )<BR>
|
||
|
|
.arg( reservationContext_.ticketId )<BR>
|
||
|
|
.arg( reservationContext_.refundAmount )<BR>
|
||
|
|
.arg( reservationContext_.soldAt.toString( dateTimeFormat ) )<BR>
|
||
|
|
.arg( reservationContext_.refundAt.toString( dateTimeFormat ) )<BR>
|
||
|
|
.arg( reservationContext_.beginAt.toString( dateTimeFormat ) );<BR>
|
||
|
|
QString failureMessage = "Failure:\n\t%1\n\tError message: %2";<BR>
|
||
|
|
return failureMessage.arg( additionalInfo ).arg( errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 101"> 101 </A>QString RefundGenerator::createSuccessMessage( ) const {<BR>
|
||
|
|
return QString( "Success: EId: %1 RAm: %2 RAt: %3" )<BR>
|
||
|
|
.arg( reservationContext_.ticketId )<BR>
|
||
|
|
.arg( reservationContext_.refundAmount )<BR>
|
||
|
|
.arg( reservationContext_.refundAt.toString( "yyyy-MM-dd hh:mm:ss" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 108"> 108 </A>qsizetype RefundGenerator::calculateRemainingCapacity( ) const {<BR>
|
||
|
|
return remainingCapacity_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 112"> 112 </A>RepositoryResult RefundGenerator::createRecord( ) {<BR>
|
||
|
|
CreateRefundRequest request;<BR>
|
||
|
|
request.setRefundAmount( reservationContext_.refundAmount );<BR>
|
||
|
|
request.setRefundAt( reservationContext_.refundAt );<BR>
|
||
|
|
request.setTicketId( reservationContext_.ticketId );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result = refundsRepository_->createRefund( request );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( result.success ) {<BR>
|
||
|
|
--remainingCapacity_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 127"> 127 </A>bool RefundGenerator::prepareData( ) {<BR>
|
||
|
|
if ( ticketIdToCacheValue_.isEmpty( ) ) {<BR>
|
||
|
|
qInfo( ) << "No tickets to refund";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qsizetype ticketIdIndex = bounded<qsizetype>( 0, ticketIdToCacheValue_.size( ) );<BR>
|
||
|
|
auto ticketIdIt = ticketIdToCacheValue_.cbegin( );<BR>
|
||
|
|
std::advance( ticketIdIt, ticketIdIndex );<BR>
|
||
|
|
<BR>
|
||
|
|
qint32 ticketId = ticketIdIt.key( );<BR>
|
||
|
|
CacheValue cacheValue = ticketIdIt.value( );<BR>
|
||
|
|
<BR>
|
||
|
|
constexpr qint32 fiveMinutesMs = 5 * 1000 * 60;<BR>
|
||
|
|
qint64 deltaBoundMs = calculateDurationMs( cacheValue ) / 2;<BR>
|
||
|
|
if ( deltaBoundMs > fiveMinutesMs ) {<BR>
|
||
|
|
deltaBoundMs = fiveMinutesMs;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const QDateTime refundAt =<BR>
|
||
|
|
// SoldAt < RefundAt < BeginAt<BR>
|
||
|
|
// SoldAt + n minute <= RefundAt <= BeginAt - n minute<BR>
|
||
|
|
generate( cacheValue.soldAt.addMSecs( +deltaBoundMs ), <BR>
|
||
|
|
cacheValue.beginAt.addMSecs( -deltaBoundMs ) );<BR>
|
||
|
|
<BR>
|
||
|
|
const auto [refundRatioLowest, refundRatioHighest] = refundRatioRange_;<BR>
|
||
|
|
int lowest = refundRatioLowest * 100;<BR>
|
||
|
|
int highest = refundRatioHighest * 100;<BR>
|
||
|
|
int numerator = bounded( lowest, highest );<BR>
|
||
|
|
double refundAmount = std::floor( numerator * cacheValue.ticketPrice ) / 100.0;<BR>
|
||
|
|
<BR>
|
||
|
|
ReservationContext context{cacheValue.beginAt, refundAt, cacheValue.soldAt, <BR>
|
||
|
|
refundAmount, ticketId};<BR>
|
||
|
|
reservationContext_ = std::move( context );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/refund_generator.cpp: 165"> 165 </A>void RefundGenerator::clearStaleData( ) {<BR>
|
||
|
|
qint32 ticketId = reservationContext_.ticketId;<BR>
|
||
|
|
ticketIdToCacheValue_.remove( ticketId );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/relation_id_config.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/services/relation_id_config.cpp: 1"> 1 </A>#include "relation_id_config.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/relation_id_config.cpp: 3"> 3 </A>RelationIdConfig::RelationIdConfig( const QString &translentTableName, <BR>
|
||
|
|
<A NAME="./core/services/relation_id_config.cpp: 4"> 4 </A> const QString &modelTableName, <BR>
|
||
|
|
<A NAME="./core/services/relation_id_config.cpp: 5"> 5 </A> const QString &primaryIdColumnName, <BR>
|
||
|
|
<A NAME="./core/services/relation_id_config.cpp: 6"> 6 </A> const QString &repositoryTableName ) noexcept<BR>
|
||
|
|
: translatedTableName_( translentTableName ), modelTableName_( modelTableName ), <BR>
|
||
|
|
primaryIdColumnName_( primaryIdColumnName ), <BR>
|
||
|
|
repositoryTableName_( repositoryTableName ) {}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/repository_manager.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/services/repository_manager.cpp: 1"> 1 </A>#include "repository_manager.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "genres_repository.h"<BR>
|
||
|
|
#include "halls_repository.h"<BR>
|
||
|
|
#include "movies_repository.h"<BR>
|
||
|
|
#include "refunds_repository.h"<BR>
|
||
|
|
#include "roles_repository.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "sessions_repository.h"<BR>
|
||
|
|
#include "sessions_statistics_repository.h"<BR>
|
||
|
|
#include "tickets_repository.h"<BR>
|
||
|
|
#include "users_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/repository_manager.cpp: 14"> 14 </A>RepositoryManager::RepositoryManager( ) {<BR>
|
||
|
|
database_ = QSqlDatabase::database( );<BR>
|
||
|
|
if ( !database_.isOpen( ) ) {<BR>
|
||
|
|
qDebug( ) << "Database is not open. Cannot initialize repositories";<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
initialize( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/repository_manager.cpp: 24"> 24 </A>RepositoryManager::~RepositoryManager( ) {<BR>
|
||
|
|
qInfo( ) << "Repositories manager is being destroyed";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/repository_manager.cpp: 28"> 28 </A>RepositoryManager &RepositoryManager::instance( ) {<BR>
|
||
|
|
static RepositoryManager instance;<BR>
|
||
|
|
return instance;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/repository_manager.cpp: 33"> 33 </A>void RepositoryManager::initialize( ) {<BR>
|
||
|
|
// clang-format off<BR>
|
||
|
|
<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
// Tables<BR>
|
||
|
|
registerRepository<GenresRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "genres" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
registerRepository<HallsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "halls" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
registerRepository<MoviesRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "movies" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
registerRepository<RefundsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "refunds" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
registerRepository<SessionsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "sessions" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
registerRepository<TicketsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "tickets" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
registerRepository<UsersRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "users" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
registerRepository<RolesRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "roles" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
// Views<BR>
|
||
|
|
registerRepository<SessionsStatisticsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "sessions_statistics" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
// clang-format on<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryInterface *<BR>
|
||
|
|
<A NAME="./core/services/repository_manager.cpp: 71"> 71 </A>RepositoryManager::getRepository( const QString &repositoryTableName ) const {<BR>
|
||
|
|
RepositoryInterface *repository =<BR>
|
||
|
|
repositories_.value( repositoryTableName, nullptr );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( repository == nullptr ) {<BR>
|
||
|
|
qDebug( ) << "Repository" << repositoryTableName << "is not registered";<BR>
|
||
|
|
return nullptr;<BR>
|
||
|
|
}<BR>
|
||
|
|
qDebug( ) << "Getting model" << repositoryTableName << "with value"<BR>
|
||
|
|
<< repository;<BR>
|
||
|
|
<BR>
|
||
|
|
return repository;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/schema_metadata.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 1"> 1 </A>#include "schema_metadata.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QDebug><BR>
|
||
|
|
<BR>
|
||
|
|
QMap<QString, RelationIdConfig> SchemaMetadata::databaseTableNameToConfigMap_;<BR>
|
||
|
|
std::once_flag SchemaMetadata::initFlag;<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 8"> 8 </A>void SchemaMetadata::initialize( ) {<BR>
|
||
|
|
qInfo( ) << "Initializing schema metadata...";<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig genreConfig;<BR>
|
||
|
|
genreConfig.setPrimaryIdColumnName( "genre_id" );<BR>
|
||
|
|
genreConfig.setTranslatedTableName( tr( "Genres" ) );<BR>
|
||
|
|
genreConfig.setModelTableName( "GenresModel" );<BR>
|
||
|
|
genreConfig.setRepositoryTableName( "GenresRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "genres", genreConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig hallConfig;<BR>
|
||
|
|
hallConfig.setPrimaryIdColumnName( "hall_id" );<BR>
|
||
|
|
hallConfig.setTranslatedTableName( tr( "Halls" ) );<BR>
|
||
|
|
hallConfig.setModelTableName( "HallsModel" );<BR>
|
||
|
|
hallConfig.setRepositoryTableName( "HallsRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "halls", hallConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig movieConfig;<BR>
|
||
|
|
movieConfig.setPrimaryIdColumnName( "movie_id" );<BR>
|
||
|
|
movieConfig.setTranslatedTableName( tr( "Movies" ) );<BR>
|
||
|
|
movieConfig.setModelTableName( "MoviesModel" );<BR>
|
||
|
|
movieConfig.setRepositoryTableName( "MoviesRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "movies", movieConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig refundConfig;<BR>
|
||
|
|
refundConfig.setPrimaryIdColumnName( "refund_id" );<BR>
|
||
|
|
refundConfig.setTranslatedTableName( tr( "Refunds" ) );<BR>
|
||
|
|
refundConfig.setModelTableName( "RefundsModel" );<BR>
|
||
|
|
refundConfig.setRepositoryTableName( "RefundsRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "refunds", refundConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig sessionConfig;<BR>
|
||
|
|
sessionConfig.setPrimaryIdColumnName( "session_id" );<BR>
|
||
|
|
sessionConfig.setTranslatedTableName( tr( "Sessions" ) );<BR>
|
||
|
|
sessionConfig.setModelTableName( "SessionsModel" );<BR>
|
||
|
|
sessionConfig.setRepositoryTableName( "SessionsRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "sessions", sessionConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig ticketConfig;<BR>
|
||
|
|
ticketConfig.setPrimaryIdColumnName( "ticket_id" );<BR>
|
||
|
|
ticketConfig.setTranslatedTableName( tr( "Tickets" ) );<BR>
|
||
|
|
ticketConfig.setModelTableName( "TicketsModel" );<BR>
|
||
|
|
ticketConfig.setRepositoryTableName( "TicketsRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "tickets", ticketConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig userConfig;<BR>
|
||
|
|
userConfig.setPrimaryIdColumnName( "user_id" );<BR>
|
||
|
|
userConfig.setTranslatedTableName( tr( "Users" ) );<BR>
|
||
|
|
userConfig.setRepositoryTableName( "UsersRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "users", userConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig roleConfig;<BR>
|
||
|
|
roleConfig.setPrimaryIdColumnName( "role_id" );<BR>
|
||
|
|
roleConfig.setTranslatedTableName( tr( "Roles" ) );<BR>
|
||
|
|
roleConfig.setRepositoryTableName( "RolesRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "roles", roleConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig tableInfoConfig;<BR>
|
||
|
|
tableInfoConfig.setTranslatedTableName( tr( "Sessions statistics" ) );<BR>
|
||
|
|
tableInfoConfig.setRepositoryTableName( "SessionsStatisticsRepository" );<BR>
|
||
|
|
databaseTableNameToConfigMap_.insert( "sessions_statistics", tableInfoConfig );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Schema metadata initialized successfully";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 73"> 73 </A>SchemaMetadata::SchemaMetadata( ) noexcept {<BR>
|
||
|
|
std::call_once( initFlag, &SchemaMetadata::initialize );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 77"> 77 </A>SchemaMetadata::SchemaMetadata( const SchemaMetadata & ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 79"> 79 </A>SchemaMetadata &SchemaMetadata::operator=( const SchemaMetadata & ) {<BR>
|
||
|
|
return *this;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 83"> 83 </A>SchemaMetadata SchemaMetadata::defaultSchema( ) { return SchemaMetadata( ); }<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 85"> 85 </A>QString SchemaMetadata::modelTableName( const QString &databaseTableName ) {<BR>
|
||
|
|
QString modelTableName = relationIdConfig( databaseTableName ).modelTableName( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( modelTableName.isEmpty( ) ) {<BR>
|
||
|
|
qFatal( ) << "Model table name is empty: Database table name:"<BR>
|
||
|
|
<< databaseTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return modelTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 96"> 96 </A>QString SchemaMetadata::primaryIdColumnName( const QString &databaseTableName ) {<BR>
|
||
|
|
QString primaryIdColumnName =<BR>
|
||
|
|
relationIdConfig( databaseTableName ).primaryIdColumnName( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( primaryIdColumnName.isEmpty( ) ) {<BR>
|
||
|
|
qFatal( ) << "Primary id column name is empty: Database table name:"<BR>
|
||
|
|
<< databaseTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return primaryIdColumnName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 108"> 108 </A>QString SchemaMetadata::repositoryTableName( const QString &databaseTableName ) {<BR>
|
||
|
|
QString repositoryTableName =<BR>
|
||
|
|
relationIdConfig( databaseTableName ).repositoryTableName( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( repositoryTableName.isEmpty( ) ) {<BR>
|
||
|
|
qFatal( ) << "Repository table name is empty: Database table name:"<BR>
|
||
|
|
<< databaseTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return repositoryTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 120"> 120 </A>QString SchemaMetadata::translatedTableName( const QString &databaseTableName ) {<BR>
|
||
|
|
QString translatedTableName =<BR>
|
||
|
|
relationIdConfig( databaseTableName ).translatedTableName( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( translatedTableName.isEmpty( ) ) {<BR>
|
||
|
|
qFatal( ) << "Translated table name is empty: Database table name:"<BR>
|
||
|
|
<< databaseTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return translatedTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RelationIdConfig<BR>
|
||
|
|
<A NAME="./core/services/schema_metadata.cpp: 133"> 133 </A>SchemaMetadata::relationIdConfig( const QString &databaseTableName ) {<BR>
|
||
|
|
RelationIdConfig config =<BR>
|
||
|
|
databaseTableNameToConfigMap_.value( databaseTableName );<BR>
|
||
|
|
return config;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/session_generator.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 1"> 1 </A>#include "session_generator.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_session_request.h"<BR>
|
||
|
|
#include "hall_dto.h"<BR>
|
||
|
|
#include "halls_repository.h"<BR>
|
||
|
|
#include "movie_dto.h"<BR>
|
||
|
|
#include "movies_repository.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "sessions_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 13"> 13 </A>SessionGenerator::SessionGenerator( <BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 14"> 14 </A> const ReservationManager &reservationReference )<BR>
|
||
|
|
: BaseGenerator( "Session" ), reservationReference_( reservationReference ) {<BR>
|
||
|
|
initializeRepositories( ); // First<BR>
|
||
|
|
<BR>
|
||
|
|
qint32 extraTime = 45; // Extra time for cleaning the room<BR>
|
||
|
|
initializeMovieIdToDurationMap( extraTime ); // After initializing repositories<BR>
|
||
|
|
<BR>
|
||
|
|
initializeBounds( ); // After initializing movieIdToDuration<BR>
|
||
|
|
initializeDayManager( ); // After initializing bounds<BR>
|
||
|
|
initializeHallIdToReservationManagerMap( ); // After initializing dayManager<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 26"> 26 </A>void SessionGenerator::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
moviesRepository_ = repositoryManager.getRepositoryAs<MoviesRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "movies" ) );<BR>
|
||
|
|
hallsRepository_ = repositoryManager.getRepositoryAs<HallsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "halls" ) );<BR>
|
||
|
|
sessionsRepository_ = repositoryManager.getRepositoryAs<SessionsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "sessions" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( moviesRepository_ && hallsRepository_ && sessionsRepository_ ) ) {<BR>
|
||
|
|
qFatal( ) << "Failed to initialize repositories";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 42"> 42 </A>void SessionGenerator::initializeMovieIdToDurationMap( <BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 43"> 43 </A> qint32 additionalMinutes ) {<BR>
|
||
|
|
QVector<MovieDTO> movies;<BR>
|
||
|
|
RepositoryResult result = moviesRepository_->getAllMovies( movies );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
qFatal( ) << "Failed to retrieve movies";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const MovieDTO &movie : movies ) {<BR>
|
||
|
|
movieIdToDurationMinutes_[movie.movieId( )] =<BR>
|
||
|
|
movie.duration( ) + additionalMinutes;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( movieIdToDurationMinutes_.isEmpty( ) ) {<BR>
|
||
|
|
qFatal( ) << "Failed to initialize movieIdToDuration";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Number of movies:" << movieIdToDurationMinutes_.size( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 63"> 63 </A>void SessionGenerator::initializeBounds( ) {<BR>
|
||
|
|
qint32 lowerBoundReservationMin = *std::min_element( <BR>
|
||
|
|
movieIdToDurationMinutes_.cbegin( ), movieIdToDurationMinutes_.cend( ) );<BR>
|
||
|
|
lowerBoundReservationMs_ = lowerBoundReservationMin * 60'000; // 60 * 1000<BR>
|
||
|
|
<BR>
|
||
|
|
qint32 upperBoundReservationMin = *std::max_element( <BR>
|
||
|
|
movieIdToDurationMinutes_.cbegin( ), movieIdToDurationMinutes_.cend( ) );<BR>
|
||
|
|
upperBoundReservationMs_ = upperBoundReservationMin * 60'000; // 60 * 1000<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 72"> 72 </A> qInfo( ) << "Lower bound reservation in Ms:" << lowerBoundReservationMs_;<BR>
|
||
|
|
qInfo( ) << "Upper bound reservation in Ms:" << upperBoundReservationMs_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void SessionGenerator::initializeDayManager( ) {<BR>
|
||
|
|
QTime minDuration = QTime::fromMSecsSinceStartOfDay( lowerBoundReservationMs_ );<BR>
|
||
|
|
DayManager dayManager( reservationReference_.reference( ) );<BR>
|
||
|
|
dayManager.setMinDuration( minDuration );<BR>
|
||
|
|
reservationReference_.setReference( dayManager );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !reservationReference_.reference( ).minDuration( ).isValid( ) ) {<BR>
|
||
|
|
qFatal( ) << "Failed to initialize dayManager";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Day manager: Min duration:"<BR>
|
||
|
|
<< reservationReference_.reference( ).minDuration( );<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 88"> 88 </A> qInfo( ) << "Day manager: Slot count:"<BR>
|
||
|
|
<< reservationReference_.reference( ).slotCount( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void SessionGenerator::initializeHallIdToReservationManagerMap( ) {<BR>
|
||
|
|
QVector<HallDTO> halls;<BR>
|
||
|
|
RepositoryResult result = hallsRepository_->getAllHalls( halls );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
qFatal( ) << "Failed to retrieve halls";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const HallDTO &hall : halls ) {<BR>
|
||
|
|
hallIdToReservationManager_[hall.hallId( )] = reservationReference_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( hallIdToReservationManager_.isEmpty( ) ) {<BR>
|
||
|
|
qFatal( ) << "Failed to initialize hallIdToReservationManager";<BR>
|
||
|
|
}<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 107"> 107 </A><BR>
|
||
|
|
qInfo( ) << "Number of halls:" << hallIdToReservationManager_.size( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult SessionGenerator::createRecord( ) {<BR>
|
||
|
|
CreateSessionRequest request;<BR>
|
||
|
|
request.setBeginAt( reservationContext_.beginAt );<BR>
|
||
|
|
request.setHallId( reservationContext_.hallId );<BR>
|
||
|
|
request.setMovieId( reservationContext_.movieId );<BR>
|
||
|
|
request.setTicketPrice( reservationContext_.ticketPrice );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result = sessionsRepository_->createSession( request );<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 120"> 120 </A> return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString<BR>
|
||
|
|
SessionGenerator::createFailureMessage( const QString &errorMessage ) const {<BR>
|
||
|
|
QString additionalInfo =<BR>
|
||
|
|
QString( "Additional info: Hall id: %1 Begin at: %2" )<BR>
|
||
|
|
.arg( reservationContext_.hallId )<BR>
|
||
|
|
.arg( reservationContext_.beginAt.toString( "yyyy-MM-dd hh:mm:ss" ) );<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 129"> 129 </A> QString failureMessage = "Failure:\n\t%1\n\tError message: %2";<BR>
|
||
|
|
return failureMessage.arg( additionalInfo ).arg( errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString SessionGenerator::createSuccessMessage( ) const {<BR>
|
||
|
|
qint32 hallId = reservationContext_.hallId;<BR>
|
||
|
|
const ReservationManager &manager = hallIdToReservationManager_.value( hallId );<BR>
|
||
|
|
QTime duration = calculateDuration( reservationContext_ );<BR>
|
||
|
|
<BR>
|
||
|
|
// return QString( "Success: TAD: %1 TAS: %2 EId: %3 AD: %4 AS: %5 CR: %6 B: %7<BR>
|
||
|
|
// D: %8" )<BR>
|
||
|
|
return QString( "Success: TAD: %1 TAS: %2 EId: %3 AD: %4 AS: %5 CR: %6" )<BR>
|
||
|
|
.arg( calculateAvailableDaysCount( ) ) // Total available days<BR>
|
||
|
|
.arg( calculateAvailableSlotsCount( ) ) // Total available slots<BR>
|
||
|
|
.arg( hallId ) // Entity id<BR>
|
||
|
|
.arg( manager.calculateAvailableDaysCount( ) ) // Available days for the<BR>
|
||
|
|
// current hall<BR>
|
||
|
|
.arg( manager.calculateAvailableSlotsCount( ) ) // Available slots for the<BR>
|
||
|
|
// current hall<BR>
|
||
|
|
.arg( manager.createdRecords( ) ); // Created records for the<BR>
|
||
|
|
// current hall<BR>
|
||
|
|
// .arg( reservationContext_.beginAt.toString( //<BR>
|
||
|
|
// "yyyy-MM-dd hh:mm:ss" ) ) // Begin<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 152"> 152 </A> // // of created record<BR>
|
||
|
|
// .arg( duration.toString( "hh:mm:ss" ) ); // Duration of created record<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qsizetype SessionGenerator::calculateRemainingCapacity( ) const {<BR>
|
||
|
|
// Maximum number of sessions that can be created<BR>
|
||
|
|
return std::accumulate( hallIdToReservationManager_.cbegin( ), <BR>
|
||
|
|
hallIdToReservationManager_.cend( ), 0, <BR>
|
||
|
|
[&]( qsizetype sum, const ReservationManager &manager ) {<BR>
|
||
|
|
return sum + manager.calculatePossibleReservations( <BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 162"> 162 </A> lowerBoundReservationMs_ );<BR>
|
||
|
|
} );<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
bool SessionGenerator::prepareData( ) {<BR>
|
||
|
|
std::random_device rd;<BR>
|
||
|
|
std::mt19937 g{rd( )};<BR>
|
||
|
|
<BR>
|
||
|
|
QList<qint32> hallIds = hallIdToReservationManager_.keys( );<BR>
|
||
|
|
std::shuffle( hallIds.begin( ), hallIds.end( ), g );<BR>
|
||
|
|
QList<qint32> movieIds = movieIdToDurationMinutes_.keys( );<BR>
|
||
|
|
std::shuffle( movieIds.begin( ), movieIds.end( ), g );<BR>
|
||
|
|
<BR>
|
||
|
|
for ( qint32 hallId : hallIds ) {<BR>
|
||
|
|
if ( prepareData( hallId, movieIds ) ) {<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
qWarning( ) << "No available halls";<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 181"> 181 </A><BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 182"> 182 </A> return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
bool SessionGenerator::prepareData( qint32 hallId, <BR>
|
||
|
|
const QList<qint32> &movieIds ) {<BR>
|
||
|
|
for ( qint32 movieId : movieIds ) {<BR>
|
||
|
|
ReservationManager &manager = hallIdToReservationManager_[hallId];<BR>
|
||
|
|
<BR>
|
||
|
|
auto [beginDateTime, endTime] = manager.reserve( duration( movieId ) );<BR>
|
||
|
|
if ( !beginDateTime.isValid( ) || !endTime.isValid( ) ) {<BR>
|
||
|
|
continue;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const QDate epochDate = QDateTime::fromMSecsSinceEpoch( 0 ).date( );<BR>
|
||
|
|
const qint64 deltaDays = epochDate.daysTo( QDate( 2025, 1, 1 ) );<BR>
|
||
|
|
const QDate newBeginDate = beginDateTime.date( ).addDays( deltaDays );<BR>
|
||
|
|
const QTime beginTime = beginDateTime.time( );<BR>
|
||
|
|
<BR>
|
||
|
|
reservationContext_ = ReservationContext{<BR>
|
||
|
|
QDateTime( std::move( newBeginDate ), std::move( beginTime ) ), <BR>
|
||
|
|
std::move( endTime ), <BR>
|
||
|
|
bounded( 10'000, 50'000 ) / 100.0, <BR>
|
||
|
|
hallId, <BR>
|
||
|
|
movieId, <BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qCritical( )<BR>
|
||
|
|
<< "SessionGenerator::prepareData: No available movies for hall with id"<BR>
|
||
|
|
<< hallId;<BR>
|
||
|
|
<A NAME="./core/services/session_generator.cpp: 214"> 214 </A><BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QTime SessionGenerator::duration( qint32 movieId ) const {<BR>
|
||
|
|
qint32 durationMin = movieIdToDurationMinutes_[movieId];<BR>
|
||
|
|
qint64 durationMs = durationMin * 60'000; // 60 * 1000<BR>
|
||
|
|
QTime durationTime = QTime::fromMSecsSinceStartOfDay( durationMs );<BR>
|
||
|
|
return durationTime;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qsizetype SessionGenerator::calculateAvailableDaysCount( ) const {<BR>
|
||
|
|
return std::accumulate( hallIdToReservationManager_.cbegin( ), <BR>
|
||
|
|
hallIdToReservationManager_.cend( ), 0, <BR>
|
||
|
|
[&]( int sum, const ReservationManager &manager ) {<BR>
|
||
|
|
return sum + manager.calculateAvailableDaysCount( );<BR>
|
||
|
|
} );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qsizetype SessionGenerator::calculateAvailableSlotsCount( ) const {<BR>
|
||
|
|
return std::accumulate( hallIdToReservationManager_.cbegin( ), <BR>
|
||
|
|
hallIdToReservationManager_.cend( ), 0, <BR>
|
||
|
|
[&]( int sum, const ReservationManager &manager ) {<BR>
|
||
|
|
return sum + manager.calculateAvailableSlotsCount( );<BR>
|
||
|
|
} );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QTime SessionGenerator::calculateDuration( ReservationContext context ) const {<BR>
|
||
|
|
QTime beginTime = context.beginAt.time( );<BR>
|
||
|
|
QTime endTime = context.endTime;<BR>
|
||
|
|
qint64 durationMs = beginTime.msecsTo( endTime );<BR>
|
||
|
|
return QTime::fromMSecsSinceStartOfDay( durationMs );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void SessionGenerator::clearStaleData( ) {<BR>
|
||
|
|
qint64 hallId = reservationContext_.hallId;<BR>
|
||
|
|
if ( hallIdToReservationManager_[hallId].calculateAvailableDaysCount( ) == 0 ) {<BR>
|
||
|
|
qWarning( ) << "No available days for hall" << hallId;<BR>
|
||
|
|
hallIdToReservationManager_.remove( hallId );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/services/ticket_generator.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 1"> 1 </A>#include "ticket_generator.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_ticket_request.h"<BR>
|
||
|
|
#include "hall_dto.h"<BR>
|
||
|
|
#include "halls_repository.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "session_dto.h"<BR>
|
||
|
|
#include "sessions_repository.h"<BR>
|
||
|
|
#include "tickets_repository.h"<BR>
|
||
|
|
#include <QDebug><BR>
|
||
|
|
#include <QStack><BR>
|
||
|
|
#include <numeric><BR>
|
||
|
|
<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
<BR>
|
||
|
|
std::random_device TicketGenerator::rd_;<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 19"> 19 </A>std::mt19937 TicketGenerator::generator_( rd_( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 21"> 21 </A>TicketGenerator::TicketGenerator( <BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 22"> 22 </A> const QPair<qint32, qint32> &dayRange, const QPair<QTime, QTime> &timeRange, <BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 23"> 23 </A> const QPair<double, double> &fillRatioPerSessionRange )<BR>
|
||
|
|
: BaseGenerator( "Ticket" ), DateTimeGenerator( dayRange, timeRange ) {<BR>
|
||
|
|
if ( !setFillRatioPerSessionRange( fillRatioPerSessionRange ) ) {<BR>
|
||
|
|
qFatal( ) << "Failed to set fill ratio per session range";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
initializeRepositories( );<BR>
|
||
|
|
initializeSessionIdToAvailableSeatMap( ); // After initializing repositories<BR>
|
||
|
|
initializeSessionIdToBeginAtMap( ); // After initializing repositories<BR>
|
||
|
|
initializeRemainingCapacity( ); // After initializing sessionToAvailableSeats<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Number of sessions:" << sessionIdToAvailableSeatNumbers_.size( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 37"> 37 </A>void TicketGenerator::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
hallsRepository_ = repositoryManager.getRepositoryAs<HallsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "halls" ) );<BR>
|
||
|
|
sessionsRepository_ = repositoryManager.getRepositoryAs<SessionsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "sessions" ) );<BR>
|
||
|
|
ticketsRepository_ = repositoryManager.getRepositoryAs<TicketsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "tickets" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( ticketsRepository_ && sessionsRepository_ ) ) {<BR>
|
||
|
|
qFatal( ) << "Failed to initialize repositories";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 53"> 53 </A>void TicketGenerator::initializeSessionIdToAvailableSeatMap( ) {<BR>
|
||
|
|
QVector<HallDTO> halls;<BR>
|
||
|
|
RepositoryResult resultGetAllHalls = hallsRepository_->getAllHalls( halls );<BR>
|
||
|
|
if ( !resultGetAllHalls.success ) {<BR>
|
||
|
|
qFatal( ) << "Failed to retrieve halls";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QVector<SessionDTO> sessions;<BR>
|
||
|
|
RepositoryResult resultGetAllSessions =<BR>
|
||
|
|
sessionsRepository_->getAllSessions( sessions );<BR>
|
||
|
|
if ( !resultGetAllSessions.success ) {<BR>
|
||
|
|
qFatal( ) << "Failed to retrieve sessions";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QMap<qint32 /* sessionId */, QSet<qint32> /* availableSeatNumbers */><BR>
|
||
|
|
hallIdToAvailableSeatNumbers;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const HallDTO &hall : halls ) {<BR>
|
||
|
|
qint32 targetCapacity =<BR>
|
||
|
|
std::ceil( hall.capacity( ) * generateFillRatioPerSession( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QVector<qint32> availableSeats( targetCapacity );<BR>
|
||
|
|
std::iota( availableSeats.begin( ), availableSeats.end( ), 1 );<BR>
|
||
|
|
std::shuffle( availableSeats.begin( ), availableSeats.end( ), generator_ );<BR>
|
||
|
|
<BR>
|
||
|
|
QSet<qint32> buffer;<BR>
|
||
|
|
for ( qint32 i = 0; i < targetCapacity; ++i ) {<BR>
|
||
|
|
buffer.insert( availableSeats[i] );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
hallIdToAvailableSeatNumbers[hall.hallId( )] = std::move( buffer );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const SessionDTO &session : sessions ) {<BR>
|
||
|
|
sessionIdToAvailableSeatNumbers_[session.sessionId( )] =<BR>
|
||
|
|
hallIdToAvailableSeatNumbers[session.hallId( )];<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 92"> 92 </A>void TicketGenerator::initializeSessionIdToBeginAtMap( ) {<BR>
|
||
|
|
QVector<SessionDTO> sessions;<BR>
|
||
|
|
RepositoryResult resultGetAllSessions =<BR>
|
||
|
|
sessionsRepository_->getAllSessions( sessions );<BR>
|
||
|
|
if ( !resultGetAllSessions.success ) {<BR>
|
||
|
|
qFatal( ) << "Failed to retrieve sessions";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const SessionDTO &session : sessions ) {<BR>
|
||
|
|
sessionIdToBeginAt_[session.sessionId( )] = session.beginAt( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 105"> 105 </A>bool TicketGenerator::setFillRatioPerSessionRange( <BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 106"> 106 </A> const QPair<double, double> &range ) {<BR>
|
||
|
|
const auto &[minValue, maxValue] = range;<BR>
|
||
|
|
if ( minValue > maxValue ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
auto &[minFillRatioPerSession, maxFillRatioPerSession] =<BR>
|
||
|
|
fillRatioPerSessionRange_;<BR>
|
||
|
|
minFillRatioPerSession = std::max( minValue, 0.0 );<BR>
|
||
|
|
maxFillRatioPerSession = std::min( maxValue, 1.0 );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 120"> 120 </A>double TicketGenerator::generateFillRatioPerSession( ) const {<BR>
|
||
|
|
const auto &[min, max] = fillRatioPerSessionRange_;<BR>
|
||
|
|
std::uniform_real_distribution<double> distribution( min, max );<BR>
|
||
|
|
return distribution( generator_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 126"> 126 </A>void TicketGenerator::initializeRemainingCapacity( ) {<BR>
|
||
|
|
remainingCapacity_ =<BR>
|
||
|
|
std::accumulate( sessionIdToAvailableSeatNumbers_.cbegin( ), <BR>
|
||
|
|
sessionIdToAvailableSeatNumbers_.cend( ), 0, <BR>
|
||
|
|
[&]( qsizetype sum, const QSet<qint32> &availableSeats ) {<BR>
|
||
|
|
return sum + availableSeats.size( );<BR>
|
||
|
|
} );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 136"> 136 </A>TicketGenerator::createFailureMessage( const QString &errorMessage ) const {<BR>
|
||
|
|
QString additionalInfo =<BR>
|
||
|
|
QString( "Additional info: Session id: %1 Seat number: %2 Sold at: %3 "<BR>
|
||
|
|
"Begin at: %4" )<BR>
|
||
|
|
.arg( reservationContext_.sessionId )<BR>
|
||
|
|
.arg( reservationContext_.seatNumber )<BR>
|
||
|
|
.arg( reservationContext_.soldAt.toString( "yyyy-MM-dd hh:mm:ss" ) )<BR>
|
||
|
|
.arg( reservationContext_.beginAt.toString( "yyyy-MM-dd hh:mm:ss" ) );<BR>
|
||
|
|
QString failureMessage = "Failure:\n\t%1\n\tError message: %2";<BR>
|
||
|
|
return failureMessage.arg( additionalInfo ).arg( errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 148"> 148 </A>QString TicketGenerator::createSuccessMessage( ) const {<BR>
|
||
|
|
return QString( "Success: EId: %1 SN: %2" )<BR>
|
||
|
|
.arg( reservationContext_.sessionId )<BR>
|
||
|
|
.arg( reservationContext_.seatNumber );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 154"> 154 </A>qsizetype TicketGenerator::calculateRemainingCapacity( ) const {<BR>
|
||
|
|
return remainingCapacity_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 158"> 158 </A>RepositoryResult TicketGenerator::createRecord( ) {<BR>
|
||
|
|
CreateTicketRequest request;<BR>
|
||
|
|
request.setSessionId( reservationContext_.sessionId );<BR>
|
||
|
|
request.setSeatNumber( reservationContext_.seatNumber );<BR>
|
||
|
|
request.setSoldAt( reservationContext_.soldAt );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result = ticketsRepository_->createTicket( request );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( result.success ) {<BR>
|
||
|
|
--remainingCapacity_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 173"> 173 </A>bool TicketGenerator::prepareData( ) {<BR>
|
||
|
|
if ( remainingCapacity_ <= 0 ) {<BR>
|
||
|
|
qInfo( ) << "All tickets have been sold";<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qsizetype deltaIndex =<BR>
|
||
|
|
bounded<qsizetype>( 0, sessionIdToAvailableSeatNumbers_.size( ) );<BR>
|
||
|
|
auto it = sessionIdToAvailableSeatNumbers_.begin( );<BR>
|
||
|
|
std::advance( it, deltaIndex );<BR>
|
||
|
|
<BR>
|
||
|
|
const qint32 sessionId = it.key( );<BR>
|
||
|
|
QSet<qint32> &availableSeatNumbers = it.value( ); // Not empty<BR>
|
||
|
|
<BR>
|
||
|
|
const QDateTime &beginAt = sessionIdToBeginAt_[sessionId];<BR>
|
||
|
|
constexpr qint32 minus20MinutesMs = -20 * 1000 * 60;<BR>
|
||
|
|
// soldAt < beginAt || soldAt + 20 minute <= beginAt<BR>
|
||
|
|
QDateTime soldAt = generate( beginAt.addMSecs( minus20MinutesMs ) );<BR>
|
||
|
|
<BR>
|
||
|
|
qsizetype seatNumberIndex =<BR>
|
||
|
|
bounded<qsizetype>( 0, availableSeatNumbers.size( ) );<BR>
|
||
|
|
auto seatNumberIt = availableSeatNumbers.cbegin( );<BR>
|
||
|
|
std::advance( seatNumberIt, seatNumberIndex );<BR>
|
||
|
|
<BR>
|
||
|
|
qint32 seatNumber = *seatNumberIt;<BR>
|
||
|
|
<BR>
|
||
|
|
ReservationContext context{beginAt, soldAt, seatNumber, sessionId};<BR>
|
||
|
|
reservationContext_ = std::move( context );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/services/ticket_generator.cpp: 205"> 205 </A>void TicketGenerator::clearStaleData( ) {<BR>
|
||
|
|
<BR>
|
||
|
|
qint32 sessionId = reservationContext_.sessionId;<BR>
|
||
|
|
qint32 seatNumber = reservationContext_.seatNumber;<BR>
|
||
|
|
QSet<qint32> &availableSeatNumbers =<BR>
|
||
|
|
sessionIdToAvailableSeatNumbers_[sessionId];<BR>
|
||
|
|
<BR>
|
||
|
|
availableSeatNumbers.remove( seatNumber );<BR>
|
||
|
|
if ( availableSeatNumbers.empty( ) ) {<BR>
|
||
|
|
qWarning( ) << "All tickets for session with id" << sessionId<BR>
|
||
|
|
<< "have been sold";<BR>
|
||
|
|
sessionIdToAvailableSeatNumbers_.remove( sessionId );<BR>
|
||
|
|
sessionIdToBeginAt_.remove( sessionId );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/utils/day_manager.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 1"> 1 </A>#include "day_manager.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QRandomGenerator><BR>
|
||
|
|
#include <algorithm><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 6"> 6 </A>DayManager::DayManager( const QTime &begin, const QTime &end ) : DayManager( ) {<BR>
|
||
|
|
addAvailableSlot( begin, end );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 10"> 10 </A>void DayManager::addAvailableSlot( const QTime &begin, const QTime &end ) {<BR>
|
||
|
|
if ( !begin.isValid( ) || !end.isValid( ) || begin >= end ) {<BR>
|
||
|
|
qWarning( ) << "DayManager::addAvailableSlot: begin or end is invalid";<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( begin.msecsTo( end ) >= minDurationMs_ ) {<BR>
|
||
|
|
availableSlots_.insert( begin, end );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 20"> 20 </A>QPair<QTime, QTime> DayManager::reserve( const QTime &duration ) {<BR>
|
||
|
|
if ( !duration.isValid( ) ) {<BR>
|
||
|
|
qWarning( ) << "DayManager::reserve: duration is invalid";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const qint64 requiredMs = duration.msecsSinceStartOfDay( );<BR>
|
||
|
|
if ( requiredMs <= 0 ) {<BR>
|
||
|
|
qWarning( ) << "DayManager::reserve: duration is invalid";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QPair<QTime, QTime> result = reserveImpl( requiredMs );<BR>
|
||
|
|
if ( !isAvailable( result.first, result.second ) ) {<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
++createdRecords_;<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <typename... Times><BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 42"> 42 </A>bool DayManager::isAvailable( const QTime &first, const Times &...others ) const {<BR>
|
||
|
|
static const auto isAvailable = []( const QTime &time ) {<BR>
|
||
|
|
return time.isValid( );<BR>
|
||
|
|
};<BR>
|
||
|
|
return isAvailable( first ) && isAvailable( others... );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 49"> 49 </A>QList<std::reference_wrapper<const QTime>><BR>
|
||
|
|
DayManager::availableSlots( qint64 requiredMs ) const {<BR>
|
||
|
|
QList<std::reference_wrapper<const QTime>> result;<BR>
|
||
|
|
for ( auto const &[begin, end] : availableSlots_.asKeyValueRange( ) ) {<BR>
|
||
|
|
if ( begin.msecsTo( end ) >= requiredMs ) {<BR>
|
||
|
|
result.append( begin );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 60"> 60 </A>QPair<QTime, QTime> DayManager::reserveAvailableSlotLeft( QTime begin, <BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 61"> 61 </A> qint64 requiredMs ) {<BR>
|
||
|
|
QTime end = availableSlots_.value( begin );<BR>
|
||
|
|
<BR>
|
||
|
|
QTime reservedEnd = begin.addMSecs( requiredMs );<BR>
|
||
|
|
if ( reservedEnd < end ) {<BR>
|
||
|
|
addAvailableSlot( reservedEnd, end );<BR>
|
||
|
|
}<BR>
|
||
|
|
availableSlots_.remove( begin );<BR>
|
||
|
|
<BR>
|
||
|
|
return {begin, reservedEnd};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 73"> 73 </A>QPair<QTime, QTime> DayManager::reserveAvailableSlotRight( QTime begin, <BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 74"> 74 </A> qint64 requiredMs ) {<BR>
|
||
|
|
QTime end = availableSlots_.value( begin );<BR>
|
||
|
|
availableSlots_.remove( begin );<BR>
|
||
|
|
<BR>
|
||
|
|
QTime reservedBegin = end.addMSecs( -requiredMs );<BR>
|
||
|
|
if ( reservedBegin > begin ) {<BR>
|
||
|
|
addAvailableSlot( begin, reservedBegin );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return {reservedBegin, end};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 86"> 86 </A>QPair<QTime, QTime> DayManager::reserveAvailableSlotRandom( QTime begin, <BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 87"> 87 </A> qint64 requiredMs ) {<BR>
|
||
|
|
QTime end = availableSlots_.value( begin );<BR>
|
||
|
|
if ( !end.isValid( ) ) {<BR>
|
||
|
|
qCritical( ) << "DayManager::reserveAvailableSlotRandom: end is invalid";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qint64 beginMs = begin.msecsSinceStartOfDay( );<BR>
|
||
|
|
qint64 endMs = end.msecsSinceStartOfDay( );<BR>
|
||
|
|
<BR>
|
||
|
|
// x <= bounded( x, y ) < y<BR>
|
||
|
|
qint64 highestMs = endMs - requiredMs;<BR>
|
||
|
|
qint64 startTimeMs =<BR>
|
||
|
|
QRandomGenerator::global( )->bounded( beginMs, highestMs + 1 );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( startTimeMs == beginMs ) {<BR>
|
||
|
|
return reserveAvailableSlotLeft( begin, requiredMs );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( startTimeMs == highestMs ) {<BR>
|
||
|
|
return reserveAvailableSlotRight( begin, requiredMs );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
availableSlots_.remove( begin );<BR>
|
||
|
|
<BR>
|
||
|
|
QTime reservedBegin = QTime::fromMSecsSinceStartOfDay( startTimeMs );<BR>
|
||
|
|
QTime reservedEnd = QTime::fromMSecsSinceStartOfDay( startTimeMs + requiredMs );<BR>
|
||
|
|
<BR>
|
||
|
|
addAvailableSlot( begin, reservedBegin );<BR>
|
||
|
|
addAvailableSlot( reservedEnd, end );<BR>
|
||
|
|
<BR>
|
||
|
|
return {reservedBegin, reservedEnd};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 119"> 119 </A>QPair<QTime, QTime> DayManager::reserveAvailableSlot( QTime begin, <BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 120"> 120 </A> qint64 requiredMs ) {<BR>
|
||
|
|
switch ( startTimeMode_ ) {<BR>
|
||
|
|
case StartTimeMode::Left:<BR>
|
||
|
|
return reserveAvailableSlotLeft( begin, requiredMs );<BR>
|
||
|
|
case StartTimeMode::Random:<BR>
|
||
|
|
return reserveAvailableSlotRandom( begin, requiredMs );<BR>
|
||
|
|
case StartTimeMode::Right:<BR>
|
||
|
|
return reserveAvailableSlotRight( begin, requiredMs );<BR>
|
||
|
|
default:<BR>
|
||
|
|
qWarning( ) << "DayManager::reserve: unknown start time mode";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 134"> 134 </A>QPair<QTime, QTime> DayManager::reserveImplMaximal( qint64 requiredMs ) {<BR>
|
||
|
|
auto keys = availableSlots( requiredMs );<BR>
|
||
|
|
if ( keys.isEmpty( ) ) {<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QTime begin = *std::max_element( <BR>
|
||
|
|
keys.begin( ), keys.end( ), [this]( const auto &largest, const auto &other ) {<BR>
|
||
|
|
return duration( largest ) < duration( other );<BR>
|
||
|
|
} );<BR>
|
||
|
|
return reserveAvailableSlot( begin, requiredMs );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 147"> 147 </A>QPair<QTime, QTime> DayManager::reserveImplMinimal( qint64 requiredMs ) {<BR>
|
||
|
|
auto keys = availableSlots( requiredMs );<BR>
|
||
|
|
if ( keys.isEmpty( ) ) {<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QTime begin =<BR>
|
||
|
|
*std::min_element( keys.begin( ), keys.end( ), <BR>
|
||
|
|
[this]( const QTime &smallest, const QTime &other ) {<BR>
|
||
|
|
return duration( smallest ) < duration( other );<BR>
|
||
|
|
} );<BR>
|
||
|
|
return reserveAvailableSlot( begin, requiredMs );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 161"> 161 </A>QPair<QTime, QTime> DayManager::reserveImplQuick( qint64 requiredMs ) {<BR>
|
||
|
|
for ( auto const &[begin, end] : availableSlots_.asKeyValueRange( ) ) {<BR>
|
||
|
|
if ( begin.msecsTo( end ) >= requiredMs ) {<BR>
|
||
|
|
return reserveAvailableSlot( begin, requiredMs );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 171"> 171 </A>QPair<QTime, QTime> DayManager::reserveImplRandom( qint64 requiredMs ) {<BR>
|
||
|
|
auto keys = availableSlots( requiredMs );<BR>
|
||
|
|
if ( keys.isEmpty( ) ) {<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QRandomGenerator *g = QRandomGenerator::global( );<BR>
|
||
|
|
QTime begin = keys.at( g->bounded( keys.size( ) ) );<BR>
|
||
|
|
return reserveAvailableSlot( begin, requiredMs );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 182"> 182 </A>QPair<QTime, QTime> DayManager::reserveImpl( qint64 requiredMs ) {<BR>
|
||
|
|
switch ( slotSelectionMode_ ) {<BR>
|
||
|
|
case SlotSelectionMode::Quick:<BR>
|
||
|
|
return DayManager::reserveImplQuick( requiredMs );<BR>
|
||
|
|
case SlotSelectionMode::Maximal:<BR>
|
||
|
|
return DayManager::reserveImplMaximal( requiredMs );<BR>
|
||
|
|
case SlotSelectionMode::Minimal:<BR>
|
||
|
|
return DayManager::reserveImplMinimal( requiredMs );<BR>
|
||
|
|
case SlotSelectionMode::Random:<BR>
|
||
|
|
return DayManager::reserveImplRandom( requiredMs );<BR>
|
||
|
|
default:<BR>
|
||
|
|
qWarning( ) << "DayManager::reserve: unknown reserve mode";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 198"> 198 </A>void DayManager::setMinDuration( const QTime &duration ) {<BR>
|
||
|
|
if ( !duration.isValid( ) ) {<BR>
|
||
|
|
qWarning( ) << "DayManager::setMinDuration: duration is invalid";<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
minDurationMs_ = duration.msecsSinceStartOfDay( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 207"> 207 </A>qsizetype DayManager::calculatePossibleReservations( qint64 requiredMs ) const {<BR>
|
||
|
|
auto keys = availableSlots( requiredMs );<BR>
|
||
|
|
return std::accumulate( keys.begin( ), keys.end( ), 0, <BR>
|
||
|
|
[this, requiredMs]( qsizetype sum, const QTime &key ) {<BR>
|
||
|
|
qint64 durationMs =<BR>
|
||
|
|
duration( key ).msecsSinceStartOfDay( );<BR>
|
||
|
|
return sum + std::floor( durationMs / requiredMs );<BR>
|
||
|
|
} );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 217"> 217 </A>QTime DayManager::duration( ) const {<BR>
|
||
|
|
if ( availableSlots_.isEmpty( ) ) {<BR>
|
||
|
|
// qWarning( ) << "DayManager::duration: no available slots";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const auto &kvRange = availableSlots_.asKeyValueRange( );<BR>
|
||
|
|
auto f = [this]( qint64 sum, const auto &kv ) -> qint64 {<BR>
|
||
|
|
auto const &[begin, end] = kv;<BR>
|
||
|
|
return sum + begin.msecsTo( end );<BR>
|
||
|
|
};<BR>
|
||
|
|
qint64 sum = std::accumulate( kvRange.begin( ), kvRange.end( ), 0, f );<BR>
|
||
|
|
<BR>
|
||
|
|
return QTime::fromMSecsSinceStartOfDay( sum );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/day_manager.cpp: 233"> 233 </A>QTime DayManager::duration( const QTime &begin ) const {<BR>
|
||
|
|
if ( !begin.isValid( ) ) {<BR>
|
||
|
|
qWarning( ) << "DayManager::duration: begin is invalid";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const QTime &end = availableSlots_.value( begin );<BR>
|
||
|
|
if ( !end.isValid( ) ) {<BR>
|
||
|
|
qWarning( ) << "DayManager::duration: end is invalid";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return end.addMSecs( -begin.msecsSinceStartOfDay( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./core/utils/reservation_manager.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 1"> 1 </A>#include "reservation_manager.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QRandomGenerator><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 5"> 5 </A>ReservationManager::ReservationManager( qsizetype dayRange, qsizetype dayBound, <BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 6"> 6 </A> const DayManager &reference )<BR>
|
||
|
|
: createdRecords_( 0 ), dayBound_( dayBound ), dayRange_( dayRange ), <BR>
|
||
|
|
excludedDays_( 0 ), lastIndex_( -1 ), dayReference_( reference ) {<BR>
|
||
|
|
prepareDaysRange( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 12"> 12 </A>void ReservationManager::setReference( const DayManager &reference ) {<BR>
|
||
|
|
dayReference_ = reference;<BR>
|
||
|
|
days_.clear( );<BR>
|
||
|
|
lastIndex_ = -1;<BR>
|
||
|
|
prepareDaysRange( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 19"> 19 </A>qsizetype ReservationManager::calculateAvailableDaysCount( ) const {<BR>
|
||
|
|
qsizetype bound =<BR>
|
||
|
|
dayBound_ != -1 ? dayBound_ : std::numeric_limits<qsizetype>::max( );<BR>
|
||
|
|
return bound - excludedDays_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qsizetype<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 26"> 26 </A>ReservationManager::calculatePossibleReservations( qint64 requiredMs ) const {<BR>
|
||
|
|
qsizetype possibleReservations = std::accumulate( <BR>
|
||
|
|
days_.cbegin( ), days_.cend( ), 0, <BR>
|
||
|
|
[&]( qsizetype sum, const DayManager manager ) {<BR>
|
||
|
|
return sum + manager.calculatePossibleReservations( requiredMs );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
qsizetype possibleReservationsByReference =<BR>
|
||
|
|
dayReference_.calculatePossibleReservations( requiredMs );<BR>
|
||
|
|
qsizetype futureReservationsCount =<BR>
|
||
|
|
calculateAvailableDaysCount( ) - days_.size( );<BR>
|
||
|
|
<BR>
|
||
|
|
return possibleReservations +<BR>
|
||
|
|
possibleReservationsByReference * futureReservationsCount;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 42"> 42 </A>qsizetype ReservationManager::calculateAvailableSlotsCount( ) const {<BR>
|
||
|
|
return std::accumulate( days_.cbegin( ), days_.cend( ), 0, <BR>
|
||
|
|
[&]( qsizetype sum, const DayManager manager ) {<BR>
|
||
|
|
return sum + manager.slotCount( );<BR>
|
||
|
|
} );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 49"> 49 </A>QPair<QDateTime, QTime> ReservationManager::reserve( const QTime &duration ) {<BR>
|
||
|
|
if ( !duration.isValid( ) ) {<BR>
|
||
|
|
qWarning( ) << "ReservationManager::reserve: duration is invalid";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const qint64 requiredMs = duration.msecsSinceStartOfDay( );<BR>
|
||
|
|
if ( requiredMs <= 0 ) {<BR>
|
||
|
|
qWarning( )<BR>
|
||
|
|
<< "ReservationManager::reserve: duration should be greater than 0";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( days_.isEmpty( ) ) {<BR>
|
||
|
|
qWarning( ) << "ReservationManager::reserve: no available days";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
std::mt19937 g{std::random_device{}( )};<BR>
|
||
|
|
QList<qsizetype> dayIndexes = days_.keys( );<BR>
|
||
|
|
std::shuffle( dayIndexes.begin( ), dayIndexes.end( ), g );<BR>
|
||
|
|
<BR>
|
||
|
|
for ( qsizetype dayIndex : dayIndexes ) {<BR>
|
||
|
|
QPair<QDateTime, QTime> result = reserve( dayIndex, duration );<BR>
|
||
|
|
const auto &[beginDateTime, endTime] = result;<BR>
|
||
|
|
if ( beginDateTime.isValid( ) && endTime.isValid( ) ) {<BR>
|
||
|
|
++createdRecords_;<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// qWarning( ) << "ReservationManager::reserve: reservation failed";<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 84"> 84 </A>DayManager &ReservationManager::dayManager( qsizetype dayIndex ) {<BR>
|
||
|
|
auto it = days_.find( dayIndex );<BR>
|
||
|
|
if ( it != days_.end( ) ) {<BR>
|
||
|
|
return it.value( );<BR>
|
||
|
|
}<BR>
|
||
|
|
qCritical( ) << "ReservationManager::dayManager: dayIndex is out of range";<BR>
|
||
|
|
throw std::out_of_range( "dayIndex is out of range" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 93"> 93 </A>QPair<QDateTime, QTime> ReservationManager::reserve( qsizetype dayIndex, <BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 94"> 94 </A> const QTime &duration ) {<BR>
|
||
|
|
<BR>
|
||
|
|
QTime beginTime, endTime;<BR>
|
||
|
|
DayManager &dayManagerValue = dayManager( dayIndex );<BR>
|
||
|
|
<BR>
|
||
|
|
std::tie( beginTime, endTime ) = dayManagerValue.reserve( duration );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !dayManagerValue.duration( ).isValid( ) ) {<BR>
|
||
|
|
days_.remove( dayIndex );<BR>
|
||
|
|
++excludedDays_;<BR>
|
||
|
|
}<BR>
|
||
|
|
prepareDaysRange( ); // Add new days after excluded days<BR>
|
||
|
|
<BR>
|
||
|
|
QDate beginDate = QDateTime::fromMSecsSinceEpoch( 0 ).date( ).addDays( dayIndex );<BR>
|
||
|
|
QDateTime beginDateTime( beginDate, beginTime );<BR>
|
||
|
|
<BR>
|
||
|
|
return {std::move( beginDateTime ), std::move( endTime )};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./core/utils/reservation_manager.cpp: 113"> 113 </A>void ReservationManager::prepareDaysRange( ) {<BR>
|
||
|
|
if ( !dayReference_.duration( ).isValid( ) ) {<BR>
|
||
|
|
qWarning( ) << "ReservationManager::prepareDaysRange: reference is invalid";<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
auto condition = [this]( qsizetype currentSize ) {<BR>
|
||
|
|
qsizetype bound =<BR>
|
||
|
|
dayBound_ != -1 ? dayBound_ : std::numeric_limits<qsizetype>::max( );<BR>
|
||
|
|
if ( lastIndex_ + 1 < bound ) {<BR>
|
||
|
|
return currentSize < dayRange_;<BR>
|
||
|
|
}<BR>
|
||
|
|
return false;<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
for ( qsizetype size = days_.size( ); condition( size ); ++size ) {<BR>
|
||
|
|
days_[++lastIndex_] = DayManager( dayReference_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/base_sql_table_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/base_sql_table_repository.cpp: 1"> 1 </A>#include "base_sql_table_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/base_sql_table_repository.cpp: 6"> 6 </A>BaseSqlTableRepository::BaseSqlTableRepository( QSqlDatabase &database, <BR>
|
||
|
|
<A NAME="./data/sql/base_sql_table_repository.cpp: 7"> 7 </A> QObject *parent )<BR>
|
||
|
|
: DataRepositorySignals( parent ), database_( database ) {<BR>
|
||
|
|
if ( !database_.isOpen( ) ) {<BR>
|
||
|
|
qWarning( ) << "Database is not open: Database name:"<BR>
|
||
|
|
<< database_.databaseName( )<BR>
|
||
|
|
<< "Database connection name:" << database_.connectionName( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/base_sql_table_repository.cpp: 16"> 16 </A>QSqlQuery BaseSqlTableRepository::foreignKeysOnQuery( ) const {<BR>
|
||
|
|
QSqlQuery query( database_ );<BR>
|
||
|
|
if ( !query.exec( "PRAGMA foreign_keys = ON" ) ) {<BR>
|
||
|
|
qFatal( ) << "Failed to enable foreign keys:" << query.lastError( ).text( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return query;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/genres_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 1"> 1 </A>#include "genres_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_genre_request.h"<BR>
|
||
|
|
#include "genre_dto.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "update_genre_request.h"<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 10"> 10 </A>GenresRepository::GenresRepository( QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 14"> 14 </A>GenresRepository::createGenre( const CreateGenreRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "INSERT INTO genres ( genre_name ) VALUES ( :genre_name )" );<BR>
|
||
|
|
query.bindValue( ":genre_name", request.genreName( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataCreated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 27"> 27 </A>RepositoryResult GenresRepository::getGenreById( qint32 id, <BR>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 28"> 28 </A> GenreDTO &genre ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"SELECT genre_id, genre_name FROM genres WHERE genre_id = :genre_id" );<BR>
|
||
|
|
query.bindValue( ":genre_id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "Genre not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
genre = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 48"> 48 </A>GenresRepository::getAllGenres( QVector<GenreDTO> &genres ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT genre_id, genre_name FROM genres" );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
genres.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 65"> 65 </A>GenresRepository::updateGenre( const UpdateGenreRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"UPDATE genres SET genre_name = :genre_name WHERE genre_id = :genre_id" );<BR>
|
||
|
|
query.bindValue( ":genre_name", request.genreName( ) );<BR>
|
||
|
|
query.bindValue( ":genre_id", request.genreId( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataUpdated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 80"> 80 </A>RepositoryResult GenresRepository::deleteGenreById( qint32 genreId ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "DELETE FROM genres WHERE genre_id = :genre_id" );<BR>
|
||
|
|
query.bindValue( ":genre_id", genreId );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataDeleted( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/genres_repository.cpp: 93"> 93 </A>GenreDTO GenresRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
GenreDTO genreDTO;<BR>
|
||
|
|
genreDTO.setGenreId( query.value( "genre_id" ).toInt( ) );<BR>
|
||
|
|
genreDTO.setGenreName( query.value( "genre_name" ).toString( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return genreDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/halls_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/halls_repository.cpp: 1"> 1 </A>#include "halls_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_hall_request.h"<BR>
|
||
|
|
#include "hall_dto.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "update_hall_request.h"<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/halls_repository.cpp: 10"> 10 </A>HallsRepository::HallsRepository( QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/halls_repository.cpp: 13"> 13 </A>RepositoryResult HallsRepository::createHall( const CreateHallRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "INSERT INTO halls ( hall_name, capacity ) VALUES "<BR>
|
||
|
|
"( :hall_name, :capacity )" );<BR>
|
||
|
|
query.bindValue( ":hall_name", request.hallName( ) );<BR>
|
||
|
|
query.bindValue( ":capacity", request.capacity( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataCreated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/halls_repository.cpp: 28"> 28 </A>RepositoryResult HallsRepository::getHallById( qint32 id, HallDTO &hall ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"SELECT hall_id, hall_name, capacity FROM halls WHERE hall_id = :id" );<BR>
|
||
|
|
query.bindValue( ":id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "Hall not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
hall = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/halls_repository.cpp: 47"> 47 </A>RepositoryResult HallsRepository::getAllHalls( QVector<HallDTO> &halls ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT hall_id, hall_name, capacity FROM halls" );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
halls.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/halls_repository.cpp: 63"> 63 </A>RepositoryResult HallsRepository::updateHall( const UpdateHallRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "UPDATE halls SET hall_name = :hall_name, capacity = :capacity "<BR>
|
||
|
|
"WHERE hall_id = :hall_id" );<BR>
|
||
|
|
query.bindValue( ":capacity", request.capacity( ) );<BR>
|
||
|
|
query.bindValue( ":hall_id", request.hallId( ) );<BR>
|
||
|
|
query.bindValue( ":hall_name", request.hallName( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataUpdated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/halls_repository.cpp: 79"> 79 </A>RepositoryResult HallsRepository::deleteHallById( qint32 hallId ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "DELETE FROM halls WHERE hall_id = :hall_id" );<BR>
|
||
|
|
query.bindValue( ":hall_id", hallId );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataDeleted( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/halls_repository.cpp: 92"> 92 </A>HallDTO HallsRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
HallDTO hallDTO;<BR>
|
||
|
|
hallDTO.setCapacity( query.value( "capacity" ).toInt( ) );<BR>
|
||
|
|
hallDTO.setHallId( query.value( "hall_id" ).toInt( ) );<BR>
|
||
|
|
hallDTO.setHallName( query.value( "hall_name" ).toString( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return hallDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/movies_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 1"> 1 </A>#include "movies_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_movie_request.h"<BR>
|
||
|
|
#include "movie_dto.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "update_movie_request.h"<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 10"> 10 </A>MoviesRepository::MoviesRepository( QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 14"> 14 </A>MoviesRepository::createMovie( const CreateMovieRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "INSERT INTO movies ( title, genre_id, duration ) VALUES "<BR>
|
||
|
|
"( :title, :genre_id, :duration )" );<BR>
|
||
|
|
query.bindValue( ":title", request.title( ) );<BR>
|
||
|
|
query.bindValue( ":genre_id", request.genreId( ) );<BR>
|
||
|
|
query.bindValue( ":duration", request.duration( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataCreated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 31"> 31 </A>MoviesRepository::getAllMovies( QVector<MovieDTO> &movies ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT movie_id, title, genre_id, duration FROM movies" );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
movies.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 47"> 47 </A>RepositoryResult MoviesRepository::getMovieById( qint32 id, <BR>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 48"> 48 </A> MovieDTO &movie ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT movie_id, title, genre_id, duration FROM movies WHERE "<BR>
|
||
|
|
"movie_id = :id" );<BR>
|
||
|
|
query.bindValue( ":id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "Movie not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
movie = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 68"> 68 </A>MoviesRepository::updateMovie( const UpdateMovieRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "UPDATE movies SET title = :title, genre_id = :genre_id, "<BR>
|
||
|
|
"duration = :duration WHERE movie_id = :id" );<BR>
|
||
|
|
query.bindValue( ":duration", request.duration( ) );<BR>
|
||
|
|
query.bindValue( ":genre_id", request.genreId( ) );<BR>
|
||
|
|
query.bindValue( ":id", request.movieId( ) );<BR>
|
||
|
|
query.bindValue( ":title", request.title( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataUpdated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 85"> 85 </A>RepositoryResult MoviesRepository::deleteMovieById( qint32 movieId ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "DELETE FROM movies WHERE movie_id = :id" );<BR>
|
||
|
|
query.bindValue( ":id", movieId );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataDeleted( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/movies_repository.cpp: 98"> 98 </A>MovieDTO MoviesRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
MovieDTO movieDTO;<BR>
|
||
|
|
movieDTO.setDuration( query.value( "duration" ).toInt( ) );<BR>
|
||
|
|
movieDTO.setGenreId( query.value( "genre_id" ).toInt( ) );<BR>
|
||
|
|
movieDTO.setMovieId( query.value( "movie_id" ).toInt( ) );<BR>
|
||
|
|
movieDTO.setTitle( query.value( "title" ).toString( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return movieDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/refunds_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 1"> 1 </A>#include "refunds_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_refund_request.h"<BR>
|
||
|
|
#include "refund_dto.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "update_refund_request.h"<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 10"> 10 </A>RefundsRepository::RefundsRepository( QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 14"> 14 </A>RefundsRepository::createRefund( const CreateRefundRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "INSERT INTO refunds ( ticket_id, refund_at, refund_amount ) "<BR>
|
||
|
|
"VALUES ( :ticket_id, :refund_at, :refund_amount )" );<BR>
|
||
|
|
query.bindValue( ":ticket_id", request.ticketId( ) );<BR>
|
||
|
|
query.bindValue( ":refund_at", request.refundAt( ) );<BR>
|
||
|
|
query.bindValue( ":refund_amount", request.refundAmount( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataCreated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 30"> 30 </A>RepositoryResult RefundsRepository::getRefundById( qint32 id, <BR>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 31"> 31 </A> RefundDTO &refund ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT refund_id, ticket_id, refund_at, refund_amount FROM "<BR>
|
||
|
|
"refunds WHERE refund_id = :id" );<BR>
|
||
|
|
query.bindValue( ":id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "Refund not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RefundDTO refundDTO;<BR>
|
||
|
|
refundDTO.setRefundAmount( query.value( "refund_amount" ).toDouble( ) );<BR>
|
||
|
|
refundDTO.setRefundAt( query.value( "refund_at" ).toDateTime( ) );<BR>
|
||
|
|
refundDTO.setRefundId( query.value( "refund_id" ).toInt( ) );<BR>
|
||
|
|
refundDTO.setTicketId( query.value( "ticket_id" ).toInt( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
refund = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 57"> 57 </A>RefundsRepository::getAllRefunds( QVector<RefundDTO> &refunds ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"SELECT refund_id, ticket_id, refund_at, refund_amount FROM refunds" );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
refunds.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 75"> 75 </A>RefundsRepository::updateRefund( const UpdateRefundRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"UPDATE refunds SET ticket_id = :ticket_id, refund_at = :refund_at, "<BR>
|
||
|
|
"refund_amount = :refund_amount WHERE refund_id = :refund_id" );<BR>
|
||
|
|
query.bindValue( ":refund_amount", request.refundAmount( ) );<BR>
|
||
|
|
query.bindValue( ":refund_at", request.refundAt( ) );<BR>
|
||
|
|
query.bindValue( ":refund_id", request.refundId( ) );<BR>
|
||
|
|
query.bindValue( ":ticket_id", request.ticketId( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataUpdated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 93"> 93 </A>RepositoryResult RefundsRepository::deleteRefundById( qint32 refundId ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "DELETE FROM refunds WHERE refund_id = :refund_id" );<BR>
|
||
|
|
query.bindValue( ":refund_id", refundId );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataDeleted( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/refunds_repository.cpp: 106"> 106 </A>RefundDTO RefundsRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
RefundDTO refundDTO;<BR>
|
||
|
|
refundDTO.setRefundAmount( query.value( "refund_amount" ).toDouble( ) );<BR>
|
||
|
|
refundDTO.setRefundAt( query.value( "refund_at" ).toDateTime( ) );<BR>
|
||
|
|
refundDTO.setRefundId( query.value( "refund_id" ).toInt( ) );<BR>
|
||
|
|
refundDTO.setTicketId( query.value( "ticket_id" ).toInt( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return refundDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/roles_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/roles_repository.cpp: 1"> 1 </A>#include "roles_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_role_request.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "role_dto.h"<BR>
|
||
|
|
#include "update_role_request.h"<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/roles_repository.cpp: 10"> 10 </A>RolesRepository::RolesRepository( QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/roles_repository.cpp: 13"> 13 </A>RepositoryResult RolesRepository::createRole( const CreateRoleRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "INSERT INTO roles ( role_name, access_level ) VALUES "<BR>
|
||
|
|
"( :role_name, :access_level )" );<BR>
|
||
|
|
query.bindValue( ":role_name", request.roleName( ) );<BR>
|
||
|
|
query.bindValue( ":access_level", request.accessLevel( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataCreated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/roles_repository.cpp: 28"> 28 </A>RepositoryResult RolesRepository::getRoleById( qint32 id, RoleDTO &role ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT role_id, role_name, access_level FROM roles WHERE "<BR>
|
||
|
|
"role_id = :role_id" );<BR>
|
||
|
|
query.bindValue( ":role_id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "Role not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
role = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/roles_repository.cpp: 47"> 47 </A>RepositoryResult RolesRepository::getAllRoles( QVector<RoleDTO> &roles ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT role_id, role_name, access_level FROM roles" );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
roles.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/roles_repository.cpp: 63"> 63 </A>RepositoryResult RolesRepository::updateRole( const UpdateRoleRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"UPDATE roles SET role_name = :role_name WHERE role_id = :role_id" );<BR>
|
||
|
|
query.bindValue( ":role_name", request.roleName( ) );<BR>
|
||
|
|
query.bindValue( ":role_id", request.roleId( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataUpdated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/roles_repository.cpp: 78"> 78 </A>RepositoryResult RolesRepository::deleteRoleById( qint32 roleId ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "DELETE FROM roles WHERE role_id = :role_id" );<BR>
|
||
|
|
query.bindValue( ":role_id", roleId );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataDeleted( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/roles_repository.cpp: 91"> 91 </A>RoleDTO RolesRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
RoleDTO roleDTO;<BR>
|
||
|
|
roleDTO.setAccessLevel( query.value( "access_level" ).toInt( ) );<BR>
|
||
|
|
roleDTO.setRoleId( query.value( "role_id" ).toInt( ) );<BR>
|
||
|
|
roleDTO.setRoleName( query.value( "role_name" ).toString( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return roleDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/sessions_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 1"> 1 </A>#include "sessions_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_session_request.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "session_dto.h"<BR>
|
||
|
|
#include "update_session_request.h"<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 10"> 10 </A>SessionsRepository::SessionsRepository( QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 14"> 14 </A>SessionsRepository::createSession( const CreateSessionRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"INSERT INTO sessions ( movie_id, hall_id, begin_at, ticket_price ) VALUES "<BR>
|
||
|
|
"( :movie_id, :hall_id, :begin_at, :ticket_price )" );<BR>
|
||
|
|
query.bindValue( ":begin_at", request.beginAt( ) );<BR>
|
||
|
|
query.bindValue( ":hall_id", request.hallId( ) );<BR>
|
||
|
|
query.bindValue( ":movie_id", request.movieId( ) );<BR>
|
||
|
|
query.bindValue( ":ticket_price", request.ticketPrice( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataCreated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 32"> 32 </A>RepositoryResult SessionsRepository::getSessionById( qint32 id, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 33"> 33 </A> SessionDTO &session ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT session_id, movie_id, hall_id, begin_at, ticket_price "<BR>
|
||
|
|
"FROM sessions WHERE session_id = :id" );<BR>
|
||
|
|
query.bindValue( ":id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "Session not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
session = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 53"> 53 </A>SessionsRepository::getAllSessions( QVector<SessionDTO> &sessions ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT session_id, movie_id, hall_id, begin_at, ticket_price "<BR>
|
||
|
|
"FROM sessions" );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
sessions.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 71"> 71 </A>SessionsRepository::updateSession( const UpdateSessionRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "UPDATE sessions SET movie_id = :movie_id, hall_id = :hall_id, "<BR>
|
||
|
|
"begin_at = :begin_at, ticket_price = :ticket_price WHERE "<BR>
|
||
|
|
"session_id = :session_id" );<BR>
|
||
|
|
query.bindValue( ":begin_at", request.beginAt( ) );<BR>
|
||
|
|
query.bindValue( ":hall_id", request.hallId( ) );<BR>
|
||
|
|
query.bindValue( ":movie_id", request.movieId( ) );<BR>
|
||
|
|
query.bindValue( ":session_id", request.sessionId( ) );<BR>
|
||
|
|
query.bindValue( ":ticket_price", request.ticketPrice( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataUpdated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 90"> 90 </A>RepositoryResult SessionsRepository::deleteSessionById( qint32 sessionId ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "DELETE FROM sessions WHERE session_id = :session_id" );<BR>
|
||
|
|
query.bindValue( ":session_id", sessionId );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataDeleted( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_repository.cpp: 103"> 103 </A>SessionDTO SessionsRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
SessionDTO sessionDTO;<BR>
|
||
|
|
sessionDTO.setBeginAt( query.value( "begin_at" ).toDateTime( ) );<BR>
|
||
|
|
sessionDTO.setHallId( query.value( "hall_id" ).toInt( ) );<BR>
|
||
|
|
sessionDTO.setMovieId( query.value( "movie_id" ).toInt( ) );<BR>
|
||
|
|
sessionDTO.setSessionId( query.value( "session_id" ).toInt( ) );<BR>
|
||
|
|
sessionDTO.setTicketPrice( query.value( "ticket_price" ).toDouble( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return sessionDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/sessions_statistics_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 1"> 1 </A>#include "sessions_statistics_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "session_statistics_dto.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
#include <QVariant><BR>
|
||
|
|
#include <QVector><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 11"> 11 </A>SessionsStatisticsRepository::SessionsStatisticsRepository( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 12"> 12 </A> QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
SessionStatisticsDTO<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 16"> 16 </A>SessionsStatisticsRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
SessionStatisticsDTO sessionStatisticsDTO;<BR>
|
||
|
|
<BR>
|
||
|
|
// clang-format off<BR>
|
||
|
|
sessionStatisticsDTO.setSessionId( query.value( "session_id" ).toInt( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setBeginAt( query.value( "begin_at" ).toDateTime( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setTicketPrice( query.value( "ticket_price" ).toDouble( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setHallId( query.value( "hall_id" ).toInt( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setHallName( query.value( "hall_name" ).toString( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setTotalSeats( query.value( "total_seats" ).toInt( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setMovieId( query.value( "movie_id" ).toInt( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setMovieTitle( query.value( "movie_title" ).toString( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setDuration( query.value( "duration" ).toInt( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setGenreId( query.value( "genre_id" ).toInt( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setGenreName( query.value( "genre_name" ).toString( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setSoldTickets( query.value( "sold_tickets" ).toInt( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setRefundedTickets( query.value( "refunded_tickets" ).toInt( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setSalesRevenue( query.value( "sales_revenue" ).toDouble( ) );<BR>
|
||
|
|
sessionStatisticsDTO.setRefundExpenses( query.value( "refund_expenses" ).toDouble( ) );<BR>
|
||
|
|
// clang-format on<BR>
|
||
|
|
<BR>
|
||
|
|
return sessionStatisticsDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 40"> 40 </A>RepositoryResult SessionsStatisticsRepository::executeAndMapQuery( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 41"> 41 </A> QSqlQuery &query, QVector<SessionStatisticsDTO> &sessions ) const {<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Executing query:" << query.executedQuery( )<BR>
|
||
|
|
<< " with values:" << query.boundValues( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
sessions.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 58"> 58 </A>RepositoryResult SessionsStatisticsRepository::getSessionById( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 59"> 59 </A> qint32 id, SessionStatisticsDTO &sessionStatisticsDTO ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( QString( "%1 WHERE session_id = :id" ).arg( SELECT_QUERY ) );<BR>
|
||
|
|
query.bindValue( ":id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "Session not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
sessionStatisticsDTO = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 77"> 77 </A>RepositoryResult SessionsStatisticsRepository::getAllSessions( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 78"> 78 </A> QVector<SessionStatisticsDTO> &sessions ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( SELECT_QUERY );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
sessions.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 94"> 94 </A>RepositoryResult SessionsStatisticsRepository::getSessionsForHall( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 95"> 95 </A> qint32 hallId, std::optional<QDateTime> startDate, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 96"> 96 </A> std::optional<QDateTime> endDate, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 97"> 97 </A> QVector<SessionStatisticsDTO> &sessions ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
QString queryString =<BR>
|
||
|
|
QString( "%1 WHERE hall_id = :hall_id" ).arg( SELECT_QUERY );<BR>
|
||
|
|
<BR>
|
||
|
|
bindDateFilters( queryString, startDate, endDate );<BR>
|
||
|
|
<BR>
|
||
|
|
query.prepare( queryString );<BR>
|
||
|
|
query.bindValue( ":hall_id", hallId );<BR>
|
||
|
|
<BR>
|
||
|
|
bindDateValues( query, startDate, endDate );<BR>
|
||
|
|
<BR>
|
||
|
|
return executeAndMapQuery( query, sessions );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 112"> 112 </A>RepositoryResult SessionsStatisticsRepository::getSessionsForMovie( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 113"> 113 </A> qint32 movieId, std::optional<QDateTime> startDate, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 114"> 114 </A> std::optional<QDateTime> endDate, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 115"> 115 </A> QVector<SessionStatisticsDTO> &sessions ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
QString queryString =<BR>
|
||
|
|
QString( "%1 WHERE movie_id = :movie_id" ).arg( SELECT_QUERY );<BR>
|
||
|
|
<BR>
|
||
|
|
bindDateFilters( queryString, startDate, endDate );<BR>
|
||
|
|
<BR>
|
||
|
|
query.prepare( queryString );<BR>
|
||
|
|
query.bindValue( ":movie_id", movieId );<BR>
|
||
|
|
<BR>
|
||
|
|
bindDateValues( query, startDate, endDate );<BR>
|
||
|
|
<BR>
|
||
|
|
return executeAndMapQuery( query, sessions );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 130"> 130 </A>RepositoryResult SessionsStatisticsRepository::getSessionsForGenre( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 131"> 131 </A> qint32 genreId, std::optional<QDateTime> startDate, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 132"> 132 </A> std::optional<QDateTime> endDate, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 133"> 133 </A> QVector<SessionStatisticsDTO> &sessions ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
QString queryString =<BR>
|
||
|
|
QString( "%1 WHERE genre_id = :genre_id" ).arg( SELECT_QUERY );<BR>
|
||
|
|
<BR>
|
||
|
|
bindDateFilters( queryString, startDate, endDate );<BR>
|
||
|
|
<BR>
|
||
|
|
query.prepare( queryString );<BR>
|
||
|
|
query.bindValue( ":genre_id", genreId );<BR>
|
||
|
|
<BR>
|
||
|
|
bindDateValues( query, startDate, endDate );<BR>
|
||
|
|
<BR>
|
||
|
|
return executeAndMapQuery( query, sessions );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 148"> 148 </A>void SessionsStatisticsRepository::bindDateFilters( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 149"> 149 </A> QString &queryString, const std::optional<QDateTime> &startDate, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 150"> 150 </A> const std::optional<QDateTime> &endDate ) const {<BR>
|
||
|
|
if ( startDate && endDate ) {<BR>
|
||
|
|
queryString += " AND begin_at BETWEEN :start_date AND :end_date";<BR>
|
||
|
|
} else if ( startDate ) {<BR>
|
||
|
|
queryString += " AND begin_at >= :start_date";<BR>
|
||
|
|
} else if ( endDate ) {<BR>
|
||
|
|
queryString += " AND begin_at <= :end_date";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 160"> 160 </A>void SessionsStatisticsRepository::bindDateValues( <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 161"> 161 </A> QSqlQuery &query, const std::optional<QDateTime> &startDate, <BR>
|
||
|
|
<A NAME="./data/sql/sessions_statistics_repository.cpp: 162"> 162 </A> const std::optional<QDateTime> &endDate ) const {<BR>
|
||
|
|
if ( startDate ) {<BR>
|
||
|
|
query.bindValue( ":start_date", *startDate );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( endDate ) {<BR>
|
||
|
|
query.bindValue( ":end_date", *endDate );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/table_info_sqlite.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
#include "table_info_sqlite.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QDebug><BR>
|
||
|
|
#include <QMetaType><BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 7"> 7 </A>TableInfoSQLite::TableInfoSQLite( ) : databaseTableName_( "" ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 9"> 9 </A>TableInfoSQLite::TableInfoSQLite( const QString &databaseTableName )<BR>
|
||
|
|
: databaseTableName_( databaseTableName ) {<BR>
|
||
|
|
loadColumnInfo( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 14"> 14 </A>void TableInfoSQLite::loadColumnInfo( ) {<BR>
|
||
|
|
QSqlDatabase defaultDatabase = QSqlDatabase::database( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !defaultDatabase.isValid( ) ) {<BR>
|
||
|
|
qCritical( ) << "TableInfoSQLite::loadColumnInfo: Database is invalid";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !defaultDatabase.isOpen( ) ) {<BR>
|
||
|
|
qCritical( ) << "TableInfoSQLite::loadColumnInfo: Database is not open";<BR>
|
||
|
|
<BR>
|
||
|
|
databaseTableName_.clear( );<BR>
|
||
|
|
columnNames_.clear( );<BR>
|
||
|
|
columnTypes_.clear( );<BR>
|
||
|
|
isPrimaryKey_.clear( );<BR>
|
||
|
|
<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QSqlQuery query( defaultDatabase );<BR>
|
||
|
|
query.prepare( QString( "PRAGMA table_info( %1 )" ).arg( databaseTableName_ ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to get table info: Error:" << query.lastError( ).text( )<BR>
|
||
|
|
<< "Database table name:" << databaseTableName_;<BR>
|
||
|
|
<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
columnNames_.append( query.value( "name" ).toString( ) );<BR>
|
||
|
|
columnTypes_.append( query.value( "type" ).toString( ) );<BR>
|
||
|
|
isPrimaryKey_.append( query.value( "pk" ).toInt( ) > 0 );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 49"> 49 </A>QString TableInfoSQLite::databaseTableName( ) const noexcept {<BR>
|
||
|
|
return databaseTableName_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 54"> 54 </A>TableInfoSQLite::foreignKeyTable( const QString &columnName ) const noexcept {<BR>
|
||
|
|
if ( databaseTableName_.isEmpty( ) ) {<BR>
|
||
|
|
qWarning( ) << "TableInfoSQLite::foreignKeyTable: No table name set";<BR>
|
||
|
|
return QString( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QSqlDatabase defaultDatabase = QSqlDatabase::database( );<BR>
|
||
|
|
if ( !defaultDatabase.isOpen( ) ) {<BR>
|
||
|
|
qCritical( ) << "TableInfoSQLite::foreignKeyTable: Database is not open";<BR>
|
||
|
|
return QString( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QSqlQuery query( defaultDatabase );<BR>
|
||
|
|
query.prepare( QString( "PRAGMA foreign_key_list( %1 )" ).arg( databaseTableName_ ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
qWarning( ) << "Failed to get foreign key info:" << query.lastError( ).text( );<BR>
|
||
|
|
return QString( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
QString fkColumn = query.value( "from" ).toString( );<BR>
|
||
|
|
QString referencedTable = query.value( "table" ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( fkColumn == columnName ) {<BR>
|
||
|
|
return referencedTable;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return QString( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 86"> 86 </A>QStringList TableInfoSQLite::columnNames( ) const noexcept {<BR>
|
||
|
|
return QStringList( columnNames_.begin( ), columnNames_.end( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 90"> 90 </A>bool TableInfoSQLite::isPrimaryKey( const QString &columnName ) const noexcept {<BR>
|
||
|
|
int index = columnIndex( columnName );<BR>
|
||
|
|
if ( index == -1 ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
return isPrimaryKey_.at( index );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 98"> 98 </A>qint32 TableInfoSQLite::columnIndex( const QString &columnName ) const noexcept {<BR>
|
||
|
|
return columnNames_.indexOf( columnName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/table_info_sqlite.cpp: 102"> 102 </A>QString TableInfoSQLite::columnName( qint32 columnIndex ) const noexcept {<BR>
|
||
|
|
if ( columnIndex < 0 || columnIndex >= columnNames_.size( ) ) {<BR>
|
||
|
|
return QString( );<BR>
|
||
|
|
}<BR>
|
||
|
|
return columnNames_.at( columnIndex );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QMetaType::Type<BR>
|
||
|
|
TableInfoSQLite::columnMetaType( const QString &columnName ) const noexcept {<BR>
|
||
|
|
int index = columnIndex( columnName );<BR>
|
||
|
|
if ( index == -1 ) {<BR>
|
||
|
|
return QMetaType::UnknownType;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString typeName = columnTypes_.at( index ).toLower( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( typeName.contains( "int" ) ) {<BR>
|
||
|
|
return QMetaType::Int;<BR>
|
||
|
|
} else if ( typeName.contains( "double" ) || typeName.contains( "real" ) ||<BR>
|
||
|
|
typeName.contains( "float" ) ) {<BR>
|
||
|
|
return QMetaType::Double;<BR>
|
||
|
|
} else if ( typeName.contains( "date" ) || typeName.contains( "time" ) ) {<BR>
|
||
|
|
return QMetaType::QDateTime;<BR>
|
||
|
|
} else if ( typeName.contains( "bool" ) ) {<BR>
|
||
|
|
return QMetaType::Bool;<BR>
|
||
|
|
} else if ( typeName.contains( "blob" ) ) {<BR>
|
||
|
|
return QMetaType::QByteArray;<BR>
|
||
|
|
} else {<BR>
|
||
|
|
return QMetaType::QString;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void TableInfoSQLite::setDatabaseTableName( <BR>
|
||
|
|
const QString &databaseTableName ) noexcept {<BR>
|
||
|
|
databaseTableName_ = databaseTableName;<BR>
|
||
|
|
loadColumnInfo( );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/tickets_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 1"> 1 </A>#include "tickets_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_ticket_request.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "ticket_dto.h"<BR>
|
||
|
|
#include "update_ticket_request.h"<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 10"> 10 </A>TicketsRepository::TicketsRepository( QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 14"> 14 </A>TicketsRepository::createTicket( const CreateTicketRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "INSERT INTO tickets ( session_id, seat_number, sold_at ) VALUES "<BR>
|
||
|
|
"( :session_id, :seat_number, :sold_at )" );<BR>
|
||
|
|
query.bindValue( ":seat_number", request.seatNumber( ) );<BR>
|
||
|
|
query.bindValue( ":session_id", request.sessionId( ) );<BR>
|
||
|
|
query.bindValue( ":sold_at", request.soldAt( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataCreated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 30"> 30 </A>RepositoryResult TicketsRepository::getTicketById( qint32 id, <BR>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 31"> 31 </A> TicketDTO &ticket ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT ticket_id, session_id, seat_number, sold_at FROM "<BR>
|
||
|
|
"tickets WHERE ticket_id = :id" );<BR>
|
||
|
|
query.bindValue( ":id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "Ticket not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
ticket = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 51"> 51 </A>TicketsRepository::getAllTickets( QVector<TicketDTO> &tickets ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"SELECT ticket_id, session_id, seat_number, sold_at FROM tickets" );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
tickets.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 69"> 69 </A>TicketsRepository::updateTicket( const UpdateTicketRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"UPDATE tickets SET session_id = :session_id, seat_number = "<BR>
|
||
|
|
":seat_number, sold_at = :sold_at WHERE ticket_id = :ticket_id" );<BR>
|
||
|
|
query.bindValue( ":seat_number", request.seatNumber( ) );<BR>
|
||
|
|
query.bindValue( ":session_id", request.sessionId( ) );<BR>
|
||
|
|
query.bindValue( ":sold_at", request.soldAt( ) );<BR>
|
||
|
|
query.bindValue( ":ticket_id", request.ticketId( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataUpdated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 87"> 87 </A>RepositoryResult TicketsRepository::deleteTicketById( qint32 ticketId ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "DELETE FROM tickets WHERE ticket_id = :ticket_id" );<BR>
|
||
|
|
query.bindValue( ":ticket_id", ticketId );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataDeleted( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/tickets_repository.cpp: 100"> 100 </A>TicketDTO TicketsRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
TicketDTO ticketDTO;<BR>
|
||
|
|
ticketDTO.setSeatNumber( query.value( "seat_number" ).toInt( ) );<BR>
|
||
|
|
ticketDTO.setSessionId( query.value( "session_id" ).toInt( ) );<BR>
|
||
|
|
ticketDTO.setSoldAt( query.value( "sold_at" ).toDateTime( ) );<BR>
|
||
|
|
ticketDTO.setTicketId( query.value( "ticket_id" ).toInt( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return ticketDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./data/sql/users_repository.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 1"> 1 </A>#include "users_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_user_request.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "update_user_request.h"<BR>
|
||
|
|
#include "user_dto.h"<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 10"> 10 </A>UsersRepository::UsersRepository( QSqlDatabase &database, QObject *parent )<BR>
|
||
|
|
: BaseSqlTableRepository( database, parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 13"> 13 </A>RepositoryResult UsersRepository::createUser( const CreateUserRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "INSERT INTO users ( username, password_hash, salt, role_id ) "<BR>
|
||
|
|
"VALUES ( :username, :password_hash, :salt, :role_id )" );<BR>
|
||
|
|
query.bindValue( ":password_hash", request.passwordHash( ) );<BR>
|
||
|
|
query.bindValue( ":role_id", request.roleId( ) );<BR>
|
||
|
|
query.bindValue( ":salt", request.salt( ) );<BR>
|
||
|
|
query.bindValue( ":username", request.username( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataCreated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 30"> 30 </A>RepositoryResult UsersRepository::getUserById( qint32 id, UserDTO &user ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT user_id, username, password_hash, salt, role_id FROM "<BR>
|
||
|
|
"users WHERE "<BR>
|
||
|
|
"user_id = :user_id" );<BR>
|
||
|
|
query.bindValue( ":user_id", id );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "User not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
user = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 50"> 50 </A>RepositoryResult UsersRepository::getUserByUsername( const QString &username, <BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 51"> 51 </A> UserDTO &user ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "SELECT user_id, username, password_hash, salt, role_id FROM "<BR>
|
||
|
|
"users WHERE "<BR>
|
||
|
|
"username = :username" );<BR>
|
||
|
|
query.bindValue( ":username", username );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !query.next( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( "User not found" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
user = mapQueryToDTO( query );<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 71"> 71 </A>RepositoryResult UsersRepository::getAllUsers( QVector<UserDTO> &users ) const {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( <BR>
|
||
|
|
"SELECT user_id, username, password_hash, salt, role_id FROM users" );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
users.append( mapQueryToDTO( query ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataRetrieved( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 88"> 88 </A>RepositoryResult UsersRepository::updateUser( const UpdateUserRequest &request ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "UPDATE users SET username = :username, password_hash = "<BR>
|
||
|
|
":password_hash, "<BR>
|
||
|
|
"salt = :salt, role_id = :role_id WHERE user_id = :user_id" );<BR>
|
||
|
|
<BR>
|
||
|
|
query.bindValue( ":username", request.username( ) );<BR>
|
||
|
|
query.bindValue( ":password_hash", request.passwordHash( ) );<BR>
|
||
|
|
query.bindValue( ":salt", request.salt( ) );<BR>
|
||
|
|
query.bindValue( ":role_id", request.roleId( ) );<BR>
|
||
|
|
query.bindValue( ":user_id", request.userId( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataUpdated( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 108"> 108 </A>RepositoryResult UsersRepository::deleteUserById( qint32 userId ) {<BR>
|
||
|
|
QSqlQuery query = foreignKeysOnQuery( );<BR>
|
||
|
|
query.prepare( "DELETE FROM users WHERE user_id = :user_id" );<BR>
|
||
|
|
query.bindValue( ":user_id", userId );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !query.exec( ) ) {<BR>
|
||
|
|
return RepositoryResult::failureResult( query.lastError( ).text( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
emit dataDeleted( );<BR>
|
||
|
|
return RepositoryResult::successResult( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./data/sql/users_repository.cpp: 121"> 121 </A>UserDTO UsersRepository::mapQueryToDTO( const QSqlQuery &query ) const {<BR>
|
||
|
|
UserDTO userDTO;<BR>
|
||
|
|
userDTO.setPasswordHash( query.value( "password_hash" ).toString( ) );<BR>
|
||
|
|
userDTO.setRoleId( query.value( "role_id" ).toInt( ) );<BR>
|
||
|
|
userDTO.setSalt( query.value( "salt" ).toString( ) );<BR>
|
||
|
|
userDTO.setUserId( query.value( "user_id" ).toInt( ) );<BR>
|
||
|
|
userDTO.setUsername( query.value( "username" ).toString( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return userDTO;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./src/main.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./src/main.cpp: 1"> 1 </A>#include "application_connector.h"<BR>
|
||
|
|
#include "application_controller.h"<BR>
|
||
|
|
#include "main_window.h"<BR>
|
||
|
|
#include <QApplication><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./src/main.cpp: 6"> 6 </A>int main( int argc, char *argv[] ) {<BR>
|
||
|
|
QApplication app( argc, argv );<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationController controller;<BR>
|
||
|
|
if ( !controller.setupApplication( ) ) {<BR>
|
||
|
|
return -1;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// MainWindow mainWindow( controller.userId( ), controller.accessLevel( ) );<BR>
|
||
|
|
MainWindow mainWindow( 1, 100 );<BR>
|
||
|
|
<BR>
|
||
|
|
ApplicationConnector connector( &mainWindow );<BR>
|
||
|
|
if ( !connector.connect( ) ) {<BR>
|
||
|
|
return -1;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
mainWindow.show( );<BR>
|
||
|
|
<BR>
|
||
|
|
return app.exec( );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_class/day_manager_test.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 1"> 1 </A>#include "day_manager.h"<BR>
|
||
|
|
#include <QtTest><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 4"> 4 </A>class DayManagerTest : public QObject {<BR>
|
||
|
|
Q_OBJECT<BR>
|
||
|
|
<BR>
|
||
|
|
private slots:<BR>
|
||
|
|
void testAddAvailableSlot( );<BR>
|
||
|
|
void testDuration( );<BR>
|
||
|
|
void testReserveFailure( );<BR>
|
||
|
|
void testReserveImplMaximal( );<BR>
|
||
|
|
void testReserveImplMinimal( );<BR>
|
||
|
|
void testReserveImplQuick( );<BR>
|
||
|
|
void testReserveImplRandom( );<BR>
|
||
|
|
void testReserveSuccess( );<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 18"> 18 </A>void DayManagerTest::testAddAvailableSlot( ) {<BR>
|
||
|
|
DayManager manager( QTime( 9, 0 ), QTime( 12, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QCOMPARE( manager.minDurationMs_, 0 );<BR>
|
||
|
|
QVERIFY( !manager.availableSlots_.isEmpty( ) );<BR>
|
||
|
|
QCOMPARE( manager.availableSlots_.size( ), 1 );<BR>
|
||
|
|
QCOMPARE( manager.availableSlots_.value( QTime( 9, 0 ) ), QTime( 12, 0 ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 27"> 27 </A>void DayManagerTest::testDuration( ) {<BR>
|
||
|
|
DayManager manager( QTime( 9, 0 ), QTime( 12, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QCOMPARE( manager.duration( QTime( 10, 0 ) ), {} ); // Print warning<BR>
|
||
|
|
QCOMPARE( manager.duration( QTime( 9, 0 ) ), QTime( 3, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
manager.addAvailableSlot( QTime( 12, 0 ), QTime( 13, 0 ) );<BR>
|
||
|
|
QCOMPARE( manager.duration( QTime( 12, 0 ) ), QTime( 1, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QCOMPARE( manager.duration( ), QTime( 4, 0 ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 39"> 39 </A>void DayManagerTest::testReserveImplQuick( ) {<BR>
|
||
|
|
DayManager manager( QTime( 9, 0 ), QTime( 12, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
for ( int i = 0; i < 3; ++i ) {<BR>
|
||
|
|
QCOMPARE( manager.slotCount( ), 1 );<BR>
|
||
|
|
QTime availableHourCount = manager.duration( QTime( 9 + i, 0 ) );<BR>
|
||
|
|
QCOMPARE( manager.duration( QTime( 9 + i, 0 ) ), QTime( 3 - i, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto [begin, end] =<BR>
|
||
|
|
manager.reserveImplQuick( QTime( 1, 0 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( end.isValid( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QCOMPARE( manager.slotCount( ), 0 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 56"> 56 </A>void DayManagerTest::testReserveImplMaximal( ) {<BR>
|
||
|
|
DayManager manager;<BR>
|
||
|
|
<BR>
|
||
|
|
manager.addAvailableSlot( QTime( 9, 0 ), QTime( 12, 0 ) ); // 3 hour; first, second<BR>
|
||
|
|
manager.addAvailableSlot( QTime( 8, 0 ), QTime( 9, 0 ) ); // 1 hour<BR>
|
||
|
|
manager.addAvailableSlot( QTime( 12, 0 ), QTime( 14, 0 ) ); // 2 hour; third<BR>
|
||
|
|
<BR>
|
||
|
|
auto [begin1, end1] =<BR>
|
||
|
|
manager.reserveImplMaximal( QTime( 1, 0 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( begin1.isValid( ) );<BR>
|
||
|
|
QVERIFY( end1.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin1, QTime( 9, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto [begin2, end2] =<BR>
|
||
|
|
manager.reserveImplMaximal( QTime( 1, 0 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( begin2.isValid( ) );<BR>
|
||
|
|
QVERIFY( end2.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin2, QTime( 10, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto [begin3, end3] =<BR>
|
||
|
|
manager.reserveImplMaximal( QTime( 1, 0 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( begin3.isValid( ) );<BR>
|
||
|
|
QVERIFY( end3.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin3, QTime( 12, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QCOMPARE( manager.slotCount( ), 3 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 84"> 84 </A>void DayManagerTest::testReserveImplMinimal( ) {<BR>
|
||
|
|
DayManager manager;<BR>
|
||
|
|
<BR>
|
||
|
|
manager.addAvailableSlot( QTime( 9, 0 ), QTime( 12, 0 ) ); // 3 hour<BR>
|
||
|
|
manager.addAvailableSlot( QTime( 8, 0 ), QTime( 9, 0 ) ); // 1 hour; first<BR>
|
||
|
|
manager.addAvailableSlot( QTime( 12, 0 ), QTime( 14, 0 ) ); // 2 hour; second, third<BR>
|
||
|
|
<BR>
|
||
|
|
auto [begin1, end1] =<BR>
|
||
|
|
manager.reserveImplMinimal( QTime( 1, 0 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( begin1.isValid( ) );<BR>
|
||
|
|
QVERIFY( end1.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin1, QTime( 8, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto [begin2, end2] =<BR>
|
||
|
|
manager.reserveImplMinimal( QTime( 1, 0 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( begin2.isValid( ) );<BR>
|
||
|
|
QVERIFY( end2.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin2, QTime( 12, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto [begin3, end3] =<BR>
|
||
|
|
manager.reserveImplMinimal( QTime( 1, 0 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( begin3.isValid( ) );<BR>
|
||
|
|
QVERIFY( end3.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin3, QTime( 13, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QCOMPARE( manager.slotCount( ), 1 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 112"> 112 </A>void DayManagerTest::testReserveImplRandom( ) {<BR>
|
||
|
|
DayManager manager( QTime( 9, 0 ), QTime( 12, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
for ( int i = 0; i < 3; ++i ) {<BR>
|
||
|
|
QCOMPARE( manager.slotCount( ), 1 );<BR>
|
||
|
|
auto [begin, end] =<BR>
|
||
|
|
manager.reserveImplRandom( QTime( 1, 0 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( end.isValid( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QCOMPARE( manager.slotCount( ), 0 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 126"> 126 </A>void DayManagerTest::testReserveSuccess( ) {<BR>
|
||
|
|
DayManager manager( QTime( 9, 0 ), QTime( 12, 0 ) );<BR>
|
||
|
|
manager.setMinDuration( QTime( 0, 30 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto [begin, end] = manager.reserve( QTime( 1, 0 ) );<BR>
|
||
|
|
QVERIFY( begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( end.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin.hour( ), 9 );<BR>
|
||
|
|
QCOMPARE( end.hour( ), 10 );<BR>
|
||
|
|
QCOMPARE( end.minute( ), 0 );<BR>
|
||
|
|
<BR>
|
||
|
|
std::tie( begin, end ) = manager.reserve( QTime( 1, 30 ) );<BR>
|
||
|
|
QVERIFY( begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( end.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin.hour( ), 10 );<BR>
|
||
|
|
QCOMPARE( end.hour( ), 11 );<BR>
|
||
|
|
QCOMPARE( end.minute( ), 30 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 145"> 145 </A>void DayManagerTest::testReserveFailure( ) {<BR>
|
||
|
|
DayManager manager( QTime( 9, 0 ), QTime( 12, 0 ) );<BR>
|
||
|
|
manager.setMinDuration( QTime( 0, 30 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QCOMPARE( manager.duration( QTime( 9, 0 ) ), QTime( 3, 0 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QTime begin, end;<BR>
|
||
|
|
<BR>
|
||
|
|
std::tie( begin, end ) = manager.reserve( QTime( 4, 0 ) );<BR>
|
||
|
|
QVERIFY( !begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( !end.isValid( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
std::tie( begin, end ) = manager.reserve( QTime( 3, 0, 1 ) );<BR>
|
||
|
|
QVERIFY( !begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( !end.isValid( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
std::tie( begin, end ) = manager.reserve( QTime( 2, 30 ) );<BR>
|
||
|
|
QVERIFY( begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( end.isValid( ) );<BR>
|
||
|
|
QVERIFY( !manager.availableSlots_.isEmpty( ) );<BR>
|
||
|
|
QCOMPARE( manager.duration( end ), QTime( 0, 30 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
std::tie( begin, end ) = manager.reserve( QTime( 0, 0, 1 ) );<BR>
|
||
|
|
QVERIFY( begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( end.isValid( ) );<BR>
|
||
|
|
QCOMPARE( begin.msecsTo( end ), QTime( 0, 0, 1 ).msecsSinceStartOfDay( ) );<BR>
|
||
|
|
QVERIFY( manager.availableSlots_.isEmpty( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/day_manager_test.cpp: 174"> 174 </A>QTEST_MAIN( DayManagerTest )<BR>
|
||
|
|
#include "day_manager_test.moc"<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_class/reservation_manager_test.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./tests_class/reservation_manager_test.cpp: 1"> 1 </A>#include "reservation_manager.h"<BR>
|
||
|
|
#include <QtTest><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/reservation_manager_test.cpp: 4"> 4 </A>class ReservationManagerTest : public QObject {<BR>
|
||
|
|
Q_OBJECT<BR>
|
||
|
|
<BR>
|
||
|
|
private slots:<BR>
|
||
|
|
void testReserveFailure( );<BR>
|
||
|
|
void testReserveSuccess( );<BR>
|
||
|
|
void testReserveBound( );<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/reservation_manager_test.cpp: 13"> 13 </A>void ReservationManagerTest::testReserveFailure( ) {<BR>
|
||
|
|
DayManager dayManager( QTime( 8, 0 ), QTime( 9, 0 ) );<BR>
|
||
|
|
ReservationManager manager( 3, 3, dayManager );<BR>
|
||
|
|
<BR>
|
||
|
|
QDateTime begin;<BR>
|
||
|
|
QTime end;<BR>
|
||
|
|
<BR>
|
||
|
|
std::tie( begin, end ) = manager.reserve( QTime( 2, 0 ) );<BR>
|
||
|
|
QVERIFY( !begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( !end.isValid( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/reservation_manager_test.cpp: 25"> 25 </A>void ReservationManagerTest::testReserveSuccess( ) {<BR>
|
||
|
|
DayManager dayManager( QTime( 8, 0 ), QTime( 9, 0 ) );<BR>
|
||
|
|
ReservationManager manager( 3, 4, dayManager );<BR>
|
||
|
|
<BR>
|
||
|
|
QDateTime begin;<BR>
|
||
|
|
QTime end;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( int i = 0; i < 3; ++i ) {<BR>
|
||
|
|
std::tie( begin, end ) = manager.reserve( QTime( 1, 0 ) );<BR>
|
||
|
|
QVERIFY( begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( end.isValid( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
QCOMPARE( manager.days_.size( ), 1 );<BR>
|
||
|
|
<BR>
|
||
|
|
const auto &keys = manager.days_.keys( );<BR>
|
||
|
|
auto it = std::find_if( keys.cbegin( ), keys.cend( ), []( const auto &key ) {<BR>
|
||
|
|
for ( auto expected : {1, 2, 3, 4} ) {<BR>
|
||
|
|
if ( key == expected ) {<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return false;<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
QVERIFY( it != keys.cend( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/reservation_manager_test.cpp: 52"> 52 </A>void ReservationManagerTest::testReserveBound( ) {<BR>
|
||
|
|
DayManager dayManager( QTime( 8, 0 ), QTime( 9, 0 ) );<BR>
|
||
|
|
ReservationManager manager( 3, 4, dayManager );<BR>
|
||
|
|
<BR>
|
||
|
|
QDateTime begin;<BR>
|
||
|
|
QTime end;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( int i = 0; i < 4; ++i ) {<BR>
|
||
|
|
std::tie( begin, end ) = manager.reserve( QTime( 1, 0 ) );<BR>
|
||
|
|
QVERIFY( begin.isValid( ) );<BR>
|
||
|
|
QVERIFY( end.isValid( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
QVERIFY( manager.days_.isEmpty( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_class/reservation_manager_test.cpp: 67"> 67 </A>QTEST_MAIN( ReservationManagerTest )<BR>
|
||
|
|
#include "reservation_manager_test.moc"<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_schema/tests/main_test.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./tests_schema/tests/main_test.cpp: 1"> 1 </A>#include <gtest/gtest.h><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_schema/tests/main_test.cpp: 3"> 3 </A>int main( int argc, char **argv ) {<BR>
|
||
|
|
::testing::InitGoogleTest( &argc, argv );<BR>
|
||
|
|
return RUN_ALL_TESTS( );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_schema/tests/sqlite_database_crud_test.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
#include "sqlite_database.h"<BR>
|
||
|
|
#include "sqlite_file_executor.h"<BR>
|
||
|
|
#include "gtest/gtest.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// WARNING: Foreign keys are off<BR>
|
||
|
|
// WARNING: Triggers are off<BR>
|
||
|
|
<BR>
|
||
|
|
const std::string TEST_DB = "test.db";<BR>
|
||
|
|
<BR>
|
||
|
|
// Test fixture for SQLiteDatabase<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_crud_test.cpp: 11"> 11 </A>class SQLiteDatabaseCRUDTest : public ::testing::Test {<BR>
|
||
|
|
protected:<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_crud_test.cpp: 13"> 13 </A> SQLiteDatabase *db_;<BR>
|
||
|
|
<BR>
|
||
|
|
void SetUp( ) override {<BR>
|
||
|
|
db_ = new SQLiteDatabase( TEST_DB );<BR>
|
||
|
|
SQLiteFileExecutor executor( TEST_DB );<BR>
|
||
|
|
executor.executeSQLFile( "sql/cinema_db_drop_table.sql" );<BR>
|
||
|
|
executor.executeSQLFile( "sql/cinema_db_create_table.sql" );<BR>
|
||
|
|
<BR>
|
||
|
|
// Not necessarily, since the default setting<BR>
|
||
|
|
std::string sql;<BR>
|
||
|
|
FileReaderInterface *reader = &executor;<BR>
|
||
|
|
reader->read( "sql/cinema_db_foreign_key_off.sql", sql );<BR>
|
||
|
|
db_->executeNonQuery( sql );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void TearDown( ) override {<BR>
|
||
|
|
delete db_;<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_crud_test.cpp: 30"> 30 </A> remove( TEST_DB.c_str( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- GENERAL -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Check that the test fixture is working<BR>
|
||
|
|
class SimpleClass : public ::testing::Test {<BR>
|
||
|
|
protected:<BR>
|
||
|
|
void SetUp( ) override {}<BR>
|
||
|
|
void TearDown( ) override {}<BR>
|
||
|
|
};<BR>
|
||
|
|
// Simle test<BR>
|
||
|
|
TEST_F( SimpleClass, SimpleTest ) { EXPECT_EQ( 1, 1 ); }<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- GENERAL -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Test checking if the database is available<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, IsDatabaseAvailable ) {<BR>
|
||
|
|
EXPECT_TRUE( db_->isDatabaseAvailable( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- GENRE -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Test adding a genre<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, AddGenre ) {<BR>
|
||
|
|
NewGenre genre{"Action"};<BR>
|
||
|
|
EXPECT_TRUE( db_->addGenre( genre ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto genres = db_->getAllGenres( );<BR>
|
||
|
|
ASSERT_EQ( genres.size( ), 1 );<BR>
|
||
|
|
EXPECT_EQ( genres[0].genre_name, "Action" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting a genre by ID<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetGenreById ) {<BR>
|
||
|
|
NewGenre genre{"Drama"};<BR>
|
||
|
|
db_->addGenre( genre );<BR>
|
||
|
|
<BR>
|
||
|
|
Genre retrieved_genre = db_->getGenre( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_genre.genre_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_genre.genre_name, "Drama" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test updating a genre<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, UpdateGenre ) {<BR>
|
||
|
|
NewGenre genre{"Drama"};<BR>
|
||
|
|
db_->addGenre( genre );<BR>
|
||
|
|
<BR>
|
||
|
|
Genre updated_genre = db_->getGenre( 1 );<BR>
|
||
|
|
updated_genre.genre_name = "Horror";<BR>
|
||
|
|
EXPECT_TRUE( db_->updateGenre( updated_genre ) );<BR>
|
||
|
|
<BR>
|
||
|
|
Genre retrieved_genre = db_->getGenre( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_genre.genre_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_genre.genre_name, "Horror" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test removing a genre<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, RemoveGenre ) {<BR>
|
||
|
|
NewGenre genre{"Horror"};<BR>
|
||
|
|
db_->addGenre( genre );<BR>
|
||
|
|
EXPECT_TRUE( db_->removeGenre( 1 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto genres = db_->getAllGenres( );<BR>
|
||
|
|
EXPECT_TRUE( genres.empty( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting all genres<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetAllGenres ) {<BR>
|
||
|
|
db_->addGenre( {"Comedy"} );<BR>
|
||
|
|
db_->addGenre( {"Thriller"} );<BR>
|
||
|
|
<BR>
|
||
|
|
auto genres = db_->getAllGenres( );<BR>
|
||
|
|
ASSERT_EQ( genres.size( ), 2 );<BR>
|
||
|
|
EXPECT_EQ( genres[0].genre_name, "Comedy" );<BR>
|
||
|
|
EXPECT_EQ( genres[1].genre_name, "Thriller" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- MOVIE -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Test adding a movie<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, AddMovie ) {<BR>
|
||
|
|
NewMovie movie{"The Shawshank Redemption", 1, 142};<BR>
|
||
|
|
EXPECT_TRUE( db_->addMovie( movie ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto movies = db_->getAllMovies( );<BR>
|
||
|
|
ASSERT_EQ( movies.size( ), 1 );<BR>
|
||
|
|
EXPECT_EQ( movies[0].title, "The Shawshank Redemption" );<BR>
|
||
|
|
EXPECT_EQ( movies[0].genre_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( movies[0].duration, 142 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting a movie by ID<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetMovieById ) {<BR>
|
||
|
|
NewMovie movie{"The Godfather", 2, 175};<BR>
|
||
|
|
db_->addMovie( movie );<BR>
|
||
|
|
<BR>
|
||
|
|
Movie retrieved_movie = db_->getMovie( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_movie.movie_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_movie.title, "The Godfather" );<BR>
|
||
|
|
EXPECT_EQ( retrieved_movie.genre_id, 2 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_movie.duration, 175 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test removing a movie<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, RemoveMovie ) {<BR>
|
||
|
|
NewMovie movie{"The Dark Knight", 3, 152};<BR>
|
||
|
|
db_->addMovie( movie );<BR>
|
||
|
|
EXPECT_TRUE( db_->removeMovie( 1 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto movies = db_->getAllMovies( );<BR>
|
||
|
|
EXPECT_TRUE( movies.empty( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test updating a movie<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, UpdateMovie ) {<BR>
|
||
|
|
NewMovie movie{"The Shawshank Redemption", 1, 142};<BR>
|
||
|
|
db_->addMovie( movie );<BR>
|
||
|
|
<BR>
|
||
|
|
Movie updated_movie = db_->getMovie( 1 );<BR>
|
||
|
|
updated_movie.title = "The Godfather";<BR>
|
||
|
|
updated_movie.duration = 155;<BR>
|
||
|
|
EXPECT_TRUE( db_->updateMovie( updated_movie ) );<BR>
|
||
|
|
<BR>
|
||
|
|
Movie retrieved_movie = db_->getMovie( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_movie.movie_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_movie.title, "The Godfather" );<BR>
|
||
|
|
EXPECT_EQ( retrieved_movie.genre_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_movie.duration, 155 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting all movies<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetAllMovies ) {<BR>
|
||
|
|
db_->addMovie( {"The Shawshank Redemption", 1, 142} );<BR>
|
||
|
|
db_->addMovie( {"The Godfather", 2, 175} );<BR>
|
||
|
|
<BR>
|
||
|
|
auto movies = db_->getAllMovies( );<BR>
|
||
|
|
ASSERT_EQ( movies.size( ), 2 );<BR>
|
||
|
|
EXPECT_EQ( movies[0].title, "The Shawshank Redemption" );<BR>
|
||
|
|
EXPECT_EQ( movies[0].genre_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( movies[0].duration, 142 );<BR>
|
||
|
|
EXPECT_EQ( movies[1].title, "The Godfather" );<BR>
|
||
|
|
EXPECT_EQ( movies[1].genre_id, 2 );<BR>
|
||
|
|
EXPECT_EQ( movies[1].duration, 175 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- HALL -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Test adding a hall<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, AddHall ) {<BR>
|
||
|
|
NewHall hall{"Hall 1", 132};<BR>
|
||
|
|
EXPECT_TRUE( db_->addHall( hall ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto halls = db_->getAllHalls( );<BR>
|
||
|
|
ASSERT_EQ( halls.size( ), 1 );<BR>
|
||
|
|
EXPECT_EQ( halls[0].hall_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( halls[0].hall_name, "Hall 1" );<BR>
|
||
|
|
EXPECT_EQ( halls[0].capacity, 132 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting a hall by ID<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetHallById ) {<BR>
|
||
|
|
NewHall hall{"Hall 2", 142};<BR>
|
||
|
|
db_->addHall( hall );<BR>
|
||
|
|
<BR>
|
||
|
|
Hall retrieved_hall = db_->getHall( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_hall.hall_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_hall.hall_name, "Hall 2" );<BR>
|
||
|
|
EXPECT_EQ( retrieved_hall.capacity, 142 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test removing a hall<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, RemoveHall ) {<BR>
|
||
|
|
NewHall hall{"Hall 3", 152};<BR>
|
||
|
|
db_->addHall( hall );<BR>
|
||
|
|
EXPECT_TRUE( db_->removeHall( 1 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto halls = db_->getAllHalls( );<BR>
|
||
|
|
EXPECT_TRUE( halls.empty( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test updating a hall<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, UpdateHall ) {<BR>
|
||
|
|
NewHall hall{"Hall 4", 162};<BR>
|
||
|
|
db_->addHall( hall );<BR>
|
||
|
|
<BR>
|
||
|
|
Hall updated_hall = db_->getHall( 1 );<BR>
|
||
|
|
updated_hall.hall_name = "Hall 5";<BR>
|
||
|
|
updated_hall.capacity = 172;<BR>
|
||
|
|
EXPECT_TRUE( db_->updateHall( updated_hall ) );<BR>
|
||
|
|
<BR>
|
||
|
|
Hall retrieved_hall = db_->getHall( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_hall.hall_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_hall.hall_name, "Hall 5" );<BR>
|
||
|
|
EXPECT_EQ( retrieved_hall.capacity, 172 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting all halls<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetAllHalls ) {<BR>
|
||
|
|
db_->addHall( {"Hall 6", 172} );<BR>
|
||
|
|
db_->addHall( {"Hall 7", 182} );<BR>
|
||
|
|
<BR>
|
||
|
|
auto halls = db_->getAllHalls( );<BR>
|
||
|
|
ASSERT_EQ( halls.size( ), 2 );<BR>
|
||
|
|
EXPECT_EQ( halls[0].hall_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( halls[0].hall_name, "Hall 6" );<BR>
|
||
|
|
EXPECT_EQ( halls[0].capacity, 172 );<BR>
|
||
|
|
EXPECT_EQ( halls[1].hall_id, 2 );<BR>
|
||
|
|
EXPECT_EQ( halls[1].hall_name, "Hall 7" );<BR>
|
||
|
|
EXPECT_EQ( halls[1].capacity, 182 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- SESSION -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Test adding a session<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, AddSession ) {<BR>
|
||
|
|
NewSession session{1, 1, "2025-01-01 12:00:00", 10};<BR>
|
||
|
|
EXPECT_TRUE( db_->addSession( session ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto sessions = db_->getAllSessions( );<BR>
|
||
|
|
ASSERT_EQ( sessions.size( ), 1 );<BR>
|
||
|
|
EXPECT_EQ( sessions[0].movie_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( sessions[0].hall_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( sessions[0].begin_at, "2025-01-01 12:00:00" );<BR>
|
||
|
|
EXPECT_EQ( sessions[0].ticket_price, 10 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting a session by ID<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetSessionById ) {<BR>
|
||
|
|
NewSession session{2, 2, "2025-01-01 12:00:00", 10};<BR>
|
||
|
|
db_->addSession( session );<BR>
|
||
|
|
<BR>
|
||
|
|
Session retrieved_session = db_->getSession( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.session_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.movie_id, 2 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.hall_id, 2 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.begin_at, "2025-01-01 12:00:00" );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.ticket_price, 10 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test removing a session<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, RemoveSession ) {<BR>
|
||
|
|
NewSession session{3, 3, "2025-01-01 12:00:00", 10};<BR>
|
||
|
|
db_->addSession( session );<BR>
|
||
|
|
EXPECT_TRUE( db_->removeSession( 1 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto sessions = db_->getAllSessions( );<BR>
|
||
|
|
EXPECT_TRUE( sessions.empty( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test updating a session<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, UpdateSession ) {<BR>
|
||
|
|
NewSession session{4, 4, "2025-01-01 12:00:00", 10};<BR>
|
||
|
|
db_->addSession( session );<BR>
|
||
|
|
<BR>
|
||
|
|
Session updated_session = db_->getSession( 1 );<BR>
|
||
|
|
updated_session.begin_at = "2025-01-01 13:00:00";<BR>
|
||
|
|
EXPECT_TRUE( db_->updateSession( updated_session ) );<BR>
|
||
|
|
<BR>
|
||
|
|
Session retrieved_session = db_->getSession( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.session_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.movie_id, 4 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.hall_id, 4 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.begin_at, "2025-01-01 13:00:00" );<BR>
|
||
|
|
EXPECT_EQ( retrieved_session.ticket_price, 10 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting all sessions<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetAllSessions ) {<BR>
|
||
|
|
db_->addSession( {5, 5, "2025-01-01 12:00:00", 10} );<BR>
|
||
|
|
db_->addSession( {6, 6, "2025-01-01 13:00:00", 10} );<BR>
|
||
|
|
<BR>
|
||
|
|
auto sessions = db_->getAllSessions( );<BR>
|
||
|
|
ASSERT_EQ( sessions.size( ), 2 );<BR>
|
||
|
|
EXPECT_EQ( sessions[0].movie_id, 5 );<BR>
|
||
|
|
EXPECT_EQ( sessions[0].hall_id, 5 );<BR>
|
||
|
|
EXPECT_EQ( sessions[0].begin_at, "2025-01-01 12:00:00" );<BR>
|
||
|
|
EXPECT_EQ( sessions[0].ticket_price, 10 );<BR>
|
||
|
|
EXPECT_EQ( sessions[1].movie_id, 6 );<BR>
|
||
|
|
EXPECT_EQ( sessions[1].hall_id, 6 );<BR>
|
||
|
|
EXPECT_EQ( sessions[1].begin_at, "2025-01-01 13:00:00" );<BR>
|
||
|
|
EXPECT_EQ( sessions[1].ticket_price, 10 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- TICKET -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Test adding a ticket<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, AddTicket ) {<BR>
|
||
|
|
NewTicket ticket{1, 1, "2025-01-01 12:00:00"};<BR>
|
||
|
|
EXPECT_TRUE( db_->addTicket( ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto tickets = db_->getAllTickets( );<BR>
|
||
|
|
ASSERT_EQ( tickets.size( ), 1 );<BR>
|
||
|
|
EXPECT_EQ( tickets[0].session_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( tickets[0].seat_number, 1 );<BR>
|
||
|
|
EXPECT_EQ( tickets[0].sold_at, "2025-01-01 12:00:00" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting a ticket by ID<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetTicketById ) {<BR>
|
||
|
|
NewTicket ticket{2, 2, "2025-01-01 12:00:00"};<BR>
|
||
|
|
db_->addTicket( ticket );<BR>
|
||
|
|
<BR>
|
||
|
|
Ticket retrieved_ticket = db_->getTicket( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_ticket.ticket_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_ticket.session_id, 2 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_ticket.seat_number, 2 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_ticket.sold_at, "2025-01-01 12:00:00" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test removing a ticket<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, RemoveTicket ) {<BR>
|
||
|
|
NewTicket ticket{3, 3, "2025-01-01 12:00:00"};<BR>
|
||
|
|
db_->addTicket( ticket );<BR>
|
||
|
|
EXPECT_TRUE( db_->removeTicket( 1 ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto tickets = db_->getAllTickets( );<BR>
|
||
|
|
EXPECT_TRUE( tickets.empty( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test updating a ticket<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, UpdateTicket ) {<BR>
|
||
|
|
NewTicket ticket{4, 4, "2025-01-01 12:00:00"};<BR>
|
||
|
|
db_->addTicket( ticket );<BR>
|
||
|
|
<BR>
|
||
|
|
Ticket updated_ticket = db_->getTicket( 1 );<BR>
|
||
|
|
updated_ticket.seat_number = 5;<BR>
|
||
|
|
EXPECT_TRUE( db_->updateTicket( updated_ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
Ticket retrieved_ticket = db_->getTicket( 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_ticket.ticket_id, 1 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_ticket.session_id, 4 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_ticket.seat_number, 5 );<BR>
|
||
|
|
EXPECT_EQ( retrieved_ticket.sold_at, "2025-01-01 12:00:00" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test getting all tickets<BR>
|
||
|
|
TEST_F( SQLiteDatabaseCRUDTest, GetAllTickets ) {<BR>
|
||
|
|
db_->addTicket( {5, 5, "2025-01-01 12:00:00"} );<BR>
|
||
|
|
db_->addTicket( {6, 6, "2025-01-01 13:00:00"} );<BR>
|
||
|
|
<BR>
|
||
|
|
auto tickets = db_->getAllTickets( );<BR>
|
||
|
|
ASSERT_EQ( tickets.size( ), 2 );<BR>
|
||
|
|
EXPECT_EQ( tickets[0].session_id, 5 );<BR>
|
||
|
|
EXPECT_EQ( tickets[0].seat_number, 5 );<BR>
|
||
|
|
EXPECT_EQ( tickets[0].sold_at, "2025-01-01 12:00:00" );<BR>
|
||
|
|
EXPECT_EQ( tickets[1].session_id, 6 );<BR>
|
||
|
|
EXPECT_EQ( tickets[1].seat_number, 6 );<BR>
|
||
|
|
EXPECT_EQ( tickets[1].sold_at, "2025-01-01 13:00:00" );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_schema/tests/sqlite_database_foreign_key_test.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
#include "sqlite_database.h"<BR>
|
||
|
|
#include "sqlite_file_executor.h"<BR>
|
||
|
|
#include "gtest/gtest.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// WARNING: Triggers are off<BR>
|
||
|
|
<BR>
|
||
|
|
const std::string TEST_DB = "test.db";<BR>
|
||
|
|
<BR>
|
||
|
|
// Test fixture for SQLiteDatabase<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_foreign_key_test.cpp: 10"> 10 </A>class SQLiteDatabaseForeignKeyTest : public ::testing::Test {<BR>
|
||
|
|
<BR>
|
||
|
|
protected:<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_foreign_key_test.cpp: 13"> 13 </A> SQLiteDatabase *db_;<BR>
|
||
|
|
<BR>
|
||
|
|
public:<BR>
|
||
|
|
// void pragmaForeignKeysOn( ) {<BR>
|
||
|
|
// const std::string query = "PRAGMA foreign_keys = ON;";<BR>
|
||
|
|
// db_->executeNonQuery( query );<BR>
|
||
|
|
// }<BR>
|
||
|
|
<BR>
|
||
|
|
std::vector<std::vector<std::string>> pragmaForeignKeys( ) {<BR>
|
||
|
|
const std::string query = "PRAGMA foreign_keys;";<BR>
|
||
|
|
auto results = db_->executeSelectQuery( query );<BR>
|
||
|
|
return results;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
protected:<BR>
|
||
|
|
void SetUp( ) override {<BR>
|
||
|
|
db_ = new SQLiteDatabase( TEST_DB );<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_foreign_key_test.cpp: 30"> 30 </A> SQLiteFileExecutor executor( TEST_DB );<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_foreign_key_test.cpp: 31"> 31 </A> executor.executeSQLFile( "sql/cinema_db_drop_table.sql" );<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_foreign_key_test.cpp: 32"> 32 </A> executor.executeSQLFile( "sql/cinema_db_create_table.sql" );<BR>
|
||
|
|
<BR>
|
||
|
|
// pragmaForeignKeysOn( );<BR>
|
||
|
|
<BR>
|
||
|
|
std::string sql;<BR>
|
||
|
|
FileReaderInterface *reader = &executor;<BR>
|
||
|
|
reader->read( "sql/cinema_db_foreign_key_on.sql", sql );<BR>
|
||
|
|
db_->executeNonQuery( sql );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void TearDown( ) override {<BR>
|
||
|
|
delete db_;<BR>
|
||
|
|
remove( TEST_DB.c_str( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- GENERAL -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Check pragma foreign_keys is true<BR>
|
||
|
|
TEST_F( SQLiteDatabaseForeignKeyTest, PragmaForeignKeys ) {<BR>
|
||
|
|
auto results = pragmaForeignKeys( );<BR>
|
||
|
|
ASSERT_FALSE( results.empty( ) );<BR>
|
||
|
|
ASSERT_EQ( results[0][0], "1" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test adding a movie<BR>
|
||
|
|
TEST_F( SQLiteDatabaseForeignKeyTest, AddMovie ) {<BR>
|
||
|
|
NewMovie movie{"The Shawshank Redemption", 1, 142};<BR>
|
||
|
|
EXPECT_FALSE( db_->addMovie( movie ) );<BR>
|
||
|
|
<BR>
|
||
|
|
auto movies = db_->getAllMovies( );<BR>
|
||
|
|
ASSERT_TRUE( movies.empty( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
NewGenre genre{"Drama"};<BR>
|
||
|
|
EXPECT_TRUE( db_->addGenre( genre ) );<BR>
|
||
|
|
EXPECT_TRUE( db_->addMovie( movie ) );<BR>
|
||
|
|
movies = db_->getAllMovies( );<BR>
|
||
|
|
ASSERT_FALSE( movies.empty( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test adding session<BR>
|
||
|
|
TEST_F( SQLiteDatabaseForeignKeyTest, AddSession ) {<BR>
|
||
|
|
NewSession session{1, 1, "2025-01-01 12:00:00", 10};<BR>
|
||
|
|
EXPECT_FALSE( db_->addSession( session ) );<BR>
|
||
|
|
<BR>
|
||
|
|
NewHall hall{"Hall 1", 100};<BR>
|
||
|
|
db_->addHall( hall );<BR>
|
||
|
|
EXPECT_FALSE( db_->addSession( session ) );<BR>
|
||
|
|
<BR>
|
||
|
|
NewGenre genre{"Drama"};<BR>
|
||
|
|
db_->addGenre( genre );<BR>
|
||
|
|
NewMovie movie{"The Shawshank Redemption", 1, 142};<BR>
|
||
|
|
db_->addMovie( movie );<BR>
|
||
|
|
EXPECT_TRUE( db_->addSession( session ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test adding ticket<BR>
|
||
|
|
TEST_F( SQLiteDatabaseForeignKeyTest, AddTicket ) {<BR>
|
||
|
|
NewTicket ticket{1, 1, "2025-01-01 12:00:00"};<BR>
|
||
|
|
EXPECT_FALSE( db_->addTicket( ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
NewHall hall{"Hall 1", 100};<BR>
|
||
|
|
db_->addHall( hall );<BR>
|
||
|
|
NewGenre genre{"Drama"};<BR>
|
||
|
|
db_->addGenre( genre );<BR>
|
||
|
|
NewMovie movie{"The Shawshank Redemption", 1, 142};<BR>
|
||
|
|
db_->addMovie( movie );<BR>
|
||
|
|
NewSession session{1, 1, "2025-01-01 12:00:00", 10};<BR>
|
||
|
|
db_->addSession( session );<BR>
|
||
|
|
<BR>
|
||
|
|
EXPECT_TRUE( db_->addTicket( ticket ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_schema/tests/sqlite_database_trigger_test.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
#include "sqlite_database.h"<BR>
|
||
|
|
#include "sqlite_file_executor.h"<BR>
|
||
|
|
#include "gtest/gtest.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// WARNING: Foreign keys are off<BR>
|
||
|
|
<BR>
|
||
|
|
const std::string TEST_DB = "test.db";<BR>
|
||
|
|
<BR>
|
||
|
|
// Test fixture for SQLiteDatabase<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_trigger_test.cpp: 10"> 10 </A>class SQLiteDatabaseTriggerTest : public ::testing::Test {<BR>
|
||
|
|
protected:<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_trigger_test.cpp: 12"> 12 </A> SQLiteDatabase *db_;<BR>
|
||
|
|
<BR>
|
||
|
|
void SetUp( ) override {<BR>
|
||
|
|
db_ = new SQLiteDatabase( TEST_DB );<BR>
|
||
|
|
SQLiteFileExecutor executor( TEST_DB );<BR>
|
||
|
|
executor.executeSQLFile( "sql/cinema_db_drop_table.sql" );<BR>
|
||
|
|
executor.executeSQLFile( "sql/cinema_db_create_table.sql" );<BR>
|
||
|
|
executor.executeSQLFile( "sql/cinema_db_drop_trigger.sql" );<BR>
|
||
|
|
executor.executeSQLFile( "sql/cinema_db_create_trigger.sql" );<BR>
|
||
|
|
<BR>
|
||
|
|
// Not necessarily, since the default setting<BR>
|
||
|
|
std::string sql;<BR>
|
||
|
|
FileReaderInterface *reader = &executor;<BR>
|
||
|
|
reader->read( "sql/cinema_db_foreign_key_off.sql", sql );<BR>
|
||
|
|
db_->executeNonQuery( sql );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
void TearDown( ) override {<BR>
|
||
|
|
delete db_;<BR>
|
||
|
|
<A NAME="./tests_schema/tests/sqlite_database_trigger_test.cpp: 31"> 31 </A> remove( TEST_DB.c_str( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- TICKET -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Test trigger check_seat_number<BR>
|
||
|
|
TEST_F( SQLiteDatabaseTriggerTest, CheckSeatNumber ) {<BR>
|
||
|
|
db_->addHall( {"Hall 1", 100} );<BR>
|
||
|
|
db_->addSession( {1, 1, "2025-01-01 12:00:00", 10} );<BR>
|
||
|
|
<BR>
|
||
|
|
NewTicket ticket;<BR>
|
||
|
|
ticket.session_id = 1;<BR>
|
||
|
|
ticket.sold_at = "2025-01-01 12:00:00";<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.seat_number = 101;<BR>
|
||
|
|
EXPECT_FALSE( db_->addTicket( ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.seat_number = 100;<BR>
|
||
|
|
EXPECT_TRUE( db_->addTicket( ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.seat_number = 1;<BR>
|
||
|
|
EXPECT_TRUE( db_->addTicket( ticket ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test trigger check_session_not_started<BR>
|
||
|
|
TEST_F( SQLiteDatabaseTriggerTest, CheckSessionNotStarted ) {<BR>
|
||
|
|
db_->addSession( {1, 1, "2025-01-01 12:00:00", 10} );<BR>
|
||
|
|
<BR>
|
||
|
|
NewTicket ticket;<BR>
|
||
|
|
ticket.session_id = 1;<BR>
|
||
|
|
ticket.seat_number = 1;<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.sold_at = "2025-01-01 13:00:00";<BR>
|
||
|
|
EXPECT_FALSE( db_->addTicket( ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.sold_at = "2025-01-01 11:00:00";<BR>
|
||
|
|
EXPECT_TRUE( db_->addTicket( ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.seat_number = 2;<BR>
|
||
|
|
ticket.sold_at = "2025-01-01 12:00:00";<BR>
|
||
|
|
EXPECT_TRUE( db_->addTicket( ticket ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test trigger prevent_late_ticket_purchase<BR>
|
||
|
|
TEST_F( SQLiteDatabaseTriggerTest, PreventLateTicketPurchase ) {<BR>
|
||
|
|
db_->addHall( {"Hall 1", 100} );<BR>
|
||
|
|
db_->addSession( {1, 1, "2025-01-01 12:00:00", 10} );<BR>
|
||
|
|
<BR>
|
||
|
|
NewTicket ticket;<BR>
|
||
|
|
ticket.session_id = 1;<BR>
|
||
|
|
ticket.seat_number = 1;<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.sold_at = "2025-01-01 13:00:00";<BR>
|
||
|
|
EXPECT_FALSE( db_->addTicket( ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.sold_at = "2025-01-01 12:00:00";<BR>
|
||
|
|
EXPECT_TRUE( db_->addTicket( ticket ) );<BR>
|
||
|
|
<BR>
|
||
|
|
ticket.seat_number = 2;<BR>
|
||
|
|
ticket.sold_at = "2025-01-01 11:00:00";<BR>
|
||
|
|
EXPECT_TRUE( db_->addTicket( ticket ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- REFUND -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Test trigger validate_refund_amount<BR>
|
||
|
|
TEST_F( SQLiteDatabaseTriggerTest, ValidateRefundAmount ) {<BR>
|
||
|
|
db_->addHall( {"Hall 1", 100} );<BR>
|
||
|
|
db_->addSession( {1, 1, "2025-01-01 12:00:00", 10} );<BR>
|
||
|
|
<BR>
|
||
|
|
// ID 1<BR>
|
||
|
|
db_->addTicket( {1, 1, "2025-01-01 10:00:00"} );<BR>
|
||
|
|
// ID 2<BR>
|
||
|
|
db_->addTicket( {1, 2, "2025-01-01 10:00:00"} );<BR>
|
||
|
|
<BR>
|
||
|
|
NewRefund refund;<BR>
|
||
|
|
refund.ticket_id = 1;<BR>
|
||
|
|
refund.refund_at = "2025-01-01 11:00:00";<BR>
|
||
|
|
<BR>
|
||
|
|
refund.refund_amount = 11;<BR>
|
||
|
|
EXPECT_FALSE( db_->addRefund( refund ) );<BR>
|
||
|
|
<BR>
|
||
|
|
refund.refund_amount = 10;<BR>
|
||
|
|
EXPECT_TRUE( db_->addRefund( refund ) );<BR>
|
||
|
|
<BR>
|
||
|
|
refund.ticket_id = 2;<BR>
|
||
|
|
refund.refund_amount = 9;<BR>
|
||
|
|
EXPECT_TRUE( db_->addRefund( refund ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Test trigger validate_refund_date<BR>
|
||
|
|
TEST_F( SQLiteDatabaseTriggerTest, ValidateRefundDate ) {<BR>
|
||
|
|
db_->addHall( {"Hall 1", 100} );<BR>
|
||
|
|
db_->addSession( {1, 1, "2025-01-01 12:00:00", 10} );<BR>
|
||
|
|
<BR>
|
||
|
|
// ID 1<BR>
|
||
|
|
db_->addTicket( {1, 1, "2025-01-01 10:00:00"} );<BR>
|
||
|
|
// ID 2<BR>
|
||
|
|
db_->addTicket( {1, 2, "2025-01-01 10:00:00"} );<BR>
|
||
|
|
<BR>
|
||
|
|
NewRefund refund;<BR>
|
||
|
|
refund.ticket_id = 1;<BR>
|
||
|
|
refund.refund_amount = 10;<BR>
|
||
|
|
<BR>
|
||
|
|
refund.refund_at = "2025-01-01 09:00:00";<BR>
|
||
|
|
EXPECT_FALSE( db_->addRefund( refund ) );<BR>
|
||
|
|
<BR>
|
||
|
|
refund.refund_at = "2025-01-01 11:00:00";<BR>
|
||
|
|
EXPECT_TRUE( db_->addRefund( refund ) );<BR>
|
||
|
|
<BR>
|
||
|
|
refund.refund_at = "2025-01-01 12:00:00";<BR>
|
||
|
|
EXPECT_FALSE( db_->addRefund( refund ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_schema/tests_sources/file_reader.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./tests_schema/tests_sources/file_reader.cpp: 1"> 1 </A>#include "file_reader.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <fstream><BR>
|
||
|
|
#include <iostream><BR>
|
||
|
|
#include <sstream><BR>
|
||
|
|
<BR>
|
||
|
|
// Read a SQL file<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/file_reader.cpp: 8"> 8 </A>bool FileReader::read( const std::string &sqlFilePath, std::string &sql ) {<BR>
|
||
|
|
// Try read the SQL file<BR>
|
||
|
|
std::ifstream file( sqlFilePath );<BR>
|
||
|
|
if ( !file.is_open( ) ) {<BR>
|
||
|
|
std::cerr << "Error opening file:" << sqlFilePath << std::endl;<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
std::stringstream buffer;<BR>
|
||
|
|
buffer << file.rdbuf( );<BR>
|
||
|
|
<BR>
|
||
|
|
sql = buffer.str( );<BR>
|
||
|
|
file.close( );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_schema/tests_sources/sqlite_database.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 1"> 1 </A>#include "sqlite_database.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "sqlite_statement.h"<BR>
|
||
|
|
#include <iostream><BR>
|
||
|
|
#include <utility> // std::exchange<BR>
|
||
|
|
<BR>
|
||
|
|
// Constructor: Opens the SQLite database<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 8"> 8 </A>SQLiteDatabase::SQLiteDatabase( const std::string &db_file ) {<BR>
|
||
|
|
// WARNING: The database is not blocked<BR>
|
||
|
|
if ( sqlite3_open( db_file.c_str( ), &db_ ) != SQLITE_OK ) {<BR>
|
||
|
|
std::cerr << "Failed to open database:" << sqlite3_errmsg( db_ ) << std::endl;<BR>
|
||
|
|
db_ = nullptr;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Destructor: Closes the database connection<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 17"> 17 </A>SQLiteDatabase::~SQLiteDatabase( ) {<BR>
|
||
|
|
if ( db_ ) {<BR>
|
||
|
|
sqlite3_close( db_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 23"> 23 </A>SQLiteDatabase::SQLiteDatabase( SQLiteDatabase &&other ) noexcept<BR>
|
||
|
|
: db_( std::exchange( other.db_, nullptr ) ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 26"> 26 </A>SQLiteDatabase &SQLiteDatabase::operator=( SQLiteDatabase &&other ) noexcept {<BR>
|
||
|
|
if ( this != &other ) {<BR>
|
||
|
|
if ( db_ ) {<BR>
|
||
|
|
sqlite3_close( db_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
db_ = std::exchange( other.db_, nullptr );<BR>
|
||
|
|
}<BR>
|
||
|
|
return *this;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Helper function for executing non-SELECT queries<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 37"> 37 </A>int SQLiteDatabase::executeNonQuery( <BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 38"> 38 </A> const std::string &query, <BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 39"> 39 </A> const std::function<void( SQLiteStatement & )> &bindFunc ) {<BR>
|
||
|
|
SQLiteStatement stmt( db_, query );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( db_ == nullptr ) {<BR>
|
||
|
|
throw std::runtime_error( "Database is not open" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( bindFunc ) {<BR>
|
||
|
|
bindFunc( stmt );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !stmt.execute( ) ) {<BR>
|
||
|
|
std::cerr << "Failed to execute query:" << sqlite3_errmsg( db_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return stmt.changes( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Helper function for executing SELECT queries<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 58"> 58 </A>std::vector<std::vector<std::string>> SQLiteDatabase::executeSelectQuery( <BR>
|
||
|
|
const std::string &query, <BR>
|
||
|
|
const std::function<void( SQLiteStatement & )> &bindFunc ) {<BR>
|
||
|
|
std::vector<std::vector<std::string>> results;<BR>
|
||
|
|
SQLiteStatement stmt( db_, query );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( db_ == nullptr ) {<BR>
|
||
|
|
throw std::runtime_error( "Database is not open" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( bindFunc ) {<BR>
|
||
|
|
bindFunc( stmt );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
while ( stmt.step( ) ) {<BR>
|
||
|
|
std::vector<std::string> row;<BR>
|
||
|
|
for ( int i = 0, count = stmt.getColumnCount( ); i < count; ++i ) {<BR>
|
||
|
|
row.emplace_back( stmt.getColumnText( i ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
results.push_back( row );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return results;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- GENRE -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Add a new genre<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 86"> 86 </A>bool SQLiteDatabase::addGenre( const NewGenre &genre ) {<BR>
|
||
|
|
const std::string query = "INSERT INTO genres ( genre_name ) VALUES ( ? );";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&genre]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, genre.genre_name );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Remove a genre by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 96"> 96 </A>bool SQLiteDatabase::removeGenre( int genre_id ) {<BR>
|
||
|
|
const std::string query = "DELETE FROM genres WHERE genre_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( <BR>
|
||
|
|
query, [&genre_id]( SQLiteStatement &stmt ) { stmt.bind( 1, genre_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Update an existing genre<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 105"> 105 </A>bool SQLiteDatabase::updateGenre( const Genre &genre ) {<BR>
|
||
|
|
const std::string query =<BR>
|
||
|
|
"UPDATE genres SET genre_name = ? WHERE genre_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&genre]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, genre.genre_name );<BR>
|
||
|
|
stmt.bind( 2, genre.genre_id );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get a genre by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 117"> 117 </A>Genre SQLiteDatabase::getGenre( int genre_id ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM genres WHERE genre_id = ?;";<BR>
|
||
|
|
auto result = executeSelectQuery( <BR>
|
||
|
|
query, [&genre_id]( SQLiteStatement &stmt ) { stmt.bind( 1, genre_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.empty( ) ) {<BR>
|
||
|
|
auto genre_id = std::stoi( result[0][0] );<BR>
|
||
|
|
auto genre_name = result[0][1];<BR>
|
||
|
|
Genre genre( genre_id, genre_name );<BR>
|
||
|
|
return genre;<BR>
|
||
|
|
}<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get all genres<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 132"> 132 </A>std::vector<Genre> SQLiteDatabase::getAllGenres( ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM genres;";<BR>
|
||
|
|
auto result = executeSelectQuery( query );<BR>
|
||
|
|
<BR>
|
||
|
|
std::vector<Genre> genres;<BR>
|
||
|
|
for ( const auto &row : result ) {<BR>
|
||
|
|
genres.push_back( {std::stoi( row[0] ), row[1]} );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return genres;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- MOVIE -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Add a new movie<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 147"> 147 </A>bool SQLiteDatabase::addMovie( const NewMovie &movie ) {<BR>
|
||
|
|
const std::string query =<BR>
|
||
|
|
"INSERT INTO movies ( title, genre_id, duration ) VALUES ( ?, ?, ? );";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&movie]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, movie.title );<BR>
|
||
|
|
stmt.bind( 2, movie.genre_id );<BR>
|
||
|
|
stmt.bind( 3, movie.duration );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Remove a movie by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 160"> 160 </A>bool SQLiteDatabase::removeMovie( int movie_id ) {<BR>
|
||
|
|
const std::string query = "DELETE FROM movies WHERE movie_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( <BR>
|
||
|
|
query, [&movie_id]( SQLiteStatement &stmt ) { stmt.bind( 1, movie_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Update an existing movie<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 169"> 169 </A>bool SQLiteDatabase::updateMovie( const Movie &movie ) {<BR>
|
||
|
|
const std::string query =<BR>
|
||
|
|
"UPDATE movies SET title = ?, genre_id = ?, duration = ? WHERE movie_id "<BR>
|
||
|
|
"= ?;";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&movie]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, movie.title );<BR>
|
||
|
|
stmt.bind( 2, movie.genre_id );<BR>
|
||
|
|
stmt.bind( 3, movie.duration );<BR>
|
||
|
|
stmt.bind( 4, movie.movie_id );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get a movie by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 184"> 184 </A>Movie SQLiteDatabase::getMovie( int movie_id ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM movies WHERE movie_id = ?;";<BR>
|
||
|
|
auto result = executeSelectQuery( <BR>
|
||
|
|
query, [&movie_id]( SQLiteStatement &stmt ) { stmt.bind( 1, movie_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.empty( ) ) {<BR>
|
||
|
|
auto movie_id = std::stoi( result[0][0] );<BR>
|
||
|
|
auto title = result[0][1];<BR>
|
||
|
|
auto genre_id = std::stoi( result[0][2] );<BR>
|
||
|
|
auto duration = std::stoi( result[0][3] );<BR>
|
||
|
|
Movie movie( movie_id, title, genre_id, duration );<BR>
|
||
|
|
return movie;<BR>
|
||
|
|
}<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get all movies<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 201"> 201 </A>std::vector<Movie> SQLiteDatabase::getAllMovies( ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM movies;";<BR>
|
||
|
|
auto result = executeSelectQuery( query );<BR>
|
||
|
|
std::vector<Movie> movies;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &row : result ) {<BR>
|
||
|
|
movies.push_back( <BR>
|
||
|
|
{std::stoi( row[0] ), row[1], std::stoi( row[2] ), std::stoi( row[3] )} );<BR>
|
||
|
|
}<BR>
|
||
|
|
return movies;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- HALL -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Add a new hall<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 216"> 216 </A>bool SQLiteDatabase::addHall( const NewHall &hall ) {<BR>
|
||
|
|
const std::string query =<BR>
|
||
|
|
"INSERT INTO halls ( hall_name, capacity ) VALUES ( ?, ? );";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&hall]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, hall.hall_name );<BR>
|
||
|
|
stmt.bind( 2, hall.capacity );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Remove a hall by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 228"> 228 </A>bool SQLiteDatabase::removeHall( int hall_id ) {<BR>
|
||
|
|
const std::string query = "DELETE FROM halls WHERE hall_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( <BR>
|
||
|
|
query, [&hall_id]( SQLiteStatement &stmt ) { stmt.bind( 1, hall_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Update an existing hall<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 237"> 237 </A>bool SQLiteDatabase::updateHall( const Hall &hall ) {<BR>
|
||
|
|
const std::string query =<BR>
|
||
|
|
"UPDATE halls SET hall_name = ?, capacity = ? WHERE hall_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&hall]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, hall.hall_name );<BR>
|
||
|
|
stmt.bind( 2, hall.capacity );<BR>
|
||
|
|
stmt.bind( 3, hall.hall_id );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get a hall by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 250"> 250 </A>Hall SQLiteDatabase::getHall( int hall_id ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM halls WHERE hall_id = ?;";<BR>
|
||
|
|
auto result = executeSelectQuery( <BR>
|
||
|
|
query, [&hall_id]( SQLiteStatement &stmt ) { stmt.bind( 1, hall_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.empty( ) ) {<BR>
|
||
|
|
auto hall_id = std::stoi( result[0][0] );<BR>
|
||
|
|
auto hall_name = result[0][1];<BR>
|
||
|
|
auto capacity = std::stoi( result[0][2] );<BR>
|
||
|
|
Hall hall( hall_id, hall_name, capacity );<BR>
|
||
|
|
return hall;<BR>
|
||
|
|
}<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get all halls<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 266"> 266 </A>std::vector<Hall> SQLiteDatabase::getAllHalls( ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM halls;";<BR>
|
||
|
|
auto result = executeSelectQuery( query );<BR>
|
||
|
|
std::vector<Hall> halls;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &row : result ) {<BR>
|
||
|
|
halls.push_back( {std::stoi( row[0] ), row[1], std::stoi( row[2] )} );<BR>
|
||
|
|
}<BR>
|
||
|
|
return halls;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- SESSION -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Add a new session<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 280"> 280 </A>bool SQLiteDatabase::addSession( const NewSession &session ) {<BR>
|
||
|
|
const std::string query = "INSERT INTO sessions ( movie_id, hall_id, "<BR>
|
||
|
|
"begin_at, ticket_price ) VALUES ( ?, ?, ?, ? );";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&session]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, session.movie_id );<BR>
|
||
|
|
stmt.bind( 2, session.hall_id );<BR>
|
||
|
|
stmt.bind( 3, session.begin_at );<BR>
|
||
|
|
stmt.bind( 4, session.ticket_price );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Remove a session by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 294"> 294 </A>bool SQLiteDatabase::removeSession( int session_id ) {<BR>
|
||
|
|
const std::string query = "DELETE FROM sessions WHERE session_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&session_id]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, session_id );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Update an existing session<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 304"> 304 </A>bool SQLiteDatabase::updateSession( const Session &session ) {<BR>
|
||
|
|
const std::string query = "UPDATE sessions SET movie_id = ?, hall_id = ?, "<BR>
|
||
|
|
"begin_at = ?, ticket_price = ? WHERE "<BR>
|
||
|
|
"session_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&session]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, session.movie_id );<BR>
|
||
|
|
stmt.bind( 2, session.hall_id );<BR>
|
||
|
|
stmt.bind( 3, session.begin_at );<BR>
|
||
|
|
stmt.bind( 4, session.ticket_price );<BR>
|
||
|
|
stmt.bind( 5, session.session_id );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get a session by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 320"> 320 </A>Session SQLiteDatabase::getSession( int session_id ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM sessions WHERE session_id = ?;";<BR>
|
||
|
|
auto result = executeSelectQuery( query, [&session_id]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, session_id );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.empty( ) ) {<BR>
|
||
|
|
auto session_id = std::stoi( result[0][0] );<BR>
|
||
|
|
auto movie_id = std::stoi( result[0][1] );<BR>
|
||
|
|
auto hall_id = std::stoi( result[0][2] );<BR>
|
||
|
|
auto begin_at = result[0][3];<BR>
|
||
|
|
auto ticket_price = std::stod( result[0][4] );<BR>
|
||
|
|
Session session( session_id, movie_id, hall_id, begin_at, ticket_price );<BR>
|
||
|
|
return session;<BR>
|
||
|
|
}<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get all sessions<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 339"> 339 </A>std::vector<Session> SQLiteDatabase::getAllSessions( ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM sessions;";<BR>
|
||
|
|
auto result = executeSelectQuery( query );<BR>
|
||
|
|
std::vector<Session> sessions;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &row : result ) {<BR>
|
||
|
|
sessions.push_back( {std::stoi( row[0] ), std::stoi( row[1] ), std::stoi( row[2] ), <BR>
|
||
|
|
row[3], std::stod( row[4] )} );<BR>
|
||
|
|
}<BR>
|
||
|
|
return sessions;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- TICKET -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Add a new ticket<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 354"> 354 </A>bool SQLiteDatabase::addTicket( const NewTicket &ticket ) {<BR>
|
||
|
|
const std::string query = "INSERT INTO tickets ( session_id, seat_number, "<BR>
|
||
|
|
"sold_at ) VALUES ( ?, ?, ? );";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&ticket]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, ticket.session_id );<BR>
|
||
|
|
stmt.bind( 2, ticket.seat_number );<BR>
|
||
|
|
stmt.bind( 3, ticket.sold_at );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Remove a ticket by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 367"> 367 </A>bool SQLiteDatabase::removeTicket( int ticket_id ) {<BR>
|
||
|
|
const std::string query = "DELETE FROM tickets WHERE ticket_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( <BR>
|
||
|
|
query, [&ticket_id]( SQLiteStatement &stmt ) { stmt.bind( 1, ticket_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Update an existing ticket<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 376"> 376 </A>bool SQLiteDatabase::updateTicket( const Ticket &ticket ) {<BR>
|
||
|
|
const std::string query = "UPDATE tickets SET session_id = ?, seat_number = "<BR>
|
||
|
|
"?, sold_at = ? WHERE ticket_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&ticket]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, ticket.session_id );<BR>
|
||
|
|
stmt.bind( 2, ticket.seat_number );<BR>
|
||
|
|
stmt.bind( 3, ticket.sold_at );<BR>
|
||
|
|
stmt.bind( 4, ticket.ticket_id );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get a ticket by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 390"> 390 </A>Ticket SQLiteDatabase::getTicket( int ticket_id ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM tickets WHERE ticket_id = ?;";<BR>
|
||
|
|
auto result = executeSelectQuery( <BR>
|
||
|
|
query, [&ticket_id]( SQLiteStatement &stmt ) { stmt.bind( 1, ticket_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.empty( ) ) {<BR>
|
||
|
|
auto ticket_id = std::stoi( result[0][0] );<BR>
|
||
|
|
auto session_id = std::stoi( result[0][1] );<BR>
|
||
|
|
auto seat_number = std::stoi( result[0][2] );<BR>
|
||
|
|
auto sold_at = result[0][3];<BR>
|
||
|
|
Ticket ticket( ticket_id, session_id, seat_number, sold_at );<BR>
|
||
|
|
return ticket;<BR>
|
||
|
|
}<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get all tickets<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 407"> 407 </A>std::vector<Ticket> SQLiteDatabase::getAllTickets( ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM tickets;";<BR>
|
||
|
|
auto result = executeSelectQuery( query );<BR>
|
||
|
|
std::vector<Ticket> tickets;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &row : result ) {<BR>
|
||
|
|
tickets.push_back( <BR>
|
||
|
|
{std::stoi( row[0] ), std::stoi( row[1] ), std::stoi( row[2] ), row[3]} );<BR>
|
||
|
|
}<BR>
|
||
|
|
return tickets;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// INFO: ----- REFUND -----<BR>
|
||
|
|
<BR>
|
||
|
|
// Add a new refund<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 422"> 422 </A>bool SQLiteDatabase::addRefund( const NewRefund &refund ) {<BR>
|
||
|
|
const std::string query =<BR>
|
||
|
|
"INSERT INTO refunds ( ticket_id, refund_at, refund_amount ) "<BR>
|
||
|
|
"VALUES ( ?, ?, ? );";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&refund]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, refund.ticket_id );<BR>
|
||
|
|
stmt.bind( 2, refund.refund_at );<BR>
|
||
|
|
stmt.bind( 3, refund.refund_amount );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Remove a refund by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 436"> 436 </A>bool SQLiteDatabase::removeRefund( int refund_id ) {<BR>
|
||
|
|
const std::string query = "DELETE FROM refunds WHERE refund_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( <BR>
|
||
|
|
query, [&refund_id]( SQLiteStatement &stmt ) { stmt.bind( 1, refund_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Update an existing refund<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 445"> 445 </A>bool SQLiteDatabase::updateRefund( const Refund &refund ) {<BR>
|
||
|
|
const std::string query =<BR>
|
||
|
|
"UPDATE refunds SET ticket_id = ?, refund_at = ?, refund_amount = ? "<BR>
|
||
|
|
"WHERE refund_id = ?;";<BR>
|
||
|
|
int changes = executeNonQuery( query, [&refund]( SQLiteStatement &stmt ) {<BR>
|
||
|
|
stmt.bind( 1, refund.ticket_id );<BR>
|
||
|
|
stmt.bind( 2, refund.refund_at );<BR>
|
||
|
|
stmt.bind( 3, refund.refund_amount );<BR>
|
||
|
|
stmt.bind( 4, refund.refund_id );<BR>
|
||
|
|
} );<BR>
|
||
|
|
<BR>
|
||
|
|
return changes > 0;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get a refund by ID<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 460"> 460 </A>Refund SQLiteDatabase::getRefund( int refund_id ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM refunds WHERE refund_id = ?;";<BR>
|
||
|
|
auto result = executeSelectQuery( <BR>
|
||
|
|
query, [&refund_id]( SQLiteStatement &stmt ) { stmt.bind( 1, refund_id ); } );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.empty( ) ) {<BR>
|
||
|
|
auto refund_id = std::stoi( result[0][0] );<BR>
|
||
|
|
auto ticket_id = std::stoi( result[0][1] );<BR>
|
||
|
|
auto refund_at = result[0][2];<BR>
|
||
|
|
auto refund_amount = std::stod( result[0][3] );<BR>
|
||
|
|
Refund refund( refund_id, ticket_id, refund_at, refund_amount );<BR>
|
||
|
|
return refund;<BR>
|
||
|
|
}<BR>
|
||
|
|
return {};<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get all refunds<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_database.cpp: 477"> 477 </A>std::vector<Refund> SQLiteDatabase::getAllRefunds( ) {<BR>
|
||
|
|
const std::string query = "SELECT * FROM refunds;";<BR>
|
||
|
|
auto result = executeSelectQuery( query );<BR>
|
||
|
|
std::vector<Refund> refunds;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const auto &row : result ) {<BR>
|
||
|
|
refunds.push_back( <BR>
|
||
|
|
{std::stoi( row[0] ), std::stoi( row[1] ), row[2], std::stod( row[3] )} );<BR>
|
||
|
|
}<BR>
|
||
|
|
return refunds;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_schema/tests_sources/sqlite_file_executor.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_file_executor.cpp: 1"> 1 </A>#include "sqlite_file_executor.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "sqlite_statement.h"<BR>
|
||
|
|
#include <iostream><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_file_executor.cpp: 6"> 6 </A>SQLiteFileExecutor::SQLiteFileExecutor( const std::string &dbPath ) {<BR>
|
||
|
|
// WARNING: The database is not blocked<BR>
|
||
|
|
if ( sqlite3_open( dbPath.c_str( ), &db_ ) != SQLITE_OK ) {<BR>
|
||
|
|
std::cerr << "Failed to open database:" << sqlite3_errmsg( db_ ) << std::endl;<BR>
|
||
|
|
db_ = nullptr;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_file_executor.cpp: 14"> 14 </A>SQLiteFileExecutor::~SQLiteFileExecutor( ) {<BR>
|
||
|
|
if ( db_ ) {<BR>
|
||
|
|
sqlite3_close( db_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Execute a SQL file<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_file_executor.cpp: 21"> 21 </A>void SQLiteFileExecutor::executeSQLFile( const std::string &sqlFilePath ) {<BR>
|
||
|
|
if ( db_ == nullptr ) {<BR>
|
||
|
|
throw std::runtime_error( "Database is not open" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
std::string sqlContent;<BR>
|
||
|
|
if ( !read( sqlFilePath, sqlContent ) ) {<BR>
|
||
|
|
throw std::runtime_error( "Failed to read SQL file: " + sqlFilePath );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
char *errorMessage = nullptr;<BR>
|
||
|
|
if ( sqlite3_exec( db_, sqlContent.c_str( ), nullptr, nullptr, &errorMessage ) !=<BR>
|
||
|
|
SQLITE_OK ) {<BR>
|
||
|
|
std::cerr << "Error executing SQL:" << errorMessage << std::endl;<BR>
|
||
|
|
sqlite3_free( errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./tests_schema/tests_sources/sqlite_statement.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 1"> 1 </A>#include "sqlite_statement.h"<BR>
|
||
|
|
#include <iostream><BR>
|
||
|
|
<BR>
|
||
|
|
// Constructor: Prepares the SQL statement<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 5"> 5 </A>SQLiteStatement::SQLiteStatement( sqlite3 *db, const std::string &query )<BR>
|
||
|
|
: db_( db ), stmt_( nullptr ) {<BR>
|
||
|
|
if ( db == nullptr ) {<BR>
|
||
|
|
throw std::invalid_argument( "Database connection is null" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( sqlite3_prepare_v2( db, query.c_str( ), -1, &stmt_, nullptr ) != SQLITE_OK ) {<BR>
|
||
|
|
std::cerr << "Error preparing SQL statement:" << "\"" + query + "\""<BR>
|
||
|
|
<< std::endl;<BR>
|
||
|
|
std::cerr << "Error message:" << sqlite3_errmsg( db ) << std::endl;<BR>
|
||
|
|
<BR>
|
||
|
|
if ( stmt_ ) {<BR>
|
||
|
|
sqlite3_finalize( stmt_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
throw std::runtime_error( "Failed to prepare SQLite statement: " + query );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Destructor: Finalizes the statement<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 25"> 25 </A>SQLiteStatement::~SQLiteStatement( ) { finalize( ); }<BR>
|
||
|
|
<BR>
|
||
|
|
// Bind integer value<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 28"> 28 </A>bool SQLiteStatement::bind( int index, int value ) {<BR>
|
||
|
|
return sqlite3_bind_int( stmt_, index, value ) == SQLITE_OK;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Bind double value<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 33"> 33 </A>bool SQLiteStatement::bind( int index, double value ) {<BR>
|
||
|
|
return sqlite3_bind_double( stmt_, index, value ) == SQLITE_OK;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Bind text value<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 38"> 38 </A>bool SQLiteStatement::bind( int index, const std::string &value ) {<BR>
|
||
|
|
return sqlite3_bind_text( stmt_, index, value.c_str( ), -1, SQLITE_TRANSIENT ) ==<BR>
|
||
|
|
SQLITE_OK;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Bind NULL value<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 44"> 44 </A>bool SQLiteStatement::bindNull( int index ) {<BR>
|
||
|
|
return sqlite3_bind_null( stmt_, index ) == SQLITE_OK;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Run the statement<BR>
|
||
|
|
// step( ) returns true if there are more rows<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 50"> 50 </A>bool SQLiteStatement::execute( ) { return step( ) == false; }<BR>
|
||
|
|
<BR>
|
||
|
|
// Execute the statement<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 53"> 53 </A>bool SQLiteStatement::step( ) {<BR>
|
||
|
|
int rc = sqlite3_step( stmt_ );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( rc == SQLITE_ROW ) {<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( rc == SQLITE_DONE ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
std::cerr << "Failed to step:" << sqlite3_errmsg( db_ ) << std::endl;<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Get the number of rows affected<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 68"> 68 </A>int SQLiteStatement::changes( ) { return sqlite3_changes( db_ ); }<BR>
|
||
|
|
<BR>
|
||
|
|
// Reset the statement for re-use<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 71"> 71 </A>void SQLiteStatement::reset( ) { sqlite3_reset( stmt_ ); }<BR>
|
||
|
|
<BR>
|
||
|
|
// Finalize and clean up the statement<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 74"> 74 </A>void SQLiteStatement::finalize( ) {<BR>
|
||
|
|
if ( stmt_ ) {<BR>
|
||
|
|
sqlite3_finalize( stmt_ );<BR>
|
||
|
|
stmt_ = nullptr;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Adapter for sqlite3_column_count<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 82"> 82 </A>int SQLiteStatement::getColumnCount( ) const {<BR>
|
||
|
|
return sqlite3_column_count( stmt_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Adapter for sqlite3_column_text<BR>
|
||
|
|
<A NAME="./tests_schema/tests_sources/sqlite_statement.cpp: 87"> 87 </A>std::string SQLiteStatement::getColumnText( int column_index ) const {<BR>
|
||
|
|
const unsigned char *text = sqlite3_column_text( stmt_, column_index );<BR>
|
||
|
|
return text ? reinterpret_cast<const char *>( text ) : "";<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/delegates/date_time_delegate.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/delegates/date_time_delegate.cpp: 1"> 1 </A>#include "date_time_delegate.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/delegates/date_time_delegate.cpp: 3"> 3 </A>DateTimeDelegate::DateTimeDelegate( QObject *parent )<BR>
|
||
|
|
: QStyledItemDelegate( parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/delegates/date_time_delegate.cpp: 6"> 6 </A>QString DateTimeDelegate::displayText( const QVariant &value, <BR>
|
||
|
|
<A NAME="./ui/delegates/date_time_delegate.cpp: 7"> 7 </A> const QLocale &locale ) const {<BR>
|
||
|
|
QDateTime datetime = QDateTime::fromString( value.toString( ), Qt::ISODate );<BR>
|
||
|
|
if ( !datetime.isValid( ) ) {<BR>
|
||
|
|
return value.toString( ); // Return raw value if parsing fails<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString formattedDateTime = locale.toString( datetime, QLocale::LongFormat );<BR>
|
||
|
|
if ( !formattedDateTime.isEmpty( ) ) {<BR>
|
||
|
|
// Capitalize the first letter of the formatted date string<BR>
|
||
|
|
formattedDateTime[0] = formattedDateTime[0].toUpper( );<BR>
|
||
|
|
}<BR>
|
||
|
|
return formattedDateTime;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/dialogs/auth_dialog.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 1"> 1 </A>#include "auth_dialog.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "role_dto.h"<BR>
|
||
|
|
#include "roles_repository.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "user_dto.h"<BR>
|
||
|
|
#include "users_repository.h"<BR>
|
||
|
|
#include <QCryptographicHash><BR>
|
||
|
|
#include <QErrorMessage><BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 14"> 14 </A>AuthDialog::AuthDialog( QWidget *parent ) : QDialog( parent ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
// WARNING: Models must be initialized before setting up table view<BR>
|
||
|
|
if ( initializeRepositories( ) ) {<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
} else {<BR>
|
||
|
|
qWarning( ) << "Initialization failed";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 25"> 25 </A>bool AuthDialog::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
rolesRepository_ = repositoryManager.getRepositoryAs<RolesRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "roles" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
usersRepository_ = repositoryManager.getRepositoryAs<UsersRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "users" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return rolesRepository_ && usersRepository_;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 38"> 38 </A>void AuthDialog::setupConnections( ) {<BR>
|
||
|
|
connect( btnLogin, &QPushButton::clicked, this, &AuthDialog::onLoginClicked );<BR>
|
||
|
|
connect( btnCancel, &QPushButton::clicked, this, &AuthDialog::onCancelClicked );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 43"> 43 </A>void AuthDialog::onCancelClicked( ) {<BR>
|
||
|
|
emit loginFailed( );<BR>
|
||
|
|
reject( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 48"> 48 </A>void AuthDialog::onLoginClicked( ) {<BR>
|
||
|
|
QString username = txtUsername->text( ).trimmed( );<BR>
|
||
|
|
QString password = txtPassword->text( );<BR>
|
||
|
|
<BR>
|
||
|
|
UserDTO userDTO;<BR>
|
||
|
|
RepositoryResult result =<BR>
|
||
|
|
usersRepository_->getUserByUsername( username, userDTO );<BR>
|
||
|
|
<BR>
|
||
|
|
bool userExists = result.success;<BR>
|
||
|
|
bool passwordMatch = !userExists ? false : verifyPassword( password, userDTO );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !userExists || !passwordMatch ) {<BR>
|
||
|
|
QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
QMessageBox::tr( "Wrong user name or password" ) );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
RoleDTO roleDTO;<BR>
|
||
|
|
result = rolesRepository_->getRoleById( userDTO.roleId( ), roleDTO );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
QMessageBox::tr( "Role of user not found" ) );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qint32 userId = userDTO.userId( );<BR>
|
||
|
|
qint32 accessLevel_ = roleDTO.accessLevel( );<BR>
|
||
|
|
<BR>
|
||
|
|
emit loginSuccessful( userId, accessLevel_ );<BR>
|
||
|
|
<BR>
|
||
|
|
accept( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 82"> 82 </A>QString AuthDialog::hashPassword( const QString &password, const QString &salt ) {<BR>
|
||
|
|
QByteArray data = ( password + salt ).toUtf8( );<BR>
|
||
|
|
<BR>
|
||
|
|
QByteArray hash = QCryptographicHash::hash( data, QCryptographicHash::Sha256 );<BR>
|
||
|
|
<BR>
|
||
|
|
return QString( hash.toHex( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 90"> 90 </A>bool AuthDialog::verifyPassword( const QString &password, <BR>
|
||
|
|
<A NAME="./ui/dialogs/auth_dialog.cpp: 91"> 91 </A> const UserDTO &userDTO ) {<BR>
|
||
|
|
QString inputHash = hashPassword( password, userDTO.salt( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return ( inputHash == userDTO.passwordHash( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/dialogs/error_dialog.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 1"> 1 </A>#include "error_dialog.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QCheckBox><BR>
|
||
|
|
#include <QDebug><BR>
|
||
|
|
#include <QErrorMessage><BR>
|
||
|
|
#include <QRegularExpression><BR>
|
||
|
|
#include <QRegularExpressionMatch><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 9"> 9 </A>QErrorMessage *ErrorDialog::getDialog( QWidget *parent, <BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 10"> 10 </A> const QString &errorMsg ) {<BR>
|
||
|
|
// Initialize the error dialog<BR>
|
||
|
|
QErrorMessage *dialog =<BR>
|
||
|
|
new QErrorMessage( parent ); // parent is needed for the correct location<BR>
|
||
|
|
dialog->setAttribute( Qt::WA_DeleteOnClose ); // delete the dialog when closed<BR>
|
||
|
|
<BR>
|
||
|
|
// Hide the "don't show again" checkbox<BR>
|
||
|
|
#define ERROR_DIALOG_NEW_VERSION 0<BR>
|
||
|
|
#if ( ERROR_DIALOG_NEW_VERSION == 1 && QT_VERSION >= QT_VERSION_CHECK( 6, 3, 0 ) )<BR>
|
||
|
|
// You need to set DontShowAgainVisible to true in Qt 6.3<BR>
|
||
|
|
errorDialog->setDontShowAgainVisible( false );<BR>
|
||
|
|
#else<BR>
|
||
|
|
QCheckBox *cb = dialog->findChild<QCheckBox *>( );<BR>
|
||
|
|
if ( cb ) {<BR>
|
||
|
|
cb->setEnabled( false );<BR>
|
||
|
|
cb->hide( );<BR>
|
||
|
|
}<BR>
|
||
|
|
#endif<BR>
|
||
|
|
#undef ERROR_DIALOG_NEW_VERSION<BR>
|
||
|
|
<BR>
|
||
|
|
// Set the window title<BR>
|
||
|
|
dialog->setWindowTitle( QObject::tr( "Information messages" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
// Set minimum width size<BR>
|
||
|
|
dialog->setMinimumWidth( 600 );<BR>
|
||
|
|
<BR>
|
||
|
|
return dialog;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 39"> 39 </A>void ErrorDialog::displayError( QWidget *parent, const QString &errorMsg ) {<BR>
|
||
|
|
qDebug( ) << "Displaying error message:" << errorMsg;<BR>
|
||
|
|
<BR>
|
||
|
|
QErrorMessage *dialog = getDialog( parent, errorMsg );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( errorMsg.contains( "constraint failed" ) ) {<BR>
|
||
|
|
QString detailedMessage = handleSqlConstraints( errorMsg );<BR>
|
||
|
|
dialog->showMessage( detailedMessage );<BR>
|
||
|
|
dialog->exec( );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( errorMsg.contains( "not found" ) ) {<BR>
|
||
|
|
QString detailedMessage = handleNotFoundErrors( errorMsg );<BR>
|
||
|
|
dialog->showMessage( detailedMessage );<BR>
|
||
|
|
dialog->exec( );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QRegularExpression regex( "Error ( \\d+ ):" );<BR>
|
||
|
|
QRegularExpressionMatch match = regex.match( errorMsg );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !match.hasMatch( ) ) {<BR>
|
||
|
|
dialog->showMessage( QObject::tr( <BR>
|
||
|
|
"An error occurred from an unknown source of the problem." ) );<BR>
|
||
|
|
dialog->exec( );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
int errorCode = match.captured( 1 ).toInt( );<BR>
|
||
|
|
QString detailedMessage = getDetailedMessage( errorCode );<BR>
|
||
|
|
<BR>
|
||
|
|
dialog->showMessage( detailedMessage );<BR>
|
||
|
|
dialog->exec( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 75"> 75 </A>QString ErrorDialog::handleNotFoundErrors( const QString &errorMsg ) {<BR>
|
||
|
|
if ( errorMsg.contains( "Genre", Qt::CaseInsensitive ) ) {<BR>
|
||
|
|
return QObject::tr( "The specified genre was not found." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "Hall", Qt::CaseInsensitive ) ) {<BR>
|
||
|
|
return QObject::tr( "The specified hall was not found." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "Movie", Qt::CaseInsensitive ) ) {<BR>
|
||
|
|
return QObject::tr( "The specified movie was not found." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "Refund", Qt::CaseInsensitive ) ) {<BR>
|
||
|
|
return QObject::tr( "The specified refund was not found." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "Session", Qt::CaseInsensitive ) ) {<BR>
|
||
|
|
return QObject::tr( "The specified session was not found." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "Ticket", Qt::CaseInsensitive ) ) {<BR>
|
||
|
|
return QObject::tr( "The specified ticket was not found." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// If the specific error is not recognized, return a general message<BR>
|
||
|
|
return QObject::tr( "The requested object was not found in the database." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 99"> 99 </A>QString ErrorDialog::handleSqlConstraints( const QString &errorMsg ) {<BR>
|
||
|
|
if ( errorMsg.contains( "UNIQUE constraint failed" ) ) {<BR>
|
||
|
|
return handleUniqueConstraint( errorMsg );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "FOREIGN KEY constraint failed" ) ) {<BR>
|
||
|
|
return handleForeignKeyConstraint( errorMsg );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "PRIMARY KEY constraint failed" ) ) {<BR>
|
||
|
|
return handlePrimaryKeyConstraint( );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "CHECK constraint failed" ) ) {<BR>
|
||
|
|
return handleCheckConstraint( errorMsg );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "NOT NULL constraint failed" ) ) {<BR>
|
||
|
|
return tr( "A required field is missing. Please fill all required fields." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return tr( "An SQL constraint violation occurred, but at the moment it has "<BR>
|
||
|
|
"not been described in detail yet." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 120"> 120 </A>QString ErrorDialog::handleUniqueConstraint( const QString &errorMsg ) {<BR>
|
||
|
|
if ( errorMsg.contains( "genres.genre_name" ) ) {<BR>
|
||
|
|
return tr( "A genre with the same name already exists." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "movies.title" ) ) {<BR>
|
||
|
|
return tr( "A movie with the same title already exists." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "halls.hall_name" ) ) {<BR>
|
||
|
|
return tr( "A hall with the same name already exists." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "tickets.session_id, tickets.seat_number" ) ) {<BR>
|
||
|
|
return tr( "A ticket with the same session and seat number already exists." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "refunds.ticket_id" ) ) {<BR>
|
||
|
|
return tr( "A refund for the same ticket already exists." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "sessions.hall_id, sessions.begin_at" ) ) {<BR>
|
||
|
|
return tr( "A session is already scheduled in this hall at the same time." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return tr( "A unique constraint violation occurred, but at the moment it has "<BR>
|
||
|
|
"not been described in detail yet." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 144"> 144 </A>QString ErrorDialog::handleForeignKeyConstraint( const QString &errorMsg ) {<BR>
|
||
|
|
if ( errorMsg.contains( "sessions.movie_id" ) ) {<BR>
|
||
|
|
return tr( "The movie ID for the session does not exist." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "sessions.hall_id" ) ) {<BR>
|
||
|
|
return tr( "The hall ID for the session does not exist." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "movies.genre_id" ) ) {<BR>
|
||
|
|
return tr( "The genre ID for the movie does not exist." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "tickets.session_id" ) ) {<BR>
|
||
|
|
return tr( "The session ID for the ticket does not exist." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "refunds.ticket_id" ) ) {<BR>
|
||
|
|
return tr( "The ticket ID for the refund does not exist." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return tr( "Operation violates a foreign key constraint, but at the moment it "<BR>
|
||
|
|
"has not been described in detail yet." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 165"> 165 </A>QString ErrorDialog::handlePrimaryKeyConstraint( ) {<BR>
|
||
|
|
return tr( "Duplicate primary key value. Ensure the primary key is unique." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 169"> 169 </A>QString ErrorDialog::handleCheckConstraint( const QString &errorMsg ) {<BR>
|
||
|
|
if ( errorMsg.contains( "length( genre_name ) > 0" ) ) {<BR>
|
||
|
|
return tr( "Genre name must not be empty." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "length( title ) > 0" ) ) {<BR>
|
||
|
|
return tr( "Movie title must not be empty." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "duration > 0" ) ) {<BR>
|
||
|
|
return tr( "Movie duration must be a positive value." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "length( hall_name ) > 0" ) ) {<BR>
|
||
|
|
return tr( "Hall name must not be empty." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "capacity > 0" ) ) {<BR>
|
||
|
|
return tr( "Hall capacity must be a positive number." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "ticket_price >= 0" ) ) {<BR>
|
||
|
|
return tr( "Ticket price must be a non-negative value." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "seat_number > 0" ) ) {<BR>
|
||
|
|
return tr( "Seat number must be a positive value." );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( errorMsg.contains( "refund_amount >= 0" ) ) {<BR>
|
||
|
|
return tr( "Refund amount must be a non-negative value." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return tr( "A value violates a CHECK constraint, but at the moment it has not "<BR>
|
||
|
|
"been described in detail yet." );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/error_dialog.cpp: 199"> 199 </A>QString ErrorDialog::getDetailedMessage( int errorCode ) {<BR>
|
||
|
|
switch ( errorCode ) {<BR>
|
||
|
|
case 1001:<BR>
|
||
|
|
return tr( "Seat number exceeds hall capacity." );<BR>
|
||
|
|
case 1002:<BR>
|
||
|
|
return tr( "Cannot purchase ticket after the session has started." );<BR>
|
||
|
|
case 1003:<BR>
|
||
|
|
return tr( "Refunds cannot be made after the session has started." );<BR>
|
||
|
|
case 1004:<BR>
|
||
|
|
return tr( "Refund amount cannot exceed the sale amount." );<BR>
|
||
|
|
case 1005:<BR>
|
||
|
|
return tr( "Refund date cannot be earlier than the sale date." );<BR>
|
||
|
|
case 1006:<BR>
|
||
|
|
return tr( "The new session overlaps with an ongoing movie in the hall." );<BR>
|
||
|
|
default:<BR>
|
||
|
|
return tr( "A known error has occurred, but at the moment it has not been "<BR>
|
||
|
|
"described in detail yet." );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/dialogs/search_dialog.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 1"> 1 </A>#include "search_dialog.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "base_sql_table_model.h"<BR>
|
||
|
|
#include "model_manager.h"<BR>
|
||
|
|
#include "multi_column_filter_proxy_model.h"<BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 8"> 8 </A>SearchDialog::SearchDialog( QWidget *parent )<BR>
|
||
|
|
: QDialog( parent ), originalModel_( nullptr ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
initializeProxyModel( );<BR>
|
||
|
|
setupTableView( ); // After initializing proxy model<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 17"> 17 </A>SearchDialog::SearchDialog( const QString &modelTableName, <BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 18"> 18 </A> const QString &fieldName, QWidget *parent )<BR>
|
||
|
|
: SearchDialog( parent ) {<BR>
|
||
|
|
if ( !setTableName( modelTableName ) ) {<BR>
|
||
|
|
qFatal( "SearchDialog::SearchDialog: Failed to set table name" );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( !setFieldName( fieldName ) ) {<BR>
|
||
|
|
qFatal( "SearchDialog::SearchDialog: Failed to set field name" );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 28"> 28 </A>SearchDialog::~SearchDialog( ) {<BR>
|
||
|
|
if ( originalModel_ != nullptr ) {<BR>
|
||
|
|
originalModel_->resetFilter( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 34"> 34 </A>bool SearchDialog::setFieldName( const QString &fieldName ) {<BR>
|
||
|
|
int columnIndex = originalModel_->columnIndex( fieldName );<BR>
|
||
|
|
if ( columnIndex == -1 ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
columnIndex_ = columnIndex;<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 43"> 43 </A>bool SearchDialog::setTableName( const QString &modelTableName ) {<BR>
|
||
|
|
ModelManager &modelManger = ModelManager::instance( );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( originalModel_ != nullptr ) {<BR>
|
||
|
|
originalModel_->resetFilter( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
modelTableName_ = modelTableName;<BR>
|
||
|
|
<BR>
|
||
|
|
originalModel_ = modelManger.getModelAs<BaseSqlTableModel>( modelTableName );<BR>
|
||
|
|
<BR>
|
||
|
|
proxyModel_->setSourceModel( originalModel_ );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->clearSelection( );<BR>
|
||
|
|
<BR>
|
||
|
|
columnIndex_ = -1;<BR>
|
||
|
|
<BR>
|
||
|
|
if ( originalModel_->isCompleteDatabaseFiltering( ) ) {<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
#ifdef NOPTIMIZATION<BR>
|
||
|
|
while ( originalModel_->canFetchMore( ) ) {<BR>
|
||
|
|
originalModel_->fetchMore( );<BR>
|
||
|
|
}<BR>
|
||
|
|
#endif<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 73"> 73 </A>void SearchDialog::initializeProxyModel( ) {<BR>
|
||
|
|
proxyModel_ = new MultiColumnSortFilterProxyModel( this );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 77"> 77 </A>void SearchDialog::setupConnections( ) {<BR>
|
||
|
|
connect( lineEditSearch, &QLineEdit::textChanged, this, <BR>
|
||
|
|
&SearchDialog::onLineEditSearchTextChanged );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( pushButtonSelect, &QPushButton::clicked, this, <BR>
|
||
|
|
&SearchDialog::onPushButtonSelectClicked );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 85"> 85 </A>void SearchDialog::setupTableView( ) {<BR>
|
||
|
|
QHeaderView *horizontalHeader = tableView->horizontalHeader( );<BR>
|
||
|
|
horizontalHeader->setHighlightSections( false );<BR>
|
||
|
|
horizontalHeader->setSectionResizeMode( QHeaderView::ResizeToContents );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setAlternatingRowColors( true );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setEditTriggers( QAbstractItemView::NoEditTriggers );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setFocusPolicy( Qt::NoFocus );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setHorizontalScrollMode( QAbstractItemView::ScrollPerPixel );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setSelectionBehavior( QAbstractItemView::SelectRows );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setSelectionMode( QAbstractItemView::SingleSelection );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setSortingEnabled( true );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->sortByColumn( 0, Qt::AscendingOrder );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setModel( proxyModel_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 111"> 111 </A>void SearchDialog::onLineEditSearchTextChanged( const QString &text ) {<BR>
|
||
|
|
ModelManager &modelManger = ModelManager::instance( );<BR>
|
||
|
|
<BR>
|
||
|
|
#ifdef NOPTIMIZATION<BR>
|
||
|
|
if ( originalModel_->isCompleteDatabaseFiltering( ) ) {<BR>
|
||
|
|
originalModel_->setMultiColumnFilter( text );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Model filtering<BR>
|
||
|
|
QRegularExpression regex( text, QRegularExpression::CaseInsensitiveOption );<BR>
|
||
|
|
proxyModel_->setFilterRegularExpression( regex );<BR>
|
||
|
|
#else<BR>
|
||
|
|
// Database filtering<BR>
|
||
|
|
originalModel_->setMultiColumnFilter( text );<BR>
|
||
|
|
#endif<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/dialogs/search_dialog.cpp: 129"> 129 </A>void SearchDialog::onPushButtonSelectClicked( ) {<BR>
|
||
|
|
if ( columnIndex_ == -1 ) {<BR>
|
||
|
|
qFatal( "SearchDialog::onPushButtonSelectClicked: Column index not set" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QModelIndexList selectedIndexes = tableView->selectionModel( )->selectedRows( );<BR>
|
||
|
|
if ( selectedIndexes.isEmpty( ) ) {<BR>
|
||
|
|
QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
QMessageBox::tr( "No row selected" ) );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QModelIndex selectedRowIndex = selectedIndexes.first( );<BR>
|
||
|
|
emit rowSelected( selectedRowIndex.row( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QSqlRecord record = originalModel_->record( selectedRowIndex.row( ) );<BR>
|
||
|
|
emit recordRetrieved( record );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( columnIndex_ != -1 ) {<BR>
|
||
|
|
QSqlRecord record = originalModel_->record( selectedRowIndex.row( ) );<BR>
|
||
|
|
QSqlField field = record.field( columnIndex_ );<BR>
|
||
|
|
emit fieldRetrieved( field );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
accept( );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/main_window/main_window.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/main_window/main_window.cpp: 1"> 1 </A>#include "main_window.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "date_time_delegate.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// Set up the table view<BR>
|
||
|
|
// #define ENABLE_SELECTION // Uncomment to enable highlighting<BR>
|
||
|
|
#define DISABLE_SELECTION // Uncomment to disable highlighting<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/main_window/main_window.cpp: 9"> 9 </A>MainWindow::MainWindow( qint32 userId, qint32 accessLevel, QWidget *parent )<BR>
|
||
|
|
: QMainWindow( parent ), userId_( userId ), accessLevel_( accessLevel ) {<BR>
|
||
|
|
qInfo( ) << "Initializing main window...";<BR>
|
||
|
|
<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
configureAllTableViews( );<BR>
|
||
|
|
configureAccessLevel( );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Main window initialized successfully";<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/main_window/main_window.cpp: 20"> 20 </A>void MainWindow::configureAccessLevel( ) {<BR>
|
||
|
|
qInfo( ) << "Configuring access level...";<BR>
|
||
|
|
<BR>
|
||
|
|
if ( accessLevel_ < 1 ) {<BR>
|
||
|
|
qCritical( ) << "Access level is less than 1";<BR>
|
||
|
|
QCoreApplication::quit( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Access level is" << accessLevel_;<BR>
|
||
|
|
<BR>
|
||
|
|
// Full access to all system functionalities<BR>
|
||
|
|
// Manage system settings and user permissions<BR>
|
||
|
|
// Can perform all actions of lower roles<BR>
|
||
|
|
if ( accessLevel_ < 100 ) { // Lower than Super Administrator<BR>
|
||
|
|
}<BR>
|
||
|
|
// Delete records ( sessions, tickets, halls, movies, genres )<BR>
|
||
|
|
// Modify system-critical data<BR>
|
||
|
|
// Has all permissions of lower roles<BR>
|
||
|
|
if ( accessLevel_ < 82 ) { // Lower than Data Administrator<BR>
|
||
|
|
findChild<QWidget *>( "DangerZonePage" )->setDisabled( true );<BR>
|
||
|
|
}<BR>
|
||
|
|
// Add new sessions, movies, halls, and genres<BR>
|
||
|
|
// Manage show schedules<BR>
|
||
|
|
// Has all permissions of lower roles<BR>
|
||
|
|
if ( accessLevel_ < 64 ) { // Lower than Repertoire Manager<BR>
|
||
|
|
findChild<QWidget *>( "DirectoriesManagementPage" )->setDisabled( true );<BR>
|
||
|
|
findChild<QWidget *>( "SessionManagementPage" )->setDisabled( true );<BR>
|
||
|
|
}<BR>
|
||
|
|
// Edit session, movie, hall, and genre information<BR>
|
||
|
|
// Adjust ticket prices<BR>
|
||
|
|
// Has all permissions of lower roles<BR>
|
||
|
|
if ( accessLevel_ < 46 ) { // Lower than Data Editor<BR>
|
||
|
|
}<BR>
|
||
|
|
// View ticket sales<BR>
|
||
|
|
// View attendance statistics<BR>
|
||
|
|
// Has all permissions of lower roles<BR>
|
||
|
|
if ( accessLevel_ < 28 ) { // Lower than Sales Manager<BR>
|
||
|
|
findChild<QWidget *>( "ReportsPage" )->setDisabled( true );<BR>
|
||
|
|
}<BR>
|
||
|
|
// Sell tickets<BR>
|
||
|
|
// Ticket refunds<BR>
|
||
|
|
if ( accessLevel_ < 10 ) { // Lower than Cashier<BR>
|
||
|
|
findChild<QWidget *>( "MainWindow" )->setDisabled( true );<BR>
|
||
|
|
}<BR>
|
||
|
|
// Nothing<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Access level configured successfully";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/main_window/main_window.cpp: 69"> 69 </A>void MainWindow::configureAllTableViews( ) {<BR>
|
||
|
|
qInfo( ) << "Configuring all QAbstractItemViews...";<BR>
|
||
|
|
<BR>
|
||
|
|
// Find all QAbstractItemView children<BR>
|
||
|
|
auto tableViews = findChildren<QAbstractItemView *>( );<BR>
|
||
|
|
<BR>
|
||
|
|
for ( QAbstractItemView *abstractItemView : tableViews ) {<BR>
|
||
|
|
<BR>
|
||
|
|
// Check if the view is a QTableView<BR>
|
||
|
|
if ( auto *tableView = qobject_cast<QTableView *>( abstractItemView ) ) {<BR>
|
||
|
|
loadDefaultConfiguration( tableView );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "All QAbstractItemViews configured successfully";<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/main_window/main_window.cpp: 86"> 86 </A>void MainWindow::MainWindow::disableSelection( QTableView *tableView ) {<BR>
|
||
|
|
qInfo( ) << "Disabling selection for QAbstractItemView:"<BR>
|
||
|
|
<< tableView->objectName( );<BR>
|
||
|
|
<BR>
|
||
|
|
// Disable selection<BR>
|
||
|
|
tableView->setSelectionMode( QAbstractItemView::NoSelection );<BR>
|
||
|
|
<BR>
|
||
|
|
// Clear the selection<BR>
|
||
|
|
tableView->clearSelection( );<BR>
|
||
|
|
<BR>
|
||
|
|
// Disable focus<BR>
|
||
|
|
tableView->setFocusPolicy( Qt::NoFocus );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/main_window/main_window.cpp: 100"> 100 </A>void enableSelection( QTableView *tableView ) {<BR>
|
||
|
|
qInfo( ) << "Enabling selection for QAbstractItemView:"<BR>
|
||
|
|
<< tableView->objectName( );<BR>
|
||
|
|
<BR>
|
||
|
|
// Set the selection behavior<BR>
|
||
|
|
tableView->setSelectionBehavior( QAbstractItemView::SelectRows );<BR>
|
||
|
|
<BR>
|
||
|
|
// Set the selection mode<BR>
|
||
|
|
tableView->setSelectionMode( QAbstractItemView::SingleSelection );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/main_window/main_window.cpp: 111"> 111 </A>void MainWindow::loadDefaultConfiguration( QTableView *tableView ) {<BR>
|
||
|
|
qInfo( ) << "Loading default configuration for QAbstractItemView:"<BR>
|
||
|
|
<< tableView->objectName( );<BR>
|
||
|
|
<BR>
|
||
|
|
DateTimeDelegate *dateTimeDelegate = new DateTimeDelegate( this );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setItemDelegate( dateTimeDelegate );<BR>
|
||
|
|
<BR>
|
||
|
|
QHeaderView *horizontalHeader = tableView->horizontalHeader( );<BR>
|
||
|
|
// Disable horizontal header highlight<BR>
|
||
|
|
horizontalHeader->setHighlightSections( false );<BR>
|
||
|
|
// Set the horizontal header to resize to contents<BR>
|
||
|
|
horizontalHeader->setSectionResizeMode( QHeaderView::ResizeToContents );<BR>
|
||
|
|
<BR>
|
||
|
|
tableView->setSortingEnabled( true ); // Enable sorting<BR>
|
||
|
|
tableView->sortByColumn( 0, Qt::AscendingOrder );<BR>
|
||
|
|
<BR>
|
||
|
|
// Disable editing<BR>
|
||
|
|
tableView->setEditTriggers( QAbstractItemView::NoEditTriggers );<BR>
|
||
|
|
<BR>
|
||
|
|
// Set the scroll mode<BR>
|
||
|
|
tableView->setVerticalScrollMode( QAbstractItemView::ScrollPerPixel );<BR>
|
||
|
|
tableView->setHorizontalScrollMode( QAbstractItemView::ScrollPerPixel );<BR>
|
||
|
|
<BR>
|
||
|
|
// Enable alternating row colors<BR>
|
||
|
|
tableView->setAlternatingRowColors( true );<BR>
|
||
|
|
<BR>
|
||
|
|
#ifdef ENABLE_SELECTION<BR>
|
||
|
|
enableSelection( view );<BR>
|
||
|
|
#elif defined( DISABLE_SELECTION )<BR>
|
||
|
|
disableSelection( tableView );<BR>
|
||
|
|
#else<BR>
|
||
|
|
#error "Define ENABLE_SELECTION or DISABLE_SELECTION"<BR>
|
||
|
|
#endif<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/models/base_sql_table_model.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 1"> 1 </A>#include "base_sql_table_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "QSqlError"<BR>
|
||
|
|
#include "table_info_sqlite.h"<BR>
|
||
|
|
#include <QDateTime><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 8"> 8 </A>BaseSqlTableModel::BaseSqlTableModel( QObject *parent, QSqlDatabase database )<BR>
|
||
|
|
: QSqlRelationalTableModel( parent, database ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 11"> 11 </A>bool BaseSqlTableModel::refreshAll( ) {<BR>
|
||
|
|
beginResetModel( );<BR>
|
||
|
|
bool result = select( );<BR>
|
||
|
|
endResetModel( );<BR>
|
||
|
|
<BR>
|
||
|
|
result ? qInfo( ) << "Model of table with database name" << tableName( )<BR>
|
||
|
|
<< "was refreshed successfully"<BR>
|
||
|
|
: qWarning( ) << "Failed to refresh model: Database name of table:"<BR>
|
||
|
|
<< tableName( ) << "Error:" << lastError( ).text( );<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 23"> 23 </A>QVariant BaseSqlTableModel::data( const QModelIndex &index, int role ) const {<BR>
|
||
|
|
// if ( role != Qt::DisplayRole ) {<BR>
|
||
|
|
return QSqlRelationalTableModel::data( index, role );<BR>
|
||
|
|
// }<BR>
|
||
|
|
//<BR>
|
||
|
|
// QVariant value = QSqlRelationalTableModel::data( index, role );<BR>
|
||
|
|
//<BR>
|
||
|
|
// QDateTime datetime = QDateTime::fromString( value.toString( ), Qt::ISODate );<BR>
|
||
|
|
//<BR>
|
||
|
|
// if ( !datetime.isValid( ) ) {<BR>
|
||
|
|
// return value;<BR>
|
||
|
|
// }<BR>
|
||
|
|
//<BR>
|
||
|
|
// QLocale locale;<BR>
|
||
|
|
// QString formattedDateTime = locale.toString( datetime, QLocale::LongFormat );<BR>
|
||
|
|
//<BR>
|
||
|
|
// formattedDateTime[0] = formattedDateTime[0].toUpper( );<BR>
|
||
|
|
//<BR>
|
||
|
|
// return formattedDateTime;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 44"> 44 </A>void BaseSqlTableModel::setTable( const QString &databaseTableName ) {<BR>
|
||
|
|
tableInfo_.setDatabaseTableName( databaseTableName );<BR>
|
||
|
|
QSqlRelationalTableModel::setTable( databaseTableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 49"> 49 </A>void BaseSqlTableModel::resetFilter( ) {<BR>
|
||
|
|
qInfo( ).noquote( ) << createUpdateFilterMessage( "" );<BR>
|
||
|
|
setFilter( "" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 54"> 54 </A>void BaseSqlTableModel::setMultiColumnFilter( const QString &filter ) {<BR>
|
||
|
|
if ( filter.isEmpty( ) ) {<BR>
|
||
|
|
resetFilter( );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const QString filterQuery = createMultiColumnFilter( filter );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ).noquote( ) << createUpdateFilterMessage( filter );<BR>
|
||
|
|
<BR>
|
||
|
|
setFilter( filterQuery );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString<BR>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 68"> 68 </A>BaseSqlTableModel::createMultiColumnFilter( const QString &filter ) const {<BR>
|
||
|
|
<BR>
|
||
|
|
QStringList conditions;<BR>
|
||
|
|
for ( const QString &column : columnNames( ) ) {<BR>
|
||
|
|
conditions.append( QString( "%1 LIKE '%%2%'" ).arg( column ).arg( filter ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return conditions.join( " OR " );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString<BR>
|
||
|
|
<A NAME="./ui/models/base_sql_table_model.cpp: 79"> 79 </A>BaseSqlTableModel::createUpdateFilterMessage( const QString &filter ) const {<BR>
|
||
|
|
QString classInfoMessage =<BR>
|
||
|
|
QString( "Model manager class name: %1" ).arg( metaObject( )->className( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QString tableInfoMessage =<BR>
|
||
|
|
QString( "Database table name: %1" ).arg( tableName( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QString filterInfoMessage = filter.isEmpty( )<BR>
|
||
|
|
? "The filter was reset"<BR>
|
||
|
|
: QString( "Filter: \"%1\"" ).arg( filter );<BR>
|
||
|
|
<BR>
|
||
|
|
QString message = QString( "The model was updated: %1: %2: %3" )<BR>
|
||
|
|
.arg( classInfoMessage )<BR>
|
||
|
|
.arg( tableInfoMessage )<BR>
|
||
|
|
.arg( filterInfoMessage );<BR>
|
||
|
|
<BR>
|
||
|
|
return message;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/models/genres_model.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/models/genres_model.cpp: 1"> 1 </A>#include "genres_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/genres_model.cpp: 5"> 5 </A>GenresModel::GenresModel( QObject *parent, const QSqlDatabase &database )<BR>
|
||
|
|
: BaseSqlTableModel( parent, database ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/genres_model.cpp: 8"> 8 </A>void GenresModel::initialize( ) {<BR>
|
||
|
|
setTable( "genres" );<BR>
|
||
|
|
<BR>
|
||
|
|
setEditStrategy( QSqlTableModel::OnFieldChange );<BR>
|
||
|
|
<BR>
|
||
|
|
bool success = select( );<BR>
|
||
|
|
if ( !success ) {<BR>
|
||
|
|
qWarning( ) << "Error:" << lastError( ).text( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/genres_model.cpp: 19"> 19 </A>QVariant GenresModel::headerData( int section, Qt::Orientation orientation, <BR>
|
||
|
|
int role ) const {<BR>
|
||
|
|
if ( role == Qt::DisplayRole && orientation == Qt::Horizontal ) {<BR>
|
||
|
|
switch ( section ) {<BR>
|
||
|
|
case GenresColumns::Id:<BR>
|
||
|
|
return tr( "ID" );<BR>
|
||
|
|
case GenresColumns::Name:<BR>
|
||
|
|
return tr( "Name" );<BR>
|
||
|
|
default:<BR>
|
||
|
|
return QVariant( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return QSqlTableModel::headerData( section, orientation, role );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/models/halls_model.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/models/halls_model.cpp: 1"> 1 </A>#include "halls_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/halls_model.cpp: 5"> 5 </A>HallsModel::HallsModel( QObject *parent, const QSqlDatabase &database )<BR>
|
||
|
|
: BaseSqlTableModel( parent, database ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/halls_model.cpp: 8"> 8 </A>void HallsModel::initialize( ) {<BR>
|
||
|
|
<BR>
|
||
|
|
setTable( "halls" );<BR>
|
||
|
|
<BR>
|
||
|
|
setEditStrategy( QSqlTableModel::OnFieldChange );<BR>
|
||
|
|
<BR>
|
||
|
|
bool success = select( );<BR>
|
||
|
|
if ( !success ) {<BR>
|
||
|
|
qWarning( ) << "Error:" << lastError( ).text( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/halls_model.cpp: 20"> 20 </A>QVariant HallsModel::headerData( int section, Qt::Orientation orientation, <BR>
|
||
|
|
int role ) const {<BR>
|
||
|
|
if ( role == Qt::DisplayRole && orientation == Qt::Horizontal ) {<BR>
|
||
|
|
switch ( section ) {<BR>
|
||
|
|
case HallsColumns::Id:<BR>
|
||
|
|
return tr( "ID" );<BR>
|
||
|
|
case HallsColumns::Name:<BR>
|
||
|
|
return tr( "Name" );<BR>
|
||
|
|
case HallsColumns::Capacity:<BR>
|
||
|
|
return tr( "Capacity" );<BR>
|
||
|
|
default:<BR>
|
||
|
|
return QVariant( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return QSqlTableModel::headerData( section, orientation, role );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/models/movies_model.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/models/movies_model.cpp: 1"> 1 </A>#include "movies_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/movies_model.cpp: 6"> 6 </A>MoviesModel::MoviesModel( QObject *parent, const QSqlDatabase &database )<BR>
|
||
|
|
: BaseSqlTableModel( parent, database ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/movies_model.cpp: 9"> 9 </A>void MoviesModel::initialize( ) {<BR>
|
||
|
|
setTable( "movies" );<BR>
|
||
|
|
<BR>
|
||
|
|
// Set up the relationship with the genres table<BR>
|
||
|
|
setRelation( fieldIndex( "genre_id" ), <BR>
|
||
|
|
QSqlRelation( "genres", "genre_id", "genre_name" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
setEditStrategy( QSqlTableModel::OnFieldChange );<BR>
|
||
|
|
<BR>
|
||
|
|
bool success = select( );<BR>
|
||
|
|
if ( !success ) {<BR>
|
||
|
|
qWarning( ) << "Error:" << lastError( ).text( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/movies_model.cpp: 24"> 24 </A>QVariant MoviesModel::headerData( int section, Qt::Orientation orientation, <BR>
|
||
|
|
int role ) const {<BR>
|
||
|
|
if ( role == Qt::DisplayRole && orientation == Qt::Horizontal ) {<BR>
|
||
|
|
switch ( section ) {<BR>
|
||
|
|
case MoviesColumns::Id:<BR>
|
||
|
|
return tr( "ID" );<BR>
|
||
|
|
case MoviesColumns::Title:<BR>
|
||
|
|
return tr( "Title" );<BR>
|
||
|
|
case MoviesColumns::GenreId:<BR>
|
||
|
|
return tr( "Genre" );<BR>
|
||
|
|
case MoviesColumns::Duration:<BR>
|
||
|
|
return tr( "Duration" );<BR>
|
||
|
|
default:<BR>
|
||
|
|
return QVariant( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return QSqlRelationalTableModel::headerData( section, orientation, role );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/movies_model.cpp: 43"> 43 </A>bool MoviesModel::buildGenreIdFilterCondition( const QString &inFilter, <BR>
|
||
|
|
<A NAME="./ui/models/movies_model.cpp: 44"> 44 </A> QString &outFilter ) const {<BR>
|
||
|
|
QSqlQuery query;<BR>
|
||
|
|
query.prepare( "SELECT genre_id FROM genres WHERE genre_name LIKE ?" );<BR>
|
||
|
|
query.addBindValue( "%" + inFilter + "%" );<BR>
|
||
|
|
query.exec( );<BR>
|
||
|
|
<BR>
|
||
|
|
QStringList genreIds;<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
genreIds << query.value( 0 ).toString( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
outFilter = QString( "movies.genre_id IN ( %1 )" ).arg( genreIds.join( ", " ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/movies_model.cpp: 60"> 60 </A>QString MoviesModel::createMultiColumnFilter( const QString &filter ) const {<BR>
|
||
|
|
QStringList conditions;<BR>
|
||
|
|
<BR>
|
||
|
|
QString buffer; // MoviesColumns::GenreId<BR>
|
||
|
|
if ( buildGenreIdFilterCondition( filter, buffer ) ) {<BR>
|
||
|
|
conditions.append( buffer );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
using Columns = MoviesColumns;<BR>
|
||
|
|
QStringList columns = {columnName( Columns::Id ), columnName( Columns::Title ), <BR>
|
||
|
|
columnName( Columns::Duration )};<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const QString &column : columns ) {<BR>
|
||
|
|
conditions.append( QString( "%1 LIKE '%%2%'" ).arg( column ).arg( filter ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return conditions.join( " OR " );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/models/multi_column_filter_proxy_model.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/models/multi_column_filter_proxy_model.cpp: 1"> 1 </A>#include "multi_column_filter_proxy_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QDateTime><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/multi_column_filter_proxy_model.cpp: 5"> 5 </A>MultiColumnSortFilterProxyModel::MultiColumnSortFilterProxyModel( <BR>
|
||
|
|
<A NAME="./ui/models/multi_column_filter_proxy_model.cpp: 6"> 6 </A> QObject *parent )<BR>
|
||
|
|
: QSortFilterProxyModel( parent ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/multi_column_filter_proxy_model.cpp: 9"> 9 </A>bool MultiColumnSortFilterProxyModel::filterAcceptsRow( <BR>
|
||
|
|
<A NAME="./ui/models/multi_column_filter_proxy_model.cpp: 10"> 10 </A> int sourceRow, const QModelIndex &sourceParent ) const {<BR>
|
||
|
|
<BR>
|
||
|
|
QRegularExpression regex = filterRegularExpression( );<BR>
|
||
|
|
if ( !regex.isValid( ) || regex.pattern( ).isEmpty( ) ) {<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
int columnCount = sourceModel( )->columnCount( sourceParent );<BR>
|
||
|
|
for ( int column = 0; column < columnCount; ++column ) {<BR>
|
||
|
|
QModelIndex sourceIndex =<BR>
|
||
|
|
sourceModel( )->index( sourceRow, column, sourceParent );<BR>
|
||
|
|
QString dataValue =<BR>
|
||
|
|
sourceModel( )->data( sourceIndex, Qt::DisplayRole ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
dataValue.replace( QRegularExpression( "\\s+" ), " " );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( regex.match( dataValue ).hasMatch( ) ) {<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/models/refunds_model.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/models/refunds_model.cpp: 1"> 1 </A>#include "refunds_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/refunds_model.cpp: 5"> 5 </A>RefundsModel::RefundsModel( QObject *parent, const QSqlDatabase &database )<BR>
|
||
|
|
: BaseSqlTableModel( parent, database ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/refunds_model.cpp: 8"> 8 </A>void RefundsModel::initialize( ) {<BR>
|
||
|
|
setTable( "refunds" );<BR>
|
||
|
|
<BR>
|
||
|
|
setEditStrategy( QSqlTableModel::OnFieldChange );<BR>
|
||
|
|
<BR>
|
||
|
|
bool success = select( );<BR>
|
||
|
|
if ( !success ) {<BR>
|
||
|
|
qWarning( ) << "Error:" << lastError( ).text( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/refunds_model.cpp: 19"> 19 </A>QVariant RefundsModel::headerData( int section, Qt::Orientation orientation, <BR>
|
||
|
|
int role ) const {<BR>
|
||
|
|
if ( role == Qt::DisplayRole && orientation == Qt::Horizontal ) {<BR>
|
||
|
|
switch ( section ) {<BR>
|
||
|
|
case RefundsColumns::Id:<BR>
|
||
|
|
return tr( "ID" );<BR>
|
||
|
|
case RefundsColumns::TicketId:<BR>
|
||
|
|
return tr( "Ticket ID" );<BR>
|
||
|
|
case RefundsColumns::RefundAt:<BR>
|
||
|
|
return tr( "Refund At" );<BR>
|
||
|
|
case RefundsColumns::RefundAmount:<BR>
|
||
|
|
return tr( "Refund Amount" );<BR>
|
||
|
|
default:<BR>
|
||
|
|
return QVariant( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return QSqlTableModel::headerData( section, orientation, role );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/refunds_model.cpp: 38"> 38 </A>QString RefundsModel::createMultiColumnFilter( const QString &filter ) const {<BR>
|
||
|
|
QStringList conditions;<BR>
|
||
|
|
<BR>
|
||
|
|
// WARNING: Does not filter these models transmitted through the data method, <BR>
|
||
|
|
// such as QDatetime<BR>
|
||
|
|
<BR>
|
||
|
|
using Columns = RefundsModel;<BR>
|
||
|
|
QStringList columns = {columnName( Columns::Id ), columnName( Columns::TicketId ), <BR>
|
||
|
|
columnName( Columns::RefundAmount )};<BR>
|
||
|
|
<BR>
|
||
|
|
#ifndef NO_DATE_TIME_SEARCH<BR>
|
||
|
|
columns.append( columnName( Columns::RefundAt ) );<BR>
|
||
|
|
#endif<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const QString &column : columns ) {<BR>
|
||
|
|
conditions.append( QString( "%1 LIKE '%%2%'" ).arg( column ).arg( filter ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return conditions.join( " OR " );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/models/sessions_model.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 1"> 1 </A>#include "sessions_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlQuery><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 6"> 6 </A>SessionsModel::SessionsModel( QObject *parent, const QSqlDatabase &database )<BR>
|
||
|
|
: BaseSqlTableModel( parent, database ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 9"> 9 </A>void SessionsModel::initialize( ) {<BR>
|
||
|
|
setTable( "sessions" );<BR>
|
||
|
|
<BR>
|
||
|
|
// Set up the relationship with the movies and halls tables<BR>
|
||
|
|
setRelation( fieldIndex( "movie_id" ), <BR>
|
||
|
|
QSqlRelation( "movies", "movie_id", "title" ) );<BR>
|
||
|
|
setRelation( fieldIndex( "hall_id" ), <BR>
|
||
|
|
QSqlRelation( "halls", "hall_id", "hall_name" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
setEditStrategy( QSqlTableModel::OnFieldChange );<BR>
|
||
|
|
<BR>
|
||
|
|
bool success = select( );<BR>
|
||
|
|
if ( !success ) {<BR>
|
||
|
|
qWarning( ) << "Error:" << lastError( ).text( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 26"> 26 </A>bool SessionsModel::buildHallIdFilterCondition( const QString &inFilter, <BR>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 27"> 27 </A> QString &outFilter ) const {<BR>
|
||
|
|
QSqlQuery query;<BR>
|
||
|
|
query.prepare( "SELECT hall_id FROM halls WHERE hall_name LIKE ?" );<BR>
|
||
|
|
query.addBindValue( "%" + inFilter + "%" );<BR>
|
||
|
|
query.exec( );<BR>
|
||
|
|
<BR>
|
||
|
|
QStringList hallIds;<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
hallIds << query.value( 0 ).toString( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( hallIds.isEmpty( ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
outFilter = QString( "sessions.hall_id IN ( %1 )" ).arg( hallIds.join( ", " ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 47"> 47 </A>bool SessionsModel::buildMovieIdFilterCondition( const QString &inFilter, <BR>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 48"> 48 </A> QString &outFilter ) const {<BR>
|
||
|
|
QSqlQuery query;<BR>
|
||
|
|
query.prepare( "SELECT movie_id FROM movies WHERE title LIKE ?" );<BR>
|
||
|
|
query.addBindValue( "%" + inFilter + "%" );<BR>
|
||
|
|
query.exec( );<BR>
|
||
|
|
<BR>
|
||
|
|
QStringList movieIds;<BR>
|
||
|
|
while ( query.next( ) ) {<BR>
|
||
|
|
movieIds << query.value( 0 ).toString( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( movieIds.isEmpty( ) ) {<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
outFilter = QString( "sessions.movie_id IN ( %1 )" ).arg( movieIds.join( ", " ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 68"> 68 </A>QVariant SessionsModel::headerData( int section, Qt::Orientation orientation, <BR>
|
||
|
|
int role ) const {<BR>
|
||
|
|
if ( role == Qt::DisplayRole && orientation == Qt::Horizontal ) {<BR>
|
||
|
|
switch ( section ) {<BR>
|
||
|
|
case SessionsColumns::Id:<BR>
|
||
|
|
return tr( "ID" );<BR>
|
||
|
|
case SessionsColumns::MovieId:<BR>
|
||
|
|
return tr( "Movie Title" );<BR>
|
||
|
|
case SessionsColumns::HallId:<BR>
|
||
|
|
return tr( "Hall Name" );<BR>
|
||
|
|
case SessionsColumns::BeginAt:<BR>
|
||
|
|
return tr( "Start Time" );<BR>
|
||
|
|
case SessionsColumns::TicketPrice:<BR>
|
||
|
|
return tr( "Ticket Price" );<BR>
|
||
|
|
default:<BR>
|
||
|
|
return QVariant( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return QSqlRelationalTableModel::headerData( section, orientation, role );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/sessions_model.cpp: 89"> 89 </A>QString SessionsModel::createMultiColumnFilter( const QString &filter ) const {<BR>
|
||
|
|
QStringList conditions;<BR>
|
||
|
|
<BR>
|
||
|
|
QString buffer; // SessionsColumns::HallId And SessionsColumns::MovieId<BR>
|
||
|
|
if ( buildHallIdFilterCondition( filter, buffer ) ) {<BR>
|
||
|
|
conditions.append( buffer );<BR>
|
||
|
|
}<BR>
|
||
|
|
if ( buildMovieIdFilterCondition( filter, buffer ) ) {<BR>
|
||
|
|
conditions.append( buffer );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// WARNING: Does not filter these models transmitted through the data method, <BR>
|
||
|
|
// such as QDatetime<BR>
|
||
|
|
<BR>
|
||
|
|
using Columns = SessionsColumns;<BR>
|
||
|
|
QStringList columns = {columnName( Columns::Id ), <BR>
|
||
|
|
columnName( Columns::TicketPrice )};<BR>
|
||
|
|
<BR>
|
||
|
|
#ifndef NO_DATE_TIME_SEARCH<BR>
|
||
|
|
columns.append( columnName( Columns::BeginAt ) );<BR>
|
||
|
|
#endif<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const QString &column : columns ) {<BR>
|
||
|
|
conditions.append( QString( "%1 LIKE '%%2%'" ).arg( column ).arg( filter ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return conditions.join( " OR " );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/models/tickets_model.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/models/tickets_model.cpp: 1"> 1 </A>#include "tickets_model.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
#include <QSqlRecord><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/tickets_model.cpp: 6"> 6 </A>TicketsModel::TicketsModel( QObject *parent, const QSqlDatabase &database )<BR>
|
||
|
|
: BaseSqlTableModel( parent, database ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/tickets_model.cpp: 9"> 9 </A>void TicketsModel::initialize( ) {<BR>
|
||
|
|
setTable( "tickets" );<BR>
|
||
|
|
<BR>
|
||
|
|
setEditStrategy( QSqlTableModel::OnFieldChange );<BR>
|
||
|
|
<BR>
|
||
|
|
bool success = select( );<BR>
|
||
|
|
if ( !success ) {<BR>
|
||
|
|
qWarning( ) << "Error:" << lastError( ).text( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/tickets_model.cpp: 20"> 20 </A>QVariant TicketsModel::headerData( int section, Qt::Orientation orientation, <BR>
|
||
|
|
int role ) const {<BR>
|
||
|
|
if ( role == Qt::DisplayRole && orientation == Qt::Horizontal ) {<BR>
|
||
|
|
switch ( section ) {<BR>
|
||
|
|
case TicketsColumns::Id:<BR>
|
||
|
|
return tr( "ID" );<BR>
|
||
|
|
case TicketsColumns::SessionId:<BR>
|
||
|
|
return tr( "Session ID" );<BR>
|
||
|
|
case TicketsColumns::SeatNumber:<BR>
|
||
|
|
return tr( "Seat Number" );<BR>
|
||
|
|
case TicketsColumns::SoldAt:<BR>
|
||
|
|
return tr( "Sold At" );<BR>
|
||
|
|
default:<BR>
|
||
|
|
return QVariant( );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
return QSqlTableModel::headerData( section, orientation, role );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/models/tickets_model.cpp: 39"> 39 </A>QString TicketsModel::createMultiColumnFilter( const QString &filter ) const {<BR>
|
||
|
|
QStringList conditions;<BR>
|
||
|
|
<BR>
|
||
|
|
// WARNING: Does not filter these models transmitted through the data method, <BR>
|
||
|
|
// such as QDatetime<BR>
|
||
|
|
<BR>
|
||
|
|
using Columns = TicketsColumns;<BR>
|
||
|
|
QStringList columns = {columnName( Columns::Id ), <BR>
|
||
|
|
columnName( Columns::SessionId ), <BR>
|
||
|
|
columnName( Columns::SeatNumber )};<BR>
|
||
|
|
<BR>
|
||
|
|
#ifndef NO_DATE_TIME_SEARCH<BR>
|
||
|
|
columns.append( columnName( Columns::SoldAt ) );<BR>
|
||
|
|
#endif<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const QString &column : columns ) {<BR>
|
||
|
|
conditions.append( QString( "%1 LIKE '%%2%'" ).arg( column ).arg( filter ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return conditions.join( " OR " );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/directories_management_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 1"> 1 </A>#include "directories_management_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// Genre<BR>
|
||
|
|
#include "create_genre_request.h"<BR>
|
||
|
|
#include "genres_model.h"<BR>
|
||
|
|
#include "genres_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// Hall<BR>
|
||
|
|
#include "create_hall_request.h"<BR>
|
||
|
|
#include "halls_model.h"<BR>
|
||
|
|
#include "halls_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// Movie<BR>
|
||
|
|
#include "create_movie_request.h"<BR>
|
||
|
|
#include "movies_model.h"<BR>
|
||
|
|
#include "movies_repository.h"<BR>
|
||
|
|
<BR>
|
||
|
|
// Common<BR>
|
||
|
|
#include "error_dialog.h"<BR>
|
||
|
|
#include "model_manager.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 26"> 26 </A>DirectoriesManagementWidget::DirectoriesManagementWidget( QWidget *parent )<BR>
|
||
|
|
: QWidget( parent ), selectedGenreId_( -1 ), selectedHallId_( -1 ), <BR>
|
||
|
|
selectedMovieId_( -1 ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
initializeRepositories( ); // First of second<BR>
|
||
|
|
initializeModels( ); // First of second<BR>
|
||
|
|
setupTableViews( ); // After initialization of models<BR>
|
||
|
|
setupGenreFinder( );<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 38"> 38 </A>void DirectoriesManagementWidget::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
genresRepository_ = repositoryManager.getRepositoryAs<GenresRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "genres" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
hallsRepository_ = repositoryManager.getRepositoryAs<HallsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "halls" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
moviesRepository_ = repositoryManager.getRepositoryAs<MoviesRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "movies" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( genresRepository_ && hallsRepository_ && moviesRepository_ ) ) {<BR>
|
||
|
|
qFatal( )<BR>
|
||
|
|
<< "DirectoriesManagementWidget::initializeRepositories: Failed to "<BR>
|
||
|
|
"initialize repositories";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 58"> 58 </A>void DirectoriesManagementWidget::initializeModels( ) {<BR>
|
||
|
|
ModelManager &modelManager = ModelManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
genresModel_ =<BR>
|
||
|
|
modelManager.getModelAs<GenresModel>( metadata.modelTableName( "genres" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
hallsModel_ =<BR>
|
||
|
|
modelManager.getModelAs<HallsModel>( metadata.modelTableName( "halls" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
moviesModel_ =<BR>
|
||
|
|
modelManager.getModelAs<MoviesModel>( metadata.modelTableName( "movies" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( genresModel_ && hallsModel_ && moviesModel_ ) ) {<BR>
|
||
|
|
qFatal( ) << "DirectoriesManagementWidget::initializeModels: Failed to "<BR>
|
||
|
|
"initialize models";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 77"> 77 </A>void DirectoriesManagementWidget::setupGenreFinder( ) {<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
genreFinder->setDefaultRelation( "genres" );<BR>
|
||
|
|
genreFinder->setLabelText( EntityFinderWidget::tr( "Select genre" ) );<BR>
|
||
|
|
genreFinder->setLineEditPlaceholder( <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected genre" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 86"> 86 </A>void DirectoriesManagementWidget::setupTableViews( ) {<BR>
|
||
|
|
tableHalls->setModel( hallsModel_ );<BR>
|
||
|
|
<BR>
|
||
|
|
tableMovies->setModel( moviesModel_ );<BR>
|
||
|
|
<BR>
|
||
|
|
tableGenres->setModel( genresModel_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 94"> 94 </A>void DirectoriesManagementWidget::setupConnections( ) {<BR>
|
||
|
|
connect( btnAddHall, &QPushButton::clicked, this, <BR>
|
||
|
|
&DirectoriesManagementWidget::onPushButtonAddHallClicked );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( btnAddMovie, &QPushButton::clicked, this, <BR>
|
||
|
|
&DirectoriesManagementWidget::onPushButtonAddMovieClicked );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( btnAddGenre, &QPushButton::clicked, this, <BR>
|
||
|
|
&DirectoriesManagementWidget::onPushButtonAddGenreClicked );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( genreFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&DirectoriesManagementWidget::onGenreFieldRetrieved );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 108"> 108 </A>void DirectoriesManagementWidget::onPushButtonAddMovieClicked( ) {<BR>
|
||
|
|
if ( selectedGenreId_ == -1 ) {<BR>
|
||
|
|
QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
QMessageBox::tr( "No genre selected" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString title = lineEditMovieName->text( );<BR>
|
||
|
|
int duration = spinBoxMovieDuration->value( );<BR>
|
||
|
|
<BR>
|
||
|
|
CreateMovieRequest request;<BR>
|
||
|
|
request.setTitle( title );<BR>
|
||
|
|
request.setDuration( duration );<BR>
|
||
|
|
request.setGenreId( selectedGenreId_ );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result = moviesRepository_->createMovie( request );<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
qWarning( ) << "Failed to create movie:" << result.errorMessage;<BR>
|
||
|
|
ErrorDialog::displayError( this, result.errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 129"> 129 </A>void DirectoriesManagementWidget::onPushButtonAddHallClicked( ) {<BR>
|
||
|
|
QString name = lineEditHallName->text( );<BR>
|
||
|
|
int capacity = spinBoxNumberOfSeats->value( );<BR>
|
||
|
|
<BR>
|
||
|
|
CreateHallRequest request;<BR>
|
||
|
|
request.setHallName( name );<BR>
|
||
|
|
request.setCapacity( capacity );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result = hallsRepository_->createHall( request );<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
qWarning( ) << "Failed to create hall:" << result.errorMessage;<BR>
|
||
|
|
ErrorDialog::displayError( this, result.errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 144"> 144 </A>void DirectoriesManagementWidget::onGenreFieldRetrieved( <BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 145"> 145 </A> const QSqlField &field ) {<BR>
|
||
|
|
selectedGenreId_ = field.value( ).toInt( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/directories_management_widget.cpp: 149"> 149 </A>void DirectoriesManagementWidget::onPushButtonAddGenreClicked( ) {<BR>
|
||
|
|
QString name = lineEditGenreName->text( );<BR>
|
||
|
|
<BR>
|
||
|
|
CreateGenreRequest request;<BR>
|
||
|
|
request.setGenreName( name );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result = genresRepository_->createGenre( request );<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
qWarning( ) << "Failed to create genre:" << result.errorMessage;<BR>
|
||
|
|
ErrorDialog::displayError( this, result.errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/entity_deleter_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 1"> 1 </A>#include "entity_deleter_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "error_dialog.h"<BR>
|
||
|
|
#include "genres_repository_interface.h"<BR>
|
||
|
|
#include "halls_repository_interface.h"<BR>
|
||
|
|
#include "movies_repository_interface.h"<BR>
|
||
|
|
#include "refunds_repository_interface.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "sessions_repository_interface.h"<BR>
|
||
|
|
#include "tickets_repository_interface.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
#include <QSqlTableModel><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 15"> 15 </A>EntityDeleterWidget::EntityDeleterWidget( QWidget *parent ) : QWidget( parent ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
setupComboBoxCurrentTable( );<BR>
|
||
|
|
setupEntityFinder( );<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 23"> 23 </A>void EntityDeleterWidget::setupComboBoxCurrentTable( ) {<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
QStringList databaseTableNames = {"genres", "halls", "movies", <BR>
|
||
|
|
"refunds", "sessions", "tickets"};<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const QString currentDTN : databaseTableNames ) {<BR>
|
||
|
|
comboBoxCurrentTable->addItem( metadata.translatedTableName( currentDTN ), <BR>
|
||
|
|
currentDTN );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 35"> 35 </A>void EntityDeleterWidget::setupConnections( ) {<BR>
|
||
|
|
connect( comboBoxCurrentTable, &QComboBox::currentIndexChanged, this, <BR>
|
||
|
|
&EntityDeleterWidget::onComboBoxCurrentTableCurrentIndexChanged );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( entityFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&EntityDeleterWidget::onFieldRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( entityFinder, &EntityFinderWidget::recordRetrieved, this, <BR>
|
||
|
|
&EntityDeleterWidget::onRecordRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( pushButtonDeleteEntity, &QPushButton::clicked, this, <BR>
|
||
|
|
&EntityDeleterWidget::onPushButtonDeleteEntityClicked );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 49"> 49 </A>void EntityDeleterWidget::setupEntityFinder( ) {<BR>
|
||
|
|
entityFinder->setLabelText( tr( "Select record of current table to delete" ) );<BR>
|
||
|
|
refreshEntityFinder( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 54"> 54 </A>void EntityDeleterWidget::refreshEntityFinder( ) {<BR>
|
||
|
|
const QString &databaseTableName =<BR>
|
||
|
|
comboBoxCurrentTable->currentData( ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
entityFinder->setDefaultRelation( databaseTableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 61"> 61 </A>void EntityDeleterWidget::onComboBoxCurrentTableCurrentIndexChanged( int index ) {<BR>
|
||
|
|
refreshEntityFinder( );<BR>
|
||
|
|
<BR>
|
||
|
|
const QString &databaseTableName =<BR>
|
||
|
|
comboBoxCurrentTable->currentData( ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Current table was changed:" << "CurrentComboBoxIndex:" << index<BR>
|
||
|
|
<< "databaseTableName:" << databaseTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 71"> 71 </A>void EntityDeleterWidget::onFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
retrievedField_ = field;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 75"> 75 </A>void EntityDeleterWidget::onRecordRetrieved( const QSqlRecord &record ) {<BR>
|
||
|
|
// NOTE: It is possible to reduce the behavior of each of the tables if the<BR>
|
||
|
|
// removal is in different ways with other data<BR>
|
||
|
|
selectedRecord_ = record;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 83"> 83 </A>EntityDeleterWidget::deleteEntityById<GenresRepositoryInterface>( ) {<BR>
|
||
|
|
return currentRepository<GenresRepositoryInterface>( )->deleteGenreById( <BR>
|
||
|
|
retrievedField_.value( ).toInt( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 90"> 90 </A>EntityDeleterWidget::deleteEntityById<HallsRepositoryInterface>( ) {<BR>
|
||
|
|
return currentRepository<HallsRepositoryInterface>( )->deleteHallById( <BR>
|
||
|
|
retrievedField_.value( ).toInt( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 97"> 97 </A>EntityDeleterWidget::deleteEntityById<MoviesRepositoryInterface>( ) {<BR>
|
||
|
|
return currentRepository<MoviesRepositoryInterface>( )->deleteMovieById( <BR>
|
||
|
|
retrievedField_.value( ).toInt( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 104"> 104 </A>EntityDeleterWidget::deleteEntityById<RefundsRepositoryInterface>( ) {<BR>
|
||
|
|
return currentRepository<RefundsRepositoryInterface>( )->deleteRefundById( <BR>
|
||
|
|
retrievedField_.value( ).toInt( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 111"> 111 </A>EntityDeleterWidget::deleteEntityById<SessionsRepositoryInterface>( ) {<BR>
|
||
|
|
return currentRepository<SessionsRepositoryInterface>( )->deleteSessionById( <BR>
|
||
|
|
retrievedField_.value( ).toInt( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 118"> 118 </A>EntityDeleterWidget::deleteEntityById<TicketsRepositoryInterface>( ) {<BR>
|
||
|
|
return currentRepository<TicketsRepositoryInterface>( )->deleteTicketById( <BR>
|
||
|
|
retrievedField_.value( ).toInt( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 123"> 123 </A>void EntityDeleterWidget::onPushButtonDeleteEntityClicked( ) {<BR>
|
||
|
|
const QString &databaseTableName =<BR>
|
||
|
|
comboBoxCurrentTable->currentData( ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result;<BR>
|
||
|
|
<BR>
|
||
|
|
if ( databaseTableName == "genres" ) {<BR>
|
||
|
|
<BR>
|
||
|
|
result = deleteEntityById<GenresRepositoryInterface>( );<BR>
|
||
|
|
showMessageDialog( result, tr( "Genre deleted successfully" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == "halls" ) {<BR>
|
||
|
|
<BR>
|
||
|
|
result = deleteEntityById<HallsRepositoryInterface>( );<BR>
|
||
|
|
showMessageDialog( result, tr( "Hall deleted successfully" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == "movies" ) {<BR>
|
||
|
|
<BR>
|
||
|
|
result = deleteEntityById<MoviesRepositoryInterface>( );<BR>
|
||
|
|
showMessageDialog( result, tr( "Movie deleted successfully" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == "refunds" ) {<BR>
|
||
|
|
<BR>
|
||
|
|
result = deleteEntityById<RefundsRepositoryInterface>( );<BR>
|
||
|
|
showMessageDialog( result, tr( "Refund deleted successfully" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == "sessions" ) {<BR>
|
||
|
|
<BR>
|
||
|
|
result = deleteEntityById<SessionsRepositoryInterface>( );<BR>
|
||
|
|
showMessageDialog( result, tr( "Session deleted successfully" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == "tickets" ) {<BR>
|
||
|
|
<BR>
|
||
|
|
result = deleteEntityById<TicketsRepositoryInterface>( );<BR>
|
||
|
|
showMessageDialog( result, tr( "Ticket deleted successfully" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
} else {<BR>
|
||
|
|
qCritical( ) << "EntityDeleterWidget::onPressPushButtonDeleteEntity: "<BR>
|
||
|
|
"Unknown database table name:"<BR>
|
||
|
|
<< databaseTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// NOTE: Application connector will reset entity finder<BR>
|
||
|
|
<BR>
|
||
|
|
// if ( result.success ) {<BR>
|
||
|
|
// entityFinder->resetToDefault( );<BR>
|
||
|
|
// }<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 172"> 172 </A>void EntityDeleterWidget::showMessageDialog( const RepositoryResult &result, <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_deleter_widget.cpp: 173"> 173 </A> const QString &successMessage ) {<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, result.errorMessage );<BR>
|
||
|
|
} else {<BR>
|
||
|
|
QMessageBox::information( this, QMessageBox::tr( "Success" ), successMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/entity_finder_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 1"> 1 </A>#include "entity_finder_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "base_sql_table_model.h"<BR>
|
||
|
|
#include "model_manager.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "search_dialog.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 8"> 8 </A>EntityFinderWidget::EntityFinderWidget( QWidget *parent ) : QWidget( parent ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
setupFrameStyle( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 15"> 15 </A>EntityFinderWidget::EntityFinderWidget( const QString &tableName, <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 16"> 16 </A> const QString &fieldName, <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 17"> 17 </A> QWidget *parent )<BR>
|
||
|
|
: EntityFinderWidget( parent ) {<BR>
|
||
|
|
setModelTableName( tableName );<BR>
|
||
|
|
setFieldName( fieldName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 23"> 23 </A>void EntityFinderWidget::setHiddenFrame( bool hidden ) {<BR>
|
||
|
|
QLayout *frameLayout = frame->layout( );<BR>
|
||
|
|
bool isHidden = frame->frameStyle( ) == QFrame::NoFrame;<BR>
|
||
|
|
<BR>
|
||
|
|
if ( isHidden == hidden ) {<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( hidden ) {<BR>
|
||
|
|
frame->setFrameStyle( QFrame::NoFrame );<BR>
|
||
|
|
frameLayout->setContentsMargins( 0, 0, 0, 0 );<BR>
|
||
|
|
} else {<BR>
|
||
|
|
frame->setFrameStyle( originalFrameStyle_ );<BR>
|
||
|
|
frameLayout->setContentsMargins( 9, 9, 9, 9 );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
parentWidget( )->adjustSize( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 42"> 42 </A>void EntityFinderWidget::refreshLineEditText( const QSqlRecord &record ) {<BR>
|
||
|
|
ModelManager &modelManager = ModelManager::instance( );<BR>
|
||
|
|
<BR>
|
||
|
|
BaseSqlTableModel *model =<BR>
|
||
|
|
modelManager.getModelAs<BaseSqlTableModel>( modelTableName_ );<BR>
|
||
|
|
<BR>
|
||
|
|
QStringList columnDataList;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( int i = 0; i < record.count( ); ++i ) {<BR>
|
||
|
|
QString columnName = model->headerData( i, Qt::Horizontal ).toString( );<BR>
|
||
|
|
QString columnValue = record.value( i ).toString( );<BR>
|
||
|
|
columnDataList.append( QString( "%1: %2" ).arg( columnName, columnValue ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
lineEditEntityInformation->setText( columnDataList.join( " | " ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 59"> 59 </A>void EntityFinderWidget::setDefaultRelation( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 60"> 60 </A> const QString &databaseRelationName ) {<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
setModelTableName( metadata.modelTableName( databaseRelationName ) );<BR>
|
||
|
|
setFieldName( metadata.primaryIdColumnName( databaseRelationName ) );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Default relation name set to:" << databaseRelationName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 68"> 68 </A>void EntityFinderWidget::setupConnections( ) {<BR>
|
||
|
|
connect( pushButtonFindEntity, &QPushButton::clicked, this, <BR>
|
||
|
|
&EntityFinderWidget::onPushButtonFindEntityClicked );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 73"> 73 </A>void EntityFinderWidget::setupFrameStyle( ) {<BR>
|
||
|
|
originalFrameStyle_ = frame->frameStyle( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 77"> 77 </A>void EntityFinderWidget::resetToDefault( ) {<BR>
|
||
|
|
qInfo( ) << "Resetting entity finder to default:"<BR>
|
||
|
|
<< "Name of EntityFinderWidget:" << objectName( );<BR>
|
||
|
|
lineEditEntityInformation->setText( "" );<BR>
|
||
|
|
<BR>
|
||
|
|
emit reseted( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 85"> 85 </A>void EntityFinderWidget::onPushButtonFindEntityClicked( ) {<BR>
|
||
|
|
SearchDialog searchDialog( modelTableName_, fieldName_, this );<BR>
|
||
|
|
<BR>
|
||
|
|
// All its signals are automatically disconnected from the slots<BR>
|
||
|
|
<BR>
|
||
|
|
connect( &searchDialog, &SearchDialog::rowSelected, this, <BR>
|
||
|
|
&EntityFinderWidget::onRowSelected );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( &searchDialog, &SearchDialog::fieldRetrieved, this, <BR>
|
||
|
|
&EntityFinderWidget::onFieldRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( &searchDialog, &SearchDialog::recordRetrieved, this, <BR>
|
||
|
|
&EntityFinderWidget::onRecordRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
searchDialog.exec( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 102"> 102 </A>void EntityFinderWidget::onRowSelected( int rowIndex ) {<BR>
|
||
|
|
emit rowSelected( rowIndex );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 106"> 106 </A>void EntityFinderWidget::onRecordRetrieved( const QSqlRecord &rowValues ) {<BR>
|
||
|
|
refreshLineEditText( rowValues );<BR>
|
||
|
|
emit recordRetrieved( rowValues );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_finder_widget.cpp: 111"> 111 </A>void EntityFinderWidget::onFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
emit fieldRetrieved( field );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/entity_updater_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 1"> 1 </A>#include "entity_updater_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "genres_repository_interface.h"<BR>
|
||
|
|
#include "halls_repository_interface.h"<BR>
|
||
|
|
#include "movies_repository_interface.h"<BR>
|
||
|
|
#include "refunds_repository_interface.h"<BR>
|
||
|
|
#include "sessions_repository_interface.h"<BR>
|
||
|
|
#include "tickets_repository_interface.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "update_genre_request.h"<BR>
|
||
|
|
#include "update_hall_request.h"<BR>
|
||
|
|
#include "update_movie_request.h"<BR>
|
||
|
|
#include "update_refund_request.h"<BR>
|
||
|
|
#include "update_session_request.h"<BR>
|
||
|
|
#include "update_ticket_request.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "error_dialog.h"<BR>
|
||
|
|
#include "model_manager.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "base_sql_table_model.h"<BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
#include <qsqlrelationaltablemodel.h><BR>
|
||
|
|
<BR>
|
||
|
|
namespace DatabaseTableNames {<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 25"> 25 </A>static constexpr char Genres[] = "genres";<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 26"> 26 </A>static constexpr char Halls[] = "halls";<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 27"> 27 </A>static constexpr char Movies[] = "movies";<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 28"> 28 </A>static constexpr char Refunds[] = "refunds";<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 29"> 29 </A>static constexpr char Sessions[] = "sessions";<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 30"> 30 </A>static constexpr char Tickets[] = "tickets";<BR>
|
||
|
|
} // namespace DatabaseTableNames<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 33"> 33 </A>EntityUpdaterWidget::EntityUpdaterWidget( QWidget *parent )<BR>
|
||
|
|
: QWidget( parent ), primaryKey_( -1 ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
setupComboBoxCurrentTable( ); // After setup connections<BR>
|
||
|
|
setupParentEntityFinderWidget( );<BR>
|
||
|
|
setupChildEntityFinderWidget( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 43"> 43 </A>void EntityUpdaterWidget::setupComboBoxCurrentTable( ) {<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
QList<QString> databaseTableNames = {<BR>
|
||
|
|
DatabaseTableNames::Genres, DatabaseTableNames::Halls, <BR>
|
||
|
|
DatabaseTableNames::Movies, DatabaseTableNames::Refunds, <BR>
|
||
|
|
DatabaseTableNames::Sessions, DatabaseTableNames::Tickets};<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const QString &tableName : databaseTableNames ) {<BR>
|
||
|
|
comboBoxCurrentTable->addItem( metadata.translatedTableName( tableName ), <BR>
|
||
|
|
tableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 57"> 57 </A>void EntityUpdaterWidget::setupConnections( ) {<BR>
|
||
|
|
connect( foreignKeyFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&EntityUpdaterWidget::onForeignFieldRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( primaryKeyFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&EntityUpdaterWidget::onPrimaryFieldRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( primaryKeyFinder, &EntityFinderWidget::recordRetrieved, this, <BR>
|
||
|
|
&EntityUpdaterWidget::onPrimaryEntityRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( comboBoxCurrentTable, &QComboBox::currentIndexChanged, this, <BR>
|
||
|
|
&EntityUpdaterWidget::onTableSelected );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( comboBoxCurrentColumn, &QComboBox::currentIndexChanged, this, <BR>
|
||
|
|
&EntityUpdaterWidget::onColumnSelected );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( pushButtonUpdate, &QPushButton::clicked, this, <BR>
|
||
|
|
&EntityUpdaterWidget::onPushButtonUpdateClicked );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 77"> 77 </A>void EntityUpdaterWidget::setupChildEntityFinderWidget( ) {<BR>
|
||
|
|
foreignKeyFinder->setLabelText( <BR>
|
||
|
|
EntityFinderWidget::tr( "Select entity for replacement" ) );<BR>
|
||
|
|
foreignKeyFinder->setLineEditPlaceholder( <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected entity" ) );<BR>
|
||
|
|
foreignKeyFinder->setHiddenFrame( true );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 85"> 85 </A>void EntityUpdaterWidget::setupParentEntityFinderWidget( ) {<BR>
|
||
|
|
primaryKeyFinder->setLabelText( <BR>
|
||
|
|
EntityFinderWidget::tr( "Select entity for updating" ) );<BR>
|
||
|
|
primaryKeyFinder->setLineEditPlaceholder( <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected entry" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 92"> 92 </A>void EntityUpdaterWidget::configureForeignKeyFinder( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 93"> 93 </A> const QString &columnName, const QString &databaseTableName ) {<BR>
|
||
|
|
TableInfoSQLite tableInfo( databaseTableName );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( tableInfo.isPrimaryKey( columnName ) ) {<BR>
|
||
|
|
// NOTE: Change Primary Key is prohibited<BR>
|
||
|
|
<BR>
|
||
|
|
// configurePrimaryKeyFinder( databaseTableName );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString foreignKeyDatabaseTableName = tableInfo.foreignKeyTable( columnName );<BR>
|
||
|
|
if ( foreignKeyDatabaseTableName.isEmpty( ) ) {<BR>
|
||
|
|
qCritical( )<BR>
|
||
|
|
<< "Could not find the database table name for the key column, which "<BR>
|
||
|
|
"contains \"_id\":"<BR>
|
||
|
|
<< columnName;<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
configureForeignKeyFinder( foreignKeyDatabaseTableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 115"> 115 </A>void EntityUpdaterWidget::configureForeignKeyFinder( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 116"> 116 </A> const QString &databaseTableName ) {<BR>
|
||
|
|
foreignKeyFinder->resetToDefault( );<BR>
|
||
|
|
foreignKeyFinder->setDefaultRelation( databaseTableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 121"> 121 </A>void EntityUpdaterWidget::configurePrimaryKeyFinder( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 122"> 122 </A> const QString &databaseTableName ) {<BR>
|
||
|
|
primaryKeyFinder->resetToDefault( );<BR>
|
||
|
|
primaryKeyFinder->setDefaultRelation( databaseTableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 127"> 127 </A>void EntityUpdaterWidget::onPrimaryFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
qInfo( ) << "Selected primary field: Name:" << field.name( )<BR>
|
||
|
|
<< "Value:" << field.value( );<BR>
|
||
|
|
primaryKey_ = field.value( ).toInt( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 133"> 133 </A>void EntityUpdaterWidget::onForeignFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
qInfo( ) << "Selected foreign field: Name:" << field.name( )<BR>
|
||
|
|
<< "Value:" << field.value( );<BR>
|
||
|
|
selectedForeignField_ = field;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 139"> 139 </A>void EntityUpdaterWidget::onPrimaryEntityRetrieved( const QSqlRecord &entity ) {<BR>
|
||
|
|
qInfo( ) << "Retrieved foreign entity:" << entity;<BR>
|
||
|
|
selectedPrimaryEntity_ = entity;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 145"> 145 </A>QString EntityUpdaterWidget::actualColumnValue( const QString &columnName ) {<BR>
|
||
|
|
QString value = isColumnsEqual( columnName )<BR>
|
||
|
|
? lineEdit->text( )<BR>
|
||
|
|
: selectedPrimaryEntity_.value( columnName ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Actual column QString value:" << value;<BR>
|
||
|
|
return value;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 155"> 155 </A>QDateTime EntityUpdaterWidget::actualColumnValue( const QString &columnName ) {<BR>
|
||
|
|
QDateTime value = isColumnsEqual( columnName )<BR>
|
||
|
|
? dateTimeEdit->dateTime( )<BR>
|
||
|
|
: selectedPrimaryEntity_.value( columnName ).toDateTime( );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Actual column QDateTime value:" << value;<BR>
|
||
|
|
return value;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 165"> 165 </A>int EntityUpdaterWidget::actualColumnValue( const QString &columnName ) {<BR>
|
||
|
|
int value = isColumnsEqual( columnName )<BR>
|
||
|
|
? spinBox->value( )<BR>
|
||
|
|
: selectedPrimaryEntity_.value( columnName ).toInt( );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Actual column int value:" << value;<BR>
|
||
|
|
return value;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 175"> 175 </A>double EntityUpdaterWidget::actualColumnValue( const QString &columnName ) {<BR>
|
||
|
|
double value = isColumnsEqual( columnName )<BR>
|
||
|
|
? doubleSpinBox->value( )<BR>
|
||
|
|
: selectedPrimaryEntity_.value( columnName ).toDouble( );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Actual column double value:" << value;<BR>
|
||
|
|
return value;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 184"> 184 </A>qint32 EntityUpdaterWidget::actualForeignKey( const QString &columnName ) {<BR>
|
||
|
|
qint32 value = isColumnsEqual( columnName )<BR>
|
||
|
|
? selectedForeignField_.value( ).toInt( )<BR>
|
||
|
|
: selectedPrimaryEntity_.value( columnName ).toInt( );<BR>
|
||
|
|
<BR>
|
||
|
|
qInfo( ) << "Actual foreign key:" << value;<BR>
|
||
|
|
return value;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 195"> 195 </A>EntityUpdaterWidget::updateEntity<GenresRepositoryInterface>( ) {<BR>
|
||
|
|
UpdateGenreRequest request;<BR>
|
||
|
|
request.setGenreId( primaryKey_ );<BR>
|
||
|
|
request.setGenreName( actualColumnValue<QString>( "genre_name" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return currentRepository<GenresRepositoryInterface>( )->updateGenre( request );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 204"> 204 </A>RepositoryResult EntityUpdaterWidget::updateEntity<HallsRepositoryInterface>( ) {<BR>
|
||
|
|
UpdateHallRequest request;<BR>
|
||
|
|
request.setHallId( primaryKey_ );<BR>
|
||
|
|
request.setCapacity( actualColumnValue<int>( "capacity" ) );<BR>
|
||
|
|
request.setHallName( actualColumnValue<QString>( "hall_name" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return currentRepository<HallsRepositoryInterface>( )->updateHall( request );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 215"> 215 </A>EntityUpdaterWidget::updateEntity<MoviesRepositoryInterface>( ) {<BR>
|
||
|
|
UpdateMovieRequest request;<BR>
|
||
|
|
request.setMovieId( primaryKey_ );<BR>
|
||
|
|
request.setDuration( actualColumnValue<int>( "duration" ) );<BR>
|
||
|
|
request.setGenreId( actualForeignKey( "genre_id" ) );<BR>
|
||
|
|
request.setTitle( actualColumnValue<QString>( "title" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return currentRepository<MoviesRepositoryInterface>( )->updateMovie( request );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 227"> 227 </A>EntityUpdaterWidget::updateEntity<RefundsRepositoryInterface>( ) {<BR>
|
||
|
|
UpdateRefundRequest request;<BR>
|
||
|
|
request.setRefundId( primaryKey_ );<BR>
|
||
|
|
request.setRefundAmount( actualColumnValue<double>( "refund_amount" ) );<BR>
|
||
|
|
request.setRefundAt( actualColumnValue<QDateTime>( "refund_at" ) );<BR>
|
||
|
|
request.setTicketId( actualForeignKey( "ticket_id" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return currentRepository<RefundsRepositoryInterface>( )->updateRefund( request );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 239"> 239 </A>EntityUpdaterWidget::updateEntity<SessionsRepositoryInterface>( ) {<BR>
|
||
|
|
UpdateSessionRequest request;<BR>
|
||
|
|
request.setSessionId( primaryKey_ );<BR>
|
||
|
|
request.setHallId( actualForeignKey( "hall_id" ) );<BR>
|
||
|
|
request.setMovieId( actualForeignKey( "movie_id" ) );<BR>
|
||
|
|
request.setBeginAt( actualColumnValue<QDateTime>( "begin_at" ) );<BR>
|
||
|
|
request.setTicketPrice( actualColumnValue<double>( "ticket_price" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return currentRepository<SessionsRepositoryInterface>( )->updateSession( <BR>
|
||
|
|
request );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
RepositoryResult<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 253"> 253 </A>EntityUpdaterWidget::updateEntity<TicketsRepositoryInterface>( ) {<BR>
|
||
|
|
UpdateTicketRequest request;<BR>
|
||
|
|
request.setTicketId( primaryKey_ );<BR>
|
||
|
|
request.setSeatNumber( actualColumnValue<int>( "seat_number" ) );<BR>
|
||
|
|
request.setSessionId( actualForeignKey( "session_id" ) );<BR>
|
||
|
|
request.setSoldAt( actualColumnValue<QDateTime>( "sold_at" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return currentRepository<TicketsRepositoryInterface>( )->updateTicket( request );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 264"> 264 </A>void EntityUpdaterWidget::processEntityUpdate<DatabaseTableNames::Genres>( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 265"> 265 </A> RepositoryResult &resultOut ) {<BR>
|
||
|
|
resultOut = updateEntity<GenresRepositoryInterface>( );<BR>
|
||
|
|
if ( !resultOut.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, resultOut.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
showMessageDialog( resultOut, <BR>
|
||
|
|
EntityUpdaterWidget::tr( "Genre updated successfully" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 276"> 276 </A>void EntityUpdaterWidget::processEntityUpdate<DatabaseTableNames::Halls>( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 277"> 277 </A> RepositoryResult &resultOut ) {<BR>
|
||
|
|
resultOut = updateEntity<HallsRepositoryInterface>( );<BR>
|
||
|
|
if ( !resultOut.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, resultOut.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
showMessageDialog( resultOut, <BR>
|
||
|
|
EntityUpdaterWidget::tr( "Hall updated successfully" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 288"> 288 </A>void EntityUpdaterWidget::processEntityUpdate<DatabaseTableNames::Movies>( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 289"> 289 </A> RepositoryResult &resultOut ) {<BR>
|
||
|
|
resultOut = updateEntity<MoviesRepositoryInterface>( );<BR>
|
||
|
|
if ( !resultOut.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, resultOut.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
showMessageDialog( resultOut, <BR>
|
||
|
|
EntityUpdaterWidget::tr( "Movie updated successfully" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 300"> 300 </A>void EntityUpdaterWidget::processEntityUpdate<DatabaseTableNames::Refunds>( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 301"> 301 </A> RepositoryResult &resultOut ) {<BR>
|
||
|
|
resultOut = updateEntity<RefundsRepositoryInterface>( );<BR>
|
||
|
|
if ( !resultOut.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, resultOut.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
showMessageDialog( resultOut, <BR>
|
||
|
|
EntityUpdaterWidget::tr( "Refund updated successfully" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 312"> 312 </A>void EntityUpdaterWidget::processEntityUpdate<DatabaseTableNames::Sessions>( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 313"> 313 </A> RepositoryResult &resultOut ) {<BR>
|
||
|
|
resultOut = updateEntity<SessionsRepositoryInterface>( );<BR>
|
||
|
|
if ( !resultOut.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, resultOut.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
showMessageDialog( resultOut, <BR>
|
||
|
|
EntityUpdaterWidget::tr( "Session updated successfully" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
template <><BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 324"> 324 </A>void EntityUpdaterWidget::processEntityUpdate<DatabaseTableNames::Tickets>( <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 325"> 325 </A> RepositoryResult &resultOut ) {<BR>
|
||
|
|
resultOut = updateEntity<TicketsRepositoryInterface>( );<BR>
|
||
|
|
if ( !resultOut.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, resultOut.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
showMessageDialog( resultOut, <BR>
|
||
|
|
EntityUpdaterWidget::tr( "Ticket updated successfully" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 335"> 335 </A>void EntityUpdaterWidget::onPushButtonUpdateClicked( ) {<BR>
|
||
|
|
const QString &databaseTableName =<BR>
|
||
|
|
comboBoxCurrentTable->currentData( ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result;<BR>
|
||
|
|
<BR>
|
||
|
|
if ( databaseTableName == DatabaseTableNames::Genres ) {<BR>
|
||
|
|
processEntityUpdate<DatabaseTableNames::Genres>( result );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == DatabaseTableNames::Halls ) {<BR>
|
||
|
|
processEntityUpdate<DatabaseTableNames::Halls>( result );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == DatabaseTableNames::Movies ) {<BR>
|
||
|
|
processEntityUpdate<DatabaseTableNames::Movies>( result );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == DatabaseTableNames::Refunds ) {<BR>
|
||
|
|
processEntityUpdate<DatabaseTableNames::Refunds>( result );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == DatabaseTableNames::Sessions ) {<BR>
|
||
|
|
processEntityUpdate<DatabaseTableNames::Sessions>( result );<BR>
|
||
|
|
<BR>
|
||
|
|
} else if ( databaseTableName == DatabaseTableNames::Tickets ) {<BR>
|
||
|
|
processEntityUpdate<DatabaseTableNames::Tickets>( result );<BR>
|
||
|
|
<BR>
|
||
|
|
} else {<BR>
|
||
|
|
qFatal( ) << "EntityDeleterWidget::onPressPushButtonDeleteEntity: "<BR>
|
||
|
|
"Unknown database table name:"<BR>
|
||
|
|
<< databaseTableName;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
processUpdateResult( result );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 368"> 368 </A>void EntityUpdaterWidget::onTableSelected( int tableIndex ) {<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
const QString &databaseTableName =<BR>
|
||
|
|
comboBoxCurrentTable->itemData( tableIndex ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
ModelManager &modelManager = ModelManager::instance( );<BR>
|
||
|
|
BaseSqlTableModel *model = modelManager.getModelAs<BaseSqlTableModel>( <BR>
|
||
|
|
metadata.modelTableName( databaseTableName ) );<BR>
|
||
|
|
<BR>
|
||
|
|
comboBoxCurrentColumn->clear( );<BR>
|
||
|
|
for ( const auto &columnName : model->columnNames( ) ) {<BR>
|
||
|
|
if ( metadata.primaryIdColumnName( databaseTableName ) == columnName ) {<BR>
|
||
|
|
// NOTE: Change Primary Key is prohibited<BR>
|
||
|
|
continue;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
int headerIndex = model->columnIndex( columnName );<BR>
|
||
|
|
QString displayName =<BR>
|
||
|
|
model->headerData( headerIndex, Qt::Horizontal ).toString( );<BR>
|
||
|
|
comboBoxCurrentColumn->addItem( displayName, columnName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
configurePrimaryKeyFinder( databaseTableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 394"> 394 </A>void EntityUpdaterWidget::onColumnSelected( int columnIndex ) {<BR>
|
||
|
|
Q_UNUSED( columnIndex );<BR>
|
||
|
|
<BR>
|
||
|
|
const QString &databaseTableName =<BR>
|
||
|
|
comboBoxCurrentTable->currentData( ).toString( );<BR>
|
||
|
|
TableInfoSQLite tableInfoSQLite( databaseTableName );<BR>
|
||
|
|
<BR>
|
||
|
|
QString columnName = comboBoxCurrentColumn->currentData( ).toString( );<BR>
|
||
|
|
bool isKey = columnName.contains( "_id", Qt::CaseInsensitive );<BR>
|
||
|
|
<BR>
|
||
|
|
QWidget *page;<BR>
|
||
|
|
switch ( tableInfoSQLite.columnMetaType( columnName ) ) {<BR>
|
||
|
|
case QMetaType::Int: {<BR>
|
||
|
|
page =<BR>
|
||
|
|
findChild<QWidget *>( isKey ? "pageChildFinderWidget" : "pageSpinBox" );<BR>
|
||
|
|
} break;<BR>
|
||
|
|
case QMetaType::Double:<BR>
|
||
|
|
page = findChild<QWidget *>( "pageDoubleSpinBox" );<BR>
|
||
|
|
break;<BR>
|
||
|
|
case QMetaType::QString:<BR>
|
||
|
|
page = findChild<QWidget *>( "pageLineEdit" );<BR>
|
||
|
|
break;<BR>
|
||
|
|
case QMetaType::QDateTime:<BR>
|
||
|
|
page = findChild<QWidget *>( "pageDateTimeEdit" );<BR>
|
||
|
|
break;<BR>
|
||
|
|
default:<BR>
|
||
|
|
qCritical( ) << "Unknown column selected";<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
stackedWidget->setCurrentWidget( page );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( isKey ) {<BR>
|
||
|
|
configureForeignKeyFinder( columnName, databaseTableName );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 430"> 430 </A>QModelIndex EntityUpdaterWidget::findIndexByColumn( QAbstractItemModel *model, <BR>
|
||
|
|
int column, <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 432"> 432 </A> const QVariant &value ) {<BR>
|
||
|
|
if ( !model || column < 0 || column >= model->columnCount( ) )<BR>
|
||
|
|
return QModelIndex( );<BR>
|
||
|
|
<BR>
|
||
|
|
for ( int row = 0; row < model->rowCount( ); ++row ) {<BR>
|
||
|
|
QModelIndex index = model->index( row, column );<BR>
|
||
|
|
if ( model->data( index ) == value ) {<BR>
|
||
|
|
return index;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return QModelIndex( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 446"> 446 </A>bool EntityUpdaterWidget::isColumnsEqual( const QString &other ) {<BR>
|
||
|
|
TableInfoSQLite tableInfo( comboBoxCurrentTable->currentData( ).toString( ) );<BR>
|
||
|
|
QString current = comboBoxCurrentColumn->currentData( ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
bool isEqual = tableInfo.columnIndex( current ) == tableInfo.columnIndex( other );<BR>
|
||
|
|
<BR>
|
||
|
|
const static QString billet( "Column \"%1\" and column \"%2\": %3" );<BR>
|
||
|
|
qInfo( ).noquote( ) << billet.arg( current ).arg( other ).arg( <BR>
|
||
|
|
isEqual ? "Equal" : "Not equal" );<BR>
|
||
|
|
<BR>
|
||
|
|
return isEqual;<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 459"> 459 </A>void EntityUpdaterWidget::processUpdateResult( const RepositoryResult &result ) {<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
const QString &databaseTableName =<BR>
|
||
|
|
comboBoxCurrentTable->currentData( ).toString( );<BR>
|
||
|
|
<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
ModelManager &modelManager = ModelManager::instance( );<BR>
|
||
|
|
<BR>
|
||
|
|
QSqlTableModel *model =<BR>
|
||
|
|
modelManager.getModel( metadata.modelTableName( databaseTableName ) );<BR>
|
||
|
|
<BR>
|
||
|
|
QString primaryKeyColumnName =<BR>
|
||
|
|
metadata.primaryIdColumnName( databaseTableName );<BR>
|
||
|
|
<BR>
|
||
|
|
int columnIndex = selectedPrimaryEntity_.indexOf( primaryKeyColumnName );<BR>
|
||
|
|
QModelIndex rowIndex = findIndexByColumn( model, columnIndex, primaryKey_ );<BR>
|
||
|
|
selectedPrimaryEntity_ = model->record( rowIndex.row( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
primaryKeyFinder->refreshLineEditText( selectedPrimaryEntity_ );<BR>
|
||
|
|
foreignKeyFinder->resetToDefault( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 484"> 484 </A>void EntityUpdaterWidget::showMessageDialog( const RepositoryResult &result, <BR>
|
||
|
|
<A NAME="./ui/widgets/entity_updater_widget.cpp: 485"> 485 </A> const QString &successMessage ) {<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, result.errorMessage );<BR>
|
||
|
|
} else {<BR>
|
||
|
|
QMessageBox::information( this, QMessageBox::tr( "Success" ), successMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/reports_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/reports_widget.cpp: 1"> 1 </A>#include "reports_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
#include <QtCharts/QBarCategoryAxis><BR>
|
||
|
|
#include <QtCharts/QDateTimeAxis><BR>
|
||
|
|
#include <QtCharts/QLineSeries><BR>
|
||
|
|
#include <QtCharts/QValueAxis><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/reports_widget.cpp: 9"> 9 </A>ReportsWidget::ReportsWidget( QWidget *parent ) : QWidget( parent ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
setupTicketSalesReportWidgets( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/reports_widget.cpp: 15"> 15 </A>void ReportsWidget::setupTicketSalesReportWidgets( ) {<BR>
|
||
|
|
genreReportWidget->configureReportForGenre( );<BR>
|
||
|
|
hallReportWidget->configureReportForHall( );<BR>
|
||
|
|
movieReportWidget->configureReportForMovie( );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/session_management_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 1"> 1 </A>#include "session_management_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_session_request.h"<BR>
|
||
|
|
#include "error_dialog.h"<BR>
|
||
|
|
#include "model_manager.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "sessions_model.h"<BR>
|
||
|
|
#include "sessions_repository.h"<BR>
|
||
|
|
#include <qnamespace.h><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 13"> 13 </A>SessionManagementWidget::SessionManagementWidget( QWidget *parent )<BR>
|
||
|
|
: QWidget( parent ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
initializeRepositories( ); // First of second<BR>
|
||
|
|
initializeModels( ); // First of second<BR>
|
||
|
|
setupTableView( ); // After initialization of repositories<BR>
|
||
|
|
setupHallFinder( );<BR>
|
||
|
|
setupMovieFinder( );<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 25"> 25 </A>void SessionManagementWidget::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
sessionsRepository_ = repositoryManager.getRepositoryAs<SessionsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "sessions" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !sessionsRepository_ ) {<BR>
|
||
|
|
qFatal( ) << "SessionManagementWidget::initializeRepositories: Failed to "<BR>
|
||
|
|
"initialize repositories";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 38"> 38 </A>void SessionManagementWidget::initializeModels( ) {<BR>
|
||
|
|
ModelManager &modelManager = ModelManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
sessionsModel_ = modelManager.getModelAs<SessionsModel>( <BR>
|
||
|
|
metadata.modelTableName( "sessions" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( sessionsModel_ ) ) {<BR>
|
||
|
|
qFatal( ) << "SessionManagementWidget::initializeModels: Failed to "<BR>
|
||
|
|
"initialize models";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 51"> 51 </A>void SessionManagementWidget::setupTableView( ) {<BR>
|
||
|
|
tableSessions->setModel( sessionsModel_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 55"> 55 </A>void SessionManagementWidget::setupConnections( ) {<BR>
|
||
|
|
connect( btnAddSession, &QPushButton::clicked, this, <BR>
|
||
|
|
&SessionManagementWidget::onPushButtonAddSessionClicked );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( hallFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&SessionManagementWidget::onHallFieldRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( movieFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&SessionManagementWidget::onMovieFieldRetrieved );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 66"> 66 </A>void SessionManagementWidget::setupHallFinder( ) {<BR>
|
||
|
|
hallFinder->setDefaultRelation( "halls" );<BR>
|
||
|
|
hallFinder->setLabelText( EntityFinderWidget::tr( "Select hall" ) );<BR>
|
||
|
|
hallFinder->setLineEditPlaceholder( <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected hall" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 73"> 73 </A>void SessionManagementWidget::setupMovieFinder( ) {<BR>
|
||
|
|
movieFinder->setDefaultRelation( "movies" );<BR>
|
||
|
|
movieFinder->setLabelText( EntityFinderWidget::tr( "Select movie" ) );<BR>
|
||
|
|
movieFinder->setLineEditPlaceholder( <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected movie" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 80"> 80 </A>void SessionManagementWidget::onPushButtonAddSessionClicked( ) {<BR>
|
||
|
|
QDateTime beginAt = dateTimeEditBeginAt->dateTime( );<BR>
|
||
|
|
double ticketPrice = spinBoxTicketPrice->value( );<BR>
|
||
|
|
<BR>
|
||
|
|
CreateSessionRequest request;<BR>
|
||
|
|
request.setBeginAt( beginAt );<BR>
|
||
|
|
request.setHallId( selectedHallId_ );<BR>
|
||
|
|
request.setMovieId( selectedMovieId_ );<BR>
|
||
|
|
request.setTicketPrice( ticketPrice );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result = sessionsRepository_->createSession( request );<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
qWarning( ) << "Failed to create session:" << result.errorMessage;<BR>
|
||
|
|
ErrorDialog::displayError( this, result.errorMessage );<BR>
|
||
|
|
}<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 97"> 97 </A>void SessionManagementWidget::onHallFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
selectedHallId_ = field.value( ).toInt( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/session_management_widget.cpp: 101"> 101 </A>void SessionManagementWidget::onMovieFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
selectedMovieId_ = field.value( ).toInt( );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/single_record_time_range_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/single_record_time_range_widget.cpp: 1"> 1 </A>#include "single_record_time_range_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/single_record_time_range_widget.cpp: 3"> 3 </A>SingleRecordTimeRangeWidget::SingleRecordTimeRangeWidget( QWidget *parent )<BR>
|
||
|
|
: QWidget( parent ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/ticket_return_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 1"> 1 </A>#include "ticket_return_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_refund_request.h"<BR>
|
||
|
|
#include "error_dialog.h"<BR>
|
||
|
|
#include "model_manager.h"<BR>
|
||
|
|
#include "refunds_model.h"<BR>
|
||
|
|
#include "refunds_repository.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 13"> 13 </A>TicketReturnWidget::TicketReturnWidget( QWidget *parent )<BR>
|
||
|
|
: QWidget( parent ), retrievedTicketField_( -1 ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
initializeRepositories( );<BR>
|
||
|
|
initializeModels( );<BR>
|
||
|
|
setupTableView( ); // After initialization of models<BR>
|
||
|
|
setupTicketFinder( );<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Setup widgets<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 25"> 25 </A>void TicketReturnWidget::setupTableView( ) {<BR>
|
||
|
|
tableRefunds->setModel( refundsModel_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 29"> 29 </A>void TicketReturnWidget::setupTicketFinder( ) {<BR>
|
||
|
|
ticketFinder->setDefaultRelation( "tickets" );<BR>
|
||
|
|
ticketFinder->setLabelText( EntityFinderWidget::tr( "Select ticket" ) );<BR>
|
||
|
|
ticketFinder->setLineEditPlaceholder( <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected ticket" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 36"> 36 </A>void TicketReturnWidget::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
refundsRepository_ = repositoryManager.getRepositoryAs<RefundsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "refunds" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( refundsRepository_ ) ) {<BR>
|
||
|
|
qFatal( ) << "TicketReturnWidget::initializeRepositories: Failed to "<BR>
|
||
|
|
"initialize repositories";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 49"> 49 </A>void TicketReturnWidget::initializeModels( ) {<BR>
|
||
|
|
ModelManager &modelManager = ModelManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
refundsModel_ =<BR>
|
||
|
|
modelManager.getModelAs<RefundsModel>( metadata.modelTableName( "refunds" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( refundsModel_ ) ) {<BR>
|
||
|
|
qFatal( ) << "TicketReturnWidget::initializeModels: Failed to initialize "<BR>
|
||
|
|
"models";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 62"> 62 </A>void TicketReturnWidget::setupConnections( ) {<BR>
|
||
|
|
connect( pushButtonRefundTicket, &QPushButton::clicked, this, <BR>
|
||
|
|
&TicketReturnWidget::onPushButtonRefundTicketClicked );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( ticketFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&TicketReturnWidget::onTicketFieldRetrieved );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 70"> 70 </A>void TicketReturnWidget::onPushButtonRefundTicketClicked( ) {<BR>
|
||
|
|
if ( retrievedTicketField_ == -1 ) {<BR>
|
||
|
|
QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
QMessageBox::tr( "No ticket selected" ) );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QDateTime refundAt;<BR>
|
||
|
|
if ( dateTimeEditRefund->isEnabled( ) ) {<BR>
|
||
|
|
refundAt = dateTimeEditRefund->dateTime( );<BR>
|
||
|
|
} else {<BR>
|
||
|
|
refundAt = QDateTime::currentDateTime( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
double refundAmount = spinBoxRefundAmount->value( );<BR>
|
||
|
|
<BR>
|
||
|
|
CreateRefundRequest request;<BR>
|
||
|
|
request.setTicketId( retrievedTicketField_ );<BR>
|
||
|
|
request.setRefundAt( refundAt );<BR>
|
||
|
|
request.setRefundAmount( refundAmount );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult refundResult = refundsRepository_->createRefund( request );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !refundResult.success ) {<BR>
|
||
|
|
qInfo( ) << "Failed to refund ticket by id:" << retrievedTicketField_;<BR>
|
||
|
|
ErrorDialog::displayError( this, refundResult.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QString successMessage =<BR>
|
||
|
|
QMessageBox::tr( "Ticket with number %1 has been successfully refunded." )<BR>
|
||
|
|
.arg( retrievedTicketField_ );<BR>
|
||
|
|
QMessageBox::information( this, QMessageBox::tr( "Success" ), successMessage );<BR>
|
||
|
|
<BR>
|
||
|
|
ticketFinder->resetLineEditText( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_return_widget.cpp: 107"> 107 </A>void TicketReturnWidget::onTicketFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
retrievedTicketField_ = field.value( ).toInt( );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/ticket_sale_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 1"> 1 </A>#include "ticket_sale_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "create_ticket_request.h"<BR>
|
||
|
|
#include "error_dialog.h"<BR>
|
||
|
|
#include "model_manager.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "tickets_model.h"<BR>
|
||
|
|
#include "tickets_repository.h"<BR>
|
||
|
|
#include <QLineEdit><BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
#include <QSqlError><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 15"> 15 </A>TicketSaleWidget::TicketSaleWidget( QWidget *parent )<BR>
|
||
|
|
: QWidget( parent ), selectedSessionId_( -1 ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
initializeRepositories( ); // First or second<BR>
|
||
|
|
initializeModels( ); // First ir second<BR>
|
||
|
|
setupTableView( ); // After initialization of models<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
setupSessionFinder( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 26"> 26 </A>void TicketSaleWidget::setupTableView( ) {<BR>
|
||
|
|
tableTickets->setModel( ticketsModel_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 30"> 30 </A>void TicketSaleWidget::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
ticketsRepository_ = repositoryManager.getRepositoryAs<TicketsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "tickets" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !ticketsRepository_ ) {<BR>
|
||
|
|
qFatal( ) << "TicketSaleWidget::initializeRepositories: Failed to "<BR>
|
||
|
|
"initialize repositories";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 43"> 43 </A>void TicketSaleWidget::initializeModels( ) {<BR>
|
||
|
|
ModelManager &modelManager = ModelManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
ticketsModel_ =<BR>
|
||
|
|
modelManager.getModelAs<TicketsModel>( metadata.modelTableName( "tickets" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( ticketsModel_ ) ) {<BR>
|
||
|
|
qFatal( ) << "TicketSaleWidget::initializeModels: Failed to initialize "<BR>
|
||
|
|
"models";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 56"> 56 </A>void TicketSaleWidget::setupConnections( ) {<BR>
|
||
|
|
connect( btnSellTicket, &QPushButton::clicked, this, <BR>
|
||
|
|
&TicketSaleWidget::onPushButtonSellTicketClicked );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( sessionFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&TicketSaleWidget::onFieldRetrieved );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 64"> 64 </A>void TicketSaleWidget::setupSessionFinder( ) {<BR>
|
||
|
|
sessionFinder->setDefaultRelation( "sessions" );<BR>
|
||
|
|
sessionFinder->setLabelText( EntityFinderWidget::tr( "Select session" ) );<BR>
|
||
|
|
sessionFinder->setLineEditPlaceholder( EntityFinderWidget::tr( <BR>
|
||
|
|
"Here will be information about selected session" ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 71"> 71 </A>void TicketSaleWidget::onPushButtonSellTicketClicked( ) {<BR>
|
||
|
|
if ( selectedSessionId_ == -1 ) {<BR>
|
||
|
|
QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
QMessageBox::tr( "No session selected" ) );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
int seatNumber = spinBoxSeatNumber->value( );<BR>
|
||
|
|
QDateTime soldAt = dateTimeEditSell->isEnabled( )<BR>
|
||
|
|
? dateTimeEditSell->dateTime( )<BR>
|
||
|
|
: QDateTime::currentDateTime( );<BR>
|
||
|
|
<BR>
|
||
|
|
CreateTicketRequest request;<BR>
|
||
|
|
request.setSeatNumber( seatNumber );<BR>
|
||
|
|
request.setSessionId( selectedSessionId_ );<BR>
|
||
|
|
request.setSoldAt( soldAt );<BR>
|
||
|
|
<BR>
|
||
|
|
RepositoryResult result = ticketsRepository_->createTicket( request );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
qInfo( ) << "Failed to create ticket:" << result.errorMessage;<BR>
|
||
|
|
ErrorDialog::displayError( this, result.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 97"> 97 </A>void TicketSaleWidget::onFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
selectedSessionId_ = field.value( ).toInt( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
// Check if all values in initializer list are valid<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 102"> 102 </A>void TicketSaleWidget::validateSessionValues( <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sale_widget.cpp: 103"> 103 </A> const std::initializer_list<QVariant> &valuesList ) {<BR>
|
||
|
|
for ( const auto &value : valuesList ) {<BR>
|
||
|
|
if ( !value.isValid( ) ) {<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT>
|
||
|
|
<H1><A NAME="">./ui/widgets/ticket_sales_report_widget.cpp</A></H1>
|
||
|
|
<TT>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 1"> 1 </A>#include "ticket_sales_report_widget.h"<BR>
|
||
|
|
<BR>
|
||
|
|
#include "error_dialog.h"<BR>
|
||
|
|
#include "repository_manager.h"<BR>
|
||
|
|
#include "repository_result.h"<BR>
|
||
|
|
#include "schema_metadata.h"<BR>
|
||
|
|
#include "session_statistics_dto.h"<BR>
|
||
|
|
#include "sessions_statistics_repository.h"<BR>
|
||
|
|
#include "table_info_sqlite.h"<BR>
|
||
|
|
#include <QDateTimeAxis><BR>
|
||
|
|
#include <QMessageBox><BR>
|
||
|
|
#include <QScatterSeries><BR>
|
||
|
|
#include <QValueAxis><BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 15"> 15 </A>TicketSalesReportWidget::SalesData::SalesData( )<BR>
|
||
|
|
: refundExpenses_( 0 ), refundedTickets_( 0 ), salesRevenue_( 0 ), <BR>
|
||
|
|
soldTickets_( 0 ), maximumTickets_( 0 ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 19"> 19 </A>TicketSalesReportWidget::SalesData::SalesData( double refundExpenses, <BR>
|
||
|
|
double salesRevenue, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 21"> 21 </A> qint32 refundedTickets, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 22"> 22 </A> qint32 soldTickets, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 23"> 23 </A> qint32 maxTickets )<BR>
|
||
|
|
: refundExpenses_( refundExpenses ), refundedTickets_( refundedTickets ), <BR>
|
||
|
|
salesRevenue_( salesRevenue ), soldTickets_( soldTickets ), <BR>
|
||
|
|
maximumTickets_( maxTickets ) {}<BR>
|
||
|
|
<BR>
|
||
|
|
TicketSalesReportWidget::SalesData<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 29"> 29 </A>TicketSalesReportWidget::SalesData::operator+( const SalesData &other ) const {<BR>
|
||
|
|
SalesData result;<BR>
|
||
|
|
result.setMaximumTickets( maximumTickets( ) + other.maximumTickets( ) );<BR>
|
||
|
|
result.setSoldTickets( soldTickets( ) + other.soldTickets( ) );<BR>
|
||
|
|
result.setRefundedTickets( refundedTickets( ) + other.refundedTickets( ) );<BR>
|
||
|
|
result.setSalesRevenue( salesRevenue( ) + other.salesRevenue( ) );<BR>
|
||
|
|
result.setRefundExpenses( refundExpenses( ) + other.refundExpenses( ) );<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
TicketSalesReportWidget::SalesData &<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 40"> 40 </A>TicketSalesReportWidget::SalesData::operator+=( const SalesData &other ) {<BR>
|
||
|
|
*this = std::move( *this + other );<BR>
|
||
|
|
return *this;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 45"> 45 </A>TicketSalesReportWidget::TicketSalesReportWidget( QWidget *parent )<BR>
|
||
|
|
: QWidget( parent ) {<BR>
|
||
|
|
setupUi( this );<BR>
|
||
|
|
<BR>
|
||
|
|
initializeRepositories( );<BR>
|
||
|
|
initializeChart( );<BR>
|
||
|
|
setupChart( ); // After initialize chart<BR>
|
||
|
|
setupConnections( );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 55"> 55 </A>void TicketSalesReportWidget::configureReportForGenre( ) {<BR>
|
||
|
|
TableInfoSQLite tableInfo( "genres" );<BR>
|
||
|
|
columnInfoIndex_ = tableInfo.columnIndex( "genre_name" );<BR>
|
||
|
|
<BR>
|
||
|
|
configureEntityFinder( <BR>
|
||
|
|
"genres", EntityFinderWidget::tr( "Select genre" ), <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected genre" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
sessionsStatisticsMethod_ =<BR>
|
||
|
|
std::bind( &SessionsStatisticsRepository::getSessionsForGenre, <BR>
|
||
|
|
sessionsStatisticsRepository, <BR>
|
||
|
|
std::placeholders::_1, // entityId<BR>
|
||
|
|
std::placeholders::_2, // startDate<BR>
|
||
|
|
std::placeholders::_3, // endDate<BR>
|
||
|
|
std::placeholders::_4 // sessions<BR>
|
||
|
|
);<BR>
|
||
|
|
<BR>
|
||
|
|
billetChartTitle_ = tr( "Popularity of Genre: Name: \"%1\"" );<BR>
|
||
|
|
seriesName_ = tr( "Tickets Sold" );<BR>
|
||
|
|
yAxisTitle_ = tr( "Number of Tickets Sold" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 77"> 77 </A>void TicketSalesReportWidget::configureReportForHall( ) {<BR>
|
||
|
|
TableInfoSQLite tableInfo( "halls" );<BR>
|
||
|
|
columnInfoIndex_ = tableInfo.columnIndex( "hall_name" );<BR>
|
||
|
|
<BR>
|
||
|
|
configureEntityFinder( <BR>
|
||
|
|
"halls", EntityFinderWidget::tr( "Select hall" ), <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected hall" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
sessionsStatisticsMethod_ =<BR>
|
||
|
|
std::bind( &SessionsStatisticsRepository::getSessionsForHall, <BR>
|
||
|
|
sessionsStatisticsRepository, <BR>
|
||
|
|
std::placeholders::_1, // entityId<BR>
|
||
|
|
std::placeholders::_2, // startDate<BR>
|
||
|
|
std::placeholders::_3, // endDate<BR>
|
||
|
|
std::placeholders::_4 // sessions<BR>
|
||
|
|
);<BR>
|
||
|
|
<BR>
|
||
|
|
billetChartTitle_ = tr( "Attendance for Hall: Name: \"%1\"" );<BR>
|
||
|
|
seriesName_ = tr( "Visitors" );<BR>
|
||
|
|
yAxisTitle_ = tr( "Number of Visitors" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 99"> 99 </A>void TicketSalesReportWidget::configureReportForMovie( ) {<BR>
|
||
|
|
TableInfoSQLite tableInfo( "movies" );<BR>
|
||
|
|
columnInfoIndex_ = tableInfo.columnIndex( "title" );<BR>
|
||
|
|
<BR>
|
||
|
|
configureEntityFinder( <BR>
|
||
|
|
"movies", EntityFinderWidget::tr( "Select movie" ), <BR>
|
||
|
|
EntityFinderWidget::tr( "Here will be information about selected movie" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
sessionsStatisticsMethod_ =<BR>
|
||
|
|
std::bind( &SessionsStatisticsRepository::getSessionsForMovie, <BR>
|
||
|
|
sessionsStatisticsRepository, <BR>
|
||
|
|
std::placeholders::_1, // entityId<BR>
|
||
|
|
std::placeholders::_2, // startDate<BR>
|
||
|
|
std::placeholders::_3, // endDate<BR>
|
||
|
|
std::placeholders::_4 // sessions<BR>
|
||
|
|
);<BR>
|
||
|
|
<BR>
|
||
|
|
billetChartTitle_ = tr( "Tickets Sold for Movie: Title: \"%1\"" );<BR>
|
||
|
|
seriesName_ = tr( "Tickets Sold" );<BR>
|
||
|
|
yAxisTitle_ = tr( "Number of Tickets Sold" );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 121"> 121 </A>void TicketSalesReportWidget::initializeRepositories( ) {<BR>
|
||
|
|
RepositoryManager &repositoryManager = RepositoryManager::instance( );<BR>
|
||
|
|
SchemaMetadata metadata = SchemaMetadata::defaultSchema( );<BR>
|
||
|
|
<BR>
|
||
|
|
sessionsStatisticsRepository =<BR>
|
||
|
|
repositoryManager.getRepositoryAs<SessionsStatisticsRepository>( <BR>
|
||
|
|
metadata.repositoryTableName( "sessions_statistics" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
if ( !bool( sessionsStatisticsRepository ) ) {<BR>
|
||
|
|
qFatal( ) << "TicketSalesReportWidget::initializeRepositories: Failed to "<BR>
|
||
|
|
"initialize repositories";<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 135"> 135 </A>void TicketSalesReportWidget::initializeChart( ) {<BR>
|
||
|
|
chartView_ = new QChartView( this );<BR>
|
||
|
|
chartView_->setRenderHint( QPainter::Antialiasing );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 140"> 140 </A>void TicketSalesReportWidget::setupChart( ) {<BR>
|
||
|
|
frameChart->layout( )->addWidget( chartView_ );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 144"> 144 </A>void TicketSalesReportWidget::setupConnections( ) {<BR>
|
||
|
|
connect( btnGenerate, &QPushButton::clicked, this, <BR>
|
||
|
|
&TicketSalesReportWidget::onPushButtonGenerateClicked );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( entityFinder, &EntityFinderWidget::fieldRetrieved, this, <BR>
|
||
|
|
&TicketSalesReportWidget::onFieldRetrieved );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( entityFinder, &EntityFinderWidget::reseted, this, <BR>
|
||
|
|
&TicketSalesReportWidget::onEntityFinderReseted );<BR>
|
||
|
|
<BR>
|
||
|
|
connect( entityFinder, &EntityFinderWidget::recordRetrieved, this, <BR>
|
||
|
|
&TicketSalesReportWidget::onRecordRetrieved );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 158"> 158 </A>void TicketSalesReportWidget::configureEntityFinder( <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 159"> 159 </A> const QString &databaseTableName, const QString &labelText, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 160"> 160 </A> const QString &placeholder ) {<BR>
|
||
|
|
entityFinder->setDefaultRelation( databaseTableName );<BR>
|
||
|
|
entityFinder->setLabelText( labelText );<BR>
|
||
|
|
entityFinder->setLineEditPlaceholder( placeholder );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 166"> 166 </A>void TicketSalesReportWidget::onEntityFinderReseted( ) {<BR>
|
||
|
|
selectedEntityId_ = -1;<BR>
|
||
|
|
chartView_->setChart( new QChart( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 171"> 171 </A>void TicketSalesReportWidget::onPushButtonGenerateClicked( ) {<BR>
|
||
|
|
if ( !dateRange( startRange_, endRange_ ) ) {<BR>
|
||
|
|
QMessageBox::QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
QMessageBox::tr( "Invalid date range" ) );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QVector<SessionStatisticsDTO> sessions;<BR>
|
||
|
|
RepositoryResult result = retrieveSessions( sessions );<BR>
|
||
|
|
if ( !result.success ) {<BR>
|
||
|
|
ErrorDialog::displayError( this, result.errorMessage );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
if ( sessions.isEmpty( ) ) {<BR>
|
||
|
|
QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
QMessageBox::tr( "No sessions found between %1 and %2." )<BR>
|
||
|
|
.arg( startRange_.toString( "dd.MM.yyyy" ) )<BR>
|
||
|
|
.arg( endRange_.toString( "dd.MM.yyyy" ) ) );<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
createChart( aggregateByDateTime( sessions ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 196"> 196 </A>void TicketSalesReportWidget::onFieldRetrieved( const QSqlField &field ) {<BR>
|
||
|
|
selectedEntityId_ = field.value( ).toInt( );<BR>
|
||
|
|
chartView_->setChart( new QChart( ) );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 201"> 201 </A>void TicketSalesReportWidget::onRecordRetrieved( const QSqlRecord &rowValues ) {<BR>
|
||
|
|
QString columnInfoValue = rowValues.value( columnInfoIndex_ ).toString( );<BR>
|
||
|
|
chartTitle_ = billetChartTitle_.arg( columnInfoValue );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QMap<QDateTime, TicketSalesReportWidget::SalesData><BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 207"> 207 </A>TicketSalesReportWidget::aggregateByDateTime( <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 208"> 208 </A> const QVector<SessionStatisticsDTO> &sessions, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 209"> 209 </A> std::function<bool( const SessionStatisticsDTO & )> filter ) {<BR>
|
||
|
|
<BR>
|
||
|
|
QMap<QDateTime, SalesData> accamulatedSalesData;<BR>
|
||
|
|
<BR>
|
||
|
|
for ( const SessionStatisticsDTO &session : sessions ) {<BR>
|
||
|
|
if ( !filter || filter( session ) ) {<BR>
|
||
|
|
QDateTime dateTime = session.beginAt( );<BR>
|
||
|
|
<BR>
|
||
|
|
SalesData buffer;<BR>
|
||
|
|
buffer.setRefundExpenses( session.refundExpenses( ) );<BR>
|
||
|
|
buffer.setRefundedTickets( session.refundedTickets( ) );<BR>
|
||
|
|
buffer.setSalesRevenue( session.salesRevenue( ) );<BR>
|
||
|
|
buffer.setSoldTickets( session.soldTickets( ) );<BR>
|
||
|
|
buffer.setMaximumTickets( session.totalSeats( ) );<BR>
|
||
|
|
<BR>
|
||
|
|
accamulatedSalesData[dateTime] += buffer;<BR>
|
||
|
|
}<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
return accamulatedSalesData;<BR>
|
||
|
|
};<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 231"> 231 </A>QAbstractAxis *TicketSalesReportWidget::createDateTimeAxis( <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 232"> 232 </A> int tickCount, const QString &axisTitle, const QDateTime &minDate, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 233"> 233 </A> const QDateTime &maxDate ) const {<BR>
|
||
|
|
QDateTimeAxis *axisX = new QDateTimeAxis( );<BR>
|
||
|
|
axisX->setTitleText( axisTitle );<BR>
|
||
|
|
axisX->setFormat( "dd.MM.yyyy" );<BR>
|
||
|
|
axisX->setTickCount( tickCount );<BR>
|
||
|
|
axisX->setRange( minDate, maxDate );<BR>
|
||
|
|
return axisX;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QAbstractAxis *<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 243"> 243 </A>TicketSalesReportWidget::createValueAxis( int maxValue, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 244"> 244 </A> const QString &axisTitle ) const {<BR>
|
||
|
|
QValueAxis *axisY = new QValueAxis( );<BR>
|
||
|
|
axisY->setTitleText( axisTitle );<BR>
|
||
|
|
axisY->setLabelFormat( "%d" );<BR>
|
||
|
|
axisY->setRange( 0, maxValue );<BR>
|
||
|
|
return axisY;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 252"> 252 </A>bool TicketSalesReportWidget::validateData( <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 253"> 253 </A> const QMap<QDateTime, SalesData> &data ) const {<BR>
|
||
|
|
if ( !data.isEmpty( ) ) {<BR>
|
||
|
|
return true;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
qWarning( ) << "No data for chart:" << chartTitle_;<BR>
|
||
|
|
<BR>
|
||
|
|
// QMessageBox::warning( this, QMessageBox::tr( "Error" ), <BR>
|
||
|
|
// QMessageBox::tr( "No data for chart" ) );<BR>
|
||
|
|
<BR>
|
||
|
|
return false;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 266"> 266 </A>RepositoryResult TicketSalesReportWidget::retrieveSessions( <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 267"> 267 </A> QVector<SessionStatisticsDTO> &sessions ) {<BR>
|
||
|
|
RepositoryResult result =<BR>
|
||
|
|
sessionsStatisticsMethod_( selectedEntityId_, std::cref( startRange_ ), <BR>
|
||
|
|
std::cref( endRange_ ), std::ref( sessions ) );<BR>
|
||
|
|
return result;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 274"> 274 </A>bool TicketSalesReportWidget::dateRange( QDateTime &startOut, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 275"> 275 </A> QDateTime &endOut ) {<BR>
|
||
|
|
startOut = dateTimeEditStartOfPeriod->dateTime( );<BR>
|
||
|
|
endOut = dateTimeEditEndOfPeriod->dateTime( );<BR>
|
||
|
|
return endOut > startOut;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 281"> 281 </A>void TicketSalesReportWidget::createChart( <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 282"> 282 </A> const QMap<QDateTime, SalesData> &data ) {<BR>
|
||
|
|
if ( !validateData( data ) ) {<BR>
|
||
|
|
return;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QDateTime minDate, maxDate;<BR>
|
||
|
|
int tickCount = data.size( );<BR>
|
||
|
|
if ( tickCount > 10 ) {<BR>
|
||
|
|
tickCount = 10;<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
QChart *chart = new QChart( );<BR>
|
||
|
|
chart->setTitle( chartTitle_ );<BR>
|
||
|
|
<BR>
|
||
|
|
QAbstractSeries *maximumTicketsSeries = createScatterSeries( <BR>
|
||
|
|
data, minDate, maxDate, &SalesData::maximumTickets, "Maximum Tickets" );<BR>
|
||
|
|
QAbstractSeries *soldTicketsSeries = createScatterSeries( <BR>
|
||
|
|
data, minDate, maxDate, &SalesData::soldTickets, "Sold Tickets" );<BR>
|
||
|
|
QAbstractSeries *refundedTicketsSeries = createScatterSeries( <BR>
|
||
|
|
data, minDate, maxDate, &SalesData::refundedTickets, "Refunded Tickets" );<BR>
|
||
|
|
QAbstractSeries *salesRevenueSeries = createScatterSeries( <BR>
|
||
|
|
data, minDate, maxDate, &SalesData::salesRevenue, "Sales Revenue" );<BR>
|
||
|
|
QAbstractSeries *refundExpensesSeries = createScatterSeries( <BR>
|
||
|
|
data, minDate, maxDate, &SalesData::refundExpenses, "Refund Expenses" );<BR>
|
||
|
|
<BR>
|
||
|
|
chart->addSeries( maximumTicketsSeries );<BR>
|
||
|
|
chart->addSeries( soldTicketsSeries );<BR>
|
||
|
|
chart->addSeries( refundedTicketsSeries );<BR>
|
||
|
|
chart->addSeries( salesRevenueSeries );<BR>
|
||
|
|
chart->addSeries( refundExpensesSeries );<BR>
|
||
|
|
<BR>
|
||
|
|
QAbstractAxis *axisX =<BR>
|
||
|
|
createDateTimeAxis( tickCount, tr( "Date" ), minDate, maxDate );<BR>
|
||
|
|
chart->addAxis( axisX, Qt::AlignBottom );<BR>
|
||
|
|
<BR>
|
||
|
|
double maxMoneyValue = std::max( {maxValue( data, &SalesData::refundExpenses ), <BR>
|
||
|
|
maxValue( data, &SalesData::salesRevenue )} );<BR>
|
||
|
|
QAbstractAxis *axisYMoney = createValueAxis( maxMoneyValue, tr( "Money" ) );<BR>
|
||
|
|
chart->addAxis( axisYMoney, Qt::AlignLeft );<BR>
|
||
|
|
<BR>
|
||
|
|
int maxTickets = maxValue( data, &SalesData::maximumTickets );<BR>
|
||
|
|
<BR>
|
||
|
|
QAbstractAxis *axisYTickets = createValueAxis( maxTickets, tr( "Tickets" ) );<BR>
|
||
|
|
chart->addAxis( axisYTickets, Qt::AlignRight );<BR>
|
||
|
|
<BR>
|
||
|
|
qDebug( ) << "Maximum movey Value" << maxMoneyValue << "maxTickets"<BR>
|
||
|
|
<< maxTickets;<BR>
|
||
|
|
<BR>
|
||
|
|
maximumTicketsSeries->attachAxis( axisYTickets );<BR>
|
||
|
|
refundedTicketsSeries->attachAxis( axisYTickets );<BR>
|
||
|
|
soldTicketsSeries->attachAxis( axisYTickets );<BR>
|
||
|
|
<BR>
|
||
|
|
refundExpensesSeries->attachAxis( axisYMoney );<BR>
|
||
|
|
salesRevenueSeries->attachAxis( axisYMoney );<BR>
|
||
|
|
<BR>
|
||
|
|
maximumTicketsSeries->attachAxis( axisX );<BR>
|
||
|
|
refundExpensesSeries->attachAxis( axisX );<BR>
|
||
|
|
refundedTicketsSeries->attachAxis( axisX );<BR>
|
||
|
|
salesRevenueSeries->attachAxis( axisX );<BR>
|
||
|
|
soldTicketsSeries->attachAxis( axisX );<BR>
|
||
|
|
<BR>
|
||
|
|
updateChartView( chart );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 346"> 346 </A>void TicketSalesReportWidget::setupChart( QChart *chart, QAbstractSeries *series, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 347"> 347 </A> QAbstractAxis *axisX, <BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 348"> 348 </A> QAbstractAxis *axisY ) const {<BR>
|
||
|
|
chart->addSeries( series );<BR>
|
||
|
|
chart->addAxis( axisX, Qt::AlignBottom );<BR>
|
||
|
|
chart->addAxis( axisY, Qt::AlignLeft );<BR>
|
||
|
|
series->attachAxis( axisX );<BR>
|
||
|
|
series->attachAxis( axisY );<BR>
|
||
|
|
}<BR>
|
||
|
|
<BR>
|
||
|
|
<A NAME="./ui/widgets/ticket_sales_report_widget.cpp: 356"> 356 </A>void TicketSalesReportWidget::updateChartView( QChart *chart ) const {<BR>
|
||
|
|
chartView_->setChart( chart );<BR>
|
||
|
|
chartView_->setRenderHint( QPainter::Antialiasing );<BR>
|
||
|
|
}<BR>
|
||
|
|
</TT> </BODY></HTML>
|
||
|
|
</BODY></HTML>
|