Invoices
ZATCA Invoice System Documentation
Table of Contents
Invoice Setup
Creating Invoices
Submitting Invoices
Returns and Credit Notes
Status Checking
Available Methods
Important Notes
Invoice Setup
Adding ZATCA Invoice Capability
First, add the HasZatcaInvoice trait to your model:
use Hazem\Zatca\Traits\HasZatcaInvoice;
class Order extends Model
{
use HasZatcaInvoice;
protected function prepareZatcaInvoiceData()
{
$items = $this->prepareZatcaItems();
return [
'invoice_number' => $this->invoice_no,
'total_amount' => round($this->final_total, 2),
'vat_amount' => collect($items)->sum(function ($item) {
return round($item['vat'] * $item['quantity'], 2);
}),
'is_pos' => true,
'is_invoice' => $this->type === 'sell',
'items' => $items,
'date' => $this->transaction_date,
// Buyer information
'buyer_name' => $this->contact->name ?? null,
'buyer_tax_number' => null,
'buyer_address' => null,
'buyer_city' => null,
'buyer_state' => null,
'buyer_postal' => null,
'buyer_building_no' => null
];
}
protected function prepareZatcaItems()
{
return $this->sell_lines->map(function($item) {
return [
'name' => $item->product?->name,
'quantity' => $item->quantity,
'price' => round($item->unit_price, 2),
'vat' => round(round($item->unit_price, 2) * 0.15, 2)
];
})->toArray();
}
}
Important Note: Always round monetary values to 2 decimal places to ensure accuracy in calculations.
Creating Invoices
Using the Fluent Interface
The fluent interface provides a clean and chainable way to create invoices:
$invoice = Zatca::prepare()
->setInvoiceNumber('INV-001') // Unique invoice number
->setTotalAmount(115.00) // Total including VAT
->setVatAmount(15.00) // VAT amount
->setBuyerName('John Doe') // Customer name
->setBuyerTaxNumber('1234567890') // Customer VAT number
->setBuyerAddress('123 Main St') // Customer address
->setBuyerCity('Riyadh') // Customer city
->setBuyerState('Riyadh') // Customer state/region
->setBuyerPostal('12345') // Customer postal code
->setBuyerBuildingNumber('1234') // Customer building number
->isPOS() // Mark as POS transaction
->isInvoice(true) // true for sales, false for returns
->setDate(now()) // Transaction date
->addItem('Product 1', 1, 100.00, 15.00); // Add items
Pro Tip: You can chain multiple
addItem()
calls to add multiple products to the invoice.
Submitting Invoices
There are two methods to submit invoices to ZATCA:
1. Basic Submission
$result = $order->submitToZatca($invoice->toArray());
2. Custom Data Submission
$result = $order->submitToZatca([
'invoice_number' => 'INV-001',
'total_amount' => 115.00,
'vat_amount' => 15.00,
'items' => [
[
'name' => 'Product 1',
'quantity' => 1,
'price' => 100.00,
'vat' => 15.00
]
]
]);
Best Practice: Always validate your data before submission to avoid rejection.
Returns and Credit Notes
To create a return/credit note invoice:
$returnInvoice = Zatca::prepare()
->setInvoiceNumber('RET-001') // Unique return number
->setTotalAmount(-115.00) // Negative amount for returns
->setVatAmount(-15.00) // Negative VAT for returns
->setBuyerName('John Doe')
->isPOS()
->isInvoice(false) // Mark as return/credit note
->setDate(now())
->addItem('Product 1', 1, -100.00, -15.00); // Negative values
$result = $order->submitToZatca($returnInvoice->toArray());
Critical Notes for Returns:
All monetary values must be negative
Reference the original invoice number when possible
Use a unique return/credit note number
Keep the same VAT rate as the original invoice
Status Checking
Monitor your invoice status:
// Check submission status
if ($order->isSubmittedToZatca()) {
// Get current status
$status = $order->getZatcaStatus();
// Check for errors
if ($order->hasZatcaErrors()) {
$errors = $order->getZatcaErrors();
}
}
Available Methods
Invoice Operations
// Zatca Facade Methods
Zatca::prepare(); // Start new invoice
Zatca::submitInvoice($businessId, $invoiceData); // Submit regular invoice
Zatca::submitSimplifiedInvoice($businessId, $data); // Submit simplified invoice
Zatca::submitStandardInvoice($businessId, $data); // Submit standard invoice
Zatca::getInvoiceStatus($businessId, $invoiceNo); // Check status
Zatca::validateInvoice($invoiceData); // Validate before submit
Zatca::generateQRCode($invoiceData); // Generate QR code
// Model Methods (HasZatcaInvoice Trait)
$model->order(); // Get order relationship
$model->submitToZatca(); // Submit invoice
$model->isSubmittedToZatca(); // Check submission status
$model->getZatcaStatus(); // Get invoice status
$model->hasZatcaErrors(); // Check for errors
$model->getZatcaErrors(); // Get error details
Important Notes
General Guidelines
Data Accuracy
Always validate data before submission
Use proper rounding for monetary values
Ensure all required fields are filled
Error Handling
Always check for errors after submission
Log all errors for debugging
Implement proper error handling in your code
Performance
Consider implementing queueing for bulk submissions
Cache device information when possible
Monitor API rate limits
Common Pitfalls to Avoid
Not handling decimal places properly
Forgetting to mark returns as non-invoices
Missing required buyer information
Incorrect VAT calculations
Not validating data before submission
Best Practices
Data Validation
// Validate before submission $isValid = Zatca::validateInvoice($invoiceData); if ($isValid) { $result = $order->submitToZatca($invoiceData); }
Error Handling
try { $result = $order->submitToZatca($invoiceData); } catch (ZatcaException $e) { Log::error('ZATCA submission failed: ' . $e->getMessage()); // Handle error appropriately }
Status Monitoring
// Implement status checking with retry logic $maxRetries = 3; $attempt = 0; do { $status = $order->getZatcaStatus(); if ($status === 'REPORTED') break; sleep(2); // Wait before retry } while (++$attempt < $maxRetries);
Security Considerations
Store sensitive data securely
Implement proper authentication
Use HTTPS for all API communications
Regular audit of access logs
Proper handling of cryptographic materials
Last updated