1
0
forked from BRT/arc
arc/database/dao/MaterialDAO.cpp
trnsmkot 38f33797c5 - Add toggleMaterial logic to NetworkService for enabling/disabling materials via PATCH request.
- Implement `toggleMaterialStatus` in `AccountSettingsWindow` for UI control and threading integration.
- Enhance `MaterialDAO` with numeric validation for `lastNumbers` field to ensure data integrity.
- Update `PayByCardScript` and `PayByPhoneScript` to handle PIN entry if required after payment confirmation.
- Introduce dynamic UI adjustments for material toggling, including a new toggle button and layout refinements.
- Add documentation for task logic in `ozon_tasks.md` and `black_tasks.md`.
- Switch default currency in `GetCardInfoScript` (Black app) from USD to ARS.
2026-03-31 11:40:34 +07:00

292 lines
9.7 KiB
C++

#include <QSqlQuery>
#include <QSqlError>
#include <QRegularExpression>
#include "MaterialDAO.h"
#include "db/MaterialInfo.h"
#include "DatabaseManager.h"
#include "time/DateUtils.h"
bool MaterialDAO::upsertAccount(const MaterialInfo &info) {
// Валидация: lastNumbers должен содержать только цифры
static const QRegularExpression digitsOnly(R"(^\d+$)");
if (!info.lastNumbers.isEmpty() && !digitsOnly.match(info.lastNumbers).hasMatch()) {
qWarning() << "[MaterialDAO] upsertAccount rejected: lastNumbers is not numeric:"
<< info.lastNumbers << "appCode:" << info.appCode;
return false;
}
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
INSERT INTO materials (device_id, app_code, last_numbers, card_number, amount, update_time, status, description, currency)
VALUES (:device_id, :app_code, :last_numbers, :card_number, :amount, :update_time, :status, :description, :currency)
ON CONFLICT(device_id, app_code, last_numbers)
DO UPDATE SET
amount = excluded.amount,
update_time = excluded.update_time,
last_numbers = excluded.last_numbers,
card_number = excluded.card_number,
status = excluded.status,
description = excluded.description,
currency = excluded.currency
)");
query.bindValue(":device_id", info.deviceId);
query.bindValue(":app_code", info.appCode);
query.bindValue(":last_numbers", info.lastNumbers);
query.bindValue(":card_number", info.cardNumber);
query.bindValue(":currency", info.currency);
query.bindValue(":description", info.description);
query.bindValue(":amount", info.amount);
query.bindValue(":update_time", DateUtils::toUtcString(info.updateTime));
query.bindValue(":status", materialStatusToString(info.status));
if (!query.exec()) {
qWarning() << "Ошибка при вставке/обновлении account:" << query.lastError().text();
return false;
}
return true;
}
bool MaterialDAO::updateAccountById(
const int id,
const QString &status,
const QString &description,
const QString &currency
) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
UPDATE materials
SET status = :status,
description = :description,
last_numbers = :last_numbers,
currency = :currency
WHERE id = :id
)");
query.bindValue(":status", status);
query.bindValue(":description", description);
query.bindValue(":last_numbers", description.length() >= 4 ? description.right(4) : description);
query.bindValue(":currency", currency);
query.bindValue(":id", id);
if (!query.exec()) {
qWarning() << "Ошибка при обновлении account по id:" << query.lastError().text();
return false;
}
return true;
}
bool MaterialDAO::deleteAccount(const int id) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare("DELETE FROM materials WHERE id = :id");
query.bindValue(":id", id);
return query.exec();
}
bool MaterialDAO::updateCardNumber(const int accountId, const QString &cardNumber) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
UPDATE materials SET card_number = :card_number WHERE id = :id
)");
query.bindValue(":card_number", cardNumber);
query.bindValue(":id", accountId);
if (!query.exec()) {
qWarning() << "Ошибка при обновлении card_number:" << query.lastError().text();
return false;
}
return true;
}
bool MaterialDAO::updateMaterialId(const int accountId, const QString &materialId) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare("UPDATE materials SET material_id = :material_id WHERE id = :id");
query.bindValue(":material_id", materialId);
query.bindValue(":id", accountId);
if (!query.exec()) {
qWarning() << "Ошибка при обновлении material_id:" << query.lastError().text();
return false;
}
return true;
}
MaterialInfo parseAccount(const QSqlQuery &query) {
MaterialInfo acc;
acc.id = query.value("id").toInt();
acc.deviceId = query.value("device_id").toString();
acc.appCode = query.value("app_code").toString();
acc.lastNumbers = query.value("last_numbers").toString();
acc.cardNumber = query.value("card_number").toString();
acc.materialId = query.value("material_id").toString();
acc.amount = query.value("amount").toDouble();
acc.updateTime = DateUtils::fromUtcString(query.value("update_time").toString());
acc.status = materialStatusFromString(query.value("status").toString());
acc.description = query.value("description").toString();
acc.currency = query.value("currency").toString();
return acc;
}
QList<MaterialInfo> MaterialDAO::getAccounts(const QString &deviceId, const QString &appName) {
QList<MaterialInfo> accounts;
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, device_id, app_code, last_numbers, card_number, material_id, amount, update_time, status, description, currency
FROM materials
WHERE device_id = :device_id AND app_code = :app_code
)");
query.bindValue(":device_id", deviceId);
query.bindValue(":app_code", appName);
if (!query.exec()) {
qWarning() << "Ошибка при получении materials:" << query.lastError().text();
return accounts;
}
while (query.next()) {
accounts.append(parseAccount(query));
}
return accounts;
}
MaterialInfo MaterialDAO::getAccountById(const int accountId) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, device_id, app_code, last_numbers, card_number, material_id, amount, update_time, status, description, currency
FROM materials
WHERE id = :id
LIMIT 1
)");
query.bindValue(":id", accountId);
if (!query.exec()) {
qWarning() << "Ошибка при получении account по ID:" << query.lastError().text();
return {};
}
if (query.next()) {
return parseAccount(query);
}
return {};
}
QList<MaterialInfo> MaterialDAO::getAccountsByAppCode(const QString &appCode) {
QList<MaterialInfo> accounts;
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, device_id, app_code, last_numbers, card_number, material_id, amount, update_time, status, description, currency
FROM materials
WHERE app_code = :app_code
)");
query.bindValue(":app_code", appCode);
if (!query.exec()) {
qWarning() << "Ошибка при получении materials по app_code:" << query.lastError().text();
return accounts;
}
while (query.next()) {
accounts.append(parseAccount(query));
}
return accounts;
}
MaterialInfo MaterialDAO::findAppAccount(const QString &deviceId, const QString &appName, const QString &lastNumber) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, device_id, app_code, last_numbers, card_number, material_id, amount, update_time, status, description, currency
FROM materials
WHERE app_code = :appName AND last_numbers = :lastNumber AND device_id = :deviceId
LIMIT 1
)");
query.bindValue(":deviceId", deviceId);
query.bindValue(":appName", appName);
query.bindValue(":lastNumber", lastNumber);
if (!query.exec()) {
qWarning() << "Ошибка при получении account по ID:" << query.lastError().text();
return {};
}
if (query.next()) {
return parseAccount(query);
}
return {};
}
QStringList MaterialDAO::getActiveMaterialIds() {
QStringList ids;
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT a.material_id
FROM materials a
JOIN bank_profiles app ON a.device_id = app.device_id AND a.app_code = app.code
JOIN devices d ON a.device_id = d.id
WHERE app.status = 'active'
AND a.material_id IS NOT NULL AND a.material_id != ''
AND d.status = 'device' AND d.image IS NOT NULL
)");
if (!query.exec()) {
qWarning() << "Ошибка при получении active material_ids:" << query.lastError().text();
return ids;
}
while (query.next()) {
ids << query.value(0).toString();
}
return ids;
}
QStringList MaterialDAO::getActiveMaterialIdsExcludingDevices(const QSet<QString> &excludeDevices) {
const QStringList all = getActiveMaterialIds();
if (excludeDevices.isEmpty()) return all;
QStringList filtered;
for (const QString &mid : all) {
const MaterialInfo acc = findByMaterialId(mid);
if (!excludeDevices.contains(acc.deviceId)) {
filtered << mid;
}
}
return filtered;
}
MaterialInfo MaterialDAO::findByMaterialId(const QString &materialId) {
QSqlQuery query(DatabaseManager::instance().database());
query.prepare(R"(
SELECT id, device_id, app_code, last_numbers, card_number, material_id, amount, update_time, status, description, currency
FROM materials
WHERE material_id = :material_id
LIMIT 1
)");
query.bindValue(":material_id", materialId);
if (!query.exec()) {
qWarning() << "Ошибка при поиске account по material_id:" << query.lastError().text();
return {};
}
if (query.next()) {
return parseAccount(query);
}
return {};
}