1
0
forked from BRT/arc
arc/android/rshb/GetLastDaysHistoryScript.cpp
slava c4f171259b Fix default timestamp and add card report asset
Corrected the default timestamp value in multiple database schemas to ensure proper functionality and consistent formatting. Added a new asset file for the card report layout to support UI rendering for card transactions.
2025-05-10 19:42:14 +07:00

348 lines
17 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 <QRandomGenerator>
#include <QThread>
#include <utility>
#include "DatabaseManager.h"
#include "adb/AdbUtils.h"
#include "dao/AccountDAO.h"
#include "dao/DeviceDAO.h"
#include "dao/TransactionDAO.h"
#include "db/DeviceInfo.h"
#include "time/DateUtils.h"
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 shortDescription = parsed.shortDescription;
// если тот же день
if (dateTime.date() == timestamp.date() && parsed.amount == info.amount) {
// Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815...
if (shortDescription.contains("Перевод")) {
if (shortDescription.contains(info.name)) {
txs.append(info);
}
} else {
// Перевод по карте
if (shortDescription == info.shortDescription) {
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.shortDescription == transaction.shortDescription
&& 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::openAndSaveDitailInfo(TransactionInfo &transaction, int width, int height) {
QString text = QString("%1 %2").arg(transaction.shortDescription, formatPrice(transaction.amount));
Node trButton = swipeToButton(m_account.deviceId, text, m_counter, width, height);
if (!trButton.isEmpty()) {
AdbUtils::makeTap(m_account.deviceId, trButton.x(), trButton.y());
QThread::msleep(500);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
Node moreDetailBtn = xmlScreenParser.findButtonNode("Детали операции", false);
if (!moreDetailBtn.isEmpty()) {
AdbUtils::makeTap(m_account.deviceId, moreDetailBtn.x(), moreDetailBtn.y());
QThread::msleep(200);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
TransactionInfo info = xmlScreenParser.parseTransactionInfoHistory(width, height);
if (transaction.id == -1) {
info.accountId = m_account.id;
info.shortDescription = transaction.shortDescription;
info.amount = transaction.amount;
info.type = info.phone.isEmpty() ? TransactionType::Card : TransactionType::Phone;
info.updateTime = DateUtils::getUtcNow();
if (info.status == TransactionStatus::Complete) {
info.completeTime = DateUtils::getUtcNow();
}
if (TransactionDAO::insertTransaction(info) == -1) {
qWarning() << "--- insertTransaction failed";
}
} else {
transaction.status = info.status;
transaction.description = info.description;
if (transaction.trExternalId.isEmpty()) {
transaction.trExternalId = info.trExternalId;
}
transaction.updateTime = DateUtils::getUtcNow();
if (transaction.status == TransactionStatus::Complete && !transaction.completeTime.isValid()) {
transaction.completeTime = DateUtils::getUtcNow();
}
if (!TransactionDAO::updateTransaction(transaction)) {
qWarning() << "--- updateTransaction failed";
}
}
}
AdbUtils::goBack(m_account.deviceId);
QThread::msleep(200);
} else {
qWarning() << "--- trButton not found..........";
}
return false;
}
void GetLastDaysHistoryScript::doStart() {
// берем все транзакции из БД
QList<TransactionInfo> localTransactions = TransactionDAO::getTransactionsWithinHours(m_account.id, 48);
const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
if (xmlScreenParser.isHomeScreen()) {
// парсим все транзакции
if (goToAllProducts(device.id, device.screenWidth, device.screenHeight)) {
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 {
qWarning() << "--- actionBtn not found";
}
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 {
qWarning() << "--- reportTitle not found";
}
// все поддвержденные
QList<TransactionInfo> parsedTransactions = xmlScreenParser.parseTodayAndYesterdayReportHistory();
QSet<int> parsedTransactionIds;
qDebug() << "--- parsedTransactions: " << parsedTransactions.length();
qDebug() << "--- localTransactions: " << localTransactions.length();
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) {
qDebug() << "--- insert: " << transaction.description;
// не нашлась транзакция
TransactionInfo tr;
tr.accountId = m_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.trExternalId = transaction.trExternalId;
tr.status = TransactionStatus::Complete;
tr.type = transaction.description.startsWith("Перевод")
? TransactionType::Phone
: TransactionType::Card;
tr.completeTime = DateUtils::getUtcNow();
if (TransactionDAO::insertTransaction(tr) == -1) {
qDebug() << "--- not inserted: " << transaction.description;
}
}
// Если это перевод
// Если совпадает по сумме + телефон + банк дата (без времени) + банк
// Если по карте, мы знаем ток дату + сумма
}
}
} else {
qDebug() << "--- home screen not found";
}
}