Skip to main content

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 negative Decimal values
  • Validates Previous Balance + Purchases - Credits + Fees + Interest = New Balance on every parse; raises BalanceMismatchError if 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ccparse-0.6.0.tar.gz (60.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ccparse-0.6.0-py3-none-any.whl (13.7 kB view details)

Uploaded Python 3

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

Hashes for ccparse-0.6.0.tar.gz
Algorithm Hash digest
SHA256 e0a08b8b06566e27584d3678cc7d8a561be23289c0db2a2b2f74f11365b21edb
MD5 0deb0efec5869a6a4341860288836845
BLAKE2b-256 352cf88b6cadd38b46b6e9dd2368c4630269174c58d7cc0b93bab714a96b5c9d

See more details on using hashes here.

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

Hashes for ccparse-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 dd3efbe62fae6088d5ddcae7a3d56aa818f0cf5b01c610ead9fbaf0c46b8b25f
MD5 0876f4a45242d9d1a47f04875e4ddf8a
BLAKE2b-256 1727e04c8205f59b0f0572e8e24f9c84de546bb8ae8bf9480f2dd345bcfdc706

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page