|
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519 |
- /* @file Сервис печати и формирования чеков. */
-
- // Qt
- #include <Common/QtHeadersBegin.h>
- #include <QtCore/QRegExp>
- #include <QtConcurrent/QtConcurrentRun>
- #include <QtCore/QFuture>
- #include <QtCore/QMutexLocker>
- #include <QtCore/QDir>
- #include <QtCore/QDate>
- #include <QtCore/QBuffer>
- #include <QtCore/QTextStream>
- #include <QtQml/QJSEngine>
- #include <QtQml/QJSValue>
- #include <QtCore/QTextCodec>
- #include <QtXML/QDomDocument>
- #include <QtCore/QXmlStreamWriter>
- #include <Common/QtHeadersEnd.h>
-
- // Thirdparty
- #include <Common/QtHeadersBegin.h>
- #include <qzint.h>
- #include <Common/QtHeadersEnd.h>
-
- // PaymentProcessor SDK
- #include <SDK/PaymentProcessor/Components.h>
- #include <SDK/PaymentProcessor/Core/IDeviceService.h>
- #include <SDK/PaymentProcessor/Core/IEventService.h>
- #include <SDK/PaymentProcessor/Core/ReceiptTypes.h>
- #include <SDK/PaymentProcessor/Core/ServiceParameters.h>
- #include <SDK/PaymentProcessor/Settings/DealerSettings.h>
- #include <SDK/PaymentProcessor/Settings/ExtensionsSettings.h>
- #include <SDK/PaymentProcessor/Payment/Parameters.h>
- #include <SDK/PaymentProcessor/Payment/Security.h>
-
- // Driver SDK
- #include <SDK/Drivers/IFiscalPrinter.h>
- #include <SDK/Drivers/FR/FiscalPrinterConstants.h>
- #include <SDK/Drivers/Components.h>
- #include <SDK/Drivers/HardwareConstants.h>
-
- // Project
- #include "System/IApplication.h"
-
- #include "Services/ServiceNames.h"
- #include "Services/PrintConstants.h"
- #include "Services/PrintingService.h"
- #include "Services/SettingsService.h"
- #include "Services/DatabaseService.h"
- #include "Services/EventService.h"
- #include "Services/PluginService.h"
- #include "Services/PaymentService.h"
-
- #include "PrintingCommands.h"
- #include "FRReportConstants.h"
-
- namespace PPSDK = SDK::PaymentProcessor;
-
- namespace CPrintingService
- {
- const QString ReceiptDateTimeFormat = "dd.MM.yyyy hh:mm:ss";
- const QString ConditionTag = "@@";
-
- const QString MaskedFieldPostfix = "_MASKED";
- const QString DislayPostfix = "_DISPLAY";
- }
-
- //---------------------------------------------------------------------------
- PrintingService::PrintingService(IApplication * aApplication) :
- mApplication(aApplication),
- mContinuousMode(false),
- mServiceOperation(false),
- mRandomReceiptsID(false),
- mNextReceiptIndex(1),
- mFiscalRegister(nullptr),
- mRandomGenerator(static_cast<unsigned>(QDateTime::currentDateTime().currentMSecsSinceEpoch()))
- {
- setLog(mApplication->getLog());
- }
-
- //---------------------------------------------------------------------------
- PrintingService::~PrintingService()
- {
- }
-
- //---------------------------------------------------------------------------
- QString PrintingService::getName() const
- {
- return CServices::PrintingService;
- }
-
- //---------------------------------------------------------------------------
- const QSet<QString> & PrintingService::getRequiredServices() const
- {
- static QSet<QString> requiredServices = QSet<QString>()
- << CServices::DeviceService
- << CServices::DatabaseService
- << CServices::SettingsService
- << CServices::PluginService
- << CServices::PaymentService;
-
- return requiredServices;
- }
-
- //---------------------------------------------------------------------------
- QVariantMap PrintingService::getParameters() const
- {
- QVariantMap parameters;
-
- parameters[PPSDK::CServiceParameters::Printing::ReceiptCount] = getReceiptCount();
-
- return parameters;
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::resetParameters(const QSet<QString> & aParameters)
- {
- if (aParameters.contains(PPSDK::CServiceParameters::Printing::ReceiptCount))
- {
- mDatabaseUtils->setDeviceParam(PPSDK::CDatabaseConstants::Devices::Terminal, PPSDK::CDatabaseConstants::Parameters::ReceiptCount, 0);
- }
- }
-
- //---------------------------------------------------------------------------
- bool PrintingService::initialize()
- {
- // Запрашиваем доступные устройства.
- mDeviceService = mApplication->getCore()->getDeviceService();
-
- loadReceiptTemplates();
- loadTags();
-
- updateHardwareConfiguration();
- createFiscalRegister();
-
- mDatabaseUtils = DatabaseService::instance(mApplication)->getDatabaseUtils<IHardwareDatabaseUtils>();
-
- connect(mDeviceService, SIGNAL(configurationUpdated()), SLOT(updateHardwareConfiguration()));
- connect(&mFutureWatcher, SIGNAL(finished()), this, SLOT(taskFinished()));
-
- return true;
- }
-
- //------------------------------------------------------------------------------
- void PrintingService::finishInitialize()
- {
- auto settings = SettingsService::instance(mApplication)->getAdapter<SDK::PaymentProcessor::TerminalSettings>();
-
- mRandomReceiptsID = settings->getCommonSettings().randomReceiptsID;
- }
-
- //---------------------------------------------------------------------------
- bool PrintingService::canShutdown()
- {
- return true;
- }
-
- //---------------------------------------------------------------------------
- bool PrintingService::shutdown()
- {
- mFutureWatcher.waitForFinished();
-
- foreach (DSDK::IPrinter * printer, mPrinterDevices)
- {
- mDeviceService->releaseDevice(printer);
- }
-
- if (mFiscalRegister)
- {
- SDK::Plugin::IPluginLoader * pluginLoader = PluginService::instance(mApplication)->getPluginLoader();
-
- pluginLoader->destroyPlugin(dynamic_cast<SDK::Plugin::IPlugin *>(mFiscalRegister));
- }
-
- return true;
- }
-
- //---------------------------------------------------------------------------
- PrintCommand * PrintingService::getPrintCommand(const QString & aReceiptType)
- {
- if (aReceiptType == PPSDK::CReceiptType::Payment)
- {
- return new PrintPayment(aReceiptType, this);
- }
- else if (aReceiptType == PPSDK::CReceiptType::Balance || aReceiptType == PPSDK::CReceiptType::XReport)
- {
- return new PrintBalance(aReceiptType, this);
- }
- else if (aReceiptType == PPSDK::CReceiptType::DispenserBalance || aReceiptType == PPSDK::CReceiptType::DispenserEncashment)
- {
- auto command = new PrintBalance(aReceiptType, this);
- command->setFiscal(false);
- return command;
- }
- else if (aReceiptType == PPSDK::CReceiptType::Encashment)
- {
- return new PrintEncashment(aReceiptType, this);
- }
- else if (aReceiptType == PPSDK::CReceiptType::ZReport)
- {
- return new PrintZReport(aReceiptType, this, false);
- }
- else if (aReceiptType == PPSDK::CReceiptType::ZReportFull)
- {
- return new PrintZReport(aReceiptType, this, true);
- }
- else
- {
- return new PrintReceipt(aReceiptType, this);
- }
- }
-
- //---------------------------------------------------------------------------
- bool PrintingService::canPrintReceipt(const QString & aReceiptType, bool aRealCheck)
- {
- DSDK::IPrinter * printer = takePrinter(aReceiptType, aRealCheck);
- giveBackPrinter(printer);
-
- return printer != nullptr;
- }
-
- //---------------------------------------------------------------------------
- int PrintingService::printReceipt(const QString & aReceiptType, const QVariantMap & aParameters, const QString & aReceiptTemplate, bool aContinuousMode, bool aServiceOperation)
- {
- mContinuousMode = aContinuousMode;
- mServiceOperation = aServiceOperation;
-
- QString receiptTemplate = (QString("%1_%2").arg(aParameters[PPSDK::CPayment::Parameters::Type].toString()).arg(aReceiptTemplate)).toLower();
-
- // Извлекаем шаблон 'PROCESSING_TYPE'_aReceiptTemplate
- if (!mCachedReceipts.contains(receiptTemplate))
- {
- receiptTemplate = aReceiptTemplate.toLower();
-
- // Извлекаем обычный шаблон для чека нужного типа.
- if (!mCachedReceipts.contains(receiptTemplate))
- {
- toLog(LogLevel::Error, QString("Failed to print receipt. Missing receipt template : %1.").arg(receiptTemplate));
-
- QMetaObject::invokeMethod(this, "printEmptyReceipt", Qt::QueuedConnection, Q_ARG(int, 0), Q_ARG(bool, true));
- return 0;
- }
- }
-
- auto printCommand = getPrintCommand(aReceiptType);
- printCommand->setReceiptTemplate(aReceiptTemplate);
-
- return performPrint(printCommand, aParameters, mCachedReceipts[receiptTemplate]);
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::printEmptyReceipt(int aJobIndex, bool aError)
- {
- emit receiptPrinted(aJobIndex, aError);
- }
-
- //---------------------------------------------------------------------------
- bool PrintingService::printReceiptDirected(DSDK::IPrinter * aPrinter, const QString & aReceiptTemplate, const QVariantMap & aParameters)
- {
- mContinuousMode = false;
-
- // Извлекаем шаблон для чека нужного типа.
- if (!mCachedReceipts.contains(aReceiptTemplate.toLower()))
- {
- toLog(LogLevel::Error, QString("Missing receipt template : %1.").arg(aReceiptTemplate));
- return false;
- }
-
- QScopedPointer<PrintCommand> printCommand(getPrintCommand(QString()));
- printCommand->setReceiptTemplate(aReceiptTemplate);
-
- QVariantMap configuration;
- configuration.insert(CHardwareSDK::Printer::ContinuousMode, mContinuousMode);
- configuration.insert(CHardwareSDK::Printer::ServiceOperation, mServiceOperation);
- aPrinter->setDeviceConfiguration(configuration);
-
- // TODO: нужно ли увеличивать счетчик чеков?
- return printCommand->print(aPrinter, aParameters);
- }
-
- //---------------------------------------------------------------------------
- template <class ResultT, class T>
- ResultT & joinMap(ResultT & aResult, const T & aParameters2)
- {
- for (auto it = aParameters2.begin(); it != aParameters2.end(); ++it)
- {
- aResult.insert(it.key(), it.value());
- }
-
- return aResult;
- }
-
- //---------------------------------------------------------------------------
- int PrintingService::performPrint(PrintCommand * aCommand, const QVariantMap & aParameters, QStringList aReceiptTemplate)
- {
- // Функция, в которой прозводится печать. Должно быть исключено обращение к общим для разных принтеров данным.
- mPrintingFunction =
- [this, aReceiptTemplate](int aJobIndex, PrintCommand * aCommand, QVariantMap aParameters) -> bool
- {
- auto printer = takePrinter(aCommand->getReceiptType(), false);
-
- if (!printer)
- {
- delete aCommand;
-
- return false;
- }
-
- QVariantMap staticParameters;
-
- QVariantMap configuration;
- configuration.insert(CHardwareSDK::Printer::ContinuousMode, mContinuousMode);
- configuration.insert(CHardwareSDK::Printer::ServiceOperation, mServiceOperation);
- configuration.insert(CHardwareSDK::Printer::TemplateParameters, aParameters);
- configuration.insert(CHardwareSDK::Printer::ReceiptParameters, joinMap(staticParameters, mStaticParameters));
- configuration.insert(CHardwareSDK::Printer::ReceiptTemplate, aReceiptTemplate);
- printer->setDeviceConfiguration(configuration);
-
- bool result = aCommand->print(printer, joinMap(aParameters, staticParameters));
-
- if (result)
- {
- incrementReceiptCount(printer);
- }
-
- giveBackPrinter(printer);
-
- delete aCommand;
-
- emit receiptPrinted(aJobIndex, !result);
-
- return result;
- };
-
- int taskIndex = mNextReceiptIndex.fetchAndAddOrdered(1);
-
- if (taskIndex != 1 && !mFutureWatcher.isFinished())
- {
- Task task = {taskIndex, aCommand, aParameters};
-
- mQueue.enqueue(task);
- }
- else
- {
- mFutureWatcher.setFuture(QtConcurrent::run(mPrintingFunction, taskIndex, aCommand, aParameters));
- }
-
- return taskIndex;
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::taskFinished()
- {
- if (!mQueue.isEmpty())
- {
- Task task = mQueue.dequeue();
-
- mFutureWatcher.setFuture(QtConcurrent::run(mPrintingFunction, task.index, task.command, task.parameters));
- }
- }
-
- //---------------------------------------------------------------------------
- int PrintingService::printReport(const QString & aReceiptType, const QVariantMap & aParameters)
- {
- auto printCommand = getPrintCommand(aReceiptType);
-
- PrintBalance * balanceCommand = dynamic_cast<PrintBalance *>(printCommand);
- if (balanceCommand && aParameters.contains(CPrintConstants::NoFiscal))
- {
- // Включаем нефискальный режим
- balanceCommand->setFiscal(false);
- }
-
- printCommand->setReceiptTemplate(aReceiptType);
-
- QVariantMap parameters;
-
- return performPrint(printCommand, joinMap(joinMap(parameters, mStaticParameters), aParameters));
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::giveBackPrinter(DSDK::IPrinter * aPrinter)
- {
- if (aPrinter)
- {
- QMutexLocker lock(&mAvailablePrintersMutex);
-
- mAvailablePrinters.insert(aPrinter);
-
- mPrintersAvailable.wakeOne();
- }
- }
-
- //---------------------------------------------------------------------------
- DSDK::IPrinter * PrintingService::takePrinter(const QString & aReceiptType, bool aCheckOnline)
- {
- if (mPrinterDevices.empty())
- {
- toLog(LogLevel::Error, "Printers are not found in current configuration.");
- return 0;
- }
-
- // Пытаемся найти предпочтительный принтер.
- auto settings = SettingsService::instance(mApplication)->getAdapter<SDK::PaymentProcessor::TerminalSettings>();
- QString preferredName = settings->getPrinterForReceipt(aReceiptType);
-
- QList<DSDK::IPrinter *> printers;
- auto printCommand = getPrintCommand(aReceiptType);
- DSDK::IPrinter * preferred = nullptr;
-
- if (!preferredName.isEmpty())
- {
- preferred = dynamic_cast<DSDK::IPrinter *>(mDeviceService->acquireDevice(preferredName));
-
- if (preferred && mPrinterDevices.contains(preferred) && printCommand->canPrint(preferred, aCheckOnline))
- {
- printers << preferred;
- }
- }
-
- foreach(auto printer, mPrinterDevices)
- {
- if (printer && (printer != preferred) && printCommand->canPrint(printer, aCheckOnline))
- {
- printers << printer;
- }
- }
-
- delete printCommand;
-
- if (printers.isEmpty())
- {
- toLog(LogLevel::Error, QString("No any available printer for type %1 with %2 checking.").arg(aReceiptType).arg(aCheckOnline ? "online" : "offline"));
- return nullptr;
- }
-
- DSDK::IPrinter * printer = printers.first();
-
- // Ждем, пока принтер не появится в списке доступных.
- QMutexLocker lock(&mAvailablePrintersMutex);
-
- if (!mAvailablePrinters.contains(printer))
- {
- mPrintersAvailable.wait(&mAvailablePrintersMutex);
- }
-
- mAvailablePrinters.remove(printer);
-
- return printer;
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::incrementReceiptCount(DSDK::IPrinter * aPrinter) const
- {
- QString deviceConfigName = mDeviceService->getDeviceConfigName(aPrinter);
-
- // Увеличиваем количество напечатанных чеков для конкртетного принтера.
- QVariant receiptCount = mDatabaseUtils->getDeviceParam(deviceConfigName, PPSDK::CDatabaseConstants::Parameters::ReceiptCount);
- receiptCount = QVariant::fromValue(receiptCount.toInt() + 1);
- mDatabaseUtils->setDeviceParam(deviceConfigName, PPSDK::CDatabaseConstants::Parameters::ReceiptCount, receiptCount);
-
- // Увеличиваем количество напечатанных чеков для терминала.
- receiptCount = mDatabaseUtils->getDeviceParam(PPSDK::CDatabaseConstants::Devices::Terminal, PPSDK::CDatabaseConstants::Parameters::ReceiptCount);
- receiptCount = QVariant::fromValue(receiptCount.toInt() + 1);
- mDatabaseUtils->setDeviceParam(PPSDK::CDatabaseConstants::Devices::Terminal, PPSDK::CDatabaseConstants::Parameters::ReceiptCount, receiptCount);
- }
-
- //---------------------------------------------------------------------------
- unsigned PrintingService::getReceiptID() const
- {
- if (mRandomReceiptsID)
- {
- return mRandomGenerator();
- }
- else
- {
- return getReceiptCount() + 1;
- }
- }
-
- //---------------------------------------------------------------------------
- int PrintingService::getReceiptCount() const
- {
- QVariant receiptCount = mDatabaseUtils->getDeviceParam(PPSDK::CDatabaseConstants::Devices::Terminal, PPSDK::CDatabaseConstants::Parameters::ReceiptCount);
-
- return receiptCount.isNull() ? 0 : receiptCount.toInt();
- }
-
- //---------------------------------------------------------------------------
- bool PrintingService::loadTags()
- {
- mStaticParameters.clear();
-
- SettingsService * settingsService = SettingsService::instance(mApplication);
-
- PPSDK::TerminalSettings * terminalSettings = settingsService->getAdapter<PPSDK::TerminalSettings>();
-
- PPSDK::SKeySettings key0 = terminalSettings->getKeys().value(0);
-
- if (key0.ap.isEmpty())
- {
- toLog(LogLevel::Error, "Failed to retrieve terminal number from configs.");
- return false;
- }
- else
- {
- mStaticParameters.insert(CPrintConstants::TermNumber, key0.ap);
- }
-
- PPSDK::DealerSettings * dealerSettings = settingsService->getAdapter<PPSDK::DealerSettings>();
-
- // TODO: проверить на валидность.
- PPSDK::SPersonalSettings dealer = dealerSettings->getPersonalSettings();
-
- joinMap(mStaticParameters, dealer.mPrintingParameters);
-
- mStaticParameters.insert(CPrintConstants::DealerName, dealer.name);
- mStaticParameters.insert(CPrintConstants::DealerPhone, dealer.phone);
- mStaticParameters.insert(CPrintConstants::DealerSupportPhone, dealer.phone);
- mStaticParameters.insert(CPrintConstants::DealerAddress, dealer.address);
- mStaticParameters.insert(CPrintConstants::DealerBusinessAddress, dealer.businessAddress.isEmpty() ? dealer.address : dealer.businessAddress);
- mStaticParameters.insert(CPrintConstants::DealerInn, dealer.inn);
- mStaticParameters.insert(CPrintConstants::DealerKbk, dealer.kbk);
- mStaticParameters.insert(CPrintConstants::DealerIsBank, dealer.isBank);
- mStaticParameters.insert(CPrintConstants::PointAddress, dealer.pointAddress);
- mStaticParameters.insert(CPrintConstants::PointName, dealer.pointName);
- mStaticParameters.insert(CPrintConstants::PointExternalID, dealer.pointExternalID);
- mStaticParameters.insert(CPrintConstants::BankName, dealer.bankName);
- mStaticParameters.insert(CPrintConstants::BankBik, dealer.bankBik);
- mStaticParameters.insert(CPrintConstants::BankPhone, dealer.bankPhone);
- mStaticParameters.insert(CPrintConstants::BankAddress, dealer.bankAddress);
- mStaticParameters.insert(CPrintConstants::BankInn, dealer.bankInn);
-
- QString currency = terminalSettings->getCurrencySettings().code;
-
- if (!currency.isEmpty())
- {
- mStaticParameters.insert(CPrintConstants::Currency, terminalSettings->getCurrencySettings().name);
- }
- else
- {
- toLog(LogLevel::Warning, "Failed to retrieve currency settings from configs. Tag <CURRENCY> will be printed empty on all receipts!");
- return false;
- }
-
- return true;
- }
-
- //---------------------------------------------------------------------------
- QStringList PrintingService::getReceipt(const QString & aReceiptTemplate, const QVariantMap & aParameters)
- {
- if (!mCachedReceipts.contains(aReceiptTemplate.toLower()))
- {
- toLog(LogLevel::Error, QString("Missing receipt template %1.").arg(aReceiptTemplate));
- }
-
- QStringList receipt = mCachedReceipts.value(aReceiptTemplate.toLower());
- expandTags(receipt, aParameters);
-
- return receipt;
- }
-
- //---------------------------------------------------------------------------
- QString maskedString(const QString & aString, bool aNeedMask)
- {
- if (aNeedMask)
- {
- int oneFourthLen = qMin(aString.size() / 4, 4);
-
- return aString.left(oneFourthLen) + QString("*").repeated(aString.size() - oneFourthLen * 2) + aString.right(oneFourthLen);
- }
-
- return aString;
- }
-
- //---------------------------------------------------------------------------
- QString PrintingService::convertImage2base64(const QString & aString)
- {
- QString result = aString;
-
- for (int extLen = 3; extLen <= 4; extLen++)
- {
- // \[img\s*\].*((?:[\w]\:|\\)?((\\|/)?[a-z_\-\s0-9\.]+)+\.[a-z]{3,4})
- QRegExp imgPattern = QRegExp(QString("\\[img\\s*\\].*((?:[\\w]\\:|\\\\)?((\\\\|/)?[a-z_\\-\\s0-9\\.]+)+\\.[a-z]{%1})").arg(extLen), Qt::CaseInsensitive);
-
- imgPattern.setMinimal(true);
-
- int offset = 0;
- while ((offset = imgPattern.indexIn(result, offset)) != -1)
- {
- QString img = "<image>";
-
- QFile file(imgPattern.cap(1));
- if (file.open(QIODevice::ReadOnly))
- {
- img = QString::fromLatin1(file.readAll().toBase64());
- }
- else
- {
- toLog(LogLevel::Error, QString("Error load image '%1': %2").arg(imgPattern.cap(1)).arg(file.errorString()));
- }
-
- result.replace(imgPattern.pos(1), imgPattern.cap(1).length(), img);
- offset = imgPattern.pos(1) + img.size();
- }
- }
-
- return result;
- }
-
- //---------------------------------------------------------------------------
- QString PrintingService::generateQR(const QString & aString)
- {
- QString result = aString;
-
- auto generateQRCode = [=](const QString & aText, int aSize, int aLeftMargin) -> QString
- {
- QImage image(QSize(aSize + aLeftMargin, aSize), QImage::Format_ARGB32);
- image.fill(QColor("transparent"));
-
- Zint::QZint zint;
-
- zint.setWidth(0);
- zint.setHeight(aSize);
- zint.setText(aText);
- zint.setWhitespace(0);
- zint.setBorderType(Zint::QZint::NO_BORDER);
- zint.setInputMode(DATA_MODE);
- zint.setHideText(true);
- zint.setSymbol(BARCODE_QRCODE);
- zint.setFgColor(QColor("black"));
- zint.setBgColor(QColor("white"));
-
- {
- QPainter painter(&image);
- painter.fillRect(QRectF(0, 0, image.width(), image.height()), QColor("white"));
- zint.render(painter, QRectF(aLeftMargin, 0, image.width() - aLeftMargin, image.height()), Zint::QZint::KeepAspectRatio);
- painter.end();
- }
-
- if (zint.hasErrors())
- {
- toLog(LogLevel::Error, QString("Failed render QR code: %1.").arg(zint.lastError()));
- }
- else
- {
- QBuffer buffer;
- if (buffer.open(QIODevice::WriteOnly))
- {
- image.save(&buffer, "png");
-
- return buffer.data().toBase64();
- }
- }
-
- return "";
- };
-
- QRegExp qrPattern("\\[qr(\\s*(\\w+)\\s*=\\s*(\\d+)\\s*)?(\\s*(\\w+)\\s*=\\s*(\\d+)\\s*)?\\](.*)\\[/qr\\]", Qt::CaseInsensitive);
-
- qrPattern.setMinimal(true);
-
- int offset = 0;
- while ((offset = qrPattern.indexIn(result, offset)) != -1)
- {
- int size = 200;
- int left_margin = 0;
-
- for (int i = 2; i < 6; i += 3)
- {
- if (qrPattern.cap(i).toLower() == "size")
- {
- size = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : size;
- }
- else if (qrPattern.cap(i).toLower() == "left_margin")
- {
- left_margin = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : left_margin;
- }
- }
-
- QString content = qrPattern.cap(7);
- QString qrImage = generateQRCode(content, size, left_margin);
-
- QString img = qrImage.isEmpty() ? "<qr-code>" : QString("[img]%1[/img]").arg(qrImage);
-
- result.replace(offset, qrPattern.cap(0).length(), img);
- offset += img.size();
- }
-
- return result;
- }
-
- //---------------------------------------------------------------------------
- QString PrintingService::generatePDF417(const QString & aString)
- {
- QString result = aString;
-
- auto generatePDFCode = [=](const QString & aText, int aSize, int aLeftMargin) -> QString
- {
- int divider = aText.size() > 100 ? 2 : 3;
-
- QImage image(QSize(aSize + aLeftMargin, aSize / divider), QImage::Format_ARGB32);
- image.fill(QColor("transparent"));
-
- Zint::QZint zint;
-
- zint.setWidth(aSize);
- zint.setHeight(aSize / divider);
- zint.setText(aText);
- zint.setWhitespace(0);
- zint.setBorderType(Zint::QZint::NO_BORDER);
- zint.setInputMode(UNICODE_MODE);
- zint.setHideText(true);
- zint.setSymbol(BARCODE_PDF417);
- zint.setFgColor(QColor("black"));
- zint.setBgColor(QColor("white"));
-
- QPainter painter(&image);
- painter.fillRect(QRectF(0, 0, image.width(), image.height()), QColor("white"));
- zint.render(painter, QRectF(aLeftMargin, 0, image.width() - aLeftMargin, image.height()));
- painter.end();
-
- if (zint.hasErrors())
- {
- toLog(LogLevel::Error, QString("Failed render PDF-417 code: %1.").arg(zint.lastError()));
- }
- else
- {
- QBuffer buffer;
- if (buffer.open(QIODevice::WriteOnly))
- {
- image.save(&buffer, "png");
-
- return buffer.data().toBase64();
- }
- }
-
- return "";
- };
-
- QRegExp qrPattern("\\[pdf417(\\s*(\\w+)\\s*=\\s*(\\d+)\\s*)?(\\s*(\\w+)\\s*=\\s*(\\d+)\\s*)?\\](.*)\\[/pdf417\\]", Qt::CaseInsensitive);
-
- qrPattern.setMinimal(true);
-
- int offset = 0;
- while ((offset = qrPattern.indexIn(result, offset)) != -1)
- {
- int size = 200;
- int left_margin = 0;
-
- for (int i = 2; i < 6; i += 3)
- {
- if (qrPattern.cap(i).toLower() == "size")
- {
- size = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : size;
- }
- else if (qrPattern.cap(i).toLower() == "left_margin")
- {
- left_margin = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : left_margin;
- }
- }
-
- QString content = qrPattern.cap(7);
- QString qrImage = generatePDFCode(content, size, left_margin);
-
- QString img = qrImage.isEmpty() ? "<pdf417-code>" : QString("[img]%1[/img]").arg(qrImage);
-
- result.replace(offset, qrPattern.cap(0).length(), img);
- offset += img.size();
- }
-
- return result;
- }
-
- //---------------------------------------------------------------------------
- QString PrintingService::generate1D(const QString & aString)
- {
- QString result = aString;
-
- auto generatePDFCode = [=](const QString & aText, int aSize, int aLeftMargin) -> QString
- {
- int divider = aText.size() > 100 ? 2 : 3;
-
- QImage image(QSize(aSize + aLeftMargin, aSize / divider), QImage::Format_ARGB32);
- image.fill(QColor("transparent"));
-
- Zint::QZint zint;
-
- zint.setWidth(aSize);
- zint.setHeight(aSize / divider);
- zint.setText(aText);
- zint.setWhitespace(0);
- zint.setBorderType(Zint::QZint::NO_BORDER);
- zint.setInputMode(UNICODE_MODE);
- zint.setHideText(true);
- zint.setSymbol(BARCODE_CODE128);
- zint.setFgColor(QColor("black"));
- zint.setBgColor(QColor("white"));
-
- QPainter painter(&image);
- painter.fillRect(QRectF(0, 0, image.width(), image.height()), QColor("white"));
- zint.render(painter, QRectF(aLeftMargin, 0, image.width() - aLeftMargin, image.height()));
- painter.end();
-
- if (zint.hasErrors())
- {
- toLog(LogLevel::Error, QString("Failed render PDF-417 code: %1.").arg(zint.lastError()));
- }
- else
- {
- QBuffer buffer;
- if (buffer.open(QIODevice::WriteOnly))
- {
- image.save(&buffer, "png");
-
- return buffer.data().toBase64();
- }
- }
-
- return "";
- };
-
- QRegExp qrPattern("\\[1d(\\s*(\\w+)\\s*=\\s*(\\d+)\\s*)?(\\s*(\\w+)\\s*=\\s*(\\d+)\\s*)?\\](.*)\\[/1d\\]", Qt::CaseInsensitive);
-
- qrPattern.setMinimal(true);
-
- int offset = 0;
- while ((offset = qrPattern.indexIn(result, offset)) != -1)
- {
- int size = 200;
- int left_margin = 0;
-
- for (int i = 2; i < 6; i += 3)
- {
- if (qrPattern.cap(i).toLower() == "size")
- {
- size = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : size;
- }
- else if (qrPattern.cap(i).toLower() == "left_margin")
- {
- left_margin = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : left_margin;
- }
- }
-
- QString content = qrPattern.cap(7);
- QString qrImage = generatePDFCode(content, size, left_margin);
-
- QString img = qrImage.isEmpty() ? "<pdf417-code>" : QString("[img]%1[/img]").arg(qrImage);
-
- result.replace(offset, qrPattern.cap(0).length(), img);
- offset += img.size();
- }
-
- return result;
- }
-
- //---------------------------------------------------------------------------
- QString PrintingService::generateLine(const QString & aString)
- {
- QString result = aString;
-
- auto generateLine = [](int aSize, int aHeight, int aDense) -> QString
- {
- QImage image(QSize(aSize, aHeight), QImage::Format_ARGB32);
- image.fill(QColor("transparent"));
-
- Qt::BrushStyle style;
-
- if (aDense <= 0) style = Qt::SolidPattern;
- else if (aDense >= 6) style = Qt::Dense7Pattern;
- else style = static_cast<Qt::BrushStyle>(aDense + 1);
-
- QPainter painter(&image);
- painter.setBrush(style);
- painter.setPen(QColor("transparent"));
- painter.drawRect(0, 0, image.width(), image.height());
- painter.end();
-
- QBuffer buffer;
- if (buffer.open(QIODevice::WriteOnly))
- {
- image.save(&buffer, "png");
- return buffer.data().toBase64();
- }
-
- return QString();
- };
-
- QRegExp qrPattern("\\[hr(\\s*(\\w+)\\s*=\\s*(\\d+)\\s*)?(\\s*(\\w+)\\s*=\\s*(\\d+)\\s*)?\\](.*)\\[/hr\\]", Qt::CaseInsensitive);
-
- qrPattern.setMinimal(true);
-
- int offset = 0;
- while ((offset = qrPattern.indexIn(result, offset)) != -1)
- {
- int size = 220;
- int height = 1;
- int dense = 0;
-
- for (int i = 2; i < 6; i += 3)
- {
- if (qrPattern.cap(i).toLower() == "size")
- {
- size = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : size;
- }
- else if (qrPattern.cap(i).toLower() == "height")
- {
- height = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : height;
- }
- else if (qrPattern.cap(i).toLower() == "ds")
- {
- dense = qrPattern.cap(i + 1).toInt() ? qrPattern.cap(i + 1).toInt() : dense;
- }
- }
-
- QString qrImage = generateLine(size, height, dense);
-
- QString img = qrImage.isEmpty() ? "<hr-code>" : QString("[img]%1[/img]").arg(qrImage);
-
- result.replace(offset, qrPattern.cap(0).length(), img);
- offset += img.size();
- }
-
- return result;
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::expandTags(QStringList & aReceipt, const QVariantMap & aParameters)
- {
- int operatorFieldIndex = 0;
-
- QVariantMap userParameters = aParameters;
-
- // Если есть дата создания платежа и она валидна, то подставляем на чек дату платежа
- userParameters[CPrintConstants::DateTime] = aParameters.contains(PPSDK::CPayment::Parameters::CreationDate) &&
- aParameters.value(PPSDK::CPayment::Parameters::CreationDate, "").toDateTime().isValid() ?
- aParameters.value(PPSDK::CPayment::Parameters::CreationDate, "").toDateTime().toString(CPrintingService::ReceiptDateTimeFormat) :
- QDateTime::currentDateTime().toLocalTime().toString(CPrintingService::ReceiptDateTimeFormat);
-
- // Добавляем поля, зависящие от конкретного вызова.
- userParameters[CPrintConstants::ReceiptNumber] = getReceiptID();
-
- int providerId = aParameters.value(PPSDK::CPayment::Parameters::Provider, -1).toInt();
- PPSDK::SProvider provider = SettingsService::instance(mApplication)->getAdapter<PPSDK::DealerSettings>()->getProvider(providerId);
- PPSDK::SProvider mnpProvider = SettingsService::instance(mApplication)->getAdapter<PPSDK::DealerSettings>()->getMNPProvider(providerId,
- aParameters.value(PPSDK::CPayment::Parameters::MNPGetewayIn, 0).toLongLong(),
- aParameters.value(PPSDK::CPayment::Parameters::MNPGetewayOut, 0).toLongLong());
-
- if (!mnpProvider.isNull())
- {
- userParameters[CPrintConstants::OpBrand] = mnpProvider.name;
- }
-
- PPSDK::SecurityFilter filter(mnpProvider, PPSDK::SProviderField::SecuritySubsystem::Printer);
-
- // Набор строк, полученных в результате применения всех подстановок.
- QStringList result;
-
- // Для каждого тега в шаблоне чека, заменяем его значением из параметров.
- for (auto it = aReceipt.begin(); it != aReceipt.end(); ++it)
- {
- QRegExp tagPattern("%(.*)%", Qt::CaseInsensitive);
-
- tagPattern.setMinimal(true);
-
- int offset = 0;
-
- while ((offset = tagPattern.indexIn(*it, offset)) != -1)
- {
- QString tag = tagPattern.cap(1);
-
- // %% заменяем на %
- if (tag.isEmpty())
- {
- it->replace(offset, tagPattern.cap(0).length(), "%");
- offset += 1;
- continue;
- }
-
- bool isMasked = tag.endsWith(CPrintingService::MaskedFieldPostfix);
- if (isMasked)
- {
- tag.remove(CPrintingService::MaskedFieldPostfix);
- }
-
- // Параметр пользователя?
- auto userParameter = userParameters.find(tag);
-
- if (userParameter != userParameters.end())
- {
- // Параметр список?
- if (tag.startsWith("[") && tag.endsWith("]"))
- {
- // удаляем строку с параметром-списком
- aReceipt.erase(it, it);
- it++;
-
- QStringList listItems = userParameter.value().toStringList();
- QStringList::const_iterator listIt;
- for (listIt = listItems.constBegin(); listIt != listItems.constEnd(); listIt++)
- {
- result.append(filter.apply(tag, *listIt));
- }
- }
- else
- {
- QString masked = isMasked ?
- maskedString(userParameter.value().toString(), isMasked) :
- filter.apply(userParameter.key(), userParameter.value().toString());
-
- it->replace(offset, tagPattern.cap(0).length(), masked);
- offset += masked.length();
- }
-
- continue;
- }
-
- // Статический параметр?
- auto staticParameter = mStaticParameters.find(tag);
-
- if (staticParameter != mStaticParameters.end())
- {
- QString masked = isMasked ?
- maskedString(staticParameter.value(), isMasked) :
- filter.apply(staticParameter.key(), staticParameter.value());
-
- it->replace(offset, tagPattern.cap(0).length(), masked);
- offset += masked.length();
-
- continue;
- }
-
- // Название или значение поля оператора?
- QString targetParameter;
-
- QRegExp operatorFieldPattern("FIELD_(.+)", Qt::CaseInsensitive);
-
- operatorFieldPattern.setMinimal(true);
-
- if (operatorFieldPattern.indexIn(tag) != -1)
- {
- targetParameter = operatorFieldPattern.cap(1);
-
- if (!filter.haveFilter(targetParameter))
- {
- targetParameter += CPrintingService::DislayPostfix;
- }
- }
- else
- {
- operatorFieldPattern.setPattern("RAWFIELD_(.+)");
-
- if (operatorFieldPattern.indexIn(tag) != -1)
- {
- targetParameter = operatorFieldPattern.cap(1);
- }
- }
-
- if (!targetParameter.isEmpty())
- {
- if (!aParameters.contains(targetParameter))
- {
- toLog(LogLevel::Error, QString("Operator parameter %1 required in receipt but missing in parameters list.").arg(targetParameter));
- }
- else
- {
- QString masked = isMasked ?
- maskedString(aParameters[targetParameter].toString(), isMasked) :
- filter.apply(targetParameter, aParameters[targetParameter].toString());
-
- it->replace(offset, tagPattern.cap(0).length(), masked);
- offset += masked.length();
-
- continue;
- }
- }
-
- // Тег OPERATOR_FIELD
- if (tag == "OPERATOR_FIELD")
- {
- if (provider.isNull())
- {
- toLog(LogLevel::Error, QString("Failed to expand operator field. Provider id %1 is not valid.").arg(providerId));
- }
-
- // Вставляем поля оператора.
- if (operatorFieldIndex < provider.fields.size())
- {
- PPSDK::SProviderField field = provider.fields.at(operatorFieldIndex);
-
- QString fieldValue = aParameters.value(field.id, QString()).toString();
-
- bool findNextField = true;
-
- while (fieldValue.isEmpty())
- {
- if (operatorFieldIndex >= provider.fields.size())
- {
- findNextField = false;
- break;
- }
-
- field = provider.fields.at(operatorFieldIndex);
- fieldValue = aParameters.value(field.id, QString()).toString();
-
- if (fieldValue.isEmpty())
- {
- ++operatorFieldIndex;
- }
- }
-
- if (findNextField)
- {
- QString masked;
-
- if (filter.haveFilter(field.id))
- {
- masked = filter.apply(field.id, aParameters.value(field.id, QString()).toString());
- }
- else
- {
- QString value = aParameters.value(field.id + CPrintingService::DislayPostfix, QString()).toString();
- masked = isMasked ? maskedString(value, isMasked) : value;
- }
-
- QString replaceString = QString("%1: %2").arg(field.title).arg(masked);
-
- it->replace(offset, tagPattern.cap(0).size(), replaceString);
- offset = replaceString.length();
-
- ++operatorFieldIndex;
- }
- }
- else
- {
- it->replace(tagPattern.cap(0), QString());
- }
- }
-
- // Оставляем поле пустым.
- it->replace(tagPattern.cap(0), QString());
- }
-
- // Предзагружаем содержимое тегов [IMG]
- *it = convertImage2base64(*it);
-
- // Преобразуем [QR] теги в [IMG]
- *it = generateQR(*it);
-
- // Преобразуем [PDF417] теги в [IMG]
- *it = generatePDF417(*it);
-
- // Преобразуем [1d] теги в [IMG]
- *it = generate1D(*it);
-
- // Преобразуем [hr] тег в [IMG]
- *it = generateLine(*it);
-
- // Обработаем тег с условием
- if (it->contains(CPrintingService::ConditionTag))
- {
- QStringList l = it->split(CPrintingService::ConditionTag);
- if (QJSEngine().evaluate(l.first()).toBool())
- {
- result.append(l.last());
- }
-
- continue;
- }
-
- if (it->length() > 0)
- {
- result.append(*it);
- }
- }
-
- aReceipt = result;
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::loadReceiptTemplates()
- {
- auto loadReceiptTemplate = [&](const QFileInfo & aFileInfo)
- {
- if (!aFileInfo.suffix().compare("xml", Qt::CaseInsensitive))
- {
- QDomDocument xmlFile(aFileInfo.fileName());
- QFile file(aFileInfo.filePath());
- if (!file.open(QIODevice::ReadOnly))
- {
- toLog(LogLevel::Error, QString("Failed to open file %1").arg(aFileInfo.filePath()));
- return;
- }
-
- xmlFile.setContent(&file);
-
- QDomElement body = xmlFile.documentElement();
-
- QStringList receiptContents;
-
- for (QDomNode node = body.firstChild(); !node.isNull(); node = node.nextSibling())
- {
- QDomElement row = node.toElement();
-
- if (row.tagName() == "string" || row.tagName() == "else")
- {
- QString prefix = row.attribute("if").isEmpty() ? "" : QString("%1%2").arg(row.attribute("if")).arg(CPrintingService::ConditionTag);
- receiptContents.append(QString("%1%2").arg(prefix).arg(row.text()));
- }
- else if (row.tagName() == "hr")
- {
- receiptContents.append("[hr]-[/hr]");
- }
- }
-
- if (!receiptContents.isEmpty())
- {
- mCachedReceipts.insert(aFileInfo.baseName().toLower(), receiptContents);
- }
- else
- {
- toLog(LogLevel::Error, QString("Bad receipt template '%1': parse xml error").arg(aFileInfo.fileName()));
- }
- }
- else
- {
- toLog(LogLevel::Error, QString("Bad receipt template file extension : %1").arg(aFileInfo.fileName()));
- }
- };
-
- // Загружаем все шаблоны чеков в папке ./receipts
- QDir receiptDirectory;
-
- receiptDirectory.setPath(mApplication->getWorkingDirectory() + "/data/receipts");
-
- // Загружаем все файлы, которые есть в каталоге.
- foreach (const QFileInfo & fileInfo, receiptDirectory.entryInfoList(QDir::Files))
- {
- loadReceiptTemplate(fileInfo);
- }
-
- // загружаем все шаблоны из папки пользовательских шаблонов чеков
- receiptDirectory.setPath(mApplication->getWorkingDirectory() + "/user/receipts");
-
- // Загружаем все файлы, которые есть в каталоге.
- foreach (const QFileInfo & fileInfo, receiptDirectory.entryInfoList(QDir::Files))
- {
- loadReceiptTemplate(fileInfo);
- }
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::saveReceiptContent(const QString & aReceiptName, const QStringList & aContents)
- {
- // Получаем имя папки с чеками.
- QString suffix = QDate::currentDate().toString("yyyy.MM.dd");
-
- QDir path(mApplication->getWorkingDirectory() + "/receipts/" + suffix);
-
- if (!path.exists())
- {
- if (!QDir().mkpath(path.path()))
- {
- toLog(LogLevel::Error, "Failed to create printed receipts folder.");
- return;
- }
- }
-
- auto fileName = path.path() + QDir::separator() + aReceiptName + ".txt";
- QFile file(fileName);
-
- // Сохраняем чек.
- if (file.open(QIODevice::WriteOnly))
- {
- QTextStream ostream(&file);
-
- ostream << aContents.join("\r\n");
-
- ostream.flush();
- }
- else
- {
- toLog(LogLevel::Error, QString("Failed to open file %1 for receipt.").arg(fileName));
- }
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::saveReceipt(const QVariantMap & aParameters, const QString & aReceiptTemplate)
- {
- QStringList receipt = getReceipt(aReceiptTemplate, aParameters);
-
- QString fileName = QTime::currentTime().toString("hhmmsszzz");
-
- if (aParameters.contains(PPSDK::CPayment::Parameters::ID))
- {
- fileName += QString("_%1").arg(aParameters[PPSDK::CPayment::Parameters::ID].toString());
- }
-
- fileName += "_not_printed";
-
- saveReceiptContent(fileName, receipt);
- }
-
- //---------------------------------------------------------------------------
- QString PrintingService::loadReceipt(qint64 aPaymentId)
- {
- // Получаем имя папки с чеками.
- QString suffix = QDate::currentDate().toString("yyyy.MM.dd");
-
- QDir path(mApplication->getWorkingDirectory() + "/receipts/" + suffix);
-
- if (!path.exists())
- {
- toLog(LogLevel::Error, "Failed to find printed receipts folder.");
- return QString();
- }
-
- QDir dir(path.path() + QDir::separator());
- QStringList receipts = dir.entryList(QStringList() << QString("*%1.txt").arg(aPaymentId) << QString("*%1_not_printed.txt").arg(aPaymentId));
-
- if (!receipts.isEmpty())
- {
- QFile f(dir.absolutePath() + QDir::separator() + receipts.takeFirst());
- if (f.open(QIODevice::ReadOnly))
- {
- return QTextCodec::codecForName("Windows-1251")->toUnicode(f.readAll());
- }
- }
-
- return QString();
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::onStatusChanged(DSDK::EWarningLevel::Enum aWarningLevel, const QString & /*aTranslation*/, int /*aStatus*/)
- {
- emit printerStatus(aWarningLevel == DSDK::EWarningLevel::OK);
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::onFRSessionClosed(const QVariantMap & aParameters)
- {
- // Получаем имя папки с отчётами.
- QDir path(mApplication->getWorkingDirectory() + "/receipts/reports");
-
- if (!path.exists())
- {
- if (!QDir().mkpath(path.path()))
- {
- toLog(LogLevel::Error, "Failed to create printed reports folder.");
- return;
- }
- }
-
- auto fileName = path.path() + QDir::separator() + QDateTime::currentDateTime().toString("yyyy.MM.dd hhmmsszzz") + ".xml";
- QFile file(fileName);
-
- // Сохраняем отчёт.
- if (file.open(QIODevice::WriteOnly))
- {
- using namespace SDK::Driver;
-
- QXmlStreamWriter stream(&file);
- stream.setAutoFormatting(true);
- stream.writeStartDocument();
-
- stream.writeStartElement(CFRReport::ZReport);
- stream.writeAttribute(CFRReport::Number, aParameters[CFiscalPrinter::ZReportNumber].toString());
-
- stream.writeStartElement(CFRReport::FR);
- stream.writeAttribute(CFRReport::Serial, aParameters[CFiscalPrinter::Serial].toString());
- stream.writeAttribute(CFRReport::RNM, aParameters[CFiscalPrinter::RNM].toString());
- stream.writeEndElement(); // CFRReport::FR
-
- stream.writeTextElement(CFRReport::PaymentCount, aParameters[CFiscalPrinter::PaymentCount].toString());
- double amount = aParameters[CFiscalPrinter::PaymentAmount].toDouble();
- stream.writeTextElement(CFRReport::PaymentAmount, QString::number(amount, 'f', 2));
- amount = aParameters[CFiscalPrinter::NonNullableAmount].toDouble();
- stream.writeTextElement(CFRReport::NonNullableAmount, QString::number(amount, 'f', 2));
- stream.writeTextElement(CFRReport::FRDateTime, aParameters[CFiscalPrinter::FRDateTime].toString());
- stream.writeTextElement(CFRReport::SystemDateTime, aParameters[CFiscalPrinter::SystemDateTime].toString());
-
- stream.writeEndElement(); // CFRReport::ZReport
- stream.writeEndDocument();
-
- file.flush();
- file.close();
- }
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::updateHardwareConfiguration()
- {
- PPSDK::TerminalSettings * settings = SettingsService::instance(mApplication)->getAdapter<PPSDK::TerminalSettings>();
-
- // Получаем информацию о принтерах из конфигов.
- QString regExpData = QString("(%1|%2|%3)")
- .arg(DSDK::CComponents::Printer).arg(DSDK::CComponents::DocumentPrinter).arg(DSDK::CComponents::FiscalRegistrator);
- QStringList printerNames = settings->getDeviceList().filter(QRegExp(regExpData));
-
- mPrinterDevices.clear();
- mAvailablePrinters.clear();
-
- QVariantMap delalerSettings;
- delalerSettings.insert(CHardwareSDK::FR::DealerTaxation, mStaticParameters.value(CPrintConstants::DealerTaxation));
- delalerSettings.insert(CHardwareSDK::FR::DealerAgentFlag, mStaticParameters.value(CPrintConstants::DealerAgentFlag));
-
- // Запрашиваем устройства.
- foreach (const QString & printerName, printerNames)
- {
- DSDK::IPrinter * device = dynamic_cast<DSDK::IPrinter *>(mDeviceService->acquireDevice(printerName));
-
- if (device)
- {
- mPrinterDevices.append(device);
-
- // Подписываемся на события принтера.
- device->subscribe(SDK::Driver::IDevice::StatusSignal, this, SLOT(onStatusChanged(SDK::Driver::EWarningLevel::Enum, const QString &, int)));
-
- // Подписываемся на события фискальника.
- if (dynamic_cast<DSDK::IFiscalPrinter *>(device))
- {
- device->subscribe(SDK::Driver::IFiscalPrinter::FRSessionClosedSignal, this, SLOT(onFRSessionClosed(const QVariantMap &)));
- }
-
- device->setDeviceConfiguration(delalerSettings);
- }
- else
- {
- toLog(LogLevel::Error, QString("Failed to acquire device %1 .").arg(printerName));
- }
- }
-
- mAvailablePrinters = mPrinterDevices.toSet();
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::createFiscalRegister()
- {
- if (!mFiscalRegister)
- {
- // Получаем информацию о фискальных регистраторах.
- PPSDK::ExtensionsSettings * extSettings = SettingsService::instance(mApplication)->getAdapter<PPSDK::ExtensionsSettings>();
- SDK::Plugin::IPluginLoader * pluginLoader = PluginService::instance(mApplication)->getPluginLoader();
-
- foreach(auto fr, pluginLoader->getPluginList(QRegExp(PPSDK::CComponents::FiscalRegister)))
- {
- auto plugin = pluginLoader->createPlugin(fr);
- if (!plugin)
- {
- continue;
- }
-
- PPSDK::IFiscalRegister * frPlugin = dynamic_cast<PPSDK::IFiscalRegister *>(plugin);
-
- if (!frPlugin)
- {
- toLog(LogLevel::Error, QString("FR %1 not have IFiscalRegister interface.").arg(fr));
- pluginLoader->destroyPlugin(plugin);
- continue;
- }
-
- auto parameters = extSettings->getSettings(plugin->getPluginName());
-
- if (parameters.isEmpty())
- {
- toLog(LogLevel::Warning, QString("FR %1 not have extensions settings. Skip it. (check config.xml).").arg(plugin->getPluginName()));
- pluginLoader->destroyPlugin(plugin);
- continue;
- }
-
- connect(dynamic_cast<QObject *>(frPlugin), SDK::Driver::IFiscalPrinter::FRSessionClosedSignal, this, SLOT(onFRSessionClosed(const QVariantMap &)));
-
- if (!frPlugin->initialize(parameters))
- {
- toLog(LogLevel::Warning, QString("FR %1 error initialize. Skip it.").arg(plugin->getPluginName()));
- pluginLoader->destroyPlugin(plugin);
- continue;
- }
-
- mFiscalRegister = frPlugin;
- toLog(LogLevel::Normal, QString("FR %1 loaded successful.").arg(plugin->getPluginName()));
- break;
- }
- }
- }
-
- //---------------------------------------------------------------------------
- SDK::PaymentProcessor::IFiscalRegister * PrintingService::getFiscalRegister() const
- {
- return mFiscalRegister;
- }
-
- //---------------------------------------------------------------------------
- void PrintingService::setFiscalNumber(qint64 aPaymentId, const QVariantMap & aParameters)
- {
- QList<PPSDK::IPayment::SParameter> parameters;
-
- foreach (auto name, aParameters.keys())
- {
- parameters.push_back(PPSDK::IPayment::SParameter(name, aParameters.value(name), true));
- }
-
- if (!PaymentService::instance(mApplication)->updatePaymentFields(aPaymentId, parameters))
- {
- toLog(LogLevel::Error, QString("Payment %1: Error update fiscal parameters.").arg(aPaymentId));
- }
- }
-
- //---------------------------------------------------------------------------
- SDK::PaymentProcessor::SCurrencySettings PrintingService::getCurrencySettings() const
- {
- SettingsService * settingsService = SettingsService::instance(mApplication);
-
- PPSDK::TerminalSettings * terminalSettings = settingsService->getAdapter<PPSDK::TerminalSettings>();
-
- return terminalSettings->getCurrencySettings();
- }
-
- //---------------------------------------------------------------------------
|