Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ describe("letter-variant-event-builder", () => {
description: "Test",
volumeGroupId: "volume-group-123" as any,
type: "STANDARD",
priority: 10,
packSpecificationIds: ["00000000-0000-0000-0000-000000000001" as any],
clientId: "client-1",
};
Expand Down
2 changes: 1 addition & 1 deletion packages/events/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@
"test:unit": "jest"
},
"types": "dist/index.d.ts",
"version": "1.0.2"
"version": "1.1.0"
}
7 changes: 6 additions & 1 deletion packages/events/src/domain/letter-variant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { $PackSpecification } from "@nhsdigital/nhs-notify-event-schemas-supplie
import { z } from "zod";
import { $VolumeGroup } from "./volume-group";
import { $Supplier } from "./supplier";
import { $Constraint, $Constraints } from "./constraint";
import { $Constraints } from "./constraint";

export const $LetterType = z.enum(["STANDARD", "BRAILLE", "AUDIO"]);

Expand Down Expand Up @@ -44,6 +44,11 @@ export const $LetterVariant = z
"This is used to restrict a particular variant to a single supplier, " +
"for example individual admail campaigns.",
}),
priority: z.int().min(1).max(99).default(50).meta({
title: "Priority",
description:
"Integer priority used to order letters for dispatch to suppliers on a 1 to 99 scale, where lower values indicate higher priority. Defaults to 50 when omitted.",
}),
packSpecificationIds: z.array(idRef($PackSpecification)).nonempty().meta({
title: "Pack Specifications",
description:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ describe("LetterVariant Events", () => {
description: "A standard letter variant for general correspondence",
volumeGroupId: "supplier-framework-123",
type: "STANDARD",
priority: 10,
status: "PROD",
packSpecificationIds: ["bau-standard-c5", "bau-standard-c4"],
},
Expand Down Expand Up @@ -68,6 +69,7 @@ describe("LetterVariant Events", () => {
name: "Braille Letter Variant",
volumeGroupId: "supplier-framework-123",
type: "BRAILLE",
priority: 20,
status: "PROD",
packSpecificationIds: ["braille"],
},
Expand All @@ -85,6 +87,7 @@ describe("LetterVariant Events", () => {
name: "Audio Letter Variant",
volumeGroupId: "supplier-framework-123",
type: "AUDIO",
priority: 30,
status: "PROD",
packSpecificationIds: ["audio"],
},
Expand Down Expand Up @@ -173,6 +176,86 @@ describe("LetterVariant Events", () => {
expect(result.success).toBe(false);
});

it("should reject event with non-integer priority", () => {
const invalidEvent = {
...validProdEvent,
data: {
...validProdEvent.data,
priority: 1.5,
},
};

const result = $LetterVariantEvent.safeParse(invalidEvent);
expect(result.success).toBe(false);
});

it("should default priority to 50 when omitted", () => {
const { priority, ...dataWithoutPriority } = validProdEvent.data;
expect(priority).toBe(10);
const eventWithoutPriority = {
...validProdEvent,
data: dataWithoutPriority,
};

const result = $LetterVariantEvent.safeParse(eventWithoutPriority);
expect(result.success).toBe(true);
expect(result.data?.data.priority).toBe(50);
});

it("should validate priority at the highest boundary value", () => {
const eventAtHighestPriority = {
...validProdEvent,
data: {
...validProdEvent.data,
priority: 1,
},
};

const result = $LetterVariantEvent.safeParse(eventAtHighestPriority);
expect(result.success).toBe(true);
expect(result.data?.data.priority).toBe(1);
});

it("should validate priority at the lowest boundary value", () => {
const eventAtLowestPriority = {
...validProdEvent,
data: {
...validProdEvent.data,
priority: 99,
},
};

const result = $LetterVariantEvent.safeParse(eventAtLowestPriority);
expect(result.success).toBe(true);
expect(result.data?.data.priority).toBe(99);
});

it("should reject priority lower than the allowed range", () => {
const invalidEvent = {
...validProdEvent,
data: {
...validProdEvent.data,
priority: 0,
},
};

const result = $LetterVariantEvent.safeParse(invalidEvent);
expect(result.success).toBe(false);
});

it("should reject priority higher than the allowed range", () => {
const invalidEvent = {
...validProdEvent,
data: {
...validProdEvent.data,
priority: 100,
},
};

const result = $LetterVariantEvent.safeParse(invalidEvent);
expect(result.success).toBe(false);
});

it("should validate specialised schema enforces PROD status", () => {
const prodSchema = letterVariantEvents["letter-variant.prod"];

Expand Down Expand Up @@ -290,6 +373,7 @@ describe("LetterVariant Events", () => {
name: "Disabled Letter Variant",
volumeGroupId: "supplier-framework-123",
type: "STANDARD",
priority: 15,
status: "INT",
packSpecificationIds: ["bau-standard-c5"],
},
Expand Down Expand Up @@ -350,6 +434,7 @@ describe("LetterVariant Events", () => {
description: "A letter variant that has been disabled",
volumeGroupId: "supplier-framework-123",
type: "STANDARD",
priority: 15,
status: "DISABLED",
packSpecificationIds: ["bau-standard-c5"],
},
Expand Down
5 changes: 5 additions & 0 deletions packages/events/src/examples/specification-examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ const variants: Record<string, LetterVariant> = {
volumeGroupId: "volume-group-12345",
packSpecificationIds: [bauStandardC5.id, bauStandardC4.id],
type: "STANDARD",
priority: 10,
status: "PROD",
constraints: {
sheets: {
Expand All @@ -186,6 +187,7 @@ const variants: Record<string, LetterVariant> = {
volumeGroupId: "volume-group-12345",
packSpecificationIds: [braille.id],
type: "BRAILLE",
priority: 20,
status: "PROD",
constraints: {
sheets: {
Expand All @@ -205,6 +207,7 @@ const variants: Record<string, LetterVariant> = {
volumeGroupId: "volume-group-12345",
packSpecificationIds: [audio.id],
type: "AUDIO",
priority: 30,
status: "PROD",
constraints: {
sheets: {
Expand All @@ -224,6 +227,7 @@ const variants: Record<string, LetterVariant> = {
volumeGroupId: "volume-group-12345",
packSpecificationIds: [sameDay.id],
type: "STANDARD",
priority: 5,
status: "PROD",
constraints: {
sheets: {
Expand All @@ -243,6 +247,7 @@ const variants: Record<string, LetterVariant> = {
volumeGroupId: "volume-group-campaign1",
packSpecificationIds: [clientPack1.id],
type: "STANDARD",
priority: 40,
status: "PROD",
clientId: "client1",
campaignIds: ["client1-campaign1"],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jest.mock("@nhsdigital/nhs-notify-event-schemas-supplier-config", () => {
}),
$LetterVariant: z.object({
id: z.string(),
priority: z.number().int().min(1).max(99).default(50),
packSpecificationIds: z.array(z.string()).min(1),
}),
$PackSpecification: z.object({
Expand Down Expand Up @@ -154,6 +155,7 @@ describe("validateConfigStore", () => {
records: [
makeRecord("letter-variant", "lv-1", {
id: "lv-1",
priority: 10,
packSpecificationIds: [123],
}),
],
Expand All @@ -163,6 +165,29 @@ describe("validateConfigStore", () => {
expect(result.issues[0]?.path).toEqual(["packSpecificationIds", 0]);
});

it("should reject letter variant priority values outside the allowed range", () => {
const result = validateConfigStore({
rootPath: mockRootPath,
records: [
makeRecord("letter-variant", "lv-1", {
id: "lv-1",
priority: 100,
packSpecificationIds: ["pack-spec-1"],
}),
],
});

expect(result.ok).toBe(false);
expect(result.issues).toEqual(
expect.arrayContaining([
expect.objectContaining({
entity: "letter-variant",
path: ["priority"],
}),
]),
);
});

it("should return ok=true with no issues when all records are valid", () => {
const result = validateConfigStore({
rootPath: mockRootPath,
Expand Down
Loading