Терминальный проект КиберПлат [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.

1508 lines
49KB

  1. /* @file Сервис, владеющий платёжными потоками. */
  2. // Boost
  3. #include <boost/foreach.hpp>
  4. // Qt
  5. #include <Common/QtHeadersBegin.h>
  6. #include <QtCore/QRegExp>
  7. #include <QtCore/QMutexLocker>
  8. #include <QtCore/QCryptographicHash>
  9. #include <QtConcurrent/QtConcurrentRun>
  10. #include <Common/QtHeadersEnd.h>
  11. // SDK
  12. #include <SDK/PaymentProcessor/Core/Event.h>
  13. #include <SDK/PaymentProcessor/Core/EventTypes.h>
  14. #include <SDK/PaymentProcessor/Core/IFundsService.h>
  15. #include <SDK/PaymentProcessor/Core/ITerminalService.h>
  16. #include <SDK/PaymentProcessor/Core/ServiceParameters.h>
  17. #include <SDK/PaymentProcessor/Core/HookConstants.h>
  18. #include <SDK/PaymentProcessor/Payment/Step.h>
  19. #include <SDK/PaymentProcessor/Payment/Parameters.h>
  20. #include <SDK/PaymentProcessor/Payment/IPayment.h>
  21. #include <SDK/PaymentProcessor/Payment/IPaymentFactory.h>
  22. #include <SDK/PaymentProcessor/Settings/DealerSettings.h>
  23. #include <SDK/PaymentProcessor/Settings/TerminalSettings.h>
  24. // Модули
  25. #include <Crypt/ICryptEngine.h>
  26. // Проект
  27. #include "DatabaseUtils/IPaymentDatabaseUtils.h"
  28. #include "Services/ServiceNames.h"
  29. #include "Services/PluginService.h"
  30. #include "Services/SettingsService.h"
  31. #include "Services/DatabaseService.h"
  32. #include "Services/CryptService.h"
  33. #include "Services/EventService.h"
  34. #include "Services/PaymentService.h"
  35. #include "Services/HookService.h"
  36. #include "Services/ServiceCommon.h"
  37. #include "Services/NetworkService.h"
  38. namespace PPSDK = SDK::PaymentProcessor;
  39. using namespace std::placeholders;
  40. //---------------------------------------------------------------------------
  41. namespace CPaymentService
  42. {
  43. /// Название нити, обрабатывающей оффлайн платежи.
  44. const char ThreadName[] = "PaymentThread";
  45. /// Таймаут обработки очереди оффлайн платежей.
  46. const int ProcessOfflineTimeout = 1 * 1000;
  47. /// Таймаут онлайн платежа, когда он гарантированно переводится в BAD
  48. const int OnlinePaymentOvertime = 30 * 60 * 1000;
  49. /// Таймаут обработки очереди оффлайн платежей при отсутствии связи.
  50. const int CheckNetworkConnectionTimeout = 5 * 1000;
  51. /// Тип платежа, в который будет добавляться неизрасходованная сдача.
  52. const char ChangePaymentType[] = "cyberplat";
  53. /// Признак того, что в платеже хранится неизрасходованная сдача.
  54. const char ChangePaymentParam[] = "UNUSED_CHANGE";
  55. }
  56. //---------------------------------------------------------------------------
  57. PaymentService * PaymentService::instance(IApplication * aApplication)
  58. {
  59. return static_cast<PaymentService *>(aApplication->getCore()->getService(CServices::PaymentService));
  60. }
  61. //---------------------------------------------------------------------------
  62. PaymentService::PaymentService(IApplication * aApplication)
  63. : ILogable("Payments"),
  64. mApplication(aApplication),
  65. mEnabled(false),
  66. mPaymentLock(QMutex::Recursive),
  67. mOfflinePaymentID(-1),
  68. mOfflinePaymentLock(QMutex::Recursive),
  69. mCommandMutex(QMutex::Recursive)
  70. {
  71. qRegisterMetaType<EPaymentCommandResult::Enum>("EPaymentCommandResult");
  72. mPaymentThread.setObjectName(CPaymentService::ThreadName);
  73. mPaymentTimer.setSingleShot(true);
  74. mPaymentTimer.moveToThread(&mPaymentThread);
  75. connect(&mPaymentThread, SIGNAL(started()), SLOT(onPaymentThreadStarted()), Qt::DirectConnection);
  76. connect(&mPaymentThread, SIGNAL(finished()), &mPaymentTimer, SLOT(stop()), Qt::DirectConnection);
  77. connect(&mPaymentTimer, SIGNAL(timeout()), SLOT(onProcessPayments()), Qt::DirectConnection);
  78. }
  79. //---------------------------------------------------------------------------
  80. bool PaymentService::initialize()
  81. {
  82. connect(mApplication->getCore()->getFundsService()->getAcceptor(), SIGNAL(amountUpdated(qint64, double, double)), SLOT(onAmountUpdated(qint64, double, double)));
  83. connect(mApplication->getCore()->getFundsService()->getDispenser(), SIGNAL(dispensed(double)), SLOT(onAmountDispensed(double)));
  84. mCommandIndex = 1;
  85. mDBUtils = DatabaseService::instance(mApplication)->getDatabaseUtils<IPaymentDatabaseUtils>();
  86. if (!mDBUtils)
  87. {
  88. toLog(LogLevel::Error, "Failed to get database utils.");
  89. return false;
  90. }
  91. QStringList factories =
  92. PluginService::instance(mApplication)->getPluginLoader()->getPluginList(QRegExp("PaymentProcessor\\.PaymentFactory\\..*"));
  93. foreach (const QString & path, factories)
  94. {
  95. SDK::Plugin::IPlugin * plugin = PluginService::instance(mApplication)->getPluginLoader()->createPlugin(path);
  96. SDK::PaymentProcessor::IPaymentFactory * factory = dynamic_cast<SDK::PaymentProcessor::IPaymentFactory *>(plugin);
  97. if (factory)
  98. {
  99. factory->setSerializer(std::bind(&PaymentService::savePayment, this, _1));
  100. foreach (const QString & type, factory->getSupportedPaymentTypes())
  101. {
  102. mFactoryByType[type] = factory;
  103. }
  104. mFactories << factory;
  105. }
  106. else
  107. {
  108. PluginService::instance(mApplication)->getPluginLoader()->destroyPlugin(plugin);
  109. }
  110. }
  111. // Ищем всех провайдеров с неподдерживаемым типом процессинга
  112. auto dealerSettings = SettingsService::instance(mApplication)->getAdapter<SDK::PaymentProcessor::DealerSettings>();
  113. foreach (const QString & processingType, dealerSettings->getProviderProcessingTypes().toSet().subtract(mFactoryByType.keys().toSet()))
  114. {
  115. // И удаляем их
  116. foreach (qint64 providerId, dealerSettings->getProviders(processingType))
  117. {
  118. toLog(LogLevel::Error, QString("Drop provider %1. Unsupported processing type: '%2'.").arg(providerId).arg(processingType));
  119. dealerSettings->disableProvider(providerId);
  120. }
  121. }
  122. return true;
  123. }
  124. //------------------------------------------------------------------------------
  125. void PaymentService::finishInitialize()
  126. {
  127. foreach (auto factory, mFactories)
  128. {
  129. if (!factory->initialize())
  130. {
  131. toLog(LogLevel::Error, QString("Failed initialize payment factory plugin for payment types: %1.").arg(factory->getSupportedPaymentTypes().join(", ")));
  132. }
  133. }
  134. // Запускаем поток на обработку оффлайн платежей.
  135. mPaymentThread.start();
  136. mEnabled = true;
  137. }
  138. //---------------------------------------------------------------------------
  139. bool PaymentService::canShutdown()
  140. {
  141. return true;
  142. }
  143. //---------------------------------------------------------------------------
  144. bool PaymentService::shutdown()
  145. {
  146. mEnabled = false;
  147. // Спрашиваем сетевой сервис может ли он закрыться. Тем самым сбрасывая все сетевые задачи.
  148. mApplication->getCore()->getService(CServices::NetworkService)->canShutdown();
  149. disconnect(mApplication->getCore()->getFundsService()->getAcceptor());
  150. disconnect(mApplication->getCore()->getFundsService()->getDispenser());
  151. mActivePaymentSynchronizer.waitForFinished();
  152. SafeStopServiceThread(&mPaymentThread, 3000, getLog());
  153. if (mChangePayment)
  154. {
  155. mChangePayment.reset();
  156. }
  157. setPaymentActive(std::shared_ptr<PPSDK::IPayment>());
  158. while (!mFactories.isEmpty())
  159. {
  160. PluginService::instance(mApplication)->getPluginLoader()->destroyPlugin(
  161. dynamic_cast<SDK::Plugin::IPlugin *>(mFactories.takeFirst()));
  162. }
  163. return true;
  164. }
  165. //---------------------------------------------------------------------------
  166. QString PaymentService::getName() const
  167. {
  168. return CServices::PaymentService;
  169. }
  170. //---------------------------------------------------------------------------
  171. const QSet<QString> & PaymentService::getRequiredServices() const
  172. {
  173. static QSet<QString> requiredServices = QSet<QString>()
  174. << CServices::SettingsService
  175. << CServices::EventService
  176. << CServices::PluginService
  177. << CServices::DatabaseService
  178. << CServices::CryptService;
  179. return requiredServices;
  180. }
  181. //---------------------------------------------------------------------------
  182. QVariantMap PaymentService::getParameters() const
  183. {
  184. // TODO Заполнить параметры
  185. QVariantMap parameters;
  186. parameters[PPSDK::CServiceParameters::Payment::UnprocessedPaymentCount] = "";
  187. parameters[PPSDK::CServiceParameters::Payment::PaymentsPerDay] = "";
  188. return parameters;
  189. }
  190. //---------------------------------------------------------------------------
  191. void PaymentService::resetParameters(const QSet<QString> &)
  192. {
  193. }
  194. //---------------------------------------------------------------------------
  195. void PaymentService::setPaymentActive(std::shared_ptr<SDK::PaymentProcessor::IPayment> aPayment)
  196. {
  197. QMutexLocker lock(&mPaymentLock);
  198. mActivePayment = aPayment;
  199. }
  200. //---------------------------------------------------------------------------
  201. bool PaymentService::isPaymentActive(std::shared_ptr<PPSDK::IPayment> aPayment)
  202. {
  203. QMutexLocker lock(&mPaymentLock);
  204. return aPayment == mActivePayment;
  205. }
  206. //---------------------------------------------------------------------------
  207. qint64 PaymentService::createPayment(qint64 aProvider)
  208. {
  209. using namespace std::placeholders;
  210. if (getActivePayment() != -1)
  211. {
  212. setPaymentActive(std::shared_ptr<PPSDK::IPayment>());
  213. }
  214. toLog(LogLevel::Normal, QString("Creating payment. Provider: %1.").arg(aProvider));
  215. PPSDK::SProvider provider = SettingsService::instance(mApplication)->getAdapter<SDK::PaymentProcessor::DealerSettings>()->getProvider(aProvider);
  216. if (provider.isNull())
  217. {
  218. toLog(LogLevel::Error, QString("Failed to get settings for provider %1.").arg(aProvider));
  219. return -1;
  220. }
  221. if (mFactoryByType.contains(provider.processor.type))
  222. {
  223. PPSDK::IPaymentFactory * factory = mFactoryByType[provider.processor.type];
  224. std::shared_ptr<PPSDK::IPayment> payment(factory->createPayment(provider.processor.type), std::bind(&PPSDK::IPaymentFactory::releasePayment, factory, _1));
  225. if (!payment)
  226. {
  227. toLog(LogLevel::Error, "Failed to create payment object.");
  228. return -1;
  229. }
  230. QList<PPSDK::IPayment::SParameter> parameters;
  231. parameters
  232. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::ID, mDBUtils->createDummyPayment(), true)
  233. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::CreationDate, QDateTime::currentDateTime(), true)
  234. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::Type, provider.processor.type, true)
  235. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::Provider, provider.id, true)
  236. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::Status, PPSDK::EPaymentStatus::Init, true)
  237. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::Priority, PPSDK::IPayment::Online, true);
  238. if (!payment->restore(parameters))
  239. {
  240. toLog(LogLevel::Error, "Failed to initialize payment object.");
  241. return -1;
  242. }
  243. if (payment->getID() == -1)
  244. {
  245. toLog(LogLevel::Error, "Failed to create payment ID.");
  246. return -1;
  247. }
  248. // Добавляем платёж в список активных
  249. setPaymentActive(payment);
  250. return payment->getID();
  251. }
  252. toLog(LogLevel::Error, QString("Failed to find factory for payment type %1.").arg(provider.processor.type));
  253. return -1;
  254. }
  255. //---------------------------------------------------------------------------
  256. bool PaymentService::savePayment(PPSDK::IPayment * aPayment)
  257. {
  258. if (mDBUtils->savePayment(aPayment, createSignature(aPayment)))
  259. {
  260. EventService::instance(mApplication)->sendEvent(PPSDK::Event(PPSDK::EEventType::PaymentUpdated, CServices::PaymentService, aPayment->getID()));
  261. return true;
  262. }
  263. else
  264. {
  265. QString amountAll = aPayment->getParameter(PPSDK::CPayment::Parameters::AmountAll).value.toString();
  266. QString msg = QString("Payment [%1] error write to database (AMOUNT_ALL=%2).").arg(aPayment->getInitialSession()).arg(amountAll);
  267. // Выставить ошибочный статус устройства "терминал"
  268. mApplication->getCore()->getEventService()->sendEvent(
  269. SDK::PaymentProcessor::Event(SDK::PaymentProcessor::EEventType::Critical, CServices::DatabaseService, msg));
  270. return false;
  271. }
  272. }
  273. //---------------------------------------------------------------------------
  274. qint64 PaymentService::getActivePayment() const
  275. {
  276. return mActivePayment ? mActivePayment->getID() : -1;
  277. }
  278. //---------------------------------------------------------------------------
  279. void PaymentService::deactivatePayment()
  280. {
  281. if (mActivePayment)
  282. {
  283. QMutexLocker lock(&mPaymentLock);
  284. savePayment(mActivePayment.get());
  285. mActivePayment.reset();
  286. }
  287. // Если существует пустой платеж "сдача", нужно его пометить в БД как удаленный
  288. if (mChangePayment && qFuzzyIsNull(getChangeAmount()))
  289. {
  290. resetChange();
  291. }
  292. }
  293. //---------------------------------------------------------------------------
  294. QString PaymentService::createSignature(PPSDK::IPayment * aPayment)
  295. {
  296. if (!aPayment)
  297. {
  298. toLog(LogLevel::Error, "Failed to create payment signature. No payment specified.");
  299. return "";
  300. }
  301. QString signature;
  302. PPSDK::SProvider provider = SettingsService::instance(mApplication)->getAdapter<SDK::PaymentProcessor::DealerSettings>()->
  303. getProvider(aPayment->getProvider(false));
  304. PPSDK::SKeySettings keys = SettingsService::instance(mApplication)->getAdapter<PPSDK::TerminalSettings>()->
  305. getKeys()[provider.processor.keyPair];
  306. signature += QString("SD: %1, AP: %2, OP: %3\n").arg(keys.sd).arg(keys.ap).arg(keys.op);
  307. // В подпись включаем все суммы платежа.
  308. QStringList controlParameters;
  309. controlParameters
  310. << PPSDK::CPayment::Parameters::Amount
  311. << PPSDK::CPayment::Parameters::AmountAll
  312. << PPSDK::CPayment::Parameters::Change
  313. << PPSDK::CPayment::Parameters::Fee;
  314. signature += "Sums:\n";
  315. foreach (const QString & parameter, controlParameters)
  316. {
  317. signature += parameter + " : " + aPayment->getParameter(parameter).value.toString() + "\n";
  318. }
  319. signature += "Provider fields:\n";
  320. // Включаем в подпись все поля данных оператора
  321. QStringList providerFields;
  322. foreach (const PPSDK::SProviderField & field, provider.fields)
  323. {
  324. if (!field.keepEncrypted())
  325. {
  326. providerFields << field.id;
  327. }
  328. }
  329. if (providerFields.isEmpty())
  330. {
  331. // Описания оператора нет, берём названия полей из базы.
  332. providerFields = aPayment->getParameter(PPSDK::CPayment::Parameters::ProviderFields).value.toString()
  333. .split(PPSDK::CPayment::Parameters::ProviderFieldsDelimiter);
  334. }
  335. providerFields.sort();
  336. foreach (const QString & field, providerFields)
  337. {
  338. signature += field + " : " + aPayment->getParameter(field).value.toString() + "\n";
  339. }
  340. // Включаем в подпись основные поля платежа.
  341. signature += "id\tcreate_date\tinitial_session\tsession\toperator\tstatus\tstep\n";
  342. signature += QString::number(aPayment->getID());
  343. signature += "\t";
  344. signature += aPayment->getCreationDate().toString("yyyy-MM-dd hh:mm:ss.zzz");
  345. signature += "\t";
  346. signature += aPayment->getInitialSession();
  347. signature += "\t";
  348. signature += aPayment->getSession();
  349. signature += "\t";
  350. signature += QString::number(aPayment->getProvider(false));
  351. signature += "\t";
  352. signature += QString::number(aPayment->getStatus());
  353. signature += "\t";
  354. signature += aPayment->getParameter(PPSDK::CPayment::Parameters::Step).value.toString();
  355. #ifndef _DEBUG
  356. signature = QString::fromUtf8(QCryptographicHash::hash(signature.toUtf8(), QCryptographicHash::Md5).toHex().toUpper());
  357. ICryptEngine * crypt = static_cast<ICryptEngine *>(CryptService::instance(mApplication)->getCryptEngine());
  358. QByteArray encodedSignature;
  359. QString error;
  360. if (!crypt->encryptLong(-1, signature.toUtf8(), encodedSignature, error))
  361. {
  362. toLog(LogLevel::Error, QString("Payment %1. Failed to encrypt signature. Error: %2.").arg(aPayment->getID()).arg(error));
  363. return QString();
  364. }
  365. return QString::fromUtf8(encodedSignature);
  366. #else
  367. return signature;
  368. #endif // _DEBUG
  369. }
  370. //---------------------------------------------------------------------------
  371. bool PaymentService::verifySignature(PPSDK::IPayment * aPayment)
  372. {
  373. QString signature = aPayment->getParameter(PPSDK::CPayment::Parameters::Signature).value.toString();
  374. if (signature.isEmpty())
  375. {
  376. toLog(LogLevel::Error, QString("Payment %1. No signature.").arg(aPayment->getID()));
  377. return false;
  378. }
  379. QString runtimeSignature = createSignature(aPayment);
  380. #ifndef _DEBUG
  381. ICryptEngine * crypt = static_cast<ICryptEngine *>(CryptService::instance(mApplication)->getCryptEngine());
  382. QByteArray decodedSignature;
  383. QByteArray decodedRuntimeSignature;
  384. QString error;
  385. if (!crypt->decryptLong(-1, signature.toUtf8(), decodedSignature, error))
  386. {
  387. toLog(LogLevel::Warning, QString("Payment %1. Failed to decrypt signature. Error: %2.").arg(aPayment->getID()).arg(error));
  388. return false;
  389. }
  390. if (!crypt->decryptLong(-1, runtimeSignature.toUtf8(), decodedRuntimeSignature, error))
  391. {
  392. toLog(LogLevel::Warning, QString("Payment %1. Failed to decrypt runtime signature. Error: %2.").arg(aPayment->getID()).arg(error));
  393. return false;
  394. }
  395. return (decodedSignature == decodedRuntimeSignature);
  396. #else
  397. return (signature == runtimeSignature);
  398. #endif // _DEBUG
  399. }
  400. //---------------------------------------------------------------------------
  401. std::shared_ptr<PPSDK::IPayment> PaymentService::getPayment(qint64 aID)
  402. {
  403. {
  404. QMutexLocker lock(&mPaymentLock);
  405. // Если спрашиваем активный платёж, не перезагружаем его из базы.
  406. if (mActivePayment && (mActivePayment->getID() == aID))
  407. {
  408. return mActivePayment;
  409. }
  410. }
  411. if (aID == -1)
  412. {
  413. toLog(LogLevel::Debug, QString("Payment %1. Payment not exist.").arg(aID));
  414. return std::shared_ptr<PPSDK::IPayment>();
  415. }
  416. toLog(LogLevel::Normal, QString("Payment %1. Loading...").arg(aID));
  417. QList<PPSDK::IPayment::SParameter> parameters = mDBUtils->getPaymentParameters(aID);
  418. PPSDK::IPayment::SParameter type = PPSDK::IPayment::parameterByName(PPSDK::CPayment::Parameters::Type, parameters);
  419. if (!type.isNull() && mFactoryByType.contains(type.value.toString()))
  420. {
  421. std::shared_ptr<PPSDK::IPayment> payment(
  422. mFactoryByType[type.value.toString()]->createPayment(type.value.toString()),
  423. std::bind(&PPSDK::IPaymentFactory::releasePayment, mFactoryByType[type.value.toString()], _1));
  424. if (!payment)
  425. {
  426. toLog(LogLevel::Normal, QString("Payment %1. Failed to create payment object.").arg(aID));
  427. return std::shared_ptr<PPSDK::IPayment>();
  428. }
  429. if (!payment->restore(parameters))
  430. {
  431. toLog(LogLevel::Normal, QString("Payment %1. Failed to restore payment object.").arg(aID));
  432. return std::shared_ptr<PPSDK::IPayment>();
  433. }
  434. if (!verifySignature(payment.get()))
  435. {
  436. toLog(LogLevel::Warning, QString("Payment %1. Cheated.").arg(payment->getID()));
  437. payment->setStatus(PPSDK::EPaymentStatus::Cheated);
  438. savePayment(payment.get());
  439. }
  440. return payment;
  441. }
  442. return std::shared_ptr<PPSDK::IPayment>();
  443. }
  444. //---------------------------------------------------------------------------
  445. std::shared_ptr<PPSDK::IPayment> PaymentService::getPayment(const QString & aInitialSession)
  446. {
  447. qint64 id = mDBUtils->getPaymentByInitialSession(aInitialSession);
  448. if (id != -1)
  449. {
  450. return getPayment(id);
  451. }
  452. return std::shared_ptr<PPSDK::IPayment>();
  453. }
  454. //---------------------------------------------------------------------------
  455. PPSDK::SProvider PaymentService::getProvider(qint64 aID)
  456. {
  457. PPSDK::SProvider provider = SettingsService::instance(mApplication)->getAdapter<SDK::PaymentProcessor::DealerSettings>()->getProvider(aID);
  458. if (!provider.isNull())
  459. {
  460. if (mFactoryByType.contains(provider.processor.type))
  461. {
  462. provider = mFactoryByType[provider.processor.type]->getProviderSpecification(provider);
  463. }
  464. else
  465. {
  466. toLog(LogLevel::Error, QString("Provider #%1: has unknown payment processor type: %2.").arg(aID).arg(provider.processor.type));
  467. }
  468. }
  469. return provider;
  470. }
  471. //---------------------------------------------------------------------------
  472. PPSDK::IPayment::SParameter PaymentService::getPaymentField(qint64 aPayment, const QString & aName)
  473. {
  474. return PPSDK::IPayment::parameterByName(aName, getPaymentFields(aPayment));
  475. }
  476. //---------------------------------------------------------------------------
  477. TPaymentParameters PaymentService::getPaymentFields(qint64 aPayment)
  478. {
  479. if (aPayment == getActivePayment())
  480. {
  481. std::shared_ptr<PPSDK::IPayment> payment = getPayment(aPayment);
  482. return payment ? payment->getParameters() : QList<PPSDK::IPayment::SParameter>();
  483. }
  484. else
  485. {
  486. return mDBUtils->getPaymentParameters(aPayment);
  487. }
  488. }
  489. //------------------------------------------------------------------------------
  490. QMap<qint64, TPaymentParameters> PaymentService::getPaymentsFields(const QList<qint64> & aIds)
  491. {
  492. QMap<qint64, TPaymentParameters> result = mDBUtils->getPaymentParameters(aIds);
  493. if (aIds.contains(getActivePayment()))
  494. {
  495. std::shared_ptr<PPSDK::IPayment> payment = getPayment(getActivePayment());
  496. if (payment)
  497. {
  498. // объединяем два списка параметров
  499. QMap<QString, SDK::PaymentProcessor::IPayment::SParameter> parameters;
  500. foreach (auto param, payment->getParameters())
  501. {
  502. parameters.insert(param.name, param);
  503. }
  504. // из базы более старые параметры
  505. foreach (auto param, result.value(getActivePayment()))
  506. {
  507. if (!parameters.contains(param.name))
  508. {
  509. parameters.insert(param.name, param);
  510. }
  511. }
  512. result.insert(getActivePayment(), parameters.values());
  513. }
  514. }
  515. return result;
  516. }
  517. //---------------------------------------------------------------------------
  518. QList<PPSDK::IPayment::SParameter> PaymentService::calculateCommission(const QList<PPSDK::IPayment::SParameter> & aParameters)
  519. {
  520. if (mActivePayment)
  521. {
  522. return mActivePayment->calculateCommission(aParameters);
  523. }
  524. return QList<PPSDK::IPayment::SParameter>();
  525. }
  526. //---------------------------------------------------------------------------
  527. bool PaymentService::updatePaymentField(qint64 aID, const PPSDK::IPayment::SParameter & aField, bool aForceUpdate)
  528. {
  529. QList<PPSDK::IPayment::SParameter> parameters;
  530. parameters.append(aField);
  531. return updatePaymentFields(aID, parameters, aForceUpdate);
  532. }
  533. //---------------------------------------------------------------------------
  534. bool PaymentService::updatePaymentFields(qint64 aID, const QList<SDK::PaymentProcessor::IPayment::SParameter> & aFields, bool aForceUpdate)
  535. {
  536. QMutexLocker lock(&mOfflinePaymentLock);
  537. if (mOfflinePaymentID != aID)
  538. {
  539. doUpdatePaymentFields(aID, getPayment(aID), aFields);
  540. }
  541. else if (aForceUpdate)
  542. {
  543. // mOfflinePaymentLock гарантирует что мы попали на запись параметра ДО сохранения оффлайн платежа в БД
  544. // сохраняем параметр в объект, обслуживаемый в оффлайне
  545. doUpdatePaymentFields(aID, mOfflinePayment, aFields, aForceUpdate);
  546. // тут же сохраняем объект в базу напрямую
  547. doUpdatePaymentFields(aID, getPayment(aID), aFields, aForceUpdate);
  548. }
  549. else
  550. {
  551. lock.unlock();
  552. // Создаем команду на обновление поля.
  553. QMutexLocker lock(&mCommandMutex);
  554. auto command = [aID, aFields](PaymentService * aService) -> EPaymentCommandResult::Enum
  555. {
  556. aService->doUpdatePaymentFields(aID, aService->getPayment(aID), aFields);
  557. aService->mPaymentHaveUnsavedParameters.remove(aID);
  558. return EPaymentCommandResult::OK;
  559. };
  560. mCommands << qMakePair(mCommandIndex++, std::function<EPaymentCommandResult::Enum(PaymentService *)>(command));
  561. mPaymentHaveUnsavedParameters.insert(aID);
  562. }
  563. // TODO: убрать возвращаемое значение.
  564. return true;
  565. }
  566. //---------------------------------------------------------------------------
  567. void PaymentService::processPaymentStep(qint64 aPayment, SDK::PaymentProcessor::EPaymentStep::Enum aStep, bool aBlocking)
  568. {
  569. if (aBlocking)
  570. {
  571. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  572. if (!payment)
  573. {
  574. toLog(LogLevel::Error, QString("Payment %1. Failed to perform step.").arg(aPayment));
  575. emit stepCompleted(aPayment, aStep, true);
  576. }
  577. else
  578. {
  579. if (aStep == PPSDK::EPaymentStep::Pay)
  580. {
  581. payment->setCompleteDate(QDateTime::currentDateTime());
  582. }
  583. bool result = payment->performStep(aStep);
  584. savePayment(payment.get());
  585. emit stepCompleted(aPayment, aStep, !result);
  586. }
  587. }
  588. else
  589. {
  590. mActivePaymentSynchronizer.addFuture(QtConcurrent::run(this, &PaymentService::processPaymentStep, aPayment, aStep, true));
  591. }
  592. }
  593. //---------------------------------------------------------------------------
  594. bool PaymentService::convertPayment(qint64 aPayment, const QString & aTargetType)
  595. {
  596. if (mFactoryByType.contains(aTargetType))
  597. {
  598. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  599. if (payment)
  600. {
  601. if (mFactoryByType[aTargetType]->convertPayment(aTargetType, payment.get()))
  602. {
  603. savePayment(payment.get());
  604. if (isPaymentActive(payment))
  605. {
  606. QMutexLocker lock(&mPaymentLock);
  607. // Заменяем активный платёж на новый экземпляр с другим типом процессинга
  608. mActivePayment.reset();
  609. setPaymentActive(getPayment(aPayment));
  610. }
  611. toLog(LogLevel::Normal, QString("Payment %1. Converted to type %2.").arg(aPayment).arg(aTargetType));
  612. return true;
  613. }
  614. }
  615. }
  616. toLog(LogLevel::Error, QString("Payment %1. Failed convert to %2 type.").arg(aPayment).arg(aTargetType));
  617. return false;
  618. }
  619. //---------------------------------------------------------------------------
  620. bool PaymentService::processPayment(qint64 aPayment, bool aOnline)
  621. {
  622. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  623. if (!payment)
  624. {
  625. toLog(LogLevel::Error, QString("Payment %1 not avaible.").arg(aPayment));
  626. return false;
  627. }
  628. // Блокируем проведение платежа с "финальными" статусами
  629. switch (payment->getStatus())
  630. {
  631. case PPSDK::EPaymentStatus::Init:
  632. case PPSDK::EPaymentStatus::ReadyForCheck:
  633. case PPSDK::EPaymentStatus::ProcessError:
  634. break;
  635. case PPSDK::EPaymentStatus::Completed: // А сюда можем попасть досрочно, если обработка платежа происходит в плагине.
  636. return true;
  637. default:
  638. toLog(LogLevel::Normal, QString("Payment %1 has status %2. Process deny.").arg(aPayment).arg(payment->getStatus()));
  639. return false;
  640. }
  641. if (!aOnline)
  642. {
  643. toLog(LogLevel::Normal, QString("Payment %1. Offline mode.").arg(aPayment));
  644. payment->setPriority(PPSDK::IPayment::Offline);
  645. payment->setStatus(PPSDK::EPaymentStatus::ReadyForCheck);
  646. auto stamp = QDateTime::currentDateTime();
  647. payment->setNextTryDate(stamp);
  648. payment->setCompleteDate(stamp);
  649. savePayment(payment.get());
  650. }
  651. else
  652. {
  653. toLog(LogLevel::Normal, QString("Payment %1. Online mode.").arg(aPayment));
  654. processPaymentStep(aPayment, SDK::PaymentProcessor::EPaymentStep::Pay, false);
  655. }
  656. return true;
  657. }
  658. //---------------------------------------------------------------------------
  659. bool PaymentService::cancelPayment(qint64 aPayment)
  660. {
  661. bool result = false;
  662. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  663. if (payment)
  664. {
  665. result = payment->cancel() && savePayment(payment.get());
  666. }
  667. return result;
  668. }
  669. //---------------------------------------------------------------------------
  670. bool PaymentService::stopPayment(qint64 aPayment, int aError, const QString & aErrorMessage)
  671. {
  672. bool result = false;
  673. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  674. if (payment)
  675. {
  676. toLog(LogLevel::Normal, QString("Payment %1. Stopped because of '%2'. Error code:%3.").arg(aPayment).arg(aErrorMessage).arg(aError));
  677. payment->setStatus(PPSDK::EPaymentStatus::BadPayment);
  678. payment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::ServerError, aError, true));
  679. payment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::ErrorMessage, aErrorMessage, true));
  680. result = savePayment(payment.get());
  681. }
  682. return result;
  683. }
  684. //---------------------------------------------------------------------------
  685. bool PaymentService::removePayment(qint64 aPayment)
  686. {
  687. bool result = false;
  688. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  689. if (payment)
  690. {
  691. result = payment->remove() && savePayment(payment.get());
  692. }
  693. return result;
  694. }
  695. //---------------------------------------------------------------------------
  696. bool PaymentService::canProcessPaymentOffline(qint64 aPayment)
  697. {
  698. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  699. if (payment)
  700. {
  701. return payment->canProcessOffline();
  702. }
  703. return false;
  704. }
  705. //---------------------------------------------------------------------------
  706. void PaymentService::hangupProcessing()
  707. {
  708. QMetaObject::invokeMethod(this, "onProcessPayments", Qt::QueuedConnection);
  709. }
  710. //---------------------------------------------------------------------------
  711. void PaymentService::doUpdatePaymentFields(quint64 aID, std::shared_ptr<PPSDK::IPayment> aPayment, const QList<SDK::PaymentProcessor::IPayment::SParameter> & aFields, bool aForce)
  712. {
  713. if (!aPayment)
  714. {
  715. toLog(LogLevel::Error, QString("Payment %1. Failed to update parameters.").arg(aID));
  716. return;
  717. }
  718. foreach (const PPSDK::IPayment::SParameter & parameter, aFields)
  719. {
  720. toLog(LogLevel::Normal, QString("Payment %1. %2pdating parameter: name '%3', value '%4'.")
  721. .arg(aID)
  722. .arg(aForce ? "Force u" : "U")
  723. .arg(parameter.name)
  724. .arg(parameter.crypted ? "** CRYPTED **" : parameter.value.toString()));
  725. if ((parameter.name == PPSDK::CPayment::Parameters::Amount) ||
  726. (parameter.name == PPSDK::CPayment::Parameters::AmountAll) ||
  727. (parameter.name == PPSDK::CPayment::Parameters::Change) ||
  728. (parameter.name == PPSDK::CPayment::Parameters::Fee) ||
  729. (parameter.name == PPSDK::CPayment::Parameters::ID))
  730. {
  731. toLog(LogLevel::Error, QString("Payment %1. Cannot update money related field manually.").arg(aID));
  732. continue;
  733. }
  734. aPayment->setParameter(parameter);
  735. }
  736. if (!savePayment(aPayment.get()))
  737. {
  738. toLog(LogLevel::Error, QString("Payment %1. Failed to save updated payment.").arg(aID));
  739. }
  740. }
  741. //---------------------------------------------------------------------------
  742. void PaymentService::onAmountUpdated(qint64 aPayment, double /*aTotalAmount*/, double aAmount)
  743. {
  744. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  745. if (payment)
  746. {
  747. // Обновляем информацию о внесённых средствах, платёж должен пересчитать суммы, включая сдачу.
  748. double amountAll = payment->getParameter(PPSDK::CPayment::Parameters::AmountAll).value.toDouble() +
  749. payment->getParameter(PPSDK::CPayment::Parameters::Change).value.toDouble() +
  750. aAmount;
  751. payment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::AmountAll, QString::number(amountAll, 'f', 2), true));
  752. if (!savePayment(payment.get()))
  753. {
  754. QString msg = QString("Payment [%1] error write to database; AMOUNT_ALL=%2;").arg(payment->getInitialSession()).arg(amountAll, 0, 'f', 2);
  755. mApplication->getCore()->getTerminalService()->sendFeedback(CServices::PaymentService, msg);
  756. }
  757. // Получаем изменение сдачи.
  758. double change = payment->getParameter(PPSDK::CPayment::Parameters::Change).value.toDouble();
  759. // Если сдача не 0, сохраняем.
  760. if (!qFuzzyIsNull(change))
  761. {
  762. setChangeAmount(change, payment);
  763. }
  764. emit amountUpdated(aPayment);
  765. }
  766. }
  767. //---------------------------------------------------------------------------
  768. void PaymentService::onAmountDispensed(double aAmount)
  769. {
  770. if (qFuzzyIsNull(aAmount))
  771. {
  772. toLog(LogLevel::Warning, QString("Dispensed zero summ %1.").arg(aAmount, 0, 'f', 2));
  773. return;
  774. }
  775. if (mChangePayment)
  776. {
  777. double amountAll = mChangePayment->getParameter(PPSDK::CPayment::Parameters::AmountAll).value.toDouble();
  778. if (amountAll >= aAmount)
  779. {
  780. setChangeAmount(amountAll - aAmount, mActivePayment);
  781. toLog(LogLevel::Normal, QString("Dispensed %1. Change %2").arg(aAmount, 0, 'f', 2).arg(amountAll - aAmount, 0, 'f', 2));
  782. }
  783. else
  784. {
  785. // Выдали денег больше чем есть в сдаче
  786. toLog(LogLevel::Fatal, QString("Dispensed %1, but change payment contain only %2.").arg(aAmount, 0, 'f', 2).arg(amountAll, 0, 'f', 2));
  787. setChangeAmount(0, mActivePayment);
  788. }
  789. }
  790. else
  791. {
  792. // Ругаемся, т.к. выдали денег, а сдачи реально нет.
  793. toLog(LogLevel::Error, QString("Dispensed %1, but change payment is NULL.").arg(aAmount, 0, 'f', 2));
  794. }
  795. }
  796. //---------------------------------------------------------------------------
  797. void PaymentService::onPaymentThreadStarted()
  798. {
  799. mPaymentTimer.start(CPaymentService::ProcessOfflineTimeout);
  800. }
  801. //---------------------------------------------------------------------------
  802. bool PaymentService::processPaymentInternal(std::shared_ptr<PPSDK::IPayment> aPayment)
  803. {
  804. // Пропускаем платежи с неизрасходованной сдачей.
  805. if (mChangePayment && (mChangePayment->getID() == aPayment->getID()))
  806. {
  807. mDBUtils->suspendPayment(aPayment->getID(), 15);
  808. return false;
  809. }
  810. // Пропускаем платёж, если он активен.
  811. if (isPaymentActive(aPayment) && (aPayment->getPriority() == PPSDK::IPayment::Online))
  812. {
  813. mDBUtils->suspendPayment(aPayment->getID(), 15);
  814. return false;
  815. }
  816. // Платеж можно удалить только в том случае, если в нем нет денег и купюр/монет
  817. if (aPayment->isNull() && getPaymentNotes(aPayment->getID()).empty())
  818. {
  819. toLog(LogLevel::Normal, QString("Payment %1. Is null.").arg(aPayment->getID()));
  820. mDBUtils->removePayment(aPayment->getID());
  821. return false;
  822. }
  823. // Запоминаем id платежа, находяшегося в обработке.
  824. {
  825. QMutexLocker lock(&mOfflinePaymentLock);
  826. mOfflinePaymentID = aPayment->getID();
  827. mOfflinePayment = aPayment;
  828. }
  829. // Проверка на неиспользованный остаток
  830. if ((aPayment->getStatus() == PPSDK::EPaymentStatus::Init) && !aPayment->getParameter(CPaymentService::ChangePaymentParam).isNull())
  831. {
  832. aPayment->setStatus(PPSDK::EPaymentStatus::LostChange);
  833. }
  834. if (aPayment->canProcessOffline())
  835. {
  836. aPayment->setPriority(PPSDK::IPayment::Offline);
  837. aPayment->process();
  838. }
  839. else
  840. {
  841. toLog(LogLevel::Normal, QString("Payment %1. Online payment can't process with offline mode.").arg(aPayment->getID()));
  842. if (aPayment->getStatus() == PPSDK::EPaymentStatus::ProcessError)
  843. {
  844. aPayment->setStatus(PPSDK::EPaymentStatus::BadPayment);
  845. }
  846. else if (aPayment->getCreationDate().msecsTo(QDateTime::currentDateTime()) > CPaymentService::OnlinePaymentOvertime)
  847. {
  848. aPayment->setStatus(PPSDK::EPaymentStatus::BadPayment);
  849. }
  850. else
  851. {
  852. toLog(LogLevel::Warning, QString("Suspending online payment %1.").arg(aPayment->getID()));
  853. aPayment->setNextTryDate(QDateTime::currentDateTime().addSecs(5 * 60)); // 5min
  854. }
  855. }
  856. // Отпускаем платеж.
  857. {
  858. QMutexLocker lock(&mOfflinePaymentLock);
  859. mOfflinePaymentID = -1;
  860. mOfflinePayment.reset();
  861. // Сохраняем платёж внутри защищенного блока для избежания записи параметров оfflline платежа
  862. savePayment(aPayment.get());
  863. }
  864. /// сообщаем об окончании процесса обработки платежа
  865. emit stepCompleted(aPayment->getID(), SDK::PaymentProcessor::EPaymentStep::Pay, aPayment->getStatus() != PPSDK::EPaymentStatus::Completed);
  866. return (aPayment->getStatus() == PPSDK::EPaymentStatus::Completed);
  867. }
  868. //---------------------------------------------------------------------------
  869. void PaymentService::onProcessPayments()
  870. {
  871. // Выгружаем старые платежи раз в день.
  872. if (mLastBackupDate.addDays(1) <= QDateTime::currentDateTime())
  873. {
  874. mDBUtils->backupOldPayments();
  875. mLastBackupDate = QDateTime::currentDateTime();
  876. }
  877. // Блокируем offline проведение платежей до установления связи
  878. if (!mApplication->getCore()->getNetworkService()->isConnected(true))
  879. {
  880. toLog(LogLevel::Warning, "Waiting network connection for payment processing.");
  881. mPaymentTimer.start(CPaymentService::CheckNetworkConnectionTimeout);
  882. return;
  883. }
  884. QList<qint64> payments = mDBUtils->getPaymentQueue();
  885. if (payments.size())
  886. {
  887. qint64 id = payments.takeFirst();
  888. if (mEnabled)
  889. {
  890. std::shared_ptr<PPSDK::IPayment> payment(getPayment(id));
  891. // Если платеж не прогрузился, останавливаем его обработку на 15 минут.
  892. if (!payment)
  893. {
  894. toLog(LogLevel::Warning, QString("Suspending bad payment %1.").arg(id));
  895. mDBUtils->suspendPayment(id, 15);
  896. }
  897. else
  898. {
  899. processPaymentInternal(payment);
  900. }
  901. }
  902. }
  903. QMutexLocker lock(&mCommandMutex);
  904. // Обрабатываем очередь команд.
  905. foreach (auto & command, mCommands)
  906. {
  907. emit paymentCommandComplete(command.first, command.second(this));
  908. }
  909. mCommands.clear();
  910. mPaymentTimer.start(CPaymentService::ProcessOfflineTimeout);
  911. }
  912. //---------------------------------------------------------------------------
  913. int PaymentService::registerForcePaymentCommand(const QString & aInitialSession, const QVariantMap & aParameters)
  914. {
  915. QMutexLocker lock(&mCommandMutex);
  916. auto command = [aInitialSession, aParameters](PaymentService * aService) -> EPaymentCommandResult::Enum
  917. {
  918. if (!aService->mEnabled)
  919. {
  920. return EPaymentCommandResult::Error;
  921. }
  922. auto payment = aService->getPayment(aInitialSession);
  923. if (!payment)
  924. {
  925. return EPaymentCommandResult::NotFound;
  926. }
  927. foreach (const QString & parameter, aParameters.keys())
  928. {
  929. // берем значения атрибутов crypted и external у предыдущего значения параметра
  930. auto oldParameter = payment->getParameter(parameter);
  931. payment->setParameter(PPSDK::IPayment::SParameter(parameter, aParameters.value(parameter), true, oldParameter.crypted, oldParameter.external));
  932. }
  933. payment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::NumberOfTries, 1, true));
  934. payment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::NextTryDate, QDateTime::currentDateTime(), true));
  935. payment->setStatus(PPSDK::EPaymentStatus::ProcessError);
  936. return aService->processPaymentInternal(payment) ? EPaymentCommandResult::OK : EPaymentCommandResult::Error;
  937. };
  938. mCommands << qMakePair(mCommandIndex++, std::function<EPaymentCommandResult::Enum(PaymentService *)>(command));
  939. auto parametersToString = [aParameters]() -> QString
  940. {
  941. QStringList list;
  942. foreach (const QString & parameter, aParameters.keys())
  943. {
  944. list << QString("%1=%2").arg(parameter).arg(aParameters.value(parameter).toString());
  945. }
  946. return list.join(";");
  947. };
  948. toLog(LogLevel::Normal, QString("Register command 'process payment %1'. Internal command id: %2. Parameters: %3")
  949. .arg(aInitialSession).arg(mCommandIndex).arg(parametersToString()));
  950. return mCommands.last().first;
  951. }
  952. //---------------------------------------------------------------------------
  953. int PaymentService::registerRemovePaymentCommand(const QString & aInitialSession)
  954. {
  955. QMutexLocker lock(&mCommandMutex);
  956. auto command = [aInitialSession](PaymentService * aService) -> EPaymentCommandResult::Enum
  957. {
  958. qint64 id = aService->mDBUtils->getPaymentByInitialSession(aInitialSession);
  959. if (id < 0)
  960. {
  961. return EPaymentCommandResult::NotFound;
  962. }
  963. return aService->removePayment(id) ? EPaymentCommandResult::OK : EPaymentCommandResult::Error;
  964. };
  965. mCommands << qMakePair(mCommandIndex++, std::function<EPaymentCommandResult::Enum(PaymentService *)>(command));
  966. toLog(LogLevel::Normal, QString("Register command 'remove payment %1'. Internal command id: %2.").arg(aInitialSession).arg(mCommandIndex));
  967. return mCommands.last().first;
  968. }
  969. //---------------------------------------------------------------------------
  970. PPSDK::SBalance PaymentService::getBalance()
  971. {
  972. return mDBUtils->getBalance();
  973. }
  974. //---------------------------------------------------------------------------
  975. PPSDK::EncashmentResult::Enum PaymentService::performEncashment(const QVariantMap & aParameters, PPSDK::SEncashment & aEncashment)
  976. {
  977. PPSDK::SBalance balance = mDBUtils->getBalance();
  978. {
  979. QMutexLocker lock(&mCommandMutex);
  980. // не можем выполнить инкассацию в случае несохраненных в БД данных
  981. if (!balance.notPrintedPayments.intersect(mPaymentHaveUnsavedParameters).isEmpty())
  982. {
  983. return PPSDK::EncashmentResult::TryLater;
  984. }
  985. }
  986. aEncashment = mDBUtils->performEncashment(aParameters);
  987. return aEncashment.isValid() ? PPSDK::EncashmentResult::OK : PPSDK::EncashmentResult::Error;
  988. }
  989. //---------------------------------------------------------------------------
  990. PPSDK::SEncashment PaymentService::getLastEncashment()
  991. {
  992. auto encashments = mDBUtils->getLastEncashments(1);
  993. return encashments.isEmpty() ? PPSDK::SEncashment() : encashments.at(0);
  994. }
  995. //---------------------------------------------------------------------------
  996. QList<PPSDK::SEncashment> PaymentService::getEncashmentList(int aDepth)
  997. {
  998. return mDBUtils->getLastEncashments(aDepth);
  999. }
  1000. //---------------------------------------------------------------------------
  1001. double PaymentService::getChangeAmount()
  1002. {
  1003. if (mChangePayment)
  1004. {
  1005. return mChangePayment->getParameter(PPSDK::CPayment::Parameters::AmountAll).value.toDouble();
  1006. }
  1007. return 0.0;
  1008. }
  1009. //---------------------------------------------------------------------------
  1010. void PaymentService::moveChangeToPayment(qint64 aPayment)
  1011. {
  1012. if (mChangePayment)
  1013. {
  1014. double change = getChangeAmount();
  1015. if (!qFuzzyIsNull(change))
  1016. {
  1017. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  1018. if (payment)
  1019. {
  1020. toLog(LogLevel::Normal, QString("Payment %1. Using change: %2.").arg(aPayment).arg(change, 0, 'f', 2));
  1021. double amountAll = payment->getParameter(PPSDK::CPayment::Parameters::AmountAll).value.toDouble() + change;
  1022. payment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::AmountAll, QString::number(amountAll, 'f', 2), true, false));
  1023. mChangePayment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::AmountAll, payment->getParameter(PPSDK::CPayment::Parameters::Change).value, true));
  1024. // Использовал мошенническую сдачу - сам мошенник
  1025. auto originalPayment = getPayment(getChangeSessionRef());
  1026. auto cheatedParameter = (originalPayment ? originalPayment : mChangePayment)->getParameter(PPSDK::CPayment::Parameters::Cheated);
  1027. if (!cheatedParameter.isNull())
  1028. {
  1029. cheatedParameter.updated = true;
  1030. payment->setParameter(cheatedParameter);
  1031. }
  1032. savePayment(mChangePayment.get());
  1033. savePayment(payment.get());
  1034. double newChange = payment->getParameter(PPSDK::CPayment::Parameters::Change).value.toDouble();
  1035. toLog(LogLevel::Normal, QString("Payment %1. Updating change: %2.").arg(aPayment).arg(newChange, 0, 'f', 2));
  1036. emit amountUpdated(aPayment);
  1037. emit changeUpdated(newChange);
  1038. }
  1039. }
  1040. }
  1041. }
  1042. //---------------------------------------------------------------------------
  1043. void PaymentService::movePaymentToChange(qint64 aPayment)
  1044. {
  1045. std::shared_ptr<PPSDK::IPayment> payment(getPayment(aPayment));
  1046. if (payment)
  1047. {
  1048. double change = getChangeAmount() + payment->getParameter(PPSDK::CPayment::Parameters::AmountAll).value.toDouble();
  1049. if (!qFuzzyIsNull(change))
  1050. {
  1051. if (setChangeAmount(change, payment))
  1052. {
  1053. toLog(LogLevel::Normal, QString("Payment %1. Move amount to change: %2.").arg(aPayment).arg(change, 0, 'f', 2));
  1054. payment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::AmountAll, QString::number(0.00, 'f', 2), true, false));
  1055. savePayment(payment.get());
  1056. }
  1057. }
  1058. }
  1059. }
  1060. //---------------------------------------------------------------------------
  1061. void PaymentService::resetChange()
  1062. {
  1063. // Если есть активный платёж со сдачей, отправляем его на мониторинг и создаём новый.
  1064. if (mChangePayment)
  1065. {
  1066. bool remove = qFuzzyIsNull(getChangeAmount());
  1067. qint64 changePaymentID = mChangePayment->getID();
  1068. auto originalPayment = getPayment(getChangeSessionRef());
  1069. auto cheatedParameter = (originalPayment ? originalPayment : mChangePayment)->getParameter(PPSDK::CPayment::Parameters::Cheated);
  1070. toLog(LogLevel::Normal, QString("Payment %1. Reset %3 change amount: %2.")
  1071. .arg(changePaymentID).arg(getChangeAmount(), 0, 'f', 2)
  1072. .arg(cheatedParameter.isNull() ? "" : "CHEATED"));
  1073. // Если есть платёж "сдача" с нулевой суммой, то не оставляем его в БД "как есть", а помечаем как удалённый.
  1074. mChangePayment->setStatus(remove ? PPSDK::EPaymentStatus::Deleted : PPSDK::EPaymentStatus::LostChange);
  1075. savePayment(mChangePayment.get());
  1076. mChangePayment.reset();
  1077. if (remove)
  1078. {
  1079. mDBUtils->removePayment(changePaymentID);
  1080. }
  1081. }
  1082. emit changeUpdated(0.0);
  1083. }
  1084. //---------------------------------------------------------------------------
  1085. QString PaymentService::getChangeSessionRef()
  1086. {
  1087. if (mChangePayment)
  1088. {
  1089. return mChangePayment->getParameter(PPSDK::CPayment::Parameters::OriginalPayment).value.toString().split(PPSDK::CPayment::Parameters::ProviderFieldsDelimiter).takeFirst();
  1090. }
  1091. return QString();
  1092. }
  1093. //---------------------------------------------------------------------------
  1094. bool PaymentService::setChangeAmount(double aChange, std::shared_ptr<PPSDK::IPayment> aPaymentSource)
  1095. {
  1096. if (!mChangePayment)
  1097. {
  1098. if (mFactoryByType.contains(CPaymentService::ChangePaymentType))
  1099. {
  1100. mChangePayment = std::shared_ptr<PPSDK::IPayment>(mFactoryByType[CPaymentService::ChangePaymentType]->createPayment(CPaymentService::ChangePaymentType),
  1101. std::bind(&PPSDK::IPaymentFactory::releasePayment, mFactoryByType[CPaymentService::ChangePaymentType], _1));
  1102. if (mChangePayment)
  1103. {
  1104. QList<PPSDK::IPayment::SParameter> parameters;
  1105. parameters
  1106. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::ID, mDBUtils->createDummyPayment(), true)
  1107. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::CreationDate, QDateTime::currentDateTime(), true)
  1108. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::Type, CPaymentService::ChangePaymentType, true)
  1109. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::Provider, -1, true)
  1110. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::Status, PPSDK::EPaymentStatus::Init, true)
  1111. << PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::Priority, PPSDK::IPayment::Offline, true)
  1112. << PPSDK::IPayment::SParameter(CPaymentService::ChangePaymentParam, 1, true);
  1113. if (!mChangePayment->restore(parameters))
  1114. {
  1115. toLog(LogLevel::Error, "Failed to register storage for the change.");
  1116. mChangePayment.reset();
  1117. return false;
  1118. }
  1119. }
  1120. else
  1121. {
  1122. toLog(LogLevel::Error, "Failed to create storage for the change.");
  1123. return false;
  1124. }
  1125. }
  1126. else
  1127. {
  1128. toLog(LogLevel::Error, "Failed to create storage for the change. Required plugin is missing.");
  1129. return false;
  1130. }
  1131. }
  1132. // В сдачу засовываем все данные из родительского платежа
  1133. if (aPaymentSource)
  1134. {
  1135. QMutexLocker lock(&mPaymentLock);
  1136. QStringList paramValues(aPaymentSource->getParameter(PPSDK::CPayment::Parameters::InitialSession).value.toString());
  1137. foreach (auto param, aPaymentSource->getParameter(PPSDK::CPayment::Parameters::ProviderFields).value.toString()
  1138. .split(PPSDK::CPayment::Parameters::ProviderFieldsDelimiter, QString::SkipEmptyParts))
  1139. {
  1140. paramValues << aPaymentSource->getParameter(param).value.toString();
  1141. }
  1142. // Если платеж с подозрением на мошенничество, сдача тоже мошенническая
  1143. auto cheatedParameter = aPaymentSource->getParameter(PPSDK::CPayment::Parameters::Cheated);
  1144. if (!cheatedParameter.isNull())
  1145. {
  1146. cheatedParameter.updated = true;
  1147. mChangePayment->setParameter(cheatedParameter);
  1148. }
  1149. mChangePayment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::OriginalPayment,
  1150. paramValues.join(PPSDK::CPayment::Parameters::ProviderFieldsDelimiter), true));
  1151. mChangePayment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::ProviderFields,
  1152. PPSDK::CPayment::Parameters::OriginalPayment, true));
  1153. }
  1154. mChangePayment->setParameter(PPSDK::IPayment::SParameter(PPSDK::CPayment::Parameters::AmountAll, QString::number(aChange, 'f', 2), true));
  1155. toLog(LogLevel::Normal, QString("Payment %1. Change: %2.").arg(getActivePayment()).arg(aChange, 0, 'f', 2));
  1156. emit changeUpdated(aChange);
  1157. return savePayment(mChangePayment.get());
  1158. }
  1159. //---------------------------------------------------------------------------
  1160. QList<PPSDK::SNote> PaymentService::getPaymentNotes(qint64 aID) const
  1161. {
  1162. return mDBUtils->getPaymentNotes(aID);
  1163. }
  1164. //---------------------------------------------------------------------------
  1165. QList<qint64> PaymentService::getPayments(const QSet<PPSDK::EPaymentStatus::Enum> & aStates)
  1166. {
  1167. return mDBUtils->getPayments(aStates);
  1168. }
  1169. //---------------------------------------------------------------------------
  1170. QList<qint64> PaymentService::findPayments(const QDate & aDate, const QString & aPhoneNumber)
  1171. {
  1172. return mDBUtils->findPayments(aDate, aPhoneNumber);
  1173. }
  1174. //------------------------------------------------------------------------------
  1175. QMap<qint64, quint32> PaymentService::getStatistic() const
  1176. {
  1177. return mDBUtils->getStatistic();
  1178. }
  1179. //------------------------------------------------------------------------------