MOBILISIS-Calculator/library/src/calculator_functions.cpp.kirchdorf

1470 lines
66 KiB
Plaintext

#include "calculator_functions.h"
#include "payment_option.h"
#include "utilities.h"
#include "tariff_log.h"
#include "tariff_time_range.h"
#include "ticket.h"
#include <sstream>
#include <algorithm>
#include <QDateTime>
#include <QScopedArrayPointer>
#include <QDebug>
double total_duration_min = 0.0f;
double total_cost = 0.0f;
bool overtime = false;
#ifdef _WIN32
inline struct tm* localtime_r(const time_t *clock, struct tm* result){
if(!clock || !result) return NULL;
memcpy(result,localtime(clock),sizeof(*result));
return result;
}
#endif
QDateTime Calculator::GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over)
{
if(!start_datetime.isValid()) {
return QDateTime();
}
double day_price = 0.0f;
int current_special_day_id = -1;
bool is_special_day = Utilities::CheckSpecialDay(cfg, start_datetime.toString(Qt::ISODate).toStdString().c_str(), &current_special_day_id, &day_price);
QDateTime inputDateTime = start_datetime;
QTime worktime_from;
QTime worktime_to;
int daily_card_price = cfg->PaymentOption.find(payment_option)->second.pop_daily_card_price;
if(daily_card_price <= 0) {
qCritical() << "Calculator::GetDailyTicketDuration(): Daily ticket price zero or less";
return QDateTime();
}
if(is_special_day)
{
worktime_from = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from.c_str(), Qt::ISODate);
worktime_to = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to.c_str(),Qt::ISODate);
if(inputDateTime.time() < worktime_from) inputDateTime.setTime(worktime_from);
if(carry_over) inputDateTime.setTime(worktime_from);
if(inputDateTime.time() >= worktime_to)
{
// Go to next day if outside worktime
inputDateTime = inputDateTime.addSecs(86400);
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
}
if(day_price <=0)
{
// Go to next day if special day price is 0
inputDateTime = inputDateTime.addSecs(86400);
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
}
int diff = abs(inputDateTime.time().secsTo(worktime_to));
inputDateTime = inputDateTime.addSecs(diff);
//qDebug() << "Ticket is valid until: " << inputDateTime.toString(Qt::ISODate) << "price = " << daily_card_price << ", duration = " << diff / 60;
return inputDateTime;
}
else
{
// Get day of week
int const weekdayId = inputDateTime.date().dayOfWeek();
// If no working day found, skip it (recursively call method again)
size_t found = cfg->WeekDaysWorktime.count(weekdayId);
// When no workday found, go to next available day
if(found <=0)
{
inputDateTime = inputDateTime.addSecs(86400);
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
}
else
{
worktime_from = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from.c_str(),Qt::ISODate);
worktime_to = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to.c_str(),Qt::ISODate);
if(inputDateTime.time() < worktime_from)
inputDateTime.setTime(worktime_from);
if(carry_over)
inputDateTime.setTime(worktime_from);
if(inputDateTime.time() >= worktime_to)
{
// Go to next day if outside worktime
inputDateTime = inputDateTime.addSecs(86400);
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
}
int diff = abs(inputDateTime.time().secsTo(worktime_to));
inputDateTime = inputDateTime.addSecs(diff);
//qDebug() << "Ticket is valid until: " << inputDateTime.toString(Qt::ISODate) << "price = " << daily_card_price << ", duration = " << diff / 60;
return inputDateTime;
}
}
return QDateTime();
}
/// <inheritdoc/>
std::string Calculator::GetDurationFromCost(Configuration* cfg,
uint8_t payment_option,
char const *startDatetimePassed, // given in local time
double cost,
bool nextDay,
bool prepaid)
{
Q_UNUSED(payment_option);
Q_UNUSED(nextDay);
// Get input date
QDateTime inputDate = QDateTime::fromString(startDatetimePassed,Qt::ISODate);
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
if (paymentMethodId == PaymentMethod::Steps) {
if (tariffIs24_7(cfg)) {
// use tariff with structure as for instance Schoenau, Koenigsee:
// without given YearPeriod, SpecialDays and SpecialDaysWorktime
inputDate = inputDate.addSecs(GetDurationForPrice(cfg, cost) * 60);
return inputDate.toString(Qt::ISODate).toStdString();
} else {
if (Utilities::IsYearPeriodActive(cfg, inputDate)) {
if (!prepaid) {
CalcState cs = isParkingAllowed(cfg, inputDate);
if (cs) {
inputDate.setTime(cs.getAllowedTimeRange().getTimeUntil());
return inputDate.toString(Qt::ISODate).toStdString();
}
}
qCritical() << __func__ << ":" << __LINE__ << "NOT YET IMPLEMENTED";
return "";
}
}
} else
if (paymentMethodId == PaymentMethod::Progressive) {
// started with Neuhauser, Kirchdorf: merge into main algo. later
// for now try out some ideas
// started with Neuhauser, Kirchdorf: merge into main algo. later
// for now try out some ideas
static const bool carryOverNotSet = Utilities::isCarryOverNotSet(cfg, paymentMethodId);
static const uint minParkingPrice = Utilities::getMinimalParkingPrice(cfg, paymentMethodId);
static const uint maxParkingPrice = Utilities::getMaximalParkingPrice(cfg, paymentMethodId);
if (cost < minParkingPrice) {
qCritical() << QString("ERROR: COST < MIN_PARKING_PRICE (%1 < %2)").arg(cost).arg(minParkingPrice);
return QDateTime().toString(Qt::ISODate).toStdString();
}
if (cost > maxParkingPrice) {
qCritical() << QString("WARN: COST > MAX_PARKING_PRICE (%1 > %2)").arg(cost).arg(maxParkingPrice);
cost = maxParkingPrice;
}
Q_ASSERT_X(carryOverNotSet, __func__, "CARRYOVER SET (FOR KIRCHDORF)");
Q_ASSERT_X(prepaid, __func__, "PREPAID NOT SET (FOR KIRCHDORF)");
QDateTime start_datetime = QDateTime::fromString(QString(startDatetimePassed), Qt::ISODate);
QDateTime start = start_datetime;
QDateTime end_datetime = QDateTime();
int weekdayId = -1;
int weekdayIdLast = -1;
int durationMinutes = Utilities::getMaximalParkingTime(cfg, paymentMethodId);
int durationMinutesBrutto = 0;
QDateTime current = start;
int days = 7;
while (--days > 0) {
weekdayId = current.date().dayOfWeek();
weekdayIdLast = weekdayId; // TODO: some end condition in json-file
while (cfg->WeekDaysWorktime.count(weekdayId) == 0) {
current = current.addDays(1);
weekdayId = current.date().dayOfWeek();
if (weekdayId == weekdayIdLast) {
qCritical() << "ERROR: NO VALID WORKDAY-TIMES DEFINED";
return QDateTime().toString(Qt::ISODate).toStdString();
}
}
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
QTime to = QTime(0, 0, 0);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
QTime const &t = Utilities::WeekDaysWorkTimeUntil(itr);
if (to < t) {
to = t;
}
}
if (current.time() >= to) {
if (carryOverNotSet) {
return end_datetime.toString(Qt::ISODate).toStdString();
} else {
QDateTime const dt = start;
start = start.addDays(1);
start.setTime(QTime(0, 0, 0));
durationMinutesBrutto += dt.secsTo(start) / 60;
current = start;
}
} else {
break;
}
}
int durationMinutesNetto = 0;
uint price = 0;
if (carryOverNotSet) {
int range = 0;
int minsToCarryOver = 0; // from one work-time to the other on the same day
int minsUsed = 0;
QDateTime lastCurrent = QDateTime();
auto timeRangeIt = cfg->TimeRange.cbegin();
for (; timeRangeIt != cfg->TimeRange.cend(); ++timeRangeIt) {
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
++range;
QTime const &from = Utilities::WeekDaysWorkTimeFrom(itr);
QTime const &to = Utilities::WeekDaysWorkTimeUntil(itr);
Q_ASSERT_X(from < to, __func__, "MISCONFIGURED WORK-TIMES");
if (current.time() >= to) {
continue; // try to use next available work-time
} else
if (current.time() <= from) {
if (prepaid) {
lastCurrent = current;
current.setTime(from); // move current forward (range==1),
// as prepaid is set
uint const minutesMoved = lastCurrent.secsTo(current) / 60;
durationMinutesBrutto += minutesMoved;
if (range == 1) {
start_datetime = current;
}
}
}
while (timeRangeIt != cfg->TimeRange.cend()) {
ATBTimeRange timeRange = timeRangeIt->second;
timeRange.computeQTimes(current.time());
int duration = timeRange.time_range_to_in_minutes_from_start -
timeRange.time_range_from_in_minutes_from_start;
if (minsUsed > 0) {
duration -= minsUsed;
minsUsed = 0;
}
if (current.addSecs(duration * 60).time() <= to) {
if (minsToCarryOver > 0) { // the price for this time range
// has been is paid already
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration*60);
minsToCarryOver = 0;
} else {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
if (price >= maxParkingPrice) {
price = maxParkingPrice;
}
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration * 60);
if (price >= cost) {
end_datetime = current;
return end_datetime.toString(Qt::ISODate).toStdString();
}
break;
}
}
}
if (durationMinutes <= 0) {
end_datetime = current;
return end_datetime.toString(Qt::ISODate).toStdString();
}
++timeRangeIt;
} else {
lastCurrent = current;
current.setTime(to);
minsUsed = lastCurrent.secsTo(current) / 60;
// mod duration: possibly discard some minutes in
// the next time-range
if (durationMinutes >= minsUsed) {
minsToCarryOver = durationMinutes - minsUsed;
}
durationMinutes -= minsUsed;
durationMinutesNetto += minsUsed;
durationMinutesBrutto += minsUsed;
if (minsUsed > 0) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
if (price >= maxParkingPrice) {
price = maxParkingPrice;
}
if (price >= cost) {
end_datetime = current;
// return end_datetime.toString(Qt::ISODate).toStdString();
}
break;
}
}
}
break;
}
}
}
end_datetime = start.addSecs(durationMinutesBrutto * 60);
return end_datetime.toString(Qt::ISODate).toStdString();
}
}
end_datetime = QDateTime();
return end_datetime.toString(Qt::ISODate).toStdString();
}
Ticket t = private_GetDurationFromCost(cfg, inputDate, cost, prepaid);
// qCritical().noquote() << t;
// TODO: im fehlerfall
return t.getValidUntil().toString(Qt::ISODate).toStdString();
}
///////////////////////////////////////
/// <inheritdoc/>
///
uint32_t Calculator::GetCostFromDuration(Configuration *cfg,
QDateTime const &start,
quint64 timeStepInMinutes) const {
// for instance, a tariff as used in Schoenau, Koenigssee: only steps, no
// special days, nonstop.
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
if (paymentMethodId == PaymentMethod::Steps) {
QDateTime const end = start.addSecs(timeStepInMinutes*60);
return GetCostFromDuration(cfg, start, end);
}
return 0;
}
uint32_t Calculator::GetCostFromDuration(Configuration * cfg,
QDateTime const &start,
QDateTime const &end) const {
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
if (paymentMethodId == PaymentMethod::Steps) {
int const timeStepInMinutes = start.secsTo(end) / 60;
return GetPriceForTimeStep(cfg, timeStepInMinutes);
}
return 0;
}
CalcState Calculator::isParkingAllowed(Configuration const *cfg, QDateTime const &start) {
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
if (paymentMethodId == PaymentMethod::Steps) {
int const weekdayId = start.date().dayOfWeek();
BusinessHours businessHours = Utilities::getBusinessHours(cfg, paymentMethodId);
if (businessHours == BusinessHours::OnlyWeekDays) {
if (weekdayId != (int)Qt::Saturday && weekdayId != (int)Qt::Sunday) { // e.g. Neuhauser, Linsinger Maschinenbau (741)
if (cfg->WeekDaysWorktime.count(weekdayId) > 0) {
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
QTime const &from = Utilities::WeekDaysWorkTimeFrom(itr);
QTime const &until = Utilities::WeekDaysWorkTimeUntil(itr);
QTime const &startTime = start.time();
if (from > startTime) {
return CalcState(CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME,
QString("%1 < %2").arg(from.toString(Qt::ISODate))
.arg(startTime.toString(Qt::ISODate)), from, until);
} else
if (startTime >= until) {
return CalcState(CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME,
QString("%1 >= %2").arg(startTime.toString(Qt::ISODate))
.arg(until.toString(Qt::ISODate)), from, until);
}
return CalcState(CalcState::State::SUCCESS,
"PARKING ALLOWED", from, until);
}
}
}
} else
if (businessHours == BusinessHours::AllDaysWithRestrictedHours) { // e.g. for Neuhauser, NAZ (744)
if (cfg->WeekDaysWorktime.count(weekdayId) > 0) {
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
QTime const &from = Utilities::WeekDaysWorkTimeFrom(itr);
QTime const &until = Utilities::WeekDaysWorkTimeUntil(itr);
QTime const &startTime = start.time();
if (from > startTime) {
return CalcState(CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME,
QString("%1 < %2").arg(from.toString(Qt::ISODate))
.arg(startTime.toString(Qt::ISODate)), from, until);
} else
if (startTime >= until) {
return CalcState(CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME,
QString("%1 >= %2").arg(startTime.toString(Qt::ISODate))
.arg(until.toString(Qt::ISODate)), from, until);
}
return CalcState(CalcState::State::SUCCESS,
"PARKING ALLOWED", from, until);
}
}
}
}
return CalcState(CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME, "UNKNOWN ERROR",
QTime(), QTime());
}
///////////////////////////////////////
/// <inheritdoc/>
double Calculator::GetCostFromDuration(Configuration* cfg,
uint8_t payment_option,
QDateTime &start_datetime,
QDateTime &end_datetime,
int durationMinutes,
bool nextDay,
bool prepaid) {
Q_UNUSED(payment_option);
Q_UNUSED(nextDay);
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
if (paymentMethodId == PaymentMethod::Steps) {
if (tariffIs24_7(cfg)) {
end_datetime = start_datetime.addSecs(durationMinutes*60);
return GetCostFromDuration(cfg, start_datetime, end_datetime);
} else {
if (Utilities::IsYearPeriodActive(cfg, start_datetime)) {
if (!prepaid) {
CalcState cs = isParkingAllowed(cfg, start_datetime);
if (cs) {
end_datetime = start_datetime.addSecs(durationMinutes*60);
double cost = GetCostFromDuration(cfg, start_datetime, end_datetime);
end_datetime = start_datetime;
end_datetime.setTime(cs.getAllowedTimeRange().getTimeUntil());
return cost;
}
} else {
// it might be that in such a case even prepaid ("vorkauf")
// is not allowed at any moment
}
qCritical() << "(" << __func__ << ":" << __LINE__ << ")" << "NOT YET IMPLEMENTED";
end_datetime = QDateTime();
return 0;
}
}
} else
if (paymentMethodId == PaymentMethod::Progressive) {
// started with Neuhauser, Kirchdorf: merge into main algo. later
// for now try out some ideas
static const bool carryOverNotSet = Utilities::isCarryOverNotSet(cfg, paymentMethodId);
static const uint minParkingPrice = Utilities::getMinimalParkingPrice(cfg, paymentMethodId);
Q_ASSERT_X(carryOverNotSet, __func__, "CARRYOVER SET (FOR KIRCHDORF)");
Q_ASSERT_X(prepaid, __func__, "PREPAID NOT SET (FOR KIRCHDORF)");
QDateTime start = start_datetime;
int weekdayId = -1;
int weekdayIdLast = -1;
int durationMinutesBrutto = 0;
QDateTime current = start;
int days = 7;
while (--days > 0) {
weekdayId = current.date().dayOfWeek();
weekdayIdLast = weekdayId; // TODO: some end condition in json-file
while (cfg->WeekDaysWorktime.count(weekdayId) == 0) {
current = current.addDays(1);
weekdayId = current.date().dayOfWeek();
if (weekdayId == weekdayIdLast) {
qCritical() << "ERROR: NO VALID WORKDAY-TIMES DEFINED";
return 0;
}
}
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
QTime to = QTime(0, 0, 0);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
QTime const &t = Utilities::WeekDaysWorkTimeUntil(itr);
if (to < t) {
to = t;
}
}
if (current.time() >= to) {
if (carryOverNotSet) {
end_datetime = start;
return 0;
} else {
QDateTime const dt = start;
start = start.addDays(1);
start.setTime(QTime(0, 0, 0));
durationMinutesBrutto += dt.secsTo(start) / 60;
current = start;
}
} else {
break;
}
}
int durationMinutesNetto = 0;
uint price = 0;
if (carryOverNotSet) {
int range = 0;
int minsToCarryOver = 0; // from one work-time to the other on the same day
int minsUsed = 0;
QDateTime lastCurrent = QDateTime();
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
++range;
QTime const &from = Utilities::WeekDaysWorkTimeFrom(itr);
QTime const &to = Utilities::WeekDaysWorkTimeUntil(itr);
Q_ASSERT_X(from < to, __func__, "MISCONFIGURED WORK-TIMES");
if (current.time() >= to) {
continue; // try to use next available work-time
} else
if (current.time() <= from) {
if (prepaid) {
lastCurrent = current;
current.setTime(from); // move current forward (range==1),
// as prepaid is set
uint const minutesMoved = lastCurrent.secsTo(current) / 60;
durationMinutesBrutto += minutesMoved;
if (range == 1) {
start_datetime = current;
}
}
}
for (auto timeRangeIt = cfg->TimeRange.cbegin(); timeRangeIt != cfg->TimeRange.cend(); ++timeRangeIt) {
ATBTimeRange timeRange = timeRangeIt->second;
timeRange.computeQTimes(current.time());
int duration = timeRange.time_range_to_in_minutes_from_start -
timeRange.time_range_from_in_minutes_from_start;
qCritical() << __func__ << ":" << __LINE__
<< "current" << current.toString(Qt::ISODate)
<< "duration" << duration
<< "minsUsed" << minsUsed
<< "minsToCarryOver" << minsToCarryOver;
//if (minsUsed > 0) {
// duration -= minsUsed;
// minsUsed = 0;
//}
if (current.addSecs(duration * 60).time() <= to) {
if (minsToCarryOver > 0) { // the price for this time range
// has been is paid already
if (minsUsed == 0) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration * 60);
if (durationMinutes <= 0) {
end_datetime = current;
return price;
}
break;
}
}
} else {
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration*60);
minsToCarryOver = 0;
}
} else {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration * 60);
break;
}
}
}
if (durationMinutes <= 0) {
end_datetime = current;
return price;
}
//++timeRangeIt;
} else {
lastCurrent = current;
current.setTime(to);
minsUsed = lastCurrent.secsTo(current) / 60;
// mod duration: possibly discard some minutes in
// the next time-range
if (durationMinutes >= minsUsed) {
minsToCarryOver = durationMinutes - minsUsed;
}
durationMinutes -= minsUsed;
durationMinutesNetto += minsUsed;
durationMinutesBrutto += minsUsed;
if (minsUsed > 0) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
break;
}
}
}
// break;
}
} // for (WTIterator itr = p.first; itr != p.second; ++itr) {
end_datetime = start.addSecs(durationMinutesBrutto * 60);
return std::max(price, minParkingPrice);
}
}
end_datetime = QDateTime();
return 0;
}
QDateTime start = start_datetime;
Ticket t = private_GetCostFromDuration(cfg, start,
durationMinutes,
prepaid);
if (t) {
// qCritical().noquote() << t;
}
end_datetime = t.getValidUntil();
return t.getPrice();
}
bool Calculator::checkDurationMinutes(int minParkingTime,
int maxParkingTime,
int durationMinutes) {
if (durationMinutes > maxParkingTime) {
qWarning() << QString("Total duration >= max_min (%1 >= %2)").arg(durationMinutes).arg(maxParkingTime);
return false;
}
if (durationMinutes < minParkingTime) {
qWarning() << QString("Total duration <= minMin (%1 <= %2)").arg(durationMinutes).arg(minParkingTime);
return false;
}
return true;
}
int Calculator::findWorkTimeRange(QDateTime const &dt,
QScopedArrayPointer<TariffTimeRange> const &worktime,
size_t size) {
for (size_t w = 0; w < size; ++w) {
QTime const &worktime_from = worktime[w].getTimeFrom();
QTime const &worktime_to = worktime[w].getTimeUntil();
if ((dt.time() >= worktime_from) && (dt.time() < worktime_to)) {
return w;
}
}
return -1;
}
int Calculator::findNextWorkTimeRange(QDateTime const &dt,
QScopedArrayPointer<TariffTimeRange> const &worktime,
size_t size) {
int nextWorkTimeRange = -1;
for (size_t w = 0; w < size; ++w) {
QTime const &worktime_from = worktime[w].getTimeFrom();
if (dt.time() < worktime_from) {
nextWorkTimeRange = w;
break;
}
}
return nextWorkTimeRange;
}
using namespace Utilities;
Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg,
QDateTime const &start,
int durationMinutes, // Netto
bool prepaid) {
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
static const bool carryOverNotSet = isCarryOverNotSet(cfg, paymentMethodId);
static const int minParkingTimeMinutes = Utilities::getMinimalParkingTime(cfg, paymentMethodId);
static const int maxParkingTimeMinutes = Utilities::getMaximalParkingTime(cfg, paymentMethodId);
static const bool checkMinMaxMinutes = (minParkingTimeMinutes < maxParkingTimeMinutes);
static const int durationMinutesNetto = durationMinutes;
static const uint32_t weekDaysPrice = Utilities::computeWeekDaysPrice(cfg, paymentMethodId);
static const double weekDaysDurationUnit = Utilities::computeWeekDaysDurationUnit(cfg, paymentMethodId);
static const double specialDaysDurationUnit = 60.0;
if (!checkMinMaxMinutes) {
qCritical() << QString(
"ERROR: CONDITION minMin < maxMin (%1 < %2) IS NOT VALID")
.arg(minParkingTimeMinutes).arg(maxParkingTimeMinutes);
return Ticket();
}
if (!checkDurationMinutes(minParkingTimeMinutes,
maxParkingTimeMinutes, durationMinutes)) {
return Ticket();
}
uint32_t price = 0;
uint32_t costFromDuration = 0;
double durationUnit = 0.0;
int specialDayId = -1;
bool isSpecialDay = false;
Ticket ticket;
QDateTime end = start;
QDateTime current;
int totalTimeRanges = 0;
for (current = start; durationMinutes > 0; current = current.addDays(1)) {
int const weekdayId = current.date().dayOfWeek();
specialDayId = -1;
// find worktime ranges for the current day
int const timeRanges = std::max((int)cfg->WeekDaysWorktime.count(weekdayId), 1);
QScopedArrayPointer<TariffTimeRange> worktime(new TariffTimeRange[timeRanges]);
int ranges = 0;
if((isSpecialDay = Utilities::CheckSpecialDay(cfg, current, &specialDayId, &price))) {
// Set special day price:
durationUnit = specialDaysDurationUnit;
worktime[ranges].setTimeRange(SpecialDaysWorkTimeFrom(cfg, specialDayId),
SpecialDaysWorkTimeUntil(cfg, specialDayId));
ranges = 1;
} else {
// Set new price for the normal day: do not use a floating-point type
// for the price, rather compute with integers. Only at the very end of
// the computation the price is divided by durationUnit.
price = weekDaysPrice;
durationUnit = weekDaysDurationUnit;
// If no working day found, skip it (epsecially Sundays!)
if (cfg->WeekDaysWorktime.count(weekdayId) <= 0) {
qDebug() << "No workday found, trying to find next available day";
end = current;
current.setTime(QTime()); // start at midnight on the next day
continue;
}
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
worktime[ranges].setTimeRange(WeekDaysWorkTimeFrom(itr),
WeekDaysWorkTimeUntil(itr));
ranges += 1;
}
}
QTime const &lastWorktimeTo = worktime[ranges-1].getTimeUntil();
// qCritical() << "start" << start.toString(Qt::ISODate)
// << "current" << current.toString(Qt::ISODate) << lastWorktimeTo;
// find worktime range to start with
int currentRange = 0;
if (!isSpecialDay) {
if (start != current) { // on next day
current.setTime(worktime[currentRange].getTimeFrom());
} else {
// check if inputDate is located inside a valid worktime-range...
if ((currentRange = findWorkTimeRange(current, worktime, ranges)) == -1) {
if (!prepaid && carryOverNotSet) { // parking is not allowed
return Ticket(start, QDateTime(), durationMinutesNetto, 0,
0, Ticket::s[INVALID_FROM_DATETIME]);
}
// find the next worktime-range (on the same day), and start from there
if ((currentRange = findNextWorkTimeRange(current, worktime, ranges)) == -1) {
end = current;
continue;
}
current.setTime(worktime[currentRange].getTimeFrom());
}
}
}
// qCritical() << "current" << current.toString(Qt::ISODate);
for (int w = currentRange; w < ranges; ++w, ++totalTimeRanges) {
if (durationMinutes > 0) {
QTime const &worktime_from = worktime[w].getTimeFrom();
QTime const &worktime_to = worktime[w].getTimeUntil();
if (totalTimeRanges) {
// durationMinutes are always meant as netto time and
// the time between worktime-ranges are free.
current.setTime(worktime_from);
}
if (price == 0) {
end = current;
current.setTime(QTime());
continue;
}
if (current.time() == worktime_to) {
end = current;
current.setTime(QTime());
continue;
}
// Check prepaid
if (!prepaid) {
if ((current.time() < worktime_from) || (current.time() > worktime_to)) {
qDebug() << "[STOP] * Ticket is not valid * ";
return Ticket();
}
} else {
//qDebug() << "* PREPAID MODE ACTIVE *";
//qCritical() << "current" << current.toString(Qt::ISODate) << worktime_from << lastWorktimeTo;
if (current.time() < worktime_from) {
current.setTime(worktime_from);
end = current;
} else if(current.time() > lastWorktimeTo) {
//qDebug() << " *** PREPAID *** Current time is past the time range end, searching for next available day";
end = current;
current.setTime(QTime());
continue;
}
}
while(durationMinutes > 0) {
// Check for active year period
if (!IsYearPeriodActive(cfg, current)) {
return Ticket();
}
if(current.time() >= lastWorktimeTo) {
// Go to next day if minutes not spent
if (carryOverNotSet) {
// no carry_over, so stop computation
break;
}
current.setTime(QTime());
break; // stop while, and continue in outer loop
} else {
//qCritical() << "current" << current.toString(Qt::ISODate) << worktime_to;
if(current.time() < worktime_to) {
// Increment input date minutes for each monetary unit
current = current.addSecs(60);
end = current;
durationMinutes -= 1;
//costFromDuration += price_per_unit;
costFromDuration += price;
//qCritical() << "current" << current.toString(Qt::ISODate);
} else break;
}
} // while(durationMinutes > 0) {
} // if (durationMinutes > 0) {
} // for (int w = currentRange; w < ranges; ++w, ++totalTimeRanges) {
} // for (current = start; durationMinutes > 0; current = current.addDays(1)) {
int durationMinutesBrutto = start.secsTo(end) / 60;
return
Ticket(start, end, durationMinutesNetto, durationMinutesBrutto,
ceil(Utilities::CalculatePricePerUnit(costFromDuration, durationUnit)),
Ticket::s[VALID]);
}
Ticket Calculator::private_GetDurationFromCost(Configuration *cfg,
QDateTime const &start,
uint32_t cost,
bool prepaid) {
// Get input date
QDateTime current = start;
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
static const bool carryOverNotSet = isCarryOverNotSet(cfg, paymentMethodId);
static const uint32_t minParkingTimeMinutes = std::max(Utilities::getMinimalParkingTime(cfg, paymentMethodId), 0);
static const uint32_t maxParkingTimeMinutes = std::max(Utilities::getMaximalParkingTime(cfg, paymentMethodId), 0);
static const uint32_t minParkingPrice = getMinimalParkingPrice(cfg, paymentMethodId);
// static const bool checkMinMaxMinutes = (minParkingTimeMinutes < maxParkingTimeMinutes);
static const uint32_t weekDaysPrice = Utilities::computeWeekDaysPrice(cfg, paymentMethodId);
static const uint32_t weekDaysDurationUnit = Utilities::computeWeekDaysDurationUnit(cfg, paymentMethodId);
static const uint32_t specialDaysDurationUnit = 60;
if(cost < minParkingPrice) {
uint64_t const durationMinutes = GetDurationForPrice(cfg, cost);
return Ticket(start, current, durationMinutes, durationMinutes,
cost, Ticket::s[INVALID_PRICE]);
}
if (minParkingTimeMinutes >= maxParkingTimeMinutes) {
// TODO
return Ticket();
}
if (maxParkingTimeMinutes <= minParkingTimeMinutes) {
// TODO
return Ticket();
}
uint32_t durationMinutesNetto = 0;
double moneyLeft = cost;
double durationUnit = 1;
int specialDayId = -1;
bool isSpecialDay = false;
QDateTime end = start;
int totalTimeRanges = 0;
double price = 0;
for (current = start; moneyLeft > 0 && moneyLeft >= price; current = current.addDays(1)) {
int const weekdayId = current.date().dayOfWeek();
specialDayId = -1;
// find worktime ranges for the current day
int const timeRanges = std::max((int)cfg->WeekDaysWorktime.count(weekdayId), 1);
QScopedArrayPointer<TariffTimeRange> worktime(new TariffTimeRange[timeRanges]);
int ranges = 0;
uint32_t p = 0;
if((isSpecialDay = Utilities::CheckSpecialDay(cfg, current, &specialDayId, &p))) {
// Set special day price:
durationUnit = specialDaysDurationUnit;
price = p / durationUnit;
price = std::round(price * 1000.0) / 1000.0;
worktime[ranges].setTimeRange(SpecialDaysWorkTimeFrom(cfg, specialDayId),
SpecialDaysWorkTimeUntil(cfg, specialDayId));
ranges = 1;
} else {
// Set new price for the normal day: do not use a floating-point type
// for the price, rather compute with integers. Only at the very end of
// the computation the price is divided by durationUnit.
price = weekDaysPrice;
durationUnit = weekDaysDurationUnit;
price /= durationUnit;
price = std::round(price * 1000.0) / 1000.0; // round to 3 decimals
// If no working day found, skip it (epsecially Sundays!)
if (cfg->WeekDaysWorktime.count(weekdayId) <= 0) {
// qDebug() << "No workday found, trying to find next available day";
end = current;
current.setTime(QTime()); // start at midnight on the next day
continue;
}
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
worktime[ranges].setTimeRange(WeekDaysWorkTimeFrom(itr),
WeekDaysWorkTimeUntil(itr));
ranges += 1;
}
}
QTime const &lastWorktimeTo = worktime[ranges-1].getTimeUntil();
// find worktime range to start with
int currentRange = 0;
if (!isSpecialDay) {
if (start != current) { // on next day
current.setTime(worktime[currentRange].getTimeFrom());
} else {
// check if inputDate is located inside a valid worktime-range...
if ((currentRange = findWorkTimeRange(current, worktime, ranges)) == -1) {
if (!prepaid && carryOverNotSet) { // parking is not allowed
return Ticket(start, QDateTime(), durationMinutesNetto, 0,
0, Ticket::s[INVALID_FROM_DATETIME]);
}
// find the next worktime-range (on the same day), and start from there
if ((currentRange = findNextWorkTimeRange(current, worktime, ranges)) == -1) {
end = current;
continue;
}
current.setTime(worktime[currentRange].getTimeFrom());
}
}
}
for (int w = currentRange; w < ranges; ++w, ++totalTimeRanges) {
if (moneyLeft > 0) {
QTime const &worktime_from = worktime[w].getTimeFrom();
QTime const &worktime_to = worktime[w].getTimeUntil();
if (totalTimeRanges) {
// durationMinutes are always meant as netto time and
// the time between worktime-ranges are free.
current.setTime(worktime_from);
}
if (price == 0) {
// inputDate = inputDate.addDays(1);
// inputDate.setTime(worktime_from);
end = current;
current.setTime(QTime());
continue;
}
if (current.time() == worktime_to) {
end = current;
current.setTime(QTime());
continue;
}
// Check prepaid
if (!prepaid) {
if (current.time() < worktime_from) {
qDebug() << "[STOP] TICKET IS NOT VALID: "
<< QString("%1 (current) < %2 (start)")
.arg(current.toString(Qt::ISODate)
.arg(worktime_from.toString(Qt::ISODate)));
return Ticket();
} else
if (current.time() > worktime_to) {
qDebug() << "[STOP] TICKET IS NOT VALID: "
<< QString("%1 (current) > %2 (end)")
.arg(current.toString(Qt::ISODate)
.arg(worktime_to.toString(Qt::ISODate)));
return Ticket();
}
} else {
if (current.time() < worktime_from) {
qDebug() << "*** PREPAID *** Current time is before time range start, fast-forward to start"
<< worktime_from.toString(Qt::ISODate);
current.setTime(worktime_from);
end = current;
} else if(current.time() > lastWorktimeTo) {
qDebug() << " *** PREPAID *** Current time is past the time range end, searching for next available day";
end = current;
current.setTime(QTime());
continue;
}
}
while(moneyLeft >= price) {
// Check for active year period
if (!IsYearPeriodActive(cfg, current)) {
return Ticket();
}
// if(durationMinutesNetto >= maxParkingTimeMinutes) {
// might be useful for overpayment
// durationMinutesNetto = maxParkingTimeMinutes;
// int durationMinutesBrutto = start.secsTo(end) / 60;
//
// return
// Ticket(start, end, durationMinutesNetto,
// durationMinutesBrutto, cost, Ticket::s[INVALID_PRICE]);
//
// }
if(current.time() >= lastWorktimeTo) {
// Go to next day if minutes not spent
if (carryOverNotSet) {
// no carry_over, so stop computation
break;
}
current.setTime(QTime());
break; // stop while, and continue in outer loop
} else {
if(current.time() < worktime_to) {
// Increment input date minutes for each monetary unit
durationMinutesNetto += 1;
moneyLeft -= price;
moneyLeft = std::round(moneyLeft * 1000.0) / 1000.0;
current = current.addSecs(60);
//qCritical() << "moneyLeft" << moneyLeft
// << "durationMinutesNetto" << durationMinutesNetto
// << "current" << current.toString(Qt::ISODate);
if(durationMinutesNetto <= maxParkingTimeMinutes) {
// stop updating of end-date if parking time is
// overshot
end = current;
}
} else break;
}
} // while(durationMinutes > 0) {
} // if (durationMinutes > 0) {
} // for (int w = currentRange; w < ranges; ++w, ++totalTimeRanges) {
} // for (current = start; durationMinutes > 0; current = current.addDays(1)) {
int durationMinutesBrutto = start.secsTo(end) / 60;
//qCritical() << "start" << start.toString(Qt::ISODate) << "end"
// << end.toString(Qt::ISODate) << durationMinutesBrutto;
return
Ticket(start, end, durationMinutesNetto, durationMinutesBrutto,
cost, Ticket::s[VALID]);
}
QList<int> Calculator::GetPriceSteps(Configuration * /*cfg*/) const {
return QList<int>();
}
QList<int> Calculator::GetTimeSteps(Configuration *cfg) const {
if (m_timeSteps.size() > 0) {
//qCritical() << __PRETTY_FUNCTION__ << "timeSteps:" << m_timeSteps;
return m_timeSteps;
}
QDateTime start = QDateTime::currentDateTime();
start.setTime(QTime(start.time().hour(), start.time().minute(), 0));
int const pop_id = cfg->getPaymentOptions().pop_id;
int const pop_carry_over = cfg->getPaymentOptions().pop_carry_over;
int const pop_time_step_config = cfg->getPaymentOptions().pop_time_step_config;
static PaymentMethod const paymentMethodId = Utilities::getPaymentMethodId(cfg);
qCritical() << __func__ << ":" << __LINE__ << " start parking time:" << start.toString(Qt::ISODate);
qCritical() << __func__ << ":" << __LINE__ << " payment option id:" << pop_id;
qCritical() << __func__ << ":" << __LINE__ << "payment option carry over:" << pop_carry_over;
if (pop_time_step_config == (int)ATBTimeStepConfig::TimeStepConfig::DYNAMIC) {
//qCritical() << __PRETTY_FUNCTION__ << "payment option time step config:" << "TimeStepConfig::DYNAMIC";
if (paymentMethodId == PaymentMethod::Progressive) { // e.g. neuhauser kirchdorf (743)
std::size_t const s = cfg->TimeRange.size();
for (std::size_t id = 1; id <= s; ++id) {
int const step = Utilities::getTimeRangeStep(cfg, id, paymentMethodId);
m_timeSteps.append(step);
}
} else {
uint16_t timeStepCompensation = 0;
if (pop_carry_over) {
int const pop_carry_over_time_range_id = cfg->getPaymentOptions().pop_carry_over_time_range_id;
QTime const carryOverTimeRangeFrom = cfg->TimeRange.find(pop_carry_over_time_range_id)->second.time_range_from;
QTime const carryOverTimeRangeTo = cfg->TimeRange.find(pop_carry_over_time_range_id)->second.time_range_to;
if (carryOverTimeRangeFrom.secsTo(carryOverTimeRangeTo) <= 60) { // carry over time point, usually 00:00:00
if (carryOverTimeRangeFrom == QTime(0, 0, 0)) {
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr) {
int const durationId = itr->second.pra_payment_unit_id;
auto search = cfg->Duration.find(durationId);
if (search != cfg->Duration.end()) {
ATBDuration duration = search->second;
if (durationId == 1) {
QDateTime carryOver = start;
carryOver = carryOver.addDays(1);
carryOver.setTime(QTime(0, 0, 0));
int const timeStep = std::ceil(start.secsTo(carryOver) / 60.0);
if (timeStep < duration.pun_duration_min || timeStep > duration.pun_duration_max) {
qCritical()
<< QString("ERROR timeStep (%1) < durationMin (%2) || timeStep (%3)) > durationMax (%4)")
.arg(timeStep).arg(duration.pun_duration_min)
.arg(timeStep).arg(duration.pun_duration_max);
break;
}
qCritical() << __PRETTY_FUNCTION__ << "configured minimal parking time:" << cfg->getPaymentOptions().pop_min_time;
// set dynamic minimal parking time
cfg->getPaymentOptions().pop_min_time = timeStep;
qCritical() << __PRETTY_FUNCTION__ << " computed minimal parking time:" << cfg->getPaymentOptions().pop_min_time;
duration.pun_duration = timeStep;
timeStepCompensation = duration.pun_duration_max - duration.pun_duration;
m_timeSteps << duration.pun_duration;
} else {
duration.pun_duration = duration.pun_duration_max - timeStepCompensation;
m_timeSteps << duration.pun_duration;;
}
cfg->Duration.erase(search);
cfg->Duration.insert(pair<int, ATBDuration>(duration.pun_id, duration));
} else { // if (search != cfg->Duration.end()) {
// TODO
}
}
} else { // if (carryOverTimeRangeFrom == QTime(0, 0, 0)) {
// TODO
}
} else { // if (carryOverTimeRangeFrom == carryOverTimeRangeTo) {
// TODO
}
} else { // if (pop_carry_over) {
// TODO
}
}
} else {
qCritical() << __PRETTY_FUNCTION__ << "payment option time step config:" << "TimeStepConfig::STATIC";
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr)
{
int const durationId = itr->second.pra_payment_unit_id;
int const durationUnit = cfg->Duration.find(durationId)->second.pun_duration;
m_timeSteps << durationUnit;
}
}
qCritical() << __PRETTY_FUNCTION__ << "NEW timeSteps:" << m_timeSteps;
return m_timeSteps;
}
uint32_t Calculator::GetPriceForTimeStep(Configuration *cfg, int timeStep) const {
int const pop_id = cfg->getPaymentOptions().pop_id;
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr)
{
int const payment_unit_id = itr->second.pra_payment_unit_id;
int const pun_id = cfg->Duration.find(payment_unit_id)->second.pun_id;
Q_ASSERT(pun_id == payment_unit_id);
int const pun_duration = cfg->Duration.find(payment_unit_id)->second.pun_duration;
if (timeStep == pun_duration) {
return (uint32_t)(itr->second.pra_price);
}
}
return 0;
}
uint32_t Calculator::GetDurationForPrice(Configuration *cfg, int price) const {
int const pop_id = cfg->getPaymentOptions().pop_id;
uint32_t duration = 0;
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr)
{
int const durationId = itr->second.pra_payment_unit_id;
int const pra_price = itr->second.pra_price;
uint32_t const durationUnit = cfg->Duration.find(durationId)->second.pun_duration;
if (pra_price == price) {
return durationUnit;
}
if (pra_price < price) {
duration = durationUnit;
}
}
return duration;
}
std::optional<struct price_t>
Calculator::GetDailyTicketPrice(Configuration* cfg,
QDateTime const &startDatetime,
QDateTime &endTime,
PERMIT_TYPE permitType) {
struct price_t price;
std::optional<struct price_t> value;
std::optional<ATBWeekDaysWorktime> workTime =
cfg->getWeekDayWorkTime(startDatetime.time(),
(Qt::DayOfWeek)startDatetime.date().dayOfWeek());
if (workTime) {
ATBWeekDaysWorktime const &wt = workTime.value();
endTime = startDatetime;
endTime.setTime(QTime::fromString(wt.pwd_time_to.c_str(), Qt::ISODate));
std::optional<QVector<ATBDailyTicket>> dailyTickets = cfg->getDailyTicketsForAllKeys();
if (dailyTickets) {
QVector<ATBDailyTicket> const tickets = dailyTickets.value();
switch (permitType) {
case PERMIT_TYPE::DAY_TICKET_ADULT: {
std::optional<ATBCustomer> c = cfg->getCustomerForType(ATBCustomer::CustomerType::ADULT);
if (c) {
for (QVector<ATBDailyTicket>::size_type i=0; i<tickets.size(); ++i) {
if (tickets[i].daily_ticket_clearance_customer_ids.contains(c.value().cust_id)) {
int priceId = tickets[i].daily_ticket_price_id;
QVector<ATBPaymentOption> const &paymentOptions = cfg->getAllPaymentOptions();
for (QVector<ATBPaymentOption>::size_type j=0; j < paymentOptions.size(); ++j) {
int const pop_id = paymentOptions.at(j).pop_id;
std::optional<QVector<ATBPaymentRate>> const &paymentRates = cfg->getPaymentRateForKey(pop_id);
if (paymentRates) {
QVector<ATBPaymentRate> const &pr = paymentRates.value();
for (QVector<ATBPaymentRate>::size_type k=0; k < pr.size(); ++k) {
if (pr.at(k).pra_payment_option_id == pop_id) {
if (priceId == pr.at(k).pra_payment_unit_id) {
price.netto = pr.at(k).pra_price;
value = value.value_or(price);
}
}
}
}
}
}
}
}
} break;
case PERMIT_TYPE::DAY_TICKET_TEEN: {
std::optional<ATBCustomer> c = cfg->getCustomerForType(ATBCustomer::CustomerType::TEEN);
if (c) {
for (QVector<ATBDailyTicket>::size_type i=0; i<tickets.size(); ++i) {
if (tickets[i].daily_ticket_clearance_customer_ids.contains(c.value().cust_id)) {
int priceId = tickets[i].daily_ticket_price_id;
QVector<ATBPaymentOption> const &paymentOptions = cfg->getAllPaymentOptions();
for (QVector<ATBPaymentOption>::size_type j=0; j < paymentOptions.size(); ++j) {
int const pop_id = paymentOptions.at(j).pop_id;
std::optional<QVector<ATBPaymentRate>> const &paymentRates = cfg->getPaymentRateForKey(pop_id);
if (paymentRates) {
QVector<ATBPaymentRate> const &pr = paymentRates.value();
for (QVector<ATBPaymentRate>::size_type k=0; k < pr.size(); ++k) {
if (pr.at(k).pra_payment_option_id == pop_id) {
if (priceId == pr.at(k).pra_payment_unit_id) {
price.netto = pr.at(k).pra_price;
value = value.value_or(price);
}
}
}
}
}
}
}
}
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD: {
std::optional<ATBCustomer> c = cfg->getCustomerForType(ATBCustomer::CustomerType::CHILD);
if (c) {
for (QVector<ATBDailyTicket>::size_type i=0; i<tickets.size(); ++i) {
if (tickets[i].daily_ticket_clearance_customer_ids.contains(c.value().cust_id)) {
int priceId = tickets[i].daily_ticket_price_id;
QVector<ATBPaymentOption> const &paymentOptions = cfg->getAllPaymentOptions();
for (QVector<ATBPaymentOption>::size_type j=0; j < paymentOptions.size(); ++j) {
int const pop_id = paymentOptions.at(j).pop_id;
std::optional<QVector<ATBPaymentRate>> const &paymentRates = cfg->getPaymentRateForKey(pop_id);
if (paymentRates) {
QVector<ATBPaymentRate> const &pr = paymentRates.value();
for (QVector<ATBPaymentRate>::size_type k=0; k < pr.size(); ++k) {
if (pr.at(k).pra_payment_option_id == pop_id) {
if (priceId == pr.at(k).pra_payment_unit_id) {
price.netto = pr.at(k).pra_price;
value = value.value_or(price);
}
}
}
}
}
}
}
}
}
// [[fallthrough]];
case PERMIT_TYPE::SHORT_TERM_PARKING: {
}
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET: {
}
// [[fallthrough]];
case PERMIT_TYPE::SZEGED_START:
// [[fallthrough]];
case PERMIT_TYPE::SZEGED_STOP:
// [[fallthrough]];
case PERMIT_TYPE::INVALID:
break;
}
} else {
// for projects which have not defined a daily ticket in their
// tariff-files (e.g. szeged)
price.netto = cfg->getPaymentOptions().pop_daily_card_price;
qCritical() << "( GetDailyTicketPrice():" << __LINE__ << ")";
qCritical() << " start:" << startDatetime.toString(Qt::ISODate);
qCritical() << " workTime from:" << QTime::fromString(QString(wt.pwd_time_from.c_str()), Qt::ISODate);
qCritical() << " workTime to:" << QTime::fromString(QString(wt.pwd_time_to.c_str()), Qt::ISODate);
qCritical() << "daily_ticket_card_price:" << price.netto;
value = value.value_or(price);
}
}
return value;
}