Added handling for event types (Balance, Phone) and respective processing logic in EventHandler. Introduced support for tracking and updating event statuses both locally and through network APIs. Enhanced data integrity and clarity by expanding the EventInfo model and associated database management.
337 lines
15 KiB
C++
337 lines
15 KiB
C++
#include "PayByPhoneScript.h"
|
||
|
||
#include <QRandomGenerator>
|
||
#include <QThread>
|
||
#include <utility>
|
||
|
||
#include "DatabaseManager.h"
|
||
#include "adb/AdbUtils.h"
|
||
#include "dao/AccountDAO.h"
|
||
#include "dao/ApplicationDAO.h"
|
||
#include "dao/DeviceDAO.h"
|
||
#include "dao/TransactionDAO.h"
|
||
#include "db/ApplicationInfo.h"
|
||
#include "db/DeviceInfo.h"
|
||
|
||
PayByPhoneScript::PayByPhoneScript(
|
||
AccountInfo account,
|
||
QString phone,
|
||
QString bankName,
|
||
const double amount,
|
||
QObject *parent
|
||
) : CommonScript(parent),
|
||
m_account(std::move(account)), m_phone(std::move(phone)),
|
||
m_bankName(std::move(bankName)), m_amount(amount) {
|
||
}
|
||
|
||
PayByPhoneScript::~PayByPhoneScript() = default;
|
||
|
||
|
||
void PayByPhoneScript::makePayment(
|
||
const QString &deviceId,
|
||
const QString &pinCode,
|
||
int width,
|
||
int height
|
||
) {
|
||
// Оплата со страницы карты
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
Node payBtn = xmlScreenParser.findButtonNode("Оплатить", false);
|
||
if (!payBtn.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, payBtn.x(), payBtn.y());
|
||
QThread::msleep(1000);
|
||
} else {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_pay_btn_not_found");
|
||
m_error = "Кнопка 'Оплатить' не нашлась";
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
// TODO - По номеру карты В РСХБ и другие банки
|
||
Node payTitle = xmlScreenParser.findTextNode("Платежи и переводы");
|
||
if (!payTitle.isEmpty() && payTitle.y() < 300) {
|
||
Node payByPhoneBtn = xmlScreenParser.findButtonNode("По номеру телефона В РСХБ и через", false);
|
||
if (!payByPhoneBtn.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, payByPhoneBtn.x(), payByPhoneBtn.y());
|
||
QThread::msleep(1000);
|
||
} else {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_not_found_pay_by_phone");
|
||
m_error = "Не смогли найти пункт 'По номеру телефона В РСХБ и через'";
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
} else {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_cant_go_to_payments");
|
||
m_error = "Не смогли перейти на экран 'Платежи и переводы'";
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
Node payByPhoneTitle = xmlScreenParser.findTextNode("Перевод по телефону");
|
||
Node continueBtn = xmlScreenParser.findButtonNode("Продолжить", false);
|
||
if (!payByPhoneTitle.isEmpty() && payByPhoneTitle.y() < 300 && continueBtn.isEmpty()) {
|
||
Node inputPhone = xmlScreenParser.findFirstEditText();
|
||
AdbUtils::makeTap(deviceId, inputPhone.x(), inputPhone.y());
|
||
QThread::msleep(500);
|
||
AdbUtils::inputText(deviceId, m_phone);
|
||
QThread::msleep(1000);
|
||
} else {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_cant_find_pay_by_phone");
|
||
m_error = "Не смогли найти пункт 'Перевод по телефону'";
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
QString payBankName = m_bankName == QStringLiteral("Россельхозбанк") ? "Россельхозбанк" : "Другой банк через СБП";
|
||
Node payOtherBankBtn = xmlScreenParser.findButtonNode(payBankName, false);
|
||
if (!payOtherBankBtn.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, payOtherBankBtn.x(), payOtherBankBtn.y());
|
||
QThread::msleep(1000);
|
||
} else {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_cant_tap_on_bank");
|
||
m_error = "Не смогли нажать на первичный выбор банка";
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
|
||
if (m_bankName != QStringLiteral("Россельхозбанк")) {
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
for (int i = 0; i < 5; ++i) {
|
||
Node allBanksTitle = xmlScreenParser.findTextNode("Банки участники");
|
||
if (!allBanksTitle.isEmpty() && allBanksTitle.y() < 300) {
|
||
Node inputBankName = xmlScreenParser.findFirstEditText();
|
||
AdbUtils::makeTap(deviceId, inputBankName.x(), inputBankName.y());
|
||
QThread::msleep(500);
|
||
AdbUtils::enableAdbIMEKeyboard(deviceId);
|
||
AdbUtils::inputAdbIMEText(deviceId, m_bankName);
|
||
AdbUtils::disableAdbIMEKeyboard(deviceId);
|
||
QThread::msleep(1000);
|
||
break;
|
||
} else {
|
||
qDebug() << "--- allBanksTitle not found, i: " << i;
|
||
}
|
||
QThread::msleep(1000);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
}
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
for (int i = 0; i < 5; ++i) {
|
||
Node bankNameListItem = xmlScreenParser.findTextNode(m_bankName);
|
||
if (!bankNameListItem.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, bankNameListItem.x(), bankNameListItem.y());
|
||
QThread::msleep(1000);
|
||
break;
|
||
} else {
|
||
qDebug() << "--- bankNameListItem not found, i: " << i;
|
||
}
|
||
QThread::msleep(1000);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
}
|
||
}
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
|
||
const bool isRshbBank = m_bankName == QStringLiteral("Россельхозбанк");
|
||
QString payByPhoneScreenTitleText = isRshbBank ? "Перевод клиенту РСХБ" : "Перевод по телефону";
|
||
Node payByPhoneScreenTitle = xmlScreenParser.findTextNode(payByPhoneScreenTitleText);
|
||
Node continuePayBtn = xmlScreenParser.findButtonNode("Продолжить", false);
|
||
|
||
if (isRshbBank ||
|
||
!payByPhoneScreenTitle.isEmpty() && payByPhoneScreenTitle.y() < 300 && !continuePayBtn.isEmpty()) {
|
||
Node sumBtn = xmlScreenParser.findButtonNode("0", false);
|
||
if (isRshbBank || !sumBtn.isEmpty()) {
|
||
if (!isRshbBank) {
|
||
AdbUtils::makeTap(deviceId, sumBtn.x(), sumBtn.y());
|
||
QThread::msleep(500);
|
||
}
|
||
AdbUtils::inputText(deviceId, QString::number(m_amount));
|
||
QThread::msleep(500);
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
Node readyBtn = xmlScreenParser.findTextNode("Готово");
|
||
if (!readyBtn.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, readyBtn.x(), readyBtn.y());
|
||
QThread::msleep(500);
|
||
if (isRshbBank) {
|
||
QThread::msleep(1000);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
continuePayBtn = xmlScreenParser.findButtonNode("Продолжить", false);
|
||
}
|
||
AdbUtils::makeTap(deviceId, continuePayBtn.x(), continuePayBtn.y());
|
||
QThread::msleep(1000);
|
||
} else {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_cant_tap_on_ready");
|
||
m_error = "Не смогли нажать 'Готово'";
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
} else {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_cant_tap_on_continue");
|
||
m_error = "Не смогли нажать 'Продолжить'";
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
} else {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_cant_find_bank_title");
|
||
m_error = "Не смогли найти заголовок: " + payByPhoneScreenTitleText;
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
bool inputedPinCode = false;
|
||
for (int i = 0; i < 5; ++i) {
|
||
// TODO кнопка содержит "Перевести 10 ₽" если будет от 1000 то скорее всвего будет "Перевести 1 000 ₽",
|
||
// TODO не ясно как форматирование будет, поэтому пока на начало зашьем
|
||
Node makePayBtn = xmlScreenParser.findButtonNode("Перевести ", true);
|
||
if (!makePayBtn.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, makePayBtn.x(), makePayBtn.y());
|
||
QThread::msleep(500);
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
if (const QList<Node> pincode = xmlScreenParser.tryToFindPinCode(pinCode, "Введите код доступа");
|
||
pincode.size() == 4) {
|
||
inputPinCode(deviceId, pincode);
|
||
inputedPinCode = true;
|
||
// После ввода пин-кода, ждем 3с
|
||
QThread::msleep(3000);
|
||
}
|
||
break;
|
||
} else {
|
||
qWarning() << "--- makePayBtn not found, i: " << i;
|
||
}
|
||
QThread::msleep(1000);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
}
|
||
|
||
if (!isRshbBank && !inputedPinCode) {
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_cant_input_pin_code");
|
||
m_error = "Не смогли ввести пин-код!'";
|
||
qDebug() << m_error;
|
||
return;
|
||
}
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
|
||
for (int i = 0; i < 10; ++i) {
|
||
Node moreDetailBtn = xmlScreenParser.findButtonNode("Детали операции", false);
|
||
if (!moreDetailBtn.isEmpty()) {
|
||
AdbUtils::makeTap(deviceId, moreDetailBtn.x(), moreDetailBtn.y());
|
||
QThread::msleep(200);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
|
||
// TODO считываем все данные по переводу
|
||
TransactionInfo transaction = xmlScreenParser.parseTransactionInfo(width, height);
|
||
if (isRshbBank) {
|
||
transaction.bankName = m_bankName;
|
||
}
|
||
transaction.accountId = m_account.id;
|
||
transaction.amount = -m_amount;
|
||
transaction.type = TransactionType::Phone;
|
||
transaction.id = TransactionDAO::insertTransaction(transaction);
|
||
if (transaction.id == -1) {
|
||
// FIXME alert!!
|
||
qDebug() << "Transaction has not inserted...";
|
||
}
|
||
|
||
// ждем 10 секунд смену статуса
|
||
for (int k = 0; k < 10; ++k) {
|
||
Node paymentCompleted = xmlScreenParser.findTextNode("Исполнен", 0, 0, width, height / 2);
|
||
if (!paymentCompleted.isEmpty()) {
|
||
transaction.status = TransactionStatus::Complete;
|
||
if (!TransactionDAO::updateTransactionStatus(transaction.id, TransactionStatus::Complete)) {
|
||
qDebug() << "Not updated: " << transaction.id;
|
||
}
|
||
// TODO обновляем данные
|
||
break;
|
||
}
|
||
|
||
QThread::msleep(1000);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
}
|
||
|
||
postNewTransactionData(m_account, transaction);
|
||
|
||
AdbUtils::takeScreenshot(deviceId, "pay_by_phone_finish_transactions_" + transaction.id);
|
||
AdbUtils::takeXmlDump(deviceId, "pay_by_phone_finish_transactions_" + transaction.id);
|
||
break;
|
||
} else {
|
||
qWarning() << "--- moreDetailBtn not found, i: " << i;
|
||
}
|
||
QThread::msleep(1000);
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||
}
|
||
|
||
Node homeBtn = xmlScreenParser.findButtonNode("Вернуться на главную", false);
|
||
AdbUtils::makeTap(deviceId, homeBtn.x(), homeBtn.y());
|
||
QThread::msleep(1000);
|
||
}
|
||
|
||
void PayByPhoneScript::doStart() {
|
||
const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);
|
||
const ApplicationInfo app = ApplicationDAO::getApplication(m_account.deviceId, m_account.appCode);
|
||
|
||
if (device.id.isEmpty() || app.id == -1) {
|
||
m_error = "Device or app not found....";
|
||
qDebug() << m_error;
|
||
emit finishedWithResult(m_error);
|
||
return;
|
||
}
|
||
|
||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||
if (!xmlScreenParser.isHomeScreen()) {
|
||
if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode, device.screenWidth, device.screenHeight)) {
|
||
m_error = "Не смогли дойти до домашней страницы";
|
||
qDebug() << m_error;
|
||
emit finishedWithResult(m_error);
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (goToAllProducts(device.id, device.screenWidth, device.screenHeight)) {
|
||
QList<QPair<AccountInfo, Node> > accounts = xmlScreenParser.parseAccountsInfo();
|
||
for (auto &[account, node]: accounts) {
|
||
account.deviceId = m_account.deviceId;
|
||
account.appCode = m_account.appCode;
|
||
account.status = account.amount > 0 ? AccountStatus::Active : AccountStatus::Blocked;
|
||
if (!AccountDAO::upsertAccount(account)) {
|
||
qDebug() << "Not updated: " << account.lastNumbers;
|
||
}
|
||
}
|
||
|
||
postAccountsData(accounts);
|
||
|
||
for (auto &[account, node]: accounts) {
|
||
// FIXME будем считать что числа последние везде уникальные
|
||
if (m_account.lastNumbers == account.lastNumbers) {
|
||
if (account.amount >= m_amount) {
|
||
AdbUtils::makeTap(device.id, node.x(), node.y());
|
||
QThread::msleep(1000);
|
||
} else {
|
||
AdbUtils::takeScreenshot(device.id, "pay_by_phone_not_enough_money_" + QString::number(m_account.id));
|
||
m_error = "Not enough money, id: " + QString::number(m_account.id)
|
||
+ ", amount: " + QString::number(account.amount)
|
||
+ ", trx amount: " + QString::number(m_amount);
|
||
qCritical() << m_error;
|
||
emit finishedWithResult(m_error);
|
||
return;
|
||
}
|
||
break;
|
||
}
|
||
}
|
||
|
||
makePayment(device.id, app.pinCode, device.screenWidth, device.screenHeight);
|
||
// AdbUtils::tryToKillApplication(device.id, app.package); TODO - надо ли это???
|
||
} else {
|
||
AdbUtils::takeScreenshot(device.id, "pay_by_phone_cant_open_all_products_" + QString::number(m_account.id));
|
||
AdbUtils::tryToKillApplication(device.id, app.package);
|
||
m_error = "Не смогли открыть 'Все продукты'";
|
||
qDebug() << m_error;
|
||
}
|
||
|
||
emit finishedWithResult(m_error);
|
||
}
|