@sabstravtech/obtservices 0.2.2606171720 → 0.2.2606301620

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,6 +2,7 @@ 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
  /**
7
8
  * Handles chatbot-driven car hire searches. Registered with
@@ -15,15 +16,21 @@ export declare class ChatbotCarHireSearchService implements ChatbotTravelHandler
15
16
  private chatbotService;
16
17
  private searchService;
17
18
  private resultAwareService;
19
+ private userService;
18
20
  readonly travelType: "car-hire";
19
- constructor(chatbotService: ChatbotService, searchService: EnterpriseSearchService, resultAwareService: ResultAwareService);
21
+ private pendingDepotChoice;
22
+ constructor(chatbotService: ChatbotService, searchService: EnterpriseSearchService, resultAwareService: ResultAwareService, userService: UserService);
23
+ private ensureSelfTraveller;
20
24
  handle(parameters: ChatSearchParameters, autoSearch: boolean): Promise<void>;
21
25
  private runSearch;
22
26
  private buildCarHireCards;
23
27
  private calculateDays;
24
28
  private injectNoResultsMessage;
29
+ private injectLocationHelpMessage;
30
+ private handleDepotSelectionReply;
25
31
  private populateCarHireParams;
26
32
  private prefersAirport;
33
+ private resolveVendorCode;
27
34
  private resolveLocation;
28
35
  private resolveAirportLocation;
29
36
  private airportToLocation;
@@ -34,7 +41,14 @@ export declare class ChatbotCarHireSearchService implements ChatbotTravelHandler
34
41
  private applyCityPickup;
35
42
  private applyCityDropoff;
36
43
  private toCityLocation;
37
- private resolveCityDepot;
44
+ private resolveCityDepots;
45
+ private fetchDepotsWithinRadius;
46
+ private resolveDepot;
47
+ private resolveEnterpriseDepot;
48
+ private fetchEnterpriseDepots;
49
+ private toEnterpriseDepot;
50
+ private applyPostcodePickupAndDropoff;
51
+ private resolvePostcode;
38
52
  static ɵfac: i0.ɵɵFactoryDeclaration<ChatbotCarHireSearchService, never>;
39
53
  static ɵprov: i0.ɵɵInjectableDeclaration<ChatbotCarHireSearchService>;
40
54
  }
@@ -20,6 +20,12 @@ export declare class ChatbotFlightSearchService implements ChatbotTravelHandler
20
20
  private resultAwareService;
21
21
  private userService;
22
22
  readonly travelType: "flight";
23
+ /** The flight form exposes four preferred-carrier slots. */
24
+ private static readonly MAX_PREFERRED_CARRIERS;
25
+ /** Terms that mean "no airline preference" and should be ignored. */
26
+ private static readonly NO_CARRIER_PREFERENCE;
27
+ /** Regional/subsidiary markers, so "KLM" doesn't resolve to "KLM Cityhopper". */
28
+ private static readonly CARRIER_SUBSIDIARY;
23
29
  private resultsSubscription;
24
30
  /**
25
31
  * The most recent full search parameters (origin, destination, dates,
@@ -81,6 +87,14 @@ export declare class ChatbotFlightSearchService implements ChatbotTravelHandler
81
87
  private splitFlightsByLeg;
82
88
  /** Build a `ChatFlightLeg` from the flights assigned to a single leg. */
83
89
  private flightsToChatLeg;
90
+ /**
91
+ * Calendar days the arrival falls after departure (0 = same day, 1 = next
92
+ * day). Compares date components rather than elapsed time so a 23:30 → 00:40
93
+ * hop still counts as +1. Returns 0 when datetimes are missing/invalid so a
94
+ * lack of data never hides an otherwise-valid result. Accepts either a full
95
+ * `CondensedResult` (outbound) or its `inbound` sub-leg.
96
+ */
97
+ private arrivalDayOffset;
84
98
  private formatHHmm;
85
99
  private formatDuration;
86
100
  private toFlightCard;
@@ -120,6 +134,20 @@ export declare class ChatbotFlightSearchService implements ChatbotTravelHandler
120
134
  private mapCabinClass;
121
135
  private normalizeTime;
122
136
  private resolveAirport;
137
+ /**
138
+ * Build the de-duplicated list of carrier search terms from the chat
139
+ * parameters. Prefers the `airlines` array (up to {@link MAX_PREFERRED_CARRIERS})
140
+ * when present, else falls back to the singular airline/airlineCode. Drops
141
+ * "no preference" sentinels ("any"/"all"/empty) and terms shorter than 2 chars.
142
+ */
143
+ private collectCarrierTerms;
144
+ /**
145
+ * Resolve a single airline search term to a real {code, name} from the
146
+ * searchAirlines GraphQL source, trying the highest-confidence match first:
147
+ * exact IATA code, exact name, then non-subsidiary startsWith/contains — so
148
+ * "KLM" resolves to "KLM Royal Dutch Airlines" rather than "KLM Cityhopper".
149
+ */
150
+ private resolveCarrier;
123
151
  static ɵfac: i0.ɵɵFactoryDeclaration<ChatbotFlightSearchService, never>;
124
152
  static ɵprov: i0.ɵɵInjectableDeclaration<ChatbotFlightSearchService>;
125
153
  }
@@ -23,6 +23,7 @@ export declare class ChatbotHotelSearchService implements ChatbotTravelHandler {
23
23
  readonly travelType: "hotel";
24
24
  private availabilitySubscription;
25
25
  lastParameters: ChatSearchParameters | null;
26
+ markAsLoading(): void;
26
27
  get hasHotelResults(): boolean;
27
28
  constructor(chatbotService: ChatbotService, searchService: EnterpriseSearchService, hotelAvalibilityService: HotelAvalibilityService, resultAwareService: ResultAwareService, userService: UserService);
28
29
  handle(parameters: ChatSearchParameters, autoSearch: boolean): Promise<void>;
@@ -32,6 +33,7 @@ export declare class ChatbotHotelSearchService implements ChatbotTravelHandler {
32
33
  private buildHotelCards;
33
34
  private injectNoResultsMessage;
34
35
  private sortHotels;
36
+ private cheapestRoomTotal;
35
37
  private populateHotelParams;
36
38
  static ɵfac: i0.ɵɵFactoryDeclaration<ChatbotHotelSearchService, never>;
37
39
  static ɵprov: i0.ɵɵInjectableDeclaration<ChatbotHotelSearchService>;
@@ -26,6 +26,9 @@ export declare class ChatbotService extends BaseChatbotService implements OnDest
26
26
  parameters: ChatSearchParameters;
27
27
  autoSearch: boolean;
28
28
  }>;
29
+ /** Fires after the car hire chatbot handler has finished populating city/depot params,
30
+ * so the component can call updateLocation() to populate the depot dropdown options. */
31
+ carHireParamsReady$: Subject<void>;
29
32
  /** Re-rank already-cached results (no new search) — routed to the handler's resort(). */
30
33
  resortResults$: Subject<{
31
34
  parameters: ChatSearchParameters;
@@ -69,9 +72,14 @@ export declare class ChatbotService extends BaseChatbotService implements OnDest
69
72
  */
70
73
  private resolveAllowedFlightCabins;
71
74
  protected getUserFirstName(): string | undefined;
75
+ /** Set by ChatbotCarHireSearchService when the user is choosing from a depot list. */
76
+ depotSelectionHandler: ((text: string) => Promise<boolean>) | null;
72
77
  connect(): void;
73
78
  clearSession(): void;
74
79
  injectMessage(message: ChatMessage): void;
80
+ /** Remove the last assistant message from the UI (e.g. when it's been superseded). */
81
+ retractLastAssistantMessage(): void;
82
+ protected beforeEmit(text: string): Promise<boolean>;
75
83
  protected handleResponse(env: ChatWsResponse): void;
76
84
  /**
77
85
  * Toggle the chatbot's "searching" indicator from a travel-type handler.
@@ -1,7 +1,7 @@
1
1
  import { Router } from '@angular/router';
2
2
  import { EnterpriseSearchService } from './search.service';
3
3
  import { EnterpriseBasketService } from './enterprise-basket.service';
4
- import { CondensedResult, ChatRailFareTicket } from '@sabstravtech/obtservices/base';
4
+ import { CondensedResult, ChatRailFareTicket, ChatFlightFareTicket } from '@sabstravtech/obtservices/base';
5
5
  import * as i0 from "@angular/core";
6
6
  export declare class ResultAwareService {
7
7
  private searchService;
@@ -12,6 +12,12 @@ export declare class ResultAwareService {
12
12
  private currentServiceType;
13
13
  private railSourceId;
14
14
  private railReturnJourneys;
15
+ /** Raw flight itineraries per leg, kept so the chat cards' "Fare Rules" links
16
+ * can resolve a fare back to its underlying journey. Outbound holds the
17
+ * outbound + combined-return journeys; inbound holds dual-single return
18
+ * journeys (priced separately). */
19
+ private flightOutboundRaw;
20
+ private flightInboundRaw;
15
21
  private resultsAvailableSubject;
16
22
  resultsAvailable$: import("rxjs").Observable<boolean>;
17
23
  constructor(searchService: EnterpriseSearchService, basketService: EnterpriseBasketService, router: Router);
@@ -44,6 +50,15 @@ export declare class ResultAwareService {
44
50
  * Open the existing OBT rail "View Conditions" dialog for a fare displayed in the chat.
45
51
  */
46
52
  openRailFareDetails(ticket: ChatRailFareTicket): Promise<void>;
53
+ /** Store the raw flight journeys for each leg so the chat cards can open fare
54
+ * rules. Called by the chat flight-search service after a search/re-rank. */
55
+ setFlightRawLegs(outbound: any[], inbound: any[]): void;
56
+ /**
57
+ * Open the existing OBT flight "Fare Rules" dialog for a fare displayed in the
58
+ * chat — mirrors the results page's fares-table behaviour (makeFareRules +
59
+ * openFlightFareRules) so the user sees the same conditions modal.
60
+ */
61
+ openFlightFareDetails(ticket: ChatFlightFareTicket): Promise<void>;
47
62
  private collectFareTickets;
48
63
  hasResults(): boolean;
49
64
  clearResults(): void;
@@ -11,6 +11,12 @@ export interface CondensedResult {
11
11
  operator?: string;
12
12
  depart: string;
13
13
  arrive: string;
14
+ /** Raw ISO departure datetime (carries the calendar date). Used to detect
15
+ * next-day arrivals and filter overnight itineraries that the supplier
16
+ * returned despite an "arrive by" same-day constraint. */
17
+ departDateTime?: string;
18
+ /** Raw ISO arrival datetime (carries the calendar date). */
19
+ arriveDateTime?: string;
14
20
  stops: number;
15
21
  duration: string;
16
22
  price: number;
@@ -30,6 +36,8 @@ export interface CondensedResult {
30
36
  inbound?: {
31
37
  depart: string;
32
38
  arrive: string;
39
+ departDateTime?: string;
40
+ arriveDateTime?: string;
33
41
  stops: number;
34
42
  duration: string;
35
43
  flightNumbers?: string;
@@ -107,6 +115,14 @@ export interface ChatSearchParameters {
107
115
  maxConnections?: number;
108
116
  outboundTimeCriteria?: 'Depart' | 'Arrive';
109
117
  returnTimeCriteria?: 'Depart' | 'Arrive';
118
+ /** How a flight time target should shape the chat cards. `around` ranks cards
119
+ * by proximity to the time ("closest to / around / at 5pm"). `before`/`after`
120
+ * treat the time as a deadline/bound ("arrive by 11", "after 9am"): the cards
121
+ * are filtered to satisfy the bound but keep the normal results page's
122
+ * Preferred order. Omitted on an initial search (the supplier already
123
+ * windowed the results) so the cards just mirror the page's Preferred top. */
124
+ outboundTimeMode?: 'around' | 'before' | 'after';
125
+ returnTimeMode?: 'around' | 'before' | 'after';
110
126
  railClass?: 'Standard' | 'First' | 'All';
111
127
  viaStation?: string;
112
128
  viaCode?: string;
@@ -118,8 +134,17 @@ export interface ChatSearchParameters {
118
134
  isEuRail?: boolean;
119
135
  airline?: string;
120
136
  airlineCode?: string;
137
+ /** Sort field — values vary by travel type (flight: cheapest/fastest/shortest/most_direct/
138
+ * lowest_emissions/preferred/earliest_departure/latest_departure/earliest_arrival/latest_arrival;
139
+ * hotel: cheapest/distance/preferred/name). */
140
+ sortType?: 'cheapest' | 'fastest' | 'shortest' | 'most_direct' | 'lowest_emissions' | 'preferred' | 'earliest_departure' | 'latest_departure' | 'earliest_arrival' | 'latest_arrival' | 'distance' | 'name';
141
+ /** Up to four preferred airlines, mapped onto the form's carrier slots. When
142
+ * set this takes precedence over the singular airline/airlineCode. */
143
+ airlines?: {
144
+ name?: string;
145
+ code?: string;
146
+ }[];
121
147
  /** Sort field — values vary by travel type (flight: cheapest/fastest/shortest; hotel: cheapest/distance/preferred/name). */
122
- sortType?: 'cheapest' | 'fastest' | 'shortest' | 'distance' | 'preferred' | 'name';
123
148
  /** When showing additional hotel results, the number of results already shown. */
124
149
  resultOffset?: number;
125
150
  adults?: number;
@@ -143,6 +168,15 @@ export interface ChatSearchParameters {
143
168
  driverAge?: number;
144
169
  carVendor?: string;
145
170
  returnToPickup?: boolean;
171
+ /** Pickup postcode — when set, the car hire search runs in postcode mode
172
+ * instead of resolving a city/airport location. */
173
+ pickupPostcode?: string;
174
+ /** Dropoff postcode when different from the pickup postcode. */
175
+ dropoffPostcode?: string;
176
+ /** Enterprise-only — deliver the rental to the pickup location. */
177
+ delivery?: boolean;
178
+ /** Enterprise-only — collect the rental from the pickup location. */
179
+ collection?: boolean;
146
180
  }
147
181
  export interface ChatRailFareTicket {
148
182
  type: string;
@@ -210,6 +244,10 @@ export interface ChatFlightLeg {
210
244
  duration: string;
211
245
  /** 0 = direct, 1, 2+ */
212
246
  stops: number;
247
+ /** Calendar days the arrival falls after departure (0 = same day, 1 = next
248
+ * day, …). Lets the UI render a "+1" badge for overnight itineraries so a
249
+ * card like "20:50 → 15:35" isn't read as an impossible same-day flight. */
250
+ arrivalDayOffset?: number;
213
251
  /** Flight numbers joined e.g. "BA123/BA456" */
214
252
  flightNumbers: string;
215
253
  }
@@ -224,6 +262,9 @@ export interface ChatFlightFareTicket {
224
262
  currency: string;
225
263
  /** Index back into the underlying journeys array for select / navigate use */
226
264
  journeyIndex?: number;
265
+ /** True when this fare belongs to a separately-priced inbound (dual-single)
266
+ * leg, so the Fare Rules lookup reads the inbound raw journeys array. */
267
+ isReturnLeg?: boolean;
227
268
  }
228
269
  /** Flight fare breakdown for the expandable panel on a chat flight card. */
229
270
  export interface ChatFlightFareBreakdown {
@@ -439,14 +480,16 @@ export interface ChatSuggestion {
439
480
  travelDateFrom?: string;
440
481
  travelDateTo?: string;
441
482
  traveller?: string;
483
+ serviceTypes?: string[];
442
484
  };
443
485
  }
444
486
  /**
445
487
  * Filters handed off from the chat widget's "View My Bookings" button to the
446
488
  * My Bookings screen. The explicit `statuses` / `travelDateFrom` /
447
- * `travelDateTo` / `traveller` fields let My Bookings reproduce the exact set
448
- * the chatbot displayed; legacy callers may instead pass `departureDate` /
449
- * `fromDate`, in which case My Bookings falls back to its default window.
489
+ * `travelDateTo` / `traveller` / `serviceTypes` fields let My Bookings
490
+ * reproduce the exact set the chatbot displayed; legacy callers may instead
491
+ * pass `departureDate` / `fromDate`, in which case My Bookings falls back to
492
+ * its default window.
450
493
  */
451
494
  export interface MyBookingsBaseParams {
452
495
  statuses?: string[];
@@ -455,6 +498,7 @@ export interface MyBookingsBaseParams {
455
498
  traveller?: string;
456
499
  fromDate?: string;
457
500
  departureDate?: string;
501
+ serviceTypes?: string[];
458
502
  }
459
503
  export interface ChatRequest {
460
504
  message: string;
@@ -480,6 +524,10 @@ export interface IRiskFlag {
480
524
  countryCode: string;
481
525
  breaking: boolean;
482
526
  }
527
+ export interface ChatDepotChoice {
528
+ index: number;
529
+ label: string;
530
+ }
483
531
  export type ChatMessageRole = 'user' | 'assistant';
484
532
  export interface ChatMessage {
485
533
  id: string;
@@ -506,6 +554,7 @@ export interface ChatMessage {
506
554
  loungeResults?: ChatLoungeResults;
507
555
  searchResults?: CondensedResult[];
508
556
  searchHeader?: string;
557
+ depotChoices?: ChatDepotChoice[];
509
558
  }
510
559
  export type ChatbotFlightCabinClass = 'Economy' | 'PremiumEconomy' | 'Business' | 'First';
511
560
  export interface UserCapabilities {
@@ -515,6 +564,9 @@ export interface UserCapabilities {
515
564
  hideHotelSearchOptions: boolean;
516
565
  /** Cabin classes the user may search/book. Empty/absent = all allowed. */
517
566
  allowedFlightCabins?: ChatbotFlightCabinClass[];
567
+ /** Whether the account can search "Any"/all cabin classes at once. When
568
+ * false the user must search a specific cabin (the form hides "Any"). */
569
+ flightAnyCabinAllowed?: boolean;
518
570
  /** Whether multi-city flight itineraries are enabled for this account. */
519
571
  flightMultiCityEnabled?: boolean;
520
572
  /** Max legs allowed in a multi-city itinerary, when enabled. */
@@ -99,6 +99,13 @@ export declare abstract class BaseChatbotService {
99
99
  * 'Portal', 'App', etc.
100
100
  */
101
101
  protected getFeedbackSource(): ChatFeedbackSource;
102
+ /**
103
+ * Called after the user message is added to the UI but before it is emitted
104
+ * to the socket. Return `true` to short-circuit the emit (the message stays
105
+ * in the UI but the agent never sees it). Used by the Angular host to handle
106
+ * depot-selection replies locally without a round-trip to the AI agent.
107
+ */
108
+ protected beforeEmit(_text: string): Promise<boolean>;
102
109
  connect(): void;
103
110
  disconnect(): void;
104
111
  sendMessage(text: string): Promise<void>;
@@ -128,6 +135,8 @@ export declare abstract class BaseChatbotService {
128
135
  protected addAssistantMessage(text: string): void;
129
136
  /** Patch the most recent assistant message in-place (e.g. to attach rail results after search). */
130
137
  protected patchLastAssistantMessage(patch: Partial<ChatMessage>): void;
138
+ /** Remove the most recent assistant message from the UI. */
139
+ protected removeLastAssistantMessage(): void;
131
140
  protected setLoading(value: boolean): void;
132
141
  protected tearDownSocket(): void;
133
142
  protected generateId(): string;