@@ -41,7 +41,8 @@ use editoast_models::timetable::Timetable;
4141use editoast_models:: timetable:: TimetableWithTrains ;
4242use itertools:: Itertools ;
4343use itertools:: izip;
44- use paced_train:: TrainScheduleResponse ;
44+ use schemas:: paced_train:: Paced ;
45+ use schemas:: paced_train:: TrainSchedule ;
4546use schemas:: rolling_stock:: EtcsBrakeParams ;
4647use schemas:: rolling_stock:: RollingResistance ;
4748use schemas:: rolling_stock:: RollingStock ;
@@ -68,6 +69,7 @@ use crate::models::train_schedule::OccurrenceId;
6869use crate :: models:: train_schedule_set:: TrainScheduleSet ;
6970use crate :: views:: AuthenticationExt ;
7071use crate :: views:: AuthorizationError ;
72+ use crate :: views:: timetable:: paced_train:: TrainScheduleResponse ;
7173use crate :: views:: timetable:: simulation:: SimulationResponseSuccess ;
7274
7375#[ derive( Debug , Error , EditoastError , derive_more:: From ) ]
@@ -226,7 +228,50 @@ pub(in crate::views) async fn get_train_schedules(
226228
227229 let ( paced_trains, stats) = models:: TrainSchedule :: list_paginated ( conn, settings) . await ?;
228230
229- let results = paced_trains. into_iter ( ) . map_into ( ) . collect ( ) ;
231+ let paced_trains_ids = paced_trains. iter ( ) . map ( |t| t. id ) . collect :: < Vec < _ > > ( ) ;
232+ let exceptions_settings = SelectionSettings :: new ( )
233+ . filter ( move || editoast_models:: TrainScheduleException :: TIMETABLE_ID . eq ( timetable_id) )
234+ . filter ( move || {
235+ editoast_models:: TrainScheduleException :: TRAIN_SCHEDULE_ID
236+ . eq_any ( paced_trains_ids. clone ( ) )
237+ } ) ;
238+
239+ let mut exceptions = editoast_models:: TrainScheduleException :: list ( conn, exceptions_settings)
240+ . await ?
241+ . into_iter ( )
242+ . into_group_map_by ( |e| e. train_schedule_id ) ;
243+
244+ let results: Vec < TrainScheduleResponse > = paced_trains
245+ . into_iter ( )
246+ . map ( |ts| {
247+ let id = ts. id ;
248+ let train_schedule_set_id = ts. train_schedule_set_id ;
249+
250+ let paced = if let ( Some ( interval) , Some ( time_window) ) = ( ts. interval , ts. time_window ) {
251+ Some ( Paced {
252+ interval : interval. try_into ( ) . unwrap ( ) ,
253+ time_window : time_window. try_into ( ) . unwrap ( ) ,
254+ exceptions : exceptions
255+ . remove ( & id)
256+ . unwrap_or_default ( )
257+ . into_iter ( )
258+ . map_into ( )
259+ . collect ( ) ,
260+ } )
261+ } else {
262+ None
263+ } ;
264+
265+ TrainScheduleResponse {
266+ id,
267+ train_schedule_set_id,
268+ train_schedule : TrainSchedule {
269+ train_occurrence : ts. into_train_occurrence ( ) ,
270+ paced,
271+ } ,
272+ }
273+ } )
274+ . collect ( ) ;
230275
231276 Ok ( Json ( ListTrainSchedulesResponse { stats, results } ) )
232277}
@@ -922,6 +967,7 @@ mod tests {
922967 use crate :: error:: InternalError ;
923968 use crate :: models:: fixtures:: create_timetable;
924969 use crate :: models:: fixtures:: create_timetable_with_train_schedule_set;
970+ use crate :: models:: fixtures:: create_train_schedule_exception;
925971 use crate :: models:: fixtures:: create_train_schedule_set;
926972 use crate :: models:: fixtures:: simple_paced_train_base;
927973 use crate :: models:: train_schedule:: TrainScheduleChangeset ;
@@ -984,38 +1030,97 @@ mod tests {
9841030 let app = TestAppBuilder :: default_app ( ) ;
9851031 let pool = app. db_pool ( ) ;
9861032
987- let ( timetable, train_schedule_set) =
1033+ // Setup timetable 1 data
1034+ let ( timetable1, train_schedule_set1) =
9881035 create_timetable_with_train_schedule_set ( & mut pool. get_ok ( ) ) . await ;
9891036
990- let train_schedule_1 = simple_paced_train_base ( ) ;
991- let mut train_schedule_2 = simple_paced_train_base ( ) ;
992- train_schedule_2 . train_occurrence . start_time += Duration :: minutes ( 200 ) ;
993- train_schedule_2 . paced . as_mut ( ) . unwrap ( ) . time_window =
1037+ let train_schedule_t1_1 = simple_paced_train_base ( ) ;
1038+ let mut train_schedule_t1_2 = simple_paced_train_base ( ) ;
1039+ train_schedule_t1_2 . train_occurrence . start_time += Duration :: minutes ( 200 ) ;
1040+ train_schedule_t1_2 . paced . as_mut ( ) . unwrap ( ) . time_window =
9941041 Duration :: minutes ( 120 ) . try_into ( ) . unwrap ( ) ;
995- train_schedule_2 . paced . as_mut ( ) . unwrap ( ) . interval =
1042+ train_schedule_t1_2 . paced . as_mut ( ) . unwrap ( ) . interval =
9961043 Duration :: seconds ( 30 ) . try_into ( ) . unwrap ( ) ;
9971044
998- let train_schedules = vec ! [ train_schedule_1, train_schedule_2] ;
999-
1000- let changesets = train_schedules
1045+ let train_schedules_bases_t1 = vec ! [ train_schedule_t1_1, train_schedule_t1_2] ;
1046+ let train_schedules_changesets_t1 = train_schedules_bases_t1
10011047 . into_iter ( )
10021048 . map ( TrainScheduleChangeset :: from)
1003- . map ( |cs| cs. train_schedule_set_id ( train_schedule_set . id ) )
1049+ . map ( |cs| cs. train_schedule_set_id ( train_schedule_set1 . id ) )
10041050 . collect :: < Vec < _ > > ( ) ;
1005-
1006- let _train_schedules: Vec < _ > =
1007- models:: TrainSchedule :: create_batch ( & mut pool. get_ok ( ) , changesets)
1051+ let train_schedules_t1: Vec < _ > =
1052+ models:: TrainSchedule :: create_batch ( & mut pool. get_ok ( ) , train_schedules_changesets_t1)
10081053 . await
10091054 . expect ( "Failed to create train schedules" ) ;
1010-
1011- let request = app. get ( format ! ( "/timetable/{}/train_schedules" , timetable. id) . as_str ( ) ) ;
1055+ let train_schedule_exception_t1_1 = create_train_schedule_exception (
1056+ & mut pool. get_ok ( ) ,
1057+ timetable1. id ,
1058+ train_schedules_t1. first ( ) . unwrap ( ) . id ,
1059+ None ,
1060+ )
1061+ . await ;
1062+
1063+ let _train_schedule_exception_t1_2 = create_train_schedule_exception (
1064+ & mut pool. get_ok ( ) ,
1065+ timetable1. id ,
1066+ train_schedules_t1. get ( 1 ) . unwrap ( ) . id ,
1067+ None ,
1068+ )
1069+ . await ;
1070+
1071+ // Setup timetable 2 data
1072+ let ( timetable2, train_schedule_set2) =
1073+ create_timetable_with_train_schedule_set ( & mut pool. get_ok ( ) ) . await ;
1074+ let mut train_schedule_t2_1 = simple_paced_train_base ( ) ;
1075+ train_schedule_t2_1. train_occurrence . start_time += Duration :: minutes ( 200 ) ;
1076+ train_schedule_t2_1. paced . as_mut ( ) . unwrap ( ) . time_window =
1077+ Duration :: minutes ( 120 ) . try_into ( ) . unwrap ( ) ;
1078+ train_schedule_t2_1. paced . as_mut ( ) . unwrap ( ) . interval =
1079+ Duration :: seconds ( 30 ) . try_into ( ) . unwrap ( ) ;
1080+ let train_schedules_bases_t2 = vec ! [ train_schedule_t2_1] ;
1081+ let train_schedules_changesets_t2 = train_schedules_bases_t2
1082+ . into_iter ( )
1083+ . map ( TrainScheduleChangeset :: from)
1084+ . map ( |cs| cs. train_schedule_set_id ( train_schedule_set2. id ) )
1085+ . collect :: < Vec < _ > > ( ) ;
1086+ let train_schedules_t2: Vec < _ > =
1087+ models:: TrainSchedule :: create_batch ( & mut pool. get_ok ( ) , train_schedules_changesets_t2)
1088+ . await
1089+ . expect ( "Failed to create train schedules" ) ;
1090+ let _train_schedule_exception_t2_1 = create_train_schedule_exception (
1091+ & mut pool. get_ok ( ) ,
1092+ timetable2. id ,
1093+ train_schedules_t2. first ( ) . unwrap ( ) . id ,
1094+ None ,
1095+ )
1096+ . await ;
1097+
1098+ let request = app. get ( format ! ( "/timetable/{}/train_schedules" , timetable1. id) . as_str ( ) ) ;
10121099 let list: ListTrainSchedulesResponse = app
10131100 . fetch ( request)
10141101 . await
10151102 . assert_status ( StatusCode :: OK )
10161103 . json_into ( ) ;
10171104
1105+ // Check if the timetable has the two train schedules
10181106 assert_eq ! ( list. results. len( ) , 2 ) ;
1107+
1108+ // Check if the first train schedule containe only his own exception
1109+ assert_eq ! (
1110+ list. results
1111+ . first( )
1112+ . unwrap( )
1113+ . clone( )
1114+ . train_schedule
1115+ . paced
1116+ . unwrap( )
1117+ . exceptions
1118+ . first( )
1119+ . unwrap( )
1120+ . id
1121+ . unwrap( ) ,
1122+ train_schedule_exception_t1_1. id
1123+ )
10191124 }
10201125
10211126 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
0 commit comments