From 41bb5e33fd9488a8bc615899b7206fe8a6f52bee Mon Sep 17 00:00:00 2001 From: slava Date: Mon, 6 Apr 2026 17:02:52 +0700 Subject: [PATCH] Add pause/resume functionality for active profiles in `AccountSettingsWindow` and improve automation scripts with OCR-based transaction ID extraction, card balance waits, and absolute value handling in event parsing. --- android/dushanbe/GetCardInfoScript.cpp | 4 ++ android/ozon/GetLastTransactionsScript.cpp | 41 ++++++++++++++++++++ services/DeviceScreener.cpp | 12 ++---- services/EventHandler.cpp | 2 +- views/bank/AccountSettingsWindow.cpp | 44 ++++++++++++++++++++++ views/bank/AccountSettingsWindow.h | 4 ++ 6 files changed, 98 insertions(+), 9 deletions(-) diff --git a/android/dushanbe/GetCardInfoScript.cpp b/android/dushanbe/GetCardInfoScript.cpp index a62577b..b4ffb19 100644 --- a/android/dushanbe/GetCardInfoScript.cpp +++ b/android/dushanbe/GetCardInfoScript.cpp @@ -133,6 +133,10 @@ void GetCardInfoScript::doStart() { continue; } + // Ждём загрузки баланса (может быть 0 пока данные подтягиваются) + QThread::msleep(1500); + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); + QString fullNumber = xmlScreenParser.parseFullCardNumber(); const double cardBalance = xmlScreenParser.parseCardDetailBalance(); const QString holder = xmlScreenParser.parseCardDetailHolder(); diff --git a/android/ozon/GetLastTransactionsScript.cpp b/android/ozon/GetLastTransactionsScript.cpp index be38ee9..3ee67da 100644 --- a/android/ozon/GetLastTransactionsScript.cpp +++ b/android/ozon/GetLastTransactionsScript.cpp @@ -260,6 +260,45 @@ void GetLastTransactionsScript::searchTransaction(const DeviceInfo &device, int << "amount=" << parsed.amount << "time=" << dtStr << "name=" << detail.name; + // Пробуем получить ID через "Документы" → OCR + QString externalId = detail.bankTrExternalId; + if (externalId.isEmpty()) { + Node docBtn = xmlScreenParser.findButtonNode("Документы", false); + if (!docBtn.isEmpty()) { + qDebug() << "[FetchTransactions] Tapping 'Документы'..."; + AdbUtils::makeTap(m_deviceId, docBtn.x(), docBtn.y()); + QThread::msleep(2000); + + bool docLoaded = false; + for (int da = 0; da < 15; ++da) { + xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); + if (!xmlScreenParser.findNodeByContentDesc("Поделиться").isEmpty()) { + docLoaded = true; + break; + } + QThread::msleep(1500); + } + + if (docLoaded) { + QThread::msleep(500); + const QByteArray screenshot = AdbUtils::captureScreenshotBytes(m_deviceId); + if (!screenshot.isEmpty()) { + const QString ocrText = recognizeTextFromImage(screenshot); + if (!ocrText.isEmpty()) { + qDebug() << "[FetchTransactions] OCR result:" << ocrText; + externalId = extractTransactionId(ocrText); + if (!externalId.isEmpty()) { + qDebug() << "[FetchTransactions] Extracted ID:" << externalId; + } + } + } + } + + AdbUtils::goBack(m_deviceId); + QThread::msleep(1000); + } + } + // Сохраняем if (accountId != -1) { TransactionInfo tx; @@ -267,6 +306,7 @@ void GetLastTransactionsScript::searchTransaction(const DeviceInfo &device, int tx.amount = parsed.amount; tx.bankName = m_appCode; tx.bankTime = dtStr; + tx.bankTrExternalId = externalId; tx.status = TransactionStatus::Complete; tx.timestamp = DateUtils::getUtcNow(); if (txTime.isValid()) tx.completeTime = txTime; @@ -352,6 +392,7 @@ void GetLastTransactionsScript::scanRecentTransactions(const DeviceInfo &device, tx.bankName = m_appCode; tx.bankTime = detail.bankTime; + tx.bankTrExternalId = detail.bankTrExternalId; tx.status = TransactionStatus::Complete; tx.timestamp = DateUtils::getUtcNow(); if (!detail.name.isEmpty()) tx.name = detail.name; diff --git a/services/DeviceScreener.cpp b/services/DeviceScreener.cpp index ea06513..b4123b9 100644 --- a/services/DeviceScreener.cpp +++ b/services/DeviceScreener.cpp @@ -373,14 +373,10 @@ void DeviceScreener::start() { qDebug() << "Cant update device"; } - if (!isChecked) { - // Новое устройство — проверяем приложения (после upsert, чтобы FK не падал) - QSet apps = AdbUtils::getListApps(adbSerial); - if (!BankProfileDAO::checkInstalledApps(device.id, apps)) { - qWarning() << "Cant check installed apps"; - } else { - qDebug() << "Apps checked:" << device.id; - } + // Проверяем установленные приложения каждый цикл + QSet apps = AdbUtils::getListApps(adbSerial); + if (!BankProfileDAO::checkInstalledApps(device.id, apps)) { + qWarning() << "Cant check installed apps"; } } diff --git a/services/EventHandler.cpp b/services/EventHandler.cpp index 5412c9c..a4e7a58 100644 --- a/services/EventHandler.cpp +++ b/services/EventHandler.cpp @@ -447,7 +447,7 @@ void EventHandler::startThreadForTask(const MaterialInfo &account, const EventIn // Парсим amount и created_at из body задачи const QJsonObject taskJson = QJsonDocument::fromJson(event.json.toUtf8()).object(); const QJsonObject body = taskJson["body"].toObject(); - const double searchAmount = body["amount"].toDouble() / 100.0; // копейки → рубли + const double searchAmount = qAbs(body["amount"].toDouble()) / 100.0; // копейки → рубли (абс. значение) const QDateTime searchTime = QDateTime::fromString(body["created_at"].toString(), Qt::ISODate); if (appCode == "ozon") diff --git a/views/bank/AccountSettingsWindow.cpp b/views/bank/AccountSettingsWindow.cpp index b73af98..56a8476 100644 --- a/views/bank/AccountSettingsWindow.cpp +++ b/views/bank/AccountSettingsWindow.cpp @@ -292,6 +292,7 @@ void AccountSettingsWindow::startCheckPinCode() { void AccountSettingsWindow::startGetProfileInfo() { m_profileBtn->setEnabled(false); m_cardsBtn->setEnabled(false); + pauseActiveProfiles(); auto *thread = new QThread(nullptr); const QString deviceId = m_deviceId; @@ -301,6 +302,7 @@ void AccountSettingsWindow::startGetProfileInfo() { QMetaObject::invokeMethod(this, [this, appCode]() { m_profileBtn->setEnabled(true); m_cardsBtn->setEnabled(true); + resumePausedProfiles(); m_app = BankProfileDAO::getApplication(m_deviceId, appCode); updateStatusUI(); }, Qt::QueuedConnection); @@ -343,6 +345,7 @@ void AccountSettingsWindow::startGetProfileInfo() { void AccountSettingsWindow::startGetCardInfo() { m_profileBtn->setEnabled(false); m_cardsBtn->setEnabled(false); + pauseActiveProfiles(); auto *thread = new QThread(nullptr); const QString deviceId = m_deviceId; @@ -352,6 +355,7 @@ void AccountSettingsWindow::startGetCardInfo() { QMetaObject::invokeMethod(this, [this]() { m_profileBtn->setEnabled(true); m_cardsBtn->setEnabled(true); + resumePausedProfiles(); reloadCards(); }, Qt::QueuedConnection); }; @@ -537,3 +541,43 @@ void AccountSettingsWindow::reloadCards() { m_cardsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); m_cardsTable->resizeRowsToContents(); } + +// ── Pause/Resume active profiles ─────────────────────────────────────────── + +static void toggleProfileOnServer(const BankProfileInfo &app, bool enable) { + if (app.bankProfileId.isEmpty()) return; + auto *thread = new QThread; + auto *net = new NetworkService; + net->moveToThread(thread); + net->addExtra("bank_profile_id", app.bankProfileId); + net->addExtra("enable", enable); + QObject::connect(thread, &QThread::started, net, &NetworkService::toggleBankProfile); + QObject::connect(net, &NetworkService::finished, thread, &QThread::quit); + QObject::connect(net, &NetworkService::finished, net, &QObject::deleteLater); + QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater); + thread->start(); +} + +void AccountSettingsWindow::pauseActiveProfiles() { + const QList apps = BankProfileDAO::getApplicationsByDeviceId(m_deviceId); + for (const BankProfileInfo &app : apps) { + if (app.status == "active") { + m_pausedProfiles.append(app.code); + BankProfileDAO::update(app.id, app.pinCode, app.comment, "off"); + toggleProfileOnServer(app, false); + qDebug() << "[AccountSettings] Paused profile:" << app.code; + } + } +} + +void AccountSettingsWindow::resumePausedProfiles() { + for (const QString &code : m_pausedProfiles) { + const BankProfileInfo app = BankProfileDAO::getApplication(m_deviceId, code); + if (app.id >= 0 && app.status == "off") { + BankProfileDAO::update(app.id, app.pinCode, app.comment, "active"); + toggleProfileOnServer(app, true); + qDebug() << "[AccountSettings] Resumed profile:" << app.code; + } + } + m_pausedProfiles.clear(); +} diff --git a/views/bank/AccountSettingsWindow.h b/views/bank/AccountSettingsWindow.h index b2509e1..015dd9a 100644 --- a/views/bank/AccountSettingsWindow.h +++ b/views/bank/AccountSettingsWindow.h @@ -47,6 +47,10 @@ private: void toggleMaterialStatus(const MaterialInfo &account); void reloadCards(); + QStringList m_pausedProfiles; + void pauseActiveProfiles(); + void resumePausedProfiles(); + protected: void resizeEvent(QResizeEvent *event) override; };