unit uVeriFactuTypes;

interface

uses
  System.SysUtils;

type
  /// <summary>Modo operativo del SIF (Sistema Informatico de Facturacion)</summary>
  TSifModoOperacion = (
    sifVeriFactuTest,  // Entorno de Pruebas / Preproduccion AEAT (Envio telematico automatico)
    sifVeriFactuProd,  // Entorno de Produccion AEAT (Envio telematico automatico)
    sifNoVeriFactu     // Custodia Local Inalterable con Firma Digital XAdES
  );

  /// <summary>Tipo de Factura segun catalogo oficial AEAT</summary>
  TSifTipoFactura = (
    tfF1, // Factura Ordinaria
    tfF2, // Factura Simplificada (Ticket)
    tfF3, // Factura en sustitucion de simplificadas
    tfR1, // Factura Rectificativa: Error fundado en derecho y Art. 80 Uno, Dos y Seis LIVA
    tfR2, // Factura Rectificativa: Concurso de acreedores (Art. 80 Tres LIVA)
    tfR3, // Factura Rectificativa: Credito total o parcialmente incobrable (Art. 80 Cuatro LIVA)
    tfR4, // Factura Rectificativa: Resto de supuestos
    tfR5  // Factura Rectificativa en facturas simplificadas
  );

  /// <summary>Estado del registro de facturacion ante la AEAT</summary>
  TSifEstadoEnvio = (
    seNoEnviado,
    sePendienteEnvio,
    seEnviado,
    seAceptado,
    seAceptadoConErrores,
    seRechazado,
    seErrorComunicacion
  );

  /// <summary>Tipos de eventos para el registro de auditoria SIF</summary>
  TSifTipoEvento = (
    steInicioSistema,
    steFinSistema,
    steLoginUsuario,
    steLogoutUsuario,
    steErrorEncadenamiento,
    steErrorComunicacionAEAT,
    steCambioModoTrabajo,
    steCambioCertificado,
    steExportacionAuditoria,
    steAnulacionFactura
  );

  /// <summary>Estructura con los campos requeridos para el calculo del Hash SHA-256</summary>
  THashInputData = record
    IDEmisorFactura: string;
    NumSerieFactura: string;
    FechaExpedicionFactura: string; // Formato DD-MM-YYYY
    TipoFactura: string;            // F1, F2, R1, etc.
    CuotaTotal: Double;
    ImporteTotal: Double;
    HuellaAnterior: string;         // Hash del registro anterior (cadena vacia si es el primero)
    FechaHoraGenRegistro: string;   // ISO 8601: YYYY-MM-DDThh:mm:ss+01:00
  end;

  /// <summary>Desglose impositivo de una linea o agrupacion de bases</summary>
  TSifDesgloseIva = record
    TipoIva: Double;
    BaseImponible: Double;
    CuotaIva: Double;
    TipoRecargoEq: Double;
    CuotaRecargoEq: Double;
    CausaExencion: string; // E1..E6 o vacio
  end;

  /// <summary>Resultado completo de la emision/sellado del registro SIF</summary>
  TSifResultadoEmision = record
    Exito: Boolean;
    HuellaHash: string;
    HuellaAnterior: string;
    QRUrl: string;
    QRPrefijoHuella: string;
    FechaHoraRegistro: TDateTime;
    ModoTrabajo: TSifModoOperacion;
    EstadoEnvio: TSifEstadoEnvio;
    CSV_AEAT: string;
    CodigoError: string;
    MensajeError: string;
    XmlEnviado: string;
    XmlRespuesta: string;
  end;

const
  URL_VERIFICACION_QR_TEST = 'https://preportal.aeat.es/PRE-Exteriores/Inicio/_menu_/VERI_FACTU___Sistemas_Informaticos_de_Facturacion/verificacion.html';
  URL_VERIFICACION_QR_PROD = 'https://sede.agenciatributaria.gob.es/Sede/iva/sistemas-informaticos-facturacion-verifactu/verificacion.html';

  WS_ENDPOINT_AEAT_TEST = 'https://prewww1.aeat.es/wlpl/TIBA-JDIT/ws/SuministroLRFacturasEmitidas';
  WS_ENDPOINT_AEAT_PROD = 'https://www1.agenciatributaria.gob.es/wlpl/TIBA-JDIT/ws/SuministroLRFacturasEmitidas';

function ModoOperacionToString(AModo: TSifModoOperacion): string;
function StringToModoOperacion(const AStr: string): TSifModoOperacion;
function TipoFacturaToString(ATipo: TSifTipoFactura): string;
function StringToTipoFactura(const AStr: string): TSifTipoFactura;
function EstadoEnvioToString(AEstado: TSifEstadoEnvio): string;
function StringToEstadoEnvio(const AStr: string): TSifEstadoEnvio;
function TipoEventoToString(ATipo: TSifTipoEvento): string;

implementation

function ModoOperacionToString(AModo: TSifModoOperacion): string;
begin
  case AModo of
    sifVeriFactuTest: Result := 'VERIFACTU_TEST';
    sifVeriFactuProd: Result := 'VERIFACTU_PROD';
    sifNoVeriFactu:   Result := 'NO_VERIFACTU';
  end;
end;

function StringToModoOperacion(const AStr: string): TSifModoOperacion;
begin
  if SameText(AStr, 'VERIFACTU_PROD') then
    Result := sifVeriFactuProd
  else if SameText(AStr, 'NO_VERIFACTU') then
    Result := sifNoVeriFactu
  else
    Result := sifVeriFactuTest;
end;

function TipoFacturaToString(ATipo: TSifTipoFactura): string;
begin
  case ATipo of
    tfF1: Result := 'F1';
    tfF2: Result := 'F2';
    tfF3: Result := 'F3';
    tfR1: Result := 'R1';
    tfR2: Result := 'R2';
    tfR3: Result := 'R3';
    tfR4: Result := 'R4';
    tfR5: Result := 'R5';
  end;
end;

function StringToTipoFactura(const AStr: string): TSifTipoFactura;
begin
  if SameText(AStr, 'F2') then Result := tfF2
  else if SameText(AStr, 'F3') then Result := tfF3
  else if SameText(AStr, 'R1') then Result := tfR1
  else if SameText(AStr, 'R2') then Result := tfR2
  else if SameText(AStr, 'R3') then Result := tfR3
  else if SameText(AStr, 'R4') then Result := tfR4
  else if SameText(AStr, 'R5') then Result := tfR5
  else Result := tfF1;
end;

function EstadoEnvioToString(AEstado: TSifEstadoEnvio): string;
begin
  case AEstado of
    seNoEnviado:           Result := 'NO_ENVIADO';
    sePendienteEnvio:      Result := 'PENDIENTE_ENVIO';
    seEnviado:             Result := 'ENVIADO';
    seAceptado:            Result := 'ACEPTADO';
    seAceptadoConErrores:  Result := 'ACEPTADO_CON_ERRORES';
    seRechazado:           Result := 'RECHAZADO';
    seErrorComunicacion:   Result := 'ERROR_COMUNICACION';
  end;
end;

function StringToEstadoEnvio(const AStr: string): TSifEstadoEnvio;
begin
  if SameText(AStr, 'PENDIENTE_ENVIO') then Result := sePendienteEnvio
  else if SameText(AStr, 'ENVIADO') then Result := seEnviado
  else if SameText(AStr, 'ACEPTADO') then Result := seAceptado
  else if SameText(AStr, 'ACEPTADO_CON_ERRORES') then Result := seAceptadoConErrores
  else if SameText(AStr, 'RECHAZADO') then Result := seRechazado
  else if SameText(AStr, 'ERROR_COMUNICACION') then Result := seErrorComunicacion
  else Result := seNoEnviado;
end;

function TipoEventoToString(ATipo: TSifTipoEvento): string;
begin
  case ATipo of
    steInicioSistema:         Result := 'INICIO_SISTEMA';
    steFinSistema:            Result := 'FIN_SISTEMA';
    steLoginUsuario:          Result := 'LOGIN_USUARIO';
    steLogoutUsuario:         Result := 'LOGOUT_USUARIO';
    steErrorEncadenamiento:   Result := 'ERROR_ENCADENAMIENTO';
    steErrorComunicacionAEAT: Result := 'ERROR_COMUNICACION_AEAT';
    steCambioModoTrabajo:     Result := 'CAMBIO_MODO_TRABAJO';
    steCambioCertificado:     Result := 'CAMBIO_CERTIFICADO';
    steExportacionAuditoria:  Result := 'EXPORTACION_AUDITORIA';
    steAnulacionFactura:      Result := 'ANULACION_FACTURA';
  end;
end;

end.
