#include "configuration.h" #include "utilities.h" #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 "tariff_global_defines.h" #include "tariff_carryover.h" #include "tariff_global_defines.h" #include #include #include /// MemberType Configuration::IdentifyJsonMember(const char* member_name) { if (strcmp(member_name, "Currency") == 0) return MemberType::CurrencyType; if (strcmp(member_name, "PaymentMethod") == 0) return MemberType::PaymentMethodType; if (strcmp(member_name, "PaymentRate") == 0) return MemberType::PaymentRateType; if (strcmp(member_name, "PaymentOption") == 0) return MemberType::PaymentOptionType; if (strcmp(member_name, "Duration") == 0) return MemberType::DurationType; //if (strcmp(member_name, "WeekDays") == 0) return MemberType::WeekDaysType; if (strcmp(member_name, "WeekDaysWorktime") == 0) return MemberType::WeekDaysWorkTimeType; if (strcmp(member_name, "SpecialDaysWorktime") == 0) return MemberType::SpecialDaysWorktimeType; if (strcmp(member_name, "SpecialDays") == 0) return MemberType::SpecialDaysType; if (strcmp(member_name, "PeriodYear") == 0) return MemberType::PeriodYearType; if (strcmp(member_name, "DailyTicket") == 0) return MemberType::DailyTicketType; if (strcmp(member_name, "TimeBase") == 0) return MemberType::TimeBaseType; 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; if (strcmp(member_name, "Interpolation") == 0) return MemberType::InterpolationType; if (strcmp(member_name, "Prepaid") == 0) return MemberType::PrepaidType; if (strcmp(member_name, "CarryOver") == 0) return MemberType::CarryOverType; else return MemberType::UnknownType; } /// bool Configuration::ParseJson(Configuration* cfg, const char* json) { try { if (cfg == nullptr) { printf("TariffConfiguration pointer not set\n"); return false; } if (json == NULL) { printf("%s", "Input JSON string is NULL\n"); return false; } // Parse JSON to document Document document; document.Parse(json); // Return if parse error has been found ParseErrorCode err = document.GetParseError(); if (err != 0) { printf("%s %d (%s)\n", "Unable to parse JSON, error code:", err, GetParseError_En(err)); return false; } // Validate JSON, check if it's a JSON object qCritical() << "JSON parsing has been successful"; if (!document.IsObject()) { printf("%s", "Error: not a (valid) JSON object\n"); return false; } qCritical() << "Valid JSON object identified"; // Validate JSON, check configuration members if (!document.HasMember("Currency") || !document.HasMember("PaymentMethod") || !document.HasMember("PaymentOption") || !document.HasMember("PaymentRate") || !document.HasMember("Duration") //|| !document.HasMember("WeekDays") //|| !document.HasMember("SpecialDaysWorktime") //|| !document.HasMember("SpecialDays") ) { printf("%s", "Error: not a valid configuration JSON\n"); return false; } qCritical() << "Valid JSON configuration identified"; ATBCurrency Currency; ATBDuration Duration; ATBPaymentMethod PaymentMethod; ATBPaymentRate PaymentRate; ATBSpecialDaysWorktime SpecialDaysWorktime; ATBSpecialDays SpecialDays; ATBWeekDays WeekDays; ATBWeekDaysWorktime WeekDaysWorktime; ATBPeriodYear YearPeriod; ATBDailyTicket DailyTicket; ATBTimeBase TimeBase; ATBCustomer Customer; ATBTimeRange TimeRange; ATBTimeStepConfig TimeStepConfig; ATBTariffProduct TariffProduct; ATBInterpolation TariffInterpolation; ATBPrepaid TariffPrepaidOption; ATBCarryOver TariffCarryOver; MemberType mb_type = MemberType::UnknownType; this->currentPaymentOptions.clear(); // Get all JSON object members // This code should run only once (to load JSON variables into memory) for (auto i = document.MemberBegin(); i != document.MemberEnd(); i++) { // Get name of all general members of JSON, don't print name if NULL const char* mb_name = i->name.GetString(); if (mb_name == NULL) continue; if (document[mb_name].IsString()) { QString const _mb_name(mb_name); if (_mb_name.startsWith("Project", Qt::CaseInsensitive)) { cfg->project.project = document[mb_name].GetString(); continue; } if (_mb_name.startsWith("Version", Qt::CaseInsensitive)) { cfg->project.version = document[mb_name].GetString(); continue; } if (_mb_name.startsWith("Info", Qt::CaseInsensitive)) { cfg->project.info = document[mb_name].GetString(); continue; } } // ... everything else should be an array if (!document[mb_name].IsArray()) { continue; } qCritical() << " -" << mb_name; // Get array for each JSON object member auto mb_array = document[mb_name].GetArray(); if (mb_array.Size() <= 0) break; //Iterate over provided array for (rapidjson::SizeType j = 0; j < mb_array.Size(); j++) { // Get all inner objects, don't print name if NULL auto inner_obj = mb_array[j].GetObject(); if (inner_obj.MemberCount() <= 0) break; // Iterate over inner object JSON members for (auto k = inner_obj.MemberBegin(); k != inner_obj.MemberEnd(); k++) { // Get inner object JSON member, don't print name if NULL const char* inner_obj_name = k->name.GetString(); if (inner_obj_name == NULL) { printf("Inner object name is NULL\n"); continue; } // Identify member type mb_type = IdentifyJsonMember(mb_name); switch (mb_type) { case MemberType::UnknownType: break; case MemberType::CarryOverType: { if (QString(inner_obj_name) == QString("carry_over_id")) { if (k->value.IsInt()) { int const &x = k->value.GetInt(); TariffCarryOver.id = x; } } else if (QString(inner_obj_name) == QString("carry_over_week")) { if (k->value.IsArray()) { auto days = k->value.GetArray(); for (rapidjson::SizeType j=0; j < days.Size(); ++j) { if (days[j].IsObject()) { auto weekday = days[j].GetObject(); for (auto w = weekday.MemberBegin(); w != weekday.MemberEnd(); ++w) { int day = j+1; // 8 entries QString member(QString::fromStdString(w->name.GetString())); if (member == "carry_over_day") { if (w->value.IsInt()) { rapidjson::SizeType const d = w->value.GetInt(); if (d != (j+1)) { qCritical() << "ERROR: misconfigured jsonfile" << d << "!=" << (j+1); } TariffCarryOver.carryover[day].day = day; } } else if (member == "carry_over_duration") { if (w->value.IsInt()) { TariffCarryOver.carryover[day].duration = w->value.GetInt(); } } else if (member == "carry_over_seemless") { if (w->value.IsBool()) { bool b = w->value.GetBool(); TariffCarryOver.carryover[day].seemless = b; } } else if (member == "carry_over_never") { if (w->value.IsBool()) { bool b = w->value.GetBool(); TariffCarryOver.carryover[day].never = b; } } else if (member == "carry_over_static_start") { if (w->value.IsString()) { QTime const &t = QTime::fromString(w->value.GetString(), Qt::ISODate); TariffCarryOver.carryover[day].static_start = t; } } else if (member == "carry_over_static_end") { if (w->value.IsString()) { QTime const &t = QTime::fromString(w->value.GetString(), Qt::ISODate); TariffCarryOver.carryover[day].static_end = t; } } } } } } } } break; case MemberType::PrepaidType: { if (QString(inner_obj_name) == QString("prepaid_id")) { if (k->value.IsInt()) { int const &x = k->value.GetInt(); TariffPrepaidOption.id = x; } } else if (QString(inner_obj_name) == QString("prepaid_anytime")) { if (k->value.IsBool()) { bool const &x = k->value.GetBool(); TariffPrepaidOption.anytime = x; } } else if (QString(inner_obj_name) == QString("prepaid_never")) { if (k->value.IsBool()) { bool const &x = k->value.GetBool(); TariffPrepaidOption.never = x; } } else if (QString(inner_obj_name) == QString("prepaid_static_start")) { if (k->value.IsString()) { QTime const &t = QTime::fromString(k->value.GetString(), Qt::ISODate); TariffPrepaidOption.static_start = t; } } else if (QString(inner_obj_name) == QString("prepaid_static_end")) { if (k->value.IsString()) { QTime const &t = QTime::fromString(k->value.GetString(), Qt::ISODate); TariffPrepaidOption.static_end = t; } } } break; case MemberType::InterpolationType: { if (QString(inner_obj_name) == QString("interpol_id")) { if (k->value.IsInt()) { int const &x = k->value.GetInt(); TariffInterpolation.id = x; } } else if (QString(inner_obj_name) == QString("interpol_static_start")) { if (k->value.IsString()) { QTime const &t = QTime::fromString(k->value.GetString(), Qt::ISODate); TariffInterpolation.static_start = t; } } else if (QString(inner_obj_name) == QString("interpol_static_end")) { if (k->value.IsString()) { QTime const &t = QTime::fromString(k->value.GetString(), Qt::ISODate); TariffInterpolation.static_end = t; } } else if (QString(inner_obj_name) == QString("interpol_static_start_str")) { if (k->value.IsString()) { QString const &s = k->value.GetString(); TariffInterpolation.static_start_str = s; } } else if (QString(inner_obj_name) == QString("interpol_static_end_str")) { if (k->value.IsString()) { QString const &s = k->value.GetString(); TariffInterpolation.static_end_str = s; } } else if (QString(inner_obj_name) == QString("interpol_static_duration")) { if (k->value.IsInt()) { int const x = k->value.GetInt(); TariffInterpolation.static_duration = x; } } else if (QString(inner_obj_name) == QString("interpol_dynamic_start")) { if (k->value.IsString()) { QTime const &t = QTime::fromString(k->value.GetString(), Qt::ISODate); TariffInterpolation.dynamic_start = t; } } else if (QString(inner_obj_name) == QString("interpol_dynamic_end")) { if (k->value.IsString()) { QTime const &t = QTime::fromString(k->value.GetString(), Qt::ISODate); TariffInterpolation.dynamic_end = t; } } else if (QString(inner_obj_name) == QString("interpol_dynamic_start_str")) { if (k->value.IsString()) { QString const &s = k->value.GetString(); TariffInterpolation.dynamic_start_str = s; } } else if (QString(inner_obj_name) == QString("interpol_dynamic_end_str")) { if (k->value.IsString()) { QString const &s = k->value.GetString(); TariffInterpolation.dynamic_end_str = s; } } else if (QString(inner_obj_name) == QString("interpol_dynamic_duration")) { if (k->value.IsInt()) { int const x = k->value.GetInt(); TariffInterpolation.dynamic_duration = x; } } else if (QString(inner_obj_name) == QString("interpol_dynamic_until_price")) { if (k->value.IsInt()) { int const x = k->value.GetInt(); TariffInterpolation.dynamic_until_price = x; } } else if (QString(inner_obj_name) == QString("interpol_seemless")) { if (k->value.IsBool()) { bool const x = k->value.GetBool(); TariffInterpolation.seemless = x; } } if (QString(inner_obj_name) == QString("interpol_never")) { if (k->value.IsBool()) { bool const x = k->value.GetBool(); TariffInterpolation.never = x; } } } 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()) { TimeRange.time_range_id = k->value.GetInt(); } } else if (QString(inner_obj_name) == QString("time_range_from")) { 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; case MemberType::TimeBaseType: if (QString(inner_obj_name) == QString("tbase_id")) { if (k->value.IsInt()) { TimeBase.tbase_id = k->value.GetInt(); } } else if (QString(inner_obj_name) == QString("tbase_type")) { if (k->value.IsInt()) { int timeBase = k->value.GetInt(); switch (timeBase) { case (int)ATBTimeBase::TimeBaseType::ABSOLUTE: TimeBase.tbase_type = ATBTimeBase::TimeBaseType::ABSOLUTE; break; case (int)ATBTimeBase::TimeBaseType::RELATIVE: TimeBase.tbase_type = ATBTimeBase::TimeBaseType::RELATIVE; break; } } } break; case MemberType::TimeStepConfigType: if (QString(inner_obj_name) == QString("tsconfig_id")) { if (k->value.IsInt()) { TimeStepConfig.tsconfig_id = k->value.GetInt(); } } else if (QString(inner_obj_name) == QString("tsconfig_label")) { if (k->value.IsString()) { TimeStepConfig.tsconfig_label = QString::fromStdString(k->value.GetString()); } } break; case MemberType::DailyTicketType: if (QString(inner_obj_name) == QString("daily_ticket_payment_option_id")) { if (k->value.IsInt()) { DailyTicket.daily_ticket_payment_option_id = k->value.GetInt(); } } else if (QString(inner_obj_name) == QString("daily_ticket_id")) { if (k->value.IsInt()) { DailyTicket.daily_ticket_id = k->value.GetInt(); } } else if (QString(inner_obj_name) == QString("daily_ticket_price_id")) { if (k->value.IsInt()) { DailyTicket.daily_ticket_price_id = k->value.GetInt(); } } else if (QString(inner_obj_name) == QString("daily_ticket_tb_id")) { if (k->value.IsInt()) { DailyTicket.daily_ticket_tb_id = k->value.GetInt(); } } else if (QString(inner_obj_name) == QString("daily_ticket_clearance_customer_ids")) { if (k->value.IsArray()) { auto customerIds = k->value.GetArray(); for (rapidjson::SizeType i=0; i < customerIds.Size(); ++i) { if (customerIds[i].IsInt()) { DailyTicket.daily_ticket_clearance_customer_ids.append(customerIds[i].GetInt()); } } } } else if (QString(inner_obj_name) == QString("daily_ticket_from_min")) { if (k->value.IsString()) { std::string const from_min = k->value.GetString(); char const *from_min_c_str = from_min.c_str(); // for debugging DailyTicket.daily_ticket_from_min = QTime::fromString(from_min_c_str, Qt::ISODate); } } else if (QString(inner_obj_name) == QString("daily_ticket_to_max")) { if (k->value.IsString()) { std::string const to_max = k->value.GetString(); char const *to_max_c_str = to_max.c_str(); DailyTicket.daily_ticket_to_max = QTime::fromString(to_max_c_str, Qt::ISODate); } } else if (QString(inner_obj_name) == QString("daily_ticket_from_offset_min")) { if (k->value.IsInt()) { int const from_offset_min = k->value.GetInt(); DailyTicket.daily_ticket_from_offset_min = from_offset_min; } } else if (QString(inner_obj_name) == QString("daily_ticket_to_offset_max")) { if (k->value.IsInt()) { int to_offset_max = k->value.GetInt(); DailyTicket.daily_ticket_to_offset_max = to_offset_max; } } break; case MemberType::CustomerType: if (QString(inner_obj_name) == QString("cust_id")) { if (k->value.IsInt()) { Customer.cust_id = k->value.GetInt(); } } else if (QString(inner_obj_name) == QString("cust_type")) { if (k->value.IsInt()) { int cust_type = k->value.GetInt(); switch (cust_type) { case (int)ATBCustomer::CustomerType::ADULT: Customer.cust_type = ATBCustomer::CustomerType::ADULT; break; case (int)ATBCustomer::CustomerType::CHILD: Customer.cust_type = ATBCustomer::CustomerType::CHILD; break; case (int)ATBCustomer::CustomerType::TEEN: Customer.cust_type = ATBCustomer::CustomerType::TEEN; break; } } } else if (QString(inner_obj_name) == QString("cust_label")) { if (k->value.IsString()) { QString label(QString::fromStdString(k->value.GetString())); if (label.contains("ADULT", Qt::CaseInsensitive)) { Customer.cust_label = label; } else if (label.contains("CHILD", Qt::CaseInsensitive)) { Customer.cust_label = label; } else if (label.contains("TEEN", Qt::CaseInsensitive)) { Customer.cust_label = label; } } } break; case MemberType::CurrencyType: if (strcmp(inner_obj_name, "pcu_id") == 0) Currency.pcu_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pcu_sign") == 0) Currency.pcu_sign = k->value.GetString(); else if (strcmp(inner_obj_name, "pcu_major") == 0) Currency.pcu_major = k->value.GetString(); else if (strcmp(inner_obj_name, "pcu_minor") == 0) Currency.pcu_minor = k->value.GetString(); else if (strcmp(inner_obj_name, "pcu_active") == 0) Currency.pcu_active = k->value.GetBool(); break; case MemberType::PaymentMethodType: if (strcmp(inner_obj_name, "pme_id") == 0) PaymentMethod.pme_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pme_label") == 0) PaymentMethod.pme_label = k->value.GetString(); break; case MemberType::PaymentRateType: if (strcmp(inner_obj_name, "pra_payment_option_id") == 0) PaymentRate.pra_payment_option_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pra_payment_unit_id") == 0) PaymentRate.pra_payment_unit_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pra_price") == 0) PaymentRate.pra_price = k->value.GetDouble(); break; case MemberType::PaymentOptionType: if (strcmp(inner_obj_name, "pop_id") == 0) { this->currentPaymentOptions.append(ATBPaymentOption()); this->currentPaymentOptions.last().reset(); this->currentPaymentOptions.last().pop_id = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_label") == 0) { this->currentPaymentOptions.last().pop_label = k->value.GetString(); } else if (strcmp(inner_obj_name, "pop_payment_method_id") == 0) { this->currentPaymentOptions.last().pop_payment_method_id = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_day_end_time") == 0) { this->currentPaymentOptions.last().pop_day_end_time = k->value.GetString(); } else if (strcmp(inner_obj_name, "pop_day_night_end_time") == 0) { this->currentPaymentOptions.last().pop_day_night_end_time = k->value.GetString(); } else if (strcmp(inner_obj_name, "pop_price_night") == 0) { this->currentPaymentOptions.last().pop_price_night = k->value.GetDouble(); } else if (strcmp(inner_obj_name, "pop_min_time") == 0) { this->currentPaymentOptions.last().pop_min_time = k->value.GetDouble(); } else if (strcmp(inner_obj_name, "pop_max_price") == 0) { this->currentPaymentOptions.last().pop_max_price = k->value.GetDouble(); } else if (strcmp(inner_obj_name, "pop_max_time") == 0) { this->currentPaymentOptions.last().pop_max_time = k->value.GetDouble(); } else if (strcmp(inner_obj_name, "pop_min_price") == 0) { this->currentPaymentOptions.last().pop_min_price = k->value.GetDouble(); } else if (strcmp(inner_obj_name, "pop_prepaid_option_id") == 0) { this->currentPaymentOptions.last().pop_prepaid_option_id = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_truncate_last_interpolation_step") == 0) { this->currentPaymentOptions.last().pop_truncate_last_interpolation_step = k->value.GetBool(); } else if (strcmp(inner_obj_name, "pop_accumulate_prices") == 0) { this->currentPaymentOptions.last().pop_accumulate_prices = k->value.GetBool(); } else if (strcmp(inner_obj_name, "pop_accumulate_durations") == 0) { this->currentPaymentOptions.last().pop_accumulate_durations = k->value.GetBool(); } else if (strcmp(inner_obj_name, "pop_carry_over_option_id") == 0) { this->currentPaymentOptions.last().pop_carry_over_option_id = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_carry_over") == 0) { this->currentPaymentOptions.last().pop_carry_over = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_carry_over_time_range_id") == 0) { this->currentPaymentOptions.last().pop_carry_over_time_range_id = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_carry_over_start_time_range") == 0) { this->currentPaymentOptions.last().pop_carry_over_start_time_range = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_carry_over_end_time_range") == 0) { this->currentPaymentOptions.last().pop_carry_over_end_time_range = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_daily_card_price") == 0) { this->currentPaymentOptions.last().pop_daily_card_price = k->value.GetInt(); } else if (strcmp(inner_obj_name, "pop_business_hours") == 0) { if (k->value.IsInt()) { int const v = k->value.GetInt(); this->currentPaymentOptions.last().pop_business_hours = v; } else if (k->value.IsString()) { bool ok; uint64_t const v = QString::fromStdString(k->value.GetString()).toLongLong(&ok); if (ok) { this->currentPaymentOptions.last().pop_business_hours = v; } } } else if (strcmp(inner_obj_name, "pop_time_step_config") == 0) { this->currentPaymentOptions.last().pop_time_step_config = k->value.GetInt(); } else if ((strcmp(inner_obj_name, "pop_min_date_time") == 0) || (strcmp(inner_obj_name, "pop_max_date_time") == 0)) { if (k->value.IsString()) { // -w0dFriT16:20:00 or +w0dMonT00:00:00 static const QRegularExpression re(R"(([+-])w([0-9]+)d([A-Za-z]{3})T([0-9]{2}:[0-9]{2}:[0-9]{2}))"); QString const &s = QString::fromStdString(k->value.GetString()); QRegularExpressionMatch match = re.match(s); if (match.hasMatch()) { ATBPaymentOption::ATBMaxDateTime dt; int lastCaptured = match.lastCapturedIndex(); if (lastCaptured == 4) { dt.direction = (match.captured(1) == "-") ? -1 : +1; bool ok; uint8_t week = match.captured(2).toUInt(&ok); if (ok) { dt.week = week; } QString const &day = match.captured(3); if (day.compare("Mon", Qt::CaseInsensitive) == 0) { dt.day = (int)Qt::Monday; } else if (day.compare("Tue", Qt::CaseInsensitive) == 0) { dt.day = (int)Qt::Tuesday; } else if (day.compare("Wed", Qt::CaseInsensitive) == 0) { dt.day = (int)Qt::Wednesday; } else if (day.compare("Thu", Qt::CaseInsensitive) == 0) { dt.day = (int)Qt::Thursday; } else if (day.compare("Fri", Qt::CaseInsensitive) == 0) { dt.day = (int)Qt::Friday; } else if (day.compare("Sat", Qt::CaseInsensitive) == 0) { dt.day = (int)Qt::Saturday; } else if (day.compare("Sun", Qt::CaseInsensitive) == 0) { dt.day = (int)Qt::Sunday; } QTime t = QTime::fromString(match.captured(4), Qt::ISODate); if (t.isValid()) { dt.time = t; } } if (strcmp(inner_obj_name, "pop_min_date_time") == 0) { this->currentPaymentOptions.last().pop_min_date_time = dt; } else if (strcmp(inner_obj_name, "pop_max_date_time") == 0) { this->currentPaymentOptions.last().pop_max_date_time = dt; } } } } else if (strcmp(inner_obj_name, "pop_carry_over_target") == 0) { if (k->value.IsBool()) { bool const v = k->value.GetBool(); this->currentPaymentOptions.last().pop_carry_over_target = v; } } break; case MemberType::DurationType: if (strcmp(inner_obj_name, "pun_id") == 0) Duration.pun_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pun_label") == 0) Duration.pun_label = k->value.GetString(); else if (strcmp(inner_obj_name, "pun_duration") == 0) Duration.pun_duration = k->value.GetDouble(); else if (strcmp(inner_obj_name, "pun_duration_min") == 0) Duration.pun_duration_min = k->value.GetInt(); else if (strcmp(inner_obj_name, "pun_duration_max") == 0) Duration.pun_duration_max = k->value.GetInt(); else if (strcmp(inner_obj_name, "pun_interpolation_id") == 0) Duration.pun_interpolation_id = k->value.GetInt(); break; case MemberType::SpecialDaysWorktimeType: if (strcmp(inner_obj_name, "pedwt_id") == 0) SpecialDaysWorktime.pedwt_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pedwt_period_exc_day_id") == 0) SpecialDaysWorktime.pedwt_period_exc_day_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pedwt_time_from") == 0) SpecialDaysWorktime.pedwt_time_from = k->value.GetString(); else if (strcmp(inner_obj_name, "pedwt_time_to") == 0) SpecialDaysWorktime.pedwt_time_to = k->value.GetString(); else if (strcmp(inner_obj_name, "pedwt_price") == 0) SpecialDaysWorktime.pedwt_price = k->value.GetDouble(); break; /*case MemberType::WeekDaysType: if (strcmp(inner_obj_name, "pdiw_id") == 0) WeekDays.pdiw_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pdiw_label") == 0) WeekDays.pdiw_label = k->value.GetString(); else if (strcmp(inner_obj_name, "pdiw_index") == 0) WeekDays.pdiw_index = k->value.GetInt(); break;*/ case MemberType::WeekDaysWorkTimeType: if (strcmp(inner_obj_name, "pwd_id") == 0) WeekDaysWorktime.pwd_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pwd_period_week_day_id") == 0) WeekDaysWorktime.pwd_period_week_day_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pwd_period_day_in_week_id") == 0) WeekDaysWorktime.pwd_period_day_in_week_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pwd_time_from") == 0) WeekDaysWorktime.pwd_time_from = k->value.GetString(); else if (strcmp(inner_obj_name, "pwd_time_to") == 0) WeekDaysWorktime.pwd_time_to = k->value.GetString(); break; case MemberType::SpecialDaysType: if (strcmp(inner_obj_name, "ped_id") == 0) SpecialDays.ped_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "ped_label") == 0) SpecialDays.ped_label = k->value.GetString(); else if (strcmp(inner_obj_name, "ped_date_start") == 0) SpecialDays.ped_date_start = k->value.GetString(); else if (strcmp(inner_obj_name, "ped_date_end") == 0) SpecialDays.ped_date_end = k->value.GetString(); else if (strcmp(inner_obj_name, "ped_period_special_day_id") == 0) SpecialDays.ped_period_special_day_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "ped_payment_option_id") == 0) SpecialDays.ped_payment_option_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "ped_year") == 0) SpecialDays.ped_year = k->value.GetInt(); break; case MemberType::PeriodYearType: if (strcmp(inner_obj_name, "pye_id") == 0) YearPeriod.pye_id = k->value.GetInt(); else if (strcmp(inner_obj_name, "pye_label") == 0) YearPeriod.pye_label = k->value.GetString(); else if (strcmp(inner_obj_name, "pye_start_month") == 0) YearPeriod.pye_start_month = k->value.GetInt(); else if (strcmp(inner_obj_name, "pye_start_day") == 0) YearPeriod.pye_start_day = k->value.GetInt(); else if (strcmp(inner_obj_name, "pye_end_month") == 0) YearPeriod.pye_end_month = k->value.GetInt(); else if (strcmp(inner_obj_name, "pye_end_day") == 0) YearPeriod.pye_end_day = k->value.GetInt(); break; default: break; } //#pragma endregion } // Push to specific list depending on member type switch (mb_type) { case MemberType::UnknownType: break; case MemberType::PaymentMethodType: cfg->PaymentMethod.insert(pair(PaymentMethod.pme_id, PaymentMethod)); break; case MemberType::PaymentRateType: // qCritical() << "PaymentRate" << PaymentRate.pra_price << PaymentRate.pra_payment_option_id; cfg->PaymentRate.insert(pair(PaymentRate.pra_payment_option_id, PaymentRate)); break; case MemberType::PaymentOptionType: { if (!this->currentPaymentOptions.isEmpty()) { ATBPaymentOption const &PaymentOption = this->currentPaymentOptions.last(); cfg->PaymentOption.insert(pair(PaymentOption.pop_payment_method_id, PaymentOption)); } } break; case MemberType::DurationType: cfg->Duration.insert(pair(Duration.pun_id, Duration)); // qCritical() << Duration; break; case MemberType::SpecialDaysWorktimeType: cfg->SpecialDaysWorktime.insert(pair(SpecialDaysWorktime.pedwt_period_exc_day_id, SpecialDaysWorktime)); break; //case MemberType::WeekDaysType: // cfg->WeekDays.insert(pair(WeekDays.pdiw_index, WeekDays)); // break; case MemberType::WeekDaysWorkTimeType: cfg->WeekDaysWorktime.insert(pair(WeekDaysWorktime.pwd_period_day_in_week_id, WeekDaysWorktime)); break; case MemberType::SpecialDaysType: cfg->SpecialDays.insert(pair(SpecialDays.ped_id, SpecialDays)); break; case MemberType::PeriodYearType: cfg->YearPeriod.insert(pair(YearPeriod.pye_id, YearPeriod)); break; case MemberType::DailyTicketType: cfg->DailyTicket.insert(pair(DailyTicket.daily_ticket_id, DailyTicket)); qCritical() << DailyTicket; DailyTicket.reset(); break; case MemberType::CustomerType: cfg->Customer.insert(pair(Customer.cust_id, Customer)); qCritical() << Customer; break; case MemberType::TimeBaseType: cfg->TimeBase.insert(pair(TimeBase.tbase_id, TimeBase)); qCritical() << TimeBase; break; case MemberType::TimeRangeType: cfg->TimeRange.insert(pair(TimeRange.time_range_id, TimeRange)); //qCritical() << TimeRange; break; case MemberType::TimeStepConfigType: cfg->TimeStepConfig.insert(pair(TimeStepConfig.tsconfig_id, TimeStepConfig)); // qCritical() << TimeStepConfig; break; case MemberType::ProductType: cfg->TariffProduct.insert(pair(TariffProduct.m_tariff_product_id, TariffProduct)); qCritical() << TariffProduct; break; case MemberType::InterpolationType: cfg->TariffInterpolations.insert(pair(TariffInterpolation.id, TariffInterpolation)); qCritical() << TariffInterpolation; break; case MemberType::PrepaidType: cfg->TariffPrepaidOptions.insert(pair(TariffPrepaidOption.id, TariffPrepaidOption)); qCritical() << TariffPrepaidOption; break; case MemberType::CarryOverType: cfg->TariffCarryOverOptions.insert(pair(TariffCarryOver.id, TariffCarryOver)); qCritical() << TariffCarryOver; break; default: break; } } } return true; } catch (...) { printf("%s\n", "General exception has occurred while parsing JSON\n"); return false; } } std::optional Configuration::getInterpolationEnd(QDateTime const &start, int paymentOptionIndex) const { int const pop_id = getPaymentOptions(paymentOptionIndex).pop_id; int const pop_carry_over_option_id = getPaymentOptions(paymentOptionIndex).pop_carry_over_option_id; int const pop_truncate_last_interpolation_step = getPaymentOptions(paymentOptionIndex).pop_truncate_last_interpolation_step; int const weekDay = start.date().dayOfWeek(); //QTime const &carryOverStart = TariffCarryOverOptions.find(pop_carry_over_option_id)->second.carryover[weekDay].static_start; //QTime const &carryOverEnd = TariffCarryOverOptions.find(pop_carry_over_option_id)->second.carryover[weekDay].static_end; //bool const carry_over_seemless = TariffCarryOverOptions.find(pop_carry_over_option_id)->second.carryover[weekDay].seemless; //bool const carry_over_never = TariffCarryOverOptions.find(pop_carry_over_option_id)->second.carryover[weekDay].never; int const carryOverDuration = TariffCarryOverOptions.find(pop_carry_over_option_id)->second.carryover[weekDay].duration; std::optional value = std::nullopt; QDateTime interpolationEndTime = start; //qCritical() << "(" << __func__ << ":" << __LINE__ << ") computed interpol end:" << interpolationEndTime.toString(Qt::ISODate); int price = 0; for (auto[itr, rangeEnd] = PaymentRate.equal_range(pop_id); itr != rangeEnd; ++itr) { int const durationId = itr->second.pra_payment_unit_id; // int const price = itr->second.pra_price; auto search = Duration.find(durationId); if (search != Duration.end()) { ATBDuration duration = search->second; if (duration.pun_interpolation_id == -1) { // should never happen -> misconfigured tariff-file qCritical() << "(" << __func__ << ":" << __LINE__ << ") ERROR pun_interpolation not set!"; qCritical() << "(" << __func__ << ":" << __LINE__ << ") See for instance customer_505/6"; break; } std::optional ipolCheck = getInterpolationType(duration.pun_interpolation_id); if (ipolCheck) { ATBInterpolation interpolation = ipolCheck.value(); switch (duration.pun_interpolation_id) { case static_cast(ATBInterpolation::NO_INTERPOLATION): //qCritical() << "(" << __func__ << ":" << __LINE__ << ") TODO"; break; case static_cast(ATBInterpolation::STATIC_WALLCLOCK_TIME_VALUES): //qCritical() << "(" << __func__ << ":" << __LINE__ << ") TODO"; break; case static_cast(ATBInterpolation::STATIC_TIMEPOINT_AND_DURATION): //qCritical() << "(" << __func__ << ":" << __LINE__ << ") TODO"; break; case static_cast(ATBInterpolation::DYNAMIC_TIMEPOINT_AND_STATIC_DURATION): //qCritical() << "(" << __func__ << ":" << __LINE__ << ") TODO"; break; case static_cast(ATBInterpolation::DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_DURATION): //qCritical() << "(" << __func__ << ":" << __LINE__ << ") TODO"; break; case static_cast(ATBInterpolation::DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_PRICE): { interpolation.dynamic_start = start.time(); interpolation.dynamic_start.setHMS(start.time().hour(), start.time().minute(), 0); //qCritical() << "(" << __func__ << ":" << __LINE__ << ") interpol start:" << interpolation.dynamic_start.toString(Qt::ISODate); //qCritical() << "(" << __func__ << ":" << __LINE__ << ") computed interpol end so far:" << interpolationEndTime.toString(Qt::ISODate); if (interpolation.seemless) { qCritical() << "(" << __func__ << ":" << __LINE__ << ") TODO"; } else if (interpolation.never) { qCritical() << "(" << __func__ << ":" << __LINE__ << ") TODO"; } else { QDateTime const &s = interpolationEndTime.addSecs(duration.pun_duration * 60); int const minutesToStaticEnd = s.time().secsTo(interpolation.static_end) / 60; //qCritical() << "(" << __func__ << ":" << __LINE__ << ") computed interpol end so far:" << s.toString(Qt::ISODate); //qCritical() << "(" << __func__ << ":" << __LINE__ << ") interpol static end:" << interpolation.static_end.toString(Qt::ISODate); //qCritical() << "(" << __func__ << ":" << __LINE__ << ") minutes to static end:" << minutesToStaticEnd; //qCritical() << "(" << __func__ << ":" << __LINE__ << ") pun-id:" << duration.pun_id; int p = 0; for (auto[it, rangeEnd] = this->PaymentRate.equal_range(pop_id); it != rangeEnd; ++it) { if (it->second.pra_payment_unit_id == duration.pun_id) { if (minutesToStaticEnd >= 0) { // the end of the interpolation for this day must be before a possible carry over interval p = it->second.pra_price; //qCritical() << "(" << __func__ << ":" << __LINE__ << ") next price:" << p; price += p; interpolationEndTime = s; } else { if (pop_truncate_last_interpolation_step == false) { p = it->second.pra_price; //qCritical() << "(" << __func__ << ":" << __LINE__ << ") next price:" << p; price += p; interpolationEndTime = s; interpolationEndTime = interpolationEndTime.addSecs(carryOverDuration * 60); } else { qCritical() << "(" << __func__ << ":" << __LINE__ << ") TODO"; } } } } //qCritical() << "(" << __func__ << ":" << __LINE__ << ") price:" << price; if (price >= interpolation.dynamic_until_price) { // qCritical() << "(" << __func__ << ":" << __LINE__ << ") price:" << price; // qCritical() << "(" << __func__ << ":" << __LINE__ << ") computed interpol end:" << interpolationEndTime.toString(Qt::ISODate); value = value.value_or(interpolationEndTime); break; } } } break; case static_cast(ATBInterpolation::DYNAMIC_ABSTRACT_TIMEPOINT_AND_STATIC_END_TIME): break; default:; } } } } return value; } int Configuration::getPaymentOptionIndexIfSpecialDay(QDateTime const &dt) const { if (isSpecialDay(dt)) { int const numOptions = getAllPaymentOptions().size(); for (int opt=0; opt < numOptions; ++opt) { uint64_t const pop_business_hours = getPaymentOptions(opt).pop_business_hours; if ((pop_business_hours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY) { return opt; } } } return -1; } int Configuration::getPaymentOptionIndex(QDateTime const &dt) const { int const numOptions = getAllPaymentOptions().size(); // special days are handled before usual week days int const sid = specialDayId(dt); if (sid > 0) { ATBSpecialDays const sd = specialDay(dt); if (sd.ped_id != 0) { for (int opt=0; opt < numOptions; ++opt) { uint64_t const pop_id = getPaymentOptions(opt).pop_id; if (pop_id == (uint64_t)sd.ped_payment_option_id) { return opt; } } } } for (int opt=0; opt < numOptions; ++opt) { uint64_t const pop_business_hours = getPaymentOptions(opt).pop_business_hours; uint64_t p = 0; int const dayOfWeek = dt.date().dayOfWeek(); switch (dayOfWeek) { case (int)Qt::Monday: { p = BusinessHours::MON; } break; case (int)Qt::Tuesday: { p = BusinessHours::TUE; } break; case (int)Qt::Wednesday: { p = BusinessHours::WED; } break; case (int)Qt::Thursday: { p = BusinessHours::THU; } break; case (int)Qt::Friday: { p = BusinessHours::FRI; } break; case (int)Qt::Saturday: { p = BusinessHours::SAT; } break; case (int)Qt::Sunday: { p = BusinessHours::SUN; qCritical() << DBG_HEADER << Utilities::dumpBusinessHours(pop_business_hours) << pop_business_hours << p; } break; } if ((pop_business_hours & p) == p) { return opt; } } qCritical() << DBG_HEADER << "ERROR: DEFAULT VALUE OF '0' RETURNED AS STATIC VALUE"; return 0; } ATBSpecialDays Configuration::specialDay(QDateTime const &dt) const { SpecialDaysType::const_iterator it; for (it = SpecialDays.cbegin(); it != SpecialDays.cend(); ++it) { if (dt.date().toString(Qt::ISODate) == QString::fromStdString(it->second.ped_date_start)) { return it->second; } } return ATBSpecialDays(); } int Configuration::specialDayId(QDateTime const &dt) const { SpecialDaysType::const_iterator it; for (it = SpecialDays.cbegin(); it != SpecialDays.cend(); ++it) { if (dt.date().toString(Qt::ISODate) == QString::fromStdString(it->second.ped_date_start)) { int const specialDayId = it->second.ped_id; return specialDayId; // must be > 0 } } return 0; } bool Configuration::isSpecialDay(QDateTime const &dt) const { return (specialDayId(dt) > 0); } bool Configuration::isDayIncludedAsSpecialDay(uint64_t businessHours, int specialDayId) const { if (specialDayId > 0) { bool const &r = ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY); return r; } return false; } bool Configuration::isDayIncludedAsSpecialDay(uint64_t businessHours, QDateTime const &dt) const { // included in 'businessHours' if (isSpecialDay(dt)) { bool const &r = ((businessHours & BusinessHours::OFFICIAL_HOLIDAY) == BusinessHours::OFFICIAL_HOLIDAY); qCritical() << "XXXXXXXXXXXXXXXXXX r" << r << businessHours; return r; } return false; } bool Configuration::isDayIncluded(uint64_t businessHours, QDateTime const &dt) const { return Utilities::isDayIncluded(businessHours, dt); } ATBPaymentOption const &Configuration::getPaymentOptions(int paymentOptionsIndex) const { Q_ASSERT(!this->currentPaymentOptions.isEmpty()); return this->currentPaymentOptions.at(paymentOptionsIndex); } ATBPaymentOption &Configuration::getPaymentOptions(int paymentOptionsIndex) { Q_ASSERT(!this->currentPaymentOptions.isEmpty()); return this->currentPaymentOptions[paymentOptionsIndex]; } QVector const &Configuration::getAllPaymentOptions() const { return this->currentPaymentOptions; } QVector &Configuration::getAllPaymentOptions() { return this->currentPaymentOptions; } std::optional> Configuration::getTariffProductForAllKeys() const { QVector products; std::optional> value; products.clear(); for (std::multimap::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> Configuration::getTariffProductForProductTypeName(QString const &permitTypeName) const { QVector products; std::optional> value; products.clear(); for(const auto &product: this->TariffProduct) { ATBTariffProduct const &v = product.second; if (v.m_tariff_product_name == permitTypeName) { products.append(v); } } if (products.size() > 0) { value = value.value_or(products); } return value; } std::optional> Configuration::getTariffProductForProductId(PermitType permitType) const { QString permitTypeName(permitType); return getTariffProductForProductTypeName(permitTypeName); /* QVector products; std::optional> 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> Configuration::getTariffProductForProductId(int id) const { return getTariffProductForProductId(PermitType(id)); } std::optional> Configuration::getDailyTicketsForAllKeys() const { QVector tickets; std::optional> value; for (std::multimap::const_iterator it = this->DailyTicket.cbegin(); it != this->DailyTicket.cend(); ++it) { tickets.append(it->second); } if (tickets.size() > 0) { value = value.value_or(tickets); } return value; } std::optional Configuration::getInterpolationType(int key) const { std::optional value; for (auto[it, rangeEnd] = this->TariffInterpolations.equal_range(key); it != rangeEnd; ++it) { value = value.value_or(it->second); } return value; } std::optional Configuration::getPrepaidType(int key) const { std::optional value; for (auto[it, rangeEnd] = this->TariffPrepaidOptions.equal_range(key); it != rangeEnd; ++it) { value = value.value_or(it->second); } return value; } std::optional Configuration::prepaidStart(QDateTime const &start, int prepaid_option_id) { std::optional value; QDateTime s = start; qCritical() << "(" << __func__ << ":" << __LINE__ << ") prepaid option id:" << prepaid_option_id; std::optional prepaid_option = getPrepaidType(prepaid_option_id); if (prepaid_option.has_value()) { ATBPrepaid prepaid = prepaid_option.value(); if (prepaid.anytime == false && prepaid.never == false) { // start: 22:00, end: 08:00 QTime prepaidStart = TariffPrepaidOptions.find(prepaid_option_id)->second.static_start; QTime prepaidEnd = TariffPrepaidOptions.find(prepaid_option_id)->second.static_end; if (s.time() >= prepaidStart) { s = s.addDays(1); s.setTime(prepaidEnd); } else if (s.time() < prepaidEnd) { s.setTime(prepaidEnd); } s.setTime(QTime(s.time().hour(), s.time().minute(), 0)); value = value.value_or(s); } } return value; } std::optional> Configuration::getDailyTicketsForKey(int key) const { QVector tickets; std::optional> value; tickets.clear(); for (auto[it, rangeEnd] = this->DailyTicket.equal_range(key); it != rangeEnd; ++it) { tickets.append(it->second); } if (tickets.size() > 0) { value = value.value_or(tickets); } return value; } std::optional> Configuration::getPaymentRateForAllKeys() const { QVector paymentRates; std::optional> value; for (std::multimap::const_iterator it = this->PaymentRate.cbegin(); it != this->PaymentRate.cend(); ++it) { paymentRates.append(it->second); } if (paymentRates.size() > 0) { value = value.value_or(paymentRates); } return value; } std::optional> Configuration::getPaymentRateForKey(int key) const { QVector paymentRate; std::optional> value; paymentRate.clear(); for (auto[it, rangeEnd] = this->PaymentRate.equal_range(key); it != rangeEnd; ++it) { paymentRate.append(it->second); } if (paymentRate.size() > 0) { value = value.value_or(paymentRate); } return value; } std::optional Configuration::getCustomerForType(ATBCustomer::CustomerType customerType) { for (std::multimap::const_iterator it = this->Customer.cbegin(); it != this->Customer.cend(); ++it) { ATBCustomer const &customer = it->second; if (customer.cust_type == customerType) { return customer; } } return std::nullopt; } std::optional Configuration::getWeekDayWorkTime(QTime const &time, Qt::DayOfWeek dayOfWeek) { ATBWeekDaysWorktime worktime; std::optional value; std::multimap::const_iterator it = this->WeekDaysWorktime.find((int)dayOfWeek); if (it != this->WeekDaysWorktime.cend()) { ATBWeekDaysWorktime const &wt = it->second; if (time >= QTime::fromString(wt.pwd_time_from.c_str(), Qt::ISODate) && time < QTime::fromString(wt.pwd_time_to.c_str(), Qt::ISODate)) { value = value.value_or(wt); } } return value; }