Class: VerifactuRails::RegistroAlta

Inherits:
Object
  • Object
show all
Defined in:
lib/verifactu_rails/registro.rb

Overview

Registro de facturación de ALTA.

El punto entero de esta clase: la huella y el XML salen de los MISMOS campos ya normalizados. Calcular una por un lado y montar el otro por otro es el bug número uno del dominio, porque la AEAT recalcula la huella sobre el XML que recibe. Aquí eso no puede pasar por construcción.

Constant Summary collapse

TIPOS_FACTURA =
%w[F1 F2 F3 R1 R2 R3 R4 R5].freeze
TIPOS_RECTIFICATIVA =

S = sustitutiva, I = incremental

%w[S I].freeze
MAXIMO_REFERENCIADAS =

maxOccurs del esquema

1000
RECHAZOS_PREVIOS =

RechazoPrevio en un ALTA admite tres valores (la anulación solo dos):

N  no hubo rechazo previo de la AEAT
S  lo hubo, y el registro sí existe en la AEAT
X  el registro NO existe en la AEAT, se remitiera o no antes. Es la vía
 para subsanar algo que está en el SIF del obligado pero nunca llegó,
 típicamente al migrar desde NO VERI*FACTU.
%w[N S X].freeze
TIPOS_CON_DESTINATARIO =

Destinatarios: obligatorio en unos tipos, prohibido en otros (Validaciones v1.2.2, ap. 13). F2 y R5 son las simplificadas, donde por definición no se identifica al destinatario.

OJO al reutilizar esta lista: otras dos reglas coinciden con ella por motivos distintos -el NIF-IVA de un destinatario (ap. 13) y la inversión del sujeto pasivo (ap. 15.4) exigen los mismos tipos-, así que si la AEAT cambia una sola de las tres habrá que separarlas.

%w[F1 F3 R1 R2 R3 R4].freeze
TIPOS_SIN_DESTINATARIO =
%w[F2 R5].freeze
EMISORES =

Ap. 11. Quién emitió la factura, si no fue el propio obligado.

%w[D T].freeze
TIPOS_CON_CUPON =

Ap. 14. El cupón solo cabe en estos dos tipos.

%w[R1 R5].freeze
FECHA_MINIMA =

Entrada en vigor de la Orden HAC/1177/2024.

Date.new(2024, 10, 28)
MAXIMO_SIMPLIFICADA =

Ap. 15.8. Una factura simplificada (F2) no puede pasar de 3.000 €, sumando base y cuota de todas las líneas del desglose. El margen lo concede la propia AEAT.

BigDecimal('3000.00')
MARGEN_SIMPLIFICADA =
BigDecimal('10.00')
UMBRAL_MACRODATO =

Ap. 3.1.3.10. Obligatorio a partir de cien millones, en valor absoluto.

BigDecimal('100000000.00')
TIPOS_SIMPLIFICADA_CUALIFICADA =

Ap. 3.1.3.8 y 3.1.3.9: cada marca solo cabe en unos tipos de factura.

%w[F1 F3 R1 R2 R3 R4].freeze
TIPOS_SIN_IDENTIF_DESTINATARIO =
%w[F2 R5].freeze
TIPOS_SIN_DESTINATARIO_NI_SUSTITUTIVA =

Ap. 15.6.4: los tipos que el grupo de entidades de nivel avanzado excluye.

%w[F2 F3 R5].freeze
TIPOS_IVA_PENDIENTE_AAPP =

Ap. 15.6.9.

%w[F1 R1 R2 R3 R4].freeze
PREFIJOS_NIF_AAPP =
%w[P Q S V].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(id_emisor:, num_serie:, fecha_expedicion:, nombre_razon_emisor:, tipo_factura:, descripcion_operacion:, desglose:, cuota_total:, importe_total:, sistema_informatico:, fecha_hora_gen:, destinatarios: [], fecha_operacion: nil, tipo_rectificativa: nil, facturas_rectificadas: [], facturas_sustituidas: [], importe_rectificacion: nil, subsanacion: nil, rechazo_previo: nil, simplificada_cualificada: nil, sin_identif_destinatario: nil, macrodato: nil, num_registro_acuerdo: nil, id_acuerdo_sistema: nil, emitida_por: nil, tercero: nil, cupon: nil) ⇒ RegistroAlta

Returns a new instance of RegistroAlta.

Parameters:

  • subsanacion ('S', 'N', true, false, nil) (defaults to: nil)

    marca el alta como subsanación de un registro ya generado. Es el ÚNICO mecanismo para corregir un registro que la AEAT aceptó con errores.

  • rechazo_previo ('N', 'S', 'X', nil) (defaults to: nil)

    ver RECHAZOS_PREVIOS.



262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
# File 'lib/verifactu_rails/registro.rb', line 262

def initialize(id_emisor:, num_serie:, fecha_expedicion:, nombre_razon_emisor:,
               tipo_factura:, descripcion_operacion:, desglose:,
               cuota_total:, importe_total:, sistema_informatico:,
               fecha_hora_gen:, destinatarios: [], fecha_operacion: nil,
               tipo_rectificativa: nil, facturas_rectificadas: [],
               facturas_sustituidas: [], importe_rectificacion: nil,
               subsanacion: nil, rechazo_previo: nil,
               simplificada_cualificada: nil, sin_identif_destinatario: nil,
               macrodato: nil, num_registro_acuerdo: nil, id_acuerdo_sistema: nil,
               emitida_por: nil, tercero: nil, cupon: nil)
  @id_emisor = Formato.nif(id_emisor, 'IDEmisorFactura')
  @num_serie = Formato.num_serie(num_serie)
  @fecha_expedicion = Formato.fecha(fecha_expedicion)
  @nombre_razon_emisor = Formato.limitar(nombre_razon_emisor, 'NombreRazonEmisor', 120)
  @tipo_factura = Formato.enumerado(tipo_factura, 'TipoFactura', TIPOS_FACTURA)
  @descripcion_operacion = Formato.limitar(descripcion_operacion, 'DescripcionOperacion', 500)
  @desglose = desglose.is_a?(Desglose) ? desglose : Desglose.new(desglose)
  @cuota_total = Importe.formatear(cuota_total)
  @importe_total = Importe.formatear(importe_total)
  @sistema_informatico = Formato.objeto(sistema_informatico, 'sistema_informatico',
                                        SistemaInformatico)
  @fecha_hora_gen = Formato.marca_temporal(fecha_hora_gen)
  @destinatarios = Formato.coleccion(destinatarios, 'destinatarios', Destinatario,
                                     maximo: MAXIMO_REFERENCIADAS)
  @fecha_operacion = fecha_operacion && Formato.fecha(fecha_operacion)
  @tipo_rectificativa = tipo_rectificativa &&
                        Formato.enumerado(tipo_rectificativa, 'TipoRectificativa', TIPOS_RECTIFICATIVA)
  @facturas_rectificadas = Formato.coleccion(facturas_rectificadas, 'facturas_rectificadas',
                                             IdFactura, maximo: MAXIMO_REFERENCIADAS)
  @facturas_sustituidas = Formato.coleccion(facturas_sustituidas, 'facturas_sustituidas',
                                            IdFactura, maximo: MAXIMO_REFERENCIADAS)
  @importe_rectificacion = importe_rectificacion &&
                           Formato.objeto(importe_rectificacion, 'importe_rectificacion',
                                          ImporteRectificacion)
  @subsanacion = Formato.si_no(subsanacion, 'Subsanacion')
  @rechazo_previo = rechazo_previo &&
                    Formato.enumerado(rechazo_previo, 'RechazoPrevio', RECHAZOS_PREVIOS)
  @simplificada_cualificada = Formato.si_no(simplificada_cualificada, 'FacturaSimplificadaArt7273')
  @sin_identif_destinatario = Formato.si_no(sin_identif_destinatario,
                                            'FacturaSinIdentifDestinatarioArt61d')
  @macrodato = Formato.si_no(macrodato, 'Macrodato')
  @num_registro_acuerdo = num_registro_acuerdo &&
                          Formato.limitar(num_registro_acuerdo, 'NumRegistroAcuerdoFacturacion', 15)
  @id_acuerdo_sistema = id_acuerdo_sistema &&
                        Formato.limitar(id_acuerdo_sistema, 'IdAcuerdoSistemaInformatico', 16)
  @emitida_por = emitida_por &&
                 Formato.enumerado(emitida_por, 'EmitidaPorTerceroODestinatario', EMISORES)
  @tercero = tercero && Formato.objeto(tercero, 'tercero', Tercero)
  @cupon = Formato.si_no(cupon, 'Cupon')

  validar_fecha_expedicion!(fecha_expedicion)
  validar_subsanacion!
  validar_marcas!
  validar_macrodato!
  validar_limite_simplificada!
  validar_destinatarios!
  validar_rectificativa!
  validar_sustitutiva!
  validar_emisor_tercero!
  validar_cupon!
  validar_desglose_cruzado!
end

Instance Attribute Details

#cuota_totalObject (readonly)

Returns the value of attribute cuota_total.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def cuota_total
  @cuota_total
end

#cuponObject (readonly)

Returns the value of attribute cupon.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def cupon
  @cupon
end

#descripcion_operacionObject (readonly)

Returns the value of attribute descripcion_operacion.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def descripcion_operacion
  @descripcion_operacion
end

#desgloseObject (readonly)

Returns the value of attribute desglose.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def desglose
  @desglose
end

#destinatariosObject (readonly)

Returns the value of attribute destinatarios.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def destinatarios
  @destinatarios
end

#emitida_porObject (readonly)

Returns the value of attribute emitida_por.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def emitida_por
  @emitida_por
end

#facturas_rectificadasObject (readonly)

Returns the value of attribute facturas_rectificadas.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def facturas_rectificadas
  @facturas_rectificadas
end

#facturas_sustituidasObject (readonly)

Returns the value of attribute facturas_sustituidas.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def facturas_sustituidas
  @facturas_sustituidas
end

#fecha_expedicionObject (readonly)

Returns the value of attribute fecha_expedicion.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def fecha_expedicion
  @fecha_expedicion
end

#fecha_hora_genObject (readonly)

Returns the value of attribute fecha_hora_gen.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def fecha_hora_gen
  @fecha_hora_gen
end

#fecha_operacionObject (readonly)

Returns the value of attribute fecha_operacion.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def fecha_operacion
  @fecha_operacion
end

#id_acuerdo_sistemaObject (readonly)

Returns the value of attribute id_acuerdo_sistema.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def id_acuerdo_sistema
  @id_acuerdo_sistema
end

#id_emisorObject (readonly)

Returns the value of attribute id_emisor.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def id_emisor
  @id_emisor
end

#importe_rectificacionObject (readonly)

Returns the value of attribute importe_rectificacion.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def importe_rectificacion
  @importe_rectificacion
end

#importe_totalObject (readonly)

Returns the value of attribute importe_total.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def importe_total
  @importe_total
end

#macrodatoObject (readonly)

Returns the value of attribute macrodato.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def macrodato
  @macrodato
end

#nombre_razon_emisorObject (readonly)

Returns the value of attribute nombre_razon_emisor.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def nombre_razon_emisor
  @nombre_razon_emisor
end

#num_registro_acuerdoObject (readonly)

Returns the value of attribute num_registro_acuerdo.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def num_registro_acuerdo
  @num_registro_acuerdo
end

#num_serieObject (readonly)

Returns the value of attribute num_serie.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def num_serie
  @num_serie
end

#rechazo_previoObject (readonly)

Returns the value of attribute rechazo_previo.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def rechazo_previo
  @rechazo_previo
end

#simplificada_cualificadaObject (readonly)

Returns the value of attribute simplificada_cualificada.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def simplificada_cualificada
  @simplificada_cualificada
end

#sin_identif_destinatarioObject (readonly)

Returns the value of attribute sin_identif_destinatario.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def sin_identif_destinatario
  @sin_identif_destinatario
end

#sistema_informaticoObject (readonly)

Returns the value of attribute sistema_informatico.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def sistema_informatico
  @sistema_informatico
end

#subsanacionObject (readonly)

Returns the value of attribute subsanacion.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def subsanacion
  @subsanacion
end

#terceroObject (readonly)

Returns the value of attribute tercero.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def tercero
  @tercero
end

#tipo_facturaObject (readonly)

Returns the value of attribute tipo_factura.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def tipo_factura
  @tipo_factura
end

#tipo_rectificativaObject (readonly)

Returns the value of attribute tipo_rectificativa.



248
249
250
# File 'lib/verifactu_rails/registro.rb', line 248

def tipo_rectificativa
  @tipo_rectificativa
end

Instance Method Details

#construir(xml, anterior: nil) ⇒ Object

Emite el subárbol sf:RegistroAlta dentro de un builder ya posicionado.



349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
# File 'lib/verifactu_rails/registro.rb', line 349

def construir(xml, anterior: nil)
  propia = huella(anterior: anterior)

  xml['sum1'].RegistroAlta do
    xml['sum1'].IDVersion IDVERSION
    xml['sum1'].IDFactura do
      xml['sum1'].IDEmisorFactura id_emisor
      xml['sum1'].NumSerieFactura num_serie
      xml['sum1'].FechaExpedicionFactura fecha_expedicion
    end
    xml['sum1'].NombreRazonEmisor nombre_razon_emisor
    xml['sum1'].Subsanacion subsanacion if subsanacion
    xml['sum1'].RechazoPrevio rechazo_previo if rechazo_previo
    xml['sum1'].TipoFactura tipo_factura
    xml['sum1'].TipoRectificativa tipo_rectificativa if tipo_rectificativa
    construir_referenciadas(xml, 'FacturasRectificadas', 'IDFacturaRectificada',
                            facturas_rectificadas)
    construir_referenciadas(xml, 'FacturasSustituidas', 'IDFacturaSustituida',
                            facturas_sustituidas)
    if importe_rectificacion
      xml['sum1'].ImporteRectificacion do
        importe_rectificacion.a_pares.each { |campo, valor| xml['sum1'].send(campo, valor) }
      end
    end
    xml['sum1'].FechaOperacion fecha_operacion if fecha_operacion
    xml['sum1'].DescripcionOperacion descripcion_operacion
    xml['sum1'].FacturaSimplificadaArt7273 simplificada_cualificada if simplificada_cualificada
    if sin_identif_destinatario
      xml['sum1'].FacturaSinIdentifDestinatarioArt61d sin_identif_destinatario
    end
    xml['sum1'].Macrodato macrodato if macrodato
    xml['sum1'].EmitidaPorTerceroODestinatario emitida_por if emitida_por
    xml['sum1'].Tercero { construir_persona(xml, tercero) } if tercero
    construir_destinatarios(xml)
    xml['sum1'].Cupon cupon if cupon
    construir_desglose(xml)
    xml['sum1'].CuotaTotal cuota_total
    xml['sum1'].ImporteTotal importe_total
    construir_encadenamiento(xml, anterior)
    construir_sistema(xml)
    xml['sum1'].FechaHoraHusoGenRegistro fecha_hora_gen
    xml['sum1'].NumRegistroAcuerdoFacturacion num_registro_acuerdo if num_registro_acuerdo
    xml['sum1'].IdAcuerdoSistemaInformatico id_acuerdo_sistema if id_acuerdo_sistema
    xml['sum1'].TipoHuella TIPO_HUELLA
    xml['sum1'].Huella propia
  end
end

#fecha_referenciaObject

FechaOperacion, y la de expedición si aquella no se informa. Es la fecha contra la que la AEAT mide las ventanas temporales de tipos y recargos (Validaciones v1.2.2, ap. 15.1 y 15.3).



328
329
330
# File 'lib/verifactu_rails/registro.rb', line 328

def fecha_referencia
  Date.strptime(fecha_operacion || fecha_expedicion, '%d-%m-%Y')
end

#huella(anterior: nil) ⇒ Object

Huella de este registro. anterior es nil solo en el primer registro de la cadena de ese SIF y NIF obligado (una sola cadena, no una por serie).

Parameters:



338
339
340
341
342
343
344
345
346
# File 'lib/verifactu_rails/registro.rb', line 338

def huella(anterior: nil)
  Huella.alta(
    id_emisor: id_emisor, num_serie: num_serie,
    fecha_expedicion: fecha_expedicion, tipo_factura: tipo_factura,
    cuota_total: cuota_total, importe_total: importe_total,
    fecha_hora_gen: fecha_hora_gen,
    huella_anterior: anterior&.huella
  )
end

#rectificativa?Boolean

Returns:

  • (Boolean)


332
# File 'lib/verifactu_rails/registro.rb', line 332

def rectificativa? = tipo_factura.start_with?('R')