FinanceTracker/src/main/java/com/example/FinanceTracker/Components/PdfManager.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;
}
}
}