Search by

webrteu / invoicing

webrteu

Core invoicing abstraction for Laravel (Romania): one API for SmartBill, e-Factura and more

v2.0.1 2026-11-04 05:08 UTC

This package is auto-updated.

Last update: 2026-11-04 05:09:10 UTC


README

PHP Laravel Licență MIT Packagist

Facturare pentru orice proiect Laravel: facturi fiscale și proforme, numerotare proprie pe serii, TVA calculat pe linii și pe cote, PDF din șablonul propriu (dompdf), anulare, tabela invoices legată de orice model din aplicație. Furnizorii externi se adaugă cu pachete separate, cu aceeași interfață: webrteu/smartbill, iar mai târziu pachetul pentru factura.webrt.eu.

Opțional, emite factura automat când webrteu/payments confirmă o plată.

Versiunea 2.x e o rescriere. 1.x era legată de aplicația Auditor (Order, Client, servicii de audit, Filament). Aplicațiile pe 1.x rămân pe ^1.0.

Cerințe

  • PHP ^8.2, Laravel 12–13
  • opțional: webrteu/smartbill (furnizor), webrteu/payments (emitere automată la plată)

Instalare

composer require webrteu/invoicing
php artisan vendor:publish --tag=invoicing-config
php artisan vendor:publish --tag=invoicing-migrations
php artisan migrate
php artisan vendor:publish --tag=invoicing-views   # doar dacă vrei să modifici șablonul PDF

Configurare

INVOICING_PROVIDER=local          # local (numerotare proprie) | smartbill | ...

INVOICING_SELLER_NAME="Firma Mea SRL"
INVOICING_SELLER_CUI=RO12345678
INVOICING_SELLER_REG_COM=J40/123/2020
INVOICING_SELLER_ADDRESS="Str. Exemplu 1"
INVOICING_SELLER_CITY=București
INVOICING_SELLER_COUNTY=București
INVOICING_SELLER_EMAIL=facturi@firma.ro
INVOICING_SELLER_PHONE=
INVOICING_SELLER_BANK="Banca Transilvania"
INVOICING_SELLER_IBAN=RO49AAAA1B31007593840000
INVOICING_SELLER_VAT_PAYER=true   # false = neplătitor de TVA: cota 0 pe toate liniile, automat

INVOICING_SERIES_FISCAL=FACT      # seriile furnizorului local
INVOICING_SERIES_PROFORMA=PROF

INVOICING_PDF_SOURCE=local        # local = șablonul propriu | provider = PDF-ul furnizorului (ex. SmartBill)
INVOICING_PDF_DISK=local          # disk privat: facturile conțin date personale
INVOICING_PDF_LOGO=/cale/absoluta/logo.png
INVOICING_PDF_FOOTER="Factură valabilă fără semnătură și ștampilă."

INVOICING_AUTO_ISSUE=false        # true = factura la fiecare plată Paid (webrteu/payments)

Datele vânzătorului se salvează pe fiecare factură, deci o schimbare ulterioară în .env nu modifică facturile vechi.

Utilizare

use WeBRTeu\Invoicing\Data\InvoiceData;
use WeBRTeu\Invoicing\Data\InvoiceLineData;
use WeBRTeu\Invoicing\Data\PartyData;
use WeBRTeu\Invoicing\Enums\InvoiceType;
use WeBRTeu\Invoicing\Facades\Invoicing;

$invoice = Invoicing::issue(new InvoiceData(
    type: InvoiceType::Fiscal,                                   // sau InvoiceType::Proforma
    buyer: new PartyData('Client SRL', cui: 'RO987654', regCom: 'J12/3/2021', address: 'Str. Mare 2', city: 'Cluj-Napoca', county: 'Cluj', email: 'client@srl.ro'),
    lines: [
        new InvoiceLineData('Tricou', unitPrice: 5000, quantity: 2, code: 'T-1'),   // 50,00 lei cu TVA 21% inclus
        new InvoiceLineData('Livrare', unitPrice: 1500, isService: true),
        new InvoiceLineData('Consultanță', unitPrice: 20000, quantity: 1.5, unit: 'ore', priceIncludesVat: false),
    ],
    reference: $order->number,
), invoiceable: $order);

$invoice->fullNumber();          // "FACT-0001"
$invoice->total;                 // în bani
return response(Invoicing::pdf($invoice), 200, ['Content-Type' => 'application/pdf']);
  • Sumele sunt în bani (int). TVA-ul se calculează și se rotunjește pe linie. Cota implicită e 21%, iar per linie poți pune vatRate: 11 sau 0.
  • Persoană fizică: new PartyData('Ion Popescu', email: ..., city: ...), fără CUI.
  • issueDate implicit e azi, iar dueDate e azi + invoicing.due_days (15; null = fără scadență).
  • La eroarea furnizorului rândul rămâne cu status Failed, cu mesajul în error, iar excepția e aruncată mai departe. Fără retry automat, ca să nu se emită de două ori.
Metodă Ce face
Invoicing::issue($data, $invoiceable, provider: null) emite factura și întoarce modelul Invoice
Invoicing::cancel($invoice) anulează la furnizor și marchează Cancelled
Invoicing::pdf($invoice, source: null) PDF-ul (bytes), din local sau provider; implicit din config
Invoicing::html($invoice) HTML-ul șablonului, pentru previzualizare
Invoicing::provider('smartbill') furnizorul, pentru metodele lui specifice
NumberSequence::set('FACT', 120) continuă numerotarea locală de la 121 (mutare de pe alt program)

PDF

Șablonul invoicing::pdf.invoice e generic, în română sau engleză (după language din InvoiceData), cu diacritice (DejaVu Sans), logo și subsol. Îl publici cu --tag=invoicing-views și îl modifici, sau pui alt view în invoicing.pdf.view.

Cu pdf.store = true, PDF-ul se salvează la prima generare (invoices/{sursa}/{tip}-{număr}.pdf pe disk-ul din config) și se refolosește. Cu SmartBill poți avea ambele variante: Invoicing::pdf($invoice, 'local') (șablonul tău, cu numărul SmartBill) sau Invoicing::pdf($invoice, 'provider') (PDF-ul SmartBill).

Emitere automată la plată

class Order extends Model implements \WeBRTeu\Invoicing\Contracts\Invoiceable
{
    public function toInvoiceData(InvoiceType $type): InvoiceData
    {
        return new InvoiceData($type, buyer: ..., lines: ..., reference: $this->number);
    }
}

Cu INVOICING_AUTO_ISSUE=true, când o plată webrteu/payments legată de comandă (payable) devine Paid, se emite factura (tipul și furnizorul din invoicing.auto_issue), o singură dată per comandă. O eroare se loghează (invoicing.auto_issue_failed) și nu oprește procesarea plății.

Evenimente

  • InvoiceIssued($invoice): ex. trimiți factura pe email
  • InvoiceCancelled($invoice)

Furnizor propriu

class MyProvider implements \WeBRTeu\Invoicing\Contracts\InvoiceProvider   // + ProvidesPdf, opțional
{
    public function name(): string { return 'my'; }
    public function issue(InvoiceData $invoice): IssuedInvoiceData { /* ... */ }
    public function cancel(Invoice $invoice): void { /* ... */ }
}

Invoicing::extend('my', fn ($app) => $app->make(MyProvider::class));   // în service provider

Ce nu face pachetul

  • e-Factura / SPV (pachet separat)
  • interfață de administrare: o faci în proiect (Filament, Livewire)
  • storno automat: o factură fiscală trimisă clientului se stornează cu o factură nouă, cu cantități negative
  • emailuri: ascultă InvoiceIssued

Testare

composer test

Changelog

Vezi CHANGELOG.md.

Autor

WeBRTeu

Licență

MIT. Vezi LICENSE.md.