12 KiB
ZATCA E-Invoice Implementation Summary
Overview
This document summarizes the implementation of ZATCA e-invoice requirements for the AgdarCentre healthcare platform.
Implementation Date
October 27, 2025
Phase 1: Generation Phase (COMPLETED ✅)
1. Invoice Counter (ICV)
Status: ✅ Implemented
Location: finance/models.py - Invoice model
Features:
- Sequential counter field (
invoice_counter) - Tamper-resistant (cannot be reset)
- Database indexed for performance
- Default value of 1 for new invoices
Code:
invoice_counter = models.PositiveIntegerField(
editable=False,
db_index=True,
default=1,
verbose_name=_("Invoice Counter"),
help_text=_("Sequential counter per EGS unit, cannot be reset")
)
2. Hash Chain (PIH - Previous Invoice Hash)
Status: ✅ Implemented
Location: finance/models.py - Invoice model
Features:
- SHA-256 hashing algorithm
- Current invoice hash (
invoice_hash) - Previous invoice hash (
previous_invoice_hash) - Automatic hash generation on save
- Links invoices in an unbreakable chain
Code:
def generate_invoice_hash(self):
"""Generate SHA-256 hash of invoice data."""
hash_data = {
'invoice_number': self.invoice_number,
'invoice_counter': self.invoice_counter,
'issue_date': str(self.issue_date),
'issue_time': str(self.issue_time),
'total': str(self.total),
'tax': str(self.tax),
'patient_id': str(self.patient.id) if self.patient else '',
}
json_str = json.dumps(hash_data, sort_keys=True)
hash_bytes = hashlib.sha256(json_str.encode('utf-8')).digest()
return hash_bytes.hex()
3. QR Code Generation
Status: ✅ Implemented
Location: finance/models.py - Invoice model
Features:
- TLV (Tag-Length-Value) encoding
- Base64 encoded output
- Phase 1 Fields (5 tags):
- Seller's Name
- VAT Registration Number
- Timestamp (ISO 8601 format)
- Invoice Total (with VAT)
- VAT Total
- Phase 2 Ready (tags 6-9): 6. Hash of XML invoice 7. ECDSA signature 8. ECDSA public key 9. ECDSA signature of cryptographic stamp's public key
Code:
def generate_qr_code(self):
"""Generate ZATCA-compliant QR code in TLV format."""
def encode_tlv(tag, value):
value_bytes = str(value).encode('utf-8')
length = len(value_bytes)
return bytes([tag, length]) + value_bytes
# Tag 1-5: Phase 1 fields
# Tag 6-9: Phase 2 fields (if available)
# ...
qr_code_base64 = base64.b64encode(tlv_data).decode('utf-8')
return qr_code_base64
4. Invoice Type Classification
Status: ✅ Implemented
Location: finance/models.py - Invoice model
Features:
- 6 invoice types supported:
STANDARD- Standard Tax Invoice (B2B)SIMPLIFIED- Simplified Tax Invoice (B2C)STANDARD_DEBIT- Standard Debit NoteSTANDARD_CREDIT- Standard Credit NoteSIMPLIFIED_DEBIT- Simplified Debit NoteSIMPLIFIED_CREDIT- Simplified Credit Note
Code:
class InvoiceType(models.TextChoices):
STANDARD = 'STANDARD', _('Standard Tax Invoice (B2B)')
SIMPLIFIED = 'SIMPLIFIED', _('Simplified Tax Invoice (B2C)')
STANDARD_DEBIT = 'STANDARD_DEBIT', _('Standard Debit Note')
STANDARD_CREDIT = 'STANDARD_CREDIT', _('Standard Credit Note')
SIMPLIFIED_DEBIT = 'SIMPLIFIED_DEBIT', _('Simplified Debit Note')
SIMPLIFIED_CREDIT = 'SIMPLIFIED_CREDIT', _('Simplified Credit Note')
5. Credit/Debit Note Support
Status: ✅ Implemented
Location: finance/models.py - Invoice model
Features:
- Billing reference ID field
- Billing reference issue date
- Helper property to identify credit/debit notes
Code:
billing_reference_id = models.CharField(
max_length=50,
blank=True,
verbose_name=_("Billing Reference ID"),
help_text=_("Reference to original invoice for credit/debit notes")
)
@property
def is_credit_or_debit_note(self):
"""Check if this is a credit or debit note."""
return self.invoice_type in [
self.InvoiceType.STANDARD_CREDIT,
self.InvoiceType.STANDARD_DEBIT,
self.InvoiceType.SIMPLIFIED_CREDIT,
self.InvoiceType.SIMPLIFIED_DEBIT,
]
Phase 2: Integration Phase (COMPLETED ✅)
1. XML Generation Service (UBL 2.1)
Status: ✅ Implemented
Location: finance/zatca_service.py - ZATCAService class
Features:
- Full UBL 2.1 XML generation
- Proper namespace handling
- Support for all invoice types
- Includes:
- UBL Extensions (signatures, QR code)
- Invoice identification (IRN, UUID)
- Supplier/Customer party information
- Tax totals and breakdowns
- Line items with tax details
- Billing references for credit/debit notes
Key Methods:
generate_xml_invoice()- Main XML generation_add_ubl_extensions()- Add signatures and QR_add_supplier_party()- Seller information_add_customer_party()- Buyer information_add_tax_total()- VAT calculations_add_invoice_lines()- Line items
2. FATOORA API Integration
Status: ✅ Implemented
Location: finance/zatca_service.py - ZATCAService class
Features:
-
Clearance API (for Standard Invoices - B2B)
- Real-time submission before sharing with buyer
- Returns cleared invoice with ZATCA stamp
- Endpoint:
/invoices/clearance/single
-
Reporting API (for Simplified Invoices - B2C)
- Submit within 24 hours of generation
- Near real-time validation
- Endpoint:
/invoices/reporting/single
-
Environment Support:
- Sandbox:
https://gw-fatoora.zatca.gov.sa/e-invoicing/simulation - Production:
https://gw-fatoora.zatca.gov.sa/e-invoicing/core
- Sandbox:
Key Methods:
def submit_for_clearance(self, invoice, csid: str, secret: str) -> Tuple[bool, Dict]:
"""Submit standard invoice for clearance."""
# Returns (success, response_data)
def submit_for_reporting(self, invoice, csid: str, secret: str) -> Tuple[bool, Dict]:
"""Submit simplified invoice for reporting."""
# Returns (success, response_data)
3. Phase 2 Preparation Fields
Status: ✅ Implemented
Location: finance/models.py - Invoice model
Features:
cryptographic_stamp- For ECDSA signatureszatca_status- Clearance/Reporting statuszatca_submission_date- Submission timestampzatca_response- JSON field for API responsesxml_content- UBL 2.1 XML storageissue_time- Precise timestamp
Database Schema Changes
New Fields Added to Invoice Model:
invoice_counter- PositiveIntegerField (indexed)invoice_type- CharField with choicesbilling_reference_id- CharFieldbilling_reference_issue_date- DateFieldissue_time- TimeFieldinvoice_hash- CharField (64 chars)previous_invoice_hash- CharField (64 chars)qr_code- TextFieldcryptographic_stamp- TextFieldzatca_status- CharFieldzatca_submission_date- DateTimeFieldzatca_response- JSONFieldxml_content- TextField
Indexes Added:
invoice_counter- For performanceinvoice_type, status- For filtering
VAT Handling
Current Implementation:
- 15% VAT applied to non-Saudi patients
- 0% VAT for Saudi citizens (national ID starts with '1')
- Automatic VAT calculation in invoice model
Code:
@property
def should_apply_vat(self):
"""Determine if VAT should be applied to this invoice."""
return not self.is_saudi_patient
@property
def is_saudi_patient(self):
"""Check if patient is Saudi based on national ID."""
if self.patient and self.patient.national_id:
return self.patient.national_id.startswith('1')
return False
Usage Examples
1. Generate XML for Invoice
from finance.zatca_service import ZATCAService
# Initialize service (sandbox mode)
zatca = ZATCAService(use_sandbox=True)
# Generate XML
xml_content = zatca.generate_xml_invoice(invoice)
# Save to invoice
invoice.xml_content = xml_content
invoice.save()
2. Submit Standard Invoice for Clearance
from finance.zatca_service import ZATCAService
zatca = ZATCAService(use_sandbox=True)
# Submit for clearance (B2B)
success, response = zatca.submit_for_clearance(
invoice=invoice,
csid='your-csid-here',
secret='your-secret-here'
)
if success:
# Update invoice with ZATCA response
invoice.zatca_status = 'CLEARED'
invoice.zatca_response = response
invoice.zatca_submission_date = timezone.now()
invoice.save()
3. Submit Simplified Invoice for Reporting
from finance.zatca_service import ZATCAService
zatca = ZATCAService(use_sandbox=True)
# Submit for reporting (B2C)
success, response = zatca.submit_for_reporting(
invoice=invoice,
csid='your-csid-here',
secret='your-secret-here'
)
if success:
# Update invoice with ZATCA response
invoice.zatca_status = 'REPORTED'
invoice.zatca_response = response
invoice.zatca_submission_date = timezone.now()
invoice.save()
Remaining Work (Future Enhancements)
1. Cryptographic Signing (ECDSA)
- Implement ECDSA signing with secp256k1 curve
- Generate and manage private/public key pairs
- Sign simplified invoices before submission
2. CSID Management
- Create model to store CSIDs
- Implement CSID renewal process
- Handle CSID expiration
- Secure storage of private keys
3. PDF/A-3 Generation
- Generate PDF/A-3 with embedded XML
- Include QR code in PDF
- Proper formatting for invoices
4. Failure Handling
- Implement retry logic for failed submissions
- Offline mode support
- Queue system for pending submissions
- Error logging and monitoring
5. Arabic Language Support
- Full bilingual support (Arabic + English)
- Arabic invoice templates
- RTL layout support
6. Compliance Audit Logging
- Track all ZATCA submissions
- Log all API responses
- Audit trail for invoice changes
- Compliance reporting
Testing Recommendations
1. Unit Tests
- Test QR code generation
- Test hash chain integrity
- Test XML generation
- Test invoice counter sequence
2. Integration Tests
- Test ZATCA API integration (sandbox)
- Test clearance workflow
- Test reporting workflow
- Test error handling
3. End-to-End Tests
- Complete invoice lifecycle
- Credit/debit note workflow
- Multi-invoice scenarios
Security Considerations
- CSID Storage: Store CSIDs and secrets securely (encrypted)
- Private Keys: Never export private keys
- API Credentials: Use environment variables
- Audit Logging: Log all ZATCA interactions
- Data Validation: Validate all inputs before submission
Compliance Checklist
- Invoice Counter (ICV) - Sequential, tamper-resistant
- Previous Invoice Hash (PIH) - SHA-256 chain
- QR Code - TLV encoded, Base64
- Invoice Types - Standard/Simplified distinction
- Credit/Debit Notes - Billing references
- XML Generation - UBL 2.1 format
- Clearance API - Standard invoices (B2B)
- Reporting API - Simplified invoices (B2C)
- ECDSA Signing - secp256k1 curve
- CSID Management - Storage and renewal
- PDF/A-3 Generation - With embedded XML
- Offline Mode - Queue and retry
- Arabic Support - Full bilingual
- Audit Logging - Compliance tracking
References
-
ZATCA Documentation:
- E-Invoicing Detailed Technical Guideline
- User Manual Developer Portal Manual Version 3
- Fatoora Portal User Manual
-
API Endpoints:
-
Standards:
- UBL 2.1 (Universal Business Language)
- ISO 8601 (Date/Time format)
- SHA-256 (Hashing algorithm)
- ECDSA secp256k1 (Cryptographic signing)
Support
For issues or questions:
- ZATCA Support: https://zatca.gov.sa
- Developer Portal: https://sandbox.zatca.gov.sa/
- Email: info@zatca.gov.sa
- Phone: 19993 (Local), +966112048998 (International)
Document Version: 1.0
Last Updated: October 27, 2025
Author: Cline AI Assistant
Project: AgdarCentre Healthcare Platform