Skip to content

Commit f4a3396

Browse files
CCM-13372 - Select Preferred Pack
1 parent b9cc6ba commit f4a3396

File tree

8 files changed

+699
-277
lines changed

8 files changed

+699
-277
lines changed

infrastructure/terraform/components/api/ddb_table_supplier_configuration.tf

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ resource "aws_dynamodb_table" "supplier-configuration" {
3030
type = "S"
3131
}
3232

33+
attribute {
34+
name = "packSpecificationId"
35+
type = "S"
36+
}
37+
3338
// The type-index GSI allows us to query for all supplier configurations of a given type (e.g. all letter supplier configurations)
3439
global_secondary_index {
3540
name = "EntityTypeIndex"
@@ -45,6 +50,13 @@ resource "aws_dynamodb_table" "supplier-configuration" {
4550
projection_type = "ALL"
4651
}
4752

53+
global_secondary_index {
54+
name = "packSpecificationId-index"
55+
hash_key = "PK"
56+
range_key = "packSpecificationId"
57+
projection_type = "ALL"
58+
}
59+
4860
point_in_time_recovery {
4961
enabled = true
5062
}

internal/datastore/src/__test__/db.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,11 +164,22 @@ const createSupplierConfigTableCommand = new CreateTableCommand({
164164
ProjectionType: "ALL",
165165
},
166166
},
167+
{
168+
IndexName: "packSpecificationId-index",
169+
KeySchema: [
170+
{ AttributeName: "PK", KeyType: "HASH" }, // Partition key for GSI
171+
{ AttributeName: "packSpecificationId", KeyType: "RANGE" }, // Sort key for GSI
172+
],
173+
Projection: {
174+
ProjectionType: "ALL",
175+
},
176+
},
167177
],
168178
AttributeDefinitions: [
169179
{ AttributeName: "PK", AttributeType: "S" },
170180
{ AttributeName: "SK", AttributeType: "S" },
171181
{ AttributeName: "volumeGroup", AttributeType: "S" },
182+
{ AttributeName: "packSpecificationId", AttributeType: "S" },
172183
],
173184
});
174185

internal/datastore/src/__test__/supplier-config-repository.test.ts

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,4 +263,89 @@ describe("SupplierConfigRepository", () => {
263263
`Supplier with id ${supplierId} not found`,
264264
);
265265
});
266+
267+
test("getSupplierPacksForPackSpecification returns correct supplier packs", async () => {
268+
const packSpecId = "pack-spec-123";
269+
const supplierId = "supplier-123";
270+
const supplierPackId = "supplier-pack-123";
271+
272+
await dbContext.docClient.send(
273+
new PutCommand({
274+
TableName: dbContext.config.supplierConfigTableName,
275+
Item: {
276+
PK: "SUPPLIER_PACK",
277+
SK: supplierPackId,
278+
id: supplierPackId,
279+
packSpecificationId: packSpecId,
280+
supplierId,
281+
status: "PROD",
282+
approval: "APPROVED",
283+
},
284+
}),
285+
);
286+
287+
const result =
288+
await repository.getSupplierPacksForPackSpecification(packSpecId);
289+
expect(result).toEqual([
290+
{
291+
approval: "APPROVED",
292+
id: supplierPackId,
293+
packSpecificationId: packSpecId,
294+
supplierId,
295+
status: "PROD",
296+
},
297+
]);
298+
});
299+
300+
test("getSupplierPacksForPackSpecification throws error for non-existent pack specification", async () => {
301+
const packSpecId = "non-existent-pack-spec";
302+
303+
await expect(
304+
repository.getSupplierPacksForPackSpecification(packSpecId),
305+
).rejects.toThrow(
306+
`No supplier packs found for pack specification id ${packSpecId}`,
307+
);
308+
});
309+
310+
test("getPackSpecification returns correct pack specification details", async () => {
311+
const packSpecId = "pack-spec-123";
312+
313+
await dbContext.docClient.send(
314+
new PutCommand({
315+
TableName: dbContext.config.supplierConfigTableName,
316+
Item: {
317+
PK: "PACK_SPECIFICATION",
318+
SK: packSpecId,
319+
id: packSpecId,
320+
name: `Pack Specification ${packSpecId}`,
321+
createdAt: new Date().toISOString(),
322+
updatedAt: new Date().toISOString(),
323+
version: 1,
324+
billingId: `billing-${packSpecId}`,
325+
postage: { id: "postageId", size: "STANDARD" },
326+
status: "PROD",
327+
},
328+
}),
329+
);
330+
331+
const result = await repository.getPackSpecification(packSpecId);
332+
expect(result).toEqual({
333+
billingId: `billing-${packSpecId}`,
334+
createdAt: expect.any(String),
335+
id: packSpecId,
336+
name: `Pack Specification ${packSpecId}`,
337+
postage: { id: "postageId", size: "STANDARD" },
338+
updatedAt: expect.any(String),
339+
version: 1,
340+
status: "PROD",
341+
});
342+
});
343+
344+
test("getPackSpecification throws error for non-existent pack specification", async () => {
345+
const packSpecId = "non-existent-pack-spec";
346+
347+
await expect(repository.getPackSpecification(packSpecId)).rejects.toThrow(
348+
`No pack specification found for id ${packSpecId}`,
349+
);
350+
});
266351
});

internal/datastore/src/supplier-config-repository.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,16 @@ import {
55
} from "@aws-sdk/lib-dynamodb";
66
import {
77
$LetterVariant,
8+
$PackSpecification,
89
$Supplier,
910
$SupplierAllocation,
11+
$SupplierPack,
1012
$VolumeGroup,
1113
LetterVariant,
14+
PackSpecification,
1215
Supplier,
1316
SupplierAllocation,
17+
SupplierPack,
1418
VolumeGroup,
1519
} from "@nhsdigital/nhs-notify-event-schemas-supplier-config";
1620

@@ -97,4 +101,44 @@ export class SupplierConfigRepository {
97101
}
98102
return suppliers;
99103
}
104+
105+
async getSupplierPacksForPackSpecification(
106+
packSpecId: string,
107+
): Promise<SupplierPack[]> {
108+
const result = await this.ddbClient.send(
109+
new QueryCommand({
110+
TableName: this.config.supplierConfigTableName,
111+
IndexName: "packSpecificationId-index",
112+
KeyConditionExpression: "#pk = :pk AND #packSpecId = :packSpecId",
113+
ExpressionAttributeNames: {
114+
"#pk": "PK",
115+
"#packSpecId": "packSpecificationId",
116+
},
117+
ExpressionAttributeValues: {
118+
":pk": "SUPPLIER_PACK",
119+
":packSpecId": packSpecId,
120+
},
121+
}),
122+
);
123+
if (!result.Items || result.Items.length === 0) {
124+
throw new Error(
125+
`No supplier packs found for pack specification id ${packSpecId}`,
126+
);
127+
}
128+
129+
return $SupplierPack.array().parse(result.Items);
130+
}
131+
132+
async getPackSpecification(packSpecId: string): Promise<PackSpecification> {
133+
const result = await this.ddbClient.send(
134+
new GetCommand({
135+
TableName: this.config.supplierConfigTableName,
136+
Key: { PK: "PACK_SPECIFICATION", SK: packSpecId },
137+
}),
138+
);
139+
if (!result.Item) {
140+
throw new Error(`No pack specification found for id ${packSpecId}`);
141+
}
142+
return $PackSpecification.parse(result.Item);
143+
}
100144
}

0 commit comments

Comments
 (0)