rewrite for eet 2.0 api version v4
This commit is contained in:
@@ -0,0 +1,139 @@
|
||||
#include "eetv4client.h"
|
||||
#include "eetv4signer.h"
|
||||
|
||||
#include <QFile>
|
||||
#include <QProcess>
|
||||
#include <QSslCertificate>
|
||||
#include <QSslKey>
|
||||
#include <QSslServer>
|
||||
#include <QTemporaryDir>
|
||||
#include <QtTest>
|
||||
|
||||
namespace
|
||||
{
|
||||
class MockEetServer : public QSslServer
|
||||
{
|
||||
public:
|
||||
explicit MockEetServer(const QByteArray &response)
|
||||
: m_response(response)
|
||||
{
|
||||
connect(this, &QSslServer::pendingConnectionAvailable, this, [this] {
|
||||
QSslSocket *socket = qobject_cast<QSslSocket *>(nextPendingConnection());
|
||||
if (socket == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
connect(socket, &QSslSocket::readyRead, this, [this, socket] {
|
||||
const QByteArray request = socket->readAll();
|
||||
const qsizetype bodyStart = request.indexOf("\r\n\r\n");
|
||||
const QByteArray soap = bodyStart < 0 ? QByteArray()
|
||||
: request.mid(bodyStart + 4);
|
||||
QString verificationError;
|
||||
m_requestVerified = !soap.isEmpty() &&
|
||||
EetV4Signer::verifySoap(soap, &verificationError);
|
||||
const QByteArray http =
|
||||
"HTTP/1.1 200 OK\r\nContent-Type: text/xml; charset=utf-8\r\n"
|
||||
"Content-Length: " + QByteArray::number(m_response.size()) +
|
||||
"\r\nConnection: close\r\n\r\n" + m_response;
|
||||
socket->write(http);
|
||||
socket->disconnectFromHost();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bool requestVerified() const
|
||||
{
|
||||
return m_requestVerified;
|
||||
}
|
||||
|
||||
private:
|
||||
QByteArray m_response;
|
||||
bool m_requestVerified{false};
|
||||
};
|
||||
}
|
||||
|
||||
class EetV4ClientIntegrationTest : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void sendsSignedSaleAndParsesPok();
|
||||
};
|
||||
|
||||
void EetV4ClientIntegrationTest::sendsSignedSaleAndParsesPok()
|
||||
{
|
||||
QTemporaryDir directory;
|
||||
QVERIFY(directory.isValid());
|
||||
const QString keyPath = directory.filePath(QStringLiteral("key.pem"));
|
||||
const QString certPath = directory.filePath(QStringLiteral("certificate.pem"));
|
||||
const QString p12Path = directory.filePath(QStringLiteral("certificate.p12"));
|
||||
auto runOpenSsl = [](const QStringList &arguments) {
|
||||
QProcess process;
|
||||
process.start(QStringLiteral("openssl"), arguments);
|
||||
QVERIFY2(process.waitForFinished(30000), qPrintable(process.errorString()));
|
||||
QVERIFY2(process.exitStatus() == QProcess::NormalExit && process.exitCode() == 0,
|
||||
process.readAllStandardError().constData());
|
||||
};
|
||||
runOpenSsl({QStringLiteral("req"), QStringLiteral("-x509"), QStringLiteral("-newkey"),
|
||||
QStringLiteral("rsa:2048"), QStringLiteral("-nodes"), QStringLiteral("-subj"),
|
||||
QStringLiteral("/CN=localhost"), QStringLiteral("-keyout"), keyPath,
|
||||
QStringLiteral("-out"), certPath, QStringLiteral("-days"), QStringLiteral("1")});
|
||||
runOpenSsl({QStringLiteral("pkcs12"), QStringLiteral("-export"), QStringLiteral("-out"),
|
||||
p12Path, QStringLiteral("-inkey"), keyPath, QStringLiteral("-in"), certPath,
|
||||
QStringLiteral("-passout"), QStringLiteral("pass:test")});
|
||||
|
||||
const QByteArray unsignedResponse =
|
||||
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
|
||||
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\""
|
||||
" xmlns:wsse=\"http://docs.oasis-open.org/wss/2004/01/"
|
||||
"oasis-200401-wss-wssecurity-secext-1.0.xsd\""
|
||||
" xmlns:wsu=\"http://docs.oasis-open.org/wss/2004/01/"
|
||||
"oasis-200401-wss-wssecurity-utility-1.0.xsd\">"
|
||||
"<soap:Header/><soap:Body wsu:Id=\"response-body\">"
|
||||
"<Odpoved xmlns=\"http://fs.gov.cz/eet/schema/v4\">"
|
||||
"<Hlavicka uuid_zpravy=\"123e4567-e89b-42d3-a456-426614174000\" "
|
||||
"dat_prij=\"2026-10-13T20:00:00+02:00\"/>"
|
||||
"<Potvrzeni pok=\"123e4567-e89b-42d3-a456-426614174000-01\"/>"
|
||||
"</Odpoved></soap:Body></soap:Envelope>";
|
||||
QString signingError;
|
||||
const QByteArray signedResponse = EetV4Signer::signSoap(
|
||||
unsignedResponse, p12Path, QByteArrayLiteral("test"), &signingError);
|
||||
QVERIFY2(!signedResponse.isEmpty(), qPrintable(signingError));
|
||||
|
||||
MockEetServer server(signedResponse);
|
||||
QSslConfiguration serverSsl = QSslConfiguration::defaultConfiguration();
|
||||
QFile keyFile(keyPath);
|
||||
QFile certificateFile(certPath);
|
||||
QVERIFY(keyFile.open(QIODevice::ReadOnly));
|
||||
QVERIFY(certificateFile.open(QIODevice::ReadOnly));
|
||||
serverSsl.setPrivateKey(QSslKey(keyFile.readAll(), QSsl::Rsa, QSsl::Pem));
|
||||
serverSsl.setLocalCertificate(QSslCertificate(certificateFile.readAll(), QSsl::Pem));
|
||||
server.setSslConfiguration(serverSsl);
|
||||
QVERIFY(server.listen(QHostAddress::LocalHost));
|
||||
|
||||
QSslConfiguration clientSsl = QSslConfiguration::defaultConfiguration();
|
||||
clientSsl.setCaCertificates({serverSsl.localCertificate()});
|
||||
EetV4Client client({
|
||||
QUrl(QStringLiteral("https://localhost:%1/eet").arg(server.serverPort())),
|
||||
5000, clientSsl
|
||||
});
|
||||
EetV4SaleRequest request;
|
||||
request.sentAt = QDateTime::currentDateTime().toOffsetFromUtc(0);
|
||||
request.saleAt = request.sentAt;
|
||||
request.taxpayerEic = QStringLiteral("CZ123456789");
|
||||
request.unitId = 1;
|
||||
request.cashRegisterId = QStringLiteral("KASA1");
|
||||
request.receiptNumber = QStringLiteral("TEST-1");
|
||||
QVERIFY(EetV4Amount::fromString(QStringLiteral("100.00"), &request.totalSale));
|
||||
|
||||
EetV4Response response;
|
||||
QString error;
|
||||
QVERIFY2(client.sendSale(request, p12Path, QByteArrayLiteral("test"), &response, &error),
|
||||
qPrintable(error));
|
||||
QVERIFY(server.requestVerified());
|
||||
QVERIFY(response.isSuccess());
|
||||
QCOMPARE(response.pok, QStringLiteral("123e4567-e89b-42d3-a456-426614174000-01"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(EetV4ClientIntegrationTest)
|
||||
#include "eetv4client_integration_test.moc"
|
||||
Reference in New Issue
Block a user