Compare commits
59 Commits
Author | SHA1 | Date | |
---|---|---|---|
d15c9dad29
|
|||
cb8cd5dead
|
|||
9d64350e4f
|
|||
1a71edc274 | |||
51d8beda2a | |||
7bab9d6ba2 | |||
8b4d64bd0c | |||
eefdde4693 | |||
6157861d62 | |||
23748966de
|
|||
7bd7f66666 | |||
268d43cdea
|
|||
a453886f0a
|
|||
eef94a3fb3
|
|||
88a0b6ebe2
|
|||
3097819c01
|
|||
acf799da7e
|
|||
3bf71f84d5
|
|||
73f5eca656
|
|||
b8753cc2ed
|
|||
29986e0451
|
|||
1146db743c
|
|||
c6302edec5
|
|||
617eee39ed | |||
6b3c1cbf0c | |||
1142efaec2 | |||
90eae152bf
|
|||
6d001f1501
|
|||
de32022b89
|
|||
1e2f1589ac
|
|||
2f8c8cab4c | |||
ee1f7eca44
|
|||
1069c5ad90
|
|||
46bffc250d
|
|||
2599513ef9 | |||
ef66c1f0c0 | |||
219d820104 | |||
ed9166c226 | |||
818c67ad63 | |||
4a076e1dad
|
|||
62426e60d5
|
|||
c28351b1bf
|
|||
69c469c918
|
|||
e7606b6568 | |||
fe0ebb409a
|
|||
3d88c8e67e
|
|||
eebb6d926e | |||
69c48e3acc | |||
5c0bbf1502
|
|||
31df676b57
|
|||
889fceaae0 | |||
5ec2a6d730
|
|||
136e6687b8 | |||
3cc447ca87
|
|||
b02115bf75 | |||
ceb545b432 | |||
01f2dc07ce | |||
c5960a031e | |||
1c03745333 |
@@ -4,6 +4,9 @@
|
||||
#include <time.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef CALCULATE_LIBRARY_EXPORTS
|
||||
#define CALCULATE_LIBRARY_API __declspec(dllexport)
|
||||
@@ -18,9 +21,9 @@ class Configuration;
|
||||
|
||||
typedef Configuration parking_tariff_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
//#ifdef __cplusplus
|
||||
//extern "C" {
|
||||
//#endif
|
||||
|
||||
struct CALCULATE_LIBRARY_API price_t {
|
||||
uint32_t units;
|
||||
@@ -30,16 +33,113 @@ struct CALCULATE_LIBRARY_API price_t {
|
||||
double vat;
|
||||
};
|
||||
|
||||
bool CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file);
|
||||
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff);
|
||||
int CALCULATE_LIBRARY_API get_zone_nr();
|
||||
struct CALCULATE_LIBRARY_API CalcState {
|
||||
enum class State : uint8_t {
|
||||
SUCCESS,
|
||||
ERROR_PARSING_ZONE_NR,
|
||||
ERROR_LOADING_TARIFF,
|
||||
ERROR_PARSING_TARIFF,
|
||||
NEGATIVE_PARING_TIME,
|
||||
INVALID_START_DATE,
|
||||
WRONG_PARAM_VALUES,
|
||||
WRONG_ISO_TIME_FORMAT,
|
||||
ABOVE_MAX_PARKING_TIME,
|
||||
BELOW_MIN_PARKING_TIME,
|
||||
BELOW_MIN_PARKING_PRICE,
|
||||
OVERPAID
|
||||
};
|
||||
|
||||
bool CALCULATE_LIBRARY_API compute_price_for_parking_ticket(parking_tariff_t *tariff,
|
||||
time_t start_parking_time,
|
||||
time_t end_parking_time,
|
||||
struct price_t *price);
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
State m_status;
|
||||
QString m_desc;
|
||||
|
||||
explicit CalcState() : m_status(State::SUCCESS), m_desc("") {}
|
||||
|
||||
explicit operator bool() const noexcept {
|
||||
return (m_status == State::SUCCESS);
|
||||
}
|
||||
|
||||
explicit operator QString () const noexcept {
|
||||
QString s;
|
||||
switch (m_status) {
|
||||
case State::SUCCESS:
|
||||
s = "SUCCESS";
|
||||
break;
|
||||
case State::ERROR_PARSING_ZONE_NR:
|
||||
s = "ERROR_PARSING_ZONE_NR";
|
||||
break;
|
||||
case State::ERROR_LOADING_TARIFF:
|
||||
s = "ERROR_LOADING_TARIFF";
|
||||
break;
|
||||
case State::ERROR_PARSING_TARIFF:
|
||||
s = "ERROR_PARSING_TARIFF";
|
||||
break;
|
||||
case State::NEGATIVE_PARING_TIME:
|
||||
s = "NEGATIVE_PARKING_TIME";
|
||||
break;
|
||||
case State::ABOVE_MAX_PARKING_TIME:
|
||||
s = "ABOVE_MAX_PARKING_TIME";
|
||||
break;
|
||||
case State::WRONG_PARAM_VALUES:
|
||||
s = "WRONG_PARAM_VALUES";
|
||||
break;
|
||||
case State::BELOW_MIN_PARKING_TIME:
|
||||
s = "BELOW_MIN_PARKING_TIME";
|
||||
break;
|
||||
case State::BELOW_MIN_PARKING_PRICE:
|
||||
s = "BELOW_MIN_PARKING_PRICE";
|
||||
break;
|
||||
case State::OVERPAID:
|
||||
s = "OVERPAID";
|
||||
break;
|
||||
case State::INVALID_START_DATE:
|
||||
s = "INVALID_START_DATE";
|
||||
break;
|
||||
case State::WRONG_ISO_TIME_FORMAT:
|
||||
s = "WRONG_ISO_TIME_FORMAT";
|
||||
}
|
||||
return s + ":" + m_desc;
|
||||
}
|
||||
|
||||
CalcState &set(State s) { m_status = s; return *this; }
|
||||
CalcState &setDesc(QString s) { m_desc = s; return *this; }
|
||||
};
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff,
|
||||
char const *config_file);
|
||||
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff);
|
||||
int CALCULATE_LIBRARY_API get_zone_nr(int zone = -1);
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // deprecated
|
||||
parking_tariff_t *tariff,
|
||||
time_t start_parking_time,
|
||||
time_t end_parking_time,
|
||||
struct price_t *price);
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
QDateTime const &start_parking_time,
|
||||
int netto_parking_time,
|
||||
QDateTime &end_parking_time, // return value
|
||||
struct price_t *price); // return value
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( // deprecated
|
||||
parking_tariff_t *tariff,
|
||||
time_t start_parking_time,
|
||||
double cost,
|
||||
QString &duration);
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
QDateTime const &start_parking_time,
|
||||
double cost,
|
||||
QDateTime &ticketEndTime); // return value
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_duration_for_daily_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
QDateTime const &start_parking_time,
|
||||
QDateTime &ticketEndTime);
|
||||
//#ifdef __cplusplus
|
||||
//} // extern "C"
|
||||
//#endif
|
||||
|
||||
#endif // CALCULATE_PRICE_H
|
||||
|
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include "configuration.h"
|
||||
|
||||
#include <QDateTime>
|
||||
using namespace std;
|
||||
|
||||
class Calculator
|
||||
@@ -23,7 +23,11 @@ public:
|
||||
/// <param name="tariff_cfg">Pointer to configuration</param>
|
||||
/// <param name="vehicle_type">Type of vehicle</param>
|
||||
/// <param name="start_datetime">Date/time of payment to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z) </param>
|
||||
/// <param name="end_datetime">Date/time of park end to be conducted in ISO8601 format (e.g. 2022-12-25T08:00:00Z) </param>
|
||||
/// <param name="durationMin">Duration of parking in minutes</param>
|
||||
/// <returns>Returns cost (data type: double)</returns>
|
||||
double GetCostFromDuration(Configuration* cfg, uint8_t vehicle_type, char const* start_datetime, double durationMin, bool nextDay = false, bool prepaid = false);
|
||||
};
|
||||
double GetCostFromDuration(Configuration* cfg, uint8_t vehicle_type, const QDateTime start_datetime, QDateTime & end_datetime, double durationMin, bool nextDay = false, bool prepaid = false);
|
||||
|
||||
// Daily ticket
|
||||
QDateTime GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over);
|
||||
};
|
||||
|
@@ -55,4 +55,4 @@ private:
|
||||
/// <param name="member_name"></param>
|
||||
/// <returns></returns>
|
||||
MemberType IdentifyJsonMember(const char* member_name);
|
||||
};
|
||||
};
|
||||
|
@@ -2,12 +2,12 @@
|
||||
|
||||
enum DayOfWeek
|
||||
{
|
||||
Saturday = 0x06,
|
||||
Sunday = 0x01,
|
||||
Monday = 0x02,
|
||||
Tuesday = 0x02,
|
||||
Wednesday = 0x03,
|
||||
Thursday = 0x04,
|
||||
Friday = 0x05,
|
||||
UndefinedDay = 0xFF
|
||||
};
|
||||
Monday = 0x01,
|
||||
Tuesday = 0x02,
|
||||
Wednesday = 0x03,
|
||||
Thursday = 0x04,
|
||||
Friday = 0x05,
|
||||
Saturday = 0x06,
|
||||
Sunday = 0x07,
|
||||
UndefinedDay = 0xFF
|
||||
};
|
||||
|
@@ -14,4 +14,5 @@ public:
|
||||
double pop_max_time;
|
||||
double pop_min_price;
|
||||
int pop_carry_over;
|
||||
};
|
||||
int pop_daily_card_price;
|
||||
};
|
||||
|
@@ -68,5 +68,6 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="pra_price"></param>
|
||||
/// <returns></returns>
|
||||
static double CalculatePricePerUnit(double pra_price);
|
||||
static double CalculatePricePerUnit(double pra_price, double durationUnit = -1);
|
||||
|
||||
};
|
||||
|
@@ -1,6 +1,6 @@
|
||||
TEMPLATE = lib
|
||||
TARGET = mobilisis_calc
|
||||
# CONFIG += staticlib
|
||||
#CONFIG += staticlib
|
||||
|
||||
QMAKE_CXXFLAGS += -std=c++17 -g -O0
|
||||
|
||||
|
@@ -10,25 +10,31 @@
|
||||
|
||||
static Calculator calculator;
|
||||
|
||||
int CALCULATE_LIBRARY_API 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)) {
|
||||
|
||||
QTextStream in(&zone);
|
||||
return in.readLine(100).toInt();
|
||||
|
||||
int CALCULATE_LIBRARY_API get_zone_nr(int zone)
|
||||
{
|
||||
if(zone > -1) return zone;
|
||||
else
|
||||
{
|
||||
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)) {
|
||||
QTextStream in(&zone);
|
||||
return in.readLine(100).toInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file) {
|
||||
CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file) {
|
||||
*tariff = new Configuration();
|
||||
|
||||
CalcState calcState;
|
||||
#if __linux__
|
||||
|
||||
int const zone = get_zone_nr();
|
||||
|
||||
// DEBUG
|
||||
@@ -36,7 +42,9 @@ bool CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *co
|
||||
qCritical() << " ... zone = " << zone;
|
||||
|
||||
if (zone <= 0) {
|
||||
return false;
|
||||
delete *tariff;
|
||||
*tariff = nullptr;
|
||||
return calcState.set(CalcState::State::ERROR_PARSING_ZONE_NR);
|
||||
}
|
||||
|
||||
QString confFile(config_file);
|
||||
@@ -48,62 +56,252 @@ bool CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *co
|
||||
memset(buffer, 0x00, sizeof(buffer));
|
||||
snprintf(buffer, sizeof(buffer)-1, "tariff%02d.json", zone);
|
||||
confFile += buffer;
|
||||
#else // windows
|
||||
QString confFile(config_file);
|
||||
#endif
|
||||
|
||||
// DEBUG
|
||||
qCritical() << " ... confFile = " << confFile;
|
||||
|
||||
QFile fname(confFile);
|
||||
if (fname.exists()) {
|
||||
|
||||
if (fname.exists() &&
|
||||
fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
// DEBUG
|
||||
qCritical() << " ... confFile exists";
|
||||
qCritical() << " ... confFile is open";
|
||||
|
||||
if (fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
|
||||
// DEBUG
|
||||
qCritical() << " ... confFile is open";
|
||||
|
||||
QString json = fname.readAll();
|
||||
return (*tariff)->ParseJson(*tariff, json.toStdString().c_str());
|
||||
QString json = fname.readAll();
|
||||
if (! (*tariff)->ParseJson(*tariff, json.toStdString().c_str())) {
|
||||
delete *tariff;
|
||||
*tariff = nullptr;
|
||||
return calcState.set(CalcState::State::ERROR_PARSING_TARIFF);
|
||||
}
|
||||
} else {
|
||||
delete *tariff;
|
||||
*tariff = nullptr;
|
||||
return calcState.set(CalcState::State::ERROR_LOADING_TARIFF);
|
||||
}
|
||||
|
||||
qCritical() << "init_tariff: Parsing tariff config (" << confFile << ") failed!";
|
||||
qCritical() << "init_tariff: Parsing tariff config (" << confFile << ")";
|
||||
|
||||
return false;
|
||||
return calcState;
|
||||
}
|
||||
|
||||
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff) {
|
||||
delete tariff;
|
||||
if (tariff != nullptr) {
|
||||
delete tariff;
|
||||
}
|
||||
}
|
||||
|
||||
bool CALCULATE_LIBRARY_API 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) {
|
||||
|
||||
// this is currently not used
|
||||
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
time_t start_parking_time, // in minutes
|
||||
time_t end_parking_time, // netto time in minutes
|
||||
struct price_t *price) {
|
||||
CalcState calcState;
|
||||
double minMin = tariff->PaymentOption.find(PaymentOption::Option1)->second.pop_min_time;
|
||||
double maxMin = tariff->PaymentOption.find(PaymentOption::Option1)->second.pop_max_time;
|
||||
|
||||
if (minMin < 0 || maxMin < 0 || maxMin < minMin) {
|
||||
calcState.setDesc(QString("minMin=%1, maxMin=%2").arg(minMin).arg(maxMin));
|
||||
return calcState.set(CalcState::State::WRONG_PARAM_VALUES);
|
||||
}
|
||||
|
||||
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) {
|
||||
calcState.setDesc(QString("end=%1, start=%2")
|
||||
.arg(end_parking_time, start_parking_time));
|
||||
return calcState.set(CalcState::State::NEGATIVE_PARING_TIME);
|
||||
}
|
||||
if (duration > maxMin) {
|
||||
calcState.setDesc(QString("duration=%1, maxMin=%2").arg(duration).arg(maxMin));
|
||||
return calcState.set(CalcState::State::ABOVE_MAX_PARKING_TIME);
|
||||
}
|
||||
if (duration < minMin) {
|
||||
calcState.setDesc(QString("duration=%1, minMin=%2").arg(duration).arg(minMin));
|
||||
return calcState.set(CalcState::State::BELOW_MIN_PARKING_TIME);
|
||||
}
|
||||
if (duration == 0) {
|
||||
memset(price, 0x00, sizeof(*price));
|
||||
return true;
|
||||
return calcState.set(CalcState::State::SUCCESS);
|
||||
}
|
||||
qCritical() << "ERROR start_parking_time (" << start_parking_time << ") <"
|
||||
<< "end_parking_time (" << end_parking_time << ")";
|
||||
return false;
|
||||
|
||||
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);
|
||||
QDateTime end(start);
|
||||
if (start.isValid()) {
|
||||
double cost = calculator.GetCostFromDuration(
|
||||
tariff, PaymentOption::Option1,
|
||||
start,
|
||||
end,
|
||||
duration, false, true);
|
||||
double minCost = tariff->PaymentOption.find(PaymentOption::Option1)->second.pop_min_price;
|
||||
if (cost < minCost) {
|
||||
calcState.setDesc(QString("minCost=%1, cost=%2").arg(minCost).arg(cost));
|
||||
return calcState.set(CalcState::State::BELOW_MIN_PARKING_PRICE);
|
||||
}
|
||||
price->units = cost;
|
||||
price->netto = cost;
|
||||
} else {
|
||||
return calcState.set(CalcState::State::INVALID_START_DATE);
|
||||
}
|
||||
|
||||
return calcState.set(CalcState::State::SUCCESS);
|
||||
}
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
QDateTime const &start_parking_time,
|
||||
int netto_parking_time,
|
||||
QDateTime &end_parking_time,
|
||||
struct price_t *price)
|
||||
{
|
||||
CalcState calcState;
|
||||
double minMin = tariff->PaymentOption.find(PaymentOption::Option1)->second.pop_min_time;
|
||||
double maxMin = tariff->PaymentOption.find(PaymentOption::Option1)->second.pop_max_time;
|
||||
|
||||
// DEBUG
|
||||
qCritical() << "compute_price_for_parking_ticket() " << endl
|
||||
<< " start_parking_time: " << start_parking_time << endl
|
||||
<< " netto_parking_time: " << netto_parking_time << endl
|
||||
<< " minMin: " << minMin << endl
|
||||
<< " maxMin: " << maxMin;
|
||||
|
||||
|
||||
if (netto_parking_time < 0) {
|
||||
calcState.setDesc(QString("end=%1, start=%2")
|
||||
.arg(end_parking_time.toString(Qt::ISODate),
|
||||
start_parking_time.toString(Qt::ISODate)));
|
||||
return calcState.set(CalcState::State::NEGATIVE_PARING_TIME);
|
||||
}
|
||||
if (netto_parking_time > maxMin) {
|
||||
calcState.setDesc(QString("duration=%1, maxMin=%2").arg(netto_parking_time).arg(maxMin));
|
||||
return calcState.set(CalcState::State::ABOVE_MAX_PARKING_TIME);
|
||||
}
|
||||
if (netto_parking_time < minMin) {
|
||||
calcState.setDesc(QString("duration=%1, minMin=%2").arg(netto_parking_time).arg(minMin));
|
||||
return calcState.set(CalcState::State::BELOW_MIN_PARKING_TIME);
|
||||
}
|
||||
if (netto_parking_time == 0) {
|
||||
memset(price, 0x00, sizeof(*price));
|
||||
return calcState.set(CalcState::State::SUCCESS);
|
||||
}
|
||||
|
||||
if (start_parking_time.isValid()) {
|
||||
double cost = calculator.GetCostFromDuration(
|
||||
tariff, PaymentOption::Option1,
|
||||
start_parking_time, // starting time
|
||||
end_parking_time, // return value: end time
|
||||
netto_parking_time, // minutes, netto
|
||||
false, true);
|
||||
double minCost = tariff->PaymentOption.find(PaymentOption::Option1)->second.pop_min_price;
|
||||
if (cost < minCost) {
|
||||
calcState.setDesc(QString("minCost=%1, cost=%2").arg(minCost, cost));
|
||||
return calcState.set(CalcState::State::BELOW_MIN_PARKING_PRICE);
|
||||
}
|
||||
|
||||
// DEBUG
|
||||
qCritical() << " -> calculated cost (price->netto) = " << cost;
|
||||
|
||||
price->units = cost;
|
||||
price->netto = cost;
|
||||
} else {
|
||||
return calcState.set(CalcState::State::INVALID_START_DATE);
|
||||
}
|
||||
|
||||
return calcState.set(CalcState::State::SUCCESS);
|
||||
}
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
time_t start_parking_time,
|
||||
double price,
|
||||
QString &duration) {
|
||||
CalcState calcState;
|
||||
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);
|
||||
|
||||
// DEBUG
|
||||
qCritical() << "compute_duration_for_parking_ticket(): ";
|
||||
qCritical() << " start (cs): " << cs;
|
||||
qCritical() << " price: " << price;
|
||||
|
||||
duration = calculator.GetDurationFromCost(tariff, PaymentOption::Option1,
|
||||
cs.toLocal8Bit().constData(),
|
||||
price, false, true).c_str();
|
||||
QDateTime d = QDateTime::fromString(duration, Qt::ISODate);
|
||||
if (!d.isValid()) {
|
||||
calcState.setDesc(QString("ticketEndTime=%1").arg(duration));
|
||||
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
|
||||
}
|
||||
} else {
|
||||
return calcState.set(CalcState::State::INVALID_START_DATE);
|
||||
}
|
||||
|
||||
return calcState.set(CalcState::State::SUCCESS);
|
||||
}
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
QDateTime const &start_parking_time,
|
||||
double price,
|
||||
QDateTime &ticketEndTime)
|
||||
{
|
||||
CalcState calcState;
|
||||
if (start_parking_time.isValid()) {
|
||||
QString cs = start_parking_time.toString(Qt::ISODate);
|
||||
QString endTime = calculator.GetDurationFromCost(
|
||||
tariff, PaymentOption::Option1,
|
||||
cs.toLocal8Bit().constData(),
|
||||
price, false, true).c_str();
|
||||
ticketEndTime = QDateTime::fromString(endTime,Qt::ISODate);
|
||||
|
||||
// DEBUG
|
||||
qCritical() << "compute_duration_for_parking_ticket(): ";
|
||||
qCritical() << " endTime: " << endTime;
|
||||
qCritical() << " ticketEndTime: " << ticketEndTime;
|
||||
|
||||
if (!ticketEndTime.isValid()) {
|
||||
calcState.setDesc(QString("ticketEndTime=%1").arg(endTime));
|
||||
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
|
||||
}
|
||||
} else {
|
||||
return calcState.set(CalcState::State::INVALID_START_DATE);
|
||||
}
|
||||
|
||||
return calcState.set(CalcState::State::SUCCESS);
|
||||
}
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_duration_for_daily_ticket(parking_tariff_t *tariff, QDateTime const &start_parking_time, QDateTime &ticketEndTime)
|
||||
{
|
||||
CalcState calcState;
|
||||
if (start_parking_time.isValid()) {
|
||||
|
||||
ticketEndTime = calculator.GetDailyTicketDuration(tariff,
|
||||
start_parking_time,
|
||||
PaymentOption::Option1,
|
||||
false); // carry over
|
||||
|
||||
// DEBUG
|
||||
qCritical() << "compute_duration_for_daily_ticket(): ";
|
||||
qCritical() << " ticketEndTime: " << ticketEndTime;
|
||||
|
||||
if (!ticketEndTime.isValid()) {
|
||||
calcState.setDesc(QString("ticketEndTime=%1").arg(ticketEndTime.toString(Qt::ISODate)));
|
||||
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
|
||||
}
|
||||
|
||||
} else {
|
||||
return calcState.set(CalcState::State::INVALID_START_DATE);
|
||||
}
|
||||
|
||||
return calcState.set(CalcState::State::SUCCESS);
|
||||
}
|
||||
|
||||
|
@@ -4,510 +4,540 @@
|
||||
#include "tariff_log.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <QDateTime>
|
||||
#include <qdebug.h>
|
||||
|
||||
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)
|
||||
#ifdef _WIN32
|
||||
inline struct tm* localtime_r(const time_t *clock, struct tm* result){
|
||||
if(!clock || !result) return NULL;
|
||||
memcpy(result,localtime(clock),sizeof(*result));
|
||||
return result;
|
||||
}
|
||||
#endif
|
||||
|
||||
QDateTime Calculator::GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over)
|
||||
{
|
||||
// Get current date time from input
|
||||
struct tm current_datetime = Utilities::DateTimeToStructTm(start_datetime);
|
||||
time_t current_datetime_t;
|
||||
if(!start_datetime.isValid()) {
|
||||
return QDateTime();
|
||||
}
|
||||
|
||||
// Get day of week
|
||||
DayOfWeek weekdayId = DayOfWeek::UndefinedDay;
|
||||
weekdayId = Utilities::GetDayOfWeek(¤t_datetime);
|
||||
double day_price = 0.0f;
|
||||
int current_special_day_id = -1;
|
||||
bool is_special_day = Utilities::CheckSpecialDay(cfg, start_datetime.toString(Qt::ISODate).toStdString().c_str(), ¤t_special_day_id, &day_price);
|
||||
|
||||
//std::stringstream ss;
|
||||
QDateTime inputDateTime = start_datetime;
|
||||
QTime worktime_from;
|
||||
QTime worktime_to;
|
||||
|
||||
// ss << "*** Input date is: " << start_datetime << " [weekday id = " << weekdayId << "]" << endl;
|
||||
LOG_DEBUG("*** Input date is: ", start_datetime, " [weekday id = ", weekdayId, "]");
|
||||
int daily_card_price = cfg->PaymentOption.find(payment_option)->second.pop_daily_card_price;
|
||||
if(daily_card_price <= 0) {
|
||||
LOG_ERROR("Calculator::GetDailyTicketDuration(): Daily ticket price zero or less");
|
||||
return QDateTime();
|
||||
}
|
||||
|
||||
double minMin = 0;
|
||||
minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
|
||||
if (minMin < 0) minMin = 0;
|
||||
if(is_special_day)
|
||||
{
|
||||
worktime_from = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from.c_str(), Qt::ISODate);
|
||||
worktime_to = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to.c_str(),Qt::ISODate);
|
||||
|
||||
double maxMin = 0;
|
||||
maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
|
||||
if (maxMin <= 0) maxMin = 60;
|
||||
if(inputDateTime.time() < worktime_from) inputDateTime.setTime(worktime_from);
|
||||
if(carry_over) inputDateTime.setTime(worktime_from);
|
||||
|
||||
if (minMin >= maxMin)
|
||||
{
|
||||
LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
|
||||
return "PARKING NOT ALLOWED";
|
||||
}
|
||||
if(inputDateTime.time() >= worktime_to)
|
||||
{
|
||||
// Go to next day if outside worktime
|
||||
inputDateTime = inputDateTime.addSecs(86400);
|
||||
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
|
||||
}
|
||||
|
||||
if (maxMin <= minMin)
|
||||
{
|
||||
LOG_ERROR("Error: max_min cannot be lower or equal than min_min");
|
||||
return "PARKING NOT ALLOWED";
|
||||
}
|
||||
if(day_price <=0)
|
||||
{
|
||||
// Go to next day if special day price is 0
|
||||
inputDateTime = inputDateTime.addSecs(86400);
|
||||
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
|
||||
}
|
||||
|
||||
uint8_t p_method = PaymentMethod::Undefined;
|
||||
p_method = payment_option;
|
||||
LOG_DEBUG("Payment method id: ", (unsigned)p_method);
|
||||
int diff = abs(inputDateTime.time().secsTo(worktime_to));
|
||||
inputDateTime = inputDateTime.addSecs(diff);
|
||||
|
||||
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);
|
||||
//qDebug() << "Ticket is valid until: " << inputDateTime.toString(Qt::ISODate) << "price = " << daily_card_price << ", duration = " << diff / 60;
|
||||
return inputDateTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get day of week
|
||||
int weekdayId = 0;
|
||||
weekdayId = Utilities::ZellersAlgorithm(inputDateTime.date().day(),inputDateTime.date().month(),inputDateTime.date().year());
|
||||
|
||||
double money_left = price;
|
||||
LOG_DEBUG("Total money:", money_left);
|
||||
// If no working day found, skip it (recursively call method again)
|
||||
size_t found = 0;
|
||||
found = cfg->WeekDaysWorktime.count(weekdayId);
|
||||
|
||||
double price_per_unit = 0.0f;
|
||||
// When no workday found, go to next available day
|
||||
if(found <=0)
|
||||
{
|
||||
inputDateTime = inputDateTime.addSecs(86400);
|
||||
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
|
||||
}
|
||||
else
|
||||
{
|
||||
worktime_from = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from.c_str(),Qt::ISODate);
|
||||
worktime_to = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to.c_str(),Qt::ISODate);
|
||||
if(inputDateTime.time() < worktime_from)
|
||||
inputDateTime.setTime(worktime_from);
|
||||
|
||||
string worktime_from = "";
|
||||
string worktime_to = "";
|
||||
if(carry_over)
|
||||
inputDateTime.setTime(worktime_from);
|
||||
|
||||
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(inputDateTime.time() >= worktime_to)
|
||||
{
|
||||
// Go to next day if outside worktime
|
||||
inputDateTime = inputDateTime.addSecs(86400);
|
||||
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
|
||||
}
|
||||
|
||||
// If no working day found, skip it (recursively call method again)
|
||||
size_t found = 0;
|
||||
found = cfg->WeekDaysWorktime.count(weekdayId);
|
||||
int diff = abs(inputDateTime.time().secsTo(worktime_to));
|
||||
inputDateTime = inputDateTime.addSecs(diff);
|
||||
|
||||
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);
|
||||
//qDebug() << "Ticket is valid until: " << inputDateTime.toString(Qt::ISODate) << "price = " << daily_card_price << ", duration = " << diff / 60;
|
||||
return inputDateTime;
|
||||
}
|
||||
}
|
||||
|
||||
char buffer_datetime[80];
|
||||
strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
|
||||
return QDateTime();
|
||||
}
|
||||
/// <inheritdoc/>
|
||||
std::string Calculator::GetDurationFromCost(Configuration* cfg,
|
||||
uint8_t payment_option,
|
||||
char const* start_datetime, // given in local time
|
||||
double price,
|
||||
bool nextDay,
|
||||
bool prepaid)
|
||||
{
|
||||
// Get input date
|
||||
QDateTime inputDate = QDateTime::fromString(start_datetime,Qt::ISODate);
|
||||
|
||||
// Make new datetime string and call function again recursively
|
||||
start_datetime = buffer_datetime;
|
||||
return GetDurationFromCost(cfg, payment_option, start_datetime, price, true);
|
||||
}
|
||||
// Get day of week
|
||||
int weekdayId = 0;
|
||||
weekdayId = Utilities::ZellersAlgorithm(inputDate.date().day(),inputDate.date().month(),inputDate.date().year());
|
||||
|
||||
worktime_from = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from;
|
||||
worktime_to = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to;
|
||||
}
|
||||
//Get min and max time defined in JSON
|
||||
double minMin = 0;
|
||||
minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
|
||||
|
||||
if (price_per_unit < 0) price_per_unit = 1.0f;
|
||||
LOG_DEBUG("Calculated price per minute: ", price_per_unit);
|
||||
double maxMin = 0;
|
||||
maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
|
||||
|
||||
LOG_DEBUG("Worktime from: ", worktime_from);
|
||||
LOG_DEBUG("Worktime to: ", worktime_to);
|
||||
double min_price = 0;
|
||||
min_price = cfg->PaymentOption.find(payment_option)->second.pop_min_price;
|
||||
|
||||
struct tm from_tm;
|
||||
struct tm to_tm;
|
||||
if(price < min_price)
|
||||
{
|
||||
return "PARKING NOT ALLOWED";
|
||||
}
|
||||
|
||||
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;
|
||||
if (minMin < 0) minMin = 0;
|
||||
if (maxMin < 0) maxMin = 0;
|
||||
if (minMin >= maxMin)
|
||||
{
|
||||
LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
|
||||
return "PARKING NOT ALLOWED";
|
||||
}
|
||||
|
||||
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 (maxMin <= minMin)
|
||||
{
|
||||
LOG_ERROR("Error: max_min cannot be lower or equal than min_min");
|
||||
return "PARKING NOT ALLOWED";
|
||||
}
|
||||
|
||||
|
||||
// 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");
|
||||
// Get payment method
|
||||
uint8_t p_method = PaymentMethod::Undefined;
|
||||
p_method = payment_option;
|
||||
LOG_DEBUG("Payment method id: ", (unsigned)p_method);
|
||||
|
||||
current_datetime_t = mktime(¤t_datetime);
|
||||
current_datetime_t -= 60;
|
||||
current_datetime = *localtime(¤t_datetime_t);
|
||||
total_duration_min = maxMin;
|
||||
break;
|
||||
}
|
||||
// Check special day
|
||||
double day_price = 0.0f;
|
||||
int current_special_day_id = -1;
|
||||
bool is_special_day = Utilities::CheckSpecialDay(cfg, inputDate.toString(Qt::ISODate).toStdString().c_str(), ¤t_special_day_id, &day_price);
|
||||
LOG_DEBUG("Special day: ", is_special_day);
|
||||
|
||||
// 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;
|
||||
double money_left = price;
|
||||
double price_per_unit = 0.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;
|
||||
QTime worktime_from;
|
||||
QTime worktime_to;
|
||||
|
||||
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);
|
||||
if(is_special_day)
|
||||
{
|
||||
// Set special day price
|
||||
price_per_unit = Utilities::CalculatePricePerUnit(day_price);
|
||||
worktime_from = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from.c_str());
|
||||
worktime_to = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set new price for the normal day
|
||||
int pop_id = cfg->PaymentOption.find(payment_option)->second.pop_id;
|
||||
day_price = cfg->PaymentRate.find(pop_id)->second.pra_price;
|
||||
|
||||
char buffer_datetime[80];
|
||||
strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
|
||||
int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id;
|
||||
double durationUnit = cfg->Duration.find(durationId)->second.pun_duration;
|
||||
price_per_unit = Utilities::CalculatePricePerUnit(day_price,durationUnit);
|
||||
|
||||
// Make new datetime string and call function again recursively
|
||||
start_datetime = buffer_datetime;
|
||||
overtime = true;
|
||||
return GetDurationFromCost(cfg, payment_option, start_datetime, price);
|
||||
}
|
||||
}
|
||||
}
|
||||
// If no working day found, skip it (recursively call method again)
|
||||
size_t found = 0;
|
||||
found = cfg->WeekDaysWorktime.count(weekdayId);
|
||||
|
||||
time_t valid_until_datetime_t = current_datetime_t;
|
||||
// When no workday found, go to next available day
|
||||
if(found <=0)
|
||||
{
|
||||
LOG_DEBUG("- No workday found, trying to find next available day");
|
||||
inputDate = inputDate.addDays(1);
|
||||
return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left,true,prepaid);
|
||||
}
|
||||
worktime_from = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from.c_str());
|
||||
worktime_to = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to.c_str());
|
||||
}
|
||||
|
||||
if ((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";
|
||||
if (price_per_unit < 0) price_per_unit = 1.0f;
|
||||
|
||||
valid_until_datetime_t = from_datetime_t;
|
||||
total_duration_min = 0;
|
||||
}
|
||||
// if((price/price_per_unit) < minMin) return "PARKING NOT ALLOWED";
|
||||
LOG_DEBUG("Calculated price per minute: ", price_per_unit);
|
||||
|
||||
double ret_val = 0;
|
||||
double calc_price = (int)total_duration_min - (int)price / price_per_unit;
|
||||
// If overtime flag is set
|
||||
if (overtime || nextDay)
|
||||
{
|
||||
inputDate.setTime(worktime_from);
|
||||
overtime = false;
|
||||
}
|
||||
|
||||
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;
|
||||
// Check prepaid
|
||||
if (!prepaid)
|
||||
{
|
||||
if ((inputDate.time() < worktime_from) || (inputDate.time() > worktime_to))
|
||||
{
|
||||
LOG_DEBUG("[STOP] * Ticket is not valid * ");
|
||||
return "PARKING NOT ALLOWED";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("* PREPAID MODE ACTIVE *");
|
||||
if (inputDate.time() < worktime_from)
|
||||
{
|
||||
inputDate.setTime(worktime_from);
|
||||
}
|
||||
else if(inputDate.time() > worktime_to)
|
||||
{
|
||||
LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day");
|
||||
inputDate = inputDate.addDays(1);
|
||||
return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left, true);
|
||||
}
|
||||
}
|
||||
|
||||
cout << "Total minutes: " << (int)ret_val << endl;
|
||||
if (ret_val <= 0) return "PARKING NOT ALLOWED";
|
||||
while(true)
|
||||
{
|
||||
if((int)money_left <= 0) break;
|
||||
|
||||
struct tm valid_until_datetime = *localtime(&valid_until_datetime_t);
|
||||
LOG_DEBUG("Ticket is valid until ", asctime(&valid_until_datetime));
|
||||
// Check year period
|
||||
bool isYearPeriodActive = false;
|
||||
|
||||
total_duration_min = 0.0f;
|
||||
return asctime(&valid_until_datetime);
|
||||
//// Parse input date
|
||||
int dayCurrent = inputDate.date().day();
|
||||
int monthCurrent = inputDate.date().month();
|
||||
|
||||
// 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) {
|
||||
isYearPeriodActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isYearPeriodActive)
|
||||
{
|
||||
LOG_DEBUG("Year period is not valid");
|
||||
return "PARKING NOT ALLOWED";
|
||||
}
|
||||
|
||||
if(total_duration_min > maxMin)
|
||||
{
|
||||
total_duration_min = maxMin;
|
||||
break;
|
||||
}
|
||||
|
||||
// If reached end of worktime go to next day
|
||||
if(inputDate.time() >= worktime_to)
|
||||
{
|
||||
int carry_over_status = 0;
|
||||
carry_over_status = cfg->PaymentOption.find(payment_option)->second.pop_carry_over;
|
||||
if (carry_over_status < 1) break;
|
||||
|
||||
inputDate = inputDate.addDays(1);
|
||||
overtime = true;
|
||||
return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left ,true, prepaid);
|
||||
}
|
||||
|
||||
if(money_left > 1)
|
||||
inputDate = inputDate.addSecs(60);
|
||||
|
||||
if(price_per_unit > 0) total_duration_min +=1;
|
||||
money_left -= price_per_unit;
|
||||
|
||||
//qDebug() <<"Timestamp:" << inputDate << ", total duration min: " << total_duration_min << ", money left = " << money_left;
|
||||
}
|
||||
|
||||
// if ((total_duration_min < minMin) || (price / price_per_unit) < minMin)
|
||||
// {
|
||||
// LOG_DEBUG("Total duration is lower than min_min");
|
||||
// inputDate.time() = worktime_from;
|
||||
// total_duration_min = 0;
|
||||
// }
|
||||
|
||||
double ret_val = 0;
|
||||
// double calc_price = (int)total_duration_min - (int)price / price_per_unit;
|
||||
|
||||
//if (calc_price > 0 && total_duration_min > 0)
|
||||
//{
|
||||
// inputDate = inputDate.addSecs(-(int)ceil(calc_price) * 60);
|
||||
//}
|
||||
|
||||
if(price >= min_price && total_duration_min >= minMin)
|
||||
qDebug() << "GetDurationFromCost(): Valid until: " << inputDate.toString(Qt::ISODate);
|
||||
else
|
||||
{
|
||||
qDebug() << "Parking not allowed";
|
||||
total_duration_min = 0;
|
||||
}
|
||||
|
||||
ret_val = total_duration_min;
|
||||
if(ret_val < 0) ret_val = 0;
|
||||
qDebug() << "Duration: " << ret_val;
|
||||
if (ret_val <= 0) return "PARKING NOT ALLOWED";
|
||||
|
||||
total_duration_min = 0;
|
||||
return inputDate.toString(Qt::ISODate).toStdString();
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
|
||||
/// <inheritdoc/>
|
||||
double Calculator::GetCostFromDuration(Configuration* cfg, uint8_t payment_option, const char* start_datetime, double durationMin, bool nextDay, bool prepaid)
|
||||
double Calculator::GetCostFromDuration(Configuration* cfg, uint8_t payment_option, const QDateTime start_datetime, QDateTime & end_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 input date
|
||||
QDateTime inputDate = start_datetime;
|
||||
|
||||
// Get day of week
|
||||
DayOfWeek weekdayId = DayOfWeek::UndefinedDay;
|
||||
weekdayId = Utilities::GetDayOfWeek(¤t_datetime);
|
||||
LOG_DEBUG("*** Input date is: ", start_datetime, " [weekday id = ", weekdayId, "]");
|
||||
// Get day of week
|
||||
int weekdayId = 0;
|
||||
weekdayId = Utilities::ZellersAlgorithm(inputDate.date().day(),inputDate.date().month(),inputDate.date().year());
|
||||
|
||||
double minMin = 0;
|
||||
minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
|
||||
if (minMin < 0) minMin = 0;
|
||||
//Get min and max time defined in JSON
|
||||
double minMin = 0;
|
||||
minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
|
||||
|
||||
double maxMin = 0;
|
||||
maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
|
||||
if (maxMin <= 0) maxMin = 60;
|
||||
double maxMin = 0;
|
||||
maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
|
||||
|
||||
if (minMin >= maxMin)
|
||||
{
|
||||
LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
|
||||
return 0.0f;
|
||||
}
|
||||
if (minMin < 0) minMin = 0;
|
||||
if (maxMin < 0) maxMin = 0;
|
||||
if (minMin >= maxMin)
|
||||
{
|
||||
LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
|
||||
return 0.0f;
|
||||
}
|
||||
if (maxMin <= minMin)
|
||||
{
|
||||
LOG_ERROR("Error: max_min cannot be lower or equal than min_min");
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
if (maxMin <= minMin)
|
||||
{
|
||||
LOG_ERROR("Error: max_min cannot be lower or equal than min_min");
|
||||
return 0.0f;
|
||||
}
|
||||
// Check overtime
|
||||
if (!overtime)
|
||||
{
|
||||
if (durationMin > maxMin)
|
||||
{
|
||||
LOG_WARNING("Total duration is greater or equal to max_min");
|
||||
return maxMin;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (durationMin < minMin)
|
||||
{
|
||||
LOG_WARNING("Total duration is lower or equal to min_min");
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
// Get payment method
|
||||
uint8_t p_method = PaymentMethod::Undefined;
|
||||
p_method = payment_option;
|
||||
LOG_DEBUG("Payment method id: ", (unsigned)p_method);
|
||||
|
||||
uint8_t p_method = PaymentMethod::Undefined;
|
||||
p_method = payment_option;
|
||||
LOG_DEBUG("Payment method id: ", (unsigned)p_method);
|
||||
// Check special day
|
||||
double day_price = 0.0f;
|
||||
int current_special_day_id = -1;
|
||||
bool is_special_day = Utilities::CheckSpecialDay(cfg, inputDate.toString(Qt::ISODate).toStdString().c_str(), ¤t_special_day_id, &day_price);
|
||||
LOG_DEBUG("Special day: ", is_special_day);
|
||||
|
||||
double 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);
|
||||
|
||||
total_duration_min = durationMin;
|
||||
LOG_DEBUG("Total min:", total_duration_min);
|
||||
double price_per_unit = 0.0f;
|
||||
QTime worktime_from;
|
||||
QTime worktime_to;
|
||||
|
||||
double price_per_unit = 0.0f;
|
||||
if(is_special_day)
|
||||
{
|
||||
// Set special day price
|
||||
price_per_unit = Utilities::CalculatePricePerUnit(day_price);
|
||||
worktime_from = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from.c_str());
|
||||
worktime_to = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set new price for the normal day
|
||||
|
||||
string worktime_from = "";
|
||||
string worktime_to = "";
|
||||
int pop_id = cfg->PaymentOption.find(payment_option)->second.pop_id;
|
||||
day_price = cfg->PaymentRate.find(pop_id)->second.pra_price;
|
||||
|
||||
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);
|
||||
int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id;
|
||||
double durationUnit = cfg->Duration.find(durationId)->second.pun_duration;
|
||||
price_per_unit = Utilities::CalculatePricePerUnit(day_price,durationUnit);
|
||||
|
||||
// If no working day found, skip it (recursively call method again)
|
||||
size_t found = 0;
|
||||
found = cfg->WeekDaysWorktime.count(weekdayId);
|
||||
// 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);
|
||||
// When no workday found, go to next available day
|
||||
if(found <=0)
|
||||
{
|
||||
LOG_DEBUG("- No workday found, trying to find next available day");
|
||||
inputDate = inputDate.addDays(1);
|
||||
return floor(GetCostFromDuration(cfg, payment_option, inputDate, end_datetime, durationMin, true, prepaid));
|
||||
}
|
||||
worktime_from = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from.c_str());
|
||||
worktime_to = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to.c_str());
|
||||
}
|
||||
|
||||
char buffer_datetime[80];
|
||||
strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
|
||||
if (price_per_unit < 0) price_per_unit = 1.0f;
|
||||
LOG_DEBUG("Calculated price per minute: ", price_per_unit);
|
||||
|
||||
//Make new datetime string and call function again recursively
|
||||
start_datetime = buffer_datetime;
|
||||
return floor(GetCostFromDuration(cfg, payment_option, start_datetime, durationMin, true, prepaid));
|
||||
}
|
||||
if (price_per_unit == 0)
|
||||
{
|
||||
inputDate = inputDate.addDays(1);
|
||||
inputDate.setTime(worktime_from);
|
||||
return GetCostFromDuration(cfg, payment_option, inputDate, end_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 overtime flag is set
|
||||
if (overtime || nextDay)
|
||||
{
|
||||
inputDate.setTime(worktime_from);
|
||||
overtime = false;
|
||||
}
|
||||
|
||||
if (price_per_unit < 0) price_per_unit = 1.0f;
|
||||
LOG_DEBUG("Calculated price per minute: ", price_per_unit);
|
||||
// Check prepaid
|
||||
if (!prepaid)
|
||||
{
|
||||
if ((inputDate.time() < worktime_from) || (inputDate.time() > worktime_to))
|
||||
{
|
||||
LOG_DEBUG("[STOP] * Ticket is not valid * ");
|
||||
return 0.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("* PREPAID MODE ACTIVE *");
|
||||
if (inputDate.time() < worktime_from)
|
||||
{
|
||||
inputDate.setTime(worktime_from);
|
||||
}
|
||||
else if(inputDate.time() > worktime_to)
|
||||
{
|
||||
LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day");
|
||||
inputDate = inputDate.addDays(1);
|
||||
return GetCostFromDuration(cfg, payment_option, inputDate, end_datetime, durationMin, true, prepaid);
|
||||
}
|
||||
}
|
||||
|
||||
LOG_DEBUG("Worktime from: ", worktime_from);
|
||||
LOG_DEBUG("Worktime to: ", worktime_to);
|
||||
while(true)
|
||||
{
|
||||
if(total_duration_min <= 0) break;
|
||||
|
||||
struct tm from_tm;
|
||||
struct tm to_tm;
|
||||
// Check year period
|
||||
bool isYearPeriodActive = false;
|
||||
|
||||
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;
|
||||
//// Parse input date
|
||||
int dayCurrent = inputDate.date().day();
|
||||
int monthCurrent = inputDate.date().month();
|
||||
|
||||
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;
|
||||
// Current date time
|
||||
int cdt = (monthCurrent * 100) + dayCurrent;
|
||||
|
||||
// Convert tm structures to time_t
|
||||
current_datetime_t = mktime(¤t_datetime);
|
||||
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;
|
||||
|
||||
time_t from_datetime_t = mktime(&from_tm);
|
||||
time_t to_datetime_t = mktime(&to_tm);
|
||||
int mStart = year_period_itr->second.pye_start_month;
|
||||
int mEnd = year_period_itr->second.pye_end_month;
|
||||
|
||||
// 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;
|
||||
}
|
||||
int start = (mStart * 100) + dStart;
|
||||
int end = (mEnd * 100) + dEnd;
|
||||
|
||||
// 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 (cdt >= start && cdt <= end) {
|
||||
isYearPeriodActive = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isYearPeriodActive)
|
||||
{
|
||||
LOG_DEBUG("Year period is not valid");
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
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);
|
||||
int carry_over_status = 0;
|
||||
carry_over_status = cfg->PaymentOption.find(payment_option)->second.pop_carry_over;
|
||||
|
||||
char buffer_datetime[80];
|
||||
strftime(buffer_datetime, 80, "%Y-%m-%dT%H:%M:%S", ¤t_datetime);
|
||||
// Go to next day if minutes not spent
|
||||
if(inputDate.time() >= worktime_to)
|
||||
{
|
||||
if (carry_over_status < 1) break;
|
||||
|
||||
//Make new datetime string and call function again recursively
|
||||
start_datetime = buffer_datetime;
|
||||
return floor(GetCostFromDuration(cfg, payment_option, start_datetime, durationMin, true, prepaid));
|
||||
}
|
||||
}
|
||||
LOG_DEBUG("Reached end of worktime, searching for the next working day");
|
||||
inputDate = inputDate.addDays(1);
|
||||
overtime = true;
|
||||
return GetCostFromDuration(cfg, payment_option, inputDate, end_datetime, total_duration_min);
|
||||
}
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (!Utilities::IsYearPeriodActive(cfg, ¤t_datetime))
|
||||
{
|
||||
LOG_DEBUG("Year period is not valid");
|
||||
return 0.0f;
|
||||
}
|
||||
// Increment input date minutes for each monetary unit
|
||||
inputDate = inputDate.addSecs(60);
|
||||
total_duration_min -=1;
|
||||
total_cost += price_per_unit;
|
||||
|
||||
// Decrement by 1 minute
|
||||
current_datetime_t = mktime(¤t_datetime);
|
||||
current_datetime_t += 60;
|
||||
current_datetime = *localtime(¤t_datetime_t);
|
||||
}
|
||||
qDebug() << "GetCostFromDuration(): Valid until:" << inputDate.toString(Qt::ISODate).toStdString().c_str();
|
||||
|
||||
total_duration_min -= 1.0f;
|
||||
total_cost += price_per_unit;
|
||||
end_datetime = inputDate;
|
||||
|
||||
// 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);
|
||||
double ret_val = total_cost;
|
||||
total_cost = 0.0f;
|
||||
return ceil(ret_val);
|
||||
}
|
||||
|
@@ -154,6 +154,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
||||
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();
|
||||
else if (strcmp(inner_obj_name, "pop_daily_card_price") == 0) PaymentOption.pop_daily_card_price = k->value.GetInt();
|
||||
break;
|
||||
case MemberType::DurationType:
|
||||
if (strcmp(inner_obj_name, "pun_id") == 0) Duration.pun_id = k->value.GetInt();
|
||||
@@ -209,7 +210,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
||||
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));
|
||||
cfg->PaymentRate.insert(pair<int, ATBPaymentRate>(PaymentRate.pra_payment_option_id, PaymentRate));
|
||||
break;
|
||||
case MemberType::PaymentOptionType:
|
||||
cfg->PaymentOption.insert(pair<int, ATBPaymentOption>(PaymentOption.pop_payment_method_id, PaymentOption));
|
||||
|
@@ -8,12 +8,15 @@ static int protection_counter = 0;
|
||||
/// </summary>
|
||||
/// <param name="pra_price"></param>
|
||||
/// <returns></returns>
|
||||
double Utilities::CalculatePricePerUnit(double pra_price)
|
||||
double Utilities::CalculatePricePerUnit(double pra_price, double durationUnit)
|
||||
{
|
||||
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
|
||||
double unit = durationUnit;
|
||||
|
||||
if(unit < 0 || unit > 65535 ) unit = 60.0f;
|
||||
price_per_unit /= unit; // Divided by 60 because price per unit is set per hour and we are using minutes
|
||||
//printf("Price per unit (min) is: %lf\n", price_per_unit);
|
||||
return price_per_unit;
|
||||
}
|
||||
@@ -33,7 +36,7 @@ time_t Utilities::GetCurrentLocalTime()
|
||||
memset(&tm_curr_time, '\0', sizeof(struct tm));
|
||||
|
||||
tm_curr_time = *localtime(&curr_time);
|
||||
curr_time = mktime(&tm_curr_time) - timezone;
|
||||
curr_time = mktime(&tm_curr_time); //- timezone;
|
||||
return curr_time;
|
||||
}
|
||||
catch (...)
|
||||
|
197
main/main.cpp
197
main/main.cpp
@@ -1,10 +1,9 @@
|
||||
#include <calculate_price.h>
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
#include <time.h>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <calculate_price.h>
|
||||
|
||||
|
||||
extern "C" char* strptime(const char* s,
|
||||
const char* f,
|
||||
@@ -27,87 +26,135 @@ extern "C" char* strptime(const char* s,
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "calculator_functions.h"
|
||||
#include <calculate_price.h>
|
||||
|
||||
|
||||
int main() {
|
||||
|
||||
std::ifstream input(QDir::homePath().append("/tariff01.json").toStdString());
|
||||
std::stringstream sstr;
|
||||
while(input >> sstr.rdbuf());
|
||||
std::string json(sstr.str());
|
||||
|
||||
Calculator calculator;
|
||||
Configuration cfg;
|
||||
|
||||
bool isParsed = cfg.ParseJson(&cfg, json.c_str());
|
||||
cout << endl;
|
||||
|
||||
char const *startDate = "";
|
||||
|
||||
if (isParsed)
|
||||
{
|
||||
startDate = "2023-05-10T13:52:18.665Z";
|
||||
std::string duration = calculator.GetDurationFromCost(&cfg, 3, (char *)startDate, 33, false, true);
|
||||
cout << "---> startDate " << startDate << " _price_ = " << 33
|
||||
<< " Total duration is: " << duration << endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
parking_tariff_t *tariff = 0;
|
||||
if (init_tariff(&tariff, "/etc/psa_tariff/")) {
|
||||
if (init_tariff(&tariff, "/etc/psa_tariff/")) {
|
||||
struct price_t price;
|
||||
memset(&price, 0x00, sizeof(price));
|
||||
QDateTime start = QDateTime::currentDateTime();
|
||||
QDateTime start = QDateTime::fromString("2023-05-11T07:50:00",Qt::ISODate); //QDateTime::currentDateTime();
|
||||
time_t start_parking_time = start.toSecsSinceEpoch() / 60;
|
||||
time_t end_parking_time = start_parking_time + 60;
|
||||
time_t end_parking_time = start_parking_time + 615;
|
||||
|
||||
if (compute_price_for_parking_ticket(tariff,
|
||||
start_parking_time,
|
||||
end_parking_time,
|
||||
&price)) {
|
||||
qDebug() << "price=" << price.netto;
|
||||
&price))
|
||||
{
|
||||
qDebug() << "GetCostFromDuration() => price=" << price.netto;
|
||||
}
|
||||
|
||||
// tests
|
||||
struct tm now;
|
||||
memset(&now, 0, sizeof(now));
|
||||
|
||||
// 3.Jan 2023 -> Tuesday
|
||||
strptime("2023-01-03T14:00:00", "%Y-%m-%dT%H:%M:%S", &now);
|
||||
for (int i = 0; i < 600; ++i) {
|
||||
start_parking_time = mktime(&now);
|
||||
end_parking_time = start_parking_time + 240; // duration == 240
|
||||
|
||||
if (compute_price_for_parking_ticket(tariff,
|
||||
start_parking_time,
|
||||
end_parking_time,
|
||||
&price)) {
|
||||
int const zone = get_zone_nr();
|
||||
switch (zone) {
|
||||
case 1:
|
||||
assert(price.netto == 879); // expected value: 880
|
||||
break;
|
||||
case 2:
|
||||
/* fall through */
|
||||
case 3:
|
||||
assert(price.netto == 1920);
|
||||
break;
|
||||
}
|
||||
}
|
||||
time_t t = start_parking_time + 60;
|
||||
now = *localtime(&t);
|
||||
QString duration;
|
||||
if(compute_duration_for_parking_ticket(tariff,start_parking_time,3090,duration))
|
||||
{
|
||||
qDebug() << "GetDurationFromCost() => duration=" << duration;
|
||||
}
|
||||
//
|
||||
// test May 1st 2023
|
||||
//
|
||||
memset(&now, 0, sizeof(now));
|
||||
strptime("2023-04-30T06:00:00", "%Y-%m-%dT%H:%M:%S", &now);
|
||||
now.tm_hour -= 1; // for ctime
|
||||
for (int i=0; i<6*24; ++i) {
|
||||
int const duration = 120;
|
||||
time_t t = mktime(&now);
|
||||
start_parking_time = t / 60;
|
||||
end_parking_time = start_parking_time + duration;
|
||||
|
||||
if (compute_price_for_parking_ticket(tariff,
|
||||
start_parking_time,
|
||||
end_parking_time,
|
||||
&price)) {
|
||||
int const zone = get_zone_nr();
|
||||
switch (zone) {
|
||||
case 1:
|
||||
qDebug() << i << zone << ctime(&t) << price.netto << " FT";
|
||||
assert(price.netto == 440);
|
||||
break;
|
||||
case 2:
|
||||
/* fall through */
|
||||
case 3:
|
||||
qDebug() << i << zone << ctime(&t) << price.netto << " FT";
|
||||
assert(price.netto == 960);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Daily ticket
|
||||
//compute_duration_for_daily_ticket(tariff,start.toString(Qt::ISODate),3);
|
||||
|
||||
t = (start_parking_time + 60)*60;
|
||||
now = *localtime(&t);
|
||||
}
|
||||
//Configuration* cfg, QString start_datetime, uint8_t payment_option, bool carry_over
|
||||
// // tests
|
||||
// struct tm now;
|
||||
// memset(&now, 0, sizeof(now));
|
||||
|
||||
// // 3.Jan 2023 -> Tuesday
|
||||
// strptime("2023-01-03T14:00:00", "%Y-%m-%dT%H:%M:%S", &now);
|
||||
// for (int i = 0; i < 600; ++i) {
|
||||
// start_parking_time = mktime(&now);
|
||||
// end_parking_time = start_parking_time + 240; // duration == 240
|
||||
|
||||
// if (compute_price_for_parking_ticket(tariff,
|
||||
// start_parking_time,
|
||||
// end_parking_time,
|
||||
// &price)) {
|
||||
// int const zone = get_zone_nr(1);
|
||||
// switch (zone) {
|
||||
// case 1:
|
||||
// assert(price.netto == 879); // expected value: 880
|
||||
// break;
|
||||
// case 2:
|
||||
// /* fall through */
|
||||
// case 3:
|
||||
// assert(price.netto == 1920);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// time_t t = start_parking_time + 60;
|
||||
// now = *localtime(&t);
|
||||
// }
|
||||
// //
|
||||
// // test May 1st 2023
|
||||
// //
|
||||
// memset(&now, 0, sizeof(now));
|
||||
// strptime("2023-04-30T06:00:00", "%Y-%m-%dT%H:%M:%S", &now);
|
||||
// now.tm_hour -= 1; // for ctime
|
||||
// // for (int i=0; i<6*24; ++i) {
|
||||
// for (int i=0; i<1; ++i) {
|
||||
// int const duration = 120;
|
||||
// time_t t = mktime(&now);
|
||||
// start_parking_time = t / 60;
|
||||
// end_parking_time = start_parking_time + duration;
|
||||
|
||||
// if (compute_price_for_parking_ticket(tariff,
|
||||
// start_parking_time,
|
||||
// end_parking_time,
|
||||
// &price)) {
|
||||
// int const zone = get_zone_nr();
|
||||
// switch (zone) {
|
||||
// case 1:
|
||||
// qDebug() << i << zone << ctime(&t) << price.netto << " FT";
|
||||
// assert(price.netto == 440);
|
||||
// break;
|
||||
// case 2:
|
||||
// /* fall through */
|
||||
// case 3:
|
||||
// qDebug() << i << zone << ctime(&t) << price.netto << " FT";
|
||||
// assert(price.netto == 960);
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
|
||||
// t = (start_parking_time + 60)*60;
|
||||
// now = *localtime(&t);
|
||||
// }
|
||||
|
||||
free_tariff(tariff);
|
||||
}
|
||||
@@ -144,7 +191,7 @@ int main() {
|
||||
struct tm now; // = Utilities::DateTimeToStructTm("2023-03-01T16:00:00");
|
||||
memset(&now, 0, sizeof(now));
|
||||
char buffer[64];
|
||||
//#if 0
|
||||
//#if 0
|
||||
// 3.Jan 2023 -> Tuesday
|
||||
strptime("2023-01-03T14:00:00", "%Y-%m-%dT%H:%M:%S", &now);
|
||||
for (int i = 0; i < 600; ++i) {
|
||||
@@ -219,8 +266,8 @@ int main() {
|
||||
|
||||
int const duration = 120;
|
||||
double cost = calculator.GetCostFromDuration(&cfg,
|
||||
PaymentOption::Option1, buffer, duration,
|
||||
false, true);
|
||||
PaymentOption::Option1, buffer, duration,
|
||||
false, true);
|
||||
|
||||
switch (zone) {
|
||||
case 1:
|
||||
@@ -258,8 +305,8 @@ int main() {
|
||||
|
||||
int const duration = 120;
|
||||
double cost = calculator.GetCostFromDuration(&cfg,
|
||||
PaymentOption::Option1, buffer, duration,
|
||||
false, true);
|
||||
PaymentOption::Option1, buffer, duration,
|
||||
false, true);
|
||||
|
||||
switch (zone) {
|
||||
case 1:
|
||||
@@ -292,8 +339,8 @@ int main() {
|
||||
|
||||
double const compCost = (duration < 15) ? 0 : duration * ((zone == 1) ? 3.6666 : 8.0);
|
||||
double cost = calculator.GetCostFromDuration(&cfg,
|
||||
PaymentOption::Option1, buffer, duration,
|
||||
false, true);
|
||||
PaymentOption::Option1, buffer, duration,
|
||||
false, true);
|
||||
if (fabs(cost - compCost) > 1.0) { // zone 1 has rounding errors
|
||||
cout << "ERROR ===> [" << i << "] " << asctime(&now)
|
||||
<< " - Total cost is: " << cost << " FT (computed="
|
||||
|
@@ -7,6 +7,8 @@ QMAKE_CFLAGS = -c -pipe -std=c11 -g -O0 -Wall -Wno-attributes -W -DDEBUG -D_REEN
|
||||
QMAKE_CXX_FLAGS += -std=c11
|
||||
|
||||
INCLUDEPATH += $$_PRO_FILE_PWD_/../../MOBILISIS-Calculator/library/include/mobilisis/
|
||||
INCLUDEPATH += $$_PRO_FILE_PWD_/../../MOBILISIS-Calculator/library/include/rapidjson/
|
||||
INCLUDEPATH += $$_PRO_FILE_PWD_/../../MOBILISIS-Calculator/library/include/
|
||||
INCLUDEPATH += .
|
||||
|
||||
unix {
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user