diff options
| -rw-r--r-- | app/controllers/concerns/ransack_date_filter.rb | 25 | ||||
| -rw-r--r-- | app/controllers/referential_vehicle_journeys_controller.rb | 6 | ||||
| -rw-r--r-- | app/models/chouette/time_table.rb | 1 | ||||
| -rw-r--r-- | app/models/chouette/vehicle_journey.rb | 14 | ||||
| -rw-r--r-- | app/views/referential_vehicle_journeys/_filters.html.slim | 10 | ||||
| -rw-r--r-- | config/locales/vehicle_journeys.en.yml | 1 | ||||
| -rw-r--r-- | config/locales/vehicle_journeys.fr.yml | 1 | ||||
| -rw-r--r-- | spec/factories/chouette_time_table.rb | 17 | ||||
| -rw-r--r-- | spec/models/chouette/vehicle_journey_spec.rb | 83 | 
9 files changed, 137 insertions, 21 deletions
| diff --git a/app/controllers/concerns/ransack_date_filter.rb b/app/controllers/concerns/ransack_date_filter.rb index 99889294c..055c01130 100644 --- a/app/controllers/concerns/ransack_date_filter.rb +++ b/app/controllers/concerns/ransack_date_filter.rb @@ -3,7 +3,15 @@ module RansackDateFilter    included do -    def set_date_time_params(param_name, klass) +    def begin_range_var prefix +      "@#{[prefix, "begin_range"].compact.join('_')}" +    end + +    def end_range_var prefix +      "@#{[prefix, "end_range"].compact.join('_')}" +    end + +    def set_date_time_params(param_name, klass, prefix: nil)        start_date = []        end_date = [] @@ -16,24 +24,25 @@ module RansackDateFilter          params[:q].delete([param_name])          if klass == DateTime -          @begin_range = klass.new(*start_date,0,0,0) rescue nil -          @end_range = klass.new(*end_date,23,59,59) rescue nil +          instance_variable_set begin_range_var(prefix), klass.new(*start_date,0,0,0) rescue nil +          instance_variable_set end_range_var(prefix), klass.new(*end_date,23,59,59) rescue nil          else -          @begin_range = klass.new(*start_date) rescue nil -          @end_range = klass.new(*end_date) rescue nil +          instance_variable_set begin_range_var(prefix), klass.new(*start_date) rescue nil +          instance_variable_set end_range_var(prefix), klass.new(*end_date) rescue nil          end        end      end      # Fake ransack filter      def ransack_period_range **options -      return options[:scope] unless !!@begin_range && !!@end_range +      prefix = options[:prefix] +      return options[:scope] unless !!instance_variable_get(begin_range_var(prefix)) && !!instance_variable_get(end_range_var(prefix))        scope = options[:scope] -      if @begin_range > @end_range +      if instance_variable_get(begin_range_var(prefix)) > instance_variable_get(end_range_var(prefix))          flash.now[:error] = options[:error_message]        else -        scope = scope.send options[:query], @begin_range..@end_range +        scope = scope.send options[:query], instance_variable_get(begin_range_var(prefix))..instance_variable_get(end_range_var(prefix))        end        scope      end diff --git a/app/controllers/referential_vehicle_journeys_controller.rb b/app/controllers/referential_vehicle_journeys_controller.rb index 385405b84..a199157dd 100644 --- a/app/controllers/referential_vehicle_journeys_controller.rb +++ b/app/controllers/referential_vehicle_journeys_controller.rb @@ -5,7 +5,8 @@ class ReferentialVehicleJourneysController < ChouetteController    include ReferentialSupport    include RansackDateFilter -  before_action only: [:index] { set_date_time_params("purchase_window", Date) } +  before_action only: [:index] { set_date_time_params("purchase_window", Date, prefix: :purchase_window) } +  before_action only: [:index] { set_date_time_params("time_table", Date, prefix: :time_table) }    defaults :resource_class => Chouette::VehicleJourney, collection_name: :vehicle_journeys @@ -16,7 +17,8 @@ class ReferentialVehicleJourneysController < ChouetteController    def collection      @q ||= end_of_association_chain      @q = @q.with_stop_area_ids(params[:q][:stop_area_ids]) if params[:q] && params[:q][:stop_area_ids] -    @q = ransack_period_range(scope: @q, error_message:  t('vehicle_journeys.errors.purchase_window'), query: :in_purchase_window) +    @q = ransack_period_range(scope: @q, error_message:  t('vehicle_journeys.errors.purchase_window'), query: :in_purchase_window, prefix: :purchase_window) +    @q = ransack_period_range(scope: @q, error_message:  t('vehicle_journeys.errors.time_table'), query: :with_matching_timetable, prefix: :time_table)      @q = @q.ransack(params[:q])      @vehicle_journeys ||= @q.result.order(:published_journey_name).includes(:vehicle_journey_at_stops).paginate page: params[:page], per_page: params[:per_page] || 10      @all_companies = Chouette::Company.where("id IN (#{@referential.vehicle_journeys.select(:company_id).to_sql})").distinct diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb index db97dd2fa..07bf35444 100644 --- a/app/models/chouette/time_table.rb +++ b/app/models/chouette/time_table.rb @@ -311,7 +311,6 @@ module Chouette          bounding_max = periods_max_date if periods_max_date &&              (bounding_max.nil? || (bounding_max < periods_max_date))        end -        [bounding_min, bounding_max].compact      end diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb index a252d4519..1756a7098 100644 --- a/app/models/chouette/vehicle_journey.rb +++ b/app/models/chouette/vehicle_journey.rb @@ -62,6 +62,20 @@ module Chouette      ransacker :stop_area_ids      ransacker :purchase_window_date_gt +    # returns VehicleJourneys with at least 1 day in their time_tables +    # included in the given range +    def self.with_matching_timetable date_range +      out = [] +      time_tables = Chouette::TimeTable.where(id: self.joins("INNER JOIN time_tables_vehicle_journeys ON vehicle_journeys.id = time_tables_vehicle_journeys.vehicle_journey_id").pluck('time_tables_vehicle_journeys.time_table_id')).overlapping(date_range) +      time_tables = time_tables.select do |time_table| +        range = date_range +        range = date_range & (time_table.start_date-1.day..time_table.end_date+1.day) || [] if time_table.start_date.present? && time_table.end_date.present? +        range.any?{|d| time_table.include_day?(d) } +      end +      out += time_tables.map{|t| t.vehicle_journey_ids}.flatten +      where(id: out) +    end +      # TODO: Remove this validator      # We've eliminated this validation because it prevented vehicle journeys      # from being saved with at-stops having a day offset greater than 0, diff --git a/app/views/referential_vehicle_journeys/_filters.html.slim b/app/views/referential_vehicle_journeys/_filters.html.slim index af8b2de3a..bfb5b77dd 100644 --- a/app/views/referential_vehicle_journeys/_filters.html.slim +++ b/app/views/referential_vehicle_journeys/_filters.html.slim @@ -28,8 +28,14 @@        = f.label Chouette::VehicleJourney.human_attribute_name(:purchase_window), class: 'control-label'        .filter_menu          = f.simple_fields_for :purchase_window do |p| -          = p.input :start_date, as: :date, label: t('simple_form.from'), wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @begin_range, include_blank: @begin_range ? false : true -          = p.input :end_date, as: :date, label: t('simple_form.to'), wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @end_range, include_blank: @end_range ? false : true +          = p.input :start_date, as: :date, label: t('simple_form.from'), wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @purchase_window_begin_range, include_blank: @purchase_window_begin_range ? false : true +          = p.input :end_date, as: :date, label: t('simple_form.to'), wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @purchase_window_end_range, include_blank: @purchase_window_end_range ? false : true +    .form-group.togglable +      = f.label Chouette::TimeTable.model_name.human, class: 'control-label' +      .filter_menu +        = f.simple_fields_for :time_table do |p| +          = p.input :start_date, as: :date, label: t('simple_form.from'), wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @time_table_begin_range, include_blank: @time_table_begin_range ? false : true +          = p.input :end_date, as: :date, label: t('simple_form.to'), wrapper_html: { class: 'date smart_date filter_menu-item' }, default: @time_table_end_range, include_blank: @time_table_end_range ? false : true    .actions diff --git a/config/locales/vehicle_journeys.en.yml b/config/locales/vehicle_journeys.en.yml index 08a9334cc..abb1da530 100644 --- a/config/locales/vehicle_journeys.en.yml +++ b/config/locales/vehicle_journeys.en.yml @@ -69,6 +69,7 @@ en:        timeless: "Timeless vehicle journeys"      errors:        purchase_window: Invalid purchase window +      time_table: Invalid dates    activerecord:      models:        vehicle_journey: diff --git a/config/locales/vehicle_journeys.fr.yml b/config/locales/vehicle_journeys.fr.yml index 8d85d877a..ca8475812 100644 --- a/config/locales/vehicle_journeys.fr.yml +++ b/config/locales/vehicle_journeys.fr.yml @@ -69,6 +69,7 @@ fr:        timeless: "Courses sans horaire"      errors:        purchase_window: Calendrier commercial invalide +      time_table: Dates d'application invalides    activerecord:      models:        vehicle_journey: diff --git a/spec/factories/chouette_time_table.rb b/spec/factories/chouette_time_table.rb index 81a08ca2a..af48e1b42 100644 --- a/spec/factories/chouette_time_table.rb +++ b/spec/factories/chouette_time_table.rb @@ -11,18 +11,21 @@ FactoryGirl.define do      end      after(:create) do |time_table, evaluator| - -      0.upto(4) do |i| -        time_table.dates  << create(:time_table_date, :time_table => time_table, :date => i.days.since.to_date, :in_out => true) +      unless time_table.dates.any? +        evaluator.dates_count.times do |i| +          time_table.dates  << create(:time_table_date, :time_table => time_table, :date => i.days.since.to_date, :in_out => true) +        end        end        start_date = Date.today        end_date = start_date + 10 -      0.upto(4) do |i| -        time_table.periods << create(:time_table_period, :time_table => time_table, :period_start => start_date, :period_end => end_date) -        start_date = start_date + 20 -        end_date = start_date + 10 +      unless time_table.periods.any? +        evaluator.periods_count.times do |i| +          time_table.periods << create(:time_table_period, :time_table => time_table, :period_start => start_date, :period_end => end_date) +          start_date = start_date + 20 +          end_date = start_date + 10 +        end        end        time_table.save_shortcuts        time_table.update_checksum! diff --git a/spec/models/chouette/vehicle_journey_spec.rb b/spec/models/chouette/vehicle_journey_spec.rb index 06f392d65..70661bcc5 100644 --- a/spec/models/chouette/vehicle_journey_spec.rb +++ b/spec/models/chouette/vehicle_journey_spec.rb @@ -60,11 +60,92 @@ describe Chouette::VehicleJourney, :type => :model do        expect(subject).to include included_purchase_window      end -    it "should include VJ with overlapping_purchase_window purchase window" do +    it "should include VJ with overlapping purchase_window purchase window" do        expect(subject).to include overlapping_purchase_window      end    end +  describe '#in_time_table' do +    let(:start_date){2.month.ago.to_date} +    let(:end_date){1.month.ago.to_date} + +    subject{Chouette::VehicleJourney.with_matching_timetable start_date..end_date} + +    context "without time table" do +      let!(:vehicle_journey){ create :vehicle_journey } +      it "should not include VJ " do +        expect(subject).to_not include vehicle_journey +      end +    end + +    context "without a time table matching on a regular day" do +      let(:timetable){ +        period = create :time_table_period, period_start: start_date-2.day, period_end: start_date +        create :time_table, periods: [period], dates_count: 0 +      } +      let!(:vehicle_journey){ create :vehicle_journey, time_tables: [timetable] } +      it "should include VJ " do +        expect(subject).to include vehicle_journey +      end +    end + +    context "without a time table matching on a regular day" do +      let(:timetable){ +        period = create :time_table_period, period_start: end_date, period_end: end_date+1.day +        create :time_table, periods: [period], dates_count: 0 +      } +      let!(:vehicle_journey){ create :vehicle_journey, time_tables: [timetable] } +      it "should include VJ " do +        expect(subject).to include vehicle_journey +      end +    end + +    context "with a time table with a matching period but not the right day" do +      let(:start_date){end_date - 1.day} +      let(:end_date){Time.now.end_of_week.to_date} + +      let(:timetable){ +        period = create :time_table_period, period_start: start_date-1.month, period_end: end_date+1.month +        create :time_table, periods: [period], int_day_types: 4 + 8, dates_count: 0 +      } +      let!(:vehicle_journey){ create :vehicle_journey, time_tables: [timetable] } +      it "should not include VJ " do +        expect(subject).to_not include vehicle_journey +      end +    end + +    context "with a time table with a matching period but day opted-out" do +      let(:start_date){end_date - 1.day} +      let(:end_date){Time.now.end_of_week.to_date} + +      let(:timetable){ +        period = create :time_table_period, period_start: start_date-1.month, period_end: start_date-1.day +        date = create(:time_table_date, :date => start_date, in_out: false) +        create :time_table, periods: [period], dates: [date] +      } +      let!(:vehicle_journey){ create :vehicle_journey, time_tables: [timetable] } +      it "should not include VJ " do +        expect(subject).to_not include vehicle_journey +      end +    end + +    context "with a time table with no matching period but not the right extra day" do +      let(:start_date){end_date - 1.day} +      let(:end_date){Time.now.end_of_week.to_date} + +      let(:timetable){ +        period = create :time_table_period, period_start: start_date-1.month, period_end: start_date-1.day +        date = create(:time_table_date, :date => start_date, in_out: true) +        create :time_table, periods: [period], dates: [date] +      } +      let!(:vehicle_journey){ create :vehicle_journey, time_tables: [timetable] } +      it "should include VJ " do +        expect(subject).to include vehicle_journey +      end +    end + +  end +    describe "vjas_departure_time_must_be_before_next_stop_arrival_time",        skip: "Validation currently commented out because it interferes with day offsets" do | 
