Add PayByCardScript implementation and XML asset for payment automation in Ozon
Implemented `PayByCardScript` to enable automated card payments on the Ozon platform. Includes ad banner detection/handling, OCR-based transaction ID extraction, fee calculation, and database updates for transactions. Added XML asset `pay_by_card_success.xml` for payment result handling.
This commit is contained in:
parent
29357f7471
commit
e9e0c20c5d
375
android/ozon/PayByCardScript.cpp
Normal file
375
android/ozon/PayByCardScript.cpp
Normal file
@ -0,0 +1,375 @@
|
||||
#include "PayByCardScript.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QRegularExpression>
|
||||
#include <QThread>
|
||||
#include <QTimeZone>
|
||||
#include <utility>
|
||||
|
||||
#include <tesseract/baseapi.h>
|
||||
#include <leptonica/allheaders.h>
|
||||
|
||||
#include "adb/AdbUtils.h"
|
||||
#include "dao/AccountDAO.h"
|
||||
#include "dao/ApplicationDAO.h"
|
||||
#include "dao/DeviceDAO.h"
|
||||
#include "dao/TransactionDAO.h"
|
||||
#include "time/DateUtils.h"
|
||||
|
||||
static QString recognizeTextFromImage(const QByteArray &pngData) {
|
||||
auto *api = new tesseract::TessBaseAPI();
|
||||
if (api->Init(nullptr, "rus+eng")) {
|
||||
qWarning() << "[OCR] Failed to init Tesseract";
|
||||
delete api;
|
||||
return {};
|
||||
}
|
||||
|
||||
Pix *pix = pixReadMem(reinterpret_cast<const l_uint8 *>(pngData.constData()),
|
||||
static_cast<size_t>(pngData.size()));
|
||||
if (!pix) {
|
||||
qWarning() << "[OCR] Failed to read image";
|
||||
api->End();
|
||||
delete api;
|
||||
return {};
|
||||
}
|
||||
|
||||
api->SetImage(pix);
|
||||
char *text = api->GetUTF8Text();
|
||||
QString result = QString::fromUtf8(text).trimmed();
|
||||
delete[] text;
|
||||
pixDestroy(&pix);
|
||||
api->End();
|
||||
delete api;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static QString extractTransactionId(const QString &ocrText) {
|
||||
// "ID операции A60130542076330K0000040011670301" или "ID операции = Аб60650..."
|
||||
QRegularExpression reId(R"(ID\s+операции\s*=?\s*([A-Za-zА-Яа-я0-9]+))");
|
||||
if (auto m = reId.match(ocrText); m.hasMatch()) return m.captured(1);
|
||||
|
||||
// "№ Ф-2026-25235663"
|
||||
QRegularExpression reRef(R"(№\s*(Ф-[\d-]+))");
|
||||
if (auto m = reRef.match(ocrText); m.hasMatch()) return m.captured(1);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
namespace Ozon {
|
||||
|
||||
PayByCardScript::PayByCardScript(
|
||||
AccountInfo account,
|
||||
QString cardNumber,
|
||||
const double amount,
|
||||
QObject *parent
|
||||
) : CommonScript(parent),
|
||||
m_account(std::move(account)), m_cardNumber(std::move(cardNumber)),
|
||||
m_amount(amount) {
|
||||
}
|
||||
|
||||
PayByCardScript::~PayByCardScript() = default;
|
||||
|
||||
void PayByCardScript::doStart() {
|
||||
const DeviceInfo device = DeviceDAO::getDeviceById(m_account.deviceId);
|
||||
const ApplicationInfo app = ApplicationDAO::getApplication(m_account.deviceId, m_account.appCode);
|
||||
|
||||
if (device.id.isEmpty() || app.id == -1) {
|
||||
m_error = "Device or app not found: " + m_account.deviceId;
|
||||
qCritical() << m_error;
|
||||
emit finishedWithResult(m_error);
|
||||
return;
|
||||
}
|
||||
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.id, ++m_counter));
|
||||
|
||||
// Закрываем рекламный bottom sheet
|
||||
if (Node adNode = xmlScreenParser.tryToFindAdBanner(); !adNode.isEmpty()) {
|
||||
qDebug() << "[PayByCard] Ad banner detected, closing...";
|
||||
AdbUtils::makeTap(device.id, adNode.x(), adNode.y());
|
||||
QThread::msleep(1000);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.id, ++m_counter));
|
||||
}
|
||||
|
||||
// Если не на домашнем экране — перезапускаем
|
||||
if (!xmlScreenParser.isHomeScreen()) {
|
||||
qDebug() << "[PayByCard] Not on home screen, restarting app...";
|
||||
if (!runAppAndGoToHomeScreen(device.id, app.package, app.pinCode,
|
||||
device.screenWidth, device.screenHeight)) {
|
||||
m_error = "Cannot reach home screen: " + device.id;
|
||||
qWarning() << m_error;
|
||||
AdbUtils::tryToKillApplication(device.id, app.package);
|
||||
emit finishedWithResult(m_error);
|
||||
return;
|
||||
}
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.id, ++m_counter));
|
||||
}
|
||||
|
||||
// Закрываем баннеры
|
||||
tryToCloseAllBannersOnHomePage(device.id, device.screenWidth, device.screenHeight);
|
||||
QThread::msleep(500);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.id, ++m_counter));
|
||||
|
||||
// Закрываем баннер Google Play "Доступно обновление"
|
||||
if (Node gpNode = xmlScreenParser.tryToFindGooglePlayBanner(); !gpNode.isEmpty()) {
|
||||
qDebug() << "[PayByCard] Google Play update banner detected, closing...";
|
||||
AdbUtils::makeTap(device.id, gpNode.x(), gpNode.y());
|
||||
QThread::msleep(1500);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.id, ++m_counter));
|
||||
}
|
||||
|
||||
// Закрываем баннер "Заказать карту" — тапаем сверху экрана
|
||||
if (Node orderCardNode = xmlScreenParser.findTextNode("Заказать карту"); !orderCardNode.isEmpty()) {
|
||||
qDebug() << "[PayByCard] 'Заказать карту' banner detected, closing...";
|
||||
AdbUtils::makeTap(device.id, device.screenWidth / 2, 100);
|
||||
QThread::msleep(1000);
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(device.id, ++m_counter));
|
||||
}
|
||||
|
||||
makePayment(device.id, app.pinCode, device.screenWidth, device.screenHeight);
|
||||
|
||||
emit finishedWithResult(m_error);
|
||||
}
|
||||
|
||||
void PayByCardScript::makePayment(
|
||||
const QString &deviceId,
|
||||
const QString &pinCode,
|
||||
const int width,
|
||||
const int height
|
||||
) {
|
||||
// 1. Нажимаем "Перевести" на домашнем экране
|
||||
Node transferBtn = xmlScreenParser.findButtonNode("Перевести", false);
|
||||
if (transferBtn.isEmpty()) {
|
||||
m_error = "Кнопка 'Перевести' не найдена на домашнем экране";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "[PayByCard] Tapping 'Перевести'...";
|
||||
AdbUtils::makeTap(deviceId, transferBtn.x(), transferBtn.y());
|
||||
QThread::msleep(2000);
|
||||
|
||||
// 2. Ждём экран "Платежи и переводы"
|
||||
bool paymentsPageLoaded = false;
|
||||
for (int attempt = 0; attempt < 10; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||||
Node title = xmlScreenParser.findTextNode("Платежи и переводы");
|
||||
if (!title.isEmpty()) {
|
||||
paymentsPageLoaded = true;
|
||||
break;
|
||||
}
|
||||
qDebug() << "[PayByCard] Waiting for 'Платежи и переводы', attempt" << attempt + 1 << "/ 10";
|
||||
QThread::msleep(1500);
|
||||
}
|
||||
|
||||
if (!paymentsPageLoaded) {
|
||||
m_error = "Экран 'Платежи и переводы' не загрузился";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Нажимаем "По номеру карты" в секции "ДРУГИЕ СПОСОБЫ"
|
||||
Node cardBtn = xmlScreenParser.findButtonNode("По номеру карты", false);
|
||||
if (cardBtn.isEmpty()) {
|
||||
m_error = "Кнопка 'По номеру карты' не найдена на экране платежей";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "[PayByCard] Tapping 'По номеру карты'...";
|
||||
AdbUtils::makeTap(deviceId, cardBtn.x(), cardBtn.y());
|
||||
QThread::msleep(2000);
|
||||
|
||||
// 4. Ждём экран "Перевод по номеру карты"
|
||||
bool cardScreenLoaded = false;
|
||||
for (int attempt = 0; attempt < 10; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||||
Node title = xmlScreenParser.findTextNode("Перевод по номеру карты");
|
||||
if (!title.isEmpty()) {
|
||||
cardScreenLoaded = true;
|
||||
break;
|
||||
}
|
||||
qDebug() << "[PayByCard] Waiting for 'Перевод по номеру карты', attempt" << attempt + 1 << "/ 10";
|
||||
QThread::msleep(1500);
|
||||
}
|
||||
|
||||
if (!cardScreenLoaded) {
|
||||
m_error = "Экран 'Перевод по номеру карты' не загрузился";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "[PayByCard] Card payment screen loaded successfully";
|
||||
|
||||
// 5. Вводим номер карты в поле "Номер карты получателя"
|
||||
Node cardInput = xmlScreenParser.findEditTextByHint("Номер карты получателя");
|
||||
if (cardInput.isEmpty()) {
|
||||
m_error = "Поле 'Номер карты получателя' не найдено";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
return;
|
||||
}
|
||||
|
||||
AdbUtils::makeTap(deviceId, cardInput.x(), cardInput.y());
|
||||
QThread::msleep(500);
|
||||
AdbUtils::inputText(deviceId, m_cardNumber);
|
||||
QThread::msleep(2000);
|
||||
|
||||
// 6. Ждём распознавания карты и вводим сумму
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||||
|
||||
Node sumInput = xmlScreenParser.findEditTextByHint("Сумма от");
|
||||
if (sumInput.isEmpty()) {
|
||||
m_error = "Поле ввода суммы не найдено";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
return;
|
||||
}
|
||||
|
||||
AdbUtils::makeTap(deviceId, sumInput.x(), sumInput.y());
|
||||
QThread::msleep(500);
|
||||
AdbUtils::inputText(deviceId, QString::number(static_cast<int>(m_amount)));
|
||||
QThread::msleep(1000);
|
||||
|
||||
qDebug() << "[PayByCard] Card number and amount entered";
|
||||
|
||||
// 7. Ждём расчёта комиссии (текст после "Комиссия" перестаёт быть "Рассчитаем...")
|
||||
double fee = 0;
|
||||
bool feeCalculated = false;
|
||||
for (int attempt = 0; attempt < 15; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||||
|
||||
bool foundKomissiya = false;
|
||||
for (const Node &node : xmlScreenParser.findAllNodes()) {
|
||||
if (node.className == "android.widget.TextView" && node.text.trimmed() == "Комиссия") {
|
||||
foundKomissiya = true;
|
||||
continue;
|
||||
}
|
||||
if (foundKomissiya && node.className == "android.widget.TextView" && !node.text.isEmpty()) {
|
||||
const QString feeText = node.text.trimmed();
|
||||
if (feeText.startsWith("Рассчитаем")) {
|
||||
foundKomissiya = false;
|
||||
break; // ещё не рассчитана
|
||||
}
|
||||
// Парсим "45 ₽" → 45.0
|
||||
QString digits = feeText;
|
||||
digits.remove(QRegularExpression("[^0-9,\\.]"));
|
||||
digits.replace(',', '.');
|
||||
fee = digits.toDouble();
|
||||
feeCalculated = true;
|
||||
qDebug() << "[PayByCard] Fee parsed:" << fee << "from text:" << feeText;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (feeCalculated) break;
|
||||
qDebug() << "[PayByCard] Waiting for fee calculation, attempt" << attempt + 1 << "/ 15";
|
||||
QThread::msleep(1500);
|
||||
}
|
||||
|
||||
if (!feeCalculated) {
|
||||
qWarning() << "[PayByCard] Fee not calculated after timeout, proceeding with fee=0";
|
||||
}
|
||||
|
||||
// 8. Нажимаем "Перевести" (или "Перевести X ₽")
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||||
Node transferBtn2 = xmlScreenParser.findButtonNode("Перевести", true);
|
||||
if (transferBtn2.isEmpty()) {
|
||||
m_error = "Кнопка 'Перевести' не найдена на экране ввода суммы";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "[PayByCard] Tapping transfer button:" << transferBtn2.text;
|
||||
AdbUtils::makeTap(deviceId, transferBtn2.x(), transferBtn2.y());
|
||||
QThread::msleep(3000);
|
||||
|
||||
// 9. Ждём результат: "Успешно" или "Не удалось"
|
||||
for (int attempt = 0; attempt < 15; ++attempt) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||||
|
||||
if (!xmlScreenParser.findTextNode("Успешно").isEmpty()) {
|
||||
qDebug() << "[PayByCard] Payment successful!";
|
||||
m_error.clear();
|
||||
|
||||
// Сохраняем транзакцию в БД
|
||||
TransactionInfo tx;
|
||||
tx.accountId = m_account.id;
|
||||
tx.amount = -m_amount;
|
||||
tx.fee = fee;
|
||||
tx.phone = m_cardNumber;
|
||||
tx.bankName = "ozon";
|
||||
tx.type = TransactionType::Card;
|
||||
tx.status = TransactionStatus::Complete;
|
||||
tx.timestamp = DateUtils::getUtcNow();
|
||||
tx.completeTime = QDateTime::currentDateTime().toTimeZone(QTimeZone("Europe/Moscow"));
|
||||
tx.bankTime = tx.completeTime.toString("dd.MM.yyyy, HH:mm");
|
||||
const int txId = TransactionDAO::insertTransaction(tx);
|
||||
qDebug() << "[PayByCard] Saved transaction to DB, id:" << txId << "fee:" << fee;
|
||||
|
||||
// Ищем кнопку "Документы" и достаём ID операции
|
||||
Node docBtn = xmlScreenParser.findButtonNode("Документы", false);
|
||||
if (!docBtn.isEmpty() && txId != -1) {
|
||||
qDebug() << "[PayByCard] Tapping 'Документы'...";
|
||||
AdbUtils::makeTap(deviceId, docBtn.x(), docBtn.y());
|
||||
QThread::msleep(2000);
|
||||
|
||||
// Ждём появления кнопки "Поделиться"
|
||||
bool docLoaded = false;
|
||||
for (int da = 0; da < 20; ++da) {
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(deviceId, ++m_counter));
|
||||
Node shareBtn = xmlScreenParser.findNodeByContentDesc("Поделиться");
|
||||
if (!shareBtn.isEmpty()) {
|
||||
docLoaded = true;
|
||||
break;
|
||||
}
|
||||
qDebug() << "[PayByCard] Waiting for 'Поделиться', attempt" << da + 1 << "/ 20";
|
||||
QThread::msleep(1500);
|
||||
}
|
||||
|
||||
if (docLoaded) {
|
||||
QThread::msleep(500);
|
||||
const QByteArray screenshot = AdbUtils::captureScreenshotBytes(deviceId);
|
||||
if (!screenshot.isEmpty()) {
|
||||
TransactionDAO::updateReceiptImage(txId, screenshot);
|
||||
qDebug() << "[PayByCard] Receipt saved to DB, txId:" << txId;
|
||||
|
||||
const QString ocrText = recognizeTextFromImage(screenshot);
|
||||
if (!ocrText.isEmpty()) {
|
||||
qDebug() << "[PayByCard] OCR result:\n" << ocrText;
|
||||
const QString externalId = extractTransactionId(ocrText);
|
||||
if (!externalId.isEmpty()) {
|
||||
TransactionDAO::updateBankTrExternalId(txId, externalId);
|
||||
qDebug() << "[PayByCard] Extracted transaction ID:" << externalId;
|
||||
} else {
|
||||
qWarning() << "[PayByCard] Could not extract transaction ID from OCR text";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[PayByCard] OCR returned empty text";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[PayByCard] Screenshot is empty";
|
||||
}
|
||||
} else {
|
||||
qWarning() << "[PayByCard] 'Поделиться' not found, skipping receipt";
|
||||
}
|
||||
|
||||
AdbUtils::goBack(deviceId);
|
||||
QThread::msleep(1000);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!xmlScreenParser.findTextNode("Не удалось").isEmpty()) {
|
||||
m_error = "Перевод не удался (экран 'Не удалось')";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "[PayByCard] Waiting for payment result, attempt" << attempt + 1 << "/ 15";
|
||||
QThread::msleep(2000);
|
||||
}
|
||||
|
||||
m_error = "Не дождались результата перевода";
|
||||
qWarning() << "[PayByCard]" << m_error;
|
||||
}
|
||||
|
||||
} // namespace Ozon
|
||||
36
android/ozon/PayByCardScript.h
Normal file
36
android/ozon/PayByCardScript.h
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
#include "CommonScript.h"
|
||||
|
||||
namespace Ozon {
|
||||
|
||||
class PayByCardScript final : public CommonScript {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
~PayByCardScript() override;
|
||||
|
||||
PayByCardScript(
|
||||
AccountInfo account,
|
||||
QString cardNumber,
|
||||
double amount,
|
||||
QObject *parent = nullptr
|
||||
);
|
||||
|
||||
protected:
|
||||
void doStart() override;
|
||||
|
||||
private:
|
||||
const AccountInfo m_account;
|
||||
const QString m_cardNumber;
|
||||
const double m_amount;
|
||||
QString m_error;
|
||||
|
||||
void makePayment(
|
||||
const QString &deviceId,
|
||||
const QString &pinCode,
|
||||
int width,
|
||||
int height
|
||||
);
|
||||
};
|
||||
|
||||
} // namespace Ozon
|
||||
@ -142,6 +142,15 @@ Node ScreenXmlParser::findFirstEditText() {
|
||||
return {};
|
||||
}
|
||||
|
||||
Node ScreenXmlParser::findEditTextByHint(const QString &hintPrefix) {
|
||||
for (const Node &node : m_nodes) {
|
||||
if (node.className == "android.widget.EditText" && node.hint.contains(hintPrefix)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
Node ScreenXmlParser::findButtonNode(const QString &text, const bool contains) {
|
||||
for (const Node &node: m_nodes) {
|
||||
if (contains) {
|
||||
@ -591,6 +600,9 @@ void ScreenXmlParser::parseAndSaveXml(const QString &xml) {
|
||||
if (reader.attributes().hasAttribute("resource-id")) {
|
||||
node.resourceId = reader.attributes().value("resource-id").toString();
|
||||
}
|
||||
if (reader.attributes().hasAttribute("hint")) {
|
||||
node.hint = reader.attributes().value("hint").toString();
|
||||
}
|
||||
|
||||
m_nodes.append(node);
|
||||
}
|
||||
|
||||
@ -28,6 +28,8 @@ public:
|
||||
|
||||
Node findFirstEditText();
|
||||
|
||||
Node findEditTextByHint(const QString &hintPrefix);
|
||||
|
||||
Node findButtonNode(const QString &text, bool contains);
|
||||
|
||||
QList<Node> findAllButtons();
|
||||
|
||||
BIN
assets/ozon/pay/pay_by_card.png
Normal file
BIN
assets/ozon/pay/pay_by_card.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 100 KiB |
820
assets/ozon/pay/pay_by_card.xml
Normal file
820
assets/ozon/pay/pay_by_card.xml
Normal file
@ -0,0 +1,820 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>
|
||||
<hierarchy rotation="0">
|
||||
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false" long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,2400]" drawing-order="0" hint="">
|
||||
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false" long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,2400]" drawing-order="1" hint="">
|
||||
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false" long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,2400]" drawing-order="1" hint="">
|
||||
<node index="0" text="" resource-id="ru.ozon.fintech.finance:id/action_bar_root"
|
||||
class="android.widget.LinearLayout" package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false" clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false" long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,2400]" drawing-order="1" hint="">
|
||||
<node index="0" text="" resource-id="android:id/content" class="android.widget.FrameLayout"
|
||||
package="ru.ozon.fintech.finance" content-desc="" checkable="false" checked="false"
|
||||
clickable="false" enabled="true" focusable="false" focused="false" scrollable="false"
|
||||
long-clickable="false" password="false" selected="false" bounds="[0,0][1080,2400]"
|
||||
drawing-order="2" hint="">
|
||||
<node index="0" text="" resource-id="ru.ozon.fintech.finance:id/main_activity_top"
|
||||
class="android.widget.FrameLayout" package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false" clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false" long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2400]" drawing-order="1" hint="">
|
||||
<node index="1" text="" resource-id="ru.ozon.fintech.finance:id/over_host_fragment"
|
||||
class="android.widget.FrameLayout" package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false" clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false" long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2400]" drawing-order="4" hint="">
|
||||
<node index="0" text="" resource-id="ru.ozon.fintech.finance:id/over_fragment_top"
|
||||
class="android.widget.FrameLayout" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false" enabled="true"
|
||||
focusable="false" focused="false" scrollable="false" long-clickable="false"
|
||||
password="false" selected="false" bounds="[0,0][1080,2400]" drawing-order="1"
|
||||
hint=""/>
|
||||
</node>
|
||||
<node index="3" text="" resource-id="" class="android.view.ViewGroup"
|
||||
package="ru.ozon.fintech.finance" content-desc="" checkable="false" checked="false"
|
||||
clickable="false" enabled="true" focusable="false" focused="false" scrollable="false"
|
||||
long-clickable="false" password="false" selected="false" bounds="[0,0][1080,2400]"
|
||||
drawing-order="3" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id="ru.ozon.fintech.finance:id/main_activity_host_fragment"
|
||||
class="android.widget.FrameLayout" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false" enabled="true"
|
||||
focusable="false" focused="false" scrollable="false" long-clickable="false"
|
||||
password="false" selected="false" bounds="[0,0][1080,2400]" drawing-order="2"
|
||||
hint="">
|
||||
<node index="0" text=""
|
||||
resource-id="ru.ozon.fintech.finance:id/main_activity_host_fragment"
|
||||
class="android.widget.FrameLayout" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false"
|
||||
enabled="true" focusable="false" focused="false" scrollable="false"
|
||||
long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,2400]" drawing-order="1" hint="">
|
||||
<node index="0" text="" resource-id="ru.ozon.fintech.finance:id/web_view_top"
|
||||
class="android.view.ViewGroup" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false"
|
||||
enabled="true" focusable="false" focused="false" scrollable="false"
|
||||
long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,2400]" drawing-order="1" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id="ru.ozon.fintech.finance:id/web_view_holder"
|
||||
class="android.widget.FrameLayout" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false"
|
||||
enabled="true" focusable="false" focused="false" scrollable="false"
|
||||
long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,2337]" drawing-order="2" hint="">
|
||||
<node index="0" text="" resource-id=""
|
||||
class="android.widget.FrameLayout"
|
||||
package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false" clickable="false" enabled="true"
|
||||
focusable="false" focused="false" scrollable="false"
|
||||
long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,2337]" drawing-order="1" hint="">
|
||||
<node index="0" text="" resource-id=""
|
||||
class="android.webkit.WebView"
|
||||
package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false" clickable="false"
|
||||
enabled="true" focusable="false" focused="false"
|
||||
scrollable="false" long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]" drawing-order="0"
|
||||
hint="">
|
||||
<node index="0" text="⠀" resource-id=""
|
||||
class="android.webkit.WebView"
|
||||
package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false" clickable="false"
|
||||
enabled="true" focusable="true" focused="true"
|
||||
scrollable="false" long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text="" resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false" clickable="false"
|
||||
enabled="true" focusable="false" focused="false"
|
||||
scrollable="false" long-clickable="false"
|
||||
password="false" selected="false"
|
||||
bounds="[0,0][1080,2337]" drawing-order="0" hint="">
|
||||
<node index="0" text="" resource-id="svelte"
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false"
|
||||
clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text="" resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id="MFTransferByCardNumber@lk-pay"
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text="" resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false" selected="false"
|
||||
bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id="movable-pan-iframe"
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false" selected="false"
|
||||
bounds="[42,779][1039,942]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id="frame-container"
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="true"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,779][1039,929]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,779][1039,929]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id="svelte"
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,779][1039,929]"
|
||||
drawing-order="0"
|
||||
hint="">
|
||||
<node index="0" text=""
|
||||
resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,779][1039,929]"
|
||||
drawing-order="0"
|
||||
hint="">
|
||||
<node NAF="true"
|
||||
index="0"
|
||||
text=""
|
||||
resource-id=""
|
||||
class="android.widget.EditText"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="true"
|
||||
enabled="true"
|
||||
focusable="true"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[84,847][987,903]"
|
||||
drawing-order="0"
|
||||
hint="Номер карты получателя"/>
|
||||
<node index="1"
|
||||
text=""
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,779][1039,929]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
<node index="2"
|
||||
text="Номер карты получателя"
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[84,826][601,884]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
</node>
|
||||
<node index="1" text=""
|
||||
resource-id="svelte-announcer"
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,779][47,787]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node index="1" text="" resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false" selected="false"
|
||||
bounds="[0,0][1080,262]"
|
||||
drawing-order="0" hint="">
|
||||
<node NAF="true" index="0" text=""
|
||||
resource-id=""
|
||||
class="android.widget.Button"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="true"
|
||||
enabled="true"
|
||||
focusable="true"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[28,154][118,241]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="1"
|
||||
text="Перевод по номеру карты"
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[133,165][945,231]"
|
||||
drawing-order="0" hint=""/>
|
||||
</node>
|
||||
<node index="2" text="" resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false" selected="false"
|
||||
bounds="[0,259][1080,2337]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text="СЧЁТ СПИСАНИЯ"
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,343][1039,388]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="1" text=""
|
||||
resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,417][1039,606]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="true"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,417][231,606]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
<node index="1" text=""
|
||||
resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="true"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[231,417][1039,606]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0"
|
||||
text="1 037,50 ₽"
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[231,506][430,572]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
<node index="1"
|
||||
text="Основной счёт"
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[231,448][819,504]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
</node>
|
||||
<node index="2" text=""
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,417][1039,606]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
</node>
|
||||
<node index="2" text=""
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[0,601][1080,711]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="3" text="ПОЛУЧАТЕЛЬ"
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,706][1039,753]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="4" text=""
|
||||
resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,958][1039,1110]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[84,958][924,1110]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text=""
|
||||
resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[84,1005][924,1060]"
|
||||
drawing-order="0"
|
||||
hint="">
|
||||
<node NAF="true"
|
||||
index="0" text=""
|
||||
resource-id="input___eEQR_Pc"
|
||||
class="android.widget.EditText"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="true"
|
||||
enabled="true"
|
||||
focusable="true"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[84,1005][924,1060]"
|
||||
drawing-order="0"
|
||||
hint="Сумма от 100 ₽ до 500 000 ₽"/>
|
||||
</node>
|
||||
</node>
|
||||
<node NAF="true" index="1"
|
||||
text="" resource-id=""
|
||||
class="android.widget.Button"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="true"
|
||||
enabled="true"
|
||||
focusable="true"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[931,1000][997,1068]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
</node>
|
||||
<node index="5" text="Комиссия"
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[84,1168][997,1218]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="6"
|
||||
text="Рассчитаем после ввода всех данных"
|
||||
resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[84,1215][997,1281]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="7" text=""
|
||||
resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="false"
|
||||
enabled="true"
|
||||
focusable="false"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,2105][1039,2254]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text="Перевести"
|
||||
resource-id=""
|
||||
class="android.widget.Button"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc=""
|
||||
checkable="false"
|
||||
checked="false"
|
||||
clickable="true"
|
||||
enabled="true"
|
||||
focusable="true"
|
||||
focused="false"
|
||||
scrollable="false"
|
||||
long-clickable="false"
|
||||
password="false"
|
||||
selected="false"
|
||||
bounds="[42,2105][1039,2254]"
|
||||
drawing-order="0"
|
||||
hint=""/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node index="1" text=""
|
||||
resource-id="modal-container"
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,2336][1080,2336]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="2" text="⠀"
|
||||
resource-id="svelte-announcer"
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][5,5]"
|
||||
drawing-order="0" hint=""/>
|
||||
</node>
|
||||
<node index="1" text="" resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false"
|
||||
clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="2" text="" resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false"
|
||||
clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text="" resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="1" text="" resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint=""/>
|
||||
</node>
|
||||
<node index="3" text="" resource-id=""
|
||||
class="android.view.View"
|
||||
package="ru.ozon.fintech.finance" content-desc=""
|
||||
checkable="false" checked="false"
|
||||
clickable="false" enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint="">
|
||||
<node index="0" text="" resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint=""/>
|
||||
<node index="1" text="" resource-id=""
|
||||
class="android.widget.TextView"
|
||||
package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false"
|
||||
checked="false" clickable="false"
|
||||
enabled="true" focusable="false"
|
||||
focused="false" scrollable="false"
|
||||
long-clickable="false" password="false"
|
||||
selected="false" bounds="[0,0][1080,2337]"
|
||||
drawing-order="0" hint=""/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node index="1" text=""
|
||||
resource-id="ru.ozon.fintech.finance:id/web_view_toolbar"
|
||||
class="android.view.ViewGroup" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false"
|
||||
enabled="true" focusable="false" focused="false" scrollable="false"
|
||||
long-clickable="false" password="false" selected="false"
|
||||
bounds="[0,0][1080,147]" drawing-order="1" hint=""/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node index="1" text=""
|
||||
resource-id="ru.ozon.fintech.finance:id/main_activity_bottom_navigation_holder"
|
||||
class="android.widget.FrameLayout" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false" enabled="true"
|
||||
focusable="false" focused="false" scrollable="false" long-clickable="false"
|
||||
password="false" selected="false" bounds="[0,2201][1080,2400]" drawing-order="3"
|
||||
hint=""/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node index="1" text="" resource-id="" class="android.view.View" package="ru.ozon.fintech.finance"
|
||||
content-desc="" checkable="false" checked="false" clickable="false" enabled="true"
|
||||
focusable="false" focused="false" scrollable="false" long-clickable="false" password="false"
|
||||
selected="false" bounds="[818,0][1080,262]" drawing-order="2" hint=""/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</hierarchy>
|
||||
BIN
assets/ozon/pay/pay_by_card_enter_sum.png
Normal file
BIN
assets/ozon/pay/pay_by_card_enter_sum.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 156 KiB |
1
assets/ozon/pay/pay_by_card_enter_sum.xml
Normal file
1
assets/ozon/pay/pay_by_card_enter_sum.xml
Normal file
File diff suppressed because one or more lines are too long
BIN
assets/ozon/pay/pay_by_card_success.png
Normal file
BIN
assets/ozon/pay/pay_by_card_success.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 607 KiB |
1
assets/ozon/pay/pay_by_card_success.xml
Normal file
1
assets/ozon/pay/pay_by_card_success.xml
Normal file
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -42,6 +42,7 @@ public:
|
||||
QString contentDesc;
|
||||
QString resourceId;
|
||||
QString className;
|
||||
QString hint;
|
||||
bool clickable = false;
|
||||
bool focusable = false;
|
||||
|
||||
|
||||
@ -29,6 +29,7 @@
|
||||
#include "toss/LoginAndCheckAccountsTossScript.h"
|
||||
#include "ziraat/GetLastDaysHistoryZiraatScript.h"
|
||||
#include "ziraat/LoginAndCheckAccountsZiraatScript.h"
|
||||
#include "ozon/PayByCardScript.h"
|
||||
#include "ozon/PayByPhoneScript.h"
|
||||
#include "rshb/PayByPhoneScript.h"
|
||||
|
||||
@ -273,7 +274,9 @@ void EventHandler::updateEventThread(const QString &key, const EventInfo &event,
|
||||
txObj["transaction_type"] = (tx.type == TransactionType::Phone) ? "top-up" : "bank";
|
||||
txObj["bank_participator_id"]= tx.phone;
|
||||
txObj["status"] = tx.status == TransactionStatus::Complete ? "completed" : (tx.status == TransactionStatus::Wait ? "progress" : "completed");
|
||||
txObj["extra"] = QJsonObject();
|
||||
QJsonObject extraObj;
|
||||
extraObj["fee"] = static_cast<int>(tx.fee * 100);
|
||||
txObj["extra"] = extraObj;
|
||||
if (tx.timestamp.isValid()) {
|
||||
txObj["created_at"] = tx.timestamp.toTimeZone(QTimeZone("Europe/Moscow")).toString(Qt::ISODateWithMs);
|
||||
} else if (!tx.bankTime.isEmpty()) {
|
||||
@ -292,23 +295,33 @@ void EventHandler::updateEventThread(const QString &key, const EventInfo &event,
|
||||
}
|
||||
taskData = arr;
|
||||
} else if (event.type == EventType::CreateTransaction) {
|
||||
// Определяем тип транзакции из JSON задачи
|
||||
const QJsonObject taskJson = QJsonDocument::fromJson(event.json.toUtf8()).object();
|
||||
const QString txType = taskJson["body"].toObject()["transaction_type"].toString();
|
||||
|
||||
QJsonObject obj;
|
||||
obj["amount"] = -static_cast<int>(event.amount * 100);
|
||||
obj["currency"] = 643;
|
||||
obj["transaction_type"] = "top-up";
|
||||
obj["transaction_type"] = txType.isEmpty() ? "top-up" : txType;
|
||||
obj["bank_participator_id"]= event.phone;
|
||||
obj["status"] = "completed";
|
||||
obj["created_at"] = QDateTime::currentDateTime().toTimeZone(QTimeZone("Europe/Moscow")).toString(Qt::ISODateWithMs);
|
||||
|
||||
// Берём bank_transaction_id из последней сохранённой транзакции
|
||||
// Берём bank_transaction_id и fee из последней сохранённой транзакции
|
||||
QList<TransactionInfo> txList = TransactionDAO::getTransactionsWithinHours(event.accountId, 1);
|
||||
int feeInCents = 0;
|
||||
for (const auto &tx : txList) {
|
||||
if (!tx.bankTrExternalId.isEmpty() && qAbs(tx.amount) == event.amount && tx.phone == event.phone) {
|
||||
obj["bank_transaction_id"] = tx.bankTrExternalId;
|
||||
feeInCents = static_cast<int>(tx.fee * 100);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject extraObj;
|
||||
extraObj["fee"] = feeInCents;
|
||||
obj["extra"] = extraObj;
|
||||
|
||||
taskData = obj;
|
||||
} else {
|
||||
QJsonObject obj;
|
||||
@ -390,9 +403,21 @@ void EventHandler::startThreadForTask(const AccountInfo &account, const EventInf
|
||||
|
||||
if (event.type == EventType::CreateTransaction) {
|
||||
const QString recipientBank = event.comment; // резолвленное имя банка-получателя
|
||||
if (appCode == "ozon") setup(new Ozon::PayByPhoneScript(account, event.phone, recipientBank, event.amount));
|
||||
else if (appCode == "rshb") setup(new Rshb::PayByPhoneScript(account, event.phone, recipientBank, event.amount));
|
||||
else qWarning() << "[EventHandler] CREATE_TRANSACTION: unknown appCode:" << appCode;
|
||||
|
||||
// Определяем тип транзакции из JSON задачи
|
||||
const QJsonObject taskJson = QJsonDocument::fromJson(event.json.toUtf8()).object();
|
||||
const QString txType = taskJson["body"].toObject()["transaction_type"].toString();
|
||||
|
||||
if (txType == "bank") {
|
||||
// Перевод по номеру карты
|
||||
if (appCode == "ozon") setup(new Ozon::PayByCardScript(account, event.phone, event.amount));
|
||||
else qWarning() << "[EventHandler] CREATE_TRANSACTION bank: unknown appCode:" << appCode;
|
||||
} else {
|
||||
// Перевод по номеру телефона (top-up)
|
||||
if (appCode == "ozon") setup(new Ozon::PayByPhoneScript(account, event.phone, recipientBank, event.amount));
|
||||
else if (appCode == "rshb") setup(new Rshb::PayByPhoneScript(account, event.phone, recipientBank, event.amount));
|
||||
else qWarning() << "[EventHandler] CREATE_TRANSACTION: unknown appCode:" << appCode;
|
||||
}
|
||||
}
|
||||
|
||||
// // Watchdog-таймер: 5 минут — убиваем зависший поток
|
||||
|
||||
Loading…
Reference in New Issue
Block a user