From 7a7b10260a924d7bf6b08078b292952f56b43b72 Mon Sep 17 00:00:00 2001 From: Gerhard Hoffmann Date: Mon, 16 Sep 2024 16:47:01 +0200 Subject: [PATCH] Add untracked(!) files --- library/include/calculate_price.h | 354 +++++++++++++++++++++++++ library/include/calculator_functions.h | 155 +++++++++++ 2 files changed, 509 insertions(+) create mode 100644 library/include/calculate_price.h create mode 100644 library/include/calculator_functions.h diff --git a/library/include/calculate_price.h b/library/include/calculate_price.h new file mode 100644 index 0000000..ee5f1e9 --- /dev/null +++ b/library/include/calculate_price.h @@ -0,0 +1,354 @@ +#ifndef CALCULATE_PRICE_H +#define CALCULATE_PRICE_H + +#include +#include +#include "tariff_time_range.h" + +#include +#include + +#ifdef WIN32 +#ifdef CALCULATE_LIBRARY_EXPORTS +#define CALCULATE_LIBRARY_API __declspec(dllexport) +#else +#define CALCULATE_LIBRARY_API __declspec(dllimport) +#endif +#else +#define CALCULATE_LIBRARY_API +#endif + +#include "tariff_permit_type.h" + +class Configuration; + +typedef Configuration parking_tariff_t; + +//#ifdef __cplusplus +//extern "C" { +//#endif + +struct CALCULATE_LIBRARY_API price_t { + uint32_t units; + double netto; + double brutto; + double vat_percentage; + double vat; + + explicit price_t() { + units = 0; + netto = brutto = vat_percentage = vat = 0.0; + } +}; + +struct CALCULATE_LIBRARY_API CalcState { + static QString const SUCCESS; + static QString const ERROR_PARSING_ZONE_NR; + static QString const ERROR_LOADING_TARIFF; + static QString const ERROR_PARSING_TARIFF; + static QString const NEGATIVE_PARKING_TIME; + static QString const INVALID_START_DATE; + static QString const WRONG_PARAM_VALUES; + static QString const WRONG_ISO_TIME_FORMAT; + static QString const ABOVE_MAX_PARKING_TIME; + static QString const BELOW_MIN_PARKING_TIME; + static QString const BELOW_MIN_PARKING_PRICE; + static QString const ABOVE_MAX_PARKING_PRICE; + static QString const OVERPAID; + static QString const OUTSIDE_ALLOWED_PARKING_TIME; + static QString const SUCCESS_MAXPRICE; + + enum class State : uint8_t { + SUCCESS, + ERROR_PARSING_ZONE_NR, + ERROR_LOADING_TARIFF, + ERROR_PARSING_TARIFF, + NEGATIVE_PARKING_TIME, + INVALID_START_DATE, + WRONG_PARAM_VALUES, + WRONG_ISO_TIME_FORMAT, + ABOVE_MAX_PARKING_TIME, + BELOW_MIN_PARKING_TIME, + BELOW_MIN_PARKING_PRICE, + ABOVE_MAX_PARKING_PRICE, + OVERPAID, + OUTSIDE_ALLOWED_PARKING_TIME, + SUCCESS_MAXPRICE + }; + + State m_status; + QString m_desc; + TariffTimeRange m_allowedTimeRange; + + explicit CalcState() + : m_status(State::SUCCESS) + , m_desc("") { + } + + explicit CalcState(State state, QString desc = "") + : m_status(state) + , m_desc(desc) { + } + + explicit CalcState(State state, QString desc = "", + QTime const &from = QTime(), + QTime const &until = QTime()) + : m_status(state) + , m_desc(desc) + , m_allowedTimeRange(from, until) { + } + + explicit operator bool() const noexcept { + return (m_status == State::SUCCESS); + } + + QString toString() { + QString s; + switch (m_status) { + case State::SUCCESS: + s = CalcState::SUCCESS; + break; + case State::SUCCESS_MAXPRICE: + s = CalcState::SUCCESS_MAXPRICE; + break; + case State::ERROR_PARSING_ZONE_NR: + s = CalcState::ERROR_PARSING_ZONE_NR; + break; + case State::ERROR_LOADING_TARIFF: + s = CalcState::ERROR_LOADING_TARIFF; + break; + case State::ERROR_PARSING_TARIFF: + s = CalcState::ERROR_PARSING_TARIFF; + break; + case State::NEGATIVE_PARKING_TIME: + s = CalcState::NEGATIVE_PARKING_TIME; + break; + case State::ABOVE_MAX_PARKING_TIME: + s = CalcState::ABOVE_MAX_PARKING_TIME; + break; + case State::WRONG_PARAM_VALUES: + s = CalcState::WRONG_PARAM_VALUES; + break; + case State::BELOW_MIN_PARKING_TIME: + s = CalcState::BELOW_MIN_PARKING_TIME; + break; + case State::BELOW_MIN_PARKING_PRICE: + s = CalcState::BELOW_MIN_PARKING_PRICE; + break; + case State::OVERPAID: + s = CalcState::OVERPAID; + break; + case State::INVALID_START_DATE: + s = CalcState::INVALID_START_DATE; + break; + case State::WRONG_ISO_TIME_FORMAT: + s = CalcState::WRONG_ISO_TIME_FORMAT; + break; + case State::OUTSIDE_ALLOWED_PARKING_TIME: + s = CalcState::OUTSIDE_ALLOWED_PARKING_TIME; + break; + case State::ABOVE_MAX_PARKING_PRICE: + s = CalcState::ABOVE_MAX_PARKING_TIME; + break; + } + if (m_desc.size() > 0) { + return s + ":" + m_desc; + } + return s; + } + + explicit operator QString () const noexcept { + QString s; + switch (m_status) { + case State::SUCCESS: + s = CalcState::SUCCESS; + break; + case State::SUCCESS_MAXPRICE: + s = CalcState::SUCCESS_MAXPRICE; + break; + case State::ERROR_PARSING_ZONE_NR: + s = CalcState::ERROR_PARSING_ZONE_NR; + break; + case State::ERROR_LOADING_TARIFF: + s = CalcState::ERROR_LOADING_TARIFF; + break; + case State::ERROR_PARSING_TARIFF: + s = CalcState::ERROR_PARSING_TARIFF; + break; + case State::NEGATIVE_PARKING_TIME: + s = CalcState::NEGATIVE_PARKING_TIME; + break; + case State::ABOVE_MAX_PARKING_TIME: + s = CalcState::ABOVE_MAX_PARKING_TIME; + break; + case State::WRONG_PARAM_VALUES: + s = CalcState::WRONG_PARAM_VALUES; + break; + case State::BELOW_MIN_PARKING_TIME: + s = CalcState::BELOW_MIN_PARKING_TIME; + break; + case State::BELOW_MIN_PARKING_PRICE: + s = CalcState::BELOW_MIN_PARKING_PRICE; + break; + case State::OVERPAID: + s = CalcState::OVERPAID; + break; + case State::INVALID_START_DATE: + s = CalcState::INVALID_START_DATE; + break; + case State::WRONG_ISO_TIME_FORMAT: + s = CalcState::WRONG_ISO_TIME_FORMAT; + break; + case State::OUTSIDE_ALLOWED_PARKING_TIME: + s = CalcState::OUTSIDE_ALLOWED_PARKING_TIME; + break; + case State::ABOVE_MAX_PARKING_PRICE: + s = CalcState::ABOVE_MAX_PARKING_TIME; + break; + } + return s + ":" + m_desc; + } + + CalcState &set(State s) { m_status = s; return *this; } + CalcState &setStatus(State s) { return set(s); } + CalcState &setStatus(QString const &desc) { + if (desc == SUCCESS) { + m_status = State::SUCCESS; + } else + if (desc == SUCCESS_MAXPRICE) { + m_status = State::SUCCESS_MAXPRICE; + } + if (desc == ERROR_PARSING_ZONE_NR) { + m_status = State::ERROR_PARSING_ZONE_NR; + } else + if (desc == ERROR_LOADING_TARIFF) { + m_status = State::SUCCESS; + } else + if (desc == ERROR_PARSING_TARIFF) { + m_status = State::ERROR_LOADING_TARIFF; + } else + if (desc == NEGATIVE_PARKING_TIME) { + m_status = State::NEGATIVE_PARKING_TIME; + } else + if (desc == INVALID_START_DATE) { + m_status = State::INVALID_START_DATE; + } else + if (desc == WRONG_PARAM_VALUES) { + m_status = State::WRONG_PARAM_VALUES; + } else + if (desc == WRONG_ISO_TIME_FORMAT) { + m_status = State::WRONG_ISO_TIME_FORMAT; + } else + if (desc == ABOVE_MAX_PARKING_TIME) { + m_status = State::ABOVE_MAX_PARKING_TIME; + } else + if (desc == BELOW_MIN_PARKING_TIME) { + m_status = State::BELOW_MIN_PARKING_TIME; + } else + if (desc == BELOW_MIN_PARKING_PRICE) { + m_status = State::BELOW_MIN_PARKING_PRICE; + } else + if (desc == OVERPAID) { + m_status = State::OVERPAID; + } else + if (desc == OUTSIDE_ALLOWED_PARKING_TIME) { + m_status = State::OUTSIDE_ALLOWED_PARKING_TIME; + } else + if (desc == ABOVE_MAX_PARKING_PRICE) { + m_status = State::ABOVE_MAX_PARKING_PRICE; + } + + return *this; + } + State getStatus() const { return m_status; } + CalcState &setDesc(QString const &s) { m_desc = s; return *this; } + + void setAllowedTimeRange(QTime const &from, QTime const &until) { + m_allowedTimeRange.setTimeRange(from, until); + } + + TariffTimeRange getAllowedTimeRange() { + return m_allowedTimeRange; + } +}; + +CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, + char const *config_file); +void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff); +int CALCULATE_LIBRARY_API get_zone_nr(int zone = -1); + +int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes, + int UpDown, PermitType const &permitType); + +QList CALCULATE_LIBRARY_API get_time_steps(Configuration *cfg); + +int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration const *cfg, + PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING, + int paymentOptionIndex=0); + +int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration const *cfg, + PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING, + int paymentOptionIndex=0); + +int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg, + PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING, + int paymentOptionIndex = 0, + QDateTime const &start = QDateTime::currentDateTime()); + +int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg, + PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING, + int paymentOptionIndex=0); + +int CALCULATE_LIBRARY_API compute_product_price(Configuration const *cfg, + PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING, + QDateTime const &start = QDateTime::currentDateTime(), + QDateTime *productStart = nullptr, + QDateTime *productEnd = nullptr); + +CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // deprecated + parking_tariff_t *tariff, + time_t start_parking_time, + time_t end_parking_time, + struct price_t *price, + PermitType permitType); + +CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( + parking_tariff_t *tariff, + QDateTime &start_parking_time, + int netto_parking_time, + QDateTime &end_parking_time, // return value + struct price_t *price, // return value + PermitType permitType, + bool prepaid = true); + +CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( // deprecated + parking_tariff_t *tariff, + time_t start_parking_time, + double cost, + QString &duration, + PermitType permitType); + +CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( + parking_tariff_t *tariff, + QDateTime const &start_parking_time, + double cost, + QDateTime &ticketEndTime, + PermitType permitType); // return value + +CalcState CALCULATE_LIBRARY_API compute_duration_for_daily_ticket( + parking_tariff_t *tariff, + QDateTime const &start_parking_time, + QDateTime &ticketEndTime, + PermitType permitType); + +CalcState CALCULATE_LIBRARY_API compute_price_for_daily_ticket( + parking_tariff_t *tariff, + QDateTime const &start_parking_time, + QDateTime &ticketEndTime, + PERMIT_TYPE permitType, + struct price_t *price); +//#ifdef __cplusplus +//} // extern "C" +//#endif + +#endif // CALCULATE_PRICE_H diff --git a/library/include/calculator_functions.h b/library/include/calculator_functions.h new file mode 100644 index 0000000..7aeb2b8 --- /dev/null +++ b/library/include/calculator_functions.h @@ -0,0 +1,155 @@ +#ifndef CALCULATOR_FUNCTIONS_H_INCLUDED +#define CALCULATOR_FUNCTIONS_H_INCLUDED + +#include +#include +#include + +#include "configuration.h" +#include "calculate_price.h" +#include "payment_method.h" +#include "ticket.h" +#include "tariff_time_range.h" + +#include +using namespace std; + +class Calculator { + mutable QVector> m_timeSteps; + mutable QList m_priceSteps; + + CalcState isParkingAllowedForWeekDay(Configuration const *cfg, + QDateTime const &start, + int netto_parking_time, + int paymentOptionIndex); + + CalcState isParkingAllowedForSpecialDay(Configuration const *cfg, + QDateTime const &start, + int netto_parking_time, + int paymentOptionIndex); + +protected: + explicit Calculator() = default; + +public: + Calculator(Calculator const &other) = delete; + void operator=(Calculator const &) = delete; + + static Calculator &GetInstance() { + static Calculator c; + return c; + } + + void ResetTimeSteps(int paymentOptionIndex) { + if (m_timeSteps.size() > 0 && paymentOptionIndex < m_timeSteps.size()) { + m_timeSteps[paymentOptionIndex].clear(); + } + } + QList timeSteps(int paymentOptionIndex=0) const { + if (m_timeSteps.size() > 0 && paymentOptionIndex < m_timeSteps.size()) { + return m_timeSteps[paymentOptionIndex]; + } + return QList(); + } + + void ResetPriceSteps() { m_priceSteps.clear(); } + QList priceSteps() const { return m_priceSteps; } + + CalcState isParkingAllowed(Configuration const *cfg, + QDateTime const &start); + + CalcState isParkingAllowed(Configuration const *cfg, + QDateTime const &start, + int netto_parking_time, + int paymentOptionIndex); + + /// + /// Gets duration in seconds from cost + /// + /// Pointer to configuration + /// Type of vehicle + /// Date/time of payment to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z) + /// + /// Returns duration in seconds (data type: double) + std::pair + GetDurationFromCost(Configuration* cfg, uint8_t vehicle_type, char const* start_datetime, double price, + PermitType permitType, bool nextDay = false, bool prepaid = false); + + /// + /// Gets cost from duration in seconds + /// + /// Pointer to configuration + /// Type of vehicle + /// Date/time of payment to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z) + /// Date/time of park end to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z) + /// Duration of parking in minutes + /// Returns cost (data type: double) + double GetCostFromDuration(Configuration* cfg, uint8_t vehicle_type, QDateTime &start_datetime, QDateTime & end_datetime, int durationMin, + PermitType permitType, bool nextDay = false, bool prepaid = false); + + // Daily ticket + QDateTime GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over); + std::optional GetDailyTicketPrice(Configuration* cfg, QDateTime const &startDatetime, QDateTime &endTime, PERMIT_TYPE permitType); + + // + // helper function to find time steps for a tariff with PaymentMethod::Steps + // (e.g. Schoenau/Koenigsee) + // + QList &GetTimeSteps(Configuration *cfg, int paymentOptionIndex=0, QDateTime const &start = QDateTime::currentDateTime()) const; + QList GetSteps(Configuration *cfg, int paymentOptionIndex=0, QDateTime const &start = QDateTime::currentDateTime()) const { + return GetTimeSteps(cfg, paymentOptionIndex, start); + } + + QList GetPriceSteps(Configuration *cfg) const; + + // additional helper functions + bool noSpecialDays(Configuration const *cfg) const { + return (cfg->SpecialDays.size() == 0) && (cfg->SpecialDaysWorktime.size() == 0); + } + bool specialDays(Configuration const *cfg) const { + return !noSpecialDays(cfg); + } + bool tariffIs24_7(Configuration const *cfg) const { + return (cfg->YearPeriod.size() == 0 && + cfg->SpecialDays.size() == 0 && + cfg->SpecialDaysWorktime.size() == 0); + } + +// testing public: + // Introduced for PaymentMethod::Steps (e.g. Schoenau) + // For tariff of following structure: only steps, no special days, nonstop. + uint32_t GetCostFromDuration(Configuration *cfg, QDateTime const &start, quint64 durationMinutes, int paymentOptionIndex=0) const; + uint32_t GetCostFromDuration(Configuration *cfg, QDateTime const &start, QDateTime const &end, int paymentOptionIndex=0) const; + +private: + Ticket private_GetCostFromDuration(Configuration const* cfg, + QDateTime const &start, + int durationMinutes, + bool prepaid = false); + Ticket private_GetDurationFromCost(Configuration *cfg, + QDateTime const &start, + uint32_t price, + bool prepaid = false); + + bool checkDurationMinutes(int minParkingTime, int maxParkingTime, + int durationMinutes); + + // + uint32_t GetPriceForTimeStep(Configuration *cfg, int timeStep, int paymentOptionIndex) const; + //uint32_t GetPriceForStep(Configuration *cfg, int step) const { + // return GetPriceForTimeStep(cfg, step, 0); + //} + uint32_t GetDurationForPrice(Configuration *cfg, int price) const; + uint32_t GetStepForPrice(Configuration *cfg, int price) const { + return GetDurationForPrice(cfg, price); + } + + int findWorkTimeRange(QDateTime const &dt, + QScopedArrayPointer const &worktime, + size_t size); + int findNextWorkTimeRange(QDateTime const &dt, + QScopedArrayPointer const &worktime, + size_t size); +}; + +#endif // CALCULATOR_FUNCTIONS_H_INCLUDED