File indexing completed on 2024-12-22 04:59:46

0001 /*
0002     SPDX-FileCopyrightText: 2023 Volker Krause <vkrause@kde.org>
0003     SPDX-License-Identifier: LGPL-2.0-or-later
0004 */
0005 
0006 #include "priceutil.h"
0007 
0008 #include <KItinerary/JsonLdDocument>
0009 #include <KItinerary/Reservation>
0010 #include <KItinerary/Ticket>
0011 
0012 #include <cmath>
0013 
0014 using namespace KItinerary;
0015 
0016 bool PriceUtil::hasPrice(const QVariant &item)
0017 {
0018     if (!PriceUtil::canHavePrice(item)) {
0019         return false;
0020     }
0021 
0022     if (!std::isnan(JsonLdDocument::readProperty(item, "totalPrice").toDouble()) && !JsonLdDocument::readProperty(item, "priceCurrency").isNull()) {
0023         return true;
0024     }
0025 
0026     if (JsonLd::canConvert<Reservation>(item)) {
0027         return PriceUtil::hasPrice(JsonLd::convert<Reservation>(item).reservedTicket());
0028     }
0029 
0030     return false;
0031 }
0032 
0033 bool PriceUtil::canHavePrice(const QVariant &item)
0034 {
0035     return JsonLd::isA<Ticket>(item) || (JsonLd::canConvert<Reservation>(item) && !JsonLd::isA<FoodEstablishmentReservation>(item));
0036 }
0037 
0038 double PriceUtil::price(const QVariant &item)
0039 {
0040     if (JsonLd::canConvert<Reservation>(item)) {
0041         const auto res = JsonLd::convert<Reservation>(item);
0042         return  !std::isnan(res.totalPrice()) ? res.totalPrice() : PriceUtil::price(res.reservedTicket());
0043     }
0044 
0045     if (JsonLd::isA<Ticket>(item)) {
0046         return item.value<Ticket>().totalPrice();
0047     }
0048 
0049     return NAN;
0050 }
0051 
0052 QString PriceUtil::currency(const QVariant &item)
0053 {
0054     if (JsonLd::canConvert<Reservation>(item)) {
0055         const auto res = JsonLd::convert<Reservation>(item);
0056         return !res.priceCurrency().isEmpty() ? res.priceCurrency() : PriceUtil::currency(res.reservedTicket());
0057     }
0058 
0059     if (JsonLd::isA<Ticket>(item)) {
0060         return item.value<Ticket>().priceCurrency();
0061     }
0062 
0063     return {};
0064 }
0065 
0066 void PriceUtil::setPrice(QVariant &item, double price, const QString &currency)
0067 {
0068     // TODO check if there is a price on a nested ticket already, and set/replace that
0069     JsonLdDocument::writeProperty(item, "totalPrice", price);
0070     JsonLdDocument::writeProperty(item, "priceCurrency", currency);
0071 }
0072 
0073 // ### keep sorted by ISO code, only needs to contain those != 2
0074 // @see https://en.wikipedia.org/wiki/List_of_circulating_currencies
0075 struct {
0076     const char isoCode[4];
0077     const uint8_t decimals;
0078 } static constexpr const currency_decimals_map[] = {
0079     { "BHD", 3 },
0080     { "CNY", 1 },
0081     { "IQD", 3 },
0082     { "IRR", 0 },
0083     { "KWD", 3 },
0084     { "LYD", 3 },
0085     { "MGA", 1 },
0086     { "MRU", 1 },
0087     { "OMR", 3 },
0088     { "TND", 3 },
0089     { "VND", 1 },
0090 };
0091 
0092 int PriceUtil::decimalCount(QStringView currency)
0093 {
0094   const auto it = std::lower_bound(
0095       std::begin(currency_decimals_map), std::end(currency_decimals_map),
0096       currency, [](const auto &m, QStringView isoCode) {
0097         return QLatin1StringView(m.isoCode, 3) < isoCode;
0098       });
0099   if (it != std::end(currency_decimals_map) &&
0100       QLatin1StringView((*it).isoCode, 3) == currency) {
0101     return (*it).decimals;
0102   }
0103     return 2;
0104 }
0105 
0106 int PriceUtil::decimalCount(const QString &currency)
0107 {
0108     return PriceUtil::decimalCount(QStringView(currency));
0109 }
0110 
0111 #include "moc_priceutil.cpp"