Skip to content

Commit 92d4d26

Browse files
Add event-schemas-letter-rendering
1 parent d6602c3 commit 92d4d26

File tree

10 files changed

+111
-161
lines changed

10 files changed

+111
-161
lines changed

.devcontainer/devcontainer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,8 @@
8383
},
8484
"mounts": [
8585
"source=${localEnv:HOME}/.ssh,target=/home/vscode/.ssh,type=bind,consistency=cached",
86-
"source=${localEnv:HOME}/.aws,target=/home/vscode/.aws,type=bind,consistency=cached"
86+
"source=${localEnv:HOME}/.aws,target=/home/vscode/.aws,type=bind,consistency=cached",
87+
"source=${localEnv:HOME}/.npmrc,target=/home/vscode/.aws,type=bind,consistency=cached"
8788
],
8889
"name": "Devcontainer",
8990
"postCreateCommand": "scripts/devcontainer/postcreatecommand.sh"

infrastructure/terraform/components/api/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ No requirements.
3030
| <a name="input_project"></a> [project](#input\_project) | The name of the tfscaffold project | `string` | n/a | yes |
3131
| <a name="input_region"></a> [region](#input\_region) | The AWS Region | `string` | n/a | yes |
3232
| <a name="input_shared_infra_account_id"></a> [shared\_infra\_account\_id](#input\_shared\_infra\_account\_id) | The AWS Account ID of the shared infrastructure account | `string` | `"000000000000"` | no |
33+
| <a name="input_variant_map"></a> [variant\_map](#input\_variant\_map) | n/a | `map(object({ supplier_id = string, spec_id = string }))` | <pre>{<br/> "lv1": {<br/> "spec_id": "spec1",<br/> "supplier_id": "supplier1"<br/> },<br/> "lv2": {<br/> "spec_id": "spec2",<br/> "supplier_id": "supplier1"<br/> },<br/> "lv3": {<br/> "spec_id": "spec3",<br/> "supplier_id": "supplier2"<br/> }<br/>}</pre> | no |
3334
## Modules
3435

3536
| Name | Source | Version |

infrastructure/terraform/components/api/module_lambda_upsert_letter.tf

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,18 @@ module "upsert_letter" {
3535
log_destination_arn = local.destination_arn
3636
log_subscription_role_arn = local.acct.log_subscription_role_arn
3737

38-
lambda_env_vars = merge(local.common_lambda_env_vars, {})
38+
lambda_env_vars = merge(local.common_lambda_env_vars, {
39+
VARIANT_MAP = jsonencode(var.variant_map)
40+
})
41+
}
42+
43+
variable "variant_map" {
44+
type = map(object({ supplier_id = string, spec_id = string }))
45+
default = {
46+
"lv1" = { supplier_id = "supplier1", spec_id = "spec1" },
47+
"lv2" = { supplier_id = "supplier1", spec_id = "spec2" },
48+
"lv3" = { supplier_id = "supplier2", spec_id = "spec3" }
49+
}
3950
}
4051

4152
data "aws_iam_policy_document" "upsert_letter_lambda" {

lambdas/upsert-letter/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
"@aws-sdk/client-dynamodb": "^3.858.0",
44
"@aws-sdk/lib-dynamodb": "^3.858.0",
55
"@internal/datastore": "*",
6+
"@nhsdigital/nhs-notify-event-schemas-letter-rendering": "^1.1.5",
67
"@types/aws-lambda": "^8.10.148",
78
"esbuild": "^0.24.0",
89
"pino": "^9.7.0",

lambdas/upsert-letter/src/config/__tests__/env.test.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,32 @@ describe("lambdaEnv", () => {
1717
it("should load all environment variables successfully", () => {
1818
process.env.LETTERS_TABLE_NAME = "letters-table";
1919
process.env.LETTER_TTL_HOURS = "12960";
20+
process.env.VARIANT_MAP = `{
21+
"lv1": {
22+
"supplierId": "supplier1",
23+
"specId": "spec1"
24+
}
25+
}`;
2026

2127
const { envVars } = require("../env");
2228

2329
expect(envVars).toEqual({
2430
LETTERS_TABLE_NAME: "letters-table",
2531
LETTER_TTL_HOURS: 12_960,
32+
VARIANT_MAP: {
33+
lv1: {
34+
supplierId: "supplier1",
35+
specId: "spec1",
36+
},
37+
},
2638
});
2739
});
2840

2941
it("should throw if a required env var is missing", () => {
30-
process.env.LETTERS_TABLE_NAME = undefined; // simulate missing var
42+
process.env.LETTERS_TABLE_NAME = "table";
3143
process.env.LETTER_TTL_HOURS = "12960";
44+
process.env.VARIANT_MAP = undefined;
3245

3346
expect(() => require("../env")).toThrow(ZodError);
3447
});
35-
36-
it("should not throw if optional are not set", () => {
37-
process.env.LETTERS_TABLE_NAME = "letters-table";
38-
process.env.LETTER_TTL_HOURS = "12960";
39-
40-
const { envVars } = require("../env");
41-
42-
expect(envVars).toEqual({
43-
LETTERS_TABLE_NAME: "letters-table",
44-
LETTER_TTL_HOURS: 12_960,
45-
});
46-
});
4748
});

lambdas/upsert-letter/src/config/env.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
import { z } from "zod";
22

3+
const LetterVariantSchema = z.record(
4+
z.string(),
5+
z.object({
6+
supplierId: z.string(),
7+
specId: z.string(),
8+
}),
9+
);
10+
export type LetterVariant = z.infer<typeof LetterVariantSchema>;
11+
312
const EnvVarsSchema = z.object({
413
LETTERS_TABLE_NAME: z.string(),
514
LETTER_TTL_HOURS: z.coerce.number().int(),
15+
VARIANT_MAP: z.string().transform((str, _) => {
16+
const parsed = JSON.parse(str);
17+
return LetterVariantSchema.parse(parsed);
18+
}),
619
});
720

821
export type EnvVars = z.infer<typeof EnvVarsSchema>;

lambdas/upsert-letter/src/contracts/letters.ts

Lines changed: 0 additions & 123 deletions
This file was deleted.

lambdas/upsert-letter/src/__tests__/upsert-handler.test.ts renamed to lambdas/upsert-letter/src/handler/__tests__/upsert-handler.test.ts

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import { SQSEvent } from "aws-lambda";
22
import pino from "pino";
33
import { LetterRepository } from "internal/datastore/src";
4-
import createUpsertLetterHandler from "../handler/upsert-handler";
5-
import { Deps } from "../config/deps";
6-
import { EnvVars } from "../config/env";
7-
import { LetterRequestPreparedEvent } from "../contracts/letters";
4+
import { LetterRequestPreparedEvent } from "@nhsdigital/nhs-notify-event-schemas-letter-rendering";
5+
import createUpsertLetterHandler from "../upsert-handler";
6+
import { Deps } from "../../config/deps";
7+
import { EnvVars } from "../../config/env";
88

99
function createValidEvent(
1010
overrides: Partial<any> = {},
@@ -17,15 +17,14 @@ function createValidEvent(
1717
id: overrides.id ?? "7b9a03ca-342a-4150-b56b-989109c45613",
1818
source: "/data-plane/letter-rendering/test",
1919
subject: "client/client1/letter-request/letterRequest1",
20-
type: "uk.nhs.notify.letter-rendering.letter-request.PREPARED.v1",
20+
type: "uk.nhs.notify.letter-rendering.letter-request.prepared.v1",
2121
time: now,
2222
dataschema:
23-
"https://notify.nhs.uk/cloudevents/schemas/letter-rendering/letter-request.PREPARED.1.0.0.schema.json",
23+
"https://notify.nhs.uk/cloudevents/schemas/letter-rendering/letter-request.prepared.1.0.0.schema.json",
2424
dataschemaversion: "1.0.0",
2525
data: {
2626
domainId: overrides.domainId ?? "letter1",
27-
supplierId: overrides.supplierId ?? "supplier1",
28-
specificationId: overrides.specificationId ?? "spec1",
27+
letterVariantId: overrides.letterVariantId ?? "lv1",
2928
requestId: overrides.requestId ?? "request1",
3029
requestItemId: overrides.requestItemId ?? "requestItem1",
3130
requestItemPlanId: overrides.requestItemPlanId ?? "requestItemPlan1",
@@ -38,11 +37,12 @@ function createValidEvent(
3837
createdAt: now,
3938
pageCount: 1,
4039
status: "PREPARED",
41-
urgency: "STANDARD",
4240
},
4341
traceparent: "00-0af7651916cd43dd8448eb211c803191-b7ad6b7169203331-01",
4442
recordedtime: now,
45-
severitynumber: 1,
43+
severitynumber: 2,
44+
severitytext: "INFO",
45+
plane: "data",
4646
};
4747
}
4848

@@ -51,11 +51,17 @@ describe("createUpsertLetterHandler", () => {
5151
letterRepo: {
5252
upsertLetter: jest.fn(),
5353
} as unknown as LetterRepository,
54-
logger: { info: jest.fn(), error: jest.fn() } as unknown as pino.Logger,
54+
logger: { error: jest.fn() } as unknown as pino.Logger,
5555
env: {
5656
LETTERS_TABLE_NAME: "LETTERS_TABLE_NAME",
5757
LETTER_TTL_HOURS: 12_960,
58-
} as unknown as EnvVars,
58+
VARIANT_MAP: {
59+
lv1: {
60+
supplierId: "supplier1",
61+
specId: "spec1",
62+
},
63+
},
64+
} as EnvVars,
5965
} as Deps;
6066

6167
beforeEach(() => {

lambdas/upsert-letter/src/handler/upsert-handler.ts

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,68 @@
11
import { SQSBatchItemFailure, SQSEvent, SQSHandler } from "aws-lambda";
22
import { UpsertLetter } from "@internal/datastore";
33
import {
4+
$LetterRequestPreparedEvent,
45
LetterRequestPreparedEvent,
5-
LetterRequestPreparedEventSchema,
6-
} from "../contracts/letters";
6+
} from "@nhsdigital/nhs-notify-event-schemas-letter-rendering";
7+
import { ZodError } from "zod";
78
import { Deps } from "../config/deps";
89

10+
type SupplierSpec = { supplierId: string; specId: string };
11+
912
function mapToUpsertLetter(
1013
upsertRequest: LetterRequestPreparedEvent,
14+
supplier: string,
15+
spec: string,
1116
): UpsertLetter {
1217
return {
1318
id: upsertRequest.data.domainId,
14-
supplierId: upsertRequest.data.supplierId,
19+
supplierId: supplier,
1520
status: "PENDING",
16-
specificationId: upsertRequest.data.specificationId,
21+
specificationId: spec,
1722
groupId:
1823
upsertRequest.data.clientId +
1924
upsertRequest.data.campaignId +
2025
upsertRequest.data.templateId,
2126
url: upsertRequest.data.url,
2227
// TODO CCM-12997 source
23-
// TODO CCM-12997 urgency
2428
// TODO CCM-12997 queueVisibility
2529
};
2630
}
2731

32+
function resolveSupplierForVariant(
33+
variantId: string,
34+
deps: Deps,
35+
): SupplierSpec {
36+
return deps.env.VARIANT_MAP[variantId];
37+
}
38+
2839
export default function createUpsertLetterHandler(deps: Deps): SQSHandler {
2940
return async (event: SQSEvent) => {
3041
const batchItemFailures: SQSBatchItemFailure[] = [];
3142

3243
const tasks = event.Records.map(async (record) => {
3344
try {
3445
const upsertRequest: LetterRequestPreparedEvent =
35-
LetterRequestPreparedEventSchema.parse(JSON.parse(record.body));
46+
$LetterRequestPreparedEvent.parse(JSON.parse(record.body));
3647

37-
const letterToUpsert: UpsertLetter = mapToUpsertLetter(upsertRequest);
48+
const supplierSpec: SupplierSpec = resolveSupplierForVariant(
49+
upsertRequest.data.letterVariantId,
50+
deps,
51+
);
52+
const letterToUpsert: UpsertLetter = mapToUpsertLetter(
53+
upsertRequest,
54+
supplierSpec.supplierId,
55+
supplierSpec.specId,
56+
);
3857

3958
await deps.letterRepo.upsertLetter(letterToUpsert);
4059
} catch (error) {
60+
if (error instanceof ZodError) {
61+
deps.logger.error(
62+
{ issues: error.issues },
63+
"Error parsing letter event in upsert",
64+
);
65+
}
4166
deps.logger.error({ err: error }, "Error processing upsert");
4267
batchItemFailures.push({ itemIdentifier: record.messageId });
4368
}

0 commit comments

Comments
 (0)