From 19428ce46c06ab081567d218c0cf83507be9c4e8 Mon Sep 17 00:00:00 2001 From: Gerhard Hoffmann Date: Fri, 1 Dec 2023 14:24:15 +0100 Subject: [PATCH] implemented both cost and duration functions. to be tested --- library/src/calculator_functions.cpp | 287 ++++++--------------------- 1 file changed, 56 insertions(+), 231 deletions(-) diff --git a/library/src/calculator_functions.cpp b/library/src/calculator_functions.cpp index f3cdd26..7b41f36 100644 --- a/library/src/calculator_functions.cpp +++ b/library/src/calculator_functions.cpp @@ -122,6 +122,8 @@ std::string Calculator::GetDurationFromCost(Configuration* cfg, bool nextDay, bool prepaid) { + Q_UNUSED(payment_option); + Q_UNUSED(nextDay); // Get input date QDateTime inputDate = QDateTime::fromString(start_datetime,Qt::ISODate); @@ -133,224 +135,15 @@ std::string Calculator::GetDurationFromCost(Configuration* cfg, && cfg->SpecialDaysWorktime.size() == 0) { inputDate = inputDate.addSecs(GetDurationForPrice(cfg, price) * 60); - return inputDate.toString(Qt::ISODate).toStdString(); } + Ticket t = private_GetDurationFromCost(cfg, inputDate, price, prepaid); - // Get day of week - int weekdayId = 0; - weekdayId = Utilities::ZellersAlgorithm(inputDate.date().day(),inputDate.date().month(),inputDate.date().year()); + qCritical().noquote() << t; - //Get min and max time defined in JSON - double minMin = 0; - minMin = cfg->getPaymentOptions().pop_min_time; - - double maxMin = 0; - maxMin = cfg->getPaymentOptions().pop_max_time; - - double min_price = 0; - min_price = cfg->getPaymentOptions().pop_min_price; - - if(price < min_price) - { - return "PARKING NOT ALLOWED"; - } - - if (minMin < 0) minMin = 0; - if (maxMin < 0) maxMin = 0; - if (minMin >= maxMin) - { - LOG_ERROR("Error: min_min cannot be greater or equal to max_min"); - return "PARKING NOT ALLOWED"; - } - - if (maxMin <= minMin) - { - LOG_ERROR("Error: max_min cannot be lower or equal than min_min"); - return "PARKING NOT ALLOWED"; - } - - - // Get payment method - uint8_t p_method = PaymentMethod::Undefined; - p_method = payment_option; - LOG_DEBUG("Payment method id: ", (unsigned)p_method); - - // Check special day - double day_price = 0.0f; - int current_special_day_id = -1; - bool is_special_day = Utilities::CheckSpecialDay(cfg, inputDate.toString(Qt::ISODate).toStdString().c_str(), ¤t_special_day_id, &day_price); - LOG_DEBUG("Special day: ", is_special_day); - - double money_left = price; - double price_per_unit = 0.0f; - - QTime worktime_from; - QTime worktime_to; - - if(is_special_day) - { - // Set special day price - price_per_unit = Utilities::CalculatePricePerUnit(day_price); - worktime_from = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from.c_str()); - worktime_to = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to.c_str()); - } - else - { - // Set new price for the normal day - int pop_id = cfg->PaymentOption.find(payment_option)->second.pop_id; - day_price = cfg->PaymentRate.find(pop_id)->second.pra_price; - - int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id; - double durationUnit = cfg->Duration.find(durationId)->second.pun_duration; - price_per_unit = Utilities::CalculatePricePerUnit(day_price,durationUnit); - - // If no working day found, skip it (recursively call method again) - size_t found = 0; - found = cfg->WeekDaysWorktime.count(weekdayId); - - // When no workday found, go to next available day - if(found <=0) - { - LOG_DEBUG("- No workday found, trying to find next available day"); - inputDate = inputDate.addDays(1); - return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left,true,prepaid); - } - worktime_from = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from.c_str()); - worktime_to = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to.c_str()); - } - - if (price_per_unit < 0) price_per_unit = 1.0f; - - // if((price/price_per_unit) < minMin) return "PARKING NOT ALLOWED"; - LOG_DEBUG("Calculated price per minute: ", price_per_unit); - - // If overtime flag is set - if (overtime || nextDay) - { - inputDate.setTime(worktime_from); - overtime = false; - } - - // Check prepaid - if (!prepaid) - { - if ((inputDate.time() < worktime_from) || (inputDate.time() > worktime_to)) - { - LOG_DEBUG("[STOP] * Ticket is not valid * "); - return "PARKING NOT ALLOWED"; - } - } - else - { - LOG_DEBUG("* PREPAID MODE ACTIVE *"); - if (inputDate.time() < worktime_from) - { - inputDate.setTime(worktime_from); - } - else if(inputDate.time() > worktime_to) - { - LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day"); - inputDate = inputDate.addDays(1); - return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left, true); - } - } - - while(true) - { - if((int)money_left <= 0) break; - - // Check year period - bool isYearPeriodActive = false; - - //// Parse input date - int dayCurrent = inputDate.date().day(); - int monthCurrent = inputDate.date().month(); - - // Current date time - int cdt = (monthCurrent * 100) + dayCurrent; - - multimap::iterator year_period_itr; - for (year_period_itr = cfg->YearPeriod.begin(); year_period_itr != cfg->YearPeriod.end(); ++year_period_itr) - { - int dStart = year_period_itr->second.pye_start_day; - int dEnd = year_period_itr->second.pye_end_day; - - int mStart = year_period_itr->second.pye_start_month; - int mEnd = year_period_itr->second.pye_end_month; - - int start = (mStart * 100) + dStart; - int end = (mEnd * 100) + dEnd; - - if (cdt >= start && cdt <= end) { - isYearPeriodActive = true; - break; - } - } - if (!isYearPeriodActive) - { - LOG_DEBUG("Year period is not valid"); - return "PARKING NOT ALLOWED"; - } - - if(total_duration_min > maxMin) - { - total_duration_min = maxMin; - break; - } - - // If reached end of worktime go to next day - if(inputDate.time() >= worktime_to) - { - int carry_over_status = 0; - carry_over_status = cfg->PaymentOption.find(payment_option)->second.pop_carry_over; - if (carry_over_status < 1) break; - - inputDate = inputDate.addDays(1); - overtime = true; - return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left ,true, prepaid); - } - - if(money_left > 1) - inputDate = inputDate.addSecs(60); - - if(price_per_unit > 0) total_duration_min +=1; - money_left -= price_per_unit; - - //qDebug() <<"Timestamp:" << inputDate << ", total duration min: " << total_duration_min << ", money left = " << money_left; - } - - // if ((total_duration_min < minMin) || (price / price_per_unit) < minMin) - // { - // LOG_DEBUG("Total duration is lower than min_min"); - // inputDate.time() = worktime_from; - // total_duration_min = 0; - // } - - double ret_val = 0; - // double calc_price = (int)total_duration_min - (int)price / price_per_unit; - - //if (calc_price > 0 && total_duration_min > 0) - //{ - // inputDate = inputDate.addSecs(-(int)ceil(calc_price) * 60); - //} - - if(price >= min_price && total_duration_min >= minMin) - qDebug() << "GetDurationFromCost(): Valid until: " << inputDate.toString(Qt::ISODate); - else - { - qDebug() << "Parking not allowed"; - total_duration_min = 0; - } - - ret_val = total_duration_min; - if(ret_val < 0) ret_val = 0; - qDebug() << "Duration: " << ret_val; - if (ret_val <= 0) return "PARKING NOT ALLOWED"; - - total_duration_min = 0; - return inputDate.toString(Qt::ISODate).toStdString(); + // TODO: im fehlerfall + return t.getValidUntil().toString(Qt::ISODate).toStdString(); } /////////////////////////////////////// @@ -397,6 +190,9 @@ double Calculator::GetCostFromDuration(Configuration* cfg, int durationMinutes, bool nextDay, bool prepaid) { + Q_UNUSED(payment_option); + Q_UNUSED(nextDay); + if (cfg->YearPeriod.size() == 0 && cfg->SpecialDays.size() == 0 && cfg->SpecialDaysWorktime.size() == 0) @@ -528,6 +324,8 @@ Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg, for (current = start; durationMinutes > 0; current = current.addDays(1)) { int const weekdayId = current.date().dayOfWeek(); + qCritical() << "current" << current.toString(Qt::ISODate) << weekdayId; + specialDayId = -1; // find worktime ranges for the current day @@ -589,6 +387,8 @@ Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg, } } + qCritical() << "current" << current.toString(Qt::ISODate) << currentRange; + for (int w = currentRange; w < ranges; ++w, ++totalTimeRanges) { if (durationMinutes > 0) { QTime const &worktime_from = worktime[w].getTimeFrom(); @@ -600,6 +400,10 @@ Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg, current.setTime(worktime_from); } + qCritical() << "worktime_from" << worktime_from; + qCritical() << "worktime_to" << worktime_to; + qCritical() << "current" << current.toString(Qt::ISODate); + if (price == 0) { // inputDate = inputDate.addDays(1); // inputDate.setTime(worktime_from); @@ -654,6 +458,7 @@ Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg, durationMinutes -= 1; //costFromDuration += price_per_unit; costFromDuration += price; + qCritical() << "current" << current.toString(Qt::ISODate) << durationMinutes << costFromDuration; } else break; } } // while(durationMinutes > 0) { @@ -663,6 +468,9 @@ Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg, int durationMinutesBrutto = start.secsTo(end) / 60; + qCritical() << "start" << start.toString(Qt::ISODate) << "end" << end + << llround(Utilities::CalculatePricePerUnit(costFromDuration, durationUnit)); + return Ticket(start, end, durationMinutesNetto, durationMinutesBrutto, llround(Utilities::CalculatePricePerUnit(costFromDuration, durationUnit)), @@ -672,24 +480,26 @@ Ticket Calculator::private_GetCostFromDuration(Configuration const* cfg, Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, QDateTime const &start, - uint32_t price, + uint32_t cost, bool prepaid) { // Get input date QDateTime current = start; + qCritical() << "current" << current.toString(Qt::ISODate); + // use tariff with structure as for instance Schnau, Koenigsee: // without given YearPeriod, SpecialDays and SpecialDaysWorktime if (cfg->YearPeriod.size() == 0 && cfg->SpecialDays.size() == 0 && cfg->SpecialDaysWorktime.size() == 0) { - uint64_t const durationMinutes = GetDurationForPrice(cfg, price); + uint64_t const durationMinutes = GetDurationForPrice(cfg, cost); uint64_t const durationSeconds = durationMinutes * 60; current = current.addSecs(durationSeconds); return Ticket(start, current, durationMinutes, durationMinutes, - price, Ticket::s[VALID]); + cost, Ticket::s[VALID]); } static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg); @@ -697,15 +507,15 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, static const uint32_t minParkingTimeMinutes = std::max(getMinimalParkingTime(cfg, paymentMethodId), 0); static const uint32_t maxParkingTimeMinutes = std::max(getMaximalParkingTime(cfg, paymentMethodId), 0); static const uint32_t minParkingPrice = getMinimalParkingPrice(cfg, paymentMethodId); - static const bool checkMinMaxMinutes = (minParkingTimeMinutes < maxParkingTimeMinutes); + // static const bool checkMinMaxMinutes = (minParkingTimeMinutes < maxParkingTimeMinutes); static const uint32_t weekDaysPrice = computeWeekDaysPrice(cfg, paymentMethodId); - static const double weekDaysDurationUnit = computeWeekDaysDurationUnit(cfg, paymentMethodId); - static const double specialDaysDurationUnit = 60.0; + static const uint32_t weekDaysDurationUnit = computeWeekDaysDurationUnit(cfg, paymentMethodId); + static const uint32_t specialDaysDurationUnit = 60; - if(price < minParkingPrice) { - uint64_t const durationMinutes = GetDurationForPrice(cfg, price); + if(cost < minParkingPrice) { + uint64_t const durationMinutes = GetDurationForPrice(cfg, cost); return Ticket(start, current, durationMinutes, durationMinutes, - price, Ticket::s[INVALID_PRICE]); + cost, Ticket::s[INVALID_PRICE]); } if (minParkingTimeMinutes >= maxParkingTimeMinutes) { // TODO @@ -716,17 +526,22 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, return Ticket(); } + qCritical() << "current" << current.toString(Qt::ISODate); + uint32_t durationMinutesNetto = 0; - int moneyLeft = price; - //double durationUnit = 0.0; + int moneyLeft = cost; + uint32_t durationUnit = 1; int specialDayId = -1; bool isSpecialDay = false; QDateTime end = start; int totalTimeRanges = 0; + uint32_t price = 0; - for (current = start; moneyLeft > 0; current = current.addDays(1)) { + for (current = start; moneyLeft > 0; current = current.addDays(1), moneyLeft /= durationUnit) { int const weekdayId = current.date().dayOfWeek(); + qCritical() << "current" << current.toString(Qt::ISODate) << weekdayId; + specialDayId = -1; // find worktime ranges for the current day @@ -736,7 +551,7 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, if((isSpecialDay = Utilities::CheckSpecialDay(cfg, current, &specialDayId, &price))) { // Set special day price: - // durationUnit = specialDaysDurationUnit; + durationUnit = specialDaysDurationUnit; worktime[ranges].setTimeRange(SpecialDaysWorkTimeFrom(cfg, specialDayId), SpecialDaysWorkTimeUntil(cfg, specialDayId)); ranges = 1; @@ -745,7 +560,7 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, // 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; + durationUnit = weekDaysDurationUnit; // If no working day found, skip it (epsecially Sundays!) if (cfg->WeekDaysWorktime.count(weekdayId) <= 0) { @@ -765,6 +580,8 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, } } + moneyLeft *= durationUnit; + QTime const &lastWorktimeTo = worktime[ranges-1].getTimeUntil(); // find worktime range to start with @@ -788,6 +605,8 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, } } + qCritical() << "current" << current.toString(Qt::ISODate) << currentRange; + for (int w = currentRange; w < ranges; ++w, ++totalTimeRanges) { if (moneyLeft > 0) { QTime const &worktime_from = worktime[w].getTimeFrom(); @@ -799,6 +618,10 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, current.setTime(worktime_from); } + qCritical() << "worktime_from" << worktime_from; + qCritical() << "worktime_to" << worktime_to; + qCritical() << "current" << current.toString(Qt::ISODate); + if (price == 0) { // inputDate = inputDate.addDays(1); // inputDate.setTime(worktime_from); @@ -852,14 +675,13 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, } else { if(current.time() < worktime_to) { // Increment input date minutes for each monetary unit - if(moneyLeft > 1) { - current = current.addSecs(60); - } + current = current.addSecs(60); end = current; if(price > 0) { durationMinutesNetto +=1; } moneyLeft -= price; + qCritical() << "current" << current.toString(Qt::ISODate) << "moneyLeft" << moneyLeft; } else break; } } // while(durationMinutes > 0) { @@ -869,9 +691,12 @@ Ticket Calculator::private_GetDurationFromCost(Configuration *cfg, int durationMinutesBrutto = start.secsTo(end) / 60; + qCritical() << "start" << start.toString(Qt::ISODate) << "end" + << end.toString(Qt::ISODate) << durationMinutesBrutto; + return Ticket(start, end, durationMinutesNetto, durationMinutesBrutto, - price, Ticket::s[VALID]); + cost, Ticket::s[VALID]); } QList Calculator::GetTimeSteps(Configuration *cfg) const {