1
0
forked from BRT/arc
arc/views/bank/AccountSettingsWindow.cpp
2026-04-08 15:43:59 +07:00

628 lines
30 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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/LoginAndCheckAccountsScript.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;'>&#9679; Не синхронизирован</span>"
: " <span style='color:green;'>&#9679; Синхронизирован</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);
// При включении профиля — включаем на сервере все локально активные материалы
if (!isActive) {
const QList<MaterialInfo> materials = MaterialDAO::getAccounts(m_deviceId, m_app.code);
for (const auto &mat : materials) {
if (mat.status == MaterialStatus::Active && !mat.materialId.isEmpty()) {
auto *thread = new QThread;
auto *net = new NetworkService;
net->moveToThread(thread);
net->addExtra("material_id", mat.materialId);
net->addExtra("enable", true);
connect(thread, &QThread::started, net, &NetworkService::toggleMaterial);
connect(net, &NetworkService::finished, thread, &QThread::quit);
connect(net, &NetworkService::finished, net, &QObject::deleteLater);
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
thread->start();
qDebug() << "[AccountSettings] Enabling material on server:" << mat.materialId;
}
}
}
}
// ── 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;
}
showOverlay("Проверка пин-кода...");
pauseActiveProfiles();
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) {
QMetaObject::invokeMethod(this, [this, appId, result]() {
resumePausedProfiles();
if (result.isEmpty()) {
BankProfileDAO::updatePinCodeStatus(appId, "yes", "");
m_app.pinCodeChecked = true;
updateStatusUI();
hideOverlay(true, "Пин-код проверен");
} else {
hideOverlay(false, "Ошибка: " + result);
}
}, 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 if (appCode == "dushanbe_city_bank") {
auto *worker = new Dushanbe::LoginAndCheckAccountsScript(deviceId, appCode, nullptr, true);
worker->moveToThread(thread);
connect(thread, &QThread::started, worker, &Dushanbe::LoginAndCheckAccountsScript::start);
connect(worker, &Dushanbe::LoginAndCheckAccountsScript::finishedWithResult, this, onResult, Qt::QueuedConnection);
connect(worker, &Dushanbe::LoginAndCheckAccountsScript::finished, thread, &QThread::quit);
connect(worker, &Dushanbe::LoginAndCheckAccountsScript::finished, worker, &QObject::deleteLater);
connect(thread, &QThread::finished, thread, &QObject::deleteLater);
} else {
resumePausedProfiles();
hideOverlay(false, "Банк не поддерживается");
thread->deleteLater();
return;
}
thread->start();
}
// ── Get Profile ────────────────────────────────────────────────────────────
void AccountSettingsWindow::startGetProfileInfo() {
m_profileBtn->setEnabled(false);
m_cardsBtn->setEnabled(false);
showOverlay("Обновление профиля...");
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();
hideOverlay(true, "Профиль обновлён");
}, 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);
showOverlay("Проверка аккаунтов...");
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();
hideOverlay(true, "Аккаунты обновлены");
}, 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: red; 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();
}