start repository for mobilisis tariff-calculation
This commit is contained in:
		
							
								
								
									
										87
									
								
								library/src/calculate_price.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								library/src/calculate_price.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,87 @@
 | 
			
		||||
#include "calculate_price.h"
 | 
			
		||||
#include "configuration.h"
 | 
			
		||||
#include "calculator_functions.h"
 | 
			
		||||
#include "payment_option.h"
 | 
			
		||||
 | 
			
		||||
#include <QFile>
 | 
			
		||||
#include <QFileInfo>
 | 
			
		||||
#include <QDateTime>
 | 
			
		||||
#include <QDebug>
 | 
			
		||||
 | 
			
		||||
static Calculator calculator;
 | 
			
		||||
 | 
			
		||||
int get_zone_nr() {
 | 
			
		||||
    QFile zone("/etc/zone_nr");
 | 
			
		||||
    if (zone.exists()) {
 | 
			
		||||
        QFileInfo finfo(zone);
 | 
			
		||||
        if (finfo.size() <= 4) { // decimal 000\n
 | 
			
		||||
            if (zone.open(QIODevice::ReadOnly | QIODevice::Text)) {
 | 
			
		||||
                return zone.readLine().toInt();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool init_tariff(parking_tariff_t **tariff, char const *config_file) {
 | 
			
		||||
    *tariff = new Configuration();
 | 
			
		||||
 | 
			
		||||
    int const zone = get_zone_nr();
 | 
			
		||||
    if (zone == -1) {
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    QString confFile(config_file);
 | 
			
		||||
    if (!confFile.endsWith(QChar('/'))) {
 | 
			
		||||
        confFile += "/";
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    char buffer[16];
 | 
			
		||||
    memset(buffer, 0x00, sizeof(buffer));
 | 
			
		||||
    snprintf(buffer, sizeof(buffer)-1, "tariff%02d.json", zone);
 | 
			
		||||
    confFile += buffer;
 | 
			
		||||
 | 
			
		||||
    QFile fname(confFile);
 | 
			
		||||
    if (fname.exists()) {
 | 
			
		||||
        if (fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
 | 
			
		||||
            QString json = fname.readAll();
 | 
			
		||||
            return (*tariff)->ParseJson(*tariff, json.toStdString().c_str());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void free_tariff(parking_tariff_t *tariff) {
 | 
			
		||||
    delete tariff;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool compute_price_for_parking_ticket(parking_tariff_t *tariff,
 | 
			
		||||
                                      time_t start_parking_time, // in minutes
 | 
			
		||||
                                      time_t end_parking_time,   // in minutes
 | 
			
		||||
                                      struct price_t *price) {
 | 
			
		||||
    int const duration = end_parking_time - start_parking_time;
 | 
			
		||||
    if (duration > 0) {
 | 
			
		||||
        QDate const d(1970, 1, 1);
 | 
			
		||||
        QTime const t(0, 0, 0);
 | 
			
		||||
        QDateTime start(d, t, Qt::UTC);
 | 
			
		||||
        start = start.toLocalTime().addSecs(start_parking_time * 60);
 | 
			
		||||
        if (start.isValid()) {
 | 
			
		||||
            QString cs = start.toString(Qt::ISODate);
 | 
			
		||||
            double cost = calculator.GetCostFromDuration(
 | 
			
		||||
                            tariff, PaymentOption::Option1,
 | 
			
		||||
                            cs.toLocal8Bit().constData(),
 | 
			
		||||
                            duration, false, true);
 | 
			
		||||
            price->units = cost;
 | 
			
		||||
            price->netto = cost;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    } else
 | 
			
		||||
    if (duration == 0) {
 | 
			
		||||
        memset(price, 0x00, sizeof(*price));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    qCritical() << "ERROR start_parking_time (" << start_parking_time << ") <"
 | 
			
		||||
                << "end_parking_time (" << end_parking_time << ")";
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										513
									
								
								library/src/calculator_functions.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										513
									
								
								library/src/calculator_functions.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,513 @@
 | 
			
		||||
#include "calculator_functions.h"
 | 
			
		||||
#include "payment_method.h"
 | 
			
		||||
#include "utilities.h"
 | 
			
		||||
#include "tariff_log.h"
 | 
			
		||||
 | 
			
		||||
#include <sstream>
 | 
			
		||||
 | 
			
		||||
double total_duration_min = 0.0f;
 | 
			
		||||
double total_cost = 0.0f;
 | 
			
		||||
bool overtime = false;
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
std::string Calculator::GetDurationFromCost(Configuration* cfg, uint8_t payment_option, char const* start_datetime, double price, bool nextDay, bool prepaid)
 | 
			
		||||
{
 | 
			
		||||
	// Get current date time from input
 | 
			
		||||
	struct tm current_datetime = Utilities::DateTimeToStructTm(start_datetime);
 | 
			
		||||
	time_t current_datetime_t;
 | 
			
		||||
 | 
			
		||||
	// Get day of week
 | 
			
		||||
	DayOfWeek weekdayId = DayOfWeek::UndefinedDay;
 | 
			
		||||
	weekdayId = Utilities::GetDayOfWeek(¤t_datetime);
 | 
			
		||||
 | 
			
		||||
	//std::stringstream ss;
 | 
			
		||||
 | 
			
		||||
	// ss << "*** Input date is: " << start_datetime << " [weekday id = " << weekdayId << "]" << endl;
 | 
			
		||||
	LOG_DEBUG("*** Input date is: ", start_datetime, " [weekday id = ", weekdayId, "]");
 | 
			
		||||
 | 
			
		||||
	double minMin = 0;
 | 
			
		||||
	minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
 | 
			
		||||
	if (minMin < 0) minMin = 0;
 | 
			
		||||
 | 
			
		||||
	double maxMin = 0;
 | 
			
		||||
	maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
 | 
			
		||||
	if (maxMin <= 0) maxMin = 60;
 | 
			
		||||
 | 
			
		||||
	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";
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t p_method = PaymentMethod::Undefined;
 | 
			
		||||
	p_method = payment_option;
 | 
			
		||||
	LOG_DEBUG("Payment method id: ", (unsigned)p_method);
 | 
			
		||||
 | 
			
		||||
	double day_price = 0.0f;
 | 
			
		||||
	int current_special_day_id = -1;
 | 
			
		||||
	bool is_special_day = Utilities::CheckSpecialDay(cfg, start_datetime, ¤t_special_day_id, &day_price);
 | 
			
		||||
	LOG_DEBUG("Special day: ", is_special_day);
 | 
			
		||||
 | 
			
		||||
	double money_left = price;
 | 
			
		||||
	LOG_DEBUG("Total money:", money_left);
 | 
			
		||||
 | 
			
		||||
	double price_per_unit = 0.0f;
 | 
			
		||||
 | 
			
		||||
	string worktime_from = "";
 | 
			
		||||
	string worktime_to = "";
 | 
			
		||||
 | 
			
		||||
	if (is_special_day)
 | 
			
		||||
	{
 | 
			
		||||
		// Set special day price
 | 
			
		||||
		price_per_unit = Utilities::CalculatePricePerUnit(day_price);
 | 
			
		||||
		worktime_from = cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from;
 | 
			
		||||
		worktime_to = cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// Set new price for the normal day
 | 
			
		||||
		day_price = cfg->PaymentRate.find(payment_option)->second.pra_price;
 | 
			
		||||
		price_per_unit = Utilities::CalculatePricePerUnit(day_price);
 | 
			
		||||
 | 
			
		||||
		// If no working day found, skip it (recursively call method again)
 | 
			
		||||
		size_t found = 0;
 | 
			
		||||
		found = cfg->WeekDaysWorktime.count(weekdayId);
 | 
			
		||||
 | 
			
		||||
		if (found <= 0)
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG("- No workday found, trying to find next available day");
 | 
			
		||||
			current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
			current_datetime_t += 86400;
 | 
			
		||||
			current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
 | 
			
		||||
			char buffer_datetime[80];
 | 
			
		||||
			strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
 | 
			
		||||
 | 
			
		||||
			// Make new datetime string and call function again recursively
 | 
			
		||||
			start_datetime = buffer_datetime;
 | 
			
		||||
			return GetDurationFromCost(cfg, payment_option, start_datetime, price, true);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		worktime_from = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from;
 | 
			
		||||
		worktime_to = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (price_per_unit < 0) price_per_unit = 1.0f;
 | 
			
		||||
	LOG_DEBUG("Calculated price per minute: ", price_per_unit);
 | 
			
		||||
 | 
			
		||||
	LOG_DEBUG("Worktime from: ", worktime_from);
 | 
			
		||||
	LOG_DEBUG("Worktime to: ", worktime_to);
 | 
			
		||||
 | 
			
		||||
	struct tm from_tm;
 | 
			
		||||
	struct tm to_tm;
 | 
			
		||||
 | 
			
		||||
	from_tm = Utilities::TimeToStructTm(worktime_from.c_str(), current_datetime.tm_year, current_datetime.tm_mon, current_datetime.tm_mday, current_datetime.tm_wday);
 | 
			
		||||
	from_tm.tm_year = current_datetime.tm_year;
 | 
			
		||||
	from_tm.tm_mon = current_datetime.tm_mon;
 | 
			
		||||
	from_tm.tm_wday = current_datetime.tm_wday;
 | 
			
		||||
	from_tm.tm_mday = current_datetime.tm_mday;
 | 
			
		||||
 | 
			
		||||
	to_tm = Utilities::TimeToStructTm(worktime_to.c_str(), current_datetime.tm_year, current_datetime.tm_mon, current_datetime.tm_mday, current_datetime.tm_wday);
 | 
			
		||||
	to_tm.tm_year = current_datetime.tm_year;
 | 
			
		||||
	to_tm.tm_mon = current_datetime.tm_mon;
 | 
			
		||||
	to_tm.tm_wday = current_datetime.tm_wday;
 | 
			
		||||
	to_tm.tm_mday = current_datetime.tm_mday;
 | 
			
		||||
 | 
			
		||||
	// Convert tm structures to time_t
 | 
			
		||||
	current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
	time_t from_datetime_t = mktime(&from_tm);
 | 
			
		||||
	time_t to_datetime_t = mktime(&to_tm);
 | 
			
		||||
 | 
			
		||||
	/*Newly added */
 | 
			
		||||
	//current_datetime.tm_hour = from_tm.tm_hour;
 | 
			
		||||
	//current_datetime.tm_min = from_tm.tm_min;
 | 
			
		||||
	//current_datetime.tm_sec = from_tm.tm_sec;
 | 
			
		||||
	//current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
 | 
			
		||||
	// If overtime flag is set
 | 
			
		||||
	if (overtime || nextDay)
 | 
			
		||||
	{
 | 
			
		||||
		current_datetime.tm_hour = from_tm.tm_hour;
 | 
			
		||||
		current_datetime.tm_min = from_tm.tm_min;
 | 
			
		||||
		current_datetime.tm_sec = from_tm.tm_sec;
 | 
			
		||||
		current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
		LOG_DEBUG(" *** New input date set according to worktime: ", asctime(¤t_datetime));
 | 
			
		||||
		overtime = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate ticket
 | 
			
		||||
	if (!prepaid)
 | 
			
		||||
	{
 | 
			
		||||
		if ((current_datetime_t < from_datetime_t) || (current_datetime_t > to_datetime_t))
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG("[STOP] * Ticket is not valid * ");
 | 
			
		||||
			return "PARKING NOT ALLOWED";
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		LOG_DEBUG("* PREPAID MODE ACTIVE *");
 | 
			
		||||
 | 
			
		||||
		if (current_datetime_t < from_datetime_t)
 | 
			
		||||
		{
 | 
			
		||||
			current_datetime.tm_hour = from_tm.tm_hour;
 | 
			
		||||
			current_datetime.tm_min = from_tm.tm_min;
 | 
			
		||||
			current_datetime.tm_sec = from_tm.tm_sec;
 | 
			
		||||
			current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
			LOG_DEBUG(" *** PREPAID *** Current time is before the time range start, adjusting time to: ", asctime(¤t_datetime));
 | 
			
		||||
		}
 | 
			
		||||
		else if (current_datetime_t > to_datetime_t)
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day");
 | 
			
		||||
			current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
			current_datetime_t += 86400;
 | 
			
		||||
			current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
 | 
			
		||||
			char buffer_datetime[80];
 | 
			
		||||
			strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
 | 
			
		||||
 | 
			
		||||
			//Make new datetime string and call function again recursively
 | 
			
		||||
			start_datetime = buffer_datetime;
 | 
			
		||||
			return GetDurationFromCost(cfg, payment_option, start_datetime, price, true, prepaid);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
		if (!Utilities::IsYearPeriodActive(cfg, ¤t_datetime))
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG("Year period is not valid");
 | 
			
		||||
			return "PARKING NOT ALLOWED";
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Increment by 1 minute
 | 
			
		||||
		current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
		current_datetime_t += 60;
 | 
			
		||||
		current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
		total_duration_min += 1.0f;
 | 
			
		||||
		money_left -= price_per_unit;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		// If no money left (e.g. spent all of the money before reaching end of worktime)
 | 
			
		||||
		if (money_left <= 0)
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG("No money left ");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			if (total_duration_min >= maxMin)
 | 
			
		||||
			{
 | 
			
		||||
				LOG_DEBUG("Total duration is greater or equal to max_min");
 | 
			
		||||
 | 
			
		||||
				current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
				current_datetime_t -= 60;
 | 
			
		||||
				current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
				total_duration_min = maxMin;
 | 
			
		||||
				break;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			// If money has left but the end of worktime has been reached (go to next day)
 | 
			
		||||
			if (current_datetime_t >= to_datetime_t)
 | 
			
		||||
			{
 | 
			
		||||
				total_duration_min -= 1.0f;
 | 
			
		||||
 | 
			
		||||
				int carry_over_status = 0;
 | 
			
		||||
				carry_over_status = cfg->PaymentOption.find(payment_option)->second.pop_carry_over;
 | 
			
		||||
				LOG_DEBUG("Carry over status: ", carry_over_status);
 | 
			
		||||
				if (carry_over_status < 1) break;
 | 
			
		||||
 | 
			
		||||
				LOG_DEBUG("Reached end of worktime");
 | 
			
		||||
				LOG_DEBUG("Trying to find next available day, money left = ", money_left);
 | 
			
		||||
				current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
				current_datetime_t += 86400;
 | 
			
		||||
				current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
 | 
			
		||||
				char buffer_datetime[80];
 | 
			
		||||
				strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
 | 
			
		||||
 | 
			
		||||
				// Make new datetime string and call function again recursively
 | 
			
		||||
				start_datetime = buffer_datetime;
 | 
			
		||||
				overtime = true;
 | 
			
		||||
                return GetDurationFromCost(cfg, payment_option, start_datetime, price);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	time_t valid_until_datetime_t = current_datetime_t;
 | 
			
		||||
 | 
			
		||||
	if ((total_duration_min < minMin) || (price / price_per_unit) < minMin)
 | 
			
		||||
	{
 | 
			
		||||
		LOG_DEBUG("Total duration is lower than min_min");
 | 
			
		||||
		//valid_until_datetime_t += (minMin - total_duration_min) * 60;
 | 
			
		||||
		//total_duration_min = minMin;
 | 
			
		||||
		//return "PARKING NOT ALLOWED";
 | 
			
		||||
 | 
			
		||||
		valid_until_datetime_t = from_datetime_t;
 | 
			
		||||
		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)
 | 
			
		||||
	{
 | 
			
		||||
		valid_until_datetime_t -= (int)ceil(calc_price) * 60;
 | 
			
		||||
		ret_val = total_duration_min - calc_price;
 | 
			
		||||
	}
 | 
			
		||||
	else ret_val = total_duration_min;
 | 
			
		||||
 | 
			
		||||
	cout << "Total minutes: " << (int)ret_val << endl;
 | 
			
		||||
	if (ret_val <= 0) return "PARKING NOT ALLOWED";
 | 
			
		||||
 | 
			
		||||
	struct tm valid_until_datetime = *localtime(&valid_until_datetime_t);
 | 
			
		||||
	LOG_DEBUG("Ticket is valid until ", asctime(&valid_until_datetime));
 | 
			
		||||
 | 
			
		||||
	total_duration_min = 0.0f;
 | 
			
		||||
	return asctime(&valid_until_datetime);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
///////////////////////////////////////
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
double Calculator::GetCostFromDuration(Configuration* cfg, uint8_t payment_option, const char* start_datetime, double durationMin, bool nextDay, bool prepaid)
 | 
			
		||||
{
 | 
			
		||||
	// Get current date time from input
 | 
			
		||||
	struct tm current_datetime = Utilities::DateTimeToStructTm(start_datetime);
 | 
			
		||||
	time_t current_datetime_t;
 | 
			
		||||
 | 
			
		||||
	// Get day of week
 | 
			
		||||
	DayOfWeek weekdayId = DayOfWeek::UndefinedDay;
 | 
			
		||||
	weekdayId = Utilities::GetDayOfWeek(¤t_datetime);
 | 
			
		||||
	LOG_DEBUG("*** Input date is: ", start_datetime, " [weekday id = ", weekdayId, "]");
 | 
			
		||||
 | 
			
		||||
	double minMin = 0;
 | 
			
		||||
	minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
 | 
			
		||||
	if (minMin < 0) minMin = 0;
 | 
			
		||||
 | 
			
		||||
	double maxMin = 0;
 | 
			
		||||
	maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
 | 
			
		||||
	if (maxMin <= 0) maxMin = 60;
 | 
			
		||||
 | 
			
		||||
	if (minMin >= maxMin)
 | 
			
		||||
	{
 | 
			
		||||
		LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
 | 
			
		||||
		return 0.0f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (maxMin <= minMin)
 | 
			
		||||
	{
 | 
			
		||||
		LOG_ERROR("Error: max_min cannot be lower or equal than min_min");
 | 
			
		||||
		return 0.0f;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (!overtime)
 | 
			
		||||
	{
 | 
			
		||||
		if (durationMin > maxMin)
 | 
			
		||||
		{
 | 
			
		||||
			LOG_WARNING("Total duration is greater or equal to max_min");
 | 
			
		||||
			return 0.0f;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if (durationMin < minMin)
 | 
			
		||||
		{
 | 
			
		||||
			LOG_WARNING("Total duration is lower or equal to min_min");
 | 
			
		||||
			return 0.0f;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	uint8_t p_method = PaymentMethod::Undefined;
 | 
			
		||||
	p_method = payment_option;
 | 
			
		||||
	LOG_DEBUG("Payment method id: ", (unsigned)p_method);
 | 
			
		||||
 | 
			
		||||
	double day_price = 0.0f;
 | 
			
		||||
	int current_special_day_id = -1;
 | 
			
		||||
	bool is_special_day = Utilities::CheckSpecialDay(cfg, start_datetime, ¤t_special_day_id, &day_price);
 | 
			
		||||
	LOG_DEBUG("Special day: ", is_special_day);
 | 
			
		||||
 | 
			
		||||
	total_duration_min = durationMin;
 | 
			
		||||
	LOG_DEBUG("Total min:", total_duration_min);
 | 
			
		||||
 | 
			
		||||
	double price_per_unit = 0.0f;
 | 
			
		||||
 | 
			
		||||
	string worktime_from = "";
 | 
			
		||||
	string worktime_to = "";
 | 
			
		||||
 | 
			
		||||
	if (is_special_day)
 | 
			
		||||
	{
 | 
			
		||||
		// Set special day price
 | 
			
		||||
		price_per_unit = Utilities::CalculatePricePerUnit(day_price);
 | 
			
		||||
		worktime_from = cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from;
 | 
			
		||||
		worktime_to = cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to;
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		// Set new price for the normal day
 | 
			
		||||
		day_price = cfg->PaymentRate.find(payment_option)->second.pra_price;
 | 
			
		||||
		price_per_unit = Utilities::CalculatePricePerUnit(day_price);
 | 
			
		||||
 | 
			
		||||
		// If no working day found, skip it (recursively call method again)
 | 
			
		||||
		size_t found = 0;
 | 
			
		||||
		found = cfg->WeekDaysWorktime.count(weekdayId);
 | 
			
		||||
 | 
			
		||||
		if (found <= 0)
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG("- No workday found, trying to find next available day");
 | 
			
		||||
			current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
			current_datetime_t += 86400;
 | 
			
		||||
			current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
 | 
			
		||||
			char buffer_datetime[80];
 | 
			
		||||
			strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
 | 
			
		||||
 | 
			
		||||
			//Make new datetime string and call function again recursively
 | 
			
		||||
			start_datetime = buffer_datetime;
 | 
			
		||||
            return floor(GetCostFromDuration(cfg, payment_option, start_datetime, durationMin, true, prepaid));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		worktime_from = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from;
 | 
			
		||||
		worktime_to = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if (price_per_unit < 0) price_per_unit = 1.0f;
 | 
			
		||||
	LOG_DEBUG("Calculated price per minute: ", price_per_unit);
 | 
			
		||||
 | 
			
		||||
	LOG_DEBUG("Worktime from: ", worktime_from);
 | 
			
		||||
	LOG_DEBUG("Worktime to: ", worktime_to);
 | 
			
		||||
 | 
			
		||||
	struct tm from_tm;
 | 
			
		||||
	struct tm to_tm;
 | 
			
		||||
 | 
			
		||||
	from_tm = Utilities::TimeToStructTm(worktime_from.c_str(), current_datetime.tm_year, current_datetime.tm_mon, current_datetime.tm_mday, current_datetime.tm_wday);
 | 
			
		||||
	from_tm.tm_year = current_datetime.tm_year;
 | 
			
		||||
	from_tm.tm_mon = current_datetime.tm_mon;
 | 
			
		||||
	from_tm.tm_wday = current_datetime.tm_wday;
 | 
			
		||||
	from_tm.tm_mday = current_datetime.tm_mday;
 | 
			
		||||
 | 
			
		||||
	to_tm = Utilities::TimeToStructTm(worktime_to.c_str(), current_datetime.tm_year, current_datetime.tm_mon, current_datetime.tm_mday, current_datetime.tm_wday);
 | 
			
		||||
	to_tm.tm_year = current_datetime.tm_year;
 | 
			
		||||
	to_tm.tm_mon = current_datetime.tm_mon;
 | 
			
		||||
	to_tm.tm_wday = current_datetime.tm_wday;
 | 
			
		||||
	to_tm.tm_mday = current_datetime.tm_mday;
 | 
			
		||||
 | 
			
		||||
	// Convert tm structures to time_t
 | 
			
		||||
	current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
 | 
			
		||||
	time_t from_datetime_t = mktime(&from_tm);
 | 
			
		||||
	time_t to_datetime_t = mktime(&to_tm);
 | 
			
		||||
 | 
			
		||||
	// If overtime flag is set
 | 
			
		||||
	if (overtime || nextDay)
 | 
			
		||||
	{
 | 
			
		||||
		current_datetime.tm_hour = from_tm.tm_hour;
 | 
			
		||||
		current_datetime.tm_min = from_tm.tm_min;
 | 
			
		||||
		current_datetime.tm_sec = from_tm.tm_sec;
 | 
			
		||||
		current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
		LOG_DEBUG(" *** New input date set according to worktime: ", asctime(¤t_datetime));
 | 
			
		||||
		overtime = false;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Validate ticket
 | 
			
		||||
	if (!prepaid)
 | 
			
		||||
	{
 | 
			
		||||
		if ((current_datetime_t < from_datetime_t) || (current_datetime_t > to_datetime_t))
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG("[STOP] * Ticket is not valid * ");
 | 
			
		||||
			return 0.0f;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	else
 | 
			
		||||
	{
 | 
			
		||||
		LOG_DEBUG("* PREPAID MODE ACTIVE *");
 | 
			
		||||
 | 
			
		||||
		if (current_datetime_t < from_datetime_t)
 | 
			
		||||
		{
 | 
			
		||||
			current_datetime.tm_hour = from_tm.tm_hour;
 | 
			
		||||
			current_datetime.tm_min = from_tm.tm_min;
 | 
			
		||||
			current_datetime.tm_sec = from_tm.tm_sec;
 | 
			
		||||
			current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
			LOG_DEBUG(" *** PREPAID *** Current time is before the time range start, adjusting time to: ", asctime(¤t_datetime));
 | 
			
		||||
		}
 | 
			
		||||
		else if (current_datetime_t > to_datetime_t)
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day");
 | 
			
		||||
			current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
			current_datetime_t += 86400;
 | 
			
		||||
			current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
 | 
			
		||||
			char buffer_datetime[80];
 | 
			
		||||
			strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
 | 
			
		||||
 | 
			
		||||
			//Make new datetime string and call function again recursively
 | 
			
		||||
			start_datetime = buffer_datetime;
 | 
			
		||||
			return floor(GetCostFromDuration(cfg, payment_option, start_datetime, durationMin, true, prepaid));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	while (true)
 | 
			
		||||
	{
 | 
			
		||||
		if (!Utilities::IsYearPeriodActive(cfg, ¤t_datetime))
 | 
			
		||||
		{
 | 
			
		||||
			LOG_DEBUG("Year period is not valid");
 | 
			
		||||
			return 0.0f;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Decrement by 1 minute
 | 
			
		||||
		current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
		current_datetime_t += 60;
 | 
			
		||||
		current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
 | 
			
		||||
		total_duration_min -= 1.0f;
 | 
			
		||||
		total_cost += price_per_unit;
 | 
			
		||||
 | 
			
		||||
		// If no minutes left (e.g. spent all of the money before reaching end of worktime)
 | 
			
		||||
		if (total_duration_min <= 0)
 | 
			
		||||
		{
 | 
			
		||||
			//total_duration_min -= 1.0f;
 | 
			
		||||
			LOG_DEBUG("No minutes left ");
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			// If minutes has left but the end of worktime has been reached (go to next day)
 | 
			
		||||
			if (current_datetime_t >= to_datetime_t)
 | 
			
		||||
			{
 | 
			
		||||
				int carry_over_status = 0;
 | 
			
		||||
				carry_over_status = cfg->PaymentOption.find(payment_option)->second.pop_carry_over;
 | 
			
		||||
				total_duration_min += 1.0f;
 | 
			
		||||
				total_cost -= price_per_unit;
 | 
			
		||||
 | 
			
		||||
				LOG_DEBUG("Carry over status: ", carry_over_status);
 | 
			
		||||
				if (carry_over_status < 1) break;
 | 
			
		||||
 | 
			
		||||
				LOG_DEBUG("Reached end of worktime");
 | 
			
		||||
				LOG_DEBUG("Trying to find next available day, min left = ", total_duration_min);
 | 
			
		||||
				current_datetime_t = mktime(¤t_datetime);
 | 
			
		||||
				current_datetime_t += 86400;
 | 
			
		||||
				current_datetime = *localtime(¤t_datetime_t);
 | 
			
		||||
 | 
			
		||||
				char buffer_datetime[80];
 | 
			
		||||
				strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
 | 
			
		||||
 | 
			
		||||
				// Make new datetime string and call function again recursively
 | 
			
		||||
				start_datetime = buffer_datetime;
 | 
			
		||||
				overtime = true;
 | 
			
		||||
				return floor(GetCostFromDuration(cfg, payment_option, start_datetime, total_duration_min));
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	time_t valid_until_datetime_t = current_datetime_t;
 | 
			
		||||
	struct tm valid_until_datetime = *localtime(&valid_until_datetime_t);
 | 
			
		||||
	LOG_DEBUG("Ticket is valid until ", asctime(&valid_until_datetime));
 | 
			
		||||
 | 
			
		||||
	double ret_val = total_cost;
 | 
			
		||||
	total_cost = 0.0f;
 | 
			
		||||
	return floor(ret_val);
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										246
									
								
								library/src/configuration.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								library/src/configuration.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,246 @@
 | 
			
		||||
#include "configuration.h"
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
MemberType Configuration::IdentifyJsonMember(const char* member_name)
 | 
			
		||||
{
 | 
			
		||||
	if (strcmp(member_name, "Currency") == 0) return MemberType::CurrencyType;
 | 
			
		||||
	if (strcmp(member_name, "PaymentMethod") == 0) return MemberType::PaymentMethodType;
 | 
			
		||||
	if (strcmp(member_name, "PaymentRate") == 0) return MemberType::PaymentRateType;
 | 
			
		||||
	if (strcmp(member_name, "PaymentOption") == 0) return MemberType::PaymentOptionType;
 | 
			
		||||
	if (strcmp(member_name, "Duration") == 0) return MemberType::DurationType;
 | 
			
		||||
	//if (strcmp(member_name, "WeekDays") == 0) return MemberType::WeekDaysType;
 | 
			
		||||
	if (strcmp(member_name, "WeekDaysWorktime") == 0) return MemberType::WeekDaysWorkTimeType;
 | 
			
		||||
	if (strcmp(member_name, "SpecialDaysWorktime") == 0) return MemberType::SpecialDaysWorktimeType;
 | 
			
		||||
	if (strcmp(member_name, "SpecialDays") == 0) return MemberType::SpecialDaysType;
 | 
			
		||||
	if (strcmp(member_name, "PeriodYear") == 0) return MemberType::PeriodYearType;
 | 
			
		||||
	else return MemberType::UnknownType;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
bool Configuration::ParseJson(Configuration* cfg, const char* json)
 | 
			
		||||
{
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		if (cfg == nullptr)
 | 
			
		||||
		{
 | 
			
		||||
			printf("TariffConfiguration pointer not set\n");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (json == NULL)
 | 
			
		||||
		{
 | 
			
		||||
			printf("%s", "Input JSON string is NULL\n");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Parse JSON to document
 | 
			
		||||
		Document document;
 | 
			
		||||
		document.Parse(json);
 | 
			
		||||
 | 
			
		||||
		// Return if parse error has been found
 | 
			
		||||
		ParseErrorCode err = document.GetParseError();
 | 
			
		||||
		if (err != 0)
 | 
			
		||||
		{
 | 
			
		||||
			printf("%s %d (%s)\n", "Unable to parse JSON, error code:", err, GetParseError_En(err));
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Validate JSON, check if it's a JSON object
 | 
			
		||||
		printf("%s", "JSON parsing has been successful\n");
 | 
			
		||||
		if (!document.IsObject()) {
 | 
			
		||||
			printf("%s", "Error: not a (valid) JSON object\n");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		printf("%s", "Valid JSON object identified\n");
 | 
			
		||||
 | 
			
		||||
		// Validate JSON, check configuration members
 | 
			
		||||
		if (!document.HasMember("Currency")
 | 
			
		||||
			|| !document.HasMember("PaymentMethod")
 | 
			
		||||
			|| !document.HasMember("PaymentOption")
 | 
			
		||||
			|| !document.HasMember("PaymentRate")
 | 
			
		||||
			|| !document.HasMember("Duration")
 | 
			
		||||
			//|| !document.HasMember("WeekDays")
 | 
			
		||||
			|| !document.HasMember("SpecialDaysWorktime")
 | 
			
		||||
			|| !document.HasMember("SpecialDays"))
 | 
			
		||||
		{
 | 
			
		||||
			printf("%s", "Error: not a valid configuration JSON\n");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		printf("%s", "Valid JSON configuration identified\n");
 | 
			
		||||
 | 
			
		||||
		ATBCurrency Currency;
 | 
			
		||||
		ATBDuration Duration;
 | 
			
		||||
		ATBPaymentMethod PaymentMethod;
 | 
			
		||||
		ATBPaymentRate PaymentRate;
 | 
			
		||||
		ATBSpecialDaysWorktime SpecialDaysWorktime;
 | 
			
		||||
		ATBSpecialDays SpecialDays;
 | 
			
		||||
		ATBWeekDays  WeekDays;
 | 
			
		||||
		ATBWeekDaysWorktime  WeekDaysWorktime;
 | 
			
		||||
		ATBPaymentOption PaymentOption;
 | 
			
		||||
		ATBPeriodYear YearPeriod;
 | 
			
		||||
		MemberType mb_type;
 | 
			
		||||
 | 
			
		||||
		// Get all JSON object members
 | 
			
		||||
		// This code should run only once (to load JSON variables into memory)
 | 
			
		||||
		for (auto i = document.MemberBegin(); i != document.MemberEnd(); i++)
 | 
			
		||||
		{
 | 
			
		||||
			// Get name of all general members of JSON, don't print name if NULL
 | 
			
		||||
			const char* mb_name = i->name.GetString();
 | 
			
		||||
            if (mb_name == NULL) continue;
 | 
			
		||||
 | 
			
		||||
            // if (!document[mb_name].IsArray()) {
 | 
			
		||||
                std::string const _mb_name(mb_name);
 | 
			
		||||
                if (_mb_name == "version" || _mb_name == "project" ||
 | 
			
		||||
                    _mb_name == "zone" || _mb_name == "info") {
 | 
			
		||||
                    continue;
 | 
			
		||||
                }
 | 
			
		||||
            // }
 | 
			
		||||
 | 
			
		||||
			//printf(" -%s\n", mb_name);
 | 
			
		||||
 | 
			
		||||
			// Get array for each JSON object member
 | 
			
		||||
			auto mb_array = document[mb_name].GetArray();
 | 
			
		||||
			if (mb_array.Size() <= 0) break;
 | 
			
		||||
 | 
			
		||||
			//Iterate over provided array
 | 
			
		||||
			for (auto j = 0; j < mb_array.Size(); j++)
 | 
			
		||||
			{
 | 
			
		||||
				// Get all inner objects, don't print name if NULL
 | 
			
		||||
				auto inner_obj = mb_array[j].GetObject();
 | 
			
		||||
				if (inner_obj.MemberCount() <= 0) break;
 | 
			
		||||
 | 
			
		||||
				// Iterate over inner object JSON members
 | 
			
		||||
				for (auto k = inner_obj.MemberBegin(); k != inner_obj.MemberEnd(); k++)
 | 
			
		||||
				{
 | 
			
		||||
					// Get inner object JSON member, don't print name if NULL
 | 
			
		||||
					const char* inner_obj_name = k->name.GetString();
 | 
			
		||||
					if (inner_obj_name == NULL)
 | 
			
		||||
					{
 | 
			
		||||
						printf("Inner object name is NULL\n");
 | 
			
		||||
						continue;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// Identify member type
 | 
			
		||||
					mb_type = IdentifyJsonMember(mb_name);
 | 
			
		||||
 | 
			
		||||
//#pragma region Get_values
 | 
			
		||||
					switch (mb_type)
 | 
			
		||||
					{
 | 
			
		||||
					case MemberType::UnknownType:
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::CurrencyType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pcu_id") == 0) Currency.pcu_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pcu_sign") == 0) Currency.pcu_sign = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pcu_major") == 0) Currency.pcu_major = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pcu_minor") == 0) Currency.pcu_minor = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pcu_active") == 0) Currency.pcu_active = k->value.GetBool();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::PaymentMethodType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pme_id") == 0) PaymentMethod.pme_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pme_label") == 0) PaymentMethod.pme_label = k->value.GetString();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::PaymentRateType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pra_payment_option_id") == 0) PaymentRate.pra_payment_option_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pra_payment_unit_id") == 0) PaymentRate.pra_payment_unit_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pra_price") == 0) PaymentRate.pra_price = k->value.GetDouble();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::PaymentOptionType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pop_id") == 0) PaymentOption.pop_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_label") == 0) PaymentOption.pop_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_payment_method_id") == 0) PaymentOption.pop_payment_method_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_day_end_time") == 0) PaymentOption.pop_day_end_time = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_day_night_end_time") == 0) PaymentOption.pop_day_night_end_time = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_price_night") == 0) PaymentOption.pop_price_night = k->value.GetDouble();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_min_time") == 0) PaymentOption.pop_min_time = k->value.GetDouble();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_max_time") == 0) PaymentOption.pop_max_time = k->value.GetDouble();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_min_price") == 0) PaymentOption.pop_min_price = k->value.GetDouble();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_carry_over") == 0) PaymentOption.pop_carry_over = k->value.GetInt();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::DurationType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pun_id") == 0) Duration.pun_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pun_label") == 0) Duration.pun_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pun_duration") == 0) Duration.pun_duration = k->value.GetDouble();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::SpecialDaysWorktimeType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pedwt_id") == 0) SpecialDaysWorktime.pedwt_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pedwt_period_exc_day_id") == 0) SpecialDaysWorktime.pedwt_period_exc_day_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pedwt_time_from") == 0) SpecialDaysWorktime.pedwt_time_from = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pedwt_time_to") == 0) SpecialDaysWorktime.pedwt_time_to = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pedwt_price") == 0) SpecialDaysWorktime.pedwt_price = k->value.GetDouble();
 | 
			
		||||
						break;
 | 
			
		||||
					/*case MemberType::WeekDaysType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pdiw_id") == 0) WeekDays.pdiw_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pdiw_label") == 0) WeekDays.pdiw_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pdiw_index") == 0) WeekDays.pdiw_index = k->value.GetInt();
 | 
			
		||||
						break;*/
 | 
			
		||||
					case MemberType::WeekDaysWorkTimeType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pwd_id") == 0) WeekDaysWorktime.pwd_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pwd_period_week_day_id") == 0) WeekDaysWorktime.pwd_period_week_day_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pwd_period_day_in_week_id") == 0) WeekDaysWorktime.pwd_period_day_in_week_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pwd_time_from") == 0) WeekDaysWorktime.pwd_time_from = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pwd_time_to") == 0) WeekDaysWorktime.pwd_time_to = k->value.GetString();
 | 
			
		||||
					case MemberType::SpecialDaysType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "ped_id") == 0) SpecialDays.ped_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_label") == 0) SpecialDays.ped_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_date_start") == 0) SpecialDays.ped_date_start = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_date_end") == 0) SpecialDays.ped_date_end = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_period_special_day_id") == 0) SpecialDays.ped_period_special_day_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_year") == 0) SpecialDays.ped_year = k->value.GetInt();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::PeriodYearType:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pye_id") == 0) YearPeriod.pye_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_label") == 0) YearPeriod.pye_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_start_month") == 0) YearPeriod.pye_start_month = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_start_day") == 0) YearPeriod.pye_start_day = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_end_month") == 0) YearPeriod.pye_end_month = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_end_day") == 0) YearPeriod.pye_end_day = k->value.GetInt();
 | 
			
		||||
						break;
 | 
			
		||||
					default:
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
//#pragma endregion
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				// Push to specific list depending on member type
 | 
			
		||||
				switch (mb_type)
 | 
			
		||||
				{
 | 
			
		||||
				case MemberType::UnknownType:
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::PaymentMethodType:
 | 
			
		||||
					cfg->PaymentMethod.insert(pair<int, ATBPaymentMethod>(PaymentMethod.pme_id, PaymentMethod));
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::PaymentRateType:
 | 
			
		||||
					cfg->PaymentRate.insert(pair<int, ATBPaymentRate>(PaymentRate.pra_payment_unit_id, PaymentRate));
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::PaymentOptionType:
 | 
			
		||||
					cfg->PaymentOption.insert(pair<int, ATBPaymentOption>(PaymentOption.pop_payment_method_id, PaymentOption));
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::DurationType:
 | 
			
		||||
					cfg->Duration.insert(pair<int, ATBDuration>(Duration.pun_id, Duration));
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::SpecialDaysWorktimeType:
 | 
			
		||||
					cfg->SpecialDaysWorktime.insert(pair<int, ATBSpecialDaysWorktime>(SpecialDaysWorktime.pedwt_period_exc_day_id, SpecialDaysWorktime));
 | 
			
		||||
					break;
 | 
			
		||||
				//case MemberType::WeekDaysType:
 | 
			
		||||
				//	cfg->WeekDays.insert(pair<int, ATBWeekDays>(WeekDays.pdiw_index, WeekDays));
 | 
			
		||||
				//	break;
 | 
			
		||||
				case MemberType::WeekDaysWorkTimeType:
 | 
			
		||||
					cfg->WeekDaysWorktime.insert(pair<int, ATBWeekDaysWorktime>(WeekDaysWorktime.pwd_period_day_in_week_id, WeekDaysWorktime));
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::SpecialDaysType:
 | 
			
		||||
					cfg->SpecialDays.insert(pair<int, ATBSpecialDays>(SpecialDays.ped_id, SpecialDays));
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::PeriodYearType:
 | 
			
		||||
					cfg->YearPeriod.insert(pair<int, ATBPeriodYear>(YearPeriod.pye_id, YearPeriod));
 | 
			
		||||
					break;
 | 
			
		||||
				default:
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	catch (...) {
 | 
			
		||||
		printf("%s\n", "General exception has occurred while parsing JSON\n");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										0
									
								
								library/src/log.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								library/src/log.cpp
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										150
									
								
								library/src/tariff_calc.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								library/src/tariff_calc.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
			
		||||
#include "tariff_calc.h"
 | 
			
		||||
#include "tariff_utils.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Helper function
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="pra_price"></param>
 | 
			
		||||
/// <returns></returns>
 | 
			
		||||
double CalculatePricePerUnit(double pra_price)
 | 
			
		||||
{
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		double price_per_unit = pra_price;
 | 
			
		||||
		price_per_unit /= 60.0f; 
 | 
			
		||||
// Divided by 60 because price per unit is set per hour and we are using minutes
 | 
			
		||||
		printf("Price per unit (min) is: %lf EUR\n", price_per_unit);
 | 
			
		||||
		return price_per_unit;
 | 
			
		||||
	}
 | 
			
		||||
	catch (...)
 | 
			
		||||
	{
 | 
			
		||||
		printf("An error has occurred in CalculatePricePerUnit() function\n");
 | 
			
		||||
		return 0.0f;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
double TariffCalculator::GetDurationFromCost(TariffConfiguration* tariff_cfg,
 | 
			
		||||
    uint8_t vehicle_type, char const* start_datetime, double price) {
 | 
			
		||||
	uint8_t pay_method = PaymentMethod::Undefined;
 | 
			
		||||
	double cost = 0.0f;
 | 
			
		||||
 | 
			
		||||
	// Payment method is automatically selected by vehicle type 
 | 
			
		||||
	// (vehicle type byte actually represents payment type according to documentation)
 | 
			
		||||
	// e.g. car (0x03) in tariff_vehicles_type == linear payment method (0x03)
 | 
			
		||||
    // tariff_payment_method
 | 
			
		||||
 | 
			
		||||
	pay_method = vehicle_type; // car = 0x03
 | 
			
		||||
	printf("Payment method: %d\n", pay_method);
 | 
			
		||||
 | 
			
		||||
	double price_per_unit = 0;
 | 
			
		||||
	double durationMin = 0;
 | 
			
		||||
 | 
			
		||||
	bool isSpecialDay = false;
 | 
			
		||||
	int spec_day_id = -1;
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i <= tariff_cfg->PaymentRate.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (pay_method == tariff_cfg->PaymentRate.at(i).pra_payment_option_id)
 | 
			
		||||
		{
 | 
			
		||||
			double pra_price = tariff_cfg->PaymentRate.at(i).pra_price;
 | 
			
		||||
 | 
			
		||||
			// If is special day, pra_price will be overriden with special day's price
 | 
			
		||||
            if ((isSpecialDay = TariffUtils::IsSpecialDay(tariff_cfg, start_datetime, spec_day_id))) {
 | 
			
		||||
                if (TariffUtils::PriceForSpecialDay(tariff_cfg, spec_day_id, &pra_price)) {
 | 
			
		||||
                    printf("Date %s is special day\n", start_datetime);
 | 
			
		||||
                    printf("Setting new price per hour: %f EUR\n", pra_price);
 | 
			
		||||
                }
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			price_per_unit = CalculatePricePerUnit(pra_price);
 | 
			
		||||
			if (price_per_unit <= 0) price_per_unit = 1; // Division by zero protection
 | 
			
		||||
 | 
			
		||||
			durationMin = price / price_per_unit;
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Check active hours for parking (override with special day active hours if special day flag is set)
 | 
			
		||||
	ActiveTimeRange active_time_range = 
 | 
			
		||||
        TariffUtils::isParkingTimeRangeActive(tariff_cfg, start_datetime, 
 | 
			
		||||
                                              isSpecialDay, spec_day_id);
 | 
			
		||||
	printf("Is active parking payment: %d\n", active_time_range.isActive);
 | 
			
		||||
 | 
			
		||||
	// TODO: CHECK
 | 
			
		||||
 | 
			
		||||
    struct tm initial_tm;
 | 
			
		||||
    TariffUtils::DateTimeToStructTm(start_datetime, &initial_tm);
 | 
			
		||||
	time_t initial = mktime(&initial_tm);
 | 
			
		||||
	TariffUtils::ValidateParkingTicket(tariff_cfg, initial, durationMin, price, 
 | 
			
		||||
                       active_time_range.timeRange, isSpecialDay, spec_day_id);
 | 
			
		||||
 | 
			
		||||
	// If parking payment active hours have passed, do not calculate duration
 | 
			
		||||
	if (!active_time_range.isActive) return 0.0f;
 | 
			
		||||
	return durationMin;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
double TariffCalculator::GetCostFromDuration(TariffConfiguration* tariff_cfg,
 | 
			
		||||
    uint8_t vehicle_type, char const* start_datetime, double durationMin) {
 | 
			
		||||
	uint8_t pay_method = PaymentMethod::Undefined;
 | 
			
		||||
	double cost = 0.0f;
 | 
			
		||||
 | 
			
		||||
	// Payment method is automatically selected by vehicle type 
 | 
			
		||||
	// (vehicle type byte actually represents payment type according to documentation)
 | 
			
		||||
	// e.g. car (0x03) in tariff_vehicles_type == linear payment method (0x03) 
 | 
			
		||||
    // tariff_payment_method
 | 
			
		||||
 | 
			
		||||
	pay_method = vehicle_type; // car = 0x03
 | 
			
		||||
	printf("Payment method: %d\n", pay_method);
 | 
			
		||||
 | 
			
		||||
	int unit = 1.0f; // Unit factor, as parameter 'durationMin' 
 | 
			
		||||
                     // represents minutes, this should stay 1
 | 
			
		||||
	double price_per_unit = 0;
 | 
			
		||||
 | 
			
		||||
	bool isSpecialDay = false;
 | 
			
		||||
	int spec_day_id = -1;
 | 
			
		||||
 | 
			
		||||
    for (size_t i = 0; i <= tariff_cfg->PaymentRate.size(); i++)
 | 
			
		||||
	{
 | 
			
		||||
		if (pay_method == tariff_cfg->PaymentRate.at(i).pra_payment_option_id)
 | 
			
		||||
		{
 | 
			
		||||
			double pra_price = tariff_cfg->PaymentRate.at(i).pra_price;
 | 
			
		||||
            if ((isSpecialDay
 | 
			
		||||
                    = TariffUtils::IsSpecialDay(tariff_cfg,
 | 
			
		||||
                                                start_datetime, spec_day_id))) {
 | 
			
		||||
                // If is special day, pra_price will be
 | 
			
		||||
                // overriden with special day's price
 | 
			
		||||
                if (TariffUtils::PriceForSpecialDay(tariff_cfg, spec_day_id, &pra_price)) {
 | 
			
		||||
                    printf("Date %s is special day\n", start_datetime);
 | 
			
		||||
                    printf("Setting new price per hour: %f EUR\n", pra_price);
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
			price_per_unit = CalculatePricePerUnit(pra_price);
 | 
			
		||||
			break;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cost = durationMin * price_per_unit;
 | 
			
		||||
 | 
			
		||||
	// Check active hours for parking (override with special day active hours
 | 
			
		||||
    // if special day flag is set)
 | 
			
		||||
	ActiveTimeRange active_time_range 
 | 
			
		||||
        = TariffUtils::isParkingTimeRangeActive(tariff_cfg, start_datetime, 
 | 
			
		||||
                                                isSpecialDay, spec_day_id);
 | 
			
		||||
	printf("Is active parking payment: %d\n", active_time_range.isActive);
 | 
			
		||||
 | 
			
		||||
	// TODO: CHECK
 | 
			
		||||
    struct tm initial_tm;
 | 
			
		||||
    TariffUtils::DateTimeToStructTm(start_datetime, &initial_tm);
 | 
			
		||||
	time_t initial = mktime(&initial_tm);
 | 
			
		||||
	TariffUtils::ValidateParkingTicket(tariff_cfg, initial, durationMin, cost, 
 | 
			
		||||
                        active_time_range.timeRange, isSpecialDay, spec_day_id);
 | 
			
		||||
 | 
			
		||||
	// If parking payment active hours have passed, do not calculate price
 | 
			
		||||
	if (!active_time_range.isActive) return 0.0f;
 | 
			
		||||
 | 
			
		||||
	return cost;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										292
									
								
								library/src/tariff_cfg.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										292
									
								
								library/src/tariff_cfg.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,292 @@
 | 
			
		||||
// #pragma once
 | 
			
		||||
#include "tariff_cfg.h"
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
MemberType TariffConfiguration::IdentifyJsonMember(const char* member_name)
 | 
			
		||||
{
 | 
			
		||||
	if (strcmp(member_name, "Currency") == 0) 
 | 
			
		||||
        return MemberType::Currency;
 | 
			
		||||
	if (strcmp(member_name, "PaymentMethod") == 0) 
 | 
			
		||||
        return MemberType::PaymentMethod;
 | 
			
		||||
	if (strcmp(member_name, "PaymentRate") == 0) 
 | 
			
		||||
        return MemberType::PaymentRate;
 | 
			
		||||
	if (strcmp(member_name, "PaymentOption") == 0) 
 | 
			
		||||
        return MemberType::PaymentOption;
 | 
			
		||||
	if (strcmp(member_name, "Duration") == 0) 
 | 
			
		||||
        return MemberType::Duration;
 | 
			
		||||
	if (strcmp(member_name, "WeekDays") == 0) 
 | 
			
		||||
        return MemberType::WeekDays;
 | 
			
		||||
	if (strcmp(member_name, "WeekDaysWorktime") == 0) 
 | 
			
		||||
        return MemberType::WeekDaysWorkTime;
 | 
			
		||||
	if (strcmp(member_name, "SpecialDaysWorktime") == 0) 
 | 
			
		||||
        return MemberType::SpecialDaysWorktime;
 | 
			
		||||
	if (strcmp(member_name, "SpecialDays") == 0) 
 | 
			
		||||
        return MemberType::SpecialDays;
 | 
			
		||||
	if (strcmp(member_name, "PeriodYear") == 0) 
 | 
			
		||||
        return MemberType::PeriodYear;
 | 
			
		||||
	else return MemberType::Unknown;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
bool TariffConfiguration::ParseJson(TariffConfiguration* tariff_cfg,
 | 
			
		||||
                                    const char* json) {
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		if (tariff_cfg == nullptr)
 | 
			
		||||
		{
 | 
			
		||||
			printf("TariffConfiguration pointer not set\n");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		if (json == NULL)
 | 
			
		||||
		{
 | 
			
		||||
			printf("%s", "Input JSON string is NULL\n");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Parse JSON to document
 | 
			
		||||
		Document document;
 | 
			
		||||
		document.Parse(json);
 | 
			
		||||
 | 
			
		||||
		// Return if parse error has been found
 | 
			
		||||
		ParseErrorCode err = document.GetParseError();
 | 
			
		||||
		if (err != 0)
 | 
			
		||||
		{
 | 
			
		||||
			printf("%s %d (%s)\n", "Unable to parse JSON, error code:",
 | 
			
		||||
                        err, GetParseError_En(err));
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Validate JSON, check if it's a JSON object
 | 
			
		||||
		printf("%s", "JSON parsing has been successful\n");
 | 
			
		||||
		if (!document.IsObject()) {
 | 
			
		||||
			printf("%s", "Error: not a (valid) JSON object\n");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		printf("%s", "Valid JSON object identified\n");
 | 
			
		||||
 | 
			
		||||
		// Validate JSON, check configuration members
 | 
			
		||||
		if (!document.HasMember("Currency")
 | 
			
		||||
			|| !document.HasMember("PaymentMethod")
 | 
			
		||||
			|| !document.HasMember("PaymentOption")
 | 
			
		||||
			|| !document.HasMember("PaymentRate")
 | 
			
		||||
			|| !document.HasMember("Duration")
 | 
			
		||||
			|| !document.HasMember("WeekDays")
 | 
			
		||||
			|| !document.HasMember("SpecialDaysWorktime")
 | 
			
		||||
			|| !document.HasMember("SpecialDays"))
 | 
			
		||||
		{
 | 
			
		||||
			printf("%s", "Error: not a valid configuration JSON\n");
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
		printf("%s", "Valid JSON configuration identified\n");
 | 
			
		||||
 | 
			
		||||
		TariffCurrency Currency;
 | 
			
		||||
		TariffDuration Duration;
 | 
			
		||||
		TariffPaymentMethod PaymentMethod;
 | 
			
		||||
		TariffPaymentRate PaymentOption;
 | 
			
		||||
		TariffSpecialDaysWorktime SpecialDaysWorktime;
 | 
			
		||||
		TariffSpecialDays SpecialDays;
 | 
			
		||||
		TariffWeekDays  WeekDays;
 | 
			
		||||
		TariffWeekDaysWorktime  WeekDaysWorktime;
 | 
			
		||||
		TariffPaymentOption VehicleType;
 | 
			
		||||
		TariffPeriodYear YearPeriod;
 | 
			
		||||
		MemberType mb_type;
 | 
			
		||||
 | 
			
		||||
		// Get all JSON object members
 | 
			
		||||
		// This code should run only once (to load JSON variables into memory)
 | 
			
		||||
		for (auto i = document.MemberBegin(); i != document.MemberEnd(); i++)
 | 
			
		||||
		{
 | 
			
		||||
			// Get name of all general members of JSON, don't print name if NULL
 | 
			
		||||
			const char* mb_name = i->name.GetString();
 | 
			
		||||
			if (mb_name == NULL) continue;
 | 
			
		||||
 | 
			
		||||
			//printf(" -%s\n", mb_name);
 | 
			
		||||
            mb_type = IdentifyJsonMember(mb_name);
 | 
			
		||||
 | 
			
		||||
			// Get array for each JSON object member
 | 
			
		||||
			auto mb_array = document[mb_name].GetArray();
 | 
			
		||||
			if (mb_array.Size() <= 0) break;
 | 
			
		||||
 | 
			
		||||
			//Iterate over provided array
 | 
			
		||||
            for (rapidjson::SizeType j = 0; j < mb_array.Size(); j++)
 | 
			
		||||
			{
 | 
			
		||||
				// Get all inner objects, don't print name if NULL
 | 
			
		||||
				auto inner_obj = mb_array[j].GetObject();
 | 
			
		||||
				if (inner_obj.MemberCount() <= 0) break;
 | 
			
		||||
 | 
			
		||||
				// Iterate over inner object JSON members
 | 
			
		||||
				for (auto k = inner_obj.MemberBegin(); k != inner_obj.MemberEnd(); k++)
 | 
			
		||||
				{
 | 
			
		||||
					// Get inner object JSON member, don't print name if NULL
 | 
			
		||||
					const char* inner_obj_name = k->name.GetString();
 | 
			
		||||
					if (inner_obj_name == NULL)
 | 
			
		||||
					{
 | 
			
		||||
						printf("Inner object name is NULL\n");
 | 
			
		||||
						continue;
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					// Identify member type
 | 
			
		||||
					mb_type = IdentifyJsonMember(mb_name);
 | 
			
		||||
// #pragma region Get_values
 | 
			
		||||
					switch (mb_type)
 | 
			
		||||
					{
 | 
			
		||||
					case MemberType::Unknown:
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::Currency:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pcu_id") == 0) 
 | 
			
		||||
                            Currency.pcu_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pcu_sign") == 0) 
 | 
			
		||||
                            Currency.pcu_sign = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pcu_major") == 0) 
 | 
			
		||||
                            Currency.pcu_major = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pcu_minor") == 0) 
 | 
			
		||||
                            Currency.pcu_minor = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pcu_active") == 0) 
 | 
			
		||||
                            Currency.pcu_active = k->value.GetBool();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::PaymentMethod:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pme_id") == 0) 
 | 
			
		||||
                            PaymentMethod.pme_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pme_label") == 0) 
 | 
			
		||||
                            PaymentMethod.pme_label = k->value.GetString();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::PaymentRate:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pra_payment_option_id") == 0) 
 | 
			
		||||
                            PaymentOption.pra_payment_option_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pra_payment_unit_id") == 0) 
 | 
			
		||||
                            PaymentOption.pra_payment_unit_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pra_price") == 0) 
 | 
			
		||||
                            PaymentOption.pra_price = k->value.GetDouble();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::PaymentOption:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pop_id") == 0) 
 | 
			
		||||
                            VehicleType.pop_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_label") == 0) 
 | 
			
		||||
                            VehicleType.pop_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_payment_method_id") == 0) 
 | 
			
		||||
                            VehicleType.pop_payment_method_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_day_end_time") == 0) 
 | 
			
		||||
                            VehicleType.pop_day_end_time = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_day_night_end_time") == 0) 
 | 
			
		||||
                            VehicleType.pop_day_night_end_time = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pop_price_night") == 0) 
 | 
			
		||||
                            VehicleType.pop_price_night = k->value.GetDouble();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::Duration:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pun_id") == 0) 
 | 
			
		||||
                            Duration.pun_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pun_label") == 0) 
 | 
			
		||||
                            Duration.pun_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pun_duration") == 0) 
 | 
			
		||||
                            Duration.pun_duration = k->value.GetDouble();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::SpecialDaysWorktime:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pedwt_id") == 0) 
 | 
			
		||||
                            SpecialDaysWorktime.pedwt_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pedwt_period_exc_day_id") == 0) 
 | 
			
		||||
                            SpecialDaysWorktime.pedwt_period_exc_day_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pedwt_time_from") == 0) 
 | 
			
		||||
                            SpecialDaysWorktime.pedwt_time_from = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pedwt_time_to") == 0) 
 | 
			
		||||
                            SpecialDaysWorktime.pedwt_time_to = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pedwt_price") == 0) 
 | 
			
		||||
                            SpecialDaysWorktime.pedwt_price = k->value.GetDouble();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::WeekDays:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pdiw_id") == 0) 
 | 
			
		||||
                            WeekDays.pdiw_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pdiw_label") == 0) 
 | 
			
		||||
                            WeekDays.pdiw_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pdiw_index") == 0) 
 | 
			
		||||
                            WeekDays.pdiw_index = k->value.GetInt();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::WeekDaysWorkTime:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pwd_id") == 0) 
 | 
			
		||||
                            WeekDaysWorktime.pwd_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pwd_period_week_day_id") == 0) 
 | 
			
		||||
                            WeekDaysWorktime.pwd_period_day_in_week_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pwd_period_day_in_week_id") == 0) 
 | 
			
		||||
                            WeekDaysWorktime.pwd_period_week_day_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pwd_time_from") == 0) 
 | 
			
		||||
                            WeekDaysWorktime.pwd_time_from = k->value.GetString();
 | 
			
		||||
                        else if (strcmp(inner_obj_name, "pwd_time_to") == 0) 
 | 
			
		||||
                            WeekDaysWorktime.pwd_time_to = k->value.GetString();
 | 
			
		||||
                        break;
 | 
			
		||||
					case MemberType::SpecialDays:
 | 
			
		||||
						if (strcmp(inner_obj_name, "ped_id") == 0) 
 | 
			
		||||
                            SpecialDays.ped_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_label") == 0) 
 | 
			
		||||
                            SpecialDays.ped_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_date_start") == 0) 
 | 
			
		||||
                            SpecialDays.ped_date_start = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_date_end") == 0) 
 | 
			
		||||
                            SpecialDays.ped_date_end = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "ped_period_special_day_id") == 0) 
 | 
			
		||||
                            SpecialDays.ped_period_special_day_id = k->value.GetInt();
 | 
			
		||||
						break;
 | 
			
		||||
					case MemberType::PeriodYear:
 | 
			
		||||
						if (strcmp(inner_obj_name, "pye_id") == 0) 
 | 
			
		||||
                            YearPeriod.pye_id = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_label") == 0) 
 | 
			
		||||
                            YearPeriod.pye_label = k->value.GetString();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_start_month") == 0) 
 | 
			
		||||
                            YearPeriod.pye_start_month = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_start_day") == 0) 
 | 
			
		||||
                            YearPeriod.pye_start_day = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_end_month") == 0) 
 | 
			
		||||
                            YearPeriod.pye_end_month = k->value.GetInt();
 | 
			
		||||
						else if (strcmp(inner_obj_name, "pye_end_day") == 0) 
 | 
			
		||||
                            YearPeriod.pye_end_day = k->value.GetInt();
 | 
			
		||||
						break;
 | 
			
		||||
					default:
 | 
			
		||||
						break;
 | 
			
		||||
					}
 | 
			
		||||
// #pragma endregion
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
				// Push to specific list depending on member type
 | 
			
		||||
				switch (mb_type)
 | 
			
		||||
				{
 | 
			
		||||
				case MemberType::Unknown:
 | 
			
		||||
					break;
 | 
			
		||||
                case MemberType::Currency:
 | 
			
		||||
					tariff_cfg->Currency.push_back(Currency);
 | 
			
		||||
					break;
 | 
			
		||||
                case MemberType::PaymentMethod:
 | 
			
		||||
					tariff_cfg->PaymentMethod.push_back(PaymentMethod);
 | 
			
		||||
					break;
 | 
			
		||||
                case MemberType::PaymentRate:
 | 
			
		||||
                    tariff_cfg->PaymentRate.push_back(PaymentOption);
 | 
			
		||||
					break;
 | 
			
		||||
                case MemberType::PaymentOption:
 | 
			
		||||
					tariff_cfg->PaymentOption.push_back(VehicleType);
 | 
			
		||||
					break;
 | 
			
		||||
                case MemberType::Duration:
 | 
			
		||||
					tariff_cfg->Duration.push_back(Duration);
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::SpecialDaysWorktime:
 | 
			
		||||
					tariff_cfg->SpecialDaysWorktime.push_back(SpecialDaysWorktime);
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::WeekDays:
 | 
			
		||||
					tariff_cfg->WeekDays.push_back(WeekDays);
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::WeekDaysWorkTime:
 | 
			
		||||
					tariff_cfg->WeekDaysWorktime.push_back(WeekDaysWorktime);
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::SpecialDays:
 | 
			
		||||
					tariff_cfg->SpecialDays.push_back(SpecialDays);
 | 
			
		||||
					break;
 | 
			
		||||
				case MemberType::PeriodYear:
 | 
			
		||||
					tariff_cfg->YearPeriod.push_back(YearPeriod);
 | 
			
		||||
					break;
 | 
			
		||||
                default:
 | 
			
		||||
					break;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return true;
 | 
			
		||||
	}
 | 
			
		||||
	catch (...) {
 | 
			
		||||
		printf("%s\n", "General exception has occurred while parsing JSON\n");
 | 
			
		||||
		return false;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										13
									
								
								library/src/tariff_log.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								library/src/tariff_log.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,13 @@
 | 
			
		||||
#include "tariff_log.h"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
static int debugLevel = DBG_LEVEL_CRITICAL;
 | 
			
		||||
// static int debugLevel = DBG_LEVEL_INFO;
 | 
			
		||||
 | 
			
		||||
void setDebugLevel(int level) {
 | 
			
		||||
    debugLevel = level;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int getDebugLevel() {
 | 
			
		||||
    return debugLevel;
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										161
									
								
								library/src/tariff_utils.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										161
									
								
								library/src/tariff_utils.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,161 @@
 | 
			
		||||
#include "tariff_utils.h"
 | 
			
		||||
#include <assert.h>
 | 
			
		||||
#include <ctime>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
time_t TariffUtils::GetCurrentLocalTime() {
 | 
			
		||||
    time_t epoch = time(NULL);
 | 
			
		||||
    struct tm *local_time = localtime(&epoch);
 | 
			
		||||
    if (local_time) {
 | 
			
		||||
        // local_time->tm_isdst > 0: DST is in effect
 | 
			
		||||
        // local_time->tm_isdst = 0: DST is not in effect
 | 
			
		||||
        // and a negative value means that mktime() should use timezone
 | 
			
		||||
        // information to attempt to determine whether DST is in effect
 | 
			
		||||
        // at the specified time.
 | 
			
		||||
        local_time->tm_isdst = -1;
 | 
			
		||||
        return mktime(local_time);
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
bool TariffUtils::DateToStructTm(const char* dateStr, struct tm *t) {
 | 
			
		||||
    return (strptime(dateStr, "%Y-%m-%d", t) != 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static time_t DateTimeStrToTime(std::string const &dateTimeStr) {
 | 
			
		||||
    struct tm t = {};
 | 
			
		||||
    if (strptime(dateTimeStr.c_str(), "%Y-%m-%dT%H:%M:%S", &t) != 0) {
 | 
			
		||||
        t.tm_isdst = -1;
 | 
			
		||||
        return mktime(&t);
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
bool TariffUtils::TimeToStructTm(const char* timeStr, struct tm *t) {
 | 
			
		||||
    return (strptime(timeStr, "%H:%M:%S", t) != 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>ateTimeToStructTm(char const* dateTimeStr) {
 | 
			
		||||
bool TariffUtils::DateTimeToStructTm(char const* dateTimeStr, struct tm *t) {
 | 
			
		||||
    return (strptime(dateTimeStr, "%Y-%m-%dT%H:%M:%S", t) != 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
DayOfWeek TariffUtils::GetDayOfWeek(struct tm const *t) {
 | 
			
		||||
    return (DayOfWeek)t->tm_wday;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
bool TariffUtils::IsSpecialDay(TariffConfiguration const* tariff_cfg,
 | 
			
		||||
                               const char* datetime, int& specialDayId) {
 | 
			
		||||
    for (size_t i = 0; i < tariff_cfg->SpecialDays.size(); i++) {
 | 
			
		||||
        TariffSpecialDays const &sd = tariff_cfg->SpecialDays[i];
 | 
			
		||||
        char const *sdt = sd.ped_date_start.c_str();
 | 
			
		||||
        char const *edt = sd.ped_date_end.c_str();
 | 
			
		||||
 | 
			
		||||
        // format datetime: 2022-12-04T22:30:30
 | 
			
		||||
        // format sdt resp. edt: 2022-12-25
 | 
			
		||||
        // comparing the strings gives the result
 | 
			
		||||
        if (strncmp(datetime, sdt, strlen(sdt)) >= 0
 | 
			
		||||
         && strncmp(datetime, edt, strlen(edt)) <= 0) {
 | 
			
		||||
            specialDayId = sd.ped_id;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool TariffUtils::PriceForSpecialDay(TariffConfiguration const* tariff_cfg,
 | 
			
		||||
                                     int specialDayId, double *price) {
 | 
			
		||||
    for (size_t j = 0; j <= tariff_cfg->SpecialDaysWorktime.size(); j++) {
 | 
			
		||||
        int wt_id = tariff_cfg->SpecialDaysWorktime.at(j).pedwt_period_exc_day_id;
 | 
			
		||||
        if (specialDayId == wt_id) {
 | 
			
		||||
            *price = tariff_cfg->SpecialDaysWorktime.at(j).pedwt_price;
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
bool TariffUtils::ValidateParkingTicket(TariffConfiguration const */*tariff_cfg*/,
 | 
			
		||||
                                        time_t /*initial*/,
 | 
			
		||||
                                        int /*durationMin*/,
 | 
			
		||||
                                        double /*price*/,
 | 
			
		||||
                                        TariffTimeRange /*time_range*/,
 | 
			
		||||
                                        bool /*isSpecialDay*/,
 | 
			
		||||
                                        int /*spec_day_id*/) {
 | 
			
		||||
    // TODO
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static ActiveTimeRange computeActiveTimeRange(std::string const ¤tDayDate,
 | 
			
		||||
                                              std::string const ¤tDayTime,
 | 
			
		||||
                                              std::string const &time_from,
 | 
			
		||||
                                              std::string const &time_to) {
 | 
			
		||||
    ActiveTimeRange result;
 | 
			
		||||
 | 
			
		||||
    if (currentDayTime.compare(time_from) >= 0
 | 
			
		||||
     && currentDayTime.compare(time_to) <= 0) {
 | 
			
		||||
        std::string timeFrom = currentDayDate + "T" + time_from;
 | 
			
		||||
        std::string timeTo = currentDayDate + "T" + time_to;
 | 
			
		||||
        time_t const from = DateTimeStrToTime(timeFrom);
 | 
			
		||||
        time_t const to = DateTimeStrToTime(timeTo);
 | 
			
		||||
        if (from != -1 && to != -1) {
 | 
			
		||||
            result.timeRange.time_from = from;
 | 
			
		||||
            result.timeRange.time_to = to;
 | 
			
		||||
            result.isActive = true;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <inheritdoc/>
 | 
			
		||||
ActiveTimeRange
 | 
			
		||||
TariffUtils::isParkingTimeRangeActive(TariffConfiguration* tariff_cfg,
 | 
			
		||||
                                      std::string datetimeStr,
 | 
			
		||||
                                      bool isSpecialDay = false,
 | 
			
		||||
                                      int spec_day_id = -1) {
 | 
			
		||||
    size_t const pos = datetimeStr.find_first_of('T');
 | 
			
		||||
    if (pos == std::string::npos || pos == 0 || pos >= datetimeStr.size()-1) {
 | 
			
		||||
        return ActiveTimeRange();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // split dateTime at 'T'
 | 
			
		||||
    std::string const currentDayDate = datetimeStr.substr(0, pos - 1);
 | 
			
		||||
    std::string const currentDayTime = datetimeStr.substr(pos + 1);
 | 
			
		||||
 | 
			
		||||
    // return (strptime(dateStr, "%Y-%m-%d", t) != 0);
 | 
			
		||||
 | 
			
		||||
    if (isSpecialDay) {
 | 
			
		||||
        for (size_t i = 0; i < tariff_cfg->SpecialDaysWorktime.size(); i++) {
 | 
			
		||||
            TariffSpecialDaysWorktime const &sdwt = tariff_cfg->SpecialDaysWorktime[i];
 | 
			
		||||
            if (sdwt.pedwt_period_exc_day_id == spec_day_id) {
 | 
			
		||||
                std::string const &time_from = sdwt.pedwt_time_from;
 | 
			
		||||
                std::string const &time_to = sdwt.pedwt_time_to;
 | 
			
		||||
                return computeActiveTimeRange(currentDayDate, currentDayTime,
 | 
			
		||||
                                              time_from, time_to);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        struct tm current_time_tm = {};
 | 
			
		||||
        if (!TariffUtils::DateTimeToStructTm(datetimeStr.c_str(), ¤t_time_tm)) {
 | 
			
		||||
            return ActiveTimeRange();
 | 
			
		||||
        }
 | 
			
		||||
        auto const dayOfWeek = TariffUtils::GetDayOfWeek(¤t_time_tm);
 | 
			
		||||
        for (size_t i = 0; i < tariff_cfg->WeekDaysWorktime.size(); i++) {
 | 
			
		||||
            TariffWeekDaysWorktime const &wdwt = tariff_cfg->WeekDaysWorktime[i];
 | 
			
		||||
            if (wdwt.pwd_period_day_in_week_id == dayOfWeek) {
 | 
			
		||||
                std::string const &time_from = wdwt.pwd_time_from;
 | 
			
		||||
                std::string const &time_to = wdwt.pwd_time_to;
 | 
			
		||||
                return computeActiveTimeRange(currentDayDate, currentDayTime,
 | 
			
		||||
                                              time_from, time_to);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return ActiveTimeRange();
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										270
									
								
								library/src/utilities.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										270
									
								
								library/src/utilities.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,270 @@
 | 
			
		||||
#include "utilities.h"
 | 
			
		||||
#include "tariff_log.h"
 | 
			
		||||
 | 
			
		||||
static int protection_counter = 0;
 | 
			
		||||
 | 
			
		||||
/// <summary>
 | 
			
		||||
/// Helper function
 | 
			
		||||
/// </summary>
 | 
			
		||||
/// <param name="pra_price"></param>
 | 
			
		||||
/// <returns></returns>
 | 
			
		||||
double Utilities::CalculatePricePerUnit(double pra_price)
 | 
			
		||||
{
 | 
			
		||||
	try
 | 
			
		||||
	{
 | 
			
		||||
		double price_per_unit = pra_price;
 | 
			
		||||
		price_per_unit /= 60.0f; // 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;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// <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;
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user