From 6d60cecef4607f02a3556819d61327d0a7d36eaa Mon Sep 17 00:00:00 2001 From: slava Date: Mon, 1 Jun 2026 22:27:34 +0500 Subject: [PATCH] Add configurable date search window for transaction history parsing. --- android/BankConfigUtils.cpp | 13 ++++ android/BankConfigUtils.h | 15 ++++ .../dushanbe/GetLastTransactionsScript.cpp | 50 ++++++------ android/ozon/ScreenXmlParser.cpp | 76 ++++++++++++------- config.ini | 4 + 5 files changed, 106 insertions(+), 52 deletions(-) create mode 100644 android/BankConfigUtils.cpp create mode 100644 android/BankConfigUtils.h diff --git a/android/BankConfigUtils.cpp b/android/BankConfigUtils.cpp new file mode 100644 index 0000000..b36a01f --- /dev/null +++ b/android/BankConfigUtils.cpp @@ -0,0 +1,13 @@ +#include "BankConfigUtils.h" + +#include + +namespace BankConfigUtils { + +int transactionSearchWindowDays(const QString &bankCode) { + const QSettings settings("config.ini", QSettings::IniFormat); + return qMax(1, settings.value( + bankCode + "/transaction_search_window_days", 2).toInt()); +} + +} // namespace BankConfigUtils diff --git a/android/BankConfigUtils.h b/android/BankConfigUtils.h new file mode 100644 index 0000000..d8be753 --- /dev/null +++ b/android/BankConfigUtils.h @@ -0,0 +1,15 @@ +#pragma once + +#include + +// Пер-банковые настройки, читаемые из config.ini. +// bankCode совпадает с именем секции в config.ini и со значением appCode +// ("ozon", "black", "dushanbe_city_bank"). +namespace BankConfigUtils { + +// Окно поиска транзакций в днях: сегодня + (N-1) предыдущих дней. +// Источник: config.ini → []/transaction_search_window_days. +// Дефолт 2 (сегодня + вчера). Гарантированный минимум — 1 (только сегодня). +int transactionSearchWindowDays(const QString &bankCode); + +} // namespace BankConfigUtils diff --git a/android/dushanbe/GetLastTransactionsScript.cpp b/android/dushanbe/GetLastTransactionsScript.cpp index 5f8d97c..75d425a 100644 --- a/android/dushanbe/GetLastTransactionsScript.cpp +++ b/android/dushanbe/GetLastTransactionsScript.cpp @@ -15,6 +15,7 @@ #include "dao/BankProfileDAO.h" #include "dao/DeviceDAO.h" #include "AppLogger.h" +#include "BankConfigUtils.h" #include @@ -502,6 +503,10 @@ GetLastTransactionsScript::SearchResult GetLastTransactionsScript::searchOne( const QTimeZone tjTz("Asia/Dushanbe"); const int maxScrolls = 10; + // Окно поиска по датам: сегодня + (N-1) предыдущих дней. Настраивается в + // config.ini → []/transaction_search_window_days (дефолт 2 = сегодня+вчера). + const int searchWindowDays = BankConfigUtils::transactionSearchWindowDays(m_appCode); + auto interrupted = []() { return QThread::currentThread()->isInterruptionRequested(); }; @@ -984,29 +989,28 @@ GetLastTransactionsScript::SearchResult GetLastTransactionsScript::searchOne( return SearchResult::Found; } - // Окно поиска — только "сегодня + вчера". Список Выписки идёт сверху-вниз - // от новых к старым; группы-даты на текущем экране собраны в groupDates. - // Как только самая свежая видимая дата уже старше вчерашнего дня — значит - // окно today+yesterday полностью проскроллено, дальше только старая история. - // Прекращаем скролл (целевой транзакции в окне нет), вместо того чтобы - // листать до упора и упереться в watchdog-таймаут. - // NOTE: окно "сегодня+вчера" временно отключено — скроллим без ограничения по дате. - // { - // const QDate cutoff = todayLocal.addDays(-1); // вчера - // QDate newestVisible; - // for (const QString &gd : groupDates) { - // const QDate d = QDate::fromString(gd, "dd.MM.yyyy"); - // if (d.isValid() && (newestVisible.isNull() || d > newestVisible)) - // newestVisible = d; - // } - // if (newestVisible.isValid() && newestVisible < cutoff) { - // qDebug() << "[Dushanbe::GetLastTransactions] Past today+yesterday window" - // " (newest visible=" << newestVisible.toString("dd.MM.yyyy") - // << "< cutoff=" << cutoff.toString("dd.MM.yyyy") - // << ") — stopping scroll"; - // return SearchResult::PastWindow; - // } - // } + // Окно поиска — "сегодня + (searchWindowDays-1) предыдущих дней". Список + // Выписки идёт сверху-вниз от новых к старым; группы-даты на текущем экране + // собраны в groupDates. Как только самая свежая видимая дата уже старше + // нижней границы окна — значит окно полностью проскроллено, дальше только + // старая история. Прекращаем скролл (целевой транзакции в окне нет), вместо + // того чтобы листать до упора и упереться в watchdog-таймаут. + { + const QDate cutoff = todayLocal.addDays(-(searchWindowDays - 1)); // нижняя граница окна + QDate newestVisible; + for (const QString &gd : groupDates) { + const QDate d = QDate::fromString(gd, "dd.MM.yyyy"); + if (d.isValid() && (newestVisible.isNull() || d > newestVisible)) + newestVisible = d; + } + if (newestVisible.isValid() && newestVisible < cutoff) { + qDebug() << "[Dushanbe::GetLastTransactions] Past today+yesterday window" + " (newest visible=" << newestVisible.toString("dd.MM.yyyy") + << "< cutoff=" << cutoff.toString("dd.MM.yyyy") + << ") — stopping scroll"; + return SearchResult::PastWindow; + } + } // Скроллим вниз — свайп внутри области транзакций if (scroll < maxScrolls) { diff --git a/android/ozon/ScreenXmlParser.cpp b/android/ozon/ScreenXmlParser.cpp index e14d480..345a0d0 100644 --- a/android/ozon/ScreenXmlParser.cpp +++ b/android/ozon/ScreenXmlParser.cpp @@ -16,6 +16,7 @@ #include "db/MaterialInfo.h" #include "db/TransactionInfo.h" #include "time/DateUtils.h" +#include "BankConfigUtils.h" namespace Ozon { @@ -1218,30 +1219,45 @@ QList ScreenXmlParser::parseTodayAndYesterdayReportHistory() { return transactions; } +// Строит заголовок дня в формате Ozon-Выписки для переданной даты. +// offset 0 → "сегодня, ...", 1 → "вчера, ...", иначе "<день> <месяц>, <дн.недели>". +static QString ozonDayTitle(const QDate &day, int offset) { + if (offset == 0) + return QString("сегодня, %1").arg(getDayOfWeekAsString(day.dayOfWeek())); + if (offset == 1) + return QString("вчера, %1").arg(getDayOfWeekAsString(day.dayOfWeek())); + return QString("%1 %2, %3").arg( + QString::number(day.day()), + getMonthAsString(day.month()), + getDayOfWeekAsString(day.dayOfWeek())); +} + QList ScreenXmlParser::parseTodayAndYesterdayHistory() { - QDate today = DateUtils::getMoscowNow().date(); - QDate yesterday = today.addDays(-1); - QDate beforeYesterday = today.addDays(-2); + // Окно поиска: сегодня + (N-1) предыдущих дней. Настраивается в + // config.ini → [ozon]/transaction_search_window_days (дефолт 2 = сегодня+вчера). + const int windowDays = BankConfigUtils::transactionSearchWindowDays("ozon"); + const QDate today = DateUtils::getMoscowNow().date(); - - 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(); + // Заголовки дней внутри окна [сегодня .. сегодня-(windowDays-1)] → дата дня. + struct DayTitle { QString title; QDate date; }; + QList windowTitles; + for (int i = 0; i < windowDays; ++i) { + const QDate d = today.addDays(-i); + windowTitles.append({ozonDayTitle(d, i), d}); } + // Заголовок первого дня ЗА окном — сигнал "дальше старая история, стоп". + const QDate boundaryDate = today.addDays(-windowDays); + const QString boundaryTitle = ozonDayTitle(boundaryDate, windowDays); + // Родительский контейнер списка: берём первый существующий заголовок окна. + QDomNode parentNode; + for (const DayTitle &dt : windowTitles) { + const QDomNode node = findNode(m_xml, dt.title); + if (!node.isNull()) { + parentNode = node.parentNode(); + break; + } + } QList transactions; if (!parentNode.isNull()) { @@ -1250,17 +1266,19 @@ QList ScreenXmlParser::parseTodayAndYesterdayHistory() { QString transactionShortText = transactionNode.toElement().attribute("text"); const QString titleLowerCase = transactionShortText.toLower(); - if (titleLowerCase.startsWith(beforeYesterdayTitle)) { - // только сегодня и вчера парсим, позавчера не трогаем + + // День за пределами окна — дальше только старая история, прекращаем. + if (titleLowerCase.startsWith(boundaryTitle)) { break; } - if (titleLowerCase.startsWith(todayTitle)) { - date = today; - transactionShortText = transactionShortText.mid(todayTitle.length() + 1); - } - if (titleLowerCase.startsWith(yesterdayTitle)) { - date = yesterday; - transactionShortText = transactionShortText.mid(yesterdayTitle.length() + 1); + + // Заголовок дня внутри окна — обновляем текущую дату и срезаем префикс. + for (const DayTitle &dt : windowTitles) { + if (titleLowerCase.startsWith(dt.title)) { + date = dt.date; + transactionShortText = transactionShortText.mid(dt.title.length() + 1); + break; + } } if (transactionShortText.contains("ЕСПП")) { diff --git a/config.ini b/config.ini index 17a76b9..3139a03 100644 --- a/config.ini +++ b/config.ini @@ -47,6 +47,8 @@ country=russia name=Ozon phone_code=7 app_version=19.17.0 +# Окно поиска транзакций в днях: сегодня + (N-1) предыдущих дней. 2 = сегодня+вчера. +transaction_search_window_days=2 [dushanbe_city_bank] android_package_name=tj.dc.next1 @@ -55,3 +57,5 @@ country=tajikistan name=Dushanbe City phone_code=992 app_version=3.2.34 +# Окно поиска транзакций в днях: сегодня + (N-1) предыдущих дней. 2 = сегодня+вчера. +transaction_search_window_days=2