Enhance error handling, improve UI parsing logic, and refine tap retry workflows across Ozon scripts
This commit is contained in:
parent
01f8801a73
commit
b42fb5eea9
@ -109,6 +109,25 @@ void GetCardInfoScript::doStart() {
|
||||
qDebug() << "[GetCardInfo] Profile info already in DB or username not found, skipping profile parse";
|
||||
}
|
||||
|
||||
// Проверяем что на домашнем экране перед поиском карт
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
if (!xmlScreenParser.isHomeScreen()) {
|
||||
qDebug() << "[GetCardInfo] Not on home screen before card search, restarting...";
|
||||
if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode,
|
||||
device.screenWidth, device.screenHeight)) {
|
||||
m_error = "Cannot reach home screen before card search: " + m_deviceId;
|
||||
qWarning() << m_error;
|
||||
AppLogger::log("ozon/GetCardInfo", m_deviceId, m_error,
|
||||
AdbUtils::captureScreenshotBytes(m_deviceId),
|
||||
"FETCH_PROFILE");
|
||||
AdbUtils::tryToKillApplication(m_deviceId, app.package);
|
||||
emit finishedWithResult(m_error);
|
||||
return;
|
||||
}
|
||||
tryToCloseAllBannersOnHomePage(m_deviceId, device.screenWidth, device.screenHeight);
|
||||
QThread::msleep(500);
|
||||
}
|
||||
|
||||
// Ждём пока все карты подгрузятся — до 5 попыток
|
||||
QList<AccountInfo> cards;
|
||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
@ -194,7 +213,17 @@ void GetCardInfoScript::doStart() {
|
||||
if (freshApp.bankProfileId.isEmpty()) {
|
||||
ns.addExtra("app_id", freshApp.id);
|
||||
ns.postBankProfile();
|
||||
// Проверяем что bankProfileId сохранился
|
||||
const ApplicationInfo afterPost = ApplicationDAO::getApplication(m_deviceId, m_appCode);
|
||||
if (afterPost.bankProfileId.isEmpty()) {
|
||||
const QString err = "postBankProfile failed for " + m_deviceId;
|
||||
qWarning() << "[GetCardInfo]" << err;
|
||||
AppLogger::log("ozon/GetCardInfo", m_deviceId, err,
|
||||
AdbUtils::captureScreenshotBytes(m_deviceId),
|
||||
"FETCH_PROFILE");
|
||||
} else {
|
||||
qDebug() << "[GetCardInfo] postBankProfile done";
|
||||
}
|
||||
} else {
|
||||
ns.addExtra("bank_profile_id", freshApp.bankProfileId);
|
||||
ns.patchBankProfile();
|
||||
@ -227,16 +256,24 @@ void GetCardInfoScript::doStart() {
|
||||
|
||||
AdbUtils::makeTap(m_deviceId, cardBtn.x(), cardBtn.y());
|
||||
|
||||
// Ждём экран карты — ищем "Реквизиты карты" в XML дампе
|
||||
// Ждём экран карты — ищем кнопку "Показать"
|
||||
Node showBtn;
|
||||
for (int attempt = 0; attempt < 10; ++attempt) {
|
||||
QThread::msleep(2000);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
Node reqNode = xmlScreenParser.findTextNode("Реквизиты карты");
|
||||
if (!reqNode.isEmpty()) {
|
||||
|
||||
showBtn = xmlScreenParser.findButtonNode("Показать", false);
|
||||
if (!showBtn.isEmpty()) break;
|
||||
|
||||
// Если всё ещё на домашнем экране — тап не сработал, повторяем
|
||||
if (xmlScreenParser.isHomeScreen()) {
|
||||
cardBtn = xmlScreenParser.findCardButtonByLastNumbers(card.lastNumbers);
|
||||
if (!cardBtn.isEmpty()) {
|
||||
qDebug() << "[GetCardInfo] Still on home screen, re-tapping card" << card.lastNumbers;
|
||||
AdbUtils::makeTap(m_deviceId, cardBtn.x(), cardBtn.y());
|
||||
}
|
||||
}
|
||||
|
||||
qDebug() << "[GetCardInfo] Card screen not loaded, attempt" << attempt + 1 << "/ 10";
|
||||
}
|
||||
|
||||
@ -277,8 +314,27 @@ void GetCardInfoScript::doStart() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// "Подождите" — загрузка в процессе, просто ждём
|
||||
if (!xmlScreenParser.findButtonNode("Подождите", false).isEmpty()) {
|
||||
qDebug() << "[GetCardInfo] 'Подождите' visible, waiting... attempt" << attempt + 1 << "/ 10";
|
||||
continue;
|
||||
}
|
||||
|
||||
// "Скрыть" видна — номер должен быть раскрыт, но парсер не нашёл
|
||||
if (!xmlScreenParser.findButtonNode("Скрыть", false).isEmpty()) {
|
||||
qDebug() << "[GetCardInfo] 'Скрыть' visible but card number not parsed, attempt" << attempt + 1 << "/ 10";
|
||||
continue;
|
||||
}
|
||||
|
||||
// Повторно нажимаем "Показать" если тап не сработал
|
||||
Node retryShowBtn = xmlScreenParser.findButtonNode("Показать", false);
|
||||
if (!retryShowBtn.isEmpty()) {
|
||||
qDebug() << "[GetCardInfo] Re-tapping 'Показать', attempt" << attempt + 1 << "/ 10";
|
||||
AdbUtils::makeTap(m_deviceId, retryShowBtn.x(), retryShowBtn.y());
|
||||
} else {
|
||||
qDebug() << "[GetCardInfo] Card number not visible, attempt" << attempt + 1 << "/ 10";
|
||||
}
|
||||
}
|
||||
|
||||
if (!cardNumber.isEmpty()) {
|
||||
qDebug() << "[GetCardInfo] Card" << card.lastNumbers << "full number:" << cardNumber;
|
||||
@ -288,7 +344,16 @@ void GetCardInfoScript::doStart() {
|
||||
AccountDAO::updateCardNumber(saved.id, cardNumber);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[GetCardInfo] Card number not found for" << card.lastNumbers;
|
||||
const QString err = "Card number not found for " + card.lastNumbers;
|
||||
qWarning() << "[GetCardInfo]" << err;
|
||||
AccountInfo saved = AccountDAO::findAppAccount(m_deviceId, m_appCode, card.lastNumbers);
|
||||
if (saved.id != -1) {
|
||||
AccountDAO::updateAccountById(saved.id, accountStatusToString(AccountStatus::Off),
|
||||
saved.description, saved.currency);
|
||||
}
|
||||
AppLogger::log("ozon/GetCardInfo", m_deviceId, err,
|
||||
AdbUtils::captureScreenshotBytes(m_deviceId),
|
||||
"FETCH_PROFILE");
|
||||
}
|
||||
|
||||
// Возвращаемся на домашний экран для следующей карты
|
||||
@ -314,6 +379,7 @@ void GetCardInfoScript::doStart() {
|
||||
materialBody["bank_profile_id"] = updatedApp.bankProfileId;
|
||||
materialBody["card_number"] = dbCard.cardNumber;
|
||||
materialBody["name"] = updatedApp.fullName;
|
||||
materialBody["state"] = accountStatusToString(dbCard.status) == "active" ? "enabled" : "disabled";
|
||||
ns.setPayload(QJsonDocument(materialBody).toJson());
|
||||
ns.addExtra("account_id", dbCard.id);
|
||||
ns.postMaterial();
|
||||
|
||||
@ -239,6 +239,13 @@ void GetLastTransactionsScript::doStart() {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
detail = xmlScreenParser.parseTransactionDetail();
|
||||
if (!detail.bankTime.isEmpty()) break;
|
||||
|
||||
// Если всё ещё на экране операций — тап не сработал, повторяем
|
||||
if (xmlScreenParser.isTransactionListScreen()) {
|
||||
qDebug() << "[GetLastTransactions] Still on transaction list, re-tapping" << i + 1;
|
||||
AdbUtils::makeTap(m_deviceId, visibleBtn.x(), visibleBtn.y());
|
||||
}
|
||||
|
||||
qDebug() << "[GetLastTransactions] Detail not loaded, attempt" << attempt + 1 << "/ 10";
|
||||
QThread::msleep(1500);
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@
|
||||
#include "dao/ApplicationDAO.h"
|
||||
#include "dao/DeviceDAO.h"
|
||||
#include "net/NetworkService.h"
|
||||
#include "AppLogger.h"
|
||||
|
||||
namespace Ozon {
|
||||
|
||||
@ -141,7 +142,16 @@ void GetProfileInfoScript::doStart() {
|
||||
if (freshApp.bankProfileId.isEmpty()) {
|
||||
ns.addExtra("app_id", freshApp.id);
|
||||
ns.postBankProfile();
|
||||
const ApplicationInfo afterPost = ApplicationDAO::getApplication(m_deviceId, m_appCode);
|
||||
if (afterPost.bankProfileId.isEmpty()) {
|
||||
const QString err = "postBankProfile failed for " + m_deviceId;
|
||||
qWarning() << "[GetProfileInfo]" << err;
|
||||
AppLogger::log("ozon/GetProfileInfo", m_deviceId, err,
|
||||
AdbUtils::captureScreenshotBytes(m_deviceId),
|
||||
"FETCH_PROFILE");
|
||||
} else {
|
||||
qDebug() << "[GetProfileInfo] postBankProfile done";
|
||||
}
|
||||
} else {
|
||||
ns.addExtra("bank_profile_id", freshApp.bankProfileId);
|
||||
ns.patchBankProfile();
|
||||
|
||||
@ -121,7 +121,7 @@ void PayByCardScript::doStart() {
|
||||
// Закрываем баннер "Заказать карту" — тапаем сверху экрана
|
||||
if (Node orderCardNode = xmlScreenParser.findTextNode("Заказать карту"); !orderCardNode.isEmpty()) {
|
||||
qDebug() << "[PayByCard] 'Заказать карту' banner detected, closing...";
|
||||
AdbUtils::makeTap(device.id, device.screenWidth / 2, 100);
|
||||
AdbUtils::makeTap(device.id, device.screenWidth / 2, device.screenHeight / 20);
|
||||
QThread::msleep(1000);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.id, ++m_counter));
|
||||
}
|
||||
|
||||
@ -122,7 +122,7 @@ void PayByPhoneScript::doStart() {
|
||||
// Закрываем баннер "Заказать карту" — тапаем сверху экрана
|
||||
if (Node orderCardNode = xmlScreenParser.findTextNode("Заказать карту"); !orderCardNode.isEmpty()) {
|
||||
qDebug() << "[PayByPhone] 'Заказать карту' banner detected, closing...";
|
||||
AdbUtils::makeTap(device.id, device.screenWidth / 2, 100);
|
||||
AdbUtils::makeTap(device.id, device.screenWidth / 2, device.screenHeight / 20);
|
||||
QThread::msleep(1000);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.id, ++m_counter));
|
||||
}
|
||||
@ -223,7 +223,7 @@ void PayByPhoneScript::makePayment(
|
||||
|
||||
// Проверяем: уже на экране суммы?
|
||||
Node sumTitle = xmlScreenParser.findTextNode("По номеру телефона");
|
||||
if (!sumTitle.isEmpty() && sumTitle.y() < 300) {
|
||||
if (!sumTitle.isEmpty() && sumTitle.y() < height / 7) {
|
||||
sumScreenLoaded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -272,8 +272,8 @@ Node ScreenXmlParser::findUserNameOnHomeScreen(const int screenHeight) {
|
||||
}
|
||||
|
||||
QString ScreenXmlParser::parseProfileFullName() {
|
||||
// Полное имя — TextView ниже зоны заголовка, выше строки с телефоном.
|
||||
// В profile.xml это единственный короткий нейтральный TextView в диапазоне y ≈ 400–750.
|
||||
// Полное имя — первый TextView ниже заголовка "Аккаунт",
|
||||
// который не является известным элементом UI и не содержит спецсимволов.
|
||||
static const QSet<QString> uiLabels = {
|
||||
"Аккаунт", "Мои документы", "Паспорт и ИНН",
|
||||
"Уровень счёта Лимиты и тарифы", "Повысить",
|
||||
@ -283,11 +283,34 @@ QString ScreenXmlParser::parseProfileFullName() {
|
||||
"QR-код для пополнений Принимайте чаевые и донаты",
|
||||
"Добавить Почта"
|
||||
};
|
||||
|
||||
// Находим y-координату заголовка "Аккаунт"
|
||||
int titleY = -1;
|
||||
for (const Node &node : m_nodes) {
|
||||
if (node.className == "android.widget.TextView"
|
||||
&& node.text.trimmed() == "Аккаунт"
|
||||
&& node.width() > 50) {
|
||||
titleY = node.y();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (titleY < 0) return {};
|
||||
|
||||
// Находим y-координату блока с телефоном (ограничение снизу)
|
||||
int phoneY = INT_MAX;
|
||||
for (const Node &node : m_nodes) {
|
||||
if (node.text.contains("Номер телефона")) {
|
||||
phoneY = node.y();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Первый подходящий TextView между заголовком и телефоном
|
||||
for (const Node &node : m_nodes) {
|
||||
if (node.className == "android.widget.TextView"
|
||||
&& !node.text.trimmed().isEmpty()
|
||||
&& node.y() > 400
|
||||
&& node.y() < 750
|
||||
&& node.y() > titleY
|
||||
&& node.y() < phoneY
|
||||
&& !uiLabels.contains(node.text.trimmed())) {
|
||||
return node.text.trimmed();
|
||||
}
|
||||
@ -1333,12 +1356,14 @@ QList<QPair<AccountInfo, Node> > ScreenXmlParser::parseAccountsInfo() {
|
||||
}
|
||||
|
||||
QString ScreenXmlParser::findFullCardNumber() {
|
||||
static const QRegularExpression cardNumberRegex(R"(^\d{4}\s\d{4}\s\d{4}\s\d{4}$)");
|
||||
static const QRegularExpression cardNumberRegex(R"(^\d{4}[\s\x{00A0}\x{202F}]\d{4}[\s\x{00A0}\x{202F}]\d{4}[\s\x{00A0}\x{202F}]\d{4}$)");
|
||||
for (const Node &node : m_nodes) {
|
||||
if (node.className == "android.widget.TextView") {
|
||||
const QString text = node.text.trimmed();
|
||||
if (cardNumberRegex.match(text).hasMatch()) {
|
||||
return QString(text).remove(QChar(' '));
|
||||
QString result = text;
|
||||
result.remove(QChar(' ')).remove(QChar(0x00A0)).remove(QChar(0x202F));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user