-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbice.cpp
More file actions
executable file
·108 lines (90 loc) · 3.41 KB
/
Copy pathbice.cpp
File metadata and controls
executable file
·108 lines (90 loc) · 3.41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include "banks/bice.h"
#include <QDate>
#include <QDateTime>
#include <QDebug>
#include <QRegularExpression>
#include <QTime>
namespace pdfparser {
namespace {
// BICE rows always start with "<day> <mon> <year> Cargos|Abonos".
// Anything else is a wrap of the previous row.
const QRegularExpression &rowStartRx()
{
static const QRegularExpression rx(
QStringLiteral(R"(^\s*\d{1,2}\s+[A-Za-zñÑ]{3,}\.?\s+\d{4}\s+(?:Cargos|Abonos)\b)"),
QRegularExpression::CaseInsensitiveOption);
return rx;
}
// Captures the first $-amount on the (un-wrapped) row; BICE prints the
// posted amount right-aligned at the end of the first physical line.
const QRegularExpression &rowRx()
{
static const QRegularExpression rx(
QStringLiteral(
R"(^(?<day>\d{1,2})\s+(?<mon>[A-Za-zñÑ]{3,})\.?\s+(?<year>\d{4})\s+)"
R"((?<section>Cargos|Abonos)\s+)"
R"((?<op>\S+)\s+)"
R"((?<desc>.*?)\s+\$\s*(?<amount>-?[\d\.,]+)\b)"
),
QRegularExpression::CaseInsensitiveOption);
return rx;
}
} // namespace
BICE::BICE(const QString &typeAccount)
: Bank(QStringLiteral("BICE"), typeAccount) {}
BICE::BICE(const QString &typeAccount, const QString &filePath)
: Bank(QStringLiteral("BICE"), typeAccount, filePath) {}
void BICE::readBankMovementsDebit(const QStringList &pagesText,
QList<Transaction> &out)
{
auto flush = [&](const QString &row) {
if (row.isEmpty()) return;
const auto m = rowRx().match(row);
if (!m.hasMatch()) return;
const int day = m.captured("day").toInt();
const int mon = spanishMonth(m.captured("mon"));
const int year = m.captured("year").toInt();
if (mon == 0) return;
const QString rawDesc = m.captured("desc").simplified();
Transaction t;
t.date = QDateTime(QDate(year, mon, day), QTime(0, 0));
t.amount = qAbs(parseClpAmount(m.captured("amount")));
t.account = nameBank;
t.category = classifier.classify(rawDesc);
t.description = cleanDescription(rawDesc);
out.append(t);
};
QString current;
bool reachedEnd = false;
for (int p = 0; p < pagesText.size() && !reachedEnd; ++p) {
const QStringList lines = pagesText.at(p).split(QChar('\n'),
Qt::KeepEmptyParts);
for (const QString &raw : lines) {
const QString line = raw.trimmed();
if (line.startsWith(QStringLiteral("Página ")))
break;
if (line.contains(QStringLiteral("Saldos diarios"))) {
reachedEnd = true;
break;
}
if (line.isEmpty()) continue;
if (rowStartRx().match(line).hasMatch()) {
flush(current);
current = line;
} else if (!current.isEmpty()) {
current.append(QChar(' ')).append(line);
}
// else: pre-table noise (page header, summary block) — drop.
}
}
flush(current);
}
void BICE::readBankMovementsCredit(const QStringList &pagesText,
QList<Transaction> &out)
{
Q_UNUSED(pagesText);
Q_UNUSED(out);
qWarning() << "[BICE/credit] parser not implemented yet — drop a sample "
"PDF in files/ and we can fill in the regexes.";
}
} // namespace pdfparser