1. Go to this page and download the library: Download bee-coded/laravel-efactura library. Choose the download type require.
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
bee-coded / laravel-efactura example snippets
namespace App\Models;
use BeeCoded\EFactura\Contracts\EFacturaUploadableInterface;
use BeeCoded\EFactura\Traits\HasEfacturaUpload;
use BeeCoded\EFacturaSdk\Data\Invoice\InvoiceData;
use BeeCoded\EFacturaSdk\Data\Invoice\PartyData;
use BeeCoded\EFacturaSdk\Data\Invoice\AddressData;
use BeeCoded\EFacturaSdk\Data\Invoice\InvoiceLineData;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model implements EFacturaUploadableInterface
{
use HasEfacturaUpload;
/**
* Transform this model into SDK's InvoiceData DTO.
*/
public function toEfacturaData(): InvoiceData
{
return new InvoiceData(
invoiceNumber: $this->number,
issueDate: $this->issued_at,
dueDate: $this->due_at,
currency: $this->currency,
supplier: new PartyData(
registrationName: $this->company->name,
companyId: $this->company->vat_number,
address: new AddressData(
street: $this->company->address,
city: $this->company->city,
postalZone: $this->company->postal_code,
countryCode: $this->company->country_code,
),
isVatPayer: $this->company->is_vat_payer,
),
customer: new PartyData(
registrationName: $this->customer->name,
companyId: $this->customer->vat_number,
address: new AddressData(
street: $this->customer->address,
city: $this->customer->city,
postalZone: $this->customer->postal_code,
countryCode: $this->customer->country_code,
),
isVatPayer: $this->customer->is_vat_payer,
),
lines: $this->lines->map(fn ($line) => new InvoiceLineData(
name: $line->description,
quantity: $line->quantity,
unitPrice: $line->unit_price,
taxAmount: $line->vat_amount, // Pre-computed VAT for this line
taxPercent: $line->vat_rate,
))->all(),
paymentIban: $this->company->iban,
// BT-111 — the VAT total converted to RON. REQUIRED when currency is not RON,
// and REJECTED when it is. Omit this line entirely if you only ever file in RON.
taxAmountRon: $this->currency === 'RON' ? null : $this->vat_total_ron,
);
}
/**
* Get the CUI for this invoice (determines which token to use).
*/
public function getEfacturaCui(): string
{
return $this->company->cui; // Without RO prefix
}
}
// Relationship
$invoice->efacturaUpload; // The EfacturaUpload model
// Status checks
$invoice->isUploadedToEfactura(); // bool
$invoice->getEfacturaStatus(); // ?UploadStatus enum
$invoice->isEfacturaProcessed(); // bool (completed or failed)
// File paths
$invoice->getEfacturaXmlPath(); // ?string
$invoice->getEfacturaResponsePath(); // ?string
$invoice->getEfacturaErrors(); // ?array
// Query scopes
Invoice::notUploadedToEfactura()->get(); // Not yet queued
Invoice::efacturaPending()->get(); // Queued, awaiting upload
Invoice::efacturaInProgress()->get(); // Currently uploading/processing
Invoice::efacturaCompleted()->get(); // Successfully processed
Invoice::efacturaFailed()->get(); // Failed
Invoice::efacturaProcessed()->get(); // Terminal state (completed or failed)
Invoice::efacturaAwaitingResponse()->get(); // Completed but response not downloaded
Invoice::withEfacturaStatus(UploadStatus::Pending)->get(); // Specific status
// Tax-exclusive pricing (you store the net unit price):
$taxAmount = round(round($quantity * $unitPrice, 2) * $vatRate / 100, 2);
// Tax-inclusive pricing (you store the gross price and extract the net):
$basePrice = round($grossPrice / (1 + $vatRate / 100), 2);
$taxAmount = $grossPrice - $basePrice; // This is what you should pass
// Queue and process immediately
$upload = EFactura::queueUpload($invoice);
EFactura::processUpload($upload);
use BeeCoded\EFacturaSdk\Data\Invoice\ListMessagesParamsData;
use BeeCoded\EFacturaSdk\Enums\DocumentStandardType;
use BeeCoded\EFacturaSdk\Enums\MessageFilter;
$client = EFactura::client('12345678'); // CUI
// Validate XML
$result = $client->validateXml($xml, DocumentStandardType::FACT1);
// Convert to PDF
$pdf = $client->convertXmlToPdf($xml, DocumentStandardType::FACT1);
// Get messages —
use BeeCoded\EFacturaSdk\Facades\AnafDetails;
$company = AnafDetails::getCompanyData('12345678');
$companies = AnafDetails::batchGetCompanyData(['12345678', '87654321']);
// In a controller or Livewire component
return redirect()->route('efactura.auth', ['cui' => '12345678']);
$url = EFactura::getAuthorizationUrl('12345678');
// In EventServiceProvider or a listener
use BeeCoded\EFactura\Events\TokenStored;
Event::listen(TokenStored::class, function (TokenStored $event) {
$token = $event->token;
// Notify user, log, etc.
Log::info("e-Factura authorized for CUI: {$token->cui}");
});
use BeeCoded\EFactura\Jobs\ProcessPendingUploads;
use BeeCoded\EFactura\Jobs\CheckUploadStatuses;
use BeeCoded\EFactura\Jobs\DownloadResponses;
use BeeCoded\EFactura\Jobs\DownloadReceivedInvoices;
use BeeCoded\EFactura\Jobs\SyncMessages;
use BeeCoded\EFactura\Jobs\RetryRateLimitedUploads;
use BeeCoded\EFactura\Jobs\SweepStaleUploads;
->withSchedule(function (Schedule $schedule): void {
// Upload pending invoices to ANAF
$schedule->job(new ProcessPendingUploads)->everyFiveMinutes();
// Check processing status at ANAF
$schedule->job(new CheckUploadStatuses)->everyTenMinutes();
// Download response ZIPs for completed uploads
$schedule->job(new DownloadResponses)->everyFifteenMinutes();
// Retry uploads that failed for a safe-to-resubmit reason (rate limit, auth blip)
$schedule->job(new RetryRateLimitedUploads)->everyTenMinutes();
// Rescue uploads stranded mid-flight by a dead worker (see Reconciliation)
$schedule->job(new SweepStaleUploads)->everyFifteenMinutes();
// Download received invoices (if feature enabled)
$schedule->job(new DownloadReceivedInvoices)->everyFourHours();
// Sync message list from ANAF
$schedule->job(new SyncMessages)->hourly();
})
use BeeCoded\EFactura\Jobs\ProcessSingleUpload;
use BeeCoded\EFactura\Jobs\CheckSingleUploadStatus;
// Queue and dispatch a single upload immediately
$upload = EFactura::queueUpload($invoice);
ProcessSingleUpload::dispatch($upload);
// Check status for a specific upload
CheckSingleUploadStatus::dispatch($upload);
namespace App\Listeners;
use BeeCoded\EFactura\Events\InvoiceFailed;
use App\Notifications\EfacturaFailedNotification;
class HandleFailedInvoice
{
public function handle(InvoiceFailed $event): void
{
$upload = $event->upload;
$errors = $event->errors;
// Get the original invoice
$invoice = $upload->uploadable;
// Notify someone
$invoice->company->owner->notify(
new EfacturaFailedNotification($invoice, $errors)
);
}
}
use BeeCoded\EFactura\Enums\FailureReason;
$upload->failure_reason?->isRetryable(); // will be re-submitted automatically
$upload->failure_reason?->needsReconciliation(); // a human must check ANAF first