diff --git a/android/birbank/CommonBirbankScript.cpp b/android/birbank/CommonBirbankScript.cpp index a8a7df9..3c2dba3 100644 --- a/android/birbank/CommonBirbankScript.cpp +++ b/android/birbank/CommonBirbankScript.cpp @@ -7,6 +7,7 @@ #include "adb/AdbUtils.h" #include "net/NetworkService.h" +#include "time/DateUtils.h" CommonBirbankScript::CommonBirbankScript(QObject *parent) : QObject(parent) { @@ -164,10 +165,10 @@ void CommonBirbankScript::postNewTransactionData(const AccountInfo &account, con obj["status"] = transactionStatusToString(transaction.status); obj["type"] = transactionTypeToString(transaction.type); obj["phone"] = transaction.phone; - obj["description"] = transaction.description; + obj["description"] = transaction.description + " | " + transaction.bankTime; obj["updatedDescription"] = transaction.updatedDescription; obj["bankName"] = transaction.bankName; - obj["bankTime"] = transaction.bankTime; + obj["bankTime"] = DateUtils::toUtcString(transaction.completeTime); obj["bankTransactionId"] = transaction.bankTrExternalId; // FIXME доставить десктоп ид из настроеек diff --git a/android/birbank/ScreenXmlBirbankParser.cpp b/android/birbank/ScreenXmlBirbankParser.cpp index 6e8e11c..ba2f8f9 100644 --- a/android/birbank/ScreenXmlBirbankParser.cpp +++ b/android/birbank/ScreenXmlBirbankParser.cpp @@ -470,24 +470,39 @@ QDomElement findElementWithPaymentsBirbank(const QDomElement &parent, const QStr } QDateTime getUtcFromBakuDate(const QString &date, const QString &time) { - int year = QDate::currentDate().year(); // Или укажи вручную нужный год - QString combined = QString("%1 %2 %3").arg(date).arg(year).arg(time); // "24 июля 2025 0:31" - - QLocale ruLocale(QLocale::Russian, QLocale::Russia); - QDateTime dt = ruLocale.toDateTime(combined, "d MMMM yyyy H:mm"); - - if (dt.isValid()) { - // Установка часового пояса Asia/Baku - dt.setTimeZone(QTimeZone("Asia/Baku")); - // Перевод в UTC - QDateTime utc = dt.toTimeZone(QTimeZone::utc()); - return utc; - } else { - qWarning() << "Ошибка разбора даты/времени"; + QDate baseDate; + QTime parsedTime = QTime::fromString(time, "H:mm"); + if (!parsedTime.isValid()) { + qWarning() << "Невалидное время:" << time; + return {}; } - return {}; -} + QString dateLower = date.trimmed().toLower(); + + if (dateLower == "сегодня") { + baseDate = QDate::currentDate(); + } else if (dateLower == "вчера") { + baseDate = QDate::currentDate().addDays(-1); + } else if (dateLower == "позавчера") { + baseDate = QDate::currentDate().addDays(-2); + } else { + // Пробуем разобрать обычную дату, например "24 июля" + QLocale ruLocale(QLocale::Russian, QLocale::Russia); + int year = QDate::currentDate().year(); + QString combined = QString("%1 %2 %3").arg(date).arg(year).arg(time); // "24 июля 2025 0:31" + QDateTime dt = ruLocale.toDateTime(combined, "d MMMM yyyy H:mm"); + if (!dt.isValid()) { + qWarning() << "Ошибка разбора даты:" << combined; + return {}; + } + dt.setTimeZone(QTimeZone("Asia/Baku")); + return dt.toTimeZone(QTimeZone::utc()); + } + + // Собираем и переводим в UTC, если дата относительная + QDateTime bakuDateTime(baseDate, parsedTime, QTimeZone("Asia/Baku")); + return bakuDateTime.toTimeZone(QTimeZone::utc()); +} QList ScreenXmlBirbankParser::parsePositiveTransactions() { QList transactions; diff --git a/android/toss/CommonTossScript.cpp b/android/toss/CommonTossScript.cpp new file mode 100644 index 0000000..f911976 --- /dev/null +++ b/android/toss/CommonTossScript.cpp @@ -0,0 +1,217 @@ +#include "CommonTossScript.h" + +#include +#include +#include +#include + +#include "adb/AdbUtils.h" +#include "net/NetworkService.h" +#include "time/DateUtils.h" + +CommonTossScript::CommonTossScript(QObject *parent) + : QObject(parent) { +} + +CommonTossScript::~CommonTossScript() = default; + +void CommonTossScript::start() { + doStart(); + emit finished(); +} + +Node CommonTossScript::swipeToButton( + const QString &deviceId, + const QString &text, int &counter, const int width, const int height +) { + for (int i = 0; i < 10; ++i) { + if (Node button = xmlScreenParser.findButtonNode(text, true); button.x() > 0 && button.y() > 0) { + return button; + } + const int x = width / 2; + const int offset = height / 4; + AdbUtils::makeSwipe(deviceId, x, height - offset, x, offset); + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter)); + } + return {}; +} + +bool CommonTossScript::runAppAndGoToHomeScreen( + const QString &deviceId, + const QString &packageName, + const QString &pinCode, + const int width, + const int height +) { + // Запустить устройство + if (const QString pid = AdbUtils::tryToGetRunningAppPid(deviceId, packageName); !pid.isEmpty()) { + qDebug() << "Process already running, pid: " << pid; + AdbUtils::getScreenDumpAsXml(deviceId, 1000); + AdbUtils::tryToKillApplication(deviceId, packageName); + } + if (!AdbUtils::tryToStartApplication(deviceId, packageName)) { + AdbUtils::takeScreenshot(deviceId, "run_app_error"); + qWarning() << "Process has not started"; + return false; + } + + // Даем минимальное время на запуск + QThread::msleep(2500); + int counter = 0; + bool findAndInputPincode = false; + + while (true) { + counter++; + + // Если более 10 раз мы пытаемся перейти на домашнюю + if (counter > 10) { + AdbUtils::takeScreenshot(deviceId, "too_many_attempts"); + return false; + } + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter)); + + // Node closeBannerNode = xmlScreenParser.findButtonNode("Maraqlı deyil", false); + // if (!closeBannerNode.isEmpty()) { + // AdbUtils::makeTap(deviceId, closeBannerNode.x(), closeBannerNode.y()); + // QThread::msleep(1000); + // continue; + // } + + if (xmlScreenParser.isHomeScreen()) { + return true; + } + + // Проверяем, что это экран ввода пин-кода + if (!findAndInputPincode) { + if (const QList pincode = xmlScreenParser.findPinCodeNodes(pinCode); pincode.size() == 6) { + for (const Node &node: pincode) { + AdbUtils::makeTap(deviceId, node.x(), node.y()); + QThread::msleep(QRandomGenerator::global()->bounded(200, 901)); + } + // После ввода пин-код нужно сделать задержку, пока подгрузка идет, чтобы снова не спарсить + findAndInputPincode = true; + QThread::msleep(3000); + continue; + } + } + + QThread::msleep(1000); + } +} + +bool CommonTossScript::goToAllProducts( + const QString &deviceId, + const int width, + const int height +) { + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, m_counter)); + Node closeBannerNode = xmlScreenParser.findButtonNode("Maraqlı deyil", false); + if (!closeBannerNode.isEmpty()) { + AdbUtils::makeTap(deviceId, closeBannerNode.x(), closeBannerNode.y()); + QThread::msleep(500); + } + + if (xmlScreenParser.isHomeScreen()) { + Node allMyAccountBtn = xmlScreenParser.findButtonNode("All My Accounts", false); + if (!allMyAccountBtn.isEmpty()) { + AdbUtils::makeTap(deviceId, allMyAccountBtn.x(), allMyAccountBtn.y()); + QThread::msleep(500); + return true; + } + } + return false; +} + +void CommonTossScript::postAccountsData(const QList &accounts) { + if (accounts.isEmpty()) { + return; + } + + auto *thread = new QThread; + auto *worker = new NetworkService; + + QJsonArray list; + for (const AccountInfo &account: accounts) { + QJsonObject obj; + obj["appName"] = account.appCode; + obj["lastNumbers"] = account.lastNumbers; + obj["amount"] = account.amount; + obj["currency"] = account.currency; + obj["description"] = account.description; + obj["status"] = accountStatusToString(account.status); + + list.append(obj); + } + // FIXME доставить десктоп ид из настроеек + worker->setDeviceId(accounts.first().deviceId); + worker->setPayload(QJsonDocument(list).toJson()); + worker->moveToThread(thread); + connect(thread, &QThread::started, worker, &NetworkService::postAccountsData); + connect(worker, &NetworkService::finished, thread, &QThread::quit); + connect(worker, &NetworkService::finished, worker, &QObject::deleteLater); + connect(thread, &QThread::finished, thread, &QThread::deleteLater); + thread->start(); +} + +void CommonTossScript::postNewTransactionData(const AccountInfo &account, const TransactionInfo &transaction) { + auto *thread = new QThread; + auto *worker = new NetworkService; + + QJsonObject obj; + obj["id"] = transaction.id; + obj["amount"] = transaction.amount; + obj["name"] = transaction.name; + obj["fee"] = transaction.fee; + obj["status"] = transactionStatusToString(transaction.status); + obj["type"] = transactionTypeToString(transaction.type); + obj["phone"] = transaction.phone; + obj["description"] = transaction.description + " | " + transaction.bankTime; + obj["updatedDescription"] = transaction.updatedDescription; + obj["bankName"] = transaction.bankName; + obj["bankTime"] = DateUtils::toUtcString(transaction.completeTime); + obj["bankTransactionId"] = transaction.bankTrExternalId; + + // FIXME доставить десктоп ид из настроеек + worker->setDeviceId(account.deviceId); + worker->addExtra("lastNumbers", account.lastNumbers); + worker->addExtra("transactionId", transaction.id); + worker->setPayload(QJsonDocument(obj).toJson()); + worker->moveToThread(thread); + connect(thread, &QThread::started, worker, &NetworkService::insertTransactionData); + connect(worker, &NetworkService::finished, thread, &QThread::quit); + connect(worker, &NetworkService::finished, worker, &QObject::deleteLater); + connect(thread, &QThread::finished, thread, &QThread::deleteLater); + thread->start(); +} + +void CommonTossScript::updateTransactionData( + const AccountInfo &account, + const int transactionId, + const TransactionStatus status, + const QString &oldDesc, + const QString &newDesc +) { + auto *thread = new QThread; + auto *worker = new NetworkService; + + QJsonObject obj; + obj["id"] = transactionId; + obj["status"] = transactionStatusToString(status); + obj["description"] = newDesc; + obj["updatedDescription"] = oldDesc; + + // FIXME доставить десктоп ид из настроеек + worker->setDeviceId(account.deviceId); + worker->addExtra("lastNumbers", account.lastNumbers); + worker->setPayload(QJsonDocument(obj).toJson()); + worker->moveToThread(thread); + connect(thread, &QThread::started, worker, &NetworkService::updateTransactionData); + connect(worker, &NetworkService::finished, thread, &QThread::quit); + connect(worker, &NetworkService::finished, worker, &QObject::deleteLater); + connect(thread, &QThread::finished, thread, &QThread::deleteLater); + thread->start(); +} + +void CommonTossScript::stop() { + m_running = false; +} diff --git a/android/toss/CommonTossScript.h b/android/toss/CommonTossScript.h new file mode 100644 index 0000000..cd5b0bc --- /dev/null +++ b/android/toss/CommonTossScript.h @@ -0,0 +1,68 @@ +#pragma once + +#include +#include "ScreenXmlTossParser.h" +#include "android/xml/Node.h" +#include "db/AccountInfo.h" +#include "db/TransactionInfo.h" + +class CommonTossScript : public QObject { + Q_OBJECT + +public: + explicit CommonTossScript(QObject *parent = nullptr); + + ~CommonTossScript() override; + +protected: + virtual void doStart() = 0; + + bool goToAllProducts( + const QString &deviceId, + int width, + int height + ); + + void postAccountsData(const QList &accounts); + + void postNewTransactionData(const AccountInfo &account, const TransactionInfo &transaction); + + void updateTransactionData( + const AccountInfo &account, + int transactionId, + TransactionStatus status, + const QString &oldDesc, + const QString &newDesc + ); + + Node swipeToButton( + const QString &deviceId, + const QString &text, + int &counter, int width, int height + ); + + bool runAppAndGoToHomeScreen( + const QString &deviceId, + const QString &packageName, + const QString &pinCode, + int width, + int height + ); + + bool m_running = true; + ScreenXmlTossParser xmlScreenParser; + int m_counter = 0; + +signals: + void finished(); + + void finishedWithResult(const QString &result); + +public slots: + virtual void start() final; + + virtual void stop() final; + +private: + Q_DISABLE_COPY(CommonTossScript); +}; diff --git a/android/toss/GetLastDaysHistoryTossScript.cpp b/android/toss/GetLastDaysHistoryTossScript.cpp new file mode 100644 index 0000000..323f4be --- /dev/null +++ b/android/toss/GetLastDaysHistoryTossScript.cpp @@ -0,0 +1,164 @@ +#include "GetLastDaysHistoryTossScript.h" + +#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/DeviceInfo.h" +#include "net/NetworkService.h" +#include "time/DateUtils.h" + +GetLastDaysHistoryTossScript::GetLastDaysHistoryTossScript( + AccountInfo account, + QObject *parent +) : CommonTossScript(parent), + m_account(std::move(account)) { +} + +GetLastDaysHistoryTossScript::~GetLastDaysHistoryTossScript() = default; + +bool GetLastDaysHistoryTossScript::saveAndPostNewTransactionData( + const AccountInfo &account, + const TransactionInfo &transaction, + const TransactionStatus &status +) { + TransactionInfo tr; + tr.accountId = account.id; + tr.description = transaction.description; + tr.bankTime = transaction.bankTime; + tr.bankName = transaction.bankName; + tr.amount = transaction.amount; + tr.phone = transaction.phone; + tr.updateTime = DateUtils::getUtcNow(); + tr.fee = transaction.fee; + tr.name = transaction.name; + tr.bankTrExternalId = transaction.bankTrExternalId; + tr.status = status; + tr.type = TransactionType::Card; + tr.completeTime = transaction.completeTime; + tr.id = TransactionDAO::insertTransaction(tr); + + if (tr.id == -1) { + return false; + } + postNewTransactionData(account, tr); + return true; +} + +bool GetLastDaysHistoryTossScript::updateAndPostTransactionData( + const AccountInfo &account, + const int transactionId, + const TransactionStatus status, + const QString &oldDesc, + const QString &newDesc +) { + if (TransactionDAO::updateTransaction(transactionId, status, oldDesc, newDesc)) { + updateTransactionData(account, transactionId, status, oldDesc, newDesc); + return true; + } + return false; +} + +void GetLastDaysHistoryTossScript::doStart() { + // берем все транзакции из БД + const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId); + const ApplicationInfo app = ApplicationDAO::getApplication(m_account.deviceId, m_account.appCode); + + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); + if (!xmlScreenParser.isHomeScreen()) { + if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode, device.screenWidth, device.screenHeight)) { + m_error = "Не смогли дойти до домашней страницы"; + qCritical() << m_error; + emit finishedWithResult(m_error); + return; + } + } + + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); + + if (xmlScreenParser.isHomeScreen()) { + QList oldAccounts = AccountDAO::getAccounts(m_account.deviceId, m_account.appCode); + QMap accountMap; + for (AccountInfo &oldAccount: oldAccounts) { + if (oldAccount.status == AccountStatus::Active) { + accountMap.insert(oldAccount.lastNumbers, oldAccount); + } + } + + QList accounts = xmlScreenParser.parseAccountsInfo(); + if (accounts.length() == 1 && accountMap.size() == 1) { + AccountInfo account = accounts[0]; + account.deviceId = m_account.deviceId; + account.appCode = m_account.appCode; + account.lastNumbers = accountMap.first().lastNumbers; + account.description = accountMap.first().description; + account.currency = accountMap.first().currency; + account.description = accountMap.first().description; + account.status = AccountStatus::Active; + if (!AccountDAO::upsertAccount(account)) { + m_error = "Not updated: " + account.lastNumbers; + qCritical() << m_error; + } + } + + QList savedAccounts = AccountDAO::getAccounts(m_account.deviceId, m_account.appCode); + postAccountsData(savedAccounts); + + + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); + Node transferText = xmlScreenParser.findTextContainsNode("토스뱅크 통장"); + if (!transferText.isEmpty()) { + AdbUtils::makeTap(device.id, transferText.x(), transferText.y()); + QThread::msleep(3000); + + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); + + for (int i = 0; i < 5; ++i) { + Node myBankText = xmlScreenParser.findTextNode("My Toss Bank"); + Node accountText = xmlScreenParser.findTextNode("Account"); + + if (!myBankText.isEmpty() && !accountText.isEmpty()) { + QList transactions = xmlScreenParser.parsePositiveTransactions(); + QList savedTransactions = TransactionDAO::getTransactionsWithinHours(m_account.id, 48); + for (TransactionInfo &transaction: transactions) { + bool isSaved = false; + for (TransactionInfo &savedTransaction: savedTransactions) { + if (savedTransaction.amount == transaction.amount + && savedTransaction.bankTime == transaction.bankTime) { + isSaved = true; + break; + } + } + if (!isSaved) { + if (!saveAndPostNewTransactionData(m_account, transaction, TransactionStatus::Complete)) { + qDebug() << "--- saveAndPostNewTransactionData failed"; + } + } + } + } else { + m_error = "Card page not found: " + m_account.deviceId + " " + m_account.lastNumbers; + qWarning() << m_error; + emit finishedWithResult(m_error); + return; + } + + QThread::msleep(1000); + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId , ++m_counter)); + } + } else { + m_error = "Card not found: " + m_account.deviceId + " " + m_account.lastNumbers; + qWarning() << m_error; + emit finishedWithResult(m_error); + return; + } + } + AdbUtils::goBack(m_account.deviceId); + emit finishedWithResult(m_error); +} diff --git a/android/toss/GetLastDaysHistoryTossScript.h b/android/toss/GetLastDaysHistoryTossScript.h new file mode 100644 index 0000000..99b8636 --- /dev/null +++ b/android/toss/GetLastDaysHistoryTossScript.h @@ -0,0 +1,35 @@ +#pragma once +#include "CommonTossScript.h" + +class GetLastDaysHistoryTossScript final : public CommonTossScript { + Q_OBJECT + +public: + ~GetLastDaysHistoryTossScript() override; + + explicit GetLastDaysHistoryTossScript( + AccountInfo account, + QObject *parent = nullptr + ); + +protected: + void doStart() override; + +private: + const AccountInfo m_account; + QString m_error; + + bool saveAndPostNewTransactionData( + const AccountInfo &account, + const TransactionInfo &transaction, + const TransactionStatus &status + ); + + bool updateAndPostTransactionData( + const AccountInfo &account, + int transactionId, + TransactionStatus status, + const QString &oldDesc, + const QString &newDesc + ); +}; diff --git a/android/toss/LoginAndCheckAccountsTossScript.cpp b/android/toss/LoginAndCheckAccountsTossScript.cpp new file mode 100644 index 0000000..23ad96e --- /dev/null +++ b/android/toss/LoginAndCheckAccountsTossScript.cpp @@ -0,0 +1,208 @@ +#include "LoginAndCheckAccountsTossScript.h" + +#include + +#include "adb/AdbUtils.h" +#include "dao/AccountDAO.h" +#include "dao/ApplicationDAO.h" +#include "dao/DeviceDAO.h" +#include "dao/TransactionDAO.h" +#include "time/DateUtils.h" + +LoginAndCheckAccountsTossScript::LoginAndCheckAccountsTossScript( + QString deviceId, + QString appCode, + QObject *parent +) : CommonTossScript(parent), + m_deviceId(std::move(deviceId)), m_appCode(std::move(appCode)) { +} + +LoginAndCheckAccountsTossScript::~LoginAndCheckAccountsTossScript() = default; + +/** +NongHyup +KakaoBank +Kookmin +Toss Bank +Shinhan +Woori +IBK +Hana +MG +Busan Bank +iM Bank(Daegu) +Kbank +Credit Union +Postal Sav. +SC +Kyongnam +Kwangju +Suhyup +Jeonbuk +Savings Banks +Jeju Bank +Jeonbuk +Savings Banks +Jeju Bank +Citibank +KDB +NFCF +SBI Sav. +BOA +Bank of China +HSBC +ICBC +Deutsche +JPMorgan +BNP Paribas +CCB +*/ +void LoginAndCheckAccountsTossScript::doStart() { + const DeviceInfo device = DeviceDAO::getDeviceById(m_deviceId); + const ApplicationInfo app = ApplicationDAO::getApplication(m_deviceId, m_appCode); + + + if (true) { + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); + + // искать Transfer кнопку + + // Node transferText = xmlScreenParser.findTextContainsNode("토스뱅크 통장"); + // if (transferText.isEmpty()) { + // } + + Node transferText = xmlScreenParser.findFirstAccountLine(); + if (!transferText.isEmpty()) { + AdbUtils::makeTap(device.id, transferText.x(), transferText.y()); + QThread::msleep(3000); + + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); + + bool historyFound = false; + for (int i = 0; i < 5; ++i) { + Node topUpBtn = xmlScreenParser.findButtonNode("Top up", false); + Node sendBtn = xmlScreenParser.findButtonNode("Send", false); + + if (!topUpBtn.isEmpty() && !sendBtn.isEmpty()) { + // подгрузка истории идет + QThread::msleep(2000); + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); + + QList transactions = xmlScreenParser.parsePositiveTransactions(); + for (auto &transaction: transactions) { + qDebug().noquote().nospace() << convertTransactionToString(transaction); + } + historyFound = true; + break; + } + QThread::msleep(1000); + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); + } + if (!historyFound) { + m_error = "Top up or send button not found: " + m_deviceId + " " + m_appCode; + qWarning() << m_error; + emit finishedWithResult(m_error); + return; + } + } else { + m_error = "Card not found: " + m_deviceId + " " + m_appCode; + qWarning() << m_error; + emit finishedWithResult(m_error); + return; + } + } else { + // "Maraqlı deyil" - не интересно + if (device.id.isEmpty() || app.id == -1) { + m_error = "Device or app not found: " + m_deviceId + " " + m_appCode; + qCritical() << m_error; + emit finishedWithResult(m_error); + return; + } + + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); + + if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode, device.screenWidth, device.screenHeight)) { + m_error = "Cant open the home screen: " + m_deviceId + " " + m_appCode; + qWarning() << m_error; + if (!ApplicationDAO::updatePinCodeStatus(app.id, "no", "Не прошла проверка [дата]")) { + qWarning() << "Cant update the pincode: " << m_deviceId << " " << m_appCode; + } + + AdbUtils::tryToKillApplication(m_deviceId, app.package); + emit finishedWithResult(m_error); + return; + } else { + if (!ApplicationDAO::updatePinCodeStatus(app.id, "yes", "")) { + qWarning() << "Cant update the pincode: " << m_deviceId << " " << m_appCode; + } + + Node mainAccount = xmlScreenParser.findTextContainsNode("Main account"); + if (!mainAccount.isEmpty()) { + // AdbUtils::makeTap(device.id, mainAccount.x(), mainAccount.y()); + // QThread::msleep(1000); + // for (int i = 0; i < 5; ++i) { + // xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); + // Node mainAccount = xmlScreenParser.findTextContainsNode("Main account"); + // if (!byDayTitle.isEmpty()) { + // qWarning() << "--- beforeYesterdayTitle found!"; + // break; + // } + // AdbUtils::makeSwipe( + // m_account.deviceId, + // device.screenWidth / 2, device.screenHeight / 4 * 3, + // device.screenWidth / 2, device.screenHeight / 4 + // ); + // QThread::msleep(1000); + // + // } + } + + QThread::msleep(2000); + + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); + + QList oldAccounts = AccountDAO::getAccounts(m_deviceId, m_appCode); + QMap accountMap; + for (AccountInfo &oldAccount: oldAccounts) { + if (oldAccount.status == AccountStatus::Active) { + accountMap.insert(oldAccount.lastNumbers, oldAccount); + } + } + + QList accounts = xmlScreenParser.parseAccountsInfo(); + if (accounts.length() == 1 && accountMap.size() == 1) { + AccountInfo account = accounts[0]; + account.deviceId = m_deviceId; + account.appCode = m_appCode; + account.lastNumbers = accountMap.first().lastNumbers; + account.description = accountMap.first().description; + account.currency = accountMap.first().currency; + account.description = accountMap.first().description; + account.status = AccountStatus::Active; + if (!AccountDAO::upsertAccount(account)) { + m_error = "Not updated: " + account.lastNumbers; + qCritical() << m_error; + } + } + // for (auto account: accounts) { + // if (accountMap.contains(account.lastNumbers)) { + // account.deviceId = m_deviceId; + // account.appCode = m_appCode; + // account.currency = accountMap[account.lastNumbers].currency; + // account.description = accountMap[account.lastNumbers].description; + // account.status = AccountStatus::Active; + // if (!AccountDAO::upsertAccount(account)) { + // m_error = "Not updated: " + account.lastNumbers; + // qCritical() << m_error; + // } + // } + // } + + QList savedAccounts = AccountDAO::getAccounts(m_deviceId, m_appCode); + postAccountsData(savedAccounts); + } + + AdbUtils::tryToKillApplication(m_deviceId, app.package); + } + emit finishedWithResult(m_error); +} diff --git a/android/toss/LoginAndCheckAccountsTossScript.h b/android/toss/LoginAndCheckAccountsTossScript.h new file mode 100644 index 0000000..7ff1922 --- /dev/null +++ b/android/toss/LoginAndCheckAccountsTossScript.h @@ -0,0 +1,23 @@ +#pragma once +#include "CommonTossScript.h" + +class LoginAndCheckAccountsTossScript final : public CommonTossScript { + Q_OBJECT + +public: + ~LoginAndCheckAccountsTossScript() override; + + explicit LoginAndCheckAccountsTossScript( + QString deviceId, + QString appCode, + QObject *parent = nullptr + ); + +protected: + void doStart() override; + +private: + const QString m_deviceId; + const QString m_appCode; + QString m_error; +}; diff --git a/android/toss/ScreenXmlTossParser.cpp b/android/toss/ScreenXmlTossParser.cpp new file mode 100644 index 0000000..328a53c --- /dev/null +++ b/android/toss/ScreenXmlTossParser.cpp @@ -0,0 +1,452 @@ +#include "ScreenXmlTossParser.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "adb/AdbUtils.h" +#include "android/xml/Node.h" +#include "db/AccountInfo.h" +#include "db/TransactionInfo.h" +#include "time/DateUtils.h" + +ScreenXmlTossParser::ScreenXmlTossParser(QObject *parent) : QObject(parent) { +} + +ScreenXmlTossParser::~ScreenXmlTossParser() = default; + +static const QRegularExpression boundsRegex(R"(\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\])"); + +Node ScreenXmlTossParser::findTextNode(const QString &text) { + for (const Node &node: m_nodes) { + if (node.className == "android.widget.TextView" && node.text.trimmed() == text) { + return node; + } + } + return {}; +} + +Node ScreenXmlTossParser::findTextContainsNode(const QString &text) { + for (const Node &node: m_nodes) { + if (node.className == "android.widget.TextView" && node.text.contains(text)) { + return node; + } + } + return {}; +} + +Node ScreenXmlTossParser::findTextNode(const QString &text, const int x1, const int y1, const int x2, const int y2) { + for (const Node &node: m_nodes) { + if (node.className == "android.widget.TextView" && node.text.trimmed() == text + && node.x() >= x1 && node.x() <= x2 && node.y() >= y1 && node.y() <= y2) { + return node; + } + } + return {}; +} + +Node ScreenXmlTossParser::findEditText(const QString &text) { + for (const Node &node: m_nodes) { + if (node.className == "android.widget.EditText" && node.text == text) { + return node; + } + } + return {}; +} + +Node ScreenXmlTossParser::findEditTextByResourceId(const QString &resourceId) { + for (const Node &node: m_nodes) { + if (node.className == "android.widget.EditText" && node.resourceId == resourceId) { + return node; + } + } + return {}; +} + +Node ScreenXmlTossParser::findButtonNode(const QString &text, const bool contains) { + for (const Node &node: m_nodes) { + if (contains) { + if (node.className == "android.widget.Button" && node.text.contains(text)) { + return node; + } + } else { + if (node.className == "android.widget.Button" && node.text.trimmed() == text) { + return node; + } + } + } + return {}; +} + +bool ScreenXmlTossParser::isHomeScreen() { + Node activitiesBtn; + for (const Node &node: m_nodes) { + if (node.text.contains("Transfer") && node.resourceId == "viva.republica.toss:id/rightButton") { + activitiesBtn = node; + } + } + return !activitiesBtn.isEmpty(); +} + +QList ScreenXmlTossParser::findPinCodeNodes(const QString &pinCode) { + QMap buttons; + const QSet numberSet = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"}; + + for (const Node &node: m_nodes) { + const QString &text = node.text.trimmed(); + if (node.className == "android.widget.Button" && numberSet.contains(text)) { + buttons[text] = node; + } + } + + QList nodes; + for (int i = 0; i < pinCode.length(); ++i) { + nodes.append(buttons[QString(pinCode.at(i))]); + } + return nodes; +} + +Node convertTossDomElementToNode(const QDomElement &element) { + auto node = Node(); + if (element.hasAttribute("bounds")) { + const QString bounds = element.attribute("bounds"); + if (const QRegularExpressionMatch match = boundsRegex.match(bounds); match.hasMatch()) { + node.setBounds( + match.captured(1).toInt(), + match.captured(2).toInt(), + match.captured(3).toInt(), + match.captured(4).toInt() + ); + } + } + if (element.hasAttribute("text")) { + node.text = element.attribute("text"); + } + if (element.hasAttribute("content-desc")) { + node.contentDesc = element.attribute("content-desc"); + } + if (element.hasAttribute("class")) { + node.className = element.attribute("class"); + } + if (element.hasAttribute("clickable")) { + node.clickable = element.attribute("clickable") == "true"; + } + if (element.hasAttribute("focusable")) { + node.focusable =element.attribute("focusable") == "true"; + } + if (element.hasAttribute("resource-id")) { + node.resourceId = element.attribute("resource-id"); + } + + return node; +} + +void ScreenXmlTossParser::parseAndSaveXml(const QString &xml) { + QDomDocument doc; + doc.setContent(xml); + m_xml = doc.documentElement(); + m_nodes.clear(); + + QXmlStreamReader reader(xml); + while (!reader.atEnd()) { + reader.readNext(); + if (reader.isStartElement() && reader.name() == "node") { + Node node = Node(); + if (reader.attributes().hasAttribute("bounds")) { + QString bounds = reader.attributes().value("bounds").toString(); + if (QRegularExpressionMatch match = boundsRegex.match(bounds); match.hasMatch()) { + node.setBounds( + match.captured(1).toInt(), + match.captured(2).toInt(), + match.captured(3).toInt(), + match.captured(4).toInt() + ); + } + } + if (reader.attributes().hasAttribute("text")) { + node.text = reader.attributes().value("text").toString(); + } + + if (reader.attributes().hasAttribute("content-desc")) { + node.contentDesc = reader.attributes().value("content-desc").toString(); + } + + if (reader.attributes().hasAttribute("class")) { + node.className = reader.attributes().value("class").toString(); + } + + if (reader.attributes().hasAttribute("clickable")) { + node.clickable = reader.attributes().value("clickable").toString() == "true"; + } + if (reader.attributes().hasAttribute("focusable")) { + node.focusable = reader.attributes().value("focusable").toString() == "true"; + } + if (reader.attributes().hasAttribute("resource-id")) { + node.resourceId = reader.attributes().value("resource-id").toString(); + } + + m_nodes.append(node); + } + } +} + +QDomElement findSubElementToss(const QDomElement &elem, const QString &index) { + if (elem.hasChildNodes()) { + QDomNodeList subInfoList = elem.childNodes(); + for (QDomNode subInfoNode: subInfoList) { + if (!subInfoNode.isElement()) continue; + QDomElement subInfo = subInfoNode.toElement(); + if (subInfo.attribute("index") == index) { + return subInfo; + } + } + } + return {}; +} + +QString findSubInfoToss(const QDomElement &elem, const QString &index) { + QDomElement subInfo = findSubElementToss(elem, index); + if (!subInfo.isNull()) { + return subInfo.attribute("text"); + } + return ""; +} + +QDomNode findNodeToss(const QDomNode &node, const QString &text) { + if (node.isElement()) { + QString nodeText = node.toElement().attribute("text"); + if (nodeText.toLower().startsWith(text)) { + return node; + } + } + + QDomNode child = node.firstChild(); + while (!child.isNull()) { + QDomNode result = findNodeToss(child, text); + if (!result.isNull()) { + return result; + } + child = child.nextSibling(); + } + return {}; +} + +QList findElementsWithPaymentsToss(const QDomElement &parent, const QString &attribute, + const QString &value) { + QList result; + + QDomElement element = parent.firstChildElement(); + while (!element.isNull()) { + // Проверка самого element + // if (element.hasAttribute(attribute) && element.attribute(attribute) == value) { + // result.append(element); + // } + + // Проверка его дочерних элементов + QDomElement child = element.firstChildElement(); + while (!child.isNull()) { + if (child.hasAttribute(attribute) && child.attribute(attribute) == value) { + result.append(child); + } + child = child.nextSiblingElement(); + } + + // Рекурсивный обход + result.append(findElementsWithPaymentsToss(element, attribute, value)); + + element = element.nextSiblingElement(); + } + + return result; +} + +QDomElement findElementWithPaymentsToss(const QDomElement &parent, const QString &attribute, const QString &value) { + QDomElement element = parent.firstChildElement(); + while (!element.isNull()) { + QDomElement child = element.firstChildElement(); + while (!child.isNull()) { + if (child.hasAttribute(attribute) && child.attribute(attribute) == value) { + return child; + } + child = child.nextSiblingElement(); + } + + QDomElement found = findElementWithPaymentsToss(element, attribute, value); + if (!found.isNull()) { + return found; + } + element = element.nextSiblingElement(); + } + return {}; +} + +QDateTime getUtcFromSeoulDate(const QString &date, const QString &time) { + int year = QDate::currentDate().year(); // или укажи вручную нужный год + QString withYear = QString("%1년 %2 %3").arg(year).arg(date).arg(time); // "2025년 7월 28일 17:54" + + QLocale korean(QLocale::Korean, QLocale::SouthKorea); + QString format = "yyyy년 M월 d일 H:mm"; + + QDateTime dt = korean.toDateTime(withYear, format); + if (dt.isValid()) { + dt.setTimeZone(QTimeZone("Asia/Seoul")); + return dt.toTimeZone(QTimeZone::utc()); + } else { + qWarning() << "Ошибка разбора даты:" << withYear; + return {}; + } +} + +Node ScreenXmlTossParser::findFirstAccountLine() { + Node node; + auto elements = findElementsWithPaymentsToss(m_xml, "text", "Transfer"); + if (elements.length() == 2) { + for (QDomElement &element: elements) { + qDebug() << "Found account: " << element.attribute("content-desc"); + } + } + if (!elements.isEmpty()) { + node = convertTossDomElementToNode(elements[0].parentNode().toElement()); + } + return node; +} + + +QList ScreenXmlTossParser::parsePositiveTransactions() { + QList transactions; + + QDomElement child = findElementWithPaymentsToss(m_xml, "class", "android.widget.ListView"); + QDomNodeList listView = child.childNodes(); + qDebug() << listView.count(); + if (!listView.isEmpty()) { + QString date = ""; + + for (QDomNode node: listView) { + QString title = node.toElement().attribute("text"); + if (title == "전체" || title.startsWith("AD") || title.endsWith("AD")) { + continue; + } + if (!title.isEmpty()) { + date = node.toElement().attribute("text"); + } + + if (date.isEmpty()) { + continue; + } + + const QDomNodeList trBoxGroup = node.childNodes(); + if (trBoxGroup.count() > 0) { + TransactionInfo transaction; + for (QDomNode item: trBoxGroup) { + QDomElement groupItem = item.toElement(); + QString line = groupItem.attribute("text"); + if (line.contains("잔액") && line.contains("입금")) { + QString beforeBalance = line.split("잔액").first().trimmed(); + + QString time = beforeBalance.split("입금").first().trimmed().last(5); + QString desc = beforeBalance.split("입금").first().replace(time, "").trimmed(); + QString amount = beforeBalance.split("입금").last().replace("원", "").replace(",", "").trimmed(); + + transaction.amount = amount.toDouble(); + transaction.description = desc; + transaction.bankTime = date + " " + time; + transaction.completeTime = getUtcFromSeoulDate(date, time); + } + } + if (transaction.amount > 0) { + transactions.append(transaction); + } + } + } + } else { + qDebug() << "ListView is empty"; + } + return transactions; +} + +float extractKoreanWonFromText(const QString &input) { + QRegularExpression re(R"(₩([\d,]+))"); + QRegularExpressionMatch match = re.match(input); + if (!match.hasMatch()) { + qWarning() << "Не удалось найти сумму в строке:" << input; + return 0.0f; + } + + QString numberStr = match.captured(1); + numberStr.remove(','); // удаляем запятые + + return numberStr.toFloat(); +} + +QList ScreenXmlTossParser::parseAccountsInfo() { + const QDomNodeList nodes = m_xml.elementsByTagName("node"); + QList accounts; + + for (int i = 0; i < nodes.count(); ++i) { + const QDomElement el = nodes.at(i).toElement(); + + // 토스뱅크 통장 + if (el.attribute("content-desc").contains("토스뱅크 통장") && el.attribute("content-desc").contains("₩")) { + AccountInfo info; + info.amount = extractKoreanWonFromText(el.attribute("content-desc")); + info.updateTime = DateUtils::getUtcNow(); + accounts.append(info); + break; + // auto amount = el.attribute("text").replace("₼", "").trimmed(); + // const QDomElement parent = el.parentNode().parentNode().toElement(); + // // Перебираем потомков + // QDomNode n = parent.firstChild().firstChild().firstChild().firstChild(); + // while (!n.isNull()) { + // const QDomElement e = n.toElement(); + // if (e.attribute("resource-id") == "az.kapitalbank.mbanking:id/tvNumber") { + // const QString account = e.attribute("text"); + // + // AccountInfo info; + // info.lastNumbers = account; + // info.amount = amount.toFloat(); + // info.description = account; + // info.updateTime = DateUtils::getUtcNow(); + // + // accounts.append(info); + // break; + // } + // n = n.nextSibling(); + // } + } + } + return accounts; +} + +void ScreenXmlTossParser::test() { + // TransactionInfo info2 = parseExpandedInfo(m_xml); + // qDebug().noquote().nospace() << convertTransactionToString(info2); + // return; + + QFile file("assets/rshb/all_products.xml"); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + qDebug() << "Cannot open file"; + } + + QDomDocument doc; + if (!doc.setContent(&file)) { + qDebug() << "Failed to parse XML"; + } + file.close(); + + qDebug() << "Start parsing XML:"; + + // Номер карты с последними цифрами + QDomElement root = doc.documentElement(); + parseAndSaveXml(doc.toString()); + // for (const AccountInfo &info: parseAccountsInfo()) { + // qDebug().noquote().nospace() << convertAccountToString(info); + // } + // TransactionInfo info = parseExpandedInfo(root); + // qDebug().noquote().nospace() << convertTransactionToString(info); + // ЕСПП +} diff --git a/android/toss/ScreenXmlTossParser.h b/android/toss/ScreenXmlTossParser.h new file mode 100644 index 0000000..b05267a --- /dev/null +++ b/android/toss/ScreenXmlTossParser.h @@ -0,0 +1,46 @@ +#pragma once + +#include +#include +#include "android/xml/Node.h" +#include "db/AccountInfo.h" +#include "db/TransactionInfo.h" + +class ScreenXmlTossParser final : public QObject { + Q_OBJECT + +public: + explicit ScreenXmlTossParser(QObject *parent = nullptr); + + ~ScreenXmlTossParser() override; + + Node findTextNode(const QString &text); + + Node findTextContainsNode(const QString &text); + + Node findFirstAccountLine(); + + Node findTextNode(const QString &text, int x1, int y1, int x2, int y2); + + Node findEditText(const QString &text); + + Node findEditTextByResourceId(const QString &resourceId); + + Node findButtonNode(const QString &text, bool contains); + + bool isHomeScreen(); + + void parseAndSaveXml(const QString &xml); + + QList parsePositiveTransactions(); + + QList parseAccountsInfo(); + + QList findPinCodeNodes(const QString &pinCode); + + void test(); + +private: + QList m_nodes; + QDomElement m_xml; +}; diff --git a/assets/birbank/banner/block_banner.png b/assets/birbank/banner/block_banner.png new file mode 100644 index 0000000..715970a Binary files /dev/null and b/assets/birbank/banner/block_banner.png differ diff --git a/assets/birbank/banner/block_banner.xml b/assets/birbank/banner/block_banner.xml new file mode 100644 index 0000000..1d77326 --- /dev/null +++ b/assets/birbank/banner/block_banner.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/birbank/transaction_by_card.png b/assets/birbank/transaction_by_card.png new file mode 100644 index 0000000..35733ba Binary files /dev/null and b/assets/birbank/transaction_by_card.png differ diff --git a/assets/birbank/transaction_by_card.xml b/assets/birbank/transaction_by_card.xml new file mode 100644 index 0000000..0a81ce1 --- /dev/null +++ b/assets/birbank/transaction_by_card.xml @@ -0,0 +1,800 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/birbank/transactions.png b/assets/birbank/transactions.png new file mode 100644 index 0000000..944522e Binary files /dev/null and b/assets/birbank/transactions.png differ diff --git a/assets/birbank/transactions.xml b/assets/birbank/transactions.xml new file mode 100644 index 0000000..ffe15f9 --- /dev/null +++ b/assets/birbank/transactions.xml @@ -0,0 +1,719 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/toss/bank_main_screen.png b/assets/toss/bank_main_screen.png new file mode 100644 index 0000000..30ee17b Binary files /dev/null and b/assets/toss/bank_main_screen.png differ diff --git a/assets/toss/bank_main_screen.xml b/assets/toss/bank_main_screen.xml new file mode 100644 index 0000000..5af0d02 --- /dev/null +++ b/assets/toss/bank_main_screen.xml @@ -0,0 +1,738 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/toss/home_screen.png b/assets/toss/home_screen.png new file mode 100644 index 0000000..650a0be Binary files /dev/null and b/assets/toss/home_screen.png differ diff --git a/assets/toss/home_screen.xml b/assets/toss/home_screen.xml new file mode 100644 index 0000000..4c77e04 --- /dev/null +++ b/assets/toss/home_screen.xml @@ -0,0 +1,1401 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/toss/pin_code.xml b/assets/toss/pin_code.xml new file mode 100644 index 0000000..c452fa7 --- /dev/null +++ b/assets/toss/pin_code.xml @@ -0,0 +1,350 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/toss/toss_banks.png b/assets/toss/toss_banks.png new file mode 100644 index 0000000..21fe6dc Binary files /dev/null and b/assets/toss/toss_banks.png differ diff --git a/assets/toss/toss_banks.xml b/assets/toss/toss_banks.xml new file mode 100644 index 0000000..843b677 --- /dev/null +++ b/assets/toss/toss_banks.xml @@ -0,0 +1,945 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/toss/toss_banks_2.xml b/assets/toss/toss_banks_2.xml new file mode 100644 index 0000000..ab72765 --- /dev/null +++ b/assets/toss/toss_banks_2.xml @@ -0,0 +1,962 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/database/app_data.db b/database/app_data.db index 5f7c59d..1b771c4 100644 Binary files a/database/app_data.db and b/database/app_data.db differ diff --git a/views/bank/AccountSettingsWindow.cpp b/views/bank/AccountSettingsWindow.cpp index 4c62262..83b2f29 100644 --- a/views/bank/AccountSettingsWindow.cpp +++ b/views/bank/AccountSettingsWindow.cpp @@ -12,7 +12,7 @@ #include #include "birbank/LoginAndCheckAccountsBirbankScript.h" -#include "common/PaddedItemDelegate.h" +#include "toss/LoginAndCheckAccountsTossScript.h" #include "dao/AccountDAO.h" #include "dao/ApplicationDAO.h" #include "device/EditBankAccountDialog.h" @@ -125,7 +125,9 @@ AccountSettingsWindow::AccountSettingsWindow( if (!m_applicationInfo.pinCode.isEmpty()) { QMessageBox msgBox(this); msgBox.setWindowTitle(tr("Запустить проверку пин-кода?")); - msgBox.setText("Запуститься скрипт проверки входа в банк " + m_applicationInfo.name + " по пин-коду. Окно с настройками закроется."); + msgBox.setText( + "Запуститься скрипт проверки входа в банк " + m_applicationInfo.name + + " по пин-коду. Окно с настройками закроется."); QPushButton *deleteBtn = msgBox.addButton(tr("Запустить"), QMessageBox::AcceptRole); QPushButton *closeBtn = msgBox.addButton(tr("Отмена"), QMessageBox::RejectRole); @@ -205,7 +207,15 @@ void AccountSettingsWindow::startCheckPinCode(const QString &appCode) { connect(worker, &LoginAndCheckAccountsBirbankScript::finished, worker, &QObject::deleteLater); connect(thread, &QThread::finished, thread, &QObject::deleteLater); thread->start(); - } else if (appCode == "ziraat") { + } else if (appCode == "toss") { + const auto thread = new QThread(nullptr); + auto *worker = new LoginAndCheckAccountsTossScript(m_deviceId, appCode, nullptr); + worker->moveToThread(thread); + connect(thread, &QThread::started, worker, &LoginAndCheckAccountsTossScript::start); + connect(worker, &LoginAndCheckAccountsTossScript::finished, thread, &QThread::quit); + connect(worker, &LoginAndCheckAccountsTossScript::finished, worker, &QObject::deleteLater); + connect(thread, &QThread::finished, thread, &QObject::deleteLater); + thread->start(); } }