Browse Source

Cooment: refs #1 Synchronize with release commit: ae92c5cb98

master
parent
commit
297d32dc0d
100 changed files with 1713 additions and 592 deletions
  1. +2
    -0
      3.0/filelist.txt
  2. +11
    -4
      3.0/src/apps/PaymentProcessor/src/Services/IntegratedDrivers.cpp
  3. +1
    -1
      3.0/src/apps/PaymentProcessor/src/Services/PaymentService.cpp
  4. +1
    -1
      3.0/src/apps/PaymentProcessor/src/Services/PaymentService.h
  5. +76
    -37
      3.0/src/apps/PaymentProcessor/src/Services/PrintingCommands.cpp
  6. +19
    -1
      3.0/src/apps/PaymentProcessor/src/Services/PrintingCommands.h
  7. +192
    -137
      3.0/src/apps/PaymentProcessor/src/Services/PrintingService.cpp
  8. +11
    -1
      3.0/src/apps/PaymentProcessor/src/Services/PrintingService.h
  9. +19
    -2
      3.0/src/apps/Updater/src/UpdaterApp.cpp
  10. +2
    -0
      3.0/src/apps/Updater/src/UpdaterApp.h
  11. +24
    -0
      3.0/src/includes/Common/ExitAction.h
  12. +1
    -0
      3.0/src/includes/Hardware/Common/HardwareConstants.h
  13. +41
    -15
      3.0/src/includes/Hardware/FR/FFDataTypes.h
  14. +2
    -2
      3.0/src/includes/Hardware/FR/FRBaseConstants.h
  15. +1
    -0
      3.0/src/includes/Hardware/FR/FRStatusCodes.h
  16. +1
    -0
      3.0/src/includes/Hardware/FR/FRStatusesDescriptions.h
  17. +1
    -1
      3.0/src/includes/Hardware/Printers/PrinterConstants.h
  18. +2
    -0
      3.0/src/includes/Hardware/Printers/PrinterStatusCodes.h
  19. +2
    -0
      3.0/src/includes/Hardware/Printers/PrinterStatusesDescriptions.h
  20. +18
    -1
      3.0/src/includes/SDK/Drivers/FR/FiscalDataTypes.h
  21. +7
    -0
      3.0/src/includes/SDK/Drivers/FR/FiscalFields.h
  22. +4
    -2
      3.0/src/includes/SDK/Drivers/HardwareConstants.h
  23. +0
    -12
      3.0/src/includes/SDK/Drivers/IFiscalPrinter.h
  24. +3
    -0
      3.0/src/includes/SDK/Drivers/IIOPort.h
  25. +3
    -0
      3.0/src/includes/SDK/PaymentProcessor/Core/IPrinterService.h
  26. +31
    -18
      3.0/src/includes/SDK/PaymentProcessor/FiscalRegister/IFiscalRegister.h
  27. +6
    -0
      3.0/src/includes/SDK/PaymentProcessor/Scripting/PaymentService.h
  28. +3
    -0
      3.0/src/includes/SDK/PaymentProcessor/Scripting/PrinterService.h
  29. +69
    -0
      3.0/src/includes/SDK/Plugins/PluginBase.h
  30. +1
    -0
      3.0/src/interface/modern/confirm_payment_scene.qml
  31. +8
    -6
      3.0/src/interface/modern/scenario/payment_scenario.js
  32. +1
    -1
      3.0/src/modules/Hardware/CashAcceptors/src/CCNet/FirmwareVersions.h
  33. +1
    -0
      3.0/src/modules/Hardware/Common/msvc/Common.vcxproj
  34. +3
    -0
      3.0/src/modules/Hardware/Common/msvc/Common.vcxproj.filters
  35. +3
    -0
      3.0/src/modules/Hardware/Common/src/Base/DeviceBase.h
  36. +2
    -2
      3.0/src/modules/Hardware/Common/src/Polling/PollingDeviceBase.cpp
  37. +1
    -1
      3.0/src/modules/Hardware/Common/src/Polling/PollingDeviceBase.h
  38. +2
    -3
      3.0/src/modules/Hardware/Common/src/Port/LibUSB/LibUSBDeviceBase.cpp
  39. +0
    -14
      3.0/src/modules/Hardware/Common/src/Utils/DeviceUtils.h
  40. +28
    -0
      3.0/src/modules/Hardware/Common/src/Utils/ProtocolUtils.cpp
  41. +6
    -0
      3.0/src/modules/Hardware/Common/src/Utils/ProtocolUtils.h
  42. +1
    -0
      3.0/src/modules/Hardware/FR/src/Atol/AtolModelData.cpp
  43. +1
    -0
      3.0/src/modules/Hardware/FR/src/Atol/AtolModelData.h
  44. +2
    -1
      3.0/src/modules/Hardware/FR/src/Atol/Base/AtolFRBase.cpp
  45. +3
    -0
      3.0/src/modules/Hardware/FR/src/Atol/Base/AtolFRBase.h
  46. +37
    -2
      3.0/src/modules/Hardware/FR/src/Atol/Online/AtolOnlineFRBase.cpp
  47. +6
    -0
      3.0/src/modules/Hardware/FR/src/Atol/Online/AtolOnlineFRBase.h
  48. +11
    -4
      3.0/src/modules/Hardware/FR/src/Atol/Online/AtolOnlineFRConstants.h
  49. +1
    -2
      3.0/src/modules/Hardware/FR/src/Atol/Online/Paymaster.cpp
  50. +112
    -73
      3.0/src/modules/Hardware/FR/src/Base/FFEngine.cpp
  51. +7
    -0
      3.0/src/modules/Hardware/FR/src/Base/FFEngine.h
  52. +170
    -49
      3.0/src/modules/Hardware/FR/src/Base/FRBase.cpp
  53. +17
    -2
      3.0/src/modules/Hardware/FR/src/Base/FRBase.h
  54. +32
    -2
      3.0/src/modules/Hardware/FR/src/Base/FiscalFieldDescriptions.cpp
  55. +55
    -37
      3.0/src/modules/Hardware/FR/src/Base/FiscalFieldDescriptions.h
  56. +43
    -1
      3.0/src/modules/Hardware/FR/src/Base/Port/PortFRBase.cpp
  57. +9
    -0
      3.0/src/modules/Hardware/FR/src/Base/Port/PortFRBase.h
  58. +29
    -22
      3.0/src/modules/Hardware/FR/src/Kasbi/KasbiFRBase.cpp
  59. +4
    -2
      3.0/src/modules/Hardware/FR/src/Kasbi/KasbiFRConstants.h
  60. +103
    -13
      3.0/src/modules/Hardware/FR/src/MStar/Online/AFPFR.cpp
  61. +6
    -0
      3.0/src/modules/Hardware/FR/src/MStar/Online/AFPFR.h
  62. +3
    -2
      3.0/src/modules/Hardware/FR/src/MStar/Online/AFPFRConstants.h
  63. +3
    -16
      3.0/src/modules/Hardware/FR/src/Prim/Online/PrimOnlineFRBase.cpp
  64. +0
    -3
      3.0/src/modules/Hardware/FR/src/Prim/Online/PrimOnlineFRBase.h
  65. +0
    -3
      3.0/src/modules/Hardware/FR/src/Prim/Online/PrimOnlineFRConstants.h
  66. +46
    -9
      3.0/src/modules/Hardware/FR/src/Prim/PrimFRBase.cpp
  67. +5
    -2
      3.0/src/modules/Hardware/FR/src/Prim/PrimFRBase.h
  68. +3
    -0
      3.0/src/modules/Hardware/FR/src/Prim/PrimFRConstants.h
  69. +13
    -3
      3.0/src/modules/Hardware/FR/src/Shtrih/Base/ProtoShtrihFR.cpp
  70. +1
    -1
      3.0/src/modules/Hardware/FR/src/Shtrih/Base/ProtoShtrihFR.h
  71. +10
    -2
      3.0/src/modules/Hardware/FR/src/Shtrih/Online/MStarTK2.cpp
  72. +1
    -2
      3.0/src/modules/Hardware/FR/src/Shtrih/Online/Pay/PayOnline.cpp
  73. +29
    -25
      3.0/src/modules/Hardware/FR/src/Shtrih/Online/ShtrihFROnlineConstants.h
  74. +13
    -1
      3.0/src/modules/Hardware/FR/src/Shtrih/Online/ShtrihOnlineFRBase.cpp
  75. +1
    -0
      3.0/src/modules/Hardware/FR/src/Shtrih/ShtrihFRConstants.h
  76. +6
    -0
      3.0/src/modules/Hardware/IOPorts/src/COM/windows/AsyncSerialPort.cpp
  77. +3
    -0
      3.0/src/modules/Hardware/IOPorts/src/COM/windows/AsyncSerialPort.h
  78. +6
    -0
      3.0/src/modules/Hardware/IOPorts/src/LibUSB/LibUSBPort.cpp
  79. +3
    -0
      3.0/src/modules/Hardware/IOPorts/src/LibUSB/LibUSBPort.h
  80. +12
    -0
      3.0/src/modules/Hardware/IOPorts/src/TCP/TCPPort.cpp
  81. +6
    -0
      3.0/src/modules/Hardware/IOPorts/src/TCP/TCPPort.h
  82. +0
    -1
      3.0/src/modules/Hardware/Printers/src/Base/Port/PortPrinterBase.cpp
  83. +18
    -9
      3.0/src/modules/Hardware/Printers/src/Base/PrinterBase.cpp
  84. +4
    -1
      3.0/src/modules/Hardware/Printers/src/Base/PrinterBase.h
  85. +0
    -3
      3.0/src/modules/Hardware/Printers/src/POSPrinters/Citizen/CitizenPPU700/CitizenPPU700.cpp
  86. +0
    -1
      3.0/src/modules/Hardware/Printers/src/POSPrinters/Common/POSPrinter.cpp
  87. +0
    -1
      3.0/src/modules/Hardware/Printers/src/POSPrinters/Custom/CustomPrinters.cpp
  88. +2
    -0
      3.0/src/modules/Hardware/Printers/src/POSPrinters/Custom/CustomTG2480H.h
  89. +2
    -1
      3.0/src/modules/Hardware/Printers/src/POSPrinters/Custom/CustomVKP/CustomVKP80.cpp
  90. +0
    -1
      3.0/src/modules/Hardware/Printers/src/POSPrinters/Custom/CustomVKP/CustomVKP80III.cpp
  91. +0
    -1
      3.0/src/modules/Hardware/Printers/src/POSPrinters/EjectorPOS/EjectorPOS.cpp
  92. +69
    -24
      3.0/src/modules/Hardware/Printers/src/SystemPrinter/SystemPrinter.cpp
  93. +4
    -1
      3.0/src/modules/Hardware/Printers/src/SystemPrinter/SystemPrinter.h
  94. +2
    -0
      3.0/src/modules/Hardware/Printers/src/Tags/Tags.h
  95. +7
    -1
      3.0/src/modules/Hardware/Protocols/FR/Atol3/src/Atol3FR.cpp
  96. +141
    -0
      3.0/src/modules/SDK/PaymentProcessor/src/Commissions.cpp
  97. +18
    -0
      3.0/src/modules/SDK/PaymentProcessor/src/Commissions.h
  98. +6
    -6
      3.0/src/modules/SDK/PaymentProcessor/src/DealerSettings.h
  99. +12
    -0
      3.0/src/modules/SDK/PaymentProcessor/src/Scripting/PaymentService.cpp
  100. +6
    -0
      3.0/src/modules/SDK/PaymentProcessor/src/Scripting/PrinterService.cpp

+ 2
- 0
3.0/filelist.txt View File

@@ -87,6 +87,8 @@
/src/plugins/NativeScenarios/Migrator3000/
/src/plugins/NativeWidgets/ServiceMenu/
/src/plugins/Payments/Cyberplat/
/src/plugins/ScenarioBackends/UCS/
/src/plugins/ScenarioBackends/Uniteller/
/src/plugins/Plugins.sln
/src/qbs/libTemplate.qbs
/src/runtimes/common/


+ 11
- 4
3.0/src/apps/PaymentProcessor/src/Services/IntegratedDrivers.cpp View File

@@ -100,12 +100,19 @@ void IntegratedDrivers::checkDriverPath(QString & aDriverPath, const QVariantMap
auto parameterIt = std::find_if(parameters.begin(), parameters.end(), [&] (const SPluginParameter & aParameter) -> bool
{ return aParameter.name == jt.key(); });

if ((parameterIt != parameters.end()) && !parameterIt->readOnly && !parameterIt->possibleValues.values().contains(jt.value()) &&
!parameterIt->possibleValues.keys().contains(CHardwareSDK::Mask))
if (parameterIt != parameters.end())
{
paths.removeAt(i--);
SPluginParameter & parameter = *parameterIt;
QList<QVariant> & possibleValueValues = parameter.possibleValues.values();
QList<QString> & possibleValueKeys = parameter.possibleValues.keys();
const QVariant & value = jt.value();

break;
if (!parameter.readOnly && !possibleValueValues.contains(value) && (value != CHardwareSDK::Values::Auto) && !possibleValueKeys.contains(CHardwareSDK::Mask))
{
paths.removeAt(i--);

break;
}
}
}
}


+ 1
- 1
3.0/src/apps/PaymentProcessor/src/Services/PaymentService.cpp View File

@@ -941,7 +941,7 @@ void PaymentService::hangupProcessing()
}

//---------------------------------------------------------------------------
void PaymentService::doUpdatePaymentFields(quint64 aID, std::shared_ptr<PPSDK::IPayment> aPayment, const QList<SDK::PaymentProcessor::IPayment::SParameter> & aFields, bool aForce)
void PaymentService::doUpdatePaymentFields(qint64 aID, std::shared_ptr<PPSDK::IPayment> aPayment, const QList<SDK::PaymentProcessor::IPayment::SParameter> & aFields, bool aForce)
{
if (!aPayment)
{


+ 1
- 1
3.0/src/apps/PaymentProcessor/src/Services/PaymentService.h View File

@@ -222,7 +222,7 @@ private:
bool setChangeAmount(double aChange, std::shared_ptr<PPSDK::IPayment> aPaymentSource);

/// Обновляет параметры платежа.
void doUpdatePaymentFields(quint64 aID, std::shared_ptr<PPSDK::IPayment> aPayment, const QList<SDK::PaymentProcessor::IPayment::SParameter> & aFields, bool aForce = false);
void doUpdatePaymentFields(qint64 aID, std::shared_ptr<PPSDK::IPayment> aPayment, const QList<SDK::PaymentProcessor::IPayment::SParameter> & aFields, bool aForce = false);

signals:
/// Сигнал о завершении обработки платёжной команды, добавленной методом registerPaymentCommand.


+ 76
- 37
3.0/src/apps/PaymentProcessor/src/Services/PrintingCommands.cpp View File

@@ -18,7 +18,6 @@
// Project
#include "PrintingCommands.h"
#include "PrintingService.h"
#include "PrintConstants.h"
#include "PaymentService.h"

namespace FiscalCommand = SDK::Driver::EFiscalPrinterCommand;
@@ -31,6 +30,20 @@ void PrintCommand::setReceiptTemplate(const QString & aTemplateName)
}

//---------------------------------------------------------------------------
QVariantMap PrintCommand::getPrintingParameters(SDK::Driver::IPrinter * aPrinter)
{
QVariantMap configuration = aPrinter->getDeviceConfiguration();
QVariantMap result;

if (configuration.contains(CHardwareSDK::Printer::LineSize) && configuration[CHardwareSDK::Printer::LineSize].isValid())
{
result.insert(CHardwareSDK::Printer::LineSize, configuration[CHardwareSDK::Printer::LineSize]);
}

return result;
}

//---------------------------------------------------------------------------
PrintFiscalCommand::PrintFiscalCommand(const QString & aReceiptType, FiscalCommand::Enum aFiscalCommand, PrintingService * aService) :
PrintCommand(aReceiptType),
mFiscalCommand(aFiscalCommand),
@@ -134,6 +147,11 @@ DSDK::SPaymentData PrintFiscalCommand::getPaymentData(const QVariantMap & aParam
result.fiscalParameters[CHardwareSDK::FR::UserPhone] = QString();
result.fiscalParameters[CHardwareSDK::FR::UserMail] = QString();

foreach (auto FFData, CPrintCommands::FFDataList)
{
result.fiscalParameters[FFData] = aParameters[FFData];
}

#if 0
//TODO - решить как на верхнем уровне в интерфейсе мы будем давать возможность
// вводить телефон/email для отправки чека ПЕРЕД печатью этого чека.
@@ -178,37 +196,45 @@ bool PrintFiscalCommand::canFiscalPrint(DSDK::IPrinter * aPrinter, bool aRealChe
}

//---------------------------------------------------------------------------
bool PrintFiscalCommand::getFiscalInfo(QVariantMap & aParameters, QStringList & aReceiptLines)
bool PrintFiscalCommand::getFiscalInfo(QVariantMap & aParameters, QStringList & aReceiptLines, bool aWaitResult)
{
PPSDK::IFiscalRegister * fr = mService->getFiscalRegister();

if (fr && fr->haveCapability(PPSDK::IFiscalRegister::Receipt))
if (!fr || !fr->hasCapability(PPSDK::ERequestType::Receipt) || !fr->isReady(PPSDK::ERequestType::Receipt))
{
qint64 paymentId = aParameters.value(PPSDK::CPayment::Parameters::ID).toLongLong();
QStringList parameterNames = fr->getParameterNames();
return false;
}

// Если в параметрах платежа ещё нет информации о фискальном номере
bool OK = !parameterNames.toSet().intersect(aParameters.keys().toSet()).isEmpty();
if (!OK)
{
auto fiscalParameters = fr->createFiscalTicket(paymentId, aParameters, getPaymentData(aParameters));
OK = !fiscalParameters.isEmpty();
aParameters.unite(fiscalParameters);
qint64 paymentId = aParameters.value(PPSDK::CPayment::Parameters::ID).toLongLong();
QStringList parameterNames = fr->getParameterNames();

mService->setFiscalNumber(paymentId, fiscalParameters);
}
// Если в параметрах платежа ещё нет информации о фискальном номере
bool OK = !parameterNames.toSet().intersect(aParameters.keys().toSet()).isEmpty();
SDK::Driver::SPaymentData fiscalPaymentData;

if (!OK)
{
fiscalPaymentData = getPaymentData(aParameters);
auto fiscalParameters = fr->createFiscalTicket(paymentId, aParameters, fiscalPaymentData, aWaitResult);

if (OK)
if (!aWaitResult)
{
aReceiptLines = fr->getReceipt(paymentId, aParameters);
return true;
}

return OK;
OK = !fiscalParameters.isEmpty();

aParameters.unite(fiscalParameters);

mService->setFiscalNumber(paymentId, fiscalParameters);
}

if (OK)
{
aReceiptLines = fr->getReceipt(paymentId, aParameters, fiscalPaymentData);
}

return false;
return OK;
}

//---------------------------------------------------------------------------
@@ -225,6 +251,16 @@ bool PrintPayment::canPrint(DSDK::IPrinter * aPrinter, bool aRealCheck)
}

//---------------------------------------------------------------------------
bool PrintPayment::makeFiscalByFR(const QVariantMap & aParameters)
{
QStringList receipt = mService->getReceipt(mReceiptTemplate, aParameters);
QVariantMap parameters(aParameters);
QStringList fiscalPart;

return getFiscalInfo(parameters, fiscalPart, false);
}

//---------------------------------------------------------------------------
bool PrintPayment::print(DSDK::IPrinter * aPrinter, const QVariantMap & aParameters)
{
// Добавляем строки основного чека
@@ -245,9 +281,11 @@ bool PrintPayment::print(DSDK::IPrinter * aPrinter, const QVariantMap & aParamet

QStringList receipt = mService->getReceipt(mReceiptTemplate, actualParameters);

QVariantMap parameters = aParameters;
QVariantMap parameters = QVariantMap(aParameters).unite(getPrintingParameters(aPrinter));
QStringList fiscalPart;
bool hasFiscalInfo = getFiscalInfo(parameters, fiscalPart);

bool hasFiscalInfo = getFiscalInfo(parameters, fiscalPart, true);

if (hasFiscalInfo)
{
receipt.append(fiscalPart);
@@ -339,16 +377,17 @@ bool PrintPayment::isFiscal(DSDK::IPrinter * aPrinter)
bool PrintBalance::print(DSDK::IPrinter * aPrinter, const QVariantMap & aParameters)
{
QStringList receipt = mService->getReceipt(mReceiptType, expandFields(aParameters));
auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);

auto virtualFR = mService->getFiscalRegister();
QStringList fiscalReceipt;

if (mFiscalMode && virtualFR && virtualFR->haveCapability(PPSDK::IFiscalRegister::Balance))
if (mFiscalMode && virtualFR && virtualFR->hasCapability(PPSDK::ERequestType::XReport) && virtualFR->isReady(PPSDK::ERequestType::XReport) &&
virtualFR->serviceRequest(PPSDK::ERequestType::XReport, fiscalReceipt, getPrintingParameters(aPrinter)))
{
receipt.append(virtualFR->balance());
receipt << fiscalReceipt;
}

mService->saveReceiptContent(QString("%1_balance").arg(QTime::currentTime().toString("hhmmsszzz")), receipt);
auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);

return mFiscalMode && fr && fr->isFiscalReady(false, mFiscalCommand) ? fr->printXReport(receipt) : aPrinter->print(receipt);
}
@@ -406,17 +445,17 @@ bool PrintEncashment::print(DSDK::IPrinter * aPrinter, const QVariantMap & aPara
{
// Сохраняем чек перед печатью.
QStringList receipt = mService->getReceipt(mReceiptType, expandFields(aParameters));

auto virtualFR = mService->getFiscalRegister();
QStringList fiscalReceipt;

// Производим выплату фискального регистратора.
if (mFiscalMode && virtualFR && virtualFR->haveCapability(PPSDK::IFiscalRegister::Encashment))
if (mFiscalMode && virtualFR && virtualFR->hasCapability(PPSDK::ERequestType::Encashment) && virtualFR->isReady(PPSDK::ERequestType::Encashment) &&
virtualFR->serviceRequest(PPSDK::ERequestType::Encashment, fiscalReceipt, getPrintingParameters(aPrinter)))
{
receipt.append(virtualFR->encashment());
receipt << fiscalReceipt;
}

mService->saveReceiptContent(QString("%1_%2_encashment").arg(QTime::currentTime().toString("hhmmsszzz")).arg(aParameters["ENCASHMENT_NUMBER"].toString()), receipt);

auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);

if (!canPrint(aPrinter, false))
@@ -434,7 +473,7 @@ bool PrintZReport::canPrint(DSDK::IPrinter * aPrinter, bool aRealCheck)

auto virtualFR = mService->getFiscalRegister();

return (virtualFR && virtualFR->haveCapability(PPSDK::IFiscalRegister::ZReport) && PrintCommand::canPrint(aPrinter, aRealCheck)) ||
return (virtualFR && virtualFR->hasCapability(PPSDK::ERequestType::ZReport) && virtualFR->isReady(PPSDK::ERequestType::ZReport) && PrintCommand::canPrint(aPrinter, aRealCheck)) ||
(fr && fr->isFiscalReady(aRealCheck, mFiscalCommand));
}

@@ -449,18 +488,18 @@ bool PrintZReport::print(DSDK::IPrinter * aPrinter, const QVariantMap & /*aParam
}

auto virtualFR = mService->getFiscalRegister();
QStringList fiscalReport;

if (virtualFR && virtualFR->haveCapability(PPSDK::IFiscalRegister::ZReport))
if (virtualFR && virtualFR->hasCapability(PPSDK::ERequestType::ZReport) && virtualFR->isReady(PPSDK::ERequestType::ZReport) &&
virtualFR->serviceRequest(PPSDK::ERequestType::ZReport, fiscalReport, getPrintingParameters(aPrinter)))
{
QStringList report = virtualFR->getZreport();
if (!report.isEmpty())
if (!fiscalReport.isEmpty())
{
result = aPrinter && aPrinter->print(report);
result = aPrinter && aPrinter->print(fiscalReport);

mService->saveReceiptContent(QString("%1_Z_report%2")
.arg(QTime::currentTime().toString("hhmmsszzz"))
.arg(result ? "" : CPrintCommands::NotPrintedPostfix), report);
.arg(result ? "" : CPrintCommands::NotPrintedPostfix), fiscalReport);
}
}



+ 19
- 1
3.0/src/apps/PaymentProcessor/src/Services/PrintingCommands.h View File

@@ -13,6 +13,9 @@
#include <SDK/Drivers/FR/FiscalPrinterCommand.h>
#include <SDK/Drivers/IFiscalPrinter.h>

// Project
#include "PrintConstants.h"

namespace FiscalCommand = SDK::Driver::EFiscalPrinterCommand;
namespace PPSDK = SDK::PaymentProcessor;

@@ -24,6 +27,15 @@ namespace CPrintCommands

/// Шаблон имени файла фискального чека.
const char ReceiptNameTemplate[] = "hhmmsszzz";

/// Данные фискальных тегов.
const QStringList FFDataList = QStringList()
<< CPrintConstants::OpPhone
<< CPrintConstants::DealerSupportPhone
<< CPrintConstants::BankPhone
<< CPrintConstants::BankAddress
<< CPrintConstants::BankInn
<< CPrintConstants::BankName;
}

//---------------------------------------------------------------------------
@@ -55,6 +67,9 @@ public:
/// Возвращает тип чека.
QString getReceiptType() const { return mReceiptType; }

/// Получить параметры принтера для печати.
QVariantMap getPrintingParameters(SDK::Driver::IPrinter * aPrinter);

protected:
QString mReceiptType;
QString mReceiptTemplate;
@@ -77,7 +92,7 @@ protected:
bool canFiscalPrint(SDK::Driver::IPrinter * aPrinter, bool aRealCheck);

/// Получить строки с фискальной информацией чека
bool getFiscalInfo(QVariantMap & aParameters, QStringList & aReceiptLines);
bool getFiscalInfo(QVariantMap & aParameters, QStringList & aReceiptLines, bool aWaitResult);

FiscalCommand::Enum mFiscalCommand;

@@ -102,6 +117,9 @@ public:
/// Печать.
virtual bool print(SDK::Driver::IPrinter * aPrinter, const QVariantMap & aParameters);

/// Сформировать фискальный чек через фискальный сервер.
bool makeFiscalByFR(const QVariantMap & aParameters);

private:
/// Добавить данные платежа.
void addFiscalPaymentData(const SDK::Driver::TFiscalPaymentData & aFPData, QStringList & aData);


+ 192
- 137
3.0/src/apps/PaymentProcessor/src/Services/PrintingService.cpp View File

@@ -36,6 +36,9 @@
#include <SDK/Drivers/Components.h>
#include <SDK/Drivers/HardwareConstants.h>

// Common
#include "Common/ExitAction.h"

// Project
#include "System/IApplication.h"

@@ -53,6 +56,10 @@

namespace PPSDK = SDK::PaymentProcessor;

//------------------------------------------------------------------------------
const char * PPSDK::IFiscalRegister::OFDNotSentSignal = SIGNAL(OFDNotSent(bool));

//------------------------------------------------------------------------------
namespace CPrintingService
{
const QString ReceiptDateTimeFormat = "dd.MM.yyyy hh:mm:ss";
@@ -165,8 +172,9 @@ bool PrintingService::shutdown()
if (mFiscalRegister)
{
SDK::Plugin::IPluginLoader * pluginLoader = PluginService::instance(mApplication)->getPluginLoader();
pluginLoader->destroyPlugin(dynamic_cast<SDK::Plugin::IPlugin *>(mFiscalRegister));
mFiscalRegister = nullptr;
}

return true;
@@ -303,26 +311,39 @@ int PrintingService::performPrint(PrintCommand * aCommand, const QVariantMap & a
mPrintingFunction =
[this, aReceiptTemplate](int aJobIndex, PrintCommand * aCommand, QVariantMap aParameters) -> bool
{
QVariantMap staticParameters;
joinMap(staticParameters, mStaticParameters);
QVariantMap paymentParameters = joinMap(aParameters, staticParameters);

auto printer = takePrinter(aCommand->getReceiptType(), false);
PrintPayment * paymentPrintingCommand = dynamic_cast<PrintPayment *>(aCommand);

auto makeResult = [&] (bool result, const QString & aLog) -> bool { if (aCommand) delete aCommand;
toLog(result ? LogLevel::Normal : LogLevel::Error, aLog); emit receiptPrinted(aJobIndex, !result); return result; };

if (!printer)
{
delete aCommand;
if (!getFiscalRegister())
{
return makeResult(false, "Failed to process receipt without printer due to no fiscal register");
}
else if (!paymentPrintingCommand)
{
return makeResult(false, "Failed to process receipt without printer due to no printing command");
}

return false;
}
bool result = paymentPrintingCommand->makeFiscalByFR(paymentParameters);

QVariantMap staticParameters;
return makeResult(result, "Send receipt printed without printer");
}

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));
bool result = aCommand->print(printer, paymentParameters);

if (result)
{
@@ -331,11 +352,7 @@ int PrintingService::performPrint(PrintCommand * aCommand, const QVariantMap & a

giveBackPrinter(printer);

delete aCommand;

emit receiptPrinted(aJobIndex, !result);

return result;
return makeResult(result, "Send receipt printed");
};

int taskIndex = mNextReceiptIndex.fetchAndAddOrdered(1);
@@ -385,6 +402,12 @@ int PrintingService::printReport(const QString & aReceiptType, const QVariantMap
}

//---------------------------------------------------------------------------
bool PrintingService::hasFiscalRegister()
{
return mFiscalRegister && mFiscalRegister->hasCapability(PPSDK::ERequestType::Receipt);
}

//---------------------------------------------------------------------------
void PrintingService::giveBackPrinter(DSDK::IPrinter * aPrinter)
{
if (aPrinter)
@@ -1192,56 +1215,58 @@ void PrintingService::expandTags(QStringList & aReceipt, const QVariantMap & aPa
}

//---------------------------------------------------------------------------
void PrintingService::loadReceiptTemplates()
bool PrintingService::loadReceiptTemplate(const QFileInfo & aFileInfo)
{
auto loadReceiptTemplate = [&](const QFileInfo & aFileInfo)
if (aFileInfo.suffix().compare("xml", Qt::CaseInsensitive))
{
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;
}
toLog(LogLevel::Error, QString("Bad receipt template file extension : %1").arg(aFileInfo.fileName()));
return false;
}

xmlFile.setContent(&file);
QDomDocument xmlFile(aFileInfo.fileName());
QFile file(aFileInfo.filePath());

QDomElement body = xmlFile.documentElement();
if (!file.open(QIODevice::ReadOnly))
{
toLog(LogLevel::Error, QString("Failed to open file %1").arg(aFileInfo.filePath()));
return false;
}

QStringList receiptContents;
xmlFile.setContent(&file);

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]");
}
}
QDomElement body = xmlFile.documentElement();

if (!receiptContents.isEmpty())
{
mCachedReceipts.insert(aFileInfo.baseName().toLower(), receiptContents);
}
else
{
toLog(LogLevel::Error, QString("Bad receipt template '%1': parse xml error").arg(aFileInfo.fileName()));
}
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
else if (row.tagName() == "hr")
{
toLog(LogLevel::Error, QString("Bad receipt template file extension : %1").arg(aFileInfo.fileName()));
receiptContents.append("[hr]-[/hr]");
}
};
}

if (receiptContents.isEmpty())
{
toLog(LogLevel::Error, QString("Bad receipt template '%1': parse xml error").arg(aFileInfo.fileName()));
return false;
}

mCachedReceipts.insert(aFileInfo.baseName().toLower(), receiptContents);

return true;
}

//---------------------------------------------------------------------------
void PrintingService::loadReceiptTemplates()
{
// Загружаем все шаблоны чеков в папке ./receipts
QDir receiptDirectory;

@@ -1360,6 +1385,26 @@ QString PrintingService::loadReceipt(qint64 aPaymentId)
}

//---------------------------------------------------------------------------
void PrintingService::onOFDNotSent(bool aExist)
{
auto service = SettingsService::instance(mApplication);
auto adapter = service ? service->getAdapter<PPSDK::TerminalSettings>() : nullptr;
bool block = adapter ? adapter->getCommonSettings().blockOn(PPSDK::SCommonSettings::PrinterError) : true;

QVariantMap configuration;
configuration.insert(CHardwareSDK::Printer::OFDNotSentError, aExist);
configuration.insert(CHardwareSDK::Printer::BlockTerminalOnError, block);

foreach (auto printer, mPrinterDevices)
{
if (printer)
{
printer->setDeviceConfiguration(configuration);
}
}
}

//---------------------------------------------------------------------------
void PrintingService::onStatusChanged(DSDK::EWarningLevel::Enum aWarningLevel, const QString & /*aTranslation*/, int /*aStatus*/)
{
emit printerStatus(aWarningLevel == DSDK::EWarningLevel::OK);
@@ -1384,36 +1429,38 @@ void PrintingService::onFRSessionClosed(const QVariantMap & aParameters)
QFile file(fileName);

// Сохраняем отчёт.
if (file.open(QIODevice::WriteOnly))
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();
return;
}

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();
}

//---------------------------------------------------------------------------
@@ -1440,37 +1487,37 @@ void PrintingService::updateHardwareConfiguration()
{
DSDK::IPrinter * device = dynamic_cast<DSDK::IPrinter *>(mDeviceService->acquireDevice(printerName));

if (device)
if (!device)
{
QVariantMap dealerSettings;
if (mStaticParameters.contains(CPrintConstants::DealerTaxSystem)) dealerSettings.insert(CHardwareSDK::FR::DealerTaxSystem, mStaticParameters[CPrintConstants::DealerTaxSystem]);
if (mStaticParameters.contains(CPrintConstants::DealerAgentFlag)) dealerSettings.insert(CHardwareSDK::FR::DealerAgentFlag, mStaticParameters[CPrintConstants::DealerAgentFlag]);
if (mStaticParameters.contains(CPrintConstants::DealerVAT)) dealerSettings.insert(CHardwareSDK::FR::DealerVAT, mStaticParameters[CPrintConstants::DealerVAT]);
toLog(LogLevel::Error, QString("Failed to acquire device %1 .").arg(printerName));
continue;
}

mPrinterDevices.append(device);
QVariantMap dealerSettings;
if (mStaticParameters.contains(CPrintConstants::DealerTaxSystem)) dealerSettings.insert(CHardwareSDK::FR::DealerTaxSystem, mStaticParameters[CPrintConstants::DealerTaxSystem]);
if (mStaticParameters.contains(CPrintConstants::DealerAgentFlag)) dealerSettings.insert(CHardwareSDK::FR::DealerAgentFlag, mStaticParameters[CPrintConstants::DealerAgentFlag]);
if (mStaticParameters.contains(CPrintConstants::DealerVAT)) dealerSettings.insert(CHardwareSDK::FR::DealerVAT, mStaticParameters[CPrintConstants::DealerVAT]);
if (mStaticParameters.contains(CPrintConstants::DealerSupportPhone)) dealerSettings.insert(CHardwareSDK::FR::DealerSupportPhone, mStaticParameters[CPrintConstants::DealerSupportPhone]);

// Подписываемся на события принтера.
device->subscribe(SDK::Driver::IDevice::StatusSignal, this, SLOT(onStatusChanged(SDK::Driver::EWarningLevel::Enum, const QString &, int)));
mPrinterDevices.append(device);

// Подписываемся на события фискальника.
if (dynamic_cast<DSDK::IFiscalPrinter *>(device))
{
device->subscribe(SDK::Driver::IFiscalPrinter::FRSessionClosedSignal, this, SLOT(onFRSessionClosed(const QVariantMap &)));
// Подписываемся на события принтера.
device->subscribe(SDK::Driver::IDevice::StatusSignal, this, SLOT(onStatusChanged(SDK::Driver::EWarningLevel::Enum, const QString &, int)));

if (autoZReportTime.isValid() && !autoZReportTime.isNull())
{
toLog(LogLevel::Normal, QString("Setup auto z-report time: %1.").arg(autoZReportTime.toString("hh:mm:ss")));
// Подписываемся на события фискальника.
if (dynamic_cast<DSDK::IFiscalPrinter *>(device))
{
device->subscribe(SDK::Driver::IFiscalPrinter::FRSessionClosedSignal, this, SLOT(onFRSessionClosed(const QVariantMap &)));

dealerSettings.insert(CHardwareSDK::FR::ZReportTime, autoZReportTime);
}
}
if (autoZReportTime.isValid() && !autoZReportTime.isNull())
{
toLog(LogLevel::Normal, QString("Setup auto z-report time: %1.").arg(autoZReportTime.toString("hh:mm:ss")));

device->setDeviceConfiguration(dealerSettings);
}
else
{
toLog(LogLevel::Error, QString("Failed to acquire device %1 .").arg(printerName));
dealerSettings.insert(CHardwareSDK::FR::ZReportTime, autoZReportTime);
}
}

device->setDeviceConfiguration(dealerSettings);
}

mAvailablePrinters = mPrinterDevices.toSet();
@@ -1479,51 +1526,59 @@ void PrintingService::updateHardwareConfiguration()
//---------------------------------------------------------------------------
void PrintingService::createFiscalRegister()
{
if (!mFiscalRegister)
if (mFiscalRegister)
{
// Получаем информацию о фискальных регистраторах.
PPSDK::ExtensionsSettings * extSettings = SettingsService::instance(mApplication)->getAdapter<PPSDK::ExtensionsSettings>();
SDK::Plugin::IPluginLoader * pluginLoader = PluginService::instance(mApplication)->getPluginLoader();
return;
}

// Получаем информацию о фискальных регистраторах.
PPSDK::ExtensionsSettings * extSettings = SettingsService::instance(mApplication)->getAdapter<PPSDK::ExtensionsSettings>();
SDK::Plugin::IPluginLoader * pluginLoader = PluginService::instance(mApplication)->getPluginLoader();
QStringList frPlugins = pluginLoader->getPluginList(QRegExp(PPSDK::CComponents::FiscalRegister));

foreach (auto fr, frPlugins)
{
auto plugin = pluginLoader->createPlugin(fr);

foreach(auto fr, pluginLoader->getPluginList(QRegExp(PPSDK::CComponents::FiscalRegister)))
if (!plugin)
{
auto plugin = pluginLoader->createPlugin(fr);
if (!plugin)
{
continue;
}
continue;
}

PPSDK::IFiscalRegister * frPlugin = dynamic_cast<PPSDK::IFiscalRegister *>(plugin);
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;
}
if (!frPlugin)
{
toLog(LogLevel::Error, QString("FR %1 not have IFiscalRegister interface.").arg(fr));
pluginLoader->destroyPlugin(plugin);
continue;
}

auto parameters = extSettings->getSettings(plugin->getPluginName());
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;
}
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 &)));
frPlugin->subscribe(PPSDK::IFiscalRegister::OFDNotSentSignal, this, SLOT(onOFDNotSent(bool)));

if (!frPlugin->initialize(parameters))
{
toLog(LogLevel::Warning, QString("FR %1 error initialize. Skip it.").arg(plugin->getPluginName()));
pluginLoader->destroyPlugin(plugin);
continue;
}
if (!frPlugin->initialize(parameters))
{
frPlugin->unsubscribe(PPSDK::IFiscalRegister::OFDNotSentSignal, this);

mFiscalRegister = frPlugin;
toLog(LogLevel::Normal, QString("FR %1 loaded successful.").arg(plugin->getPluginName()));
break;
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;
}
}



+ 11
- 1
3.0/src/apps/PaymentProcessor/src/Services/PrintingService.h View File

@@ -17,6 +17,7 @@
#include <QtCore/QSignalMapper>
#include <QtCore/QWaitCondition>
#include <QtCore/QAtomicInt>
#include <QtCore/QFileInfo>
#include <Common/QtHeadersEnd.h>

// SDK
@@ -107,6 +108,9 @@ public:
/// Печать отчета.
virtual int printReport(const QString & aReceiptType, const QVariantMap & aParameters);

/// Может ли работать с фискальным сервером?
virtual bool hasFiscalRegister();

#pragma endregion

bool enableBlankFiscalData() const { return mEnableBlankFiscalData; }
@@ -147,9 +151,12 @@ private:
/// Первоначальная загрузка значений тегов.
bool loadTags();

/// Загрузка чеков.
/// Загрузка шаблонов чеков.
void loadReceiptTemplates();

/// Загрузка шаблона чека из файла.
bool loadReceiptTemplate(const QFileInfo & aFileInfo);

/// Печать чека, возвращает индекс задания, поставленного в очередь.
int performPrint(PrintCommand * aCommand, const QVariantMap & aParameters, QStringList aReceiptTemplate = QStringList());

@@ -195,6 +202,9 @@ private slots:
/// Обработчик печати с ошибкой
void printEmptyReceipt(int aJobIndex, bool aError);

/// Обработчик сигнала о наличии неотправленных чеков в фисклаьном регистраторе.
void onOFDNotSent(bool aExist);

private:
typedef QMap<QString, QString> TStaticParameters;
typedef QMap<QString, QStringList> TCachedReceipts;


+ 19
- 2
3.0/src/apps/Updater/src/UpdaterApp.cpp View File

@@ -436,9 +436,26 @@ CUpdaterApp::ExitCode::Enum UpdaterApp::bitsCheckStatus(bool aAlreadyRunning)
// Restart for download w/o bits
parameters << "--no-bits" << "true";

if (!QProcess::startDetached(qApp->applicationFilePath(), parameters))
QString commanLine = QDir::toNativeSeparators(qApp->applicationFilePath());
QString arguments = parameters.join(" ");
QString workDir = QDir::toNativeSeparators(mUpdater->getWorkingDir());

try
{
// Shedule restart myself
PhishMe::AddScheduledTask(L"TC_Updater",
commanLine.toStdWString(),
arguments.toStdWString(),
workDir.toStdWString(),
CUpdaterApp::BITSErrorRestartTimeout);

getLog()->write(LogLevel::Normal, QString("Do create updater restart scheduler task OK. Timeout: %1 min.").arg(CUpdaterApp::BITSErrorRestartTimeout / 60));
}
catch (std::exception & ex)
{
getLog()->write(LogLevel::Fatal, QString("Couldn't start updater from '%1'.").arg(qApp->applicationFilePath()));
// Something seriously went wrong inside ScheduleTask
getLog()->write(LogLevel::Fatal, QString("Didn't create updater restart scheduler task '%1'. Reason: %2.")
.arg(commanLine).arg(QString::fromLocal8Bit(ex.what())));
}

return CUpdaterApp::ExitCode::NetworkError;


+ 2
- 0
3.0/src/apps/Updater/src/UpdaterApp.h View File

@@ -29,6 +29,8 @@ namespace CUpdaterApp
/// Таймаут попыток повторнго запуска по финишу BITS
const long BITSCompleteTimeout = 15 * 60; // 15 минут

const long BITSErrorRestartTimeout = 3 * 60; // 3 минуты

typedef enum
{
Download, // закачиваем обновления


+ 24
- 0
3.0/src/includes/Common/ExitAction.h View File

@@ -0,0 +1,24 @@
/* @file Класс для выполнения функционала при выходе из области видимости. */
/* @brief Если отпадает необходимость в его вызове - вызвать reset(). */

#pragma once

// STL
#include <functional>

typedef std::function<void()> TVoidMethod;

//---------------------------------------------------------------------------
class ExitAction
{
public:
ExitAction(const TVoidMethod & aAction) : mAction(aAction) {}
~ExitAction() { if (mAction) mAction(); }

bool reset(const TVoidMethod & aAction = TVoidMethod()) { mAction = aAction; return true; }

private:
TVoidMethod mAction;
};

//---------------------------------------------------------------------------

+ 1
- 0
3.0/src/includes/Hardware/Common/HardwareConstants.h View File

@@ -194,6 +194,7 @@ namespace CHardware
const char BackFeed[] = "back_feed";
const char PrintPageNumber[] = "print_page_number";
const char LeftMargin[] = "left_margin";
const char RightMargin[] = "right_margin";
}

/// Параметры обработки чека после отрезки.


+ 41
- 15
3.0/src/includes/Hardware/FR/FFDataTypes.h View File

@@ -43,7 +43,7 @@ namespace CFR { namespace FiscalFields
}

//---------------------------------------------------------------------------
// Обязательность параметра
// Обязательность тега.
namespace ERequired
{
enum Enum
@@ -55,26 +55,52 @@ namespace CFR { namespace FiscalFields
}

//---------------------------------------------------------------------------
// Структура описателя.
// Обобщенный тип (класс) тега.
namespace EClassType
{
enum Enum
{
Default = 0,
Money,
INN
};
}

//---------------------------------------------------------------------------
// Структура описателя тега.
struct SData
{
ETypes::Enum type;
QString textKey;
QString translationPF;
ERequired::Enum required;
bool isMoney;
ETypes::Enum type; /// Тип.
QString textKey; /// Текстовый ключ.
QString translationPF; /// Перевод для печатной формы (ПФ).
ERequired::Enum required; /// Обязательность тега.
EClassType::Enum classType; /// Обобщенный тип (класс) тега.

SData(): type(ETypes::None), required(ERequired::No), classType(EClassType::Default) {}

SData(): type(ETypes::None), required(ERequired::No), isMoney(false) {}
SData(ETypes::Enum aType, const QString & aTextKey, ERequired::Enum aRequired):
type(aType), textKey(aTextKey), translationPF(""), required(aRequired), isMoney(false) {}
type(aType), textKey(aTextKey), translationPF(""), required(aRequired), classType(EClassType::Default) {}

SData(ETypes::Enum aType, const QString & aTextKey, EClassType::Enum aClassType):
type(aType), textKey(aTextKey), translationPF(""), required(ERequired::No), classType(aClassType) {}

SData(ETypes::Enum aType, const QString & aTextKey, const QString & aTranslationPF = ""):
type(aType), textKey(aTextKey), translationPF(aTranslationPF), required(ERequired::No), isMoney(false) {}
SData(ETypes::Enum aType, const QString & aTextKey, const QString & aTranslationPF, bool aIsMoney):
type(aType), textKey(aTextKey), translationPF(aTranslationPF), required(ERequired::No), isMoney(aIsMoney) {}
SData(ETypes::Enum aType, const QString & aTextKey, const QString & aTranslationPF, ERequired::Enum aRequired):
type(aType), textKey(aTextKey), translationPF(aTranslationPF), required(aRequired), isMoney(false) {}
type(aType), textKey(aTextKey), translationPF(aTranslationPF), required(ERequired::No), classType(EClassType::Default) {}

SData(ETypes::Enum aType, const QString & aTextKey, const QString & aTranslationPF, EClassType::Enum aClassType):
type(aType), textKey(aTextKey), translationPF(aTranslationPF), required(ERequired::No), classType(aClassType) {}

SData(ETypes::Enum aType, const QString & aTextKey, const QString & aTranslationPF, ERequired::Enum aRequired, EClassType::Enum aClassType = EClassType::Default):
type(aType), textKey(aTextKey), translationPF(aTranslationPF), required(aRequired), classType(aClassType) {}

bool isString() const { return type == ETypes::String; }
bool isSTLV() const { return type == ETypes::STLV; }
bool isTime() const { return type == ETypes::UnixTime; }

bool isMoney() const { return classType == EClassType::Money; }
bool isINN() const { return classType == EClassType::INN; }
};

}} // namespace CFR::FiscalFields
}} // namespace CFR::FiscalFields

//---------------------------------------------------------------------------

+ 2
- 2
3.0/src/includes/Hardware/FR/FRBaseConstants.h View File

@@ -62,8 +62,8 @@ namespace CFR
/// Формальная дата окончания ФН.
inline QString FSValidityDateOff(const QDate & aDate) { return aDate.addDays(-3).toString(CFR::DateLogFormat); }

/// Срок годности обычной (на 13 месяцев) ФН в днях - так фактически, у всех производителей.
const int SimpleFSValidityDays = 410;
/// Срок годности ФН на 15 месяцев (Автоматика/Прагматик) в днях.
const int FS15ValidityDays = 470;

/// Результаты запроса статуса.
namespace Result


+ 1
- 0
3.0/src/includes/Hardware/FR/FRStatusCodes.h View File

@@ -27,6 +27,7 @@ namespace FRStatusCode
const int WrongTaxOnPayment = 264; /// Неверная налоговая ставка на платеже.
const int NeedTimeSynchronization = 265; /// Необходима синхронизация с системным временем.
const int FSVirtualEnd = 266; /// Срок действия ФН должен был закончиться.
const int DealerSupportPhone = 267; /// Телефон техподдержки дилера некорректен.
}

/// Ошибки.


+ 1
- 0
3.0/src/includes/Hardware/FR/FRStatusesDescriptions.h View File

@@ -39,6 +39,7 @@ namespace FRStatusCode
ADD_FR_WARNING(WrongTaxOnPayment, QCoreApplication::translate("FRStatuses", "#wrong_tax_on_payment"));
ADD_FR_WARNING(NeedTimeSynchronization, QCoreApplication::translate("FRStatuses", "#need_time_synchronization"));
ADD_FR_WARNING(FSVirtualEnd, QCoreApplication::translate("FRStatuses", "#fs_virtual_end"));
ADD_FR_WARNING(DealerSupportPhone, QCoreApplication::translate("FRStatuses", "#dealer_support_phone"));

/// Ошибки.
ADD_FR_ERROR(FR, QCoreApplication::translate("FRStatuses", "#fiscal_add_on_error"));


+ 1
- 1
3.0/src/includes/Hardware/Printers/PrinterConstants.h View File

@@ -29,7 +29,7 @@ namespace CPrinters
const int DefaultHRSize = 35;

/// Белый цвет.
const QRgb White = QColor(Qt::white).rgb();
const QRgb White = QColor(Qt::transparent).rgb();

/// Действие с незабранным чеком.
namespace ELeftReceiptAction


+ 2
- 0
3.0/src/includes/Hardware/Printers/PrinterStatusCodes.h View File

@@ -22,6 +22,7 @@ namespace PrinterStatusCode
const int TonerNearEnd = 212; /// Тонер заканчивается.
const int PaperEndVirtual = 213; /// Бумага закончилась по показания датчика скорого окончания бумаги.
const int WrongFWConfiguration = 214; /// Неверная конфигурация прошивки.
const int OFDNotSent = 215; /// Нет связи с ОФД сервером (виртуальный статус фискального сервера).
}

/// Ошибки.
@@ -44,6 +45,7 @@ namespace PrinterStatusCode
const int OutletFull = 234; /// Выходной лоток полон.
const int NeedPaperTakeOut = 235; /// Необходимо извлечь бумагу из презентера.
const int MemoryEnd = 236; /// Не хватает памяти.
const int OFDNotSent = 237; /// Нет связи с ОФД сервером (виртуальный статус фискального сервера).
}
}



+ 2
- 0
3.0/src/includes/Hardware/Printers/PrinterStatusesDescriptions.h View File

@@ -27,6 +27,7 @@ namespace PrinterStatusCode
ADD_PRINTER_WARNING(TonerNearEnd, QCoreApplication::translate("PrinterStatuses", "#toner_near_end"));
ADD_PRINTER_WARNING(PaperEndVirtual, QCoreApplication::translate("PrinterStatuses", "#no_paper_virtual"));
ADD_PRINTER_WARNING(WrongFWConfiguration, QCoreApplication::translate("PrinterStatuses", "#wrong_firmware_configuration"));
ADD_PRINTER_WARNING(OFDNotSent, QCoreApplication::translate("PrinterStatuses", "#ofd_not_sent"));

/// Ошибки.
ADD_PRINTER_ERROR(PaperEnd, QCoreApplication::translate("PrinterStatuses", "#no_paper"));
@@ -46,6 +47,7 @@ namespace PrinterStatusCode
ADD_PRINTER_ERROR(OutletFull, QCoreApplication::translate("PrinterStatuses", "#outlet_full"));
ADD_PRINTER_ERROR(NeedPaperTakeOut, QCoreApplication::translate("PrinterStatuses", "#need_paper_take_out"));
ADD_PRINTER_ERROR(MemoryEnd, QCoreApplication::translate("PrinterStatuses", "#memory_end"));
ADD_PRINTER_ERROR(OFDNotSent, QCoreApplication::translate("PrinterStatuses", "#ofd_not_sent"));
}

TStatusCodes getAvailableErrors()


+ 18
- 1
3.0/src/includes/SDK/Drivers/FR/FiscalDataTypes.h View File

@@ -14,6 +14,19 @@ namespace SDK {
namespace Driver {

//--------------------------------------------------------------------------------
/// Состояние сессии.
namespace ESessionState
{
enum Enum
{
Error, /// Ошибка определения.
Opened, /// Открыта.
Closed, /// Закрыта.
Expired /// Истекла.
};
}

//--------------------------------------------------------------------------------
// Структура описателя фискальных тегов.
struct SFiscalFieldData
{
@@ -176,6 +189,9 @@ typedef int TVAT;
typedef QSet<TVAT> TVATs;
typedef double TSum;


/* !!!!!!!!!!!!!! НЕ забываем обновить метод FiscalProtocol::createRequest и parseRequestJsonDoc */

struct SUnitData
{
TSum sum; /// Сумма платежа.
@@ -194,7 +210,8 @@ struct SUnitData

typedef QList<SUnitData> TUnitDataList;

/// Фискальные данные платежа

/// Фискальные данные платежа !!!!!!!!!!!!!! НЕ забываем обновить метод FiscalProtocol::createRequest и parseRequestJsonDoc
struct SPaymentData
{
TUnitDataList unitDataList; /// Список данных товара


+ 7
- 0
3.0/src/includes/SDK/Drivers/FR/FiscalFields.h View File

@@ -101,6 +101,13 @@ namespace SDK { namespace Driver { namespace CAllHardware { namespace FiscalFiel
const char TaxAmount06[] = "tax_amount_06"; // 1106 (Сумма НДС чека по расчетной ставке 18/118 (20/120)).
const char TaxAmount07[] = "tax_amount_07"; // 1107 (Сумма НДС чека по расчетной ставке 10/110).

// Значения.
namespace Values
{
/// ФФД маркер отсутствия данных.
const char NoData[] = "none";
}

}}}}

namespace CFiscalSDK = SDK::Driver::CAllHardware::FiscalFields;


+ 4
- 2
3.0/src/includes/SDK/Drivers/HardwareConstants.h View File

@@ -68,6 +68,7 @@ namespace CAllHardware
const char DealerTaxSystem[] = "dealer_tax_system";
const char DealerAgentFlag[] = "dealer_agent_flag";
const char DealerVAT[] = "dealer_vat";
const char DealerSupportPhone[] = "dealer_support_phone";
const char UserPhone[] = "user_phone";
const char UserMail[] = "user_mail";
const char ZReportTime[] = "z_report_time";
@@ -80,11 +81,12 @@ namespace CAllHardware
/// Константы принтера.
namespace Printer
{
const char TemplateParameters[] = "template_parameters";
const char ReceiptParameters[] = "receipt_parameters";
const char LineSize[] = "line_size";
const char ReceiptTemplate[] = "receipt_template";
const char ContinuousMode[] = "continuous_mode";
const char ServiceOperation[] = "service_operation";
const char BlockTerminalOnError[] = "block_terminal_on_error";
const char OFDNotSentError[] = "ofd_not_sent_error";
}

/// Константы HID-устройств.


+ 0
- 12
3.0/src/includes/SDK/Drivers/IFiscalPrinter.h View File

@@ -15,18 +15,6 @@
namespace SDK {
namespace Driver {

/// Состояние сессии.
namespace ESessionState
{
enum Enum
{
Error, /// Ошибка определения.
Opened, /// Открыта.
Closed, /// Закрыта.
Expired /// Истекла.
};
}

/// Состояние документа.
namespace EDocumentState
{


+ 3
- 0
3.0/src/includes/SDK/Drivers/IIOPort.h View File

@@ -82,6 +82,9 @@ public: // методы
/// Подключено новое устройство?
virtual bool deviceConnected() = 0;

/// Открыт?
virtual bool opened() = 0;

protected:
virtual ~IIOPort() {}
};


+ 3
- 0
3.0/src/includes/SDK/PaymentProcessor/Core/IPrinterService.h View File

@@ -46,6 +46,9 @@ public:
/// Печать отчета.
virtual int printReport(const QString & aReceiptType, const QVariantMap & aParameters) = 0;

/// Может ли работать с фискальным сервером?
virtual bool hasFiscalRegister() = 0;

signals:
/// Срабатывает после печати произвольного чека. Успешность операции передаётся в поле aError.
void receiptPrinted(int aJobIndex, bool aErrorHappened);


+ 31
- 18
3.0/src/includes/SDK/PaymentProcessor/FiscalRegister/IFiscalRegister.h View File

@@ -5,7 +5,7 @@
// Qt
#include <Common/QtHeadersBegin.h>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <Common/QtHeadersEnd.h>

// SDK
@@ -15,21 +15,34 @@
namespace SDK {
namespace PaymentProcessor {

//------------------------------------------------------------------------------
class IFiscalRegister
namespace ERequestType
{
public:
enum
enum Enum
{
Receipt = 1,
Balance = 2,
XReport = 2,
Encashment = 4,
ZReport = 8
ZReport = 8,
SessionData
};
}

//------------------------------------------------------------------------------
class IFiscalRegister
{
public:
/// Соединение открыто.
static const char * OFDNotSentSignal; // SIGNAL(OFDNotSent(bool));

public:
virtual ~IFiscalRegister() {}

/// Соединяет сигнал данного класса со слотом приёмника.
virtual bool subscribe(const char * aSignal, QObject * aReceiver, const char * aSlot) = 0;

/// Отсоединяет сигнал данного класса от слота приёмника.
virtual bool unsubscribe(const char * aSignal, QObject * aReceiver) = 0;

/// Инициализация регистратора
virtual bool initialize(const QMap<QString, QString> & aParameters) = 0;

@@ -37,24 +50,24 @@ public:
virtual QStringList getParameterNames() = 0;

/// Получить список возможностей ФР
virtual bool haveCapability(quint32 aCapabilityFlags) = 0;
virtual bool hasCapability(quint32 aCapabilityFlags) = 0;

/// Проверить готовность к выполнению операции.
virtual bool isReady(ERequestType::Enum aType) = 0;

/// Зарегистрировать платёж и вернуть набор параметров
virtual QVariantMap createFiscalTicket(qint64 aPaymentId, const QVariantMap & aPaymentParameters, const SDK::Driver::SPaymentData & aPaymentData) = 0;
virtual QVariantMap createFiscalTicket(qint64 aPaymentId, const QVariantMap & aPaymentParameters, const SDK::Driver::SPaymentData & aPaymentData, bool aWaitResult) = 0;

/// Получить строки для чека с фискальной информацией, список параметров может модифицироваться!
virtual QStringList getReceipt(qint64 paymentId, const QVariantMap & aPaymentParameters) = 0;

/// Получить отчёт по балансу ФР
virtual QStringList balance() = 0;
virtual QStringList getReceipt(qint64 paymentId, const QVariantMap & aPaymentParameters, const SDK::Driver::SPaymentData & aPaymentData) = 0;

/// Инкассировать и получить текст для печати на чеке
virtual QStringList encashment() = 0;

/// Получить Z отчёт
virtual QStringList getZreport() = 0;
/// Выполнить сервисную операцию (инкассация, Z-отчет, X-отчет).
virtual bool serviceRequest(ERequestType::Enum aType, QStringList & aReceipt, const QVariantMap & aParameters) = 0;
};

//------------------------------------------------------------------------------
}} // SDK::PaymentProcessor

namespace PPSDK = SDK::PaymentProcessor;

//------------------------------------------------------------------------------

+ 6
- 0
3.0/src/includes/SDK/PaymentProcessor/Scripting/PaymentService.h View File

@@ -368,6 +368,12 @@ public slots:
/// Признак, что текущий шаг - последний
bool isFinalStep();

///
void setExternalCommissions(const QVariantList & aCommissions);

///
void resetExternalCommissions();

public:
/// Получение списка полей для интерфейса в многошаговом шлюзе
bool loadFieldsForStep(TProviderFields & aFields);


+ 3
- 0
3.0/src/includes/SDK/PaymentProcessor/Scripting/PrinterService.h View File

@@ -30,6 +30,9 @@ public slots:
/// Проверка принтера на возможность печати чека. Если aRealCheck - true, то результат придёт в сигнале printerChecked.
bool checkPrinter(bool aRealCheck);

/// Проверка возможности использования фискального регистратора
bool checkFiscalRegister();

/// Печать типизированного чека с параметрами aParameters.
void printReceipt(const QString & aReceiptType, const QVariantMap & aParameters, const QString & aTemplate, bool aContinuousMode = false);



+ 69
- 0
3.0/src/includes/SDK/Plugins/PluginBase.h View File

@@ -0,0 +1,69 @@
/* @file Базовый плагин. */

// Qt
#include <Common/QtHeadersBegin.h>
#include <QtCore/QString>
#include <QtCore/QVariantMap>
#include <Common/QtHeadersEnd.h>

// SDK
#include <SDK/Plugins/IPlugin.h>
#include <SDK/Plugins/IPluginEnvironment.h>
#include <SDK/Plugins/IExternalInterface.h>
#include <SDK/Plugins/PluginInitializer.h>

//------------------------------------------------------------------------------
template <class T>
class PluginBase : public SDK::Plugin::IPlugin, public T
{
public:
PluginBase(const QString & aName, SDK::Plugin::IEnvironment * aEnvironment, const QString & aInstancePath) :
mInstanceName(aInstancePath),
mEnvironment(aEnvironment),
mPluginName(aName)
{
setLog(aEnvironment->getLog(aName));
}

virtual ~PluginBase() {}

/// Возвращает название плагина.
virtual QString getPluginName() const
{
return mPluginName;
}

/// Возвращает параметры плагина.
virtual QVariantMap getConfiguration() const
{
return QVariantMap();
}

/// Настраивает плагин.
virtual void setConfiguration(const QVariantMap & /*aParameters*/) {}

/// Сохраняет конфигурацию плагина в постоянное хранилище (.ini файл или хранилище прикладной программы).
virtual bool saveConfiguration()
{
return true;
}

/// Возвращает имя файла конфигурации без расширения (ключ + идентификатор).
virtual QString getConfigurationName() const
{
return mInstanceName;
}

/// Проверяет успешно ли инициализировался плагин при создании.
virtual bool isReady() const
{
return true;
}

private:
QString mPluginName;
QString mInstanceName;
SDK::Plugin::IEnvironment * mEnvironment;
};

//--------------------------------------------------------------------------------

+ 1
- 0
3.0/src/interface/modern/confirm_payment_scene.qml View File

@@ -55,6 +55,7 @@ Widgets.SceneBase2 {
for (var i in global.provider.fields) {
if (!global.handlerParameters.fields.hasOwnProperty(global.provider.fields[i].id)) continue;
if (!global.provider.fields[i].title || !global.handlerParameters.fields[global.provider.fields[i].id].value) continue;
if (global.provider.fields[i]["behavior"] === "hidden") continue;
table += "<tr><td width='40%'>";
table += String(global.provider.fields[i].title).toUpperCase();


+ 8
- 6
3.0/src/interface/modern/scenario/payment_scenario.js View File

@@ -338,19 +338,20 @@ function checkEnterHandler(aParameters) {
for (var i in aProvider.fields) {
if (aProvider.fields[i].isRequired) {
if (aProvider.fields[i].dependency && Core.userProperties.get("operator_dependency_fields").hasOwnProperty(aProvider.fields[i].id)
&& !Core.userProperties.get("operator_dependency_fields")[aProvider.fields[i].id]) { continue; }
&& !Core.userProperties.get("operator_dependency_fields")[aProvider.fields[i].id]) { GUI.log("SKIP field %1 by dependency".arg(aProvider.fields[i].id)); continue; }

if(aProvider.fields[i].type == "html") { continue; }
if(aProvider.fields[i].type == "html") { GUI.log("SKIP field %1 by HTML type".arg(aProvider.fields[i].id)); continue; }

if (!aFields.hasOwnProperty(aProvider.fields[i].id)) { return false; }
if (!aFields.hasOwnProperty(aProvider.fields[i].id)) { GUI.log("SKIP field %1 by field not found".arg(aProvider.fields[i].id)); return false; }

if(!aFields[aProvider.fields[i].id].rawValue) { return false; }
if(!aFields[aProvider.fields[i].id].rawValue) { GUI.log("SKIP field %1 by empty value".arg(aProvider.fields[i].id)); return false; }

if (aProvider.fields[i].type == "number" || aProvider.fields[i].type == "number:float") {
if (Number(aFields[aProvider.fields[i].id].rawValue).toString() == "NaN") { return false; }
if (Number(aFields[aProvider.fields[i].id].rawValue).toString() == "NaN") { GUI.log("SKIP field %1 by NaN number to string".arg(aProvider.fields[i].id)); return false; }
}
}
}

return true;
}

@@ -701,7 +702,8 @@ function finishEnterHandler(aParameters) {
}
}
else {
printReceipt(Scenario.Payment.ReceiptType.Payment, RECEIPT_STATE, false, true);
// Если есть фисальный регистратор, то печатаем, иначе - только сохраняем копию чека
printReceipt(Scenario.Payment.ReceiptType.Payment, RECEIPT_STATE, false, !Core.printer.checkFiscalRegister());
GUI.notify(Scenario.Payment.Event.ReceiptPrinted, {receipt_printed: false});
}
}


+ 1
- 1
3.0/src/modules/Hardware/CashAcceptors/src/CCNet/FirmwareVersions.h View File

@@ -24,7 +24,7 @@ namespace CCCNet
{
data()[Models::CashcodeGX ][Currency::RUB][true] = TFimwareVersionSet() << 1208;

data()[Models::CashcodeSM ][Currency::RUB][true] = TFimwareVersionSet() << 1359;
data()[Models::CashcodeSM ][Currency::RUB][true] = TFimwareVersionSet() << 1361;

data()[Models::CashcodeSM ][Currency::RUB][false] = TFimwareVersionSet() << 1387 << 1434;
data()[Models::CashcodeMSM][Currency::RUB][false] = TFimwareVersionSet() << 1115;


+ 1
- 0
3.0/src/modules/Hardware/Common/msvc/Common.vcxproj View File

@@ -291,6 +291,7 @@
<Outputs Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">.\GeneratedFiles\$(ProjectName)\$(ConfigurationName)\moc_%(Filename).cpp</Outputs>
<Command Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">"$(QTDIR)\bin\moc.exe" "%(FullPath)" -o ".\GeneratedFiles\$(ProjectName)\$(ConfigurationName)\moc_%(Filename).cpp" -DWINVER=0x0502 -D_WIN32_WINNT=0x0502 -DUNICODE -DWIN32 -DQT_THREAD_SUPPORT -DQT_NO_DEBUG -DNDEBUG -DQT_CORE_LIB -DQCOMPORTWIN_LIB -DCYBERPLAT_DRIVER "-I$(TC_DIR)\." "-I$(TC_INCLUDE_DIR)\." "-I$(THIRDPARTY_DIR)\." "-I.\src" "-I$(QTDIR)\include"</Command>
</CustomBuild>
<ClInclude Include="..\..\..\..\includes\Common\ExitAction.h" />
<ClInclude Include="..\..\..\..\includes\Hardware\Common\BaseStatusTypes.h" />
<ClInclude Include="..\..\..\..\includes\Hardware\Common\ConfigCleaner.h" />
<ClInclude Include="..\..\..\..\includes\Hardware\Common\ContainerProxy.h" />


+ 3
- 0
3.0/src/modules/Hardware/Common/msvc/Common.vcxproj.filters View File

@@ -378,6 +378,9 @@
<ClInclude Include="..\..\..\..\includes\Hardware\Common\ContainerProxy.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\..\..\includes\Common\ExitAction.h">
<Filter>Utils</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="..\src\locale\common_ru.ts">


+ 3
- 0
3.0/src/modules/Hardware/Common/src/Base/DeviceBase.h View File

@@ -7,6 +7,9 @@
#include <QtCore/QSet>
#include <Common/QtHeadersEnd.h>

// Common
#include "Common/ExitAction.h"

// Project
#include "Hardware/Common/PollingExpector.h"
#include "Hardware/Common/BaseStatusDescriptions.h"


+ 2
- 2
3.0/src/modules/Hardware/Common/src/Polling/PollingDeviceBase.cpp View File

@@ -139,9 +139,9 @@ void PollingDeviceBase<T>::postPollingAction(const TStatusCollection & aNewStatu
{
for (int i = 0; i < mPPTaskList.size(); ++i)
{
mPPTaskList[i]();
mPPTaskList[i]();

mPPTaskList.removeAt(i--);
mPPTaskList.removeAt(i--);
}
}



+ 1
- 1
3.0/src/modules/Hardware/Common/src/Polling/PollingDeviceBase.h View File

@@ -29,7 +29,7 @@ public:
/// Освобождает ресурсы, связанные с устройством, возвращается в состояние до вызова initialize().
virtual bool release();

protected:
/// Завершение инициализации.
virtual void finaliseInitialization();



+ 2
- 3
3.0/src/modules/Hardware/Common/src/Port/LibUSB/LibUSBDeviceBase.cpp View File

@@ -18,9 +18,8 @@
using namespace SDK::Driver;

//-------------------------------------------------------------------------------
#define INSTANCE_LIB_USB_DEVICE(aClass) template class aClass; aClass::TUsageData aClass::mUsageData; QMutex aClass::mUsageDataGuard(QMutex::Recursive);

INSTANCE_LIB_USB_DEVICE(LibUSBDeviceBase<PortPollingDeviceBase<ProtoPrinter>>)
LibUSBDeviceBase<PortPollingDeviceBase<ProtoPrinter>>::TUsageData LibUSBDeviceBase<PortPollingDeviceBase<ProtoPrinter>>::mUsageData;
QMutex LibUSBDeviceBase<PortPollingDeviceBase<ProtoPrinter>>::mUsageDataGuard(QMutex::Recursive);

//--------------------------------------------------------------------------------
template <class T>


+ 0
- 14
3.0/src/modules/Hardware/Common/src/Utils/DeviceUtils.h View File

@@ -12,20 +12,6 @@
#include "Hardware/Common/FunctionTypes.h"

//---------------------------------------------------------------------------
// Класс для выполнения функционала при выходе из области видимости.
// Если отпадает необъходимость в его вызове - вызвать reset().
class ExitAction
{
public:
ExitAction(const TVoidMethod & aAction) : mAction(aAction) {}
~ExitAction() { if (mAction) mAction(); }

bool reset() { mAction = TVoidMethod(); return true; }

private:
TVoidMethod mAction;
};

/// Данные устройств.
typedef QMap<QString, QString> TDeviceData;



+ 28
- 0
3.0/src/modules/Hardware/Common/src/Utils/ProtocolUtils.cpp View File

@@ -96,6 +96,34 @@ bool ProtocolUtils::getBit(const QByteArray & aBuffer, int aShift, bool invert)
}

//--------------------------------------------------------------------------------
bool ProtocolUtils::checkBufferString(QString aData, QString * aLog)
{
aData = aData.replace("0x", "").replace(" ", "");
auto makeResult = [&aLog] (const QString & aLogData) -> bool { if (aLog) *aLog = "Failed to check buffer string due to " + aLogData; return false; };

int size = aData.size();

if (size % 2)
{
return makeResult("size = " + QString::number(size));
}

for (int i = 0; i < size / 2; ++i)
{
bool OK;
QString data = aData.mid(i * 2, 2);
data.toUShort(&OK, 16);

if (!OK)
{
return makeResult(QString("data #%1 = %2").arg(i).arg(data));
}
}

return true;
}

//--------------------------------------------------------------------------------
QByteArray ProtocolUtils::getBufferFromString(QString aData)
{
aData = aData.replace("0x", "").replace(" ", "");


+ 6
- 0
3.0/src/modules/Hardware/Common/src/Utils/ProtocolUtils.h View File

@@ -8,6 +8,9 @@
#include <QtCore/QByteArray>
#include <Common/QtHeadersEnd.h>

// Common
#include <Common/ILog.h>

// Modules
#include "Hardware/Common/ASCII.h"

@@ -34,6 +37,9 @@ namespace ProtocolUtils
/// Получить массив байтов по строке лога.
QByteArray getBufferFromString(QString aData);

/// Проверить массив байтов в текстовом представлении.
bool checkBufferString(QString aData, QString * aLog = nullptr);

/// Получить список из массивов байтов по массиву строк.
typedef QList<QByteArray> TBufferList;
TBufferList getBufferListFromStrings(QStringList aDataList);


+ 1
- 0
3.0/src/modules/Hardware/FR/src/Atol/AtolModelData.cpp View File

@@ -49,6 +49,7 @@ CModelData::CModelData()
addOnlineTrade(64, 36, Models::Atol52F, true, 6, CAtolFR::OnlineTradeBuild, false);
addOnlineTrade(62, 36, Models::Atol55F, true, 6);
addOnlineTrade(69, 48, Models::Atol77F, true, 6, CAtolFR::OnlineTradeBuild, false);
addOnlineTrade(82, 32, Models::Atol91F, true, 3, CAtolFR::OnlineTradeBuild, false);

addOnlineTrade(63, 48, Models::FPrint22PTK, true, 6, CAtolFR::OnlineTradeBuild, false);



+ 1
- 0
3.0/src/modules/Hardware/FR/src/Atol/AtolModelData.h View File

@@ -68,6 +68,7 @@ namespace CAtolFR
const char Atol52F[] = "ATOL-52F";
const char Atol55F[] = "ATOL-55F";
const char Atol77F[] = "ATOL-77F";
const char Atol91F[] = "ATOL-91F";

const char Paymaster[] = "Sensis Kaznachej";
const char FPrint22PTK[] = "ATOL FPrint-22PTK";


+ 2
- 1
3.0/src/modules/Hardware/FR/src/Atol/Base/AtolFRBase.cpp View File

@@ -35,6 +35,7 @@ AtolFRBase::AtolFRBase()
mSubmode = CAtolFR::InnerSubmodes::NoSubmode;
mLocked = false;
mNonNullableAmount = 0;
mFDExecutionMode = CAtolFR::FiscalFlags::ExecutionMode;

// количество строк шапки (по умолчанию 4) - изменено для корректной печати на фискализированных аппаратах (как и было раньше)
mDocumentCapStrings = 6;
@@ -802,7 +803,7 @@ bool AtolFRBase::performZReport(bool aPrintDeferredReports)
bool AtolFRBase::openDocument(EPayOffTypes::Enum aPayOffType)
{
QByteArray commandData;
commandData.append(CAtolFR::FiscalFlags::ExecutionMode);
commandData.append(mFDExecutionMode);
commandData.append(CAtolFR::PayOffTypeData[aPayOffType]);

if (processCommand(CAtolFR::Commands::OpenDocument, commandData))


+ 3
- 0
3.0/src/modules/Hardware/FR/src/Atol/Base/AtolFRBase.h View File

@@ -212,6 +212,9 @@ protected:

/// Данные регистров.
CAtolFR::Registers::CData mRegisterData;

/// Режим выполнения фискального документа.
char mFDExecutionMode;
};

//--------------------------------------------------------------------------------

+ 37
- 2
3.0/src/modules/Hardware/FR/src/Atol/Online/AtolOnlineFRBase.cpp View File

@@ -327,8 +327,38 @@ bool AtolOnlineFRBase<T>::getStatus(TStatusCodes & aStatusCodes)

//--------------------------------------------------------------------------------
template<class T>
bool AtolOnlineFRBase<T>::isTradeWithoutPrinting()
{
return getModelList().contains(mDeviceName) && !canNotPrinting() && isNotPrinting();
}

//--------------------------------------------------------------------------------
template <class T>
bool AtolOnlineFRBase<T>::isPrintingNeed(const QStringList & aReceipt)
{
if (!T::isPrintingNeed(aReceipt))
{
return false;
}

bool OK = false;
mFFEngine.checkFiscalField(CFR::FiscalFields::UserContact, OK);

if (isTradeWithoutPrinting() && OK)
{
toLog(LogLevel::Normal, mDeviceName + ": Receipt has not been printed by trade ATOL:\n" + aReceipt.join("\n"));
return false;
}

return true;
}

//--------------------------------------------------------------------------------
template<class T>
bool AtolOnlineFRBase<T>::performFiscal(const QStringList & aReceipt, const SPaymentData & aPaymentData, quint32 * aFDNumber)
{
mFDExecutionMode = isTradeWithoutPrinting() ? CAtolOnlineFR::FiscalFlags::NotPrinting : CAtolFR::FiscalFlags::ExecutionMode;

if (!T::performFiscal(aReceipt, aPaymentData))
{
return false;
@@ -494,7 +524,12 @@ bool AtolOnlineFRBase<T>::checkTax(TVAT aVAT, CFR::Taxes::SData & aData)
template<class T>
bool AtolOnlineFRBase<T>::sale(const SUnitData & aUnitData)
{
if (!processCommand(CAtolOnlineFR::Commands::StartSale, CAtolOnlineFR::StartSailingData))
if (isTradeWithoutPrinting() && !setTLV(CFR::FiscalFields::UserContact))
{
toLog(LogLevel::Error, mDeviceName + ": Failed to make fiscal document without printing");
}

if (!processCommand(CAtolOnlineFR::Commands::StartSale, CAtolOnlineFR::FiscalFlags::StartSailingData))
{
return false;
}
@@ -511,7 +546,7 @@ bool AtolOnlineFRBase<T>::sale(const SUnitData & aUnitData)
QByteArray payOffSubjectMethodType = getBCD(aUnitData.payOffSubjectMethodType, 1);

QByteArray commandData;
commandData.append(CAtolOnlineFR::SaleFlags); // флаги
commandData.append(CAtolOnlineFR::FiscalFlags::Saling); // флаги
commandData.append(sum); // сумма
commandData.append(getBCD(10, 5, 2)); // количество = 1 штука
commandData.append(sum); // стоимость


+ 6
- 0
3.0/src/modules/Hardware/FR/src/Atol/Online/AtolOnlineFRBase.h View File

@@ -65,6 +65,12 @@ protected:
/// Проверить параметры налога.
virtual bool checkTax(SDK::Driver::TVAT aVAT, CFR::Taxes::SData & aData);

/// Торговый фискальник без печати чека?
bool isTradeWithoutPrinting();

/// Проверить необходимость печати.
virtual bool isPrintingNeed(const QStringList & aReceipt);

/// Продажа.
virtual bool sale(const SDK::Driver::SUnitData & aUnitData);



+ 11
- 4
3.0/src/modules/Hardware/FR/src/Atol/Online/AtolOnlineFRConstants.h View File

@@ -79,11 +79,18 @@ namespace CAtolOnlineFR
const SData SetAutoZReportTiming = SData(22, 1, 2);
}

/// Данные команды начала формирования позиции продажи - выполнить операцию + 2 магических числа
const QByteArray StartSailingData = QByteArray::fromRawData("\x00\x01\x00", 3);
/// Флаги выполнения фискальных операций.
namespace FiscalFlags
{
/// Не печатать чек - на открытии чека.
const char NotPrinting = '\x04';

/// Данные команды начала формирования позиции продажи - выполнить операцию + 2 магических числа
const QByteArray StartSailingData = QByteArray::fromRawData("\x00\x01\x00", 3);

/// Флаги выполнения продажи - Выполнить операцию + проверить денежную наличность + налог на конкретную позицию.
const char SaleFlags = CAtolFR::FiscalFlags::ExecutionMode | CAtolFR::FiscalFlags::CashChecking | CAtolFR::FiscalFlags::TaxForPosition;
/// Флаги выполнения продажи - Выполнить операцию + проверить денежную наличность + налог на конкретную позицию.
const char Saling = CAtolFR::FiscalFlags::ExecutionMode | CAtolFR::FiscalFlags::CashChecking | CAtolFR::FiscalFlags::TaxForPosition;
}

/// Регистры
namespace Registers


+ 1
- 2
3.0/src/modules/Hardware/FR/src/Atol/Online/Paymaster.cpp View File

@@ -32,10 +32,9 @@ void Paymaster<T>::setDeviceConfiguration(const QVariantMap & aConfiguration)
{
AtolVKP80BasedFR<T>::setDeviceConfiguration(aConfiguration);

bool notPrinting = getConfigParameter(CHardwareSDK::FR::WithoutPrinting) == CHardwareSDK::Values::Use;
QString printerModel = getConfigParameter(CHardware::FR::PrinterModel, CAtolOnlinePrinters::Default).toString();

if (aConfiguration.contains(CHardware::FR::PrinterModel) && (printerModel != CAtolOnlinePrinters::Default) && !notPrinting)
if (aConfiguration.contains(CHardware::FR::PrinterModel) && (printerModel != CAtolOnlinePrinters::Default) && !isNotPrinting())
{
mPPTaskList.append([&] () { mNotPrintingError = !setNotPrintDocument(false); });
}


+ 112
- 73
3.0/src/modules/Hardware/FR/src/Base/FFEngine.cpp View File

@@ -26,7 +26,25 @@ FFEngine::FFEngine(ILog * aLog): DeviceLogManager(aLog), mOperatorPresence(false
//--------------------------------------------------------------------------------
void FFEngine::setConfigParameter(const QString & aName, const QVariant & aValue)
{
DeviceConfigManager::setConfigParameter(aName, aValue);
int field = mFFData.getKey(aName);
QVariant value(aValue);

if (value.isValid() && field)
{
CFR::FiscalFields::SData & data = mFFData.data()[field];

if (data.isString())
{
value = clean(value.toString());
}

if (data.isINN())
{
value = value.toString().simplified().leftJustified(CFR::INN::Person::Natural, QChar(ASCII::Space));
}
}

DeviceConfigManager::setConfigParameter(aName, value);

mOperatorPresence = getConfigParameter(CHardwareSDK::OperatorPresence, mOperatorPresence).toBool();
}
@@ -107,6 +125,15 @@ CFR::TTLVList FFEngine::parseSTLV(const QByteArray & aData)
}

//--------------------------------------------------------------------------------