#include "GetProfileInfoScript.h" #include #include #include #include #include "adb/AdbUtils.h" #include "dao/MaterialDAO.h" #include "dao/BankProfileDAO.h" #include "dao/DeviceDAO.h" #include "dump/TaskDumpRecorder.h" #include "net/NetworkService.h" namespace Dushanbe { GetProfileInfoScript::GetProfileInfoScript( QString deviceId, QString appCode, QObject *parent ) : CommonScript(parent), m_deviceId(std::move(deviceId)), m_appCode(std::move(appCode)) { } GetProfileInfoScript::~GetProfileInfoScript() = default; void GetProfileInfoScript::doStart() { DeviceInfo device = DeviceDAO::getDeviceById(m_deviceId); if (device.id.isEmpty()) device = DeviceDAO::findByAdbSerial(m_deviceId); if (!device.adbSerial.isEmpty()) m_deviceId = device.adbSerial; const BankProfileInfo app = BankProfileDAO::getApplication(device.id, m_appCode); 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; } const TaskDumpMeta dumpMeta{}; TaskDumpRecorder::Scope dumpScope("dushanbe", "FETCH_PROFILE_INFO", m_deviceId, dumpMeta, &m_error); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); if (!xmlScreenParser.isHomeScreen()) { qDebug() << "[Dushanbe::GetProfileInfo] Not on home screen, restarting app..."; if (!runAppAndGoToHomeScreen(m_deviceId, app.package, app.pinCode, device.screenWidth, device.screenHeight)) { m_error = "Cannot reach home screen: " + device.name + " (" + m_deviceId + ") " + m_appCode; qWarning() << m_error; AdbUtils::tryToKillApplication(m_deviceId, app.package); emit finishedWithResult(m_error); return; } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); } // Всегда тапаем кнопку обновления — баланс на экране может быть закэширован // и не отражать актуальное состояние счёта. Лоадера у refresh нет, // поэтому ждём фиксированно. Node refreshBtn = xmlScreenParser.findRefreshButtonOnHomeScreen(); if (refreshBtn.x() > 0) { qDebug() << "[Dushanbe::GetProfileInfo] Tapping refresh to get up-to-date balance"; AdbUtils::makeTap(m_deviceId, refreshBtn.x(), refreshBtn.y()); QThread::msleep(3000); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); } else { qWarning() << "[Dushanbe::GetProfileInfo] Refresh button not found, parsing as-is"; } const double parsedBalance = xmlScreenParser.parseBalanceFromHomeScreen(); qDebug() << "[Dushanbe::GetProfileInfo] Parsed balance after refresh:" << parsedBalance; if (parsedBalance <= 0.0) { m_error = "Balance is zero after refresh: " + m_deviceId + " " + m_appCode; qWarning() << m_error; AdbUtils::tryToKillApplication(m_deviceId, app.package); emit finishedWithResult(m_error); return; } BankProfileDAO::updateAmount(app.id, parsedBalance); // Тапаем по кнопке меню (гамбургер, левый верхний угол) // Это первый clickable ImageView в верхней панели Node menuButton; for (const Node &node : xmlScreenParser.findAllNodes()) { if (node.className == "android.widget.ImageView" && node.clickable && node.y() < 300) { menuButton = node; break; } } if (menuButton.x() == 0 && menuButton.y() == 0) { m_error = "Cannot find menu button: " + m_deviceId; qWarning() << m_error; AdbUtils::tryToKillApplication(m_deviceId, app.package); emit finishedWithResult(m_error); return; } AdbUtils::makeTap(m_deviceId, menuButton.x(), menuButton.y()); QThread::msleep(2000); // Ждём боковое меню bool sideMenuFound = false; for (int attempt = 0; attempt < 5; ++attempt) { xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight); if (xmlScreenParser.isSideMenu()) { sideMenuFound = true; break; } QThread::msleep(1000); } if (!sideMenuFound) { m_error = "Side menu not detected: " + m_deviceId; qWarning() << m_error; AdbUtils::tryToKillApplication(m_deviceId, app.package); emit finishedWithResult(m_error); return; } // Парсим ФИО и телефон из бокового меню const QString fullName = xmlScreenParser.parseProfileFullName(); QString phone = xmlScreenParser.parseProfilePhone(); phone.remove(QRegularExpression("[^0-9+]")); qDebug() << "[Dushanbe::GetProfileInfo] fullName:" << fullName << "phone:" << phone; if (!fullName.isEmpty()) { BankProfileDAO::updateProfileInfo(app.id, fullName, phone, ""); } if (const QString err = createBankProfileIfNeeded(device.id, m_appCode, parsedBalance); !err.isEmpty()) { m_error = err; emit finishedWithResult(m_error); return; } const QList allAccounts = MaterialDAO::getAccounts(device.id, m_appCode); QList> accountsToPost; for (const auto &acc : allAccounts) { if (acc.materialId.isEmpty()) { accountsToPost.append({acc, Node()}); } } if (!accountsToPost.isEmpty()) { postAccountsData(accountsToPost); } emit finishedWithResult(m_error); } } // namespace Dushanbe