@@ -22,6 +22,7 @@ import { CsvService } from './csv.service';
2222import { parse , unparse } from 'papaparse' ;
2323import { EXPERIMENTAL_API_FIELDS_VEHICLES , UnloadingPolicy } from '../models' ;
2424import { GeocodingService } from './geocoding.service' ;
25+ import { of } from 'rxjs' ;
2526
2627describe ( 'CsvService' , ( ) => {
2728 let service : CsvService ;
@@ -157,6 +158,90 @@ describe('CsvService', () => {
157158 expect ( result [ 0 ] . errors . length ) . toBe ( 1 ) ;
158159 expect ( result [ 1 ] . errors . length ) . toBe ( 1 ) ;
159160 } ) ;
161+
162+ it ( 'should parse valid allowedVehicleIndices' , ( ) => {
163+ const shipments = [ { label : 'test shipment' , allowedVehicleIndices : '1,2,3,4' } ] ;
164+ const testMapping = { Label : 'label' , AllowedVehicleIndices : 'allowedVehicleIndices' } ;
165+ const result = service . csvToShipments ( shipments , testMapping ) ;
166+ expect ( result . length ) . toBe ( 1 ) ;
167+ expect ( result [ 0 ] . errors . length ) . toBe ( 0 ) ;
168+ expect ( result [ 0 ] . shipment . allowedVehicleIndices ) . toEqual ( [ 1 , 2 , 3 , 4 ] ) ;
169+ } ) ;
170+
171+ it ( 'should parse valid allowedVehicleIndices when spaces are present' , ( ) => {
172+ const shipments = [ { label : 'test shipment' , allowedVehicleIndices : '1, 2, 3, 4 ' } ] ;
173+ const testMapping = { Label : 'label' , AllowedVehicleIndices : 'allowedVehicleIndices' } ;
174+ const result = service . csvToShipments ( shipments , testMapping ) ;
175+ expect ( result . length ) . toBe ( 1 ) ;
176+ expect ( result [ 0 ] . errors . length ) . toBe ( 0 ) ;
177+ expect ( result [ 0 ] . shipment . allowedVehicleIndices ) . toEqual ( [ 1 , 2 , 3 , 4 ] ) ;
178+ } ) ;
179+
180+ it ( 'should parse shipment pickup time windows' , ( ) => {
181+ const shipments = [
182+ {
183+ startTime : '2025-04-01T10:00:00Z' ,
184+ softStartTime : '2025-04-01T08:00:00Z' ,
185+ endTime : '2025-04-01T20:00:00Z' ,
186+ softEndTime : '2025-04-01T19:00:00Z' ,
187+ } ,
188+ ] ;
189+ const testShipmentMapping = {
190+ PickupStartTime : 'startTime' ,
191+ PickupSoftStartTime : 'softStartTime' ,
192+ PickupEndTime : 'endTime' ,
193+ PickupSoftEndTime : 'softEndTime' ,
194+ } ;
195+
196+ const result = service . csvToShipments ( shipments , testShipmentMapping ) ;
197+ expect ( result . length ) . toBe ( 1 ) ;
198+ expect ( result [ 0 ] . errors . length ) . toBe ( 0 ) ;
199+ expect ( result [ 0 ] . shipment . pickups [ 0 ] . timeWindows [ 0 ] . startTime ) . toEqual ( {
200+ seconds : '1743501600' ,
201+ } ) ;
202+ expect ( result [ 0 ] . shipment . pickups [ 0 ] . timeWindows [ 0 ] . softStartTime ) . toEqual ( {
203+ seconds : '1743494400' ,
204+ } ) ;
205+ expect ( result [ 0 ] . shipment . pickups [ 0 ] . timeWindows [ 0 ] . endTime ) . toEqual ( {
206+ seconds : '1743537600' ,
207+ } ) ;
208+ expect ( result [ 0 ] . shipment . pickups [ 0 ] . timeWindows [ 0 ] . softEndTime ) . toEqual ( {
209+ seconds : '1743534000' ,
210+ } ) ;
211+ } ) ;
212+
213+ it ( 'should parse shipment delivery time windows' , ( ) => {
214+ const shipments = [
215+ {
216+ startTime : '2025-04-01T10:00:00Z' ,
217+ softStartTime : '2025-04-01T08:00:00Z' ,
218+ endTime : '2025-04-01T20:00:00Z' ,
219+ softEndTime : '2025-04-01T19:00:00Z' ,
220+ } ,
221+ ] ;
222+ const testShipmentMapping = {
223+ DeliveryStartTime : 'startTime' ,
224+ DeliverySoftStartTime : 'softStartTime' ,
225+ DeliveryEndTime : 'endTime' ,
226+ DeliverySoftEndTime : 'softEndTime' ,
227+ } ;
228+
229+ const result = service . csvToShipments ( shipments , testShipmentMapping ) ;
230+ expect ( result . length ) . toBe ( 1 ) ;
231+ expect ( result [ 0 ] . errors . length ) . toBe ( 0 ) ;
232+ expect ( result [ 0 ] . shipment . deliveries [ 0 ] . timeWindows [ 0 ] . startTime ) . toEqual ( {
233+ seconds : '1743501600' ,
234+ } ) ;
235+ expect ( result [ 0 ] . shipment . deliveries [ 0 ] . timeWindows [ 0 ] . softStartTime ) . toEqual ( {
236+ seconds : '1743494400' ,
237+ } ) ;
238+ expect ( result [ 0 ] . shipment . deliveries [ 0 ] . timeWindows [ 0 ] . endTime ) . toEqual ( {
239+ seconds : '1743537600' ,
240+ } ) ;
241+ expect ( result [ 0 ] . shipment . deliveries [ 0 ] . timeWindows [ 0 ] . softEndTime ) . toEqual ( {
242+ seconds : '1743534000' ,
243+ } ) ;
244+ } ) ;
160245 } ) ;
161246
162247 describe ( 'Validate vehicles' , ( ) => {
@@ -331,6 +416,68 @@ describe('CsvService', () => {
331416 expect ( result [ 2 ] . vehicle . unloadingPolicy ) . toBe ( UnloadingPolicy . FIRST_IN_FIRST_OUT ) ;
332417 expect ( result [ 3 ] . vehicle . unloadingPolicy ) . toBeUndefined ( ) ;
333418 } ) ;
419+
420+ it ( 'should parse usedIfRouteIsEmpty' , ( ) => {
421+ const vehicles = [
422+ {
423+ label : 'test vehicle 1' ,
424+ usedIfRouteIsEmpty : 'true' ,
425+ } ,
426+ {
427+ label : 'test vehicle 2' ,
428+ usedIfRouteIsEmpty : ' TRUE ' ,
429+ } ,
430+ {
431+ label : 'test vehicle 3' ,
432+ usedIfRouteIsEmpty : 'FALSE' ,
433+ } ,
434+ {
435+ label : 'test vehicle 4' ,
436+ usedIfRouteIsEmpty : 'not a bool' ,
437+ } ,
438+ ] ;
439+ const testVehicleMapping = {
440+ Label : 'label' ,
441+ UsedIfRouteIsEmpty : 'usedIfRouteIsEmpty' ,
442+ } ;
443+ const result = service . csvToVehicles ( vehicles , testVehicleMapping ) ;
444+ expect ( result . length ) . toBe ( 4 ) ;
445+ expect ( result [ 0 ] . errors . length ) . toBe ( 0 ) ;
446+ expect ( result [ 1 ] . errors . length ) . toBe ( 0 ) ;
447+ expect ( result [ 2 ] . errors . length ) . toBe ( 0 ) ;
448+ expect ( result [ 3 ] . errors . length ) . toBe ( 0 ) ;
449+ expect ( result [ 0 ] . vehicle . usedIfRouteIsEmpty ) . toBeTrue ( ) ;
450+ expect ( result [ 1 ] . vehicle . usedIfRouteIsEmpty ) . toBeTrue ( ) ;
451+ expect ( result [ 2 ] . vehicle . usedIfRouteIsEmpty ) . toBeFalse ( ) ;
452+ expect ( result [ 3 ] . vehicle . usedIfRouteIsEmpty ) . toBeFalse ( ) ;
453+ } ) ;
454+
455+ it ( 'should parse vehicle time windows' , ( ) => {
456+ const vehicles = [
457+ {
458+ startTime : '2025-04-01T10:00:00Z' ,
459+ softStartTime : '2025-04-01T08:00:00Z' ,
460+ endTime : '2025-04-01T20:00:00Z' ,
461+ softEndTime : '2025-04-01T19:00:00Z' ,
462+ } ,
463+ ] ;
464+ const testVehicleMapping = {
465+ StartTimeWindowStartTime : 'startTime' ,
466+ StartTimeWindowSoftStartTime : 'softStartTime' ,
467+ StartTimeWindowEndTime : 'endTime' ,
468+ StartTimeWindowSoftEndTime : 'softEndTime' ,
469+ } ;
470+
471+ const result = service . csvToVehicles ( vehicles , testVehicleMapping ) ;
472+ expect ( result . length ) . toBe ( 1 ) ;
473+ expect ( result [ 0 ] . errors . length ) . toBe ( 0 ) ;
474+ expect ( result [ 0 ] . vehicle . startTimeWindows [ 0 ] . startTime ) . toEqual ( { seconds : '1743501600' } ) ;
475+ expect ( result [ 0 ] . vehicle . startTimeWindows [ 0 ] . softStartTime ) . toEqual ( {
476+ seconds : '1743494400' ,
477+ } ) ;
478+ expect ( result [ 0 ] . vehicle . startTimeWindows [ 0 ] . endTime ) . toEqual ( { seconds : '1743537600' } ) ;
479+ expect ( result [ 0 ] . vehicle . startTimeWindows [ 0 ] . softEndTime ) . toEqual ( { seconds : '1743534000' } ) ;
480+ } ) ;
334481 } ) ;
335482
336483 describe ( 'Validate geocoding' , ( ) => {
@@ -441,4 +588,165 @@ describe('CsvService', () => {
441588 } ) ;
442589 } ) ;
443590 } ) ;
591+
592+ describe ( 'Geocode vehicles' , ( ) => {
593+ it ( 'should return an empty array when no vehicles are provided' , ( done ) => {
594+ service . geocodeVehicles ( [ ] ) . subscribe ( ( res ) => {
595+ expect ( res ) . toEqual ( [ ] ) ;
596+ done ( ) ;
597+ } ) ;
598+ } ) ;
599+
600+ it ( 'should return null values when no waypoints are provided' , ( done ) => {
601+ service . geocodeVehicles ( [ { } ] ) . subscribe ( ( res ) => {
602+ expect ( res ) . toEqual ( [ null , null ] ) ;
603+ done ( ) ;
604+ } ) ;
605+ } ) ;
606+
607+ it ( 'should return null values for missing start waypoints' , ( done ) => {
608+ service . geocodeVehicles ( [ { endWaypoint : '35.1, 10.53' } ] ) . subscribe ( ( res ) => {
609+ expect ( res ) . toEqual ( [ null , { latitude : 35.1 , longitude : 10.53 } ] ) ;
610+ done ( ) ;
611+ } ) ;
612+ } ) ;
613+
614+ it ( 'should return null values for missing end waypoints' , ( done ) => {
615+ service . geocodeVehicles ( [ { startWaypoint : '35.1, 10.53' } ] ) . subscribe ( ( res ) => {
616+ expect ( res ) . toEqual ( [ { latitude : 35.1 , longitude : 10.53 } , null ] ) ;
617+ done ( ) ;
618+ } ) ;
619+ } ) ;
620+
621+ it ( 'should parse geocode errors' , ( done ) => {
622+ spyOn ( service , 'geocodeLocation' ) . and . callFake ( ( loc : string ) => {
623+ return of ( {
624+ error : true ,
625+ message : 'Invalid location' ,
626+ location : loc ,
627+ } ) ;
628+ } ) ;
629+
630+ const vehicle1 = { startWaypoint : '35.1, 10.53' } ;
631+
632+ service . geocodeVehicles ( [ vehicle1 ] ) . subscribe ( ( res ) => {
633+ expect ( res ) . toEqual ( [
634+ {
635+ error : true ,
636+ message : 'Invalid location' ,
637+ field : 'startWaypoint' ,
638+ location : '35.1, 10.53' ,
639+ index : 0 ,
640+ source : vehicle1 ,
641+ vehicle : vehicle1 ,
642+ } ,
643+ {
644+ error : true ,
645+ message : 'Invalid location' ,
646+ field : 'endWaypoint' ,
647+ location : undefined ,
648+ index : 0 ,
649+ source : vehicle1 ,
650+ vehicle : vehicle1 ,
651+ } ,
652+ ] ) ;
653+ done ( ) ;
654+ } ) ;
655+ } ) ;
656+ } ) ;
657+
658+ describe ( 'Geocode shipments' , ( ) => {
659+ it ( 'should return an empty array when no shiments are provided' , ( done ) => {
660+ service . geocodeShipments ( [ ] ) . subscribe ( ( res ) => {
661+ expect ( res ) . toEqual ( [ ] ) ;
662+ done ( ) ;
663+ } ) ;
664+ } ) ;
665+
666+ it ( 'should return null values when no waypoints are provided' , ( done ) => {
667+ service . geocodeShipments ( [ { } ] ) . subscribe ( ( res ) => {
668+ expect ( res ) . toEqual ( [ null , null ] ) ;
669+ done ( ) ;
670+ } ) ;
671+ } ) ;
672+
673+ it ( 'should return null values for missing pickup arrival waypoints' , ( done ) => {
674+ service
675+ . geocodeShipments ( [ { deliveries : [ { arrivalWaypoint : '35.1, 10.53' } ] } ] )
676+ . subscribe ( ( res ) => {
677+ expect ( res ) . toEqual ( [ null , { latitude : 35.1 , longitude : 10.53 } ] ) ;
678+ done ( ) ;
679+ } ) ;
680+ } ) ;
681+
682+ it ( 'should return null values for missing delivery arrival waypoints' , ( done ) => {
683+ service
684+ . geocodeShipments ( [ { pickups : [ { arrivalWaypoint : '35.1, 10.53' } ] } ] )
685+ . subscribe ( ( res ) => {
686+ expect ( res ) . toEqual ( [ { latitude : 35.1 , longitude : 10.53 } , null ] ) ;
687+ done ( ) ;
688+ } ) ;
689+ } ) ;
690+
691+ it ( 'should only geocode the first pickup' , ( done ) => {
692+ service
693+ . geocodeShipments ( [
694+ { pickups : [ { arrivalWaypoint : '35.1, 10.53' } , { arrivalWaypoint : '-5.123, 38.3' } ] } ,
695+ ] )
696+ . subscribe ( ( res ) => {
697+ expect ( res ) . toEqual ( [ { latitude : 35.1 , longitude : 10.53 } , null ] ) ;
698+ done ( ) ;
699+ } ) ;
700+ } ) ;
701+
702+ it ( 'should only geocode the first delivery' , ( done ) => {
703+ service
704+ . geocodeShipments ( [
705+ { deliveries : [ { arrivalWaypoint : '35.1, 10.53' } , { arrivalWaypoint : '-5.123, 38.3' } ] } ,
706+ ] )
707+ . subscribe ( ( res ) => {
708+ expect ( res ) . toEqual ( [ null , { latitude : 35.1 , longitude : 10.53 } ] ) ;
709+ done ( ) ;
710+ } ) ;
711+ } ) ;
712+
713+ it ( 'should parse geocode errors' , ( done ) => {
714+ spyOn ( service , 'geocodeLocation' ) . and . callFake ( ( loc : string ) => {
715+ return of ( {
716+ error : true ,
717+ message : 'Invalid location' ,
718+ location : loc ,
719+ } ) ;
720+ } ) ;
721+
722+ const shipment1 = {
723+ pickups : [ { arrivalWaypoint : '35.1, 10.53' } ] ,
724+ deliveries : [ { arrivalWaypoint : '5.13, 3.51' } ] ,
725+ } ;
726+
727+ service . geocodeShipments ( [ shipment1 ] ) . subscribe ( ( res ) => {
728+ expect ( res ) . toEqual ( [
729+ {
730+ error : true ,
731+ message : 'Invalid location' ,
732+ field : 'arrivalWaypoint' ,
733+ location : '35.1, 10.53' ,
734+ index : 0 ,
735+ source : shipment1 . pickups [ 0 ] ,
736+ shipment : shipment1 ,
737+ } ,
738+ {
739+ error : true ,
740+ message : 'Invalid location' ,
741+ field : 'arrivalWaypoint' ,
742+ location : '5.13, 3.51' ,
743+ index : 0 ,
744+ source : shipment1 . deliveries [ 0 ] ,
745+ shipment : shipment1 ,
746+ } ,
747+ ] ) ;
748+ done ( ) ;
749+ } ) ;
750+ } ) ;
751+ } ) ;
444752} ) ;
0 commit comments