Терминальный проект КиберПлат [open source]
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

433 lines
15KB

  1. /* @file Команды печати и формирования чеков. */
  2. // Qt
  3. #include <Common/QtHeadersBegin.h>
  4. #include <QtCore/QRegExp>
  5. #include <Common/QtHeadersEnd.h>
  6. // SDK
  7. #include <SDK/PaymentProcessor/Core/ReceiptTypes.h>
  8. #include <SDK/PaymentProcessor/Payment/Parameters.h>
  9. #include <SDK/Drivers/FR/FiscalFields.h>
  10. #include <SDK/Drivers/HardwareConstants.h>
  11. // Common
  12. #include <System/IApplication.h>
  13. #include <Common/Application.h>
  14. // Project
  15. #include "PrintingCommands.h"
  16. #include "PrintingService.h"
  17. #include "PrintConstants.h"
  18. #include "PaymentService.h"
  19. namespace FiscalCommand = SDK::Driver::EFiscalPrinterCommand;
  20. namespace PPSDK = SDK::PaymentProcessor;
  21. //---------------------------------------------------------------------------
  22. void PrintCommand::setReceiptTemplate(const QString & aTemplateName)
  23. {
  24. mReceiptTemplate = aTemplateName;
  25. }
  26. //---------------------------------------------------------------------------
  27. PrintFiscalCommand::PrintFiscalCommand(const QString & aReceiptType, FiscalCommand::Enum aFiscalCommand, PrintingService * aService) :
  28. PrintCommand(aReceiptType),
  29. mFiscalCommand(aFiscalCommand),
  30. mService(aService)
  31. {
  32. }
  33. //---------------------------------------------------------------------------
  34. QVariantMap toUpperCaseKeys(const QVariantMap & aParameters)
  35. {
  36. QVariantMap result;
  37. foreach (auto key, aParameters.keys())
  38. {
  39. result.insert(key.toUpper(), aParameters.value(key));
  40. }
  41. return result;
  42. }
  43. //---------------------------------------------------------------------------
  44. SDK::Driver::SPaymentData PrintFiscalCommand::getPaymentData(const QVariantMap & aParameters)
  45. {
  46. DSDK::TAmountDataList fiscalAmountList;
  47. bool dealerIsBank = aParameters.value(CPrintConstants::DealerIsBank, false).toBool();
  48. DSDK::TVAT dealerVAT = aParameters.value(CPrintConstants::DealerVAT, 0).toInt();
  49. double amount = aParameters.value("AMOUNT").toDouble();
  50. QVariant amountList = aParameters.value("[AMOUNT]");
  51. double processingFee = aParameters.value("PROCESSING_FEE").toDouble();
  52. double fee = aParameters.value("DEALER_FEE").toDouble();
  53. int vat = aParameters.value("VAT").toInt();
  54. if (amountList.isNull())
  55. {
  56. QString paymentTitle = QString("%1 (%2)")
  57. .arg(aParameters[CPrintConstants::ServiceType].toString())
  58. .arg(aParameters[CPrintConstants::OpBrand].toString());
  59. fiscalAmountList << DSDK::SAmountData(amount, vat, paymentTitle, DSDK::EPayOffSubjectTypes::Payment);
  60. }
  61. else
  62. {
  63. QVariantList amounts = amountList.toList();
  64. QVariantList amountTitles = aParameters.value("[AMOUNT_TITLE]").toList();
  65. QVariantList amountsVAT = aParameters.value("[AMOUNT_VAT]").toList();
  66. // amount содержит список сумм для печати реестра нераспечатанных чеков
  67. for (int i = 0; i < amounts.size(); i++)
  68. {
  69. fiscalAmountList << DSDK::SAmountData(amounts[i].toDouble(), amountsVAT[i].toInt(), amountTitles[i].toString(), DSDK::EPayOffSubjectTypes::Payment);
  70. }
  71. }
  72. if (!qFuzzyIsNull(fee))
  73. {
  74. fiscalAmountList << (dealerIsBank ?
  75. DSDK::SAmountData(fee, dealerVAT, tr("#bank_fee"), DSDK::EPayOffSubjectTypes::Payment) :
  76. DSDK::SAmountData(fee, dealerVAT, tr("#dealer_fee"), DSDK::EPayOffSubjectTypes::AgentFee));
  77. }
  78. if (!qFuzzyIsNull(processingFee))
  79. {
  80. fiscalAmountList << DSDK::SAmountData(processingFee, 0, tr("#processing_fee"), DSDK::EPayOffSubjectTypes::Payment);
  81. }
  82. bool EMoney = aParameters.value(PPSDK::CPayment::Parameters::PayTool).toInt() > 0;
  83. auto payType = EMoney ? DSDK::EPayTypes::EMoney : DSDK::EPayTypes::Cash;
  84. auto taxation = aParameters.contains(CPrintConstants::DealerTaxation) ? static_cast<DSDK::ETaxations::Enum> (aParameters.value(CPrintConstants::DealerTaxation).toInt()) : DSDK::ETaxations::None;
  85. auto agentFlag = aParameters.contains(CPrintConstants::DealerAgentFlag) ? static_cast<DSDK::EAgentFlags::Enum>(aParameters.value(CPrintConstants::DealerAgentFlag).toInt()) : DSDK::EAgentFlags::None;
  86. DSDK::SPaymentData result(fiscalAmountList, false, payType, taxation, agentFlag);
  87. QVariantMap upperKeyParameters = toUpperCaseKeys(aParameters);
  88. QRegExp phoneRegexp("^9\\d{9}$");
  89. result.fiscalParameters[CHardwareSDK::FR::UserPhone] = QString();
  90. foreach (auto fieldName, QStringList() << "100" << "PHONE" << "CONTACT" << "101" << "102" << "103" << "104")
  91. {
  92. if (upperKeyParameters.contains(fieldName) && phoneRegexp.exactMatch(upperKeyParameters.value(fieldName).toString()))
  93. {
  94. result.fiscalParameters[CHardwareSDK::FR::UserPhone] = "7" + upperKeyParameters.value(fieldName).toString();
  95. break;
  96. }
  97. }
  98. result.fiscalParameters[CHardwareSDK::FR::UserMail] = QString();
  99. foreach (auto fieldName, QStringList() << "PAYER_EMAIL")
  100. {
  101. if (upperKeyParameters.contains(fieldName))
  102. {
  103. QString email = upperKeyParameters.value(fieldName).toString();
  104. if (!email.isEmpty() && email.contains("@") && email.contains("."))
  105. {
  106. result.fiscalParameters[CHardwareSDK::FR::UserMail] = upperKeyParameters.value(fieldName).toString();
  107. break;
  108. }
  109. }
  110. }
  111. return result;
  112. }
  113. //---------------------------------------------------------------------------
  114. bool PrintFiscalCommand::canFiscalPrint(DSDK::IPrinter * aPrinter, bool aRealCheck)
  115. {
  116. auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);
  117. return (mService->getFiscalRegister() && PrintCommand::canPrint(aPrinter, aRealCheck)) ||
  118. (fr && fr->isFiscalReady(aRealCheck, mFiscalCommand));
  119. }
  120. //---------------------------------------------------------------------------
  121. bool PrintFiscalCommand::getFiscalInfo(QVariantMap & aParameters, QStringList & aReceiptLines)
  122. {
  123. PPSDK::IFiscalRegister * fr = mService->getFiscalRegister();
  124. if (fr && fr->haveCapability(PPSDK::IFiscalRegister::Receipt))
  125. {
  126. qint64 paymentId = aParameters.value(PPSDK::CPayment::Parameters::ID).toLongLong();
  127. QStringList parameterNames = fr->getParameterNames();
  128. // Если в параметрах платежа ещё нет информации о фискальном номере
  129. bool OK = !parameterNames.toSet().intersect(aParameters.keys().toSet()).isEmpty();
  130. if (!OK)
  131. {
  132. auto fiscalParameters = fr->createFiscalTicket(paymentId, aParameters, getPaymentData(aParameters));
  133. OK = !fiscalParameters.isEmpty();
  134. aParameters.unite(fiscalParameters);
  135. mService->setFiscalNumber(paymentId, fiscalParameters);
  136. }
  137. if (OK)
  138. {
  139. aReceiptLines = fr->getReceipt(paymentId, aParameters);
  140. }
  141. return OK;
  142. }
  143. return false;
  144. }
  145. //---------------------------------------------------------------------------
  146. bool PrintPayment::canPrint(DSDK::IPrinter * aPrinter, bool aRealCheck)
  147. {
  148. if (!aPrinter)
  149. {
  150. return false;
  151. }
  152. auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);
  153. return isFiscal(aPrinter) ? fr->isFiscalReady(aRealCheck, FiscalCommand::Sale) : aPrinter->isDeviceReady(aRealCheck);
  154. }
  155. //---------------------------------------------------------------------------
  156. bool PrintPayment::print(DSDK::IPrinter * aPrinter, const QVariantMap & aParameters)
  157. {
  158. QVariantMap parameters = aParameters;
  159. QStringList receipt;
  160. getFiscalInfo(parameters, receipt);
  161. // Добавляем строки основного чека
  162. QVariantMap configuration = aPrinter->getDeviceConfiguration();
  163. bool onlineKKM = configuration[CHardwareSDK::CanOnline].toBool();
  164. bool fiscalPrinting = isFiscal(aPrinter) && !aParameters[PPSDK::CPayment::Parameters::ReceiptPrinted].toInt();
  165. QString KKMSerialNumber = "0";
  166. if (!fiscalPrinting)
  167. {
  168. KKMSerialNumber = configuration[CHardwareSDK::SerialNumber].toString();
  169. }
  170. QVariantMap actualParameters = aParameters;
  171. actualParameters.insert(CPrintConstants::KKM::SerialNumber, KKMSerialNumber);
  172. actualParameters.insert("ONLINE_KKM", onlineKKM ? 1 : 0);
  173. receipt.append(mService->getReceipt(mReceiptTemplate, actualParameters));
  174. bool result = false;
  175. // Повторно мы печатаем только нефискальные чеки
  176. if (!fiscalPrinting)
  177. {
  178. result = canPrint(aPrinter, false) && aPrinter->print(receipt);
  179. }
  180. else if (canFiscalPrint(aPrinter, false))
  181. {
  182. DSDK::SPaymentData paymentData = getPaymentData(actualParameters);
  183. static_cast<DSDK::IFiscalPrinter *>(aPrinter)->setDeviceConfiguration(paymentData.fiscalParameters);
  184. result = static_cast<DSDK::IFiscalPrinter *>(aPrinter)->printFiscal(receipt, paymentData, mFiscalPaymentData, mPayOffSubjectData);
  185. if (!mFiscalPaymentData.isEmpty())
  186. {
  187. #define ADD_FISCAL_TAG(aTranstation, aFiscalTag) receipt << aTranstation + ": " + mFiscalPaymentData[DSDK::FiscalFields::aFiscalTag].toString();
  188. ADD_FISCAL_TAG(tr("#taxation"), TaxSystem);
  189. ADD_FISCAL_TAG(tr("#kkt_timestamp"), FDDateTime);
  190. ADD_FISCAL_TAG(tr("#kkt_znm"), SerialFRNumber);
  191. ADD_FISCAL_TAG(tr("#kkt_rnm"), RNM);
  192. ADD_FISCAL_TAG(tr("#kkt_session"), SessionNumber);
  193. ADD_FISCAL_TAG(tr("#kkt_fd_serial"), DocumentNumber);
  194. ADD_FISCAL_TAG(tr("#kkt_fn"), SerialFSNumber);
  195. ADD_FISCAL_TAG(tr("#kkt_fd"), FDNumber);
  196. ADD_FISCAL_TAG(tr("#kkt_fp"), FDSign);
  197. ADD_FISCAL_TAG(tr("#tax_amount_02"), TaxAmount02);
  198. ADD_FISCAL_TAG(tr("#tax_amount_03"), TaxAmount03);
  199. ADD_FISCAL_TAG(tr("#tax_amount_04"), TaxAmount04);
  200. ADD_FISCAL_TAG(tr("#tax_amount_05"), TaxAmount05);
  201. }
  202. }
  203. // Сохраняем чек на диске.
  204. QString receiptName = QTime::currentTime().toString(CPrintCommands::ReceiptNameTemplate) + "_" + aParameters["ID"].toString() +
  205. (result ? "" : CPrintCommands::NotPrintedPostfix);
  206. mService->saveReceiptContent(receiptName, receipt);
  207. return result;
  208. }
  209. //---------------------------------------------------------------------------
  210. const DSDK::TFiscalPaymentData & PrintPayment::getFiscalData() const
  211. {
  212. return mFiscalPaymentData;
  213. }
  214. //---------------------------------------------------------------------------
  215. bool PrintPayment::isFiscal(DSDK::IPrinter * aPrinter)
  216. {
  217. DSDK::IFiscalPrinter * fiscalPrinter = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);
  218. return fiscalPrinter && fiscalPrinter->isFiscal();
  219. }
  220. //---------------------------------------------------------------------------
  221. bool PrintBalance::print(DSDK::IPrinter * aPrinter, const QVariantMap & aParameters)
  222. {
  223. QStringList receipt = mService->getReceipt(mReceiptType, expandFields(aParameters));
  224. auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);
  225. auto virtualFR = mService->getFiscalRegister();
  226. if (mFiscalMode && virtualFR && virtualFR->haveCapability(PPSDK::IFiscalRegister::Balance))
  227. {
  228. receipt.append(virtualFR->balance());
  229. }
  230. mService->saveReceiptContent(QString("%1_balance").arg(QTime::currentTime().toString("hhmmsszzz")), receipt);
  231. return mFiscalMode && fr && fr->isFiscalReady(false, mFiscalCommand) ? fr->printXReport(receipt) : aPrinter->print(receipt);
  232. }
  233. //---------------------------------------------------------------------------
  234. QVariantMap PrintBalance::expandFields(const QVariantMap & aParameters)
  235. {
  236. QVariantMap parameters;
  237. auto currencySettings = mService->getCurrencySettings();
  238. auto fillParameters = [&](const QString & aPrefix)
  239. {
  240. //монеты
  241. foreach (auto coin, currencySettings.coins)
  242. {
  243. parameters[aPrefix + QString("%1_COIN_COUNT").arg(coin.toString())] = 0;
  244. parameters[aPrefix + QString("%1_COIN_SUM").arg(coin.toString())] = 0;
  245. }
  246. parameters[aPrefix + "COIN_COUNT"] = 0;
  247. parameters[aPrefix + "COIN_SUM"] = 0;
  248. //купюры
  249. foreach (auto note, currencySettings.notes)
  250. {
  251. parameters[aPrefix + QString("%1_BILL_COUNT").arg(note.toString())] = 0;
  252. parameters[aPrefix + QString("%1_BILL_SUM").arg(note.toString())] = 0;
  253. }
  254. parameters[aPrefix + "BILL_COUNT"] = 0;
  255. parameters[aPrefix + "BILL_SUM"] = 0;
  256. };
  257. fillParameters("");
  258. fillParameters("DISPENSED_");
  259. for (auto i = aParameters.begin(); i != aParameters.end(); ++i)
  260. {
  261. parameters.insert(i.key(), i.value());
  262. }
  263. return parameters;
  264. }
  265. //---------------------------------------------------------------------------
  266. PrintEncashment::PrintEncashment(const QString & aReceiptType, PrintingService * aService) :
  267. PrintBalance(aReceiptType, aService)
  268. {
  269. mFiscalCommand = FiscalCommand::Encashment;
  270. }
  271. //---------------------------------------------------------------------------
  272. bool PrintEncashment::print(DSDK::IPrinter * aPrinter, const QVariantMap & aParameters)
  273. {
  274. // Сохраняем чек перед печатью.
  275. QStringList receipt = mService->getReceipt(mReceiptType, expandFields(aParameters));
  276. auto virtualFR = mService->getFiscalRegister();
  277. // Производим выплату фискального регистратора.
  278. if (mFiscalMode && virtualFR && virtualFR->haveCapability(PPSDK::IFiscalRegister::Encashment))
  279. {
  280. receipt.append(virtualFR->encashment());
  281. }
  282. mService->saveReceiptContent(QString("%1_%2_encashment").arg(QTime::currentTime().toString("hhmmsszzz")).arg(aParameters["ENCASHMENT_NUMBER"].toString()), receipt);
  283. auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);
  284. if (!canPrint(aPrinter, false))
  285. {
  286. return false;
  287. }
  288. return (mFiscalMode && fr && fr->isFiscalReady(false, mFiscalCommand)) ? fr->printEncashment(receipt) : (aPrinter && aPrinter->print(receipt));
  289. }
  290. //---------------------------------------------------------------------------
  291. bool PrintZReport::canPrint(DSDK::IPrinter * aPrinter, bool aRealCheck)
  292. {
  293. auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);
  294. auto virtualFR = mService->getFiscalRegister();
  295. return (virtualFR && virtualFR->haveCapability(PPSDK::IFiscalRegister::ZReport) && PrintCommand::canPrint(aPrinter, aRealCheck)) ||
  296. (fr && fr->isFiscalReady(aRealCheck, mFiscalCommand));
  297. }
  298. //---------------------------------------------------------------------------
  299. bool PrintZReport::print(DSDK::IPrinter * aPrinter, const QVariantMap & /*aParameters*/)
  300. {
  301. bool result = false;
  302. if (!canFiscalPrint(aPrinter, false))
  303. {
  304. return false;
  305. }
  306. auto virtualFR = mService->getFiscalRegister();
  307. if (virtualFR && virtualFR->haveCapability(PPSDK::IFiscalRegister::ZReport))
  308. {
  309. QStringList report = virtualFR->getZreport();
  310. if (!report.isEmpty())
  311. {
  312. result = aPrinter && aPrinter->print(report);
  313. mService->saveReceiptContent(QString("%1_Z_report%2")
  314. .arg(QTime::currentTime().toString("hhmmsszzz"))
  315. .arg(result ? "" : CPrintCommands::NotPrintedPostfix), report);
  316. }
  317. }
  318. auto fr = dynamic_cast<DSDK::IFiscalPrinter *>(aPrinter);
  319. return (fr && fr->isFiscalReady(false, mFiscalCommand) && fr->printZReport(mFull)) || result;
  320. }
  321. //---------------------------------------------------------------------------
  322. bool PrintReceipt::print(DSDK::IPrinter * aPrinter, const QVariantMap & aParameters)
  323. {
  324. QVariantMap configuration = aPrinter->getDeviceConfiguration();
  325. QString KKMSerialNumber = configuration[CHardwareSDK::SerialNumber].toString();
  326. if (KKMSerialNumber.isEmpty())
  327. {
  328. KKMSerialNumber = "0";
  329. }
  330. QVariantMap actualParameters = aParameters;
  331. actualParameters.insert(CPrintConstants::KKM::SerialNumber, KKMSerialNumber);
  332. QStringList receipt = mService->getReceipt(mReceiptTemplate, actualParameters);
  333. mService->saveReceiptContent(QString("%1_%2").arg(QTime::currentTime().toString("hhmmsszzz")).arg(mReceiptTemplate), receipt);
  334. return aPrinter && aPrinter->print(receipt);
  335. }
  336. //---------------------------------------------------------------------------