Add PAN field detection and account number UI updates.
- Extend `ScreenXmlParser` with `findPanCardNumberInput` for detecting empty PAN fields in Ozon WebView. - Update `PayByCardScript` to handle missing hints for recipient card input. - Temporarily disable advanced account number parsing in `GetCardInfoScript`. - Add `patchMaterial` method to `NetworkService` for updating account details. - Update card management UI with refined "Switch" button logic and label changes.
This commit is contained in:
parent
52d261a060
commit
3751406c36
@ -162,76 +162,77 @@ void GetCardInfoScript::doStart() {
|
||||
}
|
||||
|
||||
// Достаём номер счёта: Настройки карты → Реквизиты карты → таб "Реквизиты счета".
|
||||
// ВРЕМЕННО ОТКЛЮЧЕНО
|
||||
QString accountNumber;
|
||||
const Node settingsBtn = xmlScreenParser.findCardSettingsButton();
|
||||
if (settingsBtn.x() > 0) {
|
||||
AdbUtils::makeTap(m_deviceId, settingsBtn.x(), settingsBtn.y());
|
||||
QThread::msleep(1500);
|
||||
|
||||
bool sheetFound = false;
|
||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
if (xmlScreenParser.isCardSettingsBottomSheet()) {
|
||||
sheetFound = true;
|
||||
break;
|
||||
}
|
||||
QThread::msleep(1000);
|
||||
}
|
||||
|
||||
if (sheetFound) {
|
||||
const Node requisitesItem = xmlScreenParser.findCardRequisitesMenuItem();
|
||||
if (requisitesItem.x() > 0) {
|
||||
AdbUtils::makeTap(m_deviceId, requisitesItem.x(), requisitesItem.y());
|
||||
QThread::msleep(1500);
|
||||
|
||||
bool reqScreenFound = false;
|
||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
if (xmlScreenParser.isCardRequisitesScreen()) {
|
||||
reqScreenFound = true;
|
||||
break;
|
||||
}
|
||||
QThread::msleep(1000);
|
||||
}
|
||||
|
||||
if (reqScreenFound) {
|
||||
const Node accountTab = xmlScreenParser.findAccountRequisitesTab();
|
||||
if (accountTab.x() > 0) {
|
||||
AdbUtils::makeTap(m_deviceId, accountTab.x(), accountTab.y());
|
||||
QThread::msleep(1500);
|
||||
|
||||
// Несколько попыток — данные могут подгружаться
|
||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
accountNumber = xmlScreenParser.parseAccountNumber();
|
||||
if (!accountNumber.isEmpty()) break;
|
||||
QThread::msleep(1000);
|
||||
}
|
||||
qDebug() << "[Dushanbe::GetCardInfo] accountNumber for card" << i
|
||||
<< ":" << accountNumber;
|
||||
} else {
|
||||
qWarning() << "[Dushanbe::GetCardInfo] Account tab not found for card" << i;
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[Dushanbe::GetCardInfo] Requisites screen not detected for card" << i;
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[Dushanbe::GetCardInfo] 'Реквизиты карты' menu item not found for card" << i;
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[Dushanbe::GetCardInfo] Card settings bottom sheet not detected for card" << i;
|
||||
}
|
||||
|
||||
// Возврат на экран детали карты — bottom sheet и/или экран Реквизитов
|
||||
for (int attempt = 0; attempt < 4; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
if (xmlScreenParser.isCardDetailScreen()) break;
|
||||
AdbUtils::goBack(m_deviceId);
|
||||
QThread::msleep(1200);
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[Dushanbe::GetCardInfo] 'Настройки карты' button not found for card" << i;
|
||||
}
|
||||
// const Node settingsBtn = xmlScreenParser.findCardSettingsButton();
|
||||
// if (settingsBtn.x() > 0) {
|
||||
// AdbUtils::makeTap(m_deviceId, settingsBtn.x(), settingsBtn.y());
|
||||
// QThread::msleep(1500);
|
||||
//
|
||||
// bool sheetFound = false;
|
||||
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// if (xmlScreenParser.isCardSettingsBottomSheet()) {
|
||||
// sheetFound = true;
|
||||
// break;
|
||||
// }
|
||||
// QThread::msleep(1000);
|
||||
// }
|
||||
//
|
||||
// if (sheetFound) {
|
||||
// const Node requisitesItem = xmlScreenParser.findCardRequisitesMenuItem();
|
||||
// if (requisitesItem.x() > 0) {
|
||||
// AdbUtils::makeTap(m_deviceId, requisitesItem.x(), requisitesItem.y());
|
||||
// QThread::msleep(1500);
|
||||
//
|
||||
// bool reqScreenFound = false;
|
||||
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// if (xmlScreenParser.isCardRequisitesScreen()) {
|
||||
// reqScreenFound = true;
|
||||
// break;
|
||||
// }
|
||||
// QThread::msleep(1000);
|
||||
// }
|
||||
//
|
||||
// if (reqScreenFound) {
|
||||
// const Node accountTab = xmlScreenParser.findAccountRequisitesTab();
|
||||
// if (accountTab.x() > 0) {
|
||||
// AdbUtils::makeTap(m_deviceId, accountTab.x(), accountTab.y());
|
||||
// QThread::msleep(1500);
|
||||
//
|
||||
// // Несколько попыток — данные могут подгружаться
|
||||
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// accountNumber = xmlScreenParser.parseAccountNumber();
|
||||
// if (!accountNumber.isEmpty()) break;
|
||||
// QThread::msleep(1000);
|
||||
// }
|
||||
// qDebug() << "[Dushanbe::GetCardInfo] accountNumber for card" << i
|
||||
// << ":" << accountNumber;
|
||||
// } else {
|
||||
// qWarning() << "[Dushanbe::GetCardInfo] Account tab not found for card" << i;
|
||||
// }
|
||||
// } else {
|
||||
// qWarning() << "[Dushanbe::GetCardInfo] Requisites screen not detected for card" << i;
|
||||
// }
|
||||
// } else {
|
||||
// qWarning() << "[Dushanbe::GetCardInfo] 'Реквизиты карты' menu item not found for card" << i;
|
||||
// }
|
||||
// } else {
|
||||
// qWarning() << "[Dushanbe::GetCardInfo] Card settings bottom sheet not detected for card" << i;
|
||||
// }
|
||||
//
|
||||
// // Возврат на экран детали карты — bottom sheet и/или экран Реквизитов
|
||||
// for (int attempt = 0; attempt < 4; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// if (xmlScreenParser.isCardDetailScreen()) break;
|
||||
// AdbUtils::goBack(m_deviceId);
|
||||
// QThread::msleep(1200);
|
||||
// }
|
||||
// } else {
|
||||
// qWarning() << "[Dushanbe::GetCardInfo] 'Настройки карты' button not found for card" << i;
|
||||
// }
|
||||
|
||||
MaterialInfo account;
|
||||
account.deviceId = device.id;
|
||||
|
||||
@ -415,103 +415,104 @@ void GetCardInfoScript::doStart() {
|
||||
}
|
||||
|
||||
// 2.5. Достаём номер счёта (общий для всех карт): Основной счёт → Посмотреть реквизиты
|
||||
QString accountNumber;
|
||||
{
|
||||
bool needFetch = false;
|
||||
for (const MaterialInfo &c : cards) {
|
||||
const MaterialInfo dbCard = MaterialDAO::findAppAccount(device.id, m_appCode, c.lastNumbers);
|
||||
if (dbCard.id != -1 && dbCard.accountNumber.isEmpty()) { needFetch = true; break; }
|
||||
}
|
||||
|
||||
if (needFetch) {
|
||||
// Возвращаемся на главный экран — критерий именно по наличию кнопки
|
||||
// "Основной счёт ... ₽". isHomeScreen() для Озона нестрогий
|
||||
// (Перевести/Пополнить присутствуют и на других экранах).
|
||||
Node mainAcc;
|
||||
for (int attempt = 0; attempt < 6; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
mainAcc = xmlScreenParser.findMainAccountButton();
|
||||
if (mainAcc.x() > 0) break;
|
||||
AdbUtils::goBack(m_deviceId);
|
||||
QThread::msleep(1500);
|
||||
}
|
||||
|
||||
if (mainAcc.x() > 0) {
|
||||
AdbUtils::makeTap(m_deviceId, mainAcc.x(), mainAcc.y());
|
||||
QThread::msleep(2000);
|
||||
|
||||
// Скроллим WebView, пока "Посмотреть реквизиты" не окажется в верхней половине,
|
||||
// чтобы тап не ушёл в системный нав-бар.
|
||||
Node showReq;
|
||||
const int targetMaxY = device.screenHeight / 2;
|
||||
for (int attempt = 0; attempt < 6; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
Node candidate = xmlScreenParser.findShowRequisitesButton();
|
||||
if (candidate.x() > 0 && candidate.y() <= targetMaxY) {
|
||||
showReq = candidate;
|
||||
break;
|
||||
}
|
||||
AdbUtils::makeSwipe(m_deviceId, device.screenWidth / 2,
|
||||
device.screenHeight * 2 / 3,
|
||||
device.screenWidth / 2,
|
||||
device.screenHeight / 3);
|
||||
QThread::msleep(800);
|
||||
}
|
||||
|
||||
if (showReq.x() > 0) {
|
||||
AdbUtils::makeTap(m_deviceId, showReq.x(), showReq.y());
|
||||
QThread::msleep(2000);
|
||||
|
||||
bool reqScreen = false;
|
||||
for (int attempt = 0; attempt < 6; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
if (xmlScreenParser.isAccountRequisitesScreen()) {
|
||||
reqScreen = true;
|
||||
break;
|
||||
}
|
||||
QThread::msleep(1000);
|
||||
}
|
||||
|
||||
if (reqScreen) {
|
||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
accountNumber = xmlScreenParser.parseAccountNumberFromRequisites();
|
||||
if (!accountNumber.isEmpty()) break;
|
||||
QThread::msleep(800);
|
||||
}
|
||||
qDebug() << "[GetCardInfo] accountNumber:" << accountNumber;
|
||||
} else {
|
||||
qWarning() << "[GetCardInfo] Account requisites screen not detected";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[GetCardInfo] 'Посмотреть реквизиты' not reached";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[GetCardInfo] 'Основной счёт' button not found on home";
|
||||
}
|
||||
|
||||
// Возврат на главный — критерий по кнопке "Основной счёт ... ₽"
|
||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
if (xmlScreenParser.findMainAccountButton().x() > 0) break;
|
||||
AdbUtils::goBack(m_deviceId);
|
||||
QThread::msleep(1500);
|
||||
}
|
||||
|
||||
// Записываем номер счёта во все материалы device/app
|
||||
if (!accountNumber.isEmpty()) {
|
||||
for (const MaterialInfo &c : cards) {
|
||||
MaterialInfo upd = MaterialDAO::findAppAccount(device.id, m_appCode, c.lastNumbers);
|
||||
if (upd.id == -1) continue;
|
||||
upd.accountNumber = accountNumber;
|
||||
upd.updateTime = QDateTime::currentDateTimeUtc();
|
||||
if (!MaterialDAO::upsertAccount(upd)) {
|
||||
qWarning() << "[GetCardInfo] Failed to save accountNumber for" << upd.lastNumbers;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ВРЕМЕННО ОТКЛЮЧЕНО
|
||||
// QString accountNumber;
|
||||
// {
|
||||
// bool needFetch = false;
|
||||
// for (const MaterialInfo &c : cards) {
|
||||
// const MaterialInfo dbCard = MaterialDAO::findAppAccount(device.id, m_appCode, c.lastNumbers);
|
||||
// if (dbCard.id != -1 && dbCard.accountNumber.isEmpty()) { needFetch = true; break; }
|
||||
// }
|
||||
//
|
||||
// if (needFetch) {
|
||||
// // Возвращаемся на главный экран — критерий именно по наличию кнопки
|
||||
// // "Основной счёт ... ₽". isHomeScreen() для Озона нестрогий
|
||||
// // (Перевести/Пополнить присутствуют и на других экранах).
|
||||
// Node mainAcc;
|
||||
// for (int attempt = 0; attempt < 6; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// mainAcc = xmlScreenParser.findMainAccountButton();
|
||||
// if (mainAcc.x() > 0) break;
|
||||
// AdbUtils::goBack(m_deviceId);
|
||||
// QThread::msleep(1500);
|
||||
// }
|
||||
//
|
||||
// if (mainAcc.x() > 0) {
|
||||
// AdbUtils::makeTap(m_deviceId, mainAcc.x(), mainAcc.y());
|
||||
// QThread::msleep(2000);
|
||||
//
|
||||
// // Скроллим WebView, пока "Посмотреть реквизиты" не окажется в верхней половине,
|
||||
// // чтобы тап не ушёл в системный нав-бар.
|
||||
// Node showReq;
|
||||
// const int targetMaxY = device.screenHeight / 2;
|
||||
// for (int attempt = 0; attempt < 6; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// Node candidate = xmlScreenParser.findShowRequisitesButton();
|
||||
// if (candidate.x() > 0 && candidate.y() <= targetMaxY) {
|
||||
// showReq = candidate;
|
||||
// break;
|
||||
// }
|
||||
// AdbUtils::makeSwipe(m_deviceId, device.screenWidth / 2,
|
||||
// device.screenHeight * 2 / 3,
|
||||
// device.screenWidth / 2,
|
||||
// device.screenHeight / 3);
|
||||
// QThread::msleep(800);
|
||||
// }
|
||||
//
|
||||
// if (showReq.x() > 0) {
|
||||
// AdbUtils::makeTap(m_deviceId, showReq.x(), showReq.y());
|
||||
// QThread::msleep(2000);
|
||||
//
|
||||
// bool reqScreen = false;
|
||||
// for (int attempt = 0; attempt < 6; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// if (xmlScreenParser.isAccountRequisitesScreen()) {
|
||||
// reqScreen = true;
|
||||
// break;
|
||||
// }
|
||||
// QThread::msleep(1000);
|
||||
// }
|
||||
//
|
||||
// if (reqScreen) {
|
||||
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// accountNumber = xmlScreenParser.parseAccountNumberFromRequisites();
|
||||
// if (!accountNumber.isEmpty()) break;
|
||||
// QThread::msleep(800);
|
||||
// }
|
||||
// qDebug() << "[GetCardInfo] accountNumber:" << accountNumber;
|
||||
// } else {
|
||||
// qWarning() << "[GetCardInfo] Account requisites screen not detected";
|
||||
// }
|
||||
// } else {
|
||||
// qWarning() << "[GetCardInfo] 'Посмотреть реквизиты' not reached";
|
||||
// }
|
||||
// } else {
|
||||
// qWarning() << "[GetCardInfo] 'Основной счёт' button not found on home";
|
||||
// }
|
||||
//
|
||||
// // Возврат на главный — критерий по кнопке "Основной счёт ... ₽"
|
||||
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
// if (xmlScreenParser.findMainAccountButton().x() > 0) break;
|
||||
// AdbUtils::goBack(m_deviceId);
|
||||
// QThread::msleep(1500);
|
||||
// }
|
||||
//
|
||||
// // Записываем номер счёта во все материалы device/app
|
||||
// if (!accountNumber.isEmpty()) {
|
||||
// for (const MaterialInfo &c : cards) {
|
||||
// MaterialInfo upd = MaterialDAO::findAppAccount(device.id, m_appCode, c.lastNumbers);
|
||||
// if (upd.id == -1) continue;
|
||||
// upd.accountNumber = accountNumber;
|
||||
// upd.updateTime = QDateTime::currentDateTimeUtc();
|
||||
// if (!MaterialDAO::upsertAccount(upd)) {
|
||||
// qWarning() << "[GetCardInfo] Failed to save accountNumber for" << upd.lastNumbers;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// 3. Отправляем материалы (карты) — после OCR, когда номера карт уже в БД
|
||||
const BankProfileInfo updatedApp = BankProfileDAO::getApplication(device.id, m_appCode);
|
||||
@ -530,7 +531,7 @@ void GetCardInfoScript::doStart() {
|
||||
QJsonObject materialBody;
|
||||
materialBody["bank_profile_id"] = updatedApp.bankProfileId;
|
||||
materialBody["card_number"] = dbCard.cardNumber;
|
||||
// materialBody["account_number"] = dbCard.accountNumber;
|
||||
materialBody["account_number"] = dbCard.accountNumber;
|
||||
materialBody["name"] = updatedApp.fullName;
|
||||
materialBody["state"] = materialStatusToString(dbCard.status) == "active" ? "enabled" : "disabled";
|
||||
materialBody["currency"] = currencyCodes.value(dbCard.currency.toUpper(), 643);
|
||||
|
||||
@ -248,6 +248,12 @@ void PayByCardScript::makePayment(
|
||||
for (int attempt = 0; attempt < 10; ++attempt) {
|
||||
if (!checkApp()) return;
|
||||
cardInput = xmlScreenParser.findEditTextByHint("Номер карты получателя");
|
||||
if (cardInput.isEmpty()) {
|
||||
// На части сборок Ozon WebView hint у поля PAN пустой, а лейбла
|
||||
// "Номер карты получателя" на экране нет (есть только "КУДА").
|
||||
// Поле PAN всегда внутри элемента resource-id="movable-pan-iframe".
|
||||
cardInput = xmlScreenParser.findPanCardNumberInput();
|
||||
}
|
||||
if (!cardInput.isEmpty()) break;
|
||||
qDebug() << "[PayByCard] Waiting for 'Номер карты получателя' input, attempt" << attempt + 1 << "/ 10";
|
||||
QThread::msleep(1500);
|
||||
|
||||
@ -176,6 +176,47 @@ Node ScreenXmlParser::findEditTextByHint(const QString &hintPrefix) {
|
||||
return best;
|
||||
}
|
||||
|
||||
static QDomElement findPanIframeElement(const QDomElement &root) {
|
||||
if (root.isNull()) return {};
|
||||
if (root.attribute("resource-id") == "movable-pan-iframe") return root;
|
||||
for (QDomElement child = root.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) {
|
||||
QDomElement found = findPanIframeElement(child);
|
||||
if (!found.isNull()) return found;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static QDomElement findFirstEditTextDescendant(const QDomElement &root) {
|
||||
if (root.isNull()) return {};
|
||||
if (root.attribute("class") == "android.widget.EditText") return root;
|
||||
for (QDomElement child = root.firstChildElement(); !child.isNull(); child = child.nextSiblingElement()) {
|
||||
QDomElement found = findFirstEditTextDescendant(child);
|
||||
if (!found.isNull()) return found;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Node ScreenXmlParser::findPanCardNumberInput() {
|
||||
const QDomElement iframe = findPanIframeElement(m_xml);
|
||||
if (iframe.isNull()) return {};
|
||||
const QDomElement edit = findFirstEditTextDescendant(iframe);
|
||||
if (edit.isNull()) return {};
|
||||
|
||||
Node node;
|
||||
if (QRegularExpressionMatch m = boundsRegex.match(edit.attribute("bounds")); m.hasMatch()) {
|
||||
node.setBounds(m.captured(1).toInt(), m.captured(2).toInt(),
|
||||
m.captured(3).toInt(), m.captured(4).toInt());
|
||||
}
|
||||
node.className = edit.attribute("class");
|
||||
node.text = edit.attribute("text");
|
||||
node.contentDesc = edit.attribute("content-desc");
|
||||
node.resourceId = edit.attribute("resource-id");
|
||||
node.hint = edit.attribute("hint");
|
||||
node.clickable = edit.attribute("clickable") == "true";
|
||||
node.focusable = edit.attribute("focusable") == "true";
|
||||
return node;
|
||||
}
|
||||
|
||||
Node ScreenXmlParser::findButtonNode(const QString &text, const bool contains) {
|
||||
for (const Node &node: m_nodes) {
|
||||
if (contains) {
|
||||
|
||||
@ -30,6 +30,12 @@ public:
|
||||
|
||||
Node findEditTextByHint(const QString &hintPrefix);
|
||||
|
||||
// Возвращает EditText внутри Ozon "movable-pan-iframe" — поле номера карты
|
||||
// получателя на экране "Перевод по номеру карты". Нужно как fallback, когда
|
||||
// WebView не отдаёт hint и на экране нет TextView-лейбла "Номер карты
|
||||
// получателя" (лейбл — просто "КУДА").
|
||||
Node findPanCardNumberInput();
|
||||
|
||||
Node findButtonNode(const QString &text, bool contains);
|
||||
|
||||
QList<Node> findAllButtons();
|
||||
|
||||
@ -1010,6 +1010,41 @@ void NetworkService::patchBankProfile() {
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void NetworkService::patchMaterial() {
|
||||
if (!ensureValidToken()) { emit finishedWithResult(-1); emit finished(); return; }
|
||||
|
||||
const QString materialId = m_extraData.value("material_id").toString();
|
||||
if (materialId.isEmpty()) {
|
||||
qWarning() << "[NetworkService] patchMaterial: material_id is empty";
|
||||
emit finishedWithResult(-1); emit finished();
|
||||
return;
|
||||
}
|
||||
|
||||
QJsonObject body;
|
||||
if (m_extraData.contains("account_number")) {
|
||||
body["account_number"] = m_extraData.value("account_number").toString();
|
||||
}
|
||||
if (m_extraData.contains("state")) {
|
||||
body["state"] = m_extraData.value("state").toString();
|
||||
}
|
||||
|
||||
const QString path = m_apiBase + m_pathMaterial + "/" + materialId;
|
||||
const QByteArray bodyJson = QJsonDocument(body).toJson(QJsonDocument::Indented);
|
||||
qDebug().noquote() << "[NetworkService] patchMaterial PATCH" << path
|
||||
<< "\nbody:\n" << bodyJson;
|
||||
|
||||
const QJsonValue result = patchJson(path, body, true);
|
||||
if (result.isNull() || result.isUndefined()) {
|
||||
qWarning() << "[NetworkService] patchMaterial failed:" << materialId;
|
||||
emit finishedWithResult(-1);
|
||||
} else {
|
||||
qDebug() << "[NetworkService] patchMaterial done:" << materialId;
|
||||
emit finishedWithResult(0);
|
||||
}
|
||||
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void NetworkService::toggleMaterial() {
|
||||
if (!ensureValidToken()) { emit finishedWithResult(-1); emit finished(); return; }
|
||||
|
||||
|
||||
@ -32,6 +32,8 @@ public slots:
|
||||
|
||||
void postMaterial();
|
||||
|
||||
void patchMaterial();
|
||||
|
||||
void toggleMaterial();
|
||||
|
||||
void postDeviceScreenshot();
|
||||
|
||||
@ -97,6 +97,7 @@ AccountSettingsWindow::AccountSettingsWindow(
|
||||
m_cardsBtn = new QPushButton("Проверить аккаунты");
|
||||
m_cardsBtn->setStyleSheet("background-color: #1565C0; color: white; padding: 4px 12px;");
|
||||
connect(m_cardsBtn, &QPushButton::clicked, this, &AccountSettingsWindow::startGetCardInfo);
|
||||
m_cardsBtn->hide();
|
||||
actionsRow->addWidget(m_cardsBtn);
|
||||
|
||||
actionsRow->addStretch();
|
||||
@ -572,7 +573,7 @@ void AccountSettingsWindow::reloadCards() {
|
||||
m_cardsTable->setRowCount(accounts.size());
|
||||
m_cardsTable->setColumnCount(7);
|
||||
m_cardsTable->setHorizontalHeaderLabels({
|
||||
"Сервер", "Статус", "Время обновления", "Номер", "Сумма", "Валюта", ""
|
||||
"Сервер", "Статус", "Время обновления", "Номер карты", "Сумма", "Валюта", ""
|
||||
});
|
||||
m_cardsTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
|
||||
@ -597,7 +598,7 @@ void AccountSettingsWindow::reloadCards() {
|
||||
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);
|
||||
@ -613,16 +614,16 @@ void AccountSettingsWindow::reloadCards() {
|
||||
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);
|
||||
// Кнопка переключения: только для неактивных — включит этот и выключит остальные
|
||||
if (!isActive) {
|
||||
auto *toggleBtn = new QPushButton("Переключить", m_cardsTable);
|
||||
toggleBtn->setStyleSheet("background-color: green; color: white;");
|
||||
m_cardsTable->setCellWidget(k, 6, toggleBtn);
|
||||
|
||||
connect(toggleBtn, &QPushButton::clicked, this, [this, acc]() {
|
||||
toggleMaterialStatus(acc);
|
||||
});
|
||||
connect(toggleBtn, &QPushButton::clicked, this, [this, acc]() {
|
||||
toggleMaterialStatus(acc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
m_cardsTable->resizeColumnsToContents();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user