343 lines
12 KiB
C++
343 lines
12 KiB
C++
#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.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());
|
|
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
|
|
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) {
|
|
QSqlQuery query(DatabaseManager::instance().database());
|
|
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
|
|
)");
|
|
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();
|
|
}
|