#include "GetProfileInfoScript.h" #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 Black { 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("black", "FETCH_PROFILE_INFO", m_deviceId, dumpMeta, &m_error); // Читаем текущий экран xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); // Если не на домашнем экране — перезапускаем if (!xmlScreenParser.isHomeScreen()) { qDebug() << "[Black::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)); } // 1. Тапаем по кнопке "¡Hola!" (аватар с именем) на домашнем экране Node holaNode = xmlScreenParser.findHolaButton(); if (holaNode.isEmpty()) { m_error = "Cannot find Hola button on home screen: " + m_deviceId; qWarning() << m_error; AdbUtils::tryToKillApplication(m_deviceId, app.package); emit finishedWithResult(m_error); return; } // Парсим имя и баланс с домашнего экрана const QString fullName = xmlScreenParser.parseUserNameFromHomeScreen(); const double balance = xmlScreenParser.parseBalanceFromHomeScreen(); qDebug() << "[Black::GetProfileInfo] fullName from home:" << fullName << "balance:" << balance; // Сохраняем баланс BankProfileDAO::updateAmount(app.id, balance); AdbUtils::makeTap(m_deviceId, holaNode.x(), holaNode.y()); QThread::msleep(2000); // 2. Ждём боковое меню bool sideMenuFound = false; for (int attempt = 0; attempt < 5; ++attempt) { xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); 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; } // 3. Тапаем "Tu Información" Node tuInfoNode = xmlScreenParser.findNodeByContentDesc(QString::fromUtf8("Tu Información")); if (tuInfoNode.isEmpty()) { m_error = "Cannot find Tu Información button: " + m_deviceId; qWarning() << m_error; AdbUtils::tryToKillApplication(m_deviceId, app.package); emit finishedWithResult(m_error); return; } AdbUtils::makeTap(m_deviceId, tuInfoNode.x(), tuInfoNode.y()); QThread::msleep(2500); // 4. Ждём страницу профиля "Tu información" bool profileFound = false; for (int attempt = 0; attempt < 5; ++attempt) { xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); if (xmlScreenParser.isProfilePage()) { profileFound = true; break; } QThread::msleep(1000); } if (!profileFound) { m_error = "Profile page not detected: " + m_deviceId; qWarning() << m_error; AdbUtils::tryToKillApplication(m_deviceId, app.package); emit finishedWithResult(m_error); return; } // 5. Парсим данные профиля (первый экран: nombre, apellido, email) const QString nombre = xmlScreenParser.parseProfileNombre(); const QString apellido = xmlScreenParser.parseProfileApellido(); const QString email = xmlScreenParser.parseProfileEmail(); // 6. Скроллим вниз чтобы увидеть телефон const int x = device.screenWidth / 2; const int fromY = device.screenHeight * 3 / 4; const int toY = device.screenHeight / 4; AdbUtils::makeSwipe(m_deviceId, x, fromY, x, toY); QThread::msleep(1500); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter)); const QString phone = xmlScreenParser.parseProfilePhone(); // Собираем полное имя: "имя фамилия" QString parsedFullName; if (!nombre.isEmpty() && !apellido.isEmpty()) { parsedFullName = nombre + " " + apellido; } else if (!nombre.isEmpty()) { parsedFullName = nombre; } else { parsedFullName = fullName; // fallback с домашнего экрана } qDebug() << "[Black::GetProfileInfo] nombre:" << nombre << "apellido:" << apellido << "email:" << email << "phone:" << phone << "fullName:" << parsedFullName; // 7. Сохраняем в БД if (!BankProfileDAO::updateProfileInfo(app.id, parsedFullName, phone, email)) { qWarning() << "[Black::GetProfileInfo] Failed to save profile info to DB"; } // 7. Создаём bank profile если нет createBankProfileIfNeeded(m_deviceId, m_appCode); // 8. Отправляем данные аккаунтов на сервер если нет material_id 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 Black