Compare commits

...

59 Commits

Author SHA1 Message Date
7a5d797ae0 Start reimplementation of
private_GetCostFromDuration() in terms of ticket.
2023-11-27 16:21:28 +01:00
215667af61 Implement findWorkTimeRange() and indNextWorkTimeRange(). 2023-11-27 16:19:39 +01:00
2b6d116200 Implement GetCostFromDuration() in terms of private_GetCostFromDuration()
using a ticket as return value.
2023-11-27 16:18:06 +01:00
2d9ed3c1c8 testing ... 2023-11-27 16:16:50 +01:00
9ca45e613f Return a ticket from private_GetCostFromDuration().
Add helpers findWorkTimeRange() and findNextWorkTimeRange().
2023-11-27 16:15:18 +01:00
6a3d183129 Minor: overload constructor 2023-11-27 16:14:27 +01:00
684de4acd1 Reformat to Unix.
Add overload for IsYearPeriodActive().
Add several helpers.
2023-11-27 16:12:07 +01:00
e9047f995a Minor: format to Unix. 2023-11-27 16:09:38 +01:00
20cdb8b07f Add overload for IsYearPeriodActive().
Add helpers WeekDaysWorkTimeFrom(), WeekDaysWorkTimeUntil(), isCarryOverSet()
sCarryOverNotSet() and getPaymentMethodId().
2023-11-27 16:07:30 +01:00
b84970fd12 Add class Ticket for future use. 2023-11-26 19:56:38 +01:00
7ac033720e Started re-implementation of GetCostFromDuration() using
private_GetCostFromDuration().
2023-11-26 19:55:21 +01:00
c749de2bf9 Add private_GetCostFromDuration() and helpers
getMinimalParkingTime(), getMaximalParkingTime(), checkDurationMinutes().
2023-11-26 19:53:29 +01:00
c4cec1c04b Added overload for CheckSpecialDay().
Added helpers SpecialDaysWorkTimeFrom() and SpecialDaysWorkTimeUntil().
2023-11-26 19:51:37 +01:00
a53cb37291 Add explicit include guard. 2023-11-26 19:50:23 +01:00
b1a98a20c5 Add class ticket 2023-11-26 19:48:29 +01:00
d765997ca5 dos2unix. add TODO comment 2023-11-24 13:52:49 +01:00
d2664fdb95 add test json for neuhauser 2023-11-24 13:25:11 +01:00
36478e111e start changes for neuhauser 2023-11-24 13:23:59 +01:00
8f2609c4ae Fix: GetDurationFromCost for PaymentMethod::Steps 2023-11-23 11:14:21 +01:00
453ca266a5 Merge remote-tracking branch 'origin/schoenau_23112023' 2023-11-23 09:46:42 +01:00
0217bb8918 GetTimeStep() and GetPriceForTimeStep(): use getPaymentOptions(). 2023-11-23 09:41:40 +01:00
4b35b1ffb7 Implement GetDurationForPrice(). 2023-11-23 09:41:02 +01:00
80e228b498 GetCostFromDuration(): don't use condiftion PaymentMethod::Steps,
but the multimap YearPeriod, which must be empty.
2023-11-23 09:39:26 +01:00
574161ff76 Call getDurationForPrice() in GetDurationForCost(). 2023-11-23 09:38:34 +01:00
b80cd5e6ef Remove parameter paymentMethod.
Add GetDurationForPrice().
2023-11-23 09:36:50 +01:00
ccbf07a654 Use new getPaymentOptions interface 2023-11-23 08:42:35 +01:00
3a2e521345 Add interface to access 'PaymentOptions' 2023-11-22 16:27:41 +01:00
cd77e380ef Read project/version-info from tariff-config ...
... if available
2023-11-22 11:27:09 +01:00
aaa4348a9a Add ATBProject to configuration 2023-11-22 11:14:48 +01:00
17c4aac452 Add header file atb_project.h 2023-11-22 11:14:38 +01:00
68c438bfe0 Add header file for project-variables 2023-11-22 11:13:37 +01:00
509bc29d7e Fix: read tariff configuration file 2023-11-22 10:17:40 +01:00
f7e462188f Add methods for PaymentMethod::Steps 2023-11-22 09:53:07 +01:00
d15c9dad29 Update tariff04 (virtual dayticket) 2023-06-27 17:43:58 +02:00
cb8cd5dead Merge branch 'moransBranch' 2023-06-14 11:28:27 +02:00
9d64350e4f Merge branch 'moransBranch' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator into moransBranch 2023-06-14 11:27:43 +02:00
1a71edc274 max_time=300, unit_id=1 2023-06-13 13:32:16 +02:00
51d8beda2a max_time=300, unit_id=1 2023-06-13 13:32:12 +02:00
7bab9d6ba2 max_time=300, unit_id=1 2023-06-13 13:32:08 +02:00
8b4d64bd0c max_time=300, unit_id=1 2023-06-13 13:31:42 +02:00
eefdde4693 Removed section whith superfluous 'price_per_unit < 0' check.
Removed calc_price-caculation followed by shift of inputDate.
2023-06-13 12:12:23 +02:00
6157861d62 Monday starts with 1 2023-06-13 12:11:09 +02:00
23748966de Merge branch 'moransBranch' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator into moransBranch 2023-05-19 15:49:38 +02:00
7bd7f66666 Fixed pra_payment_unit_id 2023-05-17 10:08:02 +02:00
268d43cdea GetDailyTicketDuration: use QDateTime for timestamps 2023-05-16 16:43:45 +02:00
a453886f0a Merge branch 'master' into moransBranch 2023-05-16 15:35:47 +02:00
eef94a3fb3 Change interface: use QDateTime
- use QDateTime instead of char*-string
 - GetCostFromDuration: add end_datetime as a return value
2023-05-16 15:31:53 +02:00
88a0b6ebe2 Make main.c compile again 2023-05-16 11:10:49 +02:00
3097819c01 Update interface for 'compute_duration_for_daily_ticket() 2023-05-16 11:07:21 +02:00
acf799da7e Add explaining comments 2023-05-15 17:37:51 +02:00
3bf71f84d5 Merge branch 'moransBranch' 2023-05-15 17:33:51 +02:00
73f5eca656 Tariff config: add day ticket 2023-05-15 17:23:10 +02:00
b8753cc2ed Update tariff config for test 2023-05-15 17:06:57 +02:00
29986e0451 Merge branch 'moransBranch' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator into moransBranch 2023-05-15 16:58:48 +02:00
1146db743c Add explaining comments 2023-05-15 16:58:28 +02:00
c6302edec5 Format all json files 2023-05-15 16:57:45 +02:00
617eee39ed Daily ticket 2023-05-15 14:05:55 +02:00
6b3c1cbf0c Fix with min time in GetDurationFromCost 2023-05-14 17:19:24 +02:00
1142efaec2 Rounding minutes seems to be fixed ... 2023-05-14 16:15:37 +02:00
22 changed files with 5100 additions and 967 deletions

View 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

View File

@@ -109,7 +109,7 @@ CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff,
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(
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // deprecated
parking_tariff_t *tariff,
time_t start_parking_time,
time_t end_parking_time,
@@ -118,10 +118,11 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
QDateTime const &end_parking_time,
struct price_t *price);
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(
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( // deprecated
parking_tariff_t *tariff,
time_t start_parking_time,
double cost,
@@ -131,6 +132,11 @@ 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"

View File

@@ -1,12 +1,21 @@
#pragma once
#include <iostream>
#include "configuration.h"
#ifndef CALCULATOR_FUNCTIONS_H_INCLUDED
#define CALCULATOR_FUNCTIONS_H_INCLUDED
#include <iostream>
#include <optional>
#include "configuration.h"
#include "payment_method.h"
#include "ticket.h"
#include "tariff_time_range.h"
#include <QDateTime>
using namespace std;
class Calculator
{
public:
/// <summary>
/// Gets duration in seconds from cost
/// </summary>
@@ -23,7 +32,52 @@ 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, int 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;
PaymentMethod getPaymentMethodId(Configuration const *cfg);
int getMinimalParkingTime(Configuration const *cfg, PaymentMethod methodId);
int getMaximalParkingTime(Configuration const *cfg, PaymentMethod methodId);
Ticket private_GetCostFromDuration(Configuration const* cfg,
QDateTime const &start,
QDateTime &end,
int &durationMinutes,
bool nextDay = false,
bool prepaid = false,
bool overtime = false);
bool checkDurationMinutes(bool overTime,
int minParkingTime, int maxParkingTime,
int durationMinutes);
//
uint32_t GetPriceForTimeStep(Configuration *cfg, int timeStep) const;
uint32_t GetDurationForPrice(Configuration *cfg, int price) const;
int findWorkTimeRange(QDateTime const &dt,
QScopedArrayPointer<TariffTimeRange> const &worktime,
size_t size);
int findNextWorkTimeRange(QDateTime const &dt,
QScopedArrayPointer<TariffTimeRange> const &worktime,
size_t size);
};
#endif // CALCULATOR_FUNCTIONS_H_INCLUDED

View File

@@ -20,6 +20,7 @@
#include "member_type.h"
#include "period_year.h"
#include "payment_rate.h"
#include "atb_project.h"
using namespace std;
using namespace rapidjson;
@@ -27,8 +28,8 @@ using namespace rapidjson;
class Configuration
{
public:
ATBCurrency Currency;
ATBProject project;
ATBCurrency Currency;
ATBDuration duration;
multimap<int, ATBDuration> Duration;
@@ -48,6 +49,8 @@ public:
/// <returns>Returns operation status bool (OK | FAIL) </returns>
bool ParseJson(Configuration* cfg, const char* json);
ATBPaymentOption const & getPaymentOptions();
private:
/// <summary>
/// Identify type of JSON member
@@ -55,4 +58,6 @@ private:
/// <param name="member_name"></param>
/// <returns></returns>
MemberType IdentifyJsonMember(const char* member_name);
};
ATBPaymentOption currentPaymentOptions;
};

View File

@@ -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
};

View File

@@ -1,10 +1,12 @@
#pragma once
enum PaymentMethod
{
Undefined = 0xFF,
Progressive = 0x01,
Degressive = 0x02,
Linear = 0x03,
Steps = 0x04
};
#ifndef PAYMENT_METHOD_H_INCLUDED
#define PAYMENT_METHOD_H_INCLUDED
enum PaymentMethod {
Undefined = 0xFF,
Progressive = 0x01,
Degressive = 0x02,
Linear = 0x03,
Steps = 0x04
};
#endif // PAYMENT_METHOD_H_INCLUDED

View File

@@ -14,4 +14,5 @@ public:
double pop_max_time;
double pop_min_price;
int pop_carry_over;
};
int pop_daily_card_price;
};

View File

@@ -1,17 +1,28 @@
// #pragma once
#ifndef TARIFF_TIME_RANGE_H_INCLUDED
#define TARIFF_TIME_RANGE_H_INCLUDED
#include <ctime>
#include <QTime>
/// <summary>
/// Time range definition
/// </summary>
class TariffTimeRange {
QTime m_time_from;
QTime m_time_until;
public:
time_t time_from;
time_t time_to;
TariffTimeRange() : time_from(0), time_to(0) {}
TariffTimeRange()
: m_time_from(QTime())
, m_time_until(QTime()) {}
void setTimeRange(QTime const& from, QTime const &until) {
m_time_from = from;
m_time_until = until;
}
QTime const &getTimeFrom() const { return m_time_from; }
QTime const &getTimeUntil() const { return m_time_until; }
};
#endif // TARIFF_TIME_RANGE_H_INCLUDED

View File

@@ -0,0 +1,64 @@
#ifndef TICKET_H_INCLUDED
#define TICKET_H_INCLUDED
#include <tuple>
#include <vector>
#include <QDebug>
#include <QDebugStateSaver>
#include <QStringList>
#include <QDateTime>
#define NOT_INITIALIZED (0)
#define VALID (1)
#define INVALID_FROM_DATETIME (2)
#define INVALID_UNTIL_DATETIME (3)
#define STATUS_END (4)
class Ticket {
enum {CODE=0, CODE_STR=1, CODE_DESC=3};
public:
using Status = std::tuple<int, char const*, char const*>;
explicit Ticket();
explicit Ticket(QDateTime const &s, QDateTime const &e,
int durationMinutesNetto, int durationMinutesBrutto,
uint32_t price, Status status);
explicit operator bool() { return std::get<CODE>(m_status) == VALID; }
operator QString();
Status getStatus() const;
QDateTime getValidFrom() const;
QDateTime getValidUntil() const;
uint32_t getPrice() const;
Status setStatus(Status status);
void setValidFrom(QDateTime const &validFrom);
void setValidUntil(QDateTime const &validUnil);
void setPrice(uint32_t price);
bool isValid() { return operator bool(); }
static constexpr const Status s[STATUS_END] = {
{NOT_INITIALIZED , "NOT_INITIALIZED" , "Ticket not initialized" },
{VALID , "VALID" , "Ticket is valid" },
{INVALID_FROM_DATETIME , "INVALID_FROM_DATETIME" , "Ticket has invalid start datetime"},
{INVALID_UNTIL_DATETIME, "INVALID_UNTIL_DATETIME", "Ticket has invalid end datetime" }
};
private:
Status m_status;
QDateTime m_validFrom;
QDateTime m_validUntil;
int m_durationMinutesNetto;
int m_durationMinutesBrutto;
uint32_t m_price;
};
QDebug operator<<(QDebug debug, Ticket::Status const &status);
#endif // TICKET_H_INCLUDED

View File

@@ -1,72 +1,85 @@
#pragma once
#include <cstring>
#include <string.h>
#include <ctime>
#include <iostream>
#include <cmath>
#include "day_of_week.h"
#include "configuration.h"
#include "time_range.h"
using namespace std;
class Utilities {
public:
/// <summary>
/// Get day of week from current date (Zeller's Algorithm), starting day is Sunday
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
static DayOfWeek GetDayOfWeek(struct tm* tm);
/// <summary>
/// Date and time parse helper function
/// </summary>
/// <returns>Returns time (tm) structure</returns>
static struct tm DateTimeToStructTm(const char* dateTimeStr);
/// <summary>
/// Date parse helper function
/// </summary>
/// <returns>Returns time (tm) structure</returns>
static struct tm DateToStructTm(const char* dateStr);
/// <summary>
/// Time parse helper function
/// </summary>
/// <returns>Returns time (tm) structure</returns>
static struct tm TimeToStructTm(const char* timeStr, int year, int mon, int mday, int wday);
/// <summary>
/// Get current local time
/// </summary>
/// <returns>Returns time_t structure</returns>
static time_t GetCurrentLocalTime();
/// <summary>
/// Zeller's algorithm for determining day of week
/// </summary>
static int ZellersAlgorithm(int day, int month, int year);
/// <summary>
/// Checks if current datetime is in range between start and end month of parking worktime
/// </summary>
/// <param name="tariff_cfg"></param>
/// <param name="currentDateTime"></param>
/// <returns></returns>
static bool IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime);
/// <summary>
/// Check permissions
/// </summary>
static bool CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice);
/// <summary>
/// Calculates price per unit
/// </summary>
/// <param name="pra_price"></param>
/// <returns></returns>
static double CalculatePricePerUnit(double pra_price);
};
#pragma once
#include <cstring>
#include <string.h>
#include <ctime>
#include <iostream>
#include <cmath>
#include "day_of_week.h"
#include "configuration.h"
#include "time_range.h"
#include "payment_method.h"
#include <QDateTime>
using namespace std;
namespace Utilities {
/// <summary>
/// Get day of week from current date (Zeller's Algorithm), starting day is Sunday
/// </summary>
/// <param name="date"></param>
/// <returns></returns>
DayOfWeek GetDayOfWeek(struct tm* tm);
/// <summary>
/// Date and time parse helper function
/// </summary>
/// <returns>Returns time (tm) structure</returns>
struct tm DateTimeToStructTm(const char* dateTimeStr);
/// <summary>
/// Date parse helper function
/// </summary>
/// <returns>Returns time (tm) structure</returns>
struct tm DateToStructTm(const char* dateStr);
/// <summary>
/// Time parse helper function
/// </summary>
/// <returns>Returns time (tm) structure</returns>
struct tm TimeToStructTm(const char* timeStr, int year, int mon, int mday, int wday);
/// <summary>
/// Get current local time
/// </summary>
/// <returns>Returns time_t structure</returns>
time_t GetCurrentLocalTime();
/// <summary>
/// Zeller's algorithm for determining day of week
/// </summary>
int ZellersAlgorithm(int day, int month, int year);
/// <summary>
/// Checks if current datetime is in range between start and end month of parking worktime
/// </summary>
/// <param name="tariff_cfg"></param>
/// <param name="currentDateTime"></param>
/// <returns></returns>
bool IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime);
bool IsYearPeriodActive(Configuration const *cfg, QDateTime const &currentDateTime);
/// <summary>
/// Check permissions
/// </summary>
bool CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice);
bool CheckSpecialDay(Configuration const *cfg,
QDateTime const &currentDateTimeS,
int* specialDayId, uint32_t *specialDayPrice);
/// <summary>
/// Calculates price per unit
/// </summary>
/// <param name="pra_price"></param>
/// <returns></returns>
double CalculatePricePerUnit(double pra_price, double durationUnit = -1);
QTime SpecialDaysWorkTimeFrom(Configuration const *cfg, int specialDayId);
QTime SpecialDaysWorkTimeUntil(Configuration const *cfg, int specialDayId);
QTime WeekDaysWorkTimeFrom(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr);
QTime WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr);
bool isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId);
bool isCarryOverNotSet(Configuration const *cfg, PaymentMethod paymentMethodId);
PaymentMethod getPaymentMethodId(Configuration const *cfg);
}

View File

@@ -1,6 +1,6 @@
TEMPLATE = lib
TARGET = mobilisis_calc
# CONFIG += staticlib
#CONFIG += staticlib
QMAKE_CXXFLAGS += -std=c++17 -g -O0
@@ -25,7 +25,8 @@ SOURCES += \
src/utilities.cpp \
src/configuration.cpp \
src/tariff_log.cpp \
src/calculate_price.cpp
src/calculate_price.cpp \
src/ticket.cpp
HEADERS += \
include/mobilisis/calculator_functions.h \
@@ -65,7 +66,9 @@ HEADERS += \
include/mobilisis/tariff_period_year.h \
include/mobilisis/tariff_payment_rate.h \
include/mobilisis/tariff_log.h \
include/mobilisis/calculate_price.h
include/mobilisis/calculate_price.h \
include/mobilisis/atb_project.h \
include/mobilisis/ticket.h
OTHER_FILES += src/main.cpp

View File

@@ -14,7 +14,7 @@ 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);
@@ -26,7 +26,7 @@ int CALCULATE_LIBRARY_API get_zone_nr(int zone)
}
}
return -1;
}
}
}
CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file) {
@@ -65,7 +65,7 @@ CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char cons
QFile fname(confFile);
if (fname.exists() &&
fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
fname.open(QIODevice::ReadOnly | QIODevice::Text)) {
// DEBUG
qCritical() << " ... confFile is open";
@@ -92,14 +92,16 @@ void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff) {
}
}
// 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, // in minutes
struct price_t *price) {
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;
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));
@@ -109,7 +111,7 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
int const duration = end_parking_time - start_parking_time;
if (duration < 0) {
calcState.setDesc(QString("end=%1, start=%2")
.arg(end_parking_time, start_parking_time));
.arg(end_parking_time, start_parking_time));
return calcState.set(CalcState::State::NEGATIVE_PARING_TIME);
}
if (duration > maxMin) {
@@ -129,13 +131,15 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
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()) {
QString cs = start.toString(Qt::ISODate);
double cost = calculator.GetCostFromDuration(
tariff, PaymentOption::Option1,
cs.toLocal8Bit().constData(),
duration, false, true);
double minCost = tariff->PaymentOption.find(PaymentOption::Option1)->second.pop_min_price;
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);
@@ -150,51 +154,52 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
}
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
QDateTime const &end_parking_time,
struct price_t *price) {
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;
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
<< " end_parking_time: " << end_parking_time << endl
<< " netto_parking_time: " << netto_parking_time << endl
<< " minMin: " << minMin << endl
<< " maxMin: " << maxMin;
int const duration = (end_parking_time.toSecsSinceEpoch() -
start_parking_time.toSecsSinceEpoch()) / 60;
if (duration < 0) {
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)));
.arg(end_parking_time.toString(Qt::ISODate),
start_parking_time.toString(Qt::ISODate)));
return calcState.set(CalcState::State::NEGATIVE_PARING_TIME);
}
if (duration > maxMin) {
calcState.setDesc(QString("duration=%1, maxMin=%2").arg(duration, maxMin));
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 (duration < minMin) {
calcState.setDesc(QString("duration=%1, minMin=%2").arg(duration, minMin));
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 (duration == 0) {
if (netto_parking_time == 0) {
memset(price, 0x00, sizeof(*price));
return calcState.set(CalcState::State::SUCCESS);
}
if (start_parking_time.isValid()) {
QString cs = start_parking_time.toString(Qt::ISODate);
double cost = calculator.GetCostFromDuration(
tariff, PaymentOption::Option1,
cs.toLocal8Bit().constData(),
duration, false, true);
double minCost = tariff->PaymentOption.find(PaymentOption::Option1)->second.pop_min_price;
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);
@@ -213,10 +218,10 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff,
time_t start_parking_time,
double price,
QString &duration) {
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);
@@ -230,7 +235,8 @@ CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
qCritical() << " start (cs): " << cs;
qCritical() << " price: " << price;
duration = calculator.GetDurationFromCost(tariff, PaymentOption::Option1,
duration = calculator.GetDurationFromCost(tariff,
tariff->getPaymentOptions().pop_payment_method_id,
cs.toLocal8Bit().constData(),
price, false, true).c_str();
QDateTime d = QDateTime::fromString(duration, Qt::ISODate);
@@ -246,17 +252,19 @@ CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
double price,
QDateTime &ticketEndTime) {
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();
tariff,
tariff->getPaymentOptions().pop_payment_method_id,
cs.toLocal8Bit().constData(),
price, false, true).c_str();
ticketEndTime = QDateTime::fromString(endTime,Qt::ISODate);
// DEBUG
@@ -274,3 +282,30 @@ CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
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);
}

File diff suppressed because it is too large Load Diff

View File

@@ -59,8 +59,9 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|| !document.HasMember("PaymentRate")
|| !document.HasMember("Duration")
//|| !document.HasMember("WeekDays")
|| !document.HasMember("SpecialDaysWorktime")
|| !document.HasMember("SpecialDays"))
//|| !document.HasMember("SpecialDaysWorktime")
//|| !document.HasMember("SpecialDays")
)
{
printf("%s", "Error: not a valid configuration JSON\n");
return false;
@@ -87,13 +88,26 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
const char* mb_name = i->name.GetString();
if (mb_name == NULL) continue;
// if (!document[mb_name].IsArray()) {
std::string const _mb_name(mb_name);
if (_mb_name == "version" || _mb_name == "project" ||
_mb_name == "zone" || _mb_name == "info") {
if (document[mb_name].IsString()) {
QString const _mb_name(mb_name);
if (_mb_name.startsWith("Project", Qt::CaseInsensitive)) {
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;
}
//printf(" -%s\n", mb_name);
@@ -154,7 +168,9 @@ 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();
break;
else if (strcmp(inner_obj_name, "pop_daily_card_price") == 0) PaymentOption.pop_daily_card_price = k->value.GetInt();
this->currentPaymentOptions = PaymentOption;
break;
case MemberType::DurationType:
if (strcmp(inner_obj_name, "pun_id") == 0) Duration.pun_id = k->value.GetInt();
else if (strcmp(inner_obj_name, "pun_label") == 0) Duration.pun_label = k->value.GetString();
@@ -209,7 +225,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));
@@ -244,3 +260,10 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
return false;
}
}
const ATBPaymentOption & Configuration::getPaymentOptions()
{
return this->currentPaymentOptions;
}

88
library/src/ticket.cpp Normal file
View File

@@ -0,0 +1,88 @@
#include "ticket.h"
Ticket::Ticket()
: m_status(Ticket::s[NOT_INITIALIZED])
, m_validFrom()
, m_validUntil()
, m_durationMinutesNetto(0)
, m_durationMinutesBrutto(0)
, m_price() {
qDebug() << *this;
qDebug() << m_status;
}
Ticket::Ticket(QDateTime const &s, QDateTime const &e,
int durationMinutesNetto, int durationMinutesBrutto,
uint32_t price, Ticket::Status status)
: m_status(status)
, m_validFrom(s)
, m_validUntil(e)
, m_durationMinutesNetto(durationMinutesNetto)
, m_durationMinutesBrutto(durationMinutesBrutto)
, m_price(price) {
}
Ticket::Status Ticket::setStatus(Status status) {
Status old = m_status;
m_status = status;
return old;
}
Ticket::Status Ticket::getStatus() const {
return m_status;
}
void Ticket::setValidFrom(QDateTime const &validFrom) {
m_validFrom = validFrom;
}
void Ticket::setValidUntil(QDateTime const &validUntil) {
m_validUntil = validUntil;
}
QDateTime Ticket::getValidFrom() const {
if (std::get<CODE>(m_status) == VALID) {
return m_validFrom;
}
return QDateTime();
}
QDateTime Ticket::getValidUntil() const {
if (std::get<CODE>(m_status) == VALID) {
return m_validFrom;
}
return QDateTime();
}
uint32_t Ticket::getPrice() const {
return m_price;
}
void Ticket::setPrice(uint32_t price) {
m_price = price;
}
Ticket::operator QString() {
QStringList status;
status << QString("**********************");
status << QString("Status ............. : %1 (%2)")
.arg(std::get<0>(m_status))
.arg(std::get<2>(m_status));
status << QString("Valid from ......... : %1").arg(m_validFrom.toString(Qt::ISODate));
status << QString("Valid until ........ : %1").arg(m_validUntil.toString(Qt::ISODate));
status << QString("Duration (netto) ... : %1").arg(m_durationMinutesNetto);
status << QString("Duration (brutto)... : %1").arg(m_durationMinutesBrutto);
status << QString("Price .............. : %1").arg(m_price);
status << QString("**********************");
return status.join('\n');
}
QDebug operator<<(QDebug debug, Ticket::Status const &status) {
QDebugStateSaver saver(debug);
debug << "Ticket-Status: " << std::get<1>(status)
<< "(" << std::get<2>(status) << ")";
return debug;
}

View File

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

View File

@@ -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,
@@ -32,10 +31,12 @@ extern "C" char* strptime(const char* s,
#include <fstream>
#include <sstream>
#include "calculator_functions.h"
#include <calculate_price.h>
int main() {
std::ifstream input(QDir::homePath().append("/tariff01.json").toStdString());
std::ifstream input("/tmp/tariff_korneuburg.json");
std::stringstream sstr;
while(input >> sstr.rdbuf());
std::string json(sstr.str());
@@ -46,14 +47,15 @@ int main() {
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;
QDateTime start = QDateTime::fromString("2023-11-27T17:50:00",Qt::ISODate);
//QDateTime start = QDateTime::currentDateTime();
QDateTime end = start.addSecs(120);
uint32_t cost = calculator.GetCostFromDuration(&cfg, 3, start, end, 60);
qCritical() << "cost=" << cost;
qCritical() << "end=" << end;
}
return 0;
@@ -68,87 +70,93 @@ int main() {
if (init_tariff(&tariff, "/etc/psa_tariff/")) {
struct price_t price;
memset(&price, 0x00, sizeof(price));
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 + 610;
time_t end_parking_time = start_parking_time + 615;
if (compute_price_for_parking_ticket(tariff,
start_parking_time,
end_parking_time,
&price)) {
&price))
{
qDebug() << "GetCostFromDuration() => price=" << price.netto;
}
QString duration;
if(compute_duration_for_parking_ticket(tariff,start_parking_time,1525,duration))
if(compute_duration_for_parking_ticket(tariff,start_parking_time,3090,duration))
{
qDebug() << "GetDurationFromCost() => duration=" << duration;
}
// // tests
// struct tm now;
// memset(&now, 0, sizeof(now));
// Daily ticket
//compute_duration_for_daily_ticket(tariff,start.toString(Qt::ISODate),3);
// // 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
//Configuration* cfg, QString start_datetime, uint8_t payment_option, bool carry_over
// // tests
// struct tm now;
// memset(&now, 0, sizeof(now));
// 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;
// // 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:
// 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;
// }
// }
// 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;
// t = (start_parking_time + 60)*60;
// now = *localtime(&t);
// }
// 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);
}
@@ -185,7 +193,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) {
@@ -260,8 +268,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:
@@ -299,8 +307,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:
@@ -333,8 +341,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="

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

View File

@@ -0,0 +1,160 @@
{
"Project" : "Korneuburg",
"Version" : "1.0.0",
"Info" : "",
"Currency": [
{
"pcu_id": 2,
"pcu_sign": "€",
"pcu_major": "EUR",
"pcu_minor": "",
"pcu_active": true
}
],
"PaymentMethod": [
{
"pme_id": 1,
"pme_label": "progressive"
},
{
"pme_id": 2,
"pme_label": "degressive"
},
{
"pme_id": 3,
"pme_label": "linear"
},
{
"pme_id": 4,
"pme_label": "steps"
}
],
"PaymentOption": [
{
"pop_id": 1049,
"pop_label": "Zone 1",
"pop_payment_method_id": 3,
"pop_day_end_time": "00:00:00",
"pop_day_night_end_time": "00:00:00",
"pop_price_night": 0,
"pop_min_time": 30,
"pop_max_time": 180,
"pop_min_price": 60,
"pop_carry_over": 0,
"pop_daily_card_price": 0
}
],
"PaymentRate": [
{
"pra_payment_option_id": 1049,
"pra_payment_unit_id": 1,
"pra_price": 10
}
],
"Duration": [
{
"pun_id": 1,
"pun_label": "5 min",
"pun_duration": 5
},
{
"pun_id": 3,
"pun_label": "15 min",
"pun_duration": 15
},
{
"pun_id": 4,
"pun_label": "1 min",
"pun_duration": 1
}
],
"WeekDaysWorktime": [
{
"pwd_id": 621,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 1,
"pwd_time_from": "08:00:00",
"pwd_time_to": "12:00:00"
},
{
"pwd_id": 621,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 1,
"pwd_time_from": "14:00:00",
"pwd_time_to": "18:00:00"
},
{
"pwd_id": 622,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 2,
"pwd_time_from": "08:00:00",
"pwd_time_to": "12:00:00"
},
{
"pwd_id": 622,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 2,
"pwd_time_from": "14:00:00",
"pwd_time_to": "18:00:00"
},
{
"pwd_id": 623,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 3,
"pwd_time_from": "08:00:00",
"pwd_time_to": "12:00:00"
},
{
"pwd_id": 623,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 3,
"pwd_time_from": "14:00:00",
"pwd_time_to": "18:00:00"
},
{
"pwd_id": 624,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 4,
"pwd_time_from": "08:00:00",
"pwd_time_to": "12:00:00"
},
{
"pwd_id": 624,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 4,
"pwd_time_from": "14:00:00",
"pwd_time_to": "18:00:00"
},
{
"pwd_id": 625,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 5,
"pwd_time_from": "08:00:00",
"pwd_time_to": "12:00:00"
},
{
"pwd_id": 625,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 5,
"pwd_time_from": "14:00:00",
"pwd_time_to": "18:00:00"
},
{
"pwd_id": 626,
"pwd_period_week_day_id": 36,
"pwd_period_day_in_week_id": 6,
"pwd_time_from": "08:00:00",
"pwd_time_to": "12:00:00"
}
],
"PeriodYear": [
{
"pye_id": 8,
"pye_label": "Whole year",
"pye_start_month": 1,
"pye_start_day": 1,
"pye_end_month": 12,
"pye_end_day": 31
}
]
}