diff --git a/lambdas/src/order-status-lambda/index.test.ts b/lambdas/src/order-status-lambda/index.test.ts index 9ba8c161..b7ce639d 100644 --- a/lambdas/src/order-status-lambda/index.test.ts +++ b/lambdas/src/order-status-lambda/index.test.ts @@ -263,6 +263,17 @@ describe("Order Status Lambda Handler", () => { expect(result.statusCode).toBe(201); }); + + it(`should accept ${IncomingBusinessStatus.CONFIRMED} business status`, async () => { + mockEvent.body = JSON.stringify({ + ...validTaskBody, + businessStatus: { text: IncomingBusinessStatus.CONFIRMED }, + } satisfies Partial); + + const result = await handler(mockEvent as APIGatewayProxyEvent, {} as Context); + + expect(result.statusCode).toBe(201); + }); }); describe("Idempotency via Correlation ID", () => { @@ -446,6 +457,26 @@ describe("Order Status Lambda Handler", () => { ); }); + it("should delegate confirmed status to the notification service", async () => { + mockEvent.body = JSON.stringify({ + ...validTaskBody, + businessStatus: { + text: IncomingBusinessStatus.CONFIRMED, + }, + } satisfies Partial); + + const result = await handler(mockEvent as APIGatewayProxyEvent, {} as Context); + + expect(result.statusCode).toBe(201); + expect(mockHandleOrderStatusUpdated).toHaveBeenCalledWith( + expect.objectContaining({ + statusUpdate: expect.objectContaining({ + statusCode: businessStatusMapping[IncomingBusinessStatus.CONFIRMED], + }), + }), + ); + }); + it("should return 500 when notification service fails", async () => { mockHandleOrderStatusUpdated.mockRejectedValueOnce(new Error("Unexpected side effect error")); mockEvent.body = JSON.stringify(validTaskBody); diff --git a/lambdas/src/order-status-lambda/index.ts b/lambdas/src/order-status-lambda/index.ts index b7a3c0ac..b42b9466 100644 --- a/lambdas/src/order-status-lambda/index.ts +++ b/lambdas/src/order-status-lambda/index.ts @@ -149,10 +149,12 @@ export const lambdaHandler = async ( return createFhirResponse(200, validatedTask); } + const mappedStatusCode = businessStatusMapping[validatedTask.businessStatus.text]; + // Process the update const statusOrderUpdateParams: OrderStatusUpdateParams = { orderId, - statusCode: businessStatusMapping[validatedTask.businessStatus.text], + statusCode: mappedStatusCode, createdAt: validatedTask.lastModified, correlationId, }; diff --git a/lambdas/src/order-status-lambda/init.test.ts b/lambdas/src/order-status-lambda/init.test.ts index c37fa91e..a9a0bec8 100644 --- a/lambdas/src/order-status-lambda/init.test.ts +++ b/lambdas/src/order-status-lambda/init.test.ts @@ -1,6 +1,7 @@ import { PostgresDbClient } from "../lib/db/db-client"; import { postgresConfigFromEnv } from "../lib/db/db-config"; import { NotificationAuditDbClient } from "../lib/db/notification-audit-db-client"; +import { OrderDbClient } from "../lib/db/order-db-client"; import { OrderStatusService } from "../lib/db/order-status-db"; import { PatientDbClient } from "../lib/db/patient-db-client"; import { AwsSecretsClient } from "../lib/secrets/secrets-manager-client"; @@ -12,6 +13,7 @@ import { NotifyMessageBuilder } from "./notify-message-builder"; import { OrderStatusNotifyService } from "./notify-service"; jest.mock("../lib/db/order-status-db"); +jest.mock("../lib/db/order-db-client"); jest.mock("../lib/db/patient-db-client"); jest.mock("../lib/db/notification-audit-db-client"); jest.mock("../lib/db/db-client"); @@ -109,6 +111,8 @@ describe("init", () => { expect(result).toEqual({ orderStatusDb: expect.any(OrderStatusService), + patientDbClient: expect.any(PatientDbClient), + orderDbClient: expect.any(OrderDbClient), orderStatusNotifyService: expect.any(OrderStatusNotifyService), }); }); @@ -151,6 +155,11 @@ describe("init", () => { times: 1, calledWith: expect.any(PostgresDbClient), }, + { + mock: OrderDbClient as jest.Mock, + times: 1, + calledWith: expect.any(PostgresDbClient), + }, { mock: NotificationAuditDbClient as jest.Mock, times: 1, @@ -177,6 +186,7 @@ describe("init", () => { expect(NotifyMessageBuilder).toHaveBeenCalledWith( expect.any(PatientDbClient), + expect.any(OrderDbClient), "https://hometest.example.nhs.uk", ); }); diff --git a/lambdas/src/order-status-lambda/init.ts b/lambdas/src/order-status-lambda/init.ts index e2a30284..4d7aed81 100644 --- a/lambdas/src/order-status-lambda/init.ts +++ b/lambdas/src/order-status-lambda/init.ts @@ -1,6 +1,7 @@ import { PostgresDbClient } from "../lib/db/db-client"; import { postgresConfigFromEnv } from "../lib/db/db-config"; import { NotificationAuditDbClient } from "../lib/db/notification-audit-db-client"; +import { OrderDbClient } from "../lib/db/order-db-client"; import { OrderStatusService } from "../lib/db/order-status-db"; import { PatientDbClient } from "../lib/db/patient-db-client"; import { AwsSecretsClient } from "../lib/secrets/secrets-manager-client"; @@ -11,6 +12,8 @@ import { OrderStatusNotifyService } from "./notify-service"; export interface Environment { orderStatusDb: OrderStatusService; + patientDbClient: PatientDbClient; + orderDbClient: OrderDbClient; orderStatusNotifyService: OrderStatusNotifyService; } @@ -23,9 +26,14 @@ export function buildEnvironment(): Environment { const dbClient = new PostgresDbClient(postgresConfigFromEnv(secretsClient)); const orderStatusDb = new OrderStatusService(dbClient); const patientDbClient = new PatientDbClient(dbClient); + const orderDbClient = new OrderDbClient(dbClient); const notificationAuditDbClient = new NotificationAuditDbClient(dbClient); const sqsClient = new AWSSQSClient(); - const notifyMessageBuilder = new NotifyMessageBuilder(patientDbClient, homeTestBaseUrl); + const notifyMessageBuilder = new NotifyMessageBuilder( + patientDbClient, + orderDbClient, + homeTestBaseUrl, + ); const orderStatusNotifyService = new OrderStatusNotifyService({ orderStatusDb, notificationAuditDbClient, @@ -36,6 +44,8 @@ export function buildEnvironment(): Environment { return { orderStatusDb, + patientDbClient, + orderDbClient, orderStatusNotifyService, }; } diff --git a/lambdas/src/order-status-lambda/notify-message-builder.test.ts b/lambdas/src/order-status-lambda/notify-message-builder.test.ts index 9582ca90..8e51a7c6 100644 --- a/lambdas/src/order-status-lambda/notify-message-builder.test.ts +++ b/lambdas/src/order-status-lambda/notify-message-builder.test.ts @@ -1,14 +1,20 @@ +import type { OrderDbClient } from "../lib/db/order-db-client"; import type { Patient, PatientDbClient } from "../lib/db/patient-db-client"; import { NotifyEventCode } from "../lib/types/notify-message"; import { NotifyMessageBuilder } from "./notify-message-builder"; describe("NotifyMessageBuilder", () => { const mockGetPatient = jest.fn, [string]>(); + const mockGetOrder = jest.fn(); const mockPatientDbClient: Pick = { get: mockGetPatient, }; + const mockOrderDbClient: Pick = { + getOrder: mockGetOrder, + }; + let builder: NotifyMessageBuilder; beforeEach(() => { @@ -17,9 +23,13 @@ describe("NotifyMessageBuilder", () => { nhsNumber: "1234567890", birthDate: "1990-01-02", }); + mockGetOrder.mockResolvedValue({ + created_at: new Date("2026-08-06T08:30:00Z"), + }); builder = new NotifyMessageBuilder( mockPatientDbClient as PatientDbClient, + mockOrderDbClient as OrderDbClient, "https://hometest.example.nhs.uk", ); }); @@ -49,6 +59,7 @@ describe("NotifyMessageBuilder", () => { it("should normalize trailing slash in base url", async () => { const trailingSlashBuilder = new NotifyMessageBuilder( mockPatientDbClient as PatientDbClient, + mockOrderDbClient as OrderDbClient, "https://hometest.example.nhs.uk/", ); @@ -95,4 +106,43 @@ describe("NotifyMessageBuilder", () => { "https://hometest.example.nhs.uk/orders/550e8400-e29b-41d4-a716-446655440000/tracking", }); }); + + it("should build confirmed notify message with orderedDate in personalisation", async () => { + const result = await builder.buildOrderConfirmedNotifyMessage({ + patientId: "550e8400-e29b-41d4-a716-446655440111", + correlationId: "123e4567-e89b-12d3-a456-426614174000", + orderId: "550e8400-e29b-41d4-a716-446655440000", + orderedAt: "2026-08-01T10:00:00Z", + }); + + expect(result.correlationId).toBe("123e4567-e89b-12d3-a456-426614174000"); + expect(result.eventCode).toBe(NotifyEventCode.OrderConfirmed); + expect(result.personalisation).toEqual({ + orderedDate: "6 August 2026", + orderLinkUrl: + "https://hometest.example.nhs.uk/orders/550e8400-e29b-41d4-a716-446655440000/tracking", + }); + expect(mockGetOrder).toHaveBeenCalledWith( + "550e8400-e29b-41d4-a716-446655440000", + "1234567890", + expect.any(Date), + ); + }); + + it("should fall back to provided orderedAt when order lookup returns null", async () => { + mockGetOrder.mockResolvedValueOnce(null); + + const result = await builder.buildOrderConfirmedNotifyMessage({ + patientId: "550e8400-e29b-41d4-a716-446655440111", + correlationId: "123e4567-e89b-12d3-a456-426614174000", + orderId: "550e8400-e29b-41d4-a716-446655440000", + orderedAt: "2026-08-01T10:00:00Z", + }); + + expect(result.personalisation).toEqual({ + orderedDate: "1 August 2026", + orderLinkUrl: + "https://hometest.example.nhs.uk/orders/550e8400-e29b-41d4-a716-446655440000/tracking", + }); + }); }); diff --git a/lambdas/src/order-status-lambda/notify-message-builder.ts b/lambdas/src/order-status-lambda/notify-message-builder.ts index 537a4eb7..f2698cb5 100644 --- a/lambdas/src/order-status-lambda/notify-message-builder.ts +++ b/lambdas/src/order-status-lambda/notify-message-builder.ts @@ -1,5 +1,6 @@ import { v4 as uuidv4 } from "uuid"; +import type { OrderDbClient } from "../lib/db/order-db-client"; import type { PatientDbClient } from "../lib/db/patient-db-client"; import { NotifyEventCode, NotifyMessage, NotifyRecipient } from "../lib/types/notify-message"; @@ -10,6 +11,13 @@ export interface BuildOrderDispatchedNotifyMessageInput { dispatchedAt: string; } +export interface BuildOrderConfirmedNotifyMessageInput { + patientId: string; + correlationId: string; + orderId: string; + orderedAt: string; +} + export interface BuildOrderReceivedNotifyMessageInput { patientId: string; correlationId: string; @@ -30,6 +38,7 @@ export class NotifyMessageBuilder { constructor( private readonly patientDbClient: PatientDbClient, + private readonly orderDbClient: OrderDbClient, homeTestBaseUrl: string, ) { this.normalizedHomeTestBaseUrl = homeTestBaseUrl.replaceAll(/\/$/g, ""); @@ -53,6 +62,36 @@ export class NotifyMessageBuilder { }); } + async buildOrderConfirmedNotifyMessage( + input: BuildOrderConfirmedNotifyMessageInput, + ): Promise { + const { patientId, correlationId, orderId, orderedAt } = input; + + const patient = await this.patientDbClient.get(patientId); + const order = await this.orderDbClient.getOrder( + orderId, + patient.nhsNumber, + new Date(patient.birthDate), + ); + const orderedAtValue = order?.created_at.toISOString() ?? orderedAt; + + const trackingUrl = `${this.normalizedHomeTestBaseUrl}/orders/${orderId}/tracking`; + + return this.buildOrderStatusNotifyMessage({ + recipient: { + nhsNumber: patient.nhsNumber, + dateOfBirth: patient.birthDate, + }, + correlationId, + orderId, + eventCode: NotifyEventCode.OrderConfirmed, + personalisation: { + orderedDate: formatStatusDate(orderedAtValue), + orderLinkUrl: trackingUrl, + }, + }); + } + async buildOrderReceivedNotifyMessage( input: BuildOrderReceivedNotifyMessageInput, ): Promise { @@ -73,26 +112,36 @@ export class NotifyMessageBuilder { } private async buildOrderStatusNotifyMessage(input: { - patientId: string; + patientId?: string; + recipient?: NotifyRecipient; correlationId: string; orderId: string; eventCode: NotifyEventCode; personalisation: Record; }): Promise { - const { patientId, correlationId, eventCode, personalisation } = input; + const { patientId, recipient, correlationId, eventCode, personalisation } = input; - const patient = await this.patientDbClient.get(patientId); - const recipient: NotifyRecipient = { - nhsNumber: patient.nhsNumber, - dateOfBirth: patient.birthDate, - }; + const notifyRecipient = recipient ?? (await this.getRecipientFromPatientId(patientId)); return { correlationId, messageReference: uuidv4(), eventCode, - recipient, + recipient: notifyRecipient, personalisation, }; } + + private async getRecipientFromPatientId(patientId?: string): Promise { + if (!patientId) { + throw new Error("patientId is required when recipient is not provided"); + } + + const patient = await this.patientDbClient.get(patientId); + + return { + nhsNumber: patient.nhsNumber, + dateOfBirth: patient.birthDate, + }; + } } diff --git a/lambdas/src/order-status-lambda/notify-service.test.ts b/lambdas/src/order-status-lambda/notify-service.test.ts index a5aedb77..00aff5d9 100644 --- a/lambdas/src/order-status-lambda/notify-service.test.ts +++ b/lambdas/src/order-status-lambda/notify-service.test.ts @@ -4,7 +4,8 @@ import { NotifyEventCode } from "../lib/types/notify-message"; import { OrderStatusNotifyService } from "./notify-service"; describe("OrderStatusNotifyService", () => { - const mockIsFirstStatusOccurrence = jest.fn, [string, string]>(); + const mockIsFirstStatusOccurrence = jest.fn(); + const mockBuildOrderConfirmedNotifyMessage = jest.fn(); const mockBuildOrderDispatchedNotifyMessage = jest.fn(); const mockBuildOrderReceivedNotifyMessage = jest.fn(); const mockSendMessage = jest.fn(); @@ -23,6 +24,17 @@ describe("OrderStatusNotifyService", () => { jest.clearAllMocks(); mockIsFirstStatusOccurrence.mockResolvedValue(true); + + mockBuildOrderConfirmedNotifyMessage.mockResolvedValue({ + messageReference: "123e4567-e89b-12d3-a456-426614174090", + eventCode: NotifyEventCode.OrderConfirmed, + correlationId: statusUpdate.correlationId, + recipient: { + nhsNumber: "1234567890", + dateOfBirth: "1990-01-02", + }, + personalisation: {}, + }); mockBuildOrderDispatchedNotifyMessage.mockResolvedValue({ messageReference: "123e4567-e89b-12d3-a456-426614174099", eventCode: NotifyEventCode.OrderDispatched, @@ -57,6 +69,7 @@ describe("OrderStatusNotifyService", () => { sendMessage: mockSendMessage, }, notifyMessageBuilder: { + buildOrderConfirmedNotifyMessage: mockBuildOrderConfirmedNotifyMessage, buildOrderDispatchedNotifyMessage: mockBuildOrderDispatchedNotifyMessage, buildOrderReceivedNotifyMessage: mockBuildOrderReceivedNotifyMessage, } as never, @@ -76,33 +89,69 @@ describe("OrderStatusNotifyService", () => { }); expect(mockIsFirstStatusOccurrence).not.toHaveBeenCalled(); + expect(mockBuildOrderConfirmedNotifyMessage).not.toHaveBeenCalled(); expect(mockBuildOrderDispatchedNotifyMessage).not.toHaveBeenCalled(); expect(mockBuildOrderReceivedNotifyMessage).not.toHaveBeenCalled(); expect(mockSendMessage).not.toHaveBeenCalled(); expect(mockInsertNotificationAuditEntry).not.toHaveBeenCalled(); }); - it("should not send a dispatched notification when it is not the first occurrence", async () => { + it("should not send a confirmed notification when it is not the first occurrence", async () => { mockIsFirstStatusOccurrence.mockResolvedValueOnce(false); await service.handleOrderStatusUpdated({ orderId: statusUpdate.orderId, patientId: "patient-123", correlationId: statusUpdate.correlationId, - statusUpdate, + statusUpdate: { + ...statusUpdate, + statusCode: OrderStatusCodes.CONFIRMED, + }, }); expect(mockIsFirstStatusOccurrence).toHaveBeenCalledWith( statusUpdate.orderId, - OrderStatusCodes.DISPATCHED, + OrderStatusCodes.CONFIRMED, ); - expect(mockBuildOrderDispatchedNotifyMessage).not.toHaveBeenCalled(); - expect(mockBuildOrderReceivedNotifyMessage).not.toHaveBeenCalled(); + expect(mockBuildOrderConfirmedNotifyMessage).not.toHaveBeenCalled(); expect(mockSendMessage).not.toHaveBeenCalled(); expect(mockInsertNotificationAuditEntry).not.toHaveBeenCalled(); }); - it("should send and audit the first dispatched notification", async () => { + it("should send and audit a confirmed notification", async () => { + await service.handleOrderStatusUpdated({ + orderId: statusUpdate.orderId, + patientId: "patient-123", + correlationId: statusUpdate.correlationId, + statusUpdate: { + ...statusUpdate, + statusCode: OrderStatusCodes.CONFIRMED, + }, + }); + + expect(mockIsFirstStatusOccurrence).toHaveBeenCalledWith( + statusUpdate.orderId, + OrderStatusCodes.CONFIRMED, + ); + expect(mockBuildOrderConfirmedNotifyMessage).toHaveBeenCalledWith({ + patientId: "patient-123", + correlationId: statusUpdate.correlationId, + orderId: statusUpdate.orderId, + orderedAt: statusUpdate.createdAt, + }); + expect(mockSendMessage).toHaveBeenCalledWith( + "https://example.queue.local/notify", + expect.any(String), + ); + expect(mockInsertNotificationAuditEntry).toHaveBeenCalledWith({ + messageReference: "123e4567-e89b-12d3-a456-426614174090", + eventCode: NotifyEventCode.OrderConfirmed, + correlationId: statusUpdate.correlationId, + status: NotificationAuditStatus.QUEUED, + }); + }); + + it("should send and audit a dispatched notification", async () => { await service.handleOrderStatusUpdated({ orderId: statusUpdate.orderId, patientId: "patient-123", @@ -110,6 +159,10 @@ describe("OrderStatusNotifyService", () => { statusUpdate, }); + expect(mockIsFirstStatusOccurrence).toHaveBeenCalledWith( + statusUpdate.orderId, + OrderStatusCodes.DISPATCHED, + ); expect(mockBuildOrderDispatchedNotifyMessage).toHaveBeenCalledWith({ patientId: "patient-123", correlationId: statusUpdate.correlationId, @@ -128,29 +181,27 @@ describe("OrderStatusNotifyService", () => { }); }); - it("should not send a received notification when it is not the first occurrence", async () => { + it("should not send a dispatched notification when it is not the first occurrence", async () => { mockIsFirstStatusOccurrence.mockResolvedValueOnce(false); await service.handleOrderStatusUpdated({ orderId: statusUpdate.orderId, patientId: "patient-123", correlationId: statusUpdate.correlationId, - statusUpdate: { - ...statusUpdate, - statusCode: OrderStatusCodes.RECEIVED, - }, + statusUpdate, }); expect(mockIsFirstStatusOccurrence).toHaveBeenCalledWith( statusUpdate.orderId, - OrderStatusCodes.RECEIVED, + OrderStatusCodes.DISPATCHED, ); + expect(mockBuildOrderDispatchedNotifyMessage).not.toHaveBeenCalled(); expect(mockBuildOrderReceivedNotifyMessage).not.toHaveBeenCalled(); expect(mockSendMessage).not.toHaveBeenCalled(); expect(mockInsertNotificationAuditEntry).not.toHaveBeenCalled(); }); - it("should send and audit the first received notification", async () => { + it("should send and audit a received notification", async () => { await service.handleOrderStatusUpdated({ orderId: statusUpdate.orderId, patientId: "patient-123", @@ -161,6 +212,10 @@ describe("OrderStatusNotifyService", () => { }, }); + expect(mockIsFirstStatusOccurrence).toHaveBeenCalledWith( + statusUpdate.orderId, + OrderStatusCodes.RECEIVED, + ); expect(mockBuildOrderReceivedNotifyMessage).toHaveBeenCalledWith({ patientId: "patient-123", correlationId: statusUpdate.correlationId, @@ -179,6 +234,28 @@ describe("OrderStatusNotifyService", () => { }); }); + it("should not send a received notification when it is not the first occurrence", async () => { + mockIsFirstStatusOccurrence.mockResolvedValueOnce(false); + + await service.handleOrderStatusUpdated({ + orderId: statusUpdate.orderId, + patientId: "patient-123", + correlationId: statusUpdate.correlationId, + statusUpdate: { + ...statusUpdate, + statusCode: OrderStatusCodes.RECEIVED, + }, + }); + + expect(mockIsFirstStatusOccurrence).toHaveBeenCalledWith( + statusUpdate.orderId, + OrderStatusCodes.RECEIVED, + ); + expect(mockBuildOrderReceivedNotifyMessage).not.toHaveBeenCalled(); + expect(mockSendMessage).not.toHaveBeenCalled(); + expect(mockInsertNotificationAuditEntry).not.toHaveBeenCalled(); + }); + it("should swallow errors when building the notify message fails", async () => { mockBuildOrderDispatchedNotifyMessage.mockRejectedValueOnce( new Error("Notify payload build failed"), diff --git a/lambdas/src/order-status-lambda/notify-service.ts b/lambdas/src/order-status-lambda/notify-service.ts index 2e38ee0d..222111b3 100644 --- a/lambdas/src/order-status-lambda/notify-service.ts +++ b/lambdas/src/order-status-lambda/notify-service.ts @@ -36,6 +36,7 @@ interface BuildNotifyMessageInput { patientId: string; correlationId: string; createdAt: string; + orderedAt?: string; } type NotifyMessageBuilderByStatus = Partial< @@ -52,6 +53,13 @@ export class OrderStatusNotifyService { const { notifyMessageBuilder } = this.dependencies; const buildNotifyMessageByStatus: NotifyMessageBuilderByStatus = { + [OrderStatusCodes.CONFIRMED]: ({ patientId, correlationId, orderId, createdAt, orderedAt }) => + notifyMessageBuilder.buildOrderConfirmedNotifyMessage({ + patientId, + correlationId, + orderId, + orderedAt: orderedAt ?? createdAt, + }), [OrderStatusCodes.DISPATCHED]: ({ patientId, correlationId, orderId, createdAt }) => notifyMessageBuilder.buildOrderDispatchedNotifyMessage({ patientId, diff --git a/lambdas/src/order-status-lambda/types.ts b/lambdas/src/order-status-lambda/types.ts index 140f35ed..08a51105 100644 --- a/lambdas/src/order-status-lambda/types.ts +++ b/lambdas/src/order-status-lambda/types.ts @@ -1,9 +1,11 @@ export enum IncomingBusinessStatus { + CONFIRMED = "confirmed", DISPATCHED = "dispatched", RECEIVED_AT_LAB = "received-at-lab", } export enum AllowedInternalBusinessStatuses { + CONFIRMED = "CONFIRMED", DISPATCHED = "DISPATCHED", RECEIVED = "RECEIVED", } diff --git a/lambdas/src/order-status-lambda/utils.ts b/lambdas/src/order-status-lambda/utils.ts index ad2bd270..5adcd16e 100644 --- a/lambdas/src/order-status-lambda/utils.ts +++ b/lambdas/src/order-status-lambda/utils.ts @@ -1,7 +1,4 @@ -import { - AllowedInternalBusinessStatuses, - IncomingBusinessStatus, -} from "./types"; +import { AllowedInternalBusinessStatuses, IncomingBusinessStatus } from "./types"; /** * Extract UUID from a FHIR reference (e.g., "ServiceRequest/550e8400-e29b-41d4-a716-446655440000") @@ -19,8 +16,7 @@ export const businessStatusMapping: Record< IncomingBusinessStatus, AllowedInternalBusinessStatuses > = { - [IncomingBusinessStatus.DISPATCHED]: - AllowedInternalBusinessStatuses.DISPATCHED, - [IncomingBusinessStatus.RECEIVED_AT_LAB]: - AllowedInternalBusinessStatuses.RECEIVED, + [IncomingBusinessStatus.CONFIRMED]: AllowedInternalBusinessStatuses.CONFIRMED, + [IncomingBusinessStatus.DISPATCHED]: AllowedInternalBusinessStatuses.DISPATCHED, + [IncomingBusinessStatus.RECEIVED_AT_LAB]: AllowedInternalBusinessStatuses.RECEIVED, }; diff --git a/ui/package-lock.json b/ui/package-lock.json index 8ff7db7f..8012c199 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -96,7 +96,6 @@ "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", @@ -684,7 +683,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -708,7 +706,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -2236,7 +2233,6 @@ "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -2523,7 +2519,6 @@ "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "undici-types": "~7.16.0" } @@ -2534,7 +2529,6 @@ "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "csstype": "^3.2.2" } @@ -2545,7 +2539,6 @@ "integrity": "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==", "dev": true, "license": "MIT", - "peer": true, "peerDependencies": { "@types/react": "^19.2.0" } @@ -2626,7 +2619,6 @@ "integrity": "sha512-rLoGZIf9afaRBYsPUMtvkDWykwXwUPL60HebR4JgTI8mxfFe2cQTu3AGitANp4b9B2QlVru6WzjgB2IzJKiCSA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "8.58.0", "@typescript-eslint/types": "8.58.0", @@ -3107,7 +3099,6 @@ "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3535,7 +3526,6 @@ "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==", "devOptional": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/types": "^7.26.0" } @@ -3652,7 +3642,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.10.12", "caniuse-lite": "^1.0.30001782", @@ -4545,7 +4534,6 @@ "integrity": "sha512-S9jlY/ELKEUwwQnqWDO+f+m6sercqOPSqXM5Go94l7DOmxHVDgmSFGWEzeE/gwgTAr0W103BWt0QLe/7mabIvA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.2", @@ -4692,7 +4680,6 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -7406,7 +7393,6 @@ "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssstyle": "^4.2.1", "data-urls": "^5.0.0", @@ -7896,7 +7882,6 @@ "resolved": "https://registry.npmjs.org/nhsuk-frontend/-/nhsuk-frontend-10.4.2.tgz", "integrity": "sha512-DYa7E/jwWtQPKqzeF9eB9nVcTKHpjMYf+SydKao379qQapIkblfS2BNvKsVKuWpI0w+QgI8XSDNNOUTQEGRb1w==", "license": "MIT", - "peer": true, "engines": { "node": "^20.9.0 || ^22.11.0 || >= 24.11.0" }, @@ -8340,7 +8325,6 @@ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=12" }, @@ -8575,7 +8559,6 @@ "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", "license": "MIT", - "peer": true, "engines": { "node": ">=0.10.0" } @@ -8585,7 +8568,6 @@ "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", "license": "MIT", - "peer": true, "dependencies": { "scheduler": "^0.27.0" }, @@ -9734,7 +9716,6 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -9813,8 +9794,7 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD", - "peer": true + "license": "0BSD" }, "node_modules/type-check": { "version": "0.4.0", @@ -9936,7 +9916,6 @@ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "dev": true, "license": "Apache-2.0", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10550,7 +10529,6 @@ "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", "license": "MIT", - "peer": true, "funding": { "url": "https://github.com/sponsors/colinhacks" }