@@ -7,9 +7,13 @@ import {
77 $LetterStatusChangeEvent ,
88 LetterStatusChangeEvent ,
99} from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src/events/letter-events" ;
10- import { SupplierConfigRepository } from "@internal/datastore" ;
10+ import {
11+ SupplierConfigRepository ,
12+ SupplierQuotasRepository ,
13+ } from "@internal/datastore" ;
1114import createSupplierAllocatorHandler from "../allocate-handler" ;
1215import * as supplierConfig from "../../services/supplier-config" ;
16+ import * as supplierQuotas from "../../services/supplier-quotas" ;
1317
1418import { Deps } from "../../config/deps" ;
1519import { EnvVars } from "../../config/env" ;
@@ -21,6 +25,7 @@ const renderingSchemaVersion: string =
2125 ] ;
2226
2327jest . mock ( "../../services/supplier-config" ) ;
28+ jest . mock ( "../../services/supplier-quotas" ) ;
2429
2530function createSQSEvent ( records : SQSRecord [ ] ) : SQSEvent {
2631 return {
@@ -169,12 +174,19 @@ function setupDefaultMocks() {
169174 colour : false ,
170175 duplex : false ,
171176 } ) ;
177+ (
178+ supplierQuotas . calculateSupplierAllocatedFactor as jest . Mock
179+ ) . mockResolvedValue ( {
180+ supplierId : "supplier-1" ,
181+ factor : 0.5 ,
182+ } ) ;
172183}
173184
174185describe ( "createSupplierAllocatorHandler" , ( ) => {
175186 let mockSqsClient : jest . Mocked < SQSClient > ;
176187 let mockedDeps : jest . Mocked < Deps > ;
177188 let mockedSupplierConfigRepo : jest . Mocked < SupplierConfigRepository > ;
189+ let mockedSupplierQuotasRepo : jest . Mocked < SupplierQuotasRepository > ;
178190 beforeEach ( ( ) => {
179191 mockSqsClient = {
180192 send : jest . fn ( ) ,
@@ -191,10 +203,22 @@ describe("createSupplierAllocatorHandler", () => {
191203 getPackSpecification : jest . fn ( ) ,
192204 } as jest . Mocked < SupplierConfigRepository > ;
193205
206+ mockedSupplierQuotasRepo = {
207+ ddbClient : { } as any ,
208+ config : { } as any ,
209+ getOverallAllocation : jest . fn ( ) ,
210+ putOverallAllocation : jest . fn ( ) ,
211+ updateOverallAllocation : jest . fn ( ) ,
212+ getDailyAllocation : jest . fn ( ) ,
213+ putDailyAllocation : jest . fn ( ) ,
214+ updateDailyAllocation : jest . fn ( ) ,
215+ } as jest . Mocked < SupplierQuotasRepository > ;
216+
194217 mockedDeps = {
195218 logger : { error : jest . fn ( ) , info : jest . fn ( ) } as unknown as pino . Logger ,
196219 env : {
197220 SUPPLIER_CONFIG_TABLE_NAME : "SupplierConfigTable" ,
221+ SUPPLIER_QUOTAS_TABLE_NAME : "SupplierQuotasTable" ,
198222 VARIANT_MAP : {
199223 lv1 : {
200224 supplierId : "supplier1" ,
@@ -206,6 +230,7 @@ describe("createSupplierAllocatorHandler", () => {
206230 } as EnvVars ,
207231 sqsClient : mockSqsClient ,
208232 supplierConfigRepo : mockedSupplierConfigRepo ,
233+ supplierQuotasRepo : mockedSupplierQuotasRepo ,
209234 } as jest . Mocked < Deps > ;
210235 jest . clearAllMocks ( ) ;
211236 } ) ;
@@ -434,6 +459,39 @@ describe("createSupplierAllocatorHandler", () => {
434459 ) ;
435460 } ) ;
436461
462+ test ( "returns batch failure when variant mapping is missing for multiple events" , async ( ) => {
463+ const preparedEvent1 = createPreparedV2Event ( ) ;
464+ preparedEvent1 . data . letterVariantId = "missing-variant1" ;
465+ const preparedEvent2 = createPreparedV2Event ( ) ;
466+ preparedEvent2 . data . letterVariantId = "missing-variant2" ;
467+
468+ const evt : SQSEvent = createSQSEvent ( [
469+ createSqsRecord ( "msg1" , JSON . stringify ( preparedEvent1 ) ) ,
470+ createSqsRecord ( "msg2" , JSON . stringify ( preparedEvent2 ) ) ,
471+ ] ) ;
472+
473+ process . env . UPSERT_LETTERS_QUEUE_URL = "https://sqs.test.queue" ;
474+
475+ // Override variant map to be empty for this test
476+ mockedDeps . env . VARIANT_MAP = { } as any ;
477+
478+ const handler = createSupplierAllocatorHandler ( mockedDeps ) ;
479+ const result = await handler ( evt , { } as any , { } as any ) ;
480+ if ( ! result ) throw new Error ( "expected BatchResponse, got void" ) ;
481+
482+ expect ( result . batchItemFailures ) . toHaveLength ( 2 ) ;
483+ expect ( result . batchItemFailures [ 0 ] . itemIdentifier ) . toBe ( "msg1" ) ;
484+ expect ( result . batchItemFailures [ 1 ] . itemIdentifier ) . toBe ( "msg2" ) ;
485+ expect (
486+ ( mockedDeps . logger . error as jest . Mock ) . mock . calls . length ,
487+ ) . toBeGreaterThan ( 0 ) ;
488+ expect ( ( mockedDeps . logger . error as jest . Mock ) . mock . calls [ 0 ] [ 0 ] ) . toEqual (
489+ expect . objectContaining ( {
490+ description : "No supplier mapping found for variant" ,
491+ } ) ,
492+ ) ;
493+ } ) ;
494+
437495 test ( "handles SQS send errors and returns batch failure" , async ( ) => {
438496 const preparedEvent = createPreparedV2Event ( ) ;
439497
0 commit comments