164 lines
5.4 KiB
Java
164 lines
5.4 KiB
Java
package com.example.FinanceTracker.Components;
|
|
|
|
import java.math.BigDecimal;
|
|
import java.time.LocalDate;
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.util.ArrayList;
|
|
import java.util.List;
|
|
import java.util.regex.Matcher;
|
|
import java.util.regex.Pattern;
|
|
|
|
import org.springframework.ai.document.Document;
|
|
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.stereotype.Component;
|
|
import com.example.FinanceTracker.Models.Transaction;
|
|
import com.example.FinanceTracker.Repo.CategoriesRepo;
|
|
|
|
@Component
|
|
public class PdfManager {
|
|
|
|
@Autowired
|
|
private CategoriesRepo categoriesRepo;
|
|
|
|
private static final String START_HEADER = "Transaction History";
|
|
private static final String TRANSACTION_HEADING =
|
|
"Date Description Category Money In Money Out Fee* Balance";
|
|
|
|
private static final DateTimeFormatter DATE_FORMATTER =
|
|
DateTimeFormatter.ofPattern("dd/MM/yyyy");
|
|
|
|
private static final Pattern AMOUNT_PATTERN =
|
|
Pattern.compile("-?\\d{1,3}(?:\\s\\d{3})*\\.\\d{2}");
|
|
|
|
public List<Transaction> extractTransactions() {
|
|
|
|
PagePdfDocumentReader pdfReader =
|
|
new PagePdfDocumentReader("/static/statements/statement.pdf");
|
|
|
|
List<Document> documents = pdfReader.get();
|
|
StringBuilder documentText = new StringBuilder();
|
|
|
|
for (Document document : documents) {
|
|
documentText.append(document.getText());
|
|
}
|
|
|
|
String normalizedText = normalizeText(documentText.toString());
|
|
List<String> lines = normalizedText.lines().toList();
|
|
|
|
List<Transaction> transactions = new ArrayList<>();
|
|
|
|
for (String rawLine : lines) {
|
|
Transaction transaction = new Transaction();
|
|
|
|
try {
|
|
String line = rawLine.trim();
|
|
|
|
line = extractDate(line, transaction);
|
|
line = extractBalance(line, transaction);
|
|
|
|
boolean isFee = line.contains("Fees");
|
|
line = extractMonetaryValues(line, transaction, isFee);
|
|
|
|
line = extractCategory(line, transaction);
|
|
|
|
transaction.setDescription(line);
|
|
transactions.add(transaction);
|
|
|
|
} catch (Exception ignored) {
|
|
// Intentionally ignored: non-transaction lines are skipped
|
|
}
|
|
}
|
|
|
|
return transactions;
|
|
}
|
|
|
|
private String normalizeText(String text) {
|
|
return text
|
|
.replace(text.substring(0, text.indexOf(START_HEADER)), "")
|
|
.replace(TRANSACTION_HEADING, "")
|
|
.replace("*", "")
|
|
.trim();
|
|
}
|
|
|
|
private String extractMonetaryValues(
|
|
String line,
|
|
Transaction transaction,
|
|
boolean isFee
|
|
) {
|
|
Matcher matcher = AMOUNT_PATTERN.matcher(line);
|
|
List<BigDecimal> amounts = new ArrayList<>();
|
|
|
|
while (matcher.find()) {
|
|
String value = matcher.group().replace(" ", "");
|
|
amounts.add(new BigDecimal(value));
|
|
line = line.replace(" ", "").replace(value, "");
|
|
}
|
|
|
|
if (isFee) {
|
|
transaction.setFee(amounts.get(0));
|
|
transaction.setMoneyIn(BigDecimal.ZERO);
|
|
transaction.setMoneyOut(BigDecimal.ZERO);
|
|
return line;
|
|
}
|
|
|
|
BigDecimal firstAmount = amounts.get(0);
|
|
|
|
if (firstAmount.compareTo(BigDecimal.ZERO) > 0) {
|
|
transaction.setMoneyIn(firstAmount);
|
|
transaction.setMoneyOut(BigDecimal.ZERO);
|
|
transaction.setFee(BigDecimal.ZERO);
|
|
return line;
|
|
}
|
|
|
|
transaction.setMoneyIn(BigDecimal.ZERO);
|
|
transaction.setMoneyOut(firstAmount);
|
|
transaction.setFee(amounts.size() == 2 ? amounts.get(1) : BigDecimal.ZERO);
|
|
|
|
return line;
|
|
}
|
|
|
|
private String extractCategory(String line, Transaction transaction) {
|
|
|
|
int rightmostIndex = -1;
|
|
String matchedCategory = null;
|
|
|
|
for (String category : categoriesRepo.findAllCategoryNames()) {
|
|
String label = category.replace(" ", "");
|
|
int index = line.lastIndexOf(label);
|
|
|
|
if (index > rightmostIndex) {
|
|
rightmostIndex = index;
|
|
matchedCategory = category;
|
|
}
|
|
}
|
|
|
|
if (matchedCategory != null) {
|
|
String label = matchedCategory.replace(" ", "");
|
|
int categoryId = categoriesRepo.findCategoryIdByCategoryName(matchedCategory);
|
|
transaction.setCategory(Integer.toString(categoryId));
|
|
|
|
int endIndex = rightmostIndex + label.length();
|
|
line = line.substring(0, rightmostIndex) + line.substring(endIndex);
|
|
}
|
|
|
|
return line;
|
|
}
|
|
|
|
private String extractBalance(String line, Transaction transaction) {
|
|
String balanceValue = line.substring(line.length() - 10).replace(" ", "");
|
|
transaction.setBalance(new BigDecimal(balanceValue));
|
|
return line.substring(0, line.length() - 10);
|
|
}
|
|
|
|
private String extractDate(String line, Transaction transaction) {
|
|
try {
|
|
LocalDate date = LocalDate.parse(line.substring(0, 10), DATE_FORMATTER);
|
|
transaction.setDate(date);
|
|
return line.substring(11);
|
|
} catch (Exception ignored) {
|
|
return line;
|
|
}
|
|
}
|
|
}
|