From cd631e1f148831a5e2a08c7973578bd2634bc75e Mon Sep 17 00:00:00 2001 From: Saul Date: Thu, 19 Feb 2026 09:13:53 +0000 Subject: [PATCH] Corregidos errores AEAT E010330 y 20501 en registro Tipo 2 (Hoja D) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Campo BDNS (pos 300-305): rellenado con '000000' en vez de espacios - NIF declarado (pos 18-26): entidades no españolas siempre 9 espacios, corregida comparación codpais Alpha-3 vs codiso Alpha-2 mediante Paises::get() - NIF operador comunitario (pos 264-280): rellenado con código ISO país + VAT para entidades intracomunitarias - Importe criterio de caja (pos 284-299): rellenado con ceros en vez de espacios - Número total de personas (cabecera, pos 136-144): corregido STR_PAD_RIGHT por STR_PAD_LEFT para alinear ceros a la izquierda Co-Authored-By: Claude Opus 4.6 --- Lib/Txt347Export.php | 42 +++++++++++++++++++++++++++++++++--------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/Lib/Txt347Export.php b/Lib/Txt347Export.php index 602e361..2418ae2 100644 --- a/Lib/Txt347Export.php +++ b/Lib/Txt347Export.php @@ -19,6 +19,7 @@ namespace FacturaScripts\Plugins\Modelo347\Lib; +use FacturaScripts\Core\DataSrc\Paises; use FacturaScripts\Core\Tools; use FacturaScripts\Dinamic\Model\Ejercicio; use FacturaScripts\Dinamic\Model\Empresa; @@ -57,14 +58,35 @@ public static function export(string $codejercicio, array $customersData, array protected static function checkCifNif(array $item): string { - if (strtoupper($item['codpais']) !== 'ES' - && false === in_array(strtoupper($item['tipoidfiscal']), ['DNI', 'CIF', 'NIF'])) { + if (false === self::isSpanish($item['codpais'] ?? '')) { return self::formatString('', 9, ' ', STR_PAD_RIGHT); } return self::formatString($item['cifnif'], 9, '0', STR_PAD_RIGHT); } + protected static function isSpanish(string $codpais): bool + { + $pais = Paises::get($codpais); + return strtoupper($pais->codiso ?? '') === 'ES'; + } + + protected static function getNifOperadorComunitario(array $item): string + { + $codpais = $item['codpais'] ?? ''; + if (false === self::isSpanish($codpais) && !empty($item['cifnif']) && Paises::miembroUE($codpais)) { + $pais = Paises::get($codpais); + $countryCode = self::formatString($pais->codiso ?? '', 2, ' ', STR_PAD_RIGHT); + $vat = strtoupper(preg_replace('/[^A-Z0-9]/', '', $item['cifnif'])); + $iso = strtoupper($pais->codiso ?? ''); + if (!empty($iso) && str_starts_with($vat, $iso)) { + $vat = substr($vat, strlen($iso)); + } + return $countryCode . self::formatString($vat, 15, ' ', STR_PAD_RIGHT); + } + return self::formatString('', 17, ' ', STR_PAD_RIGHT); + } + protected static function formatAmount(float $amount, int $length, int $align): string { $signed = ($amount < 0.00) ? 'N' : ' '; @@ -115,7 +137,7 @@ protected static function getCompanyData(): string . self::formatString('', 1, ' ', STR_PAD_LEFT) . self::formatString('', 1, ' ', STR_PAD_LEFT) // DECLARACIÓN COMPLEMENTARIA O SUSTITUTIVA . self::formatString('', 13, '0', STR_PAD_RIGHT) // NÚMERO IDENTIFICATIVO DE LA DECLARACIÓN ANTERIOR - . self::formatString(count(self::$customersData) + count(self::$suppliersData), 9, '0', STR_PAD_RIGHT) // NÚMERO TOTAL DE PERSONAS Y ENTIDADES + . self::formatString(count(self::$customersData) + count(self::$suppliersData), 9, '0', STR_PAD_LEFT) // NÚMERO TOTAL DE PERSONAS Y ENTIDADES . self::formatAmount(self::$total, 16, STR_PAD_LEFT) // IMPORTE TOTAL ANUAL DE LAS OPERACIONES . self::formatString('', 9, '0', STR_PAD_RIGHT) // NÚMERO TOTAL DE INMUEBLES . self::formatAmount(0.00, 16, STR_PAD_LEFT) // IMPORTE TOTAL ANUAL DE LAS OPERACIONES DE ARRENDAMIENTO DE LOCALES DE NEGOCIO @@ -157,12 +179,13 @@ protected static function getCustomerData(): string . self::formatAmount(0.00, 16, STR_PAD_LEFT) // IMPORTE PERCIBIDO POR TRANSMISIONES DE INMUEBLES SUJETAS A IVA TERCER TRIMESTRE . self::formatAmount($item['t4'], 16, STR_PAD_LEFT) // IMPORTE DE LAS OPERACIONES CUARTO TRIMESTRE . self::formatAmount(0.00, 16, STR_PAD_LEFT) // IMPORTE PERCIBIDO POR TRANSMISIONES DE INMUEBLES SUJETAS A IVA CUARTO TRIMESTRE - . self::formatString('', 17, ' ', STR_PAD_LEFT) // NIF OPERADOR COMUNITARIO + . self::getNifOperadorComunitario($item) // NIF OPERADOR COMUNITARIO . ' ' // OPERACIONES RÉGIMEN ESPECIAL CRITERIO DE CAJA IVA . ' ' // OPERACIÓN CON INVERSIÓN DEL SUJETO PASIVO . ' ' // OPERACIÓN CON BIENES VINCULADOS O DESTINADOS A VINCULARSE AL RÉGIMEN DE DEPÓSITO DISTINTO DEL ADUANERO - . self::formatString('', 16, ' ', STR_PAD_LEFT) // IMPORTE ANUAL DE LAS OPERACIONES DEVENGADAS CONFORME AL CRITERIO DE CAJA DEL IVA - . self::formatString('', 201, ' ', STR_PAD_LEFT); // BLANCOS + . self::formatAmount(0.00, 16, STR_PAD_LEFT) // IMPORTE ANUAL DE LAS OPERACIONES DEVENGADAS CONFORME AL CRITERIO DE CAJA DEL IVA + . self::formatString('000000', 6, '0', STR_PAD_LEFT) // NUMERO DE CONVOCATORIA BDNS + . self::formatString('', 195, ' ', STR_PAD_LEFT); // BLANCOS } return $txt; } @@ -405,12 +428,13 @@ protected static function getSupplierData(): string . self::formatAmount(0.00, 16, STR_PAD_LEFT) // IMPORTE PERCIBIDO POR TRANSMISIONES DE INMUEBLES SUJETAS A IVA TERCER TRIMESTRE . self::formatAmount($item['t4'], 16, STR_PAD_LEFT) // IMPORTE DE LAS OPERACIONES CUARTO TRIMESTRE . self::formatAmount(0.00, 16, STR_PAD_LEFT) // IMPORTE PERCIBIDO POR TRANSMISIONES DE INMUEBLES SUJETAS A IVA CUARTO TRIMESTRE - . self::formatString('', 17, ' ', STR_PAD_LEFT) // NIF OPERADOR COMUNITARIO + . self::getNifOperadorComunitario($item) // NIF OPERADOR COMUNITARIO . ' ' // OPERACIONES RÉGIMEN ESPECIAL CRITERIO DE CAJA IVA . ' ' // OPERACIÓN CON INVERSIÓN DEL SUJETO PASIVO . ' ' // OPERACIÓN CON BIENES VINCULADOS O DESTINADOS A VINCULARSE AL RÉGIMEN DE DEPÓSITO DISTINTO DEL ADUANERO - . self::formatString('', 16, ' ', STR_PAD_LEFT) // IMPORTE ANUAL DE LAS OPERACIONES DEVENGADAS CONFORME AL CRITERIO DE CAJA DEL IVA - . self::formatString('', 201, ' ', STR_PAD_LEFT); // BLANCOS + . self::formatAmount(0.00, 16, STR_PAD_LEFT) // IMPORTE ANUAL DE LAS OPERACIONES DEVENGADAS CONFORME AL CRITERIO DE CAJA DEL IVA + . self::formatString('000000', 6, '0', STR_PAD_LEFT) // NUMERO DE CONVOCATORIA BDNS + . self::formatString('', 195, ' ', STR_PAD_LEFT); // BLANCOS } return $txt; }