Files
prodejna/shop/eet/eetv4adapter.cpp
2026-10-14 22:38:06 +02:00

153 lines
4.0 KiB
C++

#include "eetv4adapter.h"
#include <QRegularExpression>
namespace
{
void setError(QString *error, const QString &message)
{
if (error != nullptr)
{
*error = message;
}
}
QDateTime withExplicitOffset(const QDateTime &dateTime)
{
if (!dateTime.isValid())
{
return {};
}
return dateTime.timeSpec() == Qt::LocalTime
? dateTime.toOffsetFromUtc(dateTime.offsetFromUtc())
: dateTime;
}
}
bool EetV4ShopConfig::validate(QString *error) const
{
if (!endpoint.isValid() || endpoint.scheme().compare(QStringLiteral("https"),
Qt::CaseInsensitive) != 0)
{
setError(error, QStringLiteral("EET v4 endpoint must be a valid HTTPS URL."));
return false;
}
if (taxpayerEic.isEmpty())
{
setError(error, QStringLiteral("EET v4 taxpayer EIC must not be empty."));
return false;
}
if (unitId < 1)
{
setError(error, QStringLiteral("EET v4 unit ID must be positive."));
return false;
}
if (cashRegisterId.isEmpty())
{
setError(error, QStringLiteral("EET v4 cash-register ID must not be empty."));
return false;
}
if (timeoutMilliseconds < 1)
{
setError(error, QStringLiteral("EET v4 timeout must be positive."));
return false;
}
return true;
}
bool EetV4ShopAdapter::amountText(const QDecDouble &amount,
QString *text,
QString *error)
{
QString value = QString::fromLatin1(amount.toString());
if (value.contains(QRegularExpression(QStringLiteral("[eE]"))))
{
setError(error, QStringLiteral("Voucher amount must not use exponential notation."));
return false;
}
if (!value.contains(QLatin1Char('.')))
{
value += QStringLiteral(".00");
}
else
{
const int decimals = value.size() - value.indexOf(QLatin1Char('.')) - 1;
if (decimals > 2)
{
setError(error, QStringLiteral("Voucher amount has more than two decimal places."));
return false;
}
value = value.leftJustified(value.size() + (2 - decimals), QLatin1Char('0'));
}
EetV4Amount parsed;
if (!EetV4Amount::fromString(value, &parsed, error))
{
return false;
}
if (text != nullptr)
{
*text = parsed.toString();
}
return true;
}
bool EetV4ShopAdapter::createRequest(const Voucher &voucher,
const EetV4ShopConfig &config,
EetV4SaleRequest *request,
QString *error)
{
if (request == nullptr)
{
setError(error, QStringLiteral("EET v4 request output must not be null."));
return false;
}
if (!config.validate(error))
{
return false;
}
const QDateTime saleAt = withExplicitOffset(voucher.payDateTime());
if (!saleAt.isValid())
{
setError(error, QStringLiteral("Voucher payment date must be valid."));
return false;
}
QString totalText;
if (!amountText(voucher.totalPrice(), &totalText, error))
{
return false;
}
EetV4Amount total;
if (!EetV4Amount::fromString(totalText, &total, error))
{
return false;
}
EetV4SaleRequest result;
result.sentAt = withExplicitOffset(QDateTime::currentDateTime());
result.saleAt = saleAt;
result.firstSubmission = voucher.eetStatus() == Voucher::EET_FOR_SEND;
result.verificationMode = config.verificationMode;
result.taxpayerEic = config.taxpayerEic;
result.unitId = config.unitId;
result.cashRegisterId = config.cashRegisterId;
result.receiptNumber = voucher.numSer();
result.totalSale = total;
QStringList validationErrors;
if (!result.validate(&validationErrors))
{
setError(error, validationErrors.join(QStringLiteral("; ")));
return false;
}
*request = result;
return true;
}