@@ -4,9 +4,11 @@ import {
4
4
type TrainScheduleResult ,
5
5
} from 'common/api/osrdEditoastApi' ;
6
6
import type { AppDispatch } from 'store' ;
7
+ import { formatToIsoDate } from 'utils/date' ;
8
+ import { calculateTimeDifferenceInSeconds , formatDurationAsISO8601 } from 'utils/timeManipulation' ;
7
9
8
10
import nodeStore from './nodeStore' ;
9
- import type { NetzgrafikDto , NGEEvent , TrainrunSection , Node , Trainrun } from './types' ;
11
+ import type { NetzgrafikDto , NGEEvent , TrainrunSection , Node , TimeLock , Trainrun } from './types' ;
10
12
11
13
const createdTrainrun = new Map < number , number > ( ) ;
12
14
@@ -16,14 +18,9 @@ const getTrainrunSectionsByTrainrunId = (trainrunSections: TrainrunSection[], tr
16
18
const getNodeById = ( nodes : Node [ ] , nodeId : number | string ) =>
17
19
nodes . find ( ( node ) => node . id === nodeId ) ;
18
20
19
- // TODO: add a dynamic values when available
20
- const DEFAULT_PAYLOAD : Pick <
21
- TrainScheduleBase ,
22
- 'constraint_distribution' | 'rolling_stock_name' | 'start_time'
23
- > = {
21
+ const DEFAULT_PAYLOAD : Pick < TrainScheduleBase , 'constraint_distribution' | 'rolling_stock_name' > = {
24
22
constraint_distribution : 'STANDARD' ,
25
23
rolling_stock_name : '' ,
26
- start_time : '2024-07-15T08:00:00+02:00' ,
27
24
} ;
28
25
29
26
const createPathItemFromNode = ( node : Node , index : number ) => {
@@ -35,10 +32,24 @@ const createPathItemFromNode = (node: Node, index: number) => {
35
32
} ;
36
33
} ;
37
34
35
+ const getTimeLockDate = (
36
+ timeLock : TimeLock ,
37
+ startTimeLock : TimeLock ,
38
+ startDate : Date
39
+ ) : Date | null => {
40
+ if ( timeLock . time === null ) return null ;
41
+ const offset = timeLock . consecutiveTime ! - startTimeLock . consecutiveTime ! ;
42
+ return new Date ( startDate . getTime ( ) + offset * 60 * 1000 ) ;
43
+ } ;
44
+
45
+ const formatDateDifference = ( start : Date , stop : Date ) =>
46
+ formatDurationAsISO8601 ( calculateTimeDifferenceInSeconds ( start , stop ) ) ;
47
+
38
48
const createTrainSchedulePayload = (
39
49
trainrunSections : TrainrunSection [ ] ,
40
50
nodes : Node [ ] ,
41
- trainrun : Trainrun
51
+ trainrun : Trainrun ,
52
+ oldStartDate : Date
42
53
) => {
43
54
// TODO: check that the trainrunSections format is still compatible
44
55
const path = trainrunSections . flatMap ( ( section , index ) => {
@@ -47,15 +58,52 @@ const createTrainSchedulePayload = (
47
58
if ( ! sourceNode || ! targetNode ) return [ ] ;
48
59
const originPathItem = createPathItemFromNode ( sourceNode , index ) ;
49
60
if ( index === trainrunSections . length - 1 ) {
50
- const destinationPathItem = createPathItemFromNode ( targetNode , index ) ;
61
+ const destinationPathItem = createPathItemFromNode ( targetNode , index + 1 ) ;
51
62
return [ originPathItem , destinationPathItem ] ;
52
63
}
53
64
return [ originPathItem ] ;
54
65
} ) ;
55
66
67
+ // The departure time of the first section is guaranteed to be non-null
68
+ const startTimeLock = trainrunSections [ 0 ] . sourceDeparture ;
69
+ const startDate = new Date ( oldStartDate ) ;
70
+ startDate . setMinutes ( startTimeLock . time ! , 0 , 0 ) ;
71
+
72
+ const schedule = trainrunSections . flatMap ( ( section , index ) => {
73
+ const nextSection = trainrunSections [ index + 1 ] ;
74
+
75
+ // TODO: extract isNonStopTransit from transitions
76
+ let arrival = getTimeLockDate ( section . targetArrival , startTimeLock , startDate ) ;
77
+ const departure = nextSection
78
+ ? getTimeLockDate ( nextSection . sourceDeparture , startTimeLock , startDate )
79
+ : null ;
80
+ if ( ! arrival && ! departure ) {
81
+ return [ ] ;
82
+ }
83
+
84
+ // If missing arrival time, default to a zero stop duration
85
+ arrival = arrival || departure ! ;
86
+
87
+ let stopFor = null ;
88
+ if ( departure ) {
89
+ stopFor = formatDateDifference ( departure , arrival ) ;
90
+ } else if ( ! nextSection ) {
91
+ // Arrival needs to explicitly stop the train
92
+ stopFor = formatDurationAsISO8601 ( 0 ) ;
93
+ }
94
+
95
+ return {
96
+ at : `${ section . targetNodeId } -${ index + 1 } ` ,
97
+ arrival : formatDateDifference ( arrival , startDate ) ,
98
+ stop_for : stopFor ,
99
+ } ;
100
+ } ) ;
101
+
56
102
return {
57
- path,
58
103
train_name : trainrun . name ,
104
+ start_time : formatToIsoDate ( startDate ) ,
105
+ path,
106
+ schedule,
59
107
} ;
60
108
} ;
61
109
@@ -83,13 +131,19 @@ const handleTrainrunOperation = async ({
83
131
) ;
84
132
switch ( type ) {
85
133
case 'create' : {
134
+ const startDate = new Date ( ) ;
86
135
const newTrainSchedules = await dispatch (
87
136
osrdEditoastApi . endpoints . postV2TimetableByIdTrainSchedule . initiate ( {
88
137
id : timeTableId ,
89
138
body : [
90
139
{
91
140
...DEFAULT_PAYLOAD ,
92
- ...createTrainSchedulePayload ( trainrunSectionsByTrainrunId , nodes , trainrun ) ,
141
+ ...createTrainSchedulePayload (
142
+ trainrunSectionsByTrainrunId ,
143
+ nodes ,
144
+ trainrun ,
145
+ startDate
146
+ ) ,
93
147
} ,
94
148
] ,
95
149
} )
@@ -116,14 +170,15 @@ const handleTrainrunOperation = async ({
116
170
id : trainrunIdToUpdate ,
117
171
} )
118
172
) . unwrap ( ) ;
173
+ const startDate = new Date ( trainSchedule . start_time ) ;
119
174
const newTrainSchedule = await dispatch (
120
175
osrdEditoastApi . endpoints . putV2TrainScheduleById . initiate ( {
121
176
id : trainrunIdToUpdate ,
122
177
trainScheduleForm : {
123
178
...trainSchedule ,
124
- ...createTrainSchedulePayload ( trainrunSectionsByTrainrunId , nodes , trainrun ) ,
125
- // TODO: convert NGE times to OSRD schedule
126
- schedule : [ ] ,
179
+ ...createTrainSchedulePayload ( trainrunSectionsByTrainrunId , nodes , trainrun , startDate ) ,
180
+ // Reset margins because they contain references to path items
181
+ margins : undefined ,
127
182
} ,
128
183
} )
129
184
) . unwrap ( ) ;
0 commit comments