210 lines
6.9 KiB
C++
210 lines
6.9 KiB
C++
#ifndef TICKET_SALES_REPORT_WIDGET_H
|
|
#define TICKET_SALES_REPORT_WIDGET_H
|
|
|
|
#include "ui_ticket_sales_report_widget.h"
|
|
|
|
#include <QChartView>
|
|
#include <QLineSeries>
|
|
#include <QScatterSeries>
|
|
#include <functional>
|
|
|
|
// Forward declaration
|
|
class RepositoryResult;
|
|
class SessionStatisticsDTO;
|
|
class RepositoriesInterface;
|
|
class SessionsStatisticsRepository;
|
|
|
|
class TicketSalesReportWidget : public QWidget,
|
|
private Ui::TicketSalesReportWidget {
|
|
Q_OBJECT
|
|
|
|
private:
|
|
class SalesData {
|
|
private:
|
|
double refundExpenses_;
|
|
double salesRevenue_;
|
|
qint32 refundedTickets_;
|
|
qint32 soldTickets_;
|
|
qint32 maximumTickets_;
|
|
|
|
public:
|
|
SalesData();
|
|
explicit SalesData(double refundExpenses, double salesRevenue,
|
|
qint32 refundedTickets, qint32 soldTickets,
|
|
qint32 maximumTickets);
|
|
|
|
SalesData &operator+=(const SalesData &other);
|
|
SalesData operator+(const SalesData &other) const;
|
|
|
|
// clang-format off
|
|
inline double refundExpenses() const { return refundExpenses_; };
|
|
inline double salesRevenue() const { return salesRevenue_; };
|
|
inline qint32 refundedTickets() const { return refundedTickets_; };
|
|
inline qint32 soldTickets() const { return soldTickets_; };
|
|
inline qint32 maximumTickets() const { return maximumTickets_; };
|
|
inline void setRefundExpenses(double refundExpenses) { refundExpenses_ = refundExpenses; };
|
|
inline void setRefundedTickets(qint32 refundedTickets) { refundedTickets_ = refundedTickets; };
|
|
inline void setSalesRevenue(double salesRevenue) { salesRevenue_ = salesRevenue; };
|
|
inline void setSoldTickets(qint32 soldTickets) { soldTickets_ = soldTickets; };
|
|
inline void setMaximumTickets(qint32 maximumTickets) { maximumTickets_ = maximumTickets; };
|
|
// clang-format on
|
|
};
|
|
|
|
private:
|
|
using GetSessionsForEntityByIdMethod = std::function<RepositoryResult(
|
|
qint32 entityId, std::optional<QDateTime> startDate,
|
|
std::optional<QDateTime> endDate,
|
|
QVector<SessionStatisticsDTO> &sessions)>;
|
|
|
|
private:
|
|
GetSessionsForEntityByIdMethod sessionsStatisticsMethod_;
|
|
QChartView *chartView_;
|
|
QDateTime startRange_, endRange_;
|
|
QString billetChartTitle_, chartTitle_, seriesName_, yAxisTitle_;
|
|
SessionsStatisticsRepository *sessionsStatisticsRepository;
|
|
int columnInfoIndex_;
|
|
qint32 selectedEntityId_;
|
|
|
|
public:
|
|
explicit TicketSalesReportWidget(QWidget *parent = nullptr);
|
|
|
|
void configureReportForGenre();
|
|
void configureReportForHall();
|
|
void configureReportForMovie();
|
|
|
|
private:
|
|
void initializeChart();
|
|
void initializeRepositories();
|
|
void setupChart();
|
|
void setupConnections();
|
|
|
|
void configureEntityFinder(const QString &databaseTableName,
|
|
const QString &labelText,
|
|
const QString &placeholder);
|
|
|
|
private slots:
|
|
void onEntityFinderReseted();
|
|
void onPushButtonGenerateClicked();
|
|
void onFieldRetrieved(const QSqlField &field);
|
|
void onRecordRetrieved(const QSqlRecord &rowValues);
|
|
|
|
private:
|
|
template <typename T, typename SeriesType>
|
|
SeriesType *
|
|
createSeriesTemplate(const QMap<QDateTime, SalesData> &accumulatedSalesData,
|
|
QDateTime &minDate, QDateTime &maxDate,
|
|
T (SalesData::*getter)() const,
|
|
const QString &seriesName);
|
|
|
|
template <typename T>
|
|
QAbstractSeries *
|
|
createLineSeries(const QMap<QDateTime, SalesData> &accumulatedSalesData,
|
|
QDateTime &minDate, QDateTime &maxDate,
|
|
T (SalesData::*getter)() const, const QString &seriesName);
|
|
|
|
template <typename T>
|
|
QAbstractSeries *
|
|
createScatterSeries(const QMap<QDateTime, SalesData> &accumulatedSalesData,
|
|
QDateTime &minDate, QDateTime &maxDate,
|
|
T (SalesData::*getter)() const,
|
|
const QString &seriesName);
|
|
|
|
template <typename T>
|
|
T maxValue(const QMap<QDateTime, SalesData> &data,
|
|
T (SalesData::*getter)() const);
|
|
|
|
private:
|
|
QMap<QDateTime, TicketSalesReportWidget::SalesData> aggregateByDateTime(
|
|
const QVector<SessionStatisticsDTO> &sessions,
|
|
std::function<bool(const SessionStatisticsDTO &)> filter = {});
|
|
|
|
QAbstractAxis *createDateTimeAxis(int tickCount, const QString &axisTitle,
|
|
const QDateTime &minDate,
|
|
const QDateTime &maxDate) const;
|
|
|
|
QAbstractAxis *createValueAxis(int maxValue, const QString &axisTitle) const;
|
|
|
|
RepositoryResult retrieveSessions(QVector<SessionStatisticsDTO> &sessions);
|
|
|
|
bool dateRange(QDateTime &startOut, QDateTime &endOut);
|
|
|
|
bool validateData(const QMap<QDateTime, SalesData> &data) const;
|
|
|
|
void createChart(const QMap<QDateTime, SalesData> &data);
|
|
|
|
void setupChart(QChart *chart, QAbstractSeries *series, QAbstractAxis *axisX,
|
|
QAbstractAxis *axisY) const;
|
|
|
|
void updateChartView(QChart *chart) const;
|
|
};
|
|
|
|
template <typename T, typename SeriesType>
|
|
SeriesType *TicketSalesReportWidget::createSeriesTemplate(
|
|
const QMap<QDateTime, SalesData> &accumulatedSalesData, QDateTime &minDate,
|
|
QDateTime &maxDate, T (SalesData::*getter)() const,
|
|
const QString &seriesName) {
|
|
|
|
auto *series = new SeriesType();
|
|
series->setName(seriesName);
|
|
|
|
bool first = true;
|
|
|
|
for (auto it = accumulatedSalesData.cbegin();
|
|
it != accumulatedSalesData.cend(); ++it) {
|
|
const QDateTime &dateTime = it.key();
|
|
|
|
series->append(dateTime.toMSecsSinceEpoch(), (it.value().*getter)());
|
|
|
|
if (first) {
|
|
minDate = dateTime;
|
|
maxDate = dateTime;
|
|
first = false;
|
|
} else {
|
|
if (dateTime < minDate)
|
|
minDate = dateTime;
|
|
if (dateTime > maxDate)
|
|
maxDate = dateTime;
|
|
}
|
|
}
|
|
|
|
return series;
|
|
}
|
|
|
|
template <typename T>
|
|
QAbstractSeries *TicketSalesReportWidget::createScatterSeries(
|
|
const QMap<QDateTime, SalesData> &accumulatedSalesData, QDateTime &minDate,
|
|
QDateTime &maxDate, T (SalesData::*getter)() const,
|
|
const QString &seriesName) {
|
|
|
|
return createSeriesTemplate<T, QScatterSeries>(accumulatedSalesData, minDate,
|
|
maxDate, getter, seriesName);
|
|
}
|
|
|
|
template <typename T>
|
|
QAbstractSeries *TicketSalesReportWidget::createLineSeries(
|
|
const QMap<QDateTime, SalesData> &accumulatedSalesData, QDateTime &minDate,
|
|
QDateTime &maxDate, T (SalesData::*getter)() const,
|
|
const QString &seriesName) {
|
|
|
|
return createSeriesTemplate<T, QLineSeries>(accumulatedSalesData, minDate,
|
|
maxDate, getter, seriesName);
|
|
}
|
|
|
|
template <typename T>
|
|
T TicketSalesReportWidget::maxValue(const QMap<QDateTime, SalesData> &data,
|
|
T (SalesData::*getter)() const) {
|
|
if (data.isEmpty()) {
|
|
return T{};
|
|
}
|
|
|
|
T maxValue = (data.cbegin().value().*getter)();
|
|
|
|
for (auto it = data.cbegin(); it != data.cend(); ++it) {
|
|
maxValue = std::max(maxValue, (it.value().*getter)());
|
|
}
|
|
|
|
return maxValue;
|
|
}
|
|
|
|
#endif // TICKET_SALES_REPORT_WIDGET_H
|