# Generación de XML CFDI 4.0 - createXML40()

## Ubicación
`app/Commands/XMLUtils.php` - Método: `createXML40($dataFactura, $proveedor)`

## Propósito
Genera el XML del Comprobante Fiscal Digital por Internet versión 4.0 cumpliendo con el estándar del SAT.

## Parámetros de Entrada

### $dataFactura (Object)
Objeto con todos los datos necesarios para generar la factura:

#### Datos Generales
- `timeStamp` - Fecha y hora de emisión
- `serie` - Serie del comprobante
- `folio` - Folio del comprobante
- `noCertificado` - Número de certificado CSD
- `certificado` - Certificado en base64
- `tipoDeComprobante` - Tipo: I, E, P, N, T
- `exportacion` - Clave de exportación (01, 02, 03, 04)
- `lugarExpedicion` - Código postal de expedición

#### Moneda y Totales
- `moneda` - Código de moneda (MXN, USD, EUR, XXX)
- `tipoCambio` - Tipo de cambio (si moneda != MXN)
- `subtotal` - Subtotal del comprobante
- `total` - Total del comprobante
- `descuento` - Descuento aplicado
- `precission` - Decimales para redondeo (default: 2)

#### Pago
- `formaPago` - Forma de pago (catálogo SAT)
- `metodoDePago` - PUE (Pago en una exhibición) o PPD (Pago en parcialidades)
- `condicionesDePago` - Condiciones de pago (texto libre)

#### Emisor
- `nmbEmisor` - Nombre del emisor
- `rFCEmisor` - RFC del emisor
- `regimenFiscal` - Régimen fiscal del emisor

#### Receptor
- `nmbRecep` - Nombre del receptor
- `rFCRecep` - RFC del receptor
- `usoCFDI` - Uso del CFDI (catálogo SAT)
- `regimenFiscalReceptor` - Régimen fiscal del receptor
- `domicilioFiscalReceptor` - Código postal del receptor
- `numRegIdTrib` - Número de registro de identidad fiscal (extranjero)
- `pais` - Residencia fiscal (extranjero)

#### Conceptos (Array de objetos)
```php
[
    {
        clave: "84111506",              // ClaveProdServ SAT
        cdgItem: "PROD001",             // NoIdentificación (opcional)
        dscItem: "Descripción producto",
        unmdItem: "H87",                // ClaveUnidad SAT
        qtyItem: 1.00,
        montoNetoItem: 100.00,          // ValorUnitario
        prcNetoItem: 100.00,            // Importe
        descuento: 0.00,
        objetoImp: "02",                // ObjetoImp: 01-No objeto, 02-Sí objeto, 03-Sí objeto (no obligado), 04-Sí objeto (no obligado sin desglose)
        peso: 0.00,                     // Para carta porte
        fracArancelaria: "",            // Para comercio exterior
        impuestosTrasladados: [...],
        impuestosRetenidos: [...],
        alumno: {...}                   // Para complemento IEDU
    }
]
```

#### Impuestos Trasladados por Concepto
```php
{
    base: 100.00,
    tipoImp: "002",                // 001-ISR, 002-IVA, 003-IEPS
    factor: "Tasa",                // Tasa, Cuota, Exento
    tasaImp: 0.160000,             // 6 decimales
    montoImp: 16.00,
    tipo: 1                        // 1-Traslado, 0-Retención
}
```

#### Impuestos Retenidos por Concepto
Similar a trasladados pero con `tipo: 0`

#### Impuestos Generales (Resumen)
- `impuestosTrasladados` (Array) - Resumen de impuestos trasladados
- `impuestosRetenidos` (Array) - Resumen de impuestos retenidos
- `totalImpTrasladados` - Total de impuestos trasladados
- `totalImpRetenidos` - Total de impuestos retenidos

#### Complementos Opcionales

**Facturas Relacionadas**
```php
facturasRelacionadas: [
    {
        uuid: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
        tipoRelacion: "01"  // Catálogo SAT
    }
]
```

**Información Global (Público en General)**
```php
infGlobal: {
    anio: 2024,
    meses: "01",
    periodicidad: "01"
}
```

**Comercio Exterior**
```php
comercio: {
    datos: {
        Incoterm: "CFR",
        clavePedimento: "A1",
        tipoOperacion: "2",
        rfcExtranjero: "XEXX010101000",
        totalUSD: 1000.00,
        motivoTraslado: "01",
        curp: ""
    },
    emisor: { /* domicilio */ },
    receptor: { /* domicilio */ }
}
mercanciasComercio: [...]
```

**Carta Porte**
```php
cartaPorte: {
    transpInternac: "No",
    entradaSalidaMerc: "",
    paisOrigenDestino: "",
    viaEntradaSalida: "01",
    pesoBrutoTotal: 100.00,
    unidadPeso: "KGM",
    idccp: "CCC123456",
    totalDistanciaRecorrida: 150.00,
    ubicaciones: [...],
    mercancias: [...],
    autotransporte: {...},
    figurasTransporte: [...]
}
```

**Nómina 1.2**
```php
nomina: {
    Version: "1.2",
    FechaPago: "2024-01-15",
    FechaInicialPago: "2024-01-01",
    FechaFinalPago: "2024-01-15",
    NumDiasPagados: 15,
    TipoNomina: "O",
    Emisor: {...},
    Receptor: {...},
    Percepciones: {...},
    Deducciones: {...},
    OtrosPagos: {...}
}
```

**Pagos 2.0**
```php
pagos: [
    {
        FechaPago: "2024-01-15T10:30:00",
        FormaDePagoP: "03",
        MonedaP: "MXN",
        Monto: 1000.00,
        banco: "012",
        cuenta: "1234",
        documentosRelacionado: [...]
    }
]
```

**INE**
```php
ine: {
    tipoProceso: "Ordinario",
    version: "1.1",
    comite: "Ejecutivo Nacional",
    claveEntidad: "09",
    ambito: "Federal",
    idContabilidad: 123
}
```

**Leyendas Fiscales**
```php
norma: "Art. 29-A fracción VII inciso a CFF",
leyenda: "Efectos fiscales al pago"
```

**Impuestos Locales**
```php
impuestosRetenidosLcl: [...],
impuestosTrasladadosLcl: [...],
impuestosRetenidosLclTotal: 0.00,
impuestosTrasladadosLclTotal: 0.00
```

**Addenda**
```php
addenda: {
    Importe: 1000.00,
    PeriodoEnMeses: 12,
    Descripcion: "Descripción"
}
```

**Timbrado (para regeneración)**
```php
sello: "...",
fechaTimbrado: "2024-01-15T10:30:00",
milisegundos: 123,
uUID: "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX",
noCertificadoSAT: "00001000000123456789",
selloCFD: "...",
selloSAT: "...",
rfcProvCertif: "FIN930514P87"
```

### $proveedor (Object)
Información del proveedor/emisor:
- `id_proveedor` - ID del proveedor
- `rFCEmisor` - RFC
- `nmbEmisor` - Nombre
- `regimenFiscal33` - Régimen fiscal
- `tipoPersona` - 1-Moral, 2-Física
- `keypem` - Ruta al archivo .pem de la llave privada
- `domicilio` - Objeto con datos de domicilio

## Proceso de Generación

### 1. Configuración de Versiones y Namespaces

```php
// Determinar versión de Comercio Exterior
$versionComercionXSD = time() > strtotime('2024-03-08') ? '20' : '11';

// Determinar versión de Carta Porte
if(strtotime($dataFactura->timeStamp) > strtotime('2024-07-17')){
    $cartaVersion = '31';
    $cartaVersionS = '3.1';
} else if(time() > strtotime('2024-03-31')){
    $cartaVersion = '30';
    $cartaVersionS = '3.0';
} else {
    $cartaVersion = '20';
    $cartaVersionS = '2.0';
}
```

### 2. Creación de Namespaces XML

```php
$cfdiNS = new FluidNamespace('cfdi', 'http://www.sat.gob.mx/cfd/4');
$xsiNS = new FluidNamespace('xsi', 'http://www.w3.org/2001/XMLSchema-instance');
$tfdNs = new FluidNamespace('tfd', 'http://www.sat.gob.mx/TimbreFiscalDigital');
$pagosNs = new FluidNamespace('pago20', 'http://www.sat.gob.mx/Pagos20');
$impLNs = new FluidNamespace('implocal', 'http://www.sat.gob.mx/implocal');
$nomLNs = new FluidNamespace('nomina12', 'http://www.sat.gob.mx/nomina12');
$cceLNs = new FluidNamespace("cce$versionComercionXSD", ...);
$cartaNS = new FluidNamespace("cartaporte$cartaVersion", ...);
$leyendasNs = new FluidNamespace('leyendasFisc', ...);
$ineNs = new FluidNamespace('ine', ...);
$ieduNs = new FluidNamespace('iedu', ...);
```

### 3. Construcción del Nodo Raíz (Comprobante)

Atributos principales:
- Version: "4.0"
- Serie, Folio
- Fecha (formato: YYYY-MM-DDTHH:MM:SS)
- NoCertificado, Certificado
- SubTotal, Moneda, Total
- TipoDeComprobante (I, E, P, N, T)
- Exportacion
- FormaPago, MetodoPago (excepto tipo T)
- CondicionesDePago
- Descuento (si aplica)
- TipoCambio (si moneda != MXN && != XXX)
- LugarExpedicion

### 4. CFDIs Relacionados

Si existen facturas relacionadas, se crean nodos:
```xml
<cfdi:CfdiRelacionados TipoRelacion="01">
    <cfdi:CfdiRelacionado UUID="..."/>
</cfdi:CfdiRelacionados>
```

### 5. Información Global

Para público en general (RFC XAXX010101000):
```xml
<cfdi:InformacionGlobal Periodicidad="01" Meses="01" Año="2024"/>
```

### 6. Emisor

```xml
<cfdi:Emisor Rfc="..." Nombre="..." RegimenFiscal="601"/>
```

### 7. Receptor

```xml
<cfdi:Receptor 
    Rfc="..." 
    Nombre="..." 
    UsoCFDI="G03"
    RegimenFiscalReceptor="601"
    DomicilioFiscalReceptor="12345"
    NumRegIdTrib="..."  <!-- Extranjero -->
    ResidenciaFiscal="..." <!-- Extranjero -->
/>
```

### 8. Conceptos

```xml
<cfdi:Conceptos>
    <cfdi:Concepto
        ClaveProdServ="84111506"
        NoIdentificacion="PROD001"
        Cantidad="1"
        ClaveUnidad="H87"
        Unidad="Pieza"
        Descripcion="..."
        ValorUnitario="100.00"
        Importe="100.00"
        Descuento="0.00"
        ObjetoImp="02">
        
        <cfdi:Impuestos>
            <cfdi:Traslados>
                <cfdi:Traslado 
                    Base="100.00"
                    Impuesto="002"
                    TipoFactor="Tasa"
                    TasaOCuota="0.160000"
                    Importe="16.00"/>
            </cfdi:Traslados>
            
            <cfdi:Retenciones>
                <cfdi:Retencion 
                    Base="100.00"
                    Impuesto="002"
                    TipoFactor="Tasa"
                    TasaOCuota="0.040000"
                    Importe="4.00"/>
            </cfdi:Retenciones>
        </cfdi:Impuestos>
        
        <!-- ComplementoConcepto si aplica (IEDU) -->
        <cfdi:ComplementoConcepto>
            <iedu:instEducativas .../>
        </cfdi:ComplementoConcepto>
        
        <!-- CuentaPredial si aplica -->
        <cfdi:CuentaPredial Numero="..."/>
    </cfdi:Concepto>
</cfdi:Conceptos>
```

### 9. Impuestos Globales

```xml
<cfdi:Impuestos 
    TotalImpuestosRetenidos="4.00"
    TotalImpuestosTrasladados="16.00">
    
    <cfdi:Retenciones>
        <cfdi:Retencion Impuesto="002" Importe="4.00"/>
    </cfdi:Retenciones>
    
    <cfdi:Traslados>
        <cfdi:Traslado 
            Base="100.00"
            Impuesto="002"
            TipoFactor="Tasa"
            TasaOCuota="0.160000"
            Importe="16.00"/>
    </cfdi:Traslados>
</cfdi:Impuestos>
```

### 10. Complemento

El nodo Complemento contiene todos los complementos opcionales:

#### Impuestos Locales
```xml
<cfdi:Complemento>
    <implocal:ImpuestosLocales version="1.0" TotaldeRetenciones="..." TotaldeTraslados="...">
        <implocal:RetencionesLocales ImpLocRetenido="..." Importe="..." TasadeRetencion="..."/>
        <implocal:TrasladosLocales ImpLocTrasladado="..." Importe="..." TasadeTraslado="..."/>
    </implocal:ImpuestosLocales>
</cfdi:Complemento>
```

#### Leyendas Fiscales
```xml
<leyendasFisc:LeyendasFiscales version="1.0">
    <leyendasFisc:Leyenda norma="..." textoLeyenda="..."/>
</leyendasFisc:LeyendasFiscales>
```

#### INE
```xml
<ine:INE Version="1.1" TipoProceso="Ordinario" TipoComite="...">
    <ine:Entidad ClaveEntidad="09" Ambito="Federal">
        <ine:Contabilidad IdContabilidad="123"/>
    </ine:Entidad>
</ine:INE>
```

#### Carta Porte 3.1
Ver documento específico de Carta Porte

#### Nómina 1.2
Ver documento específico de Nómina

#### Pagos 2.0
Ver documento específico de Pagos

#### Comercio Exterior 2.0
Ver documento específico de Comercio Exterior

#### TimbreFiscalDigital
```xml
<tfd:TimbreFiscalDigital
    xmlns:tfd="http://www.sat.gob.mx/TimbreFiscalDigital"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="..."
    Version="1.1"
    UUID="XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
    FechaTimbrado="2024-01-15T10:30:00"
    RfcProvCertif="FIN930514P87"
    SelloCFD="..."
    NoCertificadoSAT="00001000000123456789"
    SelloSAT="..."/>
```

### 11. Addenda

Si se requiere addenda personalizada:
```xml
<cfdi:Addenda>
    <FondoGarantia:AddendaFondoGarantia ...>
        <FondoGarantia:FondoGarantia Importe="..." PeriodoEnMeses="..." Descripcion="..."/>
    </FondoGarantia:AddendaFondoGarantia>
</cfdi:Addenda>
```

### 12. Generación del Sello Digital

Si no se proporciona sello (nueva factura):
```php
$sello = XMLUtils::obtenerSello($xml, $proveedor->keypem);
$rootNode->setAttribute('Sello', $sello);
```

## Validaciones Importantes

1. **Moneda XXX**: Para tipo de comprobante "T" (Traslado)
2. **ObjetoImp**: Obligatorio en versión 4.0
3. **Exportación**: Obligatorio en versión 4.0
4. **RegimenFiscalReceptor**: Obligatorio en versión 4.0
5. **DomicilioFiscalReceptor**: Obligatorio en versión 4.0
6. **Decimales**: Todos los importes con 2 decimales, tasas con 6 decimales
7. **TotalImpuestosTrasladados**: Solo se incluye si hay impuestos trasladados que no sean "Exento"

## Salida

Retorna un objeto FluidXml que contiene el XML completo del CFDI 4.0, listo para:
1. Obtener el sello digital
2. Ser enviado a timbrado
3. Ser almacenado en el sistema

## Notas Técnicas

- Usa `FluidXml` para construcción declarativa del XML
- Maneja múltiples versiones de complementos dinámicamente
- Formato de fechas: ISO 8601 (YYYY-MM-DDTHH:MM:SS)
- Los namespaces se registran dinámicamente según complementos presentes
- El schemaLocation incluye todos los XSD necesarios
