34 KiB
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 government systems:
E-Taxes Integration (e-taxes.gov.az):
- 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
- Sending purchase acts to e-taxes for Individual suppliers
- Importing VAT Account operations and creating Journal Entries
- Managing authentication via ASAN Login with automatic token renewal
AMAS Integration (e-social.gov.az):
- Importing employees from AMAS (Azerbaijan Employment Management System)
- MyGovID/ASAN authentication for accessing AMAS
- Automatic employee synchronization with ERPNext
⚠️ CRITICAL RULES FOR E-TAXES INTEGRATION ⚠️
READ THIS BEFORE IMPLEMENTING ANY E-TAXES API CALLS!
1. Authentication Pattern (MANDATORY)
❌ WRONG - Direct API call:
function my_function(frm) {
frappe.call({
method: 'invoice_az.my_api.some_method',
// ... this will fail with "Authentication expired"
});
}
✅ CORRECT - Always wrap with authentication check:
function my_function(frm) {
ETaxes.auth.checkAndProcess(function() {
// Your code here - only runs after auth is verified
frappe.call({
method: 'invoice_az.my_api.some_method',
// ... works correctly
});
});
}
Why? ETaxes.auth.checkAndProcess() does:
- Checks if token is still valid
- If expired → prompts user to login via ASAN Imza
- Only after successful auth → executes your callback
- Prevents "Authentication expired" errors
2. ETaxes Module Inclusion (MANDATORY)
⚠️ ETaxes is NOT a global module! It must be defined in EACH JavaScript file that uses it.
❌ WRONG - Assuming ETaxes exists:
// my_custom_form.js
frappe.ui.form.on('My DocType', {
refresh: function(frm) {
ETaxes.auth.checkAndProcess(function() {
// ERROR: ETaxes is not defined
});
}
});
✅ CORRECT - Include ETaxes module at the top of your JS file:
Copy the entire ETaxes module from sales_invoice.js (lines 1-564) to the beginning of your JS file:
// ======= COPY THIS ENTIRE BLOCK =======
// From sales_invoice.js lines 1-564:
const ETaxes = {
PROGRESS_UPDATE_DELAY: 50,
AUTH_POLL_INTERVAL: 6000,
AUTH_MAX_ATTEMPTS: 20,
// ... (full module definition)
};
ETaxes.utils = { /* ... */ };
ETaxes.dialogs = { /* ... */ };
ETaxes.auth = { /* ... */ };
// ======= END COPY =======
// Now your code can use ETaxes:
frappe.ui.form.on('My DocType', {
refresh: function(frm) {
ETaxes.auth.checkAndProcess(function() {
// ✅ Works correctly
});
}
});
Files that need ETaxes module:
- ✅
sales_invoice.js- has it (564 lines) - ✅
purchase_order.js- has it - ✅
supplier.js- has it (after fix) - ❌ Any new JS file - MUST include it!
3. Backend API Pattern (MANDATORY)
All backend functions that call E-Taxes API MUST follow this pattern:
import frappe
import requests
from invoice_az.auth import record_etaxes_activity, get_default_asan_login
@frappe.whitelist()
def my_etaxes_function(doc_name):
"""My E-Taxes API function"""
try:
# Step 1: ALWAYS record activity (for token renewal)
record_etaxes_activity()
# Step 2: Get document
doc = frappe.get_doc("My DocType", doc_name)
# Step 3: Validate (business logic checks)
validation = validate_my_document(doc)
if not validation.get("valid"):
return {
"success": False,
"message": validation.get("message")
}
# Step 4: Get authentication token
asan_login = get_default_asan_login()
if not asan_login.get("found") or not asan_login.get("main_token"):
return {
"success": False,
"message": "E-Taxes authentication not found. Please login via ASAN."
}
token = asan_login.get("main_token")
# Step 5: Build headers with token
headers = DEFAULT_HEADERS.copy()
headers["x-authorization"] = f"Bearer {token}"
# Step 6: Make API request
response = requests.post(
"https://new.e-taxes.gov.az/api/...",
data=json.dumps(payload),
headers=headers,
timeout=60
)
# Step 7: Handle common errors
if response.status_code == 401:
return {
"success": False,
"message": "Authentication expired. Please login again."
}
if response.status_code == 500:
return {
"success": False,
"message": "E-Taxes service error. Please try again later."
}
if response.status_code == 404:
return {
"success": False,
"message": "Resource not found."
}
response.raise_for_status()
# Step 8: Process response
result = response.json()
# Step 9: Return success
return {
"success": True,
"data": result
}
except requests.exceptions.RequestException as e:
frappe.log_error(
f"Network error: {str(e)}",
"E-Taxes API Error"
)
return {
"success": False,
"message": f"Network error: {str(e)}"
}
except Exception as e:
frappe.log_error(
f"Unexpected error: {str(e)}\n{frappe.get_traceback()}",
"E-Taxes API Error"
)
return {
"success": False,
"message": f"Error: {str(e)}"
}
Key points:
@frappe.whitelist()- ALWAYS required for frontend callsrecord_etaxes_activity()- ALWAYS first (enables token auto-renewal)get_default_asan_login()- Get tokenheaders["x-authorization"] = f"Bearer {token}"- Required for auth- Handle 401, 500, 404 errors explicitly
- ALWAYS return
{"success": bool, "message": str}format - ALWAYS use try-except with proper error logging
4. Constants and URLs
Base URL:
BASE_URL = "https://new.e-taxes.gov.az"
Common endpoints:
- Auth:
/api/po/auth/public/v1/* - Invoices:
/api/po/invoice/public/v2/invoice - Sign:
/api/po/invoice/public/v1/invoice/sign/withAsanImza - Serial:
/api/po/invoice/public/v1/generateSerialNumber/defaultInvoice - Agricultural Serial:
/api/po/invoice/public/v1/act/generateSerialNumber/agriculturalProductsAct - Metal Scrap Serial:
/api/po/invoice/public/v1/act/generateSerialNumber/metalProductsAct - Tire Disposal Serial:
/api/po/invoice/public/v1/act/generateSerialNumber/tireProductsForDisposalAct - Plastic Disposal Serial:
/api/po/invoice/public/v1/act/generateSerialNumber/plasticProductsForDisposalAct - Rawhide Supply Serial:
/api/po/invoice/public/v1/act/generateSerialNumber/rawhideSupply - Other Product Receipt Serial:
/api/po/invoice/public/v1/act/generateSerialNumber/otherProductReceiptAct - All Acts:
/api/po/invoice/public/v1/act - Remove Drafts:
/api/po/invoice/public/v1/common/removeDrafts - VAT Operations:
/api/po/vatacc/public/v1/operation/find.outbox - Taxpayer by FIN:
/api/po/profile/public/v1/taxpayer/findByFinAndPassport
Standard headers:
DEFAULT_HEADERS = {
"Accept": "application/json, text/plain, */*",
"Accept-Language": "en-US,en;q=0.9",
"Content-Type": "application/json",
"Cache-Control": "no-cache",
"Pragma": "no-cache"
}
5. Error Handling
HTTP Status Codes:
200- Success401- Token expired → Show "Please login again"404- Resource not found500- E-Taxes server error → Show "Try again later"
Always check in this order:
if response.status_code == 401:
return {"success": False, "message": "Authentication expired. Please login again."}
if response.status_code == 500:
return {"success": False, "message": "E-Taxes service error. Please try again later."}
if response.status_code == 404:
return {"success": False, "message": "Not found"}
response.raise_for_status() # For other errors
6. Frontend Button Pattern
Always show buttons conditionally:
frappe.ui.form.on('My DocType', {
refresh: function(frm) {
// Only for submitted documents
if (frm.doc.docstatus === 1) {
add_etaxes_buttons(frm);
}
}
});
function add_etaxes_buttons(frm) {
// Check status and show appropriate buttons
if (frm.doc.etaxes_status === 'Sent and Signed') {
frm.add_custom_button(__('View Details'), function() {
// Show details
}, __('E-Taxes'));
} else if (frm.doc.etaxes_status === 'Created, not signed') {
frm.add_custom_button(__('Sign with ASAN Imza'), function() {
// Sign document
}, __('E-Taxes'));
} else {
frm.add_custom_button(__('Send to E-Taxes'), function() {
// Send to E-Taxes
}, __('E-Taxes'));
}
}
7. Build Process
After modifying JavaScript files:
# Build assets
cd /home/frappe/frappe-bench
bench build --app invoice_az
# Clear cache
bench --site site1 clear-cache
After modifying Python files:
# Just clear cache (no build needed)
bench --site site1 clear-cache
8. Common Mistakes to Avoid
❌ Don't do this:
- Call E-Taxes API without
ETaxes.auth.checkAndProcess() - Forget to include ETaxes module in new JS files
- Skip
record_etaxes_activity()in backend functions - Forget to handle 401/500/404 errors
- Use
app_include_jsin hooks.py (doesn't work for doctype-specific code) - Make API calls without Bearer token in headers
✅ Always do this:
- Wrap ALL E-Taxes operations in
ETaxes.auth.checkAndProcess() - Copy ETaxes module (564 lines) to every new JS file
- Call
record_etaxes_activity()first in every API function - Handle 401, 500, 404 explicitly
- Return consistent
{success, message}format - Add
x-authorization: Bearer {token}header - Build assets after JS changes
9. Example Files to Reference
Backend (Python):
- ✅
send_sales_api.py- Perfect example of all patterns - ✅
send_purchase_api.py- Agricultural act example - ✅
supplier_api.py- Simple API call example - ✅
auth.py- Authentication implementation
Frontend (JavaScript):
- ✅
sales_invoice.js- Complete ETaxes module (lines 1-564) - ✅
purchase_invoice.js- Button patterns - ✅
supplier.js- Minimal working example
When in doubt: Look at send_sales_api.py + sales_invoice.js - they contain all correct patterns!
Development Commands
Linting and Code Quality
# 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
# 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
# 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
-
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()
-
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
-
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
-
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
-
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()
-
VAT Operations Hooks (
invoice_az/vat_operations.py)- Delete related E-Taxes VAT Operations when Journal Entry is deleted/cancelled
-
Purchase Send API (
invoice_az/send_purchase_api.py)- Send Purchase Invoices (acts) to e-taxes for Individual suppliers
- Two-step workflow: create draft act, then sign with ASAN Imza
- Support for 6 act types: Agricultural Products, Metal Scrap Reception, Tire Disposal, Plastic Disposal, Rawhide Supply, Other Product Receipt
- Generate serial numbers from e-taxes for each act type
- Build act payload with product group codes and tax types
- E-Taxes Purchase Outbox tracking
- Cancel/remove draft acts functionality
- Retry signing for failed/pending acts
- Tax type validation (some acts allow only "Taxable" items)
-
Supplier API (
invoice_az/supplier_api.py)- Fetch Individual supplier data from E-Taxes by FIN and Passport Serial Number
- Auto-populate supplier fields (full name, phone, date of birth, first name, last name, patronymic)
- Validate supplier type (Individual only)
- Used for completing supplier information before creating purchase acts
-
AMAS Integration API (
invoice_az/amas_api.py)- Connect to AMAS (e-social.gov.az) using MyGovID JWT token
- OAuth flow: JWT token → authorization code → AMAS session
- Fetch employee lists from AMAS with pagination
- Execute AMAS reports (Magusbi reporting system)
- Multi-account support (switch between different company accounts)
- Session management with cookie handling
- Import employees into ERPNext Employee doctype
- Key functions:
connect_amas(),get_employees_report(),import_employees_from_amas(),get_connected_asan_logins()
Document Integration (hooks.py)
Extended Doctypes:
- Purchase Order - import from e-taxes, delete hooks
- Purchase Invoice - import from e-taxes, send acts to e-taxes, delete hooks
- Sales Order - import from e-taxes, delete hooks
- Sales Invoice - send to e-taxes, delete hooks
- Journal Entry - import VAT operations, delete hooks, before_save hook for title
- Supplier - fetch data from e-taxes by FIN/passport
- Employee - import from AMAS, 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 dialogspurchase_invoice.js- E-taxes import functionality, send acts to e-taxes, sign actssales_order.js- E-taxes import buttons and dialogssales_invoice.js- Send to e-taxes, sign document, retry signing, cancel buttonsjournal_entry.js- VAT operations import functionality with operation type displaysupplier.js- Fetch supplier data from e-taxes by FIN/passportemployee.js- Import employees from AMASamas_employees.js- AMAS Employees list functionalitye_taxes_items_list.js- Sync items from e-taxese_taxes_suppliers_list.js- Sync suppliers from e-taxese_taxes_customers_list.js- Sync customers from e-taxese_taxes_unit_list.js- Sync units from e-taxesetaxes_common.js- Shared utilities
Database Schema
Authentication:
- Asan Login - Stores ASAN credentials, tokens, certificates, auth status, MyGovID token, AMAS session
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)
AMAS Entities (cached from AMAS):
- AMAS Employees - Employee records from AMAS (e-social.gov.az) with FIN, name, position, status
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 Purchase Outbox - Tracks sent purchase acts (to e-taxes)
- E-Taxes VAT Operations - Tracks imported VAT operations
Key Features
E-Taxes Integration:
- 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/act, then sign with ASAN Imza
- Retry Signing: Retry signing for failed/pending invoices/acts
- 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
- Purchase Acts: Send 6 types of purchase acts to e-taxes for Individual suppliers
- Supplier Data Fetching: Auto-populate Individual supplier data from e-taxes by FIN/passport
AMAS Integration:
- MyGovID OAuth: Automatic OAuth flow using existing MyGovID token
- Employee Import: Bulk import employees from AMAS to ERPNext
- Multi-Account Support: Switch between different company accounts in AMAS
- Session Management: Cookie-based session handling with automatic renewal
- Duplicate Detection: Prevents duplicate employee imports by FIN
- Status Tracking: Import employment status (Active/Inactive/Terminated)
API Endpoints
E-Taxes (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/act- Create/manage acts/api/po/invoice/public/v1/act/generateSerialNumber/*- Generate act serials/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/findByFinAndPassport- Find taxpayer by FIN/api/po/profile/public/v1/taxpayer/{tin}/object/find- Customer objects/api/po/dictionary/public/v1/productGroups/find- Product groups dictionary
AMAS (https://eroom.e-social.gov.az):
/ssoAsan/v2- ASAN SSO callback/service/aas.changeAccount- Switch company accounts/service/magusbi.executeReport- Execute employee reports/service/aas.domains- Get available domains/request/accounts- Get available accounts
MyGovID (https://api.mygovid.gov.az):
/ssoauth/oauth2/auth/codes- Get authorization codes for OAuth
Fixtures
- E-Taxes Item Group - Pre-populated product group codes (for purchase acts)
- Classification code - Pre-populated tax classification codes from e-taxes (for VAT operations)
Install Hooks
after_install- Callssetup_token_renewal()andinstall_custom_fields()to configure scheduler and add custom fieldsafter_migrate- Callssetup_token_renewal(),create_journal_entry_custom_fields(), andcreate_supplier_custom_fields()to ensure scheduler and custom fields are up to date
Custom Fields Added:
- Purchase Invoice:
purchase_type,act_kind,product_group_code,tax_type,etaxes_status,etaxes_document_id,serial_number,seller_tin,buyer_tin - Sales Invoice:
customer_object_name,etaxes_status,etaxes_document_id,serial_number,seller_tin,buyer_tin - Journal Entry:
etaxes_vat_operation,customer_name_from_vat(for title display) - Supplier:
fin,passport_serial_number,date_of_birth,first_name,last_name,patronymic(for Individual suppliers and acts)
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
Backend (Python):
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/send_purchase_api.py- Purchase acts send API (~800 lines)invoice_az/supplier_api.py- Supplier data fetching API (~150 lines)invoice_az/vat_api.py- VAT operations import API (~620 lines)invoice_az/vat_operations.py- VAT operations hooks (~40 lines)invoice_az/amas_api.py- AMAS integration API (~500 lines)invoice_az/install.py- Custom field installation
Frontend (JavaScript):
invoice_az/client/*.js- Client-side functionality for UI enhancementsinvoice_az/client/sales_invoice.js- Send sales invoices to e-taxesinvoice_az/client/purchase_invoice.js- Send purchase acts to e-taxesinvoice_az/client/supplier.js- Fetch supplier data from e-taxesinvoice_az/client/employee.js- Import employees from AMAS
Doctypes:
invoice_az/invoice_az/doctype/*/- Custom doctype definitions
Fixtures:
invoice_az/fixtures/e_taxes_item_group.json- Item group fixturesinvoice_az/fixtures/classification_code.json- Classification code fixtures
Workflow: Importing Purchases
- User opens Purchase Order/Invoice list
- Clicks "Import from E-Taxes" button
- System fetches invoices from e-taxes inbox
- User selects invoice to import
- System validates mappings (items, suppliers, units)
- Creates Purchase Order with items
- Creates E-Taxes Purchase tracking record
Workflow: Importing Sales (from E-Taxes)
- User opens Sales Order list
- Clicks "Import from E-Taxes" button
- System fetches invoices from e-taxes outbox
- User selects invoice to import
- System validates mappings (items, customers, units)
- Creates Sales Order and Sales Invoice
- Creates E-Taxes Sales tracking record
Workflow: Sending Sales Invoice to E-Taxes
- User creates and submits Sales Invoice
- Fills customer_object_name field (required for delivery address)
- Clicks "Send to E-Taxes" button
- System generates serial number
- Creates draft invoice on e-taxes
- User clicks "Sign Document" button
- System signs with ASAN Imza
- 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: Sending Purchase Acts to E-Taxes
Supported act types for Purchase Invoices with Individual suppliers:
-
Agricultural Products Act - For agricultural goods (kind: "agriculturalProductsAct")
- Tax types: "Tax Free" (0%) or "Taxable" (5%)
- Endpoint:
/api/po/invoice/public/v1/act/generateSerialNumber/agriculturalProductsAct
-
Metal Scrap Reception Act - For ferrous/non-ferrous metal scrap (kind: "metalProductsAct")
- Tax types: Only "Taxable" (5%) - tax-free items not allowed
- Validation: All items must have tax_type = "Taxable"
- Endpoint:
/api/po/invoice/public/v1/act/generateSerialNumber/metalProductsAct
-
Tire Products For Disposal Act - For tire disposal operations (kind: "tireProductsForDisposalAct")
- Tax types: Only "Taxable" (5%) - tax-free items not allowed
- Validation: All items must have tax_type = "Taxable"
- Endpoint:
/api/po/invoice/public/v1/act/generateSerialNumber/tireProductsForDisposalAct
-
Plastic Products For Disposal Act - For plastic disposal operations (kind: "plasticProductsForDisposalAct")
- Tax types: Only "Taxable" (5%) - tax-free items not allowed
- Validation: All items must have tax_type = "Taxable"
- Endpoint:
/api/po/invoice/public/v1/act/generateSerialNumber/plasticProductsForDisposalAct
-
Rawhide Supply - For rawhide supply operations (kind: "rawhideSupply")
- Tax types: Only "Taxable" (5%) - tax-free items not allowed
- Validation: All items must have tax_type = "Taxable"
- Endpoint:
/api/po/invoice/public/v1/act/generateSerialNumber/rawhideSupply
-
Other Product Receipt Act - For other product receipts (kind: "otherProductReceiptAct")
- Tax types: "Tax Free" (0%) or "Taxable" (5%) - both allowed
- Validation: No tax type restrictions (same as Agricultural)
- Endpoint:
/api/po/invoice/public/v1/act/generateSerialNumber/otherProductReceiptAct
Workflow:
- User creates and submits Purchase Invoice
- Selects Individual supplier (with FIN, passport, DOB)
- Checks
purchase_typecheckbox to enable act fields - Selects
act_kind(one of 6 available types) - Adds items with product_group_code and tax_type
- Clicks "Send Act to E-Taxes" button (button text changes based on act_kind)
- System generates serial number from appropriate endpoint
- Creates draft act on e-taxes
- User clicks "Sign Act with ASAN Imza" button
- System signs with ASAN Imza
- E-Taxes Purchase Outbox record updated
Retry/Cancel:
- If signing fails, user can click "Retry Signing" button
- User can cancel draft act using "Cancel Act on E-Taxes" button
Workflow: Importing VAT Operations
- User opens Journal Entry list
- Clicks "Import VAT from E-Taxes" button
- Selects date range
- System fetches all VAT operations (both income and expense types)
- System shows operation selection dialog with columns:
- Date, TIN, Name, Operation Type, Classification Code, Amount
- 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
- 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).
Workflow: Importing Employees from AMAS
AMAS (e-social.gov.az) is Azerbaijan's Employment Management System maintained by the Ministry of Labour and Social Protection.
Prerequisites:
- User must have MyGovID authentication (same as ASAN Login)
- AMAS connection must be established in Asan Login
Workflow:
- User opens Asan Login
- Clicks "Connect to AMAS" button (uses existing MyGovID token)
- System performs OAuth flow:
- Gets authorization code from MyGovID API
- Exchanges code for AMAS session
- Stores AMAS cookies in Asan Login
- User opens Employee list
- Clicks "Load from AMAS" button
- System fetches employee list from AMAS (up to 1000 records)
- System displays employee selection dialog with:
- FIN, Full Name, Position, Employment Status
- User selects employees to import
- System creates/updates ERPNext Employee records
- Creates AMAS Employees tracking records
Key Features:
- Automatic MyGovID authentication reuse
- Multi-account support (can switch between company accounts in AMAS)
- Pagination support for large employee lists
- Duplicate detection (checks existing employees by FIN)
- Status tracking (Active/Inactive/Terminated)
AMAS API Endpoints:
- Base URL:
https://eroom.e-social.gov.az - SSO Callback:
/ssoAsan/v2 - Execute Report:
/service/magusbi.executeReport - Change Account:
/service/aas.changeAccount - Get Accounts:
/request/accounts
MyGovID OAuth:
- API URL:
https://api.mygovid.gov.az - Auth Codes:
/ssoauth/oauth2/auth/codes - Client ID:
64942e33ec8d49059333a1e0ebad7fe2
Workflow: Fetching Supplier Data from E-Taxes
For Individual suppliers, the system can auto-populate supplier information from E-Taxes.
Prerequisites:
- Supplier must be type "Individual"
- FIN field must be filled
- Passport Serial Number field must be filled
Workflow:
- User creates new Supplier (type: Individual)
- Fills FIN and Passport Serial Number
- Clicks "Fetch Data from E-Taxes" button
- System calls
/api/po/profile/public/v1/taxpayer/findByFinAndPassport - System auto-populates fields:
- Full Name
- Phone
- Date of Birth
- First Name
- Last Name
- Patronymic
- User can now use this supplier for Purchase Invoices with acts