1
0
forked from BRT/arc

Daily commit

This commit is contained in:
slava 2025-05-10 12:07:07 +07:00
parent cd4d6c7e89
commit ea986addb7
6 changed files with 140 additions and 80 deletions

View File

@ -190,14 +190,20 @@ bool CommonScript::goToAllProducts(
return false;
}
bool CommonScript::readTransactionData() {
bool CommonScript::findAndTapOnAccount(const QString &deviceId, const QString &accountNumbers) {
QList<QPair<AccountInfo, Node> > accounts = xmlScreenParser.parseAccountsInfo();
for (auto &[account, node]: accounts) {
// FIXME будем считать что числа последние везде уникальные
if (accountNumbers == account.lastNumbers) {
qDebug() << "findAndTapOnAccount: " << accountNumbers;
AdbUtils::makeTap(deviceId, node.x(), node.y());
QThread::msleep(1000);
return true;
}
}
return false;
}
// 1. топаем на домашнюю
// 2. распарсить мои карты и вернуть данные
// 3. синхронизировать историю транзакций (с домашней)
void CommonScript::stop() {
m_running = false;

View File

@ -23,6 +23,8 @@ protected:
int height
);
bool findAndTapOnAccount(const QString &deviceId, const QString &accountNumbers);
Node swipeToButton(
const QString &deviceId,
const QString &text,
@ -41,14 +43,13 @@ protected:
const QString &deviceId, int width, int height
);
bool readTransactionData();
bool m_running = true;
ScreenXmlParser xmlScreenParser;
int m_counter = 0;
signals:
void finished();
void finishedWithResult(const QString &result);
public slots:
virtual void start() final;

View File

@ -2,16 +2,13 @@
#include <QRandomGenerator>
#include <QThread>
#include <QTimeZone>
#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"
#include "time/DateUtils.h"
@ -33,28 +30,36 @@ QList<TransactionInfo> findSavedTransaction(
for (const TransactionInfo &info: transactions) {
QDateTime timestamp = info.timestamp;
QString shortDescription = parsed.shortDescription;
// если тот же день
if (dateTime.date() == timestamp.date() && parsed.amount == info.amount) {
// Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815...
if (parsed.shortDescription.contains(info.name)) {
if (shortDescription.contains("Перевод")) {
if (shortDescription.contains(info.name)) {
txs.append(info);
}
} else {
// Перевод по карте
if (shortDescription == info.shortDescription) {
txs.append(info);
}
}
}
}
return txs;
}
bool isSingle(const TransactionInfo &transaction, const QList<TransactionInfo> &transactions) {
int countSimilar(const TransactionInfo &transaction, const QList<TransactionInfo> &transactions) {
int count = 0;
for (const TransactionInfo &info: transactions) {
if (info.amount == transaction.amount
&& info.shortDescription == transaction.shortDescription
&& info.bankTime == transaction.bankTime) {
count++;
++count;
}
}
return count == 1;
return count;
}
QString formatPrice(const double value) {
@ -141,16 +146,7 @@ void GetLastDaysHistoryScript::doStart() {
if (xmlScreenParser.isHomeScreen()) {
// парсим все транзакции
if (goToAllProducts(device.id, device.screenWidth, device.screenHeight)) {
QList<QPair<AccountInfo, Node> > accounts = xmlScreenParser.parseAccountsInfo();
for (auto &[account, node]: accounts) {
// FIXME будем считать что числа последние везде уникальные
if (m_account.lastNumbers == account.lastNumbers) {
qDebug() << "Tap by card";
AdbUtils::makeTap(device.id, node.x(), node.y());
QThread::msleep(1000);
break;
}
}
findAndTapOnAccount(device.id, m_account.lastNumbers);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
Node filterBtn = xmlScreenParser.findButtonNode("РСХБ Онлайн", false);
@ -185,52 +181,55 @@ void GetLastDaysHistoryScript::doStart() {
qDebug() << "--- parsedTransactions: " << parsedTransactions.length();
// localTransactions
QList<TransactionInfo> updatedTransactions;
for (TransactionInfo &transaction: parsedTransactions) {
// если shortDescription + сумма + день и Complete совпадает и одна
bool single = isSingle(transaction, parsedTransactions);
int cSimilar = countSimilar(transaction, parsedTransactions);
QList<TransactionInfo> txs = findSavedTransaction(localTransactions, transaction);
if (single && txs.length() < 2) {
if (cSimilar == 1 && txs.length() < 2) {
if (txs.length() == 1) {
// смотрим, надо ли обновление
if (txs[0].status != TransactionStatus::Complete || txs[0].shortDescription.isEmpty()) {
txs[0].shortDescription = transaction.shortDescription;
openAndSaveDitailInfo(txs[0], device.screenWidth, device.screenHeight);
updatedTransactions.append(txs[0]);
}
} else {
// создаем новую
openAndSaveDitailInfo(transaction, device.screenWidth, device.screenHeight);
}
} else {
// в списке за день нашли более чем 1 одинаковых транзакций
// FIXME - что то делать если две одинаковые
if (cSimilar == txs.length()) {
// одинаковые транзакции (2 - 2)
for (TransactionInfo &tx: txs) {
if (!updatedTransactions.contains(tx)) {
openAndSaveDitailInfo(tx, device.screenWidth, device.screenHeight);
updatedTransactions.append(tx);
break;
}
if (txs.length() == 1) {
qDebug() << "--- one transaction with same amount";
qDebug().noquote().nospace() << convertTransactionToString(transaction);
if (transaction.status == TransactionStatus::Complete && !transaction.shortDescription.isEmpty()) {
continue;
}
// посмотреть подробности и обновить статус и описание
} else if (txs.length() > 1) {
// FIXME - что то делать если две одинаковые
// Alert !!!
qDebug() << "--- two transactions with same amount";
} else if (cSimilar < txs.length()) {
// Дубликаты транзакций или название изменилось (1 - 2)
qDebug() << "--- Дубликаты транзакций или название изменилось (1 - 2)!!!!!!!!!!!!";
// FIXME alert!!!
} else {
// Создаем новую, так как не найдено в БД
qDebug() << "--- new transaction";
qDebug().noquote().nospace() << convertTransactionToString(transaction);
// посмотреть подробности и создать
// нужно создать новую транзакцию, которой не было (2 - 1)
bool updated = false;
for (TransactionInfo &tx: txs) {
if (!updatedTransactions.contains(tx)) {
openAndSaveDitailInfo(tx, device.screenWidth, device.screenHeight);
updatedTransactions.append(tx);
updated = true;
break;
}
}
if (!updated) {
// создаем новую, так как у нас появилась одинаковая транзакция
openAndSaveDitailInfo(transaction, device.screenWidth, device.screenHeight);
}
}
}
// qDebug() << transaction.amount;
// qDebug() << transaction.shortDescription;
// qDebug().noquote().nospace() << convertTransactionToString(transaction);
// TODO вот мы дошли до списка транзакций
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
}

View File

@ -40,7 +40,9 @@ void PayByPhoneScript::makePayment(
AdbUtils::makeTap(deviceId, payBtn.x(), payBtn.y());
QThread::msleep(1000);
} else {
qWarning() << "--- payBtn not found";
m_error = "Кнопка 'Оплатить' не нашлась";
qDebug() << m_error;
return;
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
@ -52,10 +54,14 @@ void PayByPhoneScript::makePayment(
AdbUtils::makeTap(deviceId, payByPhoneBtn.x(), payByPhoneBtn.y());
QThread::msleep(1000);
} else {
qWarning() << "--- payByPhoneBtn not found";
m_error = "Не смогли найти пункт 'По номеру телефона В РСХБ и через'";
qDebug() << m_error;
return;
}
} else {
qWarning() << "--- payTitle not found";
m_error = "Не смогли перейти на экран 'Платежи и переводы'";
qDebug() << m_error;
return;
}
@ -69,7 +75,9 @@ void PayByPhoneScript::makePayment(
AdbUtils::inputText(deviceId, m_phone);
QThread::msleep(1000);
} else {
qWarning() << "--- payByPhoneTitle not found (no continueBtn)";
m_error = "Не смогли найти пункт 'Перевод по телефону'";
qDebug() << m_error;
return;
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
@ -80,7 +88,9 @@ void PayByPhoneScript::makePayment(
AdbUtils::makeTap(deviceId, payOtherBankBtn.x(), payOtherBankBtn.y());
QThread::msleep(1000);
} else {
qWarning() << "--- payOtherBankBtn not found";
m_error = "Не смогли нажать на первичный выбор банка";
qDebug() << m_error;
return;
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
@ -96,7 +106,7 @@ void PayByPhoneScript::makePayment(
QThread::msleep(1000);
break;
} else {
qWarning() << "--- allBanksTitle not found, i: " << i;
qDebug() << "--- allBanksTitle not found, i: " << i;
}
QThread::msleep(1000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
@ -110,7 +120,7 @@ void PayByPhoneScript::makePayment(
QThread::msleep(1000);
break;
} else {
qWarning() << "--- bankNameListItem not found, i: " << i;
qDebug() << "--- bankNameListItem not found, i: " << i;
}
QThread::msleep(1000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
@ -136,16 +146,23 @@ void PayByPhoneScript::makePayment(
AdbUtils::makeTap(deviceId, continuePayBtn.x(), continuePayBtn.y());
QThread::msleep(1000);
} else {
qWarning() << "--- readyBtn not found";
m_error = "Не смогли нажать 'Готово'";
qDebug() << m_error;
return;
}
} else {
qWarning() << "--- sumBtn not found";
m_error = "Не смогли нажать 'Продолжить'";
qDebug() << m_error;
return;
}
} else {
qWarning() << "--- payByPhoneScreenTitle not found";
m_error = "Не смогли найти 'Перевод по телефону'";
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 не ясно как форматирование будет, поэтому пока на начало зашьем
@ -158,6 +175,7 @@ void PayByPhoneScript::makePayment(
if (const QList<Node> pincode = xmlScreenParser.tryToFindPinCode(pinCode, "Введите код доступа");
pincode.size() == 4) {
inputPinCode(deviceId, pincode);
inputedPinCode = true;
// После ввода пин-кода, ждем 3с
QThread::msleep(3000);
}
@ -169,9 +187,14 @@ void PayByPhoneScript::makePayment(
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
}
if (!inputedPinCode) {
m_error = "Не смогли ввести пин-код!'";
qDebug() << m_error;
return;
}
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()) {
@ -194,7 +217,6 @@ void PayByPhoneScript::makePayment(
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;
}
@ -215,9 +237,7 @@ void PayByPhoneScript::makePayment(
Node homeBtn = xmlScreenParser.findButtonNode("Вернуться на главную", false);
AdbUtils::makeTap(deviceId, homeBtn.x(), homeBtn.y());
if (!isPaymentCompleted) {
qDebug() << "--- payment not completed";
}
QThread::msleep(1000);
}
void PayByPhoneScript::doStart() {
@ -253,9 +273,13 @@ void PayByPhoneScript::doStart() {
qDebug() << "======== 3. Make payment";
makePayment(device.id, app.pinCode, device.screenWidth, device.screenHeight);
} else {
qDebug() << "Не смогли открыть 'Все продукты'";
m_error = "Не смогли открыть 'Все продукты'";
qDebug() << m_error;
}
} else {
qDebug() << "Не смогли дойти до домашней страницы....";
m_error = "Не смогли дойти до домашней страницы....";
qDebug() << m_error;
}
emit finishedWithResult(m_error);
}

View File

@ -23,6 +23,7 @@ private:
const QString m_phone;
const QString m_bankName;
const double m_amount;
QString m_error;
void makePayment(
const QString &deviceId,

View File

@ -56,24 +56,53 @@ void setupScriptAutoPaymentAndThread(QCoreApplication &app) {
const QString phoneNumber = "79641815146";
const QString bankName = "Альфа-Банк";
// const QString bankName = "Сбербанк";
const double ammount = 310;
const double amount = 310;
AccountInfo account = AccountDAO::findAppAccount(appName, cardNumber);
if (account.id != -1) {
auto *thread = new QThread;
auto *scriptWorker = new GetLastDaysHistoryScript(account);
// auto *scriptWorker = new PayByPhoneScript(account, phoneNumber, bankName, ammount);
// Функция для подключения потоков к завершению приложения
auto connectStopOnQuit = [&](QObject *worker, QThread *thread) {
QObject::connect(&app, &QCoreApplication::aboutToQuit, worker, &QObject::deleteLater);
QObject::connect(&app, &QCoreApplication::aboutToQuit, thread, &QThread::quit);
QObject::connect(&app, &QCoreApplication::aboutToQuit, thread, &QThread::deleteLater);
};
// Первый поток
auto *thread = new QThread;
auto *scriptWorker = new PayByPhoneScript(account, phoneNumber, bankName, amount);
scriptWorker->moveToThread(thread);
QObject::connect(thread, &QThread::started, scriptWorker, &GetLastDaysHistoryScript::start);
QObject::connect(scriptWorker, &GetLastDaysHistoryScript::finished, thread, &QThread::quit);
QObject::connect(scriptWorker, &GetLastDaysHistoryScript::finished, scriptWorker, &QObject::deleteLater);
// Запуск первого потока
QObject::connect(thread, &QThread::started, scriptWorker, &PayByPhoneScript::start);
QObject::connect(scriptWorker, &PayByPhoneScript::finished, thread, &QThread::quit);
QObject::connect(scriptWorker, &PayByPhoneScript::finished, scriptWorker, &QObject::deleteLater);
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
scriptWorker->stop();
// Обработка результата первого потока
QObject::connect(scriptWorker, &PayByPhoneScript::finishedWithResult, &app, [&](const QString &result) {
qDebug() << "Получен результат: [" << result << "]";
// Создаем второй поток после завершения первого
auto *thread2 = new QThread;
auto *scriptWorker2 = new GetLastDaysHistoryScript(account);
scriptWorker2->moveToThread(thread2);
// Запуск второго потока
QObject::connect(thread2, &QThread::started, scriptWorker2, &GetLastDaysHistoryScript::start);
QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, thread2, &QThread::quit);
QObject::connect(scriptWorker2, &GetLastDaysHistoryScript::finished, scriptWorker2, &QObject::deleteLater);
QObject::connect(thread2, &QThread::finished, thread2, &QThread::deleteLater);
// Остановка второго потока при завершении приложения
connectStopOnQuit(scriptWorker2, thread2);
thread2->start();
});
// Остановка первого потока при завершении приложения
connectStopOnQuit(scriptWorker, thread);
// Запуск первого потока
thread->start();
}
}