@sabstravtech/obtservices 0.2.2606301620 → 0.2.2607131200

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.
@@ -2,18 +2,22 @@ import { ChatSearchParameters, ChatbotTravelHandler } from '@sabstravtech/obtser
2
2
  import { ChatbotService } from './chatbot.service';
3
3
  import { EnterpriseSearchService } from './search.service';
4
4
  import { ResultAwareService } from './result-aware.service';
5
+ import { UserService } from './user.service';
5
6
  import * as i0 from "@angular/core";
6
7
  export declare class ChatbotTaxiSearchService implements ChatbotTravelHandler {
7
8
  private chatbotService;
8
9
  private searchService;
9
10
  private resultAwareService;
11
+ private userService;
10
12
  readonly travelType: "taxi";
11
- constructor(chatbotService: ChatbotService, searchService: EnterpriseSearchService, resultAwareService: ResultAwareService);
13
+ constructor(chatbotService: ChatbotService, searchService: EnterpriseSearchService, resultAwareService: ResultAwareService, userService: UserService);
12
14
  handle(parameters: ChatSearchParameters, autoSearch: boolean): Promise<void>;
13
15
  private runSearch;
14
16
  private buildTaxiCards;
15
17
  private injectNoResultsMessage;
16
18
  private populateTaxiParams;
19
+ private searchAndResolveGeoLocation;
20
+ private locationDataToResolved;
17
21
  private resolveGeoLocation;
18
22
  private matchTerminal;
19
23
  static ɵfac: i0.ɵɵFactoryDeclaration<ChatbotTaxiSearchService, never>;
@@ -91,6 +91,15 @@ export declare class CabHireEnterpriseSearch<CH_Q extends CabhireQuoteFetcherTyp
91
91
  key: string;
92
92
  value: string;
93
93
  }[]);
94
+ private _viaTerminals;
95
+ get viaTerminals(): {
96
+ key: string;
97
+ value: string;
98
+ }[];
99
+ set viaTerminals(value: {
100
+ key: string;
101
+ value: string;
102
+ }[]);
94
103
  private _time;
95
104
  get time(): string;
96
105
  set time(value: string);
@@ -109,6 +109,10 @@ export interface CabHireEnterpriseSearchInterface extends BaseEnterpriseSearch<C
109
109
  key: string;
110
110
  value: string;
111
111
  }[];
112
+ viaTerminals: {
113
+ key: string;
114
+ value: string;
115
+ }[];
112
116
  time: string;
113
117
  departs: moment.Moment;
114
118
  adults: number;
@@ -153,11 +153,24 @@ export interface ChatSearchParameters {
153
153
  timeFlexibility?: number;
154
154
  refundableOnly?: boolean;
155
155
  via?: string;
156
+ viaLocationData?: string;
157
+ viaFlightNumber?: string;
158
+ viaFlightTime?: string;
159
+ viaCarrier?: string;
156
160
  vehicleType?: string;
157
161
  pickupTerminal?: string;
158
162
  pickupFlightNumber?: string;
163
+ pickupFlightTime?: string;
164
+ pickupCarrier?: string;
165
+ pickupLocationData?: string;
159
166
  dropoffTerminal?: string;
160
167
  dropoffFlightNumber?: string;
168
+ dropoffFlightTime?: string;
169
+ dropoffCarrier?: string;
170
+ dropoffLocationData?: string;
171
+ limoType?: string;
172
+ transportType?: string;
173
+ limoAsDirectedDuration?: number;
161
174
  locationCode?: string;
162
175
  flight?: string;
163
176
  terminal?: string;
@@ -265,6 +278,9 @@ export interface ChatFlightFareTicket {
265
278
  /** True when this fare belongs to a separately-priced inbound (dual-single)
266
279
  * leg, so the Fare Rules lookup reads the inbound raw journeys array. */
267
280
  isReturnLeg?: boolean;
281
+ /** True when this fare belongs to a multi-city itinerary, so the Fare Rules
282
+ * modal shows every leg's segment cards (matching the results page). */
283
+ isMultiCity?: boolean;
268
284
  }
269
285
  /** Flight fare breakdown for the expandable panel on a chat flight card. */
270
286
  export interface ChatFlightFareBreakdown {
@@ -17680,8 +17680,9 @@ class ResultAwareService {
17680
17680
  const searchParams = this.searchService.searches[ServiceType.Flight];
17681
17681
  if (typeof searchParams?.openFlightFareRules !== 'function')
17682
17682
  return;
17683
- const { rules, flights } = makeFareRules(journey, FlightDirectionEnum.Outbound);
17684
- const isReturn = (journey.inboundFlights?.length ?? 0) > 0;
17683
+ const isMultiCity = !!ticket.isMultiCity;
17684
+ const { rules, flights } = makeFareRules(journey, FlightDirectionEnum.Outbound, isMultiCity);
17685
+ const isReturn = !isMultiCity && (journey.inboundFlights?.length ?? 0) > 0;
17685
17686
  let inboundRules = null;
17686
17687
  let inboundFlights = null;
17687
17688
  if (isReturn) {
@@ -17689,7 +17690,9 @@ class ResultAwareService {
17689
17690
  inboundRules = inbound.rules;
17690
17691
  inboundFlights = inbound.flights;
17691
17692
  }
17692
- const flightDetail = isReturn ? journey : null;
17693
+ // Pass the whole itinerary as flightDetail so the modal renders every leg's
17694
+ // segment cards — matching the results page for both returns and multi-city.
17695
+ const flightDetail = isMultiCity || isReturn ? journey : null;
17693
17696
  searchParams.openFlightFareRules(rules, flights, journey.sourceId, { centered: true, size: 'xl' }, null, flightDetail, inboundRules, inboundFlights);
17694
17697
  }
17695
17698
  collectFareTickets(journey, sections, journeyIndex, isReturnLeg) {
@@ -19477,7 +19480,7 @@ class ChatbotFlightSearchService {
19477
19480
  * For combined-return journeys the key includes both outbound + inbound
19478
19481
  * flight numbers; for dual-single legs it's just that leg's numbers.
19479
19482
  */
19480
- indexFaresByFlights(raw, includeInbound, isReturnLeg = false) {
19483
+ indexFaresByFlights(raw, includeInbound, isReturnLeg = false, isMultiCity = false) {
19481
19484
  const map = new Map();
19482
19485
  if (!raw?.length)
19483
19486
  return map;
@@ -19485,7 +19488,7 @@ class ChatbotFlightSearchService {
19485
19488
  const key = this.flightSignature(it, includeInbound);
19486
19489
  if (!key)
19487
19490
  return;
19488
- const fare = this.toFareTicket(it, idx, isReturnLeg);
19491
+ const fare = this.toFareTicket(it, idx, isReturnLeg, isMultiCity);
19489
19492
  if (!fare)
19490
19493
  return;
19491
19494
  const arr = map.get(key) ?? [];
@@ -19518,7 +19521,7 @@ class ChatbotFlightSearchService {
19518
19521
  .join('/');
19519
19522
  return `${out}|${inn}`;
19520
19523
  }
19521
- toFareTicket(it, idx, isReturnLeg = false) {
19524
+ toFareTicket(it, idx, isReturnLeg = false, isMultiCity = false) {
19522
19525
  const price = it?.total?.price;
19523
19526
  if (!(price > 0))
19524
19527
  return null;
@@ -19541,7 +19544,8 @@ class ChatbotFlightSearchService {
19541
19544
  price,
19542
19545
  currency: it?.total?.currency || 'GBP',
19543
19546
  journeyIndex: idx,
19544
- isReturnLeg: isReturnLeg || undefined
19547
+ isReturnLeg: isReturnLeg || undefined,
19548
+ isMultiCity: isMultiCity || undefined
19545
19549
  };
19546
19550
  }
19547
19551
  /**
@@ -19583,7 +19587,7 @@ class ChatbotFlightSearchService {
19583
19587
  }
19584
19588
  }
19585
19589
  const sorted = [...bySig.values()];
19586
- const fareIndex = this.indexFaresByFlights(journeys, false, false);
19590
+ const fareIndex = this.indexFaresByFlights(journeys, false, false, true);
19587
19591
  const cards = [];
19588
19592
  for (let i = 0; i < Math.min(MAX_FLIGHT_CARDS, sorted.length); i++) {
19589
19593
  const journey = sorted[i];
@@ -21505,11 +21509,13 @@ class ChatbotTaxiSearchService {
21505
21509
  chatbotService;
21506
21510
  searchService;
21507
21511
  resultAwareService;
21512
+ userService;
21508
21513
  travelType = 'taxi';
21509
- constructor(chatbotService, searchService, resultAwareService) {
21514
+ constructor(chatbotService, searchService, resultAwareService, userService) {
21510
21515
  this.chatbotService = chatbotService;
21511
21516
  this.searchService = searchService;
21512
21517
  this.resultAwareService = resultAwareService;
21518
+ this.userService = userService;
21513
21519
  }
21514
21520
  async handle(parameters, autoSearch) {
21515
21521
  this.searchService.resetSearchChosenObjects();
@@ -21520,6 +21526,12 @@ class ChatbotTaxiSearchService {
21520
21526
  if (autoSearch) {
21521
21527
  this.chatbotService.setSearching(true, 'taxi');
21522
21528
  }
21529
+ if (this.searchService.travellerInformation.value.length === 0) {
21530
+ const selfTraveller = this.userService.createSelfTraveller();
21531
+ if (selfTraveller) {
21532
+ this.searchService.addTraveller(selfTraveller);
21533
+ }
21534
+ }
21523
21535
  await this.populateTaxiParams(parameters);
21524
21536
  if (!autoSearch) {
21525
21537
  return;
@@ -21618,11 +21630,34 @@ class ChatbotTaxiSearchService {
21618
21630
  if (parameters.vehicleType) {
21619
21631
  taxiSearch.vehicleType = parameters.vehicleType;
21620
21632
  }
21633
+ else {
21634
+ taxiSearch.vehicleType = CabHireVehicleType.Any;
21635
+ }
21636
+ if (parameters.limoType) {
21637
+ taxiSearch.limoType = parameters.limoType;
21638
+ }
21639
+ if (parameters.transportType) {
21640
+ taxiSearch.transportType = parameters.transportType;
21641
+ }
21642
+ if (parameters.limoAsDirectedDuration) {
21643
+ taxiSearch.limoAsDirectedDuration = parameters.limoAsDirectedDuration;
21644
+ }
21621
21645
  const [fromResolved, toResolved, viaResolved] = await Promise.all([
21622
- this.resolveGeoLocation(parameters.departure, taxiSearch),
21623
- this.resolveGeoLocation(parameters.arrival, taxiSearch),
21624
- parameters.via ? this.resolveGeoLocation(parameters.via, taxiSearch) : Promise.resolve(null),
21646
+ parameters.pickupLocationData
21647
+ ? this.locationDataToResolved(parameters.pickupLocationData, taxiSearch)
21648
+ : this.searchAndResolveGeoLocation(parameters.departure, taxiSearch),
21649
+ parameters.dropoffLocationData
21650
+ ? this.locationDataToResolved(parameters.dropoffLocationData, taxiSearch)
21651
+ : this.searchAndResolveGeoLocation(parameters.arrival, taxiSearch),
21652
+ parameters.viaLocationData
21653
+ ? this.locationDataToResolved(parameters.viaLocationData, taxiSearch)
21654
+ : parameters.via ? this.searchAndResolveGeoLocation(parameters.via, taxiSearch) : Promise.resolve(null),
21625
21655
  ]);
21656
+ // Clear via if this search has no stop
21657
+ if (!parameters.via && !parameters.viaLocationData) {
21658
+ taxiSearch.viasTo = null;
21659
+ taxiSearch.viaTerminals = [];
21660
+ }
21626
21661
  if (fromResolved) {
21627
21662
  const { result, address } = fromResolved;
21628
21663
  if (result.terminals?.length) {
@@ -21634,6 +21669,12 @@ class ChatbotTaxiSearchService {
21634
21669
  if (parameters.pickupFlightNumber) {
21635
21670
  address.FlightNumber = parameters.pickupFlightNumber;
21636
21671
  }
21672
+ if (parameters.pickupCarrier) {
21673
+ address.Carrier = parameters.pickupCarrier;
21674
+ }
21675
+ if (parameters.pickupFlightTime) {
21676
+ address.FlightTrainDateTime = parameters.pickupFlightTime;
21677
+ }
21637
21678
  taxiSearch.fromAddress = address;
21638
21679
  }
21639
21680
  if (toResolved) {
@@ -21647,37 +21688,70 @@ class ChatbotTaxiSearchService {
21647
21688
  if (parameters.dropoffFlightNumber) {
21648
21689
  address.FlightNumber = parameters.dropoffFlightNumber;
21649
21690
  }
21691
+ if (parameters.dropoffCarrier) {
21692
+ address.Carrier = parameters.dropoffCarrier;
21693
+ }
21694
+ if (parameters.dropoffFlightTime) {
21695
+ address.FlightTrainDateTime = parameters.dropoffFlightTime;
21696
+ }
21650
21697
  taxiSearch.toAddress = address;
21651
21698
  }
21652
21699
  if (viaResolved) {
21653
- taxiSearch.viasTo = viaResolved.address;
21700
+ const { result, address } = viaResolved;
21701
+ if (result.terminals?.length) {
21702
+ taxiSearch.viaTerminals = result.terminals;
21703
+ }
21704
+ if (parameters.viaFlightNumber)
21705
+ address.FlightNumber = parameters.viaFlightNumber;
21706
+ if (parameters.viaCarrier)
21707
+ address.Carrier = parameters.viaCarrier;
21708
+ if (parameters.viaFlightTime)
21709
+ address.FlightTrainDateTime = parameters.viaFlightTime;
21710
+ taxiSearch.viasTo = address;
21654
21711
  }
21655
21712
  }
21656
- async resolveGeoLocation(searchTerm, taxiSearch) {
21713
+ async searchAndResolveGeoLocation(searchTerm, taxiSearch) {
21657
21714
  if (!searchTerm)
21658
21715
  return null;
21659
21716
  try {
21660
21717
  const results = await firstValueFrom(this.searchService.getGeoLocations(searchTerm));
21661
21718
  if (results?.length) {
21662
- const term = searchTerm.toLowerCase();
21719
+ const term = searchTerm.toLowerCase().trim();
21720
+ const isIataCode = /^[a-z]{3}$/.test(term);
21663
21721
  let location = results[0];
21664
- if (term.includes('airport')) {
21665
- location = results.find((r) => r.type === 'Airport') ?? results[0];
21722
+ if (term.includes('airport') || isIataCode) {
21723
+ location = results.find((r) => r.type === LocationTypes.Airport) ?? results[0];
21666
21724
  }
21667
21725
  else if (term.includes('station') || term.includes('rail')) {
21668
- location = results.find((r) => r.type === 'Train Station') ?? results[0];
21669
- }
21670
- const address = taxiSearch.getAddress(location);
21671
- if (location.type === 'Airport' && !address?.Town) {
21672
- address.Town = location.name;
21726
+ location = results.find((r) => r.type === LocationTypes.TrainStation) ?? results[0];
21673
21727
  }
21674
- return { result: location, address };
21728
+ return this.resolveGeoLocation(location, taxiSearch);
21675
21729
  }
21676
21730
  }
21677
21731
  catch {
21678
21732
  }
21679
21733
  return null;
21680
21734
  }
21735
+ locationDataToResolved(locationDataJson, taxiSearch) {
21736
+ try {
21737
+ const location = JSON.parse(locationDataJson);
21738
+ // terminals from GetGeoLocationResult are raw string[] — process same as _getGeoLocations does
21739
+ if (Array.isArray(location.terminals)) {
21740
+ location.terminals = this.searchService.processTerminals(location.terminals);
21741
+ }
21742
+ return Promise.resolve(this.resolveGeoLocation(location, taxiSearch));
21743
+ }
21744
+ catch {
21745
+ return Promise.resolve(null);
21746
+ }
21747
+ }
21748
+ resolveGeoLocation(location, taxiSearch) {
21749
+ const address = taxiSearch.getAddress(location);
21750
+ if (location.type === LocationTypes.Airport && !address?.Town) {
21751
+ address.Town = location.name;
21752
+ }
21753
+ return { result: location, address };
21754
+ }
21681
21755
  matchTerminal(aiTerminal, terminals) {
21682
21756
  const t = aiTerminal.toLowerCase().trim();
21683
21757
  if (!t || t.includes('any') || t.includes('main'))
@@ -21688,13 +21762,13 @@ class ChatbotTaxiSearchService {
21688
21762
  const byKey = terminals.find((x) => x.key.toLowerCase().includes(t) || t.includes(x.value.toLowerCase()));
21689
21763
  return byKey ? byKey.key : null;
21690
21764
  }
21691
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotTaxiSearchService, deps: [{ token: ChatbotService }, { token: EnterpriseSearchService }, { token: ResultAwareService }], target: i0.ɵɵFactoryTarget.Injectable });
21765
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotTaxiSearchService, deps: [{ token: ChatbotService }, { token: EnterpriseSearchService }, { token: ResultAwareService }, { token: UserService }], target: i0.ɵɵFactoryTarget.Injectable });
21692
21766
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotTaxiSearchService, providedIn: 'root' });
21693
21767
  }
21694
21768
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.20", ngImport: i0, type: ChatbotTaxiSearchService, decorators: [{
21695
21769
  type: Injectable,
21696
21770
  args: [{ providedIn: 'root' }]
21697
- }], ctorParameters: () => [{ type: ChatbotService }, { type: EnterpriseSearchService }, { type: ResultAwareService }] });
21771
+ }], ctorParameters: () => [{ type: ChatbotService }, { type: EnterpriseSearchService }, { type: ResultAwareService }, { type: UserService }] });
21698
21772
 
21699
21773
  /** Safety timeout (ms) waiting for eurostar results. */
21700
21774
  const EUROSTAR_RESULTS_WAIT_MS = 60_000;