greenter/xml
Genera XML UBL 2.0/2.1 para comprobantes electrónicos con Greenter. Ideal para facturas, boletas y otros documentos en formato estándar, listo para integrarse con tus flujos de emisión electrónica. Documentación y soporte en greenter.dev.
Installation
composer require greenter/xml
Ensure your Laravel project has PHP 7.2+ and ext-dom enabled.
First Use Case: Generating a Basic Invoice
use Greenter\Xml\FacturaElectronica\Factura;
use Greenter\Xml\FacturaElectronica\Items\Item;
$factura = new Factura();
$factura->setTipoOperacion('01'); // 01: Venta interna
$factura->setSerie('F001');
$factura->setNumero('001-2023');
$factura->setFechaEmision(new \DateTime('now'));
$factura->setMoneda('PEN');
$factura->setTipoMoneda('01'); // 01: Soles
$factura->setTotal(100.00);
$item = new Item();
$item->setDescripcion('Producto de prueba');
$item->setCantidad(1);
$item->setUnidadMedida('NIU'); // Unidades
$item->setPrecioUnitario(100.00);
$factura->addItem($item);
// Generate XML
$xml = $factura->generate();
file_put_contents('factura.xml', $xml);
Where to Look First
src/Greenter/Xml/FacturaElectronica/ for core classes (e.g., Factura, Boleta, NotaCredito).src/Greenter/Xml/Common/ for reusable components like Direccion, Emisor, Receptor.Document Generation Pipeline
// 1. Create document base
$factura = new Factura();
$factura->setEmisor(new Emisor('12345678901', 'EMPRESA S.A.', 'Lima'));
// 2. Add metadata
$factura->setReceptor(new Receptor('98765432109', 'CLIENTE S.A.', 'Lima'));
$factura->setItems([$item1, $item2]);
// 3. Validate (SUNAT rules)
if ($factura->validate()) {
$xml = $factura->generate();
$factura->sign($privateKey, $certificate); // Optional: Sign XML
Storage::put('comprobantes/' . $factura->getNumero() . '.xml', $xml);
}
Integration with SUNAT API
// After generating XML, send to SUNAT for validation/approval
$response = Http::post('https://e-factura.sunat.gob.pe/ol-sunat/...', [
'file' => new \Illuminate\Http\File('factura.xml'),
'ruc' => '12345678901',
]);
Batch Processing
// Generate multiple documents in a loop
foreach ($invoices as $invoice) {
$factura = new Factura($invoice);
$xml = $factura->generate();
// Queue for SUNAT submission or storage
}
Service Provider Binding
// app/Providers/AppServiceProvider.php
public function register()
{
$this->app->bind(Factura::class, function ($app) {
return new Factura(config('sunat.ruc'), config('sunat.razon_social'));
});
}
Form Request Validation
// app/Http/Requests/GenerateInvoiceRequest.php
public function rules()
{
return [
'items.*.descripcion' => 'required|string|max:255',
'items.*.cantidad' => 'required|numeric|min:0',
// SUNAT-specific rules
'tipo_operacion' => 'required|in:01,02,03,04,05,06,07,08',
];
}
Queued Jobs for SUNAT Submission
// app/Jobs/SendToSunat.php
public function handle()
{
$xml = $this->factura->generate();
Http::post('https://e-factura.sunat.gob.pe/...', [
'file' => new File($xml),
]);
}
SUNAT Schema Validation
Ubigeo in Direccion).FechaEmision must be YYYY-MM-DD).Moneda="USD" with TipoMoneda="01").$factura->validate() and check SUNAT’s technical guide.XML Signature Requirements
FacturaElectronica).Factura::sign(), but you must:
RUC matches the emitter’s RUC.openssl pkcs12 -info -in cert.p12 to verify the certificate.DateTime Formatting
YYYY-MM-DD format. Laravel’s Carbon may output Y-m-d H:i:s.$factura->setFechaEmision((new \DateTime())->format('Y-m-d'));
Character Encoding
UTF-8).generate() call:
$dom = new \DOMDocument('1.0', 'UTF-8');
$dom->loadXML($xml);
$xml = $dom->saveXML();
Ubigeo Validation
Ubigeo (geographic code) must be 9 digits (e.g., 150101 for Lima).if (!preg_match('/^\d{9}$/', $ubigeo)) {
throw new \InvalidArgumentException('Ubigeo inválido');
}
Validate XML Against SUNAT Schema
$schema = new \DOMDocument();
$schema->load('https://e-factura.sunat.gob.pe/ubr/ schemas/ sunat/pe/niub/2.0/niub.xsd');
$validator = new \DOMDocument();
$validator->loadXML($xml);
$errors = $validator->schemaValidate($schema);
if (!$errors) {
// Valid
}
Log Generated XML for Manual Review
\Log::debug('Generated XML:', [
'content' => $xml,
'length' => strlen($xml),
]);
Common Errors and Fixes
| Error | Cause | Solution |
|---|---|---|
Invalid RUC |
RUC not 11 digits or invalid | Use 12345678901 (valid format) |
FechaEmision out of range |
Date outside allowed period | Ensure date is within SUNAT’s valid range |
Signature failed |
Invalid certificate/key | Regenerate PFX from SUNAT portal |
Total mismatch |
Sum of items ≠ Total |
Recalculate Total manually |
Custom Document Types
Greenter\Xml\BaseDocument to support non-SUNAT XML:
class CustomDocument extends BaseDocument {
public function generate(): string {
$this->setRoot('CustomRoot');
return parent::generate();
}
}
Dynamic Item Validation
validateItem() in your document class to add business rules:
protected function validateItem(Item $item): bool {
if ($item->getPrecioUnitario() > 10000) {
throw new \RuntimeException('Precio
How can I help you explore Laravel packages today?