1
0
forked from BRT/arc
arc/android/rshb/GetLastDaysHistoryScript.cpp
2026-02-22 20:48:16 +07:00

399 lines
19 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 "GetLastDaysHistoryScript.h"
#include <QJsonObject>
#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/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<TransactionInfo> findSavedTransaction(
const QList<TransactionInfo> &transactions,
const TransactionInfo &parsed
) {
QList<TransactionInfo> 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<TransactionInfo> &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<qint64>(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<TransactionInfo> localTransactions = TransactionDAO::getTransactionsWithinHours(m_account.id, 48);
QList<QPair<AccountInfo, Node> > 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<TransactionInfo> parsedTransactions = xmlScreenParser.parseTodayAndYesterdayReportHistory();
QSet<int> 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<TransactionInfo> parsedWaitTransactions = xmlScreenParser.parseTodayAndYesterdayReportHistory();
for (const TransactionInfo &transaction: parsedWaitTransactions) {
QList<TransactionInfo> 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