Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
],
"name": "@ofs-users/proxy",
"type": "module",
"version": "1.23.0",
"version": "1.24.0",
"description": "A Javascript proxy to access Oracle Field Service via REST API",
"main": "dist/ofs.es.js",
"module": "dist/ofs.es.js",
Expand Down
50 changes: 50 additions & 0 deletions src/OFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ import {
OFSSubmittedFormsResponse,
OFSActivityLinkTypeResponse,
OFSLinkTemplatesResponse,
OFSShowBookingGridParams,
OFSShowBookingGridResponse,
OFSGetActivityBookingOptionsParams,
OFSGetActivityBookingOptionsResponse,
} from "./model";

export * from "./model";
Expand Down Expand Up @@ -930,4 +934,50 @@ export class OFS {
const partialURL = `/rest/ofscMetadata/v1/timeSlots`;
return this._get(partialURL);
}

// Capacity API: Booking Grid
/**
* Retrieves the time slots in which an activity can be performed.
* @param params Parameters for the booking grid request
* @returns The booking grid response with available time slots
*/
async showBookingGrid(
params: OFSShowBookingGridParams
): Promise<OFSShowBookingGridResponse> {
const partialURL = "/rest/ofscCapacity/v1/showBookingGrid";
return this._post(partialURL, params);
}

// Capacity API: Activity Booking Options
/**
* Retrieves available booking options for an activity type on specific dates.
* @param params Parameters for the activity booking options request
* @returns The activity booking options response with available time slots by date/area
*/
async getActivityBookingOptions(
params: OFSGetActivityBookingOptionsParams
): Promise<OFSGetActivityBookingOptionsResponse> {
const partialURL = "/rest/ofscCapacity/v1/activityBookingOptions";
const queryParams: any = {};

// Known array parameters that need CSV conversion
const arrayParams = ['dates', 'areas', 'categories'];

// Process all parameters
for (const [key, value] of Object.entries(params)) {
if (value === undefined) continue;

if (arrayParams.includes(key) && Array.isArray(value)) {
// Convert arrays to CSV format
if (value.length > 0) {
queryParams[key] = value.join(',');
}
} else {
// Pass through all other parameters as-is
queryParams[key] = value;
}
}

return this._get(partialURL, queryParams);
}
}
157 changes: 156 additions & 1 deletion src/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -447,4 +447,159 @@ export class OFSSubmittedFormsResponse extends OFSResponse {
items: [],
};
}
1

// Capacity API: showBookingGrid
export interface OFSShowBookingGridParams {
activity: Record<string, any>;
dateFrom: string;
dateTo?: string;
identifyActivityBy?: 'activityId' | 'apptNumber' | 'apptNumberPlusCustomerNumber';
includeResourcesDictionary?: boolean;
includeTimeSlotsDictionary?: boolean;
returnReasons?: boolean;
resourceFields?: string[];
lateStartMitigation?: number;
forecastDuringBooking?: Record<string, any>;
}

export interface OFSBookingGridTimeSlot {
label: string;
originalQuota?: number;
remainingQuota?: number;
reason?: string;
recommendationInfo?: {
additionalTravel?: number;
travelKeyMatch?: boolean;
};
setPositionInRoute?: string;
}

export interface OFSBookingGridDate {
date: string;
timeSlots: OFSBookingGridTimeSlot[];
}

export interface OFSBookingGridArea {
label: string;
name?: string;
bucket?: string;
timeZone?: string;
timeZoneDiff?: number;
areaTimeSlots?: string[];
averageBucketTravel?: number;
dates: OFSBookingGridDate[];
}

export interface OFSTimeSlotDictionary {
label: string;
name?: string;
timeStart?: string;
timeEnd?: string;
active?: boolean;
isAllDay?: boolean;
}

export interface OFSResourceDictionary {
resourceId: string;
[key: string]: any;
}

export interface OFSShowBookingGridData {
actualAtTime?: string;
duration?: number;
travelTime?: number;
workZone?: string;
areas: OFSBookingGridArea[];
resourcesDictionary?: OFSResourceDictionary[];
timeSlotsDictionary?: OFSTimeSlotDictionary[];
}

export class OFSShowBookingGridResponse extends OFSResponse {
data: OFSShowBookingGridData = {
areas: [],
};
}

// Capacity API: getActivityBookingOptions
export interface OFSGetActivityBookingOptionsParams {
/** The type of the activity. Based on the activity type, predefined company-specific rules are applied (required) */
activityType: string;
/** The dates for which the booking options are requested in YYYY-MM-DD format (required) */
dates: string[];
/** Capacity area labels; if omitted and determineAreaByWorkZone=false, processes all visible areas */
areas?: string[];
/** Capacity category labels for filtering */
categories?: string[];
/** Customer city location; used for geocoding */
city?: string;
/** Customer postal code; used for geocoding */
postalCode?: string;
/** Customer state/province; used for geocoding */
stateProvince?: string;
/** Customer street address; used for geocoding */
streetAddress?: string;
/** Activity location latitude coordinate in degrees (-90 to 90) */
latitude?: number;
/** Activity location longitude coordinate in degrees (-180 to 180) */
longitude?: number;
/** If true, estimates activity duration using statistics. Default: true */
estimateDuration?: boolean;
/** If true, estimates travel time using statistics when configured. Default: true */
estimateTravelTime?: boolean;
/** If true, determines categories from work skill conditions. Default: true */
determineCategory?: boolean;
/** If true, determines work zone automatically; requires all work zone key fields. Default: true */
determineAreaByWorkZone?: boolean;
/** Duration in minutes when estimation disabled or statistical record unavailable. Default: activity type default */
defaultDuration?: number;
/** For day-0 bookings: only returns intervals starting after currentTime + this value (minutes) */
minTimeBeforeArrival?: number;
/** If true, returns areas with at least one matching category. Default: false */
includePartiallyDefinedCategories?: boolean;
/** Allow additional custom parameters as key-value pairs */
[key: string]: string | string[] | number | boolean | undefined;
}

export interface OFSBookingOptionsTimeSlot {
label: string;
originalQuota?: number;
remainingQuota?: number;
reason?: string;
recommendationInfo?: {
additionalTravel?: number;
travelKeyMatch?: boolean;
};
}

export interface OFSBookingOptionsArea {
label: string;
name?: string;
bucket?: string;
timeZone?: string;
timeZoneDiff?: number;
averageBucketTravel?: number;
averageTravelKeyTravel?: number;
timeSlots: OFSBookingOptionsTimeSlot[];
reason?: string;
}

export interface OFSBookingOptionsDate {
date: string;
areas: OFSBookingOptionsArea[];
}

export interface OFSGetActivityBookingOptionsData {
actualAtTime?: string;
duration?: number;
travelTime?: number;
workZone?: string;
categories?: string[];
dates: OFSBookingOptionsDate[];
timeSlotsDictionary?: OFSTimeSlotDictionary[];
}

export class OFSGetActivityBookingOptionsResponse extends OFSResponse {
data: OFSGetActivityBookingOptionsData = {
dates: [],
};
}
Loading
Loading