#include #include #include #include "DatabaseManager.h" #include "TransactionDAO.h" #include "time/DateUtils.h" bool TransactionDAO::insertTransactionIfNotExists(const TransactionInfo &info) { QSqlQuery query(DatabaseManager::instance().database()); if (info.amount < 0) { // Если исходящая, то мы знаем время timestamp query.prepare(R"( SELECT COUNT(*) FROM transactions WHERE account_id = :account_id AND amount = :amount AND timestamp = :timestamp AND type = :type )"); query.bindValue(":timestamp", DateUtils::toUtcString(info.timestamp)); } else { query.prepare(R"( SELECT COUNT(*) FROM transactions WHERE account_id = :account_id AND amount = :amount AND bank_time = :bank_time AND bank_name = :bank_name )"); query.bindValue(":bank_time", info.bankTime); query.bindValue(":bank_name", info.bankName); } query.bindValue(":account_id", info.accountId); query.bindValue(":amount", info.amount); query.bindValue(":type", transactionTypeToString(info.type)); if (!query.exec() || !query.next()) { qWarning() << "Ошибка при проверке существования transaction:" << query.lastError().text(); return false; } if (query.value(0).toInt() > 0) { return false; // Уже существует } query.prepare(R"( INSERT INTO transactions ( account_id, amount, fee, status, phone, type, description, updated_description, bank_name, bank_time, name, bank_tr_external_id, update_time, complete_time, timestamp ) VALUES ( :account_id, :amount, :fee, :status, :phone, :type, :description, :updated_description, :bank_name, :bank_time, :name, :bank_tr_external_id, :update_time, :complete_time, :timestamp ) )"); query.bindValue(":account_id", info.accountId); query.bindValue(":amount", info.amount); query.bindValue(":fee", info.fee); query.bindValue(":status", transactionStatusToString(info.status)); query.bindValue(":type", transactionTypeToString(info.type)); query.bindValue(":phone", info.phone); query.bindValue(":name", info.name); query.bindValue(":description", info.description); query.bindValue(":updated_description", info.updatedDescription); query.bindValue(":bank_name", info.bankName); query.bindValue(":bank_time", info.bankTime); query.bindValue(":bank_tr_external_id", info.bankTrExternalId); 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 true; } int TransactionDAO::insertTransaction(const TransactionInfo &info) { QSqlQuery query(DatabaseManager::instance().database()); query.prepare(R"( INSERT INTO transactions ( account_id, amount, fee, status, phone, type, description, updated_description, bank_name, bank_time, name, bank_tr_external_id, update_time, complete_time ) VALUES ( :account_id, :amount, :fee, :status, :phone, :type, :description, :updated_description, :bank_name, :bank_time, :name, :bank_tr_external_id, :update_time, :complete_time ) )"); query.bindValue(":account_id", info.accountId); query.bindValue(":amount", info.amount); query.bindValue(":fee", info.fee); query.bindValue(":status", transactionStatusToString(info.status)); query.bindValue(":type", transactionTypeToString(info.type)); query.bindValue(":phone", info.phone); query.bindValue(":name", info.name); query.bindValue(":description", info.description); query.bindValue(":updated_description", info.updatedDescription); query.bindValue(":bank_name", info.bankName); query.bindValue(":bank_time", info.bankTime); query.bindValue(":bank_tr_external_id", info.bankTrExternalId); 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 -1; } return query.lastInsertId().toInt(); } bool TransactionDAO::deleteTransaction(const int id) { QSqlQuery query(DatabaseManager::instance().database()); query.prepare("DELETE FROM transactions WHERE id = :id"); query.bindValue(":id", 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.bankName = query.value("bank_name").toString(); tx.bankTime = query.value("bank_time").toString(); tx.bankTrExternalId = query.value("bank_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()); tx.receiptImage = query.value("receipt_image").toByteArray(); return tx; } QList TransactionDAO::getTransactions(const int accountId) { QList list; QSqlQuery query(DatabaseManager::instance().database()); query.prepare(R"( SELECT * FROM transactions WHERE account_id = :account_id ORDER BY timestamp DESC )"); query.bindValue(":account_id", accountId); if (!query.exec()) { qWarning() << "Ошибка при получении transactions:" << query.lastError().text(); return list; } while (query.next()) { list.append(parseTransaction(query)); } return list; } bool TransactionDAO::updateTransaction(const TransactionInfo &info) { QSqlQuery query(DatabaseManager::instance().database()); qDebug().noquote().nospace() << convertTransactionToString(info); query.prepare(R"( UPDATE transactions SET amount = :amount, fee = :fee, status = :status, type = :type, phone = :phone, description = :description, updated_description = :updated_description, bank_name = :bank_name, bank_time = :bank_time, name = :name, bank_tr_external_id = :bank_tr_external_id, update_time = :update_time, complete_time = :complete_time, timestamp = :timestamp WHERE id = :id )"); query.bindValue(":id", info.id); query.bindValue(":amount", info.amount); query.bindValue(":fee", info.fee); query.bindValue(":status", transactionStatusToString(info.status)); query.bindValue(":type", transactionTypeToString(info.type)); query.bindValue(":phone", info.phone); query.bindValue(":name", info.name); query.bindValue(":description", info.description); query.bindValue(":updated_description", info.updatedDescription); query.bindValue(":bank_name", info.bankName); query.bindValue(":bank_time", info.bankTime); query.bindValue(":bank_tr_external_id", info.bankTrExternalId); 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(); return false; } return true; } bool TransactionDAO::updateTransactionStatus( const int id, const TransactionStatus status ) { QSqlQuery query(DatabaseManager::instance().database()); query.prepare(R"( UPDATE transactions SET status = :status, update_time = :update_time, complete_time = :complete_time WHERE id = :id )"); // const QString currentTime = now.toString("yyyy-MM-dd HH:mm:ss"); query.bindValue(":id", id); query.bindValue(":status", transactionStatusToString(status)); query.bindValue(":update_time", DateUtils::toUtcString(DateUtils::getUtcNow())); if (status == TransactionStatus::Complete) { query.bindValue(":complete_time", DateUtils::toUtcString(DateUtils::getUtcNow())); } else { query.bindValue(":complete_time", QVariant(QMetaType(QMetaType::QString))); } if (!query.exec()) { qWarning() << "Ошибка при обновлении transaction:" << query.lastError().text(); return false; } return true; } TransactionInfo TransactionDAO::getTransactionById(const int id) { QSqlQuery query(DatabaseManager::instance().database()); query.prepare("SELECT * FROM transactions WHERE id = :id"); query.bindValue(":id", id); if (!query.exec() || !query.next()) { qWarning() << "Ошибка или не найден transaction с id:" << id << query.lastError().text(); return {}; } return parseTransaction(query); } QList TransactionDAO::getTransactionsWithinHours(const int accountId, const int hours) { QList 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 {}; } while (query.next()) { list.append(parseTransaction(query)); } return list; } bool TransactionDAO::updateTransaction( const int id, const TransactionStatus status, const QString &oldDesc, const QString &newDesc ) { QSqlQuery query(DatabaseManager::instance().database()); query.prepare(R"( UPDATE transactions SET status = :status, update_time = :update_time, complete_time = :complete_time, description = :description, updated_description = :updated_description WHERE id = :id )"); query.bindValue(":id", id); query.bindValue(":status", transactionStatusToString(status)); query.bindValue(":update_time", DateUtils::toUtcString(DateUtils::getUtcNow())); if (oldDesc.isEmpty() || oldDesc != newDesc) { query.bindValue(":description", newDesc); query.bindValue(":updated_description", oldDesc); } else { query.bindValue(":description", newDesc); query.bindValue(":updated_description", ""); } if (status == TransactionStatus::Complete) { query.bindValue(":complete_time", DateUtils::toUtcString(DateUtils::getUtcNow())); } else { query.bindValue(":complete_time", QVariant(QMetaType(QMetaType::QString))); } if (!query.exec()) { qWarning() << "Ошибка при обновлении transaction:" << query.lastError().text(); return false; } return true; } bool TransactionDAO::updateExternalTransactionId(const int id, const int externalId) { QSqlQuery query(DatabaseManager::instance().database()); query.prepare(R"( UPDATE transactions SET external_id = :external_id WHERE id = :id )"); query.bindValue(":id", id); query.bindValue(":external_id", externalId); if (!query.exec()) { qWarning() << "Ошибка при обновлении external_id:" << query.lastError().text(); return false; } return true; } bool TransactionDAO::updateReceiptImage(const int id, const QByteArray &image) { QSqlQuery query(DatabaseManager::instance().database()); query.prepare("UPDATE transactions SET receipt_image = :image WHERE id = :id"); query.bindValue(":id", id); query.bindValue(":image", image); if (!query.exec()) { qWarning() << "Ошибка при сохранении receipt_image:" << query.lastError().text(); return false; } return true; } TransactionInfo TransactionDAO::findByBankTimeAndAmount( const int accountId, const QString &bankName, const QString &bankTime, const double amount ) { QSqlQuery query(DatabaseManager::instance().database()); query.prepare(R"( SELECT * FROM transactions WHERE account_id = :account_id AND bank_name = :bank_name AND bank_time = :bank_time AND amount = :amount LIMIT 1 )"); query.bindValue(":account_id", accountId); query.bindValue(":bank_name", bankName); query.bindValue(":bank_time", bankTime); query.bindValue(":amount", amount); if (!query.exec() || !query.next()) { return {}; } return parseTransaction(query); }