Hazem-Zatca
  • Get Started
  • Quick Start Guide
  • Invoices
  • Devices
  • Connect us
Powered by GitBook
On this page
  • ZATCA Invoice System Documentation
  • Table of Contents
  • Invoice Setup
  • Creating Invoices
  • Submitting Invoices
  • Returns and Credit Notes
  • Status Checking
  • Available Methods
  • Important Notes

Invoices

ZATCA Invoice System Documentation

Table of Contents

  1. Invoice Setup

  2. Creating Invoices

  3. Submitting Invoices

  4. Returns and Credit Notes

  5. Status Checking

  6. Available Methods

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

  1. Data Accuracy

    • Always validate data before submission

    • Use proper rounding for monetary values

    • Ensure all required fields are filled

  2. Error Handling

    • Always check for errors after submission

    • Log all errors for debugging

    • Implement proper error handling in your code

  3. Performance

    • Consider implementing queueing for bulk submissions

    • Cache device information when possible

    • Monitor API rate limits

Common Pitfalls to Avoid

  1. Not handling decimal places properly

  2. Forgetting to mark returns as non-invoices

  3. Missing required buyer information

  4. Incorrect VAT calculations

  5. Not validating data before submission

Best Practices

  1. Data Validation

    // Validate before submission
    $isValid = Zatca::validateInvoice($invoiceData);
    if ($isValid) {
        $result = $order->submitToZatca($invoiceData);
    }
  2. Error Handling

    try {
        $result = $order->submitToZatca($invoiceData);
    } catch (ZatcaException $e) {
        Log::error('ZATCA submission failed: ' . $e->getMessage());
        // Handle error appropriately
    }
  3. 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

  1. Store sensitive data securely

  2. Implement proper authentication

  3. Use HTTPS for all API communications

  4. Regular audit of access logs

  5. Proper handling of cryptographic materials

PreviousQuick Start GuideNextDevices

Last updated 3 months ago