Update transaction handling with a new history parsing script.
Replaced `PayByPhoneScript` with `GetLastDaysHistoryScript` in `main.cpp`. Introduced enhanced date/time utilities and improved database timestamp handling with `DateUtils`. Refactored `TransactionDAO` methods to separate parsing logic and added support for retrieving recent transactions within specified hours. Added the `GetLastDaysHistoryScript` class to parse and save recent transaction history.
This commit is contained in:
parent
8a3c1c5196
commit
cd4d6c7e89
273
android/rshb/GetLastDaysHistoryScript.cpp
Normal file
273
android/rshb/GetLastDaysHistoryScript.cpp
Normal file
@ -0,0 +1,273 @@
|
||||
#include "GetLastDaysHistoryScript.h"
|
||||
|
||||
#include <QRandomGenerator>
|
||||
#include <QThread>
|
||||
#include <QTimeZone>
|
||||
#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/ApplicationInfo.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;
|
||||
// если тот же день
|
||||
if (dateTime.date() == timestamp.date() && parsed.amount == info.amount) {
|
||||
// Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815...
|
||||
if (parsed.shortDescription.contains(info.name)) {
|
||||
txs.append(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return txs;
|
||||
}
|
||||
|
||||
bool isSingle(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 == 1;
|
||||
}
|
||||
|
||||
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);
|
||||
// for (const TransactionInfo& transaction: transactions) {
|
||||
// qDebug().noquote().nospace() << convertTransactionToString(transaction);
|
||||
// }
|
||||
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)) {
|
||||
QList<QPair<AccountInfo, Node> > accounts = xmlScreenParser.parseAccountsInfo();
|
||||
for (auto &[account, node]: accounts) {
|
||||
// FIXME будем считать что числа последние везде уникальные
|
||||
if (m_account.lastNumbers == account.lastNumbers) {
|
||||
qDebug() << "Tap by card";
|
||||
AdbUtils::makeTap(device.id, node.x(), node.y());
|
||||
QThread::msleep(1000);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
Node filterBtn = xmlScreenParser.findButtonNode("РСХБ Онлайн", false);
|
||||
if (!filterBtn.isEmpty()) {
|
||||
AdbUtils::makeTap(m_account.deviceId, filterBtn.x(), filterBtn.y());
|
||||
QThread::msleep(1000);
|
||||
} else {
|
||||
qWarning() << "--- filterBtn not found";
|
||||
}
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
Node allTransactionFilerBtn = xmlScreenParser.findButtonNode("Все операции", false);
|
||||
if (!allTransactionFilerBtn.isEmpty()) {
|
||||
AdbUtils::makeTap(m_account.deviceId, allTransactionFilerBtn.x(), allTransactionFilerBtn.y());
|
||||
QThread::msleep(1000);
|
||||
} else {
|
||||
qWarning() << "--- allTransactionFilerBtn not found";
|
||||
}
|
||||
|
||||
QList<TransactionInfo> parsedTransactions;
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
for (int i = 0; i < 5; ++i) {
|
||||
parsedTransactions = xmlScreenParser.parseTodayAndYesterdayHistory();
|
||||
if (!parsedTransactions.empty()) {
|
||||
break;
|
||||
}
|
||||
|
||||
QThread::msleep(1000);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
}
|
||||
|
||||
|
||||
qDebug() << "--- parsedTransactions: " << parsedTransactions.length();
|
||||
// localTransactions
|
||||
for (TransactionInfo &transaction: parsedTransactions) {
|
||||
// если shortDescription + сумма + день и Complete совпадает и одна
|
||||
bool single = isSingle(transaction, parsedTransactions);
|
||||
QList<TransactionInfo> txs = findSavedTransaction(localTransactions, transaction);
|
||||
|
||||
if (single && txs.length() < 2) {
|
||||
if (txs.length() == 1) {
|
||||
// смотрим, надо ли обновление
|
||||
if (txs[0].status != TransactionStatus::Complete || txs[0].shortDescription.isEmpty()) {
|
||||
txs[0].shortDescription = transaction.shortDescription;
|
||||
openAndSaveDitailInfo(txs[0], device.screenWidth, device.screenHeight);
|
||||
}
|
||||
} else {
|
||||
// создаем новую
|
||||
openAndSaveDitailInfo(transaction, device.screenWidth, device.screenHeight);
|
||||
}
|
||||
} else {
|
||||
// в списке за день нашли более чем 1 одинаковых транзакций
|
||||
// FIXME - что то делать если две одинаковые
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (txs.length() == 1) {
|
||||
qDebug() << "--- one transaction with same amount";
|
||||
qDebug().noquote().nospace() << convertTransactionToString(transaction);
|
||||
|
||||
if (transaction.status == TransactionStatus::Complete && !transaction.shortDescription.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
// посмотреть подробности и обновить статус и описание
|
||||
} else if (txs.length() > 1) {
|
||||
// FIXME - что то делать если две одинаковые
|
||||
// Alert !!!
|
||||
qDebug() << "--- two transactions with same amount";
|
||||
} else {
|
||||
// Создаем новую, так как не найдено в БД
|
||||
qDebug() << "--- new transaction";
|
||||
qDebug().noquote().nospace() << convertTransactionToString(transaction);
|
||||
|
||||
// посмотреть подробности и создать
|
||||
}
|
||||
// qDebug() << transaction.amount;
|
||||
// qDebug() << transaction.shortDescription;
|
||||
// qDebug().noquote().nospace() << convertTransactionToString(transaction);
|
||||
// TODO вот мы дошли до списка транзакций
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_account.deviceId, ++m_counter));
|
||||
}
|
||||
// сначала обработаем
|
||||
}
|
||||
} else {
|
||||
qDebug() << "--- home screen not found";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
amount: -250
|
||||
shortDescription: Перевод Надежда Юрьевна К** в Сбербанк через СБП, по номеру телефона +7964181514...
|
||||
bankTime: 08.05.2025
|
||||
|
||||
amount: -305
|
||||
shortDescription: Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815...
|
||||
bankTime: 08.05.2025
|
||||
|
||||
|
||||
amount: -250
|
||||
shortDescription: Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815...
|
||||
bankTime: 07.05.2025
|
||||
|
||||
amount: -250
|
||||
shortDescription: Перевод Надежда Юрьевна К** в Сбербанк через СБП, по номеру телефона +7964181514...
|
||||
bankTime: 07.05.2025
|
||||
|
||||
amount: -250
|
||||
shortDescription: Перевод Надежда Юрьевна К** в Альфа-Банк через СБП, по номеру телефона +79641815...
|
||||
bankTime: 07.05.2025
|
||||
|
||||
amount: 2100
|
||||
shortDescription: Перевод через СБП от Надежда Юрьевна К (+7(964)-181-51-46) из Альфа-Банк на 4081...
|
||||
bankTime: 07.05.2025
|
||||
|
||||
amount: 250
|
||||
shortDescription: Перевод через СБП от Надежда Юрьевна К (+7(964)-181-51-46) из Сбербанк на 408178...
|
||||
bankTime: 07.05.2025
|
||||
*/
|
||||
22
android/rshb/GetLastDaysHistoryScript.h
Normal file
22
android/rshb/GetLastDaysHistoryScript.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
#include "CommonScript.h"
|
||||
|
||||
class GetLastDaysHistoryScript final : public CommonScript {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
~GetLastDaysHistoryScript() override;
|
||||
|
||||
explicit GetLastDaysHistoryScript(
|
||||
AccountInfo account,
|
||||
QObject *parent = nullptr
|
||||
);
|
||||
|
||||
protected:
|
||||
void doStart() override;
|
||||
|
||||
private:
|
||||
const AccountInfo m_account;
|
||||
|
||||
bool openAndSaveDitailInfo(TransactionInfo &transaction, int width, int height);
|
||||
};
|
||||
@ -184,7 +184,8 @@ void PayByPhoneScript::makePayment(
|
||||
transaction.accountId = m_account.id;
|
||||
transaction.amount = -m_amount;
|
||||
transaction.type = TransactionType::Phone;
|
||||
if (bool inserted = TransactionDAO::insertTransaction(transaction); !inserted) {
|
||||
transaction.id = TransactionDAO::insertTransaction(transaction);
|
||||
if (transaction.id == -1) {
|
||||
// FIXME alert!!
|
||||
qDebug() << "Transaction has not inserted...";
|
||||
}
|
||||
@ -194,8 +195,7 @@ void PayByPhoneScript::makePayment(
|
||||
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)) {
|
||||
if (!TransactionDAO::updateTransactionStatus(transaction.id, TransactionStatus::Complete)) {
|
||||
qDebug() << "Not updated: " << transaction.id;
|
||||
}
|
||||
// TODO обновляем данные
|
||||
@ -205,10 +205,6 @@ void PayByPhoneScript::makePayment(
|
||||
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;
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "CommonScript.h"
|
||||
|
||||
class PayByPhoneScript final : public CommonScript {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
~PayByPhoneScript() override;
|
||||
|
||||
PayByPhoneScript(
|
||||
AccountInfo account,
|
||||
QString phone,
|
||||
@ -14,8 +15,6 @@ public:
|
||||
QObject *parent = nullptr
|
||||
);
|
||||
|
||||
~PayByPhoneScript() override;
|
||||
|
||||
protected:
|
||||
void doStart() override;
|
||||
|
||||
|
||||
@ -8,12 +8,12 @@
|
||||
#include <QDomDocument>
|
||||
#include <QFile>
|
||||
#include <QDateTime>
|
||||
#include <QTimeZone>
|
||||
|
||||
#include "adb/AdbUtils.h"
|
||||
#include "android/xml/Node.h"
|
||||
#include "db/AccountInfo.h"
|
||||
#include "db/TransactionInfo.h"
|
||||
#include "time/DateUtils.h"
|
||||
|
||||
ScreenXmlParser::ScreenXmlParser(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
@ -492,8 +492,7 @@ QString beforeAmount(const QString &text) {
|
||||
}
|
||||
|
||||
QList<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayHistory() {
|
||||
QTimeZone tz("Europe/Moscow");
|
||||
QDate today = QDateTime::currentDateTime(tz).date();
|
||||
QDate today = DateUtils::getMoscowNow().date();
|
||||
QDate yesterday = today.addDays(-1);
|
||||
QDate beforeYesterday = today.addDays(-2);
|
||||
|
||||
@ -519,6 +518,7 @@ QList<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayHistory() {
|
||||
|
||||
QList<TransactionInfo> transactions;
|
||||
if (!parentNode.isNull()) {
|
||||
QDate date = {};
|
||||
for (QDomNode transactionNode: parentNode.childNodes()) {
|
||||
QString transactionShortText = transactionNode.toElement().attribute("text");
|
||||
|
||||
@ -527,8 +527,6 @@ QList<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayHistory() {
|
||||
// только сегодня и вчера парсим, позавчера не трогаем
|
||||
break;
|
||||
}
|
||||
|
||||
QDate date = {};
|
||||
if (titleLowerCase.startsWith(todayTitle)) {
|
||||
date = today;
|
||||
transactionShortText = transactionShortText.mid(todayTitle.length() + 1);
|
||||
@ -557,8 +555,7 @@ QList<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayHistory() {
|
||||
}
|
||||
|
||||
void parse2daysHistory(const QDomNode &node) {
|
||||
QTimeZone tz("Europe/Moscow");
|
||||
QDate today = QDateTime::currentDateTime(tz).date();
|
||||
QDate today = DateUtils::getMoscowNow().date();
|
||||
QDate tomorrow = today.addDays(-1);
|
||||
QDate after2Days = today.addDays(-2);
|
||||
|
||||
@ -808,7 +805,7 @@ QList<QPair<AccountInfo, Node> > ScreenXmlParser::parseAccountsInfo() {
|
||||
info.lastNumbers = match.captured(1).remove(" ");
|
||||
info.amount = match.captured(2).remove(" ").toFloat();
|
||||
info.description = text.mid(0, text.indexOf("Номер карты"));
|
||||
info.updateTime = QDateTime::currentDateTime();
|
||||
info.updateTime = DateUtils::getUtcNow();
|
||||
|
||||
accounts.append(qMakePair(info, node));
|
||||
}
|
||||
|
||||
Binary file not shown.
@ -4,6 +4,7 @@
|
||||
|
||||
#include "db/AccountInfo.h"
|
||||
#include "DatabaseManager.h"
|
||||
#include "time/DateUtils.h"
|
||||
|
||||
bool AccountDAO::upsertAccount(const AccountInfo &info) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
@ -24,7 +25,7 @@ bool AccountDAO::upsertAccount(const AccountInfo &info) {
|
||||
query.bindValue(":numbers", info.numbers);
|
||||
query.bindValue(":last_numbers", info.lastNumbers);
|
||||
query.bindValue(":amount", info.amount);
|
||||
query.bindValue(":update_time", info.updateTime.toString(Qt::ISODate));
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
|
||||
query.bindValue(":status", accountStatusToString(info.status));
|
||||
query.bindValue(":description", info.description);
|
||||
|
||||
@ -69,7 +70,7 @@ QList<AccountInfo> AccountDAO::getAccounts(const QString &deviceId, const QStrin
|
||||
acc.numbers = query.value("numbers").toString();
|
||||
acc.lastNumbers = query.value("last_numbers").toString();
|
||||
acc.amount = query.value("amount").toDouble();
|
||||
acc.updateTime = QDateTime::fromString(query.value("update_time").toString(), Qt::ISODate);
|
||||
acc.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
|
||||
acc.status = accountStatusFromString(query.value("status").toString());
|
||||
acc.description = query.value("description").toString();
|
||||
accounts.append(acc);
|
||||
@ -86,7 +87,7 @@ AccountInfo parseAccount(const QSqlQuery &query) {
|
||||
acc.lastNumbers = query.value("last_numbers").toString();
|
||||
acc.numbers = query.value("numbers").toString();
|
||||
acc.amount = query.value("amount").toDouble();
|
||||
acc.updateTime = QDateTime::fromString(query.value("update_time").toString(), Qt::ISODate);
|
||||
acc.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
|
||||
acc.status = accountStatusFromString(query.value("status").toString());
|
||||
acc.description = query.value("description").toString();
|
||||
return acc;
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
#include <QSqlQuery>
|
||||
#include <QSqlError>
|
||||
|
||||
#include "time/DateUtils.h"
|
||||
|
||||
|
||||
QDateTime CommonDataDAO::getLastScan() {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
@ -16,16 +18,16 @@ QDateTime CommonDataDAO::getLastScan() {
|
||||
|
||||
if (query.next()) {
|
||||
const QString timestamp = query.value(0).toString();
|
||||
return QDateTime::fromString(timestamp, Qt::ISODate);
|
||||
return DateUtils::fromUtcString(timestamp);
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool CommonDataDAO::updateLastScan(const QDateTime& newTime) {
|
||||
bool CommonDataDAO::updateLastScan(const QDateTime &newTime) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
query.prepare("UPDATE common_data SET update_time = :time WHERE id = 1");
|
||||
query.bindValue(":time", newTime.toString(Qt::ISODate));
|
||||
query.bindValue(":time", DateUtils::toUtcString(newTime));
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при обновлении lastScan:" << query.lastError().text();
|
||||
@ -35,7 +37,7 @@ bool CommonDataDAO::updateLastScan(const QDateTime& newTime) {
|
||||
if (query.numRowsAffected() == 0) {
|
||||
QSqlQuery insertQuery(DatabaseManager::instance().database());
|
||||
insertQuery.prepare("INSERT INTO common_data (id, update_time) VALUES (1, :time)");
|
||||
insertQuery.bindValue(":time", newTime.toString(Qt::ISODate));
|
||||
insertQuery.bindValue(":time", DateUtils::toUtcString(newTime));
|
||||
|
||||
if (!insertQuery.exec()) {
|
||||
qWarning() << "Ошибка при INSERT lastScan:" << insertQuery.lastError().text();
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
#include "DeviceDAO.h"
|
||||
#include "DatabaseManager.h"
|
||||
#include "db/DeviceInfo.h"
|
||||
#include "time/DateUtils.h"
|
||||
|
||||
DeviceInfo parseDevice(const QSqlQuery &query) {
|
||||
DeviceInfo device;
|
||||
@ -13,7 +14,7 @@ DeviceInfo parseDevice(const QSqlQuery &query) {
|
||||
device.screenWidth = query.value("screen_width").toInt();
|
||||
device.screenHeight = query.value("screen_height").toInt();
|
||||
device.battery = query.value("battery").toInt();
|
||||
device.updateTime = QDateTime::fromString(query.value("update_time").toString(), Qt::ISODate);
|
||||
device.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
|
||||
device.image = query.value("image").toByteArray();
|
||||
return device;
|
||||
}
|
||||
@ -111,7 +112,7 @@ bool DeviceDAO::upsertDevice(const DeviceInfo &device) {
|
||||
query.bindValue(":width", device.screenWidth);
|
||||
query.bindValue(":height", device.screenHeight);
|
||||
query.bindValue(":battery", device.battery);
|
||||
query.bindValue(":update_time", device.updateTime.toString(Qt::ISODate));
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(device.updateTime));
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при вставке/обновлении устройства:" << query.lastError().text();
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include "DatabaseManager.h"
|
||||
#include "TransactionDAO.h"
|
||||
|
||||
#include "time/DateUtils.h"
|
||||
|
||||
bool TransactionDAO::insertTransactionIfNotExists(const TransactionInfo &info) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
|
||||
@ -24,7 +26,7 @@ bool TransactionDAO::insertTransactionIfNotExists(const TransactionInfo &info) {
|
||||
query.bindValue(":account_id", info.accountId);
|
||||
query.bindValue(":amount", info.amount);
|
||||
query.bindValue(":type", transactionTypeToString(info.type));
|
||||
query.bindValue(":timestamp", info.timestamp.toString(Qt::ISODate));
|
||||
query.bindValue(":timestamp", DateUtils::toUtcString(info.timestamp));
|
||||
|
||||
if (!query.exec() || !query.next()) {
|
||||
qWarning() << "Ошибка при проверке существования transaction:" << query.lastError().text();
|
||||
@ -63,9 +65,8 @@ bool TransactionDAO::insertTransactionIfNotExists(const TransactionInfo &info) {
|
||||
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));
|
||||
query.bindValue(":timestamp", info.timestamp.toString(Qt::ISODate));
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
|
||||
query.bindValue(":complete_time", DateUtils::toUtcString(info.completeTime));
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при вставке transaction:" << query.lastError().text();
|
||||
@ -75,7 +76,7 @@ bool TransactionDAO::insertTransactionIfNotExists(const TransactionInfo &info) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TransactionDAO::insertTransaction(const TransactionInfo &info) {
|
||||
int TransactionDAO::insertTransaction(const TransactionInfo &info) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
|
||||
query.prepare(R"(
|
||||
@ -106,15 +107,15 @@ bool TransactionDAO::insertTransaction(const TransactionInfo &info) {
|
||||
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));
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
|
||||
query.bindValue(":complete_time", DateUtils::toUtcString(info.completeTime));
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при вставке transaction:" << query.lastError().text();
|
||||
return false;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return true;
|
||||
return query.lastInsertId().toInt();
|
||||
}
|
||||
|
||||
bool TransactionDAO::deleteTransaction(const int id) {
|
||||
@ -124,6 +125,31 @@ bool TransactionDAO::deleteTransaction(const int id) {
|
||||
return query.exec();
|
||||
}
|
||||
|
||||
|
||||
TransactionInfo parseTransaction(const QSqlQuery &query) {
|
||||
TransactionInfo tx;
|
||||
tx.id = query.value("id").toInt();
|
||||
tx.accountId = query.value("account_id").toInt();
|
||||
tx.amount = query.value("amount").toDouble();
|
||||
tx.fee = query.value("fee").toDouble();
|
||||
tx.status = transactionStatusFromString(query.value("status").toString());
|
||||
tx.type = transactionTypeFromString(query.value("type").toString());
|
||||
tx.phone = query.value("phone").toString();
|
||||
tx.name = query.value("name").toString();
|
||||
tx.description = query.value("description").toString();
|
||||
tx.updatedDescription = query.value("updated_description").toString();
|
||||
tx.shortDescription = query.value("short_description").toString();
|
||||
tx.updatedShortDescription = query.value("updated_short_description").toString();
|
||||
tx.bankName = query.value("bank_name").toString();
|
||||
tx.bankTime = query.value("bank_time").toString();
|
||||
tx.trExternalId = query.value("tr_external_id").toString();
|
||||
tx.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
|
||||
tx.completeTime = DateUtils::fromUtcString(query.value("complete_time").toString());
|
||||
tx.timestamp = DateUtils::fromUtcString(query.value("timestamp").toString());
|
||||
return tx;
|
||||
}
|
||||
|
||||
|
||||
QList<TransactionInfo> TransactionDAO::getTransactions(const int accountId) {
|
||||
QList<TransactionInfo> list;
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
@ -142,27 +168,7 @@ QList<TransactionInfo> TransactionDAO::getTransactions(const int accountId) {
|
||||
}
|
||||
|
||||
while (query.next()) {
|
||||
TransactionInfo tx;
|
||||
tx.id = query.value("id").toInt();
|
||||
tx.accountId = query.value("account_id").toInt();
|
||||
tx.amount = query.value("amount").toDouble();
|
||||
tx.fee = query.value("fee").toDouble();
|
||||
tx.status = transactionStatusFromString(query.value("status").toString());
|
||||
tx.type = transactionTypeFromString(query.value("type").toString());
|
||||
tx.phone = query.value("phone").toString();
|
||||
tx.name = query.value("name").toString();
|
||||
tx.description = query.value("description").toString();
|
||||
tx.updatedDescription = query.value("updated_description").toString();
|
||||
tx.shortDescription = query.value("short_description").toString();
|
||||
tx.updatedShortDescription = query.value("updated_short_description").toString();
|
||||
tx.bankName = query.value("bank_name").toString();
|
||||
tx.bankTime = query.value("bank_time").toString();
|
||||
tx.trExternalId = query.value("tr_external_id").toString();
|
||||
tx.updateTime = QDateTime::fromString(query.value("update_time").toString(), Qt::ISODate);
|
||||
tx.completeTime = QDateTime::fromString(query.value("complete_time").toString(), Qt::ISODate);
|
||||
tx.timestamp = QDateTime::fromString(query.value("timestamp").toString(), Qt::ISODate);
|
||||
|
||||
list.append(tx);
|
||||
list.append(parseTransaction(query));
|
||||
}
|
||||
|
||||
return list;
|
||||
@ -171,6 +177,8 @@ QList<TransactionInfo> TransactionDAO::getTransactions(const int accountId) {
|
||||
bool TransactionDAO::updateTransaction(const TransactionInfo &info) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
|
||||
qDebug().noquote().nospace() << convertTransactionToString(info);
|
||||
|
||||
query.prepare(R"(
|
||||
UPDATE transactions SET
|
||||
amount = :amount,
|
||||
@ -206,9 +214,9 @@ bool TransactionDAO::updateTransaction(const TransactionInfo &info) {
|
||||
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));
|
||||
query.bindValue(":timestamp", info.timestamp.toString(Qt::ISODate));
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
|
||||
query.bindValue(":complete_time", DateUtils::toUtcString(info.completeTime));
|
||||
query.bindValue(":timestamp", DateUtils::toUtcString(info.timestamp));
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при обновлении transaction:" << query.lastError().text();
|
||||
@ -232,20 +240,21 @@ bool TransactionDAO::updateTransactionStatus(
|
||||
WHERE id = :id
|
||||
)");
|
||||
|
||||
// const QString currentTime = now.toString("yyyy-MM-dd HH:mm:ss");
|
||||
query.bindValue(":id", id);
|
||||
query.bindValue(":status", transactionStatusToString(status));
|
||||
QString updateTime;
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
|
||||
|
||||
if (status == TransactionStatus::Complete) {
|
||||
updateTime = QDateTime::currentDateTime().toString(Qt::ISODate);
|
||||
query.bindValue(":complete_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
|
||||
} else {
|
||||
query.bindValue(":complete_time", QVariant(QMetaType(QMetaType::QString)));
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
@ -255,30 +264,31 @@ TransactionInfo TransactionDAO::getTransactionById(const int id) {
|
||||
query.bindValue(":id", id);
|
||||
|
||||
|
||||
TransactionInfo tx;
|
||||
if (!query.exec() || !query.next()) {
|
||||
qWarning() << "Ошибка или не найден transaction с id:" << id << query.lastError().text();
|
||||
return tx;
|
||||
return {};
|
||||
}
|
||||
return parseTransaction(query);
|
||||
}
|
||||
|
||||
QList<TransactionInfo> TransactionDAO::getTransactionsWithinHours(const int accountId, const int hours) {
|
||||
QList<TransactionInfo> list;
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
query.prepare(R"(
|
||||
SELECT * FROM transactions
|
||||
WHERE account_id = :accountId
|
||||
AND timestamp >= datetime('now', '-' || :hours || ' hours')
|
||||
)");
|
||||
query.bindValue(":accountId", accountId);
|
||||
query.bindValue(":hours", hours);
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка получения транзакций: " << query.lastError().text();
|
||||
return {};
|
||||
}
|
||||
|
||||
tx.id = query.value("id").toInt();
|
||||
tx.accountId = query.value("account_id").toInt();
|
||||
tx.amount = query.value("amount").toDouble();
|
||||
tx.fee = query.value("fee").toDouble();
|
||||
tx.status = transactionStatusFromString(query.value("status").toString());
|
||||
tx.type = transactionTypeFromString(query.value("type").toString());
|
||||
tx.phone = query.value("phone").toString();
|
||||
tx.name = query.value("name").toString();
|
||||
tx.description = query.value("description").toString();
|
||||
tx.shortDescription = query.value("short_description").toString();
|
||||
tx.updatedDescription = query.value("updated_description").toString();
|
||||
tx.updatedShortDescription = query.value("updated_short_description").toString();
|
||||
tx.bankName = query.value("bank_name").toString();
|
||||
tx.bankTime = query.value("bank_time").toString();
|
||||
tx.trExternalId = query.value("tr_external_id").toString();
|
||||
tx.updateTime = QDateTime::fromString(query.value("update_time").toString(), Qt::ISODate);
|
||||
tx.completeTime = QDateTime::fromString(query.value("complete_time").toString(), Qt::ISODate);
|
||||
tx.timestamp = QDateTime::fromString(query.value("timestamp").toString(), Qt::ISODate);
|
||||
|
||||
return tx;
|
||||
while (query.next()) {
|
||||
list.append(parseTransaction(query));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
@ -1,11 +1,12 @@
|
||||
#pragma once
|
||||
#include "db/TransactionInfo.h"
|
||||
#include "rshb/GetLastDaysHistoryScript.h"
|
||||
|
||||
class TransactionDAO {
|
||||
public:
|
||||
[[nodiscard]] static bool insertTransactionIfNotExists(const TransactionInfo &info);
|
||||
|
||||
[[nodiscard]] static bool insertTransaction(const TransactionInfo &info);
|
||||
[[nodiscard]] static int insertTransaction(const TransactionInfo &info);
|
||||
|
||||
[[nodiscard]] static bool deleteTransaction(int id);
|
||||
|
||||
@ -16,4 +17,6 @@ public:
|
||||
[[nodiscard]] static bool updateTransactionStatus(int id, TransactionStatus status);
|
||||
|
||||
[[nodiscard]] static TransactionInfo getTransactionById(int id);
|
||||
|
||||
[[nodiscard]] static QList<TransactionInfo> getTransactionsWithinHours(int accountId, int hours);
|
||||
};
|
||||
|
||||
25
database/time/DateUtils.cpp
Normal file
25
database/time/DateUtils.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "DateUtils.h"
|
||||
|
||||
DateUtils::DateUtils(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
|
||||
QDateTime DateUtils::getMoscowNow() {
|
||||
const QTimeZone moscowTimeZone("Europe/Moscow");
|
||||
return QDateTime::currentDateTime().toTimeZone(moscowTimeZone);
|
||||
}
|
||||
|
||||
QDateTime DateUtils::getUtcNow() {
|
||||
return QDateTime::currentDateTimeUtc();
|
||||
}
|
||||
|
||||
QDateTime DateUtils::fromUtcString(const QString ×tamp) {
|
||||
QDateTime dateTime = QDateTime::fromString(timestamp, "dd.MM.yyyy HH:mm:ss");
|
||||
if (dateTime.isValid()) {
|
||||
dateTime.setTimeZone(QTimeZone::utc());
|
||||
}
|
||||
return dateTime;
|
||||
}
|
||||
|
||||
QString DateUtils::toUtcString(const QDateTime &dateTime) {
|
||||
return dateTime.toString("dd.MM.yyyy HH:mm:ss");
|
||||
}
|
||||
17
database/time/DateUtils.h
Normal file
17
database/time/DateUtils.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include <QTimeZone>
|
||||
|
||||
class DateUtils final : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit DateUtils(QObject *parent = nullptr);
|
||||
|
||||
static QDateTime getMoscowNow();
|
||||
|
||||
static QDateTime getUtcNow();
|
||||
|
||||
static QDateTime fromUtcString(const QString ×tamp);
|
||||
|
||||
static QString toUtcString(const QDateTime &dateTime);
|
||||
};
|
||||
12
main.cpp
12
main.cpp
@ -15,6 +15,7 @@
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include "rshb/GetLastDaysHistoryScript.h"
|
||||
#include "rshb/HomeScreenScript.h"
|
||||
#include "rshb/PayByPhoneScript.h"
|
||||
|
||||
@ -55,17 +56,18 @@ void setupScriptAutoPaymentAndThread(QCoreApplication &app) {
|
||||
const QString phoneNumber = "79641815146";
|
||||
const QString bankName = "Альфа-Банк";
|
||||
// const QString bankName = "Сбербанк";
|
||||
const double ammount = 250;
|
||||
const double ammount = 310;
|
||||
|
||||
AccountInfo account = AccountDAO::findAppAccount(appName, cardNumber);
|
||||
if (account.id != -1) {
|
||||
auto *thread = new QThread;
|
||||
auto *scriptWorker = new PayByPhoneScript(account, phoneNumber, bankName, ammount);
|
||||
auto *scriptWorker = new GetLastDaysHistoryScript(account);
|
||||
// auto *scriptWorker = new PayByPhoneScript(account, phoneNumber, bankName, ammount);
|
||||
|
||||
scriptWorker->moveToThread(thread);
|
||||
QObject::connect(thread, &QThread::started, scriptWorker, &PayByPhoneScript::start);
|
||||
QObject::connect(scriptWorker, &PayByPhoneScript::finished, thread, &QThread::quit);
|
||||
QObject::connect(scriptWorker, &PayByPhoneScript::finished, scriptWorker, &QObject::deleteLater);
|
||||
QObject::connect(thread, &QThread::started, scriptWorker, &GetLastDaysHistoryScript::start);
|
||||
QObject::connect(scriptWorker, &GetLastDaysHistoryScript::finished, thread, &QThread::quit);
|
||||
QObject::connect(scriptWorker, &GetLastDaysHistoryScript::finished, scriptWorker, &QObject::deleteLater);
|
||||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
|
||||
QObject::connect(&app, &QCoreApplication::aboutToQuit, [=]() {
|
||||
|
||||
@ -8,7 +8,7 @@ CREATE TABLE IF NOT EXISTS devices
|
||||
screen_height INTEGER,
|
||||
battery INTEGER,
|
||||
update_time DATETIME,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
timestamp DATETIME DEFAULT (strftime('%d.%m.%Y %H:%M:%S', 'now')),
|
||||
image BLOB
|
||||
);
|
||||
|
||||
@ -35,7 +35,7 @@ CREATE TABLE IF NOT EXISTS accounts
|
||||
last_numbers TEXT,
|
||||
description TEXT,
|
||||
amount REAL,
|
||||
update_time DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
update_time DATETIME DEFAULT (strftime('%d.%m.%Y %H:%M:%S', 'now')),
|
||||
status TEXT,
|
||||
FOREIGN KEY (device_id) REFERENCES devices (id) ON DELETE CASCADE,
|
||||
UNIQUE (device_id, app_name, last_numbers)
|
||||
@ -66,7 +66,7 @@ CREATE TABLE IF NOT EXISTS transactions
|
||||
|
||||
update_time DATETIME,
|
||||
complete_time DATETIME,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
timestamp DATETIME DEFAULT (strftime('%d.%m.%Y %H:%M:%S', 'now')),
|
||||
FOREIGN KEY (account_id) REFERENCES accounts (id) ON DELETE CASCADE,
|
||||
UNIQUE (amount, timestamp)
|
||||
);
|
||||
Loading…
Reference in New Issue
Block a user