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;
|
QString accountNumber;
|
||||||
const Node settingsBtn = xmlScreenParser.findCardSettingsButton();
|
// const Node settingsBtn = xmlScreenParser.findCardSettingsButton();
|
||||||
if (settingsBtn.x() > 0) {
|
// if (settingsBtn.x() > 0) {
|
||||||
AdbUtils::makeTap(m_deviceId, settingsBtn.x(), settingsBtn.y());
|
// AdbUtils::makeTap(m_deviceId, settingsBtn.x(), settingsBtn.y());
|
||||||
QThread::msleep(1500);
|
// QThread::msleep(1500);
|
||||||
|
//
|
||||||
bool sheetFound = false;
|
// bool sheetFound = false;
|
||||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
if (xmlScreenParser.isCardSettingsBottomSheet()) {
|
// if (xmlScreenParser.isCardSettingsBottomSheet()) {
|
||||||
sheetFound = true;
|
// sheetFound = true;
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
QThread::msleep(1000);
|
// QThread::msleep(1000);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (sheetFound) {
|
// if (sheetFound) {
|
||||||
const Node requisitesItem = xmlScreenParser.findCardRequisitesMenuItem();
|
// const Node requisitesItem = xmlScreenParser.findCardRequisitesMenuItem();
|
||||||
if (requisitesItem.x() > 0) {
|
// if (requisitesItem.x() > 0) {
|
||||||
AdbUtils::makeTap(m_deviceId, requisitesItem.x(), requisitesItem.y());
|
// AdbUtils::makeTap(m_deviceId, requisitesItem.x(), requisitesItem.y());
|
||||||
QThread::msleep(1500);
|
// QThread::msleep(1500);
|
||||||
|
//
|
||||||
bool reqScreenFound = false;
|
// bool reqScreenFound = false;
|
||||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
if (xmlScreenParser.isCardRequisitesScreen()) {
|
// if (xmlScreenParser.isCardRequisitesScreen()) {
|
||||||
reqScreenFound = true;
|
// reqScreenFound = true;
|
||||||
break;
|
// break;
|
||||||
}
|
// }
|
||||||
QThread::msleep(1000);
|
// QThread::msleep(1000);
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
if (reqScreenFound) {
|
// if (reqScreenFound) {
|
||||||
const Node accountTab = xmlScreenParser.findAccountRequisitesTab();
|
// const Node accountTab = xmlScreenParser.findAccountRequisitesTab();
|
||||||
if (accountTab.x() > 0) {
|
// if (accountTab.x() > 0) {
|
||||||
AdbUtils::makeTap(m_deviceId, accountTab.x(), accountTab.y());
|
// AdbUtils::makeTap(m_deviceId, accountTab.x(), accountTab.y());
|
||||||
QThread::msleep(1500);
|
// QThread::msleep(1500);
|
||||||
|
//
|
||||||
// Несколько попыток — данные могут подгружаться
|
// // Несколько попыток — данные могут подгружаться
|
||||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
accountNumber = xmlScreenParser.parseAccountNumber();
|
// accountNumber = xmlScreenParser.parseAccountNumber();
|
||||||
if (!accountNumber.isEmpty()) break;
|
// if (!accountNumber.isEmpty()) break;
|
||||||
QThread::msleep(1000);
|
// QThread::msleep(1000);
|
||||||
}
|
// }
|
||||||
qDebug() << "[Dushanbe::GetCardInfo] accountNumber for card" << i
|
// qDebug() << "[Dushanbe::GetCardInfo] accountNumber for card" << i
|
||||||
<< ":" << accountNumber;
|
// << ":" << accountNumber;
|
||||||
} else {
|
// } else {
|
||||||
qWarning() << "[Dushanbe::GetCardInfo] Account tab not found for card" << i;
|
// qWarning() << "[Dushanbe::GetCardInfo] Account tab not found for card" << i;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
qWarning() << "[Dushanbe::GetCardInfo] Requisites screen not detected for card" << i;
|
// qWarning() << "[Dushanbe::GetCardInfo] Requisites screen not detected for card" << i;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
qWarning() << "[Dushanbe::GetCardInfo] 'Реквизиты карты' menu item not found for card" << i;
|
// qWarning() << "[Dushanbe::GetCardInfo] 'Реквизиты карты' menu item not found for card" << i;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
qWarning() << "[Dushanbe::GetCardInfo] Card settings bottom sheet not detected for card" << i;
|
// qWarning() << "[Dushanbe::GetCardInfo] Card settings bottom sheet not detected for card" << i;
|
||||||
}
|
// }
|
||||||
|
//
|
||||||
// Возврат на экран детали карты — bottom sheet и/или экран Реквизитов
|
// // Возврат на экран детали карты — bottom sheet и/или экран Реквизитов
|
||||||
for (int attempt = 0; attempt < 4; ++attempt) {
|
// for (int attempt = 0; attempt < 4; ++attempt) {
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
if (xmlScreenParser.isCardDetailScreen()) break;
|
// if (xmlScreenParser.isCardDetailScreen()) break;
|
||||||
AdbUtils::goBack(m_deviceId);
|
// AdbUtils::goBack(m_deviceId);
|
||||||
QThread::msleep(1200);
|
// QThread::msleep(1200);
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
qWarning() << "[Dushanbe::GetCardInfo] 'Настройки карты' button not found for card" << i;
|
// qWarning() << "[Dushanbe::GetCardInfo] 'Настройки карты' button not found for card" << i;
|
||||||
}
|
// }
|
||||||
|
|
||||||
MaterialInfo account;
|
MaterialInfo account;
|
||||||
account.deviceId = device.id;
|
account.deviceId = device.id;
|
||||||
|
|||||||
@ -415,103 +415,104 @@ void GetCardInfoScript::doStart() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2.5. Достаём номер счёта (общий для всех карт): Основной счёт → Посмотреть реквизиты
|
// 2.5. Достаём номер счёта (общий для всех карт): Основной счёт → Посмотреть реквизиты
|
||||||
QString accountNumber;
|
// ВРЕМЕННО ОТКЛЮЧЕНО
|
||||||
{
|
// QString accountNumber;
|
||||||
bool needFetch = false;
|
// {
|
||||||
for (const MaterialInfo &c : cards) {
|
// bool needFetch = false;
|
||||||
const MaterialInfo dbCard = MaterialDAO::findAppAccount(device.id, m_appCode, c.lastNumbers);
|
// for (const MaterialInfo &c : cards) {
|
||||||
if (dbCard.id != -1 && dbCard.accountNumber.isEmpty()) { needFetch = true; break; }
|
// const MaterialInfo dbCard = MaterialDAO::findAppAccount(device.id, m_appCode, c.lastNumbers);
|
||||||
}
|
// if (dbCard.id != -1 && dbCard.accountNumber.isEmpty()) { needFetch = true; break; }
|
||||||
|
// }
|
||||||
if (needFetch) {
|
//
|
||||||
// Возвращаемся на главный экран — критерий именно по наличию кнопки
|
// if (needFetch) {
|
||||||
// "Основной счёт ... ₽". isHomeScreen() для Озона нестрогий
|
// // Возвращаемся на главный экран — критерий именно по наличию кнопки
|
||||||
// (Перевести/Пополнить присутствуют и на других экранах).
|
// // "Основной счёт ... ₽". isHomeScreen() для Озона нестрогий
|
||||||
Node mainAcc;
|
// // (Перевести/Пополнить присутствуют и на других экранах).
|
||||||
for (int attempt = 0; attempt < 6; ++attempt) {
|
// Node mainAcc;
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// for (int attempt = 0; attempt < 6; ++attempt) {
|
||||||
mainAcc = xmlScreenParser.findMainAccountButton();
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
if (mainAcc.x() > 0) break;
|
// mainAcc = xmlScreenParser.findMainAccountButton();
|
||||||
AdbUtils::goBack(m_deviceId);
|
// if (mainAcc.x() > 0) break;
|
||||||
QThread::msleep(1500);
|
// AdbUtils::goBack(m_deviceId);
|
||||||
}
|
// QThread::msleep(1500);
|
||||||
|
// }
|
||||||
if (mainAcc.x() > 0) {
|
//
|
||||||
AdbUtils::makeTap(m_deviceId, mainAcc.x(), mainAcc.y());
|
// if (mainAcc.x() > 0) {
|
||||||
QThread::msleep(2000);
|
// AdbUtils::makeTap(m_deviceId, mainAcc.x(), mainAcc.y());
|
||||||
|
// QThread::msleep(2000);
|
||||||
// Скроллим WebView, пока "Посмотреть реквизиты" не окажется в верхней половине,
|
//
|
||||||
// чтобы тап не ушёл в системный нав-бар.
|
// // Скроллим WebView, пока "Посмотреть реквизиты" не окажется в верхней половине,
|
||||||
Node showReq;
|
// // чтобы тап не ушёл в системный нав-бар.
|
||||||
const int targetMaxY = device.screenHeight / 2;
|
// Node showReq;
|
||||||
for (int attempt = 0; attempt < 6; ++attempt) {
|
// const int targetMaxY = device.screenHeight / 2;
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// for (int attempt = 0; attempt < 6; ++attempt) {
|
||||||
Node candidate = xmlScreenParser.findShowRequisitesButton();
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
if (candidate.x() > 0 && candidate.y() <= targetMaxY) {
|
// Node candidate = xmlScreenParser.findShowRequisitesButton();
|
||||||
showReq = candidate;
|
// if (candidate.x() > 0 && candidate.y() <= targetMaxY) {
|
||||||
break;
|
// showReq = candidate;
|
||||||
}
|
// break;
|
||||||
AdbUtils::makeSwipe(m_deviceId, device.screenWidth / 2,
|
// }
|
||||||
device.screenHeight * 2 / 3,
|
// AdbUtils::makeSwipe(m_deviceId, device.screenWidth / 2,
|
||||||
device.screenWidth / 2,
|
// device.screenHeight * 2 / 3,
|
||||||
device.screenHeight / 3);
|
// device.screenWidth / 2,
|
||||||
QThread::msleep(800);
|
// device.screenHeight / 3);
|
||||||
}
|
// QThread::msleep(800);
|
||||||
|
// }
|
||||||
if (showReq.x() > 0) {
|
//
|
||||||
AdbUtils::makeTap(m_deviceId, showReq.x(), showReq.y());
|
// if (showReq.x() > 0) {
|
||||||
QThread::msleep(2000);
|
// AdbUtils::makeTap(m_deviceId, showReq.x(), showReq.y());
|
||||||
|
// QThread::msleep(2000);
|
||||||
bool reqScreen = false;
|
//
|
||||||
for (int attempt = 0; attempt < 6; ++attempt) {
|
// bool reqScreen = false;
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// for (int attempt = 0; attempt < 6; ++attempt) {
|
||||||
if (xmlScreenParser.isAccountRequisitesScreen()) {
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
reqScreen = true;
|
// if (xmlScreenParser.isAccountRequisitesScreen()) {
|
||||||
break;
|
// reqScreen = true;
|
||||||
}
|
// break;
|
||||||
QThread::msleep(1000);
|
// }
|
||||||
}
|
// QThread::msleep(1000);
|
||||||
|
// }
|
||||||
if (reqScreen) {
|
//
|
||||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
// if (reqScreen) {
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||||
accountNumber = xmlScreenParser.parseAccountNumberFromRequisites();
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
if (!accountNumber.isEmpty()) break;
|
// accountNumber = xmlScreenParser.parseAccountNumberFromRequisites();
|
||||||
QThread::msleep(800);
|
// if (!accountNumber.isEmpty()) break;
|
||||||
}
|
// QThread::msleep(800);
|
||||||
qDebug() << "[GetCardInfo] accountNumber:" << accountNumber;
|
// }
|
||||||
} else {
|
// qDebug() << "[GetCardInfo] accountNumber:" << accountNumber;
|
||||||
qWarning() << "[GetCardInfo] Account requisites screen not detected";
|
// } else {
|
||||||
}
|
// qWarning() << "[GetCardInfo] Account requisites screen not detected";
|
||||||
} else {
|
// }
|
||||||
qWarning() << "[GetCardInfo] 'Посмотреть реквизиты' not reached";
|
// } else {
|
||||||
}
|
// qWarning() << "[GetCardInfo] 'Посмотреть реквизиты' not reached";
|
||||||
} else {
|
// }
|
||||||
qWarning() << "[GetCardInfo] 'Основной счёт' button not found on home";
|
// } else {
|
||||||
}
|
// qWarning() << "[GetCardInfo] 'Основной счёт' button not found on home";
|
||||||
|
// }
|
||||||
// Возврат на главный — критерий по кнопке "Основной счёт ... ₽"
|
//
|
||||||
for (int attempt = 0; attempt < 5; ++attempt) {
|
// // Возврат на главный — критерий по кнопке "Основной счёт ... ₽"
|
||||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
// for (int attempt = 0; attempt < 5; ++attempt) {
|
||||||
if (xmlScreenParser.findMainAccountButton().x() > 0) break;
|
// xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||||
AdbUtils::goBack(m_deviceId);
|
// if (xmlScreenParser.findMainAccountButton().x() > 0) break;
|
||||||
QThread::msleep(1500);
|
// AdbUtils::goBack(m_deviceId);
|
||||||
}
|
// QThread::msleep(1500);
|
||||||
|
// }
|
||||||
// Записываем номер счёта во все материалы device/app
|
//
|
||||||
if (!accountNumber.isEmpty()) {
|
// // Записываем номер счёта во все материалы device/app
|
||||||
for (const MaterialInfo &c : cards) {
|
// if (!accountNumber.isEmpty()) {
|
||||||
MaterialInfo upd = MaterialDAO::findAppAccount(device.id, m_appCode, c.lastNumbers);
|
// for (const MaterialInfo &c : cards) {
|
||||||
if (upd.id == -1) continue;
|
// MaterialInfo upd = MaterialDAO::findAppAccount(device.id, m_appCode, c.lastNumbers);
|
||||||
upd.accountNumber = accountNumber;
|
// if (upd.id == -1) continue;
|
||||||
upd.updateTime = QDateTime::currentDateTimeUtc();
|
// upd.accountNumber = accountNumber;
|
||||||
if (!MaterialDAO::upsertAccount(upd)) {
|
// upd.updateTime = QDateTime::currentDateTimeUtc();
|
||||||
qWarning() << "[GetCardInfo] Failed to save accountNumber for" << upd.lastNumbers;
|
// if (!MaterialDAO::upsertAccount(upd)) {
|
||||||
}
|
// qWarning() << "[GetCardInfo] Failed to save accountNumber for" << upd.lastNumbers;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
// 3. Отправляем материалы (карты) — после OCR, когда номера карт уже в БД
|
// 3. Отправляем материалы (карты) — после OCR, когда номера карт уже в БД
|
||||||
const BankProfileInfo updatedApp = BankProfileDAO::getApplication(device.id, m_appCode);
|
const BankProfileInfo updatedApp = BankProfileDAO::getApplication(device.id, m_appCode);
|
||||||
@ -530,7 +531,7 @@ void GetCardInfoScript::doStart() {
|
|||||||
QJsonObject materialBody;
|
QJsonObject materialBody;
|
||||||
materialBody["bank_profile_id"] = updatedApp.bankProfileId;
|
materialBody["bank_profile_id"] = updatedApp.bankProfileId;
|
||||||
materialBody["card_number"] = dbCard.cardNumber;
|
materialBody["card_number"] = dbCard.cardNumber;
|
||||||
// materialBody["account_number"] = dbCard.accountNumber;
|
materialBody["account_number"] = dbCard.accountNumber;
|
||||||
materialBody["name"] = updatedApp.fullName;
|
materialBody["name"] = updatedApp.fullName;
|
||||||
materialBody["state"] = materialStatusToString(dbCard.status) == "active" ? "enabled" : "disabled";
|
materialBody["state"] = materialStatusToString(dbCard.status) == "active" ? "enabled" : "disabled";
|
||||||
materialBody["currency"] = currencyCodes.value(dbCard.currency.toUpper(), 643);
|
materialBody["currency"] = currencyCodes.value(dbCard.currency.toUpper(), 643);
|
||||||
|
|||||||
@ -248,6 +248,12 @@ void PayByCardScript::makePayment(
|
|||||||
for (int attempt = 0; attempt < 10; ++attempt) {
|
for (int attempt = 0; attempt < 10; ++attempt) {
|
||||||
if (!checkApp()) return;
|
if (!checkApp()) return;
|
||||||
cardInput = xmlScreenParser.findEditTextByHint("Номер карты получателя");
|
cardInput = xmlScreenParser.findEditTextByHint("Номер карты получателя");
|
||||||
|
if (cardInput.isEmpty()) {
|
||||||
|
// На части сборок Ozon WebView hint у поля PAN пустой, а лейбла
|
||||||
|
// "Номер карты получателя" на экране нет (есть только "КУДА").
|
||||||
|
// Поле PAN всегда внутри элемента resource-id="movable-pan-iframe".
|
||||||
|
cardInput = xmlScreenParser.findPanCardNumberInput();
|
||||||
|
}
|
||||||
if (!cardInput.isEmpty()) break;
|
if (!cardInput.isEmpty()) break;
|
||||||
qDebug() << "[PayByCard] Waiting for 'Номер карты получателя' input, attempt" << attempt + 1 << "/ 10";
|
qDebug() << "[PayByCard] Waiting for 'Номер карты получателя' input, attempt" << attempt + 1 << "/ 10";
|
||||||
QThread::msleep(1500);
|
QThread::msleep(1500);
|
||||||
|
|||||||
@ -176,6 +176,47 @@ Node ScreenXmlParser::findEditTextByHint(const QString &hintPrefix) {
|
|||||||
return best;
|
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) {
|
Node ScreenXmlParser::findButtonNode(const QString &text, const bool contains) {
|
||||||
for (const Node &node: m_nodes) {
|
for (const Node &node: m_nodes) {
|
||||||
if (contains) {
|
if (contains) {
|
||||||
|
|||||||
@ -30,6 +30,12 @@ public:
|
|||||||
|
|
||||||
Node findEditTextByHint(const QString &hintPrefix);
|
Node findEditTextByHint(const QString &hintPrefix);
|
||||||
|
|
||||||
|
// Возвращает EditText внутри Ozon "movable-pan-iframe" — поле номера карты
|
||||||
|
// получателя на экране "Перевод по номеру карты". Нужно как fallback, когда
|
||||||
|
// WebView не отдаёт hint и на экране нет TextView-лейбла "Номер карты
|
||||||
|
// получателя" (лейбл — просто "КУДА").
|
||||||
|
Node findPanCardNumberInput();
|
||||||
|
|
||||||
Node findButtonNode(const QString &text, bool contains);
|
Node findButtonNode(const QString &text, bool contains);
|
||||||
|
|
||||||
QList<Node> findAllButtons();
|
QList<Node> findAllButtons();
|
||||||
|
|||||||
@ -1010,6 +1010,41 @@ void NetworkService::patchBankProfile() {
|
|||||||
emit finished();
|
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() {
|
void NetworkService::toggleMaterial() {
|
||||||
if (!ensureValidToken()) { emit finishedWithResult(-1); emit finished(); return; }
|
if (!ensureValidToken()) { emit finishedWithResult(-1); emit finished(); return; }
|
||||||
|
|
||||||
|
|||||||
@ -32,6 +32,8 @@ public slots:
|
|||||||
|
|
||||||
void postMaterial();
|
void postMaterial();
|
||||||
|
|
||||||
|
void patchMaterial();
|
||||||
|
|
||||||
void toggleMaterial();
|
void toggleMaterial();
|
||||||
|
|
||||||
void postDeviceScreenshot();
|
void postDeviceScreenshot();
|
||||||
|
|||||||
@ -97,6 +97,7 @@ AccountSettingsWindow::AccountSettingsWindow(
|
|||||||
m_cardsBtn = new QPushButton("Проверить аккаунты");
|
m_cardsBtn = new QPushButton("Проверить аккаунты");
|
||||||
m_cardsBtn->setStyleSheet("background-color: #1565C0; color: white; padding: 4px 12px;");
|
m_cardsBtn->setStyleSheet("background-color: #1565C0; color: white; padding: 4px 12px;");
|
||||||
connect(m_cardsBtn, &QPushButton::clicked, this, &AccountSettingsWindow::startGetCardInfo);
|
connect(m_cardsBtn, &QPushButton::clicked, this, &AccountSettingsWindow::startGetCardInfo);
|
||||||
|
m_cardsBtn->hide();
|
||||||
actionsRow->addWidget(m_cardsBtn);
|
actionsRow->addWidget(m_cardsBtn);
|
||||||
|
|
||||||
actionsRow->addStretch();
|
actionsRow->addStretch();
|
||||||
@ -572,7 +573,7 @@ void AccountSettingsWindow::reloadCards() {
|
|||||||
m_cardsTable->setRowCount(accounts.size());
|
m_cardsTable->setRowCount(accounts.size());
|
||||||
m_cardsTable->setColumnCount(7);
|
m_cardsTable->setColumnCount(7);
|
||||||
m_cardsTable->setHorizontalHeaderLabels({
|
m_cardsTable->setHorizontalHeaderLabels({
|
||||||
"Сервер", "Статус", "Время обновления", "Номер", "Сумма", "Валюта", ""
|
"Сервер", "Статус", "Время обновления", "Номер карты", "Сумма", "Валюта", ""
|
||||||
});
|
});
|
||||||
m_cardsTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
m_cardsTable->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
|
|
||||||
@ -597,7 +598,7 @@ void AccountSettingsWindow::reloadCards() {
|
|||||||
timeItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
timeItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
m_cardsTable->setItem(k, 2, timeItem);
|
m_cardsTable->setItem(k, 2, timeItem);
|
||||||
|
|
||||||
// Номер
|
// Номер карты
|
||||||
const QString displayNumber = acc.cardNumber.isEmpty() ? acc.lastNumbers : acc.cardNumber;
|
const QString displayNumber = acc.cardNumber.isEmpty() ? acc.lastNumbers : acc.cardNumber;
|
||||||
auto *numItem = new QTableWidgetItem(displayNumber);
|
auto *numItem = new QTableWidgetItem(displayNumber);
|
||||||
numItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
numItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
@ -613,16 +614,16 @@ void AccountSettingsWindow::reloadCards() {
|
|||||||
currItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
currItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
|
||||||
m_cardsTable->setItem(k, 5, currItem);
|
m_cardsTable->setItem(k, 5, currItem);
|
||||||
|
|
||||||
// Кнопка вкл/выкл
|
// Кнопка переключения: только для неактивных — включит этот и выключит остальные
|
||||||
auto *toggleBtn = new QPushButton(isActive ? "Выключить" : "Включить", m_cardsTable);
|
if (!isActive) {
|
||||||
toggleBtn->setStyleSheet(isActive
|
auto *toggleBtn = new QPushButton("Переключить", m_cardsTable);
|
||||||
? "background-color: red; color: white;"
|
toggleBtn->setStyleSheet("background-color: green; color: white;");
|
||||||
: "background-color: green; color: white;");
|
m_cardsTable->setCellWidget(k, 6, toggleBtn);
|
||||||
m_cardsTable->setCellWidget(k, 6, toggleBtn);
|
|
||||||
|
|
||||||
connect(toggleBtn, &QPushButton::clicked, this, [this, acc]() {
|
connect(toggleBtn, &QPushButton::clicked, this, [this, acc]() {
|
||||||
toggleMaterialStatus(acc);
|
toggleMaterialStatus(acc);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
m_cardsTable->resizeColumnsToContents();
|
m_cardsTable->resizeColumnsToContents();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user