1
0
forked from BRT/arc
arc/android/ozon/GetProfileInfoScript.cpp
slava 8ed25698e8 Add GetLastTransactionsScript and PayByCardScript implementations for Black app
Implemented `GetLastTransactionsScript` for automated retrieval of transactions, handling home screen navigation, "Ver más" button detection, and transaction list parsing with database storage. Introduced `PayByCardScript` for automated card payments, covering recipient selection, amount input, payment confirmation, and transaction logging. Added XML assets and updates to support these workflows.
2026-03-12 18:42:38 +07:00

168 lines
6.8 KiB
C++

#include "GetProfileInfoScript.h"
#include <QJsonDocument>
#include <QJsonObject>
#include <QMap>
#include <QtGlobal>
#include <QThread>
#include "adb/AdbUtils.h"
#include "dao/AccountDAO.h"
#include "dao/ApplicationDAO.h"
#include "dao/DeviceDAO.h"
#include "net/NetworkService.h"
namespace Ozon {
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() {
const DeviceInfo device = DeviceDAO::getDeviceById(m_deviceId);
const ApplicationInfo app = ApplicationDAO::getApplication(m_deviceId, 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;
}
// Читаем текущий экран
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
// Закрываем рекламный bottom sheet, если открыт (home_ad_1)
if (Node adNode = xmlScreenParser.tryToFindAdBanner(); !adNode.isEmpty()) {
qDebug() << "[GetProfileInfo] Ad banner detected, closing...";
AdbUtils::makeTap(m_deviceId, adNode.x(), adNode.y());
QThread::msleep(1000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
}
// Свежий дамп перед проверкой домашнего экрана
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
// Если мы не на домашнем экране — перезапускаем приложение и вводим пин-код
if (!xmlScreenParser.isHomeScreen()) {
qDebug() << "[GetProfileInfo] Not on home screen, restarting app...";
if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode,
device.screenWidth, device.screenHeight)) {
m_error = "Cannot reach home screen: " + m_deviceId + " " + m_appCode;
qWarning() << m_error;
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
return;
}
// После runAppAndGoToHomeScreen xml уже обновлён внутри метода,
// но делаем свежий дамп, чтобы убедиться
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
}
// Закрываем баннеры на главной, если есть
tryToCloseAllBannersOnHomePage(m_deviceId, device.screenWidth, device.screenHeight);
QThread::msleep(500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
// Находим имя пользователя в верхней части домашнего экрана и тапаем по нему
Node userNameNode = xmlScreenParser.findUserNameOnHomeScreen(device.screenHeight);
if (userNameNode.isEmpty()) {
m_error = "Cannot find user name on home screen: " + m_deviceId;
qWarning() << m_error;
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
return;
}
qDebug() << "[GetProfileInfo] Tapping on user name:" << userNameNode.text
<< "at" << userNameNode.x() << userNameNode.y();
AdbUtils::makeTap(m_deviceId, userNameNode.x(), userNameNode.y());
// Ждём загрузки страницы профиля
QThread::msleep(2500);
// Читаем XML профиля и проверяем что мы действительно там
for (int attempt = 0; attempt < 5; ++attempt) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
if (xmlScreenParser.isProfileScreen()) {
break;
}
QThread::msleep(1000);
}
if (!xmlScreenParser.isProfileScreen()) {
m_error = "Profile screen not detected after tap: " + m_deviceId;
qWarning() << m_error;
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
return;
}
// Извлекаем полное имя и телефон
const QString fullName = xmlScreenParser.parseProfileFullName();
const QString phone = xmlScreenParser.parseProfilePhone().simplified().remove(' ');
qDebug() << "[GetProfileInfo] fullName:" << fullName << "phone:" << phone;
if (!ApplicationDAO::updateProfileInfo(app.id, fullName, phone)) {
m_error = "Failed to save profile info to DB: " + m_deviceId;
qWarning() << m_error;
}
// Отправляем bank_profile на сервер
const ApplicationInfo freshApp = ApplicationDAO::getApplication(m_deviceId, m_appCode);
const QMap<QString, int> currencyCodes = {
{"RUB", 643}, {"USD", 840}, {"KRW", 410}, {"AZN", 944}, {"ARS", 32}
};
const int currencyCode = currencyCodes.value(freshApp.currency.toUpper(), 643);
const QStringList parts = fullName.split(' ', Qt::SkipEmptyParts);
QJsonObject profileBody;
profileBody["first_name"] = parts.value(0);
profileBody["middle_name"] = parts.size() >= 3 ? parts.value(1) : "";
profileBody["last_name"] = parts.size() >= 3 ? parts.value(2) : parts.value(1);
profileBody["bank_name"] = m_appCode;
profileBody["phone_number"] = phone;
profileBody["balance"] = QString::number(qRound64(freshApp.amount * 100));
profileBody["state"] = (freshApp.status == "active") ? "enabled" : "disabled";
profileBody["currency"] = currencyCode;
NetworkService ns;
ns.setDeviceId(m_deviceId);
ns.setPayload(QJsonDocument(profileBody).toJson());
if (freshApp.bankProfileId.isEmpty()) {
ns.addExtra("app_id", freshApp.id);
ns.postBankProfile();
qDebug() << "[GetProfileInfo] postBankProfile done";
} else {
ns.addExtra("bank_profile_id", freshApp.bankProfileId);
ns.patchBankProfile();
qDebug() << "[GetProfileInfo] patchBankProfile done";
}
// Отправляем данные аккаунтов на сервер если нет material_id
const QList<AccountInfo> allAccounts = AccountDAO::getAccounts(m_deviceId, m_appCode);
QList<QPair<AccountInfo, Node>> accountsToPost;
for (const auto &acc : allAccounts) {
if (acc.materialId.isEmpty()) {
accountsToPost.append({acc, Node()});
}
}
if (!accountsToPost.isEmpty()) {
postAccountsData(accountsToPost);
}
AdbUtils::tryToKillApplication(m_deviceId, app.package);
emit finishedWithResult(m_error);
}
} // namespace Ozon