djouamaah/laravel-algeria-invoice
A Laravel package for generating and managing Algerian invoices, with helpers for invoice data, totals, and tax details. It integrates cleanly into Laravel apps to simplify billing workflows for Algerian businesses.
Install the package, publish its config, and run migrations before issuing anything:
composer require djouamaah/laravel-algeria-invoice
php artisan vendor:publish --tag=algeria-invoice-config # confirm exact tag in README
php artisan migrate
composer require mpdf/mpdf # optional, PDF only
Look first at config/algeria-invoice.php; it controls the stamp-duty behaviour (mode, exempt_up_to, minimum, maximum, base), template registration, and likely series/locale defaults. Then inspect the package migrations to see which fields are persisted, and finally the package’s invoice/calculation service to confirm the exact method names. The release notes describe behaviour rather than a full API, so verify the builder/facade names in the README before wiring it into production.
The first useful use case is a cash sale invoice with mixed VAT rates:
19, 9, or exempt.template: 'classic', 'modern', or 'minimal', and a document language (ar, fr, en).Treat this first invoice as a smoke test: verify the number format (FA-2026-00001), the per-rate VAT breakdown, the stamp-duty line, the amount-in-words output, and the RTL layout in the PDF.
Wrap the package in an application-level action. Do not scatter invoice calls through controllers. Create an IssueInvoice action or service that accepts your Order/Sale model, maps it to the package payload, calls the calculator, persists a snapshot, and returns the document. This keeps legal formatting, numbering, and config access in one place.
Use the package calculator as the source of truth for totals. Call it for checkout previews and again at issuance. Persist the computed subtotal, VAT per rate, stamp duty, total, and net-to-pay rather than recalculating from product prices later. Store all amounts as integer centimes and convert only at display/import boundaries.
Model VAT per rate, not per invoice. The package supports 19%, 9%, and exempt lines. Group invoice lines by rate for the tax breakdown, and make sure rounding happens per rate group, not only on the grand total. Store the rate on each line so historical invoices remain explainable.
Separate document types and series. Invoices, credit notes (Avoir), and proforma invoices should use distinct series. A credit note should reference the original invoice number and date. Proforma documents should be visibly marked as non-tax documents even though they receive a sequential number. Keep the numbering call inside the same database transaction that persists the document.
Snapshot everything needed to re-render. Persist seller/buyer details, line items, VAT rates, computed totals, stamp-duty amount, template name, language, invoice date, and the config values that affected stamp duty. Config changes must not alter already-issued documents.
Choose templates per call, with a whitelist. The template: argument makes it easy to select classic, modern, or minimal per document. If you register custom templates in config, validate the requested template against an application whitelist rather than passing user input directly.
Set document language explicitly. Do not rely on the ambient app locale. Pass or set the locale around generation, and persist it so the same invoice can be re-rendered in Arabic, French, or English later. Validation messages are bundled in all three languages, but the active locale determines which one appears.
Generate PDFs on demand or in a queue. HTML preview is cheap and useful for email or admin review. PDF via mPDF is heavier; for bulk generation, queue the job and store the output on a private disk. Guard PDF paths with class_exists(\Mpdf\Mpdf::class) because mPDF is optional.
Test the legal edges. Freeze time at a year boundary, assert gapless numbering under concurrent issuance, verify centime conversion, assert the VAT breakdown for mixed-rate invoices, and snapshot the amount-in-words output for Arabic and French edge cases.
1900.00 for 1,900 DZD; pass 190000. Convert at the UI, import, and PDF-display boundaries only. Check whether config values such as exempt_up_to, minimum, and maximum are also in centimes — the release notes do not make this explicit.mode, base, and thresholds with an accountant before production use. Record which config version was used for each invoice.now()—to determine the year, especially around 31 December.Avoir and keep the original.App::setLocale() can affect validation messages, date formatting, and other requests in long-running workers. Prefer passing the document locale explicitly, or set and restore it around generation.config/algeria-invoice.php in production, run php artisan config:cache. A stale cached config is a common cause of “my stamp-duty change did nothing”.Africa/Algiers for invoice dates and year rollover logic. A UTC timestamp near midnight can put a document in the wrong numbering year.How can I help you explore Laravel packages today?