Upload files to "/"

This commit is contained in:
2026-08-16 04:07:21 +02:00
parent 5f95ad7361
commit 799a1c305a
5 changed files with 1826 additions and 0 deletions
+86
View File
@@ -0,0 +1,86 @@
import camelot
import pandas as pd
import re
import csv
def clean_amount(val):
"""Removes '=' and whitespace from amount strings."""
if not val: return ""
return val.replace('=', '').strip()
def extract_account(text):
"""Extracts IBAN (SI56...) from a text block."""
match = re.search(r'[A-Z]{2}\d{2}\s?(?:\d{4}\s?){4}\d{1,3}', text)
return match.group(0).strip() if match else ""
def process_bank_statement(pdf_path, output_csv):
# Load all pages. 'stream' flavor is ideal for this layout.
tables = camelot.read_pdf(pdf_path, pages='all', flavor='stream', split_text=True)
all_transactions = []
current_tx = None
# Regex to identify a date (DD.MM.YY) which anchors a new transaction
date_pattern = re.compile(r'\d{2}\.\d{2}\.\d{2}')
for table in tables:
df = table.df
for index, row in df.iterrows():
# Skip the header rows (usually contains 'Creditor' or 'value date')
if "Creditor" in row[0] or "value date" in str(row.iloc[-1]):
continue
# Detect if this row contains a date in the last column (Column 4)
date_val = str(row.iloc[-1]).strip()
is_new_tx = bool(date_pattern.search(date_val))
if is_new_tx:
# If we were already building a transaction, save it before starting a new one
if current_tx:
all_transactions.append(current_tx)
# Initialize a new transaction object
current_tx = {
'value date': date_pattern.search(date_val).group(0),
'raw_text': row[0],
'debit': clean_amount(row[1]),
'credit': clean_amount(row[2])
}
else:
# If it's not a new date, it's a continuation of the previous transaction's text
if current_tx and row[0].strip():
current_tx['raw_text'] += " " + row[0].strip()
# Append the last transaction processed
if current_tx:
all_transactions.append(current_tx)
# Final formatting: Split raw_text into Name, Account, and Details
final_data = []
for tx in all_transactions:
text = tx['raw_text']
account = extract_account(text)
# Simple split logic: First part is Name, rest is Details (excluding account)
# Note: This logic can be refined based on specific name lengths
details = text.replace(account, "").strip()
parts = details.split(" ", 1) # Try to find a larger gap
name = parts[0].strip()
payment_details = parts[1].strip() if len(parts) > 1 else details
final_data.append({
"value date": tx['value date'],
"Creditor / Debtor": name,
"account": account,
"payment details": payment_details,
"debit": tx['debit'],
"credit": tx['credit']
})
# Export to CSV with semicolon delimiter
output_df = pd.DataFrame(final_data)
output_df.to_csv(output_csv, index=False, sep=';', encoding='utf-8-sig', quoting=csv.QUOTE_ALL)
print(f"Successfully exported {len(final_data)} transactions to {output_csv}")
# Execution
process_bank_statement("MSDataReport (1).pdf", "Processed_Transactions.csv")