ticketbai 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +32 -0
- data/CHANGELOG.md +13 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +107 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/ticketbai/api/client.rb +63 -0
- data/lib/ticketbai/api/registry.rb +34 -0
- data/lib/ticketbai/api/request.rb +125 -0
- data/lib/ticketbai/api/response_parser.rb +36 -0
- data/lib/ticketbai/checksum_calculator.rb +15 -0
- data/lib/ticketbai/document.rb +21 -0
- data/lib/ticketbai/document_validator.rb +42 -0
- data/lib/ticketbai/documents/annulment.rb +45 -0
- data/lib/ticketbai/documents/api_payload.rb +47 -0
- data/lib/ticketbai/documents/issuance.rb +55 -0
- data/lib/ticketbai/documents/issuance_unsigned.rb +58 -0
- data/lib/ticketbai/errors.rb +27 -0
- data/lib/ticketbai/nodes/breakdown_type.rb +72 -0
- data/lib/ticketbai/nodes/invoice_chaining.rb +22 -0
- data/lib/ticketbai/nodes/invoice_data.rb +24 -0
- data/lib/ticketbai/nodes/invoice_header.rb +26 -0
- data/lib/ticketbai/nodes/issuer.rb +18 -0
- data/lib/ticketbai/nodes/lroe_header.rb +29 -0
- data/lib/ticketbai/nodes/lroe_issued_invoices.rb +28 -0
- data/lib/ticketbai/nodes/receiver.rb +36 -0
- data/lib/ticketbai/nodes/software.rb +17 -0
- data/lib/ticketbai/operation.rb +59 -0
- data/lib/ticketbai/operations/annulment.rb +41 -0
- data/lib/ticketbai/operations/issuance.rb +93 -0
- data/lib/ticketbai/operations/issuance_unsigned.rb +89 -0
- data/lib/ticketbai/signer.rb +273 -0
- data/lib/ticketbai/tbai_identifier.rb +33 -0
- data/lib/ticketbai/tbai_qr.rb +50 -0
- data/lib/ticketbai/version.rb +5 -0
- data/lib/ticketbai/xmldsig-core-schema.xsd +318 -0
- data/lib/ticketbai/xsd_validators/annulment.xsd +392 -0
- data/lib/ticketbai/xsd_validators/issuance.xsd +865 -0
- data/lib/ticketbai.rb +89 -0
- data/ticketbai.gemspec +42 -0
- metadata +186 -0
@@ -0,0 +1,55 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Documents
|
3
|
+
class Issuance < Document
|
4
|
+
ROOT_NAME = 'T:TicketBai'.freeze
|
5
|
+
XMLNS = {
|
6
|
+
'xmlns:T' => 'urn:ticketbai:emision'
|
7
|
+
}.freeze
|
8
|
+
|
9
|
+
ATTRIBUTES = %i[issuer receiver invoice_header invoice_data breakdown_type invoice_chaining software].freeze
|
10
|
+
|
11
|
+
attr_accessor(*ATTRIBUTES)
|
12
|
+
|
13
|
+
###
|
14
|
+
# @param [Ticketbai::Nodes::Isuer] issuer
|
15
|
+
# @param [Ticketbai::Nodes::Receiver] receiver
|
16
|
+
# @param [Ticketbai::Nodes::InvoiceHeader] invoice_header
|
17
|
+
# @param [Ticketbai::Nodes::InvoiceData] invoice_data
|
18
|
+
# @param [Ticketbai::Nodes::BreakdownType] breakdown_type
|
19
|
+
# @param [Ticketbai::Nodes::InvoiceChaining] invoice_chaining
|
20
|
+
# @param [Ticketbai::Nodes::Software] software
|
21
|
+
###
|
22
|
+
def initialize(**args)
|
23
|
+
super(args)
|
24
|
+
end
|
25
|
+
|
26
|
+
# @return [Nokogiri::XML::Builder]
|
27
|
+
def create
|
28
|
+
builder = Nokogiri::XML::Builder.new(encoding: Encoding::UTF_8.to_s) do |xml|
|
29
|
+
xml.TicketBai(XMLNS) do
|
30
|
+
xml.Cabecera do
|
31
|
+
xml.IDVersionTBAI TBAI_VERSION
|
32
|
+
end
|
33
|
+
xml.Sujetos do
|
34
|
+
@issuer.build_xml(xml)
|
35
|
+
@receiver&.build_xml(xml)
|
36
|
+
end
|
37
|
+
xml.Factura do
|
38
|
+
@invoice_header.build_xml(xml)
|
39
|
+
@invoice_data.build_xml(xml)
|
40
|
+
@breakdown_type.build_xml(xml)
|
41
|
+
end
|
42
|
+
xml.HuellaTBAI do
|
43
|
+
@invoice_chaining&.build_xml(xml)
|
44
|
+
@software.build_xml(xml)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
modify_xml_root_name(builder)
|
50
|
+
|
51
|
+
builder
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Documents
|
3
|
+
# This document has the pecualiarity that it does not need to be signed and it must be sent to the API without a root node, so it's not considered
|
4
|
+
# as a valid XML either. The structure of the document is as follows:
|
5
|
+
# <Destinatarios>
|
6
|
+
# ...
|
7
|
+
# ...
|
8
|
+
# </Destinatarios>
|
9
|
+
# <CabeceraFactura>
|
10
|
+
# ...
|
11
|
+
# ...
|
12
|
+
# </CabeceraFactura>
|
13
|
+
# <DatosFactura>
|
14
|
+
# ...
|
15
|
+
# ...
|
16
|
+
# </DatosFactura>
|
17
|
+
# <TipoDesglose>
|
18
|
+
# ...
|
19
|
+
# ...
|
20
|
+
# </TipoDesglose>
|
21
|
+
#
|
22
|
+
# The document is created with a temporary root node (TicketBai), and after creating it, it's returned without the root node.
|
23
|
+
class IssuanceUnsigned
|
24
|
+
###
|
25
|
+
# @param [Ticketbai::Nodes::Receiver] receiver
|
26
|
+
# @param [Ticketbai::Nodes::InvoiceHeader] invoice_header
|
27
|
+
# @param [Ticketbai::Nodes::InvoiceData] invoice_data
|
28
|
+
# @param [Ticketbai::Nodes::BreakdownType] breakdown_type
|
29
|
+
###
|
30
|
+
def initialize(**args)
|
31
|
+
@receiver = args[:receiver]
|
32
|
+
@invoice_header = args[:invoice_header]
|
33
|
+
@invoice_data = args[:invoice_data]
|
34
|
+
@breakdown_type = args[:breakdown_type]
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [String]
|
38
|
+
def create
|
39
|
+
builder = Nokogiri::XML::Builder.new(encoding: Encoding::UTF_8.to_s) do |xml|
|
40
|
+
xml.TicketBai do
|
41
|
+
@receiver&.build_xml(xml)
|
42
|
+
@invoice_header.build_xml(xml)
|
43
|
+
@invoice_data.build_xml(xml)
|
44
|
+
@breakdown_type.build_xml(xml)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
filter_root_node(builder)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def filter_root_node(builder)
|
54
|
+
Nokogiri::XML(builder.to_xml).at('TicketBai').children.to_xml
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
# Generic Ticketbai exception class.
|
3
|
+
class Error < StandardError; end
|
4
|
+
|
5
|
+
# For errors returned by the client library, like HTTP errors
|
6
|
+
class ClientError < Error; end
|
7
|
+
|
8
|
+
# For errors returned by the API
|
9
|
+
class APIError < Error
|
10
|
+
attr_reader :code
|
11
|
+
|
12
|
+
def initialize(message = nil, code = nil)
|
13
|
+
@code = code
|
14
|
+
super(message)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# For errors returned by the TBAIFile validation.
|
19
|
+
class TBAIFileError < Error
|
20
|
+
attr_reader :code
|
21
|
+
|
22
|
+
def initialize(message = nil, code = nil)
|
23
|
+
@code = code
|
24
|
+
super(message)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class BreakdownType
|
4
|
+
# Exemption causes (CausaExencion):
|
5
|
+
# E1: Exenta por el articulo 20 de la Norma Foral del IVA
|
6
|
+
# E2: Exenta por el articulo 21 de la Norma Foral del IVA
|
7
|
+
# E3: Exenta por el articulo 22 de la Norma Foral del IVA
|
8
|
+
# E4: Exenta por el articulo 23 y 24 de la Norma Foral del IVA
|
9
|
+
# E5: Exenta por el articulo 25 de la Norma Foral del IVA
|
10
|
+
# E6: Exenta por otra causa
|
11
|
+
|
12
|
+
# Type of non-exempt (TipoNoExenta):
|
13
|
+
# S1: Sin inversion del sujeto pasivo
|
14
|
+
# S2: Con inversion del sujeto pasivo
|
15
|
+
def initialize(args = {})
|
16
|
+
@receiver_country = args[:receiver_country]
|
17
|
+
@invoice_amount = args[:invoice_amount]
|
18
|
+
@invoice_vat = args[:invoice_vat]
|
19
|
+
@invoice_vat_total = args[:invoice_vat_total]
|
20
|
+
@receiver_in_eu = args[:receiver_in_eu]
|
21
|
+
@simplified_invoice = args[:simplified_invoice]
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [Nokogiri::XML::Builder]
|
25
|
+
def build_xml(node)
|
26
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
27
|
+
node.TipoDesglose do |xml|
|
28
|
+
if (@receiver_country == 'ES') || (@receiver_country != 'ES' && @simplified_invoice)
|
29
|
+
xml.DesgloseFactura do
|
30
|
+
xml.Sujeta do
|
31
|
+
if (@receiver_country != 'ES') && @simplified_invoice
|
32
|
+
xml.Exenta do
|
33
|
+
xml.DetalleExenta do
|
34
|
+
xml.CausaExencion @receiver_in_eu == true ? 'E6' : 'E2'
|
35
|
+
xml.BaseImponible @invoice_amount
|
36
|
+
end
|
37
|
+
end
|
38
|
+
else
|
39
|
+
xml.NoExenta do
|
40
|
+
xml.DetalleNoExenta do
|
41
|
+
xml.TipoNoExenta 'S1'
|
42
|
+
xml.DesgloseIVA do
|
43
|
+
xml.DetalleIVA do
|
44
|
+
xml.BaseImponible @invoice_amount
|
45
|
+
xml.TipoImpositivo @invoice_vat
|
46
|
+
xml.CuotaImpuesto @invoice_vat_total
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
else
|
55
|
+
xml.DesgloseTipoOperacion do
|
56
|
+
xml.PrestacionServicios do
|
57
|
+
xml.Sujeta do
|
58
|
+
xml.Exenta do
|
59
|
+
xml.DetalleExenta do
|
60
|
+
xml.CausaExencion @receiver_in_eu == true ? 'E6' : 'E2'
|
61
|
+
xml.BaseImponible @invoice_amount
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class InvoiceChaining
|
4
|
+
def initialize(args = {})
|
5
|
+
@prev_invoice_serial = args[:prev_invoice_serial]
|
6
|
+
@prev_invoice_number = args[:prev_invoice_number]
|
7
|
+
@prev_invoice_date = args[:prev_invoice_date]
|
8
|
+
@prev_invoice_signature = args[:prev_invoice_signature]
|
9
|
+
end
|
10
|
+
|
11
|
+
def build_xml(node)
|
12
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
13
|
+
node.EncadenamientoFacturaAnterior do |xml|
|
14
|
+
xml.SerieFacturaAnterior @prev_invoice_serial if @prev_invoice_serial
|
15
|
+
xml.NumFacturaAnterior @prev_invoice_number
|
16
|
+
xml.FechaExpedicionFacturaAnterior @prev_invoice_date
|
17
|
+
xml.SignatureValueFirmaFacturaAnterior @prev_invoice_signature
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class InvoiceData
|
4
|
+
def initialize(args = {})
|
5
|
+
@invoice_description = args[:invoice_description]
|
6
|
+
@invoice_total = args[:invoice_total]
|
7
|
+
@invoice_vat_key = args[:invoice_vat_key]
|
8
|
+
end
|
9
|
+
|
10
|
+
def build_xml(node)
|
11
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
12
|
+
node.DatosFactura do |xml|
|
13
|
+
xml.DescripcionFactura @invoice_description
|
14
|
+
xml.ImporteTotalFactura @invoice_total
|
15
|
+
xml.Claves do
|
16
|
+
xml.IDClave do
|
17
|
+
xml.ClaveRegimenIvaOpTrascendencia @invoice_vat_key
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class InvoiceHeader
|
4
|
+
SIMPLIFIED_INVOICE = 'S'.freeze
|
5
|
+
|
6
|
+
def initialize(args = {})
|
7
|
+
@invoice_serial = args[:invoice_serial]
|
8
|
+
@invoice_number = args[:invoice_number]
|
9
|
+
@invoice_date = args[:invoice_date]
|
10
|
+
@invoice_time = args[:invoice_time]
|
11
|
+
@simplified_invoice = args[:simplified_invoice]
|
12
|
+
end
|
13
|
+
|
14
|
+
def build_xml(node)
|
15
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
16
|
+
node.CabeceraFactura do |xml|
|
17
|
+
xml.SerieFactura @invoice_serial
|
18
|
+
xml.NumFactura @invoice_number
|
19
|
+
xml.FechaExpedicionFactura @invoice_date
|
20
|
+
xml.HoraExpedicionFactura @invoice_time if @invoice_time
|
21
|
+
xml.FacturaSimplificada SIMPLIFIED_INVOICE if @simplified_invoice
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class Issuer
|
4
|
+
def initialize(args = {})
|
5
|
+
@issuing_company_nif = args[:issuing_company_nif]
|
6
|
+
@issuing_company_name = args[:issuing_company_name]
|
7
|
+
end
|
8
|
+
|
9
|
+
def build_xml(node)
|
10
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
11
|
+
node.Emisor do |xml|
|
12
|
+
xml.NIF @issuing_company_nif
|
13
|
+
xml.ApellidosNombreRazonSocial @issuing_company_name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class LroeHeader
|
4
|
+
def initialize(args = {})
|
5
|
+
@year = args[:year]
|
6
|
+
@nif = args[:nif]
|
7
|
+
@company_name = args[:company_name]
|
8
|
+
@operation = args[:operation]
|
9
|
+
@subchapter = args[:subchapter]
|
10
|
+
end
|
11
|
+
|
12
|
+
def build_xml(node)
|
13
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
14
|
+
node.Cabecera do |xml|
|
15
|
+
xml.Modelo Ticketbai::Api::Request::LROE_MODEL
|
16
|
+
xml.Capitulo Ticketbai::Api::Request::LROE_CHAPTER
|
17
|
+
xml.Subcapitulo @subchapter
|
18
|
+
xml.Operacion @operation
|
19
|
+
xml.Version '1.0'
|
20
|
+
xml.Ejercicio @year
|
21
|
+
xml.ObligadoTributario do
|
22
|
+
xml.NIF @nif
|
23
|
+
xml.ApellidosNombreRazonSocial @company_name
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class LroeIssuedInvoices
|
4
|
+
def initialize(args = {})
|
5
|
+
@issued_invoices = args[:issued_invoices]
|
6
|
+
@operation = args[:operation]
|
7
|
+
end
|
8
|
+
|
9
|
+
def build_xml(node)
|
10
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
11
|
+
node.FacturasEmitidas do |xml|
|
12
|
+
@issued_invoices.each do |issued_invoice|
|
13
|
+
xml.FacturaEmitida do
|
14
|
+
case @operation
|
15
|
+
when :annulment
|
16
|
+
xml.AnulacionTicketBai Base64.strict_encode64(issued_invoice)
|
17
|
+
when :issuance
|
18
|
+
xml.TicketBai Base64.strict_encode64(issued_invoice)
|
19
|
+
when :issuance_unsigned
|
20
|
+
xml << issued_invoice
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class Receiver
|
4
|
+
# ID TYPES
|
5
|
+
# 02: NIF-IVA
|
6
|
+
# 03: Pasaporte
|
7
|
+
# 04: Documento oficial de identificacion expedido por el pais o territorio de residencia
|
8
|
+
# 05: Certificado de residencia
|
9
|
+
# 06: Otro documento probatorio
|
10
|
+
|
11
|
+
def initialize(args = {})
|
12
|
+
@receiver_country = args[:receiver_country]
|
13
|
+
@receiver_nif = args[:receiver_nif]
|
14
|
+
@receiver_name = args[:receiver_name]
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_xml(node)
|
18
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
19
|
+
node.Destinatarios do |xml|
|
20
|
+
xml.IDDestinatario do
|
21
|
+
if @receiver_country == 'ES'
|
22
|
+
xml.NIF @receiver_nif
|
23
|
+
else
|
24
|
+
xml.IDOtro do
|
25
|
+
xml.CodigoPais @receiver_country
|
26
|
+
xml.IDType '04'
|
27
|
+
xml.ID @receiver_nif
|
28
|
+
end
|
29
|
+
end
|
30
|
+
xml.ApellidosNombreRazonSocial @receiver_name
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Nodes
|
3
|
+
class Software
|
4
|
+
def build_xml(node)
|
5
|
+
node = Nokogiri::XML::Builder.new if node.nil?
|
6
|
+
node.Software do |xml|
|
7
|
+
xml.LicenciaTBAI Ticketbai.config.license_key
|
8
|
+
xml.EntidadDesarrolladora do
|
9
|
+
xml.NIF Ticketbai.config.developer_company_nif
|
10
|
+
end
|
11
|
+
xml.Nombre Ticketbai.config.app_name
|
12
|
+
xml.Version Ticketbai.config.app_version
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
class Operation
|
3
|
+
attr_accessor :company_cert
|
4
|
+
|
5
|
+
def initialize(args)
|
6
|
+
self.class::ATTRIBUTES.each do |p|
|
7
|
+
instance_variable_set "@#{p}", args[p]
|
8
|
+
end
|
9
|
+
|
10
|
+
@company_cert = Ticketbai.config.certificates[args[:company_cert]]
|
11
|
+
end
|
12
|
+
|
13
|
+
###
|
14
|
+
# Creates the Ticketbai operation by doing the following:
|
15
|
+
# 1. Build the document
|
16
|
+
# 2. Sign the document
|
17
|
+
# 3. Validate the signed document
|
18
|
+
#
|
19
|
+
# @return [Hash] xml_doc: The signed document. signature_value: The first 100 characters of the signature value
|
20
|
+
###
|
21
|
+
def create
|
22
|
+
document = build_document
|
23
|
+
|
24
|
+
signed_document = sign_document(document)
|
25
|
+
|
26
|
+
validate_document(signed_document)
|
27
|
+
|
28
|
+
signature_value = read_signature_value(signed_document)[0..99]
|
29
|
+
|
30
|
+
{ xml_doc: signed_document, signature_value: signature_value }
|
31
|
+
end
|
32
|
+
|
33
|
+
def build_document
|
34
|
+
raise NotImplementedError, 'Must implement this method'
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def modify_xml_root_name(builder)
|
40
|
+
builder.doc.root.name = self.class::ROOT_NAME
|
41
|
+
end
|
42
|
+
|
43
|
+
def decoded_cert
|
44
|
+
Base64.decode64(@company_cert[:cert])
|
45
|
+
end
|
46
|
+
|
47
|
+
def sign_document(document)
|
48
|
+
Signer.new({ xml: document.to_xml, certificate: decoded_cert, key: @company_cert[:key] }).sign
|
49
|
+
end
|
50
|
+
|
51
|
+
def validate_document(document)
|
52
|
+
DocumentValidator.new(document: document, validator_type: self.class::OPERATION_NAME).validate
|
53
|
+
end
|
54
|
+
|
55
|
+
def read_signature_value(document)
|
56
|
+
Nokogiri::XML(document).children.last.children.last.children[1].children.first.text
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Operations
|
3
|
+
class Annulment < Operation
|
4
|
+
OPERATION_NAME = :annulment
|
5
|
+
|
6
|
+
ATTRIBUTES = %i[issuing_company_nif issuing_company_name invoice_serial invoice_number invoice_date].freeze
|
7
|
+
|
8
|
+
attr_accessor(*ATTRIBUTES)
|
9
|
+
|
10
|
+
###
|
11
|
+
# @param [String] issuing_company_nif NIF of the taxpayer's company
|
12
|
+
# @param [String] issuing_company_name Name of the taxpayer's company
|
13
|
+
# @param [String] invoice_serial Invoice's serial number
|
14
|
+
# @param [String] invoice_number Invoice's number
|
15
|
+
# @param [String] invoice_date Invoices emission date (Format: d-m-Y)
|
16
|
+
# @param [String] company_cert The name of the certificate to be used for issuance
|
17
|
+
###
|
18
|
+
def initialize(**args)
|
19
|
+
super(args)
|
20
|
+
end
|
21
|
+
|
22
|
+
def build_document
|
23
|
+
@issuer = Ticketbai::Nodes::Issuer.new(issuing_company_nif: @issuing_company_nif, issuing_company_name: @issuing_company_name)
|
24
|
+
|
25
|
+
@invoice_header = Ticketbai::Nodes::InvoiceHeader.new(
|
26
|
+
invoice_serial: @invoice_serial,
|
27
|
+
invoice_number: @invoice_number,
|
28
|
+
invoice_date: @invoice_date
|
29
|
+
)
|
30
|
+
|
31
|
+
@software = Ticketbai::Nodes::Software.new
|
32
|
+
|
33
|
+
Ticketbai::Documents::Annulment.new(
|
34
|
+
issuer: @issuer,
|
35
|
+
invoice_header: @invoice_header,
|
36
|
+
software: @software
|
37
|
+
).create
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
module Ticketbai
|
2
|
+
module Operations
|
3
|
+
class Issuance < Operation
|
4
|
+
DEFAULT_VAT_KEY = '01'.freeze
|
5
|
+
OPERATION_NAME = :issuance
|
6
|
+
|
7
|
+
ATTRIBUTES = %i[company_cert issuing_company_nif issuing_company_name receiver_nif receiver_name receiver_country receiver_in_eu invoice_serial
|
8
|
+
invoice_number invoice_date invoice_time simplified_invoice invoice_description invoice_total invoice_vat_key
|
9
|
+
invoice_amount invoice_vat invoice_vat_total prev_invoice_number prev_invoice_signature prev_invoice_date].freeze
|
10
|
+
|
11
|
+
attr_accessor(*ATTRIBUTES)
|
12
|
+
|
13
|
+
###
|
14
|
+
# @param [String] issuing_company_nif NIF of the taxpayer's company
|
15
|
+
# @param [String] issuing_company_name Name of the taxpayer's company
|
16
|
+
# @param [String] receiver_nif Spanish NIF or official identification document in case of being another country
|
17
|
+
# @param [String] receiver_name Name of the receiver
|
18
|
+
# @param [String] receiver_country Country code of the receiver (Ex: ES|DE)
|
19
|
+
# @param [Boolean] receiver_in_eu The receiver residence is in Europe?
|
20
|
+
# @param [String] invoice_serial Invoices serial number
|
21
|
+
# @param [String] invoice_number Invoices number
|
22
|
+
# @param [String] invoice_date Invoices emission date (Format: d-m-Y)
|
23
|
+
# @param [String] invoice_time Invoices emission time (Format: H:M:S)
|
24
|
+
# @param [Boolean] simplified_invoice is a simplified invoice?
|
25
|
+
# @param [String] invoice_description Invoices description text
|
26
|
+
# @param [String] invoice_total Total invoice amount
|
27
|
+
# @param [String] invoice_vat_key Key of the VAT regime
|
28
|
+
# @param [String] invoice_amount Taxable base of the invoice
|
29
|
+
# @param [Float] invoice_vat Invoice VAT (Ex: 21.0)
|
30
|
+
# @param [String] invoice_vat_total Invoices number
|
31
|
+
# @param [String] prev_invoice_number Number of the last invoice generated
|
32
|
+
# @param [String] prev_invoice_signature Signature of the last invoice generated
|
33
|
+
# @param [String] prev_invoice_date Emission date of the last invoice generated
|
34
|
+
# @param [Symbol] company_cert: The name of the certificate to be used for issuance
|
35
|
+
###
|
36
|
+
def initialize(**args)
|
37
|
+
args[:receiver_nif]&.strip!
|
38
|
+
args[:receiver_country] = args[:receiver_country]&.upcase || 'ES'
|
39
|
+
|
40
|
+
super(args)
|
41
|
+
end
|
42
|
+
|
43
|
+
def build_document
|
44
|
+
@issuer = Ticketbai::Nodes::Issuer.new(issuing_company_nif: @issuing_company_nif, issuing_company_name: @issuing_company_name)
|
45
|
+
|
46
|
+
if @receiver_nif && @receiver_name
|
47
|
+
@receiver = Ticketbai::Nodes::Receiver.new(receiver_country: @receiver_country, receiver_nif: @receiver_nif, receiver_name: @receiver_name)
|
48
|
+
end
|
49
|
+
|
50
|
+
@invoice_header = Ticketbai::Nodes::InvoiceHeader.new(
|
51
|
+
invoice_serial: @invoice_serial,
|
52
|
+
invoice_number: @invoice_number,
|
53
|
+
invoice_date: @invoice_date,
|
54
|
+
invoice_time: @invoice_time,
|
55
|
+
simplified_invoice: @simplified_invoice
|
56
|
+
)
|
57
|
+
@invoice_data = Ticketbai::Nodes::InvoiceData.new(
|
58
|
+
invoice_description: @invoice_description,
|
59
|
+
invoice_total: @invoice_total,
|
60
|
+
invoice_vat_key: @invoice_vat_key
|
61
|
+
)
|
62
|
+
@breakdown_type = Ticketbai::Nodes::BreakdownType.new(
|
63
|
+
receiver_country: @receiver_country,
|
64
|
+
invoice_amount: @invoice_amount,
|
65
|
+
invoice_vat: @invoice_vat,
|
66
|
+
invoice_vat_total: @invoice_vat_total,
|
67
|
+
receiver_in_eu: @receiver_in_eu,
|
68
|
+
simplified_invoice: @simplified_invoice
|
69
|
+
)
|
70
|
+
if @prev_invoice_number && @prev_invoice_date && @prev_invoice_signature
|
71
|
+
@invoice_chaining = Ticketbai::Nodes::InvoiceChaining.new(
|
72
|
+
prev_invoice_serial: @prev_invoice_serial,
|
73
|
+
prev_invoice_number: @prev_invoice_number,
|
74
|
+
prev_invoice_date: @prev_invoice_date,
|
75
|
+
prev_invoice_signature: @prev_invoice_signature
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
@software = Ticketbai::Nodes::Software.new
|
80
|
+
|
81
|
+
Ticketbai::Documents::Issuance.new(
|
82
|
+
issuer: @issuer,
|
83
|
+
receiver: @receiver,
|
84
|
+
invoice_header: @invoice_header,
|
85
|
+
invoice_data: @invoice_data,
|
86
|
+
breakdown_type: @breakdown_type,
|
87
|
+
invoice_chaining: @invoice_chaining,
|
88
|
+
software: @software
|
89
|
+
).create
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|