PHP code example of squareetlabs / laravel-verifactu
1. Go to this page and download the library: Download squareetlabs/laravel-verifactu 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/ */
squareetlabs / laravel-verifactu example snippets
return [
'enabled' => true,
'system_id' => env('VERIFACTU_SYSTEM_ID', '01'),
'default_currency' => 'EUR',
'issuer' => [
'name' => env('VERIFACTU_ISSUER_NAME', ''),
'vat' => env('VERIFACTU_ISSUER_VAT', ''),
],
// Modo Verifactu (true) o NO Verifactu/Requerimiento (false)
'verifactu_mode' => env('VERIFACTU_MODE', true),
// Parámetros del Sistema Informático
'tipo_uso_posible_solo_verifactu' => env('VERIFACTU_TIPO_USO_SOLO_VF', 'N'),
'tipo_uso_posible_multi_ot' => env('VERIFACTU_TIPO_USO_MULTI_OT', 'S'),
'indicador_multiples_ot' => env('VERIFACTU_INDICADOR_MULTI_OT', 'N'),
// Define si se cargan las migraciones del paquete (por defecto false)
'load_migrations' => env('VERIFACTU_LOAD_MIGRATIONS', false),
];
use Squareetlabs\VeriFactu\Services\AeatClientFactory;
use Squareetlabs\VeriFactu\Services\AeatSubmissionResponse;
$client = app(AeatClientFactory::class)->make(
issuer: ['name' => $company->legal_name, 'vat' => $company->tax_id],
representative: config('verifactu.representative'),
);
// Huella y timestamp precalculados de tu propia cadena (ver $record):
$result = $client->sendInvoice($invoice, $previous, [
'hash' => $record->hash,
'generated_at' => $record->generated_at,
]);
// Respuesta tipada: EstadoEnvio, CSV y errores por línea ya parseados
$response = AeatSubmissionResponse::fromClientResult($result);
if ($response->accepted()) {
// EstadoEnvio = Correcto; $response->csv disponible
} else {
Log::warning('AEAT rechazo', ['error' => $response->firstError()]);
}
use Squareetlabs\VeriFactu\Contracts\VeriFactuInvoice;
use Illuminate\Database\Eloquent\Model;
class Invoice extends Model implements VeriFactuInvoice
{
// Implementa los métodos requeridos por la interfaz
public function getInvoiceNumber(): string
{
return $this->invoice_number; // Tu campo personalizado
}
// ... resto de métodos
}
use Squareetlabs\VeriFactu\Http\Requests\StoreInvoiceRequest;
use Squareetlabs\VeriFactu\Models\Invoice;
use Squareetlabs\VeriFactu\Http\Resources\InvoiceResource;
public function store(StoreInvoiceRequest $request)
{
$invoice = Invoice::create($request->validated());
// Opcionalmente puedes asociar breakdowns y recipients
// $invoice->breakdowns()->createMany([...]);
// $invoice->recipients()->createMany([...]);
return new InvoiceResource($invoice->load(['breakdowns', 'recipients']));
}
$invoice = Invoice::create([
'number' => 'INV-002',
'is_first_invoice' => false, // false si no es la primera
'previous_invoice_number' => 'INV-001', // Número de factura anterior
'previous_invoice_date' => '2024-07-01', // Fecha de factura anterior
'previous_invoice_hash' => 'ABC123...', // Hash de factura anterior
// ... otros campos
]);
$invoice = Invoice::create([
'number' => 'INV-SUBS-001',
'is_subsanacion' => true, // Indica que es subsanación
'rejected_invoice_number' => 'INV-REJECTED-001', // Número de factura rechazada
'rejection_date' => '2024-06-30', // Fecha de rechazo
// ... otros campos
]);
$invoice = Invoice::create([
'number' => 'INV-001',
'numero_instalacion' => 'INST-001', // Identificador de instalación
// ... otros campos
]);
$invoice->update([
'aeat_status' => 'ACEPTADA', // Estado de respuesta AEAT
'aeat_response_code' => '0', // Código de respuesta
'aeat_response_message' => 'Registro aceptado', // Mensaje de respuesta
'aeat_registration_date' => now(), // Fecha de registro en AEAT
'aeat_csv' => 'CSV-123456789', // CSV de registro
'has_aeat_warnings' => false, // Si tiene advertencias
]);
$invoice = Invoice::create([
'number' => 'INV-001',
'operation_date' => '2024-07-01', // Fecha de operación (si difiere de date)
'tax_period' => '01', // Período fiscal (01, 02, 0A, etc.)
'external_reference' => 'REF-EXT-123', // Referencia externa opcional
'description' => 'Descripción de la operación',
'status' => 'draft', // Estado interno: draft, sent, accepted, rejected
// ... otros campos
]);
use Squareetlabs\VeriFactu\Models\Invoice;
use Squareetlabs\VeriFactu\Models\Recipient;
use Squareetlabs\VeriFactu\Enums\ForeignIdType;
$invoice = Invoice::create([
'number' => 'INV-INT-001',
'date' => '2024-07-01',
'customer_name' => 'Foreign Customer Ltd',
'customer_tax_id' => null, // Sin NIF para extranjeros
'customer_country' => 'GB', // Código ISO del país
// ... otros campos
]);
// Crear recipient con identificador extranjero
$recipient = Recipient::create([
'invoice_id' => $invoice->id,
'name' => 'Foreign Customer Ltd',
'tax_id' => 'GB123456789', // VAT number del país
'country' => 'GB',
'id_type' => ForeignIdType::VAT_NUMBER, // Tipo de identificador
]);
use Squareetlabs\VeriFactu\Models\Invoice;
use Squareetlabs\VeriFactu\Enums\InvoiceType;
// Factura original
$originalInvoice = Invoice::create([
'number' => 'INV-001',
'date' => '2024-07-01',
'amount' => 100.00,
'tax' => 21.00,
'total' => 121.00,
'type' => InvoiceType::STANDARD,
// ... otros campos
]);
// Factura rectificativa por diferencia
$rectificativeInvoice = Invoice::create([
'number' => 'INV-RECT-001',
'date' => '2024-07-15',
'type' => InvoiceType::RECTIFICATIVE_R1,
'rectificative_type' => 'I', // I = Diferencia
'rectified_invoices' => ['INV-001'], // Facturas rectificadas
'rectification_amount' => [
'base' => -20.00, // Diferencia en base
'tax' => -4.20, // Diferencia en impuesto
'total' => -24.20 // Diferencia total
],
'amount' => -20.00, // Importe negativo
'tax' => -4.20,
'total' => -24.20,
// ... otros campos
]);
$invoice = Invoice::create([
'number' => 'INV-001',
'date' => '2024-07-01',
'numero_instalacion' => 'INST-001', // Identificador de instalación
'issuer_name' => 'Empresa Principal S.A.',
'issuer_tax_id' => 'B12345678',
// ... otros campos
]);
// Otra factura de diferente instalación pero mismo emisor
$invoice2 = Invoice::create([
'number' => 'INV-002',
'date' => '2024-07-01',
'numero_instalacion' => 'INST-002', // Diferente instalación
'issuer_name' => 'Empresa Principal S.A.',
'issuer_tax_id' => 'B12345678', // Mismo NIF emisor
// ... otros campos
]);
use Squareetlabs\VeriFactu\Http\Requests\StoreBreakdownRequest;
use Squareetlabs\VeriFactu\Models\Breakdown;
public function storeBreakdown(StoreBreakdownRequest $request)
{
$breakdown = Breakdown::create($request->validated());
return response()->json($breakdown);
}
use Squareetlabs\VeriFactu\Helpers\QrUrlHelper;
use Squareetlabs\VeriFactu\Models\Invoice;
// Obtener la factura
$invoice = Invoice::find(1);
// Generar URL para QR en modo VERIFACTU (producción)
$qrUrl = QrUrlHelper::build(
$invoice,
'B12345678', // NIF del emisor
true, // true = producción, false = pruebas
true // true = VERIFACTU, false = NO VERIFACTU
);
// Resultado: https://www2.agenciatributaria.gob.es/wlpl/TIKE-CONT/ValidarQR?nif=B12345678&numserie=FAC-001&fecha=15-01-2024&importe=121.00
// Usa la configuración por defecto del modo
$qrUrl = QrUrlHelper::build($invoice, 'B12345678', true);
use Squareetlabs\VeriFactu\Helpers\QrUrlHelper;
use Squareetlabs\VeriFactu\Models\Invoice;
class InvoiceQrController extends Controller
{
public function generateQr($invoiceId)
{
$invoice = Invoice::findOrFail($invoiceId);
$issuerVat = config('verifactu.issuer.vat');
$isProduction = app()->environment('production');
$qrUrl = QrUrlHelper::build($invoice, $issuerVat, $isProduction);
// Generar el código QR usando alguna librería (ej: SimpleSoftwareIO/simple-qrcode)
// $qrCode = QrCode::size(300)->generate($qrUrl);
return response()->json([
'url' => $qrUrl,
// 'qr_image' => $qrCode
]);
}
}
// app/Events/InvoiceSentToAeat.php
namespace App\Events;
use Squareetlabs\VeriFactu\Models\Invoice;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class InvoiceSentToAeat
{
use Dispatchable, SerializesModels;
public function __construct(public Invoice $invoice, public array $aeatResponse) {}
}
use App\Events\InvoiceSentToAeat;
// ... después de enviar a AEAT
InvoiceSentToAeat::dispatch($invoice, $result);
// app/Listeners/LogAeatResponse.php
namespace App\Listeners;
use App\Events\InvoiceSentToAeat;
use Illuminate\Support\Facades\Log;
class LogAeatResponse
{
public function handle(InvoiceSentToAeat $event)
{
Log::info('AEAT response', [
'invoice_id' => $event->invoice->id,
'response' => $event->aeatResponse,
]);
}
}
public function update(Request $request, Invoice $invoice)
{
$this->authorize('update', $invoice);
// ...
}
// app/Notifications/InvoiceSentNotification.php
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Squareetlabs\VeriFactu\Models\Invoice;
class InvoiceSentNotification extends Notification
{
use Queueable;
public function __construct(public Invoice $invoice) {}
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new \Illuminate\Notifications\Messages\MailMessage)
->subject('Invoice Sent to AEAT')
->line('Invoice #' . $this->invoice->number . ' was sent to AEAT successfully.');
}
}
use Squareetlabs\VeriFactu\Models\Invoice;
use App\Jobs\SendInvoiceToAeatJob;
// Despacha el job a la cola
SendInvoiceToAeatJob::dispatch($invoice->id);
use Illuminate\Contracts\Queue\ShouldQueue;
class SendInvoiceToAeatJob implements ShouldQueue
{
// ...
}
use OwenIt\Auditing\Contracts\Auditable;
class Invoice extends Model implements Auditable
{
use \OwenIt\Auditing\Auditable;
// ...
}