flights_gui_henry_tests_ds 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. data/Gemfile +3 -0
  2. data/features/data/home-offers-config.csv +883 -0
  3. data/features/data/host.yml +78 -0
  4. data/features/data/miles.yml +216 -0
  5. data/features/data/search.yml +27 -0
  6. data/features/data/sites.yml +49 -0
  7. data/features/data/sites.yml.orig +54 -0
  8. data/features/data/tag_microsoft.yml +68 -0
  9. data/features/step_definitions/checkout/agencia_steps.rb +6 -0
  10. data/features/step_definitions/checkout/cash_payment_steps.rb +70 -0
  11. data/features/step_definitions/checkout/chat_steps.rb +57 -0
  12. data/features/step_definitions/checkout/checkout_steps.rb +265 -0
  13. data/features/step_definitions/checkout/cupones_steps.rb +36 -0
  14. data/features/step_definitions/checkout/error_messages.rb +291 -0
  15. data/features/step_definitions/checkout/fast_checkout.rb +55 -0
  16. data/features/step_definitions/checkout/price_jump_steps.rb +70 -0
  17. data/features/step_definitions/checkout/seguros_steps.rb +79 -0
  18. data/features/step_definitions/checkout/thanks_steps.rb +81 -0
  19. data/features/step_definitions/content/contents_steps.rb +140 -0
  20. data/features/step_definitions/desambiguation/disambiguation_airports_steps.rb +82 -0
  21. data/features/step_definitions/desambiguation/disambiguation_city_steps.rb +53 -0
  22. data/features/step_definitions/filter/filters_airlines.rb +37 -0
  23. data/features/step_definitions/filter/filters_airports_steps.rb +31 -0
  24. data/features/step_definitions/filter/filters_price_steps.rb +91 -0
  25. data/features/step_definitions/filter/filters_stops_steps.rb +44 -0
  26. data/features/step_definitions/filter/filters_time_steps.rb +146 -0
  27. data/features/step_definitions/filter/matrix_steps.rb +276 -0
  28. data/features/step_definitions/landing/landing_checkout_steps.rb +49 -0
  29. data/features/step_definitions/landing/landing_filters_steps.rb +17 -0
  30. data/features/step_definitions/landing/landing_home_alerts_steps.rb +21 -0
  31. data/features/step_definitions/landing/landing_home_steps.rb +82 -0
  32. data/features/step_definitions/landing/landing_long_tail.rb +58 -0
  33. data/features/step_definitions/landing/landing_negative_steps.rb +128 -0
  34. data/features/step_definitions/landing/landing_passenger_review_steps.rb +8 -0
  35. data/features/step_definitions/landing/landing_steps.rb +348 -0
  36. data/features/step_definitions/orders/orders.rb +83 -0
  37. data/features/step_definitions/others/advancedgui_steps.rb +28 -0
  38. data/features/step_definitions/others/advancednogui_steps.rb +34 -0
  39. data/features/step_definitions/others/anticipatedsearch_steps.rb +13 -0
  40. data/features/step_definitions/others/cookies_steps.rb +40 -0
  41. data/features/step_definitions/others/flights_tracker_steps.rb +74 -0
  42. data/features/step_definitions/others/generic_steps.rb +33 -0
  43. data/features/step_definitions/others/newsletter_steps.rb +29 -0
  44. data/features/step_definitions/others/one_day_search.rb +58 -0
  45. data/features/step_definitions/others/print_steps.rb +26 -0
  46. data/features/step_definitions/others/querystringparameters_steps.rb +6 -0
  47. data/features/step_definitions/others/recommendation_steps.rb +78 -0
  48. data/features/step_definitions/others/render_steps.rb +70 -0
  49. data/features/step_definitions/others/tag_steps.rb +164 -0
  50. data/features/step_definitions/others/upgrade_bussines_steps.rb +27 -0
  51. data/features/step_definitions/results/devtools_steps.rb +10 -0
  52. data/features/step_definitions/results/itineraries_steps.rb +43 -0
  53. data/features/step_definitions/results/load_steps.rb +73 -0
  54. data/features/step_definitions/results/results_steps.rb +79 -0
  55. data/features/step_definitions/results/search_steps.rb +115 -0
  56. data/features/step_definitions/search/alerts_steps.rb +132 -0
  57. data/features/step_definitions/search/basefare_steps.rb +88 -0
  58. data/features/step_definitions/search/bestprices_steps.rb +70 -0
  59. data/features/step_definitions/search/cross_sell_row_hoteles.rb +52 -0
  60. data/features/step_definitions/search/cross_sell_steps.rb +15 -0
  61. data/features/step_definitions/search/delays_steps.rb +67 -0
  62. data/features/step_definitions/search/details_steps.rb +9 -0
  63. data/features/step_definitions/search/ecoflights_steps.rb +9 -0
  64. data/features/step_definitions/search/errors_steps.rb +24 -0
  65. data/features/step_definitions/search/fenix_steps.rb +99 -0
  66. data/features/step_definitions/search/flight_gui_steps.rb +376 -0
  67. data/features/step_definitions/search/miles_step.rb +13 -0
  68. data/features/step_definitions/search/pagination_steps.rb +29 -0
  69. data/features/step_definitions/search/reviews_step.rb +58 -0
  70. data/features/step_definitions/search/search_no_gui_steps.rb +185 -0
  71. data/features/step_definitions/search/wish_list_steps.rb +128 -0
  72. data/features/support/env.rb +86 -0
  73. data/features/support/lib/clusters.rb +6 -0
  74. data/features/support/lib/clusters/checkout_cluster.rb +111 -0
  75. data/features/support/lib/clusters/data/data.rb +33 -0
  76. data/features/support/lib/clusters/details/details_cluster.rb +36 -0
  77. data/features/support/lib/clusters/results/landing_cluster.rb +87 -0
  78. data/features/support/lib/clusters/results/render_cluster.rb +86 -0
  79. data/features/support/lib/clusters/results_cluster.rb +168 -0
  80. data/features/support/lib/helpers.rb +5 -0
  81. data/features/support/lib/helpers/browser.rb +235 -0
  82. data/features/support/lib/helpers/checkout.rb +29 -0
  83. data/features/support/lib/helpers/clusters.rb +166 -0
  84. data/features/support/lib/helpers/landing.rb +121 -0
  85. data/features/support/lib/helpers/render.rb +135 -0
  86. data/features/support/lib/price.rb +66 -0
  87. data/features/support/lib/process_manager.rb +104 -0
  88. data/features/support/lib/services.rb +4 -0
  89. data/features/support/lib/services/fenix.rb +14 -0
  90. data/features/support/lib/services/landing.rb +18 -0
  91. data/features/support/lib/services/results.rb +62 -0
  92. data/features/support/matchers.rb +120 -0
  93. data/features/support/redefinitions.rb +42 -0
  94. data/features/tests/checkout/agency.feature +27 -0
  95. data/features/tests/checkout/button_cac.feature +53 -0
  96. data/features/tests/checkout/cash_payment.feature +50 -0
  97. data/features/tests/checkout/compras_duplicadas.feature +95 -0
  98. data/features/tests/checkout/cupones.feature +34 -0
  99. data/features/tests/checkout/error_messages.feature +80 -0
  100. data/features/tests/checkout/fast_checkout.feature +82 -0
  101. data/features/tests/checkout/integration.feature +235 -0
  102. data/features/tests/checkout/low_cost.feature +62 -0
  103. data/features/tests/checkout/online_payment.feature +50 -0
  104. data/features/tests/checkout/price_jump.feature +103 -0
  105. data/features/tests/checkout/providers.feature +76 -0
  106. data/features/tests/checkout/seguros.feature +42 -0
  107. data/features/tests/contents/costs.feature +29 -0
  108. data/features/tests/contents/rules.feature +58 -0
  109. data/features/tests/contents/webcheckin.feature +26 -0
  110. data/features/tests/desambiguation/airports.feature +89 -0
  111. data/features/tests/desambiguation/airports_landing.feature +88 -0
  112. data/features/tests/desambiguation/city.feature +86 -0
  113. data/features/tests/filters/filters.feature +113 -0
  114. data/features/tests/fixes/advancedgui.feature +171 -0
  115. data/features/tests/fixes/advancednogui.feature +60 -0
  116. data/features/tests/fixes/book_no_gui.feature +21 -0
  117. data/features/tests/fixes/cross_sell_row_hoteles.feature +70 -0
  118. data/features/tests/fixes/facebook.feature +31 -0
  119. data/features/tests/fixes/landing_checkout.feature +286 -0
  120. data/features/tests/fixes/landing_home_alerts.feature +82 -0
  121. data/features/tests/fixes/matrix_stops.feature +104 -0
  122. data/features/tests/fixes/one_day_search.feature +63 -0
  123. data/features/tests/fixes/print.feature +87 -0
  124. data/features/tests/fixes/searches_no_gui.feature +85 -0
  125. data/features/tests/fixes/upgrade_bussines.feature +100 -0
  126. data/features/tests/landing/landing_alerts.feature +93 -0
  127. data/features/tests/landing/landing_filters.feature +171 -0
  128. data/features/tests/landing/landing_home.feature +68 -0
  129. data/features/tests/landing/landing_integration.feature +149 -0
  130. data/features/tests/landing/landing_long_tail.feature +169 -0
  131. data/features/tests/landing/landing_matrix.feature +152 -0
  132. data/features/tests/landing/landing_negative.feature +151 -0
  133. data/features/tests/landing/landing_orders.feature +79 -0
  134. data/features/tests/landing/landing_pagination.feature +141 -0
  135. data/features/tests/landing/landing_passenger_review.feature +135 -0
  136. data/features/tests/landing/landing_positive.feature +151 -0
  137. data/features/tests/landing/landing_reviews.feature +135 -0
  138. data/features/tests/landing/landing_sort.feature +140 -0
  139. data/features/tests/landing/landing_tags.feature +142 -0
  140. data/features/tests/matrix/matrix_airlines.feature +80 -0
  141. data/features/tests/matrix/matrix_fare_chart.feature +40 -0
  142. data/features/tests/matrix/matrix_price.feature +40 -0
  143. data/features/tests/others/alerts.feature +89 -0
  144. data/features/tests/others/anticipatedsearch.feature +82 -0
  145. data/features/tests/others/chat.feature +23 -0
  146. data/features/tests/others/flights_tracker.feature +94 -0
  147. data/features/tests/others/newsletter.feature +118 -0
  148. data/features/tests/others/querystringparameters.feature +82 -0
  149. data/features/tests/others/recommendation.feature +107 -0
  150. data/features/tests/others/semaphore.feature +206 -0
  151. data/features/tests/search/basefare.feature +89 -0
  152. data/features/tests/search/errors.feature +198 -0
  153. data/features/tests/search/itineraries.feature +92 -0
  154. data/features/tests/search/orders.feature +88 -0
  155. data/features/tests/search/pagination.feature +73 -0
  156. data/features/tests/search/reviews.feature +83 -0
  157. data/features/tests/search/searches.feature +214 -0
  158. data/features/tests/search/wish_list.feature +58 -0
  159. data/flights_gui_henry_tests.gemspec +32 -0
  160. data/henry-context.yml +17262 -0
  161. metadata +382 -0
@@ -0,0 +1,6 @@
1
+ # -*- encoding : utf-8 -*-
2
+ require_relative 'clusters/results_cluster'
3
+ require_relative 'clusters/results/landing_cluster'
4
+ require_relative 'clusters/results/render_cluster'
5
+ require_relative 'clusters/details/details_cluster'
6
+ require_relative 'clusters/checkout_cluster'
@@ -0,0 +1,111 @@
1
+ class CheckoutCluster
2
+
3
+ attr_accessor :ida, :vuelta, :tarifas, :idas, :vueltas
4
+
5
+ def initialize(itinerario,html,page = 0)
6
+ self.load_prices((html/"div.price-info"))
7
+ eval "#{itinerario.downcase}(html)"
8
+ end
9
+ def roundtrip(html)
10
+ self.load_data_from((html/"div#itinerary div[@class='route outbound-route row-col']"))
11
+ self.load_data_to((html/"div#itinerary div[@class='route inbound-route row-col']"))
12
+ end
13
+ def oneway(html)
14
+ self.load_data_from((html/"div#itinerary div[@class='route outbound-route row-col']"))
15
+ @nro_vuelo_vuelta = -1
16
+ end
17
+ def multipledestinations(html)
18
+ self.load_data_from((html/"div#itinerary div[@class='route outbound-route row-col']"))
19
+ self.load_data_to((html/"div#itinerary div[@class='route outbound-route row-col']").last)
20
+ end
21
+ def load_data_from(div_datos)
22
+ @idas = Array.new
23
+ (div_datos/"div.segment").each do |div_datos_ida|
24
+ origen = (div_datos/"span.cities").first.inner_html.to_s.match("(.*)\<span class=\"separator\"\>\<\/span\>(.*)")[1].strip.no_accents
25
+ destino= (div_datos/"span.cities").last.inner_html.to_s.match("(.*)\<span class=\"separator\"\>\<\/span\>(.*)")[2].strip.no_accents
26
+ origen_iata = (div_datos/"li.outbound a")[0].inner_text.strip
27
+ destino_iata = (div_datos/"li.inbound a")[-1].inner_text.strip
28
+ fecha = (div_datos_ida/"li.outbound span.date")[0] ? (div_datos_ida/"li.outbound span.date")[0].inner_text.strip.no_accents : (div_datos_ida/"li.inbound span.date")[0].inner_text.strip.no_accents
29
+ escala = (div_datos/"span.stops a").inner_text.strip.empty? ? "Sin escalas" : (div_datos/"span.stops a").inner_text.to_i
30
+ aerolinea = Array.new
31
+ i = 0
32
+ (div_datos_ida/"span.airline-logo//img").each do |aer|
33
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
34
+ i = i + 1
35
+ end
36
+ hou_sal_ida = Time.parse((div_datos/"li.outbound").first.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)") ? (div_datos/"li.outbound").first.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)")[2].strip.no_accents : (div_datos/"li.outbound").last.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)")[2].strip.no_accents)
37
+ hou_lle_ida = Time.parse((div_datos/"li.outbound").last.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)") ? (div_datos/"li.outbound").last.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)")[2].strip.no_accents : (div_datos/"li.outbound").first.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)")[2].strip.no_accents)
38
+ @idas << DataCluster.new(origen,destino,fecha, aerolinea, escala_to_i(escala),origen_iata,destino_iata,hou_sal_ida,hou_lle_ida)
39
+ end
40
+ @nro_vuelo_ida = 0
41
+ @ida = @idas[@nro_vuelo_ida]
42
+ end
43
+ def load_data_to(div_datos)
44
+ @vueltas = Array.new
45
+ (div_datos/"div.segment").each do |div_datos_vuelta|
46
+ origen = (div_datos/"span.cities").first.inner_html.to_s.match("(.*)\<span class=\"separator\"\>\<\/span\>(.*)")[1].strip.no_accents
47
+ destino= (div_datos/"span.cities").last.inner_html.to_s.match("(.*)\<span class=\"separator\"\>\<\/span\>(.*)")[2].strip.no_accents
48
+ origen_iata = (div_datos/"li.outbound a")[0].inner_text.strip
49
+ destino_iata = (div_datos/"li.inbound a")[-1].inner_text.strip
50
+ fecha = (div_datos_vuelta/"li.outbound span.date")[0] ? (div_datos_vuelta/"li.outbound span.date")[0].inner_text.strip.no_accents : (div_datos_vuelta/"li.inbound span.date")[0].inner_text.strip.no_accents
51
+ escala = (div_datos/"span.stops a").inner_text.strip.empty? ? "Sin escalas" : (div_datos/"span.stops a").inner_text.to_i
52
+ aerolinea = Array.new
53
+ i = 0
54
+ (div_datos_vuelta/"span.airline-logo//img").each do |aer|
55
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
56
+ i = i + 1
57
+ end
58
+ hou_sal_ida = Time.parse((div_datos/"li.outbound").first.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)") ? (div_datos/"li.outbound").first.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)")[2].strip.no_accents : (div_datos/"li.outbound").last.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)")[2].strip.no_accents)
59
+ hou_lle_ida = Time.parse((div_datos/"li.outbound").last.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)") ? (div_datos/"li.outbound").last.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)")[2].strip.no_accents : (div_datos/"li.outbound").first.inner_html.to_s.match("(.*)\<\/span\>(.*)hs(.*)\<a(.*)")[2].strip.no_accents)
60
+ @vueltas << DataCluster.new(origen,destino,fecha, aerolinea, escala_to_i(escala),origen_iata,destino_iata,hou_sal_ida,hou_lle_ida)
61
+ end
62
+ @nro_vuelo_vuelta = 0
63
+ @vuelta = @vueltas[@nro_vuelo_vuelta]
64
+ end
65
+ def load_prices(p_html)
66
+ @tarifas = Hash.new
67
+ if (p_html/"span#secondary-currency").empty?
68
+ @tarifas['tarifa_adulto'] = Price.new((p_html/"li.adult-price span[@class='price-currency'] span.currency").first.inner_text.strip + " " + (p_html/"li.adult-price span[@class='price-currency'] span.amount").first.inner_text.strip)
69
+ else
70
+ @tarifas['tarifa_adulto'] = Price.new((p_html/"div.adult-price-conversion span#local-currency span.code").first.inner_text.strip + " " + (p_html/"div.adult-price-conversion span#local-currency span.amount").first.inner_text.strip)
71
+ end
72
+
73
+ adt = (p_html/"li.adult_fare").select{|li| li.inner_text.no_accents.downcase =~ /adulto|adult/}.first
74
+ @tarifas['adt'] = adt ? Price.new((adt/"span.currency").first.inner_text.strip + " " + (adt/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
75
+
76
+ cnn = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /nino|criancas|child/}.first
77
+ @tarifas['cnn'] = cnn ? Price.new((cnn/"span.currency").first.inner_text.strip + " " + (cnn/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
78
+
79
+ inf = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /bebe|infant/}.first
80
+ @tarifas['inf'] = inf ? Price.new((inf/"span.currency").first.inner_text.strip + " " + (inf/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
81
+
82
+ tasas = (p_html/"li.taxes").empty? ? (p_html/"li[@class='taxDetail.OTHER-price']").first : (p_html/"li.taxes").first
83
+ @tarifas['tasas'] = tasas ? Price.new((tasas/"span.currency").first.inner_text.strip + " " + (tasas/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
84
+
85
+ cargos = (p_html/"li.charges").first
86
+ @tarifas['cargos'] = cargos ? Price.new((cargos/"span.currency").first.inner_text.strip + " " + (cargos/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
87
+
88
+ afip = (p_html/"li.tax_afip").first
89
+ @tarifas['afip'] = afip ? Price.new((afip/"span.currency").first.inner_text.strip + " " + (afip/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
90
+
91
+ servicio = (p_html/"li.service_taxes").first
92
+ @tarifas['encargos'] = servicio ? Price.new((servicio/"span.currency").first.inner_text.strip + " " + (servicio/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
93
+
94
+ campo = "total"
95
+ @tarifas['total'] = (p_html/"li.#{campo} span.currency").empty? ? Price.new("$ 0",true) : Price.new((p_html/"li.#{campo} span.currency").first.inner_text.strip + " " + (p_html/"li.#{campo} span.amount").first.inner_text.strip)
96
+ end
97
+
98
+ def validarSumaDesgloce(linea = "total|tarifa_adulto|tarifa_adulto_dolar")
99
+
100
+ sumaTarifas = 0
101
+ @tarifas.each_pair do |key,tarifa|
102
+ if key !~ /#{linea}/
103
+ sumaTarifas += tarifa.valor
104
+ end
105
+ end
106
+
107
+ return sumaTarifas.to_i
108
+
109
+ end
110
+
111
+ end
@@ -0,0 +1,33 @@
1
+ class DataCluster
2
+ attr_accessor :origen, :destino, :fecha, :aerolinea, :escalas, :destino_iata, :origen_iata, :hou_sal_ida, :hou_lle_ida,:attributes, :duracion
3
+
4
+ def initialize (origen,destino,fecha, aerolinea, escalas, origen_iata=nil, destino_iata=nil,hou_sal_ida=nil,hou_lle_ida=nil,duracion=nil)
5
+
6
+ @duracion = duracion
7
+ @origen = origen
8
+ @destino = destino
9
+ @origen_iata = origen_iata
10
+ @destino_iata = destino_iata
11
+ @fecha = fecha.empty? ? nil : Date.parse_new_result(fecha)
12
+ @aerolinea = aerolinea
13
+ @escalas = escalas
14
+ @hou_sal_ida = hou_sal_ida
15
+ @hou_lle_ida = hou_lle_ida
16
+ @attributes = [:origen, :destino, :origen_iata, :destino_iata, :fecha, :aerolinea, :escalas, :hou_sal_ida, :hou_lle_ida, :duracion]
17
+ end
18
+
19
+ def to_s
20
+ return "Escalas: #{@escalas}, Duracion: #{@duracion}, Origen: #{@origen}, Destino: #{@destino}, Iata: #{@origen_iata}-#{@destino_iata}, Fecha: #{@fecha}, Aerolinea: #{@aerolinea}, Hr salida: #{@hou_sal_ida}, Hr llegada: #{@hou_lle_ida}"
21
+ end
22
+
23
+ #se usa en el dinamico para comparar
24
+ def ==(other)
25
+ eq = true
26
+ self.attributes.each do |attrb|
27
+ if other
28
+ eq = false if self.send(attrb) != other.send(attrb)
29
+ end
30
+ end
31
+ eq
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class DetailsCluster
3
+ attr_accessor :tramos, :duracion
4
+ def initialize(p_html)
5
+ @duracion = (p_html/"div.popup-container div.popup-content span.total-duration").inner_text.strip.no_accents
6
+ @tramos = []
7
+ (p_html/"div.popup-container div.popup-content div.detail").each do |div|
8
+ tramo = Hash.new
9
+ if (div/"div.segment span.not-economy-segments").first.nil?
10
+ tramo['bussines'] = nil
11
+ tramo['clase'] = (div/"div.segment span.class").first.inner_text.strip.no_accents
12
+ else
13
+ tramo['bussines'] = true #((div/"div.segment span.not-economy-segments span.not-economy-segments-description").first.inner_text.strip.no_accents == "Business")
14
+ tramo['clase'] = (div/"div.segment span.not-economy-segments span.not-economy-segments-description").first.inner_text.strip.no_accents
15
+ end
16
+ tramo['ciudad_origen'] = (div/"li.departure span.location span.data").first.inner_text.strip.no_accents
17
+ tramo['fecha_origen'] = Date.parse_new_details((div/"li.departure span.date span.day").first.inner_text.strip.no_accents)
18
+ tramo['hora_origen'] = Time.parse((div/"li.departure span.date span.hour").first.inner_text.strip.no_accents)
19
+ tramo['ciudad_destino'] = (div/"li.arrival span.location span.data").last.inner_text.strip.no_accents
20
+ tramo['hora_destino'] = Time.parse((div/"li.arrival span.date span.hour").last.inner_text.strip.no_accents)
21
+ @tramos << tramo
22
+ end
23
+ end
24
+
25
+ def to_s
26
+ text = String.new
27
+ @tramos.each_with_index do |tramo,i|
28
+ text << "[Tramo #{i}: "
29
+ tramo.each_pair do |key,value|
30
+ text << "#{key}:#{value} - "
31
+ end
32
+ text << "]"
33
+ end
34
+ return text
35
+ end
36
+ end
@@ -0,0 +1,87 @@
1
+ # -*- encoding : utf-8 -*-
2
+ class LandingCluster < ResultsCluster
3
+
4
+ def load_data_from(div_datos)
5
+ @idas = Array.new
6
+ (div_datos/"li.itinerary").each do |div_datos_ida|
7
+ duracion = (div_datos_ida/"li.time").inner_text.strip
8
+ origen = (div_datos/"span.city-departure").first.inner_text.gsub(/,/,'').strip.no_accents
9
+ destino= (div_datos/"span.city-arrival").first.inner_text.gsub(/,/,'').strip.no_accents
10
+ origen_iata = (div_datos/"a")[0].inner_text.strip
11
+ destino_iata = (div_datos/"a")[1].inner_text.strip
12
+ fecha = (div_datos_ida/"li.date").first.inner_text.strip.no_accents
13
+ escala = (div_datos_ida/"li.stops/a").inner_text.strip.empty? ? "Sin escalas" : (div_datos_ida/"li.stops/a").inner_text.to_i
14
+ aerolinea = Array.new
15
+ i = 0
16
+ (div_datos_ida/"li.airlinesShort//img").each do |aer|
17
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
18
+ i = i + 1
19
+ end
20
+ (div_datos_ida/"li.airlines//img").each do |aer|
21
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
22
+ i = i + 1
23
+ end
24
+ hou_sal_ida = Time.parse((div_datos_ida/"li.leave span.hour").inner_text.strip)
25
+ hou_lle_ida = Time.parse((div_datos_ida/"li.arrive span.hour").inner_text.strip)
26
+ @idas << DataCluster.new(origen,destino,fecha, aerolinea, escala_to_i(escala),origen_iata,destino_iata,hou_sal_ida,hou_lle_ida,duracion)
27
+ end
28
+ @nro_vuelo_ida = 0
29
+ @ida = @idas[@nro_vuelo_ida]
30
+
31
+ end
32
+ def load_data_to(div_datos)
33
+
34
+ @vueltas = Array.new
35
+ (div_datos/"li.itinerary").each do |div_datos_vuelta|
36
+ duracion = (div_datos_vuelta/"li.time").inner_text.strip
37
+ origen = (div_datos/"span.city-departure").first.inner_text.gsub(/,/,'').strip.no_accents
38
+ destino= (div_datos/"span.city-arrival").first.inner_text.gsub(/,/,'').strip.no_accents
39
+ origen_iata = (div_datos/"a")[0].inner_text.strip
40
+ destino_iata = (div_datos/"a")[1].inner_text.strip
41
+ fecha = (div_datos_vuelta/"li.date").last.inner_text.strip.no_accents
42
+ escala = (div_datos_vuelta/"li.stops/a").inner_text.strip.empty? ? "Sin escalas" : (div_datos_vuelta/"li.stops/a").inner_text.to_i
43
+ aerolinea = Array.new
44
+ i = 0
45
+ (div_datos_vuelta/"li.airlinesShort//img").each do |aer|
46
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
47
+ i = i + 1
48
+ end
49
+ (div_datos_vuelta/"li.airlines//img").each do |aer|
50
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
51
+ i = i + 1
52
+ end
53
+ hou_sal_ida = Time.parse((div_datos_vuelta/"li.leave span.hour").inner_text.strip)
54
+ hou_lle_ida = Time.parse((div_datos_vuelta/"li.arrive span.hour").inner_text.strip)
55
+ @vueltas << DataCluster.new(origen,destino,fecha, aerolinea, escala_to_i(escala),origen_iata,destino_iata,hou_sal_ida,hou_lle_ida,duracion)
56
+ end
57
+ @nro_vuelo_vuelta = 0
58
+ @vuelta = @vueltas[@nro_vuelo_vuelta]
59
+
60
+ end
61
+
62
+ def load_prices(p_html)
63
+
64
+ @tarifas = Hash.new
65
+ @tarifas['tarifa_adulto'] = Price.new((p_html/"span.price-currency span.currency").first.inner_text.strip + " " + (p_html/"span.price-currency span.amount").first.inner_text.strip)
66
+ @tarifas['tarifa_adulto_dolar'] = Price.new((p_html/"span.price-currency span.currency").last.inner_text.strip + " " + (p_html/"span.price-currency span.amount").last.inner_text.strip)
67
+ @tarifas['adt'] = (p_html/"ul.fare-detail//li").empty? ? Price.new("$ 0",true) : Price.new(((p_html/"ul.fare-detail//li").select{|li| li.inner_text.no_accents.downcase =~ /adulto/}.first/"span[@class='price-currency ARS']").inner_text.strip)
68
+
69
+ adt = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /adulto/}.first
70
+ @tarifas['adt'] = adt ? Price.new((adt/"span.currency").first.inner_text.strip + " " + (adt/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
71
+
72
+ tasas = (p_html/"li.taxes-price").empty? ? (p_html/"li[@class='taxDetail.OTHER-price']").first : (p_html/"li.taxes-price").first
73
+ @tarifas['tasas'] = tasas ? Price.new((tasas/"span.currency").first.inner_text.strip + " " + (tasas/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
74
+
75
+ cargos = (p_html/"li.charges-price").first
76
+ @tarifas['cargos'] = cargos ? Price.new((cargos/"span.currency").first.inner_text.strip + " " + (cargos/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
77
+
78
+ afip = (p_html/"li[@class='taxDetail.ZK-price']").first
79
+ @tarifas['afip'] = afip ? Price.new((afip/"span.currency").first.inner_text.strip + " " + (afip/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
80
+
81
+ @tarifas['encargos'] = Price.new("$ 0",true)
82
+
83
+ campo = (p_html/"li").empty? ? "total" : "fare"
84
+ @tarifas['total'] = (p_html/"li.#{campo}-price span.currency").empty? ? Price.new("$ 0",true) : Price.new((p_html/"li.#{campo}-price span.currency").first.inner_text.strip + " " + (p_html/"li.#{campo}-price span.amount").first.inner_text.strip)
85
+ end
86
+
87
+ end
@@ -0,0 +1,86 @@
1
+ class RenderCluster < ResultsCluster
2
+ def initialize(itinerario,html,page = 0)
3
+ self.load_prices((html/"div.fare-container"))
4
+ eval "#{itinerario.downcase}(html)"
5
+ end
6
+ def load_prices(p_html)
7
+
8
+ @tarifas = Hash.new
9
+
10
+ if !(p_html/"span.fare-difference-price").empty?
11
+ con_diferencia(p_html)
12
+ else
13
+ sin_diferencia(p_html)
14
+ end
15
+
16
+ end
17
+
18
+ def con_diferencia(p_html)
19
+ @tarifas = Hash.new
20
+ @tarifas['diferencia'] = @tarifas['tarifa_adulto'] = Price.new((p_html/"span.fare-difference-price span[@class='price-currency #{currency($SITE)} '] span.currency").first.inner_text.strip + " " + (p_html/"span.fare-difference-price span[@class='price-currency #{currency($SITE)} '] span.amount").first.inner_text.strip)
21
+ @tarifas['tarifa_adulto_dolar'] = Price.new((p_html/"span.price-currency span.currency").first.inner_text.strip + " " + (p_html/"span.price-currency span.amount").first.inner_text.strip)
22
+ if (p_html/"span[@class='price-currency #{currency($SITE)} '] span.currency").first
23
+ @tarifas['tarifa_adulto'] = Price.new((p_html/"span[@class='price-currency #{currency($SITE)} '] span.currency").first.inner_text.strip + " " + (p_html/"span[@class='price-currency #{currency($SITE)} '] span.amount").first.inner_text.strip)
24
+ else
25
+ @tarifas['tarifa_adulto'] = @tarifas['tarifa_adulto_dolar']
26
+ end
27
+
28
+ adt = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /adulto/}.first
29
+ @tarifas['adt'] = adt ? Price.new((adt/"span.currency").first.inner_text.strip + " " + (adt/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
30
+
31
+ cnn = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /nino/}.first
32
+ @tarifas['cnn'] = cnn ? Price.new((cnn/"span.currency").first.inner_text.strip + " " + (cnn/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
33
+
34
+ inf = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /bebe/}.first
35
+ @tarifas['inf'] = inf ? Price.new((inf/"span.currency").first.inner_text.strip + " " + (inf/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
36
+
37
+ tasas = (p_html/"li.taxes-price").empty? ? (p_html/"li[@class='taxDetail.OTHER-price']").first : (p_html/"li.taxes-price").first
38
+ @tarifas['tasas'] = tasas ? Price.new((tasas/"span.currency").first.inner_text.strip + " " + (tasas/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
39
+
40
+ cargos = (p_html/"li.charges-price").first
41
+ @tarifas['cargos'] = cargos ? Price.new((cargos/"span.currency").first.inner_text.strip + " " + (cargos/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
42
+
43
+ afip = (p_html/"li[@class='taxDetail.ZK-price']").first
44
+ @tarifas['afip'] = afip ? Price.new((afip/"span.currency").first.inner_text.strip + " " + (afip/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
45
+
46
+ @tarifas['encargos'] = Price.new("$ 0",true)
47
+
48
+ campo = (p_html/"li").empty? ? "total" : "fare"
49
+ @tarifas['total'] = (p_html/"li.#{campo}-price span.currency").empty? ? Price.new("$ 0",true) : Price.new((p_html/"li.#{campo}-price span.currency").first.inner_text.strip + " " + (p_html/"li.#{campo}-price span.amount").first.inner_text.strip)
50
+ end
51
+
52
+ def sin_diferencia(p_html)
53
+ @tarifas = Hash.new
54
+ @tarifas['diferencia'] = Price.new("$ 0",true)
55
+ @tarifas['tarifa_adulto_dolar'] = Price.new("$ 0",true)
56
+ if (p_html/"span[@class='price-currency #{currency($SITE)} '] span.currency").first
57
+ @tarifas['tarifa_adulto'] = Price.new((p_html/"span[@class='price-currency #{currency($SITE)} '] span.currency").first.inner_text.strip + " " + (p_html/"span[@class='price-currency #{currency($SITE)} '] span.amount").first.inner_text.strip)
58
+ else
59
+ @tarifas['tarifa_adulto'] = @tarifas['tarifa_adulto_dolar']
60
+ end
61
+
62
+ adt = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /adulto/}.first
63
+ @tarifas['adt'] = adt ? Price.new((adt/"span.currency").first.inner_text.strip + " " + (adt/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
64
+
65
+ cnn = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /nino/}.first
66
+ @tarifas['cnn'] = cnn ? Price.new((cnn/"span.currency").first.inner_text.strip + " " + (cnn/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
67
+
68
+ inf = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /bebe/}.first
69
+ @tarifas['inf'] = inf ? Price.new((inf/"span.currency").first.inner_text.strip + " " + (inf/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
70
+
71
+ tasas = (p_html/"li.taxes-price").empty? ? (p_html/"li[@class='taxDetail.OTHER-price']").first : (p_html/"li.taxes-price").first
72
+ @tarifas['tasas'] = tasas ? Price.new((tasas/"span.currency").first.inner_text.strip + " " + (tasas/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
73
+
74
+ cargos = (p_html/"li.charges-price").first
75
+ @tarifas['cargos'] = cargos ? Price.new((cargos/"span.currency").first.inner_text.strip + " " + (cargos/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
76
+
77
+ afip = (p_html/"li[@class='taxDetail.ZK-price']").first
78
+ @tarifas['afip'] = afip ? Price.new((afip/"span.currency").first.inner_text.strip + " " + (afip/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
79
+
80
+ @tarifas['encargos'] = Price.new("$ 0",true)
81
+
82
+ campo = (p_html/"li").empty? ? "total" : "fare"
83
+ @tarifas['total'] = (p_html/"li.#{campo}-price span.currency").empty? ? Price.new("$ 0",true) : Price.new((p_html/"li.#{campo}-price span.currency").first.inner_text.strip + " " + (p_html/"li.#{campo}-price span.amount").first.inner_text.strip)
84
+ end
85
+ end
86
+
@@ -0,0 +1,168 @@
1
+ require_relative 'data/data'
2
+ class ResultsCluster
3
+
4
+ attr_accessor :ida, :vuelta, :tarifas, :idas, :vueltas
5
+
6
+ def initialize(itinerario,html,page = 0)
7
+ eval "#{itinerario.downcase}(html)"
8
+ self.load_prices((html/"div.fare-container"))
9
+ end
10
+
11
+ def roundtrip(html)
12
+ self.load_data_from((html/"div.itineraries div[@class='sub-cluster outbound']"))
13
+ self.load_data_to((html/"div.itineraries div[@class='sub-cluster inbound']"))
14
+ end
15
+ def oneway(html)
16
+ self.load_data_from((html/"div.itineraries//div[@class='sub-cluster outbound']"))
17
+ @nro_vuelo_vuelta = -1
18
+ end
19
+ def multipledestinations(html)
20
+ self.load_data_from((html/"div.itineraries//div[@class='sub-cluster multiple']"))
21
+ self.load_data_to((html/"div.itineraries//div[@class='sub-cluster multiple']").last)
22
+ end
23
+ def load_data_from(div_datos)
24
+ @idas = Array.new
25
+ (div_datos/"li.itinerary").each do |div_datos_ida|
26
+ duracion = (div_datos_ida/"li.time").inner_text.strip
27
+ origen = (div_datos/"span.city-departure").first.inner_text.gsub(/,/,'').strip.no_accents
28
+ destino= (div_datos/"span.city-arrival").first.inner_text.gsub(/,/,'').strip.no_accents
29
+ origen_iata = (div_datos/"a")[0].inner_text.strip
30
+ destino_iata = (div_datos/"a")[1].inner_text.strip
31
+ fecha = (div_datos/"span.date").first.empty? ? (div_datos_ida/"li.date").first.inner_text.strip.no_accents : (div_datos/"span.date").first.inner_text.strip.no_accents
32
+ escala = (div_datos_ida/"li.stops/a").inner_text.strip.empty? ? "Sin escalas" : (div_datos_ida/"li.stops/a").inner_text.to_i
33
+ aerolinea = Array.new
34
+ i = 0
35
+ (div_datos_ida/"li.airlinesShort//img").each do |aer|
36
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
37
+ i = i + 1
38
+ end
39
+ (div_datos_ida/"li.airlines//img").each do |aer|
40
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
41
+ i = i + 1
42
+ end
43
+ hou_sal_ida = Time.parse((div_datos_ida/"li.leave span.hour").inner_text.strip)
44
+ hou_lle_ida = Time.parse((div_datos_ida/"li.arrive span.hour").inner_text.strip)
45
+ @idas << DataCluster.new(origen,destino,fecha, aerolinea, escala_to_i(escala),origen_iata,destino_iata,hou_sal_ida,hou_lle_ida,duracion)
46
+ end
47
+ @nro_vuelo_ida = 0
48
+ @ida = @idas[@nro_vuelo_ida]
49
+
50
+ end
51
+ def load_data_to(div_datos)
52
+
53
+ @vueltas = Array.new
54
+ (div_datos/"li.itinerary").each do |div_datos_vuelta|
55
+ duracion = (div_datos_vuelta/"li.time").inner_text.strip
56
+ origen = (div_datos/"span.city-departure").first.inner_text.gsub(/,/,'').strip.no_accents
57
+ destino= (div_datos/"span.city-arrival").first.inner_text.gsub(/,/,'').strip.no_accents
58
+ origen_iata = (div_datos/"a")[0].inner_text.strip
59
+ destino_iata = (div_datos/"a")[1].inner_text.strip
60
+ fecha = (div_datos/"span.date").last.empty? ? (div_datos_vuelta/"li.date").last.inner_text.strip.no_accents : (div_datos/"span.date").last.inner_text.strip.no_accents
61
+ escala = (div_datos_vuelta/"li.stops/a").inner_text.strip.empty? ? "Sin escalas" : (div_datos_vuelta/"li.stops/a").inner_text.to_i
62
+ aerolinea = Array.new
63
+ i = 0
64
+ (div_datos_vuelta/"li.airlinesShort//img").each do |aer|
65
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
66
+ i = i + 1
67
+ end
68
+ (div_datos_vuelta/"li.airlines//img").each do |aer|
69
+ aerolinea << aer.attributes['src'].match(/(..).png/)[1].upcase
70
+ i = i + 1
71
+ end
72
+ hou_sal_ida = Time.parse((div_datos_vuelta/"li.leave span.hour").inner_text.strip)
73
+ hou_lle_ida = Time.parse((div_datos_vuelta/"li.arrive span.hour").inner_text.strip)
74
+ @vueltas << DataCluster.new(origen,destino,fecha, aerolinea, escala_to_i(escala),origen_iata,destino_iata,hou_sal_ida,hou_lle_ida,duracion)
75
+ end
76
+ @nro_vuelo_vuelta = 0
77
+ @vuelta = @vueltas[@nro_vuelo_vuelta]
78
+
79
+ end
80
+
81
+ def load_prices(p_html)
82
+
83
+ @tarifas = Hash.new
84
+ @tarifas['tarifa_adulto_dolar'] = Price.new((p_html/"span.price-currency span.currency").first.inner_text.strip + " " + (p_html/"span.price-currency span.amount").first.inner_text.strip)
85
+ if (p_html/"span[@class='price-currency #{currency($SITE)} '] span.currency").first
86
+ @tarifas['tarifa_adulto'] = Price.new((p_html/"span[@class='price-currency #{currency($SITE)} '] span.currency").first.inner_text.strip + " " + (p_html/"span[@class='price-currency #{currency($SITE)} '] span.amount").first.inner_text.strip)
87
+ else
88
+ @tarifas['tarifa_adulto'] = @tarifas['tarifa_adulto_dolar']
89
+ end
90
+
91
+ adt = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /adulto/}.first
92
+ @tarifas['adt'] = adt ? Price.new((adt/"span.currency").first.inner_text.strip + " " + (adt/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
93
+
94
+ cnn = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /nino/}.first
95
+ @tarifas['cnn'] = cnn ? Price.new((cnn/"span.currency").first.inner_text.strip + " " + (cnn/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
96
+
97
+ inf = (p_html/"li").select{|li| li.inner_text.no_accents.downcase =~ /bebe/}.first
98
+ @tarifas['inf'] = inf ? Price.new((inf/"span.currency").first.inner_text.strip + " " + (inf/"span.amount").first.inner_text.strip) : Price.new("$ 0",true)
99
+
100
+ tasas = (p_html/"li.taxes-price").empty? ? (p_html/"li[@class='taxDetail.OTHER-price']").first : (p_html/"li.taxes-price").first
101
+ @tarifas['tasas'] = tasas ? Price.new((tasas/"span.currency").first.inner_text.strip + " " + (tasas/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
102
+
103
+ cargos = (p_html/"li.charges-price").first
104
+ @tarifas['cargos'] = cargos ? Price.new((cargos/"span.currency").first.inner_text.strip + " " + (cargos/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
105
+
106
+ afip = (p_html/"li[@class='taxDetail.ZK-price']").first
107
+ @tarifas['afip'] = afip ? Price.new((afip/"span.currency").first.inner_text.strip + " " + (afip/"span.amount").first.inner_text.strip,true) : Price.new("$ 0",true)
108
+
109
+ @tarifas['encargos'] = Price.new("$ 0",true)
110
+
111
+ campo = (p_html/"li").empty? ? "total" : "fare"
112
+ @tarifas['total'] = (p_html/"li.#{campo}-price span.currency").empty? ? Price.new("$ 0",true) : Price.new((p_html/"li.#{campo}-price span.currency").first.inner_text.strip + " " + (p_html/"li.#{campo}-price span.amount").first.inner_text.strip)
113
+ end
114
+
115
+ def validarSumaDesgloce(linea = "total|tarifa_adulto")
116
+
117
+ sumaTarifas = 0
118
+ @tarifas.each_pair do |key,tarifa|
119
+ if key !~ /#{linea}/
120
+ sumaTarifas += tarifa.valor
121
+ end
122
+ if @tarifas['total'] and (tarifa.valor > @tarifas['total'].valor) and (linea !~ /tarifa_adulto/)
123
+ true.should be_true
124
+ end
125
+ end
126
+
127
+ if @tarifas['total'] and ((sumaTarifas.to_i - @tarifas['total'].valor.to_i) > 3)
128
+ true.should be_true
129
+ end
130
+
131
+ end
132
+ def validarEcuacionTarifasPorCantidadDePasajeros(cant)
133
+ unless @tarifas['adt'].valor.zero?
134
+ (@tarifas['adt'].valor == @tarifas['tarifa_adulto'].valor * cant).should be_true
135
+ end
136
+ end
137
+ def validarResolucionAFIP
138
+ (@tarifas['total'] * 20 / 100).truncate + 1 == @tarifas['afip']
139
+ end
140
+ def total_escalas()
141
+ vueltas = @vueltas ? @vueltas.collect{|vuelta| vuelta.escalas} : []
142
+ (vueltas + @idas.collect{|vuelta| vuelta.escalas}).sort
143
+ end
144
+
145
+ def duracion
146
+ menor_ida = menor_duracion(@idas.collect{|ida| ida.duracion})
147
+ menor_vuelta = @vueltas ? menor_duracion(@vueltas.collect{|ida| ida.duracion}) : 0
148
+
149
+ return menor_vuelta + menor_ida
150
+ end
151
+
152
+ def menor_duracion(rutas)
153
+ totales = []
154
+ rutas.each do |custom|
155
+ if custom.match("^(.*)h (.*)m$")
156
+ total = custom.match("^(.*)h (.*)m$")[1].to_i * 60
157
+ total += custom.match("^(.*)h (.*)m$")[2].to_i
158
+ elsif custom.match("^(.*)h$")
159
+ total = custom.match("^(.*)h$")[1].to_i * 60
160
+ else
161
+ total = custom.match("^(.*)m$")[1].to_i
162
+ end
163
+ totales << total
164
+ end
165
+ return totales.sort.first
166
+ end
167
+
168
+ end