Skip to content

Instantly share code, notes, and snippets.

@IlyaDonskikh
Last active August 29, 2015 14:15
Show Gist options
  • Save IlyaDonskikh/e68240899be1c23d5f4f to your computer and use it in GitHub Desktop.
Save IlyaDonskikh/e68240899be1c23d5f4f to your computer and use it in GitHub Desktop.
Flight search
class FlightSearch
include ActiveModel::Validations
include ActiveModel::Conversion
extend ActiveModel::Naming
attr_accessor :departure, :arrival, :date, :quotas, :return_quotas, :business_class, :with_return, :return_date,
:errors, :all_flights, :all_rt_flights, :adults, :childrens, :infants
## Validates
validates :departure, :arrival, :date, presence: true
validates_format_of :date, with: /\A[0-9]{2}\.[0-9]{2}\.[0-9]{4}\z/, message: :format
validate :date_range
## Etc.
def initialize(opts = {})
@errors = ActiveModel::Errors.new(self)
self.date = (Time.now + 3.days).strftime('%d.%m.%Y')
self.adults = 1
self.childrens = 0
self.infants = 0
self.business_class = false
opts.each do |name, value|
send("#{name}=", value)
end
end
def adults; @adults.to_i end
def childrens; @childrens.to_i end
def infants; @infants.to_i end
def point_downcase(type)
self.send(type.to_sym).to_s.mb_chars.downcase.to_s
end
def departure_downcase
departure.to_s.mb_chars.downcase.to_s
end
def passenger_stats
{ adult: adults, children: childrens, infant: infants, count: adults + childrens + infants }
end
def get_flight_point(name)
result = GeoSearch.new(text: name).result
result.first
end
def short_url
code = ''
[:departure, :arrival].each_with_index do |type_code, i|
item = get_flight_point(self.send(type_code))
code += item[:code]
code += case i
when 0 then date.strftime('%d%m')
else return_date.blank? ? '' : return_date.strftime('%d%m')
end
end
code += 'b' if bussines_class_formatted == true
code += '_' + self.adults.to_s
code += self.childrens.to_s if childrens > 0
code += self.infants.to_s if infants > 0
code
end
def results
discount_rt_objects = quotas.to_a
.select { |q| !q.pair_quotas.blank? }
.collect { |q| q.pair_quotas }
.flatten.to_a
found_quotas = find_quotas()
format_quotas = format_quotas(found_quotas)
flights_by_format_quotas(format_quotas, discount_rt_objects)
end
private
def bussines_class_formatted
[1, '1', true, 'true'].include?(self.business_class) ? true : false
end
def find_quotas()
departure_name = point_downcase('departure')
arrival_name = point_downcase('arrival')
business_class = bussines_class_formatted
found_quotas = {}
%w[ow return].each do |type|
prefix = type == 'ow' ? '' : 'return_'
flight_date = self.send(prefix + 'date')
quotas_type = (prefix + 'quotas').to_sym
departure_point = type == 'ow' ? departure_name : arrival_name
arrival_point = type == 'ow' ? arrival_name : departure_name
if self.send(quotas_type)
found_quotas[type.to_sym] = self.send(quotas_type).select { |qt| qt.business == business_class &&
qt.date == flight_date && qt.points('arrival').include?(arrival_point) &&
qt.points('departure').include?(departure_point) &&
qt.seats_available > 0 && qt.flight.status == nil }
end
end
found_quotas
end
def format_quotas(found_quotas)
data = []
found_quotas[:ow].sort_by { |data| data[:price] }.each do |qt|
code = { flight: qt.flight, return_flight: nil,
date: qt.date, tag: qt.flight.number,
start_time: qt.start_time, end_time: qt.end_time,
cabin: qt.business ? 'Business' : 'Economy' }
if found_quotas[:return].blank? && return_date.blank?
data << { code: code, quota: qt, return_quota: nil }
elsif !found_quotas[:return].blank?
found_quotas[:return].sort_by { |data| data[:price] }.each do |return_qt|
rt_code = code.merge({
return_cabin: (return_qt.business ? 'Business' : 'Economy'),
return_flight: return_qt.flight,
return_start_time: return_qt.start_time,
return_date: return_qt.date,
return_end_time: return_qt.end_time,
tag: qt.flight.number + '_' + return_qt.flight.number })
data << { code: rt_code, quota: qt, return_quota: return_qt }
end
end
end
data.group_by { |data| data[:code] }
end
def flights_by_format_quotas(format_quotas, discount_rt_objects)
flights_sort = []
format_quotas.each do |flight_sort|
flight_sort[0].merge!({ quotas: flight_sort[1].map { |fs| fs[:quota] }.uniq })
flight_sort[0].merge!({ return_quotas: flight_sort[1].map { |fs| fs[:return_quota] }.uniq })
passengers = passenger_stats
quotas = flight_sort[0][:quotas].compact
return_quotas = flight_sort[0][:return_quotas].compact
seats_available = [quotas.map { |qt| qt.seats_available }.inject{ |sum,x| sum + x }]
seats_available << return_quotas.map { |qt| qt.seats_available }.inject{|sum,x| sum + x } unless return_quotas.blank?
seats_available = seats_available.min
used_quotas = []
passengers = Passenger.generate_list(passenger_stats, date)
passengers = Passenger.calc_list(
passengers, quotas, return_quotas,
discount_rt_objects, flight_sort[0][:flight], flight_sort[0][:return_flight])
price = passengers.map(&:price).inject{|sum,x| sum.to_i + x.to_i }
flight_sort[0].merge!( { price: price } )
flight_sort[0].merge!( { passengers: passengers } )
flights_sort << flight_sort if flight_sort[0][:price].to_i > 0
end
flights_sort.sort_by { |flight_sort| flight_sort[0][:price] }
end
def date_range
self.date = date.to_date unless date.blank?
self.return_date = return_date.to_date unless with_return != '1' && return_date.blank?
errors.add(:date, :date_rang) if date.blank? || date < DateTime.now.to_date
errors.add(:return_date, :date_range) if with_return == '1' && (return_date.blank? || return_date < date)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment