]> Piment Noir Git Repositories - e-mobility-charging-stations-simulator.git/blame - src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts
chore(deps-dev): apply updates
[e-mobility-charging-stations-simulator.git] / src / charging-station / ocpp / 1.6 / OCPP16ServiceUtils.ts
CommitLineData
a19b897d 1// Partial Copyright Jerome Benoit. 2021-2024. All Rights Reserved.
c8eeb62b 2
66a7748d 3import type { JSONSchemaType } from 'ajv'
0749233f 4
ef9e3b33
JB
5import {
6 addSeconds,
7 areIntervalsOverlapping,
8 differenceInSeconds,
4c3f6c20 9 type Interval,
ef9e3b33
JB
10 isAfter,
11 isBefore,
d1f5bfd8 12 isWithinInterval,
66a7748d 13} from 'date-fns'
130783a7 14
90aceaf6
JB
15import {
16 type ChargingStation,
17 hasFeatureProfile,
d1f5bfd8 18 hasReservationExpired,
66a7748d 19} from '../../../charging-station/index.js'
e7aeea18 20import {
563e40ce 21 type ConfigurationKey,
d19b10a8 22 type GenericResponse,
268a74bb 23 type JsonType,
d19b10a8 24 OCPP16AuthorizationStatus,
66a7748d 25 type OCPP16AvailabilityType,
366f75f6
JB
26 type OCPP16ChangeAvailabilityResponse,
27 OCPP16ChargePointStatus,
268a74bb 28 type OCPP16ChargingProfile,
ef9e3b33 29 type OCPP16ChargingSchedule,
41f3983a 30 type OCPP16ClearChargingProfileRequest,
268a74bb 31 type OCPP16IncomingRequestCommand,
27782dbc 32 type OCPP16MeterValue,
41f3983a
JB
33 OCPP16MeterValueContext,
34 OCPP16MeterValueUnit,
66a7748d 35 type OCPP16RequestCommand,
268a74bb 36 OCPP16StandardParametersKey,
d19b10a8 37 OCPP16StopTransactionReason,
268a74bb 38 type OCPP16SupportedFeatureProfiles,
d1f5bfd8 39 OCPPVersion,
66a7748d 40} from '../../../types/index.js'
95dab6cf 41import { convertToDate, isNotEmptyArray, logger, roundTo } from '../../../utils/index.js'
66a7748d 42import { OCPPServiceUtils } from '../OCPPServiceUtils.js'
4c3f6c20 43import { OCPP16Constants } from './OCPP16Constants.js'
6ed92bc1 44
7bc31f9c 45export class OCPP16ServiceUtils extends OCPPServiceUtils {
c4a89082
JB
46 public static buildTransactionBeginMeterValue (
47 chargingStation: ChargingStation,
48 connectorId: number,
49 meterStart: number | undefined
50 ): OCPP16MeterValue {
51 const meterValue: OCPP16MeterValue = {
52 sampledValue: [],
53 timestamp: new Date(),
54 }
55 // Energy.Active.Import.Register measurand (default)
56 const sampledValueTemplate = OCPP16ServiceUtils.getSampledValueTemplate(
57 chargingStation,
58 connectorId
59 )
60 const unitDivider =
61 sampledValueTemplate?.unit === OCPP16MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1
62 meterValue.sampledValue.push(
63 OCPP16ServiceUtils.buildSampledValue(
64 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
65 sampledValueTemplate!,
66 roundTo((meterStart ?? 0) / unitDivider, 4),
67 OCPP16MeterValueContext.TRANSACTION_BEGIN
68 )
69 )
70 return meterValue
71 }
72
73 public static buildTransactionDataMeterValues (
74 transactionBeginMeterValue: OCPP16MeterValue,
75 transactionEndMeterValue: OCPP16MeterValue
76 ): OCPP16MeterValue[] {
77 const meterValues: OCPP16MeterValue[] = []
78 meterValues.push(transactionBeginMeterValue)
79 meterValues.push(transactionEndMeterValue)
80 return meterValues
81 }
82
366f75f6
JB
83 public static changeAvailability = async (
84 chargingStation: ChargingStation,
225e32b0 85 connectorIds: number[],
366f75f6 86 chargePointStatus: OCPP16ChargePointStatus,
66a7748d 87 availabilityType: OCPP16AvailabilityType
366f75f6 88 ): Promise<OCPP16ChangeAvailabilityResponse> => {
66a7748d 89 const responses: OCPP16ChangeAvailabilityResponse[] = []
225e32b0
JB
90 for (const connectorId of connectorIds) {
91 let response: OCPP16ChangeAvailabilityResponse =
66a7748d
JB
92 OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
93 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
94 const connectorStatus = chargingStation.getConnectorStatus(connectorId)!
5199f9fd 95 if (connectorStatus.transactionStarted === true) {
66a7748d 96 response = OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED
225e32b0 97 }
66a7748d 98 connectorStatus.availability = availabilityType
225e32b0
JB
99 if (response === OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
100 await OCPP16ServiceUtils.sendAndSetConnectorStatus(
101 chargingStation,
102 connectorId,
66a7748d
JB
103 chargePointStatus
104 )
225e32b0 105 }
66a7748d 106 responses.push(response)
366f75f6 107 }
3b0ed034 108 if (responses.includes(OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED)) {
66a7748d 109 return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED
366f75f6 110 }
66a7748d
JB
111 return OCPP16Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED
112 }
366f75f6 113
c4a89082
JB
114 public static checkFeatureProfile (
115 chargingStation: ChargingStation,
116 featureProfile: OCPP16SupportedFeatureProfiles,
117 command: OCPP16IncomingRequestCommand | OCPP16RequestCommand
118 ): boolean {
119 if (hasFeatureProfile(chargingStation, featureProfile) === false) {
120 logger.warn(
121 `${chargingStation.logPrefix()} Trying to '${command}' without '${featureProfile}' feature enabled in ${
122 OCPP16StandardParametersKey.SupportedFeatureProfiles
123 } in configuration`
124 )
125 return false
126 }
127 return true
128 }
129
73d87be1
JB
130 public static clearChargingProfiles = (
131 chargingStation: ChargingStation,
41f3983a 132 commandPayload: OCPP16ClearChargingProfileRequest,
66a7748d 133 chargingProfiles: OCPP16ChargingProfile[] | undefined
73d87be1 134 ): boolean => {
0749233f 135 const { chargingProfilePurpose, id, stackLevel } = commandPayload
66a7748d 136 let clearedCP = false
73d87be1 137 if (isNotEmptyArray(chargingProfiles)) {
5dc7c990 138 chargingProfiles.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
66a7748d 139 let clearCurrentCP = false
0d1f33ba 140 if (chargingProfile.chargingProfileId === id) {
66a7748d 141 clearCurrentCP = true
73d87be1 142 }
66a7748d
JB
143 if (chargingProfilePurpose == null && chargingProfile.stackLevel === stackLevel) {
144 clearCurrentCP = true
73d87be1 145 }
66a7748d
JB
146 if (
147 stackLevel == null &&
148 chargingProfile.chargingProfilePurpose === chargingProfilePurpose
149 ) {
150 clearCurrentCP = true
73d87be1
JB
151 }
152 if (
0d1f33ba
JB
153 chargingProfile.stackLevel === stackLevel &&
154 chargingProfile.chargingProfilePurpose === chargingProfilePurpose
73d87be1 155 ) {
66a7748d 156 clearCurrentCP = true
73d87be1
JB
157 }
158 if (clearCurrentCP) {
66a7748d 159 chargingProfiles.splice(index, 1)
73d87be1
JB
160 logger.debug(
161 `${chargingStation.logPrefix()} Matching charging profile(s) cleared: %j`,
66a7748d
JB
162 chargingProfile
163 )
164 clearedCP = true
73d87be1 165 }
66a7748d 166 })
73d87be1 167 }
66a7748d
JB
168 return clearedCP
169 }
73d87be1 170
ef9e3b33 171 public static composeChargingSchedules = (
4abf6441
JB
172 chargingScheduleHigher: OCPP16ChargingSchedule | undefined,
173 chargingScheduleLower: OCPP16ChargingSchedule | undefined,
66a7748d 174 compositeInterval: Interval
ef9e3b33 175 ): OCPP16ChargingSchedule | undefined => {
66a7748d
JB
176 if (chargingScheduleHigher == null && chargingScheduleLower == null) {
177 return undefined
ef9e3b33 178 }
66a7748d
JB
179 if (chargingScheduleHigher != null && chargingScheduleLower == null) {
180 return OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleHigher, compositeInterval)
ef9e3b33 181 }
66a7748d
JB
182 if (chargingScheduleHigher == null && chargingScheduleLower != null) {
183 return OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleLower, compositeInterval)
ef9e3b33 184 }
4abf6441 185 const compositeChargingScheduleHigher: OCPP16ChargingSchedule | undefined =
66a7748d
JB
186 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
187 OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleHigher!, compositeInterval)
4abf6441 188 const compositeChargingScheduleLower: OCPP16ChargingSchedule | undefined =
66a7748d
JB
189 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
190 OCPP16ServiceUtils.composeChargingSchedule(chargingScheduleLower!, compositeInterval)
4abf6441 191 const compositeChargingScheduleHigherInterval: Interval = {
ef9e3b33 192 end: addSeconds(
66a7748d 193 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
4abf6441 194 compositeChargingScheduleHigher!.startSchedule!,
66a7748d
JB
195 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
196 compositeChargingScheduleHigher!.duration!
d1f5bfd8 197 ),
0749233f
JB
198 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
199 start: compositeChargingScheduleHigher!.startSchedule!,
66a7748d 200 }
4abf6441 201 const compositeChargingScheduleLowerInterval: Interval = {
ef9e3b33 202 end: addSeconds(
66a7748d 203 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
4abf6441 204 compositeChargingScheduleLower!.startSchedule!,
66a7748d
JB
205 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
206 compositeChargingScheduleLower!.duration!
d1f5bfd8 207 ),
0749233f
JB
208 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
209 start: compositeChargingScheduleLower!.startSchedule!,
66a7748d 210 }
4abf6441
JB
211 const higherFirst = isBefore(
212 compositeChargingScheduleHigherInterval.start,
66a7748d
JB
213 compositeChargingScheduleLowerInterval.start
214 )
ef9e3b33
JB
215 if (
216 !areIntervalsOverlapping(
4abf6441 217 compositeChargingScheduleHigherInterval,
66a7748d 218 compositeChargingScheduleLowerInterval
ef9e3b33
JB
219 )
220 ) {
221 return {
4abf6441 222 ...compositeChargingScheduleLower,
66a7748d 223 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
4abf6441 224 ...compositeChargingScheduleHigher!,
4abf6441 225 chargingSchedulePeriod: [
66a7748d 226 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
a974c8e4 227 ...compositeChargingScheduleHigher!.chargingSchedulePeriod.map(schedulePeriod => {
4abf6441
JB
228 return {
229 ...schedulePeriod,
230 startPeriod: higherFirst
231 ? 0
232 : schedulePeriod.startPeriod +
233 differenceInSeconds(
234 compositeChargingScheduleHigherInterval.start,
66a7748d 235 compositeChargingScheduleLowerInterval.start
d1f5bfd8 236 ),
66a7748d 237 }
4abf6441 238 }),
66a7748d 239 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
a974c8e4 240 ...compositeChargingScheduleLower!.chargingSchedulePeriod.map(schedulePeriod => {
4abf6441
JB
241 return {
242 ...schedulePeriod,
243 startPeriod: higherFirst
244 ? schedulePeriod.startPeriod +
245 differenceInSeconds(
246 compositeChargingScheduleLowerInterval.start,
66a7748d 247 compositeChargingScheduleHigherInterval.start
4abf6441 248 )
d1f5bfd8 249 : 0,
66a7748d 250 }
d1f5bfd8
JB
251 }),
252 ].sort((a, b) => a.startPeriod - b.startPeriod),
0749233f
JB
253 duration: higherFirst
254 ? differenceInSeconds(
255 compositeChargingScheduleLowerInterval.end,
256 compositeChargingScheduleHigherInterval.start
257 )
258 : differenceInSeconds(
259 compositeChargingScheduleHigherInterval.end,
260 compositeChargingScheduleLowerInterval.start
261 ),
262 startSchedule: higherFirst
263 ? (compositeChargingScheduleHigherInterval.start as Date)
264 : (compositeChargingScheduleLowerInterval.start as Date),
66a7748d 265 }
ef9e3b33 266 }
4abf6441
JB
267 return {
268 ...compositeChargingScheduleLower,
66a7748d 269 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
4abf6441 270 ...compositeChargingScheduleHigher!,
4abf6441 271 chargingSchedulePeriod: [
66a7748d 272 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
a974c8e4 273 ...compositeChargingScheduleHigher!.chargingSchedulePeriod.map(schedulePeriod => {
4abf6441
JB
274 return {
275 ...schedulePeriod,
276 startPeriod: higherFirst
277 ? 0
278 : schedulePeriod.startPeriod +
279 differenceInSeconds(
280 compositeChargingScheduleHigherInterval.start,
66a7748d 281 compositeChargingScheduleLowerInterval.start
d1f5bfd8 282 ),
66a7748d 283 }
4abf6441 284 }),
66a7748d 285 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
4abf6441 286 ...compositeChargingScheduleLower!.chargingSchedulePeriod
c4ab56ba 287 .filter((schedulePeriod, index) => {
4abf6441
JB
288 if (
289 higherFirst &&
290 isWithinInterval(
291 addSeconds(
292 compositeChargingScheduleLowerInterval.start,
66a7748d 293 schedulePeriod.startPeriod
4abf6441
JB
294 ),
295 {
d1f5bfd8 296 end: compositeChargingScheduleHigherInterval.end,
0749233f 297 start: compositeChargingScheduleLowerInterval.start,
66a7748d 298 }
4abf6441
JB
299 )
300 ) {
66a7748d 301 return false
4abf6441 302 }
c4ab56ba
JB
303 if (
304 higherFirst &&
66a7748d 305 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
c4ab56ba
JB
306 index < compositeChargingScheduleLower!.chargingSchedulePeriod.length - 1 &&
307 !isWithinInterval(
308 addSeconds(
309 compositeChargingScheduleLowerInterval.start,
66a7748d 310 schedulePeriod.startPeriod
c4ab56ba
JB
311 ),
312 {
d1f5bfd8 313 end: compositeChargingScheduleHigherInterval.end,
0749233f 314 start: compositeChargingScheduleLowerInterval.start,
66a7748d 315 }
c4ab56ba
JB
316 ) &&
317 isWithinInterval(
318 addSeconds(
319 compositeChargingScheduleLowerInterval.start,
66a7748d
JB
320 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
321 compositeChargingScheduleLower!.chargingSchedulePeriod[index + 1].startPeriod
c4ab56ba
JB
322 ),
323 {
d1f5bfd8 324 end: compositeChargingScheduleHigherInterval.end,
0749233f 325 start: compositeChargingScheduleLowerInterval.start,
66a7748d 326 }
c4ab56ba
JB
327 )
328 ) {
66a7748d 329 return false
c4ab56ba 330 }
4abf6441
JB
331 if (
332 !higherFirst &&
333 isWithinInterval(
334 addSeconds(
335 compositeChargingScheduleLowerInterval.start,
66a7748d 336 schedulePeriod.startPeriod
4abf6441
JB
337 ),
338 {
d1f5bfd8 339 end: compositeChargingScheduleLowerInterval.end,
0749233f 340 start: compositeChargingScheduleHigherInterval.start,
66a7748d 341 }
4abf6441
JB
342 )
343 ) {
66a7748d 344 return false
4abf6441 345 }
66a7748d 346 return true
4abf6441 347 })
0e14e1d4
JB
348 .map((schedulePeriod, index) => {
349 if (index === 0 && schedulePeriod.startPeriod !== 0) {
66a7748d 350 schedulePeriod.startPeriod = 0
0e14e1d4 351 }
4abf6441
JB
352 return {
353 ...schedulePeriod,
354 startPeriod: higherFirst
355 ? schedulePeriod.startPeriod +
356 differenceInSeconds(
357 compositeChargingScheduleLowerInterval.start,
66a7748d 358 compositeChargingScheduleHigherInterval.start
4abf6441 359 )
d1f5bfd8 360 : 0,
66a7748d 361 }
d1f5bfd8
JB
362 }),
363 ].sort((a, b) => a.startPeriod - b.startPeriod),
0749233f
JB
364 duration: higherFirst
365 ? differenceInSeconds(
366 compositeChargingScheduleLowerInterval.end,
367 compositeChargingScheduleHigherInterval.start
368 )
369 : differenceInSeconds(
370 compositeChargingScheduleHigherInterval.end,
371 compositeChargingScheduleLowerInterval.start
372 ),
373 startSchedule: higherFirst
374 ? (compositeChargingScheduleHigherInterval.start as Date)
375 : (compositeChargingScheduleLowerInterval.start as Date),
66a7748d
JB
376 }
377 }
ef9e3b33 378
90aceaf6
JB
379 public static hasReservation = (
380 chargingStation: ChargingStation,
381 connectorId: number,
66a7748d 382 idTag: string
90aceaf6 383 ): boolean => {
66a7748d
JB
384 const connectorReservation = chargingStation.getReservationBy('connectorId', connectorId)
385 const chargingStationReservation = chargingStation.getReservationBy('connectorId', 0)
90aceaf6
JB
386 if (
387 (chargingStation.getConnectorStatus(connectorId)?.status ===
388 OCPP16ChargePointStatus.Reserved &&
66a7748d 389 connectorReservation != null &&
56563a3c 390 !hasReservationExpired(connectorReservation) &&
5199f9fd 391 connectorReservation.idTag === idTag) ||
90aceaf6 392 (chargingStation.getConnectorStatus(0)?.status === OCPP16ChargePointStatus.Reserved &&
66a7748d 393 chargingStationReservation != null &&
56563a3c 394 !hasReservationExpired(chargingStationReservation) &&
5199f9fd 395 chargingStationReservation.idTag === idTag)
90aceaf6 396 ) {
88499f52 397 logger.debug(
d1f5bfd8 398 `${chargingStation.logPrefix()} Connector id ${connectorId.toString()} has a valid reservation for idTag ${idTag}: %j`,
66a7748d
JB
399 connectorReservation ?? chargingStationReservation
400 )
401 return true
90aceaf6 402 }
66a7748d
JB
403 return false
404 }
90aceaf6 405
0749233f
JB
406 public static isConfigurationKeyVisible (key: ConfigurationKey): boolean {
407 if (key.visible == null) {
408 return true
409 }
410 return key.visible
411 }
412
6375d3cd 413 public static override parseJsonSchemaFile<T extends JsonType>(
1b271a54
JB
414 relativePath: string,
415 moduleName?: string,
66a7748d 416 methodName?: string
1b271a54 417 ): JSONSchemaType<T> {
0c58e0c2 418 return OCPPServiceUtils.parseJsonSchemaFile<T>(
51022aa0 419 relativePath,
1b271a54
JB
420 OCPPVersion.VERSION_16,
421 moduleName,
66a7748d
JB
422 methodName
423 )
130783a7
JB
424 }
425
c4a89082
JB
426 public static remoteStopTransaction = async (
427 chargingStation: ChargingStation,
428 connectorId: number
429 ): Promise<GenericResponse> => {
430 await OCPP16ServiceUtils.sendAndSetConnectorStatus(
431 chargingStation,
432 connectorId,
433 OCPP16ChargePointStatus.Finishing
434 )
435 const stopResponse = await chargingStation.stopTransactionOnConnector(
436 connectorId,
437 OCPP16StopTransactionReason.REMOTE
438 )
439 if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
440 return OCPP16Constants.OCPP_RESPONSE_ACCEPTED
441 }
442 return OCPP16Constants.OCPP_RESPONSE_REJECTED
443 }
444
0749233f
JB
445 public static setChargingProfile (
446 chargingStation: ChargingStation,
447 connectorId: number,
448 cp: OCPP16ChargingProfile
449 ): void {
450 if (chargingStation.getConnectorStatus(connectorId)?.chargingProfiles == null) {
451 logger.error(
452 `${chargingStation.logPrefix()} Trying to set a charging profile on connector id ${connectorId.toString()} with an uninitialized charging profiles array attribute, applying deferred initialization`
453 )
66a7748d 454 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0749233f
JB
455 chargingStation.getConnectorStatus(connectorId)!.chargingProfiles = []
456 }
457 if (!Array.isArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)) {
458 logger.error(
459 `${chargingStation.logPrefix()} Trying to set a charging profile on connector id ${connectorId.toString()} with an improper attribute type for the charging profiles array, applying proper type deferred initialization`
460 )
66a7748d 461 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
0749233f 462 chargingStation.getConnectorStatus(connectorId)!.chargingProfiles = []
66a7748d 463 }
0749233f
JB
464 cp.chargingSchedule.startSchedule = convertToDate(cp.chargingSchedule.startSchedule)
465 cp.validFrom = convertToDate(cp.validFrom)
466 cp.validTo = convertToDate(cp.validTo)
467 let cpReplaced = false
468 if (isNotEmptyArray(chargingStation.getConnectorStatus(connectorId)?.chargingProfiles)) {
469 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
470 for (const [index, chargingProfile] of chargingStation
471 .getConnectorStatus(connectorId)!
472 .chargingProfiles!.entries()) {
473 if (
474 chargingProfile.chargingProfileId === cp.chargingProfileId ||
475 (chargingProfile.stackLevel === cp.stackLevel &&
476 chargingProfile.chargingProfilePurpose === cp.chargingProfilePurpose)
477 ) {
478 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
479 chargingStation.getConnectorStatus(connectorId)!.chargingProfiles![index] = cp
480 cpReplaced = true
66a7748d 481 }
ef9e3b33 482 }
ef9e3b33 483 }
0749233f 484 !cpReplaced && chargingStation.getConnectorStatus(connectorId)?.chargingProfiles?.push(cp)
66a7748d 485 }
33f023c8 486
487 private static readonly composeChargingSchedule = (
488 chargingSchedule: OCPP16ChargingSchedule,
489 compositeInterval: Interval
490 ): OCPP16ChargingSchedule | undefined => {
491 const chargingScheduleInterval: Interval = {
492 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
493 end: addSeconds(chargingSchedule.startSchedule!, chargingSchedule.duration!),
494 // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
495 start: chargingSchedule.startSchedule!,
496 }
497 if (areIntervalsOverlapping(chargingScheduleInterval, compositeInterval)) {
498 chargingSchedule.chargingSchedulePeriod.sort((a, b) => a.startPeriod - b.startPeriod)
499 if (isBefore(chargingScheduleInterval.start, compositeInterval.start)) {
500 return {
501 ...chargingSchedule,
502 chargingSchedulePeriod: chargingSchedule.chargingSchedulePeriod
503 .filter((schedulePeriod, index) => {
504 if (
505 isWithinInterval(
506 addSeconds(chargingScheduleInterval.start, schedulePeriod.startPeriod),
507 compositeInterval
508 )
509 ) {
510 return true
511 }
512 if (
513 index < chargingSchedule.chargingSchedulePeriod.length - 1 &&
514 !isWithinInterval(
515 addSeconds(chargingScheduleInterval.start, schedulePeriod.startPeriod),
516 compositeInterval
517 ) &&
518 isWithinInterval(
519 addSeconds(
520 chargingScheduleInterval.start,
521 chargingSchedule.chargingSchedulePeriod[index + 1].startPeriod
522 ),
523 compositeInterval
524 )
525 ) {
526 return true
527 }
528 return false
529 })
530 .map((schedulePeriod, index) => {
531 if (index === 0 && schedulePeriod.startPeriod !== 0) {
532 schedulePeriod.startPeriod = 0
533 }
534 return schedulePeriod
535 }),
536 duration: differenceInSeconds(
537 chargingScheduleInterval.end,
538 compositeInterval.start as Date
539 ),
540 startSchedule: compositeInterval.start as Date,
541 }
542 }
543 if (isAfter(chargingScheduleInterval.end, compositeInterval.end)) {
544 return {
545 ...chargingSchedule,
546 chargingSchedulePeriod: chargingSchedule.chargingSchedulePeriod.filter(schedulePeriod =>
547 isWithinInterval(
548 addSeconds(chargingScheduleInterval.start, schedulePeriod.startPeriod),
549 compositeInterval
550 )
551 ),
552 duration: differenceInSeconds(
553 compositeInterval.end as Date,
554 chargingScheduleInterval.start
555 ),
556 }
557 }
558 return chargingSchedule
559 }
560 }
6ed92bc1 561}