Compare commits
No commits in common. "1d7779f66603d76c6f3fdc4a2dd8a5e2be476535" and "631378deeb4784145dae2e1c3a87933ef88f3c3c" have entirely different histories.
1d7779f666
...
631378deeb
@ -171,7 +171,7 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket( // depre
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
QDateTime &start_parking_time,
|
||||
QDateTime const &start_parking_time,
|
||||
int netto_parking_time,
|
||||
QDateTime &end_parking_time, // return value
|
||||
struct price_t *price); // return value
|
||||
|
@ -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="durationMin">Duration of parking in minutes</param>
|
||||
/// <returns>Returns cost (data type: double)</returns>
|
||||
double GetCostFromDuration(Configuration* cfg, uint8_t vehicle_type, QDateTime &start_datetime, QDateTime & end_datetime, int 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);
|
||||
|
@ -1,5 +1,4 @@
|
||||
#ifndef PAYMENT_RATE_INCLUDED_H
|
||||
#define PAYMENT_RATE_INCLUDED_H
|
||||
#pragma once
|
||||
|
||||
class ATBPaymentRate
|
||||
{
|
||||
@ -8,5 +7,3 @@ public:
|
||||
int pra_payment_unit_id;
|
||||
double pra_price;
|
||||
};
|
||||
|
||||
#endif // PAYMENT_RATE_INCLUDED_H
|
||||
|
@ -10,58 +10,15 @@ struct ATBTimeRange {
|
||||
int time_range_id;
|
||||
QTime time_range_from;
|
||||
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) {
|
||||
QDebugStateSaver saver(debug);
|
||||
|
||||
debug.nospace()
|
||||
<< " time_range_id: " << timeRange.time_range_id << "\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_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";
|
||||
<< "time_range_from: " << timeRange.time_range_from.toString(Qt::ISODate) << "\n"
|
||||
<< " time_range_to: " << timeRange.time_range_to.toString(Qt::ISODate) << "\n";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
@ -79,8 +79,6 @@ namespace Utilities {
|
||||
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);
|
||||
int WeekDayId(std::multimap<int, ATBWeekDaysWorktime>::const_iterator itr);
|
||||
// PaymentRate GetPaymentRate(Configuration const *cfg, );
|
||||
bool isCarryOverSet(Configuration const *cfg, PaymentMethod paymentMethodId);
|
||||
bool isCarryOverNotSet(Configuration const *cfg, PaymentMethod paymentMethodId);
|
||||
PaymentMethod getPaymentMethodId(Configuration const *cfg);
|
||||
|
@ -342,7 +342,7 @@ CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
||||
|
||||
CalcState CALCULATE_LIBRARY_API compute_price_for_parking_ticket(
|
||||
parking_tariff_t *tariff,
|
||||
QDateTime &start_parking_time,
|
||||
QDateTime const &start_parking_time,
|
||||
int netto_parking_time,
|
||||
QDateTime &end_parking_time,
|
||||
struct price_t *price)
|
||||
|
@ -255,7 +255,7 @@ CalcState Calculator::isParkingAllowed(Configuration const *cfg, QDateTime const
|
||||
/// <inheritdoc/>
|
||||
double Calculator::GetCostFromDuration(Configuration* cfg,
|
||||
uint8_t payment_option,
|
||||
QDateTime &start_datetime,
|
||||
const QDateTime start_datetime,
|
||||
QDateTime &end_datetime,
|
||||
int durationMinutes,
|
||||
bool nextDay,
|
||||
@ -286,179 +286,6 @@ double Calculator::GetCostFromDuration(Configuration* cfg,
|
||||
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;
|
||||
|
@ -56,12 +56,12 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
||||
}
|
||||
|
||||
// Validate JSON, check if it's a JSON object
|
||||
qCritical() << "JSON parsing has been successful";
|
||||
printf("%s", "JSON parsing has been successful\n");
|
||||
if (!document.IsObject()) {
|
||||
printf("%s", "Error: not a (valid) JSON object\n");
|
||||
return false;
|
||||
}
|
||||
qCritical() << "Valid JSON object identified";
|
||||
printf("%s", "Valid JSON object identified\n");
|
||||
|
||||
// Validate JSON, check configuration members
|
||||
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");
|
||||
return false;
|
||||
}
|
||||
qCritical() << "Valid JSON configuration identified";
|
||||
printf("%s", "Valid JSON configuration identified\n");
|
||||
|
||||
ATBCurrency Currency;
|
||||
ATBDuration Duration;
|
||||
@ -126,7 +126,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
||||
continue;
|
||||
}
|
||||
|
||||
qCritical() << " -" << mb_name;
|
||||
printf(" -%s\n", mb_name);
|
||||
|
||||
// Get array for each JSON object member
|
||||
auto mb_array = document[mb_name].GetArray();
|
||||
@ -167,32 +167,12 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
||||
if (k->value.IsString()) {
|
||||
QTime timeRangeFrom = QTime::fromString(QString::fromStdString(k->value.GetString()), Qt::ISODate);
|
||||
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
|
||||
if (QString(inner_obj_name) == QString("time_range_to")) {
|
||||
if (k->value.IsString()) {
|
||||
QTime timeRangeTo = QTime::fromString(QString::fromStdString(k->value.GetString()), Qt::ISODate);
|
||||
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;
|
||||
@ -471,7 +451,7 @@ bool Configuration::ParseJson(Configuration* cfg, const char* json)
|
||||
break;
|
||||
case MemberType::TimeRangeType:
|
||||
cfg->TimeRange.insert(pair<int, ATBTimeRange>(TimeRange.time_range_id, TimeRange));
|
||||
//qCritical() << TimeRange;
|
||||
// qCritical() << TimeRange;
|
||||
break;
|
||||
case MemberType::TimeStepConfigType:
|
||||
cfg->TimeStepConfig.insert(pair<int, ATBTimeStepConfig>(TimeStepConfig.tsconfig_id, TimeStepConfig));
|
||||
|
@ -345,10 +345,6 @@ QTime Utilities::WeekDaysWorkTimeUntil(std::multimap<int, ATBWeekDaysWorktime>::
|
||||
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) {
|
||||
return !isCarryOverNotSet(cfg, paymentMethodId);
|
||||
}
|
||||
@ -410,6 +406,8 @@ uint32_t Utilities::getFirstDurationStep(Configuration const *cfg, PaymentMethod
|
||||
BusinessHours Utilities::getBusinessHours(Configuration const *cfg, PaymentMethod methodId) {
|
||||
int businessHours = cfg->PaymentOption.find(methodId)->second.pop_business_hours;
|
||||
|
||||
qCritical() << __func__ << ":" << __LINE__ << businessHours;
|
||||
|
||||
switch (businessHours) {
|
||||
case NoRestriction_24_7: return BusinessHours::NoRestriction_24_7;
|
||||
case OnlyWorkingDays: return BusinessHours::OnlyWorkingDays;
|
||||
|
@ -38,8 +38,7 @@ extern "C" char* strptime(const char* s,
|
||||
#define NEUHAUSER_KORNEUBURG (0)
|
||||
#define NEUHAUSER_LINSINGER_MASCHINENBAU (0)
|
||||
#define NEUHAUSER_NORDISCHES_AUSBILDUNGSZENTRUM (0)
|
||||
#define NEUHAUSER_BILEXA_GALTUER (0)
|
||||
#define NEUHAUSER_KIRCHDORF (1)
|
||||
#define NEUHAUSER_BILEXA_GALTUER (1)
|
||||
|
||||
|
||||
int main() {
|
||||
@ -88,91 +87,6 @@ int main() {
|
||||
}
|
||||
#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
|
||||
std::ifstream input("/opt/ptu5/opt/customer_745/etc/psa_tariff/tariff01.json");
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user