aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/controllers/routes_controller.rb3
-rw-r--r--app/decorators/route_decorator.rb17
-rw-r--r--app/javascript/time_tables/actions/index.js5
-rw-r--r--app/models/chouette/route.rb24
-rw-r--r--app/models/chouette/stop_point.rb3
-rw-r--r--app/models/chouette/vehicle_journey.rb27
-rw-r--r--app/models/concerns/custom_fields_support.rb2
-rw-r--r--app/policies/route_policy.rb4
-rw-r--r--app/views/calendars/show.html.slim4
-rw-r--r--config/locales/routes.fr.yml4
-rw-r--r--spec/controllers/routes_controller_spec.rb36
-rw-r--r--spec/models/chouette/route/route_duplication_spec.rb3
-rw-r--r--spec/models/chouette/vehicle_journey_spec.rb51
13 files changed, 163 insertions, 20 deletions
diff --git a/app/controllers/routes_controller.rb b/app/controllers/routes_controller.rb
index 96a23c938..ac243c8eb 100644
--- a/app/controllers/routes_controller.rb
+++ b/app/controllers/routes_controller.rb
@@ -63,7 +63,8 @@ class RoutesController < ChouetteController
end
def duplicate
- route = Chouette::Route.find(params[:id]).duplicate
+ source = Chouette::Route.find(params[:id])
+ route = source.duplicate params[:opposite]
flash[:notice] = t('routes.duplicate.success')
redirect_to referential_line_path(@referential, route.line)
end
diff --git a/app/decorators/route_decorator.rb b/app/decorators/route_decorator.rb
index fa6367924..4a173cbb9 100644
--- a/app/decorators/route_decorator.rb
+++ b/app/decorators/route_decorator.rb
@@ -71,6 +71,23 @@ class RouteDecorator < AF83::Decorator
end
end
+ instance_decorator.action_link(
+ secondary: :show,
+ policy: :create_opposite,
+ if: ->{h.has_feature?(:create_opposite_routes) && object.opposite_route.nil?}
+ ) do |l|
+ l.content h.t('routes.create_opposite.title')
+ l.method :post
+ l.href do
+ h.duplicate_referential_line_route_path(
+ context[:referential],
+ context[:line],
+ object,
+ opposite: true
+ )
+ end
+ end
+
instance_decorator.destroy_action_link do |l|
l.data confirm: h.t('routes.actions.destroy_confirm')
end
diff --git a/app/javascript/time_tables/actions/index.js b/app/javascript/time_tables/actions/index.js
index 3127d11b8..7c79dfe52 100644
--- a/app/javascript/time_tables/actions/index.js
+++ b/app/javascript/time_tables/actions/index.js
@@ -306,10 +306,11 @@ const actions = {
})
},
errorModalKey: (periods, dayTypes) => {
- const withoutPeriodsWithDaysTypes = reject(periods, 'deleted').length == 0 && some(dayTypes) && "withoutPeriodsWithDaysTypes"
+ // const withoutPeriodsWithDaysTypes = reject(periods, 'deleted').length == 0 && some(dayTypes) && "withoutPeriodsWithDaysTypes"
const withPeriodsWithoutDayTypes = reject(periods, 'deleted').length > 0 && every(dayTypes, dt => dt == false) && "withPeriodsWithoutDayTypes"
- return (withoutPeriodsWithDaysTypes || withPeriodsWithoutDayTypes) && (withoutPeriodsWithDaysTypes ? "withoutPeriodsWithDaysTypes" : "withPeriodsWithoutDayTypes")
+ // return (withoutPeriodsWithDaysTypes || withPeriodsWithoutDayTypes) && (withoutPeriodsWithDaysTypes ? "withoutPeriodsWithDaysTypes" : "withPeriodsWithoutDayTypes")
+ return withPeriodsWithoutDayTypes
},
errorModalMessage: (errorKey) => {
diff --git a/app/models/chouette/route.rb b/app/models/chouette/route.rb
index 13288bc6b..65947c392 100644
--- a/app/models/chouette/route.rb
+++ b/app/models/chouette/route.rb
@@ -68,28 +68,34 @@ module Chouette
validates_presence_of :published_name
validates_presence_of :line
validates :wayback, inclusion: { in: self.wayback.values }
-
after_save :calculate_costs!, if: ->() { TomTom.enabled? }
-
- def duplicate
+
+ def duplicate opposite=false
overrides = {
'opposite_route_id' => nil,
'name' => I18n.t('activerecord.copy', name: self.name)
}
+ keys_for_create = attributes.keys - %w{id objectid created_at updated_at}
atts_for_create = attributes
- .slice!(*%w{id objectid created_at updated_at})
+ .slice(*keys_for_create)
.merge(overrides)
+ if opposite
+ atts_for_create[:wayback] = self.opposite_wayback
+ atts_for_create[:name] = I18n.t('routes.opposite', name: self.name)
+ atts_for_create[:published_name] = atts_for_create[:name]
+ atts_for_create[:opposite_route_id] = self.id
+ end
new_route = self.class.create!(atts_for_create)
- duplicate_stop_points(for_route: new_route)
+ duplicate_stop_points(for_route: new_route, opposite: opposite)
new_route
end
- def duplicate_stop_points(for_route:)
- stop_points.each(&duplicate_stop_point(for_route: for_route))
+ def duplicate_stop_points(for_route:, opposite: false)
+ stop_points.each(&duplicate_stop_point(for_route: for_route, opposite: opposite))
end
- def duplicate_stop_point(for_route:)
+ def duplicate_stop_point(for_route:, opposite: false)
-> stop_point do
- stop_point.duplicate(for_route: for_route)
+ stop_point.duplicate(for_route: for_route, opposite: opposite)
end
end
diff --git a/app/models/chouette/stop_point.rb b/app/models/chouette/stop_point.rb
index 6b363cd93..da2da998a 100644
--- a/app/models/chouette/stop_point.rb
+++ b/app/models/chouette/stop_point.rb
@@ -39,11 +39,12 @@ module Chouette
end
end
- def duplicate(for_route:)
+ def duplicate(for_route:, opposite: false)
keys_for_create = attributes.keys - %w{id objectid created_at updated_at}
atts_for_create = attributes
.slice(*keys_for_create)
.merge('route_id' => for_route.id)
+ atts_for_create["position"] = self.route.stop_points.size - atts_for_create["position"] if opposite
self.class.create!(atts_for_create)
end
diff --git a/app/models/chouette/vehicle_journey.rb b/app/models/chouette/vehicle_journey.rb
index 525036077..be05d4053 100644
--- a/app/models/chouette/vehicle_journey.rb
+++ b/app/models/chouette/vehicle_journey.rb
@@ -346,6 +346,33 @@ module Chouette
end
end
+ def fill_passing_time_at_borders
+ encountered_borders = []
+ previous_stop = nil
+ vehicle_journey_at_stops.each do |vjas|
+ sp = vjas.stop_point
+ if sp.stop_area.area_type == "border"
+ encountered_borders << vjas
+ else
+ if encountered_borders.any?
+ before_cost = journey_pattern.costs_between previous_stop.stop_point, encountered_borders.first.stop_point
+ after_cost = journey_pattern.costs_between encountered_borders.last.stop_point, sp
+ if before_cost && before_cost[:distance] && after_cost && after_cost[:distance]
+ before_distance = before_cost[:distance].to_f
+ after_distance = after_cost[:distance].to_f
+ time = previous_stop.departure_time + before_distance / (before_distance+after_distance) * (vjas.arrival_time - previous_stop.departure_time)
+ encountered_borders.each do |b|
+ b.update_attribute :arrival_time, time
+ b.update_attribute :departure_time, time
+ end
+ end
+ encountered_borders = []
+ end
+ previous_stop = vjas
+ end
+ end
+ end
+
def self.matrix(vehicle_journeys)
Hash[*VehicleJourneyAtStop.where(vehicle_journey_id: vehicle_journeys.pluck(:id)).map do |vjas|
[ "#{vjas.vehicle_journey_id}-#{vjas.stop_point_id}", vjas]
diff --git a/app/models/concerns/custom_fields_support.rb b/app/models/concerns/custom_fields_support.rb
index ef6b4f4af..017f496a8 100644
--- a/app/models/concerns/custom_fields_support.rb
+++ b/app/models/concerns/custom_fields_support.rb
@@ -12,7 +12,7 @@ module CustomFieldsSupport
end
def method_missing method_name, *args
- if method_name =~ /custom_field_*/ && !@custom_fields_initialized
+ if method_name =~ /custom_field_*/ && method_name.to_sym != :custom_field_values && !@custom_fields_initialized
initialize_custom_fields
send method_name, *args
else
diff --git a/app/policies/route_policy.rb b/app/policies/route_policy.rb
index 0337a5300..4fcb6be11 100644
--- a/app/policies/route_policy.rb
+++ b/app/policies/route_policy.rb
@@ -20,4 +20,8 @@ class RoutePolicy < ApplicationPolicy
def duplicate?
create?
end
+
+ def create_opposite?
+ create?
+ end
end
diff --git a/app/views/calendars/show.html.slim b/app/views/calendars/show.html.slim
index f65dd2cae..880db99f6 100644
--- a/app/views/calendars/show.html.slim
+++ b/app/views/calendars/show.html.slim
@@ -17,7 +17,7 @@
.pagination.pull-right
= @year
.page_links
- = link_to '', calendar_path(@calendar, year: (@year - 1)), class: 'previous_page'
- = link_to '', calendar_path(@calendar, year: (@year + 1)), class: 'next_page'
+ = link_to '', workgroup_calendar_path(@workgroup, @calendar, year: (@year - 1)), class: 'previous_page'
+ = link_to '', workgroup_calendar_path(@workgroup, @calendar, year: (@year + 1)), class: 'next_page'
= render 'time_tables/show_time_table', time_table: @calendar
diff --git a/config/locales/routes.fr.yml b/config/locales/routes.fr.yml
index ddf706794..9539a2ee3 100644
--- a/config/locales/routes.fr.yml
+++ b/config/locales/routes.fr.yml
@@ -16,6 +16,7 @@ fr:
add_stop_point: "Ajouter un arrêt"
new_stop_point: "Créer un arrêt pour l'ajouter"
opposite_route_timetable: "Horaires retour"
+ opposite: "%{name} (retour)"
new:
title: "Ajouter un itinéraire"
edit:
@@ -56,6 +57,9 @@ fr:
stop_area_name: "Nom de l'arrêt"
for_boarding: "Montée"
for_alighting: "Descente"
+ create_opposite:
+ title: "Créer retour"
+ success: "itinéraire créé avec succès"
duplicate:
title: "Dupliquer l'itinéraire"
success: "itinéraire dupliqué avec succès"
diff --git a/spec/controllers/routes_controller_spec.rb b/spec/controllers/routes_controller_spec.rb
index e4dc6bc23..a001a942d 100644
--- a/spec/controllers/routes_controller_spec.rb
+++ b/spec/controllers/routes_controller_spec.rb
@@ -83,6 +83,42 @@ RSpec.describe RoutesController, type: :controller do
expect(Chouette::Route.last.name).to eq(I18n.t('activerecord.copy', name: route.name))
expect(Chouette::Route.last.published_name).to eq(route.published_name)
+ expect(Chouette::Route.last.stop_area_ids).to eq route.stop_area_ids
+ end
+
+ context "when opposite = true" do
+ it "creates a new route on the opposite way " do
+ expect do
+ post :duplicate,
+ referential_id: route.line.line_referential_id,
+ line_id: route.line_id,
+ id: route.id,
+ opposite: TRUE
+ end.to change { Chouette::Route.count }.by(1)
+
+ expect(Chouette::Route.last.name).to eq(I18n.t('routes.opposite', name: route.name))
+ expect(Chouette::Route.last.published_name).to eq(Chouette::Route.last.name)
+ expect(Chouette::Route.last.opposite_route).to eq(route)
+ expect(Chouette::Route.last.stop_area_ids).to eq route.stop_area_ids.reverse
+ end
+ end
+
+ context "on a duplicated route" do
+ let!(:duplicated){ route.duplicate }
+ it "creates a new route on the opposite way " do
+ expect do
+ post :duplicate,
+ referential_id: duplicated.line.line_referential_id,
+ line_id: duplicated.line_id,
+ id: duplicated.id,
+ opposite: TRUE
+ end.to change { Chouette::Route.count }.by(1)
+
+ expect(Chouette::Route.last.name).to eq(I18n.t('routes.opposite', name: duplicated.name))
+ expect(Chouette::Route.last.published_name).to eq(Chouette::Route.last.name)
+ expect(Chouette::Route.last.opposite_route).to eq(duplicated)
+ expect(Chouette::Route.last.stop_area_ids).to eq duplicated.stop_area_ids.reverse
+ end
end
end
end
diff --git a/spec/models/chouette/route/route_duplication_spec.rb b/spec/models/chouette/route/route_duplication_spec.rb
index 8b3a948a2..47233b04e 100644
--- a/spec/models/chouette/route/route_duplication_spec.rb
+++ b/spec/models/chouette/route/route_duplication_spec.rb
@@ -8,9 +8,6 @@ RSpec.describe Chouette::Route do
route.duplicate
expect( values_for_create(Chouette::Route.last, except: %w{objectid name checksum checksum_source}) ).to eq( values_for_create( route, except: %w{objectid name checksum checksum_source} ) )
end
- it 'and others cannot' do
- expect{ route.duplicate name: 'YAN', line_id: 42 }.to raise_error(ArgumentError)
- end
it 'same associated stop_areeas' do
expect( route.duplicate.stop_areas.pluck(:id) ).to eq(route.stop_areas.pluck(:id))
end
diff --git a/spec/models/chouette/vehicle_journey_spec.rb b/spec/models/chouette/vehicle_journey_spec.rb
index 7292f09f9..41ac5d7d0 100644
--- a/spec/models/chouette/vehicle_journey_spec.rb
+++ b/spec/models/chouette/vehicle_journey_spec.rb
@@ -868,7 +868,6 @@ describe Chouette::VehicleJourney, :type => :model do
let!( :footnote_first) {create( :footnote, :code => "1", :label => "dummy 1", :line => route.line)}
let!( :footnote_second) {create( :footnote, :code => "2", :label => "dummy 2", :line => route.line)}
-
it "should update vehicle's footnotes" do
expect(Chouette::VehicleJourney.find(subject.id).footnotes).to be_empty
subject.footnote_ids = [ footnote_first.id ]
@@ -877,4 +876,54 @@ describe Chouette::VehicleJourney, :type => :model do
end
end
end
+
+ describe "#fill_passing_time_at_borders" do
+ before do
+ start = create :stop_area
+ border = create :stop_area, kind: :non_commercial, area_type: :border
+ border_2 = create :stop_area, kind: :non_commercial, area_type: :border
+ middle = create :stop_area
+ border_3 = create :stop_area, kind: :non_commercial, area_type: :border
+ border_4 = create :stop_area, kind: :non_commercial, area_type: :border
+ _end = create :stop_area
+ journey_pattern = create :journey_pattern
+ journey_pattern.stop_points.destroy_all
+ journey_pattern.stop_points << start_point = create(:stop_point, stop_area: start, position: 0)
+ journey_pattern.stop_points << border_point = create(:stop_point, stop_area: border, position: 1)
+ journey_pattern.stop_points << border_point_2 = create(:stop_point, stop_area: border_2, position: 2)
+ journey_pattern.stop_points << middle_point = create(:stop_point, stop_area: middle, position: 3)
+ journey_pattern.stop_points << border_point_3 = create(:stop_point, stop_area: border_3, position: 4)
+ journey_pattern.stop_points << border_point_4 = create(:stop_point, stop_area: border_4, position: 5)
+ journey_pattern.stop_points << end_point = create(:stop_point, stop_area: _end, position: 6)
+ journey_pattern.update_attribute :costs, {
+ "#{start_point.stop_area_id}-#{border_point.stop_area_id}" => {distance: 50},
+ "#{border_point.stop_area_id}-#{border_point_2.stop_area_id}" => {distance: 0},
+ "#{border_point_2.stop_area_id}-#{middle_point.stop_area_id}" => {distance: 100},
+ "#{middle_point.stop_area_id}-#{border_point_3.stop_area_id}" => {distance: 100},
+ "#{border_point_3.stop_area_id}-#{border_point_4.stop_area_id}" => {distance: 0},
+ "#{border_point_4.stop_area_id}-#{end_point.stop_area_id}" => {distance: 100}
+ }
+ @journey = create :vehicle_journey, journey_pattern: journey_pattern
+ @journey.vehicle_journey_at_stops.destroy_all
+ @start = create :vehicle_journey_at_stop, stop_point: start_point, vehicle_journey: @journey
+ @target = create :vehicle_journey_at_stop, stop_point: border_point, vehicle_journey: @journey, arrival_time: nil, departure_time: nil
+ @target_2 = create :vehicle_journey_at_stop, stop_point: border_point_2, vehicle_journey: @journey, arrival_time: nil, departure_time: nil
+ @middle = create :vehicle_journey_at_stop, stop_point: middle_point, vehicle_journey: @journey, arrival_time: @start.arrival_time + 4.hours, departure_time: @start.departure_time + 4.hours
+ @target_3 = create :vehicle_journey_at_stop, stop_point: border_point_3, vehicle_journey: @journey, arrival_time: nil, departure_time: nil
+ @target_4 = create :vehicle_journey_at_stop, stop_point: border_point_4, vehicle_journey: @journey, arrival_time: nil, departure_time: nil
+ @end = create :vehicle_journey_at_stop, stop_point: end_point, vehicle_journey: @journey, arrival_time: @middle.arrival_time + 4.hours, departure_time: @middle.departure_time + 4.hours
+ end
+
+ it "should compute passing time" do
+ @journey.reload.fill_passing_time_at_borders
+ expect(@target.reload.arrival_time.to_i).to eq (@start.reload.departure_time + 1.0/3 * (@middle.reload.arrival_time - @start.departure_time)).to_i
+ expect(@target_2.reload.arrival_time).to eq @target.arrival_time
+ expect(@target.departure_time).to eq @target.arrival_time
+ expect(@target_2.departure_time).to eq @target.arrival_time
+ expect(@target_3.reload.arrival_time.to_i).to eq (@middle.reload.departure_time + 0.5 * (@end.reload.arrival_time - @middle.departure_time)).to_i
+ expect(@target_4.reload.arrival_time).to eq @target_3.arrival_time
+ expect(@target_3.departure_time).to eq @target_3.arrival_time
+ expect(@target_4.departure_time).to eq @target_3.arrival_time
+ end
+ end
end