1
0
forked from BRT/arc
arc/android/rshb/PayByPhoneScript.cpp
trnsmkot 688a71c0b2 Update transaction handling with a new history parsing script.
Replaced `PayByPhoneScript` with `GetLastDaysHistoryScript` in `main.cpp`. Introduced enhanced date/time utilities and improved database timestamp handling with `DateUtils`. Refactored `TransactionDAO` methods to separate parsing logic and added support for retrieving recent transactions within specified hours. Added the `GetLastDaysHistoryScript` class to parse and save recent transaction history.
2025-05-09 22:44:29 +07:00

262 lines
11 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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 {
qWarning() << "--- payBtn not found";
}
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 {
qWarning() << "--- payByPhoneBtn not found";
}
} else {
qWarning() << "--- payTitle not found";
}
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 {
qWarning() << "--- payByPhoneTitle not found (no continueBtn)";
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
QString payBankName;
payBankName = m_bankName == "Россельхозбанк" ? "Россельхозбанк" : "Другой банк через СБП";
Node payOtherBankBtn = xmlScreenParser.findButtonNode(payBankName, false);
if (!payOtherBankBtn.isEmpty()) {
AdbUtils::makeTap(deviceId, payOtherBankBtn.x(), payOtherBankBtn.y());
QThread::msleep(1000);
} else {
qWarning() << "--- payOtherBankBtn not found";
}
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 {
qWarning() << "--- 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 {
qWarning() << "--- bankNameListItem not found, i: " << i;
}
QThread::msleep(1000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
Node payByPhoneScreenTitle = xmlScreenParser.findTextNode("Перевод по телефону");
Node continuePayBtn = xmlScreenParser.findButtonNode("Продолжить", false);
if (!payByPhoneScreenTitle.isEmpty() && payByPhoneScreenTitle.y() < 300 && !continuePayBtn.isEmpty()) {
Node sumBtn = xmlScreenParser.findButtonNode("0", false);
if (!sumBtn.isEmpty()) {
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);
AdbUtils::makeTap(deviceId, continuePayBtn.x(), continuePayBtn.y());
QThread::msleep(1000);
} else {
qWarning() << "--- readyBtn not found";
}
} else {
qWarning() << "--- sumBtn not found";
}
} else {
qWarning() << "--- payByPhoneScreenTitle not found";
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
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);
// После ввода пин-кода, ждем 3с
QThread::msleep(3000);
}
break;
} else {
qWarning() << "--- makePayBtn not found, i: " << i;
}
QThread::msleep(1000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
bool isPaymentCompleted = false;
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);
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()) {
isPaymentCompleted = true;
if (!TransactionDAO::updateTransactionStatus(transaction.id, TransactionStatus::Complete)) {
qDebug() << "Not updated: " << transaction.id;
}
// TODO обновляем данные
break;
}
QThread::msleep(1000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
}
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());
if (!isPaymentCompleted) {
qDebug() << "--- payment not completed";
}
}
void PayByPhoneScript::doStart() {
const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);
const ApplicationInfo app = ApplicationDAO::getApplicationsByDeviceId(m_account.deviceId, m_account.appName);
if (device.id.isEmpty() || app.id.isEmpty()) {
qDebug() << "Device or app not found....";
return;
}
if (runAppAndGoToHomeScreen(device.id, app.package, app.pinCode, device.screenWidth, device.screenHeight)) {
if (goToAllProducts(device.id, device.screenWidth, device.screenHeight)) {
qDebug() << "======== 1. All products";
QList<QPair<AccountInfo, Node> > accounts = xmlScreenParser.parseAccountsInfo();
for (auto &[account, node]: accounts) {
account.deviceId = m_account.deviceId;
account.appName = m_account.appName;
if (!AccountDAO::upsertAccount(account)) {
qDebug() << "Not updated: " << account.lastNumbers;
}
}
for (auto &[account, node]: accounts) {
// FIXME будем считать что числа последние везде уникальные
if (m_account.lastNumbers == account.lastNumbers) {
qDebug() << "======== 2. Tap by card";
AdbUtils::makeTap(device.id, node.x(), node.y());
QThread::msleep(1000);
break;
}
}
qDebug() << "======== 3. Make payment";
makePayment(device.id, app.pinCode, device.screenWidth, device.screenHeight);
} else {
qDebug() << "Не смогли открыть 'Все продукты'";
}
} else {
qDebug() << "Не смогли дойти до домашней страницы....";
}
}