Metadata-Version: 2.4
Name: repaykit
Version: 1.0.0
Summary: Pure Python repayment schedule, financing, loan ledger, and settlement calculation toolkit.
Project-URL: Homepage, https://github.com/finsure-techlab/repaykit
Project-URL: Repository, https://github.com/finsure-techlab/repaykit
Project-URL: Issues, https://github.com/finsure-techlab/repaykit/issues
Author: finsure techlab
License-Expression: MIT
License-File: LICENSE
Keywords: amortization,financing,ledger,loan,repayment,settlement
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Financial and Insurance Industry
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Office/Business :: Financial
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.11
Provides-Extra: dev
Requires-Dist: build; extra == 'dev'
Requires-Dist: coverage; extra == 'dev'
Requires-Dist: mypy; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-cov; extra == 'dev'
Requires-Dist: ruff; extra == 'dev'
Requires-Dist: twine; extra == 'dev'
Description-Content-Type: text/markdown

# repaykit

Pure Python repayment schedule, financing, loan ledger, and settlement calculation toolkit.

`repaykit` helps software teams calculate loan and financing schedules, payment ledgers, late
charges, statement balances, and settlement quotes. It is framework-agnostic, uses `Decimal` for
money and rates, and keeps business rules policy-driven.

## What It Is Not

`repaykit` is not a loan origination system, accounting system, regulatory compliance engine, or
legal opinion. It does not provide legal, accounting, tax, Shariah, regulatory, lending, or
financial advice. Users are responsible for validating calculations, policies, disclosures, and
compliance requirements for their jurisdiction and product.

## Installation

```bash
pip install repaykit
```

## Supported Methods

- Flat rate
- Sum-of-digits / Rule of 78
- Reducing balance amortization
- Constant principal repayment

## Supported Schedules

- Daily, with optional weekend skipping
- Weekly
- Biweekly
- Monthly, with month-end safety
- Quarterly
- Yearly
- Custom explicit due dates

## Quickstart

```python
from datetime import date
from decimal import Decimal

from repaykit import Loan

loan = Loan.create(
    amount=Decimal("10000.00"),
    annual_rate=Decimal("0.08"),
    term="24 months",
    payment_frequency="monthly",
    method="flat_rate",
    start_date=date(2026, 6, 1),
)

payment = loan.payment_amount()
rows = loan.schedule()
```

Use `iter_schedule()` for lazy row generation, especially for daily schedules.

## Expert Mode

```python
from datetime import date
from decimal import Decimal

from repaykit import Loan
from repaykit.accruals import FlatAccrual
from repaykit.methods import FlatRateAllocation
from repaykit.policies import RoundingPolicy
from repaykit.schedules import MonthlySchedule
from repaykit.terms import Term

loan = Loan(
    principal=Decimal("10000.00"),
    term=Term(months=24),
    payment_schedule=MonthlySchedule(day=1),
    accrual_policy=FlatAccrual(annual_rate=Decimal("0.08")),
    repayment_method=FlatRateAllocation(),
    rounding=RoundingPolicy(currency="MYR"),
    start_date=date(2026, 6, 1),
)
```

## Flat Rate Example

```python
loan = Loan.create(
    amount=Decimal("10000.00"),
    annual_rate=Decimal("0.08"),
    term="24 months",
    payment_frequency="monthly",
    method="flat_rate",
    start_date=date(2026, 6, 1),
)
```

Flat-rate total profit is `principal * annual_rate * term_in_years`. Future scheduled profit is
treated as unearned profit rebate in the default settlement policy.

## Sum-of-Digits / Rule of 78 Example

```python
loan = Loan.create(
    amount=Decimal("10000.00"),
    annual_rate=Decimal("0.08"),
    term="12 months",
    payment_frequency="monthly",
    method="sum_of_digits",
    start_date=date(2026, 1, 1),
)
```

The denominator is generalized as `n * (n + 1) / 2`, so the method works with non-monthly period
counts such as 52 weekly periods.

## Reducing Balance Example

```python
loan = Loan.create(
    amount=Decimal("10000.00"),
    annual_rate=Decimal("0.08"),
    term="24 months",
    payment_frequency="monthly",
    method="reducing_balance",
    start_date=date(2026, 6, 1),
)
```

Reducing balance uses fixed-payment amortization. Profit is calculated on the outstanding balance
for each period.

## Constant Principal Example

```python
loan = Loan.create(
    amount=Decimal("10000.00"),
    annual_rate=Decimal("0.08"),
    term="24 months",
    payment_frequency="monthly",
    method="constant_principal",
    start_date=date(2026, 6, 1),
)
```

The principal component is constant except for the final rounding adjustment; installments decline
as profit declines.

## Weekly Payment Example

```python
loan = Loan.create(
    amount=Decimal("5000.00"),
    annual_rate=Decimal("0.10"),
    term="52 weeks",
    payment_frequency="weekly",
    method="constant_principal",
    start_date=date(2026, 1, 1),
)
```

## Daily Payment Example

```python
loan = Loan.create(
    amount=Decimal("1000.00"),
    annual_rate=Decimal("0.12"),
    term="30 days",
    payment_frequency="daily",
    method="reducing_balance",
    start_date=date(2026, 1, 1),
)
```

## Payment Ledger Example

```python
from repaykit import LoanAccount

account = LoanAccount(loan)
account.add_payment(
    amount=Decimal("500.00"),
    paid_at=date(2026, 7, 5),
    reference="ANGKASA-JULY-2026",
)

statement = account.statement(as_of=date(2026, 8, 1))
print(statement.total_due)
print(statement.total_paid)
print(statement.arrears)
print(statement.outstanding_balance)
```

Statements use aggregate oldest-due-first allocation for due installments and late-charge exposure.
They do not maintain a double-entry accounting ledger or split each payment into principal/profit
transactions.

## Late Charge Example

```python
from repaykit.policies import LateChargePolicy

loan.late_charge_policy = LateChargePolicy(
    rate=Decimal("0.01"),
    grace_days=5,
    basis="flat",
    minimum_charge=Decimal("0.00"),
)
```

Supported bases are `flat` and `daily`. Negative overdue amounts are treated as zero.

## Settlement Example

```python
settlement = account.full_settlement(as_of=date(2026, 12, 15))

print(settlement.outstanding_principal)
print(settlement.unearned_profit_rebate)
print(settlement.late_charges)
print(settlement.amount_payable)
print(settlement.explanation)
```

Settlement is policy-based. Flat-rate and sum-of-digits methods rebate future scheduled profit by
default. Reducing-balance and constant-principal methods have no unearned profit rebate by default.
Validate settlement behavior against your contract and regulatory requirements.

## Export Example

```python
from repaykit.exporters import schedule_to_csv, schedule_to_dicts

rows = loan.schedule()
data = schedule_to_dicts(rows)
schedule_to_csv(rows, "schedule.csv")
```

Exporters serialize `Decimal` values as strings and dates as ISO strings. They never convert money
to floats.

## Rounding Warning

The default `RoundingPolicy` uses half-up money rounding with two decimal places. Different
institutions and jurisdictions may require different rounding points, decimal places, or settlement
rebate rules. Configure and test policies against the governing contract and regulation.

## Release Status

Version 1.0.0 declares the public API documented in `docs/api.md`. Breaking public API changes
after 1.0.0 require a major version bump.
