Parse credit card PDF statements into structured financial data with multiple export formats (Pandas, CSV, OFX, QBO). Currently supports TD Business Solutions Visa.
Project description
ccparse
A Python library for extracting high-fidelity financial data from TD Business Solutions Visa "born-digital" PDF statements.
Parses transactions, balance summaries, and rewards points into structured domain objects, validates the Golden Equation on every parse, and exports to Pandas DataFrames.
Features
- Extracts all transactions with activity date, post date, reference number, description, and amount
- Correctly handles
CR(credit balance) signage — stored as negativeDecimalvalues - Validates
Previous Balance + Purchases - Credits + Fees + Interest = New Balanceon every parse; raisesBalanceMismatchErrorif it fails - All monetary values use
decimal.Decimal— floating-point arithmetic is never used - Exports to multiple formats: Pandas DataFrame, CSV, OFX, and QBO
- All processing is local — no network calls, no data storage
- Clean layered architecture with Strategy Pattern for multi-bank extensibility
Installation
pip install ccparse
Requires Python 3.11+.
Quick Start
from ccparse import TDStatementParser
parser = TDStatementParser()
statement = parser.parse("path/to/statement.pdf")
# Metadata
print(statement.account_suffix) # "5679"
print(statement.billing_period_start) # datetime.date(2024, 7, 4)
print(statement.billing_period_end) # datetime.date(2024, 8, 3)
# Balance summary
print(statement.balance_summary.new_balance) # Decimal('-1151.02')
print(statement.balance_summary.previous_balance) # Decimal('-1516.49')
print(statement.balance_summary.purchases) # Decimal('365.47')
# Transactions
for t in statement.transactions:
print(t.activity_date, t.reference_number, t.description, t.amount)
# Rewards
print(statement.current_points) # 6050
Pandas Export
from ccparse import TDStatementParser
from ccparse.export import to_df
statement = TDStatementParser().parse("path/to/statement.pdf")
df = to_df(statement)
print(df.dtypes)
# activity_date datetime64[ns]
# post_date datetime64[ns]
# reference_number object
# description object
# amount float64
CSV Export
from ccparse.export import to_csv
statement = TDStatementParser().parse("path/to/statement.pdf")
csv_output = to_csv(statement)
# Save to file
with open("transactions.csv", "w") as f:
f.write(csv_output)
OFX/QBO Export (QuickBooks, Xero, etc.)
from ccparse.export import to_ofx, to_qbo
statement = TDStatementParser().parse("path/to/statement.pdf")
# OFX format (Open Financial Exchange)
ofx_output = to_ofx(statement)
with open("transactions.ofx", "w") as f:
f.write(ofx_output)
# QBO format (QuickBooks Online) - same as OFX
qbo_output = to_qbo(statement)
with open("transactions.qbo", "w") as f:
f.write(qbo_output)
The OFX/QBO export maps reference_number to <FITID> (Financial Institution Transaction ID), which prevents duplicate imports in accounting software.
Error Handling
from ccparse import TDStatementParser, BalanceMismatchError, DataIntegrityError
try:
statement = TDStatementParser().parse("path/to/statement.pdf")
except BalanceMismatchError as e:
# Golden Equation failed — the PDF figures don't add up
print(e)
except DataIntegrityError as e:
# A required field could not be extracted
print(e)
| Exception | Raised when |
|---|---|
BalanceMismatchError |
Golden Equation validation fails |
DataIntegrityError |
A required field is missing or unparseable |
UnsupportedFormatError |
PDF format is not recognized |
TDParserError |
Base class for all library errors |
Architecture
ccparse uses a clean layered architecture following Domain-Driven Design principles:
┌─────────────────────────────────────────┐
│ Public API Layer │
│ TDStatementParser (backward compat) │
├─────────────────────────────────────────┤
│ Parser Strategy Layer │
│ StatementParser (ABC) │
│ └─ TDBusinessVisaParser │
├─────────────────────────────────────────┤
│ Infrastructure Layer │
│ PDFExtractor (pdfplumber wrapper) │
├─────────────────────────────────────────┤
│ Application Layer │
│ ExportService (to_df, to_csv, etc.) │
├─────────────────────────────────────────┤
│ Domain Layer │
│ Statement, Transaction, etc. │
└─────────────────────────────────────────┘
Strategy Pattern: The StatementParser abstract base class enables multi-bank support. Adding a new bank (Chase, Amex) requires implementing a new parser strategy — no changes to infrastructure or domain layers.
See docs/architecture-diagram.md for detailed architecture documentation.
Data Model
@dataclass
class Statement:
entity_name: str
primary_cardholder: str
account_suffix: str
billing_period_start: date
billing_period_end: date
balance_summary: BalanceSummary
current_points: int
transactions: List[Transaction]
@dataclass(frozen=True)
class Transaction:
activity_date: date
post_date: date
reference_number: str # maps to <FITID> in OFX/QBO
description: str
amount: Decimal # positive = spend, negative = payment/credit
@dataclass(frozen=True)
class BalanceSummary:
previous_balance: Decimal
purchases: Decimal
credits: Decimal
fees: Decimal
interest: Decimal
new_balance: Decimal
available_credit: Decimal
minimum_payment: Decimal
Project Structure
ccparse/
├── infrastructure/
│ └── pdf_extractor.py # PDF extraction utilities
├── parsers/
│ ├── base.py # StatementParser ABC
│ └── td_business_visa.py # TD Business Visa implementation
├── export/
│ └── export_service.py # Export strategies (Pandas, CSV, OFX, QBO)
├── models.py # Domain models
├── exceptions.py # Domain exceptions
├── export.py # Export API (backward compat)
└── parser.py # Public API (backward compat)
Development
git clone https://github.com/rmuktader/ccparse
cd ccparse
uv sync
uv run pytest tests/ -v
Running Tests
All 66 tests validate:
- Unit tests for amount/date parsing and balance validation
- Integration tests for full statement parsing
- Export functionality (Pandas, CSV, OFX, QBO)
- Golden Equation validation
- Backward compatibility
Roadmap
| Version | Features |
|---|---|
| 0.1 (MVP) | TD Business Visa parsing, Pandas export, balance validation |
| 0.2 (Current) | Layered architecture, CSV/OFX/QBO export |
| 1.0 | Rewards validation, optional dependency extras |
| 2.0 | Multi-bank strategy (Chase, Amex) |
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ccparse-0.6.0.tar.gz.
File metadata
- Download URL: ccparse-0.6.0.tar.gz
- Upload date:
- Size: 60.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e0a08b8b06566e27584d3678cc7d8a561be23289c0db2a2b2f74f11365b21edb
|
|
| MD5 |
0deb0efec5869a6a4341860288836845
|
|
| BLAKE2b-256 |
352cf88b6cadd38b46b6e9dd2368c4630269174c58d7cc0b93bab714a96b5c9d
|
File details
Details for the file ccparse-0.6.0-py3-none-any.whl.
File metadata
- Download URL: ccparse-0.6.0-py3-none-any.whl
- Upload date:
- Size: 13.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd3efbe62fae6088d5ddcae7a3d56aa818f0cf5b01c610ead9fbaf0c46b8b25f
|
|
| MD5 |
0876f4a45242d9d1a47f04875e4ddf8a
|
|
| BLAKE2b-256 |
1727e04c8205f59b0f0572e8e24f9c84de546bb8ae8bf9480f2dd345bcfdc706
|