Compare commits

...

9 Commits

10 changed files with 346 additions and 17 deletions

View File

@ -171,7 +171,7 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // depre
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff, parking_tariff_t *tariff,
QDateTime const &start_parking_time, QDateTime &start_parking_time,
int netto_parking_time, int netto_parking_time,
QDateTime &end_parking_time, // return value QDateTime &end_parking_time, // return value
struct price_t *price); // return value struct price_t *price); // return value

View File

@ -56,7 +56,7 @@ public:
/// <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="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, const QDateTime start_datetime, QDateTime & end_datetime, int durationMin, bool nextDay = false, bool prepaid = false); double GetCostFromDuration(Configuration* cfg, uint8_t vehicle_type, QDateTime &start_datetime, QDateTime & end_datetime, int durationMin, bool nextDay = false, bool prepaid = false);
// Daily ticket // Daily ticket
QDateTime GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over); QDateTime GetDailyTicketDuration(Configuration* cfg, const QDateTime start_datetime, uint8_t payment_option, bool carry_over);

View File

@ -1,4 +1,5 @@
#pragma once #ifndef PAYMENT_RATE_INCLUDED_H
#define PAYMENT_RATE_INCLUDED_H
class ATBPaymentRate class ATBPaymentRate
{ {
@ -6,4 +7,6 @@ public:
int pra_payment_option_id; int pra_payment_option_id;
int pra_payment_unit_id; int pra_payment_unit_id;
double pra_price; double pra_price;
}; };
#endif // PAYMENT_RATE_INCLUDED_H

View File

@ -10,15 +10,58 @@ struct ATBTimeRange {
int time_range_id; int time_range_id;
QTime time_range_from; QTime time_range_from;
QTime time_range_to; QTime time_range_to;
int time_range_from_in_minutes_from_start;
int time_range_to_in_minutes_from_start;
int time_range_tbase_id;
int time_range_payment_type_id;
explicit ATBTimeRange()
: time_range_id(-1)
, time_range_from(QTime())
, time_range_to(QTime())
, time_range_from_in_minutes_from_start(-1)
, time_range_to_in_minutes_from_start(-1)
, time_range_tbase_id(-1)
, time_range_payment_type_id(-1) {
}
QTime const &getTimeFrom() const { return time_range_from; }
QTime const &getTimeUntil() const { return time_range_to; }
bool computeQTimeFrom(QTime const &t) {
if (time_range_from_in_minutes_from_start != -1) {
time_range_from = t.addSecs(time_range_from_in_minutes_from_start * 60);
return time_range_from.isValid();
}
return false;
}
bool computeQTimeTo(QTime const &t) {
if (time_range_to_in_minutes_from_start != -1) {
time_range_to = t.addSecs(time_range_to_in_minutes_from_start * 60);
return time_range_to.isValid();
}
return false;
}
bool computeQTimes(QTime const &t) {
if (!t.isNull() && t.isValid()) {
return computeQTimeFrom(t) && computeQTimeTo(t);
}
return false;
}
friend QDebug operator<<(QDebug debug, ATBTimeRange const &timeRange) { friend QDebug operator<<(QDebug debug, ATBTimeRange const &timeRange) {
QDebugStateSaver saver(debug); QDebugStateSaver saver(debug);
debug.nospace() debug.nospace()
<< " time_range_id: " << timeRange.time_range_id << "\n" << " time_range_id: " << timeRange.time_range_id << "\n"
<< "time_range_from: " << timeRange.time_range_from.toString(Qt::ISODate) << "\n" << " time_range_from: " << timeRange.time_range_from.toString(Qt::ISODate) << "\n"
<< " time_range_to: " << timeRange.time_range_to.toString(Qt::ISODate) << "\n"; << " time_range_to: " << timeRange.time_range_to.toString(Qt::ISODate) << "\n"
<< " time_range_from_in_minutes_from_start: " << timeRange.time_range_from_in_minutes_from_start << "\n"
<< " time_range_to_in_minutes_from_start: " << timeRange.time_range_to_in_minutes_from_start << "\n"
<< " time_range_tbase_id: " << timeRange.time_range_tbase_id << "\n"
<< " time_range_payment_type_id: " << timeRange.time_range_payment_type_id << "\n";
return debug; return debug;
} }

View File

@ -79,6 +79,8 @@ namespace Utilities {
QTime SpecialDaysWorkTimeUntil(Configuration const *cfg, int specialDayId); QTime SpecialDaysWorkTimeUntil(Configuration const *cfg, int specialDayId);
QTime WeekDaysWorkTimeFrom(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr); QTime WeekDaysWorkTimeFrom(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr);
QTime WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr); QTime WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr);
int WeekDayId(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr);
// PaymentRate GetPaymentRate(Configuration const *cfg, );
bool isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId); bool isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId);
bool isCarryOverNotSet(Configuration const *cfg, PaymentMethod paymentMethodId); bool isCarryOverNotSet(Configuration const *cfg, PaymentMethod paymentMethodId);
PaymentMethod getPaymentMethodId(Configuration const *cfg); PaymentMethod getPaymentMethodId(Configuration const *cfg);

View File

@ -342,7 +342,7 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
parking_tariff_t *tariff, parking_tariff_t *tariff,
QDateTime const &start_parking_time, QDateTime &start_parking_time,
int netto_parking_time, int netto_parking_time,
QDateTime &end_parking_time, QDateTime &end_parking_time,
struct price_t *price) struct price_t *price)

View File

@ -255,7 +255,7 @@ CalcState Calculator::isParkingAllowed(Configuration const *cfg, QDateTime const
/// <inheritdoc/> /// <inheritdoc/>
double Calculator::GetCostFromDuration(Configuration* cfg, double Calculator::GetCostFromDuration(Configuration* cfg,
uint8_t payment_option, uint8_t payment_option,
const QDateTime start_datetime, QDateTime &start_datetime,
QDateTime &end_datetime, QDateTime &end_datetime,
int durationMinutes, int durationMinutes,
bool nextDay, bool nextDay,
@ -286,6 +286,179 @@ double Calculator::GetCostFromDuration(Configuration* cfg,
return 0; return 0;
} }
} }
} else
if (paymentMethodId == PaymentMethod::Progressive) {
// started with Neuhauser, Kirchdorf: merge into main algo. later
// for now try out some ideas
static const bool carryOverNotSet = Utilities::isCarryOverNotSet(cfg, paymentMethodId);
static const uint minParkingPrice = Utilities::getMinimalParkingPrice(cfg, paymentMethodId);
Q_ASSERT_X(carryOverNotSet, __func__, "CARRYOVER SET (FOR KIRCHDORF)");
Q_ASSERT_X(prepaid, __func__, "PREPAID NOT SET (FOR KIRCHDORF)");
QDateTime start = start_datetime;
int weekdayId = -1;
int weekdayIdLast = -1;
int timeRanges = 0;
int durationMinutesBrutto = 0;
QDateTime current = start;
int days = 7;
while (--days > 0) {
weekdayId = current.date().dayOfWeek();
weekdayIdLast = weekdayId; // TODO: some end condition in json-file
while ((timeRanges = cfg->WeekDaysWorktime.count(weekdayId)) == 0) {
current = current.addDays(1);
weekdayId = current.date().dayOfWeek();
if (weekdayId == weekdayIdLast) {
qCritical() << "ERROR: NO VALID WORKDAY-TIMES DEFINED";
return 0;
}
}
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
QTime to = QTime(0, 0, 0);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
QTime const &t = Utilities::WeekDaysWorkTimeUntil(itr);
if (to < t) {
to = t;
}
}
if (current.time() >= to) {
QDateTime const dt = start;
start = start.addDays(1);
start.setTime(QTime(0, 0, 0));
durationMinutesBrutto += dt.secsTo(start) / 60;
current = start;
} else {
break;
}
}
int durationMinutesNetto = 0;
uint price = 0;
if (carryOverNotSet) {
int range = 0;
int minsToCarryOver = 0; // from one work-time to the other on the same day
QDateTime lastCurrent = QDateTime();
auto timeRangeIt = cfg->TimeRange.cbegin();
for (; timeRangeIt != cfg->TimeRange.cend(); ++timeRangeIt) {
using WTIterator = std::multimap<int, ATBWeekDaysWorktime>::const_iterator;
std::pair<WTIterator, WTIterator> p = cfg->WeekDaysWorktime.equal_range(weekdayId);
for (WTIterator itr = p.first; itr != p.second; ++itr) {
++range;
QTime const &from = Utilities::WeekDaysWorkTimeFrom(itr);
QTime const &to = Utilities::WeekDaysWorkTimeUntil(itr);
Q_ASSERT_X(from < to, __func__, "MISCONFIGURED WORK-TIMES");
if (current.time() >= to) {
continue; // try to use next available work-time
} else
if (current.time() <= from) {
if (prepaid) {
lastCurrent = current;
current.setTime(from); // move current forward (range==1),
// as prepaid is set
uint const minutesMoved = lastCurrent.secsTo(current) / 60;
durationMinutesBrutto += minutesMoved;
if (range == 1) {
start_datetime = current;
}
}
}
while (timeRangeIt != cfg->TimeRange.cend()) {
ATBTimeRange timeRange = timeRangeIt->second;
timeRange.computeQTimes(current.time());
int duration = timeRange.time_range_to_in_minutes_from_start -
timeRange.time_range_from_in_minutes_from_start;
if (current.addSecs(duration * 60).time() <= to) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
if (minsToCarryOver > 0) {
durationMinutes -= minsToCarryOver;
durationMinutesNetto += minsToCarryOver;
durationMinutesBrutto += minsToCarryOver;
current = current.addSecs(minsToCarryOver*60);
minsToCarryOver = 0;
} else {
price += (uint)rate.pra_price;
durationMinutes -= duration;
durationMinutesNetto += duration;
durationMinutesBrutto += duration;
current = current.addSecs(duration * 60);
}
break;
}
}
if (durationMinutes <= 0) {
end_datetime = current;
return price;
}
++timeRangeIt;
} else {
lastCurrent = current;
current.setTime(to);
int const minsLeft = lastCurrent.secsTo(current) / 60;
// mod duration: possibly discard some minutes in
// the next time-range
minsToCarryOver = (durationMinutes - minsLeft) % duration;
durationMinutes -= minsLeft;
durationMinutesNetto += minsLeft;
durationMinutesBrutto += minsLeft;
if (minsLeft > 0) {
for(const auto &x: cfg->PaymentRate) {
ATBPaymentRate const rate = x.second;
if (rate.pra_payment_unit_id == timeRange.time_range_payment_type_id) {
price += (uint)rate.pra_price;
break;
}
}
}
break;
}
}
}
end_datetime = start.addSecs(durationMinutesBrutto * 60);
return std::max(price, minParkingPrice);
}
}
end_datetime = QDateTime();
return 0;
} }
QDateTime start = start_datetime; QDateTime start = start_datetime;

View File

@ -56,12 +56,12 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
} }
// Validate JSON, check if it's a JSON object // Validate JSON, check if it's a JSON object
printf("%s", "JSON parsing has been successful\n"); qCritical() << "JSON parsing has been successful";
if (!document.IsObject()) { if (!document.IsObject()) {
printf("%s", "Error: not a (valid) JSON object\n"); printf("%s", "Error: not a (valid) JSON object\n");
return false; return false;
} }
printf("%s", "Valid JSON object identified\n"); qCritical() << "Valid JSON object identified";
// Validate JSON, check configuration members // Validate JSON, check configuration members
if (!document.HasMember("Currency") if (!document.HasMember("Currency")
@ -77,7 +77,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
printf("%s", "Error: not a valid configuration JSON\n"); printf("%s", "Error: not a valid configuration JSON\n");
return false; return false;
} }
printf("%s", "Valid JSON configuration identified\n"); qCritical() << "Valid JSON configuration identified";
ATBCurrency Currency; ATBCurrency Currency;
ATBDuration Duration; ATBDuration Duration;
@ -126,7 +126,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
continue; continue;
} }
printf(" -%s\n", mb_name); qCritical() << " -" << mb_name;
// Get array for each JSON object member // Get array for each JSON object member
auto mb_array = document[mb_name].GetArray(); auto mb_array = document[mb_name].GetArray();
@ -167,12 +167,32 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
if (k->value.IsString()) { if (k->value.IsString()) {
QTime timeRangeFrom = QTime::fromString(QString::fromStdString(k->value.GetString()), Qt::ISODate); QTime timeRangeFrom = QTime::fromString(QString::fromStdString(k->value.GetString()), Qt::ISODate);
TimeRange.time_range_from = timeRangeFrom; TimeRange.time_range_from = timeRangeFrom;
} else
if (k->value.IsInt()) {
int timeRangeFrom = k->value.GetInt();
TimeRange.time_range_from_in_minutes_from_start = timeRangeFrom;
} }
} else } else
if (QString(inner_obj_name) == QString("time_range_to")) { if (QString(inner_obj_name) == QString("time_range_to")) {
if (k->value.IsString()) { if (k->value.IsString()) {
QTime timeRangeTo = QTime::fromString(QString::fromStdString(k->value.GetString()), Qt::ISODate); QTime timeRangeTo = QTime::fromString(QString::fromStdString(k->value.GetString()), Qt::ISODate);
TimeRange.time_range_to = timeRangeTo; TimeRange.time_range_to = timeRangeTo;
} else
if (k->value.IsInt()) {
int timeRangeTo = k->value.GetInt();
TimeRange.time_range_to_in_minutes_from_start = timeRangeTo;
}
} else
if (QString(inner_obj_name) == QString("time_range_tbase_id")) {
if (k->value.IsInt()) {
int tbase = k->value.GetInt();
TimeRange.time_range_tbase_id = tbase;
}
} else
if (QString(inner_obj_name) == QString("time_range_payment_rate_id")) {
if (k->value.IsInt()) {
int ptype = k->value.GetInt();
TimeRange.time_range_payment_type_id = ptype;
} }
} }
break; break;
@ -451,7 +471,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
break; break;
case MemberType::TimeRangeType: case MemberType::TimeRangeType:
cfg->TimeRange.insert(pair<int, ATBTimeRange>(TimeRange.time_range_id, TimeRange)); cfg->TimeRange.insert(pair<int, ATBTimeRange>(TimeRange.time_range_id, TimeRange));
// qCritical() << TimeRange; //qCritical() << TimeRange;
break; break;
case MemberType::TimeStepConfigType: case MemberType::TimeStepConfigType:
cfg->TimeStepConfig.insert(pair<int, ATBTimeStepConfig>(TimeStepConfig.tsconfig_id, TimeStepConfig)); cfg->TimeStepConfig.insert(pair<int, ATBTimeStepConfig>(TimeStepConfig.tsconfig_id, TimeStepConfig));

View File

@ -345,6 +345,10 @@ QTime Utilities::WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::
return QTime::fromString(itr->second.pwd_time_to.c_str(), Qt::ISODate); return QTime::fromString(itr->second.pwd_time_to.c_str(), Qt::ISODate);
} }
int Utilities::WeekDayId(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr) {
return itr->second.pwd_period_day_in_week_id;
}
bool Utilities::isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId) { bool Utilities::isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId) {
return !isCarryOverNotSet(cfg, paymentMethodId); return !isCarryOverNotSet(cfg, paymentMethodId);
} }
@ -406,8 +410,6 @@ uint32_t Utilities::getFirstDurationStep(Configuration const *cfg, PaymentMethod
BusinessHours Utilities::getBusinessHours(Configuration const *cfg, PaymentMethod methodId) { BusinessHours Utilities::getBusinessHours(Configuration const *cfg, PaymentMethod methodId) {
int businessHours = cfg->PaymentOption.find(methodId)->second.pop_business_hours; int businessHours = cfg->PaymentOption.find(methodId)->second.pop_business_hours;
qCritical() << __func__ << ":" << __LINE__ << businessHours;
switch (businessHours) { switch (businessHours) {
case NoRestriction_24_7: return BusinessHours::NoRestriction_24_7; case NoRestriction_24_7: return BusinessHours::NoRestriction_24_7;
case OnlyWorkingDays: return BusinessHours::OnlyWorkingDays; case OnlyWorkingDays: return BusinessHours::OnlyWorkingDays;

View File

@ -38,7 +38,8 @@ extern "C" char* strptime(const char* s,
#define NEUHAUSER_KORNEUBURG (0) #define NEUHAUSER_KORNEUBURG (0)
#define NEUHAUSER_LINSINGER_MASCHINENBAU (0) #define NEUHAUSER_LINSINGER_MASCHINENBAU (0)
#define NEUHAUSER_NORDISCHES_AUSBILDUNGSZENTRUM (0) #define NEUHAUSER_NORDISCHES_AUSBILDUNGSZENTRUM (0)
#define NEUHAUSER_BILEXA_GALTUER (1) #define NEUHAUSER_BILEXA_GALTUER (0)
#define NEUHAUSER_KIRCHDORF (1)
int main() { int main() {
@ -87,6 +88,91 @@ int main() {
} }
#endif #endif
#if NEUHAUSER_KIRCHDORF==1
const char *f = "/opt/ptu5/opt/customer_743/etc/psa_tariff/tariff01.json";
std::ifstream input(f);
std::stringstream sstr;
while(input >> sstr.rdbuf());
std::string json(sstr.str());
Configuration cfg;
bool isParsed = cfg.ParseJson(&cfg, json.c_str());
if (isParsed) {
qCritical() << "Parsed" << f;
int minParkingTime = get_minimal_parkingtime(&cfg);
int maxParkingTime = get_maximal_parkingtime(&cfg);
int minParkingPrice = get_minimal_parkingprice(&cfg);
qCritical() << "min_parking_time " << minParkingTime;
qCritical() << "max_parking_time " << maxParkingTime;
qCritical() << "min_parking_price" << minParkingPrice;
#if 1
bool nextDay = false;
bool prePaid = true;
// bool carryOver = false;
QDateTime s(QDate(2023, 11, 30), QTime());
// QDateTime s(QDate(2023, 11, 26), QTime());
QDateTime end;
for (int duration = 30; duration <= 30; duration += 5) {
// for (int duration = 30; duration <= maxParkingTime; duration += 5) {
qCritical() << "";
for (int offset = 721; offset <= 721; ++offset) {
//for (int offset = 420; offset <= 1080; ++offset) {
//if (offset > 720 && offset < 840) {
// continue;
//}
QDateTime start = s.addSecs(offset * 60);
QDateTime const firstStart = start;
// qCritical() << "start" << start.toString(Qt::ISODate);
double cost = Calculator::GetInstance().GetCostFromDuration(&cfg, 3, start, end, duration, nextDay, prePaid);
double cost_soll = 30 + ((duration-30)/5 * 10);
uint32_t duration_ist = start.secsTo(end) / 60;
if (duration_ist >= 120) {
duration_ist = duration_ist - 120;
}
qCritical() << "****" << offset << duration << "****";
qCritical() << " firstStart :" << firstStart.toString(Qt::ISODate);
qCritical() << " start :" << start.toString(Qt::ISODate);
qCritical() << " end :" << end.toString(Qt::ISODate);
qCritical() << "duration (soll):" << duration;
qCritical() << "duration (ist) :" << duration_ist;
qCritical() << " cost (soll):" << cost_soll;
qCritical() << " cost (ist) :" << cost;
if (cost_soll != cost) {
qCritical() << "ERROR" << __func__ << ":" << __LINE__
<< "cost_soll" << cost_soll << "cost_ist" << cost;
break;
}
if (duration != duration_ist) {
//qCritical() << "ERROR" << __func__ << ":" << __LINE__
// << "duration_soll" << duration << "duration_ist" << duration_ist;
//break;
}
//std::string duration = calculator.GetDurationFromCost(&cfg, 3, start.toString(Qt::ISODate).toStdString().c_str(), cost);
//qCritical() << "start" << start.toString(Qt::ISODate)
// << "cost" << cost
// << "until" << duration.c_str() << start.secsTo(QDateTime::fromString(duration.c_str(), Qt::ISODate)) / 60;
}
}
#endif // 0
}
#endif
#if NEUHAUSER_BILEXA_GALTUER==1 #if NEUHAUSER_BILEXA_GALTUER==1
std::ifstream input("/opt/ptu5/opt/customer_745/etc/psa_tariff/tariff01.json"); std::ifstream input("/opt/ptu5/opt/customer_745/etc/psa_tariff/tariff01.json");