436 lines
15 KiB
C++
436 lines
15 KiB
C++
#include "utilities.h"
|
|
#include "tariff_log.h"
|
|
|
|
#include <QDebug>
|
|
#include <algorithm>
|
|
|
|
// static int protection_counter = 0;
|
|
|
|
/// <summary>
|
|
/// Helper function
|
|
/// </summary>
|
|
/// <param name="pra_price"></param>
|
|
/// <returns></returns>
|
|
double Utilities::CalculatePricePerUnit(double pra_price, double durationUnit)
|
|
{
|
|
try
|
|
{
|
|
double price_per_unit = pra_price;
|
|
double unit = durationUnit;
|
|
|
|
if(unit < 0 || unit > 65535 ) unit = 60.0f;
|
|
price_per_unit /= unit; // Divided by 60 because price per unit is set per hour and we are using minutes
|
|
//printf("Price per unit (min) is: %lf\n", price_per_unit);
|
|
return price_per_unit;
|
|
}
|
|
catch (...)
|
|
{
|
|
throw std::invalid_argument("An error has occurred in CalculatePricePerUnit() function\n");
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
time_t Utilities::GetCurrentLocalTime()
|
|
{
|
|
try
|
|
{
|
|
time_t curr_time = time(NULL);
|
|
tm tm_curr_time = {};
|
|
memset(&tm_curr_time, '\0', sizeof(struct tm));
|
|
|
|
tm_curr_time = *localtime(&curr_time);
|
|
curr_time = mktime(&tm_curr_time); //- timezone;
|
|
return curr_time;
|
|
}
|
|
catch (...)
|
|
{
|
|
throw std::invalid_argument("An error has occurred in GetCurrentLocalTime() function\n");
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
int Utilities::ZellersAlgorithm(int day, int month, int year)
|
|
{
|
|
int mon;
|
|
if (month > 2) mon = month; //for march to december month code is same as month
|
|
else {
|
|
mon = (12 + month); //for Jan and Feb, month code will be 13 and 14
|
|
year--; //decrease year for month Jan and Feb
|
|
}
|
|
int y = year % 100; //last two digit
|
|
int c = year / 100; //first two digit
|
|
int w = (day + floor((13 * (mon + 1)) / 5) + y + floor(y / 4) + floor(c / 4) + (5 * c));
|
|
w = ((w + 5) % 7) + 1; //w % 7;
|
|
return w;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
struct tm Utilities::DateToStructTm(const char* dateStr)
|
|
{
|
|
struct tm t = {};
|
|
memset(&t, '\0', sizeof(struct tm));
|
|
|
|
if (dateStr == nullptr || strlen(dateStr) <= 0) throw std::invalid_argument("DateToStructTm has failed parsing date string (null or empty)\n");
|
|
try
|
|
{
|
|
int success = sscanf(dateStr, "%d-%d-%d", &t.tm_year, &t.tm_mon, &t.tm_mday);
|
|
if (success != 3) throw std::invalid_argument("DateToStructTm() has failed parsing datetime string\n");
|
|
|
|
t.tm_year = t.tm_year - 1900;
|
|
t.tm_mon = t.tm_mon - 1;
|
|
t.tm_isdst = 0;
|
|
return t;
|
|
}
|
|
catch (...)
|
|
{
|
|
throw std::invalid_argument("An error has occurred in DateToStructTm() function\n");
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
struct tm Utilities::TimeToStructTm(const char* timeStr, int year, int mon, int mday, int wday)
|
|
{
|
|
struct tm t = {};
|
|
memset(&t, '\0', sizeof(struct tm));
|
|
|
|
if (timeStr == nullptr || strlen(timeStr) <= 0) throw std::invalid_argument("TimeToStructTm() has failed parsing time string (null or empty)\n");
|
|
try
|
|
{
|
|
int success_time = sscanf(timeStr, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
|
|
if (success_time != 3) throw std::invalid_argument("TimeToStructTm() has failed parsing time string\n");
|
|
|
|
struct tm tm_struct;
|
|
t.tm_year = year;
|
|
t.tm_mon = mon;
|
|
t.tm_mday = mday;
|
|
t.tm_wday = wday;
|
|
t.tm_isdst = 0;
|
|
return t;
|
|
}
|
|
catch (...)
|
|
{
|
|
throw std::invalid_argument("An error has occurred in TimeToStructTm() function\n");
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
struct tm Utilities::DateTimeToStructTm(const char* dateTimeStr)
|
|
{
|
|
struct tm t = {};
|
|
memset(&t, '\0', sizeof(struct tm));
|
|
|
|
if (dateTimeStr == nullptr || strlen(dateTimeStr) <= 0) throw std::invalid_argument("DateTimeToStructTm() has failed parsing date string (null or empty)");
|
|
try
|
|
{
|
|
int success = sscanf(dateTimeStr, "%d-%d-%dT%d:%d:%dZ", &t.tm_year, &t.tm_mon, &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec);
|
|
if (success != 6) throw std::invalid_argument("DateTimeToStructTm() has failed parsing datetime string\n");
|
|
|
|
t.tm_year = t.tm_year - 1900;
|
|
t.tm_mon = t.tm_mon - 1;
|
|
t.tm_isdst = 0;
|
|
return t;
|
|
}
|
|
catch (...)
|
|
{
|
|
throw std::invalid_argument("An error has occurred in DateTimeToStructTm() function\n");
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
DayOfWeek Utilities::GetDayOfWeek(struct tm* t)
|
|
{
|
|
if (t == nullptr) throw std::invalid_argument("GetDayOfWeekFromDate() => parameter 't' is null\n");
|
|
try
|
|
{
|
|
int d = t->tm_mday;
|
|
int m = t->tm_mon + 1;
|
|
int y = t->tm_year + 1900;
|
|
|
|
int wd = Utilities::ZellersAlgorithm(d, m, y);
|
|
return static_cast<DayOfWeek>(wd);
|
|
}
|
|
catch (...)
|
|
{
|
|
throw std::invalid_argument("An error has occurred in GetDayOfWeekFromDate() function\n");
|
|
}
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
bool Utilities::IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime_tm)
|
|
{
|
|
if (cfg == nullptr) throw std::invalid_argument("IsYearPeriodActive() = > Configuration not set\n");
|
|
if (currentDateTime_tm == nullptr) throw std::invalid_argument("IsYearPeriodActive() = > Current datetime not set\n");
|
|
|
|
try
|
|
{
|
|
//// Parse input date
|
|
int dayCurrent = currentDateTime_tm->tm_mday;
|
|
int monthCurrent = currentDateTime_tm->tm_mon + 1;
|
|
|
|
// Current date time
|
|
int cdt = (monthCurrent * 100) + dayCurrent;
|
|
|
|
multimap<int, ATBPeriodYear>::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)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
catch (...)
|
|
{
|
|
cout << "IsYearPeriodActive() => An exception has occurred, ignoring check, returning true" << endl;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool Utilities::IsYearPeriodActive(Configuration const *cfg, QDateTime const &dt) {
|
|
if ((cfg->YearPeriod.size() > 0) &&
|
|
std::none_of(cfg->YearPeriod.cbegin(),
|
|
cfg->YearPeriod.cend(),
|
|
[&dt](std::pair<int, ATBPeriodYear> const &year) {
|
|
QDate const d(2004, // 2004 is a leap year
|
|
dt.date().month(),
|
|
dt.date().day());
|
|
QDate const s(2004, year.second.pye_start_month, year.second.pye_start_day);
|
|
QDate const e(2004, year.second.pye_end_month, year.second.pye_end_day);
|
|
return (d >= s && d <= e);
|
|
})) {
|
|
qCritical() << "NO VALID YEAR PERIOD";
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/// <inheritdoc/>
|
|
bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice)
|
|
{
|
|
try
|
|
{
|
|
*specialDayId = -1;
|
|
*specialDayPrice = 0.0f;
|
|
|
|
if (cfg == nullptr) throw std::invalid_argument("CheckSpecialDay() => configuration is not set\n");
|
|
if (currentDateTimeStr == nullptr) throw std::invalid_argument("CheckSpecialDay() => invalid date/time string set\n");
|
|
|
|
|
|
struct tm current_tm = Utilities::DateTimeToStructTm(currentDateTimeStr);
|
|
//cout << "CheckSpecialDay() => Current: " << asctime(¤t_tm) << endl;
|
|
|
|
multimap<int, ATBSpecialDays>::iterator spec_days_itr;
|
|
|
|
for (spec_days_itr = cfg->SpecialDays.begin(); spec_days_itr != cfg->SpecialDays.end(); spec_days_itr++)
|
|
{
|
|
int repeat_every_year = 0;
|
|
repeat_every_year = spec_days_itr->second.ped_year;
|
|
|
|
string start = spec_days_itr->second.ped_date_start;
|
|
if (start.length() <= 0) continue;
|
|
//cout << "CheckSpecialDay() => Start: " << start << endl;
|
|
|
|
string end = spec_days_itr->second.ped_date_end;
|
|
if (end.length() <= 0) continue;
|
|
//cout << "CheckSpecialDay() => End: " << end << endl;
|
|
|
|
struct tm start_tm = Utilities::DateToStructTm(start.c_str());
|
|
//cout << "CheckSpecialDay() => Start: " << asctime(&start_tm) << endl;
|
|
|
|
struct tm end_tm = Utilities::DateToStructTm(end.c_str());
|
|
//cout << "CheckSpecialDay() => End: " << asctime(&end_tm) << endl;
|
|
|
|
if (repeat_every_year <= 0)
|
|
{
|
|
//cout << "CheckSpecialDay() => Repeat every year is: 0" << endl;
|
|
if ((current_tm.tm_year == start_tm.tm_year) && (current_tm.tm_year == end_tm.tm_year))
|
|
{
|
|
if ((current_tm.tm_mon >= start_tm.tm_mon) && (current_tm.tm_mon <= end_tm.tm_mon))
|
|
{
|
|
//cout << "CheckSpecialDay() => Month is in range between start and end" << endl;
|
|
if ((current_tm.tm_mday >= start_tm.tm_mday) && (current_tm.tm_mday <= end_tm.tm_mday))
|
|
{
|
|
LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY");
|
|
*specialDayId = spec_days_itr->second.ped_id;
|
|
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((current_tm.tm_mon >= start_tm.tm_mon) && (current_tm.tm_mon <= end_tm.tm_mon))
|
|
{
|
|
//cout << "CheckSpecialDay() => Month is in range between start and end" << endl;
|
|
if ((current_tm.tm_mday >= start_tm.tm_mday) && (current_tm.tm_mday <= end_tm.tm_mday))
|
|
{
|
|
LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY");
|
|
*specialDayId = spec_days_itr->second.ped_id;
|
|
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
//cout << "CheckSpecialDay() => NOT SPECIAL DAY" << endl;
|
|
return false;
|
|
}
|
|
catch (...)
|
|
{
|
|
throw std::invalid_argument("CheckSpecialDay() => An error has occurred\n");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool Utilities::CheckSpecialDay(Configuration const *cfg,
|
|
QDateTime const ¤tDateTime,
|
|
int* specialDayId,
|
|
uint32_t *specialDayPrice) {
|
|
*specialDayId = -1;
|
|
*specialDayPrice = 0;
|
|
|
|
std::multimap<int, ATBSpecialDays>::const_iterator spec_days_itr;
|
|
|
|
for (spec_days_itr = cfg->SpecialDays.cbegin(); spec_days_itr != cfg->SpecialDays.cend(); ++spec_days_itr) {
|
|
int repeat_every_year = spec_days_itr->second.ped_year;
|
|
QDate start = QDate::fromString(spec_days_itr->second.ped_date_start.c_str(), Qt::ISODate);
|
|
QDate end = QDate::fromString(spec_days_itr->second.ped_date_end.c_str(), Qt::ISODate);
|
|
if (start.isValid() && end.isValid()) {
|
|
if ((currentDateTime.date().month() >= start.month()) &&
|
|
(currentDateTime.date().month() <= end.month())) {
|
|
if ((currentDateTime.date().day() >= start.day()) &&
|
|
(currentDateTime.date().day() <= end.day())) {
|
|
if (repeat_every_year <= 0) {
|
|
if ((currentDateTime.date().year() != start.year()) ||
|
|
(currentDateTime.date().year() != end.year())) {
|
|
continue;
|
|
}
|
|
}
|
|
qDebug() << "CheckSpecialDay() => SPECIAL DAY";
|
|
*specialDayId = spec_days_itr->second.ped_id;
|
|
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
QTime Utilities::SpecialDaysWorkTimeFrom(Configuration const *cfg, int specialDayId) {
|
|
return QTime::fromString(cfg->SpecialDaysWorktime.find(specialDayId)->second.pedwt_time_from.c_str(), Qt::ISODate);
|
|
}
|
|
|
|
QTime Utilities::SpecialDaysWorkTimeUntil(Configuration const *cfg, int specialDayId) {
|
|
return QTime::fromString(cfg->SpecialDaysWorktime.find(specialDayId)->second.pedwt_time_to.c_str(), Qt::ISODate);
|
|
}
|
|
|
|
QTime Utilities::WeekDaysWorkTimeFrom(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr) {
|
|
return QTime::fromString(itr->second.pwd_time_from.c_str(), Qt::ISODate);
|
|
}
|
|
|
|
QTime Utilities::WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr) {
|
|
return QTime::fromString(itr->second.pwd_time_to.c_str(), Qt::ISODate);
|
|
}
|
|
|
|
bool Utilities::isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId) {
|
|
return !isCarryOverNotSet(cfg, paymentMethodId);
|
|
}
|
|
|
|
bool Utilities::isCarryOverNotSet(Configuration const *cfg, PaymentMethod paymentMethodId) {
|
|
return (cfg->PaymentOption.find(paymentMethodId)->second.pop_carry_over < 1);
|
|
}
|
|
|
|
PaymentMethod Utilities::getPaymentMethodId(Configuration const *cfg) {
|
|
if (cfg->PaymentOption.size() == 0) {
|
|
return PaymentMethod::Undefined;
|
|
}
|
|
|
|
std::multimap<int, ATBPaymentOption>::const_iterator it =
|
|
cfg->PaymentOption.cbegin();
|
|
|
|
if (it != cfg->PaymentOption.cend()) {
|
|
switch (it->first) {
|
|
case PaymentMethod::Linear:
|
|
return PaymentMethod::Linear;
|
|
case PaymentMethod::Steps:
|
|
return PaymentMethod::Steps;
|
|
case PaymentMethod::Degressive:
|
|
return PaymentMethod::Degressive;
|
|
case PaymentMethod::Progressive:
|
|
return PaymentMethod::Progressive;
|
|
}
|
|
}
|
|
|
|
return PaymentMethod::Undefined;
|
|
}
|
|
|
|
int Utilities::getMinimalParkingTime(Configuration const *cfg, PaymentMethod methodId) {
|
|
return std::max((int)cfg->PaymentOption.find(methodId)->second.pop_min_time, 0);
|
|
}
|
|
|
|
int Utilities::getMaximalParkingTime(Configuration const *cfg, PaymentMethod methodId) {
|
|
return std::max((int)cfg->PaymentOption.find(methodId)->second.pop_max_time, 0);
|
|
}
|
|
|
|
uint32_t Utilities::getMinimalParkingPrice(Configuration const *cfg, PaymentMethod methodId) {
|
|
return std::max((int)cfg->PaymentOption.find(methodId)->second.pop_min_price, 0);
|
|
}
|
|
|
|
uint32_t Utilities::getFirstDurationStep(Configuration const *cfg, PaymentMethod methodId) {
|
|
|
|
int const popId = cfg->PaymentOption.find(methodId)->second.pop_id;
|
|
int const punId = cfg->PaymentRate.find(popId)->second.pra_payment_unit_id;
|
|
uint32_t const firstDurationStep= cfg->Duration.find(punId)->second.pun_duration;
|
|
|
|
qCritical() << "getFirstDurationStep() payment-method-id:" << (int)methodId;
|
|
qCritical() << "getFirstDurationStep() pop-id:" << popId;
|
|
qCritical() << "getFirstDurationStep() pun-id:" << punId;
|
|
qCritical() << "getFirstDurationStep() first-step:" << firstDurationStep;
|
|
|
|
return firstDurationStep;
|
|
}
|
|
|
|
BusinessHours Utilities::getBusinessHours(Configuration const *cfg, PaymentMethod methodId) {
|
|
int businessHours = cfg->PaymentOption.find(methodId)->second.pop_business_hours;
|
|
|
|
qCritical() << __func__ << ":" << __LINE__ << businessHours;
|
|
|
|
switch (businessHours) {
|
|
case NoRestriction_24_7: return BusinessHours::NoRestriction_24_7;
|
|
case OnlyWorkingDays: return BusinessHours::OnlyWorkingDays;
|
|
case OnlyWeekDays: return BusinessHours::OnlyWeekDays;
|
|
case OnlyWeekEnd: return BusinessHours::OnlyWeekEnd;
|
|
case OnlyOfficialHolidays: return BusinessHours::OnlyOfficialHolidays;
|
|
case OnlySpecialDays: return BusinessHours::OnlySpecialDays;
|
|
case OnlySchoolHolidays: return BusinessHours::OnlySchoolHolidays;
|
|
case SpecialAndSchoolHolidays: return BusinessHours::SpecialAndSchoolHolidays;
|
|
case OnlyOpenForBusinessDays: return BusinessHours::OnlyOpenForBusinessDays;
|
|
case AllDaysWithRestrictedHours: return BusinessHours::AllDaysWithRestrictedHours;
|
|
}
|
|
return BusinessHours::NoBusinessHoursDefined;
|
|
}
|
|
|
|
uint32_t Utilities::computeWeekDaysPrice(Configuration const *cfg, PaymentMethod id) {
|
|
int pop_id = cfg->PaymentOption.find(id)->second.pop_id;
|
|
return cfg->PaymentRate.find(pop_id)->second.pra_price;
|
|
}
|
|
|
|
double Utilities::computeWeekDaysDurationUnit(Configuration const *cfg, PaymentMethod id) {
|
|
int pop_id = cfg->PaymentOption.find(id)->second.pop_id;
|
|
int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id;
|
|
return (double)(cfg->Duration.find(durationId)->second.pun_duration);
|
|
}
|