diff --git a/android/rshb/CommonScript.cpp b/android/rshb/CommonScript.cpp index 5118bbe..09791f2 100644 --- a/android/rshb/CommonScript.cpp +++ b/android/rshb/CommonScript.cpp @@ -190,14 +190,20 @@ bool CommonScript::goToAllProducts( return false; } -bool CommonScript::readTransactionData() { +bool CommonScript::findAndTapOnAccount(const QString &deviceId, const QString &accountNumbers) { + QList > accounts = xmlScreenParser.parseAccountsInfo(); + for (auto &[account, node]: accounts) { + // FIXME будем считать что числа последние везде уникальные + if (accountNumbers == account.lastNumbers) { + qDebug() << "findAndTapOnAccount: " << accountNumbers; + AdbUtils::makeTap(deviceId, node.x(), node.y()); + QThread::msleep(1000); + return true; + } + } return false; } -// 1. топаем на домашнюю -// 2. распарсить мои карты и вернуть данные -// 3. синхронизировать историю транзакций (с домашней) - void CommonScript::stop() { m_running = false; diff --git a/android/rshb/CommonScript.h b/android/rshb/CommonScript.h index 4e73aea..9982bc6 100644 --- a/android/rshb/CommonScript.h +++ b/android/rshb/CommonScript.h @@ -23,6 +23,8 @@ protected: int height ); + bool findAndTapOnAccount(const QString &deviceId, const QString &accountNumbers); + Node swipeToButton( const QString &deviceId, const QString &text, @@ -41,14 +43,13 @@ protected: const QString &deviceId, int width, int height ); - bool readTransactionData(); - bool m_running = true; ScreenXmlParser xmlScreenParser; int m_counter = 0; signals: void finished(); + void finishedWithResult(const QString &result); public slots: virtual void start() final; diff --git a/android/rshb/GetLastDaysHistoryScript.cpp b/android/rshb/GetLastDaysHistoryScript.cpp index ac4e930..e639950 100644 --- a/android/rshb/GetLastDaysHistoryScript.cpp +++ b/android/rshb/GetLastDaysHistoryScript.cpp @@ -2,16 +2,13 @@ #include #include -#include #include #include "DatabaseManager.h" #include "adb/AdbUtils.h" #include "dao/AccountDAO.h" -#include "dao/ApplicationDAO.h" #include "dao/DeviceDAO.h" #include "dao/TransactionDAO.h" -#include "db/ApplicationInfo.h" #include "db/DeviceInfo.h" #include "time/DateUtils.h" @@ -33,11 +30,19 @@ QList findSavedTransaction( for (const TransactionInfo &info: transactions) { QDateTime timestamp = info.timestamp; + QString shortDescription = parsed.shortDescription; // если тот же день if (dateTime.date() == timestamp.date() && parsed.amount == info.amount) { // Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815... - if (parsed.shortDescription.contains(info.name)) { - txs.append(info); + if (shortDescription.contains("Перевод")) { + if (shortDescription.contains(info.name)) { + txs.append(info); + } + } else { + // Перевод по карте + if (shortDescription == info.shortDescription) { + txs.append(info); + } } } } @@ -45,16 +50,16 @@ QList findSavedTransaction( return txs; } -bool isSingle(const TransactionInfo &transaction, const QList &transactions) { +int countSimilar(const TransactionInfo &transaction, const QList &transactions) { int count = 0; for (const TransactionInfo &info: transactions) { if (info.amount == transaction.amount && info.shortDescription == transaction.shortDescription && info.bankTime == transaction.bankTime) { - count++; + ++count; } } - return count == 1; + return count; } QString formatPrice(const double value) { @@ -141,16 +146,7 @@ void GetLastDaysHistoryScript::doStart() { if (xmlScreenParser.isHomeScreen()) { // парсим все транзакции if (goToAllProducts(device.id, device.screenWidth, device.screenHeight)) { - QList > accounts = xmlScreenParser.parseAccountsInfo(); - for (auto &[account, node]: accounts) { - // FIXME будем считать что числа последние везде уникальные - if (m_account.lastNumbers == account.lastNumbers) { - qDebug() << "Tap by card"; - AdbUtils::makeTap(device.id, node.x(), node.y()); - QThread::msleep(1000); - break; - } - } + findAndTapOnAccount(device.id, m_account.lastNumbers); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); Node filterBtn = xmlScreenParser.findButtonNode("РСХБ Онлайн", false); @@ -185,52 +181,55 @@ void GetLastDaysHistoryScript::doStart() { qDebug() << "--- parsedTransactions: " << parsedTransactions.length(); // localTransactions + QList updatedTransactions; for (TransactionInfo &transaction: parsedTransactions) { // если shortDescription + сумма + день и Complete совпадает и одна - bool single = isSingle(transaction, parsedTransactions); + int cSimilar = countSimilar(transaction, parsedTransactions); QList txs = findSavedTransaction(localTransactions, transaction); - if (single && txs.length() < 2) { + if (cSimilar == 1 && txs.length() < 2) { if (txs.length() == 1) { // смотрим, надо ли обновление if (txs[0].status != TransactionStatus::Complete || txs[0].shortDescription.isEmpty()) { txs[0].shortDescription = transaction.shortDescription; openAndSaveDitailInfo(txs[0], device.screenWidth, device.screenHeight); + updatedTransactions.append(txs[0]); } } else { // создаем новую openAndSaveDitailInfo(transaction, device.screenWidth, device.screenHeight); } } else { - // в списке за день нашли более чем 1 одинаковых транзакций - // FIXME - что то делать если две одинаковые - } - - - - if (txs.length() == 1) { - qDebug() << "--- one transaction with same amount"; - qDebug().noquote().nospace() << convertTransactionToString(transaction); - - if (transaction.status == TransactionStatus::Complete && !transaction.shortDescription.isEmpty()) { - continue; + if (cSimilar == txs.length()) { + // одинаковые транзакции (2 - 2) + for (TransactionInfo &tx: txs) { + if (!updatedTransactions.contains(tx)) { + openAndSaveDitailInfo(tx, device.screenWidth, device.screenHeight); + updatedTransactions.append(tx); + break; + } + } + } else if (cSimilar < txs.length()) { + // Дубликаты транзакций или название изменилось (1 - 2) + qDebug() << "--- Дубликаты транзакций или название изменилось (1 - 2)!!!!!!!!!!!!"; + // FIXME alert!!! + } else { + // нужно создать новую транзакцию, которой не было (2 - 1) + bool updated = false; + for (TransactionInfo &tx: txs) { + if (!updatedTransactions.contains(tx)) { + openAndSaveDitailInfo(tx, device.screenWidth, device.screenHeight); + updatedTransactions.append(tx); + updated = true; + break; + } + } + if (!updated) { + // создаем новую, так как у нас появилась одинаковая транзакция + openAndSaveDitailInfo(transaction, device.screenWidth, device.screenHeight); + } } - // посмотреть подробности и обновить статус и описание - } else if (txs.length() > 1) { - // FIXME - что то делать если две одинаковые - // Alert !!! - qDebug() << "--- two transactions with same amount"; - } else { - // Создаем новую, так как не найдено в БД - qDebug() << "--- new transaction"; - qDebug().noquote().nospace() << convertTransactionToString(transaction); - - // посмотреть подробности и создать } - // qDebug() << transaction.amount; - // qDebug() << transaction.shortDescription; - // qDebug().noquote().nospace() << convertTransactionToString(transaction); - // TODO вот мы дошли до списка транзакций xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); } diff --git a/android/rshb/PayByPhoneScript.cpp b/android/rshb/PayByPhoneScript.cpp index 0ae0210..d0e8be6 100644 --- a/android/rshb/PayByPhoneScript.cpp +++ b/android/rshb/PayByPhoneScript.cpp @@ -40,7 +40,9 @@ void PayByPhoneScript::makePayment( AdbUtils::makeTap(deviceId, payBtn.x(), payBtn.y()); QThread::msleep(1000); } else { - qWarning() << "--- payBtn not found"; + m_error = "Кнопка 'Оплатить' не нашлась"; + qDebug() << m_error; + return; } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); @@ -52,10 +54,14 @@ void PayByPhoneScript::makePayment( AdbUtils::makeTap(deviceId, payByPhoneBtn.x(), payByPhoneBtn.y()); QThread::msleep(1000); } else { - qWarning() << "--- payByPhoneBtn not found"; + m_error = "Не смогли найти пункт 'По номеру телефона В РСХБ и через'"; + qDebug() << m_error; + return; } } else { - qWarning() << "--- payTitle not found"; + m_error = "Не смогли перейти на экран 'Платежи и переводы'"; + qDebug() << m_error; + return; } @@ -69,7 +75,9 @@ void PayByPhoneScript::makePayment( AdbUtils::inputText(deviceId, m_phone); QThread::msleep(1000); } else { - qWarning() << "--- payByPhoneTitle not found (no continueBtn)"; + m_error = "Не смогли найти пункт 'Перевод по телефону'"; + qDebug() << m_error; + return; } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); @@ -80,7 +88,9 @@ void PayByPhoneScript::makePayment( AdbUtils::makeTap(deviceId, payOtherBankBtn.x(), payOtherBankBtn.y()); QThread::msleep(1000); } else { - qWarning() << "--- payOtherBankBtn not found"; + m_error = "Не смогли нажать на первичный выбор банка"; + qDebug() << m_error; + return; } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); @@ -96,7 +106,7 @@ void PayByPhoneScript::makePayment( QThread::msleep(1000); break; } else { - qWarning() << "--- allBanksTitle not found, i: " << i; + qDebug() << "--- allBanksTitle not found, i: " << i; } QThread::msleep(1000); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); @@ -110,7 +120,7 @@ void PayByPhoneScript::makePayment( QThread::msleep(1000); break; } else { - qWarning() << "--- bankNameListItem not found, i: " << i; + qDebug() << "--- bankNameListItem not found, i: " << i; } QThread::msleep(1000); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); @@ -136,16 +146,23 @@ void PayByPhoneScript::makePayment( AdbUtils::makeTap(deviceId, continuePayBtn.x(), continuePayBtn.y()); QThread::msleep(1000); } else { - qWarning() << "--- readyBtn not found"; + m_error = "Не смогли нажать 'Готово'"; + qDebug() << m_error; + return; } } else { - qWarning() << "--- sumBtn not found"; + m_error = "Не смогли нажать 'Продолжить'"; + qDebug() << m_error; + return; } } else { - qWarning() << "--- payByPhoneScreenTitle not found"; + m_error = "Не смогли найти 'Перевод по телефону'"; + qDebug() << m_error; + return; } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); + bool inputedPinCode = false; for (int i = 0; i < 5; ++i) { // TODO кнопка содержит "Перевести 10 ₽" если будет от 1000 то скорее всвего будет "Перевести 1 000 ₽", // TODO не ясно как форматирование будет, поэтому пока на начало зашьем @@ -158,6 +175,7 @@ void PayByPhoneScript::makePayment( if (const QList pincode = xmlScreenParser.tryToFindPinCode(pinCode, "Введите код доступа"); pincode.size() == 4) { inputPinCode(deviceId, pincode); + inputedPinCode = true; // После ввода пин-кода, ждем 3с QThread::msleep(3000); } @@ -169,9 +187,14 @@ void PayByPhoneScript::makePayment( xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); } + if (!inputedPinCode) { + m_error = "Не смогли ввести пин-код!'"; + qDebug() << m_error; + return; + } + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); - bool isPaymentCompleted = false; for (int i = 0; i < 10; ++i) { Node moreDetailBtn = xmlScreenParser.findButtonNode("Детали операции", false); if (!moreDetailBtn.isEmpty()) { @@ -194,7 +217,6 @@ void PayByPhoneScript::makePayment( for (int k = 0; k < 10; ++k) { Node paymentCompleted = xmlScreenParser.findTextNode("Исполнен", 0, 0, width, height / 2); if (!paymentCompleted.isEmpty()) { - isPaymentCompleted = true; if (!TransactionDAO::updateTransactionStatus(transaction.id, TransactionStatus::Complete)) { qDebug() << "Not updated: " << transaction.id; } @@ -215,9 +237,7 @@ void PayByPhoneScript::makePayment( Node homeBtn = xmlScreenParser.findButtonNode("Вернуться на главную", false); AdbUtils::makeTap(deviceId, homeBtn.x(), homeBtn.y()); - if (!isPaymentCompleted) { - qDebug() << "--- payment not completed"; - } + QThread::msleep(1000); } void PayByPhoneScript::doStart() { @@ -253,9 +273,13 @@ void PayByPhoneScript::doStart() { qDebug() << "======== 3. Make payment"; makePayment(device.id, app.pinCode, device.screenWidth, device.screenHeight); } else { - qDebug() << "Не смогли открыть 'Все продукты'"; + m_error = "Не смогли открыть 'Все продукты'"; + qDebug() << m_error; } } else { - qDebug() << "Не смогли дойти до домашней страницы...."; + m_error = "Не смогли дойти до домашней страницы...."; + qDebug() << m_error; } + + emit finishedWithResult(m_error); } diff --git a/android/rshb/PayByPhoneScript.h b/android/rshb/PayByPhoneScript.h index 6a9f878..e114725 100644 --- a/android/rshb/PayByPhoneScript.h +++ b/android/rshb/PayByPhoneScript.h @@ -23,6 +23,7 @@ private: const QString m_phone; const QString m_bankName; const double m_amount; + QString m_error; void makePayment( const QString &deviceId, diff --git a/main.cpp b/main.cpp index cbbb90e..2c83275 100644 --- a/main.cpp +++ b/main.cpp @@ -56,24 +56,53 @@ void setupScriptAutoPaymentAndThread(QCoreApplication &app) { const QString phoneNumber = "79641815146"; const QString bankName = "Альфа-Банк"; // const QString bankName = "Сбербанк"; - const double ammount = 310; + const double amount = 310; AccountInfo account = AccountDAO::findAppAccount(appName, cardNumber); if (account.id != -1) { - auto *thread = new QThread; - auto *scriptWorker = new GetLastDaysHistoryScript(account); - // auto *scriptWorker = new PayByPhoneScript(account, phoneNumber, bankName, ammount); + // Функция для подключения потоков к завершению приложения + auto connectStopOnQuit = [&](QObject *worker, QThread *thread) { + QObject::connect(&app, &QCoreApplication::aboutToQuit, worker, &QObject::deleteLater); + QObject::connect(&app, &QCoreApplication::aboutToQuit, thread, &QThread::quit); + QObject::connect(&app, &QCoreApplication::aboutToQuit, thread, &QThread::deleteLater); + }; + // Первый поток + auto *thread = new QThread; + auto *scriptWorker = new PayByPhoneScript(account, phoneNumber, bankName, amount); scriptWorker->moveToThread(thread); - QObject::connect(thread, &QThread::started, scriptWorker, &GetLastDaysHistoryScript::start); - QObject::connect(scriptWorker, &GetLastDaysHistoryScript::finished, thread, &QThread::quit); - QObject::connect(scriptWorker, &GetLastDaysHistoryScript::finished, scriptWorker, &QObject::deleteLater); + + // Запуск первого потока + QObject::connect(thread, &QThread::started, scriptWorker, &PayByPhoneScript::start); + QObject::connect(scriptWorker, &PayByPhoneScript::finished, thread, &QThread::quit); + QObject::connect(scriptWorker, &PayByPhoneScript::finished, scriptWorker, &QObject::deleteLater); QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); - QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() { - scriptWorker->stop(); + // Обработка результата первого потока + QObject::connect(scriptWorker, &PayByPhoneScript::finishedWithResult, &app, [&](const QString &result) { + qDebug() << "Получен результат: [" << result << "]"; + + // Создаем второй поток после завершения первого + auto *thread2 = new QThread; + auto *scriptWorker2 = new GetLastDaysHistoryScript(account); + scriptWorker2->moveToThread(thread2); + + // Запуск второго потока + QObject::connect(thread2, &QThread::started, scriptWorker2, &GetLastDaysHistoryScript::start); + QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, thread2, &QThread::quit); + QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, scriptWorker2, &QObject::deleteLater); + QObject::connect(thread2, &QThread::finished, thread2, &QThread::deleteLater); + + // Остановка второго потока при завершении приложения + connectStopOnQuit(scriptWorker2, thread2); + + thread2->start(); }); + // Остановка первого потока при завершении приложения + connectStopOnQuit(scriptWorker, thread); + + // Запуск первого потока thread->start(); } }