diff --git a/library/src/calculator_functions.cpp b/library/src/calculator_functions.cpp index c0b0ce8..abb985c 100644 --- a/library/src/calculator_functions.cpp +++ b/library/src/calculator_functions.cpp @@ -408,15 +408,15 @@ double Calculator::GetCostFromDuration(Configuration* cfg, QDateTime start = start_datetime; Ticket t = private_GetCostFromDuration(cfg, start, - end_datetime, durationMinutes, - nextDay, prepaid); + durationMinutes, + prepaid); if (t) { qCritical().noquote() << t; - - return t.getPrice(); } - return -1; + end_datetime = t.getValidUntil(); + + return t.getPrice(); } int Calculator::getMinimalParkingTime(Configuration const *cfg, PaymentMethod methodId) { @@ -427,20 +427,18 @@ int Calculator::getMaximalParkingTime(Configuration const *cfg, PaymentMethod me return std::max((int)cfg->PaymentOption.find(methodId)->second.pop_max_time, 0); } -bool Calculator::checkDurationMinutes(bool overtime, - int minParkingTime, +bool Calculator::checkDurationMinutes(int minParkingTime, int maxParkingTime, int durationMinutes) { - if (!overtime) { - 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; - } + 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; } @@ -459,8 +457,8 @@ int Calculator::findWorkTimeRange(QDateTime const &dt, } int Calculator::findNextWorkTimeRange(QDateTime const &dt, - QScopedArrayPointer const &worktime, - size_t size) { + QScopedArrayPointer const &worktime, + size_t size) { int nextWorkTimeRange = -1; for (size_t w = 0; w < size; ++w) { QTime const &worktime_from = worktime[w].getTimeFrom(); @@ -488,20 +486,18 @@ using namespace Utilities; Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg, QDateTime const &start, - QDateTime &end, - int &durationMinutes, - bool nextDay, - bool prepaid, - bool overtime) { + int durationMinutes, // Netto + bool prepaid) { static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg); static const bool carryOverNotSet = isCarryOverNotSet(cfg, paymentMethodId); - static int const minParkingTimeMinutes = getMinimalParkingTime(cfg, paymentMethodId); - static int const maxParkingTimeMinutes = getMaximalParkingTime(cfg, paymentMethodId); - - static bool const checkMinMaxMinutes = (minParkingTimeMinutes < maxParkingTimeMinutes); - + static const int minParkingTimeMinutes = getMinimalParkingTime(cfg, paymentMethodId); + static const int maxParkingTimeMinutes = getMaximalParkingTime(cfg, paymentMethodId); + static const bool checkMinMaxMinutes = (minParkingTimeMinutes < maxParkingTimeMinutes); static const int durationMinutesNetto = durationMinutes; + static const uint32_t weekDaysPrice = computeWeekDaysPrice(cfg, paymentMethodId); + static const double weekDaysDurationUnit = computeWeekDaysDurationUnit(cfg, paymentMethodId); + static const double specialDaysDurationUnit = 60.0; if (!checkMinMaxMinutes) { qCritical() << QString( @@ -510,204 +506,162 @@ Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg, return Ticket(); } - if (!checkDurationMinutes(overtime, minParkingTimeMinutes, + if (!checkDurationMinutes(minParkingTimeMinutes, maxParkingTimeMinutes, durationMinutes)) { return Ticket(); } - QDateTime inputDate = start; - - int const weekdayId = inputDate.date().dayOfWeek(); - uint32_t price = 0; - double durationUnit = 60.0; - - int current_special_day_id = -1; - - // there might be more than 1 worktime ranges per day - int const timeRanges = std::max((int)cfg->WeekDaysWorktime.count(weekdayId), 1); - QScopedArrayPointer worktime(new TariffTimeRange[timeRanges]); - int ranges = 0; - - if(Utilities::CheckSpecialDay(cfg, inputDate, ¤t_special_day_id, &price)) { - // Set special day price: - durationUnit = 60.0; - worktime[ranges].setTimeRange(SpecialDaysWorkTimeFrom(cfg, current_special_day_id), - SpecialDaysWorkTimeUntil(cfg, current_special_day_id)); - 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. - int pop_id = cfg->PaymentOption.find(paymentMethodId)->second.pop_id; - price = cfg->PaymentRate.find(pop_id)->second.pra_price; - - int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id; - durationUnit = cfg->Duration.find(durationId)->second.pun_duration; - - // If no working day found, skip it (recursively call method again) - if (cfg->WeekDaysWorktime.count(weekdayId) <= 0) { - // When no workday found, go to next available day - qDebug() << "No workday found, trying to find next available day"; - inputDate = inputDate.addDays(1); - return private_GetCostFromDuration(cfg, inputDate, end, durationMinutes, true, prepaid, overtime); - } - - using WTIterator = std::multimap::const_iterator; - std::pair p = cfg->WeekDaysWorktime.equal_range(weekdayId); - - for (WTIterator itr = p.first; itr != p.second; ++itr) { - worktime[ranges].setTimeRange(WeekDaysWorkTimeFrom(itr), - WeekDaysWorkTimeUntil(itr)); - ranges += 1; - } - } - uint32_t costFromDuration = 0; - QTime const &lastWorktimeTo = worktime[ranges-1].getTimeUntil(); - int currentRange = -1; + double durationUnit = 0.0; + int specialDayId = -1; + bool isSpecialDay = false; + Ticket ticket; + QDateTime end = start; + QDateTime current; + int totalTimeRanges = 0; - if (nextDay) { // this means the function has been called recursively - currentRange = 0; - inputDate.setTime(worktime[currentRange].getTimeFrom()); - } else { - // check if inputDate is located inside a valid worktime-range... - currentRange = findWorkTimeRange(inputDate, worktime, ranges); - if (currentRange == -1) { // no... - if (!prepaid) { // parking is not allowed - return Ticket(start, end, durationMinutesNetto, 0, - 0, Ticket::s[INVALID_FROM_DATETIME]); - } - // find the next worktime-range (on the same day), and start from there - currentRange = findNextWorkTimeRange(inputDate, worktime, ranges); - inputDate.setTime(worktime[currentRange].getTimeFrom()); - } - } + for (current = start; durationMinutes > 0; current = current.addDays(1)) { + int const weekdayId = current.date().dayOfWeek(); - for (int w = currentRange; w < ranges; ++w) { - if (durationMinutes > 0) { - QTime const &worktime_from = worktime[w].getTimeFrom(); - QTime const &worktime_to = worktime[w].getTimeUntil(); + specialDayId = -1; - qCritical() << "from" << worktime_from; - qCritical() << "until" << worktime_to; + // find worktime ranges for the current day + int const timeRanges = std::max((int)cfg->WeekDaysWorktime.count(weekdayId), 1); + QScopedArrayPointer worktime(new TariffTimeRange[timeRanges]); + int ranges = 0; - //if (w > 0) { // durationMinutes are always meant as netto time and - // // the time between worktime-ranges are free. - // inputDate.setTime(worktime_from); - //} + 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; - // TODO: hier muss dann der preis hin - if (price == 0) { - inputDate = inputDate.addDays(1); - inputDate.setTime(worktime_from); - Ticket t = private_GetCostFromDuration( - cfg, // TODO: erklaerung - inputDate, - end, durationMinutes, - true, prepaid); - if (!t.isValid()) { - return t; - } - costFromDuration += t.getPrice(); + // 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; } - // If overtime flag is set - // TODO: ueberpruefen, kann man wohl nach oben ziehen - //if (overtime || nextDay) { - // inputDate.setTime(worktime_from); - // overtime = false; - //} + using WTIterator = std::multimap::const_iterator; + std::pair p = cfg->WeekDaysWorktime.equal_range(weekdayId); - qCritical() << "inputDate.time()=" << inputDate.time(); - - // Check prepaid - if (!prepaid) { - if ((inputDate.time() < worktime_from) || (inputDate.time() > worktime_to)) { - qDebug() << "[STOP] * Ticket is not valid * "; - return Ticket(); - } - } else { - qDebug() << "* PREPAID MODE ACTIVE *"; - if (inputDate.time() < worktime_from) { - inputDate.setTime(worktime_from); - //} else if(inputDate.time() > worktime_to) { - } else if(inputDate.time() > lastWorktimeTo) { - qDebug() << " *** PREPAID *** Current time is past the time range end, searching for next available day"; - // wieso ist hier overtime nicht gesetzt - inputDate = inputDate.addDays(1); - Ticket t = private_GetCostFromDuration( - cfg, inputDate, end, - durationMinutes, true, prepaid); - if (!t.isValid()) { - return t; - } - costFromDuration += t.getPrice(); - continue; - } + for (WTIterator itr = p.first; itr != p.second; ++itr) { + worktime[ranges].setTimeRange(WeekDaysWorkTimeFrom(itr), + WeekDaysWorkTimeUntil(itr)); + ranges += 1; } + } - while(durationMinutes > 0) { - // Check for active year period - if (!IsYearPeriodActive(cfg, inputDate)) { - return Ticket(); - } + QTime const &lastWorktimeTo = worktime[ranges-1].getTimeUntil(); - qDebug() << "inputDate" << inputDate.toString(Qt::ISODate); + // find worktime range to start with - if(inputDate.time() >= lastWorktimeTo) { - // Go to next day if minutes not spent - if (carryOverNotSet) { - // no carry_over, so stop computation - break; + 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... + currentRange = findWorkTimeRange(current, worktime, ranges); + if (currentRange == -1) { // no... + if (!prepaid) { // parking is not allowed + return Ticket(start, QDateTime(), durationMinutesNetto, 0, + 0, Ticket::s[INVALID_FROM_DATETIME]); } - - qDebug() << "Reached end of worktime, searching for the next working day"; - - inputDate = inputDate.addDays(1); - inputDate.setTime(QTime()); - overtime = true; - Ticket t = private_GetCostFromDuration( - cfg, inputDate, end, - durationMinutes, true, prepaid, overtime); - if (!t.isValid()) { - return t; - } - costFromDuration += t.getPrice(); - break; // stop while, and continue in outer loop - } else { - if(inputDate.time() < worktime_to) { - // Increment input date minutes for each monetary unit - inputDate = inputDate.addSecs(60); - - qDebug() << "inputDate" << inputDate.toString(Qt::ISODate); - - durationMinutes -= 1; - //costFromDuration += price_per_unit; - costFromDuration += price; - } else break; + // find the next worktime-range (on the same day), and start from there + currentRange = findNextWorkTimeRange(current, worktime, ranges); + current.setTime(worktime[currentRange].getTimeFrom()); } } } - } + 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 (inputDate >= end) { - end = inputDate; - } + if (totalTimeRanges) { + // durationMinutes are always meant as netto time and + // the time between worktime-ranges are free. + current.setTime(worktime_from); + } - if (nextDay == false) { - qDebug() << "GetCostFromDuration(): Valid until:" << end.toString(Qt::ISODate); - } + 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) || (current.time() > worktime_to)) { + qDebug() << "[STOP] * Ticket is not valid * "; + return Ticket(); + } + } else { + qDebug() << "* PREPAID MODE ACTIVE *"; + 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 { + 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; + } 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, - start.secsTo(end) / 60, - nextDay ? - costFromDuration : - llround(Utilities::CalculatePricePerUnit(costFromDuration, durationUnit)), + Ticket(start, end, durationMinutesNetto, durationMinutesBrutto, + llround(Utilities::CalculatePricePerUnit(costFromDuration, durationUnit)), Ticket::s[VALID]); }