@sabstravtech/obtservices 0.2.2511121920 → 0.2.2511200338

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,7 +4,6 @@ import moment from 'moment';
4
4
  import { __decorate } from 'tslib';
5
5
  import _, { uniq } from 'lodash';
6
6
  import Ajv from 'ajv';
7
- import addFormats from 'ajv-formats';
8
7
  import * as i0 from '@angular/core';
9
8
  import { Directive } from '@angular/core';
10
9
 
@@ -2845,22 +2844,32 @@ const genders = [
2845
2844
  Gender.Unspecified_Others
2846
2845
  ];
2847
2846
  const PREFERENCE_VALUES$1 = [
2847
+ { label: "Asian Vegetarian", type: PreferenceKey.MealRequest, code: "AVML" },
2848
2848
  { label: "Bland", type: PreferenceKey.MealRequest, code: "BLML" },
2849
2849
  { label: "Child", type: PreferenceKey.MealRequest, code: "CHML" },
2850
2850
  { label: "Diabetic", type: PreferenceKey.MealRequest, code: "DBML" },
2851
+ { label: "Fish", type: PreferenceKey.MealRequest, code: "FSML" },
2851
2852
  { label: "Fruit Plate", type: PreferenceKey.MealRequest, code: "FPML" },
2852
- { label: "Gluten intolerant", type: PreferenceKey.MealRequest, code: "GFML" },
2853
+ { label: "Gluten Free", type: PreferenceKey.MealRequest, code: "GFML" },
2853
2854
  { label: "Hindu", type: PreferenceKey.MealRequest, code: "HNML" },
2855
+ { label: "Indian Vegetarian", type: PreferenceKey.MealRequest, code: "IVML" },
2856
+ { label: "Japanese", type: PreferenceKey.MealRequest, code: "JPML" },
2854
2857
  { label: "Kosher", type: PreferenceKey.MealRequest, code: "KSML" },
2858
+ { label: "Kosher Vegetarian", type: PreferenceKey.MealRequest, code: "KVML" },
2859
+ { label: "Low Calorie", type: PreferenceKey.MealRequest, code: "LCML" },
2855
2860
  { label: "Low Fat/Cholesterol", type: PreferenceKey.MealRequest, code: "LFML" },
2856
2861
  { label: "Low Sodium", type: PreferenceKey.MealRequest, code: "LSML" },
2857
2862
  { label: "Muslim", type: PreferenceKey.MealRequest, code: "MOML" },
2863
+ { label: "No Fish", type: PreferenceKey.MealRequest, code: "NFML" },
2858
2864
  { label: "Non-Lactose", type: PreferenceKey.MealRequest, code: "NLML" },
2865
+ { label: "No Salt", type: PreferenceKey.MealRequest, code: "NSML" },
2866
+ { label: "Peanuts Free", type: PreferenceKey.MealRequest, code: "PFML" },
2859
2867
  { label: "Raw Vegetarian/Vegan", type: PreferenceKey.MealRequest, code: "RVML" },
2860
2868
  { label: "Seafood", type: PreferenceKey.MealRequest, code: "SFML" },
2861
2869
  { label: "Vegetarian-Vegan", type: PreferenceKey.MealRequest, code: "VGML" },
2870
+ { label: "Vegetarian Jain", type: PreferenceKey.MealRequest, code: "VJML" },
2862
2871
  { label: "Vegetarian Lacto-Ovo", type: PreferenceKey.MealRequest, code: "VLML" },
2863
- { label: "Asian Vegetarian", type: PreferenceKey.MealRequest, code: "VOML" },
2872
+ { label: "Vegetarian Oriental", type: PreferenceKey.MealRequest, code: "VOML" },
2864
2873
  { label: "Aisle", type: PreferenceKey.SeatingPreference },
2865
2874
  { label: "Window", type: PreferenceKey.SeatingPreference },
2866
2875
  { label: "Bassinet", type: PreferenceKey.SpecialNeed, code: "BSCT" },
@@ -4624,22 +4633,32 @@ var ErmFareTypes;
4624
4633
  var MealType;
4625
4634
  (function (MealType) {
4626
4635
  MealType["None"] = "None";
4627
- MealType["VGML"] = "Vegetarian-Vegan";
4628
- MealType["VOML"] = "Asian Vegetarian";
4629
- MealType["RVML"] = "Raw Vegetarian/Vegan";
4636
+ MealType["AVML"] = "Asian Vegetarian";
4637
+ MealType["BLML"] = "Bland";
4638
+ MealType["CHML"] = "Child";
4639
+ MealType["DBML"] = "Diabetic";
4630
4640
  MealType["FPML"] = "Fruit Plate";
4631
- MealType["SFML"] = "Seafood";
4632
- MealType["KSML"] = "Kosher";
4633
- MealType["MOML"] = "Muslim";
4641
+ MealType["FSML"] = "Fish";
4642
+ MealType["GFML"] = "Gluten intolerant";
4634
4643
  MealType["HNML"] = "Hindu";
4644
+ MealType["IVML"] = "Indian Vegetarian";
4645
+ MealType["JPML"] = "Japanese";
4646
+ MealType["KSML"] = "Kosher";
4647
+ MealType["KVML"] = "Kosher Vegetarian";
4648
+ MealType["LCML"] = "Low Calorie";
4635
4649
  MealType["LFML"] = "Low Fat/Cholesterol";
4636
- MealType["VLML"] = "Vegetarian Lacto-Ovo";
4637
4650
  MealType["LSML"] = "Low Sodium";
4638
- MealType["GFML"] = "Gluten intolerant";
4639
- MealType["DBML"] = "Diabetic";
4651
+ MealType["MOML"] = "Muslim";
4652
+ MealType["NFML"] = "No Fish";
4640
4653
  MealType["NLML"] = "Non-Lactose";
4641
- MealType["CHML"] = "Child";
4642
- MealType["BLML"] = "Bland";
4654
+ MealType["NSML"] = "No Salt";
4655
+ MealType["PFML"] = "Peanuts Free";
4656
+ MealType["RVML"] = "Raw Vegetarian/Vegan";
4657
+ MealType["SFML"] = "Seafood";
4658
+ MealType["VGML"] = "Vegetarian-Vegan";
4659
+ MealType["VJML"] = "Vegetarian Jain";
4660
+ MealType["VLML"] = "Vegetarian Lacto-Ovo";
4661
+ MealType["VOML"] = "Vegetarian Oriental";
4643
4662
  })(MealType || (MealType = {}));
4644
4663
  var SpecialNeeds;
4645
4664
  (function (SpecialNeeds) {
@@ -4931,7 +4950,7 @@ class BookableBasket {
4931
4950
  this.isUpdating?.next(true);
4932
4951
  return this.basketService.setBasketItemPaymentOption(this.basket.value, basketItem, paymentMethod);
4933
4952
  }
4934
- async bookBasket(results, additionalEmail, approverNotes) {
4953
+ async bookBasket(results, additionalEmail, notificationOptIn, approverNotes) {
4935
4954
  this.isUpdating.next(true);
4936
4955
  if (results) {
4937
4956
  const basketValue = this.basket.value;
@@ -4943,7 +4962,7 @@ class BookableBasket {
4943
4962
  && !basketValue.requiresSelectedNotifyApproverPerMi)) {
4944
4963
  this.removeInvalidPassport(results);
4945
4964
  }
4946
- return this.basketService.bookBasket(this.id, results, additionalEmail, approverNotes || "");
4965
+ return this.basketService.bookBasket(this.id, results, additionalEmail, notificationOptIn, approverNotes || "");
4947
4966
  }
4948
4967
  }
4949
4968
  _needsMiGroups(basket) {
@@ -11784,7 +11803,7 @@ class FlightEnterpriseSearch extends BaseEnterpriseSearch {
11784
11803
  inboundDate,
11785
11804
  outboundClass,
11786
11805
  returnClass
11787
- }).toPromise();
11806
+ }).pipe(take(1)).toPromise();
11788
11807
  const results = { ...flightsExchange };
11789
11808
  const flightJourneys = [];
11790
11809
  const { journeyWhenSelected, whenSelectedAlone } = results.ruleActionSummary;
@@ -12250,7 +12269,6 @@ class FlightEnterpriseSearch extends BaseEnterpriseSearch {
12250
12269
  returnTimeWindow: ss.returnDepartureTimeWindow
12251
12270
  }
12252
12271
  : null);
12253
- this.searchService.saveRecentSearch(this.getRecentSearchQuery(query));
12254
12272
  delete this.ssoObject;
12255
12273
  console.warn('+++ starting sso search +++');
12256
12274
  return this._startSearch(this.flightfetcher.fetchList(query));
@@ -16505,7 +16523,7 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
16505
16523
  // build the query
16506
16524
  this.buildQuery();
16507
16525
  const query = this.getSearchQuery();
16508
- this.searchService.saveRecentSearch(this.getRecentSearchQuery(this.getSearchQuery()));
16526
+ this.searchService.saveRecentSearch(this.getRecentSearchQuery(query));
16509
16527
  return this._startSearch(this.tempParams.location_type_select === LocationTypes.Shortlist
16510
16528
  ? this.quickListFetcher.fetchList({
16511
16529
  countryCode: this.country.cCode,
@@ -16542,7 +16560,10 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
16542
16560
  countryCode: locationDetails.countryCode
16543
16561
  }
16544
16562
  };
16545
- this.boltSearchQuery = originalSearchHotel;
16563
+ this.boltSearchQuery = _.clone(query);
16564
+ this.boltSearchQuery.location_type_select = 'Address';
16565
+ this.boltSearchQuery.checkin_date = moment(this.boltSearchQuery.startDate);
16566
+ this.boltSearchQuery.checkout_date = moment(this.boltSearchQuery.endDate);
16546
16567
  this.resetSearch();
16547
16568
  this.checkin_date = null;
16548
16569
  this.checkout_date = null;
@@ -16632,7 +16653,11 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
16632
16653
  return this.helpers.removeNulls(this.query);
16633
16654
  }
16634
16655
  buildQuery(ogSearch = false) {
16635
- const tempParams = ogSearch && this.originalUserSearch ? this.originalUserSearch : this.tempParams;
16656
+ const tempParams = ogSearch && this.originalUserSearch
16657
+ ? this.originalUserSearch
16658
+ : this.boltSearchQuery && this.boltSearchQuery?.length
16659
+ ? this.boltSearchQuery
16660
+ : this.tempParams;
16636
16661
  const currencyObject = this.userService.getUserFavoriteObject(UserFavorurite.PreferredCurrency);
16637
16662
  if ((!this.userCurrency || this.userCurrency !== currencyObject?.currency) &&
16638
16663
  currencyObject?.hotel?.enable) {
@@ -16673,46 +16698,56 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
16673
16698
  this.getRoomNumber();
16674
16699
  switch (tempParams.location_type_select) {
16675
16700
  case LocationTypes.Address:
16676
- switch (tempParams.location.type) {
16677
- case LocationTypes.Airport:
16678
- query.iata = tempParams.location.iata;
16679
- break;
16680
- case LocationTypes.City:
16681
- query.countryCode = tempParams.location.countryCode;
16682
- if (tempParams.location?.city || tempParams.location?.name) {
16683
- query.cityName = tempParams.location?.city || tempParams.location?.name;
16684
- }
16685
- else if (tempParams.location.postcode) {
16701
+ if (tempParams.location?.type) {
16702
+ switch (tempParams.location.type) {
16703
+ case LocationTypes.Airport:
16704
+ query.iata = tempParams.location.iata;
16705
+ query.countryCode = tempParams.location.countryCode;
16706
+ break;
16707
+ case LocationTypes.City:
16708
+ query.countryCode = tempParams.location.countryCode;
16709
+ if (tempParams.location?.name || tempParams.location?.city) {
16710
+ query.cityName = tempParams.location?.name || tempParams.location?.city;
16711
+ }
16712
+ else if (tempParams.location.postcode) {
16713
+ query.postOrZipCode = tempParams.location.postcode;
16714
+ }
16715
+ query.latitude = tempParams.location.latitude;
16716
+ query.longitude = tempParams.location.longitude;
16717
+ break;
16718
+ case LocationTypes.Hotel:
16686
16719
  query.postOrZipCode = tempParams.location.postcode;
16687
- }
16688
- query.latitude = tempParams.location.latitude;
16689
- query.longitude = tempParams.location.longitude;
16690
- break;
16691
- case LocationTypes.Hotel:
16692
- query.postOrZipCode = tempParams.location.postcode;
16693
- query.latitude = tempParams.location.latitude;
16694
- query.longitude = tempParams.location.longitude;
16695
- query.hotelName = tempParams.location.hotelTitle;
16696
- query.countryCode = tempParams.location.countryCode;
16697
- // Use location name as fallback for hotel name if hotel_name field is empty (for recent searches)
16698
- if (!tempParams.hotel_name && tempParams.location?.name && !query.hotelName) {
16699
- query.hotelName = tempParams.location.name;
16700
- }
16701
- // Also set cityName if location has city property
16702
- if (tempParams.location?.city) {
16703
- query.cityName = tempParams.location.city;
16704
- }
16705
- break;
16706
- case LocationTypes.TrainStation:
16707
- if (tempParams.location.latitude && tempParams.location.longitude) {
16708
- //For EU stations
16709
16720
  query.latitude = tempParams.location.latitude;
16710
16721
  query.longitude = tempParams.location.longitude;
16711
- if (tempParams.location.stationCode || tempParams.location.trainStationCode) {
16712
- query.trainStationCode = tempParams.location.stationCode || tempParams.location.trainStationCode;
16722
+ query.hotelName = tempParams.location.hotelTitle;
16723
+ query.countryCode = tempParams.location.countryCode;
16724
+ // Use location name as fallback for hotel name if hotel_name field is empty (for recent searches)
16725
+ if (!tempParams.hotel_name && tempParams.location?.name && !query.hotelName) {
16726
+ query.hotelName = tempParams.location.name;
16713
16727
  }
16714
- }
16715
- break;
16728
+ // Also set cityName if location has city property
16729
+ if (tempParams.location?.city) {
16730
+ query.cityName = tempParams.location.city;
16731
+ }
16732
+ break;
16733
+ case LocationTypes.TrainStation:
16734
+ if (tempParams.location.latitude && tempParams.location.longitude) {
16735
+ //For EU stations
16736
+ query.latitude = tempParams.location.latitude;
16737
+ query.longitude = tempParams.location.longitude;
16738
+ query.countryCode = tempParams.location.countryCode;
16739
+ if (tempParams.location.stationCode || tempParams.location.trainStationCode) {
16740
+ query.trainStationCode =
16741
+ tempParams.location.stationCode || tempParams.location.trainStationCode;
16742
+ }
16743
+ }
16744
+ break;
16745
+ }
16746
+ }
16747
+ else {
16748
+ query.countryCode = 'GB';
16749
+ query.latitude = tempParams.latitude;
16750
+ query.longitude = tempParams.longitude;
16716
16751
  }
16717
16752
  break;
16718
16753
  case LocationTypes.Office:
@@ -17429,7 +17464,13 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
17429
17464
  const arriveLocation = outboundFlights[outboundFlights.length - 1]?.destinationAirportDetail;
17430
17465
  if (arriveLocation) {
17431
17466
  this.country = { cCode: arriveLocation.countryCode, cName: arriveLocation.countryName };
17432
- this.location = { countryCode: arriveLocation.countryCode, latitude: arriveLocation.latitude, longitude: arriveLocation.longitude, type: LocationTypes.City, name: arriveLocation.city };
17467
+ this.location = {
17468
+ countryCode: arriveLocation.countryCode,
17469
+ latitude: arriveLocation.latitude,
17470
+ longitude: arriveLocation.longitude,
17471
+ type: LocationTypes.City,
17472
+ name: arriveLocation.city
17473
+ };
17433
17474
  }
17434
17475
  else {
17435
17476
  this.location = null;
@@ -17451,6 +17492,9 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
17451
17492
  if (railstation?.stationCode) {
17452
17493
  locationDetail.stationCode = railstation.stationCode;
17453
17494
  }
17495
+ if (railstation?.locationDetails?.countryCode) {
17496
+ locationDetail.countryCode = railstation.locationDetails.countryCode;
17497
+ }
17454
17498
  this.location = locationDetail;
17455
17499
  }
17456
17500
  catch {
@@ -17471,6 +17515,9 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
17471
17515
  if (railstation?.stationCode) {
17472
17516
  locationDetail.stationCode = railstation.stationCode;
17473
17517
  }
17518
+ if (railstation?.locationDetails?.countryCode) {
17519
+ locationDetail.countryCode = railstation.locationDetails.countryCode;
17520
+ }
17474
17521
  this.location = locationDetail;
17475
17522
  }
17476
17523
  catch {
@@ -17486,7 +17533,13 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
17486
17533
  const arriveLocation = outboundFlights[outboundFlights.length - 1]?.destinationAirportDetail;
17487
17534
  if (arriveLocation) {
17488
17535
  this.country = { cCode: arriveLocation.countryCode, cName: arriveLocation.countryName };
17489
- this.location = { countryCode: arriveLocation.countryCode, latitude: arriveLocation.latitude, longitude: arriveLocation.longitude, type: LocationTypes.City, name: arriveLocation.city };
17536
+ this.location = {
17537
+ countryCode: arriveLocation.countryCode,
17538
+ latitude: arriveLocation.latitude,
17539
+ longitude: arriveLocation.longitude,
17540
+ type: LocationTypes.City,
17541
+ name: arriveLocation.city
17542
+ };
17490
17543
  }
17491
17544
  else {
17492
17545
  this.location = null;
@@ -17509,13 +17562,25 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
17509
17562
  switch (carHireSearch.locationType) {
17510
17563
  case LocationTypes.Airport:
17511
17564
  this.country = { cCode: pickup_location.countryCode, cName: pickup_location.country };
17512
- this.location = { countryCode: pickup_location.countryCode, latitude: pickup_location.latitude, longitude: pickup_location.longitude, type: LocationTypes.City, name: pickup_location.destination };
17565
+ this.location = {
17566
+ countryCode: pickup_location.countryCode,
17567
+ latitude: pickup_location.latitude,
17568
+ longitude: pickup_location.longitude,
17569
+ type: LocationTypes.City,
17570
+ name: pickup_location.destination
17571
+ };
17513
17572
  break;
17514
17573
  case LocationTypes.City:
17515
17574
  {
17516
17575
  const cityCountryInfo = Countries.find(c => c.cCode === cityPickup.countryCode);
17517
17576
  this.country = { cCode: cityCountryInfo.cCode, cName: cityCountryInfo.cName };
17518
- this.location = { countryCode: cityPickup.countryCode, latitude: cityPickup.latitude, longitude: cityPickup.longitude, type: LocationTypes.City, name: cityPickup.city ? cityPickup.city : cityPickup.name };
17577
+ this.location = {
17578
+ countryCode: cityPickup.countryCode,
17579
+ latitude: cityPickup.latitude,
17580
+ longitude: cityPickup.longitude,
17581
+ type: LocationTypes.City,
17582
+ name: cityPickup.city ? cityPickup.city : cityPickup.name
17583
+ };
17519
17584
  }
17520
17585
  break;
17521
17586
  case LocationTypes.Postcode:
@@ -17523,7 +17588,12 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
17523
17588
  const postCodeCountryInfo = Countries.find(c => c.cCode === postcodePickup.countryCode);
17524
17589
  this.country = { cCode: postCodeCountryInfo.cCode, cName: postCodeCountryInfo.cName };
17525
17590
  this.location = null;
17526
- this.location = { countryCode: postcodePickup.countryCode, postcode: postcodePickupRaw.postcode, type: LocationTypes.City, name: postcodePickupRaw.postcode };
17591
+ this.location = {
17592
+ countryCode: postcodePickup.countryCode,
17593
+ postcode: postcodePickupRaw.postcode,
17594
+ type: LocationTypes.City,
17595
+ name: postcodePickupRaw.postcode
17596
+ };
17527
17597
  this.postcode = postcodePickupRaw;
17528
17598
  }
17529
17599
  break;
@@ -18021,9 +18091,7 @@ class HotelEnterpriseSearch extends BaseEnterpriseSearch {
18021
18091
  this.no_of_rooms = query.rooms;
18022
18092
  // Don't populate hotel_name from recent search to avoid duplication with location field
18023
18093
  // The hotel name will be used from location.name as fallback in buildQuery()
18024
- this.hotel_name = cloneBasketItem
18025
- ? this.clonedBasketItemDetails.hotelName
18026
- : null;
18094
+ this.hotel_name = cloneBasketItem ? this.clonedBasketItemDetails.hotelName : null;
18027
18095
  this.hotel_chain = query.groupName ? { name: query.groupName } : null;
18028
18096
  this.country = query.countryCode
18029
18097
  ? (this.country = {
@@ -29318,6 +29386,8 @@ class BaseRequiresReasonService {
29318
29386
  basketService;
29319
29387
  currentBasketid;
29320
29388
  workingOn;
29389
+ processedDualSingleBasketItems = new Set();
29390
+ pendingDualSingleBasketItem = null;
29321
29391
  reasonChecked = new BehaviorSubject(null);
29322
29392
  reasonSelected = new BehaviorSubject(false);
29323
29393
  isReasonCancel;
@@ -29327,13 +29397,47 @@ class BaseRequiresReasonService {
29327
29397
  this.modalService = modalService;
29328
29398
  this.basketService = basketService;
29329
29399
  }
29400
+ isDualSingleFlight(basket) {
29401
+ return basket.basketItems.length === 2 &&
29402
+ basket.basketItems.every(item => item?.service?.type === ServiceType.Flight && item?.detail?.journeyType === 'single') &&
29403
+ basket.basketItems.every(item => item?.reasonKeys?.length > 0) &&
29404
+ JSON.stringify(basket.basketItems[0]?.searchQuery) === JSON.stringify(basket.basketItems[1]?.searchQuery);
29405
+ }
29406
+ isFirstLegOfDualSingle(basket) {
29407
+ return basket.basketItems.length === 1 &&
29408
+ basket.basketItems[0]?.service?.type === ServiceType.Flight &&
29409
+ basket.basketItems[0]?.detail?.journeyType === 'single' &&
29410
+ basket.basketItems[0]?.reasonKeys?.length > 0 &&
29411
+ basket.basketItems[0]?.searchQuery?.returnTrip === true;
29412
+ }
29413
+ getFilteredManagementInfo(basketItem) {
29414
+ return basketItem.managementInfo?.filter((mi) => {
29415
+ return mi.required && this.reasonKeysOverlap(basketItem.reasonKeys, mi.managementInfo.reasonKeys);
29416
+ }) || [];
29417
+ }
29418
+ buildWorkingOnForItems(basket, basketItems, isDualSingle) {
29419
+ return {
29420
+ basket,
29421
+ isDualSingleFlight: isDualSingle,
29422
+ required: basketItems.reduce((required, bi) => {
29423
+ required[bi.id] = this.getFilteredManagementInfo(bi);
29424
+ return required;
29425
+ }, {})
29426
+ };
29427
+ }
29330
29428
  async addBasketItem(basket, basketItemId) {
29331
29429
  if (basket.id !== this.currentBasketid) {
29430
+ this.processedDualSingleBasketItems.clear();
29431
+ this.pendingDualSingleBasketItem = null;
29432
+ return;
29433
+ }
29434
+ const isDualSingle = this.isDualSingleFlight(basket);
29435
+ if (isDualSingle && this.processedDualSingleBasketItems.has(basketItemId)) {
29332
29436
  return;
29333
29437
  }
29334
29438
  const basketItems = basket.basketItems.filter((bi) => {
29335
- return (!bi.agentOverrodeUnavailable && // we ask for reason and override in the override modal if applicable
29336
- basketItemId === bi.id &&
29439
+ return (!bi.agentOverrodeUnavailable &&
29440
+ (isDualSingle ? true : basketItemId === bi.id) &&
29337
29441
  bi.reasonKeys?.length &&
29338
29442
  !!bi.managementInfo?.filter((mi) => {
29339
29443
  return mi.required && !mi.selectedValue && this.reasonKeysOverlap(bi.reasonKeys, mi.managementInfo.reasonKeys);
@@ -29341,22 +29445,31 @@ class BaseRequiresReasonService {
29341
29445
  });
29342
29446
  this.isReadyToBook.next(false);
29343
29447
  if (basketItems.length > 0) {
29344
- this.workingOn = {
29345
- basket,
29346
- required: basketItems.reduce((required, bi) => {
29347
- required[bi.id] = bi.managementInfo?.filter((mi) => {
29348
- return mi.required && this.reasonKeysOverlap(bi.reasonKeys, mi.managementInfo.reasonKeys);
29349
- });
29350
- return required;
29351
- }, {})
29352
- };
29353
- // Check if dialog is not already open
29448
+ const isFirstLeg = this.isFirstLegOfDualSingle(basket);
29449
+ const hasPendingItemThatNeedsModal = this.pendingDualSingleBasketItem && basket.basketItems.length === 2 && !isDualSingle;
29450
+ if (hasPendingItemThatNeedsModal) {
29451
+ const pendingItem = basket.basketItems.find(item => item.id === this.pendingDualSingleBasketItem);
29452
+ if (pendingItem) {
29453
+ this.workingOn = this.buildWorkingOnForItems(basket, [pendingItem], false);
29454
+ }
29455
+ this.pendingDualSingleBasketItem = null;
29456
+ }
29457
+ else if (isFirstLeg && !hasPendingItemThatNeedsModal) {
29458
+ this.pendingDualSingleBasketItem = basketItemId;
29459
+ return;
29460
+ }
29461
+ else {
29462
+ this.workingOn = this.buildWorkingOnForItems(basket, basketItems, isDualSingle);
29463
+ }
29354
29464
  if (!this.basketService.isDialogOpen.value) {
29355
29465
  this.basketService.isDialogOpen.next(true);
29356
29466
  await this.showDialogueWithNewData(this.workingOn);
29357
29467
  }
29358
29468
  }
29359
29469
  else {
29470
+ if (this.pendingDualSingleBasketItem && basket.basketItems.length === 2) {
29471
+ this.pendingDualSingleBasketItem = null;
29472
+ }
29360
29473
  this.reasonChecked.next({
29361
29474
  basketId: this.currentBasketid,
29362
29475
  reason: ''
@@ -29374,16 +29487,28 @@ class BaseRequiresReasonService {
29374
29487
  this.basketService.isDialogOpen.next(false);
29375
29488
  this.basketService.toggleMenu();
29376
29489
  this.reasonSelected.next(true);
29490
+ workingOn.basket?.basketItems.forEach(bi => {
29491
+ this.processedDualSingleBasketItems.add(bi.id);
29492
+ });
29493
+ const parentMiIdToValue = {};
29494
+ Object.keys(results).forEach(miId => {
29495
+ const bi = workingOn.basket?.basketItems.find(item => item.managementInfo?.some(mi => mi.managementInfo.id === miId));
29496
+ const mi = bi?.managementInfo?.find(m => m.managementInfo.id === miId);
29497
+ if (mi && results[miId]) {
29498
+ parentMiIdToValue[mi.managementInfo.parentManagementInfoId] = results[miId];
29499
+ }
29500
+ });
29377
29501
  await Promise.all(workingOn.basket?.basketItems.map((bi) => {
29378
29502
  return Promise.all((bi.managementInfo || []).map((mi) => {
29379
- if (results[mi.managementInfo.id]) {
29503
+ const selectedValue = results[mi.managementInfo.id] || parentMiIdToValue[mi.managementInfo.parentManagementInfoId];
29504
+ if (selectedValue && mi.required && this.reasonKeysOverlap(bi.reasonKeys, mi.managementInfo.reasonKeys)) {
29380
29505
  this.reasonChecked.next({
29381
29506
  basketId: this.currentBasketid,
29382
- reason: results[mi.managementInfo.id]
29507
+ reason: selectedValue
29383
29508
  });
29384
29509
  const value = {
29385
29510
  miId: mi.managementInfo.id,
29386
- miValueId: results[mi.managementInfo.id],
29511
+ miValueId: selectedValue,
29387
29512
  miFreeValue: ''
29388
29513
  };
29389
29514
  return this.basketService.setMiValues(false, value);
@@ -29399,6 +29524,10 @@ class BaseRequiresReasonService {
29399
29524
  workingOn = null;
29400
29525
  }
29401
29526
  else {
29527
+ // Clear processed items for cancelled items
29528
+ workingOn.basket?.basketItems.forEach(bi => {
29529
+ this.processedDualSingleBasketItems.delete(bi.id);
29530
+ });
29402
29531
  await Promise.all(Object.entries(workingOn.required).map(([biId, mis]) => {
29403
29532
  return this.basketService.removeBasketItem(workingOn.basket.id, workingOn.basket.basketItems.find((bi) => bi.id === biId));
29404
29533
  }));
@@ -29693,16 +29822,20 @@ class InternalBasket {
29693
29822
  };
29694
29823
  toSend.mixedCurrency = Object.keys(toSend.prices).length > 1;
29695
29824
  this._basketSubject.next(toSend);
29696
- if (basket.basketItems.every(item => item?.detail?.outwardDetail?.splitID)) {
29697
- if (!(basket.basketItems.length % 2)) {
29825
+ // Only check for requires-reason when a specific basket item is being added
29826
+ // Don't trigger when basketItemId is empty (basket-wide updates like setting MI values)
29827
+ if (basketItemId !== '') {
29828
+ if (basket.basketItems.every(item => item?.detail?.outwardDetail?.splitID)) {
29829
+ if (!(basket.basketItems.length % 2)) {
29830
+ this.requiresService.addBasketItem(basket, basketItemId);
29831
+ this.requiresOverrideService.addBasketItem(basket);
29832
+ }
29833
+ }
29834
+ else {
29698
29835
  this.requiresService.addBasketItem(basket, basketItemId);
29699
29836
  this.requiresOverrideService.addBasketItem(basket);
29700
29837
  }
29701
29838
  }
29702
- else {
29703
- this.requiresService.addBasketItem(basket, basketItemId);
29704
- this.requiresOverrideService.addBasketItem(basket);
29705
- }
29706
29839
  }
29707
29840
  }
29708
29841
  class BaseEnterpriseBasketService {
@@ -30163,7 +30296,7 @@ class BaseEnterpriseBasketService {
30163
30296
  this.addingToBasket.next(true);
30164
30297
  // this is the last point
30165
30298
  try {
30166
- const newBasket = await this.addItemToBasketUpdater.updateOne(item).toPromise();
30299
+ const newBasket = await this.addItemToBasketUpdater.updateOne(item).pipe(take(1)).toPromise();
30167
30300
  this.miViewed = false;
30168
30301
  // here I want the new basketItem Id
30169
30302
  const oldItemIds = intBasket.subject.value.basketItems.map(item => item.id);
@@ -30322,7 +30455,7 @@ class BaseEnterpriseBasketService {
30322
30455
  const newBasket = await this.removeItemFromBasketUpdater.updateOne({
30323
30456
  convertCurrencyTo: this.userCurrency,
30324
30457
  basketItem: item.id
30325
- }).toPromise();
30458
+ }).pipe(take(1)).toPromise();
30326
30459
  if (newBasket) {
30327
30460
  this.miViewed = false;
30328
30461
  intBasket?.next({
@@ -30338,7 +30471,7 @@ class BaseEnterpriseBasketService {
30338
30471
  const newBasket = await this.removeItemFromBasketUpdater.updateOne({
30339
30472
  convertCurrencyTo: this.userCurrency,
30340
30473
  basketItem: item.id
30341
- }).toPromise();
30474
+ }).pipe(take(1)).toPromise();
30342
30475
  if (newBasket) {
30343
30476
  this.miViewed = false;
30344
30477
  intBasket?.next({
@@ -30354,7 +30487,7 @@ class BaseEnterpriseBasketService {
30354
30487
  const newBasket = await this.removeItemFromBasketUpdater.updateOne({
30355
30488
  convertCurrencyTo: this.userCurrency,
30356
30489
  basketItem: item.id
30357
- }).toPromise();
30490
+ }).pipe(take(1)).toPromise();
30358
30491
  if (newBasket) {
30359
30492
  this.miViewed = false;
30360
30493
  intBasket?.next({
@@ -30516,7 +30649,7 @@ class BaseEnterpriseBasketService {
30516
30649
  }
30517
30650
  // check the item.detail object against the relevant service detailSchema using Ajv
30518
30651
  const ajv = new Ajv();
30519
- addFormats(ajv);
30652
+ // addFormats(ajv); <=== this is problem for app
30520
30653
  // Custom Javascript ISO Date Time format
30521
30654
  ajv.addFormat('js-date-time', (dateTimeString) => {
30522
30655
  if (typeof dateTimeString === 'object' && dateTimeString.hasOwnProperty('toISOString')) {
@@ -30889,7 +31022,8 @@ class BaseEnterpriseBasketService {
30889
31022
  paymentMethod
30890
31023
  });
30891
31024
  }
30892
- bookBasket(basketid, supplementaryInfo, additionalEmail, approverNotes) {
31025
+ bookBasket(basketid, supplementaryInfo, additionalEmail, notificationOptIn, // <-- ADD THIS PARAMETER
31026
+ approverNotes) {
30893
31027
  this.isApprovedBasket = false;
30894
31028
  return this.bookBasketUpdater
30895
31029
  .updateOne({
@@ -30897,6 +31031,7 @@ class BaseEnterpriseBasketService {
30897
31031
  id: basketid,
30898
31032
  supplementaryInfo,
30899
31033
  additionalEmail,
31034
+ notificationOptIn, // <-- PASS THE PARAMETER HERE
30900
31035
  approverNotes
30901
31036
  })
30902
31037
  .pipe(take(1))
@@ -30923,6 +31058,11 @@ class BaseEnterpriseBasketService {
30923
31058
  intBasketItem.pnrLocator = basket.basketItems[i].pnrLocator;
30924
31059
  intBasketItem.bookingDetail =
30925
31060
  basket.basketItems[i]?.bookingDetail || intBasketItem.bookingDetail;
31061
+ intBasketItem.price = basket.basketItems[i].price;
31062
+ intBasketItem.latestValidationPrice = basket.basketItems[i].latestValidationPrice;
31063
+ intBasketItem.latestValidationPriceDifference = basket.basketItems[i].latestValidationPriceDifference;
31064
+ intBasketItem.latestValidationAvailable = basket.basketItems[i].latestValidationAvailable;
31065
+ intBasketItem.validated = basket.basketItems[i].validated;
30926
31066
  }
30927
31067
  else {
30928
31068
  console.error(`+++ Unable to find basket item with id: ${responseBasketItems.id} +++`);
@@ -31698,22 +31838,32 @@ const PREFERENCE_KEYS = [
31698
31838
  { key: "7", label: "Flight Notifications", value: "FLIGHT_NOTIFICATIONS_ENABLED", type: "FLIGHT" },
31699
31839
  ];
31700
31840
  const PREFERENCE_VALUES = [
31841
+ { label: "Asian Vegetarian", type: "MEAL_REQUEST", code: "AVML" },
31701
31842
  { label: "Bland", type: "MEAL_REQUEST", code: "BLML" },
31702
31843
  { label: "Child", type: "MEAL_REQUEST", code: "CHML" },
31703
31844
  { label: "Diabetic", type: "MEAL_REQUEST", code: "DBML" },
31845
+ { label: "Fish", type: "MEAL_REQUEST", code: "FSML" },
31704
31846
  { label: "Fruit Plate", type: "MEAL_REQUEST", code: "FPML" },
31705
- { label: "Gluten intolerant", type: "MEAL_REQUEST", code: "GFML" },
31847
+ { label: "Gluten Free", type: "MEAL_REQUEST", code: "GFML" },
31706
31848
  { label: "Hindu", type: "MEAL_REQUEST", code: "HNML" },
31849
+ { label: "Indian Vegetarian", type: "MEAL_REQUEST", code: "IVML" },
31850
+ { label: "Japanese", type: "MEAL_REQUEST", code: "JPML" },
31707
31851
  { label: "Kosher", type: "MEAL_REQUEST", code: "KSML" },
31852
+ { label: "Kosher Vegetarian", type: "MEAL_REQUEST", code: "KVML" },
31853
+ { label: "Low Calorie", type: "MEAL_REQUEST", code: "LCML" },
31708
31854
  { label: "Low Fat/Cholesterol", type: "MEAL_REQUEST", code: "LFML" },
31709
31855
  { label: "Low Sodium", type: "MEAL_REQUEST", code: "LSML" },
31710
31856
  { label: "Muslim", type: "MEAL_REQUEST", code: "MOML" },
31857
+ { label: "No Fish", type: "MEAL_REQUEST", code: "NFML" },
31711
31858
  { label: "Non-Lactose", type: "MEAL_REQUEST", code: "NLML" },
31859
+ { label: "No Salt", type: "MEAL_REQUEST", code: "NSML" },
31860
+ { label: "Peanuts Free", type: "MEAL_REQUEST", code: "PFML" },
31712
31861
  { label: "Raw Vegetarian/Vegan", type: "MEAL_REQUEST", code: "RVML" },
31713
31862
  { label: "Seafood", type: "MEAL_REQUEST", code: "SFML" },
31714
31863
  { label: "Vegetarian-Vegan", type: "MEAL_REQUEST", code: "VGML" },
31864
+ { label: "Vegetarian Jain", type: "MEAL_REQUEST", code: "VJML" },
31715
31865
  { label: "Vegetarian Lacto-Ovo", type: "MEAL_REQUEST", code: "VLML" },
31716
- { label: "Asian Vegetarian", type: "MEAL_REQUEST", code: "VOML" },
31866
+ { label: "Vegetarian Oriental", type: "MEAL_REQUEST", code: "VOML" },
31717
31867
  { label: "Aisle", type: "SEATING_PREFERENCE" },
31718
31868
  { label: "Window", type: "SEATING_PREFERENCE" },
31719
31869
  { label: "Bassinet", type: "SPECIAL_NEED", code: "BSCT" },
@@ -39016,10 +39166,10 @@ class BaseEnterpriseSearchService {
39016
39166
  const obs = this.searchDiscoverLocationFetcher.fetchList(query);
39017
39167
  return obs.pipe(take(1), finalize(() => isLoading?.next(false)));
39018
39168
  }
39019
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: BaseEnterpriseSearchService, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
39020
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.11", type: BaseEnterpriseSearchService, isStandalone: true, ngImport: i0 });
39169
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: BaseEnterpriseSearchService, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive });
39170
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.15", type: BaseEnterpriseSearchService, isStandalone: true, ngImport: i0 });
39021
39171
  }
39022
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: BaseEnterpriseSearchService, decorators: [{
39172
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.15", ngImport: i0, type: BaseEnterpriseSearchService, decorators: [{
39023
39173
  type: Directive
39024
39174
  }], ctorParameters: () => [{ type: BaseSearchAirportsFetcher }, { type: BaseSearchAirlinesFetcher }, { type: BaseStorageService }, { type: undefined }, { type: BaseModalOpenerService }, { type: undefined }, { type: BaseHelperRoutines }, { type: BaseHotelAvalibilityService }, { type: BaseSearchCityFetcher }, { type: BaseSearchPostcodeFetcher }, { type: BaseSearchRailStationsFetcher }, { type: BaseSaveUserAddressUpdater }, { type: BaseEditUserAddressUpdater }, { type: BaseUserAddressesFetcher }, { type: undefined }, { type: BaseGetUserCompanyOfficesFetcher }, { type: BaseSearchHotelChainsFetcher }, { type: BaseGetConfermaRoomImagesFetcher }, { type: BaseValidateIsPostcodeValidTester }, { type: BaseSearchDepotFetcher }, { type: BaseDeleteUserAddressUpdater }, { type: BaseDeleteRecentSearchUpdater }, { type: BaseSaveRecentSearchUpdater }, { type: BaseGetUserCarbonAllowanceFetcher }, { type: BaseSaveFavouriteSearchUpdater }, { type: BaseEnvironment }, { type: BaseLoungeQuoteFetcher }, { type: BaseParkingQuoteFetcher }, { type: AbstractHttpCallService }, { type: BaseFlightQuoteFetcher }, { type: BaseHotelQuoteFetcher }, { type: BaseCarhireQuoteFetcher }, { type: BaseCarHireAvailabilityDetailFetcher }, { type: BaseCabhireQuoteFetcher }, { type: BaseRailQuoteFetcher }, { type: BaseIrlQuoteFetcher }, { type: BaseGetRailStationInfoFetcher }, { type: BaseGetRailStationFetcher }, { type: BaseGetIrlSupplierStationFetcher }, { type: BaseWebTokenService }, { type: BaseGetRiskAlertsFetcher }, { type: BaseSearchConfermaQuicklistFetcher }, { type: BaseGetUserRecentSearchesFetcher }, { type: BaseGetRailcardsFetcher }, { type: BaseGetCovidMicrositeTokenFetcher }, { type: BaseEurostarQuoteFetcher }, { type: BaseSearchUsersCanBookForFetcher }, { type: BaseSearchIrlStationsFetcher }, { type: BaseIrlDiscountCardFetcher }, { type: BaseGetFlightFareRulesFetcher }, { type: BaseGetFlightSeatMapFetcher }, { type: BaseGetRailLiveDeparturesFetcher }, { type: BaseHotelRulesFetcher }, { type: BaseApplyJitFlightRulesFetcher }, { type: BaseGetUserFavouriteSearchesFetcher }, { type: BaseDeleteFavouriteSearchUpdater }, { type: BaseEmailBasketFetcher }, { type: BaseFastTrackQuoteFetcher }, { type: BaseSendOfflineNotificationFetcher }, { type: BaseGetHotelChainsFetcher }, { type: BaseGetRailProvidersFetcher }, { type: BaseGetAllAirlinesFetcher }, { type: BaseGetCarHireProvidersFetcher }, { type: BaseGenerateBasketPdfFetcher }, { type: BaseEmailFerryBookingFetcher }, { type: BaseGetFlightExtrasOptionsFetcher }, { type: BaseConvertCurrencyFetcher }, { type: BaseGetCurrencyConversionRatesFetcher }, { type: BaseGetHotelDetailsFetcher }, { type: BaseGetServiceFetcher }, { type: BaseGetFlightBrandedFaresFetcher }, { type: BaseGetTrainlineSearchConfigFetcher }, { type: BaseSearchRailInwardFetcher }, { type: BaseRailSearchExchangeFetcher }, { type: BaseCreateItineraryExchangeUpdater }, { type: BaseGetAirAvailabilityFetcher }, { type: BaseGetFlightAtNewClassFetcher }, { type: BaseGetFlightUpsellOffersFetcher }, { type: BaseGetOfficesFetcher }, { type: BaseEmailApartmentBookingFetcher }, { type: BaseEmailSeasonTicketBookingFetcher }, { type: BaseSuggestPlacesFetcher }, { type: BaseGetLatLonFromHereIdFetcher }, { type: BaseGetGmtItineraryOptionsFetcher }, { type: BaseGetGutCitySuggestionsFetcher }, { type: BaseGetGutLocationSuggestionsFetcher }, { type: BaseGetRouteHappyFetcher }, { type: BaseGetMultipleHotelRatingFetcher }, { type: BaseEmailMeetingRoomBookingFetcher }, { type: BaseFlightSearchExchangeFetcher }, { type: BaseFlightExchangeDetailsFetcher }, { type: BaseGetEntLocationByPostcode }, { type: BaseGetEntLocationByCity }, { type: BaseGetUserRecentBoltSearchesFetcher }, { type: BaseSaveRecentBoltSearchUpdater }, { type: BaseGetFerryPortsFetcher }, { type: BaseGetBannerFetcher }, { type: BaseupdateDOBUpdater }, { type: BaseUpdateFlightSeatMapUpdater }, { type: BaseDeleteAllRecentSearchesUpdater }, { type: BaseGetOfficeDivisionsFetcher }, { type: BaseSearchGeoLocationFetcher }, { type: BaseSearchDiscoverLocationFetcher }] });
39025
39175