Refactor ScreenXmlParser to handle transaction parsing
Enhanced transaction parsing by integrating QDomElement for XML handling and adding functions to parse transaction details, history, and metadata. Replaced raw QString operations with structured data extraction and improved formatting for date, amount, and bank information parsing.
This commit is contained in:
parent
a269de840b
commit
15a9e788eb
@ -7,8 +7,12 @@
|
||||
#include <QXmlStreamReader>
|
||||
#include <QDomDocument>
|
||||
#include <QFile>
|
||||
#include <QDateTime>
|
||||
#include <QTimeZone>
|
||||
|
||||
#include "adb/AdbUtils.h"
|
||||
#include "android/xml/Node.h"
|
||||
#include "db/TransactionInfo.h"
|
||||
|
||||
ScreenXmlParser::ScreenXmlParser(QObject *parent) : QObject(parent) {
|
||||
}
|
||||
@ -16,6 +20,16 @@ ScreenXmlParser::ScreenXmlParser(QObject *parent) : QObject(parent) {
|
||||
ScreenXmlParser::~ScreenXmlParser() = default;
|
||||
|
||||
static const QRegularExpression boundsRegex(R"(\[([0-9]+),([0-9]+)\]\[([0-9]+),([0-9]+)\])");
|
||||
static const QRegularExpression onlyDigitsRegex(R"([^0-9])");
|
||||
|
||||
static const QRegularExpression rePhone(R"raw((\+7\(?\d{3}\)?[- ]?\d{3}[- ]?\d{2}[- ]?\d{2}))raw");
|
||||
static const QRegularExpression reFromBank(R"raw(из (.+?) на)raw");
|
||||
static const QRegularExpression reToBank(R"raw(в (.+?) через)raw");
|
||||
static const QRegularExpression reSbpId(R"(СБП(?: С2С)? ([A-Z0-9]{30,}))");
|
||||
static const QRegularExpression reIdAlt(R"(ID перевода (\d+))");
|
||||
static const QRegularExpression reDate(R"((?:Дата операции|дата) (\d{2}\.\d{2}\.\d{4}(?: \d{2}:\d{2}:\d{2})?))");
|
||||
static const QRegularExpression reSender(R"(от ([^\(]+))");
|
||||
static const QRegularExpression reNameAlt(R"(Перевод ([А-Яа-яЁё\s\*]+) в)");
|
||||
|
||||
Node ScreenXmlParser::tryToFindBannerOrDialog(const int width, const int height) {
|
||||
// 1. Ищем push banner - он перекрывает весь экран
|
||||
@ -179,7 +193,9 @@ QList<Node> ScreenXmlParser::getLast2DaysTransactions() {
|
||||
selected="false" bounds="[952,159][1039,248]"/>
|
||||
*/
|
||||
void ScreenXmlParser::parseAndSaveXml(const QString &xml) {
|
||||
m_xml = xml;
|
||||
QDomDocument doc;
|
||||
doc.setContent(xml);
|
||||
m_xml = doc.documentElement();
|
||||
m_nodes.clear();
|
||||
|
||||
QXmlStreamReader reader(xml);
|
||||
@ -221,6 +237,95 @@ void ScreenXmlParser::parseAndSaveXml(const QString &xml) {
|
||||
}
|
||||
}
|
||||
|
||||
QString getDayOfWeekAsString(const int day_of_week) {
|
||||
switch (day_of_week) {
|
||||
case 1: return "понедельник";
|
||||
case 2: return "вторник";
|
||||
case 3: return "среда";
|
||||
case 4: return "четверг";
|
||||
case 5: return "пятница";
|
||||
case 6: return "суббота";
|
||||
case 7: return "воскресенье";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
QString getMonthAsString(const int month) {
|
||||
switch (month) {
|
||||
case 1: return "января";
|
||||
case 2: return "февраля";
|
||||
case 3: return "марта";
|
||||
case 4: return "апреля";
|
||||
case 5: return "мая";
|
||||
case 6: return "июня";
|
||||
case 7: return "июля";
|
||||
case 8: return "августа";
|
||||
case 9: return "сентября";
|
||||
case 10: return "октября";
|
||||
case 11: return "ноября";
|
||||
case 12: return "декабря";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
QString findSubInfo(const QDomElement &elem) {
|
||||
if (elem.hasChildNodes()) {
|
||||
QDomNodeList subInfoList = elem.childNodes();
|
||||
for (QDomNode subInfoNode: subInfoList) {
|
||||
if (!subInfoNode.isElement()) continue;
|
||||
QDomElement subInfo = subInfoNode.toElement();
|
||||
if (subInfo.attribute("index") == "1") {
|
||||
return subInfo.attribute("text");
|
||||
}
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool hasTimeComponent(const QString &datetimeStr) {
|
||||
QDateTime dt = QDateTime::fromString(datetimeStr, "dd.MM.yyyy HH:mm:ss");
|
||||
if (!dt.isValid()) {
|
||||
return false; // Строка не соответствует формату даты и времени
|
||||
}
|
||||
return dt.time() != QTime(0, 0, 0); // Проверка, что время не равно 00:00:00
|
||||
}
|
||||
|
||||
void parseTransferInfo(const QString &text, TransactionInfo &info) {
|
||||
if (const auto m = reSender.match(text); m.hasMatch()) {
|
||||
info.name = m.captured(1).trimmed();
|
||||
} else if (const auto m1 = reNameAlt.match(text); m1.hasMatch()) {
|
||||
info.name = m1.captured(1).trimmed();
|
||||
}
|
||||
|
||||
if (const auto m = rePhone.match(text); m.hasMatch()) {
|
||||
info.phone = m.captured(1).trimmed().remove(onlyDigitsRegex);
|
||||
}
|
||||
|
||||
if (const auto m = reFromBank.match(text); m.hasMatch()) {
|
||||
if (const QString bank = m.captured(1).trimmed(); !bank.isEmpty()) {
|
||||
info.bankName = bank;
|
||||
}
|
||||
} else if (const auto m1 = reToBank.match(text); m1.hasMatch()) {
|
||||
if (const QString bank = m1.captured(1).trimmed(); !bank.isEmpty()) {
|
||||
info.bankName = bank;
|
||||
}
|
||||
}
|
||||
|
||||
if (const auto m = reSbpId.match(text); m.hasMatch()) {
|
||||
info.trExternalId = m.captured(1);
|
||||
} else if (const auto m1 = reIdAlt.match(text); m1.hasMatch()) {
|
||||
info.trExternalId = m1.captured(1);
|
||||
}
|
||||
|
||||
if (const auto m = reDate.match(text); m.hasMatch()) {
|
||||
const QString date = m.captured(1);
|
||||
// если не пустая и дата у нас с 00:00
|
||||
if (hasTimeComponent(date)) {
|
||||
info.bankTime = date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void traverseNodes(const QDomNode &node) {
|
||||
if (node.isElement()) {
|
||||
QDomElement elem = node.toElement();
|
||||
@ -231,68 +336,85 @@ void traverseNodes(const QDomNode &node) {
|
||||
if (elem.tagName() == "node" &&
|
||||
elem.attribute("class") == "android.widget.Button" &&
|
||||
elem.attribute("text") == "Детали операции") {
|
||||
// Ищем сиблингов от текущего узла и далее
|
||||
QDomNodeList siblings = elem.parentNode().childNodes();
|
||||
|
||||
// Получение строки для анализа
|
||||
// QString xmlString;
|
||||
// QTextStream stream(&xmlString);
|
||||
// elem.parentNode().save(stream, 0);
|
||||
// qDebug() << xmlString;
|
||||
// return;
|
||||
|
||||
for (int j = 0; j < siblings.count(); ++j) {
|
||||
QDomNode sib = siblings.at(j);
|
||||
if (!sib.isElement()) continue;
|
||||
QDomElement sibElem = sib.toElement();
|
||||
// Все что ниже деталей операции
|
||||
QDomNodeList detailInfo = elem.parentNode().childNodes();
|
||||
|
||||
|
||||
qDebug() << "Node:"
|
||||
<< sibElem.attribute("index")
|
||||
<< sibElem.attribute("text");
|
||||
// << sibElem.attribute("class");
|
||||
|
||||
if (sibElem.hasChildNodes()) {
|
||||
QDomNodeList sibChildren = sibElem.childNodes();
|
||||
for (int k = 0; k < sibChildren.count(); ++k) {
|
||||
QDomNode sibChild = sibChildren.at(k);
|
||||
if (!sibChild.isElement()) continue;
|
||||
QDomElement sibChildElem = sibChild.toElement();
|
||||
qDebug() << "... Node:"
|
||||
<< sibChildElem.attribute("index")
|
||||
<< sibChildElem.attribute("text");
|
||||
// << sibChildElem.attribute("class");
|
||||
|
||||
|
||||
if (sibChildElem.hasChildNodes()) {
|
||||
QDomNodeList sibChildren2 = sibChildElem.childNodes();
|
||||
for (int k = 0; k < sibChildren2.count(); ++k) {
|
||||
QDomNode sibChild2 = sibChildren2.at(k);
|
||||
if (!sibChild2.isElement()) continue;
|
||||
QDomElement sibChildElem2 = sibChild2.toElement();
|
||||
|
||||
qDebug() << "...... Node:"
|
||||
<< sibChildElem2.attribute("index")
|
||||
<< sibChildElem2.attribute("text");
|
||||
// << sibChildElem2.attribute("class");
|
||||
|
||||
if (sibChildElem2.hasChildNodes()) {
|
||||
QDomNodeList sibChildren3 = sibChildElem2.childNodes();
|
||||
for (int k = 0; k < sibChildren3.count(); ++k) {
|
||||
QDomNode sibChild3 = sibChildren3.at(k);
|
||||
if (!sibChild3.isElement()) continue;
|
||||
QDomElement sibChildElem3 = sibChild3.toElement();
|
||||
|
||||
qDebug() << "......... Node:"
|
||||
<< sibChildElem3.attribute("index")
|
||||
<< sibChildElem3.attribute("text");
|
||||
// << sibChildElem2.attribute("class");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int j = 0; j < detailInfo.count(); ++j) {
|
||||
QDomNode info = detailInfo.at(j);
|
||||
if (!info.isElement()) continue;
|
||||
QDomElement infoElement = info.toElement();
|
||||
QString index = infoElement.attribute("index");
|
||||
switch (index.toInt()) {
|
||||
case 2:
|
||||
qDebug() << "Дата операции:" << findSubInfo(infoElement);
|
||||
continue;
|
||||
case 5:
|
||||
qDebug() << "Название:" << findSubInfo(infoElement);
|
||||
qDebug() << "-------------------------------------";
|
||||
// parseTransfer(findSubInfo(infoElement));
|
||||
continue;
|
||||
case 7:
|
||||
qDebug() << "Комиссия:" << findSubInfo(infoElement);;
|
||||
continue;
|
||||
default:
|
||||
qDebug() << "Прочее:" << findSubInfo(infoElement);;
|
||||
continue;
|
||||
}
|
||||
|
||||
/**
|
||||
Node: "2" ""
|
||||
... Node: "0" "Дата операции"
|
||||
... Node: "1" "30.04.2025 17:46:29"
|
||||
Node: "5" ""
|
||||
... Node: "0" "Название"
|
||||
... Node: "1" "DBO TRANSFER RSHB INTERNET-BANK"
|
||||
Node: "7" ""
|
||||
... Node: "0" "Комиссия"
|
||||
... Node: "1" "50 ₽"
|
||||
*/
|
||||
|
||||
// if (sibElem.hasChildNodes()) {
|
||||
// QDomNodeList sibChildren = sibElem.childNodes();
|
||||
// for (int k = 0; k < sibChildren.count(); ++k) {
|
||||
// QDomNode sibChild = sibChildren.at(k);
|
||||
// if (!sibChild.isElement()) continue;
|
||||
// QDomElement sibChildElem = sibChild.toElement();
|
||||
// qDebug() << "... Node:"
|
||||
// << sibChildElem.attribute("index")
|
||||
// << sibChildElem.attribute("text");
|
||||
// // << sibChildElem.attribute("class");
|
||||
//
|
||||
//
|
||||
// if (sibChildElem.hasChildNodes()) {
|
||||
// QDomNodeList sibChildren2 = sibChildElem.childNodes();
|
||||
// for (int k = 0; k < sibChildren2.count(); ++k) {
|
||||
// QDomNode sibChild2 = sibChildren2.at(k);
|
||||
// if (!sibChild2.isElement()) continue;
|
||||
// QDomElement sibChildElem2 = sibChild2.toElement();
|
||||
//
|
||||
// qDebug() << "...... Node:"
|
||||
// << sibChildElem2.attribute("index")
|
||||
// << sibChildElem2.attribute("text");
|
||||
// // << sibChildElem2.attribute("class");
|
||||
//
|
||||
// if (sibChildElem2.hasChildNodes()) {
|
||||
// QDomNodeList sibChildren3 = sibChildElem2.childNodes();
|
||||
// for (int k = 0; k < sibChildren3.count(); ++k) {
|
||||
// QDomNode sibChild3 = sibChildren3.at(k);
|
||||
// if (!sibChild3.isElement()) continue;
|
||||
// QDomElement sibChildElem3 = sibChild3.toElement();
|
||||
//
|
||||
// qDebug() << "......... Node:"
|
||||
// << sibChildElem3.attribute("index")
|
||||
// << sibChildElem3.attribute("text");
|
||||
// // << sibChildElem2.attribute("class");
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -306,8 +428,286 @@ void traverseNodes(const QDomNode &node) {
|
||||
}
|
||||
}
|
||||
|
||||
QDomNode findNode(const QDomNode &node, const QString &text) {
|
||||
if (node.isElement()) {
|
||||
QString nodeText = node.toElement().attribute("text");
|
||||
if (nodeText.toLower().startsWith(text)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
QDomNode child = node.firstChild();
|
||||
while (!child.isNull()) {
|
||||
QDomNode result = findNode(child, text);
|
||||
if (!result.isNull()) {
|
||||
return result;
|
||||
}
|
||||
child = child.nextSibling();
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
float extractAmounts(const QString &text) {
|
||||
// Разрешаем пробелы внутри чисел, захватываем "рубль", "рубля", "рублей" и т.д.
|
||||
// QRegularExpression re(R"((Плюс|Минус)\s+([\d\s]+)\s+рубл\w*\s+(\d+)\s+копе\w*)");
|
||||
QRegularExpression re(
|
||||
R"((Плюс|Минус)\s+([\d\s]+)\s+рубл\w*\s+(\d+)\s+копе\w*)",
|
||||
QRegularExpression::UseUnicodePropertiesOption
|
||||
);
|
||||
|
||||
QRegularExpressionMatch match = re.match(text);
|
||||
if (match.hasMatch()) {
|
||||
QString signStr = match.captured(1); // "Плюс" или "Минус"
|
||||
QString rublesStr = match.captured(2).remove(' '); // "1 000" → "1000"
|
||||
int rubles = rublesStr.toInt();
|
||||
int kopecks = match.captured(3).toInt();
|
||||
|
||||
int totalKopecks = rubles * 100 + kopecks;
|
||||
if (signStr == "Минус") {
|
||||
totalKopecks *= -1;
|
||||
}
|
||||
|
||||
return totalKopecks / 100.0f;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
QString beforeAmount(const QString &text) {
|
||||
int index = text.indexOf(QRegularExpression("Плюс|Минус"));
|
||||
if (index != -1) {
|
||||
return text.left(index).trimmed();
|
||||
}
|
||||
return text; // если не найдено — вернуть всю строку
|
||||
}
|
||||
|
||||
QList<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayHistory() {
|
||||
QTimeZone tz("Europe/Moscow");
|
||||
QDate today = QDateTime::currentDateTime(tz).date();
|
||||
QDate yesterday = today.addDays(-1);
|
||||
QDate beforeYesterday = today.addDays(-2);
|
||||
|
||||
|
||||
QString todayTitle = QString("сегодня, %1").arg(getDayOfWeekAsString(today.dayOfWeek()));
|
||||
QString yesterdayTitle = QString("вчера, %1").arg(getDayOfWeekAsString(yesterday.dayOfWeek()));
|
||||
QString beforeYesterdayTitle = QString("%1 %2, %3").arg(
|
||||
QString::number(beforeYesterday.day()),
|
||||
getMonthAsString(beforeYesterday.month()),
|
||||
getDayOfWeekAsString(beforeYesterday.dayOfWeek())
|
||||
);
|
||||
|
||||
QDomNode todayNode = findNode(m_xml, todayTitle);
|
||||
QDomNode yesterdayNode = findNode(m_xml, yesterdayTitle);
|
||||
|
||||
QDomNode parentNode;
|
||||
if (!yesterdayNode.isNull()) {
|
||||
parentNode = yesterdayNode.parentNode();
|
||||
} else if (!todayNode.isNull()) {
|
||||
parentNode = todayNode.parentNode();
|
||||
}
|
||||
|
||||
|
||||
QList<TransactionInfo> transactions;
|
||||
if (!parentNode.isNull()) {
|
||||
for (QDomNode transactionNode: parentNode.childNodes()) {
|
||||
QString transactionShortText = transactionNode.toElement().attribute("text");
|
||||
|
||||
const QString titleLowerCase = transactionShortText.toLower();
|
||||
if (titleLowerCase.startsWith(beforeYesterdayTitle)) {
|
||||
// только сегодня и вчера парсим, позавчера не трогаем
|
||||
break;
|
||||
}
|
||||
|
||||
QDate date = {};
|
||||
if (titleLowerCase.startsWith(todayTitle)) {
|
||||
date = today;
|
||||
transactionShortText = transactionShortText.mid(todayTitle.length() + 1);
|
||||
}
|
||||
if (titleLowerCase.startsWith(yesterdayTitle)) {
|
||||
date = yesterday;
|
||||
transactionShortText = transactionShortText.mid(yesterdayTitle.length() + 1);
|
||||
}
|
||||
|
||||
if (transactionShortText.contains("ЕСПП")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float amount = extractAmounts(transactionShortText);
|
||||
QString shortDesc = beforeAmount(transactionShortText);
|
||||
|
||||
TransactionInfo info;
|
||||
info.amount = amount;
|
||||
info.bankTime = date.toString("dd.MM.yyyy");
|
||||
info.shortDescription = shortDesc;
|
||||
|
||||
transactions.append(info);
|
||||
}
|
||||
}
|
||||
return transactions;
|
||||
}
|
||||
|
||||
void parse2daysHistory(const QDomNode &node) {
|
||||
QTimeZone tz("Europe/Moscow");
|
||||
QDate today = QDateTime::currentDateTime(tz).date();
|
||||
QDate tomorrow = today.addDays(-1);
|
||||
QDate after2Days = today.addDays(-2);
|
||||
|
||||
QString todayTitle = QString("сегодня, %1").arg(getDayOfWeekAsString(today.dayOfWeek()));
|
||||
QDomNode todayNode = findNode(node, todayTitle);
|
||||
if (todayNode.isNull()) {
|
||||
} else {
|
||||
qDebug() << "todayNode: " << todayNode.toElement().attribute("text");
|
||||
}
|
||||
|
||||
QString tomorrowTitle = QString("вчера, %1").arg(getDayOfWeekAsString(tomorrow.dayOfWeek()));
|
||||
QDomNode tomorrowNode = findNode(node, tomorrowTitle);
|
||||
if (tomorrowNode.isNull()) {
|
||||
} else {
|
||||
qDebug() << "tomorrowNode: " << tomorrowNode.toElement().attribute("text");
|
||||
}
|
||||
|
||||
// 30 апреля, Среда
|
||||
QString after2DaysTitle = QString("%1 %2, %3").arg(
|
||||
QString::number(after2Days.day()),
|
||||
getMonthAsString(after2Days.month()),
|
||||
getDayOfWeekAsString(after2Days.dayOfWeek()));
|
||||
QDomNode after2DaysNode = findNode(node, after2DaysTitle);
|
||||
if (after2DaysNode.isNull()) {
|
||||
qDebug() << "No after2DaysNode";
|
||||
} else {
|
||||
qDebug() << "after2DaysNode: " << after2DaysNode.toElement().attribute("text");
|
||||
}
|
||||
|
||||
QDomNode parentNode;
|
||||
if (!todayNode.isNull() || !tomorrowNode.isNull() || !after2DaysNode.isNull()) {
|
||||
if (!todayNode.isNull()) {
|
||||
parentNode = todayNode.parentNode();
|
||||
}
|
||||
if (!tomorrowNode.isNull()) {
|
||||
parentNode = tomorrowNode.parentNode();
|
||||
}
|
||||
if (!after2DaysNode.isNull()) {
|
||||
parentNode = after2DaysNode.parentNode();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!parentNode.isNull()) {
|
||||
for (QDomNode child_node: parentNode.childNodes()) {
|
||||
QString child_text = child_node.toElement().attribute("text");
|
||||
if (child_text.toLower().startsWith(todayTitle)) {
|
||||
qDebug() << "=== Today: " << todayTitle;
|
||||
qDebug() << "node: " << beforeAmount(child_text.mid(todayTitle.length() + 1));
|
||||
qDebug() << "--> sum: " << QString::number(extractAmounts(child_text), 'f', 2);
|
||||
// qDebug() << "";
|
||||
continue;
|
||||
}
|
||||
if (child_text.toLower().startsWith(tomorrowTitle)) {
|
||||
qDebug() << "=== Yesterday: " << todayTitle;
|
||||
qDebug() << "node: " << beforeAmount(child_text.mid(tomorrowTitle.length() + 1));
|
||||
qDebug() << "--> sum: " << QString::number(extractAmounts(child_text), 'f', 2);
|
||||
// qDebug() << "";
|
||||
continue;
|
||||
}
|
||||
if (child_text.toLower().startsWith(after2DaysTitle)) {
|
||||
qDebug() << "=== Before yesterday: " << todayTitle;
|
||||
qDebug() << "node: " << beforeAmount(child_text.mid(after2DaysTitle.length() + 1));
|
||||
qDebug() << "--> sum: " << QString::number(extractAmounts(child_text), 'f', 2);
|
||||
// qDebug() << "";
|
||||
continue;
|
||||
}
|
||||
|
||||
qDebug() << "node: " << beforeAmount(child_node.toElement().attribute("text"));
|
||||
qDebug() << "--> sum: " <<
|
||||
QString::number(extractAmounts(child_node.toElement().attribute("text")), 'f', 2);
|
||||
// qDebug() << "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// QString d = today.day() > 9 ? QString::number(today.day()) : "0" + QString::number(today.day());
|
||||
// QString m = today.month() > 9 ? QString::number(today.month()) : "0" + QString::number(today.month());
|
||||
// QString y = QString::number(today.year());
|
||||
// QString w = getDayOfWeekAsString(today.dayOfWeek());
|
||||
// QString mm = getMonthAsString(today.month());
|
||||
// qDebug() << "Date:" << d << m << y << w << mm;
|
||||
|
||||
|
||||
// QString d2 = after2Days.day() > 9 ? QString::number(after2Days.day()) : "0" + QString::number(after2Days.day());
|
||||
// QString m2 = after2Days.month() > 9
|
||||
// ? QString::number(after2Days.month())
|
||||
// : "0" + QString::number(after2Days.month());
|
||||
// QString y2 = QString::number(after2Days.year());
|
||||
// QString w2 = getDayOfWeekAsString(after2Days.dayOfWeek());
|
||||
// QString mm2 = getMonthAsString(after2Days.month());
|
||||
// qDebug() << "Date:" << d2 << m2 << y2 << w2 << mm2;
|
||||
}
|
||||
|
||||
TransactionInfo parseExpandedInfoHistory(const QDomElement &root) {
|
||||
if (root.isElement()) {
|
||||
QDomElement elem = root.toElement();
|
||||
if (elem.tagName() == "node"
|
||||
&& elem.attribute("class") == "android.widget.Button"
|
||||
&& elem.attribute("text") == "Детали операции"
|
||||
) {
|
||||
TransactionInfo transaction;
|
||||
// Все что ниже деталей операции
|
||||
QDomNodeList detailInfo = elem.parentNode().childNodes();
|
||||
|
||||
for (int i = 0; i < detailInfo.count(); ++i) {
|
||||
QDomNode info = detailInfo.at(i);
|
||||
if (!info.isElement()) continue;
|
||||
|
||||
switch (QDomElement e = info.toElement(); e.attribute("index").toInt()) {
|
||||
case 2:
|
||||
// Дата операции
|
||||
transaction.bankTime = findSubInfo(e);
|
||||
break;
|
||||
case 5:
|
||||
transaction.description = findSubInfo(e);
|
||||
parseTransferInfo(transaction.description, transaction);
|
||||
break;
|
||||
case 7:
|
||||
// Комиссия
|
||||
transaction.fee = findSubInfo(e).remove(onlyDigitsRegex).toFloat();
|
||||
break;
|
||||
default:
|
||||
// qDebug() << "Прочее:" << findSubInfo(e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
}
|
||||
|
||||
// Рекурсивно обходим всех детей
|
||||
QDomNode child = root.firstChild();
|
||||
while (!child.isNull()) {
|
||||
if (TransactionInfo info = parseExpandedInfoHistory(child.toElement()); !info.bankTime.isEmpty()) {
|
||||
return info;
|
||||
}
|
||||
child = child.nextSibling();
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
TransactionInfo ScreenXmlParser::parseTransactionInfoHistory(int screenWidth, int screenHeight) {
|
||||
// 1. Распарсить описание транзакции
|
||||
TransactionInfo transaction = parseExpandedInfoHistory(m_xml);
|
||||
// 1. Найти статус: Исполнен | Операция исполнена
|
||||
transaction.status = TransactionStatus::Wait;
|
||||
Node status1 = findTextNode("Исполнен", 0, 0, screenWidth, screenHeight / 2);
|
||||
Node status2 = findTextNode("Операция исполнена", 0, 0, screenWidth, screenHeight / 2);
|
||||
if (!status1.isEmpty() || !status2.isEmpty()) {
|
||||
transaction.status = TransactionStatus::Complete;
|
||||
}
|
||||
return transaction;
|
||||
}
|
||||
|
||||
void ScreenXmlParser::test() {
|
||||
QFile file("assets/rshb/pay/pay_by_phone_history_expanded.xml");
|
||||
return;
|
||||
QFile file("assets/rshb/test/spb_test_send.xml");
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qDebug() << "Cannot open file";
|
||||
}
|
||||
@ -321,5 +721,5 @@ void ScreenXmlParser::test() {
|
||||
qDebug() << "Start parsing XML:";
|
||||
|
||||
QDomElement root = doc.documentElement();
|
||||
traverseNodes(root);
|
||||
// ЕСПП
|
||||
}
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QDomElement>
|
||||
#include "android/xml/Node.h"
|
||||
#include "db/TransactionInfo.h"
|
||||
|
||||
class ScreenXmlParser final : public QObject {
|
||||
Q_OBJECT
|
||||
@ -31,11 +33,14 @@ public:
|
||||
|
||||
void parseAndSaveXml(const QString &xml);
|
||||
|
||||
TransactionInfo parseTransactionInfoHistory(int screenWidth, int screenHeight);
|
||||
QList<TransactionInfo> parseTodayAndYesterdayHistory();
|
||||
|
||||
void test();
|
||||
|
||||
private:
|
||||
QList<Node> m_nodes;
|
||||
QString m_xml;
|
||||
QDomElement m_xml;
|
||||
|
||||
QList<Node> findPinCodeNodes(const QString &pinCode);
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user