Compare commits

...

92 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
90eae152bf Merge branch 'moransBranch' 2023-05-12 14:48:19 +02:00
6d001f1501 Fix: QDateTime.addSecs() creates a new object 2023-05-12 14:28:30 +02:00
de32022b89 Merge branch 'moransBranch' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator into moransBranch 2023-05-12 14:10:57 +02:00
1e2f1589ac Fix: QDateTime::fromString() 2023-05-12 14:10:16 +02:00
2f8c8cab4c Another small fix on GetDurationFromCost() 2023-05-12 13:02:10 +02:00
ee1f7eca44 Merge branch 'master' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator 2023-05-12 12:43:49 +02:00
1069c5ad90 main: add test for GetDurationFromCost 2023-05-12 12:43:07 +02:00
46bffc250d Fix: includepath for main 2023-05-12 12:41:37 +02:00
2599513ef9 Minor fixes with +/- 1 minute offset. 2023-05-12 12:40:25 +02:00
ef66c1f0c0 Fixed GetDurationFromCost() 2023-05-12 11:55:35 +02:00
219d820104 GetCostFromDuration fixed 2023-05-12 09:20:46 +02:00
ed9166c226 Windows: set timezone as -3600. 2023-05-11 13:58:33 +02:00
818c67ad63 Windows debug: for init-Tariff, do not read zone_ne, but use the path given directly. 2023-05-11 13:57:31 +02:00
4a076e1dad Fix: string to QDateTime 2023-05-11 09:59:37 +02:00
62426e60d5 Fix: use toSecsSinceEpoch() 2023-05-11 09:58:54 +02:00
c28351b1bf Add debug messages 2023-05-11 09:58:15 +02:00
69c469c918 Merge branch 'master' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator 2023-05-10 16:27:34 +02:00
e7606b6568 Added overoaded versions for compute_price_for_parking_ticket() and
compute_duration_for_parking_ticket() using QDateTime parameters.
Added new error code WRONG_ISO_TIME_FORMAT.
2023-05-10 16:16:24 +02:00
fe0ebb409a Merge branch 'master' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator 2023-05-10 13:34:18 +02:00
3d88c8e67e Fix: setting calcState description 2023-05-10 13:33:28 +02:00
eebb6d926e Merge branch 'master' of https://git.mimbach49.de/GerhardHoffmann/MOBILISIS-Calculator 2023-05-10 13:11:47 +02:00
69c48e3acc Correction for argument-value of localtime_r()-function
(expects UTC-time instead of local time.)
2023-05-10 13:08:28 +02:00
5c0bbf1502 Fix: init_tariff(): cleanup on error 2023-05-09 13:05:02 +02:00
31df676b57 Merge branch 'master' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator 2023-05-09 13:04:23 +02:00
889fceaae0 Use strftime to get ISO time format for valid ticket end time. 2023-05-09 13:03:51 +02:00
5ec2a6d730 Merge branch 'master' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator 2023-05-09 11:53:31 +02:00
136e6687b8 remove wrong debug-out-put. Use ceil() instead on floor() to prevent rounding error.:w 2023-05-09 11:52:17 +02:00
3cc447ca87 Merge branch 'master' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator 2023-05-09 11:47:05 +02:00
b02115bf75 Prepare the use of ceil() instead of floor(). 2023-05-09 11:41:41 +02:00
ceb545b432 Implemented compute_duration_for_parking_ticket(). 2023-05-09 11:40:14 +02:00
01f2dc07ce Added INVALID_START_DATE.
Added compute_duration_for_parking_ticket().
2023-05-09 11:38:39 +02:00
c5960a031e init_tariff, compute_price_for_parking_ticket:
return instance of CalcState as info for errors or success status.
2023-05-08 12:34:01 +02:00
1c03745333 Add CalcState to be used as return type of tarif_init and compute_price_for_parking_ticket. 2023-05-08 12:32:44 +02:00
23 changed files with 5410 additions and 1043 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

@@ -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,113 @@ 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;
time_t start_parking_time, QString m_desc;
time_t end_parking_time,
struct price_t *price); explicit CalcState() : m_status(State::SUCCESS), m_desc("") {}
#ifdef __cplusplus
} // extern "C" explicit operator bool() const noexcept {
#endif return (m_status == State::SUCCESS);
}
explicit operator QString () const noexcept {
QString s;
switch (m_status) {
case State::SUCCESS:
s = "SUCCESS";
break;
case State::ERROR_PARSING_ZONE_NR:
s = "ERROR_PARSING_ZONE_NR";
break;
case State::ERROR_LOADING_TARIFF:
s = "ERROR_LOADING_TARIFF";
break;
case State::ERROR_PARSING_TARIFF:
s = "ERROR_PARSING_TARIFF";
break;
case State::NEGATIVE_PARING_TIME:
s = "NEGATIVE_PARKING_TIME";
break;
case State::ABOVE_MAX_PARKING_TIME:
s = "ABOVE_MAX_PARKING_TIME";
break;
case State::WRONG_PARAM_VALUES:
s = "WRONG_PARAM_VALUES";
break;
case State::BELOW_MIN_PARKING_TIME:
s = "BELOW_MIN_PARKING_TIME";
break;
case State::BELOW_MIN_PARKING_PRICE:
s = "BELOW_MIN_PARKING_PRICE";
break;
case State::OVERPAID:
s = "OVERPAID";
break;
case State::INVALID_START_DATE:
s = "INVALID_START_DATE";
break;
case State::WRONG_ISO_TIME_FORMAT:
s = "WRONG_ISO_TIME_FORMAT";
}
return s + ":" + m_desc;
}
CalcState &set(State s) { m_status = s; return *this; }
CalcState &setDesc(QString s) { m_desc = s; return *this; }
};
CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff,
char const *config_file);
void CALCULATE_LIBRARY_API free_tariff(parking_tariff_t *tariff);
int CALCULATE_LIBRARY_API get_zone_nr(int zone = -1);
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // deprecated
parking_tariff_t *tariff,
time_t start_parking_time,
time_t end_parking_time,
struct price_t *price);
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
int netto_parking_time,
QDateTime &end_parking_time, // return value
struct price_t *price); // return value
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( // deprecated
parking_tariff_t *tariff,
time_t start_parking_time,
double cost,
QString &duration);
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
double cost,
QDateTime &ticketEndTime); // return value
CalcState CALCULATE_LIBRARY_API compute_duration_for_daily_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
QDateTime &ticketEndTime);
//#ifdef __cplusplus
//} // extern "C"
//#endif
#endif // CALCULATE_PRICE_H #endif // CALCULATE_PRICE_H

View File

@@ -1,12 +1,21 @@
#pragma once #ifndef CALCULATOR_FUNCTIONS_H_INCLUDED
#include <iostream> #define CALCULATOR_FUNCTIONS_H_INCLUDED
#include "configuration.h"
#include <iostream>
#include <optional>
#include "configuration.h"
#include "payment_method.h"
#include "ticket.h"
#include "tariff_time_range.h"
#include <QDateTime>
using namespace std; using namespace std;
class Calculator class Calculator
{ {
public: public:
/// <summary> /// <summary>
/// Gets duration in seconds from cost /// Gets duration in seconds from cost
/// </summary> /// </summary>
@@ -23,7 +32,52 @@ 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, 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 "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,8 +28,8 @@ using namespace rapidjson;
class Configuration class Configuration
{ {
public: public:
ATBProject project;
ATBCurrency Currency; ATBCurrency Currency;
ATBDuration duration; ATBDuration duration;
multimap<int, ATBDuration> Duration; multimap<int, 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;
};

View File

@@ -2,12 +2,12 @@
enum DayOfWeek enum DayOfWeek
{ {
Saturday = 0x06, Monday = 0x01,
Sunday = 0x01, Tuesday = 0x02,
Monday = 0x02, Wednesday = 0x03,
Tuesday = 0x02, Thursday = 0x04,
Wednesday = 0x03, Friday = 0x05,
Thursday = 0x04, Saturday = 0x06,
Friday = 0x05, Sunday = 0x07,
UndefinedDay = 0xFF UndefinedDay = 0xFF
}; };

View File

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

View File

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

View File

@@ -1,17 +1,28 @@
// #pragma once
#ifndef TARIFF_TIME_RANGE_H_INCLUDED #ifndef TARIFF_TIME_RANGE_H_INCLUDED
#define TARIFF_TIME_RANGE_H_INCLUDED #define TARIFF_TIME_RANGE_H_INCLUDED
#include <ctime> #include <QTime>
/// <summary> /// <summary>
/// Time range definition /// Time range definition
/// </summary> /// </summary>
class TariffTimeRange { class TariffTimeRange {
QTime m_time_from;
QTime m_time_until;
public: public:
time_t time_from;
time_t time_to; TariffTimeRange()
TariffTimeRange() : time_from(0), time_to(0) {} : 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 #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 #pragma once
#include <cstring> #include <cstring>
#include <string.h> #include <string.h>
#include <ctime> #include <ctime>
#include <iostream> #include <iostream>
#include <cmath> #include <cmath>
#include "day_of_week.h" #include "day_of_week.h"
#include "configuration.h" #include "configuration.h"
#include "time_range.h" #include "time_range.h"
#include "payment_method.h"
using namespace std;
#include <QDateTime>
class Utilities {
public: using namespace std;
/// <summary> namespace Utilities {
/// Get day of week from current date (Zeller's Algorithm), starting day is Sunday /// <summary>
/// </summary> /// Get day of week from current date (Zeller's Algorithm), starting day is Sunday
/// <param name="date"></param> /// </summary>
/// <returns></returns> /// <param name="date"></param>
static DayOfWeek GetDayOfWeek(struct tm* tm); /// <returns></returns>
DayOfWeek GetDayOfWeek(struct tm* tm);
/// <summary>
/// Date and time parse helper function /// <summary>
/// </summary> /// Date and time parse helper function
/// <returns>Returns time (tm) structure</returns> /// </summary>
static struct tm DateTimeToStructTm(const char* dateTimeStr); /// <returns>Returns time (tm) structure</returns>
struct tm DateTimeToStructTm(const char* dateTimeStr);
/// <summary>
/// Date parse helper function /// <summary>
/// </summary> /// Date parse helper function
/// <returns>Returns time (tm) structure</returns> /// </summary>
static struct tm DateToStructTm(const char* dateStr); /// <returns>Returns time (tm) structure</returns>
struct tm DateToStructTm(const char* dateStr);
/// <summary>
/// Time parse helper function /// <summary>
/// </summary> /// Time parse helper function
/// <returns>Returns time (tm) structure</returns> /// </summary>
static struct tm TimeToStructTm(const char* timeStr, int year, int mon, int mday, int wday); /// <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>
/// </summary> /// Get current local time
/// <returns>Returns time_t structure</returns> /// </summary>
static time_t GetCurrentLocalTime(); /// <returns>Returns time_t structure</returns>
time_t GetCurrentLocalTime();
/// <summary>
/// Zeller's algorithm for determining day of week /// <summary>
/// </summary> /// Zeller's algorithm for determining day of week
static int ZellersAlgorithm(int day, int month, int year); /// </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>
/// </summary> /// Checks if current datetime is in range between start and end month of parking worktime
/// <param name="tariff_cfg"></param> /// </summary>
/// <param name="currentDateTime"></param> /// <param name="tariff_cfg"></param>
/// <returns></returns> /// <param name="currentDateTime"></param>
static bool IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime); /// <returns></returns>
bool IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime);
/// <summary> bool IsYearPeriodActive(Configuration const *cfg, QDateTime const &currentDateTime);
/// Check permissions
/// </summary> /// <summary>
static bool CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice); /// Check permissions
/// </summary>
/// <summary> bool CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice);
/// Calculates price per unit bool CheckSpecialDay(Configuration const *cfg,
/// </summary> QDateTime const &currentDateTimeS,
/// <param name="pra_price"></param> int* specialDayId, uint32_t *specialDayPrice);
/// <returns></returns>
static double CalculatePricePerUnit(double pra_price); /// <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 TEMPLATE = lib
TARGET = mobilisis_calc TARGET = mobilisis_calc
# CONFIG += staticlib #CONFIG += staticlib
QMAKE_CXXFLAGS += -std=c++17 -g -O0 QMAKE_CXXFLAGS += -std=c++17 -g -O0
@@ -25,7 +25,8 @@ SOURCES += \
src/utilities.cpp \ src/utilities.cpp \
src/configuration.cpp \ src/configuration.cpp \
src/tariff_log.cpp \ src/tariff_log.cpp \
src/calculate_price.cpp src/calculate_price.cpp \
src/ticket.cpp
HEADERS += \ HEADERS += \
include/mobilisis/calculator_functions.h \ include/mobilisis/calculator_functions.h \
@@ -65,7 +66,9 @@ 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 \
include/mobilisis/ticket.h
OTHER_FILES += src/main.cpp OTHER_FILES += src/main.cpp

View File

@@ -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)
QFile zone("/etc/zone_nr"); {
if (zone.exists()) { if(zone > -1) return zone;
QFileInfo finfo(zone); else
if (finfo.size() <= 4) { // decimal 000\n {
if (zone.open(QIODevice::ReadOnly | QIODevice::Text)) { QFile zone("/etc/zone_nr");
if (zone.exists()) {
QTextStream in(&zone); QFileInfo finfo(zone);
return in.readLine(100).toInt(); if (finfo.size() <= 4) { // decimal 000\n
if (zone.open(QIODevice::ReadOnly | QIODevice::Text)) {
QTextStream in(&zone);
return in.readLine(100).toInt();
}
} }
} }
return -1;
} }
return -1;
} }
bool CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file) { CalcState CALCULATE_LIBRARY_API init_tariff(parking_tariff_t **tariff, char const *config_file) {
*tariff = new Configuration(); *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,256 @@ 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 // DEBUG
qCritical() << " ... confFile exists"; qCritical() << " ... confFile is open";
if (fname.open(QIODevice::ReadOnly | QIODevice::Text)) { QString json = fname.readAll();
if (! (*tariff)->ParseJson(*tariff, json.toStdString().c_str())) {
// DEBUG delete *tariff;
qCritical() << " ... confFile is open"; *tariff = nullptr;
return calcState.set(CalcState::State::ERROR_PARSING_TARIFF);
QString json = fname.readAll();
return (*tariff)->ParseJson(*tariff, json.toStdString().c_str());
} }
} 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) {
delete tariff; if (tariff != nullptr) {
delete tariff;
}
} }
bool CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff, // this is currently not used
time_t start_parking_time, // in minutes CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
time_t end_parking_time, // in minutes parking_tariff_t *tariff,
struct price_t *price) { 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(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) {
QDate const d(1970, 1, 1); calcState.setDesc(QString("end=%1, start=%2")
QTime const t(0, 0, 0); .arg(end_parking_time, start_parking_time));
QDateTime start(d, t, Qt::UTC); return calcState.set(CalcState::State::NEGATIVE_PARING_TIME);
start = start.toLocalTime().addSecs(start_parking_time * 60); }
if (start.isValid()) { if (duration > maxMin) {
QString cs = start.toString(Qt::ISODate); calcState.setDesc(QString("duration=%1, maxMin=%2").arg(duration).arg(maxMin));
double cost = calculator.GetCostFromDuration( return calcState.set(CalcState::State::ABOVE_MAX_PARKING_TIME);
tariff, PaymentOption::Option1, }
cs.toLocal8Bit().constData(), if (duration < minMin) {
duration, false, true); calcState.setDesc(QString("duration=%1, minMin=%2").arg(duration).arg(minMin));
price->units = cost; return calcState.set(CalcState::State::BELOW_MIN_PARKING_TIME);
price->netto = cost; }
return true;
}
} else
if (duration == 0) { if (duration == 0) {
memset(price, 0x00, sizeof(*price)); memset(price, 0x00, sizeof(*price));
return true; return calcState.set(CalcState::State::SUCCESS);
} }
qCritical() << "ERROR start_parking_time (" << start_parking_time << ") <"
<< "end_parking_time (" << end_parking_time << ")"; QDate const d(1970, 1, 1);
return false; 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);
QTime const t(0, 0, 0);
QDateTime start(d, t, Qt::UTC);
start = start.toLocalTime().addSecs(start_parking_time * 60);
if (start.isValid()) {
QString cs = start.toString(Qt::ISODate);
// DEBUG
qCritical() << "compute_duration_for_parking_ticket(): ";
qCritical() << " start (cs): " << cs;
qCritical() << " price: " << price;
duration = calculator.GetDurationFromCost(tariff,
tariff->getPaymentOptions().pop_payment_method_id,
cs.toLocal8Bit().constData(),
price, false, true).c_str();
QDateTime d = QDateTime::fromString(duration, Qt::ISODate);
if (!d.isValid()) {
calcState.setDesc(QString("ticketEndTime=%1").arg(duration));
return calcState.set(CalcState::State::WRONG_ISO_TIME_FORMAT);
}
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}
return calcState.set(CalcState::State::SUCCESS);
}
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket(
parking_tariff_t *tariff,
QDateTime const &start_parking_time,
double price,
QDateTime &ticketEndTime)
{
CalcState calcState;
if (start_parking_time.isValid()) {
QString cs = start_parking_time.toString(Qt::ISODate);
QString endTime = calculator.GetDurationFromCost(
tariff,
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);
}

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("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; 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); //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_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();
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: 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();
else if (strcmp(inner_obj_name, "pun_label") == 0) Duration.pun_label = k->value.GetString(); 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)); 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;
}

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 "utilities.h"
#include "tariff_log.h" #include "tariff_log.h"
static int protection_counter = 0; #include <QDebug>
#include <algorithm>
/// <summary>
/// Helper function static int protection_counter = 0;
/// </summary>
/// <param name="pra_price"></param> /// <summary>
/// <returns></returns> /// Helper function
double Utilities::CalculatePricePerUnit(double pra_price) /// </summary>
{ /// <param name="pra_price"></param>
try /// <returns></returns>
{ double Utilities::CalculatePricePerUnit(double pra_price, double durationUnit)
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 try
//printf("Price per unit (min) is: %lf\n", price_per_unit); {
return price_per_unit; double price_per_unit = pra_price;
} double unit = durationUnit;
catch (...)
{ if(unit < 0 || unit > 65535 ) unit = 60.0f;
throw std::invalid_argument("An error has occurred in CalculatePricePerUnit() function\n"); 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;
}
/// <inheritdoc/> catch (...)
time_t Utilities::GetCurrentLocalTime() {
{ throw std::invalid_argument("An error has occurred in CalculatePricePerUnit() function\n");
try }
{ }
time_t curr_time = time(NULL);
tm tm_curr_time = {}; /// <inheritdoc/>
memset(&tm_curr_time, '\0', sizeof(struct tm)); time_t Utilities::GetCurrentLocalTime()
{
tm_curr_time = *localtime(&curr_time); try
curr_time = mktime(&tm_curr_time) - timezone; {
return curr_time; time_t curr_time = time(NULL);
} tm tm_curr_time = {};
catch (...) memset(&tm_curr_time, '\0', sizeof(struct tm));
{
throw std::invalid_argument("An error has occurred in GetCurrentLocalTime() function\n"); tm_curr_time = *localtime(&curr_time);
} curr_time = mktime(&tm_curr_time); //- timezone;
} return curr_time;
}
/// <inheritdoc/> catch (...)
int Utilities::ZellersAlgorithm(int day, int month, int year) {
{ throw std::invalid_argument("An error has occurred in GetCurrentLocalTime() function\n");
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 /// <inheritdoc/>
year--; //decrease year for month Jan and Feb int Utilities::ZellersAlgorithm(int day, int month, int year)
} {
int y = year % 100; //last two digit int mon;
int c = year / 100; //first two digit if (month > 2) mon = month; //for march to december month code is same as month
int w = (day + floor((13 * (mon + 1)) / 5) + y + floor(y / 4) + floor(c / 4) + (5 * c)); else {
w = ((w + 5) % 7) + 1; //w % 7; mon = (12 + month); //for Jan and Feb, month code will be 13 and 14
return w; year--; //decrease year for month Jan and Feb
} }
int y = year % 100; //last two digit
/// <inheritdoc/> int c = year / 100; //first two digit
struct tm Utilities::DateToStructTm(const char* dateStr) int w = (day + floor((13 * (mon + 1)) / 5) + y + floor(y / 4) + floor(c / 4) + (5 * c));
{ w = ((w + 5) % 7) + 1; //w % 7;
struct tm t = {}; return w;
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"); /// <inheritdoc/>
try struct tm Utilities::DateToStructTm(const char* dateStr)
{ {
int success = sscanf(dateStr, "%d-%d-%d", &t.tm_year, &t.tm_mon, &t.tm_mday); struct tm t = {};
if (success != 3) throw std::invalid_argument("DateToStructTm() has failed parsing datetime string\n"); memset(&t, '\0', sizeof(struct tm));
t.tm_year = t.tm_year - 1900; if (dateStr == nullptr || strlen(dateStr) <= 0) throw std::invalid_argument("DateToStructTm has failed parsing date string (null or empty)\n");
t.tm_mon = t.tm_mon - 1; try
t.tm_isdst = 0; {
return t; 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");
catch (...)
{ t.tm_year = t.tm_year - 1900;
throw std::invalid_argument("An error has occurred in DateToStructTm() function\n"); t.tm_mon = t.tm_mon - 1;
} t.tm_isdst = 0;
} return t;
}
/// <inheritdoc/> catch (...)
struct tm Utilities::TimeToStructTm(const char* timeStr, int year, int mon, int mday, int wday) {
{ throw std::invalid_argument("An error has occurred in DateToStructTm() function\n");
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"); /// <inheritdoc/>
try struct tm Utilities::TimeToStructTm(const char* timeStr, int year, int mon, int mday, int wday)
{ {
int success_time = sscanf(timeStr, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec); struct tm t = {};
if (success_time != 3) throw std::invalid_argument("TimeToStructTm() has failed parsing time string\n"); memset(&t, '\0', sizeof(struct tm));
struct tm tm_struct; if (timeStr == nullptr || strlen(timeStr) <= 0) throw std::invalid_argument("TimeToStructTm() has failed parsing time string (null or empty)\n");
t.tm_year = year; try
t.tm_mon = mon; {
t.tm_mday = mday; int success_time = sscanf(timeStr, "%d:%d:%d", &t.tm_hour, &t.tm_min, &t.tm_sec);
t.tm_wday = wday; if (success_time != 3) throw std::invalid_argument("TimeToStructTm() has failed parsing time string\n");
t.tm_isdst = 0;
return t; struct tm tm_struct;
} t.tm_year = year;
catch (...) t.tm_mon = mon;
{ t.tm_mday = mday;
throw std::invalid_argument("An error has occurred in TimeToStructTm() function\n"); t.tm_wday = wday;
} t.tm_isdst = 0;
} return t;
}
/// <inheritdoc/> catch (...)
struct tm Utilities::DateTimeToStructTm(const char* dateTimeStr) {
{ throw std::invalid_argument("An error has occurred in TimeToStructTm() function\n");
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)"); /// <inheritdoc/>
try struct tm Utilities::DateTimeToStructTm(const char* dateTimeStr)
{ {
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); struct tm t = {};
if (success != 6) throw std::invalid_argument("DateTimeToStructTm() has failed parsing datetime string\n"); memset(&t, '\0', sizeof(struct tm));
t.tm_year = t.tm_year - 1900; if (dateTimeStr == nullptr || strlen(dateTimeStr) <= 0) throw std::invalid_argument("DateTimeToStructTm() has failed parsing date string (null or empty)");
t.tm_mon = t.tm_mon - 1; try
t.tm_isdst = 0; {
return t; 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");
catch (...)
{ t.tm_year = t.tm_year - 1900;
throw std::invalid_argument("An error has occurred in DateTimeToStructTm() function\n"); t.tm_mon = t.tm_mon - 1;
} t.tm_isdst = 0;
} return t;
}
/// <inheritdoc/> catch (...)
DayOfWeek Utilities::GetDayOfWeek(struct tm* t) {
{ throw std::invalid_argument("An error has occurred in DateTimeToStructTm() function\n");
if (t == nullptr) throw std::invalid_argument("GetDayOfWeekFromDate() => parameter 't' is null\n"); }
try }
{
int d = t->tm_mday; /// <inheritdoc/>
int m = t->tm_mon + 1; DayOfWeek Utilities::GetDayOfWeek(struct tm* t)
int y = t->tm_year + 1900; {
if (t == nullptr) throw std::invalid_argument("GetDayOfWeekFromDate() => parameter 't' is null\n");
int wd = Utilities::ZellersAlgorithm(d, m, y); try
return static_cast<DayOfWeek>(wd); {
} int d = t->tm_mday;
catch (...) int m = t->tm_mon + 1;
{ int y = t->tm_year + 1900;
throw std::invalid_argument("An error has occurred in GetDayOfWeekFromDate() function\n");
} int wd = Utilities::ZellersAlgorithm(d, m, y);
} return static_cast<DayOfWeek>(wd);
}
/// <inheritdoc/> catch (...)
bool Utilities::IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime_tm) {
{ throw std::invalid_argument("An error has occurred in GetDayOfWeekFromDate() function\n");
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 /// <inheritdoc/>
{ bool Utilities::IsYearPeriodActive(Configuration* cfg, struct tm* currentDateTime_tm)
//// Parse input date {
int dayCurrent = currentDateTime_tm->tm_mday; if (cfg == nullptr) throw std::invalid_argument("IsYearPeriodActive() = > Configuration not set\n");
int monthCurrent = currentDateTime_tm->tm_mon + 1; if (currentDateTime_tm == nullptr) throw std::invalid_argument("IsYearPeriodActive() = > Current datetime not set\n");
// Current date time try
int cdt = (monthCurrent * 100) + dayCurrent; {
//// Parse input date
multimap<int, ATBPeriodYear>::iterator year_period_itr; int dayCurrent = currentDateTime_tm->tm_mday;
for (year_period_itr = cfg->YearPeriod.begin(); year_period_itr != cfg->YearPeriod.end(); ++year_period_itr) int monthCurrent = currentDateTime_tm->tm_mon + 1;
{
int dStart = year_period_itr->second.pye_start_day; // Current date time
int dEnd = year_period_itr->second.pye_end_day; int cdt = (monthCurrent * 100) + dayCurrent;
int mStart = year_period_itr->second.pye_start_month; multimap<int, ATBPeriodYear>::iterator year_period_itr;
int mEnd = year_period_itr->second.pye_end_month; for (year_period_itr = cfg->YearPeriod.begin(); year_period_itr != cfg->YearPeriod.end(); ++year_period_itr)
{
int start = (mStart * 100) + dStart; int dStart = year_period_itr->second.pye_start_day;
int end = (mEnd * 100) + dEnd; int dEnd = year_period_itr->second.pye_end_day;
if (cdt >= start && cdt <= end) int mStart = year_period_itr->second.pye_start_month;
{ int mEnd = year_period_itr->second.pye_end_month;
return true;
} int start = (mStart * 100) + dStart;
} int end = (mEnd * 100) + dEnd;
return false;
} if (cdt >= start && cdt <= end)
catch (...) {
{ return true;
cout << "IsYearPeriodActive() => An exception has occurred, ignoring check, returning true" << endl; }
return true; }
} return false;
} }
catch (...)
/// <inheritdoc/> {
bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice) cout << "IsYearPeriodActive() => An exception has occurred, ignoring check, returning true" << endl;
{ return true;
try }
{ }
*specialDayId = -1;
*specialDayPrice = 0.0f; bool Utilities::IsYearPeriodActive(Configuration const *cfg, QDateTime const &dt) {
if (std::none_of(cfg->YearPeriod.cbegin(),
if (cfg == nullptr) throw std::invalid_argument("CheckSpecialDay() => configuration is not set\n"); cfg->YearPeriod.cend(),
if (currentDateTimeStr == nullptr) throw std::invalid_argument("CheckSpecialDay() => invalid date/time string set\n"); [&dt](std::pair<int, ATBPeriodYear> const &year) {
QDate const d(2004, // 2004 is a leap year
dt.date().month(),
struct tm current_tm = Utilities::DateTimeToStructTm(currentDateTimeStr); dt.date().day());
//cout << "CheckSpecialDay() => Current: " << asctime(&current_tm) << endl; 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);
multimap<int, ATBSpecialDays>::iterator spec_days_itr; return (d >= s && d <= e);
})) {
for (spec_days_itr = cfg->SpecialDays.begin(); spec_days_itr != cfg->SpecialDays.end(); spec_days_itr++) qCritical() << "NO VALID YEAR PERIOD";
{ return false;
int repeat_every_year = 0; }
repeat_every_year = spec_days_itr->second.ped_year; return true;
}
string start = spec_days_itr->second.ped_date_start;
if (start.length() <= 0) continue; /// <inheritdoc/>
//cout << "CheckSpecialDay() => Start: " << start << endl; bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeStr, int* specialDayId, double* specialDayPrice)
{
string end = spec_days_itr->second.ped_date_end; try
if (end.length() <= 0) continue; {
//cout << "CheckSpecialDay() => End: " << end << endl; *specialDayId = -1;
*specialDayPrice = 0.0f;
struct tm start_tm = Utilities::DateToStructTm(start.c_str());
//cout << "CheckSpecialDay() => Start: " << asctime(&start_tm) << endl; 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 end_tm = Utilities::DateToStructTm(end.c_str());
//cout << "CheckSpecialDay() => End: " << asctime(&end_tm) << endl;
struct tm current_tm = Utilities::DateTimeToStructTm(currentDateTimeStr);
if (repeat_every_year <= 0) //cout << "CheckSpecialDay() => Current: " << asctime(&current_tm) << endl;
{
//cout << "CheckSpecialDay() => Repeat every year is: 0" << endl; multimap<int, ATBSpecialDays>::iterator spec_days_itr;
if ((current_tm.tm_year == start_tm.tm_year) && (current_tm.tm_year == end_tm.tm_year))
{ for (spec_days_itr = cfg->SpecialDays.begin(); spec_days_itr != cfg->SpecialDays.end(); spec_days_itr++)
if ((current_tm.tm_mon >= start_tm.tm_mon) && (current_tm.tm_mon <= end_tm.tm_mon)) {
{ int repeat_every_year = 0;
//cout << "CheckSpecialDay() => Month is in range between start and end" << endl; repeat_every_year = spec_days_itr->second.ped_year;
if ((current_tm.tm_mday >= start_tm.tm_mday) && (current_tm.tm_mday <= end_tm.tm_mday))
{ string start = spec_days_itr->second.ped_date_start;
LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY"); if (start.length() <= 0) continue;
*specialDayId = spec_days_itr->second.ped_id; //cout << "CheckSpecialDay() => Start: " << start << endl;
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
return true; 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());
else //cout << "CheckSpecialDay() => Start: " << asctime(&start_tm) << endl;
{
if ((current_tm.tm_mon >= start_tm.tm_mon) && (current_tm.tm_mon <= end_tm.tm_mon)) struct tm end_tm = Utilities::DateToStructTm(end.c_str());
{ //cout << "CheckSpecialDay() => End: " << asctime(&end_tm) << endl;
//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)) if (repeat_every_year <= 0)
{ {
LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY"); //cout << "CheckSpecialDay() => Repeat every year is: 0" << endl;
*specialDayId = spec_days_itr->second.ped_id; if ((current_tm.tm_year == start_tm.tm_year) && (current_tm.tm_year == end_tm.tm_year))
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price; {
return true; 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))
} {
//cout << "CheckSpecialDay() => NOT SPECIAL DAY" << endl; LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY");
return false; *specialDayId = spec_days_itr->second.ped_id;
} *specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
catch (...) return true;
{ }
throw std::invalid_argument("CheckSpecialDay() => An error has occurred\n"); }
return false; }
} }
} 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 #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,137 @@ 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("/tmp/tariff_korneuburg.json");
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;
if (isParsed)
{
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;
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, // Daily ticket
start_parking_time, //compute_duration_for_daily_ticket(tariff,start.toString(Qt::ISODate),3);
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; //Configuration* cfg, QString start_datetime, uint8_t payment_option, bool carry_over
now = *localtime(&t); // // 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);
} }
@@ -144,7 +193,7 @@ int main() {
struct tm now; // = Utilities::DateTimeToStructTm("2023-03-01T16:00:00"); struct tm now; // = Utilities::DateTimeToStructTm("2023-03-01T16:00:00");
memset(&now, 0, sizeof(now)); memset(&now, 0, sizeof(now));
char buffer[64]; char buffer[64];
//#if 0 //#if 0
// 3.Jan 2023 -> Tuesday // 3.Jan 2023 -> Tuesday
strptime("2023-01-03T14:00:00", "%Y-%m-%dT%H:%M:%S", &now); strptime("2023-01-03T14:00:00", "%Y-%m-%dT%H:%M:%S", &now);
for (int i = 0; i < 600; ++i) { for (int i = 0; i < 600; ++i) {
@@ -219,8 +268,8 @@ int main() {
int const duration = 120; int const duration = 120;
double cost = calculator.GetCostFromDuration(&cfg, double cost = calculator.GetCostFromDuration(&cfg,
PaymentOption::Option1, buffer, duration, PaymentOption::Option1, buffer, duration,
false, true); false, true);
switch (zone) { switch (zone) {
case 1: case 1:
@@ -258,8 +307,8 @@ int main() {
int const duration = 120; int const duration = 120;
double cost = calculator.GetCostFromDuration(&cfg, double cost = calculator.GetCostFromDuration(&cfg,
PaymentOption::Option1, buffer, duration, PaymentOption::Option1, buffer, duration,
false, true); false, true);
switch (zone) { switch (zone) {
case 1: case 1:
@@ -292,8 +341,8 @@ int main() {
double const compCost = (duration < 15) ? 0 : duration * ((zone == 1) ? 3.6666 : 8.0); double const compCost = (duration < 15) ? 0 : duration * ((zone == 1) ? 3.6666 : 8.0);
double cost = calculator.GetCostFromDuration(&cfg, double cost = calculator.GetCostFromDuration(&cfg,
PaymentOption::Option1, buffer, duration, PaymentOption::Option1, buffer, duration,
false, true); false, true);
if (fabs(cost - compCost) > 1.0) { // zone 1 has rounding errors if (fabs(cost - compCost) > 1.0) { // zone 1 has rounding errors
cout << "ERROR ===> [" << i << "] " << asctime(&now) cout << "ERROR ===> [" << i << "] " << asctime(&now)
<< " - Total cost is: " << cost << " FT (computed=" << " - Total cost is: " << cost << " FT (computed="

View File

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

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
}
]
}