584 lines
27 KiB
C++
584 lines
27 KiB
C++
#include "AccountSettingsWindow.h"
|
||
|
||
#include <QVBoxLayout>
|
||
#include <QHBoxLayout>
|
||
#include <QHeaderView>
|
||
#include <QScrollArea>
|
||
#include <QCoreApplication>
|
||
#include <QMessageBox>
|
||
#include <QInputDialog>
|
||
#include <QThread>
|
||
#include <QTimer>
|
||
|
||
#include "ozon/LoginAndCheckAccountsScript.h"
|
||
#include "ozon/GetProfileInfoScript.h"
|
||
#include "ozon/GetCardInfoScript.h"
|
||
#include "black/LoginAndCheckAccountsScript.h"
|
||
#include "black/GetProfileInfoScript.h"
|
||
#include "black/GetCardInfoScript.h"
|
||
#include "dushanbe/GetProfileInfoScript.h"
|
||
#include "dushanbe/GetCardInfoScript.h"
|
||
#include "dao/BankProfileDAO.h"
|
||
#include "dao/MaterialDAO.h"
|
||
#include "net/NetworkService.h"
|
||
|
||
AccountSettingsWindow::AccountSettingsWindow(
|
||
QWidget *parent, QString deviceId, QString deviceName, const BankProfileInfo &app
|
||
) : QWidget(parent,
|
||
Qt::Window
|
||
| Qt::WindowTitleHint
|
||
| Qt::WindowSystemMenuHint
|
||
| Qt::WindowCloseButtonHint
|
||
| Qt::WindowMinMaxButtonsHint),
|
||
m_deviceId(std::move(deviceId)),
|
||
m_deviceName(std::move(deviceName)),
|
||
m_app(app) {
|
||
setWindowTitle("Настройки банка [" + m_app.name + "]");
|
||
setMinimumSize(700, 400);
|
||
resize(750, 500);
|
||
|
||
auto *mainLayout = new QVBoxLayout(this);
|
||
|
||
auto *scrollArea = new QScrollArea(this);
|
||
scrollArea->setWidgetResizable(true);
|
||
auto *content = new QWidget;
|
||
auto *layout = new QVBoxLayout(content);
|
||
layout->setContentsMargins(8, 8, 8, 8);
|
||
layout->setAlignment(Qt::AlignTop);
|
||
|
||
// ── Статус профиля ─────────────────────────────────────────────────
|
||
auto *statusRow = new QHBoxLayout;
|
||
statusRow->addWidget(new QLabel("Статус профиля:"));
|
||
m_statusLabel = new QLabel;
|
||
m_statusLabel->setTextFormat(Qt::RichText);
|
||
statusRow->addWidget(m_statusLabel);
|
||
statusRow->addStretch();
|
||
|
||
m_toggleBtn = new QPushButton;
|
||
m_toggleBtn->setFixedWidth(120);
|
||
connect(m_toggleBtn, &QPushButton::clicked, this, &AccountSettingsWindow::toggleProfileStatus);
|
||
statusRow->addWidget(m_toggleBtn);
|
||
layout->addLayout(statusRow);
|
||
|
||
// ── Пин-код ────────────────────────────────────────────────────────
|
||
auto *pinRow = new QHBoxLayout;
|
||
pinRow->addWidget(new QLabel("Пин-код:"));
|
||
m_pinLabel = new QLabel;
|
||
m_pinLabel->setTextFormat(Qt::RichText);
|
||
pinRow->addWidget(m_pinLabel);
|
||
pinRow->addStretch();
|
||
|
||
auto *editPinBtn = new QPushButton("Редактировать");
|
||
editPinBtn->setStyleSheet("background-color: green; color: white; padding: 4px 12px;");
|
||
connect(editPinBtn, &QPushButton::clicked, this, &AccountSettingsWindow::editPinCode);
|
||
pinRow->addWidget(editPinBtn);
|
||
|
||
auto *checkPinBtn = new QPushButton("Проверить пин-код");
|
||
checkPinBtn->setStyleSheet("background-color: orange; color: white; padding: 4px 12px;");
|
||
connect(checkPinBtn, &QPushButton::clicked, this, &AccountSettingsWindow::startCheckPinCode);
|
||
pinRow->addWidget(checkPinBtn);
|
||
layout->addLayout(pinRow);
|
||
|
||
// ── Профиль ────────────────────────────────────────────────────────
|
||
m_profileLabel = new QLabel;
|
||
m_profileLabel->setTextFormat(Qt::RichText);
|
||
m_profileLabel->setStyleSheet("margin: 4px 0;");
|
||
layout->addWidget(m_profileLabel);
|
||
|
||
// ── Кнопки обновления ──────────────────────────────────────────────
|
||
auto *actionsRow = new QHBoxLayout;
|
||
|
||
m_profileBtn = new QPushButton("Обновить профиль");
|
||
m_profileBtn->setStyleSheet("background-color: #1565C0; color: white; padding: 4px 12px;");
|
||
connect(m_profileBtn, &QPushButton::clicked, this, &AccountSettingsWindow::startGetProfileInfo);
|
||
actionsRow->addWidget(m_profileBtn);
|
||
|
||
m_cardsBtn = new QPushButton("Проверить аккаунты");
|
||
m_cardsBtn->setStyleSheet("background-color: #1565C0; color: white; padding: 4px 12px;");
|
||
connect(m_cardsBtn, &QPushButton::clicked, this, &AccountSettingsWindow::startGetCardInfo);
|
||
actionsRow->addWidget(m_cardsBtn);
|
||
|
||
actionsRow->addStretch();
|
||
layout->addLayout(actionsRow);
|
||
|
||
// ── Таблица карт ───────────────────────────────────────────────────
|
||
layout->addSpacing(8);
|
||
layout->addWidget(new QLabel("<b>Счета</b>"));
|
||
|
||
m_cardsTable = new QTableWidget;
|
||
m_cardsTable->setSelectionMode(QAbstractItemView::NoSelection);
|
||
m_cardsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||
m_cardsTable->setFocusPolicy(Qt::NoFocus);
|
||
layout->addWidget(m_cardsTable);
|
||
|
||
content->setLayout(layout);
|
||
scrollArea->setWidget(content);
|
||
mainLayout->addWidget(scrollArea);
|
||
|
||
// Overlay (скрыт по умолчанию)
|
||
m_overlay = new QWidget(this);
|
||
m_overlay->setStyleSheet("background-color: rgba(0, 0, 0, 150);");
|
||
m_overlay->hide();
|
||
|
||
m_overlayText = new QLabel(m_overlay);
|
||
m_overlayText->setAlignment(Qt::AlignCenter);
|
||
m_overlayText->setStyleSheet("color: white; font-size: 16px; font-weight: bold;");
|
||
auto *overlayLayout = new QVBoxLayout(m_overlay);
|
||
overlayLayout->addWidget(m_overlayText);
|
||
|
||
m_overlayTimer = new QTimer(this);
|
||
m_overlayTimer->setSingleShot(true);
|
||
|
||
updateStatusUI();
|
||
reloadCards();
|
||
}
|
||
|
||
// ── Overlay ────────────────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::resizeEvent(QResizeEvent *event) {
|
||
QWidget::resizeEvent(event);
|
||
if (m_overlay) m_overlay->setGeometry(rect());
|
||
}
|
||
|
||
void AccountSettingsWindow::showOverlay(const QString &text) {
|
||
m_overlayText->setText(text);
|
||
m_overlay->setGeometry(rect());
|
||
m_overlay->raise();
|
||
m_overlay->show();
|
||
}
|
||
|
||
void AccountSettingsWindow::hideOverlay(bool success, const QString &message, std::function<void()> onHidden) {
|
||
m_overlayText->setText(message);
|
||
m_overlayText->setStyleSheet(success
|
||
? "color: #4CAF50; font-size: 16px; font-weight: bold;"
|
||
: "color: #F44336; font-size: 16px; font-weight: bold;");
|
||
m_overlayTimer->disconnect();
|
||
connect(m_overlayTimer, &QTimer::timeout, this, [this, onHidden]() {
|
||
m_overlay->hide();
|
||
m_overlayText->setStyleSheet("color: white; font-size: 16px; font-weight: bold;");
|
||
if (onHidden) onHidden();
|
||
});
|
||
m_overlayTimer->start(1500);
|
||
}
|
||
|
||
// ── UI update ──────────────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::updateStatusUI() {
|
||
// Статус профиля
|
||
const bool active = m_app.status == "active";
|
||
m_statusLabel->setText(active
|
||
? "<span style='color:green;'>Активен</span>"
|
||
: "<span style='color:red;'>Неактивен</span>");
|
||
m_toggleBtn->setText(active ? "Выключить" : "Включить");
|
||
m_toggleBtn->setStyleSheet(active
|
||
? "background-color: red; color: white; padding: 4px 12px;"
|
||
: "background-color: green; color: white; padding: 4px 12px;");
|
||
|
||
// Пин-код
|
||
const QString pinDisplay = m_app.pinCode.isEmpty() ? "не задан" : m_app.pinCode;
|
||
const QString pinStatus = m_app.pinCodeChecked
|
||
? "<span style='color:green;'>" + pinDisplay + " (проверен)</span>"
|
||
: "<span style='color:red;'>" + pinDisplay + " (не проверен)</span>";
|
||
m_pinLabel->setText(pinStatus);
|
||
|
||
// Профиль
|
||
if (m_app.fullName.isEmpty() && m_app.phone.isEmpty()) {
|
||
m_profileLabel->setText("<span style='color:gray;'>Данные профиля не получены</span>");
|
||
} else {
|
||
QString text;
|
||
if (!m_app.fullName.isEmpty()) text += m_app.fullName;
|
||
if (!m_app.phone.isEmpty()) text += " | " + m_app.phone;
|
||
if (!m_app.email.isEmpty()) text += " | " + m_app.email;
|
||
|
||
const QString syncText = m_app.bankProfileId.isEmpty()
|
||
? " <span style='color:red;'>● Не синхронизирован</span>"
|
||
: " <span style='color:green;'>● Синхронизирован</span>";
|
||
m_profileLabel->setText(text + syncText);
|
||
}
|
||
}
|
||
|
||
// ── Toggle On/Off ──────────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::toggleProfileStatus() {
|
||
const bool isActive = m_app.status == "active";
|
||
const QString newStatus = isActive ? "off" : "active";
|
||
|
||
// Если включаем — проверяем что есть хотя бы одна активная карта
|
||
if (!isActive) {
|
||
const QList<MaterialInfo> materials = MaterialDAO::getAccounts(m_deviceId, m_app.code);
|
||
bool hasActive = false;
|
||
for (const auto &m : materials) {
|
||
if (m.status == MaterialStatus::Active) { hasActive = true; break; }
|
||
}
|
||
if (!hasActive) {
|
||
QMessageBox::warning(this, "Невозможно включить",
|
||
"Ни одна карта не активна.\nВключите хотя бы одну карту перед включением профиля.");
|
||
return;
|
||
}
|
||
}
|
||
|
||
if (!BankProfileDAO::update(m_app.id, m_app.pinCode, m_app.comment, newStatus))
|
||
return;
|
||
|
||
m_app.status = newStatus;
|
||
showOverlay(isActive ? "Выключение профиля..." : "Включение профиля...");
|
||
sendAppStatus(newStatus);
|
||
}
|
||
|
||
// ── Edit PIN ───────────────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::editPinCode() {
|
||
bool ok;
|
||
const QString pin = QInputDialog::getText(this, "Пин-код",
|
||
"Введите пин-код:", QLineEdit::Normal, m_app.pinCode, &ok);
|
||
if (!ok) return;
|
||
|
||
if (BankProfileDAO::update(m_app.id, pin, m_app.comment, m_app.status)) {
|
||
m_app.pinCode = pin;
|
||
m_app.pinCodeChecked = false;
|
||
BankProfileDAO::updatePinCodeStatus(m_app.id, "no", "");
|
||
updateStatusUI();
|
||
}
|
||
}
|
||
|
||
// ── Check PIN ──────────────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::startCheckPinCode() {
|
||
if (m_app.pinCode.isEmpty()) {
|
||
QMessageBox::warning(this, "Пин-код не задан",
|
||
"Сначала укажите пин-код через кнопку \"Редактировать\".");
|
||
return;
|
||
}
|
||
|
||
auto *thread = new QThread(nullptr);
|
||
const QString deviceId = m_deviceId;
|
||
const QString appCode = m_app.code;
|
||
const int appId = m_app.id;
|
||
|
||
auto onResult = [this, appId](const QString &result) {
|
||
if (result.isEmpty()) {
|
||
BankProfileDAO::updatePinCodeStatus(appId, "yes", "");
|
||
m_app.pinCodeChecked = true;
|
||
QMetaObject::invokeMethod(this, [this]() { updateStatusUI(); }, Qt::QueuedConnection);
|
||
}
|
||
};
|
||
|
||
if (appCode == "ozon") {
|
||
auto *worker = new Ozon::LoginAndCheckAccountsScript(deviceId, appCode, nullptr, false, true);
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &Ozon::LoginAndCheckAccountsScript::start);
|
||
connect(worker, &Ozon::LoginAndCheckAccountsScript::finishedWithResult, this, onResult, Qt::QueuedConnection);
|
||
connect(worker, &Ozon::LoginAndCheckAccountsScript::finished, thread, &QThread::quit);
|
||
connect(worker, &Ozon::LoginAndCheckAccountsScript::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
} else if (appCode == "black") {
|
||
auto *worker = new Black::LoginAndCheckAccountsScript(deviceId, appCode, nullptr, true);
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &Black::LoginAndCheckAccountsScript::start);
|
||
connect(worker, &Black::LoginAndCheckAccountsScript::finishedWithResult, this, onResult, Qt::QueuedConnection);
|
||
connect(worker, &Black::LoginAndCheckAccountsScript::finished, thread, &QThread::quit);
|
||
connect(worker, &Black::LoginAndCheckAccountsScript::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
} else {
|
||
thread->deleteLater();
|
||
return;
|
||
}
|
||
|
||
thread->start();
|
||
}
|
||
|
||
// ── Get Profile ────────────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::startGetProfileInfo() {
|
||
m_profileBtn->setEnabled(false);
|
||
m_cardsBtn->setEnabled(false);
|
||
pauseActiveProfiles();
|
||
|
||
auto *thread = new QThread(nullptr);
|
||
const QString deviceId = m_deviceId;
|
||
const QString appCode = m_app.code;
|
||
|
||
auto onDone = [this, appCode]() {
|
||
QMetaObject::invokeMethod(this, [this, appCode]() {
|
||
m_profileBtn->setEnabled(true);
|
||
m_cardsBtn->setEnabled(true);
|
||
resumePausedProfiles();
|
||
m_app = BankProfileDAO::getApplication(m_deviceId, appCode);
|
||
updateStatusUI();
|
||
}, Qt::QueuedConnection);
|
||
};
|
||
|
||
if (appCode == "ozon") {
|
||
auto *worker = new Ozon::GetProfileInfoScript(deviceId, appCode, nullptr);
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &Ozon::GetProfileInfoScript::start);
|
||
connect(worker, &Ozon::GetProfileInfoScript::finished, this, onDone, Qt::QueuedConnection);
|
||
connect(worker, &Ozon::GetProfileInfoScript::finished, thread, &QThread::quit);
|
||
connect(worker, &Ozon::GetProfileInfoScript::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
} else if (appCode == "black") {
|
||
auto *worker = new Black::GetProfileInfoScript(deviceId, appCode, nullptr);
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &Black::GetProfileInfoScript::start);
|
||
connect(worker, &Black::GetProfileInfoScript::finished, this, onDone, Qt::QueuedConnection);
|
||
connect(worker, &Black::GetProfileInfoScript::finished, thread, &QThread::quit);
|
||
connect(worker, &Black::GetProfileInfoScript::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
} else if (appCode == "dushanbe_city_bank") {
|
||
auto *worker = new Dushanbe::GetProfileInfoScript(deviceId, appCode, nullptr);
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &Dushanbe::GetProfileInfoScript::start);
|
||
connect(worker, &Dushanbe::GetProfileInfoScript::finished, this, onDone, Qt::QueuedConnection);
|
||
connect(worker, &Dushanbe::GetProfileInfoScript::finished, thread, &QThread::quit);
|
||
connect(worker, &Dushanbe::GetProfileInfoScript::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
} else {
|
||
thread->deleteLater();
|
||
return;
|
||
}
|
||
|
||
thread->start();
|
||
}
|
||
|
||
// ── Get Cards ──────────────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::startGetCardInfo() {
|
||
m_profileBtn->setEnabled(false);
|
||
m_cardsBtn->setEnabled(false);
|
||
pauseActiveProfiles();
|
||
|
||
auto *thread = new QThread(nullptr);
|
||
const QString deviceId = m_deviceId;
|
||
const QString appCode = m_app.code;
|
||
|
||
auto onDone = [this]() {
|
||
QMetaObject::invokeMethod(this, [this]() {
|
||
m_profileBtn->setEnabled(true);
|
||
m_cardsBtn->setEnabled(true);
|
||
resumePausedProfiles();
|
||
reloadCards();
|
||
}, Qt::QueuedConnection);
|
||
};
|
||
|
||
if (appCode == "ozon") {
|
||
auto *worker = new Ozon::GetCardInfoScript(deviceId, appCode, "", nullptr);
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &Ozon::GetCardInfoScript::start);
|
||
connect(worker, &Ozon::GetCardInfoScript::finished, this, onDone, Qt::QueuedConnection);
|
||
connect(worker, &Ozon::GetCardInfoScript::finished, thread, &QThread::quit);
|
||
connect(worker, &Ozon::GetCardInfoScript::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
} else if (appCode == "black") {
|
||
auto *worker = new Black::GetCardInfoScript(deviceId, appCode, nullptr);
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &Black::GetCardInfoScript::start);
|
||
connect(worker, &Black::GetCardInfoScript::finished, this, onDone, Qt::QueuedConnection);
|
||
connect(worker, &Black::GetCardInfoScript::finished, thread, &QThread::quit);
|
||
connect(worker, &Black::GetCardInfoScript::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
} else if (appCode == "dushanbe_city_bank") {
|
||
auto *worker = new Dushanbe::GetCardInfoScript(deviceId, appCode, nullptr);
|
||
worker->moveToThread(thread);
|
||
connect(thread, &QThread::started, worker, &Dushanbe::GetCardInfoScript::start);
|
||
connect(worker, &Dushanbe::GetCardInfoScript::finished, this, onDone, Qt::QueuedConnection);
|
||
connect(worker, &Dushanbe::GetCardInfoScript::finished, thread, &QThread::quit);
|
||
connect(worker, &Dushanbe::GetCardInfoScript::finished, worker, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
|
||
} else {
|
||
thread->deleteLater();
|
||
return;
|
||
}
|
||
|
||
thread->start();
|
||
}
|
||
|
||
// ── Send status to server ──────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::sendAppStatus(const QString &status) {
|
||
if (m_app.bankProfileId.isEmpty()) {
|
||
qWarning() << "[AccountSettings] sendAppStatus: no bankProfileId for" << m_app.code;
|
||
hideOverlay(true, "Сохранено локально", [this]() { updateStatusUI(); });
|
||
return;
|
||
}
|
||
|
||
const bool enable = (status == "active");
|
||
auto *thread = new QThread;
|
||
auto *net = new NetworkService;
|
||
net->moveToThread(thread);
|
||
net->addExtra("bank_profile_id", m_app.bankProfileId);
|
||
net->addExtra("enable", enable);
|
||
connect(thread, &QThread::started, net, &NetworkService::toggleBankProfile);
|
||
connect(net, &NetworkService::finishedWithResult, this, [this](int result) {
|
||
if (result == 0) {
|
||
hideOverlay(true, "Успешно", [this]() { updateStatusUI(); });
|
||
} else {
|
||
hideOverlay(false, "Ошибка отправки на сервер", [this]() { updateStatusUI(); });
|
||
}
|
||
}, Qt::QueuedConnection);
|
||
connect(net, &NetworkService::finished, thread, &QThread::quit);
|
||
connect(net, &NetworkService::finished, net, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
}
|
||
|
||
// ── Toggle card status ─────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::toggleMaterialStatus(const MaterialInfo &account) {
|
||
const bool isActive = account.status == MaterialStatus::Active;
|
||
const QString newStatus = isActive ? "off" : "active";
|
||
|
||
if (!MaterialDAO::updateStatus(account.id, newStatus)) {
|
||
qWarning() << "[AccountSettings] Failed to update material status:" << account.id;
|
||
return;
|
||
}
|
||
|
||
showOverlay(isActive ? "Выключение карты..." : "Включение карты...");
|
||
|
||
auto finishToggle = [this, isActive]() {
|
||
// Если выключили — проверяем остались ли активные
|
||
if (isActive) {
|
||
const QList<MaterialInfo> materials = MaterialDAO::getAccounts(m_deviceId, m_app.code);
|
||
bool hasActive = false;
|
||
for (const auto &m : materials) {
|
||
if (m.status == MaterialStatus::Active) { hasActive = true; break; }
|
||
}
|
||
if (!hasActive && m_app.status == "active") {
|
||
BankProfileDAO::update(m_app.id, m_app.pinCode, m_app.comment, "off");
|
||
m_app.status = "off";
|
||
sendAppStatus("off");
|
||
return; // sendAppStatus покажет свой overlay
|
||
}
|
||
}
|
||
reloadCards();
|
||
};
|
||
|
||
if (!account.materialId.isEmpty()) {
|
||
auto *thread = new QThread;
|
||
auto *net = new NetworkService;
|
||
net->moveToThread(thread);
|
||
net->addExtra("material_id", account.materialId);
|
||
net->addExtra("enable", !isActive);
|
||
connect(thread, &QThread::started, net, &NetworkService::toggleMaterial);
|
||
connect(net, &NetworkService::finishedWithResult, this, [this, finishToggle](int result) {
|
||
if (result == 0) {
|
||
hideOverlay(true, "Успешно", finishToggle);
|
||
} else {
|
||
hideOverlay(false, "Ошибка отправки на сервер", finishToggle);
|
||
}
|
||
}, Qt::QueuedConnection);
|
||
connect(net, &NetworkService::finished, thread, &QThread::quit);
|
||
connect(net, &NetworkService::finished, net, &QObject::deleteLater);
|
||
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
} else {
|
||
hideOverlay(true, "Сохранено локально", finishToggle);
|
||
}
|
||
}
|
||
|
||
// ── Cards table ────────────────────────────────────────────────────────────
|
||
|
||
void AccountSettingsWindow::reloadCards() {
|
||
const QList<MaterialInfo> accounts = MaterialDAO::getAccounts(m_deviceId, m_app.code);
|
||
|
||
m_cardsTable->clearContents();
|
||
m_cardsTable->setRowCount(accounts.size());
|
||
m_cardsTable->setColumnCount(7);
|
||
m_cardsTable->setHorizontalHeaderLabels({
|
||
"Сервер", "Статус", "Время обновления", "Номер", "Сумма", "Валюта", ""
|
||
});
|
||
m_cardsTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||
|
||
for (int k = 0; k < accounts.size(); ++k) {
|
||
const MaterialInfo &acc = accounts[k];
|
||
|
||
// Сервер
|
||
auto *syncItem = new QTableWidgetItem(acc.materialId.isEmpty() ? "Не синхр." : "Синхр.");
|
||
syncItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||
syncItem->setForeground(acc.materialId.isEmpty() ? QBrush(Qt::red) : QBrush(Qt::darkGreen));
|
||
m_cardsTable->setItem(k, 0, syncItem);
|
||
|
||
// Статус
|
||
const bool isActive = acc.status == MaterialStatus::Active;
|
||
auto *statusItem = new QTableWidgetItem(materialStatusToUiString(acc.status));
|
||
statusItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||
statusItem->setForeground(isActive ? QBrush(Qt::darkGreen) : QBrush(Qt::red));
|
||
m_cardsTable->setItem(k, 1, statusItem);
|
||
|
||
// Время обновления
|
||
auto *timeItem = new QTableWidgetItem(acc.updateTime.toString("dd.MM.yyyy HH:mm:ss"));
|
||
timeItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||
m_cardsTable->setItem(k, 2, timeItem);
|
||
|
||
// Номер
|
||
const QString displayNumber = acc.cardNumber.isEmpty() ? acc.lastNumbers : acc.cardNumber;
|
||
auto *numItem = new QTableWidgetItem(displayNumber);
|
||
numItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||
m_cardsTable->setItem(k, 3, numItem);
|
||
|
||
// Сумма
|
||
auto *amountItem = new QTableWidgetItem(QString::number(acc.amount));
|
||
amountItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||
m_cardsTable->setItem(k, 4, amountItem);
|
||
|
||
// Валюта
|
||
auto *currItem = new QTableWidgetItem(acc.currency);
|
||
currItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||
m_cardsTable->setItem(k, 5, currItem);
|
||
|
||
// Кнопка вкл/выкл
|
||
auto *toggleBtn = new QPushButton(isActive ? "Выключить" : "Включить", m_cardsTable);
|
||
toggleBtn->setStyleSheet(isActive
|
||
? "background-color: orange; color: white;"
|
||
: "background-color: green; color: white;");
|
||
m_cardsTable->setCellWidget(k, 6, toggleBtn);
|
||
|
||
connect(toggleBtn, &QPushButton::clicked, this, [this, acc]() {
|
||
toggleMaterialStatus(acc);
|
||
});
|
||
}
|
||
|
||
m_cardsTable->resizeColumnsToContents();
|
||
m_cardsTable->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch);
|
||
m_cardsTable->resizeRowsToContents();
|
||
}
|
||
|
||
// ── Pause/Resume active profiles ───────────────────────────────────────────
|
||
|
||
static void toggleProfileOnServer(const BankProfileInfo &app, bool enable) {
|
||
if (app.bankProfileId.isEmpty()) return;
|
||
auto *thread = new QThread;
|
||
auto *net = new NetworkService;
|
||
net->moveToThread(thread);
|
||
net->addExtra("bank_profile_id", app.bankProfileId);
|
||
net->addExtra("enable", enable);
|
||
QObject::connect(thread, &QThread::started, net, &NetworkService::toggleBankProfile);
|
||
QObject::connect(net, &NetworkService::finished, thread, &QThread::quit);
|
||
QObject::connect(net, &NetworkService::finished, net, &QObject::deleteLater);
|
||
QObject::connect(thread, &QThread::finished, thread, &QThread::deleteLater);
|
||
thread->start();
|
||
}
|
||
|
||
void AccountSettingsWindow::pauseActiveProfiles() {
|
||
const QList<BankProfileInfo> apps = BankProfileDAO::getApplicationsByDeviceId(m_deviceId);
|
||
for (const BankProfileInfo &app : apps) {
|
||
if (app.status == "active") {
|
||
m_pausedProfiles.append(app.code);
|
||
BankProfileDAO::update(app.id, app.pinCode, app.comment, "off");
|
||
toggleProfileOnServer(app, false);
|
||
qDebug() << "[AccountSettings] Paused profile:" << app.code;
|
||
}
|
||
}
|
||
}
|
||
|
||
void AccountSettingsWindow::resumePausedProfiles() {
|
||
for (const QString &code : m_pausedProfiles) {
|
||
const BankProfileInfo app = BankProfileDAO::getApplication(m_deviceId, code);
|
||
if (app.id >= 0 && app.status == "off") {
|
||
BankProfileDAO::update(app.id, app.pinCode, app.comment, "active");
|
||
toggleProfileOnServer(app, true);
|
||
qDebug() << "[AccountSettings] Resumed profile:" << app.code;
|
||
}
|
||
}
|
||
m_pausedProfiles.clear();
|
||
}
|