Compare commits

..

60 Commits

Author SHA1 Message Date
b70094abb5 Extend compute_product_price() for use of PERMIT_TYPE::DAY_TICKET.
First time used for Neuhauder-Pernegg-an-der-Mur.
2024-04-16 12:10:34 +02:00
aa15d1c126 Add default-parameters to compute_product_price():
start [in]: currentDateTime(): start date-time for daily-ticket-price computation.
startProduct, endProduct: real start- and end-date/time for daily-ticket.
Used first time for Neuhauser-Pernegg-an-der-Mur (747).
2024-04-16 12:07:18 +02:00
cd159f2bbd Add case for BusinessHours::NoRestriction_24_7: used for Neuhauder-Christoph-Reisen 2024-04-16 12:05:55 +02:00
475487c2ce Minor: add utility getProductPrice() 2024-04-16 12:03:42 +02:00
8ff5b8e2b5 Added test-cases for Neuhauser-Christoph-Reisen (746) and Neuhauser-Pernegg-an-der-Mur (747) 2024-04-16 12:01:36 +02:00
b0c4ad0e2e getCurrentPaymentOptionIndex(): start implementation.
getPaymentOptions(): use new parameter paymentOptionIndex.
2024-04-12 14:31:02 +02:00
7e3347b043 GetTimeSteps(): use new parameter paymentOptionIndex 2024-04-12 14:30:04 +02:00
4e7fa83507 get_minimal_parkingtime()
get_maximal_parkingtime()
get_minimal_parkingprice()
get_maximal_parkingprice():
use new parameter paymentOptionIndex.
2024-04-12 14:27:08 +02:00
ac76f194e1 Added new constants 2024-04-12 14:26:03 +02:00
fe485b7b39 pop_business_hours as uint64_t. 2024-04-12 14:24:32 +02:00
e210224340 getPaymentOptions(): added default-parameter 'paymentOptionsIndex'
Added getCurrentPaymentOptionIndex() and isHoliday().
2024-04-12 14:22:20 +02:00
afa62183fd ResetTimeSteps(), GetTimeSteps(), GetSteps():
add parameter paymentOptionIndex (default=0)
2024-04-12 14:20:05 +02:00
f241a87dc1 get_minimal_parking_price()
get_maximal_parking_price()
get_maximal_parking_time()
get_minimal_parking_time():
	adden perameter paymentOptionIndex
2024-04-12 14:17:43 +02:00
9b1cc49d34 Minor: remove some debug output 2024-04-12 14:16:18 +02:00
449e618417 Add test-cases 2024-04-12 14:14:40 +02:00
aba38d2614 compute_price_for_parking_ticket(): add handling for PaymentMethod::Steps. 2024-04-08 13:58:24 +02:00
57d6b85f52 get_maximal_parking_price(): add handling for PaymentMethod::Steps. 2024-04-08 13:57:40 +02:00
4f9c0422fc Start test case for Bad Neuenahr 2024-04-08 13:53:29 +02:00
a5b95d71b8 CalcState: Add setStatus()/getStatus() 2024-04-08 13:52:53 +02:00
fcbc8dcdc3 Merge branch 'neuhauser-kirchdorf' of https://git.mimbach49.de/GerhardHoffmann/MOBILISIS-Calculator into neuhauser-kirchdorf 2024-03-07 08:19:26 +01:00
ed99bae725 Use Calculator::getInstance() 2024-03-07 08:18:40 +01:00
627d14204d Use paymentRate.last() instead of aymentRate.at(0) so we can enter new entries
in tariff-files to provide the prices for an hour.
2024-03-07 08:17:32 +01:00
d8a4c4eaa7 Merge branch 'neuhauser-kirchdorf' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator into neuhauser-kirchdorf 2024-02-29 09:30:22 +01:00
4f45db4fde revised tests for Neuhauser/Linsinger Maschinenbau (744) 2024-02-28 12:06:43 +01:00
a744a1ebb3 compute_product_price(): add handling for FOOD_STAMP 2024-02-28 12:06:02 +01:00
df16bd7f9c GetDailyTicketPrice(): add case for FOOD_STAMP (not implemented) 2024-02-28 12:05:14 +01:00
b751ba339e Add permit type FOOD_STAMP 2024-02-28 12:03:13 +01:00
588a88455b CalcState: add toString() method 2024-02-28 11:31:28 +01:00
92bfdced6a Merge branch 'neuhauser-kirchdorf' of git.mimbach49.de:GerhardHoffmann/MOBILISIS-Calculator into neuhauser-kirchdorf 2024-02-28 10:04:09 +01:00
8bbec596c9 Check for 08:00 <= currentTime <= 20:00 removed:
assumption is prepaid.
2024-02-28 09:58:00 +01:00
87b14ee3f8 Added check for NEUHAUSER_NORDISCHES_AUSBILDUNGSZENTRUM:
08:00 <= currentTime <= 20:00.
2024-02-28 09:26:51 +01:00
3ad2c77467 Adapted tests for NEUHAUSER_NORDISCHES_AUSBILDUNGSZENTRUM 2024-02-28 09:26:05 +01:00
493d94aaa1 Add re-check 2024-02-27 17:30:15 +01:00
7831329b11 kirchdorf: getDurationFromCost(): to be tested 2024-02-27 17:11:00 +01:00
abbbd06f93 GetCostFromDuration(): re-implement cpmputation for paymentMethod==progressive
(e.g. neuhauser/kirchdorf (743))
2024-02-27 12:25:13 +01:00
ac6e45a913 test cases for neuhauser-kirchdorf 2024-02-27 12:23:52 +01:00
b741d2e312 test 2024-02-26 16:57:37 +01:00
6756aa5b88 Added zone3 - zone6 to szeged 2024-02-24 11:07:04 +01:00
7845ab8077 testing: started with zone 3 for szeged 2024-02-23 14:20:16 +01:00
cc222c298a Add test case for szeged: zone 2 2024-02-23 13:54:31 +01:00
eb645273cc Add declaration for get_maximal_parkingprice() 2024-02-23 13:17:03 +01:00
bd1bdf8a8c Implement compute_procuct_price() 2024-02-22 16:38:41 +01:00
6d18ce4caa GetDailyTicketPrice(): improve for projects which have not defined a daily ticket in their tariff-files. 2024-02-22 16:37:11 +01:00
e980d8c451 Implement
std::optional<QVector<ATBTariffProduct>> getTariffProductForAllKeys() const;
    std::optional<QVector<ATBTariffProduct>> getTariffProductForProductId(int id) const;
    std::optional<QVector<ATBTariffProduct>> getTariffProductForProductId(PermitType permitType) const;
2024-02-22 16:34:57 +01:00
afb0e20dd2 Implement parsing of "Product" and adding into TariffProduct. 2024-02-22 16:33:19 +01:00
39ab08a5b7 Add ProductType 2024-02-22 16:32:16 +01:00
c4c0e2fd77 Added TariffProduct including necessary functions to retrieve product infos from tariff-file 2024-02-22 16:31:51 +01:00
7a5487aa41 Add compute_product_price 2024-02-22 16:27:52 +01:00
a8c1caf611 Add tariff_product.h and tariff_permit_type.h 2024-02-22 16:26:09 +01:00
a22145002c Add test case for NAZ 2024-02-22 16:25:30 +01:00
7b7dd6d103 Add representations for PERMIT_TYPE and Product 2024-02-22 16:25:09 +01:00
1c801f1053 re-tested neuhauser-linisinger-maschinenbau 2024-02-22 09:44:35 +01:00
56fc95e33c GetDurationFromCost(): reverted, as there is a new default parameter (prepaid)
in compute_price_for_parming_ticket().
2024-02-22 09:43:04 +01:00
c0f81f174a compute_price_for_parking_ticket(): added parameter bool prepaid. Set to true as default. 2024-02-22 09:42:02 +01:00
6ba3963f25 compute_price_for_parking_ticket(): added default parameter prepaid=true.
(Needed e.g. for Neuhauser/Linsinger Maschinenbau (741)
2024-02-22 09:40:27 +01:00
1a350c0aeb GetDurationFromCost(): aded section if prepaid is not set.
E.g. for Linsinger Maschinenbau (Neuhauser, 741): here, the buying
of food stamps is obviously only possible at certain times.
2024-02-22 09:31:41 +01:00
15801be88e re-tested neuhauser-naz 2024-02-22 09:30:15 +01:00
20e146d3c9 re-tested neuhauser-naz 2024-02-22 09:10:26 +01:00
30768c6931 prepared test case for neuhauser-kirchdorf 2024-02-22 08:02:55 +01:00
7933c826e6 Synced GetDurationFromCost() with GetCostFromDuration() 2024-02-21 14:53:06 +01:00
14 changed files with 2579 additions and 421 deletions

View File

@@ -18,6 +18,8 @@
#define CALCULATE_LIBRARY_API
#endif
#include "tariff_permit_type.h"
class Configuration;
typedef Configuration parking_tariff_t;
@@ -39,17 +41,6 @@ struct CALCULATE_LIBRARY_API price_t {
}
};
enum class PERMIT_TYPE : quint8 {
SHORT_TERM_PARKING,
DAY_TICKET,
SZEGED_START,
SZEGED_STOP,
DAY_TICKET_ADULT,
DAY_TICKET_TEEN,
DAY_TICKET_CHILD,
INVALID
};
struct CALCULATE_LIBRARY_API CalcState {
enum class State : uint8_t {
SUCCESS,
@@ -93,6 +84,51 @@ struct CALCULATE_LIBRARY_API CalcState {
return (m_status == State::SUCCESS);
}
QString toString() {
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";
break;
case State::OUTSIDE_ALLOWED_PARKING_TIME:
s = "OUTSIDE_ALLOWED_PARKING_TIME";
}
return s + ":" + m_desc;
}
explicit operator QString () const noexcept {
QString s;
switch (m_status) {
@@ -139,6 +175,8 @@ struct CALCULATE_LIBRARY_API CalcState {
}
CalcState &set(State s) { m_status = s; return *this; }
CalcState &setStatus(State s) { return set(s); }
State getStatus() const { return m_status; }
CalcState &setDesc(QString s) { m_desc = s; return *this; }
void setAllowedTimeRange(QTime const &from, QTime const &until) {
@@ -158,10 +196,28 @@ int CALCULATE_LIBRARY_API get_zone_nr(int zone = -1);
int CALCULATE_LIBRARY_API compute_next_timestep(parking_tariff_t *tariff, int currentTimeMinutes, int UpDown);
QList<int> CALCULATE_LIBRARY_API get_time_steps(Configuration *cfg);
int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration *cfg, PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING);
int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration *cfg, PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING);
int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg, PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING);
int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg, PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING);
int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
int paymentOptionIndex=0);
int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
int paymentOptionIndex=0);
int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
int paymentOptionIndex=0);
int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
int paymentOptionIndex=0);
int CALCULATE_LIBRARY_API compute_product_price(Configuration const *cfg,
PERMIT_TYPE permitType = PERMIT_TYPE::SHORT_TERM_PARKING,
QDateTime const &start = QDateTime::currentDateTime(),
QDateTime *productStart = nullptr,
QDateTime *productEnd = nullptr);
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // deprecated
parking_tariff_t *tariff,
@@ -174,7 +230,8 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
QDateTime &start_parking_time,
int netto_parking_time,
QDateTime &end_parking_time, // return value
struct price_t *price); // return value
struct price_t *price, // return value
bool prepaid = true);
CalcState CALCULATE_LIBRARY_API compute_duration_for_parking_ticket( // deprecated
parking_tariff_t *tariff,

View File

@@ -14,7 +14,7 @@
using namespace std;
class Calculator {
mutable QList<int> m_timeSteps;
mutable QVector<QList<int>> m_timeSteps;
mutable QList<int> m_priceSteps;
protected:
@@ -29,8 +29,17 @@ public:
return c;
}
void ResetTimeSteps() { m_timeSteps.clear(); }
QList<int> timeSteps() const { return m_timeSteps; }
void ResetTimeSteps(int paymentOptionIndex) {
if (m_timeSteps.size() > 0) {
m_timeSteps[paymentOptionIndex].clear();
}
}
QList<int> timeSteps(int paymentOptionIndex=0) const {
if (m_timeSteps.size() > 0) {
return m_timeSteps[paymentOptionIndex];
}
return QList<int>();
}
void ResetPriceSteps() { m_priceSteps.clear(); }
QList<int> priceSteps() const { return m_priceSteps; }
@@ -66,8 +75,8 @@ public:
// helper function to find time steps for a tariff with PaymentMethod::Steps
// (e.g. Schoenau/Koenigsee)
//
QList<int> GetTimeSteps(Configuration *cfg) const;
QList<int> GetSteps(Configuration *cfg) const { return GetTimeSteps(cfg); }
QList<int> GetTimeSteps(Configuration *cfg, int paymentOptionIndex=0) const;
QList<int> GetSteps(Configuration *cfg, int paymentOptionIndex=0) const { return GetTimeSteps(cfg, paymentOptionIndex); }
QList<int> GetPriceSteps(Configuration *cfg) const;

View File

@@ -24,6 +24,7 @@
#include "tariff_daily_ticket.h"
#include "time_range_header.h"
#include "tariff_timestep_config.h"
#include "tariff_product.h"
#include <QVector>
#include <optional>
@@ -53,6 +54,7 @@ public:
multimap<int, ATBTimeStepConfig> TimeStepConfig;
multimap<int, ATBTimeBase> TimeBase;
multimap<int, ATBCustomer> Customer;
multimap<int, ATBTariffProduct> TariffProduct;
/// <summary>
/// Parse JSON string
@@ -61,14 +63,19 @@ public:
/// <returns>Returns operation status bool (OK | FAIL) </returns>
bool ParseJson(Configuration* cfg, const char* json);
ATBPaymentOption &getPaymentOptions();
ATBPaymentOption const &getPaymentOptions() const;
ATBPaymentOption &getPaymentOptions(int paymentOptionsIndex=0);
ATBPaymentOption const &getPaymentOptions(int paymentOptionsIndex=0) const;
QVector<ATBPaymentOption> &getAllPaymentOptions();
QVector<ATBPaymentOption> const &getAllPaymentOptions() const;
int getCurrentPaymentOptionIndex(QDateTime const &dt) const;
bool isHoliday(QDateTime const &dt) const;
std::optional<QVector<ATBPaymentRate>> getPaymentRateForAllKeys() const;
std::optional<QVector<ATBPaymentRate>> getPaymentRateForKey(int key) const;
std::optional<QVector<ATBDailyTicket>> getDailyTicketsForAllKeys() const;
std::optional<QVector<ATBDailyTicket>> getDailyTicketsForKey(int key) const;
std::optional<QVector<ATBTariffProduct>> getTariffProductForAllKeys() const;
std::optional<QVector<ATBTariffProduct>> getTariffProductForProductId(int id) const;
std::optional<QVector<ATBTariffProduct>> getTariffProductForProductId(PermitType permitType) const;
std::optional<ATBCustomer> getCustomerForType(ATBCustomer::CustomerType customerType);
std::optional<ATBWeekDaysWorktime> getWeekDayWorkTime(QTime const &time, Qt::DayOfWeek dayOfWeek);

View File

@@ -18,7 +18,8 @@ enum MemberType
CustomerType = 0x0B,
TimeBaseType = 0x0C,
TimeRangeType = 0x0D,
TimeStepConfigType = 0x0E
TimeStepConfigType = 0x0E,
ProductType = 0x0F
};
#endif // MEMBER_TYPE_H_INCLUDED

View File

@@ -1,5 +1,9 @@
#pragma once
#ifndef PAYMENT_OPT_H_INCLUDED
#define PAYMENT_OPT_H_INCLUDED
#include <string>
#include <cinttypes>
class ATBPaymentOption
{
@@ -37,6 +41,8 @@ public:
int pop_carry_over;
int pop_carry_over_time_range_id;
int pop_daily_card_price;
int pop_business_hours;
uint64_t pop_business_hours;
int pop_time_step_config;
};
#endif // PAYMENT_OPT_H_INCLUDED

View File

@@ -4,19 +4,58 @@
/// <summary>
/// Business hours (byte represents payment option id)
/// </summary>
enum BusinessHours
///
#define _MON_ (1ULL << 8)
#define _TUE_ (1ULL << 9)
#define _WED_ (1ULL << 10)
#define _THU_ (1ULL << 11)
#define _FRI_ (1ULL << 12)
#define _SAT_ (1ULL << 13)
#define _SUN_ (1ULL << 14)
#define _WEEK_DAYS_ ((_MON_|_TUE_|_WED_|_THU_|_FRI_))
#define _WORKING_DAYS_ ((_MON_|_TUE_|_WED_|_THU_|_FRI_|_SAT_))
#define _ALL_DAYS_ ((_MON_|_TUE_|_WED_|_THU_|_FRI_|_SAT_|_SUN_))
#define _OFFICIAL_HOLIDAY_ (1ULL << 15)
#define _ONLY_WEEKEND ((_SAT_|_SUN_))
#define _ONLY_OPEN_FOR_BUSINESS_DAYS (1ULL << 16) /* verkaufsoffen */
#define _NOT_DEFINED (~0ULL)
enum BusinessHours : std::uint64_t
{
NoRestriction_24_7 = 0,
OnlyWorkingDays = 1, // [Monday-Friday]
OnlyWeekDays = 2, // [Monday-Saturday]
OnlyWeekEnd = 4, // [Saturday+Sunday]
OnlyOfficialHolidays = 8,
OnlySundaysAndHolidays = 12, // [Sun+Holiday]
OnlySpecialDays = 16,
OnlySchoolHolidays = 32,
SpecialAndSchoolHolidays = 48,
OnlyOpenForBusinessDays = 64, // verkaufsoffen
AllDaysWithRestrictedHours = 128, // every day, restricted to some time range
NoBusinessHoursDefined = 255
NoBusinessHoursDefined = 255,
// new 12.04.2024
NO_RESTRICTION_24_7 = 0,
MON = _MON_,
TUE = _TUE_,
WED = _WED_,
THU = _THU_,
FRI = _FRI_,
SAT = _SAT_,
SUN = _SUN_,
WEEK_DAYS = _WEEK_DAYS_,
WORKING_DAYS = _WORKING_DAYS_,
ALL_DAYS = _ALL_DAYS_,
OFFICIAL_HOLIDAY = _OFFICIAL_HOLIDAY_,
ONLY_WEEKEND = _ONLY_WEEKEND,
ONLY_OPEN_FOR_BUSINESS_DAYS = _ONLY_OPEN_FOR_BUSINESS_DAYS,
NOT_DEFINED = _NOT_DEFINED
};
struct BusinessHours_struct {
BusinessHours bh;
};
#endif // TARIFF_BUSINESS_HOURS_H_INCLUDED

View File

@@ -0,0 +1,133 @@
#ifndef TARIFF_PERMIT_TYPE_H_INCLUDED
#define TARIFF_PERMIT_TYPE_H_INCLUDED
#include <QString>
enum class PERMIT_TYPE : quint8 {
SHORT_TERM_PARKING,
DAY_TICKET,
SZEGED_START,
SZEGED_STOP,
DAY_TICKET_ADULT,
DAY_TICKET_TEEN,
DAY_TICKET_CHILD,
FOOD_STAMP,
INVALID
};
struct PermitType {
PERMIT_TYPE m_permitType;
PermitType() { m_permitType = PERMIT_TYPE::INVALID; }
PermitType(int permitType) {
switch(permitType) {
case 0:
m_permitType = PERMIT_TYPE::SHORT_TERM_PARKING;
break;
case 1:
m_permitType = PERMIT_TYPE::DAY_TICKET;
break;
case 2:
m_permitType = PERMIT_TYPE::SZEGED_START;
break;
case 3:
m_permitType = PERMIT_TYPE::SZEGED_STOP;
break;
case 4:
m_permitType = PERMIT_TYPE::DAY_TICKET_ADULT;
break;
case 5:
m_permitType = PERMIT_TYPE::DAY_TICKET_TEEN;
break;
case 6:
m_permitType = PERMIT_TYPE::DAY_TICKET_CHILD;
break;
case 7:
m_permitType = PERMIT_TYPE::FOOD_STAMP;
break;
default:
m_permitType = PERMIT_TYPE::INVALID;
}
}
PermitType(PERMIT_TYPE permitType) : m_permitType(permitType) {}
void set(PERMIT_TYPE p) { m_permitType = p; }
PERMIT_TYPE get() const { return m_permitType; }
operator PERMIT_TYPE() const { return m_permitType; }
operator int () const {
switch(m_permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING:
return 0;
case PERMIT_TYPE::DAY_TICKET:
return 1;
case PERMIT_TYPE::SZEGED_START:
return 2;
case PERMIT_TYPE::SZEGED_STOP:
return 3;
case PERMIT_TYPE::DAY_TICKET_ADULT:
return 4;
case PERMIT_TYPE::DAY_TICKET_CHILD:
return 5;
case PERMIT_TYPE::DAY_TICKET_TEEN:
return 6;
case PERMIT_TYPE::FOOD_STAMP:
return 7;
default:
break;
}
return 7;
}
operator QString () {
switch(m_permitType) {
case PERMIT_TYPE::DAY_TICKET:
return QString("DAY_TICKET");
case PERMIT_TYPE::DAY_TICKET_ADULT:
return QString("DAY_TICKET_ADULT");
case PERMIT_TYPE::DAY_TICKET_CHILD:
return QString("DAY_TICKET_CHILD");
case PERMIT_TYPE::DAY_TICKET_TEEN:
return QString("DAY_TICKET_TEEN");
case PERMIT_TYPE::SHORT_TERM_PARKING:
return QString("SHORT_TERM_PARKING");
case PERMIT_TYPE::SZEGED_START:
return QString("SZEGED_START");
case PERMIT_TYPE::SZEGED_STOP:
return QString("SZEGED_STOP");
case PERMIT_TYPE::FOOD_STAMP:
return QString("FOOD_STAMP");
default:
break;
}
return QString("INVALID");
}
operator QString () const {
switch(m_permitType) {
case PERMIT_TYPE::DAY_TICKET:
return QString("DAY_TICKET");
case PERMIT_TYPE::DAY_TICKET_ADULT:
return QString("DAY_TICKET_ADULT");
case PERMIT_TYPE::DAY_TICKET_CHILD:
return QString("DAY_TICKET_CHILD");
case PERMIT_TYPE::DAY_TICKET_TEEN:
return QString("DAY_TICKET_TEEN");
case PERMIT_TYPE::SHORT_TERM_PARKING:
return QString("SHORT_TERM_PARKING");
case PERMIT_TYPE::SZEGED_START:
return QString("SZEGED_START");
case PERMIT_TYPE::SZEGED_STOP:
return QString("SZEGED_STOP");
case PERMIT_TYPE::FOOD_STAMP:
return QString("FOOD_STAMP");
default:
break;
}
return QString("INVALID");
}
};
#endif // TARIFF_PERMIT_TYPE_H_INCLUDED

View File

@@ -0,0 +1,66 @@
#ifndef TARIFF_PRODUCT_H_INCLUDED
#define TARIFF_PRODUCT_H_INCLUDED
#include <QString>
#include <QDateTime>
#include <QDebug>
#include <QDebugStateSaver>
#include "tariff_permit_type.h"
struct ATBTariffProduct {
PermitType m_tariff_product_id;
uint32_t m_tariff_product_price;
QString m_tariff_product_name;
QTime m_tariff_product_start;
QTime m_tariff_product_end;
int m_tariff_product_from_in_minutes_from_start;
int m_tariff_product_to_in_minutes_from_start;
explicit ATBTariffProduct() = default;
QTime const &getTimeStart() const { return m_tariff_product_start; }
QTime const &getTimeEnd() const { return m_tariff_product_end; }
bool computeQTimeStart(QTime const &t) {
if (m_tariff_product_from_in_minutes_from_start != -1) {
m_tariff_product_start = t.addSecs(m_tariff_product_from_in_minutes_from_start * 60);
return m_tariff_product_start.isValid();
}
return false;
}
bool computeQTimeEnd(QTime const &t) {
if (m_tariff_product_to_in_minutes_from_start != -1) {
m_tariff_product_end = t.addSecs(m_tariff_product_from_in_minutes_from_start * 60);
return m_tariff_product_end.isValid();
}
return false;
}
bool computeQTimes(QTime const &t) {
if (!t.isNull() && t.isValid()) {
return computeQTimeStart(t) && computeQTimeEnd(t);
}
return false;
}
uint32_t getProductPrice() const { return m_tariff_product_price; }
friend QDebug operator<<(QDebug debug, ATBTariffProduct const &product) {
QDebugStateSaver saver(debug);
debug.nospace()
<< " m_tariff_product_id: " << QString(product.m_tariff_product_id) << "\n"
<< " m_tariff_product_name: " << product.m_tariff_product_name << "\n"
<< " m_tariff_product_price: " << product.m_tariff_product_price << "\n"
<< " m_tariff_product_start: " << product.m_tariff_product_start << "\n"
<< " m_tariff_product_end: " << product.m_tariff_product_end << "\n"
<< "m_tariff_product_from_in_minutes_from_start: " << product.m_tariff_product_from_in_minutes_from_start << "\n"
<< " m_tariff_product_to_in_minutes_from_start: " << product.m_tariff_product_to_in_minutes_from_start << "\n";
return debug;
}
};
#endif // TARIFF_PRODUCT_H_INCLUDED

View File

@@ -77,7 +77,9 @@ HEADERS += \
include/mobilisis/tariff_daily_ticket.h \
include/mobilisis/tariff_customer.h \
include/mobilisis/tariff_timebase.h \
include/mobilisis/tariff_timestep_config.h
include/mobilisis/tariff_timestep_config.h \
include/mobilisis/tariff_product.h \
include/mobilisis/tariff_permit_type.h
OTHER_FILES += src/main.cpp \
../tariffs/tariff_korneuburg.json \

View File

@@ -14,12 +14,14 @@ QList<int> CALCULATE_LIBRARY_API get_time_steps(Configuration *cfg) {
return Calculator::GetInstance().GetTimeSteps(cfg);
}
int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration *cfg, PERMIT_TYPE permitType) {
int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int minTime = 0;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
minTime = cfg->getPaymentOptions().pop_min_time;
minTime = cfg->getPaymentOptions(paymentOptionIndex).pop_min_time;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
@@ -30,20 +32,22 @@ int CALCULATE_LIBRARY_API get_minimal_parkingtime(Configuration *cfg, PERMIT_TYP
default:
// for each new sell-procedure, recomute the timesteps. implicitly, set
// the minimal parking time.
Calculator::GetInstance().ResetTimeSteps();
Calculator::GetInstance().GetTimeSteps(cfg);
minTime = qRound(cfg->getPaymentOptions().pop_min_time);
Calculator::GetInstance().ResetTimeSteps(paymentOptionIndex);
Calculator::GetInstance().GetTimeSteps(cfg, paymentOptionIndex);
minTime = qRound(cfg->getPaymentOptions(paymentOptionIndex).pop_min_time);
}
return minTime;
}
int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration *cfg, PERMIT_TYPE permitType) {
int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int maxTime = 0;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
maxTime = cfg->getPaymentOptions().pop_max_time;
maxTime = cfg->getPaymentOptions(paymentOptionIndex).pop_max_time;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
@@ -57,12 +61,14 @@ int CALCULATE_LIBRARY_API get_maximal_parkingtime(Configuration *cfg, PERMIT_TYP
return maxTime;
}
int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg, PERMIT_TYPE permitType) {
int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int minPrice = -1;
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
minPrice = cfg->getPaymentOptions().pop_min_price;
minPrice = cfg->getPaymentOptions(paymentOptionIndex).pop_min_price;
} break;
case PERMIT_TYPE::DAY_TICKET_ADULT: {
} break;
@@ -76,22 +82,105 @@ int CALCULATE_LIBRARY_API get_minimal_parkingprice(Configuration *cfg, PERMIT_TY
return minPrice;
}
int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg, PERMIT_TYPE permitType) {
int CALCULATE_LIBRARY_API compute_product_price(Configuration const *cfg,
PERMIT_TYPE permitType,
QDateTime const &start,
QDateTime *productStart,
QDateTime *productEnd) {
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
} break;
case PERMIT_TYPE::DAY_TICKET_CHILD:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET_TEEN:
// [[fallthrough]];
case PERMIT_TYPE::FOOD_STAMP:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET_ADULT: {
std::optional<QVector<ATBTariffProduct>> products = cfg->getTariffProductForProductId(permitType);
if (products) {
QVector<ATBTariffProduct> product = products.value();
if (product.size() > 0) {
ATBTariffProduct const &p = product[0];
return p.m_tariff_product_price;
#if 0
// in case we do not have prepaid-option
QTime const &currentTime = QDateTime::currentDateTime().time();
if (p.m_tariff_product_start <= currentTime && currentTime <= p.m_tariff_product_end) {
return p.m_tariff_product_price;
} else {
qCritical() << "(" << __func__ << ":" << __LINE__ << ")"
<< "ERROR currentTime"
<< currentTime.toString(Qt::ISODate)
<< "INVALID ("
<< p.m_tariff_product_start.toString(Qt::ISODate)
<< p.m_tariff_product_end.toString(Qt::ISODate) << ")";
}
#endif
}
}
} break;
case PERMIT_TYPE::INVALID:
// [[fallthrough]];
case PERMIT_TYPE::DAY_TICKET: {
std::optional<QVector<ATBTariffProduct>> products = cfg->getTariffProductForProductId(permitType);
if (products) {
QVector<ATBTariffProduct> product = products.value();
int product_price = 0;
if (productStart && productEnd) {
*productStart = start;
*productEnd = start;
if (product.size() > 0) {
productStart->setTime(product[0].getTimeStart());
productEnd->setTime(product[0].getTimeEnd());
}
}
for (QVector<ATBTariffProduct>::size_type i=0; i<product.size(); ++i) {
ATBTariffProduct const &p = product[i];
QTime const &startTime = p.getTimeStart();
QTime const &endTime = p.getTimeEnd();
if (start.time() >= startTime && start.time() < endTime) {
product_price = p.getProductPrice();
if (productStart && productEnd) {
productStart->setTime(startTime);
productEnd->setTime(endTime);
}
}
}
return product_price;
}
} break;
default:
break;
}
return 0;
}
int CALCULATE_LIBRARY_API get_maximal_parkingprice(Configuration *cfg,
PERMIT_TYPE permitType,
int paymentOptionIndex) {
int maxPrice = -1;
static const PaymentMethod paymentMethodId = Utilities::getPaymentMethodId(cfg);
switch(permitType) {
case PERMIT_TYPE::SHORT_TERM_PARKING: { // e.g. szeged (customer_281)
if (paymentMethodId == PaymentMethod::Progressive) {
if (paymentMethodId == PaymentMethod::Progressive || paymentMethodId == PaymentMethod::Steps) {
maxPrice = Utilities::getMaximalParkingPrice(cfg, paymentMethodId);
} else { // PaymentMethod::Linear -> e.g. szeged
int const key = cfg->getPaymentOptions().pop_id;
int const maxTime = cfg->getPaymentOptions().pop_max_time; // maxTime is given in minutes
int const key = cfg->getPaymentOptions(paymentOptionIndex).pop_id;
int const maxTime = cfg->getPaymentOptions(paymentOptionIndex).pop_max_time; // maxTime is given in minutes
std::optional<QVector<ATBPaymentRate>> const &pv = cfg->getPaymentRateForKey(key);
if (pv) {
QVector<ATBPaymentRate> const &paymentRate = pv.value();
if (paymentRate.size() > 0) {
int const price = paymentRate.at(0).pra_price; // price is given per hour
int const price = paymentRate.last().pra_price; // price is given per hour
maxPrice = qRound((maxTime * price) / 60.0f);
}
}
@@ -352,7 +441,8 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
QDateTime &start_parking_time,
int netto_parking_time,
QDateTime &end_parking_time,
struct price_t *price)
struct price_t *price,
bool prepaid)
{
CalcState calcState;
double minMin = tariff->getPaymentOptions().pop_min_time;
@@ -384,14 +474,23 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
return calcState.set(CalcState::State::SUCCESS);
}
double cost = -1;
if (start_parking_time.isValid()) {
double cost = Calculator::GetInstance().GetCostFromDuration(
if (tariff->getPaymentOptions().pop_payment_method_id == PaymentMethod::Steps) {
calcState = Calculator::GetInstance().isParkingAllowed(tariff, start_parking_time);
if (calcState.getStatus() == CalcState::State::OUTSIDE_ALLOWED_PARKING_TIME) {
return calcState;
}
cost = Calculator::GetInstance().GetCostFromDuration(tariff, start_parking_time, netto_parking_time);
} else {
cost = Calculator::GetInstance().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);
false, prepaid);
}
double minCost = tariff->getPaymentOptions().pop_min_price;
if (cost < minCost) {
calcState.setDesc(QString("minCost=%1, cost=%2").arg(minCost, cost));
@@ -401,8 +500,10 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
// DEBUG
qCritical() << " -> calculated cost (price->netto) = " << cost;
price->brutto = price->vat = price->vat_percentage = 0;
price->units = cost;
price->netto = cost;
} else {
return calcState.set(CalcState::State::INVALID_START_DATE);
}

File diff suppressed because it is too large Load Diff

View File

@@ -2,6 +2,8 @@
#include "tariff_timebase.h"
#include "time_range_header.h"
#include "tariff_timestep_config.h"
#include "tariff_permit_type.h"
#include "tariff_business_hours.h"
#include <QString>
#include <QDebug>
@@ -24,6 +26,7 @@ MemberType Configuration::IdentifyJsonMember(const char* member_name)
if (strcmp(member_name, "Customer") == 0) return MemberType::CustomerType;
if (strcmp(member_name, "TimeRange") == 0) return MemberType::TimeRangeType;
if (strcmp(member_name, "TimeStepConfig") == 0) return MemberType::TimeStepConfigType;
if (strcmp(member_name, "Product") == 0) return MemberType::ProductType;
else return MemberType::UnknownType;
}
@@ -93,6 +96,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
ATBCustomer Customer;
ATBTimeRange TimeRange;
ATBTimeStepConfig TimeStepConfig;
ATBTariffProduct TariffProduct;
MemberType mb_type = MemberType::UnknownType;
this->currentPaymentOptions.clear();
@@ -157,6 +161,50 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
{
case MemberType::UnknownType:
break;
case MemberType::ProductType: {
if (QString(inner_obj_name) == QString("tariff_product_id")) {
if (k->value.IsInt()) {
int const x = k->value.GetInt();
TariffProduct.m_tariff_product_id = PermitType(x);
}
} else
if (QString(inner_obj_name) == QString("tariff_product_price")) {
if (k->value.IsInt()) {
int const x = k->value.GetInt();
TariffProduct.m_tariff_product_price = x;
}
} else
if (QString(inner_obj_name) == QString("tariff_product_name")) {
if (k->value.IsString()) {
std::string const &s = k->value.GetString();
TariffProduct.m_tariff_product_name = QString::fromStdString(s);
}
} else
if (QString(inner_obj_name) == QString("tariff_product_start")) {
if (k->value.IsString()) {
std::string const &s = k->value.GetString();
TariffProduct.m_tariff_product_start = QTime::fromString(QString::fromStdString(s), Qt::ISODate);
}
} else
if (QString(inner_obj_name) == QString("tariff_product_end")) {
if (k->value.IsString()) {
std::string const &s = k->value.GetString();
TariffProduct.m_tariff_product_end = QTime::fromString(QString::fromStdString(s), Qt::ISODate);
}
} else
if (QString(inner_obj_name) == QString("tariff_product_from_in_minutes_from_start")) {
if (k->value.IsInt()) {
int const x = k->value.GetInt();
TariffProduct.m_tariff_product_from_in_minutes_from_start = x;
}
} else
if (QString(inner_obj_name) == QString("tariff_product_to_in_minutes_from_start")) {
if (k->value.IsInt()) {
int const x = k->value.GetInt();
TariffProduct.m_tariff_product_to_in_minutes_from_start = x;
}
}
} break;
case MemberType::TimeRangeType:
if (QString(inner_obj_name) == QString("time_range_id")) {
if (k->value.IsInt()) {
@@ -479,6 +527,9 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
cfg->TimeStepConfig.insert(pair<int, ATBTimeStepConfig>(TimeStepConfig.tsconfig_id, TimeStepConfig));
// qCritical() << TimeStepConfig;
break;
case MemberType::ProductType:
cfg->TariffProduct.insert(pair<int, ATBTariffProduct>(TariffProduct.m_tariff_product_id, TariffProduct));
qCritical() << TariffProduct;
default:
break;
}
@@ -492,14 +543,76 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
}
}
ATBPaymentOption const &Configuration::getPaymentOptions() const {
Q_ASSERT(!this->currentPaymentOptions.isEmpty());
return this->currentPaymentOptions.at(0);
int Configuration::getCurrentPaymentOptionIndex(QDateTime const &dt) const {
int const numOptions = getAllPaymentOptions().size();
for (int opt=0; opt < numOptions; ++opt) {
uint64_t const pop_business_hours = getPaymentOptions(opt).pop_business_hours;
uint64_t p = 0;
switch (dt.date().dayOfWeek()) {
case (int)Qt::Monday: {
p = BusinessHours::MON;
if ((pop_business_hours & p) == p) {
return opt;
}
} break;
case (int)Qt::Tuesday: {
p = BusinessHours::TUE;
if ((pop_business_hours & p) == p) {
return opt;
}
} break;
case (int)Qt::Wednesday: {
p = BusinessHours::WED;
if ((pop_business_hours & p) == p) {
return opt;
}
} break;
case (int)Qt::Thursday: {
p = BusinessHours::THU;
if ((pop_business_hours & p) == p) {
return opt;
}
} break;
case (int)Qt::Friday: {
p = BusinessHours::FRI;
if ((pop_business_hours & p) == p) {
return opt;
}
} break;
case (int)Qt::Saturday: {
p = BusinessHours::SAT;
if ((pop_business_hours & p) == p) {
return opt;
}
} break;
case (int)Qt::Sunday: {
p = BusinessHours::SUN;
if (isHoliday(dt)) {
p |= BusinessHours::OFFICIAL_HOLIDAY;
}
if ((pop_business_hours & p) == p) {
return opt;
}
} break;
}
}
return -1;
}
ATBPaymentOption &Configuration::getPaymentOptions() {
bool Configuration::isHoliday(QDateTime const &dt) const {
return false;
}
ATBPaymentOption const &Configuration::getPaymentOptions(int paymentOptionsIndex) const {
Q_ASSERT(!this->currentPaymentOptions.isEmpty());
return this->currentPaymentOptions[0];
return this->currentPaymentOptions.at(paymentOptionsIndex);
}
ATBPaymentOption &Configuration::getPaymentOptions(int paymentOptionsIndex) {
Q_ASSERT(!this->currentPaymentOptions.isEmpty());
return this->currentPaymentOptions[paymentOptionsIndex];
}
QVector<ATBPaymentOption> const &Configuration::getAllPaymentOptions() const {
@@ -510,6 +623,48 @@ QVector<ATBPaymentOption> &Configuration::getAllPaymentOptions() {
return this->currentPaymentOptions;
}
std::optional<QVector<ATBTariffProduct>>
Configuration::getTariffProductForAllKeys() const {
QVector<ATBTariffProduct> products;
std::optional<QVector<ATBTariffProduct>> value;
products.clear();
for (std::multimap<int, ATBTariffProduct>::const_iterator it = this->TariffProduct.cbegin();
it != this->TariffProduct.cend(); ++it) {
products.append(it->second);
}
if (products.size() > 0) {
value = value.value_or(products);
}
return value;
}
std::optional<QVector<ATBTariffProduct>>
Configuration::getTariffProductForProductId(PermitType permitType) const {
QVector<ATBTariffProduct> products;
std::optional<QVector<ATBTariffProduct>> value;
products.clear();
for (auto[it, rangeEnd] = this->TariffProduct.equal_range(permitType); it != rangeEnd; ++it) {
products.append(it->second);
}
if (products.size() > 0) {
value = value.value_or(products);
}
return value;
}
std::optional<QVector<ATBTariffProduct>>
Configuration::getTariffProductForProductId(int id) const {
return getTariffProductForProductId(PermitType(id));
}
std::optional<QVector<ATBDailyTicket>>
Configuration::getDailyTicketsForAllKeys() const {
QVector<ATBDailyTicket> tickets;

View File

@@ -260,7 +260,7 @@ bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeS
//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");
//LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY");
*specialDayId = spec_days_itr->second.ped_id;
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
return true;
@@ -275,7 +275,7 @@ bool Utilities::CheckSpecialDay(Configuration* cfg, const char* currentDateTimeS
//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");
//LOG_DEBUG("CheckSpecialDay() => SPECIAL DAY");
*specialDayId = spec_days_itr->second.ped_id;
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
return true;
@@ -317,7 +317,7 @@ bool Utilities::CheckSpecialDay(Configuration const *cfg,
continue;
}
}
qDebug() << "CheckSpecialDay() => SPECIAL DAY";
//qDebug() << "CheckSpecialDay() => SPECIAL DAY";
*specialDayId = spec_days_itr->second.ped_id;
*specialDayPrice = cfg->SpecialDaysWorktime.find(*specialDayId)->second.pedwt_price;
return true;

File diff suppressed because it is too large Load Diff