1
0
forked from BRT/arc
arc/database/dao/EventDAO.cpp

378 lines
13 KiB
C++

#include "EventDAO.h"
#include <QSqlError>
#include <QSqlQuery>
#include <QSqlRecord>
#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.type = eventTypeFromString(query.value("type").toString());
event.externalId = query.value("external_id").toString();
event.accountId = query.value("account_id").toInt();
event.deviceId = query.value("device_id").toString();
event.amount = query.value("amount").toDouble();
event.phone = query.value("phone").toString();
event.bankName = query.value("bank_name").toString();
event.comment = query.value("comment").toString();
event.json = query.value("json").toString();
event.sentToServer = query.value("sent_to_server").toBool();
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());
const int hasScreenshotIdx = query.record().indexOf("has_screenshot");
if (hasScreenshotIdx >= 0) {
event.hasScreenshot = query.value(hasScreenshotIdx).toBool();
}
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, comment, json, timestamp, device_id, type
) VALUES (
:status, :external_id, :account_id, :amount, :phone, :bank_name, :comment, :json, :timestamp, :device_id, :type
)
)");
query.bindValue(":status", eventStatusToString(event.status));
query.bindValue(":type", eventTypeToString(event.type));
query.bindValue(":external_id", event.externalId);
query.bindValue(":account_id", event.accountId);
query.bindValue(":device_id", event.deviceId);
query.bindValue(":amount", event.amount);
query.bindValue(":phone", event.phone);
query.bindValue(":bank_name", event.bankName);
query.bindValue(":comment", event.comment);
query.bindValue(":json", event.json);
query.bindValue(":timestamp", DateUtils::toUtcString(event.timestamp));
if (!query.exec()) {
qCritical() << "Ошибка при вставке event:" << query.lastError().text();
return -1;
}
return query.lastInsertId().toInt();
}
bool EventDAO::updateEvent(
const int id,
const EventStatus &status,
const QString &comment
) {
QSqlQuery query(DatabaseManager::instance().database());
if (status == EventStatus::InProgress) {
query.prepare(R"(
UPDATE events SET
status = :status,
update_time = :update_time
WHERE id = :id
)");
query.bindValue(":update_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
}
if (status == EventStatus::Complete) {
query.prepare(R"(
UPDATE events SET
status = :status,
complete_time = :complete_time
WHERE id = :id
)");
query.bindValue(":complete_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
}
if (status == EventStatus::Error) {
query.prepare(R"(
UPDATE events SET
status = :status,
update_time = :update_time,
comment = :comment
WHERE id = :id
)");
query.bindValue(":update_time", DateUtils::toUtcString(DateUtils::getUtcNow()));
query.bindValue(":comment", comment);
}
query.bindValue(":id", id);
query.bindValue(":status", eventStatusToString(status));
if (!query.exec()) {
qCritical() << "Ошибка при обновлении event:" << query.lastError().text();
return false;
}
return true;
}
bool EventDAO::updateEventAmount(int id, double amount) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare("UPDATE events SET amount = :amount WHERE id = :id");
query.bindValue(":amount", amount);
query.bindValue(":id", id);
if (!query.exec()) {
qCritical() << "Ошибка при обновлении amount event:" << query.lastError().text();
return false;
}
return true;
}
bool EventDAO::markSentToServer(int id) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare("UPDATE events SET sent_to_server = 1 WHERE id = :id");
query.bindValue(":id", id);
if (!query.exec()) {
qWarning() << "Ошибка markSentToServer:" << 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, device_id, external_id, amount, phone, bank_name,
status, type, comment, json, sent_to_server, update_time, complete_time, timestamp
FROM events
WHERE status = :status
)");
query.bindValue(":status", eventStatusToString(status));
if (!query.exec()) {
qWarning() << "Ошибка при получении getAllEvents:" << query.lastError().text();
return events;
}
while (query.next()) {
events.append(parseEvent(query));
}
return events;
}
EventInfo EventDAO::getFirstWaitEventByDeviceId(const QString &key) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, account_id, device_id, external_id, amount, phone, bank_name,
status, type, comment, json, sent_to_server, update_time, complete_time, timestamp
FROM events
WHERE status = :status AND device_id = :device_id
ORDER BY
CASE type
WHEN 'CREATE_TRANSACTION' THEN 0
WHEN 'FETCH_TRANSACTIONS' THEN 1
WHEN 'FETCH_PROFILE' THEN 2
ELSE 3
END ASC,
timestamp ASC
LIMIT 1
)");
query.bindValue(":status", eventStatusToString(EventStatus::Wait));
query.bindValue(":device_id", key);
if (!query.exec()) {
qCritical() << "Ошибка при получении getFirstWaitEventByDeviceId:" << query.lastError().text();
return {};
}
while (query.next()) {
return parseEvent(query);
}
return {};
}
QList<EventInfo> EventDAO::getEvents(int page, int pageSize) {
QList<EventInfo> events;
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, account_id, device_id, external_id, amount, phone, bank_name,
status, type, comment, json, sent_to_server, update_time, complete_time, timestamp,
(LENGTH(screenshot) > 0) as has_screenshot
FROM events
ORDER BY id DESC
LIMIT :limit OFFSET :offset
)");
query.bindValue(":limit", pageSize);
query.bindValue(":offset", page * pageSize);
if (!query.exec()) {
qWarning() << "Ошибка при получении getEvents:" << query.lastError().text();
return events;
}
while (query.next()) {
events.append(parseEvent(query));
}
return events;
}
int EventDAO::getTotalCount() {
QSqlQuery query(DatabaseManager::instance().database());
if (!query.exec("SELECT COUNT(*) FROM events")) {
qWarning() << "Ошибка при получении getTotalCount:" << query.lastError().text();
return 0;
}
if (query.next()) return query.value(0).toInt();
return 0;
}
bool EventDAO::hasPendingEvents() {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT 1 FROM events
WHERE status IN ('wait', 'iPprogress')
LIMIT 1
)");
if (!query.exec()) {
qCritical() << "Ошибка при hasPendingEvents:" << query.lastError().text();
return false;
}
return query.next();
}
QSet<QString> EventDAO::getDevicesWithPendingEvents() {
QSet<QString> devices;
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT DISTINCT device_id FROM events
WHERE status IN ('wait', 'iPprogress')
)");
if (!query.exec()) {
qCritical() << "Ошибка при getDevicesWithPendingEvents:" << query.lastError().text();
return devices;
}
while (query.next()) {
devices.insert(query.value(0).toString());
}
return devices;
}
bool EventDAO::existsActiveByExternalId(const QString &externalId) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT 1 FROM events
WHERE external_id = :external_id
AND status IN ('wait', 'iPprogress')
LIMIT 1
)");
query.bindValue(":external_id", externalId);
if (!query.exec()) {
qCritical() << "Ошибка при existsActiveByExternalId:" << query.lastError().text();
return false;
}
return query.next();
}
bool EventDAO::cancelWaitingByType(const QString &deviceId, EventType type, const QString &bankName) {
QSqlQuery query(DatabaseManager::instance().database());
if (bankName.isEmpty()) {
query.prepare(R"(
UPDATE events SET status = :cancelled, comment = 'Cancelled: replaced by new task'
WHERE device_id = :device_id AND type = :type AND status = :wait
)");
} else {
query.prepare(R"(
UPDATE events SET status = :cancelled, comment = 'Cancelled: replaced by new task'
WHERE device_id = :device_id AND type = :type AND status = :wait AND bank_name = :bank_name
)");
query.bindValue(":bank_name", bankName);
}
query.bindValue(":cancelled", eventStatusToString(EventStatus::Error));
query.bindValue(":device_id", deviceId);
query.bindValue(":type", eventTypeToString(type));
query.bindValue(":wait", eventStatusToString(EventStatus::Wait));
if (!query.exec()) {
qWarning() << "Ошибка при cancelWaitingByType:" << query.lastError().text();
return false;
}
return true;
}
QList<EventInfo> EventDAO::cancelWaitingByBank(const QString &deviceId, const QString &bankName) {
// Сначала получаем задачи которые будем отменять (для отправки на сервер)
QList<EventInfo> cancelled;
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, account_id, device_id, external_id, amount, phone, bank_name,
status, type, comment, json, sent_to_server, update_time, complete_time, timestamp
FROM events
WHERE device_id = :device_id AND bank_name = :bank_name AND status = :wait
)");
query.bindValue(":device_id", deviceId);
query.bindValue(":bank_name", bankName);
query.bindValue(":wait", eventStatusToString(EventStatus::Wait));
if (query.exec()) {
while (query.next()) {
cancelled.append(parseEvent(query));
}
}
// Отменяем
query.prepare(R"(
UPDATE events SET status = :error, comment = 'Bank profile disabled'
WHERE device_id = :device_id AND bank_name = :bank_name AND status = :wait
)");
query.bindValue(":error", eventStatusToString(EventStatus::Error));
query.bindValue(":device_id", deviceId);
query.bindValue(":bank_name", bankName);
query.bindValue(":wait", eventStatusToString(EventStatus::Wait));
if (!query.exec()) {
qWarning() << "Ошибка при cancelWaitingByBank:" << query.lastError().text();
}
return cancelled;
}
bool EventDAO::updateScreenshot(int id, const QByteArray &screenshot) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare("UPDATE events SET screenshot = :screenshot WHERE id = :id");
query.bindValue(":screenshot", screenshot.isEmpty()
? QVariant(QMetaType(QMetaType::QByteArray))
: QVariant(screenshot));
query.bindValue(":id", id);
if (!query.exec()) {
qWarning() << "Ошибка при updateScreenshot:" << query.lastError().text();
return false;
}
return true;
}
QByteArray EventDAO::getScreenshot(int id) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare("SELECT screenshot FROM events WHERE id = :id");
query.bindValue(":id", id);
if (!query.exec() || !query.next()) return {};
return query.value(0).toByteArray();
}
QList<EventInfo> EventDAO::getRecentEvents(int hours) {
QList<EventInfo> events;
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, account_id, device_id, external_id, amount, phone, bank_name,
status, type, comment, json, sent_to_server, update_time, complete_time, timestamp
FROM events
WHERE timestamp >= datetime('now', :hours)
ORDER BY id DESC
)");
query.bindValue(":hours", QString("-%1 hours").arg(hours));
if (!query.exec()) {
qWarning() << "Ошибка при getRecentEvents:" << query.lastError().text();
return events;
}
while (query.next()) {
events.append(parseEvent(query));
}
return events;
}