Compare commits

...

88 Commits

Author SHA1 Message Date
ed6d355517 last fixes before presentation 2025-06-03 11:52:42 +02:00
f1f033d1cd restrict tariff 3 to stop before 23:00 2025-06-02 15:31:25 +02:00
f547f563bf added out-of-service handling 2025-05-30 13:11:00 +02:00
141d3281b7 just save for muenchen presentation 2025-05-28 15:17:11 +02:00
f2156e4650 Merge branch 'include-tariff-files' 2025-05-09 09:25:49 +02:00
338a1a4ebc Merge branch 'vorkauf-fix-2025-April-22' into include-tariff-files 2025-05-09 09:25:19 +02:00
b4818a3918 get_minimal_parkingtime()
get_maximal_parkingtime()
compute_product_price()
get_maximal_parkingprice()
compute_price_for_parking_ticket()
compute_duration_for_parking_ticket()
compute_duration_for_daily_ticket()
compute_price_for_daily_ticket():

In case main-tariff file contains an Includes-section, change to the
included tariff based on product-id (permit-type).
2025-05-08 11:15:23 +02:00
35294e99f0 Parse possible Includes-section in tariff-file 2025-05-06 12:00:22 +02:00
edfa5dc1b1 Minor: add case FREE_TICKET to prevent compiler warning. 2025-05-06 11:59:10 +02:00
d95741baae compute_duration_for_parking_ticket():
Switch to different tariff based on product-type/product-id.
2025-05-06 11:57:36 +02:00
e172e814e7 load and parse additional (included) tariff-files 2025-05-06 11:57:14 +02:00
37aa10fc85 Add product FREE_TICKET. 2025-05-06 11:55:35 +02:00
4b9edb0f47 Minor: add IncludeType to be used by json-parser 2025-05-06 11:54:49 +02:00
e70e9a8586 Add TariffIncludes: the main tariff-file will include (load) other tariff-files. 2025-05-06 11:52:47 +02:00
aec290fe26 test code 2025-05-06 11:52:16 +02:00
78cae24389 Fix: if start-time is out-of-range (after valid time for sell), switch
to next valid time, taking into account if next valid time is on next day.
2025-04-23 11:00:33 +02:00
de0be1d19b Minor: added/changed debug messages. 2025-04-23 10:59:39 +02:00
54921f0e85 If price (=key) is not found, compute the next smaller valid price (=key)
and use this as maxPrice.
Usage: (Innichen (508) with) direct coin input.
2025-04-17 13:33:22 +02:00
077c2334ca Restore pop_max_price in case it has been changed (for certain settings). 2025-04-17 13:09:53 +02:00
d605af5c5a Check prepaidIf and carryOverIf for null and emptyness. 2025-04-16 11:32:20 +02:00
c5900f9f2b Minor: extend debug output 2025-04-16 11:31:05 +02:00
9b137c2873 Fix in Calculator::GetPriceForTimeStep():
Allow some tolerance (of 3 minutes) when looking up the
	current time-step value in the duration-array.
	Otherwise, when corossing a minute-boundary, it can happen to
	not find the match and returning a price of 0 (which is almost
	always wrong).
2025-04-03 11:53:47 +02:00
dd249a87d5 Set cnt-limit to 20. This allows a bigger time-range for tariff, which
have in principle no time-limit.
2025-04-02 15:28:46 +02:00
575885c19e Merge branch 'master' into kleipeda-experimental 2025-04-02 09:44:20 +02:00
d82a732a8d if end of parking time equals carry-over-end, then, if configured, go back to carry-over-start. 2025-04-01 14:26:21 +02:00
99dbd7c194 Minor: debug output. 2025-04-01 14:24:42 +02:00
ae985d25ce Merge branch 'kleipeda-experimental' 2025-02-04 14:58:58 +01:00
6a215d4cf9 Allow zone_nr > 999 2025-02-04 14:47:07 +01:00
a3f4a742ce Read zone_nr from system_data 2025-02-04 14:44:28 +01:00
e6d8c04076 Fix: for time change summer -> winter term. Compute minutes until midnight manually. 2024-10-30 15:56:58 +01:00
1f6606f382 Add some tests for Forchach (749) 2024-10-10 11:40:29 +02:00
4b9a4319b3 ComputeDurationFromCost():
Fix: take into account that there may be more than just two
	carry-over-ranges. For instance, in Korneuburg (714), there are three
	as they have a break from 12:00-14:00.
2024-10-10 11:38:14 +02:00
5e673788b4 ComputeDurationFromCost():
Use helper function computeMinutesUntilCarryOverEnd() to compute
	the offset until the end of the carry-over-range.
2024-10-10 11:36:14 +02:00
7e2f40a7b5 Add assigment-operator (otherwise compilation error). 2024-10-10 11:33:33 +02:00
44e2ce24a3 Add helper computeMinutesUntilCarryOverEnd().
Used in new tariff-calculator. Replace of previous wrong approach of
        using m_range.duration.
2024-10-10 11:30:53 +02:00
5a55ad6ef0 ComputeDurationFromCost():
brutto-time must be updated in case of an carry-over-section.
2024-10-02 15:21:21 +02:00
5a77958e8d getOutOfService():
Check for special days (holidays) with out-of-service-time-ranges.
	Holidays have higher priority than usual days ("default").
2024-10-02 15:19:32 +02:00
a1e7f4629a getService():
Check for special days (holidays) with service-time-ranges.
	Holidays have higher priority than usual days ("default").
2024-10-02 15:18:16 +02:00
efc2582c36 getCarryOver():
Check for special days (holidays) with carry-over-sections.
	Holidays have higher priority than usual days.
2024-10-02 15:17:00 +02:00
a72f5a5019 getPrepaid():
Check for special days (holidays) with prepaid sections.
	Holidays have higher priority than usual days.
2024-10-02 15:15:19 +02:00
28f0ea9fce Merge from kleipeda-experimental-snapshot-2024-09-27:
started new implementation of tariff-calculator.
2024-10-01 09:25:53 +02:00
3109e82ef8 If out-of-service, use start of out-of-service action as output-date. 2024-10-01 09:23:15 +02:00
03dd6c44da Always reset pop_max_price to configured value. 2024-09-30 16:58:23 +02:00
212c792b77 compute_price_for_parking_ticket():
Include opverpaid option in price-computation.
2024-09-30 16:57:18 +02:00
ab3cdb32ae compute_next_timestep():
Restrict time-step-list when time-limit has been reached: +/-_button
	does not move upward anymore.
2024-09-30 16:55:25 +02:00
4f23ab3d68 ComputeCostFromDuration():
Add price when overpaid occurred.
2024-09-30 16:53:25 +02:00
acbc27cfb2 ComputeDurationFromCost():
If overapid or trunctae has been set, then truncated max. parking time
	to time-limit configured in tariff-file.
2024-09-30 16:51:51 +02:00
bcbe95d483 Add hard-coded trauncate flag. 2024-09-30 16:51:02 +02:00
e3bbca86d5 Minor: changed parameter type to non-const. 2024-09-30 16:50:21 +02:00
5868d3b510 Introduce computational state 2024-09-30 16:46:36 +02:00
d4363e71cd Keep bacjward compatibility before using payment-method Unified. 2024-09-27 14:24:10 +02:00
fd99c20bd9 Take into account new payment method 'Unified' to call new tariff-calculator. 2024-09-27 14:20:20 +02:00
dbccdba9fe isParkingAllowedForWeekDay():
Minor: adapt function call to changes parameter arity.
2024-09-27 14:18:31 +02:00
b035f4f887 Calculator::GetDurationFromCost():
Minor: move scope of some variables upward.
2024-09-27 14:17:35 +02:00
18f09fccb9 GetDurationFromCost():
Call ComputeDurationFromCost() of new tariff calculator for payment-method Unified.
2024-09-27 14:10:02 +02:00
1086e360e5 Start of implementing new tariff calculator:
Added serveral helper function for parsing tariff file:
	  * getPrepaid()
	  * getCarryOver()
          * getService()
          * getOutOfService()

	Added main functions of tariff calculator:

	  * ComputeDurationFromCost()
	  * ComputeCostFromDuration()
2024-09-27 14:04:39 +02:00
ada7bebd90 Minor: Add headers. 2024-09-27 13:57:30 +02:00
2b9ea67ef5 Added function to implement new tariff-calculator:
std::pair<CalcState, QDateTime> ComputeDurationFromCost(Configuration const* cfg, QDateTime const &startDatetimePassed,  int cost);
std::pair<CalcState, std::optional<int>> ComputeCostFromDuration(Configuration const* cfg, QDateTime const &startDatetime, QDateTime &endDatetime, int nettoParkingTime);
2024-09-27 13:48:30 +02:00
d117328bed Minor: removed default parameter in constructor 2024-09-27 13:47:26 +02:00
fd04531474 Added payment <unified> payment-methode 2024-09-27 13:45:45 +02:00
5749fa422e Added structures for parsing of tariff05 in bad neuenahr 2024-09-27 13:45:04 +02:00
1347f1f208 Added parsing for tariff05.json (bad neuenarh (249)) 2024-09-27 13:44:01 +02:00
576c3fefdd Added PaymentMethod::Unified 2024-09-27 13:42:44 +02:00
9ca7018fc1 tests for bad neuenahr 2024-09-27 13:42:04 +02:00
515dfaf35c reprogrammed to use ATBTime class 2024-09-27 13:41:30 +02:00
0ab833709c Added struct ATBTariffCarryOver 2024-09-27 13:40:18 +02:00
8e4f47c7b6 Added struct ATBTariffPrepaid 2024-09-27 13:39:35 +02:00
bc9645f1fa Minor: removed "pragma once" compiler flag 2024-09-27 13:38:39 +02:00
713b483918 Added/fixed several functions. final testing needed. 2024-09-27 13:37:54 +02:00
3c7af1cb32 Minor: Added tariff_service and tariff_out_of_service 2024-09-27 13:35:54 +02:00
356e451839 Add structures to encode service and out-of-service times 2024-09-27 13:35:03 +02:00
c4e1d412a5 Add some assinment operators to support assignment of tariff-time-ranges. 2024-09-27 13:31:01 +02:00
1b716c48d2 Fix: copy header files 2024-09-19 14:10:05 +02:00
77e1414c13 compute_duration_for_parking_ticket():
Recompute pop_max_price using netto-parking-time.
	Search Duration for the time-step with time-step == netto-parking-time,
	then search for the corresponding price in PaymentRate.
	The result is the new pop_max_price.
2024-09-17 17:05:23 +02:00
d95275a72d Compute real netto_parking_time.
This time will be used to find the real time-step, and from here the actual price to pay.
2024-09-17 17:04:27 +02:00
577a17dc6a Set seconds of serveral date-times to 0.
Compute netto_parking_time (which includes carry-over duration).
2024-09-17 17:03:29 +02:00
d8d32820a3 compute_price_for_parking_ticket():
Reset pop_max_price to original value using pop_max_price_saved.
2024-09-17 17:01:32 +02:00
2ce0aeef1d Minor: include atb_time.h 2024-09-17 16:59:07 +02:00
0cba85eafb Set pop_max_price_saved 2024-09-17 16:58:20 +02:00
4030a4b165 Add pop_max_price_save in case pop_max_price has to be re-computed dynamically, so it can be reset 2024-09-17 16:57:34 +02:00
8c7afdfcb1 Add additional constructor. 2024-09-17 16:53:45 +02:00
932d4e8cb9 check it ticket-end-time hits carry-over-start. if configured, move to end of carry-over. 2024-09-16 16:56:48 +02:00
38abc65425 compute_price_for_parking_ticket():
Check if minutesUntilCarryOver is positive (usually must be).
2024-09-16 16:54:25 +02:00
205896903b Handle SUCCESS_MAXPRICE (calc-state). 2024-09-16 16:53:44 +02:00
dbedfd094f Add some OTHER files 2024-09-16 16:52:00 +02:00
57b9d16abc GetDurationFromCost():
Handle carry-over for direct coin insertion.
	Carefully check if this might be a problem for other projects.
2024-09-16 16:50:16 +02:00
48afbc071c Added new calc-state: SUCCESS_MAXPRICE.
Return whenever cost (=price) equals max-price.
2024-09-16 16:49:00 +02:00
7a7b10260a Add untracked(!) files 2024-09-16 16:47:01 +02:00
28 changed files with 8851 additions and 167 deletions

1
\ Normal file
View File

@@ -0,0 +1 @@
return std::make_pair(CalcState(CalcState::State::OVERPAID), dt);

View File

@@ -4,19 +4,42 @@
#include <QDateTime>
class ATBTime {
QDateTime const m_end;
static QDateTime const m_end;
mutable QDateTime m_time;
public:
explicit ATBTime();
explicit ATBTime(int h, int m, int s = 0, int ms = 0);
explicit ATBTime(QString const &time);
explicit ATBTime(QTime const &time);
explicit ATBTime(ATBTime const &atbTime) {
m_time = atbTime.m_time;
}
ATBTime &operator=(ATBTime && atbTime) {
m_time = std::move(atbTime.m_time);
return *this;
}
ATBTime &operator=(ATBTime const &atbTime) {
m_time = atbTime.m_time;
return *this;
}
int hour() const { return m_time.time().hour(); }
int minute() const { return m_time.time().minute(); }
int second() const { return m_time.time().second(); }
int msec() const { return m_time.time().msec(); }
int secsTo(QTime t) const { return m_time.time().secsTo(t); }
int secsTo(QString const &t) const {
if (t == "24:00:00") {
return m_time.secsTo(m_end);
}
return m_time.time().secsTo(QTime::fromString(t, Qt::ISODate));
}
int msecsTo(QTime t) const { return m_time.time().msecsTo(t); }
bool setHMS(int h, int m, int s, int ms = 0);
@@ -47,10 +70,12 @@ public:
friend bool operator!=(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator<(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator<=(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator>=(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator<(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator>(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend bool operator==(const ATBTime &lhs, const ATBTime &rhs) noexcept;
friend QDataStream &operator<<(QDataStream &out, ATBTime time);
friend QDataStream &operator<<(QDataStream &out, ATBTime const &time);
friend QDebug &operator<<(QDebug &out, ATBTime const &time);
friend QDataStream &operator>>(QDataStream &in, ATBTime &time);
};

View File

@@ -56,6 +56,7 @@ struct CALCULATE_LIBRARY_API CalcState {
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,
@@ -71,7 +72,8 @@ struct CALCULATE_LIBRARY_API CalcState {
BELOW_MIN_PARKING_PRICE,
ABOVE_MAX_PARKING_PRICE,
OVERPAID,
OUTSIDE_ALLOWED_PARKING_TIME
OUTSIDE_ALLOWED_PARKING_TIME,
SUCCESS_MAXPRICE
};
State m_status;
@@ -88,9 +90,9 @@ struct CALCULATE_LIBRARY_API CalcState {
, m_desc(desc) {
}
explicit CalcState(State state, QString desc = "",
QTime const &from = QTime(),
QTime const &until = QTime())
explicit CalcState(State state, QString desc,
QTime const &from,
QTime const &until)
: m_status(state)
, m_desc(desc)
, m_allowedTimeRange(from, until) {
@@ -106,6 +108,9 @@ struct CALCULATE_LIBRARY_API CalcState {
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;
@@ -158,6 +163,9 @@ struct CALCULATE_LIBRARY_API CalcState {
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;
@@ -207,6 +215,9 @@ struct CALCULATE_LIBRARY_API CalcState {
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
@@ -266,6 +277,12 @@ CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff,
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff);
int CALCULATE_LIBRARY_API get_zone_nr(int zone = -1);
int CALCULATE_LIBRARY_API isOutOfService(Configuration const *cfg,
QDateTime const &dt);
int CALCULATE_LIBRARY_API isOutOfService(QDateTime const &dt);
int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes,
int UpDown, PermitType const &permitType);

View File

@@ -27,9 +27,16 @@ class Calculator {
QDateTime const &start,
int netto_parking_time,
int paymentOptionIndex);
struct State {
bool m_timeLimitReached;
uint32_t m_costAtTimeLimit;
} m_state;
protected:
explicit Calculator() = default;
explicit Calculator() {
m_state.m_timeLimitReached = false;
m_state.m_costAtTimeLimit = ~0;
}
public:
Calculator(Calculator const &other) = delete;
@@ -40,6 +47,12 @@ public:
return c;
}
bool timeLimitReached() const { return m_state.m_timeLimitReached; }
void setTimeLimitReached(bool timeLimitReached) { m_state.m_timeLimitReached = timeLimitReached; }
bool costAtTimeLimit() const { return m_state.m_costAtTimeLimit; }
void setCostAtTimeLimit(uint32_t cost) { if (m_state.m_costAtTimeLimit > cost) m_state.m_costAtTimeLimit = cost; }
void resetCostAtTimeLimit() { m_state.m_costAtTimeLimit = ~0; }
void ResetTimeSteps(int paymentOptionIndex) {
if (m_timeSteps.size() > 0 && paymentOptionIndex < m_timeSteps.size()) {
m_timeSteps[paymentOptionIndex].clear();
@@ -73,7 +86,7 @@ public:
/// <returns>Returns duration in seconds (data type: double)</returns>
std::pair<std::string, QDateTime>
GetDurationFromCost(Configuration* cfg, uint8_t vehicle_type, char const* start_datetime, double price,
PermitType permitType, bool nextDay = false, bool prepaid = false);
PermitType permitType, bool nextDay = false, bool prepaid = false);
/// <summary>
/// Gets cost from duration in seconds
@@ -87,6 +100,9 @@ public:
double GetCostFromDuration(Configuration* cfg, uint8_t vehicle_type, QDateTime &start_datetime, QDateTime & end_datetime, int durationMin,
PermitType permitType, bool nextDay = false, bool prepaid = false);
std::pair<CalcState, QDateTime> ComputeDurationFromCost(Configuration *cfg, QDateTime const &startDatetimePassed, int cost);
std::pair<CalcState, std::optional<int>> ComputeCostFromDuration(Configuration *cfg, QDateTime const &startDatetime, QDateTime &endDatetime, int nettoParkingTime);
// Daily ticket
QDateTime GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over);
std::optional<struct price_t> GetDailyTicketPrice(Configuration* cfg, QDateTime const &startDatetime, QDateTime &endTime, PERMIT_TYPE permitType);

View File

@@ -29,9 +29,13 @@
#include "tariff_prepaid.h"
#include "tariff_carryover.h"
#include "tariff_permit_type.h"
#include "tariff_service.h"
#include "tariff_out_of_service.h"
#include <QVector>
#include <optional>
#include <QList>
#include <QPair>
using namespace std;
using namespace rapidjson;
@@ -50,6 +54,10 @@ public:
using TariffPrepaidType = std::multimap<int, ATBPrepaid>;
using TariffCarryOverType = std::multimap<int, ATBCarryOver>;
using TariffDurationType = std::multimap<int, ATBDuration>;
using TariffServiceType = std::multimap<int, ATBTariffService>;
using TariffOutOfServiceType = std::multimap<int, ATBTariffOutOfService>;
using ATBTariffPrepaidType = std::multimap<int, ATBTariffPrepaid>;
using ATBTariffCarryOverType = std::multimap<int, ATBTariffCarryOver>;
ATBProject project;
ATBCurrency Currency;
@@ -73,6 +81,15 @@ public:
TariffInterpolationType TariffInterpolations;
TariffPrepaidType TariffPrepaidOptions;
TariffCarryOverType TariffCarryOverOptions;
TariffServiceType TariffServices;
TariffOutOfServiceType TariffOutOfServices;
ATBTariffPrepaidType TariffPrepaids;
ATBTariffCarryOverType TariffCarryOvers;
QList<QPair<QString, QString>> TariffIncludes;
QTime ValidFrom;
int ValidForWeekDay{};
QStringList tariffFileName{};
/// <summary>
/// Parse JSON string
@@ -113,6 +130,9 @@ public:
std::optional<ATBWeekDaysWorktime> getWeekDayWorkTime(QTime const &time, Qt::DayOfWeek dayOfWeek);
std::optional<QVector<ATBWeekDaysWorktime>> getAllWeekDayWorkTimes();
QList<QPair<QString, QString>> const &getTariffIncludes() const { return TariffIncludes; }
QList<QPair<QString, QString>> &getTariffIncludes() { return TariffIncludes; }
std::optional<QDateTime> prepaidStart(QDateTime const &start, int prepaid_option_id);
int getPaymentOptionIndex(PERMIT_TYPE permitType);
int getPaymentOptionIndex(PERMIT_TYPE permitType) const;

View File

@@ -22,7 +22,8 @@ enum MemberType
ProductType = 0x0F,
InterpolationType = 0x10,
PrepaidType = 0x11,
CarryOverType = 0x12
CarryOverType = 0x12,
IncludesType = 0x13
};
#endif // MEMBER_TYPE_H_INCLUDED

View File

@@ -6,7 +6,8 @@ enum PaymentMethod {
Progressive = 0x01,
Degressive = 0x02,
Linear = 0x03,
Steps = 0x04
Steps = 0x04,
Unified = 0x05
};
#endif // PAYMENT_METHOD_H_INCLUDED

View File

@@ -25,6 +25,7 @@ public:
pop_max_time = 0;
pop_min_price = 0;
pop_max_price = 0;
pop_max_price_save = 0;
pop_carry_over = -1;
pop_carry_over_option_id = -1;
pop_prepaid_option_id = -1;
@@ -61,6 +62,7 @@ public:
double pop_max_time;
double pop_min_price;
double pop_max_price;
double pop_max_price_save;
int pop_carry_over;
int pop_carry_over_option_id;
bool pop_truncate_last_interpolation_step;

View File

@@ -3,6 +3,111 @@
#include <QTime>
#include "time_range.h"
enum class ApplyCarryOver {
NEVER = 0,
MATCH_PREV_DAY = 1,
MATCH_NEXT_DAY = 2,
ALWAYS = 3
};
struct ATBTariffCarryOver {
int m_id;
QString m_weekDay;
TimeRange m_range;
QDate m_date;
ApplyCarryOver m_carryOverIf;
explicit ATBTariffCarryOver()
: m_id(-1)
, m_carryOverIf(ApplyCarryOver::NEVER) {
}
void setCarryOverIf(QString const &coif) {
if (coif == "never") {
m_carryOverIf = ApplyCarryOver::NEVER;
} else
if (coif == "match_prev_day") {
m_carryOverIf = ApplyCarryOver::MATCH_PREV_DAY;
} else
if (coif == "match_next_day") {
m_carryOverIf = ApplyCarryOver::MATCH_NEXT_DAY;
} else
if (coif == "always") {
m_carryOverIf = ApplyCarryOver::ALWAYS;
} else {
qCritical() << __func__ << ":" << __LINE__ << "ERROR unknown carry over application" << coif;
}
}
ApplyCarryOver carryOverIf() const {
return m_carryOverIf;
}
QString carryOverIfStr() const {
if (m_carryOverIf == ApplyCarryOver::NEVER) {
return "never";
}
if (m_carryOverIf == ApplyCarryOver::ALWAYS) {
return "always";
}
if (m_carryOverIf == ApplyCarryOver::MATCH_PREV_DAY) {
return "match prev day";
}
if (m_carryOverIf == ApplyCarryOver::MATCH_NEXT_DAY) {
return "match next day";
}
return QString("ERROR unknown carry over application: %1").arg(static_cast<int>(m_carryOverIf));
}
int computeMinutesUntilCarryOverEnd(QDateTime const &dt) {
int minutes = 0;
QString end = m_range.m_end.toString(Qt::ISODate);
if (end == "24:00:00") {
// note: this did not work
// QDateTime t(dt.addDays(1));
// t.setTime(QTime(0,0,0));
// dt: 2024-10-27T00:00:00 EEST, but t: 2024-10-28T00:00:00 EET (!)
// so the difference is 1500 instead of 1440
// reason: change from summer to winter time
// compute minutes directly
if (dt.time().isValid()) {
minutes = 1440 - (dt.time().hour() * 60 + dt.time().minute());
}
} else {
QTime t(QTime::fromString(end, Qt::ISODate));
if (t.isValid() && dt.time().isValid()) {
minutes = (t.hour() * 60 + t.minute()) - (dt.time().hour() * 60 + dt.time().minute());
}
}
if (minutes < 0 || minutes > m_range.m_duration) {
minutes = 0;
}
// qCritical() << __func__ << ":" << __LINE__ << "minutes" << minutes;
return minutes;
}
friend QDebug operator<<(QDebug debug, ATBTariffCarryOver const &co) {
QDebugStateSaver saver(debug);
debug.nospace()
<< "\nTariffCarryOver:\n"
<< " week day: " << co.m_weekDay << "\n"
<< " date: " << co.m_date.toString(Qt::ISODate) << "\n"
<< " id: " << co.m_id << "\n"
<< " start: " << co.m_range.m_start << "\n"
<< " end: " << co.m_range.m_end << "\n"
<< " duration: " << co.m_range.m_duration << "\n"
<< " carry over if: " << co.carryOverIfStr() << endl;
return debug;
}
};
struct ATBCarryOver {
struct week {
int day;

View File

@@ -1,4 +1,3 @@
#pragma once
#include <variant>
#include <cstddef>
#include <stdio.h>

View File

@@ -0,0 +1,79 @@
#ifndef TARIFF_OUT_OF_SERVICE_H_INCLUDED
#define TARIFF_OUT_OF_SERVICE_H_INCLUDED
#include <QDateTime>
#include <QString>
#include "time_range.h"
enum class ApplyOutOfService {
NEVER = 0,
MATCH_PREV_DAY = 1,
MATCH_NEXT_DAY = 2,
ALWAYS = 3
};
struct ATBTariffOutOfService {
int m_id;
QString m_weekDay;
QDate m_date;
TimeRange m_range;
ApplyOutOfService m_outOfServiceIf;
explicit ATBTariffOutOfService()
: m_id(-1)
, m_outOfServiceIf(ApplyOutOfService::NEVER) {
}
void setOutOfServiceIf(QString const &oosif) {
if (oosif == "never") {
m_outOfServiceIf = ApplyOutOfService::NEVER;
} else
if (oosif == "match_prev_day") {
m_outOfServiceIf = ApplyOutOfService::MATCH_PREV_DAY;
} else
if (oosif == "match_next_day") {
m_outOfServiceIf = ApplyOutOfService::MATCH_NEXT_DAY;
} else
if (oosif == "always") {
m_outOfServiceIf = ApplyOutOfService::ALWAYS;
} else {
qCritical() << "ERROR unknown servcie application" << oosif;
}
}
ApplyOutOfService outOfServiceIf() const {
return m_outOfServiceIf;
}
QString outOfServiceIfStr() const {
if (m_outOfServiceIf == ApplyOutOfService::NEVER) {
return "never";
}
if (m_outOfServiceIf == ApplyOutOfService::ALWAYS) {
return "always";
}
if (m_outOfServiceIf == ApplyOutOfService::MATCH_PREV_DAY) {
return "match prev day";
}
if (m_outOfServiceIf == ApplyOutOfService::MATCH_NEXT_DAY) {
return "match next day";
}
return QString("ERROR unknown out of service application: %1").arg(static_cast<int>(m_outOfServiceIf));
}
friend QDebug operator<<(QDebug debug, ATBTariffOutOfService const &oos) {
QDebugStateSaver saver(debug);
debug.nospace()
<< "\nTariffOutOfService:\n"
<< " week day: " << oos.m_weekDay << "\n"
<< " date: " << oos.m_date.toString(Qt::ISODate) << "\n"
<< " id: " << oos.m_id << "\n"
<< " start: " << oos.m_range.m_start << "\n"
<< " end: " << oos.m_range.m_end << "\n"
<< " duration: " << oos.m_range.m_duration << endl;
return debug;
}
};
#endif // TARIFF_SERVICE_H_INCLUDED

View File

@@ -19,7 +19,12 @@ enum class PERMIT_TYPE : quint8 {
SHORT_TERM_PARKING_CAMPER=12,
DAY_TICKET_PKW=13,
DAY_TICKET_BUS=14,
DAY_TICKET_CAMPER=15
DAY_TICKET_CAMPER=15,
FREE_TICKET=16,
TEST_PRODUCT_1=17,
TEST_PRODUCT_2=18,
PRODUCT_MAX
};
struct PermitType {
@@ -73,6 +78,15 @@ struct PermitType {
case 15:
m_permitType = PERMIT_TYPE::DAY_TICKET_CAMPER;
break;
case 16:
m_permitType = PERMIT_TYPE::FREE_TICKET;
break;
case 17:
m_permitType = PERMIT_TYPE::TEST_PRODUCT_1;
break;
case 18:
m_permitType = PERMIT_TYPE::TEST_PRODUCT_2;
break;
default:
m_permitType = PERMIT_TYPE::INVALID;
}
@@ -116,6 +130,12 @@ struct PermitType {
return 14;
case PERMIT_TYPE::DAY_TICKET_CAMPER:
return 15;
case PERMIT_TYPE::FREE_TICKET:
return 16;
case PERMIT_TYPE::TEST_PRODUCT_1:
return 17;
case PERMIT_TYPE::TEST_PRODUCT_2:
return 18;
default:
break;
}
@@ -132,9 +152,6 @@ struct PermitType {
if (permitTypeStr == "DAY_TICKET_CHILD") {
return PERMIT_TYPE::DAY_TICKET_CHILD;
} else
if (permitTypeStr == "DAY_TICKET_ADULT") {
return PERMIT_TYPE::DAY_TICKET_ADULT;
} else
if (permitTypeStr == "DAY_TICKET_TEEN") {
return PERMIT_TYPE::DAY_TICKET_TEEN;
} else
@@ -170,6 +187,15 @@ struct PermitType {
} else
if (permitTypeStr == "DAY_TICKET_CAMPER") {
return PERMIT_TYPE::DAY_TICKET_CAMPER;
} else
if (permitTypeStr == "FREE_TICKET") {
return PERMIT_TYPE::FREE_TICKET;
} else
if (permitTypeStr == "TEST_PRODUCT_1") {
return PERMIT_TYPE::TEST_PRODUCT_1;
} else
if (permitTypeStr == "TEST_PRODUCT_2") {
return PERMIT_TYPE::TEST_PRODUCT_2;
}
return PERMIT_TYPE::INVALID;
@@ -207,6 +233,12 @@ struct PermitType {
return QString("DAY_TICKET_BUS");
case PERMIT_TYPE::DAY_TICKET_CAMPER:
return QString("DAY_TICKET_CAMPER");
case PERMIT_TYPE::FREE_TICKET:
return QString("FREE_TICKET");
case PERMIT_TYPE::TEST_PRODUCT_1:
return QString("TEST_PRODUCT_1");
case PERMIT_TYPE::TEST_PRODUCT_2:
return QString("TEST_PRODUCT_2");
default:
break;
}
@@ -245,6 +277,12 @@ struct PermitType {
return QString("DAY_TICKET_BUS");
case PERMIT_TYPE::DAY_TICKET_CAMPER:
return QString("DAY_TICKET_CAMPER");
case PERMIT_TYPE::FREE_TICKET:
return QString("FREE_TICKET");
case PERMIT_TYPE::TEST_PRODUCT_1:
return QString("TEST_PRODUCT_1");
case PERMIT_TYPE::TEST_PRODUCT_2:
return QString("TEST_PRODUCT_2");
default:
break;
}

View File

@@ -1,9 +1,85 @@
#ifndef TARIFF_PREPAID_H_INCLUDED
#define TARIFF_PREPAID_H_INCLUDED
#include <QTime>
#include <QDateTime>
#include <QString>
#include "time_range.h"
enum class ApplyPrepaid {
NEVER = 0,
MATCH_PREV_DAY = 1,
MATCH_NEXT_DAY = 2,
ALWAYS = 3
};
struct ATBTariffPrepaid {
int m_id;
QString m_weekDay;
QDate m_date;
TimeRange m_range;
ApplyPrepaid m_prepaidIf;
explicit ATBTariffPrepaid()
: m_id(-1)
, m_prepaidIf(ApplyPrepaid::NEVER) {
}
void setPrepaidIf(QString const &ppif) {
if (ppif == "never") {
m_prepaidIf = ApplyPrepaid::NEVER;
} else
if (ppif == "match_prev_day") {
m_prepaidIf = ApplyPrepaid::MATCH_PREV_DAY;
} else
if (ppif == "match_next_day") {
m_prepaidIf = ApplyPrepaid::MATCH_NEXT_DAY;
} else
if (ppif == "always") {
m_prepaidIf = ApplyPrepaid::ALWAYS;
} else {
qCritical() << __func__ << ":" << __LINE__ << "ERROR unknown carry over application" << ppif;
}
}
ApplyPrepaid prepaidIf() const {
return m_prepaidIf;
}
QString prepaidIfStr() const {
if (m_prepaidIf == ApplyPrepaid::NEVER) {
return "never";
}
if (m_prepaidIf == ApplyPrepaid::ALWAYS) {
return "always";
}
if (m_prepaidIf == ApplyPrepaid::MATCH_PREV_DAY) {
return "match prev day";
}
if (m_prepaidIf == ApplyPrepaid::MATCH_NEXT_DAY) {
return "match next day";
}
return QString("ERROR unknown prepaid application: %1").arg(static_cast<int>(m_prepaidIf));
}
friend QDebug operator<<(QDebug debug, ATBTariffPrepaid const &pp) {
QDebugStateSaver saver(debug);
debug.nospace()
<< "\nTariffPrepaid:\n"
<< " week day: " << pp.m_weekDay << "\n"
<< " date: " << pp.m_date.toString(Qt::ISODate) << "\n"
<< " id: " << pp.m_id << "\n"
<< " start: " << pp.m_range.m_start << "\n"
<< " end: " << pp.m_range.m_end << "\n"
<< " duration: " << pp.m_range.m_duration << "\n"
<< " prepaid if: " << pp.prepaidIfStr() << endl;
return debug;
}
};
// deprecated
struct ATBPrepaid {
int id;
bool anytime;

View File

@@ -0,0 +1,81 @@
#ifndef TARIFF_SERVICE_H_INCLUDED
#define TARIFF_SERVICE_H_INCLUDED
#include <QDateTime>
#include <QString>
#include "time_range.h"
enum class ApplyService {
NEVER = 0,
MATCH_PREV_DAY = 1,
MATCH_NEXT_DAY = 2,
ALWAYS = 3
};
struct ATBTariffService {
int m_id;
QString m_weekDay;
QDate m_date;
TimeRange m_range;
ApplyService m_serviceIf;
explicit ATBTariffService()
: m_id(-1)
, m_serviceIf(ApplyService::NEVER) {
}
void setServiceIf(QString const &sif) {
if (sif == "never") {
m_serviceIf = ApplyService::NEVER;
} else
if (sif == "match_prev_day") {
m_serviceIf = ApplyService::MATCH_PREV_DAY;
} else
if (sif == "match_next_day") {
m_serviceIf = ApplyService::MATCH_NEXT_DAY;
} else
if (sif == "always") {
m_serviceIf = ApplyService::ALWAYS;
} else {
qCritical() << "ERROR unknown servcie application" << sif;
}
}
ApplyService serviceIf() const {
return m_serviceIf;
}
QString serviceIfStr() const {
if (m_serviceIf == ApplyService::NEVER) {
return "never";
}
if (m_serviceIf == ApplyService::ALWAYS) {
return "always";
}
if (m_serviceIf == ApplyService::MATCH_PREV_DAY) {
return "match prev day";
}
if (m_serviceIf == ApplyService::MATCH_NEXT_DAY) {
return "match next day";
}
return QString("ERROR unknown service application: %1").arg(static_cast<int>(m_serviceIf));
}
friend QDebug operator<<(QDebug debug, ATBTariffService const &ts) {
QDebugStateSaver saver(debug);
debug.nospace()
<< "\nTariffService:\n"
<< " week day: " << ts.m_weekDay << "\n"
<< " date: " << ts.m_date.toString(Qt::ISODate) << "\n"
<< " id: " << ts.m_id << "\n"
<< " start: " << ts.m_range.m_start << "\n"
<< " end: " << ts.m_range.m_end << "\n"
<< " duration: " << ts.m_range.m_duration << "\n"
<< " prepaid if: " << ts.serviceIfStr() << endl;
return debug;
}
};
#endif // TARIFF_SERVICE_H_INCLUDED

View File

@@ -1,12 +1,46 @@
#ifndef TIME_RANGE_H_INCLUDED
#define TIME_RANGE_H_INCLUDED
#include "time_range_header.h"
struct TimeRange {
public:
bool IsActive;
ATBTimeRange TimeRangeStructure;
};
#endif // TIME_RANGE_H_INCLUDED
#ifndef TIME_RANGE_H_INCLUDED
#define TIME_RANGE_H_INCLUDED
#include "atb_time.h"
#include <QString>
struct TimeRange {
ATBTime m_start;
ATBTime m_end;
int m_duration;
explicit TimeRange() = default;
explicit TimeRange(QString const &start, QString const &end, int duration)
: m_start(start)
, m_end(end)
, m_duration(duration) {
}
explicit TimeRange(ATBTime const &start, ATBTime const &end, int duration)
: m_start(start)
, m_end(end)
, m_duration(duration) {
}
explicit TimeRange(TimeRange const &timeRange) {
m_start = timeRange.m_start;
m_end = timeRange.m_end;
m_duration = timeRange.m_duration;
}
TimeRange &operator=(TimeRange && timeRange) {
m_start = std::move(timeRange.m_start);
m_end = std::move(timeRange.m_end);
m_duration = timeRange.m_duration;
return *this;
}
TimeRange &operator=(TimeRange const &timeRange) {
m_start = timeRange.m_start;
m_end = timeRange.m_end;
m_duration = timeRange.m_duration;
return *this;
}
};
#endif // TIME_RANGE_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -91,7 +91,9 @@ HEADERS += \
include/mobilisis/tariff_prepaid.h \
include/mobilisis/tariff_carryover.h \
include/mobilisis/tariff_global_defines.h \
include/mobilisis/atb_time.h
include/mobilisis/atb_time.h \
include/mobilisis/tariff_service.h \
include/mobilisis/tariff_out_of_service.h
OTHER_FILES += src/main.cpp \
../tariffs/tariff_korneuburg.json \

View File

@@ -1,16 +1,38 @@
#include "atb_time.h"
#include <QDebugStateSaver>
QDateTime const ATBTime::m_end(QDateTime::fromString("1970-01-02T00:00:00", Qt::ISODate));
ATBTime::ATBTime()
: m_end(QDateTime::fromString("1970-01-02T00:00:00"))
, m_time(QDateTime::fromString("1970-01-01T00:00:00")) {
: m_time(QDateTime::fromString("1970-01-01T00:00:00", Qt::ISODate)) {
}
ATBTime::ATBTime(int h, int m, int s, int ms)
: m_end(QDateTime::fromString("1970-01-02T00:00:00"))
, m_time(QDateTime::fromString("1970-01-01T00:00:00")) {
ATBTime::ATBTime(int h, int m, int /*s*/, int /*ms*/)
: m_time(QDateTime::fromString("1970-01-01T00:00:00", Qt::ISODate)) {
QTime t(h, m, s, ms);
if (h == 24 && m == 0) {
m_time = m_end;
} else {
QTime const t(h, m, 0, 0);
m_time.setTime(t);
}
}
ATBTime::ATBTime(QString const &t)
: m_time(QDateTime::fromString("1970-01-01T00:00:00")) {
if (t == "24:00:00") {
m_time = m_end;
} else {
QTime tmp = QTime::fromString(t, Qt::ISODate);
if (tmp.isValid()) {
m_time.setTime(tmp);
}
}
}
ATBTime::ATBTime(QTime const &t)
: m_time(QDateTime::fromString("1970-01-01T00:00:00")) {
m_time.setTime(t);
}
@@ -66,6 +88,9 @@ bool ATBTime::setHMS(int h, int m, int s, int ms) {
}
QString ATBTime::toString(Qt::DateFormat format) const {
if (m_time == m_end) {
return "24:00:00";
}
return m_time.time().toString(format);
}
@@ -74,11 +99,20 @@ bool operator!=(const ATBTime &lhs, const ATBTime &rhs) noexcept {
}
bool operator<=(const ATBTime &lhs, const ATBTime &rhs) noexcept {
if (rhs.m_time == rhs.m_end) {
return true;
}
return lhs.m_time.time() <= rhs.m_time.time();
}
bool operator>=(const ATBTime &lhs, const ATBTime &rhs) noexcept {
return lhs.m_time.time() >= rhs.m_time.time();
}
bool operator<(const ATBTime &lhs, const ATBTime &rhs) noexcept {
if (rhs.m_time == rhs.m_end) {
return true;
}
return lhs.m_time.time() < rhs.m_time.time();
}
@@ -90,8 +124,22 @@ bool operator==(const ATBTime &lhs, const ATBTime &rhs) noexcept {
return lhs.m_time.time() == rhs.m_time.time();
}
QDataStream &operator<<(QDataStream &out, ATBTime time) {
out << time.m_time.time();
QDebug &operator<<(QDebug &debug, ATBTime const &time) {
QDebugStateSaver saver(debug);
if (time.m_time == time.m_end) {
debug.nospace() << QString("24:00:00");
} else {
debug.nospace() << time.m_time.time().toString(Qt::ISODate);
}
return debug;
}
QDataStream &operator<<(QDataStream &out, ATBTime const &time) {
if (time.m_time == time.m_end) {
out << QString("24:00:00");
} else {
out << time.m_time.time();
}
return out;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,762 @@
#include "calculate_price.h"
#include "configuration.h"
#include "calculator_functions.h"
#include "payment_option.h"
#include "utilities.h"
#include <QFile>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>
#include <QList>
QString const CalcState::SUCCESS = "SUCCESS";
QString const CalcState::ERROR_PARSING_ZONE_NR = "ERROR_PARSING_ZONE_NR";
QString const CalcState::ERROR_LOADING_TARIFF = "ERROR_LOADING_TARIFF";
QString const CalcState::ERROR_PARSING_TARIFF = "ERROR_PARSING_TARIFF";
QString const CalcState::NEGATIVE_PARKING_TIME = "NEGATIVE_PARKING_TIME";
QString const CalcState::INVALID_START_DATE = "INVALID_START_DATE";
QString const CalcState::WRONG_PARAM_VALUES = "WRONG_PARAM_VALUES";
QString const CalcState::WRONG_ISO_TIME_FORMAT = "WRONG_ISO_TIME_FORMAT";
QString const CalcState::ABOVE_MAX_PARKING_TIME = "ABOVE_MAX_PARKING_TIME";
QString const CalcState::BELOW_MIN_PARKING_TIME = "BELOW_MIN_PARKING_TIME";
QString const CalcState::BELOW_MIN_PARKING_PRICE = "BELOW_MIN_PARKING_PRICE";
QString const CalcState::ABOVE_MAX_PARKING_PRICE = "ABOVE_MAX_PARKING_PRICE";
QString const CalcState::OVERPAID = "OVERPAID";
QString const CalcState::OUTSIDE_ALLOWED_PARKING_TIME = "OUTSIDE_ALLOWED_PARKING_TIME";
QList<int> CALCULATE_LIBRARY_API get_time_steps(Configuration *cfg) {
return Calculator::GetInstance().GetTimeSteps(cfg);
}
int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration const *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int minTime = 0;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
QList<int> const tsteps = Calculator::GetInstance().GetTimeSteps((Configuration *)cfg, paymentOptionIndex);
Q_UNUSED(tsteps);
minTime = cfg->getPaymentOptions(paymentOptionIndex).pop_min_time;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
case PERMIT_TYPE::DAY_TICKET_TEEN: {
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD: {
} break;
default:
// for each new sell-procedure, recomute the timesteps. implicitly, set
// the minimal parking time.
Calculator::GetInstance().ResetTimeSteps(paymentOptionIndex);
Calculator::GetInstance().GetTimeSteps((Configuration *)cfg, paymentOptionIndex);
minTime = qRound(cfg->getPaymentOptions(paymentOptionIndex).pop_min_time);
}
return minTime;
}
int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration const *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int maxTime = 0;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
maxTime = cfg->getPaymentOptions(paymentOptionIndex).pop_max_time;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
case PERMIT_TYPE::DAY_TICKET_TEEN: {
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD: {
} break;
default: ;
}
return maxTime;
}
int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex,
QDateTime const &start) {
int minPrice = -1;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
minPrice = cfg->getPaymentOptions(paymentOptionIndex).pop_min_price;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
case PERMIT_TYPE::DAY_TICKET_TEEN: {
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD: {
} break;
case PERMIT_TYPE::DAY_TICKET: {
minPrice = compute_product_price(cfg, permitType, start);
} break;
default: ;
}
return minPrice;
}
int CALCULATE_LIBRARY_API compute_product_price(Configuration const *cfg,
PERMIT_TYPE permitType,
QDateTime const &start,
QDateTime *productStart,
QDateTime *productEnd) {
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET_TEEN:
// [[fallthrough]];
case PERMIT_TYPE::FOOD_STAMP:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET_ADULT: {
std::optional<QVector<ATBTariffProduct>> products = cfg->getTariffProductForProductId(permitType);
if (products) {
QVector<ATBTariffProduct> product = products.value();
if (product.size() > 0) {
ATBTariffProduct const &p = product[0];
return p.m_tariff_product_price;
#if 0
// in case we do not have prepaid-option
QTime const &currentTime = QDateTime::currentDateTime().time();
if (p.m_tariff_product_start <= currentTime && currentTime <= p.m_tariff_product_end) {
return p.m_tariff_product_price;
} else {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "ERROR currentTime"
<< currentTime.toString(Qt::ISODate)
<< "INVALID ("
<< p.m_tariff_product_start.toString(Qt::ISODate)
<< p.m_tariff_product_end.toString(Qt::ISODate) << ")";
}
#endif
}
}
} break;
case PERMIT_TYPE::INVALID:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET: {
std::optional<QVector<ATBTariffProduct>> products = cfg->getTariffProductForProductId(permitType);
if (products) {
QVector<ATBTariffProduct> product = products.value();
int product_price = 0;
if (productStart && productEnd) {
*productStart = start;
*productEnd = start;
if (product.size() > 0) {
productStart->setTime(product[0].getTimeStart());
productEnd->setTime(product[0].getTimeEnd());
}
}
for (QVector<ATBTariffProduct>::size_type i=0; i<product.size(); ++i) {
ATBTariffProduct const &p = product[i];
QTime const &startTime = p.getTimeStart();
QTime const &endTime = p.getTimeEnd();
// qCritical() << __LINE__ << startTime.toString(Qt::ISODate);
// qCritical() << __LINE__ << endTime.toString(Qt::ISODate);
// qCritical() << __LINE__ << start.toString(Qt::ISODate);
if (start.time() >= startTime && start.time() < endTime) {
product_price = p.getProductPrice();
if (productStart && productEnd) {
productStart->setTime(startTime);
productEnd->setTime(endTime);
}
}
}
return product_price;
} else {
// SZEGED
int const pop_daily_card_price = cfg->getPaymentOptions().pop_daily_card_price;
qDebug() << QString("(%1:%2) no products defined in tariff-file").arg(__func__).arg(__LINE__);
qDebug() << QString("(%1:%2) pop_daily_card_price=%3").arg(__func__).arg(__LINE__).arg(pop_daily_card_price);
// static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
// return Utilities::getDailyTicketCardPrice(cfg, paymentMethodId);
return pop_daily_card_price;
}
} break;
case PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET: {
std::optional<QVector<ATBTariffProduct>> products = cfg->getTariffProductForProductId(permitType);
if (products) {
int product_price = 0;
QVector<ATBTariffProduct> product = products.value();
if (product.size() > 0) {
if (productStart && productEnd) {
int pop_min_time = get_minimal_parkingtime(cfg); // in minutes
int pop_max_time = get_maximal_parkingtime(cfg); // in minutes
if (pop_max_time >= pop_min_time) {
*productStart = start;
*productEnd = start.addSecs(pop_max_time*60);
product_price = product[0].getProductPrice();
}
}
}
return product_price;
}
} break;
default:
break;
}
return 0;
}
int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int maxPrice = -1;
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
if (paymentMethodId == PaymentMethod::Progressive || paymentMethodId == PaymentMethod::Steps) {
maxPrice = Utilities::getMaximalParkingPrice(cfg, paymentMethodId);
} else { // PaymentMethod::Linear -> e.g. szeged
int const key = cfg->getPaymentOptions(paymentOptionIndex).pop_id;
int const maxTime = cfg->getPaymentOptions(paymentOptionIndex).pop_max_time; // maxTime is given in minutes
std::optional<QVector<ATBPaymentRate>> const &pv = cfg->getPaymentRateForKey(key);
if (pv) {
QVector<ATBPaymentRate> const &paymentRate = pv.value();
if (paymentRate.size() > 0) {
int const price = paymentRate.last().pra_price; // price is given per hour
maxPrice = qRound((maxTime * price) / 60.0f);
}
}
}
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT:
break;
case PERMIT_TYPE::DAY_TICKET_TEEN:
break;
case PERMIT_TYPE::DAY_TICKET_CHILD:
break;
default: ;
}
return maxPrice;
}
int CALCULATE_LIBRARY_API get_zone_nr(int zone)
{
if(zone > -1) return zone;
else
{
QFile zone("/etc/zone_nr");
if (zone.exists()) {
QFileInfo finfo(zone);
if (finfo.size() <= 4) { // decimal 000\n
if (zone.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&zone);
return in.readLine(100).toInt();
}
}
}
return -1;
}
}
CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file) {
*tariff = new Configuration();
CalcState calcState;
#if __linux__
int const zone = get_zone_nr();
// DEBUG
qCritical() << "init_tariff:";
qCritical() << " ... zone = " << zone;
if (zone <= 0) {
delete *tariff;
*tariff = nullptr;
return calcState.set(CalcState::State::ERROR_PARSING_ZONE_NR);
}
QString confFile(config_file);
if (!confFile.endsWith(QChar('/'))) {
confFile += "/";
}
char buffer[32];
memset(buffer, 0x00, sizeof(buffer));
snprintf(buffer, sizeof(buffer)-1, "tariff%02d.json", zone);
confFile += buffer;
#else // windows
QString confFile(config_file);
#endif
// DEBUG
qCritical() << " ... confFile = " << confFile;
QFile fname(confFile);
if (fname.exists() &&
fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
// DEBUG
qCritical() << " ... confFile is open";
QString json = fname.readAll();
if (! (*tariff)->ParseJson(*tariff, json.toStdString().c_str())) {
delete *tariff;
*tariff = nullptr;
return calcState.set(CalcState::State::ERROR_PARSING_TARIFF);
}
} else {
delete *tariff;
*tariff = nullptr;
return calcState.set(CalcState::State::ERROR_LOADING_TARIFF);
}
qCritical() << "init_tariff: Parsing tariff config (" << confFile << ")";
return calcState;
}
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff) {
if (tariff != nullptr) {
delete tariff;
}
}
//
// UpDown 1 -> up; 0 -> down
int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes, int UpDown)
{
qCritical() << " compute_next_timestep() currentTimeMinutes: " << currentTimeMinutes;
qCritical() << " compute_next_timestep() up/down (1=up, 0=down): " << UpDown;
Configuration const *cfg = tariff;
// compute payment method id (e.g. Linear=3, Steps=4)
PaymentMethod const paymentMethodId = Utilities::getPaymentMethodId(cfg);
switch (paymentMethodId) {
case PaymentMethod::Progressive:
qCritical() << " compute_next_timestep() paymentMethodId: Progressive";
break;
case PaymentMethod::Degressive:
qCritical() << " compute_next_timestep() paymentMethodId: Degressive";
break;
case PaymentMethod::Linear:
qCritical() << " compute_next_timestep() paymentMethodId: Linear";
break;
case PaymentMethod::Steps:
qCritical() << " compute_next_timestep() paymentMethodId: Steps";
break;
case PaymentMethod::Undefined:
qCritical() << " compute_next_timestep() paymentMethodId: Undefined";
break;
}
// use tariff with structure as for instance Schnau, Koenigsee:
// without given YearPeriod, SpecialDays and SpecialDaysWorktime
if ((paymentMethodId == PaymentMethod::Steps) ||
// progressive tariff: e.g. Neuhauser, Kirchdorf (743)
(paymentMethodId == PaymentMethod::Progressive))
{
const QList<int> stepList = Calculator::GetInstance().GetTimeSteps(tariff);
qCritical() << " compute_next_timestep() timeSteps:" << stepList;
int currentStepIndex = stepList.indexOf(currentTimeMinutes);
if (currentStepIndex == -1) {
qCritical() << "compute_next_timestep() *NO STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
return currentTimeMinutes;
}
if (UpDown == 1) { // UP
if (stepList[currentStepIndex] == stepList.last()) {
qCritical() << "compute_next_timestep() *NO NEXT STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
return currentTimeMinutes;
}
else {
return stepList[currentStepIndex + 1];
}
}
if (UpDown == 0) { // DOWN
if (stepList[currentStepIndex] == stepList.first()) {
qCritical() << "compute_next_timestep() *NO PREVIOUS STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
return currentTimeMinutes;
}
else {
return stepList[currentStepIndex - 1];
}
}
} else
if (paymentMethodId == PaymentMethod::Linear) {
// currentTimeMinutes is the number of minutes actually used. This
// value is an offset from the start time and cannot be used as a
// QDateTime.
qCritical() << "compute_next_timestep() up/down (1=up, 0=down):" << UpDown;
// get minimal and maximal parking times
int const minParkingTime = Utilities::getMinimalParkingTime(cfg, paymentMethodId);
int const maxParkingTime = Utilities::getMaximalParkingTime(cfg, paymentMethodId);
qCritical() << " compute_next_timestep() maxParkingTime:" << maxParkingTime;
qCritical() << " compute_next_timestep() minParkingTime:" << minParkingTime;
// use the first (i.e. main duration step contained in the tariff json-file)
int firstDurationStep = Utilities::getFirstDurationStep(cfg, paymentMethodId);
firstDurationStep = ((UpDown == 1) ? firstDurationStep : -firstDurationStep);
qCritical() << " compute_next_timestep() firstDurationStep:" << firstDurationStep;
int const nextTimeStep = currentTimeMinutes + firstDurationStep;
if (nextTimeStep >= minParkingTime && nextTimeStep <= maxParkingTime) {
qCritical() << " compute_next_timestep() nextTimeStep:" << nextTimeStep;
return nextTimeStep;
}
}
qCritical() << "compute_next_timestep() *CAN NOT COMPUTE* for currentTimeMinutes (" << currentTimeMinutes << ")";
return currentTimeMinutes;
}
// this is currently not used
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff,
time_t start_parking_time, // in minutes
time_t end_parking_time, // netto time in minutes
struct price_t *price) {
CalcState calcState;
double minMin = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->second.pop_min_time;
double maxMin = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->second.pop_max_time;
if (minMin < 0 || maxMin < 0 || maxMin < minMin) {
calcState.setDesc(QString("minMin=%1, maxMin=%2").arg(minMin).arg(maxMin));
return calcState.set(CalcState::State::WRONG_PARAM_VALUES);
}
int const duration = end_parking_time - start_parking_time;
if (duration < 0) {
calcState.setDesc(QString("end=%1, start=%2")
.arg(end_parking_time, start_parking_time));
return calcState.set(CalcState::State::NEGATIVE_PARKING_TIME);
}
if (duration > maxMin) {
calcState.setDesc(QString("duration=%1, maxMin=%2").arg(duration).arg(maxMin));
return calcState.set(CalcState::State::ABOVE_MAX_PARKING_TIME);
}
if (duration < minMin) {
calcState.setDesc(QString("duration=%1, minMin=%2").arg(duration).arg(minMin));
return calcState.set(CalcState::State::BELOW_MIN_PARKING_TIME);
}
if (duration == 0) {
return calcState.set(CalcState::State::SUCCESS);
}
QDate const d(1970, 1, 1);
QTime const t(0, 0, 0);
QDateTime start(d, t, Qt::UTC);
start = start.toLocalTime().addSecs(start_parking_time * 60);
QDateTime end(start);
if (start.isValid()) {
double cost = Calculator::GetInstance().GetCostFromDuration(
tariff,
tariff->getPaymentOptions().pop_payment_method_id,
start,
end,
duration, false, true);
double minCost = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->second.pop_min_price;
if (cost < minCost) {
calcState.setDesc(QString("minCost=%1, cost=%2").arg(minCost).arg(cost));
return calcState.set(CalcState::State::BELOW_MIN_PARKING_PRICE);
}
price->units = cost;
price->netto = cost;
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
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,
struct price_t *price,
bool prepaid)
{
CalcState calcState;
int paymentOptionIndex = tariff->getPaymentOptionIndex(start_parking_time);
double minMin = tariff->getPaymentOptions(paymentOptionIndex).pop_min_time;
double maxMin = tariff->getPaymentOptions(paymentOptionIndex).pop_max_time;
// DEBUG
qCritical() << "compute_price_for_parking_ticket() " << endl
<< " paymentOptionIndex: " << paymentOptionIndex << endl
<< " start_parking_time: " << start_parking_time << endl
<< " netto_parking_time: " << netto_parking_time << endl
<< " minMin: " << minMin << endl
<< " maxMin: " << maxMin;
if (netto_parking_time < 0) {
calcState.setDesc(QString("end=%1, start=%2")
.arg(end_parking_time.toString(Qt::ISODate),
start_parking_time.toString(Qt::ISODate)));
return calcState.set(CalcState::State::NEGATIVE_PARKING_TIME);
}
if (netto_parking_time > maxMin) {
calcState.setDesc(QString("duration=%1, maxMin=%2").arg(netto_parking_time).arg(maxMin));
return calcState.set(CalcState::State::ABOVE_MAX_PARKING_TIME);
}
if (netto_parking_time < minMin) {
calcState.setDesc(QString("duration=%1, minMin=%2").arg(netto_parking_time).arg(minMin));
return calcState.set(CalcState::State::BELOW_MIN_PARKING_TIME);
}
if (netto_parking_time == 0) {
return calcState.set(CalcState::State::SUCCESS);
}
double cost = -1;
if (start_parking_time.isValid()) {
if (tariff->getPaymentOptions(paymentOptionIndex).pop_payment_method_id == PaymentMethod::Steps) {
// hier muesste man unterscheiden: uebertrag oder nicht?
calcState = Calculator::GetInstance().isParkingAllowed(tariff, start_parking_time,
netto_parking_time, paymentOptionIndex);
if (calcState.getStatus() == CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME) {
// qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
// << calcState.toString();
return calcState;
}
cost = Calculator::GetInstance().GetCostFromDuration(tariff, start_parking_time, netto_parking_time, paymentOptionIndex);
end_parking_time = start_parking_time.addSecs(netto_parking_time*60);
// qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
// << "end_parking_time" << end_parking_time.toString(Qt::ISODate);
} else {
cost = Calculator::GetInstance().GetCostFromDuration(
tariff,
tariff->getPaymentOptions().pop_payment_method_id,
start_parking_time, // starting time
end_parking_time, // return value: end time
netto_parking_time, // minutes, netto
false, prepaid);
}
double minCost = tariff->getPaymentOptions(paymentOptionIndex).pop_min_price;
if (cost < minCost) {
calcState.setDesc(QString("minCost=%1, cost=%2").arg(minCost, cost));
return calcState.set(CalcState::State::BELOW_MIN_PARKING_PRICE);
}
// DEBUG
qCritical() << " end_parking_time: " << end_parking_time;
qCritical() << " -> calculated cost (netto): " << cost;
price->brutto = price->vat = price->vat_percentage = 0;
price->units = cost;
price->netto = cost;
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff,
time_t start_parking_time,
double price,
QString &duration) {
CalcState calcState;
QDate const d(1970, 1, 1);
QTime const t(0, 0, 0);
QDateTime start(d, t, Qt::UTC);
start = start.toLocalTime().addSecs(start_parking_time * 60);
if (start.isValid()) {
QString cs = start.toString(Qt::ISODate);
// DEBUG
qCritical() << "compute_duration_for_parking_ticket(): ";
qCritical() << " start (cs): " << cs;
qCritical() << " price: " << price;
duration = Calculator::GetInstance().GetDurationFromCost(tariff,
tariff->getPaymentOptions().pop_payment_method_id,
cs.toLocal8Bit().constData(),
price, false, true).c_str();
QDateTime d = QDateTime::fromString(duration, Qt::ISODate);
if (!d.isValid()) {
calcState.setDesc(QString("ticketEndTime=%1").arg(duration));
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
double price,
QDateTime &ticketEndTime)
{
CalcState calcState;
if (start_parking_time.isValid()) {
QString cs = start_parking_time.toString(Qt::ISODate);
QString endTime = Calculator::GetInstance().GetDurationFromCost(
tariff,
tariff->getPaymentOptions().pop_payment_method_id,
cs.toLocal8Bit().constData(),
price, false, true).c_str();
if (endTime == CalcState::SUCCESS) {
calcState.setDesc(QString("SUCCESS"));
calcState.setStatus(endTime);
} else
if (endTime == CalcState::ERROR_PARSING_ZONE_NR) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::ERROR_LOADING_TARIFF) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::ERROR_PARSING_TARIFF) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::NEGATIVE_PARKING_TIME) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::INVALID_START_DATE) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::WRONG_PARAM_VALUES) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::WRONG_ISO_TIME_FORMAT) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::ABOVE_MAX_PARKING_TIME) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::BELOW_MIN_PARKING_TIME) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::BELOW_MIN_PARKING_PRICE) {
calcState.setStatus(endTime);
return calcState;
} else
if (endTime == CalcState::ABOVE_MAX_PARKING_PRICE) {
calcState.setDesc(CalcState::ABOVE_MAX_PARKING_PRICE);
calcState.setStatus(CalcState::ABOVE_MAX_PARKING_PRICE);
return calcState;
} else
if (endTime == CalcState::OVERPAID) {
calcState.setDesc(CalcState::OVERPAID);
calcState.setStatus(CalcState::OVERPAID);
return calcState;
} else
if (endTime == CalcState::OUTSIDE_ALLOWED_PARKING_TIME) {
calcState.setStatus(endTime);
return calcState;
} else {
ticketEndTime = QDateTime::fromString(endTime,Qt::ISODate);
// DEBUG
//qCritical() << "compute_duration_for_parking_ticket(): ";
//qCritical() << " endTime: " << endTime;
//qCritical() << " ticketEndTime: " << ticketEndTime;
if (!ticketEndTime.isValid()) {
calcState.setDesc(QString("ticketEndTime=%1").arg(endTime));
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
}
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_daily_ticket(parking_tariff_t *tariff, QDateTime const &start_parking_time, QDateTime &ticketEndTime)
{
CalcState calcState;
if (start_parking_time.isValid()) {
ticketEndTime = Calculator::GetInstance().GetDailyTicketDuration(tariff,
start_parking_time,
tariff->getPaymentOptions().pop_payment_method_id,
false); // carry over
// DEBUG
qCritical() << "compute_duration_for_daily_ticket(): ";
qCritical() << " ticketEndTime: " << ticketEndTime;
if (!ticketEndTime.isValid()) {
calcState.setDesc(QString("ticketEndTime=%1").arg(ticketEndTime.toString(Qt::ISODate)));
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_price_for_daily_ticket(
parking_tariff_t *tariff,
QDateTime const &startDatetime,
QDateTime &endDatetime,
PERMIT_TYPE permitType,
struct price_t *price) {// return value
CalcState calcState;
if (startDatetime.isValid()) {
if (std::optional<struct price_t> p =
Calculator::GetInstance().GetDailyTicketPrice(tariff,
startDatetime,
endDatetime,
permitType)) {
*price = p.value();
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}

View File

@@ -6,6 +6,8 @@
#include "ticket.h"
#include "tariff_global_defines.h"
#include "tariff_prepaid.h"
#include "tariff_out_of_service.h"
#include "tariff_service.h"
#include <sstream>
#include <algorithm>
@@ -117,6 +119,677 @@ QDateTime Calculator::GetDailyTicketDuration(Configuration* cfg, const QDateTime
return QDateTime();
}
///
/// \brief getPrepaid
/// \param cfg
/// \param dt
/// \return
///
std::optional<ATBTariffPrepaid> getPrepaid(Configuration const *cfg, QDateTime const &dt) {
std::optional<ATBTariffPrepaid> value = std::nullopt;
int weekDay = dt.date().dayOfWeek();
// qCritical() << __func__ << ":" << __LINE__ << dt.toString(Qt::ISODate) << weekDay;
ATBTime inputTime(dt.time());
QDate d; // check if a special date is configured in tariff-file for this day
auto const &prepaidRange = cfg->TariffPrepaids.equal_range(weekDay);
for (auto i = prepaidRange.first; i != prepaidRange.second; ++i) {
ATBTariffPrepaid const &prepaid = i->second;
if (!prepaid.m_date.isNull() && prepaid.m_date.isValid() && prepaid.m_date == dt.date()) {
d = dt.date();
// qCritical() << __func__ << ":" << __LINE__ << "found special day" << d.toString(Qt::ISODate);
break;
}
}
if (!d.isNull() && d.isValid()) {
for (auto i = prepaidRange.first; i != prepaidRange.second; ++i) {
ATBTariffPrepaid const &prepaid = i->second;
if (!prepaid.m_date.isNull() && prepaid.m_date.isValid() && prepaid.m_date == d) {
TimeRange const &prepaidTimeRange = prepaid.m_range;
if (inputTime >= prepaidTimeRange.m_start && inputTime < prepaidTimeRange.m_end) {
// qCritical() << __func__ << ":" << __LINE__ << prepaidTimeRange.m_start.toString(Qt::ISODate);
// qCritical() << __func__ << ":" << __LINE__ << prepaidTimeRange.m_end.toString(Qt::ISODate);
value = value.value_or(i->second);
break;
}
}
}
} else {
// qCritical() << __func__ << ":" << __LINE__ << "no special day" << dt.date().toString(Qt::ISODate);
for (auto i = prepaidRange.first; i != prepaidRange.second; ++i) {
ATBTariffPrepaid const &prepaid = i->second;
if (prepaid.m_date.isNull() || !prepaid.m_date.isValid()) {
qCritical() << __func__ << ":" << __LINE__ << "default";
TimeRange const &prepaidTimeRange = prepaid.m_range;
if (inputTime >= prepaidTimeRange.m_start && inputTime < prepaidTimeRange.m_end) {
// qCritical() << __func__ << ":" << __LINE__ << prepaidTimeRange.m_start.toString(Qt::ISODate);
// qCritical() << __func__ << ":" << __LINE__ << prepaidTimeRange.m_end.toString(Qt::ISODate);
value = value.value_or(i->second);
break;
}
}
}
}
return value;
}
///
/// \brief getCarryOver
/// \param cfg
/// \param dt
/// \return
///
std::optional<ATBTariffCarryOver> getCarryOver(Configuration const *cfg, QDateTime const &dt) {
std::optional<ATBTariffCarryOver> value = std::nullopt;
int weekDay = dt.date().dayOfWeek();
// qCritical() << __func__ << ":" << __LINE__ << dt.toString(Qt::ISODate) << weekDay;
ATBTime inputTime(dt.time());
auto const &carryOverRange = cfg->TariffCarryOvers.equal_range(weekDay);
QDate d; // check if a special date is configured in tariff-file for this day
for (auto i = carryOverRange.first; i != carryOverRange.second; ++i) {
ATBTariffCarryOver const &carryOver = i->second;
if (!carryOver.m_date.isNull() && carryOver.m_date.isValid() && carryOver.m_date == dt.date()) {
d = dt.date();
// qCritical() << __func__ << ":" << __LINE__ << "found special day" << d.toString(Qt::ISODate);
break;
}
}
if (!d.isNull() && d.isValid()) {
for (auto i = carryOverRange.first; i != carryOverRange.second; ++i) {
ATBTariffCarryOver const &carryOver = i->second;
if (!carryOver.m_date.isNull() && carryOver.m_date.isValid() && carryOver.m_date == d) {
TimeRange const &carryOverTimeRange = carryOver.m_range;
if (inputTime >= carryOverTimeRange.m_start && inputTime < carryOverTimeRange.m_end) {
// qCritical() << __func__ << ":" << __LINE__ << carryOverTimeRange.m_start.toString(Qt::ISODate);
// qCritical() << __func__ << ":" << __LINE__ << carryOverTimeRange.m_end.toString(Qt::ISODate);
value = value.value_or(carryOver);
break;
}
}
}
} else {
// qCritical() << __func__ << ":" << __LINE__ << "no special day" << dt.date().toString(Qt::ISODate);
for (auto i = carryOverRange.first; i != carryOverRange.second; ++i) {
ATBTariffCarryOver const &carryOver = i->second;
if (carryOver.m_date.isNull() || !carryOver.m_date.isValid()) {
// qCritical() << __func__ << ":" << __LINE__ << "default";
TimeRange const &carryOverTimeRange = carryOver.m_range;
if (inputTime >= carryOverTimeRange.m_start && inputTime < carryOverTimeRange.m_end) {
// qCritical() << __func__ << ":" << __LINE__ << carryOverTimeRange.m_start.toString(Qt::ISODate);
// qCritical() << __func__ << ":" << __LINE__ << carryOverTimeRange.m_end.toString(Qt::ISODate);
value = value.value_or(carryOver);
break;
}
}
}
}
return value;
}
///
/// \brief getService
/// \param cfg
/// \param dt
/// \return
///
std::optional<ATBTariffService> getService(Configuration const *cfg, QDateTime const &dt) {
std::optional<ATBTariffService> value = std::nullopt;
int weekDay = dt.date().dayOfWeek();
// qCritical() << __func__ << ":" << __LINE__ << dt.toString(Qt::ISODate) << weekDay;
ATBTime inputTime(dt.time());
auto const &serviceRange = cfg->TariffServices.equal_range(weekDay);
QDate d; // check if a special date is configured in tariff-file for this day
for (auto i = serviceRange.first; i != serviceRange.second; ++i) {
ATBTariffService const &service = i->second;
if (!service.m_date.isNull() && service.m_date.isValid() && service.m_date == dt.date()) {
d = dt.date();
// qCritical() << __func__ << ":" << __LINE__ << "found special day" << d.toString(Qt::ISODate);
break;
}
}
if (!d.isNull() && d.isValid()) {
for (auto i = serviceRange.first; i != serviceRange.second; ++i) {
ATBTariffService const &service = i->second;
if (!service.m_date.isNull() && service.m_date.isValid() && service.m_date == d) {
TimeRange const &serviceTimeRange = service.m_range;
if (inputTime >= serviceTimeRange.m_start && inputTime < serviceTimeRange.m_end) {
// qCritical() << __func__ << ":" << __LINE__ << serviceTimeRange.m_start.toString(Qt::ISODate);
// qCritical() << __func__ << ":" << __LINE__ << serviceTimeRange.m_end.toString(Qt::ISODate);
value = value.value_or(service);
break;
}
}
}
} else {
// qCritical() << __func__ << ":" << __LINE__ << "no special day" << dt.date().toString(Qt::ISODate);
for (auto i = serviceRange.first; i != serviceRange.second; ++i) {
ATBTariffService const &service = i->second;
if (service.m_date.isNull() || !service.m_date.isValid()) {
// qCritical() << __func__ << ":" << __LINE__ << "default";
TimeRange const &serviceTimeRange = service.m_range;
if (inputTime >= serviceTimeRange.m_start && inputTime < serviceTimeRange.m_end) {
// qCritical() << __func__ << ":" << __LINE__ << serviceTimeRange.m_start.toString(Qt::ISODate);
// qCritical() << __func__ << ":" << __LINE__ << serviceTimeRange.m_end.toString(Qt::ISODate);
value = value.value_or(service);
break;
}
}
}
}
return value;
}
///
/// \brief getOutOfService
/// \param cfg
/// \param dt
/// \return
///
std::optional<ATBTariffOutOfService> getOutOfService(Configuration const *cfg, QDateTime const &dt) {
std::optional<ATBTariffOutOfService> value = std::nullopt;
int weekDay = dt.date().dayOfWeek();
// qCritical() << __func__ << ":" << __LINE__ << dt.toString(Qt::ISODate) << weekDay;
ATBTime inputTime(dt.time());
QDate date;
auto const &outOfServiceRange = cfg->TariffOutOfServices.equal_range(weekDay);
QDate d; // check if a special date is configured in tariff-file for this day
for (auto i = outOfServiceRange.first; i != outOfServiceRange.second; ++i) {
ATBTariffOutOfService const &outOfService = i->second;
if (!outOfService.m_date.isNull() && outOfService.m_date.isValid() && outOfService.m_date == dt.date()) {
d = dt.date();
// qCritical() << __func__ << ":" << __LINE__ << "found special day" << d.toString(Qt::ISODate);
break;
}
}
if (!d.isNull() && d.isValid()) {
for (auto i = outOfServiceRange.first; i != outOfServiceRange.second; ++i) {
ATBTariffOutOfService const &outOfService = i->second;
if (!outOfService.m_date.isNull() && outOfService.m_date.isValid() && outOfService.m_date == d) {
TimeRange const &outOfServiceTimeRange = outOfService.m_range;
if (inputTime >= outOfServiceTimeRange.m_start && inputTime < outOfServiceTimeRange.m_end) {
// qCritical() << __func__ << ":" << __LINE__ << outOfServiceTimeRange.m_start.toString(Qt::ISODate);
// qCritical() << __func__ << ":" << __LINE__ << outOfServiceTimeRange.m_end.toString(Qt::ISODate);
value = value.value_or(outOfService);
break;
}
}
}
} else {
// qCritical() << __func__ << ":" << __LINE__ << "no special day" << dt.date().toString(Qt::ISODate);
for (auto i = outOfServiceRange.first; i != outOfServiceRange.second; ++i) {
ATBTariffOutOfService const &outOfService = i->second;
if (outOfService.m_date.isNull() || !outOfService.m_date.isValid()) {
// qCritical() << __func__ << ":" << __LINE__ << "default";
TimeRange const &outOfServiceTimeRange = outOfService.m_range;
if (inputTime >= outOfServiceTimeRange.m_start && inputTime < outOfServiceTimeRange.m_end) {
// qCritical() << __func__ << ":" << __LINE__ << outOfServiceTimeRange.m_start.toString(Qt::ISODate);
// qCritical() << __func__ << ":" << __LINE__ << outOfServiceTimeRange.m_end.toString(Qt::ISODate);
value = value.value_or(outOfService);
break;
}
}
}
}
return value;
}
std::pair<CalcState, QDateTime>
Calculator::ComputeDurationFromCost(Configuration *cfg,
QDateTime const &startDatetimePassed, // given in local time
int cost) {
QDateTime inputDate = startDatetimePassed;
inputDate.setTime(QTime(inputDate.time().hour(), inputDate.time().minute(), 0));
// TODO:
int paymentOptionIndex = 0;
bool overPaid = false;
bool successMaxPrice = false;
int const pop_id = cfg->getPaymentOptions(paymentOptionIndex).pop_id;
int const pop_accumulate_prices = cfg->getPaymentOptions(paymentOptionIndex).pop_accumulate_prices;
int const pop_max_price = cfg->getPaymentOptions(paymentOptionIndex).pop_max_price =
cfg->getPaymentOptions(paymentOptionIndex).pop_max_price_save;
int const pop_max_time = cfg->getPaymentOptions(paymentOptionIndex).pop_max_time;
int const pop_min_price = cfg->getPaymentOptions(paymentOptionIndex).pop_min_price;
int const pop_allow_overpay = cfg->getPaymentOptions(paymentOptionIndex).pop_allow_overpay;
int price = 0;
int durationId = 0;
int netto_parking_time_in_minutes = 0;
int brutto_parking_time_in_minutes = 0;
int free_parking_time_in_minutes = 0;
QMap<int, int> nettoParktimePrice;
QMap<int, int> priceNettoParktime;
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr) {
durationId = itr->second.pra_payment_unit_id;
int const pra_price = itr->second.pra_price;
if (pop_accumulate_prices) {
price += pra_price;
} else {
price = pra_price;
}
//if ((double)price == cost) {
auto search = cfg->Duration.find(durationId);
if (search != cfg->Duration.end()) {
// found now the duration in minutes
// check if we are still inside the working-time-range
ATBDuration duration = search->second;
nettoParktimePrice.insert(duration.pun_duration, price);
priceNettoParktime.insert(price, duration.pun_duration);
}
//}
}
// qCritical() << __func__ << ":" << __LINE__ << nettoParktimePrice;
// qCritical() << __func__ << ":" << __LINE__ << priceNettoParktime;
if (cost == pop_max_price) {
qCritical() << DBG_HEADER << "SUCCESS MAX-PARKING-PRICE" << pop_max_price << ", COST" << cost;
successMaxPrice = true;
}
if (cost > pop_max_price) {
qCritical() << DBG_HEADER << "MAX-PARKING-PRICE" << pop_max_price << ", COST" << cost;
if (pop_allow_overpay == false) {
return std::make_pair(CalcState(CalcState::State::OVERPAID), QDateTime());
}
cost = pop_max_price;
overPaid = true;
qCritical() << DBG_HEADER << "OVERPAID, MAX-PARKING-PRICE" << pop_max_price << ", COST" << cost;
// return CalcState::OVERPAID.toStdString();
}
if (cost < pop_min_price) {
qCritical() << DBG_HEADER << "MIN-PARKING-PRICE" << pop_min_price << ", COST" << cost;
return std::make_pair(CalcState(CalcState::State::BELOW_MIN_PARKING_PRICE), QDateTime());
}
int weekDay = inputDate.date().dayOfWeek();
qCritical() << __func__ << ":" << __LINE__ << "START weekDay" << weekDay << inputDate.toString(Qt::ISODate);
qCritical() << __func__ << ":" << __LINE__ << "START cost" << cost;
QDateTime dt;
bool computationStarted = false;
price = 0;
netto_parking_time_in_minutes = 0;
brutto_parking_time_in_minutes = 0;
free_parking_time_in_minutes = 0;
int nettoParktimeForCost = 0;
if (priceNettoParktime.contains(int(cost))) {
nettoParktimeForCost = priceNettoParktime[int(cost)];
qCritical() << __func__ << ":" << __LINE__ << QString("cost=%1 nettoParkTimeForCost=%2").
arg(cost).arg(nettoParktimeForCost);
} else {
// cannot find netto-parking time for cost (=price)
// this happens for direct coin input and should not happen otherwise
// take the value for the nearest value of cost and mark result as overpaid
QList <int> keys = priceNettoParktime.keys(); // keys (=prices) are sorted in ascending order
QSet<int> s; // make keys unique
for (int k = 0; k < keys.size(); ++k) {
if (keys[k] < cost) {
s << keys[k];
}
}
keys = s.values();
// sort in descending order
std::sort(std::begin(keys), std::end(keys), std::greater<>());
// qCritical() << __func__ << ":" << __LINE__ << "keys=" << keys;
if (!keys.isEmpty()) {
int const maxCost = keys[0];
auto const p = priceNettoParktime.equal_range(maxCost);
for (auto it = p.first; it != p.second; ++it) {
nettoParktimeForCost = std::max(nettoParktimeForCost, it.value());
}
ATBPaymentOption &po = cfg->getPaymentOptions(paymentOptionIndex);
po.pop_max_price = maxCost;
cfg->getPaymentOptions(paymentOptionIndex).pop_max_price = maxCost;
if (pop_allow_overpay) {
overPaid = true;
}
qCritical() << __func__ << ":" << __LINE__ << QString("cost=%1 -> maxCost=%2 nettoParkTimeForCost=%3").
arg(cost).arg(maxCost).arg(nettoParktimeForCost);
} else {
qCritical() << __func__ << ":" << __LINE__ << "ERROR empty keys -> check tariff file";
}
}
int cnt = 0;
while (++cnt < 20 && netto_parking_time_in_minutes < nettoParktimeForCost) {
// qCritical() << __func__ << ":" << __LINE__ << "cnt [" << cnt;
brutto_parking_time_in_minutes = free_parking_time_in_minutes + netto_parking_time_in_minutes;
dt = inputDate.addSecs(brutto_parking_time_in_minutes * 60);
weekDay = dt.date().dayOfWeek();
qCritical() << __func__ << ":" << __LINE__ << QString("%1 (%2): brutto: %3 = netto: %4 + free: %5")
.arg(dt.toString(Qt::ISODate))
.arg(weekDay)
.arg(brutto_parking_time_in_minutes)
.arg(netto_parking_time_in_minutes)
.arg(free_parking_time_in_minutes);
if (std::optional<ATBTariffOutOfService> oos = getOutOfService(cfg, dt)) {
dt.setTime(QTime(oos.value().m_range.m_start.hour(),
oos.value().m_range.m_start.minute(), 0));
if (overPaid) {
QList <int> keys = nettoParktimePrice.keys();
for (int k = 0; k < keys.size(); ++k) {
if (keys[k] < netto_parking_time_in_minutes) {
continue;
}
int const maxPriceForTimeLimit = nettoParktimePrice[keys[k]];
if (cost > maxPriceForTimeLimit) {
cfg->getPaymentOptions(paymentOptionIndex).pop_max_price = maxPriceForTimeLimit;
CalcState cs(CalcState::State::OVERPAID);
return std::make_pair(cs, dt);
}
if (cost == maxPriceForTimeLimit) {
cfg->getPaymentOptions(paymentOptionIndex).pop_max_price = maxPriceForTimeLimit;
CalcState cs(CalcState::State::SUCCESS_MAXPRICE);
return std::make_pair(cs, dt);
}
}
return std::make_pair(CalcState(CalcState::State::OVERPAID), dt);
}
qCritical() << __func__ << ":" << __LINE__ << "set time-limit reached";
qCritical() << __func__ << ":" << __LINE__ << "netto-parking-time" << netto_parking_time_in_minutes;
Calculator::GetInstance().setTimeLimitReached(true);
QList <int> keys = nettoParktimePrice.keys();
for (int k = 0; k < keys.size(); ++k) {
if (keys[k] < netto_parking_time_in_minutes) {
continue;
}
int const maxPriceForTimeLimit = nettoParktimePrice[keys[k]];
qCritical() << __func__ << ":" << __LINE__ << keys[k] << maxPriceForTimeLimit << cost;
// Calculator::GetInstance().setCostAtTimeLimit(nettoParktimePrice[keys[k]]);
if (cost > maxPriceForTimeLimit) {
cfg->getPaymentOptions(paymentOptionIndex).pop_max_price = maxPriceForTimeLimit;
CalcState cs(CalcState::State::OVERPAID);
return std::make_pair(cs, dt);
}
if (cost == maxPriceForTimeLimit) {
cfg->getPaymentOptions(paymentOptionIndex).pop_max_price = maxPriceForTimeLimit;
CalcState cs(CalcState::State::SUCCESS_MAXPRICE);
return std::make_pair(cs, dt);
}
qCritical() << __func__ << ":" << __LINE__ << "DT" << dt.toString(Qt::ISODate);
return std::make_pair(CalcState(CalcState::State::SUCCESS), dt);
}
qCritical() << __func__ << ":" << __LINE__ << "outside allowed parking time" << dt.toString(Qt::ISODate);
return std::make_pair(CalcState(CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME,
CalcState::OUTSIDE_ALLOWED_PARKING_TIME), dt);
}
if (computationStarted == false) {
computationStarted = true;
if (std::optional<ATBTariffPrepaid> pp = getPrepaid(cfg, dt)) {
TimeRange const &prepaidTimeRange = pp.value().m_range;
ATBTime t(dt.time().hour(), dt.time().minute(), 0, 0);
free_parking_time_in_minutes += t.secsTo(prepaidTimeRange.m_end.toString(Qt::ISODate)) / 60;
}
}
brutto_parking_time_in_minutes = free_parking_time_in_minutes + netto_parking_time_in_minutes;
dt = inputDate.addSecs(brutto_parking_time_in_minutes * 60);
weekDay = dt.date().dayOfWeek();
qCritical() << __func__ << ":" << __LINE__ << QString("%1 (%2): brutto: %3 = netto: %4 + free: %5")
.arg(dt.toString(Qt::ISODate))
.arg(weekDay)
.arg(brutto_parking_time_in_minutes)
.arg(netto_parking_time_in_minutes)
.arg(free_parking_time_in_minutes);
if (std::optional<ATBTariffCarryOver> co = getCarryOver(cfg, dt)) {
int minutes = co.value().computeMinutesUntilCarryOverEnd(dt);
if (minutes > 0) {
free_parking_time_in_minutes += minutes;
brutto_parking_time_in_minutes = free_parking_time_in_minutes + netto_parking_time_in_minutes;
dt = inputDate.addSecs(brutto_parking_time_in_minutes * 60);
weekDay = dt.date().dayOfWeek();
qCritical() << __func__ << ":" << __LINE__ << QString("%1 (%2): brutto: %3 = netto: %4 + free: %5")
.arg(dt.toString(Qt::ISODate))
.arg(weekDay)
.arg(brutto_parking_time_in_minutes)
.arg(netto_parking_time_in_minutes)
.arg(free_parking_time_in_minutes);
}
}
if (std::optional<ATBTariffService> serv = getService(cfg, dt)) {
TimeRange const &serviceTimeRange = serv.value().m_range;
if (nettoParktimeForCost > netto_parking_time_in_minutes) {
int rest_parking_time_in_minutes = nettoParktimeForCost - netto_parking_time_in_minutes;
ATBTime t(dt.time().hour(), dt.time().minute(), 0, 0);
int timeToServiceEnd = t.secsTo(serviceTimeRange.m_end.toString(Qt::ISODate)) / 60;
// TODO: wohl aehnlich wie carry-over zu behandlen
if (serviceTimeRange.m_duration > 0) {
if (timeToServiceEnd < rest_parking_time_in_minutes) {
netto_parking_time_in_minutes += timeToServiceEnd;
} else {
netto_parking_time_in_minutes += rest_parking_time_in_minutes;
}
}
}
}
brutto_parking_time_in_minutes = free_parking_time_in_minutes + netto_parking_time_in_minutes;
dt = inputDate.addSecs(brutto_parking_time_in_minutes * 60);
weekDay = dt.date().dayOfWeek();
qCritical() << __func__ << ":" << __LINE__ << QString("%1 (%2): brutto: %3 = netto: %4 + free: %5")
.arg(dt.toString(Qt::ISODate))
.arg(weekDay)
.arg(brutto_parking_time_in_minutes)
.arg(netto_parking_time_in_minutes)
.arg(free_parking_time_in_minutes);
// qCritical() << __func__ << ":" << __LINE__ << "cnt" << cnt << "]";
}
if (cnt >= 10) {
qCritical() << __func__ << ":" << __LINE__ << "BREAK";
}
// configure if last carry-over ranges shall be added to ticket-end-time
dt = inputDate.addSecs(brutto_parking_time_in_minutes * 60);
cnt = 0;
QVector<TimeRange> timeRanges;
while (std::optional<ATBTariffCarryOver> co = getCarryOver(cfg, dt)) {
if (++cnt > 10) {
break;
}
TimeRange const &carryOverTimeRange = co.value().m_range;
if (!timeRanges.isEmpty()) {
if (timeRanges.last().m_end != carryOverTimeRange.m_start) {
break;
}
}
timeRanges.push_back(carryOverTimeRange);
int minutes = co.value().computeMinutesUntilCarryOverEnd(dt);
if (minutes > 0) {
free_parking_time_in_minutes += co.value().computeMinutesUntilCarryOverEnd(dt);
brutto_parking_time_in_minutes = free_parking_time_in_minutes + netto_parking_time_in_minutes;
qCritical() << __func__ << ":" << __LINE__ << QString("%1 (%2): brutto: %3 = netto: %4 + free: %5")
.arg(dt.toString(Qt::ISODate))
.arg(weekDay)
.arg(brutto_parking_time_in_minutes)
.arg(netto_parking_time_in_minutes)
.arg(free_parking_time_in_minutes);
dt = inputDate.addSecs(brutto_parking_time_in_minutes * 60);
} else break;
}
brutto_parking_time_in_minutes = free_parking_time_in_minutes + netto_parking_time_in_minutes;
dt = inputDate.addSecs(brutto_parking_time_in_minutes * 60);
weekDay = dt.date().dayOfWeek();
qCritical() << __func__ << ":" << __LINE__ << QString("ticket-end-time %1 (%2): brutto: %3 = netto: %4 + free: %5")
.arg(dt.toString(Qt::ISODate))
.arg(weekDay)
.arg(brutto_parking_time_in_minutes)
.arg(netto_parking_time_in_minutes)
.arg(free_parking_time_in_minutes);
if (successMaxPrice) {
qCritical() << __func__ << ":" << __LINE__ << "SUCC" << dt;
return std::make_pair(CalcState(CalcState::State::SUCCESS_MAXPRICE), dt);
}
if (overPaid) {
qCritical() << __func__ << ":" << __LINE__ << "OVER" << dt;
return std::make_pair(CalcState(CalcState::State::OVERPAID), dt);
}
qCritical() << __func__ << ":" << __LINE__ << "DT" << dt.toString(Qt::ISODate);
return std::make_pair(CalcState(CalcState::State::SUCCESS), dt);
}
std::pair<CalcState, std::optional<int>>
Calculator::ComputeCostFromDuration(Configuration *cfg, QDateTime const &startDatetime,
QDateTime &endDatetime, int nettoParkingTime) {
// TODO
int paymentOptionIndex = 0;
std::optional<int> cost{};
int const pop_id = cfg->getPaymentOptions(paymentOptionIndex).pop_id;
int const pop_accumulate_prices = cfg->getPaymentOptions(paymentOptionIndex).pop_accumulate_prices;
int price = 0;
int durationId = 0;
int netto_parking_time_in_minutes = 0;
int brutto_parking_time_in_minutes = 0;
int free_parking_time_in_minutes = 0;
QMap<int, int> nettoParktimePrice;
QMap<int, int> priceNettoParktime;
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr) {
durationId = itr->second.pra_payment_unit_id;
int const pra_price = itr->second.pra_price;
if (pop_accumulate_prices) {
price += pra_price;
} else {
price = pra_price;
}
auto search = cfg->Duration.find(durationId);
if (search != cfg->Duration.end()) {
// found now the duration in minutes
// check if we are still inside the working-time-range
ATBDuration duration = search->second;
nettoParktimePrice.insert(duration.pun_duration, price);
priceNettoParktime.insert(price, duration.pun_duration);
}
}
qCritical() << __func__ << ":" << __LINE__ << "START netto-parking-time" << nettoParkingTime;
CalcState returnState;
QList<int> keys = nettoParktimePrice.keys();
qCritical() << __func__ << ":" << __LINE__ << "Times Keys" << keys;
qCritical() << __func__ << ":" << __LINE__ << "Prices Keys" << priceNettoParktime.keys();
int index = keys.indexOf(nettoParkingTime);
if (index != -1) {
int c = nettoParktimePrice[keys.at(index)];
qCritical() << __func__ << ":" << __LINE__ << "cost for netto-parking-time" << c;
std::pair<CalcState, QDateTime> r = ComputeDurationFromCost(cfg, startDatetime, c);
qCritical() << __func__ << ":" << __LINE__ << "result"
<< r.first.toString() << r.second.toString(Qt::ISODate);
returnState = r.first;
endDatetime = r.second;
if (returnState.getStatus() == CalcState::State::SUCCESS ||
returnState.getStatus() == CalcState::State::SUCCESS_MAXPRICE ||
returnState.getStatus() == CalcState::State::OVERPAID) {
qCritical() << __func__ << ":" << __LINE__ << "--- endDateTime" << endDatetime.toString(Qt::ISODate);
qCritical() << __func__ << ":" << __LINE__ << "------ r.second" << r.second.toString(Qt::ISODate);
qCritical() << __func__ << ":" << __LINE__ << "status" << returnState.toString() << (int)returnState.getStatus();
if (!endDatetime.isNull() && endDatetime.isValid()) {
cost = c;
}
}
}
if (cost) {
qCritical() << __func__ << ":" << __LINE__ << "--- return cost" << cost.value();
return std::make_pair(returnState, cost);
}
qCritical() << __func__ << ":" << __LINE__ << "--- return error for cost" << returnState.toString();
return std::make_pair(returnState, cost);
}
/// <inheritdoc/>
std::pair<std::string, QDateTime>
Calculator::GetDurationFromCost(Configuration* cfg,
@@ -136,6 +809,7 @@ Calculator::GetDurationFromCost(Configuration* cfg,
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
bool overPaid = false;
bool successMaxPrice = false; // max-price and cost match
int paymentOptionIndex = getPaymentOptionIndex(*cfg, inputDate);
if (paymentOptionIndex == -1) {
@@ -252,6 +926,17 @@ Calculator::GetDurationFromCost(Configuration* cfg,
qCritical() << DBG_HEADER << " TODO";
}
} else
if (paymentMethodId == PaymentMethod::Unified) {
std::pair<CalcState, QDateTime> r =
ComputeDurationFromCost(cfg, QDateTime::fromString(startDatetimePassed, Qt::ISODate), cost);
CalcState cs = r.first;
qCritical() << __func__ << ":" << __LINE__ << cs.toString();
qCritical() << __func__ << ":" << __LINE__ << r.second.toString(Qt::ISODate);
return std::make_pair(r.first.toString().toStdString(), r.second);
} else
if (paymentMethodId == PaymentMethod::Steps) {
if (tariffIs24_7(cfg)) {
// use tariff with structure as for instance Schoenau, Koenigsee:
@@ -269,9 +954,18 @@ Calculator::GetDurationFromCost(Configuration* cfg,
}
int const pop_id = cfg->getPaymentOptions(paymentOptionIndex).pop_id;
int const pop_max_price = cfg->getPaymentOptions(paymentOptionIndex).pop_max_price;
int const pop_max_price = cfg->getPaymentOptions(paymentOptionIndex).pop_max_price
= cfg->getPaymentOptions(paymentOptionIndex).pop_max_price_save;
//int const pop_max_time = cfg->getPaymentOptions(paymentOptionIndex).pop_max_time;
int const pop_min_price = cfg->getPaymentOptions(paymentOptionIndex).pop_min_price;
int const pop_allow_overpay = cfg->getPaymentOptions(paymentOptionIndex).pop_allow_overpay;
int const pop_accumulate_prices = cfg->getPaymentOptions(paymentOptionIndex).pop_accumulate_prices;
int price = 0;
if (cost == pop_max_price) {
qCritical() << DBG_HEADER << "SUCCESS MAX-PARKING-PRICE" << pop_max_price << ", COST" << cost;
successMaxPrice = true;
}
if (cost > pop_max_price) {
qCritical() << DBG_HEADER << "MAX-PARKING-PRICE" << pop_max_price << ", COST" << cost;
@@ -280,6 +974,7 @@ Calculator::GetDurationFromCost(Configuration* cfg,
}
cost = pop_max_price;
overPaid = true;
qCritical() << DBG_HEADER << "OVERPAID, MAX-PARKING-PRICE" << pop_max_price << ", COST" << cost;
// return CalcState::OVERPAID.toStdString();
}
@@ -403,9 +1098,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
qCritical() << DBG_HEADER << " CURRENT WORKING-TIME-TO" << current_working_time_to.toString(Qt::ISODate);
#endif
int const pop_accumulate_prices = cfg->getPaymentOptions(paymentOptionIndex).pop_accumulate_prices;
// int const pop_accumulate_prices = cfg->getPaymentOptions(paymentOptionIndex).pop_accumulate_prices;
// int const pop_accumulate_durations = cfg->getPaymentOptions(paymentOptionIndex).pop_accumulate_durations;
int price = 0;
// int price = 0;
int new_price = 0;
int durationInSecs = 0;
uint32_t duration_previous = 0;
@@ -447,6 +1142,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
if (overPaid) {
return std::make_pair(CalcState::OVERPAID.toStdString(), d);
}
if (successMaxPrice) {
return std::make_pair(CalcState::SUCCESS_MAXPRICE.toStdString(), d);
}
return std::make_pair(d.toString(Qt::ISODate).toStdString(), d);
}
} else {
@@ -523,6 +1221,16 @@ Calculator::GetDurationFromCost(Configuration* cfg,
//qCritical() << DBG_HEADER << "NEW INPUT" << inputDate.toString(Qt::ISODate);
int const pop_carry_over = cfg->getPaymentOptions(paymentOptionIndex).pop_carry_over;
if (pop_carry_over) {
int weekDay = inputDate.date().dayOfWeek();
int const pop_carry_over_option_id = cfg->getPaymentOptions(paymentOptionIndex).pop_carry_over_option_id;
if (pop_carry_over_option_id != -1) {
int const carryOverDuration = cfg->TariffCarryOverOptions.find(pop_carry_over_option_id)->second.carryover[weekDay].duration;
inputDate = inputDate.addSecs(carryOverDuration * 60);
}
}
inputDate = inputDate.addSecs(durationInSecs);
#if DEBUG_GET_DURATION_FROM_COST==1
qCritical() << DBG_HEADER << "TICKET-END" << inputDate.toString(Qt::ISODate);
@@ -561,6 +1269,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
if (overPaid) {
return std::make_pair(CalcState::OVERPAID.toStdString(), inputDate);
}
if (successMaxPrice) {
return std::make_pair(CalcState::SUCCESS_MAXPRICE.toStdString(), inputDate);
}
return std::make_pair(s.toStdString(), inputDate);
} // if ((double)price == cost) {
else {
@@ -648,6 +1359,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
if (overPaid) {
return std::make_pair(CalcState::OVERPAID.toStdString(), end_datetime);
}
if (successMaxPrice) {
return std::make_pair(CalcState::SUCCESS_MAXPRICE.toStdString(), end_datetime);
}
return std::make_pair(end_datetime.toString(Qt::ISODate).toStdString(), end_datetime);
} else {
QDateTime const dt = start;
@@ -698,6 +1412,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
if (overPaid) {
return std::make_pair(CalcState::OVERPAID.toStdString(), end_datetime);
}
if (successMaxPrice) {
return std::make_pair(CalcState::SUCCESS_MAXPRICE.toStdString(), end_datetime);
}
return std::make_pair(end_datetime.toString(Qt::ISODate).toStdString(), end_datetime);
}
@@ -796,6 +1513,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
if (overPaid) {
return std::make_pair(CalcState::OVERPAID.toStdString(), end_datetime);
}
if (successMaxPrice) {
return std::make_pair(CalcState::SUCCESS_MAXPRICE.toStdString(), end_datetime);
}
return std::make_pair(end_datetime.toString(Qt::ISODate).toStdString(), end_datetime);
}
}
@@ -840,6 +1560,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
if (overPaid) {
return std::make_pair(CalcState::OVERPAID.toStdString(), end_datetime);
}
if (successMaxPrice) {
return std::make_pair(CalcState::SUCCESS_MAXPRICE.toStdString(), end_datetime);
}
return std::make_pair(end_datetime.toString(Qt::ISODate).toStdString(), end_datetime);
}
@@ -874,6 +1597,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
if (overPaid) {
return std::make_pair(CalcState::OVERPAID.toStdString(), end_datetime);
}
if (successMaxPrice) {
return std::make_pair(CalcState::SUCCESS_MAXPRICE.toStdString(), end_datetime);
}
return std::make_pair(end_datetime.toString(Qt::ISODate).toStdString(), end_datetime);
}
@@ -993,6 +1719,9 @@ Calculator::GetDurationFromCost(Configuration* cfg,
if (overPaid) {
return std::make_pair(CalcState::OVERPAID.toStdString(), end_datetime);
}
if (successMaxPrice) {
return std::make_pair(CalcState::SUCCESS_MAXPRICE.toStdString(), end_datetime);
}
return std::make_pair(end_datetime.toString(Qt::ISODate).toStdString(), end_datetime);
}
}
@@ -1162,7 +1891,7 @@ CalcState Calculator::isParkingAllowedForWeekDay(Configuration const *cfg,
(int)cfg->TimeRange.count(pop_carry_over_end_time_range) <= 0) {
qCritical() << DBG_HEADER << "PARKING_ALLOWED. startTime" << startTime.toString(Qt::ISODate);
return CalcState(CalcState::State::SUCCESS, "PARKING_ALLOWED", startTime);
return CalcState(CalcState::State::SUCCESS, "PARKING_ALLOWED", startTime, QTime());
} else
// search entry in time-range-field of tariff-file
@@ -2898,7 +3627,9 @@ uint32_t Calculator::GetPriceForTimeStep(Configuration *cfg, int timeStep, int p
qCritical() << "(" << __func__ << ":" << __LINE__ << ") timeStep" << timeStep;
}
if (timeStep == pun_duration) {
// allow some tolerance when searching for [timeStep == pun_duration]:
// this might happen when crossing minute boundaries
if (std::abs(timeStep - pun_duration) < 4) {
qCritical() << "(" << __func__ << ":" << __LINE__ << ") return price" << price;
return price;
}
@@ -2969,6 +3700,9 @@ Calculator::GetDailyTicketPrice(Configuration* cfg,
if (dailyTickets) {
QVector<ATBDailyTicket> const tickets = dailyTickets.value();
switch (permitType) {
case PERMIT_TYPE::FREE_TICKET: {
// TODO
} break;
case PERMIT_TYPE::TWENTY_FOUR_HOURS_TICKET: {
// TODO
} break;
@@ -3056,6 +3790,10 @@ Calculator::GetDailyTicketPrice(Configuration* cfg,
// [[fallthrough]];
case PERMIT_TYPE::SHORT_TERM_PARKING: {
}
case PERMIT_TYPE::TEST_PRODUCT_1: {
}
case PERMIT_TYPE::TEST_PRODUCT_2: {
}
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET: {
} break;

View File

@@ -10,10 +10,15 @@
#include "tariff_global_defines.h"
#include "tariff_settings.h"
#include "tariff_carryover_settings.h"
#include "atb_time.h"
#include "tariff_prepaid.h"
#include "tariff_carryover.h"
#include <QString>
#include <QDebug>
#include <QRegularExpression>
#include <QPair>
#include <QList>
/// <inheritdoc/>
MemberType Configuration::IdentifyJsonMember(const char* member_name)
@@ -43,6 +48,7 @@ MemberType Configuration::IdentifyJsonMember(const char* member_name)
if (strcmp(member_name, "Interpolation") == 0) return MemberType::InterpolationType;
if (strcmp(member_name, "Prepaid") == 0) return MemberType::PrepaidType;
if (strcmp(member_name, "CarryOver") == 0) return MemberType::CarryOverType;
if (strcmp(member_name, "Includes") == 0) return MemberType::IncludesType;
else return MemberType::UnknownType;
}
@@ -61,6 +67,414 @@ ATBWeekDay parseWeekDay(Configuration &cfg,
ATBWeekDay WeekDay;
QTime start, end, parking_time_limit, about_to_exceed_limit;
ATBTariffCarryOverSettings::ParkingTimeLimitChecker parkTimeLimitChecker;
QDate const &d = QDate::fromString(innerObjName, Qt::ISODate);
if (innerObjName == QString("default") ||
(!d.isNull() && d.isValid())) { // special day, given in date-format
// start with new implementation of tariff-calculator
// see for instance: bad neuenahr (249), Zone5
qCritical() << __func__ << ":" << __LINE__ << innerObjName;
if (k->value.IsObject()) {
auto obj = k->value.GetObject();
for (auto m = obj.MemberBegin(); m != obj.MemberEnd(); ++m) {
QString const &name = m->name.GetString();
if (name == "payment_settings") {
if (m->value.IsArray()) {
auto payment = m->value.GetArray();
if (payment.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no payment settings for" << weekDayName;
} else {
for (rapidjson::SizeType j = 0; j < payment.Size(); ++j) {
if (payment[j].IsObject()) {
auto paymentSetting = payment[j].GetObject();
for (auto n = paymentSetting.MemberBegin(); n != paymentSetting.MemberEnd(); ++n) {
QString const &name = QString::fromStdString(n->name.GetString());
if (name == "min_time") {
if (n->value.IsInt()) { min_time = n->value.GetInt(); }
} else if (name == "max_time") {
if (n->value.IsInt()) { max_time = n->value.GetInt(); }
} else if (name == "min_price") {
if (n->value.IsInt()) { min_price = n->value.GetInt(); }
} else if (name == "max_price") {
if (n->value.IsInt()) { max_price = n->value.GetInt(); }
}
}
}
}
}
}
} else
if (name == "prepaid_settings") {
if (m->value.IsArray()) {
auto prepaid = m->value.GetArray();
if (prepaid.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no prepaid-settings for" << weekDayName;
} else {
ATBTariffPrepaid TariffPrepaid;
for (rapidjson::SizeType j = 0; j < prepaid.Size(); ++j) {
if (prepaid[j].IsObject()) {
auto prepaidSetting = prepaid[j].GetObject();
for (auto n = prepaidSetting.MemberBegin(); n != prepaidSetting.MemberEnd(); ++n) {
QString const &name = QString::fromStdString(n->name.GetString());
if (name == "prepaid_ranges") {
if (n->value.IsArray()) {
auto prepaidRanges = n->value.GetArray();
if (prepaidRanges.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no prepaid-ranges for" << weekDayName;
} else {
QString prepaidStartStr;
QString prepaidEndStr;
QString prepaidIf;
int prepaidDuration = -1;
for (rapidjson::SizeType i = 0; i < prepaidRanges.Size(); ++i) {
if (prepaidRanges[j].IsObject()) {
auto prepaidRange = prepaidRanges[i].GetObject();
for (auto r = prepaidRange.MemberBegin(); r != prepaidRange.MemberEnd(); ++r) {
QString const &memName = QString::fromStdString(r->name.GetString());
if (memName == "prepaid_id") {
if (r->value.IsInt()) {
TariffPrepaid.m_id = r->value.GetInt();
} else {
qCritical() << __func__ << ":" << __LINE__ << "prepaidId not an integer";
}
} else
if (memName == "prepaid_duration") {
if (r->value.IsInt()) {
prepaidDuration = r->value.GetInt();
}
} else
if (memName == "prepaid_start") {
if (r->value.IsString()) {
prepaidStartStr = QString::fromStdString(r->value.GetString());
}
} else
if (memName == "prepaid_end") {
if (r->value.IsString()) {
prepaidEndStr = QString::fromStdString(r->value.GetString());
}
} else
if (memName == "prepaid_if") {
if (r->value.IsString()) {
prepaidIf = QString::fromStdString(r->value.GetString());
}
} else {
qCritical() << __func__ << ":" << __LINE__ << "WARNING unknown prepaid setting" << memName;
}
}
}
if (!prepaidStartStr.isEmpty() && !prepaidEndStr.isEmpty() && prepaidDuration != -1) {
ATBTime prepaidStart(prepaidStartStr);
ATBTime prepaidEnd(prepaidEndStr);
if (prepaidStart.isValid() && prepaidEnd.isValid()) {
TariffPrepaid.m_range = TimeRange(prepaidStart, prepaidEnd, prepaidDuration);
TariffPrepaid.m_weekDay = weekDayName;
if (!d.isNull() && d.isValid()) {
TariffPrepaid.m_date = d;
}
if (!prepaidIf.isNull() && !prepaidIf.trimmed().isEmpty()) {
TariffPrepaid.setPrepaidIf(prepaidIf);
}
qCritical() << TariffPrepaid;
cfg.TariffPrepaids.insert(std::pair<int, ATBTariffPrepaid>(weekDay, TariffPrepaid));
}
}
}
}
}
} else {
}
}
}
}
}
}
} else
if (name == "carry_over_settings") {
if (m->value.IsArray()) {
auto carryOver = m->value.GetArray();
if (carryOver.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no carry-over-settings for" << weekDayName;
} else {
ATBTariffCarryOver TariffCarryOver;
for (rapidjson::SizeType j = 0; j < carryOver.Size(); ++j) {
if (carryOver[j].IsObject()) {
auto carryOverSetting = carryOver[j].GetObject();
for (auto n = carryOverSetting.MemberBegin(); n != carryOverSetting.MemberEnd(); ++n) {
QString const &name = QString::fromStdString(n->name.GetString());
if (name == "carry_over_ranges") {
if (n->value.IsArray()) {
auto carryOverRanges = n->value.GetArray();
if (carryOverRanges.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no carry-over-ranges for" << weekDayName;
} else {
QString carryOverStartStr;
QString carryOverEndStr;
QString carryOverIf;
int carryOverDuration = -1;
for (rapidjson::SizeType i = 0; i < carryOverRanges.Size(); ++i) {
if (carryOverRanges[j].IsObject()) {
auto carryOverRange = carryOverRanges[i].GetObject();
for (auto r = carryOverRange.MemberBegin(); r != carryOverRange.MemberEnd(); ++r) {
QString const &memName = QString::fromStdString(r->name.GetString());
if (memName == "carry_over_id") {
if (r->value.IsInt()) {
TariffCarryOver.m_id = r->value.GetInt();
} else {
qCritical() << __func__ << ":" << __LINE__ << "carryOverId not an integer";
}
} else
if (memName == "carry_over_duration") {
if (r->value.IsInt()) {
carryOverDuration = r->value.GetInt();
}
} else
if (memName == "carry_over_start") {
if (r->value.IsString()) {
carryOverStartStr = QString::fromStdString(r->value.GetString());
}
} else
if (memName == "carry_over_end") {
if (r->value.IsString()) {
carryOverEndStr = QString::fromStdString(r->value.GetString());
}
} else
if (memName == "carry_over_if") {
if (r->value.IsString()) {
carryOverIf = QString::fromStdString(r->value.GetString());
}
} else {
qCritical() << __func__ << ":" << __LINE__ << "WARNING unknown carry-over setting" << memName;
}
}
}
if (!carryOverStartStr.isEmpty() && !carryOverEndStr.isEmpty() && carryOverDuration != -1) {
ATBTime carryOverStart(carryOverStartStr);
ATBTime carryOverEnd(carryOverEndStr);
if (carryOverStart.isValid() && carryOverEnd.isValid()) {
TariffCarryOver.m_range = TimeRange(carryOverStart, carryOverEnd, carryOverDuration);
TariffCarryOver.m_weekDay = weekDayName;
if (!d.isNull() && d.isValid()) {
TariffCarryOver.m_date = d;
}
if (!carryOverIf.isNull() && !carryOverIf.trimmed().isEmpty()) {
TariffCarryOver.setCarryOverIf(carryOverIf);
}
// qCritical() << TariffCarryOver;
cfg.TariffCarryOvers.insert(std::pair<int, ATBTariffCarryOver>(weekDay, TariffCarryOver));
}
}
}
}
}
} else {
}
}
}
}
}
}
} else
if (name == "service_settings") {
ATBTariffService TariffService;
if (m->value.IsArray()) {
auto service = m->value.GetArray();
if (service.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no service settings for" << weekDayName;
} else {
for (rapidjson::SizeType j = 0; j < service.Size(); ++j) {
if (service[j].IsObject()) {
auto serviceSetting = service[j].GetObject();
for (auto n = serviceSetting.MemberBegin(); n != serviceSetting.MemberEnd(); ++n) {
QString const &name = QString::fromStdString(n->name.GetString());
if (name == "service_ranges") {
if (n->value.IsArray()) {
auto serviceRanges = n->value.GetArray();
if (serviceRanges.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no service ranges for" << weekDayName;
} else {
QString serviceStartStr;
QString serviceEndStr;
QString serviceIf;
int serviceDuration = -1;
for (rapidjson::SizeType i = 0; i < serviceRanges.Size(); ++i) {
if (serviceRanges[j].IsObject()) {
auto serviceRange = serviceRanges[i].GetObject();
for (auto r = serviceRange.MemberBegin(); r != serviceRange.MemberEnd(); ++r) {
QString const &memName = QString::fromStdString(r->name.GetString());
if (memName == "service_id") {
if (r->value.IsInt()) {
TariffService.m_id = r->value.GetInt();
} else {
qCritical() << __func__ << ":" << __LINE__ << "serviceId not an integer";
}
} else
if (memName == "service_duration") {
if (r->value.IsInt()) {
serviceDuration = r->value.GetInt();
}
} else
if (memName == "service_start") {
if (r->value.IsString()) {
serviceStartStr = QString::fromStdString(r->value.GetString());
}
} else
if (memName == "service_end") {
if (r->value.IsString()) {
serviceEndStr = QString::fromStdString(r->value.GetString());
}
} else
if (memName == "service_if") {
if (r->value.IsString()) {
serviceIf = QString::fromStdString(r->value.GetString());
}
} else {
qCritical() << __func__ << ":" << __LINE__ << "WARNING unknown service setting" << memName;
}
}
}
if (!serviceStartStr.isEmpty() && !serviceEndStr.isEmpty() && serviceDuration != -1) {
ATBTime serviceStart(serviceStartStr);
ATBTime serviceEnd(serviceEndStr);
if (serviceStart.isValid() && serviceEnd.isValid()) {
TariffService.m_range = TimeRange(serviceStart, serviceEnd, serviceDuration);
TariffService.m_weekDay = weekDayName;
if (!d.isNull() && d.isValid()) {
TariffService.m_date = d;
}
if (!serviceIf.isEmpty()) {
TariffService.setServiceIf(serviceIf);
}
// qCritical() << TariffService;
cfg.TariffServices.insert(std::pair<int, ATBTariffService>(weekDay, TariffService));
}
}
}
}
}
} else {
}
}
}
}
}
}
} else
if (name == "out_of_service_settings") {
ATBTariffOutOfService TariffOutOfService;
if (m->value.IsArray()) {
auto outOfService = m->value.GetArray();
if (outOfService.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no out of service settings for" << weekDayName;
} else {
for (rapidjson::SizeType j = 0; j < outOfService.Size(); ++j) {
if (outOfService[j].IsObject()) {
auto outOfServiceSetting = outOfService[j].GetObject();
for (auto n = outOfServiceSetting.MemberBegin(); n != outOfServiceSetting.MemberEnd(); ++n) {
QString const &name = QString::fromStdString(n->name.GetString());
if (name == "out_of_service_ranges") {
if (n->value.IsArray()) {
auto outOfServiceRanges = n->value.GetArray();
if (outOfServiceRanges.Size() == 0) {
qCritical() << __func__ << ":" << __LINE__ << "no out of service ranges for" << weekDayName;
} else {
QString outOfServiceStartStr;
QString outOfServiceEndStr;
QString outOfServiceIf;
int outOfServiceDuration = -1;
for (rapidjson::SizeType i = 0; i < outOfServiceRanges.Size(); ++i) {
if (outOfServiceRanges[j].IsObject()) {
auto outOfServiceRange = outOfServiceRanges[i].GetObject();
for (auto r = outOfServiceRange.MemberBegin(); r != outOfServiceRange.MemberEnd(); ++r) {
QString const &memName = QString::fromStdString(r->name.GetString());
if (memName == "out_of_service_id") {
if (r->value.IsInt()) {
TariffOutOfService.m_id = r->value.GetInt();
} else {
qCritical() << __func__ << ":" << __LINE__ << "outOfServiceId not an integer";
}
} else
if (memName == "out_of_service_duration") {
if (r->value.IsInt()) {
outOfServiceDuration = r->value.GetInt();
}
} else
if (memName == "out_of_service_start") {
if (r->value.IsString()) {
outOfServiceStartStr = QString::fromStdString(r->value.GetString());
}
} else
if (memName == "out_of_service_end") {
if (r->value.IsString()) {
outOfServiceEndStr = QString::fromStdString(r->value.GetString());
}
} else
if (memName == "out_of_service_if") {
if (r->value.IsString()) {
outOfServiceIf = QString::fromStdString(r->value.GetString());
}
} else {
qCritical() << __func__ << ":" << __LINE__ << "WARNING unknown out of service setting" << memName;
}
}
}
if (!outOfServiceStartStr.isEmpty() && !outOfServiceEndStr.isEmpty() && outOfServiceDuration != -1) {
ATBTime outOfServiceStart(outOfServiceStartStr);
ATBTime outOfServiceEnd(outOfServiceEndStr);
if (outOfServiceStart.isValid() && outOfServiceEnd.isValid()) {
TariffOutOfService.m_range = TimeRange(outOfServiceStart, outOfServiceEnd, outOfServiceDuration);
TariffOutOfService.m_weekDay = weekDayName;
if (!d.isNull() && d.isValid()) {
TariffOutOfService.m_date = d;
}
if (!outOfServiceIf.isEmpty()) {
TariffOutOfService.setOutOfServiceIf(outOfServiceIf);
}
// qCritical() << TariffOutOfService;
cfg.TariffOutOfServices.insert(std::pair<int, ATBTariffOutOfService>(weekDay, TariffOutOfService));
}
}
}
}
}
} else {
}
}
}
}
}
}
} else {
}
}
ATBTariffSettings ts(max_price, min_price, max_time, min_time);
ATBTariffCarryOverSettings cs(duration, start, end, parking_time_limit, about_to_exceed_limit,
parkTimeLimitChecker);
if (!d.isNull() && d.isValid()) { // special day, given in date-format
WeekDay = ATBWeekDay(weekDay, weekDayName, ATBWeekDay::HOLIDAY, QDate(), ts, cs);
} else {
WeekDay = ATBWeekDay(weekDay, weekDayName, ATBWeekDay::USUAL_WEEKDAY, QDate(), ts, cs);
}
}
} else
if (innerObjName == QString("week_day_default")) {
if (k->value.IsObject()) {
auto obj = k->value.GetObject();
@@ -408,6 +822,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
ATBInterpolation TariffInterpolation;
ATBPrepaid TariffPrepaidOption;
ATBCarryOver TariffCarryOver;
QList<QPair<QString, QString>> TariffIncludes;
MemberType mb_type = MemberType::UnknownType;
this->currentPaymentOptions.clear();
@@ -473,32 +888,32 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
break;
case MemberType::WeekDaysType: {
ATBWeekDay WeekDay;
if (QString(mb_name) == "Monday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Monday, mb_name);
if (QString(mb_name).trimmed() == "Monday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Monday, QString(mb_name).trimmed());
} else
if (QString(mb_name) == "Tuesday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Tuesday, mb_name);
if (QString(mb_name).trimmed() == "Tuesday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Tuesday, QString(mb_name).trimmed());
} else
if (QString(mb_name) == "Wednesday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Wednesday, mb_name);
if (QString(mb_name).trimmed() == "Wednesday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Wednesday, QString(mb_name).trimmed());
} else
if (QString(mb_name) == "Thursday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Thursday, mb_name);
if (QString(mb_name).trimmed() == "Thursday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Thursday, QString(mb_name).trimmed());
} else
if (QString(mb_name) == "Friday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Friday, mb_name);
if (QString(mb_name).trimmed() == "Friday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Friday, QString(mb_name).trimmed());
} else
if (QString(mb_name) == "Saturday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Saturday, mb_name);
if (QString(mb_name).trimmed() == "Saturday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Saturday, QString(mb_name).trimmed());
} else
if (QString(mb_name) == "Sunday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Sunday, mb_name);
if (QString(mb_name).trimmed() == "Sunday") {
WeekDay = parseWeekDay(*cfg, k, inner_obj_name, Qt::Sunday, QString(mb_name).trimmed());
} else {
qCritical() << "ERROR: unknown week day" << mb_name;
}
cfg->WeekDays.insert(pair<Qt::DayOfWeek, ATBWeekDay>(WeekDay.m_id, WeekDay));
// qCritical() << WeekDay;
qCritical() << __func__ << ":" << __LINE__ << cfg << "CCCC insert" << (int)WeekDay.m_id << WeekDay.m_name;
} break;
case MemberType::CarryOverType: {
@@ -939,6 +1354,9 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
else if (strcmp(inner_obj_name, "pcu_minor") == 0) Currency.pcu_minor = k->value.GetString();
else if (strcmp(inner_obj_name, "pcu_active") == 0) Currency.pcu_active = k->value.GetBool();
break;
case MemberType::IncludesType:
TariffIncludes << QPair<QString, QString>(QString(inner_obj_name), k->value.GetString());
break;
case MemberType::PaymentMethodType:
if (strcmp(inner_obj_name, "pme_id") == 0) PaymentMethod.pme_id = k->value.GetInt();
else if (strcmp(inner_obj_name, "pme_label") == 0) PaymentMethod.pme_label = k->value.GetString();
@@ -1000,6 +1418,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
this->currentPaymentOptions.last().pop_min_time = k->value.GetDouble();
} else if (strcmp(inner_obj_name, "pop_max_price") == 0) {
this->currentPaymentOptions.last().pop_max_price = k->value.GetDouble();
this->currentPaymentOptions.last().pop_max_price_save = k->value.GetDouble();
} else if (strcmp(inner_obj_name, "pop_max_time") == 0) {
this->currentPaymentOptions.last().pop_max_time = k->value.GetDouble();
} else if (strcmp(inner_obj_name, "pop_min_price") == 0) {
@@ -1227,6 +1646,9 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
cfg->TariffCarryOverOptions.insert(pair<int, ATBCarryOver>(TariffCarryOver.id, TariffCarryOver));
// qCritical() << TariffCarryOver;
break;
case MemberType::IncludesType:
cfg->TariffIncludes = TariffIncludes;
// qCritical() << "TariffIncludes" << cfg->TariffIncludes;
default:
break;
}

View File

@@ -427,6 +427,8 @@ PaymentMethod Utilities::getPaymentMethodId(Configuration const *cfg) {
return PaymentMethod::Degressive;
case PaymentMethod::Progressive:
return PaymentMethod::Progressive;
case PaymentMethod::Unified:
return PaymentMethod::Unified;
}
}

View File

@@ -39,11 +39,11 @@ extern "C" char* strptime(const char* s,
#define SZEGED (0)
#define SCHOENAU_KOENIGSEE (0)
#define NEUHAUSER_KORNEUBURG (0)
#define NEUHAUSER_KORNEUBURG (1)
#define NEUHAUSER_LINSINGER_MASCHINENBAU (0)
#define NEUHAUSER_NORDISCHES_AUSBILDUNGSZENTRUM (0)
#define NEUHAUSER_BILEXA_GALTUER (0)
#define BAD_NEUENAHR_AHRWEILER (1)
#define BAD_NEUENAHR_AHRWEILER (0)
#define NEUHAUSER_CHRISTOPH_REISEN (0)
#define NEUHAUSER_PERNEGG_AN_DER_MUR (0)
#define NEUHAUSER_STOCKERAU (0)
@@ -52,6 +52,7 @@ extern "C" char* strptime(const char* s,
#define SCHNALS_LEITER_KIRCHL (0)
#define SCHNALS_STAUMAUER (SCHNALS_LEITER_KIRCHL)
#define VALSER_ALM (0)
#define NEUHAUSER_FORCHACH (0)
#if NEUHAUSER_KIRCHDORF==1
static bool test_neuhauser_kirchdorf(int step, double cost) {
@@ -210,21 +211,73 @@ static bool test_neuhauser_kirchdorf(int step, double cost) {
return 0;
*/
#include <QProcess>
#include <QCoreApplication>
QString getCalculatorLibVersion() {
static QString v;
if (v.isEmpty()) {
QProcess shell;
QString command = QString("cat /proc/%1/maps | awk '{print $6;}' | grep 'libmobilisis_calc' | uniq").arg(QCoreApplication::applicationPid());
shell.start("/bin/bash", {"-c", command});
if ( shell.waitForFinished( 5000 )) {
v = shell.readAllStandardOutput();
// /usr/lib/libmobilisis_calc.so.2.3.99-18
if (!v.isEmpty()) {
QStringList vlst = v.trimmed().split("/", QString::SkipEmptyParts);
if (vlst.size() > 0) {
vlst = vlst.last().split(".", QString::SkipEmptyParts);
if (vlst.size() > 4) {
v = QString("%1.%2.%3").arg(vlst[2]).arg(vlst[3]).arg(vlst[4]);
}
}
}
}
}
return v;
}
bool isProductSupportedInCalculatorLib(QString const &product) {
bool supported{false};
QProcess shell;
QString command = QString("cat /proc/%1/maps | awk '{print $6;}' | grep 'libmobilisis_calc' | uniq | xargs strings | grep %2").arg(QCoreApplication::applicationPid()).arg(product);
shell.start("/bin/bash", {"-c", command});
if ( shell.waitForFinished( 5000 )) {
QString s = shell.readAllStandardOutput().trimmed();
// /usr/lib/libmobilisis_calc.so.2.3.99-18
if (!s.isEmpty() && (s == product)) {
qCritical() << "product" << s << "supported";
supported = true;
} else {
qCritical() << "product" << product << "not supported";
}
}
return supported;
}
int main() {
qCritical() << getCalculatorLibVersion();
isProductSupportedInCalculatorLib("FREE_TICKET");
return 0;
//487 {
// 488 "pra_payment_option_id": 1049,
// 489 "pra_payment_unit_id": 84,
// 490 "pra_price":"840"
//>>491 }
//for (int i = 1; i < 85; ++i) {
//printf("{\n \"\pra_payment_option_id\": 1049,\n \"\pra_payment_unit_id\": %d,\n \"pra_price\": %d\n},\n",
// i, i*10);
//for (int i = 1; i < 346; ++i) {
//printf("{\n \"pun_id\": %i,\n \"pun_duration\": %d\n},\n",
// i, 60 + i*4);
//}
//return 0;
for (int i = 1; i < 361; ++i) {
printf("{\n \"pra_payment_option_id\": 1049,\n \"pra_payment_unit_id\": %i,\n \"pra_price\":%i\n},\n",
i, i*10);
}
return 0;
#if 0
MessageHelper msgHelp;
// msgHelp.createLoginMessageChunksToSend(0x02);
@@ -755,7 +808,7 @@ int main() {
int pop_max_price;
int pop_daily_card_price;
int zone = 3;
int zone = 1;
if (zone == 1) {
input.open("/opt/ptu5/opt/customer_502/etc/psa_tariff/tariff01.json");
@@ -844,7 +897,7 @@ int main() {
CalcState calcState;
QDateTime s(QDateTime::currentDateTime());
s.setTime(QTime(12, 0, 0));
// s.setTime(QTime(12, 0, 0));
//calcState = compute_duration_for_parking_ticket(&cfg, s,
// (double)1200, end, PermitType(PERMIT_TYPE::SHORT_TERM_PARKING_PKW));
@@ -852,9 +905,26 @@ int main() {
//qCritical() << calcState.toString();
calcState = compute_duration_for_parking_ticket(&cfg, s,
(double)50, end, PermitType(PERMIT_TYPE::SHORT_TERM_PARKING_BUS));
(double)9000, end, PermitType(PERMIT_TYPE::SHORT_TERM_PARKING_BUS));
qCritical() << end.toString(Qt::ISODate);
qCritical() << calcState.toString();
struct price_t costs;
CalcState cs;
for (int i = 0, j=timeSteps.size() ; i < timeSteps.size(); --j, ++i) {
QDateTime end = start.addSecs(timeSteps.at(i)*60);
qCritical() << "XXXXX end" << end.toString(Qt::ISODate);
cs = compute_price_for_parking_ticket(&cfg, s, timeSteps.at(i), end, &costs,
PermitType(PERMIT_TYPE::SHORT_TERM_PARKING));
if (cs.getStatus() != CalcState::State::SUCCESS) {
qCritical() << "ERROR STATUS" << costs.netto;
exit(-1);
}
}
}
if (zone == 2) {
@@ -1369,6 +1439,29 @@ int main() {
}
}
#endif
#if NEUHAUSER_FORCHACH==1
std::ifstream input;
input.open("/opt/ptu5/opt/customer_749/etc/psa_tariff/tariff01.json");
std::stringstream sstr;
while(input >> sstr.rdbuf());
std::string json(sstr.str());
Configuration cfg;
bool isParsed = cfg.ParseJson(&cfg, json.c_str());
cout << endl;
if (isParsed) {
compute_product_price(&cfg, PermitType(PERMIT_TYPE::DAY_TICKET_PKW));
compute_product_price(&cfg, PermitType(PERMIT_TYPE::DAY_TICKET_CAMPER));
QDateTime start = QDateTime::currentDateTime();
QDateTime ticketEndTime;
compute_duration_for_daily_ticket(&cfg, start, ticketEndTime, PermitType(PERMIT_TYPE::DAY_TICKET));
}
#endif
#if BAD_NEUENAHR_AHRWEILER==1
std::ifstream input;
@@ -1391,7 +1484,8 @@ int main() {
case 2: {
qCritical() << " ZONE 2: KURZZEIT 1";
// kuzzeit-1-tarif
input.open("/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff02.json");
//input.open("/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff02.json");
input.open("/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff05.json");
//pop_max_time = 5*60;
} break;
case 3: {
@@ -1583,7 +1677,8 @@ int main() {
break;
case 1:
//start = QDateTime(QDate(2024, 10, 3), QTime(17, 0, 0)); // sunday
start = QDateTime(QDate(2024, 9, 8), QTime(16, 2, 0)); // sunday
//start = QDateTime(QDate(2025, 4, 20), QTime(18, 0, 0)); // sunday
start = QDateTime(QDate(2024, 9, 27), QTime(17, 0, 0)); // friday
fail = false;
break;
case 2:
@@ -1615,8 +1710,8 @@ int main() {
// << "START" << start.toString(Qt::ISODate)
// << "<duration" << *step;
// if (*step != 180)
// continue;
if (*step != 180)
continue;
double cost = 0;
@@ -2761,24 +2856,62 @@ int main() {
bool nextDay = false;
bool prePaid = true;
// zone 1 (lila)
QDateTime s(QDate(2023, 11, 30), QTime());
QDateTime s(QDate(2024, 10, 8), QTime());
QDateTime end;
static QList<int> const timeSteps = Calculator::GetInstance().GetTimeSteps(&cfg);
qCritical() << "TimeSteps" << timeSteps;
for (int duration = 30; duration <= pop_max_time; duration += 5) {
for (int offset = 420; offset < 1140; ++offset) {
if (offset > 720 && offset < 840) {
continue;
}
int offset = 600;
//for (int offset = 720; offset < 601; ++offset) {
//if (offset > 720 && offset < 840) {
// continue;
//}
QDateTime start = s.addSecs(offset * 60);
//qCritical() << "start" << start.toString(Qt::ISODate);
double cost = Calculator::GetInstance().GetCostFromDuration(&cfg, 3, start, end, duration, nextDay, prePaid);
CalcState cs;
#if 1
struct price_t costs;
for (int i = 0, j=timeSteps.size() ; i < timeSteps.size(); --j, ++i) {
QDateTime end = start.addSecs(timeSteps.at(i)*60);
// if (i != 2) continue;
cs = compute_price_for_parking_ticket(&cfg, start, timeSteps.at(i), end, &costs, PermitType(PERMIT_TYPE::SHORT_TERM_PARKING));
int price1 = costs.netto;
qCritical() << "compute_price_for_parking_ticket()/GetCostFromDuration() TIME: "
<< timeSteps.at(i) << "ZZZZZZZZZZZZZ PRICE=" << price1 << "end=" << end.toString(Qt::ISODate);
}
exit(0);
#else
double cost = 360;
qCritical() << "XXXXXXXX START" << start.toString(Qt::ISODate) << "cost" << cost;
QDateTime end;
cs = compute_duration_for_parking_ticket(&cfg, start, cost, end,
PermitType(PERMIT_TYPE::SHORT_TERM_PARKING));
qCritical() << __LINE__ << cs.toString()
<< "START" << start.toString(Qt::ISODate)
<< "<duration" << start.secsTo(end) / 60
<< "cost" << cost
<< "> end" << end.toString(Qt::ISODate);
//}
exit(0);
#endif
//double cost = Calculator::GetInstance().GetCostFromDuration(&cfg, 3, start, end, duration, nextDay, prePaid);
//Q_ASSERT(cost == duration*2.5);
//qCritical() << "";
qCritical() << "start" << start.toString(Qt::ISODate)
<< "end" << end.toString(Qt::ISODate)
<< "duration" << duration
<< "cost" << cost;
//qCritical() << "start" << start.toString(Qt::ISODate)
// << "end" << end.toString(Qt::ISODate)
// << "duration" << duration
// << "cost" << cost;
#if 0
switch(duration) {
case 30:
if (cost == 60.0) {
@@ -2942,15 +3075,17 @@ int main() {
<< "cost" << cost;
exit(-1);
}
#endif
//std::string duration = Calculator::GetInstance().GetDurationFromCost(&cfg, 3, start.toString(Qt::ISODate).toStdString().c_str(), cost);
//Q_ASSERT(cost == duration*2.5);
//qCritical() << "start" << start.toString(Qt::ISODate)
// << "cost" << cost
// << "until" << duration.c_str() << start.secsTo(QDateTime::fromString(duration.c_str(), Qt::ISODate)) / 60;
}
//}
}
#if 0
Configuration::SpecialDaysType specialDays = cfg.SpecialDays;
for (Configuration::SpecialDaysType::const_iterator it = specialDays.cbegin();
it != specialDays.cend(); ++it) {
@@ -2971,7 +3106,7 @@ int main() {
<< "duration" << duration
<< "cost" << cost;
}
#endif
}
}
return 0;

View File

@@ -1,3 +1,5 @@
QT += core
TEMPLATE = app
TARGET = main
@@ -34,7 +36,12 @@ OTHER_FILES += \
/opt/ptu5/opt/customer_335/etc/psa_tariff/tariff02.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff01.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff02.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff03.json
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff03.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff04.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff05.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff06.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff07.json \
/opt/ptu5/opt/customer_249/etc/psa_tariff/tariff08.json

1529
out.txt Normal file

File diff suppressed because it is too large Load Diff