1
0
forked from BRT/arc

Add configurable date search window for transaction history parsing.

This commit is contained in:
slava 2026-06-01 22:27:34 +05:00
parent e5a11b0a57
commit 6d60cecef4
5 changed files with 106 additions and 52 deletions

View File

@ -0,0 +1,13 @@
#include "BankConfigUtils.h"
#include <QSettings>
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

15
android/BankConfigUtils.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <QString>
// Пер-банковые настройки, читаемые из config.ini.
// bankCode совпадает с именем секции в config.ini и со значением appCode
// ("ozon", "black", "dushanbe_city_bank").
namespace BankConfigUtils {
// Окно поиска транзакций в днях: сегодня + (N-1) предыдущих дней.
// Источник: config.ini → [<bankCode>]/transaction_search_window_days.
// Дефолт 2 (сегодня + вчера). Гарантированный минимум — 1 (только сегодня).
int transactionSearchWindowDays(const QString &bankCode);
} // namespace BankConfigUtils

View File

@ -15,6 +15,7 @@
#include "dao/BankProfileDAO.h" #include "dao/BankProfileDAO.h"
#include "dao/DeviceDAO.h" #include "dao/DeviceDAO.h"
#include "AppLogger.h" #include "AppLogger.h"
#include "BankConfigUtils.h"
#include <QCoreApplication> #include <QCoreApplication>
@ -502,6 +503,10 @@ GetLastTransactionsScript::SearchResult GetLastTransactionsScript::searchOne(
const QTimeZone tjTz("Asia/Dushanbe"); const QTimeZone tjTz("Asia/Dushanbe");
const int maxScrolls = 10; const int maxScrolls = 10;
// Окно поиска по датам: сегодня + (N-1) предыдущих дней. Настраивается в
// config.ini → [<bankCode>]/transaction_search_window_days (дефолт 2 = сегодня+вчера).
const int searchWindowDays = BankConfigUtils::transactionSearchWindowDays(m_appCode);
auto interrupted = []() { auto interrupted = []() {
return QThread::currentThread()->isInterruptionRequested(); return QThread::currentThread()->isInterruptionRequested();
}; };
@ -984,29 +989,28 @@ GetLastTransactionsScript::SearchResult GetLastTransactionsScript::searchOne(
return SearchResult::Found; return SearchResult::Found;
} }
// Окно поиска — только "сегодня + вчера". Список Выписки идёт сверху-вниз // Окно поиска — "сегодня + (searchWindowDays-1) предыдущих дней". Список
// от новых к старым; группы-даты на текущем экране собраны в groupDates. // Выписки идёт сверху-вниз от новых к старым; группы-даты на текущем экране
// Как только самая свежая видимая дата уже старше вчерашнего дня — значит // собраны в groupDates. Как только самая свежая видимая дата уже старше
// окно today+yesterday полностью проскроллено, дальше только старая история. // нижней границы окна — значит окно полностью проскроллено, дальше только
// Прекращаем скролл (целевой транзакции в окне нет), вместо того чтобы // старая история. Прекращаем скролл (целевой транзакции в окне нет), вместо
// листать до упора и упереться в watchdog-таймаут. // того чтобы листать до упора и упереться в watchdog-таймаут.
// NOTE: окно "сегодня+вчера" временно отключено — скроллим без ограничения по дате. {
// { const QDate cutoff = todayLocal.addDays(-(searchWindowDays - 1)); // нижняя граница окна
// const QDate cutoff = todayLocal.addDays(-1); // вчера QDate newestVisible;
// QDate newestVisible; for (const QString &gd : groupDates) {
// for (const QString &gd : groupDates) { const QDate d = QDate::fromString(gd, "dd.MM.yyyy");
// const QDate d = QDate::fromString(gd, "dd.MM.yyyy"); if (d.isValid() && (newestVisible.isNull() || d > newestVisible))
// if (d.isValid() && (newestVisible.isNull() || d > newestVisible)) newestVisible = d;
// newestVisible = d; }
// } if (newestVisible.isValid() && newestVisible < cutoff) {
// if (newestVisible.isValid() && newestVisible < cutoff) { qDebug() << "[Dushanbe::GetLastTransactions] Past today+yesterday window"
// qDebug() << "[Dushanbe::GetLastTransactions] Past today+yesterday window" " (newest visible=" << newestVisible.toString("dd.MM.yyyy")
// " (newest visible=" << newestVisible.toString("dd.MM.yyyy") << "< cutoff=" << cutoff.toString("dd.MM.yyyy")
// << "< cutoff=" << cutoff.toString("dd.MM.yyyy") << ") — stopping scroll";
// << ") — stopping scroll"; return SearchResult::PastWindow;
// return SearchResult::PastWindow; }
// } }
// }
// Скроллим вниз — свайп внутри области транзакций // Скроллим вниз — свайп внутри области транзакций
if (scroll < maxScrolls) { if (scroll < maxScrolls) {

View File

@ -16,6 +16,7 @@
#include "db/MaterialInfo.h" #include "db/MaterialInfo.h"
#include "db/TransactionInfo.h" #include "db/TransactionInfo.h"
#include "time/DateUtils.h" #include "time/DateUtils.h"
#include "BankConfigUtils.h"
namespace Ozon { namespace Ozon {
@ -1218,30 +1219,45 @@ QList<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayReportHistory() {
return transactions; 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<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayHistory() { QList<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayHistory() {
QDate today = DateUtils::getMoscowNow().date(); // Окно поиска: сегодня + (N-1) предыдущих дней. Настраивается в
QDate yesterday = today.addDays(-1); // config.ini → [ozon]/transaction_search_window_days (дефолт 2 = сегодня+вчера).
QDate beforeYesterday = today.addDays(-2); const int windowDays = BankConfigUtils::transactionSearchWindowDays("ozon");
const QDate today = DateUtils::getMoscowNow().date();
// Заголовки дней внутри окна [сегодня .. сегодня-(windowDays-1)] → дата дня.
QString todayTitle = QString("сегодня, %1").arg(getDayOfWeekAsString(today.dayOfWeek())); struct DayTitle { QString title; QDate date; };
QString yesterdayTitle = QString("вчера, %1").arg(getDayOfWeekAsString(yesterday.dayOfWeek())); QList<DayTitle> windowTitles;
QString beforeYesterdayTitle = QString("%1 %2, %3").arg( for (int i = 0; i < windowDays; ++i) {
QString::number(beforeYesterday.day()), const QDate d = today.addDays(-i);
getMonthAsString(beforeYesterday.month()), windowTitles.append({ozonDayTitle(d, i), d});
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();
} }
// Заголовок первого дня ЗА окном — сигнал "дальше старая история, стоп".
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<TransactionInfo> transactions; QList<TransactionInfo> transactions;
if (!parentNode.isNull()) { if (!parentNode.isNull()) {
@ -1250,17 +1266,19 @@ QList<TransactionInfo> ScreenXmlParser::parseTodayAndYesterdayHistory() {
QString transactionShortText = transactionNode.toElement().attribute("text"); QString transactionShortText = transactionNode.toElement().attribute("text");
const QString titleLowerCase = transactionShortText.toLower(); const QString titleLowerCase = transactionShortText.toLower();
if (titleLowerCase.startsWith(beforeYesterdayTitle)) {
// только сегодня и вчера парсим, позавчера не трогаем // День за пределами окна — дальше только старая история, прекращаем.
if (titleLowerCase.startsWith(boundaryTitle)) {
break; break;
} }
if (titleLowerCase.startsWith(todayTitle)) {
date = today; // Заголовок дня внутри окна — обновляем текущую дату и срезаем префикс.
transactionShortText = transactionShortText.mid(todayTitle.length() + 1); for (const DayTitle &dt : windowTitles) {
if (titleLowerCase.startsWith(dt.title)) {
date = dt.date;
transactionShortText = transactionShortText.mid(dt.title.length() + 1);
break;
} }
if (titleLowerCase.startsWith(yesterdayTitle)) {
date = yesterday;
transactionShortText = transactionShortText.mid(yesterdayTitle.length() + 1);
} }
if (transactionShortText.contains("ЕСПП")) { if (transactionShortText.contains("ЕСПП")) {

View File

@ -47,6 +47,8 @@ country=russia
name=Ozon name=Ozon
phone_code=7 phone_code=7
app_version=19.17.0 app_version=19.17.0
# Окно поиска транзакций в днях: сегодня + (N-1) предыдущих дней. 2 = сегодня+вчера.
transaction_search_window_days=2
[dushanbe_city_bank] [dushanbe_city_bank]
android_package_name=tj.dc.next1 android_package_name=tj.dc.next1
@ -55,3 +57,5 @@ country=tajikistan
name=Dushanbe City name=Dushanbe City
phone_code=992 phone_code=992
app_version=3.2.34 app_version=3.2.34
# Окно поиска транзакций в днях: сегодня + (N-1) предыдущих дней. 2 = сегодня+вчера.
transaction_search_window_days=2