Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CSV output columns consistent with provided language [former PR32] #196

Merged
merged 5 commits into from
Jun 23, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

### Added

- 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)
fonsecadeline marked this conversation as resolved.
Show resolved Hide resolved

### 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: 'tech@mapotempo.com',
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: 'tech@mapotempo.com',
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: 'tech@mapotempo.com',
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 @@ -1210,6 +1209,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