diff --git a/src/abax-client.ts b/src/abax-client.ts index 3f26c3a..4880716 100644 --- a/src/abax-client.ts +++ b/src/abax-client.ts @@ -142,35 +142,42 @@ export class AbaxClient { return { items: expenses.flatMap(expense => expense.items) }; } + /** Gets odometer values of trips. Required scopes: `abax_profile`, `open_api`, `open_api.trips`.*/ async getOdometerValuesOfTrips( input: GetOdometerValuesOfTripsInput, ): Promise { - // TODO: batch trips in batches of 150 (max allowed per query), similar to listTripExpenses - if (input.query.trip_ids.length > 150) { - throw new Error( - 'Cannot get odometer values of more than 150 trips at once', - ); + const tripIdBatches = input.query.trip_ids.reduce( + (batches, tripId) => { + const currentBatchIndex = batches.length - 1; + + if (batches[currentBatchIndex]?.length === 150) { + batches.push([tripId]); + } else if (batches[currentBatchIndex]) { + batches[currentBatchIndex]?.push(tripId); + } else { + batches[currentBatchIndex] = [tripId]; + } + + return batches; + }, + [[]], + ); + + const odometerValues: GetOdometerValuesOfTripsResponse['items'][] = []; + + for (const batch of tripIdBatches) { + const response = await this.getOdometerValuesOf150Trips({ + query: { trip_ids: batch }, + }); + + odometerValues.push(response.items); } - const call = this.buildCall() - .args<{ input: GetOdometerValuesOfTripsInput }>() - .method('get') - .path('v1/trips/odometerReadings') - .query( - ({ - input: { - query: { trip_ids }, - }, - }) => { - const params = new URLSearchParams(); - trip_ids.forEach(trip => params.append('trip_ids', trip)); - return params; - }, - ) - .parseJson(withZod(getOdometerValuesOfTripsResponseSchema)) - .build(); - return this.performRequest(apiKey => call({ input, apiKey })); + const items = odometerValues.flat(1); + + return { items }; } + /** Gets equipment by ID. Required scopes: `abax_profile`, `open_api`, `open_api.equipment` */ getEquipment(input: GetEquipmentInput): Promise { const call = this.buildCall() @@ -277,6 +284,35 @@ export class AbaxClient { return this.performRequest(apiKey => call({ input, apiKey })); } + private async getOdometerValuesOf150Trips( + input: GetOdometerValuesOfTripsInput, + ): Promise { + if (input.query.trip_ids.length > 150) { + throw new Error( + 'Cannot get odometer values of more than 150 trips at once', + ); + } + const call = this.buildCall() + .args<{ input: GetOdometerValuesOfTripsInput }>() + .method('get') + .path('v1/trips/odometerReadings') + .query( + ({ + input: { + query: { trip_ids }, + }, + }) => { + const params = new URLSearchParams(); + trip_ids.forEach(trip => params.append('trip_ids', trip)); + return params; + }, + ) + .parseJson(withZod(getOdometerValuesOfTripsResponseSchema)) + .build(); + + return this.performRequest(apiKey => call({ input, apiKey })); + } + private makeApiUrl() { if (this.config.environment === 'production' || !this.config.environment) { return apiUrls.production; diff --git a/src/calls/get-odometer-values.ts b/src/calls/get-odometer-values.ts index cb38105..8f49f92 100644 --- a/src/calls/get-odometer-values.ts +++ b/src/calls/get-odometer-values.ts @@ -2,7 +2,7 @@ import { z } from 'zod'; import type { QueryEnvelope } from '../common/types.js'; export type GetOdometerValuesOfTripsInput = QueryEnvelope<{ - /** Ids of trips. Can have up to 150 ids */ + /** Ids of trips. */ trip_ids: string[]; }>;