placementt-core 1.400.1226 → 1.400.1227

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,6 +47,19 @@ export declare const resolveBlackouts: (today: string) => OutreachBlackout[];
47
47
  * @return {OutreachBlackout|undefined} the blackout containing the date.
48
48
  */
49
49
  export declare const blackoutOn: (date: string, blackouts: OutreachBlackout[]) => OutreachBlackout | undefined;
50
+ /**
51
+ * @param {Date} date an instant.
52
+ * @return {string} its date in London, YYYY-MM-DD.
53
+ */
54
+ export declare const londonYmd: (date: Date) => string;
55
+ /**
56
+ * 7:30am London on the next school day after today: a weekday outside every
57
+ * school holiday. When approved engagement emails go out.
58
+ *
59
+ * @param {Date} now the clock.
60
+ * @return {string} ISO instant.
61
+ */
62
+ export declare const nextSchoolMorning: (now: Date) => string;
50
63
  /**
51
64
  * A term week is any week whose Tuesday is outside every blackout.
52
65
  *
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultCooldownUntil = exports.isTermWeek = exports.blackoutOn = exports.resolveBlackouts = exports.schoolHolidays = exports.easterSunday = exports.phaseOf = exports.ymdDaysBetween = exports.addYmdDays = void 0;
3
+ exports.defaultCooldownUntil = exports.isTermWeek = exports.nextSchoolMorning = exports.londonYmd = exports.blackoutOn = exports.resolveBlackouts = exports.schoolHolidays = exports.easterSunday = exports.phaseOf = exports.ymdDaysBetween = exports.addYmdDays = void 0;
4
4
  /**
5
5
  * Pure outreach rules shared by the web admin and the backend: school phase,
6
6
  * term weeks and cooldown dates. Dates are YYYY-MM-DD strings (Europe/London
@@ -144,6 +144,39 @@ exports.resolveBlackouts = resolveBlackouts;
144
144
  */
145
145
  const blackoutOn = (date, blackouts) => blackouts.find((b) => date >= b.start && date <= b.end);
146
146
  exports.blackoutOn = blackoutOn;
147
+ /**
148
+ * @param {Date} date an instant.
149
+ * @return {string} its date in London, YYYY-MM-DD.
150
+ */
151
+ const londonYmd = (date) => new Intl.DateTimeFormat("en-CA", { timeZone: "Europe/London", year: "numeric", month: "2-digit", day: "2-digit" }).format(date);
152
+ exports.londonYmd = londonYmd;
153
+ /**
154
+ * @param {string} date YYYY-MM-DD.
155
+ * @return {number} London's offset from UTC that day, in hours (0 or 1).
156
+ */
157
+ const londonOffsetHours = (date) => {
158
+ const name = new Intl.DateTimeFormat("en-GB", { timeZone: "Europe/London", timeZoneName: "shortOffset" })
159
+ .formatToParts(new Date(`${date}T12:00:00Z`)).find((p) => p.type === "timeZoneName")?.value;
160
+ return name === "GMT+1" ? 1 : 0;
161
+ };
162
+ /**
163
+ * 7:30am London on the next school day after today: a weekday outside every
164
+ * school holiday. When approved engagement emails go out.
165
+ *
166
+ * @param {Date} now the clock.
167
+ * @return {string} ISO instant.
168
+ */
169
+ const nextSchoolMorning = (now) => {
170
+ const today = (0, exports.londonYmd)(now);
171
+ const blackouts = (0, exports.resolveBlackouts)(today);
172
+ let day = (0, exports.addYmdDays)(today, 1);
173
+ const weekend = (d) => [0, 6].includes(new Date(toMs(d)).getUTCDay());
174
+ while (weekend(day) || (0, exports.blackoutOn)(day, blackouts))
175
+ day = (0, exports.addYmdDays)(day, 1);
176
+ const [y, m, d] = day.split("-").map(Number);
177
+ return new Date(Date.UTC(y, m - 1, d, 7 - londonOffsetHours(day), 30)).toISOString();
178
+ };
179
+ exports.nextSchoolMorning = nextSchoolMorning;
147
180
  /**
148
181
  * A term week is any week whose Tuesday is outside every blackout.
149
182
  *
@@ -1 +1 @@
1
- {"version":3,"file":"outreachRules.js","sourceRoot":"","sources":["../src/outreachRules.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"outreachRules.js","sourceRoot":"","sources":["../src/outreachRules.ts"],"names":[],"mappings":"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"}
@@ -91,4 +91,19 @@ describe("defaultCooldownUntil", () => {
91
91
  expect((0, outreachRules_1.defaultCooldownUntil)("2026-11-10")).toBe("2027-04-10");
92
92
  });
93
93
  });
94
+ describe("nextSchoolMorning", () => {
95
+ it("is 7:30am London the next weekday", () => {
96
+ expect((0, outreachRules_1.nextSchoolMorning)(new Date("2026-11-02T10:00:00Z"))).toBe("2026-11-03T07:30:00.000Z");
97
+ expect((0, outreachRules_1.nextSchoolMorning)(new Date("2026-11-06T16:00:00Z"))).toBe("2026-11-09T07:30:00.000Z");
98
+ });
99
+ it("is 6:30 UTC in British Summer Time", () => {
100
+ expect((0, outreachRules_1.nextSchoolMorning)(new Date("2026-06-11T10:00:00Z"))).toBe("2026-06-12T06:30:00.000Z");
101
+ });
102
+ it("skips school holidays", () => {
103
+ expect((0, outreachRules_1.nextSchoolMorning)(new Date("2026-12-11T10:00:00Z"))).toBe("2027-01-04T07:30:00.000Z");
104
+ });
105
+ it("reads the date in London, not UTC", () => {
106
+ expect((0, outreachRules_1.londonYmd)(new Date("2026-06-11T23:30:00Z"))).toBe("2026-06-12");
107
+ });
108
+ });
94
109
  //# sourceMappingURL=outreachRules.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"outreachRules.test.js","sourceRoot":"","sources":["../src/outreachRules.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"outreachRules.test.js","sourceRoot":"","sources":["../src/outreachRules.test.ts"],"names":[],"mappings":"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"}
@@ -4478,6 +4478,50 @@ export type EngagementEmailLog = {
4478
4478
  recipients: string[];
4479
4479
  sentAt: string;
4480
4480
  campaignId?: string;
4481
+ /** The approved draft it was sent from. */
4482
+ draftId?: string;
4483
+ };
4484
+ /** Where an engagement email is in its approval: written as a draft, approved
4485
+ * by an admin for the next school morning, then sent; or skipped by an admin,
4486
+ * expired unapproved, or dropped because the school did the step first. */
4487
+ export type EngagementDraftStatus = "draft" | "approved" | "sent" | "skipped" | "expired" | "dropped";
4488
+ /** `engagementDrafts/{autoId}`: one engagement email to one institute. The
4489
+ * daily check writes every email as one of these and nothing sends until an
4490
+ * admin approves it. */
4491
+ export type EngagementDraft = {
4492
+ oId: string;
4493
+ instituteName: string;
4494
+ kind: "marketing" | "onboarding";
4495
+ key: string;
4496
+ variant?: "setup" | "resend";
4497
+ touch?: number;
4498
+ templateId: number;
4499
+ label: string;
4500
+ description: string;
4501
+ path: string;
4502
+ campaignId?: string;
4503
+ /** Onboarding: `engagement.onboarding.repeats` once this is sent. */
4504
+ repeats?: number;
4505
+ recipients: {
4506
+ email: string;
4507
+ forename: string;
4508
+ surname: string;
4509
+ }[];
4510
+ /** Drafts with the same template and step, approved together. */
4511
+ batchKey: string;
4512
+ status: EngagementDraftStatus;
4513
+ createdAt: string;
4514
+ approvedAt?: string;
4515
+ approvedBy?: string;
4516
+ /** 7:30am London on the school day after approval. */
4517
+ sendAt?: string;
4518
+ sentAt?: string;
4519
+ sentTo?: string[];
4520
+ /** When it was skipped, expired or dropped, and why. */
4521
+ closedAt?: string;
4522
+ closedReason?: string;
4523
+ /** An admin changed the description or recipients. */
4524
+ edited?: boolean;
4481
4525
  };
4482
4526
  export type CustomerTask = {
4483
4527
  id: string;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "private": false,
3
3
  "name": "placementt-core",
4
4
  "author": "Placementt",
5
- "version": "1.400.1226",
5
+ "version": "1.400.1227",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
8
8
  "scripts": {
@@ -1,5 +1,5 @@
1
1
  import {isInBlackout} from "./customerCareConfig";
2
- import {addYmdDays, blackoutOn, ymdDaysBetween, defaultCooldownUntil, easterSunday, isTermWeek, phaseOf, resolveBlackouts, schoolHolidays} from "./outreachRules";
2
+ import {addYmdDays, blackoutOn, ymdDaysBetween, defaultCooldownUntil, easterSunday, isTermWeek, londonYmd, nextSchoolMorning, phaseOf, resolveBlackouts, schoolHolidays} from "./outreachRules";
3
3
 
4
4
  // customerCareConfig pulls in productResolver, whose imports jest cannot parse; only isInBlackout is needed here.
5
5
  jest.mock("./productResolver", () => ({resolveProducts: jest.fn()}));
@@ -102,3 +102,19 @@ describe("defaultCooldownUntil", () => {
102
102
  expect(defaultCooldownUntil("2026-11-10")).toBe("2027-04-10");
103
103
  });
104
104
  });
105
+
106
+ describe("nextSchoolMorning", () => {
107
+ it("is 7:30am London the next weekday", () => {
108
+ expect(nextSchoolMorning(new Date("2026-11-02T10:00:00Z"))).toBe("2026-11-03T07:30:00.000Z");
109
+ expect(nextSchoolMorning(new Date("2026-11-06T16:00:00Z"))).toBe("2026-11-09T07:30:00.000Z");
110
+ });
111
+ it("is 6:30 UTC in British Summer Time", () => {
112
+ expect(nextSchoolMorning(new Date("2026-06-11T10:00:00Z"))).toBe("2026-06-12T06:30:00.000Z");
113
+ });
114
+ it("skips school holidays", () => {
115
+ expect(nextSchoolMorning(new Date("2026-12-11T10:00:00Z"))).toBe("2027-01-04T07:30:00.000Z");
116
+ });
117
+ it("reads the date in London, not UTC", () => {
118
+ expect(londonYmd(new Date("2026-06-11T23:30:00Z"))).toBe("2026-06-12");
119
+ });
120
+ });
@@ -152,6 +152,40 @@ export const resolveBlackouts = (today: string): OutreachBlackout[] => {
152
152
  export const blackoutOn = (date: string, blackouts: OutreachBlackout[]): OutreachBlackout | undefined =>
153
153
  blackouts.find((b) => date >= b.start && date <= b.end);
154
154
 
155
+ /**
156
+ * @param {Date} date an instant.
157
+ * @return {string} its date in London, YYYY-MM-DD.
158
+ */
159
+ export const londonYmd = (date: Date): string =>
160
+ new Intl.DateTimeFormat("en-CA", {timeZone: "Europe/London", year: "numeric", month: "2-digit", day: "2-digit"}).format(date);
161
+
162
+ /**
163
+ * @param {string} date YYYY-MM-DD.
164
+ * @return {number} London's offset from UTC that day, in hours (0 or 1).
165
+ */
166
+ const londonOffsetHours = (date: string): number => {
167
+ const name = new Intl.DateTimeFormat("en-GB", {timeZone: "Europe/London", timeZoneName: "shortOffset"})
168
+ .formatToParts(new Date(`${date}T12:00:00Z`)).find((p) => p.type === "timeZoneName")?.value;
169
+ return name === "GMT+1" ? 1 : 0;
170
+ };
171
+
172
+ /**
173
+ * 7:30am London on the next school day after today: a weekday outside every
174
+ * school holiday. When approved engagement emails go out.
175
+ *
176
+ * @param {Date} now the clock.
177
+ * @return {string} ISO instant.
178
+ */
179
+ export const nextSchoolMorning = (now: Date): string => {
180
+ const today = londonYmd(now);
181
+ const blackouts = resolveBlackouts(today);
182
+ let day = addYmdDays(today, 1);
183
+ const weekend = (d: string) => [0, 6].includes(new Date(toMs(d)).getUTCDay());
184
+ while (weekend(day) || blackoutOn(day, blackouts)) day = addYmdDays(day, 1);
185
+ const [y, m, d] = day.split("-").map(Number);
186
+ return new Date(Date.UTC(y, m - 1, d, 7 - londonOffsetHours(day), 30)).toISOString();
187
+ };
188
+
155
189
  /**
156
190
  * A term week is any week whose Tuesday is outside every blackout.
157
191
  *
@@ -4647,6 +4647,48 @@ export type EngagementEmailLog = {
4647
4647
  recipients: string[],
4648
4648
  sentAt: string,
4649
4649
  campaignId?: string,
4650
+ /** The approved draft it was sent from. */
4651
+ draftId?: string,
4652
+ };
4653
+
4654
+ /** Where an engagement email is in its approval: written as a draft, approved
4655
+ * by an admin for the next school morning, then sent; or skipped by an admin,
4656
+ * expired unapproved, or dropped because the school did the step first. */
4657
+ export type EngagementDraftStatus = "draft"|"approved"|"sent"|"skipped"|"expired"|"dropped";
4658
+
4659
+ /** `engagementDrafts/{autoId}`: one engagement email to one institute. The
4660
+ * daily check writes every email as one of these and nothing sends until an
4661
+ * admin approves it. */
4662
+ export type EngagementDraft = {
4663
+ oId: string,
4664
+ instituteName: string,
4665
+ kind: "marketing"|"onboarding",
4666
+ key: string,
4667
+ variant?: "setup"|"resend",
4668
+ touch?: number,
4669
+ templateId: number,
4670
+ label: string,
4671
+ description: string,
4672
+ path: string,
4673
+ campaignId?: string,
4674
+ /** Onboarding: `engagement.onboarding.repeats` once this is sent. */
4675
+ repeats?: number,
4676
+ recipients: {email: string, forename: string, surname: string}[],
4677
+ /** Drafts with the same template and step, approved together. */
4678
+ batchKey: string,
4679
+ status: EngagementDraftStatus,
4680
+ createdAt: string,
4681
+ approvedAt?: string,
4682
+ approvedBy?: string,
4683
+ /** 7:30am London on the school day after approval. */
4684
+ sendAt?: string,
4685
+ sentAt?: string,
4686
+ sentTo?: string[],
4687
+ /** When it was skipped, expired or dropped, and why. */
4688
+ closedAt?: string,
4689
+ closedReason?: string,
4690
+ /** An admin changed the description or recipients. */
4691
+ edited?: boolean,
4650
4692
  };
4651
4693
 
4652
4694
  export type CustomerTask = {