Compare commits
76 Commits
Author | SHA1 | Date | |
---|---|---|---|
9bfea0f46d
|
|||
7ee90a9e8a
|
|||
8f2609c4ae
|
|||
453ca266a5
|
|||
0217bb8918 | |||
4b35b1ffb7 | |||
80e228b498 | |||
574161ff76 | |||
b80cd5e6ef | |||
ccbf07a654
|
|||
3a2e521345
|
|||
cd77e380ef
|
|||
aaa4348a9a
|
|||
17c4aac452
|
|||
68c438bfe0
|
|||
509bc29d7e
|
|||
f7e462188f
|
|||
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 |
13
library/include/mobilisis/atb_project.h
Normal file
13
library/include/mobilisis/atb_project.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#ifndef ATB_PROJECT_H_INCLUDED
|
||||||
|
#define ATB_PROJECT_H_INCLUDED
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class ATBProject {
|
||||||
|
public:
|
||||||
|
QString project;
|
||||||
|
QString version;
|
||||||
|
QString info;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ATB_PROJECT_H_INCLUDED
|
@@ -4,6 +4,9 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
#include <QDateTime>
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#ifdef CALCULATE_LIBRARY_EXPORTS
|
#ifdef CALCULATE_LIBRARY_EXPORTS
|
||||||
#define CALCULATE_LIBRARY_API __declspec(dllexport)
|
#define CALCULATE_LIBRARY_API __declspec(dllexport)
|
||||||
@@ -18,9 +21,9 @@ class Configuration;
|
|||||||
|
|
||||||
typedef Configuration parking_tariff_t;
|
typedef Configuration parking_tariff_t;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
//#ifdef __cplusplus
|
||||||
extern "C" {
|
//extern "C" {
|
||||||
#endif
|
//#endif
|
||||||
|
|
||||||
struct CALCULATE_LIBRARY_API price_t {
|
struct CALCULATE_LIBRARY_API price_t {
|
||||||
uint32_t units;
|
uint32_t units;
|
||||||
@@ -30,16 +33,115 @@ struct CALCULATE_LIBRARY_API price_t {
|
|||||||
double vat;
|
double vat;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file);
|
struct CALCULATE_LIBRARY_API CalcState {
|
||||||
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff);
|
enum class State : uint8_t {
|
||||||
int CALCULATE_LIBRARY_API get_zone_nr();
|
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,
|
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);
|
||||||
|
|
||||||
|
int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes, int UpDown);
|
||||||
|
|
||||||
|
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // deprecated
|
||||||
|
parking_tariff_t *tariff,
|
||||||
time_t start_parking_time,
|
time_t start_parking_time,
|
||||||
time_t end_parking_time,
|
time_t end_parking_time,
|
||||||
struct price_t *price);
|
struct price_t *price);
|
||||||
#ifdef __cplusplus
|
|
||||||
} // extern "C"
|
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
||||||
#endif
|
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
|
#endif // CALCULATE_PRICE_H
|
||||||
|
@@ -1,7 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include "configuration.h"
|
#include "configuration.h"
|
||||||
|
#include "payment_method.h"
|
||||||
|
#include <QDateTime>
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
class Calculator
|
class Calculator
|
||||||
@@ -23,7 +24,25 @@ public:
|
|||||||
/// <param name="tariff_cfg">Pointer to configuration</param>
|
/// <param name="tariff_cfg">Pointer to configuration</param>
|
||||||
/// <param name="vehicle_type">Type of vehicle</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="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>
|
/// <param name="durationMin">Duration of parking in minutes</param>
|
||||||
/// <returns>Returns cost (data type: double)</returns>
|
/// <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);
|
||||||
|
|
||||||
|
//
|
||||||
|
// helper function to find time steps for a tariff with PaymentMethod::Steps
|
||||||
|
// (e.g. Schoenau/Koenigsee)
|
||||||
|
//
|
||||||
|
QList<int> GetTimeSteps(Configuration *cfg) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Introduced for PaymentMethod::Steps (e.g. Schoenau)
|
||||||
|
// For tariff of following structure: only steps, no special days, nonstop.
|
||||||
|
uint32_t GetCostFromDuration(Configuration *cfg, QDateTime const &start, quint64 durationMinutes) const;
|
||||||
|
uint32_t GetCostFromDuration(Configuration *cfg, QDateTime const &start, QDateTime const &end) const;
|
||||||
|
uint32_t GetPriceForTimeStep(Configuration *cfg, int timeStep) const;
|
||||||
|
uint32_t GetDurationForPrice(Configuration *cfg, int price) const;
|
||||||
};
|
};
|
@@ -20,6 +20,7 @@
|
|||||||
#include "member_type.h"
|
#include "member_type.h"
|
||||||
#include "period_year.h"
|
#include "period_year.h"
|
||||||
#include "payment_rate.h"
|
#include "payment_rate.h"
|
||||||
|
#include "atb_project.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace rapidjson;
|
using namespace rapidjson;
|
||||||
@@ -27,7 +28,7 @@ using namespace rapidjson;
|
|||||||
class Configuration
|
class Configuration
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
ATBProject project;
|
||||||
ATBCurrency Currency;
|
ATBCurrency Currency;
|
||||||
ATBDuration duration;
|
ATBDuration duration;
|
||||||
|
|
||||||
@@ -48,6 +49,8 @@ public:
|
|||||||
/// <returns>Returns operation status bool (OK | FAIL) </returns>
|
/// <returns>Returns operation status bool (OK | FAIL) </returns>
|
||||||
bool ParseJson(Configuration* cfg, const char* json);
|
bool ParseJson(Configuration* cfg, const char* json);
|
||||||
|
|
||||||
|
ATBPaymentOption const & getPaymentOptions();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Identify type of JSON member
|
/// Identify type of JSON member
|
||||||
@@ -55,4 +58,6 @@ private:
|
|||||||
/// <param name="member_name"></param>
|
/// <param name="member_name"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
MemberType IdentifyJsonMember(const char* member_name);
|
MemberType IdentifyJsonMember(const char* member_name);
|
||||||
|
|
||||||
|
ATBPaymentOption currentPaymentOptions;
|
||||||
};
|
};
|
@@ -2,12 +2,12 @@
|
|||||||
|
|
||||||
enum DayOfWeek
|
enum DayOfWeek
|
||||||
{
|
{
|
||||||
Saturday = 0x06,
|
Monday = 0x01,
|
||||||
Sunday = 0x01,
|
|
||||||
Monday = 0x02,
|
|
||||||
Tuesday = 0x02,
|
Tuesday = 0x02,
|
||||||
Wednesday = 0x03,
|
Wednesday = 0x03,
|
||||||
Thursday = 0x04,
|
Thursday = 0x04,
|
||||||
Friday = 0x05,
|
Friday = 0x05,
|
||||||
|
Saturday = 0x06,
|
||||||
|
Sunday = 0x07,
|
||||||
UndefinedDay = 0xFF
|
UndefinedDay = 0xFF
|
||||||
};
|
};
|
@@ -14,4 +14,5 @@ public:
|
|||||||
double pop_max_time;
|
double pop_max_time;
|
||||||
double pop_min_price;
|
double pop_min_price;
|
||||||
int pop_carry_over;
|
int pop_carry_over;
|
||||||
|
int pop_daily_card_price;
|
||||||
};
|
};
|
@@ -68,5 +68,6 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pra_price"></param>
|
/// <param name="pra_price"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
static double CalculatePricePerUnit(double pra_price);
|
static double CalculatePricePerUnit(double pra_price, double durationUnit = -1);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@@ -65,7 +65,8 @@ HEADERS += \
|
|||||||
include/mobilisis/tariff_period_year.h \
|
include/mobilisis/tariff_period_year.h \
|
||||||
include/mobilisis/tariff_payment_rate.h \
|
include/mobilisis/tariff_payment_rate.h \
|
||||||
include/mobilisis/tariff_log.h \
|
include/mobilisis/tariff_log.h \
|
||||||
include/mobilisis/calculate_price.h
|
include/mobilisis/calculate_price.h \
|
||||||
|
include/mobilisis/atb_project.h
|
||||||
|
|
||||||
OTHER_FILES += src/main.cpp
|
OTHER_FILES += src/main.cpp
|
||||||
|
|
||||||
|
@@ -10,25 +10,31 @@
|
|||||||
|
|
||||||
static Calculator calculator;
|
static Calculator calculator;
|
||||||
|
|
||||||
int CALCULATE_LIBRARY_API get_zone_nr() {
|
int CALCULATE_LIBRARY_API get_zone_nr(int zone)
|
||||||
|
{
|
||||||
|
if(zone > -1) return zone;
|
||||||
|
else
|
||||||
|
{
|
||||||
QFile zone("/etc/zone_nr");
|
QFile zone("/etc/zone_nr");
|
||||||
if (zone.exists()) {
|
if (zone.exists()) {
|
||||||
QFileInfo finfo(zone);
|
QFileInfo finfo(zone);
|
||||||
if (finfo.size() <= 4) { // decimal 000\n
|
if (finfo.size() <= 4) { // decimal 000\n
|
||||||
if (zone.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
if (zone.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
|
|
||||||
QTextStream in(&zone);
|
QTextStream in(&zone);
|
||||||
return in.readLine(100).toInt();
|
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();
|
*tariff = new Configuration();
|
||||||
|
|
||||||
|
CalcState calcState;
|
||||||
|
#if __linux__
|
||||||
|
|
||||||
int const zone = get_zone_nr();
|
int const zone = get_zone_nr();
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
@@ -36,7 +42,9 @@ bool CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *co
|
|||||||
qCritical() << " ... zone = " << zone;
|
qCritical() << " ... zone = " << zone;
|
||||||
|
|
||||||
if (zone <= 0) {
|
if (zone <= 0) {
|
||||||
return false;
|
delete *tariff;
|
||||||
|
*tariff = nullptr;
|
||||||
|
return calcState.set(CalcState::State::ERROR_PARSING_ZONE_NR);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString confFile(config_file);
|
QString confFile(config_file);
|
||||||
@@ -48,62 +56,294 @@ bool CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *co
|
|||||||
memset(buffer, 0x00, sizeof(buffer));
|
memset(buffer, 0x00, sizeof(buffer));
|
||||||
snprintf(buffer, sizeof(buffer)-1, "tariff%02d.json", zone);
|
snprintf(buffer, sizeof(buffer)-1, "tariff%02d.json", zone);
|
||||||
confFile += buffer;
|
confFile += buffer;
|
||||||
|
#else // windows
|
||||||
|
QString confFile(config_file);
|
||||||
|
#endif
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
qCritical() << " ... confFile = " << confFile;
|
qCritical() << " ... confFile = " << confFile;
|
||||||
|
|
||||||
QFile fname(confFile);
|
QFile fname(confFile);
|
||||||
if (fname.exists()) {
|
if (fname.exists() &&
|
||||||
|
fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||||
// DEBUG
|
|
||||||
qCritical() << " ... confFile exists";
|
|
||||||
|
|
||||||
if (fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
qCritical() << " ... confFile is open";
|
qCritical() << " ... confFile is open";
|
||||||
|
|
||||||
QString json = fname.readAll();
|
QString json = fname.readAll();
|
||||||
return (*tariff)->ParseJson(*tariff, json.toStdString().c_str());
|
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) {
|
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff) {
|
||||||
|
if (tariff != nullptr) {
|
||||||
delete tariff;
|
delete tariff;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
|
||||||
|
//
|
||||||
|
// UpDown 1 -> up; 0 -> down
|
||||||
|
int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes, int UpDown)
|
||||||
|
{
|
||||||
|
static const QList<int> stepList = calculator.GetTimeSteps(tariff);
|
||||||
|
|
||||||
|
int currentStepIndex = stepList.indexOf(currentTimeMinutes);
|
||||||
|
|
||||||
|
if (currentStepIndex == -1) {
|
||||||
|
qCritical() << "compute_next_timestep() *NO STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
|
||||||
|
return currentTimeMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UpDown == 1) { // UP
|
||||||
|
if (stepList[currentStepIndex] == stepList.last()) {
|
||||||
|
qCritical() << "compute_next_timestep() *NO NEXT STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
|
||||||
|
return currentTimeMinutes;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return stepList[currentStepIndex + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (UpDown == 0) { // DOWN
|
||||||
|
if (stepList[currentStepIndex] == stepList.first()) {
|
||||||
|
qCritical() << "compute_next_timestep() *NO PREVIOUS STEP* for currentTimeMinutes (" << currentTimeMinutes << ")";
|
||||||
|
return currentTimeMinutes;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return stepList[currentStepIndex - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qCritical() << "compute_next_timestep() *CAN NOT COMPUTE* for currentTimeMinutes (" << currentTimeMinutes << ")";
|
||||||
|
return currentTimeMinutes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// this is currently not used
|
||||||
|
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
||||||
parking_tariff_t *tariff,
|
parking_tariff_t *tariff,
|
||||||
time_t start_parking_time, // in minutes
|
time_t start_parking_time, // in minutes
|
||||||
time_t end_parking_time, // in minutes
|
time_t end_parking_time, // netto time in minutes
|
||||||
struct price_t *price) {
|
struct price_t *price) {
|
||||||
|
CalcState calcState;
|
||||||
|
double minMin = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->second.pop_min_time;
|
||||||
|
double maxMin = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->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;
|
int const duration = end_parking_time - start_parking_time;
|
||||||
if (duration > 0) {
|
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 calcState.set(CalcState::State::SUCCESS);
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
tariff->getPaymentOptions().pop_payment_method_id,
|
||||||
|
start,
|
||||||
|
end,
|
||||||
|
duration, false, true);
|
||||||
|
double minCost = tariff->PaymentOption.find(tariff->getPaymentOptions().pop_payment_method_id)->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->getPaymentOptions().pop_min_time;
|
||||||
|
double maxMin = tariff->getPaymentOptions().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,
|
||||||
|
tariff->getPaymentOptions().pop_payment_method_id,
|
||||||
|
start_parking_time, // starting time
|
||||||
|
end_parking_time, // return value: end time
|
||||||
|
netto_parking_time, // minutes, netto
|
||||||
|
false, true);
|
||||||
|
double minCost = tariff->getPaymentOptions().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);
|
QDate const d(1970, 1, 1);
|
||||||
QTime const t(0, 0, 0);
|
QTime const t(0, 0, 0);
|
||||||
QDateTime start(d, t, Qt::UTC);
|
QDateTime start(d, t, Qt::UTC);
|
||||||
start = start.toLocalTime().addSecs(start_parking_time * 60);
|
start = start.toLocalTime().addSecs(start_parking_time * 60);
|
||||||
if (start.isValid()) {
|
if (start.isValid()) {
|
||||||
QString cs = start.toString(Qt::ISODate);
|
QString cs = start.toString(Qt::ISODate);
|
||||||
double cost = calculator.GetCostFromDuration(
|
|
||||||
tariff, PaymentOption::Option1,
|
// DEBUG
|
||||||
|
qCritical() << "compute_duration_for_parking_ticket(): ";
|
||||||
|
qCritical() << " start (cs): " << cs;
|
||||||
|
qCritical() << " price: " << price;
|
||||||
|
|
||||||
|
duration = calculator.GetDurationFromCost(tariff,
|
||||||
|
tariff->getPaymentOptions().pop_payment_method_id,
|
||||||
cs.toLocal8Bit().constData(),
|
cs.toLocal8Bit().constData(),
|
||||||
duration, false, true);
|
price, false, true).c_str();
|
||||||
price->units = cost;
|
QDateTime d = QDateTime::fromString(duration, Qt::ISODate);
|
||||||
price->netto = cost;
|
if (!d.isValid()) {
|
||||||
return true;
|
calcState.setDesc(QString("ticketEndTime=%1").arg(duration));
|
||||||
|
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
if (duration == 0) {
|
return calcState.set(CalcState::State::INVALID_START_DATE);
|
||||||
memset(price, 0x00, sizeof(*price));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
qCritical() << "ERROR start_parking_time (" << start_parking_time << ") <"
|
|
||||||
<< "end_parking_time (" << end_parking_time << ")";
|
return calcState.set(CalcState::State::SUCCESS);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
tariff->getPaymentOptions().pop_payment_method_id,
|
||||||
|
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,
|
||||||
|
tariff->getPaymentOptions().pop_payment_method_id,
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1,38 +1,160 @@
|
|||||||
#include "calculator_functions.h"
|
#include "calculator_functions.h"
|
||||||
#include "payment_method.h"
|
#include "payment_option.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
#include "tariff_log.h"
|
#include "tariff_log.h"
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <QDateTime>
|
||||||
|
#include <qdebug.h>
|
||||||
|
|
||||||
double total_duration_min = 0.0f;
|
double total_duration_min = 0.0f;
|
||||||
double total_cost = 0.0f;
|
double total_cost = 0.0f;
|
||||||
bool overtime = false;
|
bool overtime = false;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
#ifdef _WIN32
|
||||||
std::string Calculator::GetDurationFromCost(Configuration* cfg, uint8_t payment_option, char const* start_datetime, double price, bool nextDay, bool prepaid)
|
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
|
if(!start_datetime.isValid()) {
|
||||||
struct tm current_datetime = Utilities::DateTimeToStructTm(start_datetime);
|
return QDateTime();
|
||||||
time_t current_datetime_t;
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
QDateTime inputDateTime = start_datetime;
|
||||||
|
QTime worktime_from;
|
||||||
|
QTime worktime_to;
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if(inputDateTime.time() < worktime_from) inputDateTime.setTime(worktime_from);
|
||||||
|
if(carry_over) inputDateTime.setTime(worktime_from);
|
||||||
|
|
||||||
|
if(inputDateTime.time() >= worktime_to)
|
||||||
|
{
|
||||||
|
// Go to next day if outside worktime
|
||||||
|
inputDateTime = inputDateTime.addSecs(86400);
|
||||||
|
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
int diff = abs(inputDateTime.time().secsTo(worktime_to));
|
||||||
|
inputDateTime = inputDateTime.addSecs(diff);
|
||||||
|
|
||||||
|
//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());
|
||||||
|
|
||||||
|
// If no working day found, skip it (recursively call method again)
|
||||||
|
size_t found = 0;
|
||||||
|
found = cfg->WeekDaysWorktime.count(weekdayId);
|
||||||
|
|
||||||
|
// When no workday found, go to next available day
|
||||||
|
if(found <=0)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
if(carry_over)
|
||||||
|
inputDateTime.setTime(worktime_from);
|
||||||
|
|
||||||
|
if(inputDateTime.time() >= worktime_to)
|
||||||
|
{
|
||||||
|
// Go to next day if outside worktime
|
||||||
|
inputDateTime = inputDateTime.addSecs(86400);
|
||||||
|
return GetDailyTicketDuration(cfg,inputDateTime, payment_option,true);
|
||||||
|
}
|
||||||
|
|
||||||
|
int diff = abs(inputDateTime.time().secsTo(worktime_to));
|
||||||
|
inputDateTime = inputDateTime.addSecs(diff);
|
||||||
|
|
||||||
|
//qDebug() << "Ticket is valid until: " << inputDateTime.toString(Qt::ISODate) << "price = " << daily_card_price << ", duration = " << diff / 60;
|
||||||
|
return inputDateTime;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// use tariff with structure as for instance Schnau, Koenigsee:
|
||||||
|
// without given YearPeriod, SpecialDays and SpecialDaysWorktime
|
||||||
|
if (cfg->YearPeriod.size() == 0
|
||||||
|
&& cfg->SpecialDays.size() == 0
|
||||||
|
&& cfg->SpecialDaysWorktime.size() == 0)
|
||||||
|
{
|
||||||
|
inputDate = inputDate.addSecs(GetDurationForPrice(cfg, price) * 60);
|
||||||
|
|
||||||
|
return inputDate.toString(Qt::ISODate).toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// Get day of week
|
// Get day of week
|
||||||
DayOfWeek weekdayId = DayOfWeek::UndefinedDay;
|
int weekdayId = 0;
|
||||||
weekdayId = Utilities::GetDayOfWeek(¤t_datetime);
|
weekdayId = Utilities::ZellersAlgorithm(inputDate.date().day(),inputDate.date().month(),inputDate.date().year());
|
||||||
|
|
||||||
//std::stringstream ss;
|
|
||||||
|
|
||||||
// ss << "*** Input date is: " << start_datetime << " [weekday id = " << weekdayId << "]" << endl;
|
|
||||||
LOG_DEBUG("*** Input date is: ", start_datetime, " [weekday id = ", weekdayId, "]");
|
|
||||||
|
|
||||||
|
//Get min and max time defined in JSON
|
||||||
double minMin = 0;
|
double minMin = 0;
|
||||||
minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
|
minMin = cfg->getPaymentOptions().pop_min_time;
|
||||||
if (minMin < 0) minMin = 0;
|
|
||||||
|
|
||||||
double maxMin = 0;
|
double maxMin = 0;
|
||||||
maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
|
maxMin = cfg->getPaymentOptions().pop_max_time;
|
||||||
if (maxMin <= 0) maxMin = 60;
|
|
||||||
|
|
||||||
|
double min_price = 0;
|
||||||
|
min_price = cfg->getPaymentOptions().pop_min_price;
|
||||||
|
|
||||||
|
if(price < min_price)
|
||||||
|
{
|
||||||
|
return "PARKING NOT ALLOWED";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minMin < 0) minMin = 0;
|
||||||
|
if (maxMin < 0) maxMin = 0;
|
||||||
if (minMin >= maxMin)
|
if (minMin >= maxMin)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
|
LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
|
||||||
@@ -45,106 +167,72 @@ std::string Calculator::GetDurationFromCost(Configuration* cfg, uint8_t payment_
|
|||||||
return "PARKING NOT ALLOWED";
|
return "PARKING NOT ALLOWED";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Get payment method
|
||||||
uint8_t p_method = PaymentMethod::Undefined;
|
uint8_t p_method = PaymentMethod::Undefined;
|
||||||
p_method = payment_option;
|
p_method = payment_option;
|
||||||
LOG_DEBUG("Payment method id: ", (unsigned)p_method);
|
LOG_DEBUG("Payment method id: ", (unsigned)p_method);
|
||||||
|
|
||||||
|
// Check special day
|
||||||
double day_price = 0.0f;
|
double day_price = 0.0f;
|
||||||
int current_special_day_id = -1;
|
int current_special_day_id = -1;
|
||||||
bool is_special_day = Utilities::CheckSpecialDay(cfg, start_datetime, ¤t_special_day_id, &day_price);
|
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);
|
LOG_DEBUG("Special day: ", is_special_day);
|
||||||
|
|
||||||
double money_left = price;
|
double money_left = price;
|
||||||
LOG_DEBUG("Total money:", money_left);
|
|
||||||
|
|
||||||
double price_per_unit = 0.0f;
|
double price_per_unit = 0.0f;
|
||||||
|
|
||||||
string worktime_from = "";
|
QTime worktime_from;
|
||||||
string worktime_to = "";
|
QTime worktime_to;
|
||||||
|
|
||||||
if(is_special_day)
|
if(is_special_day)
|
||||||
{
|
{
|
||||||
// Set special day price
|
// Set special day price
|
||||||
price_per_unit = Utilities::CalculatePricePerUnit(day_price);
|
price_per_unit = Utilities::CalculatePricePerUnit(day_price);
|
||||||
worktime_from = cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from;
|
worktime_from = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from.c_str());
|
||||||
worktime_to = cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to;
|
worktime_to = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set new price for the normal day
|
// Set new price for the normal day
|
||||||
day_price = cfg->PaymentRate.find(payment_option)->second.pra_price;
|
int pop_id = cfg->PaymentOption.find(payment_option)->second.pop_id;
|
||||||
price_per_unit = Utilities::CalculatePricePerUnit(day_price);
|
day_price = cfg->PaymentRate.find(pop_id)->second.pra_price;
|
||||||
|
|
||||||
|
int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id;
|
||||||
|
double durationUnit = cfg->Duration.find(durationId)->second.pun_duration;
|
||||||
|
price_per_unit = Utilities::CalculatePricePerUnit(day_price,durationUnit);
|
||||||
|
|
||||||
// If no working day found, skip it (recursively call method again)
|
// If no working day found, skip it (recursively call method again)
|
||||||
size_t found = 0;
|
size_t found = 0;
|
||||||
found = cfg->WeekDaysWorktime.count(weekdayId);
|
found = cfg->WeekDaysWorktime.count(weekdayId);
|
||||||
|
|
||||||
|
// When no workday found, go to next available day
|
||||||
if(found <=0)
|
if(found <=0)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("- No workday found, trying to find next available day");
|
LOG_DEBUG("- No workday found, trying to find next available day");
|
||||||
current_datetime_t = mktime(¤t_datetime);
|
inputDate = inputDate.addDays(1);
|
||||||
current_datetime_t += 86400;
|
return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left,true,prepaid);
|
||||||
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 = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from.c_str());
|
||||||
worktime_from = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from;
|
worktime_to = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to.c_str());
|
||||||
worktime_to = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (price_per_unit < 0) price_per_unit = 1.0f;
|
if (price_per_unit < 0) price_per_unit = 1.0f;
|
||||||
|
|
||||||
|
// if((price/price_per_unit) < minMin) return "PARKING NOT ALLOWED";
|
||||||
LOG_DEBUG("Calculated price per minute: ", price_per_unit);
|
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 flag is set
|
||||||
if (overtime || nextDay)
|
if (overtime || nextDay)
|
||||||
{
|
{
|
||||||
current_datetime.tm_hour = from_tm.tm_hour;
|
inputDate.setTime(worktime_from);
|
||||||
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;
|
overtime = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate ticket
|
// Check prepaid
|
||||||
if (!prepaid)
|
if (!prepaid)
|
||||||
{
|
{
|
||||||
if ((current_datetime_t < from_datetime_t) || (current_datetime_t > to_datetime_t))
|
if ((inputDate.time() < worktime_from) || (inputDate.time() > worktime_to))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("[STOP] * Ticket is not valid * ");
|
LOG_DEBUG("[STOP] * Ticket is not valid * ");
|
||||||
return "PARKING NOT ALLOWED";
|
return "PARKING NOT ALLOWED";
|
||||||
@@ -153,166 +241,195 @@ std::string Calculator::GetDurationFromCost(Configuration* cfg, uint8_t payment_
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_DEBUG("* PREPAID MODE ACTIVE *");
|
LOG_DEBUG("* PREPAID MODE ACTIVE *");
|
||||||
|
if (inputDate.time() < worktime_from)
|
||||||
if (current_datetime_t < from_datetime_t)
|
|
||||||
{
|
{
|
||||||
current_datetime.tm_hour = from_tm.tm_hour;
|
inputDate.setTime(worktime_from);
|
||||||
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)
|
else if(inputDate.time() > worktime_to)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day");
|
LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day");
|
||||||
current_datetime_t = mktime(¤t_datetime);
|
inputDate = inputDate.addDays(1);
|
||||||
current_datetime_t += 86400;
|
return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left, true);
|
||||||
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)
|
while(true)
|
||||||
{
|
{
|
||||||
if (!Utilities::IsYearPeriodActive(cfg, ¤t_datetime))
|
if((int)money_left <= 0) break;
|
||||||
|
|
||||||
|
// Check year period
|
||||||
|
bool isYearPeriodActive = false;
|
||||||
|
|
||||||
|
//// Parse input date
|
||||||
|
int dayCurrent = inputDate.date().day();
|
||||||
|
int monthCurrent = inputDate.date().month();
|
||||||
|
|
||||||
|
// Current date time
|
||||||
|
int cdt = (monthCurrent * 100) + dayCurrent;
|
||||||
|
|
||||||
|
multimap<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");
|
LOG_DEBUG("Year period is not valid");
|
||||||
return "PARKING NOT ALLOWED";
|
return "PARKING NOT ALLOWED";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment by 1 minute
|
if(total_duration_min > maxMin)
|
||||||
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;
|
total_duration_min = maxMin;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If money has left but the end of worktime has been reached (go to next day)
|
// If reached end of worktime go to next day
|
||||||
if (current_datetime_t >= to_datetime_t)
|
if(inputDate.time() >= worktime_to)
|
||||||
{
|
{
|
||||||
total_duration_min -= 1.0f;
|
|
||||||
|
|
||||||
int carry_over_status = 0;
|
int carry_over_status = 0;
|
||||||
carry_over_status = cfg->PaymentOption.find(payment_option)->second.pop_carry_over;
|
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;
|
if (carry_over_status < 1) break;
|
||||||
|
|
||||||
LOG_DEBUG("Reached end of worktime");
|
inputDate = inputDate.addDays(1);
|
||||||
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;
|
overtime = true;
|
||||||
return GetDurationFromCost(cfg, payment_option, start_datetime, price);
|
return GetDurationFromCost(cfg, payment_option, inputDate.toString(Qt::ISODate).toStdString().c_str(), money_left ,true, prepaid);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t valid_until_datetime_t = current_datetime_t;
|
if(money_left > 1)
|
||||||
|
inputDate = inputDate.addSecs(60);
|
||||||
|
|
||||||
if ((total_duration_min < minMin) || (price / price_per_unit) < minMin)
|
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
|
||||||
{
|
{
|
||||||
LOG_DEBUG("Total duration is lower than min_min");
|
qDebug() << "Parking not allowed";
|
||||||
//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;
|
total_duration_min = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ret_val = 0;
|
ret_val = total_duration_min;
|
||||||
double calc_price = (int)total_duration_min - (int)price / price_per_unit;
|
if(ret_val < 0) ret_val = 0;
|
||||||
|
qDebug() << "Duration: " << ret_val;
|
||||||
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";
|
if (ret_val <= 0) return "PARKING NOT ALLOWED";
|
||||||
|
|
||||||
struct tm valid_until_datetime = *localtime(&valid_until_datetime_t);
|
total_duration_min = 0;
|
||||||
LOG_DEBUG("Ticket is valid until ", asctime(&valid_until_datetime));
|
return inputDate.toString(Qt::ISODate).toStdString();
|
||||||
|
|
||||||
total_duration_min = 0.0f;
|
|
||||||
return asctime(&valid_until_datetime);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////
|
///////////////////////////////////////
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
double Calculator::GetCostFromDuration(Configuration* cfg, uint8_t payment_option, const char* start_datetime, double durationMin, bool nextDay, bool prepaid)
|
///
|
||||||
|
|
||||||
|
uint32_t Calculator::GetCostFromDuration(Configuration *cfg,
|
||||||
|
QDateTime const &start,
|
||||||
|
quint64 timeStepInMinutes) const {
|
||||||
|
// for instance, a tariff as used in Schoenau, Koenigssee: only steps, no
|
||||||
|
// special days, nonstop.
|
||||||
|
if (cfg->YearPeriod.size() == 0
|
||||||
|
&& cfg->SpecialDays.size() == 0
|
||||||
|
&& cfg->SpecialDaysWorktime.size() == 0) {
|
||||||
|
QDateTime const end = start.addSecs(timeStepInMinutes*60);
|
||||||
|
return GetCostFromDuration(cfg, start, end);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Calculator::GetCostFromDuration(Configuration * cfg,
|
||||||
|
QDateTime const &start,
|
||||||
|
QDateTime const &end) const {
|
||||||
|
if (cfg->YearPeriod.size() == 0
|
||||||
|
&& cfg->SpecialDays.size() == 0
|
||||||
|
&& cfg->SpecialDaysWorktime.size() == 0) {
|
||||||
|
int const timeStepInMinutes = start.secsTo(end) / 60;
|
||||||
|
return GetPriceForTimeStep(cfg, timeStepInMinutes);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
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
|
if (cfg->YearPeriod.size() == 0
|
||||||
struct tm current_datetime = Utilities::DateTimeToStructTm(start_datetime);
|
&& cfg->SpecialDays.size() == 0
|
||||||
time_t current_datetime_t;
|
&& cfg->SpecialDaysWorktime.size() == 0)
|
||||||
|
{
|
||||||
|
end_datetime = start_datetime.addSecs(durationMin*60);
|
||||||
|
return GetCostFromDuration(cfg, start_datetime, end_datetime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get input date
|
||||||
|
QDateTime inputDate = start_datetime;
|
||||||
|
|
||||||
// Get day of week
|
// Get day of week
|
||||||
DayOfWeek weekdayId = DayOfWeek::UndefinedDay;
|
int weekdayId = 0;
|
||||||
weekdayId = Utilities::GetDayOfWeek(¤t_datetime);
|
weekdayId = Utilities::ZellersAlgorithm(inputDate.date().day(),inputDate.date().month(),inputDate.date().year());
|
||||||
LOG_DEBUG("*** Input date is: ", start_datetime, " [weekday id = ", weekdayId, "]");
|
|
||||||
|
|
||||||
|
//Get min and max time defined in JSON
|
||||||
double minMin = 0;
|
double minMin = 0;
|
||||||
minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
|
minMin = cfg->PaymentOption.find(payment_option)->second.pop_min_time;
|
||||||
if (minMin < 0) minMin = 0;
|
|
||||||
|
|
||||||
double maxMin = 0;
|
double maxMin = 0;
|
||||||
maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
|
maxMin = cfg->PaymentOption.find(payment_option)->second.pop_max_time;
|
||||||
if (maxMin <= 0) maxMin = 60;
|
|
||||||
|
|
||||||
|
if (minMin < 0) minMin = 0;
|
||||||
|
if (maxMin < 0) maxMin = 0;
|
||||||
if (minMin >= maxMin)
|
if (minMin >= maxMin)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
|
LOG_ERROR("Error: min_min cannot be greater or equal to max_min");
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (maxMin <= minMin)
|
if (maxMin <= minMin)
|
||||||
{
|
{
|
||||||
LOG_ERROR("Error: max_min cannot be lower or equal than min_min");
|
LOG_ERROR("Error: max_min cannot be lower or equal than min_min");
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check overtime
|
||||||
if (!overtime)
|
if (!overtime)
|
||||||
{
|
{
|
||||||
if (durationMin > maxMin)
|
if (durationMin > maxMin)
|
||||||
{
|
{
|
||||||
LOG_WARNING("Total duration is greater or equal to max_min");
|
LOG_WARNING("Total duration is greater or equal to max_min");
|
||||||
return 0.0f;
|
return maxMin;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (durationMin < minMin)
|
if (durationMin < minMin)
|
||||||
@@ -322,101 +439,78 @@ double Calculator::GetCostFromDuration(Configuration* cfg, uint8_t payment_optio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get payment method
|
||||||
uint8_t p_method = PaymentMethod::Undefined;
|
uint8_t p_method = PaymentMethod::Undefined;
|
||||||
p_method = payment_option;
|
p_method = payment_option;
|
||||||
LOG_DEBUG("Payment method id: ", (unsigned)p_method);
|
LOG_DEBUG("Payment method id: ", (unsigned)p_method);
|
||||||
|
|
||||||
|
// Check special day
|
||||||
double day_price = 0.0f;
|
double day_price = 0.0f;
|
||||||
int current_special_day_id = -1;
|
int current_special_day_id = -1;
|
||||||
bool is_special_day = Utilities::CheckSpecialDay(cfg, start_datetime, ¤t_special_day_id, &day_price);
|
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);
|
LOG_DEBUG("Special day: ", is_special_day);
|
||||||
|
|
||||||
total_duration_min = durationMin;
|
total_duration_min = durationMin;
|
||||||
LOG_DEBUG("Total min:", total_duration_min);
|
LOG_DEBUG("Total min:", total_duration_min);
|
||||||
|
|
||||||
double price_per_unit = 0.0f;
|
double price_per_unit = 0.0f;
|
||||||
|
QTime worktime_from;
|
||||||
string worktime_from = "";
|
QTime worktime_to;
|
||||||
string worktime_to = "";
|
|
||||||
|
|
||||||
if(is_special_day)
|
if(is_special_day)
|
||||||
{
|
{
|
||||||
// Set special day price
|
// Set special day price
|
||||||
price_per_unit = Utilities::CalculatePricePerUnit(day_price);
|
price_per_unit = Utilities::CalculatePricePerUnit(day_price);
|
||||||
worktime_from = cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from;
|
worktime_from = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_from.c_str());
|
||||||
worktime_to = cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to;
|
worktime_to = QTime::fromString(cfg->SpecialDaysWorktime.find(current_special_day_id)->second.pedwt_time_to.c_str());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Set new price for the normal day
|
// 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 pop_id = cfg->PaymentOption.find(payment_option)->second.pop_id;
|
||||||
|
day_price = cfg->PaymentRate.find(pop_id)->second.pra_price;
|
||||||
|
|
||||||
|
int durationId = cfg->PaymentRate.find(pop_id)->second.pra_payment_unit_id;
|
||||||
|
double durationUnit = cfg->Duration.find(durationId)->second.pun_duration;
|
||||||
|
price_per_unit = Utilities::CalculatePricePerUnit(day_price,durationUnit);
|
||||||
|
|
||||||
// If no working day found, skip it (recursively call method again)
|
// If no working day found, skip it (recursively call method again)
|
||||||
size_t found = 0;
|
size_t found = 0;
|
||||||
found = cfg->WeekDaysWorktime.count(weekdayId);
|
found = cfg->WeekDaysWorktime.count(weekdayId);
|
||||||
|
|
||||||
|
// When no workday found, go to next available day
|
||||||
if(found <=0)
|
if(found <=0)
|
||||||
{
|
{
|
||||||
LOG_DEBUG("- No workday found, trying to find next available day");
|
LOG_DEBUG("- No workday found, trying to find next available day");
|
||||||
current_datetime_t = mktime(¤t_datetime);
|
inputDate = inputDate.addDays(1);
|
||||||
current_datetime_t += 86400;
|
return floor(GetCostFromDuration(cfg, payment_option, inputDate, end_datetime, durationMin, true, prepaid));
|
||||||
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 = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from.c_str());
|
||||||
worktime_from = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_from;
|
worktime_to = QTime::fromString(cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to.c_str());
|
||||||
worktime_to = cfg->WeekDaysWorktime.find(weekdayId)->second.pwd_time_to;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (price_per_unit < 0) price_per_unit = 1.0f;
|
if (price_per_unit < 0) price_per_unit = 1.0f;
|
||||||
LOG_DEBUG("Calculated price per minute: ", price_per_unit);
|
LOG_DEBUG("Calculated price per minute: ", price_per_unit);
|
||||||
|
|
||||||
LOG_DEBUG("Worktime from: ", worktime_from);
|
if (price_per_unit == 0)
|
||||||
LOG_DEBUG("Worktime to: ", worktime_to);
|
{
|
||||||
|
inputDate = inputDate.addDays(1);
|
||||||
struct tm from_tm;
|
inputDate.setTime(worktime_from);
|
||||||
struct tm to_tm;
|
return GetCostFromDuration(cfg, payment_option, inputDate, end_datetime, durationMin, true, prepaid);
|
||||||
|
}
|
||||||
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 flag is set
|
||||||
if (overtime || nextDay)
|
if (overtime || nextDay)
|
||||||
{
|
{
|
||||||
current_datetime.tm_hour = from_tm.tm_hour;
|
inputDate.setTime(worktime_from);
|
||||||
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;
|
overtime = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate ticket
|
// Check prepaid
|
||||||
if (!prepaid)
|
if (!prepaid)
|
||||||
{
|
{
|
||||||
if ((current_datetime_t < from_datetime_t) || (current_datetime_t > to_datetime_t))
|
if ((inputDate.time() < worktime_from) || (inputDate.time() > worktime_to))
|
||||||
{
|
{
|
||||||
LOG_DEBUG("[STOP] * Ticket is not valid * ");
|
LOG_DEBUG("[STOP] * Ticket is not valid * ");
|
||||||
return 0.0f;
|
return 0.0f;
|
||||||
@@ -425,89 +519,144 @@ double Calculator::GetCostFromDuration(Configuration* cfg, uint8_t payment_optio
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
LOG_DEBUG("* PREPAID MODE ACTIVE *");
|
LOG_DEBUG("* PREPAID MODE ACTIVE *");
|
||||||
|
if (inputDate.time() < worktime_from)
|
||||||
if (current_datetime_t < from_datetime_t)
|
|
||||||
{
|
{
|
||||||
current_datetime.tm_hour = from_tm.tm_hour;
|
inputDate.setTime(worktime_from);
|
||||||
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)
|
else if(inputDate.time() > worktime_to)
|
||||||
{
|
{
|
||||||
LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day");
|
LOG_DEBUG(" *** PREPAID *** Current time is past the time range end, searching for next available day");
|
||||||
current_datetime_t = mktime(¤t_datetime);
|
inputDate = inputDate.addDays(1);
|
||||||
current_datetime_t += 86400;
|
return GetCostFromDuration(cfg, payment_option, inputDate, end_datetime, durationMin, true, prepaid);
|
||||||
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)
|
while(true)
|
||||||
{
|
{
|
||||||
if (!Utilities::IsYearPeriodActive(cfg, ¤t_datetime))
|
if(total_duration_min <= 0) break;
|
||||||
|
|
||||||
|
// Check year period
|
||||||
|
bool isYearPeriodActive = false;
|
||||||
|
|
||||||
|
//// Parse input date
|
||||||
|
int dayCurrent = inputDate.date().day();
|
||||||
|
int monthCurrent = inputDate.date().month();
|
||||||
|
|
||||||
|
// Current date time
|
||||||
|
int cdt = (monthCurrent * 100) + dayCurrent;
|
||||||
|
|
||||||
|
multimap<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");
|
LOG_DEBUG("Year period is not valid");
|
||||||
return 0.0f;
|
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;
|
int carry_over_status = 0;
|
||||||
carry_over_status = cfg->PaymentOption.find(payment_option)->second.pop_carry_over;
|
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);
|
// Go to next day if minutes not spent
|
||||||
|
if(inputDate.time() >= worktime_to)
|
||||||
|
{
|
||||||
if (carry_over_status < 1) break;
|
if (carry_over_status < 1) break;
|
||||||
|
|
||||||
LOG_DEBUG("Reached end of worktime");
|
LOG_DEBUG("Reached end of worktime, searching for the next working day");
|
||||||
LOG_DEBUG("Trying to find next available day, min left = ", total_duration_min);
|
inputDate = inputDate.addDays(1);
|
||||||
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;
|
overtime = true;
|
||||||
return floor(GetCostFromDuration(cfg, payment_option, start_datetime, total_duration_min));
|
return GetCostFromDuration(cfg, payment_option, inputDate, end_datetime, total_duration_min);
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
time_t valid_until_datetime_t = current_datetime_t;
|
// Increment input date minutes for each monetary unit
|
||||||
struct tm valid_until_datetime = *localtime(&valid_until_datetime_t);
|
inputDate = inputDate.addSecs(60);
|
||||||
LOG_DEBUG("Ticket is valid until ", asctime(&valid_until_datetime));
|
total_duration_min -=1;
|
||||||
|
total_cost += price_per_unit;
|
||||||
|
|
||||||
|
}
|
||||||
|
qDebug() << "GetCostFromDuration(): Valid until:" << inputDate.toString(Qt::ISODate).toStdString().c_str();
|
||||||
|
|
||||||
|
end_datetime = inputDate;
|
||||||
|
|
||||||
double ret_val = total_cost;
|
double ret_val = total_cost;
|
||||||
total_cost = 0.0f;
|
total_cost = 0.0f;
|
||||||
return floor(ret_val);
|
return ceil(ret_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
QList<int> Calculator::GetTimeSteps(Configuration *cfg) const {
|
||||||
|
QList<int> timeSteps;
|
||||||
|
|
||||||
|
int const pop_id = cfg->getPaymentOptions().pop_id;
|
||||||
|
|
||||||
|
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr)
|
||||||
|
{
|
||||||
|
int const durationId = itr->second.pra_payment_unit_id;
|
||||||
|
int const durationUnit = cfg->Duration.find(durationId)->second.pun_duration;
|
||||||
|
timeSteps << durationUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
return timeSteps;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t Calculator::GetPriceForTimeStep(Configuration *cfg, int timeStep) const {
|
||||||
|
|
||||||
|
int const pop_id = cfg->getPaymentOptions().pop_id;
|
||||||
|
|
||||||
|
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr)
|
||||||
|
{
|
||||||
|
int const payment_unit_id = itr->second.pra_payment_unit_id;
|
||||||
|
int const pun_id = cfg->Duration.find(payment_unit_id)->second.pun_id;
|
||||||
|
|
||||||
|
Q_ASSERT(pun_id == payment_unit_id);
|
||||||
|
|
||||||
|
int const pun_duration = cfg->Duration.find(payment_unit_id)->second.pun_duration;
|
||||||
|
if (timeStep == pun_duration) {
|
||||||
|
return (uint32_t)(itr->second.pra_price);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* private: read price directly from config file (used with PaymentMethod::Steps)
|
||||||
|
*
|
||||||
|
* return duration in minutes for greatest pra_price < price
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint32_t Calculator::GetDurationForPrice(Configuration *cfg, int price) const {
|
||||||
|
int const pop_id = cfg->getPaymentOptions().pop_id;
|
||||||
|
uint32_t duration = 0;
|
||||||
|
|
||||||
|
for (auto[itr, rangeEnd] = cfg->PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr)
|
||||||
|
{
|
||||||
|
int const durationId = itr->second.pra_payment_unit_id;
|
||||||
|
int const pra_price = itr->second.pra_price;
|
||||||
|
uint32_t const durationUnit = cfg->Duration.find(durationId)->second.pun_duration;
|
||||||
|
|
||||||
|
if (price == pra_price) {
|
||||||
|
return durationUnit;
|
||||||
|
}
|
||||||
|
if (pra_price < price) {
|
||||||
|
duration = durationUnit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return duration;
|
||||||
}
|
}
|
||||||
|
@@ -59,8 +59,9 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
|||||||
|| !document.HasMember("PaymentRate")
|
|| !document.HasMember("PaymentRate")
|
||||||
|| !document.HasMember("Duration")
|
|| !document.HasMember("Duration")
|
||||||
//|| !document.HasMember("WeekDays")
|
//|| !document.HasMember("WeekDays")
|
||||||
|| !document.HasMember("SpecialDaysWorktime")
|
//|| !document.HasMember("SpecialDaysWorktime")
|
||||||
|| !document.HasMember("SpecialDays"))
|
//|| !document.HasMember("SpecialDays")
|
||||||
|
)
|
||||||
{
|
{
|
||||||
printf("%s", "Error: not a valid configuration JSON\n");
|
printf("%s", "Error: not a valid configuration JSON\n");
|
||||||
return false;
|
return false;
|
||||||
@@ -87,13 +88,26 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
|||||||
const char* mb_name = i->name.GetString();
|
const char* mb_name = i->name.GetString();
|
||||||
if (mb_name == NULL) continue;
|
if (mb_name == NULL) continue;
|
||||||
|
|
||||||
// if (!document[mb_name].IsArray()) {
|
if (document[mb_name].IsString()) {
|
||||||
std::string const _mb_name(mb_name);
|
QString const _mb_name(mb_name);
|
||||||
if (_mb_name == "version" || _mb_name == "project" ||
|
if (_mb_name.startsWith("Project", Qt::CaseInsensitive)) {
|
||||||
_mb_name == "zone" || _mb_name == "info") {
|
cfg->project.project = document[mb_name].GetString();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_mb_name.startsWith("Version", Qt::CaseInsensitive)) {
|
||||||
|
cfg->project.version = document[mb_name].GetString();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (_mb_name.startsWith("Info", Qt::CaseInsensitive)) {
|
||||||
|
cfg->project.info = document[mb_name].GetString();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ... everything else should be an array
|
||||||
|
if (!document[mb_name].IsArray()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
//printf(" -%s\n", mb_name);
|
//printf(" -%s\n", mb_name);
|
||||||
|
|
||||||
@@ -154,6 +168,8 @@ 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_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_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_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();
|
||||||
|
this->currentPaymentOptions = PaymentOption;
|
||||||
break;
|
break;
|
||||||
case MemberType::DurationType:
|
case MemberType::DurationType:
|
||||||
if (strcmp(inner_obj_name, "pun_id") == 0) Duration.pun_id = k->value.GetInt();
|
if (strcmp(inner_obj_name, "pun_id") == 0) Duration.pun_id = k->value.GetInt();
|
||||||
@@ -209,7 +225,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
|||||||
cfg->PaymentMethod.insert(pair<int, ATBPaymentMethod>(PaymentMethod.pme_id, PaymentMethod));
|
cfg->PaymentMethod.insert(pair<int, ATBPaymentMethod>(PaymentMethod.pme_id, PaymentMethod));
|
||||||
break;
|
break;
|
||||||
case MemberType::PaymentRateType:
|
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;
|
break;
|
||||||
case MemberType::PaymentOptionType:
|
case MemberType::PaymentOptionType:
|
||||||
cfg->PaymentOption.insert(pair<int, ATBPaymentOption>(PaymentOption.pop_payment_method_id, PaymentOption));
|
cfg->PaymentOption.insert(pair<int, ATBPaymentOption>(PaymentOption.pop_payment_method_id, PaymentOption));
|
||||||
@@ -244,3 +260,10 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const ATBPaymentOption & Configuration::getPaymentOptions()
|
||||||
|
{
|
||||||
|
return this->currentPaymentOptions;
|
||||||
|
}
|
||||||
|
@@ -8,12 +8,15 @@ static int protection_counter = 0;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pra_price"></param>
|
/// <param name="pra_price"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
double Utilities::CalculatePricePerUnit(double pra_price)
|
double Utilities::CalculatePricePerUnit(double pra_price, double durationUnit)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
double price_per_unit = pra_price;
|
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);
|
//printf("Price per unit (min) is: %lf\n", price_per_unit);
|
||||||
return price_per_unit;
|
return price_per_unit;
|
||||||
}
|
}
|
||||||
@@ -33,7 +36,7 @@ time_t Utilities::GetCurrentLocalTime()
|
|||||||
memset(&tm_curr_time, '\0', sizeof(struct tm));
|
memset(&tm_curr_time, '\0', sizeof(struct tm));
|
||||||
|
|
||||||
tm_curr_time = *localtime(&curr_time);
|
tm_curr_time = *localtime(&curr_time);
|
||||||
curr_time = mktime(&tm_curr_time) - timezone;
|
curr_time = mktime(&tm_curr_time); //- timezone;
|
||||||
return curr_time;
|
return curr_time;
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
|
183
main/main.cpp
183
main/main.cpp
@@ -1,10 +1,9 @@
|
|||||||
#include <calculate_price.h>
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <calculate_price.h>
|
||||||
|
|
||||||
|
|
||||||
extern "C" char* strptime(const char* s,
|
extern "C" char* strptime(const char* s,
|
||||||
const char* f,
|
const char* f,
|
||||||
@@ -27,87 +26,135 @@ extern "C" char* strptime(const char* s,
|
|||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
#include <QDir>
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <sstream>
|
||||||
|
#include "calculator_functions.h"
|
||||||
|
#include <calculate_price.h>
|
||||||
|
|
||||||
|
|
||||||
int main() {
|
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;
|
parking_tariff_t *tariff = 0;
|
||||||
if (init_tariff(&tariff, "/etc/psa_tariff/")) {
|
if (init_tariff(&tariff, "/etc/psa_tariff/")) {
|
||||||
struct price_t price;
|
struct price_t price;
|
||||||
memset(&price, 0x00, sizeof(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 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,
|
if (compute_price_for_parking_ticket(tariff,
|
||||||
start_parking_time,
|
start_parking_time,
|
||||||
end_parking_time,
|
end_parking_time,
|
||||||
&price)) {
|
&price))
|
||||||
qDebug() << "price=" << price.netto;
|
{
|
||||||
|
qDebug() << "GetCostFromDuration() => price=" << price.netto;
|
||||||
}
|
}
|
||||||
|
|
||||||
// tests
|
QString duration;
|
||||||
struct tm now;
|
if(compute_duration_for_parking_ticket(tariff,start_parking_time,3090,duration))
|
||||||
memset(&now, 0, sizeof(now));
|
{
|
||||||
|
qDebug() << "GetDurationFromCost() => duration=" << duration;
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
//
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
t = (start_parking_time + 60)*60;
|
// Daily ticket
|
||||||
now = *localtime(&t);
|
//compute_duration_for_daily_ticket(tariff,start.toString(Qt::ISODate),3);
|
||||||
}
|
|
||||||
|
//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);
|
free_tariff(tariff);
|
||||||
}
|
}
|
||||||
|
@@ -7,6 +7,8 @@ QMAKE_CFLAGS = -c -pipe -std=c11 -g -O0 -Wall -Wno-attributes -W -DDEBUG -D_REEN
|
|||||||
QMAKE_CXX_FLAGS += -std=c11
|
QMAKE_CXX_FLAGS += -std=c11
|
||||||
|
|
||||||
INCLUDEPATH += $$_PRO_FILE_PWD_/../../MOBILISIS-Calculator/library/include/mobilisis/
|
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 += .
|
INCLUDEPATH += .
|
||||||
|
|
||||||
unix {
|
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