diff options
Diffstat (limited to 'app')
| -rw-r--r-- | app/assets/images/icons/file_calc.png | bin | 0 -> 1275 bytes | |||
| -rw-r--r-- | app/assets/images/icons/file_csv.png | bin | 0 -> 1074 bytes | |||
| -rw-r--r-- | app/assets/images/icons/file_excel.png | bin | 0 -> 1293 bytes | |||
| -rw-r--r-- | app/assets/stylesheets/vehicle_journey_imports.css.scss | 10 | ||||
| -rw-r--r-- | app/controllers/vehicle_journey_exports_controller.rb | 36 | ||||
| -rw-r--r-- | app/controllers/vehicle_journey_imports_controller.rb | 50 | ||||
| -rw-r--r-- | app/helpers/stop_areas_helper.rb | 4 | ||||
| -rw-r--r-- | app/models/vehicle_journey_export.rb | 33 | ||||
| -rw-r--r-- | app/models/vehicle_journey_import.rb | 107 | ||||
| -rw-r--r-- | app/views/routes/show.html.erb | 5 | ||||
| -rw-r--r-- | app/views/vehicle_journey_imports/new.html.erb | 27 | 
11 files changed, 269 insertions, 3 deletions
| diff --git a/app/assets/images/icons/file_calc.png b/app/assets/images/icons/file_calc.pngBinary files differ new file mode 100644 index 000000000..6339ff181 --- /dev/null +++ b/app/assets/images/icons/file_calc.png diff --git a/app/assets/images/icons/file_csv.png b/app/assets/images/icons/file_csv.pngBinary files differ new file mode 100644 index 000000000..795cba0a6 --- /dev/null +++ b/app/assets/images/icons/file_csv.png diff --git a/app/assets/images/icons/file_excel.png b/app/assets/images/icons/file_excel.pngBinary files differ new file mode 100644 index 000000000..e60ab1319 --- /dev/null +++ b/app/assets/images/icons/file_excel.png 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 %> | 
