facturama 0.0.1

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.
Files changed (39) hide show
  1. checksums.yaml +7 -0
  2. data/lib/facturama.rb +56 -0
  3. data/lib/facturama/facturama_api_multi.rb +37 -0
  4. data/lib/facturama/facturama_api_web.rb +55 -0
  5. data/lib/facturama/models/address.rb +16 -0
  6. data/lib/facturama/models/branch_office.rb +14 -0
  7. data/lib/facturama/models/cfdi.rb +80 -0
  8. data/lib/facturama/models/cfdi_relation.rb +10 -0
  9. data/lib/facturama/models/cfdi_relations.rb +12 -0
  10. data/lib/facturama/models/client.rb +19 -0
  11. data/lib/facturama/models/complement.rb +8 -0
  12. data/lib/facturama/models/connection_info.rb +36 -0
  13. data/lib/facturama/models/csd.rb +14 -0
  14. data/lib/facturama/models/exception/facturama_exception.rb +18 -0
  15. data/lib/facturama/models/exception/model_exception.rb +11 -0
  16. data/lib/facturama/models/image.rb +11 -0
  17. data/lib/facturama/models/item.rb +25 -0
  18. data/lib/facturama/models/model.rb +75 -0
  19. data/lib/facturama/models/product.rb +27 -0
  20. data/lib/facturama/models/product_tax.rb +14 -0
  21. data/lib/facturama/models/receiver.rb +15 -0
  22. data/lib/facturama/models/serie.rb +13 -0
  23. data/lib/facturama/models/tax.rb +14 -0
  24. data/lib/facturama/models/tax_entity.rb +21 -0
  25. data/lib/facturama/models/tax_stamp.rb +12 -0
  26. data/lib/facturama/services/branch_office_service.rb +16 -0
  27. data/lib/facturama/services/catalog_service.rb +42 -0
  28. data/lib/facturama/services/cfdi_multi_service.rb +164 -0
  29. data/lib/facturama/services/cfdi_service.rb +172 -0
  30. data/lib/facturama/services/client_service.rb +19 -0
  31. data/lib/facturama/services/crud_service.rb +41 -0
  32. data/lib/facturama/services/csd_service.rb +16 -0
  33. data/lib/facturama/services/http_service.rb +152 -0
  34. data/lib/facturama/services/product_service.rb +16 -0
  35. data/lib/facturama/version.rb +4 -0
  36. data/lib/samples/sample_api.rb +17 -0
  37. data/lib/samples/sample_api_multi.rb +352 -0
  38. data/lib/samples/sample_api_web.rb +454 -0
  39. metadata +94 -0
@@ -0,0 +1,19 @@
1
+ require_relative "crud_service"
2
+
3
+ module Facturama
4
+
5
+ module Services
6
+ class ClientService < CrudService
7
+
8
+ def initialize(connection_info )
9
+ super(connection_info, "client")
10
+ end
11
+
12
+
13
+
14
+
15
+ end # class ClientService
16
+
17
+ end # module Services
18
+
19
+ end # module Facturama
@@ -0,0 +1,41 @@
1
+ require_relative "http_service"
2
+
3
+ module Facturama
4
+
5
+ module Services
6
+ class CrudService < HttpService
7
+
8
+ def initialize( connection_info, uri_resource )
9
+ super( connection_info, uri_resource)
10
+ end
11
+
12
+
13
+ def retrieve(message)
14
+ HttpService.instance_method(:get).bind(self).call(message)
15
+ end
16
+
17
+
18
+ def list
19
+ HttpService.instance_method(:get).bind(self).call('')
20
+ end
21
+
22
+
23
+ def create (message, url = "")
24
+ HttpService.instance_method(:post).bind(self).call(message, url)
25
+ end
26
+
27
+
28
+ def remove(message)
29
+ HttpService.instance_method(:delete).bind(self).call(message)
30
+ end
31
+
32
+
33
+ def update(message, url = "" )
34
+ HttpService.instance_method(:put).bind(self).call(message, url)
35
+ end
36
+
37
+ end # class CrudService
38
+
39
+ end # module Services
40
+
41
+ end # module Facturama
@@ -0,0 +1,16 @@
1
+ require_relative "crud_service"
2
+
3
+ module Facturama
4
+
5
+ module Services
6
+ class CsdService < CrudService
7
+
8
+ def initialize( connection_info )
9
+ super(connection_info, "api-lite/csds")
10
+ end
11
+
12
+ end # class CsdService
13
+
14
+ end # module Services
15
+
16
+ end # module Facturama
@@ -0,0 +1,152 @@
1
+
2
+ require_relative "../models/exception/facturama_exception"
3
+ require_relative "../models/connection_info.rb"
4
+
5
+ module Facturama
6
+
7
+ module Services
8
+
9
+ class HttpService
10
+
11
+ def initialize(connection_info, uri_resource )
12
+ @connection_info = connection_info
13
+ @uri_resource = uri_resource
14
+ end
15
+
16
+
17
+
18
+ def get(args='')
19
+ res=RestClient::Request.new(
20
+ :method => :get,
21
+ :url => url(args),
22
+ :user => @connection_info.facturama_user,
23
+ :password => @connection_info.facturama_password ,
24
+ :headers => {:accept => :json,
25
+ :content_type => :json,
26
+ :user_agent => '',
27
+ }
28
+ )
29
+
30
+ executor(res)
31
+ end
32
+
33
+
34
+
35
+
36
+ def post(message, args = "")
37
+ json =message.to_json
38
+
39
+ res= RestClient::Request.new(
40
+ :method => :post,
41
+ :url => url(args),
42
+ :user => @connection_info.facturama_user,
43
+ :password => @connection_info.facturama_password,
44
+ :payload => json,
45
+ :headers => { :content_type => :json }
46
+ )
47
+
48
+ executor(res)
49
+ end
50
+
51
+
52
+
53
+
54
+
55
+ def put(message, args = "")
56
+ json =message.to_json
57
+
58
+ res= RestClient::Request.new(
59
+ :method => :put,
60
+ :url => url(args),
61
+ :user => @connection_info.facturama_user,
62
+ :password => @connection_info.facturama_password ,
63
+ :payload => json,
64
+ :headers => {:accept => :json,
65
+ :content_type => :json}
66
+ )
67
+
68
+ executor(res)
69
+ end
70
+
71
+
72
+
73
+
74
+ def delete(args = "")
75
+ res=RestClient::Request.new(
76
+ :method => :delete,
77
+ :url => url(args),
78
+ :user => @connection_info.facturama_user,
79
+ :password => @connection_info.facturama_password ,
80
+ :headers => {:accept => :json,
81
+ :content_type => :json
82
+ }
83
+ )
84
+
85
+ executor(res)
86
+ end
87
+
88
+
89
+
90
+
91
+ private
92
+
93
+ def url(args = '')
94
+ slash = ""
95
+ args = args.to_s
96
+
97
+ if args.length > 0
98
+ slash = (args =~ /^\?/)? "" : "/"
99
+ end
100
+
101
+ if(@uri_resource.length > 0)
102
+ @uri_resource = "/" + @uri_resource;
103
+ end
104
+
105
+ @connection_info.uri_base + @uri_resource + slash + args
106
+ end
107
+
108
+
109
+ # Executa la peticion y procesa la respuesta decodificando el JSON a un Hash y
110
+ # Conviriendo los errores de la API en FacturamaExceptions
111
+ def executor(request)
112
+
113
+ begin
114
+ response = request.execute
115
+
116
+ if response.code != 204 && response.body != "" # 204 = sin contenido
117
+ JSON[ response]
118
+ end
119
+
120
+
121
+ #exceptions
122
+ rescue Exception => e
123
+ case e.class.name
124
+ when "RestClient::NotFound"
125
+ raise( FacturamaException.new( "404 NotFound: Elemento no encontrado" ) )
126
+ when "RestClient::BadRequest"
127
+ json_response = JSON[e.response]
128
+ model_state = json_response['ModelState']
129
+ if model_state != nil
130
+ model_state = json_response['ModelState'].map{|k,v| [k.to_s, v]}
131
+ fact_exception = FacturamaException.new( json_response['Message'] )
132
+ end
133
+
134
+ fact_exception = FacturamaException.new( json_response['Message'], model_state )
135
+ raise( fact_exception )
136
+ else
137
+ raise( Exception.new( e.response ) )
138
+ end
139
+
140
+ end
141
+
142
+ end
143
+
144
+
145
+
146
+
147
+
148
+ end # class HttpService
149
+
150
+ end # module Services
151
+
152
+ end # module Facturama
@@ -0,0 +1,16 @@
1
+ require_relative "crud_service"
2
+
3
+ module Facturama
4
+
5
+ module Services
6
+ class ProductService < CrudService
7
+
8
+ def initialize( connection_info )
9
+ super(connection_info, "product")
10
+ end
11
+
12
+ end # class ProductService
13
+
14
+ end # module Services
15
+
16
+ end # module Facturama
@@ -0,0 +1,4 @@
1
+ # -*- encoding : utf-8 -*-
2
+ module Facturama
3
+ VERSION = '0.0.1'
4
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module Facturama
3
+
4
+
5
+ module Samples
6
+
7
+ class SampleApi
8
+
9
+ def run
10
+ rasie "Este método debe ser sobrecargado, colocando las pruebas adecuadas, segun el tipo de API (Web, Multiemisor)"
11
+ end
12
+
13
+ end
14
+ end
15
+
16
+
17
+ end
@@ -0,0 +1,352 @@
1
+
2
+ require_relative "../facturama"
3
+ require_relative "sample_api.rb"
4
+ require 'json'
5
+
6
+
7
+ module Facturama
8
+
9
+
10
+ module Samples
11
+
12
+ class SampleApiMulti < SampleApi
13
+
14
+
15
+ def run
16
+ puts "====================================================================="
17
+ puts " FACTURAMA MULTIEMISOR SDK #{Facturama::VERSION}"
18
+ puts "====================================================================="
19
+
20
+
21
+ # Creación de una instacia de la API Multiemisor de Facturama, configurado con los datos del usuario de pruebas
22
+ facturama = create_api_instance
23
+
24
+
25
+ # Invocaciones a los ejemplos de uso de los servicios de Facturama API
26
+ begin
27
+
28
+ #sample_csds(facturama) # Servicio de CSD (certificados)
29
+
30
+ sample_cfdis(facturama) # Servicio de CFDI
31
+
32
+
33
+ rescue FacturamaException => ex
34
+ puts "----------- EXCEPCIONES -----------"
35
+ puts " * " + ex.message
36
+
37
+ if ex.details
38
+ ex.details.each do |item|
39
+ puts "#{item[0]}: " + item[1].join(",")
40
+ end
41
+
42
+ end
43
+
44
+ rescue Exception => ex
45
+ puts "----------- EXCEPCIONES -----------"
46
+ puts " * " + ex.to_s
47
+ end
48
+ end # run
49
+
50
+
51
+
52
+
53
+
54
+ # ---------------------------------------------------------------------------------------------------------------------
55
+ # CONFIGURACION DEL ENTORNO DE LA API
56
+ def create_api_instance
57
+ facturama_user='pruebas'
58
+ facturama_password='pruebas2011'
59
+ is_development = true # true = Modo de pruebas / sandbox, false = Modo de Producción (Timbrado real)
60
+
61
+
62
+ #Creacion de una instancia de FacturamaApiMultiemisor
63
+ Facturama::FacturamaApiMulti.new(facturama_user,facturama_password,is_development)
64
+ end
65
+
66
+
67
+
68
+ # ---------------------------------------------------------------------------------------------------------------------
69
+ # EJEMPLO DEL SERVICIO DE CSDS
70
+ def sample_csds(facturama)
71
+ puts "===== Ejemplo de CSD - Inicio ====="
72
+
73
+ sample_csds_list(facturama) # Listar todos los csd de la cuenta
74
+
75
+ sample_csds_load(facturama) # Cargar un nuevo CSD
76
+
77
+ sample_csds_update(facturama) # Obtiene un CSD mediante el RFC y lo actualiza
78
+
79
+ #sample_csds_remove(facturama) # Elmina el CSD asociado con el RFC
80
+
81
+ puts "===== Ejemplo de CSD - Fin ====="
82
+ end
83
+
84
+ # Ejemplo de obtener el listado de todos los certifiados cargados
85
+ def sample_csds_list(facturama)
86
+ puts "===== Obtener los CSD cargados - Inicio ====="
87
+
88
+ lst_csds = facturama.csds.list # Se obtiene una lista con todos los csds
89
+ lst_csds_count = lst_csds.count # Cantidad de csds
90
+
91
+ puts "Cantidad de CSDs: " + lst_csds_count.to_s
92
+
93
+ puts "===== Obtener los CSD cargados - Fin ====="
94
+ end
95
+
96
+
97
+ # Carga de un nuevo certificado, para un RFC
98
+ # * La API espera que el certificado y la llave sean enviados en base64. Por lo que las cadenas aqui expuestas,
99
+ # representan el contenido de los archivos corresponidientes, en dicho formato
100
+ def sample_csds_load(facturama)
101
+ puts "===== Cargar nuevo CSD - Inicio ====="
102
+
103
+ csd_model = Facturama::Models::Csd.new({
104
+ Rfc: "AAA010101AAA",
105
+ Certificate: "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",
106
+ PrivateKey: "MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIAgEAAoIBAQACAggAMBQGCCqGSIb3DQMHBAgwggS9AgEAMASCBMh4EHl7aNSCaMDA1VlRoXCZ5UUmqErAbucRBAKNQXH8tz2zJ7hdZaOZx7PEfMiWh5Nh6e8G8kxY+GW4YCSbLxslkhBtfTR6v5JYv3vhgH7XzMCwJPOfX6gxeeCYZ4HTdDNAyBVCjTbJpqbo778ri33o+I4yx7zgMqA3mzVE61re6MPrGXh1YT/K9zZeEdmwvXQfPs9VnioKUhiswoMcJ3kc3FxGLrEAsjQqv/ZVOHPY3NrbcfpQUyprsCKv3rRdxkIRdMPY4eiA720mffzvDqyzeQ8xfwHTE8Xjunja4KXvW/mV7ItTH0vRXHc3HJQ0dNnyawXmbC1FiYbCVdswoYuVQmslvq3QEXUGwP3KYfxQzKatnU7nprkmsipPqPBqDrzqc6NSN/8rxIc5zTAL4bFul+CEKz9VybwdavgewEy7u3fPnKPN+y4HilNgmlbtS7seWpbIgVPA+woG2Ph5hsgREXZCjGKSRuI77/FLcI5CMrZR+FvbnaqG+gXDBTz2lWhK9pmWlVawT2pvfiHOLzYRf2YyuVbJ79D2EgbUKyp3kCQ6fddMzspPhD/pvLQizExeyIxImb/kQXs2mmtDnyFIsj4Hcn5wCcs+SDIj+FJnwRiKB6YfdzjIig/ZMfpgMpl0u69LX649uL318o+Hy3d5t3wxgSkTaJ5McKhWyh9x9vlHZhYyM6HArBNfP9cGF86M3GwAMHAiJQl9UevyKe6rlvAIDlop6l3M02m5hHUXUpPjz4j7inFXZzvSv0tFoSbEqGgno0Pa+0gWHqRwBEGLGEwHVfyEy+Of8g4+0jzo0jNPIcurA5xRh9HSRSAd3kdEhx75eeVL7lBdLjRUkbtRtg7nelSjqAX7tQZK6Awp5C/17W96+f/vtjB+Y+ZgrSUjnQDADnZCnapIrzHgE3ZanhGAtnMMl+o4aLd1+74inG4jht/GJB60raSQfYrDrM3kBs0oyfpbEk5TI8ISzRlRmejv+mqpTogJaAqhnLP7rAli3d4pRhUjbACn/xQSFKxl2OURdmnMlvlbb6pleXviJHRxzPPQ25NVdWvmCYWrDfAZYn8X1sABOdyrth38BfmAVsyyPATYFB+5cXuNIZkPz1swz3859iZWTn5JRfPEAGICu5G6w6nrgOLYM9UqOPmxofzEdiEPafLQ5orMxdSWF6+3mD2Yw/VP+B43B/oYehgfrYjBUJt2D04VU/v8XK1ZUVgX/Co0odcdcszAP+ljQ7UVhW+uxVMd2sEprwepPPjYT3HvdI6RBB94yYBWfkoCSo/jsrrRpw2DVEyvoDp/hOXKyt8Y/8UGLCxJUhhv5fEiezYnlUAmwAGjgZfzfAErx0gkQFBgNKglEA7jz0Dqc2Z92pGVGTyPtXqRsqX3IYX5WsZVUoJim0wI7+LNmKpu147ePC0G4Sf4AGoZyPWVXq2SZSPpN261pIKSoLEDeA8WIKj2U5JG2DMMYokV0bZ1TsabrwHvwsp3muLnaP8L+n2fBplbhAEE2buBXvsATixMGu57ZI5WKFLnHn4KIBrZzALCtGehfFbCsdf1nBR6aAt+BpWhhZki54fZTurgMr6zuC5hAaP4rExW+LCc3upHMW7R9DcHWaZuZIfwnVDImnAQ9UOsz+A=",
107
+ PrivateKeyPassword:"12345678a"
108
+ })
109
+
110
+ facturama.csds.create(csd_model)
111
+ puts "Se ha cargado un nuevo CSD para el Rfc: #{csd_model.Rfc}"
112
+
113
+ puts "===== Cargar nuevo CSD - Fin ====="
114
+
115
+ end
116
+
117
+
118
+
119
+ # Ejemplo de eliminacion del un CSD asociado como RFC
120
+ def sample_csds_remove(facturama)
121
+ puts "===== Eliminar CSD asociado con un RFC- Inicio ====="
122
+
123
+ facturama.csds.remove("AAA010101AAA")
124
+ puts "Se ha eliminado el CSD asociado al Rfc"
125
+
126
+ puts "===== Eliminar CSD asociado con un RFC- Inicio ====="
127
+ end
128
+
129
+
130
+ # Ejemplo de actualización de CSD asociado con un RFC
131
+ def sample_csds_update(facturama)
132
+ puts "===== Actualiza el CSD asociado con un RFC- Inicio ====="
133
+
134
+ csd = facturama.csds.retrieve("AAA010101AAA")
135
+
136
+ csd['Certificate'] = "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"
137
+ csd['PrivateKey'] = "MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIAgEAAoIBAQACAggAMBQGCCqGSIb3DQMHBAgwggS9AgEAMASCBMh4EHl7aNSCaMDA1VlRoXCZ5UUmqErAbucRBAKNQXH8tz2zJ7hdZaOZx7PEfMiWh5Nh6e8G8kxY+GW4YCSbLxslkhBtfTR6v5JYv3vhgH7XzMCwJPOfX6gxeeCYZ4HTdDNAyBVCjTbJpqbo778ri33o+I4yx7zgMqA3mzVE61re6MPrGXh1YT/K9zZeEdmwvXQfPs9VnioKUhiswoMcJ3kc3FxGLrEAsjQqv/ZVOHPY3NrbcfpQUyprsCKv3rRdxkIRdMPY4eiA720mffzvDqyzeQ8xfwHTE8Xjunja4KXvW/mV7ItTH0vRXHc3HJQ0dNnyawXmbC1FiYbCVdswoYuVQmslvq3QEXUGwP3KYfxQzKatnU7nprkmsipPqPBqDrzqc6NSN/8rxIc5zTAL4bFul+CEKz9VybwdavgewEy7u3fPnKPN+y4HilNgmlbtS7seWpbIgVPA+woG2Ph5hsgREXZCjGKSRuI77/FLcI5CMrZR+FvbnaqG+gXDBTz2lWhK9pmWlVawT2pvfiHOLzYRf2YyuVbJ79D2EgbUKyp3kCQ6fddMzspPhD/pvLQizExeyIxImb/kQXs2mmtDnyFIsj4Hcn5wCcs+SDIj+FJnwRiKB6YfdzjIig/ZMfpgMpl0u69LX649uL318o+Hy3d5t3wxgSkTaJ5McKhWyh9x9vlHZhYyM6HArBNfP9cGF86M3GwAMHAiJQl9UevyKe6rlvAIDlop6l3M02m5hHUXUpPjz4j7inFXZzvSv0tFoSbEqGgno0Pa+0gWHqRwBEGLGEwHVfyEy+Of8g4+0jzo0jNPIcurA5xRh9HSRSAd3kdEhx75eeVL7lBdLjRUkbtRtg7nelSjqAX7tQZK6Awp5C/17W96+f/vtjB+Y+ZgrSUjnQDADnZCnapIrzHgE3ZanhGAtnMMl+o4aLd1+74inG4jht/GJB60raSQfYrDrM3kBs0oyfpbEk5TI8ISzRlRmejv+mqpTogJaAqhnLP7rAli3d4pRhUjbACn/xQSFKxl2OURdmnMlvlbb6pleXviJHRxzPPQ25NVdWvmCYWrDfAZYn8X1sABOdyrth38BfmAVsyyPATYFB+5cXuNIZkPz1swz3859iZWTn5JRfPEAGICu5G6w6nrgOLYM9UqOPmxofzEdiEPafLQ5orMxdSWF6+3mD2Yw/VP+B43B/oYehgfrYjBUJt2D04VU/v8XK1ZUVgX/Co0odcdcszAP+ljQ7UVhW+uxVMd2sEprwepPPjYT3HvdI6RBB94yYBWfkoCSo/jsrrRpw2DVEyvoDp/hOXKyt8Y/8UGLCxJUhhv5fEiezYnlUAmwAGjgZfzfAErx0gkQFBgNKglEA7jz0Dqc2Z92pGVGTyPtXqRsqX3IYX5WsZVUoJim0wI7+LNmKpu147ePC0G4Sf4AGoZyPWVXq2SZSPpN261pIKSoLEDeA8WIKj2U5JG2DMMYokV0bZ1TsabrwHvwsp3muLnaP8L+n2fBplbhAEE2buBXvsATixMGu57ZI5WKFLnHn4KIBrZzALCtGehfFbCsdf1nBR6aAt+BpWhhZki54fZTurgMr6zuC5hAaP4rExW+LCc3upHMW7R9DcHWaZuZIfwnVDImnAQ9UOsz+A="
138
+ csd['PrivateKeyPassword'] = "12345678a"
139
+
140
+ facturama.csds.update(csd, "AAA010101AAA")
141
+
142
+ puts "===== Actualiza CSD asociado con un RFC - Inicio ====="
143
+ end
144
+
145
+
146
+
147
+ # ---------------------------------------------------------------------------------------------------------------------
148
+ # EJEMPLO DEL SERVICIO DE CFDI
149
+ def sample_cfdis( facturama )
150
+ puts "===== Ejemplo de CFDI - Inicio ====="
151
+
152
+ # Creacion del cfdi en su forma general (sin items / productos) asociados
153
+ cfdi = sample_cfdis_create(facturama)
154
+
155
+ cfdi_uuid = cfdi['Complement']['TaxStamp']['Uuid']
156
+ puts "Se creó exitosamente el cfdi con el folio fiscal: " + cfdi_uuid
157
+
158
+ # Descarga de los arvhivos PDF y XML del cfdi recien creado
159
+ file_path = "factura" + cfdi_uuid
160
+ facturama.cfdis.save_pdf( file_path + ".pdf", cfdi['Id'])
161
+ facturama.cfdis.save_xml( file_path + ".xml", cfdi['Id'])
162
+
163
+ # Envio del cfdi por correo
164
+ if facturama.cfdis.send_by_mail(cfdi['Id'], "chucho@facturama.mx", "Factura del servicio" )
165
+ puts "Se envió por correo exitosamente el cfdi con el folio fiscal: " + cfdi_uuid
166
+ end
167
+
168
+ # Se elmina el cfdi recien creado
169
+ facturama.cfdis.remove(cfdi['Id'])
170
+ puts "Se elminó exitosamente el cfdi con el folio fiscal: " + cfdi_uuid
171
+
172
+
173
+ # Consulta de cfdi por palabra clave o Rfc
174
+ lst_by_rfc = facturama.cfdis.list_by_rfc("ESO1202108R2")
175
+ lst_by_keyword = facturama.cfdis.list_by_keyword("Software")
176
+
177
+ puts "Se obtiene la lista de facturas por RFC: #{lst_by_rfc.length}"
178
+ puts "Se obtiene la lista de facturas por KEYWORD: #{lst_by_keyword.length}"
179
+
180
+
181
+ puts "===== Ejemplo de CFDI - Fin ====="
182
+ end
183
+
184
+
185
+
186
+ # Ejemplo de creación de un CFDI
187
+ # En la API MULTIMEMISOR Se puede cambiar el campo de "Issuer" y emitir una factura,
188
+ # siempre y cuando previamente cargáramos los Certificados CSD
189
+ # * Nota:
190
+ # La creación de una factura muy similar a la forma de crearla en API WEB.
191
+ # Y se diferencía en que aquí se tiene la sección de:
192
+ # "Issuer": {
193
+ # "FiscalRegime": "601",
194
+ # "Rfc": "AAA010101AAA",
195
+ # "Name": "EXPRESION EN SOFTWARE"
196
+ # },
197
+ def sample_cfdis_create(facturama)
198
+
199
+ cfdi = {
200
+ "Serie": "R",
201
+ "Currency": "MXN",
202
+ "ExpeditionPlace": "78116",
203
+ "PaymentConditions": "CREDITO A SIETE DIAS",
204
+ "Folio": "100",
205
+ "CfdiType": "I",
206
+ "PaymentForm": "03",
207
+ "PaymentMethod": "PUE",
208
+
209
+
210
+ "Issuer": {
211
+ "FiscalRegime": "601",
212
+ "Rfc": "AAA010101AAA",
213
+ "Name": "EXPRESION EN SOFTWARE"
214
+ },
215
+
216
+
217
+ "Receiver": {
218
+ "Rfc": "XAXX010101000",
219
+ "Name": "RADIAL SOFTWARE SOLUTIONS",
220
+ "CfdiUse": "P01"
221
+ },
222
+ "Items": [
223
+ {
224
+ "ProductCode": "10101504",
225
+ "IdentificationNumber": "EDL",
226
+ "Description": "Estudios de viabilidad",
227
+ "Unit": "NO APLICA",
228
+ "UnitCode": "MTS",
229
+ "UnitPrice": 50.0,
230
+ "Quantity": 2.0,
231
+ "Subtotal": 100.0,
232
+ "Taxes": [{
233
+ "Total": 16.0,
234
+ "Name": "IVA",
235
+ "Base": 100.0,
236
+ "Rate": 0.16,
237
+ "IsRetention": false
238
+ }],
239
+ "Total": 116.0
240
+ },
241
+ {
242
+ "ProductCode": "10101504",
243
+ "IdentificationNumber": "001",
244
+ "Description": "SERVICIO DE COLOCACION",
245
+ "Unit": "NO APLICA",
246
+ "UnitCode": "E49",
247
+ "UnitPrice": 100.0,
248
+ "Quantity": 15.0,
249
+ "Subtotal": 1500.0,
250
+ "Discount": 0.0,
251
+ "Taxes": [{
252
+ "Total": 240.0,
253
+ "Name": "IVA",
254
+ "Base": 1500.0,
255
+ "Rate": 0.16,
256
+ "IsRetention": false
257
+ }],
258
+ "Total": 1740.0
259
+ }
260
+ ]
261
+ }
262
+
263
+
264
+ # Creación del CFDI mediante la API, para su creación
265
+ facturama.cfdis.create(cfdi)
266
+ end
267
+
268
+
269
+ def add_items_to_cfdi(facturama, currency, cfdi)
270
+
271
+ lst_products = facturama.products.list
272
+ lst_products_size = lst_products.length
273
+
274
+ n_items = (rand( lst_products.length ) % 10) + 1
275
+
276
+ decimals = currency['Decimals'].to_i
277
+
278
+ # Lista de conceptos para el CFDI
279
+ lst_items = Array.new
280
+
281
+
282
+ n_begin = lst_products_size - 1 - n_items
283
+
284
+ for index in n_begin..lst_products_size
285
+
286
+ product = lst_products[index] # Un producto cualquiera
287
+
288
+ if( product.nil? )
289
+ break
290
+
291
+ end
292
+
293
+ quantity = rand(5) + 1 # una cantidad aleatoria de elementos de este producto
294
+
295
+ discount = product['Price'] % ( product['Price']) == 0 ? 1 : rand( (product['Price'].to_i ) )
296
+ subtotal = ( product['Price'] * quantity).round(decimals) # Redondeo de acuerdo a la moneda
297
+
298
+
299
+
300
+ item = Facturama::Models::Item.new({
301
+ ProductCode: product['CodeProdServ'],
302
+ UnitCode: product['UnitCode'],
303
+ Unit: product['Unit'],
304
+ Description: product['Description'],
305
+ IdentificationNumber: product['IdentificationNumber'],
306
+ Quantity: quantity,
307
+ Discount: discount.round(decimals),
308
+ UnitPrice: product['Price'].round(decimals),
309
+ Subtotal: subtotal,
310
+ Taxes: nil
311
+
312
+ })
313
+
314
+
315
+ base_amount = (subtotal - discount).round(decimals)
316
+ taxes = product['Taxes'].map { |t|
317
+ Facturama::Models::Tax.new(
318
+ Name: t['Name'],
319
+ IsQuota: t['IsQuota'],
320
+ IsRetention: t['IsRetention'],
321
+ Rate: t['Rate'].to_f.round(decimals),
322
+ Base: base_amount,
323
+ Total: (base_amount * t['Rate'].to_f).round(decimals)
324
+ )
325
+ }
326
+
327
+ retentions_amount = 0
328
+ transfers_amount = 0
329
+ if taxes.length > 0
330
+ item.Taxes = taxes
331
+ # Calculo del monto total del concepto, tomando en cuenta los impuestos
332
+ retentions_amount = item.Taxes.select { |tax| tax.IsRetention }.sum(&:Total)
333
+ transfers_amount = item.Taxes.select { |tax| ! tax.IsRetention }.sum(&:Total)
334
+
335
+ end
336
+
337
+ item.Total = (item.Subtotal - item.Discount + transfers_amount - retentions_amount).round(decimals)
338
+
339
+ lst_items.push(item)
340
+
341
+ end
342
+
343
+ cfdi.Items = lst_items
344
+
345
+ end
346
+
347
+
348
+
349
+ end # class SampleApiWeb
350
+ end
351
+
352
+ end