diff options
| author | Robert | 2017-06-29 17:24:29 +0200 |
|---|---|---|
| committer | Robert | 2017-06-29 17:24:29 +0200 |
| commit | 40c642d8fa6f32298d8995f70c82d9808810fadd (patch) | |
| tree | 030af6f49b791c101435087f55f7ab0d65f0cae8 | |
| parent | b45ed915dc41b5d0e286bfc2517fb776eec4dc80 (diff) | |
| parent | e32e370ece3fa78efc8cce97e3ea827b01bfe7d1 (diff) | |
| download | chouette-core-40c642d8fa6f32298d8995f70c82d9808810fadd.tar.bz2 | |
Merge branch 'master' of github.com:af83/stif-boiv
13 files changed, 236 insertions, 175 deletions
diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js index 43c40a4d5..18ed5f889 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/components/JourneyPattern.js @@ -43,75 +43,79 @@ class JourneyPattern extends Component{ ) } + getErrors(errors) { + let err = Object.keys(errors).map((key, index) => { + return ( + <li key={index} style={{listStyleType: 'disc'}}> + <strong>{key}</strong> { errors[key] } + </li> + ) + }) + + return ( + <ul className="alert alert-danger">{err}</ul> + ) + } + render() { this.previousCity = undefined return ( - <div className={'t2e-item' + (this.props.value.deletable ? ' disabled' : '') + (this.props.value.object_id ? '' : ' to_record')}> + <div className={'t2e-item' + (this.props.value.deletable ? ' disabled' : '') + (this.props.value.object_id ? '' : ' to_record') + (this.props.value.errors ? ' has-error': '')}> {/* Errors */} - {(this.props.value.errors) && ( - <ul className='alert alert-danger small' style={{paddingLeft: 30}}> - {Object.keys(this.props.value.errors).map(function(key, i) { - return ( - <li key={i} style={{listStyleType: 'disc'}}> - <strong>'{key}'</strong> {this.props.value.errors[key]} - </li> - ) - })} - </ul> - )} + {/* this.props.value.errors ? this.getErrors(this.props.value.errors) : '' */} - <div className='th'> - <div className='strong mb-xs'>{this.props.value.object_id ? actions.humanOID(this.props.value.object_id) : '-'}</div> - <div>{this.props.value.registration_number}</div> - <div>{actions.getChecked(this.props.value.stop_points).length} arrêt(s)</div> + <div className='th'> + <div className='strong mb-xs'>{this.props.value.object_id ? actions.humanOID(this.props.value.object_id) : '-'}</div> + <div>{this.props.value.registration_number}</div> + <div>{actions.getChecked(this.props.value.stop_points).length} arrêt(s)</div> - <div className={this.props.value.deletable ? 'btn-group disabled' : 'btn-group'}> - <div - className={this.props.value.deletable ? 'btn dropdown-toggle disabled' : 'btn dropdown-toggle'} - data-toggle='dropdown' - > - <span className='fa fa-cog'></span> - </div> - <ul className='dropdown-menu'> - <li className={(this.props.value.deletable || this.props.status.policy['journey_patterns.edit'] == false) ? 'disabled' : ''}> - <button - type='button' - onClick={this.props.onOpenEditModal} - data-toggle='modal' - data-target='#JourneyPatternModal' - > - Editer + <div className={this.props.value.deletable ? 'btn-group disabled' : 'btn-group'}> + <div + className={this.props.value.deletable ? 'btn dropdown-toggle disabled' : 'btn dropdown-toggle'} + data-toggle='dropdown' + > + <span className='fa fa-cog'></span> + </div> + <ul className='dropdown-menu'> + <li className={(this.props.value.deletable || this.props.status.policy['journey_patterns.edit'] == false) ? 'disabled' : ''}> + <button + type='button' + onClick={this.props.onOpenEditModal} + data-toggle='modal' + data-target='#JourneyPatternModal' + > + Editer + </button> + </li> + <li className={this.props.value.object_id ? '' : 'disabled'}> + {this.vehicleJourneyURL(this.props.value.object_id)} + </li> + <li className={'delete-action' + ((this.props.status.policy['journey_patterns.edit'] == false)? ' disabled' : '')}> + <button + type='button' + disabled={(this.props.status.policy['journey_patterns.edit'] == false)? 'disabled' : ''} + onClick={(e) => { + e.preventDefault() + this.props.onDeleteJourneyPattern(this.props.index)} + } + > + <span className='fa fa-trash'></span>Supprimer </button> </li> - <li className={this.props.value.object_id ? '' : 'disabled'}> - {this.vehicleJourneyURL(this.props.value.object_id)} - </li> - <li className={'delete-action' + ((this.props.status.policy['journey_patterns.edit'] == false)? ' disabled' : '')}> - <button - type='button' - disabled={(this.props.status.policy['journey_patterns.edit'] == false)? 'disabled' : ''} - onClick={(e) => { - e.preventDefault() - this.props.onDeleteJourneyPattern(this.props.index)} - } - > - <span className='fa fa-trash'></span>Supprimer - </button> - </li> - </ul> - </div> + </ul> </div> - - {this.props.value.stop_points.map((stopPoint, i) =>{ - return ( - <div key={i} className='td'> - {this.cityNameChecker(stopPoint)} - </div> - ) - })} </div> - ) + + {this.props.value.stop_points.map((stopPoint, i) =>{ + return ( + <div key={i} className='td'> + {this.cityNameChecker(stopPoint)} + </div> + ) + })} + </div> + ) } } diff --git a/app/assets/javascripts/es6_browserified/journey_patterns/reducers/status.js b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/status.js index 6241777da..d7ef12d0b 100644 --- a/app/assets/javascripts/es6_browserified/journey_patterns/reducers/status.js +++ b/app/assets/javascripts/es6_browserified/journey_patterns/reducers/status.js @@ -9,6 +9,8 @@ const status = (state = {}, action) => { return _.assign({}, state, {isFetching: true}) case 'RECEIVE_JOURNEY_PATTERNS': return _.assign({}, state, {fetchSuccess: true, isFetching: false}) + case 'RECEIVE_ERRORS': + return _.assign({}, state, {isFetching: false}) default: return state } diff --git a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js index a8a92c522..a54131984 100644 --- a/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js +++ b/app/assets/javascripts/es6_browserified/time_tables/components/PeriodForm.js @@ -61,7 +61,7 @@ const PeriodForm = ({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriod <div className="nested-fields"> <div className="wrapper"> <div> - <div className={'form-group date smart_date' + (modal.modalProps.error ? ' has-error' : '')}> + <div className={'form-group date ' + (modal.modalProps.error ? ' has-error' : '')}> <div className="form-inline"> <select value={formatNumber(modal.modalProps.begin.day)} onChange={(e) => onUpdatePeriodForm(e, 'begin', 'day')} id="q_validity_period_begin_gteq_3i" className="date required form-control"> {makeDaysOptions(modal.modalProps.begin.day)} @@ -76,7 +76,7 @@ const PeriodForm = ({modal, timetable, metas, onOpenAddPeriodForm, onClosePeriod </div> </div> <div> - <div className={'form-group date smart_date' + (modal.modalProps.error ? ' has-error' : '')}> + <div className={'form-group date ' + (modal.modalProps.error ? ' has-error' : '')}> <div className="form-inline"> <select value={formatNumber(modal.modalProps.end.day)} onChange={(e) => onUpdatePeriodForm(e, 'end', 'day')} id="q_validity_period_end_gteq_3i" className="date required form-control"> {makeDaysOptions(modal.modalProps.end.day)} diff --git a/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js b/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js index e90d2d307..c30f460d8 100644 --- a/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js +++ b/app/assets/javascripts/es6_browserified/vehicle_journeys/actions/index.js @@ -449,12 +449,18 @@ const actions = { if (parseInt(schedule.departure_time.minute) < 0){ hours = Math.floor(parseInt(schedule.departure_time.minute) / 60) minutes = (parseInt(schedule.departure_time.minute) % 60) + 60 + if(minutes == 60){ + minutes = 0 + } schedule.departure_time.minute = actions.simplePad(minutes, 'minute') schedule.departure_time.hour = parseInt(schedule.departure_time.hour) + hours } if (parseInt(schedule.arrival_time.minute) < 0){ hours = Math.floor(parseInt(schedule.arrival_time.minute) / 60) minutes = (parseInt(schedule.arrival_time.minute) % 60) + 60 + if(minutes == 60){ + minutes = 0 + } schedule.arrival_time.minute = actions.simplePad(minutes, 'minute') schedule.arrival_time.hour = parseInt(schedule.arrival_time.hour) + hours } diff --git a/app/assets/stylesheets/components/_tables.sass b/app/assets/stylesheets/components/_tables.sass index 20679a3ba..b991e7b8d 100644 --- a/app/assets/stylesheets/components/_tables.sass +++ b/app/assets/stylesheets/components/_tables.sass @@ -296,7 +296,7 @@ border-right: 1px solid rgba($grey, 0.5) .th - > div + > div:not(.btn-group) min-height: 19px > *:first-child diff --git a/app/assets/stylesheets/modules/_jp_collection.sass b/app/assets/stylesheets/modules/_jp_collection.sass index c109fc71a..f579cf87b 100644 --- a/app/assets/stylesheets/modules/_jp_collection.sass +++ b/app/assets/stylesheets/modules/_jp_collection.sass @@ -98,3 +98,33 @@ left: -23px top: 50% margin-top: -8px + + // Errors + .table-2entries .t2e-item-list + .t2e-item + position: relative + + .th .vj_tt + display: inline-block + vertical-align: top + + + .vj_tt + margin-left: 5px + + &.has-error + &:before + content: '' + position: absolute + top: 0 + left: 0 + right: 0 + bottom: 0 + border: 2px solid $red + + > .th + > div:first-child, > div:first-child + div + color: $red + + // Reset default behaviour + .form-control + border-color: #ccc diff --git a/app/controllers/routing_constraint_zones_controller.rb b/app/controllers/routing_constraint_zones_controller.rb index 9d2fd712c..6fb5348f0 100644 --- a/app/controllers/routing_constraint_zones_controller.rb +++ b/app/controllers/routing_constraint_zones_controller.rb @@ -10,29 +10,39 @@ class RoutingConstraintZonesController < ChouetteController belongs_to :line, parent_class: Chouette::Line end - def index - @routing_constraint_zones = collection - end - - def show - @routing_constraint_zone = collection.find(params[:id]) - @routing_constraint_zone = @routing_constraint_zone.decorate(context: { - referential: @referential, - line: @line - }) - end - protected def collection - @q = resource.routing_constraint_zones.search(params[:q]) + @q = current_referential.routing_constraint_zones.search(params[:q]) - if sort_column && sort_direction - @routing_constraint_zones ||= @q.result(distinct: true).order(sort_column + ' ' + sort_direction) - else - @routing_constraint_zones ||= @q.result(distinct: true).order(:name) + @routing_constraint_zones ||= begin + if sort_column && sort_direction + routing_constraint_zones = @q.result(distinct: true).order(sort_column + ' ' + sort_direction) + else + routing_constraint_zones = @q.result(distinct: true).order(:name) + end + routing_constraint_zones = routing_constraint_zones.paginate(page: params[:page], per_page: 10) end - @routing_constraint_zones = @routing_constraint_zones.paginate(page: params[:page], per_page: 10) + end + + def resource + @routing_constraint_zone ||= begin + routing_constraint_zone = current_referential.routing_constraint_zones.find(params[:id]) + routing_constraint_zone = routing_constraint_zone.decorate(context: { + referential: current_referential, + line: parent.id + }) + end + end + + def build_resource + @routing_constraint_zone ||= begin + routing_constraint_zone = current_referential.routing_constraint_zones.new + routing_constraint_zone = routing_constraint_zone.decorate(context: { + referential: current_referential, + line: parent.id + }) + end end private @@ -43,11 +53,6 @@ class RoutingConstraintZonesController < ChouetteController %w[asc desc].include?(params[:direction]) ? params[:direction] : 'asc' end - def resource - @referential = Referential.find params[:referential_id] - @line = @referential.lines.find params[:line_id] - end - def routing_constraint_zone_params params.require(:routing_constraint_zone).permit( :name, diff --git a/app/models/chouette/time_table.rb b/app/models/chouette/time_table.rb index c566452f4..cb1d0c5da 100644 --- a/app/models/chouette/time_table.rb +++ b/app/models/chouette/time_table.rb @@ -496,16 +496,25 @@ class Chouette::TimeTable < Chouette::TridentActiveRecord self.convert_continuous_dates_to_periods end + def included_days_in_dates_and_periods + in_day = self.dates.select {|d| d.in_out }.map(&:date) + out_day = self.dates.select {|d| !d.in_out }.map(&:date) + + in_periods = self.periods.map{|p| (p.period_start..p.period_end).to_a }.flatten + days = in_periods + in_day + days -= out_day + days + end + # remove dates form tt which aren't in another_tt def intersect!(another_tt) transaction do - - # transform tt as effective dates and get common ones - days = another_tt.intersects(self.effective_days) & self.intersects(another_tt.effective_days) + days = self.included_days_in_dates_and_periods & another_tt.included_days_in_dates_and_periods self.dates.clear - days.each {|d| self.dates << Chouette::TimeTableDate.new( :date =>d, :in_out => true)} self.periods.clear - self.dates.to_a.sort! { |a,b| a.date <=> b.date} + days.sort.each do |d| + self.dates << Chouette::TimeTableDate.new(:date => d, :in_out => true) + end self.save! end self.convert_continuous_dates_to_periods diff --git a/app/models/referential.rb b/app/models/referential.rb index 0ce325bd6..ed23e2e51 100644 --- a/app/models/referential.rb +++ b/app/models/referential.rb @@ -114,6 +114,10 @@ class Referential < ActiveRecord::Base Chouette::RouteSection.all end + def routing_constraint_zones + Chouette::RoutingConstraintZone.all + end + after_initialize :define_default_attributes def define_default_attributes diff --git a/app/views/routing_constraint_zones/_form.html.slim b/app/views/routing_constraint_zones/_form.html.slim index 3d4764ef7..5e5f44269 100644 --- a/app/views/routing_constraint_zones/_form.html.slim +++ b/app/views/routing_constraint_zones/_form.html.slim @@ -3,7 +3,7 @@ .row .col-lg-12 = form.input :name - = form.input :route_id, collection: @line.routes.select { |route| route.stop_points.count > 2 }, include_blank: false + = form.input :route_id, collection: @line.routes, include_blank: false .separator diff --git a/app/views/routing_constraint_zones/edit.html.slim b/app/views/routing_constraint_zones/edit.html.slim index d81a347e0..589083927 100644 --- a/app/views/routing_constraint_zones/edit.html.slim +++ b/app/views/routing_constraint_zones/edit.html.slim @@ -1,6 +1,6 @@ / PageHeader = pageheader 'map-marker', - t('.title'), + t('.title', routing_constraint_zone: @routing_constraint_zone.name), '', t('last_update', time: l(@routing_constraint_zone.updated_at, format: :short)) diff --git a/lib/tasks/referential.rake b/lib/tasks/referential.rake index ce1ded4fc..d27354a40 100644 --- a/lib/tasks/referential.rake +++ b/lib/tasks/referential.rake @@ -39,6 +39,8 @@ namespace :referential do print " ✓ Created Route ".green, route.name, "(#{route.id}), ".blue, "Line (#{line.id}) has #{line.routes.count} routes\n" journey_pattern = Chouette::JourneyPattern.create!(route: route, name: "Journey Pattern #{Faker::Name.unique.name}") + print "✓ Created JourneyPattern ".green, journey_pattern.name, "(#{journey_pattern.id})".blue, "\n" + journey_pattern.stop_points = stop_areas.inject([]) { |stop_points, stop_area| stop_points += stop_area.stop_points } time_tables = [] @@ -46,11 +48,14 @@ namespace :referential do name = "Test #{Faker::Name.unique.name}" time_table = Chouette::TimeTable.create!(comment: name, start_date: Date.parse(args[:start_date]) + j.days, end_date: Date.parse(args[:end_date]) - j.days) + print "✓ Created TimeTable ".green, time_table.comment, "(#{time_table.id})".blue, "\n" time_tables << time_table end 25.times do |j| vehicle_journey = Chouette::VehicleJourney.create!(journey_pattern: journey_pattern, route: route, number: Faker::Number.unique.number(4), time_tables: time_tables) + print "✓ Created VehicleJourney ".green, vehicle_journey.number, "(#{vehicle_journey.id})".blue, "\n" + time = Time.current.at_noon + j.minutes journey_pattern.stop_points.each_with_index do |stop_point, k| vehicle_journey.vehicle_journey_at_stops.create!(stop_point: stop_point, arrival_time: time + k.minutes, departure_time: time + k.minutes + 30.seconds) diff --git a/spec/models/chouette/time_table_spec.rb b/spec/models/chouette/time_table_spec.rb index 76c5def5c..536de873a 100644 --- a/spec/models/chouette/time_table_spec.rb +++ b/spec/models/chouette/time_table_spec.rb @@ -72,6 +72,86 @@ describe Chouette::TimeTable, :type => :model do end end + describe '#intersect! with time_table' do + let(:another_tt) { create(:time_table) } + + context 'dates' do + # Clear periods as we are testing dates + before do + subject.periods.clear + another_tt.periods.clear + end + + it 'should keep common dates' do + days = subject.dates.map(&:date) + subject.intersect!(another_tt) + expect(subject.included_days_in_dates_and_periods).to include(*days) + end + + it 'should not keep dates who are not in common' do + # Add 1 year interval, to make sur we have not dates in common + another_tt.dates.map{|d| d.date = d.date + 1.year } + subject.intersect!(another_tt) + + expect(subject.reload.dates).to be_empty + end + end + + context 'periods' do + let(:another_tt_periods_to_range) { another_tt.periods.map{|p| p.period_start..p.period_end } } + # Clear dates as we are testing periods + before do + subject.dates.clear + another_tt.dates.clear + end + + def create_time_table_periode time_table, start_date, end_date + create(:time_table_period, time_table: time_table, :period_start => start_date, :period_end => end_date) + end + + it 'should keep common dates in periods' do + subject.intersect!(another_tt) + expect(subject_periods_to_range).to include(*another_tt_periods_to_range) + end + + it 'should build new period with common dates in periods' do + subject.periods.clear + another_tt.periods.clear + + subject.periods << create_time_table_periode(subject, Date.today, Date.today + 10.day) + another_tt.periods << create_time_table_periode(another_tt, Date.tomorrow, Date.today + 3.day) + + subject.intersect!(another_tt) + expected_range = Date.tomorrow..Date.today + 3.day + + expect(subject_periods_to_range).to include(expected_range) + expect(subject.periods.count).to eq 1 + end + + it 'should not keep dates in periods who are not in common' do + another_tt.periods.map do |p| + p.period_start = p.period_start + 1.year + p.period_end = p.period_end + 1.year + end + + subject.intersect!(another_tt) + expect(subject.periods).to be_empty + end + + context 'with calendar' do + let(:period_start) { subject.periods[0].period_start } + let(:period_end) { subject.periods[0].period_end } + let(:another_tt) { create(:calendar, date_ranges: [period_start..period_end]).convert_to_time_table } + + it 'should keep common dates in periods' do + subject.intersect!(another_tt) + expect(subject.reload.periods.count).to eq 1 + expect(subject_periods_to_range).to include(*another_tt_periods_to_range) + end + end + end + end + describe "actualize" do let(:calendar) { create(:calendar) } let(:int_day_types) { 508 } @@ -1037,90 +1117,6 @@ end end end - describe "#intersect!" do - context "timetables have periods with common day_types " do - before do - subject.periods.clear - subject.dates.clear - subject.periods << Chouette::TimeTablePeriod.new(:period_start => Date.new(2014,8,1), :period_end => Date.new(2014,8,6)) - subject.periods << Chouette::TimeTablePeriod.new(:period_start => Date.new(2014,6,30), :period_end => Date.new(2014,7,20)) - subject.dates << Chouette::TimeTableDate.new( :date => Date.new(2014,7,16), :in_out => true) - subject.int_day_types = 4|16|32|128 - another_tt = create(:time_table , :int_day_types => (4|16|64|128) ) - another_tt.periods.clear - another_tt.dates.clear - another_tt.periods << Chouette::TimeTablePeriod.new(:period_start => Date.new(2014,8,6), :period_end => Date.new(2014,8,12)) - another_tt.periods << Chouette::TimeTablePeriod.new(:period_start => Date.new(2014,7,15), :period_end => Date.new(2014,7,25)) - subject.intersect! another_tt - subject.reload - end - it "should have no period" do - expect(subject.periods.size).to eq(0) - end - it "should have date all common days" do - expect(subject.dates.size).to eq(3) - expect(subject.dates[0].date).to eq(Date.new(2014,7,16)) - expect(subject.dates[1].date).to eq(Date.new(2014,7,19)) - expect(subject.dates[2].date).to eq(Date.new(2014,8,6)) - end - end - context "timetables have periods or dates " do - before do - subject.periods.clear - subject.dates.clear - subject.dates << Chouette::TimeTableDate.new( :date => Date.new(2014,7,16), :in_out => true) - subject.dates << Chouette::TimeTableDate.new( :date => Date.new(2014,7,17), :in_out => true) - subject.dates << Chouette::TimeTableDate.new( :date => Date.new(2014,7,18), :in_out => true) - subject.dates << Chouette::TimeTableDate.new( :date => Date.new(2014,7,19), :in_out => true) - subject.dates << Chouette::TimeTableDate.new( :date => Date.new(2014,7,20), :in_out => true) - subject.int_day_types = 0 - another_tt = create(:time_table , :int_day_types => (4|16|64|128) ) - another_tt.periods.clear - another_tt.dates.clear - another_tt.periods << Chouette::TimeTablePeriod.new(:period_start => Date.new(2014,8,6), :period_end => Date.new(2014,8,12)) - another_tt.periods << Chouette::TimeTablePeriod.new(:period_start => Date.new(2014,7,17), :period_end => Date.new(2014,7,25)) - subject.intersect! another_tt - subject.reload - end - it "should have 0 period" do - expect(subject.periods.size).to eq(0) - end - it "should not modify day_types" do - expect(subject.int_day_types).to eq(0) - end - it "should have date reduced for period" do - expect(subject.dates.size).to eq(2) - expect(subject.dates[0].date).to eq(Date.new(2014,7,18)) - expect(subject.dates[1].date).to eq(Date.new(2014,7,19)) - end - end - context "with only periods : intersect timetable have no one day period" do - before do - subject.periods.clear - subject.dates.clear - subject.periods << Chouette::TimeTablePeriod.new(:period_start => Date.new(2014,8,1), :period_end => Date.new(2014,8,6)) - subject.int_day_types = 4|8|16 - another_tt = create(:time_table , :int_day_types => (4|8|16) ) - another_tt.periods.clear - another_tt.dates.clear - another_tt.periods << Chouette::TimeTablePeriod.new(:period_start => Date.new(2014,8,6), :period_end => Date.new(2014,8,12)) - subject.intersect! another_tt - subject.reload - end - it "should have 0 result periods" do - expect(subject.periods.size).to eq(0) - end - it "should not modify day_types" do - expect(subject.int_day_types).to eq(4|8|16) - end - it "should have 1 date " do - expect(subject.dates.size).to eq(1) - expect(subject.dates[0].date).to eq(Date.new(2014,8,6)) - end - end - - end - describe "#disjoin!" do context "timetables have periods with common day_types " do before do |
