# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Project Overview

Kapital Bank is a Frappe app integrating BIRBank B2B API with ERPNext. It handles three workflows:
1. **Import**: Bank statement transactions → Payment Entries / Bank Transactions with fuzzy matching
2. **Mapping**: Purpose-based GL account routing with multi-currency Journal Entry creation
3. **Payments**: Outbound transfers via Payment Request → bank API → status polling

## Development Commands

```bash
# Start development server (from bench directory)
bench start

# Install/reinstall the app
bench install-app kapital_bank

# Run migrations after doctype changes
bench migrate

# Run tests
bench --site <site-name> run-tests --app kapital_bank

# Run a single test
bench --site <site-name> run-tests --app kapital_bank --module kapital_bank.kapital_bank.doctype.kapital_bank_settings.test_kapital_bank_settings

# Linting and formatting (from app directory)
pre-commit run --all-files
pre-commit run ruff --all-files      # Python only
pre-commit run eslint --all-files    # JavaScript only
```

## Code Style

- **Python**: Ruff linter/formatter — tabs, double quotes, line-length 110, target Python 3.10
- **JavaScript**: ESLint + Prettier — tabs, indent size 4
- **Indentation**: Tabs everywhere (spaces only in JSON, indent size 1)
- **Ruff ignores**: B017, E101/402/501/741, W191, UP030/031/032, F401/403/405

## Architecture

### Core Modules

| File | Purpose |
|---|---|
| `kapital_bank/auth.py` | JWT auth: login, token refresh, scheduled renewal (cron every 4 min) |
| `kapital_bank/api.py` | `BIRBankClient` — HTTP wrapper with auto token refresh on 401 |
| `kapital_bank/bank_api.py` | Registry loading, fuzzy matching, transaction import (largest module) |
| `kapital_bank/payment_api.py` | Outbound transfer execution, status polling, cancellation |
| `kapital_bank/mapping.py` | Purpose-based GL mapping + multi-currency Journal Entry creation |
| `kapital_bank/setup.py` | Custom field injection on Bank Transaction, Bank Account, Payment Request |
| `kapital_bank/overrides/payment_request.py` | Wraps `before_submit()` to survive wkhtmltopdf failures during email send |
| `kapital_bank/hooks.py` | Frappe hooks: doctype_js, scheduler_events, doc_events |

### Client-Side Modules

| File | Purpose |
|---|---|
| `client/bank_transaction.js` | Bank Transaction import UI: date/source selection, realtime progress, error CSV export |
| `client/payment_entry.js` | Payment Entry import UI (mirrors bank_transaction.js functionality) |
| `client/bank_reconciliation_tool.js` | Adds checkbox selection + "Create & Reconcile" bulk action to BRT |
| `client/mapping.js` | Shared module: purpose search/preview table for mapping workflows |
| `client/payment_order.js` | "Send to Kapital Bank" / "Check Status" / "Cancel" buttons on Payment Order |
| `client/payment_request.js` | Same transfer buttons + KB status indicator on Payment Request |
| `client/kapital_bank_bank_code.js` | "Sync Bank Codes" button on Bank Code list view |

### Data Flow

1. **Auth**: Credentials in `Kapital Bank Login` → JWT tokens stored as encrypted Password fields → auto-refresh on 401, cron renewal every 4 min
2. **Registry**: API data fetched into local doctypes (Account, Card, Customer, Supplier)
3. **Mapping**: Settings child tables link bank entities to ERPNext records (Bank Account, Customer, Supplier, GL Account)
4. **Import**: Statement transactions → fuzzy match party/purpose → create Payment Entry or Bank Transaction + tracking record
5. **Purpose mapping**: Bank Transactions → match purpose/counterparty → create Transaction Mapping → optionally create Journal Entry + auto-reconcile
6. **Outbound payments**: Payment Request → `send_payment_request()` → Kapital Bank Payment (status tracking) → `poll_pending_payments()` cron → auto-create Payment Entry on success
7. **Cleanup**: Doc events on Payment Entry, Journal Entry, Bank Transaction (on_trash/on_cancel) auto-delete associated KB Transaction records

### Outbound Payment Flow

```
Payment Request (Outward, submitted)
  → send_payment_request() validates: KB Account mapping, beneficiary IBAN + Bank Code, party name latinization
  → POST /v2/internal-transfer → creates Kapital Bank Payment (status: "Sent")
  → poll_pending_payments() cron (every 30 min) → GET /internal-transfer/status
  → Success: auto-creates Payment Entry via PR.create_payment_entry()
  → Rejected: logs error, PR stays "Initiated"
  → Cancel: DELETE /internal-transfer (blocked if pending KB Payments exist)
```

### Purpose Mapping Modes

`mapping.py` supports three modes via `create_purpose_mappings()`:
- **Mappings Only**: Creates Transaction Mapping rows (purpose→GL account) without documents
- **Documents & Reconcile**: Creates Journal Entries with exchange rates + auto-reconciles Bank Transactions
- **Both**: Creates mappings AND documents

Priority-based matching in `_find_mapping_for_txn()`: purpose+party > purpose-only > party-only > fallback

### Matching Algorithm

Three-tier party matching with configurable similarity thresholds:
1. Exact VÖEN (tax ID) match
2. Name similarity via `SequenceMatcher` (defaults: customer 90%, supplier 80%, purpose 70%)
3. Optional Azərbaycan character normalization (Ə→E, ə→e, etc.)

### DocTypes

- **Single doctypes**: `Kapital Bank Login` (credentials), `Kapital Bank Settings` (central config hub with mapping child tables)
- **Registry doctypes**: Account, Card, Customer, Supplier — local copies of bank data
- **Child tables**: Account Mapping, Card Mapping, Customer Mapping, Supplier Mapping, Transaction Mapping
- **Tracking**: `Kapital Bank Transaction` — tracks imported Payment Entries/Journal Entries/Bank Transactions by reference_no for deduplication
- **Payment tracking**: `Kapital Bank Payment` — tracks outbound transfer status (Sent → Confirm Wait → Success/Rejected/Cancelled)
- **Routing**: `Kapital Bank Bank Code` — 6-char bank codes for transfer routing (synced from API)
- **Purpose master**: `Kapital Bank Purpose` — unique purpose keywords with direction (Incoming/Outgoing/Both), status (New/Mapped)
- **Utility**: `Kapital Bank API Test` — manual API testing

### Custom Fields Injected on ERPNext Doctypes

- **Bank Transaction**: `kb_currency` (Link to Currency) — for multi-currency matching
- **Bank Account**: `kb_bank_code` (Link to Kapital Bank Bank Code) — required for outbound transfers
- **Payment Request**: `kb_account` (Link to KB Account) + `kb_beneficiary_bank_account` (Link to Bank Account with IBAN)

### Key Patterns

- All `@frappe.whitelist()` functions use `ignore_permissions=True` for system-level operations
- Bulk imports run as background jobs via `frappe.enqueue()` with 10-min timeout
- Progress published via `frappe.publish_realtime()` over Socket.IO (`kb_bt_import_progress`, `kb_bt_import_complete`)
- Sensitive data (tokens, passwords) stored in Password-type fields (encrypted in DB)
- Error logging via `frappe.log_error()` with `_mask()` hiding account numbers (7+ digits → `first3***last3`)
- Party names latinized via `_latinize()` for bank transfers (Azərbaycan → ASCII)
- Card statements limited to 90-day range; cross-account transfers deduplicated by reference_no

### Scheduler Events

- **Every 4 min**: `auth.renew_token` — JWT token renewal
- **Every 30 min**: `payment_api.poll_pending_payments` — check status of outbound transfers

## API Documentation

BIRBank B2B API documentation PDFs are in `birbank_docs/`. The base URL is `https://my.birbank.business/api/b2b`.

Key endpoints: `/accounts`, `/statements/{id}/transactions`, `/card-statements/{id}/transactions`, `/v2/internal-transfer`, `/internal-transfer/status`, `/bank-codes`
