facturama 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/facturama.rb +56 -0
- data/lib/facturama/facturama_api_multi.rb +37 -0
- data/lib/facturama/facturama_api_web.rb +55 -0
- data/lib/facturama/models/address.rb +16 -0
- data/lib/facturama/models/branch_office.rb +14 -0
- data/lib/facturama/models/cfdi.rb +80 -0
- data/lib/facturama/models/cfdi_relation.rb +10 -0
- data/lib/facturama/models/cfdi_relations.rb +12 -0
- data/lib/facturama/models/client.rb +19 -0
- data/lib/facturama/models/complement.rb +8 -0
- data/lib/facturama/models/connection_info.rb +36 -0
- data/lib/facturama/models/csd.rb +14 -0
- data/lib/facturama/models/exception/facturama_exception.rb +18 -0
- data/lib/facturama/models/exception/model_exception.rb +11 -0
- data/lib/facturama/models/image.rb +11 -0
- data/lib/facturama/models/item.rb +25 -0
- data/lib/facturama/models/model.rb +75 -0
- data/lib/facturama/models/product.rb +27 -0
- data/lib/facturama/models/product_tax.rb +14 -0
- data/lib/facturama/models/receiver.rb +15 -0
- data/lib/facturama/models/serie.rb +13 -0
- data/lib/facturama/models/tax.rb +14 -0
- data/lib/facturama/models/tax_entity.rb +21 -0
- data/lib/facturama/models/tax_stamp.rb +12 -0
- data/lib/facturama/services/branch_office_service.rb +16 -0
- data/lib/facturama/services/catalog_service.rb +42 -0
- data/lib/facturama/services/cfdi_multi_service.rb +164 -0
- data/lib/facturama/services/cfdi_service.rb +172 -0
- data/lib/facturama/services/client_service.rb +19 -0
- data/lib/facturama/services/crud_service.rb +41 -0
- data/lib/facturama/services/csd_service.rb +16 -0
- data/lib/facturama/services/http_service.rb +152 -0
- data/lib/facturama/services/product_service.rb +16 -0
- data/lib/facturama/version.rb +4 -0
- data/lib/samples/sample_api.rb +17 -0
- data/lib/samples/sample_api_multi.rb +352 -0
- data/lib/samples/sample_api_web.rb +454 -0
- metadata +94 -0
@@ -0,0 +1,454 @@
|
|
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 SampleApiWeb < SampleApi
|
13
|
+
|
14
|
+
def initialize
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
|
23
|
+
puts "============================================================"
|
24
|
+
puts " FACTURAMA WEB SDK #{Facturama::VERSION}"
|
25
|
+
puts "============================================================"
|
26
|
+
|
27
|
+
|
28
|
+
# Creación de una instacia de la API Facturama, configurado con los datos del usuario de pruebas
|
29
|
+
facturama = create_api_instance
|
30
|
+
|
31
|
+
|
32
|
+
# Invocaciones a los ejemplos de uso de los servicios de Facturama API
|
33
|
+
begin
|
34
|
+
#sample_clients(facturama) # Servicio de cliente
|
35
|
+
|
36
|
+
sample_products(facturama) # Servicio de productos
|
37
|
+
|
38
|
+
#sample_cfdis(facturama) # Servicio de CFDI
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
rescue FacturamaException => ex
|
45
|
+
puts "----------- EXCEPCIONES -----------"
|
46
|
+
puts " * " + ex.message
|
47
|
+
|
48
|
+
if ex.details
|
49
|
+
ex.details.each do |item|
|
50
|
+
puts "#{item[0]}: " + item[1].join(",")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
|
58
|
+
rescue Exception => ex
|
59
|
+
puts "----------- EXCEPCIONES -----------"
|
60
|
+
puts " * " + ex.to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
|
66
|
+
|
67
|
+
|
68
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
69
|
+
# CONFIGURACION DEL ENTORNO DE LA API
|
70
|
+
def create_api_instance
|
71
|
+
facturama_user='pruebas'
|
72
|
+
facturama_password='pruebas2011'
|
73
|
+
is_development = true # true = Modo de pruebas / sandbox, false = Modo de Producción (Timbrado real)
|
74
|
+
|
75
|
+
|
76
|
+
#Creacion de una instancia de FacturamaApi
|
77
|
+
Facturama::FacturamaApiWeb.new(facturama_user,facturama_password,is_development)
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
|
82
|
+
|
83
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
84
|
+
# EJEMPLO DEL SERVICIO DE CLIENTES
|
85
|
+
# - Listado de clientes
|
86
|
+
# - Agregar cliente
|
87
|
+
# - Obtener cliente específico y editarlo
|
88
|
+
def sample_clients(facturama)
|
89
|
+
|
90
|
+
sample_clients_list(facturama) # Listar todos los clientes
|
91
|
+
|
92
|
+
new_client = sample_clients_create(facturama) # Agregar cliente
|
93
|
+
client_id = new_client['Id'] # Id del cliente recientemente agregado
|
94
|
+
|
95
|
+
sample_clients_retrieve_and_update(facturama, client_id)
|
96
|
+
|
97
|
+
sample_clients_remove(facturama, client_id)
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
|
103
|
+
# Obtiene el listado de clientes y muestra la cantidad de los mismos
|
104
|
+
def sample_clients_list(facturama)
|
105
|
+
puts "===== Obtener los clientes - Inicio ====="
|
106
|
+
|
107
|
+
lst_clients = facturama.clients.list # Se obtiene una lista con todos los clientes
|
108
|
+
lst_clients_count = lst_clients.count # Cantidad inicial de clientes
|
109
|
+
|
110
|
+
|
111
|
+
|
112
|
+
puts "Cantidad inicial de clientes: " + lst_clients_count.to_s
|
113
|
+
|
114
|
+
puts "===== Obtener los clientes - Fin ====="
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
# Agrega un cliente
|
120
|
+
def sample_clients_create(facturama)
|
121
|
+
puts "===== Agregar cliente - Inicio ====="
|
122
|
+
|
123
|
+
facturama.clients.create(Facturama::Models::Client.new(
|
124
|
+
{ Email: "info@pedroperez.net",
|
125
|
+
Rfc: "RODJ899315654",
|
126
|
+
CfdiUse: "P01",
|
127
|
+
Name: "Pedro Perez Development Environment",
|
128
|
+
|
129
|
+
Address: {Country: "MEXICO",
|
130
|
+
ExteriorNumber: "1230",
|
131
|
+
InteriorNumber: "B",
|
132
|
+
Locality: "San Luis",
|
133
|
+
Municipality: "San Luis Potosí",
|
134
|
+
Neighborhood: "Lomas 4ta",
|
135
|
+
State: "San Luis Potosí",
|
136
|
+
Street: "Cañada de Gomez",
|
137
|
+
ZipCode: "78220"
|
138
|
+
}
|
139
|
+
}))
|
140
|
+
|
141
|
+
puts "===== Agregar cliente - Fin ====="
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
# Obtiene un cliente específico, lo edita y lo guarda
|
147
|
+
def sample_clients_retrieve_and_update(facturama, client_id)
|
148
|
+
|
149
|
+
puts "===== Obtener cliente y editarlo - Inicio ====="
|
150
|
+
|
151
|
+
# Se obtiene el cliente con el Id especificado
|
152
|
+
specific_client = facturama.clients.retrieve(client_id)
|
153
|
+
|
154
|
+
|
155
|
+
# Se ha encontrado un cliente con ese Id
|
156
|
+
if specific_client != nil then
|
157
|
+
|
158
|
+
puts "Specific Client: "
|
159
|
+
puts JSON[specific_client]
|
160
|
+
|
161
|
+
# Edición del campo RFC
|
162
|
+
specific_client['Rfc'] = "XAXX010101000"
|
163
|
+
specific_client['Email'] = "wm@joseromero.net"
|
164
|
+
facturama.clients.update(specific_client, client_id)
|
165
|
+
|
166
|
+
|
167
|
+
# Se obtiene nuevamente el cliente para confirmar que ha cambiado
|
168
|
+
specific_client = facturama.clients.retrieve(client_id)
|
169
|
+
|
170
|
+
if specific_client['Rfc'] == "XAXX010101000" then
|
171
|
+
puts "Cliente editado, ahora su RFC es XAXX010101000"
|
172
|
+
else
|
173
|
+
puts "Error al editar cliente"
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
|
178
|
+
puts "===== Obtener cliente y editarlo - Fin ====="
|
179
|
+
end
|
180
|
+
|
181
|
+
|
182
|
+
|
183
|
+
# Elimina un cliente
|
184
|
+
def sample_clients_remove(facturama, client_id)
|
185
|
+
|
186
|
+
puts "===== Eliminar cliente - Inicio ====="
|
187
|
+
|
188
|
+
specific_client = facturama.clients.remove(client_id)
|
189
|
+
|
190
|
+
puts "Cliente eliminado: "
|
191
|
+
puts JSON[specific_client]
|
192
|
+
|
193
|
+
puts "===== Eliminar cliente - Fin ====="
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
|
199
|
+
|
200
|
+
|
201
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
202
|
+
# EJEMPLO DEL SERVICIO DE PRODUCTOS
|
203
|
+
def sample_products( facturama )
|
204
|
+
sample_products_list(facturama) # Listar todos los productos
|
205
|
+
|
206
|
+
sample_products_create(facturama) # Agregar producto y eliminarlo
|
207
|
+
end
|
208
|
+
|
209
|
+
|
210
|
+
|
211
|
+
# Obtiene el listado de productos y muestra la cantidad de los mismos
|
212
|
+
def sample_products_list(facturama)
|
213
|
+
puts "===== Obtener los productos - Inicio ====="
|
214
|
+
|
215
|
+
lst_products = facturama.products.list # Se obtiene una lista con todos los productos
|
216
|
+
lst_products_count = lst_products.count # Cantidad inicial de productos
|
217
|
+
|
218
|
+
puts "Cantidad inicial de productos: " + lst_products_count.to_s
|
219
|
+
|
220
|
+
puts "===== Obtener los productos - Fin ====="
|
221
|
+
end
|
222
|
+
|
223
|
+
|
224
|
+
|
225
|
+
# Agrega un cliente
|
226
|
+
def sample_products_create(facturama)
|
227
|
+
puts "===== Agregar producto - Inicio ====="
|
228
|
+
|
229
|
+
unit = facturama.catalog.units("servicio").first # La primera unidad que tenga que ver con servicio
|
230
|
+
prod = facturama.catalog.products_or_services("desarrollo").first # Se toma el primer producto o servicio
|
231
|
+
|
232
|
+
|
233
|
+
|
234
|
+
product_model = Facturama::Models::Product.new(
|
235
|
+
{
|
236
|
+
Unit: "Servicio",
|
237
|
+
UnitCode: unit['Value'],
|
238
|
+
IdentificationNumber: "WEB003",
|
239
|
+
Name: "Sitio Web CMS",
|
240
|
+
Description: "Desarrollo e implementación de sitio web empleando un CMS",
|
241
|
+
Price: 6500.0,
|
242
|
+
CodeProdServ: prod['Value'],
|
243
|
+
CuentaPredial: "123",
|
244
|
+
|
245
|
+
Taxes: [
|
246
|
+
{
|
247
|
+
Name: "IVA",
|
248
|
+
Rate: 0.16,
|
249
|
+
IsRetention: false
|
250
|
+
}
|
251
|
+
]
|
252
|
+
}
|
253
|
+
)
|
254
|
+
|
255
|
+
product = facturama.products.create(product_model)
|
256
|
+
|
257
|
+
puts "Se creo exitosamente un producto con el id: " + product['Id']
|
258
|
+
|
259
|
+
|
260
|
+
facturama.products.delete( product['Id'] )
|
261
|
+
puts "Se eliminó exitosamente un producto con el id: " + product['Id']
|
262
|
+
|
263
|
+
|
264
|
+
puts "===== Agregar producto - Fin ====="
|
265
|
+
end
|
266
|
+
|
267
|
+
|
268
|
+
|
269
|
+
|
270
|
+
|
271
|
+
|
272
|
+
|
273
|
+
|
274
|
+
# ---------------------------------------------------------------------------------------------------------------------
|
275
|
+
# EJEMPLO DEL SERVICIO DE CFDI
|
276
|
+
# En la API WEB el emisor es Siempre la entidad fiscal configurada en la cuenta
|
277
|
+
def sample_cfdis( facturama )
|
278
|
+
puts "===== Ejemplo de CFDI - Inicio ====="
|
279
|
+
|
280
|
+
# Se obtiene la moneda con el valor "MXN"
|
281
|
+
lst_currencies = facturama::catalog.currencies
|
282
|
+
currency = lst_currencies.select {|currency| currency["Value"] == "MXN" }.first
|
283
|
+
|
284
|
+
|
285
|
+
# Creacion del cfdi en su forma general (sin items / productos) asociados
|
286
|
+
cfdi_model = sample_cfdis_create(facturama, currency)
|
287
|
+
|
288
|
+
# Agregar los items que lleva el cfdi ( para este ejemplo, se agregan con datos aleatorios)
|
289
|
+
add_items_to_cfdi(facturama, currency, cfdi_model)
|
290
|
+
|
291
|
+
# Creación del CFDI mediante la API, para su creación
|
292
|
+
cfdi = facturama.cfdis.create(cfdi_model)
|
293
|
+
cfdi_uuid = cfdi['Complement']['TaxStamp']['Uuid']
|
294
|
+
puts "Se creó exitosamente el cfdi con el folio fiscal: " + cfdi_uuid
|
295
|
+
|
296
|
+
# Descarga de los arvhivos PDF y XML del cfdi recien creado
|
297
|
+
file_path = "factura" + cfdi_uuid
|
298
|
+
facturama.cfdis.save_pdf( file_path + ".pdf", cfdi['Id'])
|
299
|
+
facturama.cfdis.save_xml( file_path + ".xml", cfdi['Id'])
|
300
|
+
|
301
|
+
# Envio del cfdi por correo
|
302
|
+
if facturama.cfdis.send_by_mail(cfdi['Id'], "chucho@facturama.mx", "Factura del servicio" )
|
303
|
+
puts "Se envió por correo exitosamente el cfdi con el folio fiscal: " + cfdi_uuid
|
304
|
+
end
|
305
|
+
|
306
|
+
# Se elmina el cfdi recien creado
|
307
|
+
facturama.cfdis.remove(cfdi['Id'])
|
308
|
+
puts "Se elminó exitosamente el cfdi con el folio fiscal: " + cfdi_uuid
|
309
|
+
|
310
|
+
|
311
|
+
# Consulta de cfdi por palabra clave o Rfc
|
312
|
+
lst_by_rfc = facturama.cfdis.list_by_rfc("ESO1202108R2")
|
313
|
+
lst_by_keyword = facturama.cfdis.list_by_keyword("Software")
|
314
|
+
|
315
|
+
puts "Se obtiene la lista de facturas por RFC: #{lst_by_rfc.length}"
|
316
|
+
puts "Se obtiene la lista de facturas por KEYWORD: #{lst_by_keyword.length}"
|
317
|
+
|
318
|
+
|
319
|
+
|
320
|
+
puts "===== Ejemplo de CFDI - Fin ====="
|
321
|
+
end
|
322
|
+
|
323
|
+
|
324
|
+
|
325
|
+
def sample_cfdis_create(facturama, currency)
|
326
|
+
|
327
|
+
# Nombre para el CFDI, para el ejemplo, tomado el primero de la lista del catálogo de nombres en el PDF
|
328
|
+
name_for_pdf = facturama.catalog.name_ids.first; # Nombre en el pdf: "Factura"
|
329
|
+
|
330
|
+
# Método de pago
|
331
|
+
payment_method = facturama.catalog.payment_methods.select {|method| method["Name"] == "Pago en una sola exhibición" }.first
|
332
|
+
|
333
|
+
|
334
|
+
# Forma de pago
|
335
|
+
payment_form = facturama.catalog.payment_forms.select {|method| method["Name"] == "Efectivo" }.first
|
336
|
+
|
337
|
+
|
338
|
+
# Cliente (se toma como cliente el "cliente generico", aquel que tiene el RFC genérico),
|
339
|
+
#(como los clientes son exclusivos para cada usuario, se debe previamente dar de alta este cliente)
|
340
|
+
client = facturama.clients.list.select {|client| client["Rfc"] == "XAXX010101000" }.first
|
341
|
+
|
342
|
+
|
343
|
+
# Lugar de expedición
|
344
|
+
branch_office = facturama.branch_office.list.first
|
345
|
+
|
346
|
+
# Fecha de emision (ahora mismo)
|
347
|
+
date = Time.now.strftime("%Y-%m-%d %H:%M:%S")
|
348
|
+
|
349
|
+
cfdi = Facturama::Models::Cfdi.new(
|
350
|
+
{
|
351
|
+
NameId: name_for_pdf['Value'],
|
352
|
+
CfdiType: Facturama::CfdiType::INGRESO,
|
353
|
+
PaymentForm: payment_form['Value'],
|
354
|
+
PaymentMethod: payment_method['Value'],
|
355
|
+
Currency: currency['Value'],
|
356
|
+
Date: date,
|
357
|
+
ExpeditionPlace: branch_office['Address']['ZipCode'],
|
358
|
+
Receiver: {
|
359
|
+
CfdiUse: client['CfdiUse'],
|
360
|
+
Name: client['Name'],
|
361
|
+
Rfc: client['Rfc']
|
362
|
+
},
|
363
|
+
Items: []
|
364
|
+
}
|
365
|
+
)
|
366
|
+
|
367
|
+
|
368
|
+
end
|
369
|
+
|
370
|
+
|
371
|
+
def add_items_to_cfdi(facturama, currency, cfdi)
|
372
|
+
|
373
|
+
lst_products = facturama.products.list
|
374
|
+
lst_products_size = lst_products.length
|
375
|
+
|
376
|
+
n_items = (rand( lst_products.length ) % 10) + 1
|
377
|
+
|
378
|
+
decimals = currency['Decimals'].to_i
|
379
|
+
|
380
|
+
# Lista de conceptos para el CFDI
|
381
|
+
lst_items = Array.new
|
382
|
+
|
383
|
+
|
384
|
+
n_begin = lst_products_size - 1 - n_items
|
385
|
+
|
386
|
+
for index in n_begin..lst_products_size
|
387
|
+
|
388
|
+
product = lst_products[index] # Un producto cualquiera
|
389
|
+
|
390
|
+
if( product.nil? )
|
391
|
+
break
|
392
|
+
|
393
|
+
end
|
394
|
+
|
395
|
+
quantity = rand(5) + 1 # una cantidad aleatoria de elementos de este producto
|
396
|
+
|
397
|
+
discount = product['Price'] % ( product['Price']) == 0 ? 1 : rand( (product['Price'].to_i ) )
|
398
|
+
subtotal = ( product['Price'] * quantity).round(decimals) # Redondeo de acuerdo a la moneda
|
399
|
+
|
400
|
+
|
401
|
+
|
402
|
+
item = Facturama::Models::Item.new({
|
403
|
+
ProductCode: product['CodeProdServ'],
|
404
|
+
UnitCode: product['UnitCode'],
|
405
|
+
Unit: product['Unit'],
|
406
|
+
Description: product['Description'],
|
407
|
+
IdentificationNumber: product['IdentificationNumber'],
|
408
|
+
Quantity: quantity,
|
409
|
+
Discount: discount.round(decimals),
|
410
|
+
UnitPrice: product['Price'].round(decimals),
|
411
|
+
Subtotal: subtotal,
|
412
|
+
Taxes: nil
|
413
|
+
|
414
|
+
})
|
415
|
+
|
416
|
+
|
417
|
+
base_amount = (subtotal - discount).round(decimals)
|
418
|
+
taxes = product['Taxes'].map { |t|
|
419
|
+
Facturama::Models::Tax.new(
|
420
|
+
Name: t['Name'],
|
421
|
+
IsQuota: t['IsQuota'],
|
422
|
+
IsRetention: t['IsRetention'],
|
423
|
+
Rate: t['Rate'].to_f.round(decimals),
|
424
|
+
Base: base_amount,
|
425
|
+
Total: (base_amount * t['Rate'].to_f).round(decimals)
|
426
|
+
)
|
427
|
+
}
|
428
|
+
|
429
|
+
retentions_amount = 0
|
430
|
+
transfers_amount = 0
|
431
|
+
if taxes.length > 0
|
432
|
+
item.Taxes = taxes
|
433
|
+
# Calculo del monto total del concepto, tomando en cuenta los impuestos
|
434
|
+
retentions_amount = item.Taxes.select { |tax| tax.IsRetention }.sum(&:Total)
|
435
|
+
transfers_amount = item.Taxes.select { |tax| ! tax.IsRetention }.sum(&:Total)
|
436
|
+
|
437
|
+
end
|
438
|
+
|
439
|
+
item.Total = (item.Subtotal - item.Discount + transfers_amount - retentions_amount).round(decimals)
|
440
|
+
|
441
|
+
lst_items.push(item)
|
442
|
+
|
443
|
+
end
|
444
|
+
|
445
|
+
cfdi.Items = lst_items
|
446
|
+
|
447
|
+
end
|
448
|
+
|
449
|
+
|
450
|
+
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
end
|