297 lines
14 KiB
Markdown
297 lines
14 KiB
Markdown
# CLAUDE.md
|
||
|
||
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
||
|
||
## Overview
|
||
|
||
Invoice Az is a Frappe application that integrates with Azerbaijan's e-taxes.gov.az system for:
|
||
- Downloading and importing purchase invoices from e-taxes
|
||
- Downloading and importing sales invoices from e-taxes
|
||
- Sending sales invoices to e-taxes with ASAN Imza signing
|
||
- Importing VAT Account operations and creating Journal Entries
|
||
- Managing authentication via ASAN Login with automatic token renewal
|
||
|
||
## Development Commands
|
||
|
||
### Linting and Code Quality
|
||
```bash
|
||
# Run ruff for Python linting
|
||
ruff check invoice_az/
|
||
|
||
# Run ruff format
|
||
ruff format invoice_az/
|
||
|
||
# Run pre-commit hooks (includes ruff, eslint, prettier, pyupgrade)
|
||
pre-commit run --all-files
|
||
```
|
||
|
||
### Testing
|
||
```bash
|
||
# Run unit tests for a specific doctype
|
||
bench run-tests --app invoice_az --doctype "E-Taxes Item"
|
||
|
||
# Run all tests for the app
|
||
bench run-tests --app invoice_az
|
||
```
|
||
|
||
### Development
|
||
```bash
|
||
# Clear cache after making changes
|
||
bench clear-cache
|
||
|
||
# Restart workers after API changes
|
||
bench restart
|
||
|
||
# Watch logs
|
||
bench --site [site-name] console
|
||
```
|
||
|
||
## Architecture
|
||
|
||
### Core Modules
|
||
|
||
1. **Authentication Module** (`invoice_az/auth.py`)
|
||
- ASAN Login integration for Azerbaijan government authentication
|
||
- Token management with automatic renewal every 4 minutes via cron job
|
||
- Activity tracking to prevent unnecessary token renewals
|
||
- Retry logic with exponential backoff for failed requests
|
||
- Token validity checking and automatic refresh on 401 errors
|
||
- Full authentication flow: start auth → poll status → get certificates → select taxpayer
|
||
- Key functions: `renew_token()`, `get_auth_token()`, `check_auth_status()`, `get_certificates()`, `choose_taxpayer()`, `check_token_validity()`, `handle_unauthorized_request()`, `handle_authentication()`, `poll_auth_status()`, `select_certificate()`, `select_taxpayer()`
|
||
|
||
2. **Purchase API** (`invoice_az/api.py`)
|
||
- Download and import purchase invoices from e-taxes
|
||
- Party, item, and unit mapping system
|
||
- Separate Customer and Supplier mapping systems
|
||
- Create Purchase Orders and Purchase Invoices
|
||
- E-Taxes Purchase tracking records
|
||
- Reference data management (sync items, units, parties from e-taxes)
|
||
- Batch invoice processing for loading reference data
|
||
- Auto-matching for items, units, customers, suppliers by name similarity
|
||
|
||
3. **Sales Import API** (`invoice_az/sales_api.py`)
|
||
- Download and import sales invoices from e-taxes outbox
|
||
- Customer mapping system (separate from suppliers)
|
||
- Create Sales Orders and Sales Invoices
|
||
- E-Taxes Sales tracking records
|
||
- Azerbaijani character normalization for matching
|
||
|
||
4. **Sales Send API** (`invoice_az/send_sales_api.py`)
|
||
- Send Sales Invoices to e-taxes system
|
||
- Two-step workflow: create draft, then sign with ASAN Imza
|
||
- Generate serial numbers from e-taxes
|
||
- Build invoice payload with product codes and VAT fields
|
||
- E-Taxes Sales Outbox tracking
|
||
- Cancel/remove draft invoices functionality
|
||
- Retry signing for failed/pending invoices
|
||
- Get customer objects by TIN for delivery address selection
|
||
|
||
5. **VAT Operations API** (`invoice_az/vat_api.py`)
|
||
- Import VAT Account operations from e-taxes
|
||
- Import all operations (both income and expense types)
|
||
- Create Journal Entries with configurable account mappings
|
||
- VAT Account Mappings by operation type and expense/income type (Sub uçot hesabı → Sub uçot hesabı, Sub uçot hesabı → Büdcə, etc.)
|
||
- Classification Code support - allows specific account mappings per tax code with priority:
|
||
- Priority 1: Mapping with matching operation_type + expense_income + classification_code
|
||
- Priority 2: Default mapping with matching operation_type + expense_income (empty classification_code)
|
||
- Required mapping configuration - operation fails with error if mapping not found
|
||
- Smart party assignment: adds Customer/Supplier only for Receivable/Payable accounts
|
||
- Customer lookup by TIN
|
||
- E-Taxes VAT Operations tracking
|
||
- Key functions: `get_accounts_for_operation_type()`, `find_account_by_number()`, `create_journal_entry_from_vat_operation()`, `map_operation_type()`
|
||
|
||
6. **VAT Operations Hooks** (`invoice_az/vat_operations.py`)
|
||
- Delete related E-Taxes VAT Operations when Journal Entry is deleted/cancelled
|
||
|
||
### Document Integration (hooks.py)
|
||
|
||
**Extended Doctypes:**
|
||
- Purchase Order - import from e-taxes, delete hooks
|
||
- Purchase Invoice - import from e-taxes
|
||
- Sales Order - import from e-taxes, delete hooks
|
||
- Sales Invoice - send to e-taxes, delete hooks
|
||
- Journal Entry - import VAT operations, delete hooks
|
||
- E-Taxes Settings - on_update hook to sync mapped statuses
|
||
|
||
**Client-side Scripts (`invoice_az/client/`):**
|
||
- `purchase_order.js` - E-taxes import buttons and dialogs
|
||
- `purchase_invoice.js` - E-taxes import functionality
|
||
- `sales_order.js` - E-taxes import buttons and dialogs
|
||
- `sales_invoice.js` - Send to e-taxes, sign document, retry signing, cancel buttons
|
||
- `journal_entry.js` - VAT operations import functionality with operation type display
|
||
- `e_taxes_items_list.js` - Sync items from e-taxes
|
||
- `e_taxes_suppliers_list.js` - Sync suppliers from e-taxes
|
||
- `e_taxes_customers_list.js` - Sync customers from e-taxes
|
||
- `e_taxes_unit_list.js` - Sync units from e-taxes
|
||
- `etaxes_common.js` - Shared utilities
|
||
|
||
### Database Schema
|
||
|
||
**Authentication:**
|
||
- **Asan Login** - Stores ASAN credentials, tokens, certificates, auth status
|
||
|
||
**Settings:**
|
||
- **E-Taxes Settings** - Global settings, status mappings, item/party/customer/supplier/VAT account mappings
|
||
|
||
**E-Taxes Entities (cached from e-taxes):**
|
||
- **E-Taxes Item** - Products/services from e-taxes with EQM codes
|
||
- **E-Taxes Parties** - All parties (legacy, for purchases)
|
||
- **E-Taxes Suppliers** - Supplier companies for purchases
|
||
- **E-Taxes Customers** - Customer companies for sales
|
||
- **E-Taxes Unit** - Units of measurement
|
||
- **E-Taxes Item Group** - Product group codes (fixtures)
|
||
- **Classification code** - Tax classification codes from e-taxes (code and description)
|
||
|
||
**Mapping Tables:**
|
||
- **E-Taxes Item Mapping** - Links ERPNext Items to e-taxes items
|
||
- **E-Taxes Party Mapping** - Links ERPNext parties to e-taxes parties (legacy)
|
||
- **E-Taxes Supplier Mappings** - Links ERPNext Suppliers to e-taxes suppliers
|
||
- **E-Taxes Customer Mappings** - Links ERPNext Customers to e-taxes customers
|
||
- **E-Taxes Unit Mapping** - Links ERPNext UOM to e-taxes units
|
||
- **E-Taxes VAT Account Mapping** - Maps VAT operation types to Chart of Accounts (debit/credit), with expense/income type and optional classification code filtering
|
||
|
||
**Tracking Records:**
|
||
- **E-Taxes Purchase** - Tracks imported purchase documents
|
||
- **E-Taxes Sales** - Tracks imported sales documents (from e-taxes)
|
||
- **E-Taxes Sales Outbox** - Tracks sent sales invoices (to e-taxes)
|
||
- **E-Taxes VAT Operations** - Tracks imported VAT operations
|
||
|
||
### Key Features
|
||
|
||
- **Token Renewal**: Automatic token renewal via scheduler (every 4 minutes) with activity check
|
||
- **Token Validity Check**: Verify token validity before API calls, auto-refresh on 401 errors
|
||
- **Activity Tracking**: Records user activity to optimize token renewals
|
||
- **Entity Mapping**: Maps ERPNext items, parties, suppliers, customers, and units to e-taxes equivalents
|
||
- **Auto-Matching**: Automatic matching of items, units, customers, suppliers by name similarity
|
||
- **Bulk Operations**: Support for syncing multiple entities at once
|
||
- **Batch Processing**: Load reference data from invoices in batches
|
||
- **Error Handling**: Comprehensive error logging and user-friendly error messages
|
||
- **Azerbaijani Support**: Character normalization for Ə, Ü, Ö, Ğ, İ, Ç, Ş characters
|
||
- **Two-step Signing**: Create draft invoice, then sign with ASAN Imza
|
||
- **Retry Signing**: Retry signing for failed/pending invoices
|
||
- **VAT Import**: Import VAT account operations as Journal Entries with configurable account mappings
|
||
- **VAT Account Mappings**: Configure debit/credit accounts by operation type and expense/income type (Sub uçot hesabı → Sub uçot hesabı, Sub uçot hesabı → Büdcə, etc.)
|
||
- **Smart Party Assignment**: Automatically adds party (Customer/Supplier) only for Receivable/Payable accounts
|
||
|
||
### API Endpoints (E-Taxes)
|
||
|
||
**Base URL:** `https://new.e-taxes.gov.az`
|
||
|
||
- `/api/po/auth/public/v1/*` - Authentication endpoints
|
||
- `/api/po/invoice/public/v2/invoice/find.inbox` - Purchase invoices
|
||
- `/api/po/invoice/public/v2/invoice/find.outbox` - Sales invoices (sent)
|
||
- `/api/po/invoice/public/v2/invoice` - Create invoice
|
||
- `/api/po/invoice/public/v1/invoice/sign/withAsanImza` - Sign invoice
|
||
- `/api/po/invoice/public/v1/generateSerialNumber/defaultInvoice` - Generate serial
|
||
- `/api/po/invoice/public/v1/common/removeDrafts` - Remove draft invoices
|
||
- `/api/po/vatacc/public/v1/operation/find.outbox` - VAT operations
|
||
- `/api/po/profile/public/v1/taxpayer/{tin}/object/find` - Customer objects
|
||
- `/api/po/dictionary/public/v1/productGroups/find` - Product groups dictionary
|
||
|
||
### Fixtures
|
||
|
||
- **E-Taxes Item Group** - Pre-populated product group codes
|
||
|
||
### Install Hooks
|
||
|
||
- `after_install` and `after_migrate` both call `setup_token_renewal()` to ensure scheduler is configured
|
||
|
||
### Security Considerations
|
||
|
||
- All API endpoints are whitelisted with `@frappe.whitelist()`
|
||
- Token storage uses Frappe's password field type
|
||
- Activity tracking prevents unnecessary API calls
|
||
- Retry logic includes exponential backoff to prevent API flooding
|
||
- Automatic token refresh on 401 errors
|
||
|
||
### Important Files
|
||
|
||
- `invoice_az/hooks.py` - App configuration, event hooks, scheduler setup, and fixtures (~310 lines)
|
||
- `invoice_az/auth.py` - Authentication and token management (~970 lines)
|
||
- `invoice_az/api.py` - Purchase invoice API and reference data management (~4460 lines)
|
||
- `invoice_az/sales_api.py` - Sales invoice import API (~890 lines)
|
||
- `invoice_az/send_sales_api.py` - Sales invoice send API (~1060 lines)
|
||
- `invoice_az/vat_api.py` - VAT operations import API (~620 lines)
|
||
- `invoice_az/vat_operations.py` - VAT operations hooks (~40 lines)
|
||
- `invoice_az/client/*.js` - Client-side functionality for UI enhancements
|
||
- `invoice_az/invoice_az/doctype/*/` - Custom doctype definitions
|
||
- `invoice_az/fixtures/e_taxes_item_group.json` - Item group fixtures
|
||
|
||
### Workflow: Importing Purchases
|
||
|
||
1. User opens Purchase Order/Invoice list
|
||
2. Clicks "Import from E-Taxes" button
|
||
3. System fetches invoices from e-taxes inbox
|
||
4. User selects invoice to import
|
||
5. System validates mappings (items, suppliers, units)
|
||
6. Creates Purchase Order with items
|
||
7. Creates E-Taxes Purchase tracking record
|
||
|
||
### Workflow: Importing Sales (from E-Taxes)
|
||
|
||
1. User opens Sales Order list
|
||
2. Clicks "Import from E-Taxes" button
|
||
3. System fetches invoices from e-taxes outbox
|
||
4. User selects invoice to import
|
||
5. System validates mappings (items, customers, units)
|
||
6. Creates Sales Order and Sales Invoice
|
||
7. Creates E-Taxes Sales tracking record
|
||
|
||
### Workflow: Sending Sales Invoice to E-Taxes
|
||
|
||
1. User creates and submits Sales Invoice
|
||
2. Fills customer_object_name field (required for delivery address)
|
||
3. Clicks "Send to E-Taxes" button
|
||
4. System generates serial number
|
||
5. Creates draft invoice on e-taxes
|
||
6. User clicks "Sign Document" button
|
||
7. System signs with ASAN Imza
|
||
8. E-Taxes Sales Outbox record updated
|
||
|
||
**Retry/Cancel:**
|
||
- If signing fails, user can click "Retry Signing" button
|
||
- User can cancel draft invoice using "Cancel on E-Taxes" button
|
||
|
||
### Workflow: Importing VAT Operations
|
||
|
||
1. User opens Journal Entry list
|
||
2. Clicks "Import VAT from E-Taxes" button
|
||
3. Selects date range
|
||
4. System fetches all VAT operations (both income and expense types)
|
||
5. System shows operation selection dialog with columns:
|
||
- Date, TIN, Name, Operation Type, Classification Code, Amount
|
||
6. Creates Journal Entries using account mappings:
|
||
- API returns technical operation types (SUB_TO_SUB, etc.) which are mapped to Azerbaijani names
|
||
- API returns taxCodeInfo with code (e.g., "114117") and description
|
||
- Looks up mapping in E-Taxes Settings with priority:
|
||
- First: operation_type + classification_code (if taxCodeInfo.code exists)
|
||
- Second: operation_type + empty classification_code (default mapping)
|
||
- If mapping not found, operation fails with error (shown in error log)
|
||
- Automatically adds party (Customer) only if account type is Receivable/Payable
|
||
- Supports different debit/credit accounts for different operation types and classification codes
|
||
7. Creates E-Taxes VAT Operations tracking records
|
||
|
||
**VAT Account Mapping Configuration:**
|
||
- Configure in E-Taxes Settings > VAT Account Mappings tab
|
||
- Each mapping specifies: operation type, expense/income type (required), classification code (optional), debit account, credit account
|
||
- Expense/Income field: Select "Expense" or "Income" to distinguish between expense and income operations
|
||
- Classification Code field links to Classification code doctype
|
||
- Uniqueness: Each combination of operation_type + expense_income + classification_code must be unique
|
||
- Priority logic:
|
||
- System determines expense/income type from API data (income > 0 → Income, expense > 0 → Expense)
|
||
- If classification_code is set: mapping applies only to operations with matching taxCodeInfo.code
|
||
- If classification_code is empty: mapping is default for this operation type
|
||
- System searches with priority: specific classification_code first, then default (empty)
|
||
- All searches include expense_income filter
|
||
- Supported operation types:
|
||
- Sub uçot hesabı → Sub uçot hesabı (SUB_TO_SUB in API)
|
||
- Naməlum → digər Sub hesab (UNKNOWN_TO_OTHER_SUB in API)
|
||
- Cari → Sub uçot hesabı (CURRENT_TO_SUB in API)
|
||
- Cari → Naməlum (CURRENT_TO_UNKNOWN in API)
|
||
- Sub uçot hesabı → İdxal (SUB_TO_IMPORT in API)
|
||
- Naməlum → İdxal (UNKNOWN_TO_IMPORT in API)
|
||
- Sub uçot hesabı → Büdcə (SUB_TO_BUDGET and AUTO in API)
|
||
- Naməlum → Büdcə (UNKNOWN_TO_BUDGET in API)
|
||
|
||
**Note:** AUTO operation types from API are automatically mapped to "Sub uçot hesabı → Büdcə" (SUB_TO_BUDGET).
|