diff --git a/src/common/httpClient/models.ts b/src/common/httpClient/models.ts index 0213aac..a2247db 100644 --- a/src/common/httpClient/models.ts +++ b/src/common/httpClient/models.ts @@ -9,7 +9,7 @@ export enum HttpMethod { OPTIONS = 'OPTIONS', } -export type QueryParams = Record; +export type QueryParams = Record; export interface HttpRequestConfiguration { method: HttpMethod; diff --git a/src/fft-api/index.ts b/src/fft-api/index.ts index 8a42088..6b8481e 100644 --- a/src/fft-api/index.ts +++ b/src/fft-api/index.ts @@ -12,3 +12,4 @@ export * from './routing-plan'; export * from './shipment'; export * from './subscription'; export * from './types'; +export * from './stock'; diff --git a/src/fft-api/stock/fftStockService.ts b/src/fft-api/stock/fftStockService.ts new file mode 100644 index 0000000..339e012 --- /dev/null +++ b/src/fft-api/stock/fftStockService.ts @@ -0,0 +1,253 @@ +import { Logger } from 'tslog'; +import { FftApiClient } from '../common'; +import { + FacilityServiceType, + FacilityStatus, + Stock, + StockDistribution, + StockForCreation, + StockForUpdate, + StockPaginatedResult, + StocksForUpsert, + StockSummaries, + StockUpsertOperationResult, +} from '../types'; +import { CustomLogger, QueryParams } from '../../common'; +import { ResponseError } from 'superagent'; + +export class FftStockService { + private readonly path: string = 'stocks'; + private readonly logger: Logger = new CustomLogger(); + + constructor(private readonly apiClient: FftApiClient) {} + + public async createStock(stockForCreation: StockForCreation): Promise { + try { + return await this.apiClient.post(this.path, { ...stockForCreation }); + } catch (error) { + const httpError = error as ResponseError; + this.logger.error( + `Could not create stock. Failed with status ${httpError.status}, error: ${ + httpError.response ? JSON.stringify(httpError.response.body) : '' + }` + ); + + throw error; + } + } + + public async getAll( + facilityRef?: string, + tenantArticleIds?: string[], + locationRefs?: string[], + size?: number, + startAfterId?: string + ): Promise { + try { + const queryParams: QueryParams = {}; + + if (facilityRef) { + queryParams['facilityRef'] = facilityRef; + } + + if (tenantArticleIds) { + tenantArticleIds = tenantArticleIds.slice(0, 499); + queryParams['tenantArticleId'] = tenantArticleIds; + } + + if (locationRefs) { + locationRefs = locationRefs.slice(0, 499); + queryParams['locationRef'] = locationRefs; + } + + if (size && size <= 100) { + queryParams['size'] = size.toString(); + } + + if (startAfterId) { + queryParams['startAfterId'] = startAfterId; + } + + return await this.apiClient.get(this.path, queryParams); + } catch (error) { + const httpError = error as ResponseError; + this.logger.error( + `Fetching all stock failed with status ${httpError.status}, error: ${ + httpError.response ? JSON.stringify(httpError.response.body) : '' + }` + ); + + throw error; + } + } + + public async upsertStocks(stocksForUpsert: StocksForUpsert): Promise { + try { + return await this.apiClient.put(this.path, { ...stocksForUpsert }); + } catch (error) { + const httpError = error as ResponseError; + this.logger.error( + `Could not upsert stock. Failed with status ${httpError.status}, error: ${ + httpError.response ? JSON.stringify(httpError.response.body) : '' + }` + ); + + throw error; + } + } + + public async updateById(stockId: string, stockForUpdate: StockForUpdate): Promise { + try { + return await this.apiClient.put(`${this.path}/${stockId}`, { ...stockForUpdate }); + } catch (error) { + const httpError = error as ResponseError; + this.logger.error( + `Could not update stock. Failed with status ${httpError.status}, error: ${ + httpError.response ? JSON.stringify(httpError.response.body) : '' + }` + ); + + throw error; + } + } + + public async deleteById(stockId: string): Promise { + try { + return await this.apiClient.delete(`${this.path}/${stockId}`); + } catch (error) { + const httpError = error as ResponseError; + this.logger.error( + `Could not delete stock with id ${stockId}. Failed with status ${httpError.status}, error: ${ + httpError.response ? JSON.stringify(httpError.response.body) : '' + }` + ); + + throw error; + } + } + + public async getById(stockId: string): Promise { + try { + return await this.apiClient.get(`${this.path}/${stockId}`); + } catch (error) { + const httpError = error as ResponseError; + this.logger.error( + `Could not get stock with id '${stockId}'. Failed with status ${httpError.status}, error: ${ + httpError.response ? JSON.stringify(httpError.response.body) : '' + }` + ); + + throw error; + } + } + + public async getStockSummaries( + size?: number, + startAfterId?: string, + facilityServiceTypes?: FacilityServiceType[], + facilityStatuses?: FacilityStatus[], + facilityRefs?: string[], + allowStale?: boolean, + tenantArticleIds?: string[], + channelRefs?: string[] + ): Promise { + try { + const queryParams: QueryParams = {}; + + if (size && size <= 100) { + queryParams['size'] = size.toString(); + } + + if (startAfterId) { + queryParams['startAfterId'] = startAfterId; + } + + if (facilityServiceTypes && facilityServiceTypes.length > 0) { + queryParams['facilityServiceTypes'] = facilityServiceTypes; + } + + if (facilityStatuses) { + queryParams['facilityStatus'] = facilityStatuses; + } + + if (facilityRefs) { + facilityRefs = facilityRefs.slice(0, 499); + queryParams['facilityRefs'] = facilityRefs; + } + + if (allowStale) { + queryParams['allowStale'] = String(allowStale); + } + + if (tenantArticleIds) { + tenantArticleIds = tenantArticleIds.slice(0, 499); + queryParams['tenantArticleIds'] = tenantArticleIds; + } + + if (channelRefs) { + channelRefs = channelRefs.slice(0, 49); + queryParams['channelRefs'] = channelRefs; + } + return await this.apiClient.get(`${this.path}/summaries`, queryParams); + } catch (error) { + const httpError = error as ResponseError; + this.logger.error( + `Fetching stock summaries failed with status ${httpError.status}, error: ${ + httpError.response ? JSON.stringify(httpError.response.body) : '' + }` + ); + + throw error; + } + } + + public async getStockDistribution( + tenantArticleId: string, + facilityServiceTypes?: FacilityServiceType[], + facilityStatuses?: FacilityStatus[], + facilityName?: string, + facilityIds?: string[], + channelRefs?: string[] + ): Promise { + if (!tenantArticleId) { + throw new Error('tenantArticleId is missing.'); + } + + try { + const queryParams: QueryParams = {}; + + if (facilityServiceTypes) { + queryParams['facilityServiceTypes'] = facilityServiceTypes; + } + + if (facilityStatuses) { + queryParams['facilityStatus'] = facilityStatuses; + } + + if (facilityName) { + queryParams['facilityName'] = facilityName; + } + + if (facilityIds) { + facilityIds = facilityIds.slice(0, 499); + queryParams['facilityIds'] = facilityIds; + } + + if (channelRefs) { + channelRefs = channelRefs.slice(0, 49); + queryParams['channelRefs'] = channelRefs; + } + + return await this.apiClient.get(`articles/${tenantArticleId}/stockdistribution`, queryParams); + } catch (error) { + const httpError = error as ResponseError; + this.logger.error( + `Fetching stock distribution for tenantArticleId ${tenantArticleId} failed with status ${ + httpError.status + }, error: ${httpError.response ? JSON.stringify(httpError.response.body) : ''}` + ); + + throw error; + } + } +} diff --git a/src/fft-api/stock/index.ts b/src/fft-api/stock/index.ts new file mode 100644 index 0000000..7a95601 --- /dev/null +++ b/src/fft-api/stock/index.ts @@ -0,0 +1 @@ +export * from './fftStockService'; diff --git a/src/fft-api/types/api.swagger.yaml b/src/fft-api/types/api.swagger.yaml index 878617a..59533e2 100644 --- a/src/fft-api/types/api.swagger.yaml +++ b/src/fft-api/types/api.swagger.yaml @@ -35809,6 +35809,12 @@ components: $ref: '#/components/schemas/ServiceJobLink' type: array minItems: 1 + fullIdentifier: + type: string + description: >- + Full identifier of the service job. Using the full name of the + customer when created from an order. + example: 240429_lorem-42 required: - id - serviceJobLinks @@ -35834,6 +35840,12 @@ components: $ref: '#/components/schemas/ServiceJobLinkForCreation' type: array minItems: 1 + fullIdentifier: + type: string + description: >- + Full identifier of the service job. Using the full name of the + customer when created from an order. + example: 240429_lorem-42 required: - serviceJobLinks ServiceJobLinkForCreation: @@ -36324,6 +36336,8 @@ components: properties: name: type: string + facilityRef: + type: string InboundProcessPurchaseOrder: type: object properties: @@ -36591,6 +36605,12 @@ components: type: number available: type: number + deprecated: true + description: >- + This field is deprecated and replaced by new availability concepts. + Please see + https://docs.fulfillmenttools.com/api-docs/use-cases/inventory-management/global-inventory/availability + for more information. byTrait: $ref: '#/components/schemas/InventoryFacilityStockShapeByTrait' changeReason: @@ -36599,8 +36619,20 @@ components: - UNKNOWN availableToPromise: type: number + deprecated: true + description: >- + This field is deprecated and replaced by new availability concepts. + Please see + https://docs.fulfillmenttools.com/api-docs/use-cases/inventory-management/global-inventory/availability + for more information. readyToPick: type: number + deprecated: true + description: >- + This field is deprecated and replaced by new availability concepts. + Please see + https://docs.fulfillmenttools.com/api-docs/use-cases/inventory-management/global-inventory/availability + for more information. availableForPicking: type: number delta: @@ -36609,6 +36641,10 @@ components: type: array items: $ref: '#/components/schemas/InventoryFacilityStockStaleReason' + stockOnHand: + type: number + availableOnStock: + type: number required: - facilityRef - tenantArticleId @@ -36623,6 +36659,8 @@ components: - availableForPicking - delta - staleReasons + - stockOnHand + - availableOnStock RequestedDate: type: object properties: diff --git a/src/fft-api/types/typescript-fetch-client/api.ts b/src/fft-api/types/typescript-fetch-client/api.ts index f17c56d..1079d2a 100644 --- a/src/fft-api/types/typescript-fetch-client/api.ts +++ b/src/fft-api/types/typescript-fetch-client/api.ts @@ -9552,7 +9552,7 @@ export interface InventoryFacilityStockShape { */ safetyStock: number; /** - * + * This field is deprecated and replaced by new availability concepts. Please see https://docs.fulfillmenttools.com/api-docs/use-cases/inventory-management/global-inventory/availability for more information. * @type {number} * @memberof InventoryFacilityStockShape */ @@ -9570,13 +9570,13 @@ export interface InventoryFacilityStockShape { */ changeReason: InventoryFacilityStockShape.ChangeReasonEnum; /** - * + * This field is deprecated and replaced by new availability concepts. Please see https://docs.fulfillmenttools.com/api-docs/use-cases/inventory-management/global-inventory/availability for more information. * @type {number} * @memberof InventoryFacilityStockShape */ availableToPromise: number; /** - * + * This field is deprecated and replaced by new availability concepts. Please see https://docs.fulfillmenttools.com/api-docs/use-cases/inventory-management/global-inventory/availability for more information. * @type {number} * @memberof InventoryFacilityStockShape */ @@ -9599,6 +9599,18 @@ export interface InventoryFacilityStockShape { * @memberof InventoryFacilityStockShape */ staleReasons: Array; + /** + * + * @type {number} + * @memberof InventoryFacilityStockShape + */ + stockOnHand: number; + /** + * + * @type {number} + * @memberof InventoryFacilityStockShape + */ + availableOnStock: number; } /** @@ -10254,6 +10266,12 @@ export interface LinkedServiceJobs extends VersionedResource { * @memberof LinkedServiceJobs */ serviceJobLinks: Array; + /** + * Full identifier of the service job. Using the full name of the customer when created from an order. + * @type {string} + * @memberof LinkedServiceJobs + */ + fullIdentifier?: string; } /** * @@ -10276,6 +10294,12 @@ export interface LinkedServiceJobsForCreation { * @memberof LinkedServiceJobsForCreation */ serviceJobLinks: Array; + /** + * Full identifier of the service job. Using the full name of the customer when created from an order. + * @type {string} + * @memberof LinkedServiceJobsForCreation + */ + fullIdentifier?: string; } /** * Attribute to order linked service jobs by @@ -19498,6 +19522,12 @@ export interface PurchaseOrderSupplier { * @memberof PurchaseOrderSupplier */ name?: string; + /** + * + * @type {string} + * @memberof PurchaseOrderSupplier + */ + facilityRef?: string; } /** *