buho_cfdi 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,89 @@
1
+ require 'active_model'
2
+
3
+ module BuhoCfdi
4
+ class BaseNode
5
+ include ActiveModel::Validations
6
+ attr_accessor :node_hash
7
+
8
+ def initialize(params = {})
9
+ @node_hash = {}
10
+
11
+ params.each_pair do |key, value|
12
+ if respond_to? key
13
+ instance_variable_set("@#{key}", value)
14
+ end
15
+ end
16
+ end
17
+
18
+ def to_hash
19
+ self.class.params.each do |param|
20
+ node_hash[define_locale(param)] = send(param) unless send(param).blank?
21
+ end
22
+
23
+ node_hash
24
+ end
25
+
26
+ def build_child!(klass, params)
27
+ node = klass.new(params)
28
+
29
+ if node.valid?
30
+ self.class.send(:attr_reader, klass.name.downcase.sub( '::', '_'))
31
+ instance_variable_set("@#{klass.name.downcase.sub( '::', '_')}", node)
32
+ else
33
+ nil
34
+ end
35
+ end
36
+
37
+ def build_child(params)
38
+ node = self.class.new(params)
39
+
40
+ if node.valid?
41
+ self.class.send(:attr_reader, self.class.name.downcase.sub( '::', '_'))
42
+ instance_variable_set("@#{self.class.name.downcase.sub( '::', '_')}", self.class.new)
43
+ else
44
+ nil
45
+ end
46
+ end
47
+
48
+ def build_children(klass)
49
+ self.class.send(:attr_reader, klass.name.downcase.sub( '::', '_'))
50
+
51
+ instance_variable_set(
52
+ "@#{klass.name.downcase.sub( '::', '_')}",
53
+ ::Nodes::Collection.new(klass)
54
+ )
55
+
56
+ self
57
+ end
58
+
59
+ private
60
+
61
+ def define_locale(param)
62
+ I18n.t("nodes.#{self.class.name.demodulize.underscore}.#{param}")
63
+ end
64
+
65
+ class << self
66
+ def build_child(params)
67
+ node = self.new(params)
68
+
69
+ if node.valid?
70
+ self.class.send(:attr_reader, self.name.downcase.sub( '::', '_'))
71
+ instance_variable_set("@#{self.name.downcase.sub( '::', '_')}", self.new)
72
+ else
73
+ nil
74
+ end
75
+ end
76
+
77
+ def attr_accessor(*args)
78
+ @params ||= []
79
+ @params.concat(args)
80
+
81
+ super(*args)
82
+ end
83
+
84
+ def params
85
+ @params
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,27 @@
1
+ module BuhoCfdi
2
+ require 'openssl'
3
+
4
+ class Certificate
5
+
6
+ attr_reader :certificate_number, :certificate_value
7
+
8
+ def initialize (file)
9
+ if file.is_a? String
10
+ file = file
11
+ end
12
+ certificate = OpenSSL::X509::Certificate.new(file)
13
+ @certificate_number = '';
14
+ certificate.serial.to_s(16).scan(/.{2}/).each { |v| @certificate_number += v[1]; }
15
+ @certificate_value = certificate.to_s.gsub(/^-.+/, '').gsub(/\n/, '')
16
+
17
+ end
18
+
19
+ def certificate(xml)
20
+ xml = Nokogiri::XML(xml)
21
+ xml.at_css('cfdi|Comprobante').set_attribute('NoCertificado',@certificate_number)
22
+ xml.at_css('cfdi|Comprobante').set_attribute('Certificado',@certificate_value)
23
+ xml.to_xml
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,9 @@
1
+ begin
2
+ require "i18n"
3
+ rescue LoadError => e
4
+ puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
5
+ raise e
6
+ end
7
+
8
+ I18n.load_path << File.expand_path("locale/es.yml", __dir__)
9
+ I18n.locale = :es
@@ -0,0 +1,37 @@
1
+ module BuhoCfdi
2
+ require 'openssl'
3
+
4
+ class Key
5
+
6
+ attr_reader :private_key
7
+
8
+ def initialize(file, password=nil)
9
+ if file.is_a? String
10
+ @private_key = file
11
+ end
12
+ end
13
+
14
+ def seal(xml)
15
+ xml = Nokogiri::XML(xml)
16
+ signature = generate_seal(xml)
17
+ xml.at_css('cfdi|Comprobante').set_attribute('Sello',signature)
18
+ xml.to_xml
19
+ end
20
+
21
+ def generate_seal(xml)
22
+ chain = original_chain(xml)
23
+ key = OpenSSL::PKey::RSA.new(@private_key)
24
+ digester = OpenSSL::Digest::SHA256.new
25
+ signature = key.sign(digester, chain)
26
+ signature = Base64.strict_encode64(signature)
27
+ signature
28
+ end
29
+
30
+ def original_chain(invoice)
31
+ invoice = invoice
32
+ xslt = Nokogiri::XSLT(File.read('storage/xslt/cadenaoriginal_3_3.xslt'))
33
+ chain = xslt.transform(invoice)
34
+ chain.text.gsub("\n","")
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,83 @@
1
+ es:
2
+ nodes:
3
+ receipt:
4
+ version: Version
5
+ serie: Serie
6
+ folio_number: Folio
7
+ date: Fecha
8
+ stamp: Sello
9
+ payment_way: FormaPago
10
+ certificate_number: NoCertificado
11
+ certificate: Certificado
12
+ payment_conditions: CondicionesDePago
13
+ subtotal: SubTotal
14
+ discount: Descuento
15
+ currency: Moneda
16
+ exchange_rate: TipoCambio
17
+ total: Total
18
+ type_of_receipt: TipoDeComprobante
19
+ payment_method: MetodoPago
20
+ expedition_place: LugarExpedicion
21
+ confirmation: Confirmacion
22
+ cfdi_related:
23
+ relationship_type: TipoRelacion
24
+ related:
25
+ uuid: UUID
26
+ issuer:
27
+ rfc: Rfc
28
+ name: Nombre
29
+ fiscal_regime: RegimenFiscal
30
+ receiver:
31
+ rfc: Rfc
32
+ name: Nombre
33
+ tax_residency: ResidenciaFiscal
34
+ tax_identity_registration_number: NumRegIdTrib
35
+ cfdi_usage: UsoCFDI
36
+ concept:
37
+ prod_or_svc_key: ClaveProdServ
38
+ identification_number: NoIdentificacion
39
+ quantity: Cantidad
40
+ unit_measure_key: ClaveUnidad
41
+ unit_measure: Unidad
42
+ description: Descripcion
43
+ unit_value: ValorUnitario
44
+ amount: Importe
45
+ discount: Descuento
46
+ tax_transferred:
47
+ base: Base
48
+ tax: Impuesto
49
+ factor_type: TipoFactor
50
+ rate_or_fee: TasaOCuota
51
+ import: Importe
52
+ tax_detained:
53
+ base: Base
54
+ tax: Impuesto
55
+ factor_type: TipoFactor
56
+ rate_or_fee: TasaOCuota
57
+ import: Importe
58
+ customs_information: # InformacionAduanera
59
+ requirement_number: NumeroPedimento
60
+ property_account: # CuentaPredial
61
+ number: Numero
62
+ part: # Parte
63
+ prod_or_svc_key: ClaveProdServ
64
+ identification_number: NoIdentificacion
65
+ quantity: Cantidad
66
+ unit_measure: Unidad
67
+ description: Descripcion
68
+ unit_value: ValorUnitario
69
+ amount: Importe
70
+ taxes: # Impuestos
71
+ total_taxes_transferred: TotalImpuestosTrasladados
72
+ total_taxes_detained: TotalImpuestosRetenidos
73
+ detained:
74
+ tax: Impuesto
75
+ import: Importe
76
+ transferred:
77
+ tax: Impuesto
78
+ factor_type: TipoFactor
79
+ rate_or_fee: TasaOCuota
80
+ import: Importe
81
+
82
+
83
+
@@ -0,0 +1,9 @@
1
+ module Nodes
2
+ class CfdiRelated < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :relationship_type # TipoRelacion - required
5
+ )
6
+
7
+ validates_presence_of :relationship_type
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module Nodes
2
+ class Collection
3
+ attr_accessor :_collection, :klass
4
+
5
+ def initialize(klass)
6
+ @klass = klass
7
+ @_collection = []
8
+ end
9
+
10
+ def all
11
+ _collection
12
+ end
13
+
14
+ def add(params)
15
+ instance = klass.new(params)
16
+ _collection << instance
17
+
18
+ instance
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
1
+ module Nodes
2
+ class Concept < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :prod_or_svc_key, # ClaveProdServ - required
5
+ :identification_number, # NoIdentificacion - optional
6
+ :quantity, # Cantidad - required
7
+ :unit_measure_key, # ClaveUnidad - required
8
+ :unit_measure, # Unidad - optional
9
+ :description, # Descripcion - required
10
+ :unit_value, # ValorUnitario - required
11
+ :amount, # Importe - required
12
+ :discount # Descuento - optional
13
+ )
14
+
15
+ validates_presence_of(
16
+ :prod_or_svc_key,
17
+ :quantity,
18
+ :unit_measure_key,
19
+ :description,
20
+ :unit_value,
21
+ :amount
22
+ )
23
+ end
24
+ end
@@ -0,0 +1,9 @@
1
+ module Nodes
2
+ class CustomsInformation < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :requirement_number # NumeroPedimento - required
5
+ )
6
+
7
+ validates_presence_of :requirement_number
8
+ end
9
+ end
@@ -0,0 +1,10 @@
1
+ module Nodes
2
+ class Detained < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :tax, # Impuesto - required
5
+ :import # Importe - required
6
+ )
7
+
8
+ validates_presence_of :tax, :import
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Nodes
2
+ class Issuer < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :rfc, # Rfc - required
5
+ :name, # Nombre - optional
6
+ :fiscal_regime # RegimenFiscal - required
7
+ )
8
+
9
+ validates_presence_of :rfc, :fiscal_regime
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ module Nodes
2
+ class Part < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :prod_or_svc_key, # ClaveProdServ - required
5
+ :identification_number, # NoIdentificacion - optional
6
+ :quantity, # Cantidad - required
7
+ :unit_measure, # Unidad - optional
8
+ :description, # Descripcion - required
9
+ :unit_value, # ValorUnitario - optional
10
+ :amount # Importe - optional
11
+ )
12
+
13
+ validates_presence_of(
14
+ :prod_or_svc_key,
15
+ :quantity,
16
+ :description
17
+ )
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module Nodes
2
+ class PropertyAccount < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :number # Numero - required
5
+ )
6
+
7
+ validates_presence_of :number
8
+ end
9
+ end
@@ -0,0 +1,45 @@
1
+ module Nodes
2
+ class Receipt < ::BuhoCfdi::BaseNode
3
+ DEFAULT = {
4
+ 'xsi:schemaLocation' => 'http://www.sat.gob.mx/cfd/3 http://www.sat.gob.mx/sitio_internet/cfd/3/cfdv33.xsd',
5
+ }
6
+
7
+ attr_accessor(
8
+ :version, # Version - required
9
+ :serie, # Serie - optional
10
+ :folio_number, # Folio - optional
11
+ :date, # Fecha - required
12
+ :stamp, # Sello - required
13
+ :payment_way, # FormaPago - optional
14
+ :certificate_number, # NoCertificado - required
15
+ :certificate, # Certificado - required
16
+ :payment_conditions, # CondicionesDePago - optional
17
+ :subtotal, # SubTotal - required
18
+ :discount, # Descuento - optional
19
+ :currency, # Moneda - required
20
+ :exchange_rate, # TipoCambio - optional
21
+ :total, # Total - required
22
+ :type_of_receipt, # TipoDeComprobante - required
23
+ :payment_method, # MetodoPago - optional
24
+ :expedition_place, # LugarExpedicion - required
25
+ :confirmation # Confirmacion - optional
26
+ )
27
+
28
+ validates_presence_of(
29
+ :version,
30
+ :date,
31
+ :stamp,
32
+ :certificate_number,
33
+ :certificate,
34
+ :subtotal,
35
+ :currency,
36
+ :total,
37
+ :type_of_receipt,
38
+ :expedition_place
39
+ )
40
+
41
+ def to_hash
42
+ super.merge! DEFAULT
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,13 @@
1
+ module Nodes
2
+ class Receiver < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :rfc, # Rfc - required
5
+ :name, # Nombre - optional
6
+ :tax_residency, # ResidenciaFiscal - optional
7
+ :tax_identity_registration_number, # NumRegIdTrib - optional
8
+ :cfdi_usage # UsoCFDI - required
9
+ )
10
+
11
+ validates_presence_of :rfc, :cfdi_usage
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Nodes
2
+ class Related < ::BuhoCfdi::BaseNode
3
+ attr_accessor(
4
+ :uuid # UUID - required
5
+ )
6
+
7
+ validates_presence_of :uuid
8
+ end
9
+ end