aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/assets/images/icons/file_calc.pngbin0 -> 1275 bytes
-rw-r--r--app/assets/images/icons/file_csv.pngbin0 -> 1074 bytes
-rw-r--r--app/assets/images/icons/file_excel.pngbin0 -> 1293 bytes
-rw-r--r--app/assets/stylesheets/vehicle_journey_imports.css.scss10
-rw-r--r--app/controllers/vehicle_journey_exports_controller.rb36
-rw-r--r--app/controllers/vehicle_journey_imports_controller.rb50
-rw-r--r--app/helpers/stop_areas_helper.rb4
-rw-r--r--app/models/vehicle_journey_export.rb33
-rw-r--r--app/models/vehicle_journey_import.rb107
-rw-r--r--app/views/routes/show.html.erb5
-rw-r--r--app/views/vehicle_journey_imports/new.html.erb27
11 files changed, 269 insertions, 3 deletions
diff --git a/app/assets/images/icons/file_calc.png b/app/assets/images/icons/file_calc.png
new file mode 100644
index 000000000..6339ff181
--- /dev/null
+++ b/app/assets/images/icons/file_calc.png
Binary files differ
diff --git a/app/assets/images/icons/file_csv.png b/app/assets/images/icons/file_csv.png
new file mode 100644
index 000000000..795cba0a6
--- /dev/null
+++ b/app/assets/images/icons/file_csv.png
Binary files differ
diff --git a/app/assets/images/icons/file_excel.png b/app/assets/images/icons/file_excel.png
new file mode 100644
index 000000000..e60ab1319
--- /dev/null
+++ b/app/assets/images/icons/file_excel.png
Binary files differ
diff --git a/app/assets/stylesheets/vehicle_journey_imports.css.scss b/app/assets/stylesheets/vehicle_journey_imports.css.scss
new file mode 100644
index 000000000..6aab362d1
--- /dev/null
+++ b/app/assets/stylesheets/vehicle_journey_imports.css.scss
@@ -0,0 +1,10 @@
+@import "common/mixins";
+
+#workspace.vehicle_journey_imports.new
+{
+ .export{
+ margin: 5px 0 15px 0 !important;
+
+ .file{ margin-left: 5px; }
+ }
+} \ No newline at end of file
diff --git a/app/controllers/vehicle_journey_exports_controller.rb b/app/controllers/vehicle_journey_exports_controller.rb
new file mode 100644
index 000000000..f29cd01aa
--- /dev/null
+++ b/app/controllers/vehicle_journey_exports_controller.rb
@@ -0,0 +1,36 @@
+class VehicleJourneyExportsController < ChouetteController
+ belongs_to :referential do
+ belongs_to :line, :parent_class => Chouette::Line do
+ belongs_to :route, :parent_class => Chouette::Route
+ end
+ end
+
+ respond_to :csv, :only => [:new, :index]
+ respond_to :xls, :only => [:new, :index]
+
+ def new
+ new! do |format|
+ @vehicle_journey_export = VehicleJourneyExport.new(:route => @route)
+
+ format.csv { render text: @vehicle_journey_export.to_csv }
+ format.xls { render text: @vehicle_journey_export.to_csv(col_sep: "\t") }
+ end
+ end
+
+ def index
+ index! do |format|
+ @vehicle_journey_export = VehicleJourneyExport.new(:route => @route)
+
+ format.csv { render text: @vehicle_journey_export.to_csv }
+ format.xls { render text: @vehicle_journey_export.to_csv(col_sep: "\t") }
+ end
+ end
+
+ protected
+ alias_method :route, :parent
+
+ def collection
+ @vehicle_journey_exports = []
+ end
+
+end
diff --git a/app/controllers/vehicle_journey_imports_controller.rb b/app/controllers/vehicle_journey_imports_controller.rb
new file mode 100644
index 000000000..e3a6dde77
--- /dev/null
+++ b/app/controllers/vehicle_journey_imports_controller.rb
@@ -0,0 +1,50 @@
+class VehicleJourneyImportsController < ChouetteController
+ belongs_to :referential do
+ belongs_to :line, :parent_class => Chouette::Line do
+ belongs_to :route, :parent_class => Chouette::Route
+ end
+ end
+
+ actions :new, :create
+ respond_to :html, :only => :new
+
+ def new
+ @vehicle_journey_import = VehicleJourneyImport.new(:route => route)
+ flash[:notice] = "A CSV or Excel file can be used to import records. The first row should be the column name.
+<p>
+The following columns are allowed :
+<ul>
+ <li>
+ <strong>stop_point_id</strong> -
+ Integer type
+ </li>
+ <li>
+ <strong>stop_area_name</strong> -
+ String type
+ </li>
+ <li>
+ <strong>published_journey_name </strong> -
+ String type
+ </li>
+ <li>
+ <strong>published_journey_name </strong> -
+ String type ....
+ </li>
+</ul>
+</p>"
+ new!
+ end
+
+ def create
+ @vehicle_journey_import = VehicleJourneyImport.new(params[:vehicle_journey_import].merge({:route => route}))
+ if @vehicle_journey_import.save
+ redirect_to referential_line_route_path( @referential, @line, @route ), notice: "Import successful"
+ else
+ render :new
+ end
+ end
+
+ protected
+ alias_method :route, :parent
+
+end
diff --git a/app/helpers/stop_areas_helper.rb b/app/helpers/stop_areas_helper.rb
index da29b2ec6..e654857a8 100644
--- a/app/helpers/stop_areas_helper.rb
+++ b/app/helpers/stop_areas_helper.rb
@@ -1,7 +1,7 @@
module StopAreasHelper
def genealogical_title
- return t(".genealogical_routing") if @stop_area.stop_area_type == 'itl'
- t(".genealogical")
+ return t("genealogical_routing") if @stop_area.stop_area_type == 'itl'
+ t("genealogical")
end
def show_map?
diff --git a/app/models/vehicle_journey_export.rb b/app/models/vehicle_journey_export.rb
new file mode 100644
index 000000000..8fe7869f1
--- /dev/null
+++ b/app/models/vehicle_journey_export.rb
@@ -0,0 +1,33 @@
+# -*- coding: utf-8 -*-
+require "csv"
+
+class VehicleJourneyExport
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :route
+
+ validates_presence_of :route
+
+ def initialize(attributes = {})
+ attributes.each { |name, value| send("#{name}=", value) }
+ end
+
+ def persisted?
+ false
+ end
+
+ def to_csv(options = {})
+ CSV.generate(options) do |csv|
+ vehicle_journeys_sorted = route.vehicle_journeys.includes(:vehicle_journey_at_stops).order("vehicle_journey_at_stops.departure_time")
+
+ vehicle_journey_at_stops_matrix = (vehicle_journeys_sorted.collect{ |vj| vj.vehicle_journey_at_stops.collect(&:departure_time).collect{|time| time.strftime("%H:%M")} }).transpose
+ csv << ["stop_point_id", "stop_area_name"] + vehicle_journeys_sorted.collect(&:objectid)
+ route.stop_points.each_with_index do |stop_point, index|
+ csv << [stop_point.id, stop_point.stop_area.name] + vehicle_journey_at_stops_matrix[index]
+ end
+ end
+ end
+
+end
diff --git a/app/models/vehicle_journey_import.rb b/app/models/vehicle_journey_import.rb
new file mode 100644
index 000000000..d637c9e5f
--- /dev/null
+++ b/app/models/vehicle_journey_import.rb
@@ -0,0 +1,107 @@
+# -*- coding: utf-8 -*-
+
+class VehicleJourneyImport
+ include ActiveModel::Validations
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :file, :route
+
+ validates_presence_of :file
+ validates_presence_of :route
+
+ def initialize(attributes = {})
+ attributes.each { |name, value| send("#{name}=", value) }
+ end
+
+ def persisted?
+ false
+ end
+
+ def save
+ begin
+ Chouette::VehicleJourney.transaction do
+ if imported_vehicle_journeys.map(&:valid?).all?
+ imported_vehicle_journeys.each(&:save!)
+ true
+ else
+ imported_vehicle_journeys.each_with_index do |imported_vehicle_journey, index|
+ imported_vehicle_journey.errors.full_messages.each do |message|
+ errors.add :base, I18n.t("vehicle_journey_imports.errors.invalid_vehicle_journey", :column => index, :message => message)
+ end
+ end
+ false
+ end
+ end
+ rescue Exception => exception
+ errors.add :base, I18n.t("vehicle_journey_imports.errors.exception", :message => exception.message)
+ false
+ end
+ end
+
+ def imported_vehicle_journeys
+ @imported_vehicle_journeys ||= load_imported_vehicle_journeys
+ end
+
+ # Find journey pattern on stop points used in vehicle journey at stops
+ def find_journey_pattern_schedule(hours_by_stop_point_ids)
+ stop_points_used = hours_by_stop_point_ids.reject{ |key,value| value == nil }.keys
+ journey_pattern_founded = route.journey_patterns.select{ |jp| jp.stop_points.collect(&:id) == stop_points_used }.first
+
+ # If no journey pattern founded, create a new one
+ journey_pattern_founded ? journey_pattern_founded : route.journey_patterns.create(:stop_points => Chouette::StopPoint.find(stop_points_used) )
+ end
+
+ def load_imported_vehicle_journeys
+ spreadsheet = open_spreadsheet(file)
+ vehicle_journeys = []
+
+ first_column = spreadsheet.column(1)
+ stop_point_ids = first_column[1..spreadsheet.last_row].map(&:to_i)
+ same_stop_points = route.stop_points.collect(&:id) == stop_point_ids
+
+ unless same_stop_points
+ errors.add :base, I18n.t("vehicle_journey_imports.errors.not_same_stop_points", :route => route.id)
+ return vehicle_journeys
+ end
+
+ Chouette::VehicleJourney.transaction do
+ (3..spreadsheet.last_column).each do |i|
+ vehicle_journey_objectid = spreadsheet.column(i)[0]
+ hours_by_stop_point_ids = Hash[[stop_point_ids, spreadsheet.column(i)[1..spreadsheet.last_row]].transpose]
+
+ journey_pattern = find_journey_pattern_schedule(hours_by_stop_point_ids)
+ vehicle_journey = journey_pattern.vehicle_journeys.where(:objectid => vehicle_journey_objectid, :route_id => route.id, :journey_pattern_id => journey_pattern.id).first_or_create
+
+ line = 0
+ hours_by_stop_point_ids.each_pair do |key, value|
+ line += 1
+ if value.present? # Create a vehicle journey at stop when time is present
+ main_time = Time.parse(value)
+
+ if main_time.present?
+ vjas = Chouette::VehicleJourneyAtStop.where(:vehicle_journey_id => vehicle_journey.id, :stop_point_id => key).first_or_create(:departure_time => main_time, :arrival_time => main_time)
+ else
+ errors.add :base, I18n.t("vehicle_journey_imports.errors.invalid_vehicle_journey", :column => i, :line => line, :time => value)
+ end
+ end
+ end
+
+ vehicle_journeys << vehicle_journey
+ end
+ end
+
+ vehicle_journeys
+ end
+
+ def open_spreadsheet(file)
+ case File.extname(file.original_filename)
+ when '.csv' then Roo::CSV.new(file.path)
+ when '.xls' then Roo::Excel.new(file.path)
+ when '.xlsx' then Roo::Excelx.new(file.path)
+ else
+ raise "Unknown file type: #{file.original_filename}"
+ end
+ end
+
+end
diff --git a/app/views/routes/show.html.erb b/app/views/routes/show.html.erb
index 8383366b3..6642f2bd7 100644
--- a/app/views/routes/show.html.erb
+++ b/app/views/routes/show.html.erb
@@ -91,7 +91,10 @@
<li>
<%= link_to t('vehicle_journeys.actions.index'), [@referential, @line, @route, :vehicle_journeys], :class => "link" %>
</li>
-<% end %>
+ <% end %>
+ <li>
+ <%= link_to t('vehicle_journey_imports.new.title'), new_referential_line_route_vehicle_journey_import_path( @referential, @line, @route ), :class => "import" %>
+ </li>
</ul>
<%= creation_tag(@route) %>
diff --git a/app/views/vehicle_journey_imports/new.html.erb b/app/views/vehicle_journey_imports/new.html.erb
new file mode 100644
index 000000000..a1078c88d
--- /dev/null
+++ b/app/views/vehicle_journey_imports/new.html.erb
@@ -0,0 +1,27 @@
+<%= title_tag t('vehicle_journey_imports.new.title') %>
+
+<p class="export"><%= t('vehicle_journey_imports.new.export_vehicle_journeys') %>
+ <span class="file"><%= link_to image_tag("icons/file_csv.png"), referential_line_route_vehicle_journey_exports_path(@referential, @line, @route, :format => :csv) %></span>
+ <span class="file"><%= link_to image_tag("icons/file_excel.png"), referential_line_route_vehicle_journey_exports_path(@referential, @line, @route, :format => :xls) %></span>
+</p>
+
+<%= semantic_form_for [@referential, @line, @route, @vehicle_journey_import] do |form| %>
+ <% if @vehicle_journey_import.errors.any? %>
+ <div id="error_explanation">
+ <h2><%= pluralize(@vehicle_journey_import.errors.count, "error") %> prohibited this import from completing:</h2>
+ <ul>
+ <% @vehicle_journey_import.errors.full_messages.each do |msg| %>
+ <li><%= msg %></li>
+ <% end %>
+ </ul>
+ </div>
+ <% end %>
+ <br>
+ <%= form.inputs do %>
+ <%= form.input :file, :as => :file %>
+ <% end %>
+ <%= form.actions do %>
+ <%= form.action :submit, :as => :button , :label => t( 'formtastic.import' ) %>
+ <%= form.action :cancel, :as => :link %>
+ <% end %>
+<% end %>