From 1d7779f66603d76c6f3fdc4a2dd8a5e2be476535 Mon Sep 17 00:00:00 2001 From: Gerhard Hoffmann Date: Thu, 15 Feb 2024 16:15:28 +0100 Subject: [PATCH] GetCostFromDuration(): implement progressive tariff for Kirchdorf. --- library/src/calculator_functions.cpp | 175 ++++++++++++++++++++++++++- 1 file changed, 174 insertions(+), 1 deletion(-) diff --git a/library/src/calculator_functions.cpp b/library/src/calculator_functions.cpp index 986dadf..1b7cb56 100644 --- a/library/src/calculator_functions.cpp +++ b/library/src/calculator_functions.cpp @@ -255,7 +255,7 @@ CalcState Calculator::isParkingAllowed(Configuration const *cfg, QDateTime const /// double Calculator::GetCostFromDuration(Configuration* cfg, uint8_t payment_option, - const QDateTime start_datetime, + QDateTime &start_datetime, QDateTime &end_datetime, int durationMinutes, bool nextDay, @@ -286,6 +286,179 @@ double Calculator::GetCostFromDuration(Configuration* cfg, 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 timeRanges = 0; + 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 ((timeRanges = 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::const_iterator; + std::pair 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) { + 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 + QDateTime lastCurrent = QDateTime(); + + auto timeRangeIt = cfg->TimeRange.cbegin(); + for (; timeRangeIt != cfg->TimeRange.cend(); ++timeRangeIt) { + using WTIterator = std::multimap::const_iterator; + std::pair 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 (current.addSecs(duration * 60).time() <= to) { + + for(const auto &x: cfg->PaymentRate) { + ATBPaymentRate const rate = x.second; + if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) { + if (minsToCarryOver > 0) { + durationMinutes -= minsToCarryOver; + durationMinutesNetto += minsToCarryOver; + durationMinutesBrutto += minsToCarryOver; + current = current.addSecs(minsToCarryOver*60); + minsToCarryOver = 0; + } else { + 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); + int const minsLeft = lastCurrent.secsTo(current) / 60; + + // mod duration: possibly discard some minutes in + // the next time-range + minsToCarryOver = (durationMinutes - minsLeft) % duration; + + durationMinutes -= minsLeft; + durationMinutesNetto += minsLeft; + durationMinutesBrutto += minsLeft; + + if (minsLeft > 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; + } + } + } + + end_datetime = start.addSecs(durationMinutesBrutto * 60); + return std::max(price, minParkingPrice); + } + } + + end_datetime = QDateTime(); + return 0; } QDateTime start = start_datetime;