diff --git a/android/adb/AdbUtils.cpp b/android/adb/AdbUtils.cpp index bad48ed..daa9c90 100644 --- a/android/adb/AdbUtils.cpp +++ b/android/adb/AdbUtils.cpp @@ -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(); diff --git a/android/rshb/CommonScript.cpp b/android/rshb/CommonScript.cpp index 41b2c75..5118bbe 100644 --- a/android/rshb/CommonScript.cpp +++ b/android/rshb/CommonScript.cpp @@ -42,7 +42,7 @@ bool CommonScript::inputPinCode(const QString &deviceId, const QList &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,27 +140,24 @@ 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()) { // идем на экран "Все продукты" - if (Node allCardTitle = xmlScreenParser.findTextNode("Счета и карты"); !allCardTitle.isEmpty()) { + if (Node allCardTitle = xmlScreenParser.findTextNode("Счета и карты"); !allCardTitle.isEmpty()) { // 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; diff --git a/android/rshb/CommonScript.h b/android/rshb/CommonScript.h index ded17f7..4e73aea 100644 --- a/android/rshb/CommonScript.h +++ b/android/rshb/CommonScript.h @@ -17,7 +17,11 @@ protected: // static method static bool inputPinCode(const QString &deviceId, const QList &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); }; diff --git a/android/rshb/PayByPhoneScript.cpp b/android/rshb/PayByPhoneScript.cpp index 08bea1a..ce6921e 100644 --- a/android/rshb/PayByPhoneScript.cpp +++ b/android/rshb/PayByPhoneScript.cpp @@ -1,8 +1,11 @@ #include "PayByPhoneScript.h" +#include +#include #include #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 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 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 > 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() << "Не смогли открыть 'Все продукты'"; } diff --git a/android/rshb/PayByPhoneScript.h b/android/rshb/PayByPhoneScript.h index eec6488..4e648da 100644 --- a/android/rshb/PayByPhoneScript.h +++ b/android/rshb/PayByPhoneScript.h @@ -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 + ); }; diff --git a/android/rshb/ScreenXmlParser.cpp b/android/rshb/ScreenXmlParser.cpp index ebbbf56..79f7dd4 100644 --- a/android/rshb/ScreenXmlParser.cpp +++ b/android/rshb/ScreenXmlParser.cpp @@ -775,19 +775,42 @@ TransactionInfo parseExpandedInfo(const QDomElement &root) { return {}; } -QList ScreenXmlParser::parseAccountsInfo() { - QList 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 > ScreenXmlParser::parseAccountsInfo() { + QList > accounts; for (const Node &node: m_nodes) { - if (node.text.contains("Номер карты с последними цифрами")) { - if (QRegularExpressionMatch match = reCardData.match(node.text); match.hasMatch()) { - 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.updateTime = QDateTime::currentDateTime(); - accounts.append(info); - } + 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 = text.mid(0, text.indexOf("Номер карты")); + info.updateTime = QDateTime::currentDateTime(); + + 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); // ЕСПП diff --git a/android/rshb/ScreenXmlParser.h b/android/rshb/ScreenXmlParser.h index bf9559b..b7e15d8 100644 --- a/android/rshb/ScreenXmlParser.h +++ b/android/rshb/ScreenXmlParser.h @@ -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 parseTodayAndYesterdayHistory(); - QList parseAccountsInfo(); + + QList > parseAccountsInfo(); void test(); diff --git a/database/app_data.db b/database/app_data.db index 03cd6f8..64524c5 100644 Binary files a/database/app_data.db and b/database/app_data.db differ diff --git a/database/dao/AccountDAO.cpp b/database/dao/AccountDAO.cpp index f2c579e..2ee24f1 100644 --- a/database/dao/AccountDAO.cpp +++ b/database/dao/AccountDAO.cpp @@ -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); diff --git a/database/dao/TransactionDAO.cpp b/database/dao/TransactionDAO.cpp index 662da36..575154c 100644 --- a/database/dao/TransactionDAO.cpp +++ b/database/dao/TransactionDAO.cpp @@ -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"); diff --git a/database/dao/TransactionDAO.h b/database/dao/TransactionDAO.h index 6c9b3e1..0a84bbb 100644 --- a/database/dao/TransactionDAO.h +++ b/database/dao/TransactionDAO.h @@ -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 getTransactions(int accountId); [[nodiscard]] static bool updateTransaction(const TransactionInfo &info); + + [[nodiscard]] static bool updateTransactionStatus(int id, TransactionStatus status); + [[nodiscard]] static TransactionInfo getTransactionById(int id); }; diff --git a/main.cpp b/main.cpp index 6d0526b..7cb84e9 100644 --- a/main.cpp +++ b/main.cpp @@ -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);