Add event handling and improved account management
Introduced a new "events" table and corresponding EventDAO for managing event data. Enhanced account handling with device ID and partial card number support. Added a NetworkService method to fetch payments from an API and store them as events.
This commit is contained in:
parent
5878705ae0
commit
e32dd21827
@ -244,13 +244,6 @@ void PayByPhoneScript::doStart() {
|
||||
const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);
|
||||
const ApplicationInfo app = ApplicationDAO::getApplicationsByDeviceId(m_account.deviceId, m_account.appName);
|
||||
|
||||
for (TransactionInfo &transaction: TransactionDAO::getTransactions(m_account.id)) {
|
||||
// postNewTransactionData(m_account, transaction);
|
||||
updateTransactionData(m_account, transaction.id, transaction.status, transaction.updatedDescription, transaction.description);
|
||||
}
|
||||
|
||||
emit finishedWithResult(m_error);
|
||||
return;
|
||||
if (device.id.isEmpty() || app.id.isEmpty()) {
|
||||
qDebug() << "Device or app not found....";
|
||||
return;
|
||||
|
||||
Binary file not shown.
@ -44,6 +44,20 @@ bool AccountDAO::deleteAccount(const int id) {
|
||||
return query.exec();
|
||||
}
|
||||
|
||||
AccountInfo parseAccount(const QSqlQuery &query) {
|
||||
AccountInfo acc;
|
||||
acc.id = query.value("id").toInt();
|
||||
acc.deviceId = query.value("device_id").toString();
|
||||
acc.appName = query.value("app_name").toString();
|
||||
acc.lastNumbers = query.value("last_numbers").toString();
|
||||
acc.numbers = query.value("numbers").toString();
|
||||
acc.amount = query.value("amount").toDouble();
|
||||
acc.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
|
||||
acc.status = accountStatusFromString(query.value("status").toString());
|
||||
acc.description = query.value("description").toString();
|
||||
return acc;
|
||||
}
|
||||
|
||||
QList<AccountInfo> AccountDAO::getAccounts(const QString &deviceId, const QString &appName) {
|
||||
QList<AccountInfo> accounts;
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
@ -63,36 +77,12 @@ QList<AccountInfo> AccountDAO::getAccounts(const QString &deviceId, const QStrin
|
||||
}
|
||||
|
||||
while (query.next()) {
|
||||
AccountInfo acc;
|
||||
acc.id = query.value("id").toInt();
|
||||
acc.deviceId = query.value("device_id").toString();
|
||||
acc.appName = query.value("app_name").toString();
|
||||
acc.numbers = query.value("numbers").toString();
|
||||
acc.lastNumbers = query.value("last_numbers").toString();
|
||||
acc.amount = query.value("amount").toDouble();
|
||||
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);
|
||||
accounts.append(parseAccount(query));
|
||||
}
|
||||
|
||||
return accounts;
|
||||
}
|
||||
|
||||
AccountInfo parseAccount(const QSqlQuery &query) {
|
||||
AccountInfo acc;
|
||||
acc.id = query.value("id").toInt();
|
||||
acc.deviceId = query.value("device_id").toString();
|
||||
acc.appName = query.value("app_name").toString();
|
||||
acc.lastNumbers = query.value("last_numbers").toString();
|
||||
acc.numbers = query.value("numbers").toString();
|
||||
acc.amount = query.value("amount").toDouble();
|
||||
acc.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
|
||||
acc.status = accountStatusFromString(query.value("status").toString());
|
||||
acc.description = query.value("description").toString();
|
||||
return acc;
|
||||
}
|
||||
|
||||
AccountInfo AccountDAO::getAccountById(const int accountId) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
|
||||
@ -116,18 +106,19 @@ AccountInfo AccountDAO::getAccountById(const int accountId) {
|
||||
return {};
|
||||
}
|
||||
|
||||
AccountInfo AccountDAO::findAppAccount(const QString &appName, const QString &cardNumber) {
|
||||
AccountInfo AccountDAO::findAppAccount(const QString &deviceId, const QString &appName, const QString &lastNumber) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
|
||||
query.prepare(R"(
|
||||
SELECT id, device_id, app_name, numbers, last_numbers, amount, update_time, status, description
|
||||
FROM accounts
|
||||
WHERE app_name = :app_name AND numbers = :numbers
|
||||
WHERE app_name = :appName AND last_numbers = :lastNumber AND device_id = :deviceId
|
||||
LIMIT 1
|
||||
)");
|
||||
|
||||
query.bindValue(":app_name", appName);
|
||||
query.bindValue(":numbers", cardNumber);
|
||||
query.bindValue(":deviceId", deviceId);
|
||||
query.bindValue(":appName", appName);
|
||||
query.bindValue(":lastNumber", lastNumber);
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при получении account по ID:" << query.lastError().text();
|
||||
|
||||
@ -11,5 +11,9 @@ public:
|
||||
|
||||
[[nodiscard]] static AccountInfo getAccountById(int accountId);
|
||||
|
||||
[[nodiscard]] static AccountInfo findAppAccount(const QString &appName, const QString &cardNumber);
|
||||
[[nodiscard]] static AccountInfo findAppAccount(
|
||||
const QString &deviceId,
|
||||
const QString &appName,
|
||||
const QString &lastNumber
|
||||
);
|
||||
};
|
||||
|
||||
108
database/dao/EventDAO.cpp
Normal file
108
database/dao/EventDAO.cpp
Normal file
@ -0,0 +1,108 @@
|
||||
#include "EventDAO.h"
|
||||
|
||||
#include <QSqlError>
|
||||
#include <QSqlQuery>
|
||||
|
||||
#include "DatabaseManager.h"
|
||||
#include "time/DateUtils.h"
|
||||
|
||||
EventInfo parseEvent(const QSqlQuery &query) {
|
||||
EventInfo event;
|
||||
event.id = query.value("id").toInt();
|
||||
event.status = eventStatusFromString(query.value("status").toString());
|
||||
event.externalId = query.value("external_id").toInt();
|
||||
event.accountId = query.value("account_id").toInt();
|
||||
event.amount = query.value("amount").toDouble();
|
||||
event.phone = query.value("phone").toString();
|
||||
event.bankName = query.value("bank_name").toString();
|
||||
event.timestamp = DateUtils::fromUtcString(query.value("timestamp").toString());
|
||||
event.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
|
||||
event.completeTime = DateUtils::fromUtcString(query.value("complete_time").toString());
|
||||
return event;
|
||||
}
|
||||
|
||||
int EventDAO::insertEvent(const EventInfo &event) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
|
||||
query.prepare(R"(
|
||||
INSERT INTO events (
|
||||
status, external_id, account_id, amount, phone, bank_name, timestamp
|
||||
) VALUES (
|
||||
:status, :external_id, :account_id, :amount, :phone, :bank_name, :timestamp
|
||||
)
|
||||
)");
|
||||
|
||||
query.bindValue(":status", eventStatusToString(event.status));
|
||||
query.bindValue(":external_id", event.externalId);
|
||||
query.bindValue(":account_id", event.accountId);
|
||||
query.bindValue(":amount", event.amount);
|
||||
query.bindValue(":phone", event.phone);
|
||||
query.bindValue(":bank_name", event.bankName);
|
||||
query.bindValue(":timestamp", DateUtils::toUtcString(DateUtils::getUtcNow()));
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при вставке event:" << query.lastError().text();
|
||||
return -1;
|
||||
}
|
||||
|
||||
return query.lastInsertId().toInt();
|
||||
}
|
||||
|
||||
bool EventDAO::updateEvent(
|
||||
const int id,
|
||||
const EventStatus &status
|
||||
) {
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
|
||||
query.prepare(R"(
|
||||
UPDATE events SET
|
||||
status = :status,
|
||||
update_time = :update_time,
|
||||
complete_time = :complete_time
|
||||
WHERE id = :id
|
||||
)");
|
||||
|
||||
query.bindValue(":id", id);
|
||||
query.bindValue(":status", eventStatusToString(status));
|
||||
|
||||
if (status == EventStatus::Wait) {
|
||||
query.bindValue(":update_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
|
||||
} else {
|
||||
query.bindValue(":update_time", QVariant(QMetaType(QMetaType::QString)));
|
||||
}
|
||||
|
||||
if (status == EventStatus::Complete) {
|
||||
query.bindValue(":complete_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
|
||||
} else {
|
||||
query.bindValue(":complete_time", QVariant(QMetaType(QMetaType::QString)));
|
||||
}
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при обновлении event:" << query.lastError().text();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
QList<EventInfo> EventDAO::getAllEvents(const EventStatus &status) {
|
||||
QList<EventInfo> events;
|
||||
|
||||
QSqlQuery query(DatabaseManager::instance().database());
|
||||
query.prepare(R"(
|
||||
SELECT id, account_id, external_id, amount, phone, bank_name, status, update_time, complete_time, timestamp
|
||||
FROM events
|
||||
WHERE status = :status
|
||||
)");
|
||||
query.bindValue(":status", eventStatusToString(status));
|
||||
|
||||
if (!query.exec()) {
|
||||
qWarning() << "Ошибка при получении списка устройств:" << query.lastError().text();
|
||||
return events;
|
||||
}
|
||||
|
||||
while (query.next()) {
|
||||
events.append(parseEvent(query));
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
15
database/dao/EventDAO.h
Normal file
15
database/dao/EventDAO.h
Normal file
@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <db/EventInfo.h>
|
||||
|
||||
class EventDAO {
|
||||
public:
|
||||
[[nodiscard]] static int insertEvent(const EventInfo &event);
|
||||
|
||||
[[nodiscard]] static bool updateEvent(
|
||||
int id,
|
||||
const EventStatus &status
|
||||
);
|
||||
|
||||
[[nodiscard]] static QList<EventInfo> getAllEvents(const EventStatus &status);
|
||||
};
|
||||
26
main.cpp
26
main.cpp
@ -16,6 +16,7 @@
|
||||
#include <chrono>
|
||||
#include <QFile>
|
||||
|
||||
#include "net/NetworkService.h"
|
||||
#include "rshb/GetLastDaysHistoryScript.h"
|
||||
#include "rshb/HomeScreenScript.h"
|
||||
#include "rshb/PayByPhoneScript.h"
|
||||
@ -52,8 +53,9 @@ void setupWorkerAndThread(QCoreApplication &app) {
|
||||
|
||||
void setupWorkerAndThreadHistory(QCoreApplication &app) {
|
||||
const QString appName = "rshb";
|
||||
const QString cardNumber = "2200380317107183";
|
||||
AccountInfo account = AccountDAO::findAppAccount(appName, cardNumber);
|
||||
const QString lastNumber = "7183";
|
||||
const QString deviceId = "6edc4a47";
|
||||
AccountInfo account = AccountDAO::findAppAccount(deviceId, appName, lastNumber);
|
||||
auto *thread = new QThread;
|
||||
auto *deviceScreenerWorker = new GetLastDaysHistoryScript(account);
|
||||
|
||||
@ -72,14 +74,15 @@ void setupWorkerAndThreadHistory(QCoreApplication &app) {
|
||||
|
||||
void setupScriptAutoPaymentAndThread(QCoreApplication &app) {
|
||||
const QString appName = "rshb";
|
||||
const QString cardNumber = "2200380317107183";
|
||||
const QString lastNumber = "7183";
|
||||
|
||||
const QString phoneNumber = "79641815146";
|
||||
const QString deviceId = "6edc4a47";
|
||||
const QString bankName = "Альфа-Банк";
|
||||
// const QString bankName = "Сбербанк";
|
||||
const double amount = 320;
|
||||
|
||||
const AccountInfo account = AccountDAO::findAppAccount(appName, cardNumber);
|
||||
const AccountInfo account = AccountDAO::findAppAccount(deviceId, appName, lastNumber);
|
||||
if (account.id != -1) {
|
||||
// Функция для подключения потоков к завершению приложения
|
||||
auto connectStopOnQuit = [&](QObject *worker, QThread *thread) {
|
||||
@ -193,7 +196,20 @@ int main(int argc, char *argv[]) {
|
||||
// Устанавливаем свой обработчик
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
setupScriptAutoPaymentAndThread(app);
|
||||
|
||||
auto *thread = new QThread;
|
||||
auto *worker = new NetworkService;
|
||||
|
||||
// FIXME доставить десктоп ид из настроеек
|
||||
worker->setDeviceData("DT88bokcwQ", "");
|
||||
worker->moveToThread(thread);
|
||||
QObject::connect(thread, &QThread::started, worker, &NetworkService::getPayments);
|
||||
QObject::connect(worker, &NetworkService::finished, thread, &QThread::quit);
|
||||
QObject::connect(worker, &NetworkService::finished, worker, &QObject::deleteLater);
|
||||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||||
thread->start();
|
||||
|
||||
// setupScriptAutoPaymentAndThread(app);
|
||||
// setupWorkerAndThread(app);
|
||||
|
||||
MainWindow window;
|
||||
|
||||
@ -67,4 +67,23 @@ CREATE TABLE IF NOT EXISTS transactions
|
||||
complete_time DATETIME,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (account_id) REFERENCES accounts (id) ON DELETE CASCADE
|
||||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS events
|
||||
(
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
account_id INTEGER,
|
||||
external_id INTEGER,
|
||||
|
||||
amount REAL,
|
||||
phone TEXT,
|
||||
bank_name TEXT,
|
||||
|
||||
status TEXT,
|
||||
|
||||
update_time DATETIME,
|
||||
complete_time DATETIME,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
|
||||
FOREIGN KEY (account_id) REFERENCES accounts (id) ON DELETE CASCADE,
|
||||
UNIQUE (external_id)
|
||||
);
|
||||
44
models/db/EventInfo.h
Normal file
44
models/db/EventInfo.h
Normal file
@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
|
||||
enum class EventStatus {
|
||||
Wait,
|
||||
InProgress,
|
||||
Complete,
|
||||
Unknown
|
||||
};
|
||||
|
||||
|
||||
inline QString eventStatusToString(const EventStatus type) {
|
||||
switch (type) {
|
||||
case EventStatus::Wait: return "wait";
|
||||
case EventStatus::Complete: return "complete";
|
||||
case EventStatus::InProgress: return "iPprogress";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
inline EventStatus eventStatusFromString(const QString &str) {
|
||||
if (str == "wait") return EventStatus::Wait;
|
||||
if (str == "complete") return EventStatus::Complete;
|
||||
if (str == "iPprogress") return EventStatus::InProgress;
|
||||
return EventStatus::Unknown;
|
||||
}
|
||||
|
||||
struct EventInfo {
|
||||
int id = -1;
|
||||
int externalId = -1;
|
||||
int accountId = -1;
|
||||
|
||||
double amount = 0;
|
||||
QString phone;
|
||||
QString bankName;
|
||||
|
||||
EventStatus status = EventStatus::Unknown;
|
||||
|
||||
QDateTime updateTime;
|
||||
QDateTime completeTime;
|
||||
QDateTime timestamp;
|
||||
};
|
||||
@ -1,11 +1,16 @@
|
||||
#include "NetworkService.h"
|
||||
|
||||
#include <QEventLoop>
|
||||
#include <QUrlQuery>
|
||||
#include <QHttpPart>
|
||||
#include <QNetworkReply>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonArray>
|
||||
|
||||
#include "dao/AccountDAO.h"
|
||||
#include "dao/EventDAO.h"
|
||||
#include "dao/TransactionDAO.h"
|
||||
#include "db/EventInfo.h"
|
||||
|
||||
NetworkService::NetworkService(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
@ -69,6 +74,47 @@ QJsonValue NetworkService::post(QHttpMultiPart *multiPart, const QString &path)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
QJsonArray NetworkService::get(const QString &path, const QMap<QString, QString> ¶ms) {
|
||||
QNetworkAccessManager manager; // создаём внутри потока
|
||||
|
||||
QUrl url(path);
|
||||
QUrlQuery query;
|
||||
for (auto it = params.constBegin(); it != params.constEnd(); ++it) {
|
||||
query.addQueryItem(it.key(), it.value());
|
||||
}
|
||||
url.setQuery(query);
|
||||
|
||||
const QNetworkRequest request(url);
|
||||
QNetworkReply *reply = manager.get(request);
|
||||
|
||||
QEventLoop loop;
|
||||
connect(reply, &QNetworkReply::finished, &loop, &QEventLoop::quit);
|
||||
connect(reply, &QNetworkReply::errorOccurred, [&loop](QNetworkReply::NetworkError) {
|
||||
loop.quit();
|
||||
});
|
||||
loop.exec(); // <- здесь и запускается event-loop потока
|
||||
|
||||
QJsonArray result;
|
||||
if (reply->error() == QNetworkReply::NoError) {
|
||||
const QByteArray raw = reply->readAll();
|
||||
QJsonParseError err;
|
||||
const QJsonDocument doc = QJsonDocument::fromJson(raw, &err);
|
||||
if (err.error == QJsonParseError::NoError && doc.isObject()) {
|
||||
const QJsonObject root = doc.object();
|
||||
if (root.value("success").toBool()) {
|
||||
result = root.value("data").toArray();
|
||||
} else {
|
||||
qWarning() << "Ошибка:" << root;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
qWarning() << "Ошибка:" << reply->errorString();
|
||||
}
|
||||
reply->deleteLater();
|
||||
return result;
|
||||
}
|
||||
|
||||
void NetworkService::postAccountsData() {
|
||||
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
@ -83,6 +129,43 @@ void NetworkService::postAccountsData() {
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void NetworkService::getPayments() {
|
||||
QMap<QString, QString> params;
|
||||
params["desktopUniqueName"] = m_desktopId;
|
||||
const QJsonArray data = get("http://localhost:9999/api/v1/payments", params);
|
||||
|
||||
for (QJsonValue item: data) {
|
||||
QJsonObject obj = item.toObject();
|
||||
EventInfo eventInfo;
|
||||
eventInfo.status = EventStatus::Wait;
|
||||
eventInfo.externalId = obj["id"].toInt();
|
||||
eventInfo.amount = obj["amount"].toDouble();
|
||||
eventInfo.bankName = obj["bankName"].toString();
|
||||
eventInfo.phone = obj["phone"].toString();
|
||||
|
||||
QString deviceId = obj["deviceId"].toString();
|
||||
QString appName = obj["appName"].toString();
|
||||
QString lastNumbers = obj["lastNumbers"].toString();
|
||||
AccountInfo account = AccountDAO::findAppAccount(deviceId, appName, lastNumbers);
|
||||
|
||||
eventInfo.accountId = account.id;
|
||||
|
||||
|
||||
int id = EventDAO::insertEvent(eventInfo);
|
||||
if (id == -1) {
|
||||
qDebug() << "Cant insert event";
|
||||
} else {
|
||||
if (!EventDAO::updateEvent(id, EventStatus::Wait)) {
|
||||
qDebug() << "Cant update event";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
emit finished();
|
||||
}
|
||||
|
||||
|
||||
void NetworkService::updateTransactionData() {
|
||||
QHttpMultiPart *multiPart = new QHttpMultiPart(QHttpMultiPart::FormDataType);
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ public:
|
||||
public slots:
|
||||
void postAccountsData();
|
||||
|
||||
void getPayments();
|
||||
|
||||
void insertTransactionData();
|
||||
|
||||
@ -42,4 +43,6 @@ private:
|
||||
|
||||
|
||||
QJsonValue post(QHttpMultiPart *multiPart, const QString &path);
|
||||
|
||||
QJsonArray get(const QString &path, const QMap<QString, QString> ¶ms);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user