add new eet and qt 6.12

This commit is contained in:
2026-10-14 22:38:06 +02:00
parent 464216d6c3
commit 99f98b0451
17 changed files with 505 additions and 100 deletions
+3
View File
@@ -7,3 +7,6 @@
[submodule "3rdparty/LimeReport"]
path = 3rdparty/LimeReport
url = https://github.com/fralx/LimeReport.git
[submodule "3rdparty/EetCpp"]
path = 3rdparty/EetCpp
url = https://gitea.itsolved.cz/ITsolved/EetCpp.git
+25 -2
View File
@@ -3,11 +3,35 @@ project(prodejna-root)
include(CTest)
option(ENABLE_ZINT "Enable LimeReport barcode support" ON)
option(ENABLE_EET_V4 "Enable EET v4 integration" OFF)
find_package(Qt6 6.11.2 REQUIRED COMPONENTS Core Core5Compat Test Gui Widgets PrintSupport Sql Qml Network Xml Svg)
set(EETCPP_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/EetCpp" CACHE PATH
"Path to the EetCpp source tree when EET v4 integration is enabled")
find_package(Qt6 6.12 REQUIRED COMPONENTS Core Core5Compat Test Gui Widgets PrintSupport Sql Qml Network Xml Svg)
set(CMAKE_POLICY_VERSION_MINIMUM 3.10)
if(ENABLE_EET_V4)
if(NOT EETCPP_SOURCE_DIR)
message(FATAL_ERROR
"ENABLE_EET_V4 requires EETCPP_SOURCE_DIR pointing to the EetCpp source tree")
endif()
if(NOT EXISTS "${EETCPP_SOURCE_DIR}/CMakeLists.txt")
message(FATAL_ERROR
"EETCPP_SOURCE_DIR does not contain a CMakeLists.txt: ${EETCPP_SOURCE_DIR}")
endif()
set(EETCPP_BUILD_PLAYGROUND OFF CACHE BOOL
"Build the EetCpp Playground CLI" FORCE)
set(_prodejna_build_testing "${BUILD_TESTING}")
set(BUILD_TESTING OFF)
add_subdirectory("${EETCPP_SOURCE_DIR}"
"${CMAKE_BINARY_DIR}/_deps/eetcpp-build"
EXCLUDE_FROM_ALL)
set(BUILD_TESTING "${_prodejna_build_testing}")
endif()
add_subdirectory(3rdparty/qdecimal)
add_subdirectory(3rdparty/QxOrm)
set(USE_QT6 ON CACHE BOOL "Build LimeReport with Qt6" FORCE)
@@ -26,4 +50,3 @@ add_subdirectory(camp)
if(BUILD_TESTING)
add_subdirectory(tests)
endif()
+1 -1
View File
@@ -8,7 +8,7 @@
"configurePresets": [
{
"name": "qt6-debug",
"displayName": "Qt 6.11.2+ Debug",
"displayName": "Qt 6.12+ Debug",
"generator": "Ninja",
"binaryDir": "${sourceDir}/build/presets/${presetName}",
"cacheVariables": {
+10 -1
View File
@@ -92,4 +92,13 @@ target_link_libraries(shop
QxOrm
core
addressbook
)
)
if(ENABLE_EET_V4)
target_sources(shop PRIVATE
eet/eetv4adapter.cpp
eet/eetv4adapter.h
)
target_link_libraries(shop EetCpp::EetCpp)
target_compile_definitions(shop PRIVATE PRODEJNA_EET_V4)
endif()
+11
View File
@@ -30,6 +30,7 @@ namespace qx {
t.data(&Voucher::m_eetPkp, "eetPkp");
t.data(&Voucher::m_eetBkp, "eetBkp");
t.data(&Voucher::m_eetFik, "eetFik");
t.data(&Voucher::m_eetPok, "eetPok");
t.data(&Voucher::m_saveDateTime, "saveDateTime");
t.data(&Voucher::m_createdBy, "createdBy");
t.data(&Voucher::m_created, "created");
@@ -329,6 +330,16 @@ void Voucher::setEetFik(const QString &eetFik)
m_eetFik = eetFik;
}
QString Voucher::eetPok() const
{
return m_eetPok;
}
void Voucher::setEetPok(const QString &eetPok)
{
m_eetPok = eetPok;
}
QDateTime Voucher::saveDateTime() const
{
return m_saveDateTime;
+5
View File
@@ -36,6 +36,7 @@ class SHOPSHARED_EXPORT Voucher : public QObject
Q_PROPERTY(QString eetBkp READ eetBkp WRITE setEetBkp)
Q_PROPERTY(QString eetPkp READ eetPkp WRITE setEetPkp)
Q_PROPERTY(QString eetFik READ eetFik WRITE setEetFik)
Q_PROPERTY(QString eetPok READ eetPok WRITE setEetPok)
Q_PROPERTY(VoucherStatus status READ status WRITE setStatus)
Q_PROPERTY(QString createdBy READ createdBy WRITE setCreatedBy)
Q_PROPERTY(QString updatedBy READ updatedBy WRITE setUpdatedBy)
@@ -147,6 +148,9 @@ public:
QString eetFik() const;
void setEetFik(const QString &eetFik);
QString eetPok() const;
void setEetPok(const QString &eetPok);
QDateTime saveDateTime() const;
void setSaveDateTime(const QDateTime &saveDateTime);
@@ -192,6 +196,7 @@ private:
QString m_eetPkp;
QString m_eetBkp;
QString m_eetFik;
QString m_eetPok;
QList<QSharedPointer<VoucherItem>> m_items;
VoucherStatus m_status;
SeasonPtr m_season;
+152
View File
@@ -0,0 +1,152 @@
#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;
}
+34
View File
@@ -0,0 +1,34 @@
#ifndef SHOP_EETV4ADAPTER_H
#define SHOP_EETV4ADAPTER_H
#include <QUrl>
#include <eetv4request.h>
#include "../data/voucher.h"
struct EetV4ShopConfig
{
QUrl endpoint;
QString taxpayerEic;
qint32 unitId{0};
QString cashRegisterId;
int timeoutMilliseconds{30000};
bool verificationMode{true};
bool validate(QString *error = nullptr) const;
};
class EetV4ShopAdapter
{
public:
static bool createRequest(const Voucher &voucher,
const EetV4ShopConfig &config,
EetV4SaleRequest *request,
QString *error = nullptr);
private:
static bool amountText(const QDecDouble &amount, QString *text, QString *error);
};
#endif // SHOP_EETV4ADAPTER_H
+1 -1
View File
@@ -47,7 +47,7 @@ PaydVouchersDialog::PaydVouchersDialog(QWidget *parent) :
ui->tableItems->setColumnHidden(0, true);
ui->tableItems->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 30px; }");
#ifndef EET
#ifndef PRODEJNA_EET_V4
ui->btnEetNotSen->setVisible(false);
ui->btnSendEet->setVisible(false);
ui->label_2->setVisible(false);
+11 -1
View File
@@ -305,7 +305,17 @@ QByteArray ReceiptGenerator::generate()
out.append("Datum:");
out.append(prepareString(m_voucher->payDateTime().toString()));
out.append("\x0a");
if (!m_voucher->eetBkp().isEmpty())
if (!m_voucher->eetPok().isEmpty())
{
out.append("Rezim EET: v4");
out.append("\x0a");
out.append("POK:");
out.append("\x0a");
out.append(prepareString(m_voucher->eetPok()));
out.append("\x0a");
out.append("\x0a");
}
else if (!m_voucher->eetBkp().isEmpty())
{
out.append("Rezim EET: bezny");
out.append("\x0a");
+33
View File
@@ -6,6 +6,9 @@ ShopSettings::ShopSettings(QObject *parent) : QObject(parent)
m_lettersPerLine = 48;
m_eetActive = false;
m_eetKeyPassword = QStringLiteral("EET_PKCS12_PASSWORD");
m_eetUnitId = 1;
m_eetTimeout = 30000;
m_eetMode = 1;
m_eetTest = 0;
m_eetPlayground = 0;
@@ -94,6 +97,36 @@ void ShopSettings::setEetRegisterId(const QString &eetRegisterId)
m_eetRegisterId = eetRegisterId;
}
QString ShopSettings::eetEndpoint() const
{
return m_eetEndpoint;
}
void ShopSettings::setEetEndpoint(const QString &eetEndpoint)
{
m_eetEndpoint = eetEndpoint;
}
int ShopSettings::eetUnitId() const
{
return m_eetUnitId;
}
void ShopSettings::setEetUnitId(int eetUnitId)
{
m_eetUnitId = eetUnitId;
}
int ShopSettings::eetTimeout() const
{
return m_eetTimeout;
}
void ShopSettings::setEetTimeout(int eetTimeout)
{
m_eetTimeout = eetTimeout;
}
int ShopSettings::eetMode() const
{
return m_eetMode;
+15
View File
@@ -13,6 +13,9 @@ class ShopSettings : public QObject
Q_PROPERTY(bool eetActive READ eetActive WRITE setEetActive)
Q_PROPERTY(QString eetShopId READ eetShopId WRITE setEetShopId)
Q_PROPERTY(QString eetRegisterId READ eetRegisterId WRITE setEetRegisterId)
Q_PROPERTY(QString eetEndpoint READ eetEndpoint WRITE setEetEndpoint)
Q_PROPERTY(int eetUnitId READ eetUnitId WRITE setEetUnitId)
Q_PROPERTY(int eetTimeout READ eetTimeout WRITE setEetTimeout)
Q_PROPERTY(int eetMode READ eetMode WRITE setEetMode)
Q_PROPERTY(QString eetCertificate READ eetCertificate WRITE setEetCertificate)
Q_PROPERTY(QString eetKeyPassword READ eetKeyPassword WRITE setEetKeyPassword)
@@ -65,6 +68,15 @@ public:
QString eetRegisterId() const;
void setEetRegisterId(const QString &eetRegisterId);
QString eetEndpoint() const;
void setEetEndpoint(const QString &eetEndpoint);
int eetUnitId() const;
void setEetUnitId(int eetUnitId);
int eetTimeout() const;
void setEetTimeout(int eetTimeout);
int eetMode() const;
void setEetMode(int eetMode);
@@ -119,6 +131,9 @@ private:
bool m_eetActive;
QString m_eetShopId;
QString m_eetRegisterId;
QString m_eetEndpoint;
int m_eetUnitId;
int m_eetTimeout;
int m_eetMode;
QString m_eetCertificate;
QString m_eetKeyPassword;
+4 -1
View File
@@ -16,10 +16,13 @@ ShopSettingsForm::ShopSettingsForm(QWidget *parent) :
registerBinding(ui->lettersPerLine);
registerBinding(ui->byMessage);
#ifdef EET
#ifdef PRODEJNA_EET_V4
registerBinding(ui->eetActive);
registerBinding(ui->eetShopId);
registerBinding(ui->eetRegisterId);
registerBinding(ui->eetEndpoint);
registerBinding(ui->eetUnitId);
registerBinding(ui->eetTimeout);
QList<ComboData> listModes;
listModes << ComboData(0, tr("Simplifyed")) << ComboData(1, tr("Standard"));
registerBinding(ui->eetMode, listModes);
+61 -11
View File
@@ -187,7 +187,7 @@
<item row="0" column="0">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Shop ID</string>
<string>Taxpayer EIC</string>
</property>
</widget>
</item>
@@ -204,24 +204,54 @@
<item row="1" column="1">
<widget class="QLineEdit" name="eetRegisterId"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="label_17">
<property name="text">
<string>EET endpoint</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="eetEndpoint"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="label_18">
<property name="text">
<string>Unit ID</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QSpinBox" name="eetUnitId">
<property name="minimum">
<number>1</number>
</property>
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>1</number>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QLabel" name="label_8">
<property name="text">
<string>EET mode</string>
</property>
</widget>
</item>
<item row="3" column="1">
<item row="4" column="1">
<widget class="QComboBox" name="eetMode"/>
</item>
<item row="4" column="0">
<item row="5" column="0">
<widget class="QLabel" name="label_6">
<property name="text">
<string>Certificate file</string>
</property>
</widget>
</item>
<item row="4" column="1">
<item row="5" column="1">
<widget class="QWidget" name="widget_2" native="true">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<property name="leftMargin">
@@ -249,28 +279,48 @@
</layout>
</widget>
</item>
<item row="5" column="0">
<item row="6" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
<string>Private key password</string>
<string>Certificate password environment variable</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="6" column="1">
<widget class="QLineEdit" name="eetKeyPassword">
<property name="echoMode">
<enum>QLineEdit::Password</enum>
<property name="text">
<string>EET_PKCS12_PASSWORD</string>
</property>
</widget>
</item>
<item row="6" column="0">
<item row="7" column="0">
<widget class="QLabel" name="label_19">
<property name="text">
<string>Request timeout (ms)</string>
</property>
</widget>
</item>
<item row="7" column="1">
<widget class="QSpinBox" name="eetTimeout">
<property name="minimum">
<number>1000</number>
</property>
<property name="maximum">
<number>600000</number>
</property>
<property name="value">
<number>30000</number>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QCheckBox" name="eetTest">
<property name="text">
<string>Test mode</string>
</property>
</widget>
</item>
<item row="7" column="0" colspan="2">
<item row="9" column="0" colspan="2">
<widget class="QCheckBox" name="eetPlayground">
<property name="text">
<string>Communication with playground </string>
+2 -2
View File
@@ -8,7 +8,7 @@ ShopOverview::ShopOverview(QWidget *parent) :
{
ui->setupUi(this);
#ifndef EET
#ifndef PRODEJNA_EET_V4
ui->labelUnsendEET->setVisible(false);
ui->label_6->setVisible(false);
#endif
@@ -32,7 +32,7 @@ void ShopOverview::refresh()
ui->labelSales->setText(QString::number(today.totalPrice().toDouble()));
ui->labelNumSales->setText(QString::number(today.count()));
#ifdef EET
#ifdef PRODEJNA_EET_V4
VoucherSum unsend = srv.unsendEET();
ui->labelUnsendEET->setText(QString::number(unsend.count()));
#endif
+88 -80
View File
@@ -4,10 +4,11 @@
#include "settings/shopsettings.h"
#ifdef EET
#include <eetcpp.h>
#ifdef PRODEJNA_EET_V4
#include "eet/eetv4adapter.h"
#include <eetv4client.h>
#endif
#include <QEventLoop>
#include <QProcessEnvironment>
#include <seasonservice.h>
#include <cmath>
@@ -15,6 +16,15 @@
inline double round(double value) { return value < 0 ? -std::floor(0.5 - value) : std::floor(0.5 + value); }
#endif
namespace
{
bool &eetOnlineState()
{
static bool online = true;
return online;
}
}
VoucherPtr ShopService::createVoucher()
{
QSharedPointer<Voucher> voucher(new Voucher);
@@ -189,96 +199,95 @@ void ShopService::updateRelatedItem(VoucherItem* item, int countAdded)
bool ShopService::processEet(VoucherPtr voucher, QString &message)
{
#ifdef EET
#ifdef PRODEJNA_EET_V4
if (voucher->eetStatus() == Voucher::EET_NOT_ENTERING)
{
return true;
}
if (!eetOnlineState())
{
message = QStringLiteral("EET is offline; the voucher remains queued for sending.");
return false;
}
SettingsService srvSettings("SHOP");
ShopSettingsPtr settings = srvSettings.loadSettings<ShopSettings>();
loadSettings();
EetRequest request;
request.setCelkTrzba(voucher->totalPrice().toDouble());
request.setDatTrzby(voucher->payDateTime());
request.setIdPokl(settings->eetRegisterId());
request.setIdProvoz(settings->eetShopId());
request.setPrvniZaslani(voucher->eetStatus() == Voucher::EET_FOR_SEND);
request.setDicPopl(m_gs->dic());
request.setPoradCis(voucher->numSer());
request.setDatOdesl(QDateTime::currentDateTime());
request.setRezim((EetRequest::EetRezim)settings->eetMode());
EetV4ShopConfig adapterConfig;
adapterConfig.endpoint = QUrl(settings->eetEndpoint());
adapterConfig.taxpayerEic = settings->eetShopId();
adapterConfig.unitId = settings->eetUnitId();
adapterConfig.cashRegisterId = settings->eetRegisterId();
adapterConfig.timeoutMilliseconds = settings->eetTimeout();
adapterConfig.verificationMode = settings->eetTest();
if (m_gs->vatPayer())
EetV4SaleRequest request;
QString adapterError;
if (!EetV4ShopAdapter::createRequest(*voucher, adapterConfig, &request, &adapterError))
{
request.setDan1(voucher->vatAmountHigh().toDouble());
request.setDan2(voucher->vatAmountFirstLower().toDouble());
request.setDan3(voucher->VatAmountSecondLower().toDouble());
request.setZaklDan1(voucher->priceVatHigh().toDouble());
request.setZaklDan2(voucher->priceVatFirstLower().toDouble());
request.setZaklDan3(voucher->priceVatSecondLower().toDouble());
request.setZaklNepodlDph(voucher->priceNoVat().toDouble());
message = adapterError;
voucher->setEetStatus(Voucher::EET_ERROR);
update(voucher);
return false;
}
EetSender *sender = new EetSender(this);
sender->setupSigner(settings->eetCertificate(), settings->eetKeyPassword());
sender->setPlayground(settings->eetPlayground());
QEventLoop loop;
bool replyFinished = false;
connect(sender, &EetSender::sendFinished, [this, voucher, sender, &loop, &replyFinished](){
Transaction tx;
voucher->setEetBkp(sender->resut()->bkp());
voucher->setEetPkp(sender->resut()->pkp());
voucher->setEetFik(sender->resut()->fik());
if (sender->resut()->status() == EetResult::RESPONSE_OK)
{
voucher->setEetSendDateTime(QDateTime::currentDateTime());
voucher->setEetStatus(Voucher::EET_SENT);
}
else
{
voucher->setEetStatus(Voucher::EET_ERROR);
}
this->update(voucher);
tx.commit();
sender->deleteLater();
loop.quit();
replyFinished = true;
});
sender->sendRequest(&request);
if (!replyFinished)
const QString passwordVariable = settings->eetKeyPassword().trimmed();
const QByteArray password = QProcessEnvironment::systemEnvironment()
.value(passwordVariable)
.toUtf8();
if (passwordVariable.isEmpty() || password.isEmpty())
{
loop.exec();
message = QStringLiteral("EET certificate password environment variable is missing.");
voucher->setEetStatus(Voucher::EET_ERROR);
update(voucher);
return false;
}
auto addMessage = [&message](EetMessage *msg, const QString &label){
if (message.isEmpty())
EetV4ClientConfig clientConfig;
clientConfig.endpoint = adapterConfig.endpoint;
clientConfig.timeoutMilliseconds = adapterConfig.timeoutMilliseconds;
EetV4Client client(clientConfig);
EetV4Response response;
QString clientError;
if (!client.sendSale(request,
settings->eetCertificate(),
password,
&response,
&clientError))
{
message = clientError;
voucher->setEetStatus(Voucher::EET_ERROR);
update(voucher);
return false;
}
if (!response.isSuccess() || response.pok.isEmpty())
{
message = response.message.isEmpty()
? QStringLiteral("EET returned an unsuccessful response.")
: response.message;
voucher->setEetStatus(Voucher::EET_ERROR);
update(voucher);
return false;
}
voucher->setEetPok(response.pok);
voucher->setEetSendDateTime(QDateTime::currentDateTime());
voucher->setEetStatus(Voucher::EET_SENT);
update(voucher);
if (!response.warningCodes.isEmpty())
{
message = QStringLiteral("EET warning codes: ");
for (int i = 0; i < response.warningCodes.size(); ++i)
{
message = label + "\n";
if (i > 0)
{
message += QStringLiteral(", ");
}
message += QString::number(response.warningCodes.at(i));
}
message += QString::number(msg->code()) + ": " + msg->message();
};
foreach (EetMessage *msg, sender->resut()->errors()) {
addMessage(msg, "Errors:");
}
foreach (EetMessage *msg, sender->resut()->warnings()) {
addMessage(msg, "Warnings:");
}
return voucher->eetStatus() == Voucher::EET_SENT;
return true;
#else
return true;
#endif
@@ -286,15 +295,15 @@ bool ShopService::processEet(VoucherPtr voucher, QString &message)
void ShopService::setEetOnline(bool online)
{
#ifdef EET
EetSender::m_online = online;
#ifdef PRODEJNA_EET_V4
eetOnlineState() = online;
#endif
}
bool ShopService::isEetOnline()
{
#ifdef EET
return EetSender::m_online;
#ifdef PRODEJNA_EET_V4
return eetOnlineState();
#else
return false;
#endif
@@ -562,4 +571,3 @@ VoucherSum ShopService::summary(const QString& where) {
return sum;
}
+49
View File
@@ -2,6 +2,9 @@
#include <QtTest>
#include "data/voucher.h"
#ifdef PRODEJNA_EET_V4
#include "eet/eetv4adapter.h"
#endif
class ShopTests : public QObject
{
@@ -45,6 +48,52 @@ private slots:
QVERIFY(qAbs(sum.totalPrice().toDouble() - 20.0) < 0.0001);
}
#ifdef PRODEJNA_EET_V4
void eetV4AdapterBuildsRequestFromVoucher()
{
Voucher voucher;
voucher.setNumSer(QStringLiteral("SHOP-42"));
voucher.setPayDateTime(QDateTime(QDate(2026, 10, 13),
QTime(20, 30),
Qt::OffsetFromUTC,
7200));
voucher.setTotalPrice(QDecDouble(QStringLiteral("19.90").toLatin1().constData()));
EetV4ShopConfig config;
config.endpoint = QUrl(QStringLiteral("https://eet.example.test/eet"));
config.taxpayerEic = QStringLiteral("CZ123456789");
config.unitId = 3;
config.cashRegisterId = QStringLiteral("KASA1");
EetV4SaleRequest request;
QString error;
QVERIFY2(EetV4ShopAdapter::createRequest(voucher, config, &request, &error),
qPrintable(error));
QCOMPARE(request.receiptNumber, QStringLiteral("SHOP-42"));
QCOMPARE(request.totalSale.toString(), QStringLiteral("19.90"));
QCOMPARE(request.unitId, 3);
QCOMPARE(request.cashRegisterId, QStringLiteral("KASA1"));
QVERIFY(request.verificationMode);
QVERIFY(request.firstSubmission);
}
void eetV4AdapterRejectsInvalidConfiguration()
{
Voucher voucher;
voucher.setNumSer(QStringLiteral("SHOP-42"));
voucher.setPayDateTime(QDateTime::currentDateTime());
voucher.setTotalPrice(QDecDouble(QStringLiteral("1.00").toLatin1().constData()));
EetV4ShopConfig config;
config.endpoint = QUrl(QStringLiteral("http://not-tls.example.test/eet"));
EetV4SaleRequest request;
QString error;
QVERIFY(!EetV4ShopAdapter::createRequest(voucher, config, &request, &error));
QVERIFY(error.contains(QStringLiteral("HTTPS")));
}
#endif
};
int main(int argc, char *argv[])