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.
348 lines
17 KiB
C++
348 lines
17 KiB
C++
#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";
|
||
}
|
||
}
|