Skip to content

Commit ced0897

Browse files
Get the variant details
1 parent 06efb12 commit ced0897

10 files changed

Lines changed: 118 additions & 12 deletions

File tree

infrastructure/terraform/components/api/locals.tf

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,16 @@ locals {
2020
destination_arn = "arn:aws:logs:${var.region}:${var.shared_infra_account_id}:destination:nhs-main-obs-firehose-logs"
2121

2222
common_lambda_env_vars = {
23-
LETTERS_TABLE_NAME = aws_dynamodb_table.letters.name,
24-
MI_TABLE_NAME = aws_dynamodb_table.mi.name,
25-
LETTER_TTL_HOURS = 12960, # 18 months * 30 days * 24 hours
26-
MI_TTL_HOURS = 2160 # 90 days * 24 hours
27-
SUPPLIER_ID_HEADER = "nhsd-supplier-id",
28-
APIM_CORRELATION_HEADER = "nhsd-correlation-id",
29-
DOWNLOAD_URL_TTL_SECONDS = 60
30-
SNS_TOPIC_ARN = "${module.eventsub.sns_topic.arn}",
31-
EVENT_SOURCE = "/data-plane/supplier-api/${var.group}/${var.environment}/letters"
23+
LETTERS_TABLE_NAME = aws_dynamodb_table.letters.name,
24+
MI_TABLE_NAME = aws_dynamodb_table.mi.name,
25+
LETTER_TTL_HOURS = 12960, # 18 months * 30 days * 24 hours
26+
MI_TTL_HOURS = 2160 # 90 days * 24 hours
27+
SUPPLIER_ID_HEADER = "nhsd-supplier-id",
28+
APIM_CORRELATION_HEADER = "nhsd-correlation-id",
29+
DOWNLOAD_URL_TTL_SECONDS = 60
30+
SNS_TOPIC_ARN = "${module.eventsub.sns_topic.arn}",
31+
EVENT_SOURCE = "/data-plane/supplier-api/${var.group}/${var.environment}/letters"
32+
SUPPLIER_CONFIG_TABLE_NAME = aws_dynamodb_table.supplier-configuration.name
3233
}
3334

3435
core_pdf_bucket_arn = "arn:aws:s3:::comms-${var.core_account_id}-eu-west-2-${var.core_environment}-api-stg-pdf-pipeline"

infrastructure/terraform/components/api/module_lambda_supplier_allocator.tf

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,4 +82,18 @@ data "aws_iam_policy_document" "supplier_allocator_lambda" {
8282
module.sqs_letter_updates.sqs_queue_arn
8383
]
8484
}
85+
86+
statement {
87+
sid = "AllowDynamoDBAccess"
88+
effect = "Allow"
89+
90+
actions = [
91+
"dynamodb:GetItem",
92+
"dynamodb:Query"
93+
]
94+
95+
resources = [
96+
aws_dynamodb_table.supplier-configuration.arn
97+
]
98+
}
8599
}

internal/datastore/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,6 @@ export * from "./errors";
33
export * from "./mi-repository";
44
export * from "./letter-repository";
55
export * from "./supplier-repository";
6+
export * from "./supplier-config-repository";
67
export { default as LetterQueueRepository } from "./letter-queue-repository";
78
export { default as DBHealthcheck } from "./healthcheck";
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { DynamoDBDocumentClient, GetCommand } from "@aws-sdk/lib-dynamodb";
2+
import { Logger } from "pino";
3+
import { $LetterVariant, LetterVariant } from "./SupplierConfigDomain";
4+
5+
export type SupplierConfigRepositoryConfig = {
6+
supplierConfigTableName: string;
7+
};
8+
9+
export class SupplierConfigRepository {
10+
constructor(
11+
readonly ddbClient: DynamoDBDocumentClient,
12+
readonly log: Logger,
13+
readonly config: SupplierConfigRepositoryConfig,
14+
) {}
15+
16+
async getLetterVariant(variantId: string): Promise<LetterVariant> {
17+
const result = await this.ddbClient.send(
18+
new GetCommand({
19+
TableName: this.config.supplierConfigTableName,
20+
Key: { PK: "LETTER_VARIANT", SK: variantId },
21+
}),
22+
);
23+
if (!result.Item) {
24+
throw new Error(`Letter variant with id ${variantId} not found`);
25+
}
26+
return $LetterVariant.parse(result.Item);
27+
}
28+
}

lambdas/supplier-allocator/src/config/__tests__/deps.test.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import type { Deps } from "lambdas/supplier-allocator/src/config/deps";
22

33
describe("createDependenciesContainer", () => {
44
const env = {
5+
SUPPLIER_CONFIG_TABLE_NAME: "SupplierConfigTable",
56
VARIANT_MAP: {
67
lv1: {
78
supplierId: "supplier1",
@@ -25,19 +26,30 @@ describe("createDependenciesContainer", () => {
2526
})),
2627
}));
2728

29+
// Repo client
30+
jest.mock("@internal/datastore", () => ({
31+
SupplierConfigRepository: jest.fn(),
32+
}));
33+
2834
// Env
2935
jest.mock("../env", () => ({ envVars: env }));
3036
});
3137

3238
test("constructs deps and wires repository config correctly", async () => {
3339
// get current mock instances
3440
const { createLogger } = jest.requireMock("@internal/helpers");
35-
41+
const { SupplierConfigRepository } = jest.requireMock(
42+
"@internal/datastore",
43+
);
3644
// eslint-disable-next-line @typescript-eslint/no-require-imports
3745
const { createDependenciesContainer } = require("../deps");
3846
const deps: Deps = createDependenciesContainer();
3947
expect(createLogger).toHaveBeenCalledTimes(1);
40-
48+
expect(SupplierConfigRepository).toHaveBeenCalledTimes(1);
49+
const supplierConfigRepoCtorArgs = SupplierConfigRepository.mock.calls[0];
50+
expect(supplierConfigRepoCtorArgs[2]).toEqual({
51+
supplierConfigTableName: "SupplierConfigTable",
52+
});
4153
expect(deps.env).toEqual(env);
4254
});
4355
});

lambdas/supplier-allocator/src/config/__tests__/env.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ describe("lambdaEnv", () => {
1515
});
1616

1717
it("should load all environment variables successfully", () => {
18+
process.env.SUPPLIER_CONFIG_TABLE_NAME = "SupplierConfigTable";
1819
process.env.VARIANT_MAP = `{
1920
"lv1": {
2021
"supplierId": "supplier1",
@@ -25,6 +26,7 @@ describe("lambdaEnv", () => {
2526
const { envVars } = require("../env");
2627

2728
expect(envVars).toEqual({
29+
SUPPLIER_CONFIG_TABLE_NAME: "SupplierConfigTable",
2830
VARIANT_MAP: {
2931
lv1: {
3032
supplierId: "supplier1",

lambdas/supplier-allocator/src/config/deps.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,40 @@
1+
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
2+
import { DynamoDBDocumentClient } from "@aws-sdk/lib-dynamodb";
13
import { SQSClient } from "@aws-sdk/client-sqs";
24
import { Logger } from "pino";
35
import { createLogger } from "@internal/helpers";
6+
import { SupplierConfigRepository } from "@internal/datastore";
47
import { EnvVars, envVars } from "./env";
58

69
export type Deps = {
10+
supplierConfigRepo: SupplierConfigRepository;
711
logger: Logger;
812
env: EnvVars;
913
sqsClient: SQSClient;
1014
};
1115

16+
function createDocumentClient(): DynamoDBDocumentClient {
17+
const ddbClient = new DynamoDBClient({});
18+
return DynamoDBDocumentClient.from(ddbClient);
19+
}
20+
21+
function createSupplierConfigRepository(
22+
log: Logger,
23+
// eslint-disable-next-line @typescript-eslint/no-shadow
24+
envVars: EnvVars,
25+
): SupplierConfigRepository {
26+
const config = {
27+
supplierConfigTableName: envVars.SUPPLIER_CONFIG_TABLE_NAME,
28+
};
29+
30+
return new SupplierConfigRepository(createDocumentClient(), log, config);
31+
}
32+
1233
export function createDependenciesContainer(): Deps {
1334
const log = createLogger({ logLevel: envVars.PINO_LOG_LEVEL });
1435

1536
return {
37+
supplierConfigRepo: createSupplierConfigRepository(log, envVars),
1638
logger: log,
1739
env: envVars,
1840
sqsClient: new SQSClient({}),

lambdas/supplier-allocator/src/config/env.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const LetterVariantSchema = z.record(
1010
export type LetterVariant = z.infer<typeof LetterVariantSchema>;
1111

1212
const EnvVarsSchema = z.object({
13+
SUPPLIER_CONFIG_TABLE_NAME: z.string(),
1314
PINO_LOG_LEVEL: z.coerce.string().optional(),
1415
VARIANT_MAP: z.string().transform((str, _) => {
1516
const parsed = JSON.parse(str);

lambdas/supplier-allocator/src/handler/__tests__/allocate-handler.test.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
$LetterEvent,
88
LetterEvent,
99
} from "@nhsdigital/nhs-notify-event-schemas-supplier-api/src/events/letter-events";
10+
import { SupplierConfigRepository } from "@internal/datastore";
1011
import createSupplierAllocatorHandler from "../allocate-handler";
1112
import { Deps } from "../../config/deps";
1213
import { EnvVars } from "../../config/env";
@@ -139,8 +140,16 @@ describe("createSupplierAllocatorHandler", () => {
139140
} as unknown as jest.Mocked<SQSClient>;
140141

141142
mockedDeps = {
143+
supplierConfigRepo: {
144+
getLetterVariant: jest.fn().mockResolvedValue({
145+
id: "variant1",
146+
supplierId: "supplier1",
147+
specId: "spec1",
148+
}),
149+
} as unknown as SupplierConfigRepository,
142150
logger: { error: jest.fn(), info: jest.fn() } as unknown as pino.Logger,
143151
env: {
152+
SUPPLIER_CONFIG_TABLE_NAME: "SupplierConfigTable",
144153
VARIANT_MAP: {
145154
lv1: {
146155
supplierId: "supplier1",

lambdas/supplier-allocator/src/handler/allocate-handler.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SQSBatchItemFailure, SQSEvent, SQSHandler } from "aws-lambda";
22
import { SendMessageCommand } from "@aws-sdk/client-sqs";
33
import { LetterRequestPreparedEvent } from "@nhsdigital/nhs-notify-event-schemas-letter-rendering-v1";
4-
4+
import { LetterVariant } from "internal/datastore/src/SupplierConfigDomain";
55
import { LetterRequestPreparedEventV2 } from "@nhsdigital/nhs-notify-event-schemas-letter-rendering";
66
import z from "zod";
77
import { Deps } from "../config/deps";
@@ -46,7 +46,23 @@ function validateType(event: unknown) {
4646
}
4747
}
4848

49+
async function getVariantDetails(variantId: string, deps: Deps) {
50+
deps.logger.info({
51+
description: "Fetching letter variant details from database",
52+
variantId,
53+
});
54+
55+
const variantDetails: LetterVariant =
56+
await deps.supplierConfigRepo.getLetterVariant(variantId);
57+
deps.logger.info({
58+
description: "Fetched letter variant details",
59+
variantId,
60+
variantDetails,
61+
});
62+
}
63+
4964
function getSupplier(letterEvent: PreparedEvents, deps: Deps): SupplierSpec {
65+
getVariantDetails(letterEvent.data.letterVariantId, deps);
5066
return resolveSupplierForVariant(letterEvent.data.letterVariantId, deps);
5167
}
5268

0 commit comments

Comments
 (0)