Improve GetLastTransactionsScript to parse bottom-sheet transaction details for version 3.2.33. Add parseDushanbeAmount for enhanced number extraction.
This commit is contained in:
parent
8f7bc16090
commit
790b0b1847
@ -2,6 +2,7 @@
|
||||
|
||||
#include <QJsonDocument>
|
||||
#include <QRegularExpression>
|
||||
#include <QSet>
|
||||
#include <QThread>
|
||||
#include <QTimeZone>
|
||||
|
||||
@ -16,6 +17,24 @@
|
||||
#include "AppLogger.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
|
||||
// Душанбе показывает суммы как "100,50", "100.50 TJS", "1 000,50",
|
||||
// "1 000.50 TJS" и т.п. Голый QString::toDouble на таком вернёт 0,
|
||||
// потому что требует, чтобы вся строка была валидным числом.
|
||||
static double parseDushanbeAmount(const QString &raw) {
|
||||
QString s = raw;
|
||||
s.remove(QRegularExpression(R"([^\d,.\-])"));
|
||||
s.replace(',', '.');
|
||||
const int firstDot = s.indexOf('.');
|
||||
if (firstDot >= 0) {
|
||||
QString head = s.left(firstDot);
|
||||
QString tail = s.mid(firstDot + 1);
|
||||
tail.remove('.');
|
||||
s = head + '.' + tail;
|
||||
}
|
||||
return s.toDouble();
|
||||
}
|
||||
|
||||
static QString recognizeTextFromImage(const QByteArray &pngData) {
|
||||
auto *api = new tesseract::TessBaseAPI();
|
||||
if (api->Init(QCoreApplication::applicationDirPath().toUtf8().constData(), "rus+eng")) {
|
||||
@ -649,9 +668,72 @@ void GetLastTransactionsScript::doStart() {
|
||||
if (interrupted()) { m_error = "Interrupted"; emit finishedWithResult(m_error); return; }
|
||||
xmlScreenParser.parseAndSaveXml(AdbUtils::getScreenDumpAsXml(m_deviceId, ++m_counter));
|
||||
closeGooglePlayBannerIfVisible(m_deviceId, device.screenWidth, device.screenHeight);
|
||||
// 1) Старый blob-формат (до 3.2.33): "Успешный платеж" / "Поступление" —
|
||||
// одна нода с ключами и значениями через \n.
|
||||
// 1) Bottom-sheet формат (3.2.33, см. assets/dushanbe/3.2.33/tx_detail.xml):
|
||||
// одна нода со всем content-desc через \n. Лейблы без двоеточий, сумма —
|
||||
// отдельной строкой со знаком сразу после даты+времени.
|
||||
// "Успешный платёж\n21.05.2026 16:58:32\n-10\nКарта\n...\nПолучатель\n...\nЗакрыть"
|
||||
for (const Node &n : xmlScreenParser.findAllNodes()) {
|
||||
const QString cd = n.contentDesc;
|
||||
if (!cd.contains(QString::fromUtf8("Карта"))) continue;
|
||||
if (!cd.contains(QString::fromUtf8("Получатель"))) continue;
|
||||
if (!cd.contains(QString::fromUtf8("Операция"))) continue;
|
||||
const QStringList lines = cd.split('\n', Qt::SkipEmptyParts);
|
||||
if (lines.size() < 6) continue;
|
||||
|
||||
// lines[0] — заголовок: "Успешный платёж" / "Поступление" / ...
|
||||
if (lines[0].contains(QString::fromUtf8("Успешн"))
|
||||
|| lines[0].contains(QString::fromUtf8("Поступление"))
|
||||
|| lines[0].contains(QString::fromUtf8("выполнен"))) {
|
||||
detail.status = QString::fromUtf8("Успешный");
|
||||
}
|
||||
// lines[1] — "dd.MM.yyyy HH:mm:ss"
|
||||
{
|
||||
static const QRegularExpression reDt(
|
||||
R"((\d{2}\.\d{2}\.\d{4})\s+(\d{2}:\d{2}:\d{2}))");
|
||||
const auto m = reDt.match(lines[1]);
|
||||
if (m.hasMatch()) {
|
||||
detail.date = m.captured(1);
|
||||
detail.time = m.captured(2);
|
||||
}
|
||||
}
|
||||
// lines[2] — сумма со знаком: "-10" / "30" / "30.50" / "1 000,50".
|
||||
detail.amount = parseDushanbeAmount(lines[2]);
|
||||
|
||||
// Дальше — пары label/value; значение может быть multi-line (Получатель).
|
||||
// На сервер шлём первую строку получателя — таков сложившийся контракт.
|
||||
static const QSet<QString> labels{
|
||||
QString::fromUtf8("Карта"),
|
||||
QString::fromUtf8("Получатель"),
|
||||
QString::fromUtf8("Операция"),
|
||||
QString::fromUtf8("Дата"),
|
||||
QString::fromUtf8("Время"),
|
||||
QString::fromUtf8("Закрыть"),
|
||||
QString::fromUtf8("Назад"),
|
||||
};
|
||||
for (int i = 3; i < lines.size(); ++i) {
|
||||
const QString lbl = lines[i].trimmed();
|
||||
if (!labels.contains(lbl)) continue;
|
||||
QStringList vals;
|
||||
for (int j = i + 1; j < lines.size(); ++j) {
|
||||
const QString cand = lines[j].trimmed();
|
||||
if (labels.contains(cand)) break;
|
||||
vals << cand;
|
||||
}
|
||||
if (vals.isEmpty()) continue;
|
||||
if (lbl == QString::fromUtf8("Получатель")) {
|
||||
detail.receiverAccount = vals.first();
|
||||
} else if (lbl == QString::fromUtf8("Дата") && detail.date.isEmpty()) {
|
||||
detail.date = vals.first();
|
||||
} else if (lbl == QString::fromUtf8("Время") && detail.time.isEmpty()) {
|
||||
detail.time = vals.first();
|
||||
}
|
||||
}
|
||||
detailLoaded = true;
|
||||
break;
|
||||
}
|
||||
// 2) Старый blob-формат (до 3.2.33): "Успешный платеж" / "Поступление" —
|
||||
// одна нода с ключами и значениями через \n.
|
||||
if (!detailLoaded) for (const Node &n : xmlScreenParser.findAllNodes()) {
|
||||
if (!n.contentDesc.contains(QString::fromUtf8("Дата"))) continue;
|
||||
if (!n.contentDesc.contains(QString::fromUtf8("Время"))) continue;
|
||||
const QStringList lines = n.contentDesc.split('\n');
|
||||
@ -663,7 +745,7 @@ void GetLastTransactionsScript::doStart() {
|
||||
if (key == QString::fromUtf8("Получатель")) {
|
||||
detail.receiverAccount = val;
|
||||
} else if (key == QString::fromUtf8("Сумма")) {
|
||||
detail.amount = val.toDouble();
|
||||
detail.amount = parseDushanbeAmount(val);
|
||||
} else if (key == QString::fromUtf8("Дата")) {
|
||||
detail.date = val;
|
||||
} else if (key == QString::fromUtf8("Время")) {
|
||||
@ -673,7 +755,8 @@ void GetLastTransactionsScript::doStart() {
|
||||
detailLoaded = true;
|
||||
break;
|
||||
}
|
||||
// 2) Новый split-формат (с 3.2.33): лейблы и значения в отдельных View-нодах.
|
||||
// 3) Split-формат: лейблы (с ':') и значения в отдельных View-нодах
|
||||
// на одной Y-полосе. Промежуточная версия между blob и bottom-sheet.
|
||||
if (!detailLoaded) {
|
||||
const QMap<QString, QString> pairs = xmlScreenParser.parseLabelValuePairs();
|
||||
const QString d = pairs.value(QString::fromUtf8("Дата"));
|
||||
@ -682,11 +765,11 @@ void GetLastTransactionsScript::doStart() {
|
||||
detail.date = d;
|
||||
detail.time = t;
|
||||
detail.receiverAccount = pairs.value(QString::fromUtf8("Получатель"));
|
||||
detail.amount = pairs.value(QString::fromUtf8("Сумма")).toDouble();
|
||||
detail.amount = parseDushanbeAmount(pairs.value(QString::fromUtf8("Сумма")));
|
||||
if (detail.amount == 0.0) {
|
||||
detail.amount = pairs.value(QString::fromUtf8("К зачислению")).toDouble();
|
||||
detail.amount = parseDushanbeAmount(pairs.value(QString::fromUtf8("К зачислению")));
|
||||
}
|
||||
detail.fee = pairs.value(QString::fromUtf8("Комиссия")).toDouble();
|
||||
detail.fee = parseDushanbeAmount(pairs.value(QString::fromUtf8("Комиссия")));
|
||||
detail.operationId = pairs.value(QString::fromUtf8("Номер операции"));
|
||||
detail.status = pairs.value(QString::fromUtf8("Статус"));
|
||||
detailLoaded = true;
|
||||
|
||||
BIN
assets/dushanbe/3.2.33/tx_detail.jpg
Normal file
BIN
assets/dushanbe/3.2.33/tx_detail.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
1
assets/dushanbe/3.2.33/tx_detail.xml
Normal file
1
assets/dushanbe/3.2.33/tx_detail.xml
Normal file
@ -0,0 +1 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes' ?><hierarchy rotation="0"><node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="tj.dc.next1" 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][720,1640]"><node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="tj.dc.next1" 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][720,1640]"><node index="0" text="" resource-id="android:id/content" class="android.widget.FrameLayout" package="tj.dc.next1" 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][720,1640]"><node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="tj.dc.next1" 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][720,1640]"><node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="tj.dc.next1" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][720,1640]"><node index="0" text="" resource-id="" class="android.view.View" package="tj.dc.next1" 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][720,1640]"><node index="0" text="" resource-id="" class="android.view.View" package="tj.dc.next1" 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][720,1640]"><node index="0" text="" resource-id="" class="android.view.View" package="tj.dc.next1" 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][720,1640]"><node index="0" text="" resource-id="" class="android.view.View" package="tj.dc.next1" 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][720,1640]"><node index="0" text="" resource-id="" class="android.widget.ImageView" package="tj.dc.next1" content-desc="Успешный платёж 21.05.2026 16:58:32 -10 Карта 9762 0002 2091 6042 Получатель DCWallet*WDC0000**TAJIKISTAN 992176827668-9762000191282739- Операция Дебетная часть P2P/операции Дата 21.05.2026 Время 16:58:32 Закрыть" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" bounds="[0,0][720,1640]"><node index="0" text="" resource-id="" class="android.view.View" package="tj.dc.next1" 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][720,1640]" /></node></node></node><node index="1" text="" resource-id="" class="android.view.View" package="tj.dc.next1" content-desc="Закрыть" checkable="false" checked="false" clickable="true" enabled="true" focusable="true" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][720,1640]" /></node></node></node></node></node></node><node index="1" text="" resource-id="android:id/navigationBarBackground" class="android.view.View" package="tj.dc.next1" 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,1544][720,1640]" /></node></hierarchy>
|
||||
Loading…
Reference in New Issue
Block a user