#include "GetLastDaysHistoryScript.h" #include #include #include #include #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/DeviceInfo.h" #include "net/NetworkService.h" #include "time/DateUtils.h" namespace Rshb { GetLastDaysHistoryScript::GetLastDaysHistoryScript( AccountInfo account, QObject *parent ) : CommonScript(parent), m_account(std::move(account)) { } GetLastDaysHistoryScript::~GetLastDaysHistoryScript() = default; QList findSavedTransaction( const QList &transactions, const TransactionInfo &parsed ) { QList txs; const QDateTime dateTime = QDateTime::fromString(parsed.bankTime, "dd.MM.yyyy"); // Московское время for (const TransactionInfo &info: transactions) { QDateTime timestamp = info.timestamp; QString description = parsed.description; // если тот же день if (dateTime.date() == timestamp.date() && parsed.amount == info.amount) { // Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815... if (description.contains("Перевод")) { if (description.contains(info.name)) { txs.append(info); } } else { // Перевод по карте if (description == info.description) { txs.append(info); } } } } return txs; } int countSimilar(const TransactionInfo &transaction, const QList &transactions) { int count = 0; for (const TransactionInfo &info: transactions) { if (info.amount == transaction.amount && info.description == transaction.description && info.bankTime == transaction.bankTime) { ++count; } } return count; } QString formatPrice(const double value) { QString sign = value < 0 ? "Минус" : "Плюс"; const auto intValue = static_cast(std::abs(value)); // округление до целого QString number = QString::number(intValue); QString formatted; int count = 0; for (int i = number.length() - 1; i >= 0; --i) { formatted.prepend(number[i]); ++count; if (count % 3 == 0 && i != 0) { formatted.prepend(' '); } } return QString("%1 %2").arg(sign, formatted); } bool GetLastDaysHistoryScript::saveAndPostNewTransactionData( const AccountInfo &account, const TransactionInfo &transaction, const TransactionStatus &status ) { TransactionInfo tr; tr.accountId = account.id; tr.description = transaction.description; tr.bankTime = transaction.bankTime; tr.bankName = transaction.bankName; tr.amount = transaction.amount; tr.phone = transaction.phone; tr.updateTime = DateUtils::getUtcNow(); tr.fee = transaction.fee; tr.name = transaction.name; tr.bankTrExternalId = transaction.bankTrExternalId; tr.status = status; tr.type = transaction.description.startsWith("Перевод") ? TransactionType::Phone : TransactionType::Card; tr.completeTime = DateUtils::getUtcNow(); tr.id = TransactionDAO::insertTransaction(tr); if (tr.id == -1) { return false; } postNewTransactionData(account, tr); return true; } bool GetLastDaysHistoryScript::updateAndPostTransactionData( const AccountInfo &account, const int transactionId, const TransactionStatus status, const QString &oldDesc, const QString &newDesc ) { if (TransactionDAO::updateTransaction(transactionId, status, oldDesc, newDesc)) { updateTransactionData(account, transactionId, status, oldDesc, newDesc); return true; } return false; } void GetLastDaysHistoryScript::doStart() { // берем все транзакции из БД const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId); const ApplicationInfo app = ApplicationDAO::getApplication(m_account.deviceId, m_account.appCode); if (!xmlScreenParser.isHomeScreen()) { if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode, device.screenWidth, device.screenHeight)) { m_error = "Не смогли дойти до домашней страницы"; qCritical() << m_error; emit finishedWithResult(m_error); return; } } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); Node closeBannerOrDialogNode = xmlScreenParser.tryToFindBannerOrDialog(device.screenWidth, device.screenHeight); if (closeBannerOrDialogNode.x() != -1 && closeBannerOrDialogNode.y() != -1) { AdbUtils::makeTap(device.id, closeBannerOrDialogNode.x(), closeBannerOrDialogNode.y()); QThread::msleep(500); } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); if (xmlScreenParser.isHomeScreen()) { if (goToAllProducts(device.id, device.screenWidth, device.screenHeight)) { QList localTransactions = TransactionDAO::getTransactionsWithinHours(m_account.id, 48); QList > accounts = xmlScreenParser.parseAccountsInfo(); for (auto &[account, node]: accounts) { account.deviceId = m_account.deviceId; account.appCode = m_account.appCode; if (!AccountDAO::upsertAccount(account)) { qDebug() << "Not updated: " << account.lastNumbers; } } postAccountsData(accounts); findAndTapOnAccount(device.id, m_account.lastNumbers); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); Node actionBtn = xmlScreenParser.findButtonNode("Действия", false); if (!actionBtn.isEmpty()) { AdbUtils::makeTap(m_account.deviceId, actionBtn.x(), actionBtn.y()); QThread::msleep(200); } else { m_error = "All action btn not found"; qCritical() << m_error; emit finishedWithResult(m_error); return; } Node reportButton = swipeToButton( m_account.deviceId, "Выписка", m_counter, device.screenWidth, device.screenHeight ); if (!reportButton.isEmpty()) { AdbUtils::makeTap(m_account.deviceId, reportButton.x(), reportButton.y()); QThread::msleep(1000); } xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); Node reportTitle = xmlScreenParser.findTextNode("Выписка"); if (!reportTitle.isEmpty() && reportTitle.y() < 300) { QDate beforeYesterday = DateUtils::getMoscowNow().date().addDays(-2); QString beforeYesterdayTitle = beforeYesterday.toString("dd.MM.yyyy"); for (int i = 0; i < 5; ++i) { Node byDayTitle = xmlScreenParser.findTextNode(beforeYesterdayTitle); if (!byDayTitle.isEmpty()) { qWarning() << "--- beforeYesterdayTitle found!"; break; } AdbUtils::makeSwipe( m_account.deviceId, device.screenWidth / 2, device.screenHeight / 4 * 3, device.screenWidth / 2, device.screenHeight / 4 ); QThread::msleep(1000); xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter)); } } else { m_error = "All action - report title not found"; qCritical() << m_error; emit finishedWithResult(m_error); return; } // все поддвержденные QList parsedTransactions = xmlScreenParser.parseTodayAndYesterdayReportHistory(); QSet parsedTransactionIds; for (const TransactionInfo &transaction: parsedTransactions) { bool updated = false; for (const TransactionInfo &saved: localTransactions) { if (parsedTransactionIds.contains(saved.id)) { continue; } QDate sDate = QDateTime::fromString(saved.bankTime, "dd.MM.yyyy HH:mm:ss").date(); if (!sDate.isValid()) { sDate = QDateTime::fromString(saved.bankTime, "dd.MM.yyyy").date(); } QDate pDate = QDateTime::fromString(transaction.bankTime, "dd.MM.yyyy HH:mm:ss").date(); if (!pDate.isValid()) { pDate = QDateTime::fromString(transaction.bankTime, "dd.MM.yyyy").date(); } // Если сумма и дата совпадают if (saved.amount == transaction.amount && sDate == pDate) { if (transaction.description.startsWith("Перевод")) { // Перевод по номеру if (saved.bankName == transaction.bankName && saved.phone == transaction.phone) { parsedTransactionIds.insert(saved.id); updated = true; if (saved.status != TransactionStatus::Complete || saved.description.isEmpty()) { if (!TransactionDAO::updateTransaction( saved.id, TransactionStatus::Complete, saved.description, transaction.description )) { qDebug().noquote().nospace() << "--- updated+phone failed" << convertTransactionToString(transaction);; } } break; } } else { // перевод по карте // перезаписать saved.description -> updatedDescription если не равны if (!saved.description.isEmpty()) { if (saved.description == transaction.description) { // описания совпадают if (saved.status != TransactionStatus::Complete) { if (!TransactionDAO::updateTransaction( saved.id, TransactionStatus::Complete, saved.description, transaction.description )) { qDebug().noquote().nospace() << "--- updated+card[description same] failed" << convertTransactionToString(transaction);; } } parsedTransactionIds.insert(saved.id); updated = true; break; } else { // описания не совпадают, то пробуем найти такое же, если не находим то это новая bool findWithSameName = false; for (const TransactionInfo &saved2: localTransactions) { if (saved2.description == transaction.description && !parsedTransactionIds. contains( saved2.id)) { // мы нашли с одинаковым описанием и еще не обработанную if (saved2.status != TransactionStatus::Complete) { if (!TransactionDAO::updateTransaction( saved2.id, TransactionStatus::Complete, saved2.description, transaction.description )) { qDebug().noquote().nospace() << "--- updated+card2[description same] failed" << convertTransactionToString(transaction);; } } parsedTransactionIds.insert(saved2.id); updated = true; findWithSameName = true; break; } } if (!findWithSameName) { // обновляем описание if (!TransactionDAO::updateTransaction( saved.id, TransactionStatus::Complete, saved.description, transaction.description )) { qDebug().noquote().nospace() << "--- updated+card2+new desc[description same] failed" << convertTransactionToString(transaction);; } } parsedTransactionIds.insert(saved.id); updated = true; break; } } else { // пустой описание if (!TransactionDAO::updateTransaction( saved.id, TransactionStatus::Complete, saved.description, transaction.description )) { qDebug().noquote().nospace() << "--- updated+card[empty description]" << convertTransactionToString(transaction);; } parsedTransactionIds.insert(saved.id); updated = true; break; } } } } if (!updated) { if (!saveAndPostNewTransactionData(m_account, transaction, TransactionStatus::Complete)) { qDebug() << "--- saveAndPostNewTransactionData failed"; } } // Если это перевод // Если совпадает по сумме + телефон + банк дата (без времени) + банк // Если по карте, мы знаем ток дату + сумма } Node waitTab = xmlScreenParser.findButtonNode("Ожидающие обработки", true); if (!waitTab.isEmpty()) { AdbUtils::makeTap(m_account.deviceId, waitTab.x(), waitTab.y()); QThread::msleep(1000); QList parsedWaitTransactions = xmlScreenParser.parseTodayAndYesterdayReportHistory(); for (const TransactionInfo &transaction: parsedWaitTransactions) { QList localActualTransactions = TransactionDAO::getTransactionsWithinHours( m_account.id, 48 ); for (const TransactionInfo &saved: localActualTransactions) { if (saved.status != TransactionStatus::Wait) { continue; } QDate sDate = QDateTime::fromString(saved.bankTime, "dd.MM.yyyy HH:mm:ss").date(); if (!sDate.isValid()) { sDate = QDateTime::fromString(saved.bankTime, "dd.MM.yyyy").date(); } QDate pDate = QDateTime::fromString(transaction.bankTime, "dd.MM.yyyy HH:mm:ss").date(); if (!pDate.isValid()) { pDate = QDateTime::fromString(transaction.bankTime, "dd.MM.yyyy").date(); } if (saved.amount == transaction.amount && sDate == pDate) { // одно и тоже } else { if (!saveAndPostNewTransactionData(m_account, transaction, TransactionStatus::Wait)) { qDebug() << "--- saveAndPostNewTransactionData - Wait failed"; } } } } } } } else { m_error = "GetLastDaysHistoryScript - home screen not found"; qWarning() << m_error; emit finishedWithResult(m_error); } AdbUtils::goBack(m_account.deviceId); AdbUtils::goBack(m_account.deviceId); AdbUtils::goBack(m_account.deviceId); emit finishedWithResult(m_error); } } // namespace Rshb