@@ -15,6 +15,7 @@ use core_client::signal_projection::SignalUpdate;
1515use core_client:: simulation:: PhysicsConsist ;
1616use database:: DbConnectionPoolV2 ;
1717use editoast_derive:: EditoastError ;
18+ use editoast_models:: TrainScheduleException ;
1819use editoast_models:: prelude:: * ;
1920use editoast_models:: round_trips:: TrainScheduleRoundTrips ;
2021use itertools:: Itertools ;
@@ -401,6 +402,12 @@ pub(in crate::views) struct ExceptionQueryParam {
401402 exception_key : Option < String > ,
402403}
403404
405+ #[ derive( Debug , Default , Clone , Serialize , Deserialize , IntoParams , ToSchema ) ]
406+ #[ into_params( parameter_in = Query ) ]
407+ pub ( in crate :: views) struct TrainScheduleExceptionQueryParam {
408+ exception_id : Option < i64 > ,
409+ }
410+
404411/// Get a path from a paced train given an infrastructure id and a paced train id
405412#[ editoast_derive:: route]
406413#[ utoipa:: path(
@@ -516,7 +523,9 @@ pub(in crate::views) async fn simulation(
516523 Query ( ElectricalProfileSetIdQueryParam {
517524 electrical_profile_set_id,
518525 } ) : Query < ElectricalProfileSetIdQueryParam > ,
519- Query ( ExceptionQueryParam { exception_key } ) : Query < ExceptionQueryParam > ,
526+ Query ( TrainScheduleExceptionQueryParam { exception_id } ) : Query <
527+ TrainScheduleExceptionQueryParam ,
528+ > ,
520529) -> Result < Json < simulation:: Response > > {
521530 let authorized = auth
522531 . check_roles ( [ authz:: Role :: OperationalStudies ] . into ( ) )
@@ -547,17 +556,20 @@ pub(in crate::views) async fn simulation(
547556 } )
548557 . await ?;
549558
550- let train_schedule = match exception_key {
551- Some ( exception_key) => {
552- let exception = train_schedule
553- . exceptions
554- . iter ( )
555- . find ( |e| e. key == exception_key)
556- . ok_or_else ( || TrainScheduleError :: ExceptionNotFound {
557- exception_key : exception_key. clone ( ) ,
558- } ) ?;
559-
560- train_schedule. apply_exception ( exception)
559+ let train_schedule = match exception_id {
560+ Some ( exception_id) => {
561+ let exception = TrainScheduleException :: retrieve_or_fail (
562+ db_pool. get ( ) . await ?,
563+ exception_id,
564+ || {
565+ TrainScheduleError :: ExceptionNotFound {
566+ // TODO rename to exception_id
567+ exception_key : exception_id. to_string ( ) ,
568+ }
569+ } ,
570+ )
571+ . await ?;
572+ train_schedule. apply_train_schedule_exception ( & exception. into ( ) )
561573 }
562574 None => train_schedule. into_train_occurrence ( ) ,
563575 } ;
@@ -1548,6 +1560,7 @@ mod tests {
15481560 use core_client:: simulation:: ReportTrain ;
15491561 use core_client:: simulation:: SpeedLimitProperties ;
15501562 use database:: DbConnectionPoolV2 ;
1563+ use editoast_models:: TrainScheduleException ;
15511564 use editoast_models:: prelude:: * ;
15521565 use editoast_models:: rolling_stock:: TrainMainCategory ;
15531566 use pretty_assertions:: assert_eq;
@@ -1579,6 +1592,8 @@ mod tests {
15791592 use crate :: models:: fixtures:: create_paced_train_with_exceptions;
15801593 use crate :: models:: fixtures:: create_simple_paced_train;
15811594 use crate :: models:: fixtures:: create_small_infra;
1595+ use crate :: models:: fixtures:: create_timetable_with_train_schedule_set;
1596+ use crate :: models:: fixtures:: create_train_schedule_exception;
15821597 use crate :: models:: fixtures:: create_train_schedule_set;
15831598 use crate :: models:: fixtures:: simple_paced_train_base;
15841599 use crate :: models:: fixtures:: simple_paced_train_changeset;
@@ -1884,12 +1899,16 @@ mod tests {
18841899 assert_eq ! ( response. train_schedule, paced_train. into( ) ) ;
18851900 }
18861901
1887- async fn app_infra_id_paced_train_id_for_simulation_tests ( ) -> ( TestApp , i64 , i64 ) {
1902+ async fn app_infra_id_paced_train_id_for_simulation_tests ( )
1903+ -> ( TestApp , i64 , i64 , TrainScheduleException ) {
18881904 let db_pool = DbConnectionPoolV2 :: for_tests ( ) ;
18891905 let small_infra = create_small_infra ( & mut db_pool. get_ok ( ) ) . await ;
1890- let train_schedule_set = create_train_schedule_set ( & mut db_pool. get_ok ( ) ) . await ;
18911906 let rolling_stock =
18921907 create_fast_rolling_stock ( & mut db_pool. get_ok ( ) , "simulation_rolling_stock" ) . await ;
1908+ let ( timetable, train_schedule_set) =
1909+ create_timetable_with_train_schedule_set ( & mut db_pool. get_ok ( ) ) . await ;
1910+ let exception = create_created_exception_with_change_groups ( "created_exception_key" ) ;
1911+
18931912 let paced_train_base = TrainSchedule {
18941913 train_occurrence : TrainOccurrence {
18951914 rolling_stock_name : rolling_stock. name . clone ( ) ,
@@ -1898,9 +1917,7 @@ mod tests {
18981917 paced : Some ( Paced {
18991918 time_window : Duration :: hours ( 1 ) . try_into ( ) . unwrap ( ) ,
19001919 interval : Duration :: minutes ( 15 ) . try_into ( ) . unwrap ( ) ,
1901- exceptions : vec ! [ create_created_exception_with_change_groups(
1902- "created_exception_key" ,
1903- ) ] ,
1920+ exceptions : vec ! [ ] ,
19041921 } ) ,
19051922 } ;
19061923 let paced_train: TrainScheduleChangeset = paced_train_base. into ( ) ;
@@ -1909,17 +1926,28 @@ mod tests {
19091926 . create ( & mut db_pool. get_ok ( ) )
19101927 . await
19111928 . expect ( "Failed to create paced train" ) ;
1929+
1930+ let exception = create_train_schedule_exception (
1931+ & mut db_pool. get_ok ( ) ,
1932+ timetable. id ,
1933+ paced_train. id ,
1934+ None ,
1935+ Some ( "created_exception_key" . to_string ( ) ) ,
1936+ Some ( exception. change_groups ) ,
1937+ )
1938+ . await ;
1939+
19121940 let core = mocked_core_pathfinding_sim_and_proj ( ) ;
19131941 let app = TestAppBuilder :: new ( )
19141942 . db_pool ( db_pool)
19151943 . core_client ( core. into ( ) )
19161944 . build ( ) ;
1917- ( app, small_infra. id , paced_train. id )
1945+ ( app, small_infra. id , paced_train. id , exception )
19181946 }
19191947
19201948 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
19211949 async fn paced_train_simulation ( ) {
1922- let ( app, infra_id, train_schedule_id) =
1950+ let ( app, infra_id, train_schedule_id, _exception ) =
19231951 app_infra_id_paced_train_id_for_simulation_tests ( ) . await ;
19241952 let request = app. get (
19251953 format ! ( "/train_schedules/{train_schedule_id}/simulation/?infra_id={infra_id}" )
@@ -1936,11 +1964,11 @@ mod tests {
19361964
19371965 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
19381966 async fn paced_train_exception_simulation_with_invalid_exception_key ( ) {
1939- let ( app, infra_id, train_schedule_id) =
1967+ let ( app, infra_id, train_schedule_id, _exception ) =
19401968 app_infra_id_paced_train_id_for_simulation_tests ( ) . await ;
19411969 let request = app. get (
19421970 format ! (
1943- "/train_schedules/{train_schedule_id}/simulation/?infra_id={infra_id}&exception_key=toto "
1971+ "/train_schedules/{train_schedule_id}/simulation/?infra_id={infra_id}&exception_id=9999 "
19441972 )
19451973 . as_str ( ) ,
19461974 ) ;
@@ -1958,10 +1986,14 @@ mod tests {
19581986
19591987 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
19601988 async fn paced_train_exception_simulation ( ) {
1961- let ( app, infra_id, train_schedule_id) =
1989+ let ( app, infra_id, train_schedule_id, exception ) =
19621990 app_infra_id_paced_train_id_for_simulation_tests ( ) . await ;
19631991 let request = app. get (
1964- format ! ( "/train_schedules/{train_schedule_id}/simulation/?infra_id={infra_id}&exception_key=created_exception_key" ) . as_str ( ) ,
1992+ format ! (
1993+ "/train_schedules/{train_schedule_id}/simulation/?infra_id={infra_id}&exception_id={}" ,
1994+ exception. id
1995+ )
1996+ . as_str ( ) ,
19651997 ) ;
19661998 let response: simulation:: Response = app
19671999 . fetch ( request)
@@ -2014,34 +2046,28 @@ mod tests {
20142046 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
20152047 async fn paced_train_exception_simulation_with_rolling_stock_not_found ( ) {
20162048 // GIVEN
2017- let ( app, infra_id, train_schedule_id) =
2049+ let ( app, infra_id, train_schedule_id, exception ) =
20182050 app_infra_id_paced_train_id_for_simulation_tests ( ) . await ;
2019- let request = app. get ( format ! ( "/train_schedules/{train_schedule_id}" ) . as_str ( ) ) ;
2020- let mut paced_train_response: TrainScheduleResponse = app
2021- . fetch ( request)
2022- . await
2023- . assert_status ( StatusCode :: OK )
2024- . json_into ( ) ;
2025- paced_train_response
2026- . train_schedule
2027- . paced
2028- . as_mut ( )
2029- . unwrap ( )
2030- . exceptions [ 0 ]
2031- . change_groups
2032- . rolling_stock = Some ( RollingStockChangeGroup {
2051+
2052+ let mut change_groupe = exception. change_groups ;
2053+ change_groupe. rolling_stock = Some ( RollingStockChangeGroup {
20332054 rolling_stock_name : "R2D2" . into ( ) ,
20342055 comfort : Comfort :: AirConditioning ,
20352056 } ) ;
2036- let request = app
2037- . put ( format ! ( "/train_schedules/{train_schedule_id}" ) . as_str ( ) )
2038- . json ( & json ! ( paced_train_response. train_schedule) ) ;
2039- app. fetch ( request)
2057+ let exception = editoast_models:: TrainScheduleException :: changeset ( )
2058+ . change_groups ( change_groupe)
2059+ . update ( & mut app. db_pool ( ) . get_ok ( ) , train_schedule_id)
20402060 . await
2041- . assert_status ( StatusCode :: NO_CONTENT ) ;
2061+ . expect ( "Fail to update exception" )
2062+ . expect ( "Fail to update exception" ) ;
2063+
20422064 // WHEN
20432065 let request = app. get (
2044- format ! ( "/train_schedules/{train_schedule_id}/simulation/?infra_id={infra_id}&exception_key=created_exception_key" ) . as_str ( ) ,
2066+ format ! (
2067+ "/train_schedules/{train_schedule_id}/simulation/?infra_id={infra_id}&exception_id={}" ,
2068+ exception. id
2069+ )
2070+ . as_str ( ) ,
20452071 ) ;
20462072 let response: simulation:: Response = app
20472073 . fetch ( request)
@@ -2064,7 +2090,7 @@ mod tests {
20642090
20652091 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
20662092 async fn paced_train_simulation_not_found ( ) {
2067- let ( app, infra_id, _paced_train_id) =
2093+ let ( app, infra_id, _paced_train_id, _exception ) =
20682094 app_infra_id_paced_train_id_for_simulation_tests ( ) . await ;
20692095 let request =
20702096 app. get ( format ! ( "/train_schedules/{}/simulation/?infra_id={}" , 0 , infra_id) . as_str ( ) ) ;
@@ -2080,7 +2106,7 @@ mod tests {
20802106
20812107 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
20822108 async fn paced_train_simulation_summary ( ) {
2083- let ( app, infra_id, paced_train_id) =
2109+ let ( app, infra_id, paced_train_id, _exception ) =
20842110 app_infra_id_paced_train_id_for_simulation_tests ( ) . await ;
20852111 let request = app. get ( format ! ( "/train_schedules/{paced_train_id}" ) . as_str ( ) ) ;
20862112 let mut paced_train_response: TrainScheduleResponse = app
@@ -2184,7 +2210,7 @@ mod tests {
21842210
21852211 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
21862212 async fn paced_train_simulation_summary_not_found ( ) {
2187- let ( app, infra_id, _paced_train_id) =
2213+ let ( app, infra_id, _paced_train_id, _exception ) =
21882214 app_infra_id_paced_train_id_for_simulation_tests ( ) . await ;
21892215 let request = app
21902216 . post ( "/train_schedules/simulation_summary" )
@@ -2478,8 +2504,8 @@ mod tests {
24782504 }
24792505
24802506 #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
2481- async fn train_schedule_occupancy_blocks ( ) {
2482- let ( app, infra_id, paced_train_id) =
2507+ async fn paced_train_occupancy_blocks ( ) {
2508+ let ( app, infra_id, paced_train_id, _exception ) =
24832509 app_infra_id_paced_train_id_for_simulation_tests ( ) . await ;
24842510
24852511 let request = app. get ( format ! ( "/train_schedules/{paced_train_id}" ) . as_str ( ) ) ;
0 commit comments