Module: VerifactuRails::Importe
- Defined in:
- lib/verifactu_rails/importe.rb
Overview
Formateo canónico de importes monetarios.
REGLA DE ORO: el string que produce este módulo es el que debe ir TANTO en la cadena de la huella COMO en el XML. Si divergen aunque sea en un decimal, la AEAT recalcula la huella sobre lo que recibe en el XML y rechaza el registro. Por eso el formateo vive aquí y en un solo sitio.
Constant Summary collapse
- PATRON =
/\A-?\d{1,12}\.\d{2}\z/
Class Method Summary collapse
-
.formatear(valor) ⇒ Object
Normaliza a string con exactamente 2 decimales y punto como separador.
-
.porcentaje(valor, campo) ⇒ Object
sf:Tipo2.2Type, para los porcentajes: patrón \d1,3(.\d0,2)? — SIN signo y con tres dígitos enteros como mucho.
Class Method Details
.formatear(valor) ⇒ Object
Normaliza a string con exactamente 2 decimales y punto como separador. Acepta BigDecimal, Integer, Rational o String; rechaza Float por imprecisión binaria (0.1 + 0.2 no es 0.3 y aquí eso es un rechazo AEAT).
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/verifactu_rails/importe.rb', line 22 def formatear(valor) case valor when Float raise ValidacionError, 'No se admiten Float en importes: usa BigDecimal, Integer o String ' \ "(recibido: #{valor.inspect})" when BigDecimal then decimal = valor when Integer then decimal = valor.to_d when Rational then decimal = valor.to_d(20) when String then decimal = parsear_string(valor) when nil then raise ValidacionError, 'Importe requerido' else raise ValidacionError, "Tipo de importe no admitido: #{valor.class}" end # ROUND_HALF_UP explícito, y NO porque Ruby traiga otro por defecto: el # suyo ya es HALF_UP, tanto en BigDecimal.mode como en Float#round. El # motivo es que BigDecimal.mode es estado GLOBAL del proceso: cualquier # gema de la aplicación puede cambiarlo, y entonces todos los importes # redondearían distinto y con ellos las huellas, sin que nadie relacionara # una cosa con la otra. Pasándolo en la llamada, da igual lo que haga el # resto. HALF_UP es además el que aplica la normativa fiscal española. resultado = decimal.round(2, BigDecimal::ROUND_HALF_UP).to_s('F') resultado = format('%.2f', resultado.to_d) # asegura los 2 decimales unless resultado.match?(PATRON) raise ValidacionError, "Importe fuera de rango o mal formado: #{resultado}" end # -0.00 no existe fiscalmente y rompería la comparación de huellas resultado == '-0.00' ? '0.00' : resultado end |
.porcentaje(valor, campo) ⇒ Object
sf:Tipo2.2Type, para los porcentajes: patrón \d1,3(.\d0,2)? — SIN
signo y con tres dígitos enteros como mucho. Es un tipo distinto de
sf:ImporteSgn12.2Type, así que formatear con formatear a secas dejaba
pasar un -21.00 o un 1000.00 que luego rechaza el esquema.
59 60 61 62 63 64 65 66 67 68 |
# File 'lib/verifactu_rails/importe.rb', line 59 def porcentaje(valor, campo) cadena = formatear(valor) unless cadena.match?(/\A\d{1,3}\.\d{2}\z/) raise ValidacionError, "#{campo} debe ser un porcentaje sin signo y de hasta 3 dígitos " \ "enteros (recibido: #{cadena})" end cadena end |