1
0
forked from BRT/arc

Refactor scripts to improve modularity and add transaction handling.

Enhanced `CommonScript` and `PayByPhoneScript` functionalities by restructuring functions for better readability and parameterization (e.g., device-specific inputs). Included a new transaction handling process and database updates for tracking payment details and statuses.
This commit is contained in:
slava 2025-05-07 19:16:08 +07:00
parent 59cef50ad3
commit 8a3c1c5196
12 changed files with 380 additions and 77 deletions

View File

@ -94,13 +94,15 @@ bool AdbUtils::tryToKillApplication(const QString &deviceId, const QString &pack
// adb -s 6edc4a47 shell 'uiautomator dump /sdcard/uidump.xml' && adb -s 6edc4a47 pull /sdcard/uidump.xml step_1.xml && adb -s 6edc4a47 shell 'rm /sdcard/uidump.xml'
QString AdbUtils::getScreenDumpAsXml(const QString &deviceId, const int idx) {
// TODO убрать логирование в xml файл
// "adb -s %1 pull /sdcard/uidump.xml step_%2.xml && "
QProcess process;
QString xml = QString(
"adb -s %1 shell 'uiautomator dump /sdcard/uidump.xml' && "
"adb -s %1 pull /sdcard/uidump.xml step_%2.xml && "
"adb -s %1 shell 'cat /sdcard/uidump.xml' && "
"adb -s %1 shell 'rm /sdcard/uidump.xml'"
).arg(deviceId, QString::number(idx));
// ).arg(deviceId, QString::number(idx));
).arg(deviceId);
process.start("sh", {"-c", xml});
process.waitForFinished();

View File

@ -42,7 +42,7 @@ bool CommonScript::inputPinCode(const QString &deviceId, const QList<Node> &pinc
return true;
}
bool CommonScript::goToHomeScreen(
bool CommonScript::runAppAndGoToHomeScreen(
const QString &deviceId,
const QString &packageName,
const QString &pinCode,
@ -85,7 +85,7 @@ bool CommonScript::goToHomeScreen(
counter = 0;
}
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, totalCounter + 1));
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
if (xmlScreenParser.isHomeScreen()) {
return true;
@ -129,29 +129,6 @@ bool CommonScript::goToHomeScreen(
}
}
bool CommonScript::runAppAndGoToHomeScreen() {
const QString deviceId = "6edc4a47";
const QString packageName = "ru.rshb.dbo";
const QString pinCode = "1102";
const int width = 720;
const int height = 1600;
const QString cardNumber = "7 1 8 3";
// В том числе и данные на каком устройстве это делать
// TODO тут код работы с БД
// +7 (964) 181-51-46
const QString phoneNumber = "+79641815146";
const QString bankName = "Альфа-Банк";
const QString paySum = "250";
xmlScreenParser.test();
return false;
// выше достаем данные и все прочее
return goToHomeScreen(deviceId, packageName, pinCode, width, height);
}
bool CommonScript::tryToCloseAllBannersOnHomePage(const QString &deviceId, const int width, const int height) {
Node closeBannerOrDialogNode = xmlScreenParser.tryToFindBannerOrDialog(width, height);
if (closeBannerOrDialogNode.x() != -1 && closeBannerOrDialogNode.y() != -1) {
@ -163,16 +140,15 @@ bool CommonScript::tryToCloseAllBannersOnHomePage(const QString &deviceId, const
return false;
}
bool CommonScript::goToAllProducts() {
int counter = 100;
const QString deviceId = "6edc4a47";
const int width = 720;
const int height = 1600;
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, counter));
bool CommonScript::goToAllProducts(
const QString &deviceId,
const int width,
const int height
) {
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, m_counter));
if (tryToCloseAllBannersOnHomePage(deviceId, width, height)) {
QThread::msleep(500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
}
if (xmlScreenParser.isHomeScreen()) {
@ -181,9 +157,7 @@ bool CommonScript::goToAllProducts() {
// 1. Если нет кнопки видимой, свайпаем. Кликаем на "Все продукты"
for (int i = 0; i < 5; ++i) {
Node allProductsBtn = xmlScreenParser.findButtonNode("Все продукты", false);
// Node allProductsBtn = xmlScreenParser.findTextNode("Курсы валют и металлов"); для теста
if (allProductsBtn.x() > 0 && allProductsBtn.y() > 0) {
qDebug() << "--- All Product in focus";
AdbUtils::makeTap(deviceId, allProductsBtn.x(), allProductsBtn.y());
QThread::msleep(1000);
break;
@ -191,7 +165,7 @@ bool CommonScript::goToAllProducts() {
AdbUtils::makeSwipe(deviceId,
allCardTitle.x(), allCardTitle.y(),
allCardTitle.x(), allCardTitle.y() - 200);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
}
for (int i = 0; i < 5; ++i) {
@ -202,15 +176,15 @@ bool CommonScript::goToAllProducts() {
}
QThread::msleep(1000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++counter));
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
}
} else {
// пишем в БД, что не дошли до домашней страницы, и завершаемся
// FIXME пишем в БД, что не дошли до домашней страницы, и завершаемся
// сохраняем скрин приложения
// дделаем алерт
}
} else {
// FIXME
qDebug() << "Not home screen...";
}
return false;

View File

@ -17,7 +17,11 @@ protected:
// static method
static bool inputPinCode(const QString &deviceId, const QList<Node> &pincode);
bool goToAllProducts();
bool goToAllProducts(
const QString &deviceId,
int width,
int height
);
Node swipeToButton(
const QString &deviceId,
@ -25,7 +29,13 @@ protected:
int &counter, int width, int height
);
bool runAppAndGoToHomeScreen();
bool runAppAndGoToHomeScreen(
const QString &deviceId,
const QString &packageName,
const QString &pinCode,
int width,
int height
);
bool tryToCloseAllBannersOnHomePage(
const QString &deviceId, int width, int height
@ -35,10 +45,7 @@ protected:
bool m_running = true;
ScreenXmlParser xmlScreenParser;
QString m_packageName;
QString m_pinCode;
int m_width = 0;
int m_height = 0;
int m_counter = 0;
signals:
void finished();
@ -49,9 +56,5 @@ public slots:
virtual void stop() final;
private:
// Q_DISABLE_COPY(CommonScript);
bool goToHomeScreen(
const QString &deviceId, const QString &packageName,
const QString &pinCode, int width, int height);
Q_DISABLE_COPY(CommonScript);
};

View File

@ -1,8 +1,11 @@
#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"
@ -23,6 +26,204 @@ PayByPhoneScript::PayByPhoneScript(
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;
if (bool inserted = TransactionDAO::insertTransaction(transaction); !inserted) {
// 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;
transaction.status = TransactionStatus::Complete;
if (!TransactionDAO::updateTransactionStatus(transaction.id, transaction.status)) {
qDebug() << "Not updated: " << transaction.id;
}
// TODO обновляем данные
break;
}
QThread::msleep(1000);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
}
transaction.updateTime = QDateTime::currentDateTime();
if (!TransactionDAO::updateTransaction(transaction)) {
qDebug() << "Not updated: " << 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());
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);
@ -31,21 +232,30 @@ void PayByPhoneScript::doStart() {
qDebug() << "Device or app not found....";
return;
}
m_width = device.screenWidth;
m_height = device.screenHeight;
m_pinCode = app.pinCode;
m_packageName = app.package;
if (runAppAndGoToHomeScreen()) {
if (goToAllProducts()) {
QList<AccountInfo> accounts = xmlScreenParser.parseAccountsInfo();
for (AccountInfo &account: accounts) {
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() << "Не смогли открыть 'Все продукты'";
}

View File

@ -24,4 +24,11 @@ private:
const QString m_phone;
const QString m_bankName;
const double m_amount;
void makePayment(
const QString &deviceId,
const QString &pinCode,
int width,
int height
);
};

View File

@ -775,19 +775,42 @@ TransactionInfo parseExpandedInfo(const QDomElement &root) {
return {};
}
QList<AccountInfo> ScreenXmlParser::parseAccountsInfo() {
QList<AccountInfo> accounts;
TransactionInfo ScreenXmlParser::parseTransactionInfo(int screenWidth, int screenHeight) {
// 1. Распарсить описание транзакции
TransactionInfo transaction = parseExpandedInfo(m_xml);
// 1. Найти статус: Исполнен | Операция исполнена
transaction.status = TransactionStatus::Wait;
Node status1 = findTextNode("Исполнен", 0, 0, screenWidth, screenHeight / 2);
Node status2 = findTextNode("Операция исполнена", 0, 0, screenWidth, screenHeight / 2);
if (!status1.isEmpty() || !status2.isEmpty()) {
transaction.status = TransactionStatus::Complete;
}
return transaction;
}
QList<QPair<AccountInfo, Node> > ScreenXmlParser::parseAccountsInfo() {
QList<QPair<AccountInfo, Node> > accounts;
for (const Node &node: m_nodes) {
if (node.text.contains("Номер карты с последними цифрами")) {
if (QRegularExpressionMatch match = reCardData.match(node.text); match.hasMatch()) {
const QString text = node.text;
// Проверяем только нужные строки
if (!text.contains("Номер карты с последними цифрами")) {
continue;
}
QRegularExpressionMatch match = reCardData.match(text);
if (!match.hasMatch()) {
continue;
}
AccountInfo info;
info.lastNumbers = match.captured(1).remove(" ");
info.amount = match.captured(2).remove(" ").toFloat();
info.description = node.text.mid(0, node.text.indexOf("Номер карты"));
info.description = text.mid(0, text.indexOf("Номер карты"));
info.updateTime = QDateTime::currentDateTime();
accounts.append(info);
}
}
accounts.append(qMakePair(info, node));
}
return accounts;
@ -814,9 +837,9 @@ void ScreenXmlParser::test() {
// Номер карты с последними цифрами
QDomElement root = doc.documentElement();
parseAndSaveXml(doc.toString());
for (const AccountInfo& info : parseAccountsInfo()) {
qDebug().noquote().nospace() << convertAccountToString(info);
}
// for (const AccountInfo &info: parseAccountsInfo()) {
// qDebug().noquote().nospace() << convertAccountToString(info);
// }
// TransactionInfo info = parseExpandedInfo(root);
// qDebug().noquote().nospace() << convertTransactionToString(info);
// ЕСПП

View File

@ -19,6 +19,7 @@ public:
Node tryToFindSecurityBanner();
Node findTextNode(const QString &text);
Node findTextNode(const QString &text, int x1, int y1, int x2, int y2);
Node findFirstEditText();
@ -35,9 +36,12 @@ public:
void parseAndSaveXml(const QString &xml);
TransactionInfo parseTransactionInfoHistory(int screenWidth, int screenHeight);
TransactionInfo parseTransactionInfo(int screenWidth, int screenHeight);
QList<TransactionInfo> parseTodayAndYesterdayHistory();
QList<AccountInfo> parseAccountsInfo();
QList<QPair<AccountInfo, Node> > parseAccountsInfo();
void test();

Binary file not shown.

View File

@ -15,7 +15,8 @@ bool AccountDAO::upsertAccount(const AccountInfo &info) {
DO UPDATE SET
amount = excluded.amount,
update_time = excluded.update_time,
status = excluded.status
status = excluded.status,
description = excluded.description
)");
query.bindValue(":device_id", info.deviceId);

View File

@ -75,6 +75,48 @@ bool TransactionDAO::insertTransactionIfNotExists(const TransactionInfo &info) {
return true;
}
bool TransactionDAO::insertTransaction(const TransactionInfo &info) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
INSERT INTO transactions (
account_id, amount, fee, status, phone, type,
description, updated_description, short_description, updated_short_description,
bank_name, bank_time, name, tr_external_id,
update_time, complete_time
) VALUES (
:account_id, :amount, :fee, :status, :phone, :type,
:description, :updated_description, :short_description, :updated_short_description,
:bank_name, :bank_time, :name, :tr_external_id,
:update_time, :complete_time
)
)");
query.bindValue(":account_id", info.accountId);
query.bindValue(":amount", info.amount);
query.bindValue(":fee", info.fee);
query.bindValue(":status", transactionStatusToString(info.status));
query.bindValue(":type", transactionTypeToString(info.type));
query.bindValue(":phone", info.phone);
query.bindValue(":name", info.name);
query.bindValue(":description", info.description);
query.bindValue(":updated_description", info.updatedDescription);
query.bindValue(":short_description", info.shortDescription);
query.bindValue(":updated_short_description", info.updatedShortDescription);
query.bindValue(":bank_name", info.bankName);
query.bindValue(":bank_time", info.bankTime);
query.bindValue(":tr_external_id", info.trExternalId);
query.bindValue(":update_time", info.updateTime.toString(Qt::ISODate));
query.bindValue(":complete_time", info.completeTime.toString(Qt::ISODate));
if (!query.exec()) {
qWarning() << "Ошибка при вставке transaction:" << query.lastError().text();
return false;
}
return true;
}
bool TransactionDAO::deleteTransaction(const int id) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare("DELETE FROM transactions WHERE id = :id");
@ -176,6 +218,37 @@ bool TransactionDAO::updateTransaction(const TransactionInfo &info) {
return true;
}
bool TransactionDAO::updateTransactionStatus(
const int id,
const TransactionStatus status
) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
UPDATE transactions SET
status = :status,
update_time = :update_time,
complete_time = :complete_time
WHERE id = :id
)");
query.bindValue(":id", id);
query.bindValue(":status", transactionStatusToString(status));
QString updateTime;
if (status == TransactionStatus::Complete) {
updateTime = QDateTime::currentDateTime().toString(Qt::ISODate);
}
query.bindValue(":update_time", updateTime);
query.bindValue(":complete_time", QDateTime::currentDateTime().toString(Qt::ISODate));
if (!query.exec()) {
qWarning() << "Ошибка при обновлении transaction:" << query.lastError().text();
return false;
}
return true;
}
TransactionInfo TransactionDAO::getTransactionById(const int id) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare("SELECT * FROM transactions WHERE id = :id");

View File

@ -5,10 +5,15 @@ class TransactionDAO {
public:
[[nodiscard]] static bool insertTransactionIfNotExists(const TransactionInfo &info);
[[nodiscard]] static bool insertTransaction(const TransactionInfo &info);
[[nodiscard]] static bool deleteTransaction(int id);
[[nodiscard]] static QList<TransactionInfo> getTransactions(int accountId);
[[nodiscard]] static bool updateTransaction(const TransactionInfo &info);
[[nodiscard]] static bool updateTransactionStatus(int id, TransactionStatus status);
[[nodiscard]] static TransactionInfo getTransactionById(int id);
};

View File

@ -54,6 +54,7 @@ void setupScriptAutoPaymentAndThread(QCoreApplication &app) {
const QString phoneNumber = "79641815146";
const QString bankName = "Альфа-Банк";
// const QString bankName = "Сбербанк";
const double ammount = 250;
AccountInfo account = AccountDAO::findAppAccount(appName, cardNumber);