Files
2026-07-12 14:34:52 +04:00

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