Skip to content

Commit

Permalink
Merge pull request #196 from fonsecadeline/language_in_csv
Browse files Browse the repository at this point in the history
CSV output columns consistent with provided language [former PR32]
  • Loading branch information
fab-girard authored Jun 23, 2021
2 parents e44f968 + 0044c6f commit e4e171d
Show file tree
Hide file tree
Showing 22 changed files with 611 additions and 190 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

- Implementation of `vehicle_trips` relation: the routes can be successive or with a minimum duration `lapse` in between [#123] (https://github.com/Mapotempo/optimizer-api/pull/123)

- CSV headers adapts to the language provided through HTTP_ACCEPT_LANGUAGE header to facilitate import in Mapotempo-Web [#196](https://github.com/Mapotempo/optimizer-api/pull/196)
- Return route day/date and visits' index in result [#196](https://github.com/Mapotempo/optimizer-api/pull/196)

### Changed

### Removed
Expand Down
8 changes: 7 additions & 1 deletion api/v01/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,13 @@ class Api < Grape::API

helpers do
def set_locale
I18n.locale = env.http_accept_language.compatible_language_from(I18n.available_locales.map(&:to_s)) || I18n.default_locale
I18n.locale =
if env.http_accept_language.header.nil? || env.http_accept_language.header == :unspecified
# we keep previous behaviour
:legacy
else
env.http_accept_language.compatible_language_from(I18n.available_locales.map(&:to_s)) || I18n.default_locale
end
end

def redis_count
Expand Down
1 change: 1 addition & 0 deletions api/v01/entities/vrp_input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ module VrpConfiguration
optional(:geometry_polyline, type: Boolean, documentation: { hidden: true }, desc: '[DEPRECATED] Use geometry instead, with :polylines or :encoded_polylines')
optional(:intermediate_solutions, type: Boolean, desc: 'Return intermediate solutions if available')
optional(:csv, type: Boolean, desc: 'The output is a CSV file if you do not specify api format')
optional(:use_deprecated_csv_headers, type: Boolean, desc: 'Forces API to ignore provided language to return old CSV headers')
optional(:allow_empty_result, type: Boolean, desc: 'Allow no solution from the solver used')
end

Expand Down
6 changes: 5 additions & 1 deletion api/v01/entities/vrp_result.rb
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,14 @@ class VrpResultSolutionRouteActivities < Grape::Entity
expose :type, documentation: { type: String, desc: 'depot, rest, service, pickup or delivery' }
expose :current_distance, documentation: { type: Integer, desc: 'Travel distance from route start to current point (in m)' }
expose :alternative, documentation: { type: Integer, desc: 'When one service has alternative activities, index of the chosen one' }
expose :visit_index, documentation: { type: Integer, desc: 'Index of the visit' }
end

class VrpResultSolutionRoute < Grape::Entity
expose :vehicle_id, documentation: { type: String, desc: 'Internal reference of the vehicule used for the current route' }
expose :day, documentation: { type: [Integer, Date],
desc: 'Day index or date (if provided within schedule) where route takes place' }
expose :vehicle_id, documentation: { type: String,
desc: 'Internal reference of vehicule corresponding to this route' }
expose :activities, using: VrpResultSolutionRouteActivities, documentation: { is_array: true, desc: 'Every step of the route' }
expose :total_travel_time, documentation: { type: Integer, desc: 'Sum of every travel time within the route (in s)' }
expose :total_distance, documentation: { type: Integer, desc: 'Sum of every distance within the route (in m)' }
Expand Down
6 changes: 3 additions & 3 deletions api/v01/vrp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ class Vrp < APIBase
elsif ret.is_a?(Hash)
status 200
if vrp.restitution_csv
present(OptimizerWrapper.build_csv([ret]), type: CSV)
present(OutputHelper::Result.build_csv([ret]), type: CSV)
else
present({ solutions: [ret], job: { status: :completed }}, with: VrpResult)
end
Expand Down Expand Up @@ -172,7 +172,7 @@ class Vrp < APIBase
end

if output_format == :csv && (job.nil? || job.completed?) # At this step, if the job is nil then it has already been retrieved into the result store
present(OptimizerWrapper.build_csv(solution[:result]), type: CSV)
present(OutputHelper::Result.build_csv(solution[:result]), type: CSV)
else
present({
solutions: solution[:result],
Expand Down Expand Up @@ -226,7 +226,7 @@ class Vrp < APIBase
if solution && !solution.empty?
output_format = params[:format]&.to_sym || (solution[:configuration] && solution[:configuration][:csv] ? :csv : env['api.format'])
if output_format == :csv
present(OptimizerWrapper.build_csv(solution[:result]), type: CSV)
present(OutputHelper::Result.build_csv(solution[:result]), type: CSV)
else
present({
solutions: [solution[:result]],
Expand Down
3 changes: 0 additions & 3 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,6 @@ module OptimizerWrapper
OptimizerLogger.with_datetime = true
OptimizerLogger.caller_location = :relative

I18n.available_locales = [:en, :fr]
I18n.default_locale = :en

@@c = {
product_title: 'Optimizers API',
product_contact_email: '[email protected]',
Expand Down
3 changes: 0 additions & 3 deletions config/environments/production.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,6 @@ module OptimizerWrapper
OptimizerLogger.with_datetime = true
# OptimizerLogger.caller_location = nil => nil is default

I18n.available_locales = [:en, :fr]
I18n.default_locale = :en

@@c = {
product_title: 'Optimizers API',
product_contact_email: '[email protected]',
Expand Down
3 changes: 0 additions & 3 deletions config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,6 @@ module OptimizerWrapper
OptimizerLogger.with_datetime = true
# OptimizerLogger.caller_location = nil => nil is default

I18n.available_locales = [:en, :fr]
I18n.default_locale = :en

@@c = {
product_title: 'Optimizers API',
product_contact_email: '[email protected]',
Expand Down
2 changes: 2 additions & 0 deletions config/initializers/i18n.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
I18n.load_path += Dir['lib/grape/locale/*.yml']
I18n::Backend::Simple.include(I18n::Backend::Fallbacks)
I18n.enforce_available_locales = false
I18n.available_locales = [:en, :fr, :es, :legacy]
I18n.default_locale = :en
34 changes: 34 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,37 @@
#

en:
export_file:
comment: comment
plan:
name: plan
ref: reference plan
route:
day: day
id: route
original_id: vehicle
total_travel_distance: total travel distance
total_travel_time: total travel time
total_wait_time: total waiting time
stop:
additional_value: additional_value
duration: visit duration
end_time: end time
lat: lat
lon: lng
name: name
point_id: reference
quantity: "quantity[%{unit}]"
reference: reference visit
setup: duration per destination
skills: tags visit
start_time: time
tw_end: "time window end %{index}"
tw_start: "time window start %{index}"
type: stop type
type_rest: rest
type_store: store
type_visit: visit
visit_index: visit index
wait_time: waiting time
tags: tags
53 changes: 53 additions & 0 deletions config/locales/es.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright © Mapotempo, 2021
#
# This file is part of Mapotempo.
#
# Mapotempo is free software. You can redistribute it and/or
# modify since you respect the terms of the GNU Affero General
# Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
#
# Mapotempo is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the Licenses for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Mapotempo. If not, see:
# <http://www.gnu.org/licenses/agpl.html>
#

es:
export_file:
comment: comentario
plan:
name: plan
ref: referencia del plan
route:
day: día
id: gira
original_id: vehículo
total_travel_distance: recorrido total
total_travel_time: duración total
total_wait_time: tiempo de espera total
stop:
additional_value: valor adicional
duration: duración visita
end_time: fin
lat: lat
lon: lng
name: nombre
point_id: referencia
quantity: "cantidad[%{unit}]"
reference: referencia visita
setup: duración de preparación
skills: etiquetas visita
start_time: hora
tw_end: "horario fin %{index}"
tw_start: "horario inicio %{index}"
type: tipo parada
type_rest: descanso
type_store: depósito
type_visit: visita
visit_index: índice de la visita
wait_time: tiempo de espera
tags: etiquetas
34 changes: 34 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,37 @@
#

fr:
export_file:
comment: commentaire
plan:
name: plan
ref: référence plan
route:
day: jour
id: tournée
original_id: véhicule
total_travel_distance: distance totale
total_travel_time: temps de trajet total
total_wait_time: temps d'attente total
stop:
additional_value: valeur additionnelle
duration: durée visite
end_time: fin de la mission
lat: lat
lon: lng
name: nom
point_id: référence
quantity: "quantité[%{unit}]"
reference: référence visite
setup: durée client
skills: libellés visite
start_time: heure
tw_end: "horaire fin %{index}"
tw_start: "horaire début %{index}"
type: type arrêt
type_rest: pause
type_store: dépôt
type_visit: visite
visit_index: indice de la visite
wait_time: attente
tags: libellés
53 changes: 53 additions & 0 deletions config/locales/legacy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# Copyright © Mapotempo, 2021
#
# This file is part of Mapotempo.
#
# Mapotempo is free software. You can redistribute it and/or
# modify since you respect the terms of the GNU Affero General
# Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
#
# Mapotempo is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the Licenses for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with Mapotempo. If not, see:
# <http://www.gnu.org/licenses/agpl.html>
#

legacy:
export_file:
comment: unassigned_reason
plan:
name: day_week_num
ref: day_week
route:
day: day
id: vehicle_id
original_id: original_vehicle_id
total_travel_distance: total_travel_distance
total_travel_time: total_travel_time
total_wait_time: total_waiting_time
stop:
additional_value: additional_value
duration: duration
end_time: end_time
lat: lat
lon: lon
name: original_id
point_id: point_id
quantity: "quantity_%{unit}"
reference: id
setup: setup_duration
skills: skills
start_time: begin_time
tw_end: "timewindow_end_%{index}"
tw_start: "timewindow_start_%{index}"
type: type
type_rest: rest
type_store: store
type_visit: visit
visit_index: visit_index
wait_time: waiting_time
tags: tags
26 changes: 14 additions & 12 deletions lib/helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,21 @@ def self.euclidean_distance(loc_a, loc_b)

def self.merge_results(results, merge_unassigned = true)
results.flatten!
results.compact!
{
solvers: results.flat_map{ |r| r && r[:solvers] }.compact,
cost: results.map{ |r| r && r[:cost] }.compact.reduce(&:+),
cost_details: results.map{ |r| r && r[:cost_details] }.compact.sum,
iterations: (results.size != 1) ? nil : results[0] && results[0][:iterations],
heuristic_synthesis: (results.size != 1) ? nil : results[0] && results[0][:heuristic_synthesis],
routes: results.flat_map{ |r| r && r[:routes] }.compact.uniq,
unassigned: merge_unassigned ? results.flat_map{ |r| r && r[:unassigned] }.compact.uniq : results.map{ |r| r && r[:unassigned] }.compact.last,
elapsed: results.map{ |r| r && r[:elapsed] || 0 }.reduce(&:+),
total_time: results.map{ |r| r && r[:total_time] }.compact.reduce(&:+),
total_travel_time: results.map{ |r| r && r[:total_travel_time] }.compact.reduce(&:+),
total_value: results.map{ |r| r && r[:total_travel_value] }.compact.reduce(&:+),
total_distance: results.map{ |r| r && r[:total_distance] }.compact.reduce(&:+)
solvers: results.flat_map{ |r| r[:solvers] }.compact,
cost: results.map{ |r| r[:cost] }.compact.reduce(&:+),
cost_details: results.map{ |r| r[:cost_details] }.compact.sum,
iterations: results.size != 1 ? nil : results[0][:iterations],
heuristic_synthesis: results.size != 1 ? nil : results[0][:heuristic_synthesis],
routes: results.flat_map{ |r| r[:routes] }.compact.uniq,
unassigned: merge_unassigned ? results.flat_map{ |r| r[:unassigned] }.compact.uniq : results.map{ |r| r[:unassigned] }.compact.last,
elapsed: results.map{ |r| r[:elapsed] || 0 }.reduce(&:+),
total_time: results.map{ |r| r[:total_time] }.compact.reduce(&:+),
total_travel_time: results.map{ |r| r[:total_travel_time] }.compact.reduce(&:+),
total_value: results.map{ |r| r[:total_travel_value] }.compact.reduce(&:+),
total_distance: results.map{ |r| r[:total_distance] }.compact.reduce(&:+),
use_deprecated_csv_headers: results.any?{ |r| r[:use_deprecated_csv_headers] },
}
end

Expand Down
2 changes: 1 addition & 1 deletion lib/heuristics/scheduling_heuristic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

require './lib/helper.rb'
require './wrappers/wrapper.rb'
require './lib/output_helper.rb'
require './lib/heuristics/concerns/scheduling_data_initialisation'
require './lib/heuristics/concerns/scheduling_end_phase'

Expand Down Expand Up @@ -1260,6 +1259,7 @@ def construct_sub_vrp(vrp, vehicle, current_route)

# configuration
route_vrp.schedule_range_indices = nil
route_vrp.schedule_start_date = nil

route_vrp.resolution_minimum_duration = 100
route_vrp.resolution_time_out_multiplier = 5
Expand Down
1 change: 0 additions & 1 deletion lib/interpreters/split_clustering.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
require './lib/clusterers/average_tree_linkage.rb'
require './lib/helper.rb'
require './lib/interpreters/periodic_visits.rb'
require './lib/output_helper.rb'

module Interpreters
class SplitClustering
Expand Down
Loading

0 comments on commit e4e171d

Please sign in to comment.