SaudiElectronIcinvoice Documentation
Saudi Electronic Invoice Controller Documentation
File: /controllers/saudiElectronIcinvoiceController.php
Purpose: Manages ZATCA (Saudi Arabia Tax Authority) electronic invoice integration and compliance
Last Updated: December 20, 2024
Total Functions: 7 main actions + 3 utility functions
Lines of Code: ~382
---
๐ Overview
The Saudi Electronic Invoice Controller implements the complete ZATCA (Zakat, Tax and Customs Authority) electronic invoicing system for Saudi Arabia tax compliance. This controller handles:
- โข ZATCA API authentication and token management
- โข Device registration and certification
- โข Electronic invoice submission and validation
- โข Compliance testing and production initialization
- โข Integration with existing sales bills
- โข UUID generation and QR code handling
- โข Multi-step setup process for ZATCA compliance
Primary Functions
- โ ZATCA device registration and setup
- โ OTP validation for device activation
- โ Compliance invoice testing (6 test invoices)
- โ Production environment initialization
- โ Sales bill electronic submission
- โ Authentication token management
- โ Invoice tracking and status management
- โ QR code generation for invoices
Related Controllers
- โข sellbillController.php - Sales bill creation
- โข clientController.php - Customer management
- โข productController.php - Product management
---
๐๏ธ Database Tables
Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **saudielectronicinvoice** | ZATCA configuration and settings | id, tokenapi, urlapi, deviceuuid, deviceid, stepnow, endsetup | |
| **esaudiclientsetting** | Client electronic invoice settings | clientid, licensetype, licensenumber, companyname | |
| **etasellbillstatus** | Electronic invoice submission tracking | sellbillid, estatus, submissionid, accepteddocuments, errors |
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **sellbill** | Sales bills for electronic submission | sellbillid, sellbillclientid, sellbilldate, sellbilltotalPayed, visaPayed | |
| **sellbilldetail** | Sales bill line items | sellbilldetailproductid, sellbilldetailquantity, sellbilldetailprice | |
| **product** | Product information for invoices | productId, productName |
-- Electronic invoice settings
saudielectronicinvoice.id = 1 (single configuration record)
-- Client settings for electronic invoicing
esaudiclientsetting.clientid -> client.clientid
-- Invoice submission tracking
etasellbillstatus.sellbillid -> sellbill.sellbillid
---
๐ Key Functions
1. Default Action (empty $do) - Configuration Display
Location: Lines 21-27
Purpose: Display ZATCA configuration interface
Process Flow:
1. Load ZATCA configuration from database
2. Assign configuration to template
3. Display setup interface via saudiElectronIcinvoiceView/saudielectronicinvoice.html
---
2. devices ($do == "devices") - Device Management
Location: Lines 28-33
Purpose: Display registered ZATCA devices
Process Flow:
1. Make API call to /api/v1/zatca/devices
2. Parse JSON response for device list
3. Display devices via template
API Call:
$devices = json_decode(HTTPRequester::HTTPGet($urlapi.'/api/v1/zatca/devices', [], $headers), true);
---
3. devicestatus ($do == "devicestatus") - Device Status Check
Location: Lines 34-39
Purpose: Check status of specific ZATCA device
Parameters:
- โข
deviceuuid- UUID of device to check
API Call:
$device = json_decode(HTTPRequester::HTTPGet($urlapi.'/api/v1/zatca/device-status/'.$_GET['deviceuuid'], [], $headers), true);
---
4. getallinvoices ($do == "getallinvoices") - Invoice Listing
Location: Lines 40-51
Purpose: Retrieve submitted invoices from ZATCA
Parameters:
- โข
status- Invoice status filter (default: 'accepted') - โข
limit- Number of invoices to retrieve (default: 50) - โข
offset- Pagination offset (default: 0)
API Call:
$data = [
'device_uuid' => $saudielectronicinvoice->deviceuuid,
'status' => isset($_POST['status']) ? trim($_POST['status']) : 'accepted',
'limit' => isset($_POST['limit']) ? trim($_POST['limit']) : 50,
'offset' => isset($_POST['offset']) ? trim($_POST['offset']) : 0,
];
$getallinvoices = json_decode(HTTPRequester::HTTPGet($urlapi.'/api/v1/zatca/invoices', $data, $headers), true);
---
5. detail ($do == "detail") - Invoice Detail View
Location: Lines 52-57
Purpose: Display detailed invoice information including XML
Parameters:
- โข
uuid- Invoice UUID to display
API Call:
$invoice = json_decode(HTTPRequester::HTTPGet($urlapi.'/api/v1/zatca/invoice/'.$_GET['uuid'].'?include_xml=true', [], $headers), true);
---
6. update ($do == "update") - Multi-Step ZATCA Setup
Location: Lines 58-203
Purpose: Handle 4-step ZATCA device setup and compliance process
Step 1: Device Registration
- โข Authenticate with ZATCA API
- โข Submit company and device information
- โข Generate CSR (Certificate Signing Request)
- โข Store device UUID and ID
Step 2: OTP Validation
- โข Submit OTP received from ZATCA
- โข Validate device registration
Step 3: Compliance Testing
- โข Submit 6 compliance test invoices
- โข Track progress until all 6 are accepted
Step 4: Production Initialization
- โข Initialize production environment
- โข Mark setup as complete
Process Flow for Each Step:
switch($step){
case 1: // Device Registration
// Authenticate and register device
$result = json_decode(HTTPRequester::HTTPPost($urlapi.'/api/auth/login', $data, $headers), true);
// Generate CSR
$result = json_decode(HTTPRequester::HTTPPost($urlapi.'/api/v1/zatca/generate-csr', $data, $headers), true);
break;
case 2: // OTP Validation
$result = json_decode(HTTPRequester::HTTPPost($urlapi.'/api/v1/zatca/validate-otp', $data, $headers), true);
break;
case 3: // Compliance Testing
$result = json_decode(HTTPRequester::HTTPPost($urlapi.'/api/v1/zatca/send-compliance-invoice', $data, $headers), true);
break;
case 4: // Production Initialization
$result = json_decode(HTTPRequester::HTTPPost($urlapi.'/api/v1/zatca/initialize-production', $data, $headers), true);
break;
}
---
7. etsellbill ($do == "etsellbill") - Electronic Bill Submission
Location: Lines 204-340
Purpose: Submit sales bill to ZATCA for electronic invoicing
Parameters:
- โข
sellbillid- Sales bill ID to submit
Process Flow:
1. Load sales bill and detail data
2. Load client electronic settings
3. Determine payment method based on bill payments
4. Build invoice line items from bill details
5. Generate invoice data structure
6. Submit to ZATCA API
7. Update bill with submission status and QR code
8. Log submission status
Payment Method Mapping:
if($sellbill['isBankAccountTransfer'] > 0){
$payment_method = 42; // Bank transfer
}else if($sellbill['sellbilltotalPayed'] == 0 && $sellbill['visaPayed'] == 0){
$payment_method = 30; // Credit
}else if($sellbill['visaPayed'] > 0 && $sellbill['sellbilltotalPayed'] > 0){
$payment_method = 1; // Mixed payment
}else if($sellbill['visaPayed'] > 0){
$payment_method = 48; // Card payment
}else{
$payment_method = 10; // Cash payment
}
Invoice Data Structure:
$data = [
"device_uuid" => $saudielectronicinvoice->deviceuuid,
"invoice_type_code" => "0200000",
"invoice_subtype_code" => "388",
"invoice_number" => "INV-" . $sellbill['sellbillid'],
"invoice_uuid" => makeUuidFromHex($sellbill['sellbillserial']),
"invoice_counter" => $saudielectronicinvoice->invoicecounter,
"previous_invoice_hash" => $saudielectronicinvoice->previousinvoicehash,
"issue_date" => date("Y-m-d", strtotime($sellbill['sellbilldate'])),
"issue_time" => date("H:i:s", strtotime($sellbill['sellbilldate'])),
"seller_data" => [...], // Company information
"customer_data" => [...], // Customer information (if applicable)
"payment_method" => $payment_method,
"products" => $invoiceLines // Product line items
];
---
๐ Workflows
Workflow 1: ZATCA Device Setup (4-Step Process)
---
Workflow 2: Electronic Invoice Submission
---
๐ URL Routes & Actions
| URL Parameter | Function Called | Description | |
|---|---|---|---|
| `do=` (empty) | Default action | Display ZATCA configuration interface | |
| `do=devices` | Device listing | Show registered ZATCA devices | |
| `do=devicestatus` | Device status | Check specific device status | |
| `do=getallinvoices` | Invoice listing | List submitted invoices | |
| `do=detail` | Invoice detail | Show detailed invoice information | |
| `do=update` | Setup process | Handle 4-step ZATCA setup | |
| `do=etsellbill` | Invoice submission | Submit sales bill to ZATCA |
Device Status (do=devicestatus):
- โข
deviceuuid- Device UUID to check
Invoice Detail (do=detail):
- โข
uuid- Invoice UUID to display
Setup Process (do=update):
- โข
step- Setup step number (1-4) - โข Various configuration parameters based on step
Invoice Submission (do=etsellbill):
- โข
sellbillid- Sales bill ID to submit
---
๐งฎ Calculation Methods
Tax Calculation (15% VAT)
// Applied to all product lines
$array = array(
"tax_percentage" => 15.0,
"tax_code" => "S" // Standard rate
);
UUID Generation
function makeUuidFromHex($hex) {
// Convert to hex if not already
if (!ctype_xdigit($hex)) {
$hex = bin2hex($hex);
}
// Pad to 32 characters (128 bits)
$hex = str_pad($hex, 32, "0");
// Format as UUID
return substr($hex, 0, 8) . "-" .
substr($hex, 8, 4) . "-" .
substr($hex, 12, 4) . "-" .
substr($hex, 16, 4) . "-" .
substr($hex, 20, 12);
}
Token Expiration Check
function istokenexpired() {
if (empty($_SESSION['auth_token']) || empty($_SESSION['auth_token_exp']))
return true;
return (time() >= $_SESSION['auth_token_exp']);
}
---
๐ Security & Permissions
Authentication & Authorization
- โข API Token Authentication: Uses bearer token for ZATCA API access
- โข Session Management: Maintains authentication tokens in session
- โข Token Refresh: Automatic token refresh when expired
// Authentication headers for ZATCA API
$headers = array(
'Accept: application/json',
'Content-Type: application/json',
"Authorization: Bearer $saudielectronicinvoice->tokenapi",
"token: $saudielectronicinvoice->logintoken"
);
// Auto-refresh expired tokens
if (istokenexpired() && $_SESSION['auth_token']) {
$result = refreshtoken();
$authtoken = $_SESSION['auth_token'] = $result['data']['auth_token'];
$_SESSION['auth_token_exp'] = time() + (int)$result['data']['expires_in'];
}
Input Validation
- โข Email validation:
filter_input(INPUT_POST,"loginemail",FILTER_VALIDATE_EMAIL) - โข Parameter sanitization:
trim()applied to user inputs - โข Step validation: Numeric step validation for setup process
---
๐ Performance Considerations
API Rate Limiting
1. Token Management: Reuse tokens until expiration to avoid excessive authentication
2. Batch Operations: Consider batching multiple invoice submissions
3. Error Handling: Implement proper retry logic for API failures
Database Optimization
-- Recommended indexes
CREATE INDEX idx_sellbill_client_date ON sellbill(sellbillclientid, sellbilldate);
CREATE INDEX idx_sellbilldetail_bill ON sellbilldetail(sellbillid);
CREATE INDEX idx_etasellbillstatus_bill ON etasellbillstatus(sellbillid);
---
๐ Common Issues & Troubleshooting
1. Setup Step Failures
Issue: Setup process fails at any step
Cause: API connectivity, invalid data, or ZATCA service issues
Debug:
// Check stored responses
SELECT responsestepone, responsesteptwo, responsestepthree, responsestepfour
FROM saudielectronicinvoice WHERE id = 1;
// Check current step status
SELECT stepnow, endsetup FROM saudielectronicinvoice WHERE id = 1;
2. Token Expiration Issues
Issue: API calls fail with authentication errors
Cause: Expired authentication tokens
Fix:
// Manual token refresh
if (istokenexpired()) {
$result = refreshtoken();
// Update stored token
}
3. Invoice Submission Failures
Issue: Sales bills not accepted by ZATCA
Cause: Invalid customer data, missing fields, or format errors
Debug:
-- Check submission status
SELECT * FROM etasellbillstatus WHERE sellbillid = [BILL_ID];
-- Check bill electronic status
SELECT estatus, ereason, qrerpids FROM sellbill WHERE sellbillid = [BILL_ID];
4. Missing Client Electronic Settings
Issue: Customer invoices fail due to missing settings
Cause: No electronic settings configured for B2B customers
Fix:
-- Check client settings
SELECT * FROM esaudiclientsetting WHERE clientid = [CLIENT_ID];
-- Add required settings for B2B customers
INSERT INTO esaudiclientsetting (clientid, licensetype, licensenumber, companyname, ...) VALUES (...);
---
๐งช Testing Scenarios
Test Case 1: Complete Setup Process
1. Start fresh ZATCA setup (stepnow = 0)
2. Complete Step 1 with valid company data
3. Validate OTP in Step 2
4. Monitor compliance testing in Step 3
5. Initialize production in Step 4
6. Verify endsetup = 1
Test Case 2: Invoice Submission
1. Create test sales bill
2. Configure customer electronic settings (if B2B)
3. Submit bill via etsellbill action
4. Verify ZATCA acceptance
5. Check QR code generation
6. Confirm bill status update
Test Case 3: Error Handling
1. Submit invoice with invalid data
2. Check error logging in etasellbillstatus
3. Verify bill marked with error status
4. Test retry functionality
---
๐ Related Documentation
- โข CLAUDE.md - PHP 8.2 migration guide
- โข sellbillController.md - Sales bill creation
- โข ZATCA API Documentation - Official ZATCA integration guide
- โข Electronic Invoicing Requirements - Saudi Arabia e-invoicing rules
---
Documented By: AI Assistant
Review Status: โ Complete
Next Review: When ZATCA requirements change