agdar/ZATCA_EINVOICE_IMPLEMENTATION.md
2025-11-02 14:35:35 +03:00

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):
    1. Seller's Name
    2. VAT Registration Number
    3. Timestamp (ISO 8601 format)
    4. Invoice Total (with VAT)
    5. 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 Note
    • STANDARD_CREDIT - Standard Credit Note
    • SIMPLIFIED_DEBIT - Simplified Debit Note
    • SIMPLIFIED_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

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 signatures
  • zatca_status - Clearance/Reporting status
  • zatca_submission_date - Submission timestamp
  • zatca_response - JSON field for API responses
  • xml_content - UBL 2.1 XML storage
  • issue_time - Precise timestamp

Database Schema Changes

New Fields Added to Invoice Model:

  1. invoice_counter - PositiveIntegerField (indexed)
  2. invoice_type - CharField with choices
  3. billing_reference_id - CharField
  4. billing_reference_issue_date - DateField
  5. issue_time - TimeField
  6. invoice_hash - CharField (64 chars)
  7. previous_invoice_hash - CharField (64 chars)
  8. qr_code - TextField
  9. cryptographic_stamp - TextField
  10. zatca_status - CharField
  11. zatca_submission_date - DateTimeField
  12. zatca_response - JSONField
  13. xml_content - TextField

Indexes Added:

  • invoice_counter - For performance
  • invoice_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

  1. CSID Storage: Store CSIDs and secrets securely (encrypted)
  2. Private Keys: Never export private keys
  3. API Credentials: Use environment variables
  4. Audit Logging: Log all ZATCA interactions
  5. 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

  1. ZATCA Documentation:

    • E-Invoicing Detailed Technical Guideline
    • User Manual Developer Portal Manual Version 3
    • Fatoora Portal User Manual
  2. API Endpoints:

  3. 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:


Document Version: 1.0
Last Updated: October 27, 2025
Author: Cline AI Assistant
Project: AgdarCentre Healthcare Platform