169 lines
6.9 KiB
C++
169 lines
6.9 KiB
C++
#include "GetCardInfoScript.h"
|
||
|
||
#include <QThread>
|
||
|
||
#include <QJsonDocument>
|
||
#include <QJsonObject>
|
||
|
||
#include "adb/AdbUtils.h"
|
||
#include "dao/MaterialDAO.h"
|
||
#include "dao/BankProfileDAO.h"
|
||
#include "dao/DeviceDAO.h"
|
||
#include "dump/TaskDumpRecorder.h"
|
||
#include "net/NetworkService.h"
|
||
#include "net/MaterialPayload.h"
|
||
|
||
namespace Black {
|
||
|
||
GetCardInfoScript::GetCardInfoScript(
|
||
QString deviceId,
|
||
QString appCode,
|
||
QObject *parent
|
||
) : CommonScript(parent),
|
||
m_deviceId(std::move(deviceId)),
|
||
m_appCode(std::move(appCode)) {
|
||
}
|
||
|
||
GetCardInfoScript::~GetCardInfoScript() = default;
|
||
|
||
void GetCardInfoScript::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{{}, 0, {}, {}, app.bankProfileId, app.phone, device.id};
|
||
TaskDumpRecorder::Scope dumpScope("black", "FETCH_CARDS", m_deviceId, dumpMeta, &m_error);
|
||
|
||
// Читаем текущий экран
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
|
||
|
||
// Если не на домашнем экране — перезапускаем
|
||
if (!xmlScreenParser.isHomeScreen()) {
|
||
qDebug() << "[Black::GetCardInfo] 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));
|
||
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
|
||
}
|
||
|
||
// 1. Парсим баланс с домашнего экрана
|
||
const double balance = xmlScreenParser.parseBalanceFromHomeScreen();
|
||
qDebug() << "[Black::GetCardInfo] balance from home:" << balance;
|
||
BankProfileDAO::updateAmount(app.id, balance);
|
||
|
||
// 2. Нажимаем "Tu CVU" на домашнем экране
|
||
Node cvuButton = xmlScreenParser.findButtonNode("Tu CVU", false);
|
||
if (cvuButton.isEmpty()) {
|
||
m_error = "Cannot find Tu CVU button: " + m_deviceId;
|
||
qWarning() << m_error;
|
||
AdbUtils::tryToKillApplication(m_deviceId, app.package);
|
||
emit finishedWithResult(m_error);
|
||
return;
|
||
}
|
||
|
||
AdbUtils::makeTap(m_deviceId, cvuButton.x(), cvuButton.y());
|
||
QThread::msleep(2000);
|
||
|
||
// 3. Ждём экран CVU
|
||
bool cvuScreenFound = 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.isCVUScreen()) {
|
||
cvuScreenFound = true;
|
||
break;
|
||
}
|
||
QThread::msleep(1000);
|
||
}
|
||
|
||
if (!cvuScreenFound) {
|
||
m_error = "CVU screen not detected: " + m_deviceId;
|
||
qWarning() << m_error;
|
||
AdbUtils::tryToKillApplication(m_deviceId, app.package);
|
||
emit finishedWithResult(m_error);
|
||
return;
|
||
}
|
||
|
||
// 4. Парсим номер CVU
|
||
const QString cvuNumber = xmlScreenParser.parseCVUNumber();
|
||
qDebug() << "[Black::GetCardInfo] CVU number:" << cvuNumber;
|
||
|
||
if (cvuNumber.isEmpty()) {
|
||
m_error = "Cannot parse CVU number: " + m_deviceId;
|
||
qWarning() << m_error;
|
||
AdbUtils::tryToKillApplication(m_deviceId, app.package);
|
||
emit finishedWithResult(m_error);
|
||
return;
|
||
}
|
||
|
||
// 5. Сохраняем аккаунт в БД (lastNumbers = последние 4 цифры CVU)
|
||
const QString lastNumbers = cvuNumber.right(4);
|
||
|
||
MaterialInfo account;
|
||
account.deviceId = device.id;
|
||
account.appCode = m_appCode;
|
||
account.lastNumbers = lastNumbers;
|
||
account.cardNumber = cvuNumber;
|
||
account.amount = balance;
|
||
account.currency = "ARS";
|
||
account.description = "CVU";
|
||
account.status = MaterialStatus::Off;
|
||
account.updateTime = QDateTime::currentDateTimeUtc();
|
||
|
||
if (!MaterialDAO::upsertAccount(account)) {
|
||
qWarning() << "[Black::GetCardInfo] Failed to upsert account";
|
||
}
|
||
|
||
// 6. Отправляем материал на сервер.
|
||
// Инвариант: на сервере одновременно живёт максимум один материал на (deviceId, appCode) —
|
||
// тот, что локально active. Пушим только active-карту и только если другой
|
||
// материал ещё не синхронизирован.
|
||
const MaterialInfo savedAccount = MaterialDAO::findAppAccount(device.id, m_appCode, lastNumbers);
|
||
const BankProfileInfo updatedApp = BankProfileDAO::getApplication(device.id, m_appCode);
|
||
|
||
if (savedAccount.id != -1 && !updatedApp.bankProfileId.isEmpty()) {
|
||
if (savedAccount.status != MaterialStatus::Active) {
|
||
qDebug() << "[Black::GetCardInfo] CVU" << lastNumbers << "is off, not pushing to server";
|
||
} else if (!savedAccount.materialId.isEmpty()) {
|
||
qDebug() << "[Black::GetCardInfo] material already synced for CVU" << lastNumbers << ", skipping";
|
||
} else {
|
||
bool otherSynced = false;
|
||
for (const MaterialInfo &m : MaterialDAO::getAccounts(device.id, m_appCode)) {
|
||
if (m.id != savedAccount.id && !m.materialId.isEmpty()) { otherSynced = true; break; }
|
||
}
|
||
if (otherSynced) {
|
||
qDebug() << "[Black::GetCardInfo] another material already synced in app, skipping POST for CVU" << lastNumbers;
|
||
} else {
|
||
NetworkService ns;
|
||
ns.setDeviceId(m_deviceId);
|
||
ns.setPayload(buildMaterialPayload(savedAccount, updatedApp));
|
||
ns.addExtra("account_id", savedAccount.id);
|
||
ns.postMaterial();
|
||
qDebug() << "[Black::GetCardInfo] postMaterial done for CVU" << lastNumbers;
|
||
}
|
||
}
|
||
} else {
|
||
qWarning() << "[Black::GetCardInfo] bankProfileId empty or account not found, skipping material";
|
||
}
|
||
|
||
qDebug() << "[Black::GetCardInfo] Done. CVU:" << cvuNumber << "balance:" << balance;
|
||
|
||
AdbUtils::tryToKillApplication(m_deviceId, app.package);
|
||
emit finishedWithResult(m_error);
|
||
}
|
||
|
||
} // namespace Black
|