placementt-core 1.400.1226 → 1.400.1228

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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"}
@@ -3869,6 +3869,12 @@ export type EmailInteraction = {
3869
3869
  * cycle later instead of just stopping. A reminder chain spawned BY a fallback
3870
3870
  * must NOT set this, or it would escalate recursively. */
3871
3871
  fallback?: ReminderFallbackType;
3872
+ /** Narrows the backend's 24 hour duplicate-email guard: an earlier send only
3873
+ * blocks a new one when their keys match. Placement emails use the stage they
3874
+ * are about (`stage:<id>` for action required, `to:<stage name>` for status
3875
+ * changes), so a new stage's email isn't mistaken for a repeat. Absent on
3876
+ * sends from before it existed and on emails that don't use it. */
3877
+ cooldownKey?: string;
3872
3878
  };
3873
3879
  /** Skills framework a skill can be tagged against. "custom" is the school's own selection
3874
3880
  * and is never used as a tag on a SkillLabel. */
@@ -4478,6 +4484,50 @@ export type EngagementEmailLog = {
4478
4484
  recipients: string[];
4479
4485
  sentAt: string;
4480
4486
  campaignId?: string;
4487
+ /** The approved draft it was sent from. */
4488
+ draftId?: string;
4489
+ };
4490
+ /** Where an engagement email is in its approval: written as a draft, approved
4491
+ * by an admin for the next school morning, then sent; or skipped by an admin,
4492
+ * expired unapproved, or dropped because the school did the step first. */
4493
+ export type EngagementDraftStatus = "draft" | "approved" | "sent" | "skipped" | "expired" | "dropped";
4494
+ /** `engagementDrafts/{autoId}`: one engagement email to one institute. The
4495
+ * daily check writes every email as one of these and nothing sends until an
4496
+ * admin approves it. */
4497
+ export type EngagementDraft = {
4498
+ oId: string;
4499
+ instituteName: string;
4500
+ kind: "marketing" | "onboarding";
4501
+ key: string;
4502
+ variant?: "setup" | "resend";
4503
+ touch?: number;
4504
+ templateId: number;
4505
+ label: string;
4506
+ description: string;
4507
+ path: string;
4508
+ campaignId?: string;
4509
+ /** Onboarding: `engagement.onboarding.repeats` once this is sent. */
4510
+ repeats?: number;
4511
+ recipients: {
4512
+ email: string;
4513
+ forename: string;
4514
+ surname: string;
4515
+ }[];
4516
+ /** Drafts with the same template and step, approved together. */
4517
+ batchKey: string;
4518
+ status: EngagementDraftStatus;
4519
+ createdAt: string;
4520
+ approvedAt?: string;
4521
+ approvedBy?: string;
4522
+ /** 7:30am London on the school day after approval. */
4523
+ sendAt?: string;
4524
+ sentAt?: string;
4525
+ sentTo?: string[];
4526
+ /** When it was skipped, expired or dropped, and why. */
4527
+ closedAt?: string;
4528
+ closedReason?: string;
4529
+ /** An admin changed the description or recipients. */
4530
+ edited?: boolean;
4481
4531
  };
4482
4532
  export type CustomerTask = {
4483
4533
  id: string;
@@ -1 +1 @@
1
- {"version":3,"file":"typeDefinitions.js","sourceRoot":"","sources":["../src/typeDefinitions.ts"],"names":[],"mappings":";;;AA6wIA,sDASC;AAeD,oDAKC;AAaD,0CAEC;AA/qED;;;;;kFAKkF;AACrE,QAAA,qBAAqB,GAAG,SAAS,CAAC;AAClC,QAAA,iBAAiB,GAAG,OAAO,CAAC;AA2lEzC;yEACyE;AAC5D,QAAA,0BAA0B,GAA2C;IAC9E,gBAAgB,EAAE,2BAA2B;IAC7C,mBAAmB,EAAE,sBAAsB;IAC3C,cAAc,EAAE,iBAAiB;IACjC,kBAAkB,EAAE,qBAAqB;IACzC,UAAU,EAAE,oCAAoC;IAChD,aAAa,EAAE,yBAAyB;IACxC,aAAa,EAAE,wBAAwB;IACvC,KAAK,EAAE,OAAO;CACjB,CAAC;AAEW,QAAA,0BAA0B,GAA+C;IAClF,QAAQ,EAAE,WAAW;IACrB,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,OAAO;CACjB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,SAAgB,qBAAqB,CAAC,SAAsC;IACxE,QAAQ,SAAS,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC;QAC5B,KAAK,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC;QAC7B,KAAK,WAAW,CAAC;QACjB,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,OAAO,CAAC,CAAC,OAAO,UAAU,CAAC;IAC3B,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,oBAAoB,CAChC,IAAwC,EACxC,MAA6C;IAE7C,OAAO,IAAI,EAAE,WAAW,IAAI,MAAM,EAAE,YAAY,IAAI,KAAK,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,eAAe,CAAC,KAA6D;IACzF,OAAO,GAAG,KAAK,CAAC,cAAc,IAAI,EAAE,IAAI,KAAK,CAAC,aAAa,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;AAC/E,CAAC"}
1
+ {"version":3,"file":"typeDefinitions.js","sourceRoot":"","sources":["../src/typeDefinitions.ts"],"names":[],"mappings":";;;AAmxIA,sDASC;AAeD,oDAKC;AAaD,0CAEC;AArrED;;;;;kFAKkF;AACrE,QAAA,qBAAqB,GAAG,SAAS,CAAC;AAClC,QAAA,iBAAiB,GAAG,OAAO,CAAC;AAimEzC;yEACyE;AAC5D,QAAA,0BAA0B,GAA2C;IAC9E,gBAAgB,EAAE,2BAA2B;IAC7C,mBAAmB,EAAE,sBAAsB;IAC3C,cAAc,EAAE,iBAAiB;IACjC,kBAAkB,EAAE,qBAAqB;IACzC,UAAU,EAAE,oCAAoC;IAChD,aAAa,EAAE,yBAAyB;IACxC,aAAa,EAAE,wBAAwB;IACvC,KAAK,EAAE,OAAO;CACjB,CAAC;AAEW,QAAA,0BAA0B,GAA+C;IAClF,QAAQ,EAAE,WAAW;IACrB,KAAK,EAAE,YAAY;IACnB,KAAK,EAAE,OAAO;CACjB,CAAC;AAEF;;;;;;;;;;;;;GAaG;AACH,SAAgB,qBAAqB,CAAC,SAAsC;IACxE,QAAQ,SAAS,EAAE,CAAC;QACpB,KAAK,MAAM,CAAC,CAAC,OAAO,OAAO,CAAC;QAC5B,KAAK,OAAO,CAAC,CAAC,OAAO,OAAO,CAAC;QAC7B,KAAK,WAAW,CAAC;QACjB,KAAK,OAAO,CAAC;QACb,KAAK,OAAO,CAAC;QACb,OAAO,CAAC,CAAC,OAAO,UAAU,CAAC;IAC3B,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,oBAAoB,CAChC,IAAwC,EACxC,MAA6C;IAE7C,OAAO,IAAI,EAAE,WAAW,IAAI,MAAM,EAAE,YAAY,IAAI,KAAK,CAAC;AAC9D,CAAC;AAED;;;;;;;;;;GAUG;AACH,SAAgB,eAAe,CAAC,KAA6D;IACzF,OAAO,GAAG,KAAK,CAAC,cAAc,IAAI,EAAE,IAAI,KAAK,CAAC,aAAa,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;AAC/E,CAAC"}
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.1228",
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
  *
@@ -3857,6 +3857,12 @@ export type EmailInteraction = {
3857
3857
  * cycle later instead of just stopping. A reminder chain spawned BY a fallback
3858
3858
  * must NOT set this, or it would escalate recursively. */
3859
3859
  fallback?: ReminderFallbackType,
3860
+ /** Narrows the backend's 24 hour duplicate-email guard: an earlier send only
3861
+ * blocks a new one when their keys match. Placement emails use the stage they
3862
+ * are about (`stage:<id>` for action required, `to:<stage name>` for status
3863
+ * changes), so a new stage's email isn't mistaken for a repeat. Absent on
3864
+ * sends from before it existed and on emails that don't use it. */
3865
+ cooldownKey?: string,
3860
3866
  }
3861
3867
 
3862
3868
  /** Skills framework a skill can be tagged against. "custom" is the school's own selection
@@ -4647,6 +4653,48 @@ export type EngagementEmailLog = {
4647
4653
  recipients: string[],
4648
4654
  sentAt: string,
4649
4655
  campaignId?: string,
4656
+ /** The approved draft it was sent from. */
4657
+ draftId?: string,
4658
+ };
4659
+
4660
+ /** Where an engagement email is in its approval: written as a draft, approved
4661
+ * by an admin for the next school morning, then sent; or skipped by an admin,
4662
+ * expired unapproved, or dropped because the school did the step first. */
4663
+ export type EngagementDraftStatus = "draft"|"approved"|"sent"|"skipped"|"expired"|"dropped";
4664
+
4665
+ /** `engagementDrafts/{autoId}`: one engagement email to one institute. The
4666
+ * daily check writes every email as one of these and nothing sends until an
4667
+ * admin approves it. */
4668
+ export type EngagementDraft = {
4669
+ oId: string,
4670
+ instituteName: string,
4671
+ kind: "marketing"|"onboarding",
4672
+ key: string,
4673
+ variant?: "setup"|"resend",
4674
+ touch?: number,
4675
+ templateId: number,
4676
+ label: string,
4677
+ description: string,
4678
+ path: string,
4679
+ campaignId?: string,
4680
+ /** Onboarding: `engagement.onboarding.repeats` once this is sent. */
4681
+ repeats?: number,
4682
+ recipients: {email: string, forename: string, surname: string}[],
4683
+ /** Drafts with the same template and step, approved together. */
4684
+ batchKey: string,
4685
+ status: EngagementDraftStatus,
4686
+ createdAt: string,
4687
+ approvedAt?: string,
4688
+ approvedBy?: string,
4689
+ /** 7:30am London on the school day after approval. */
4690
+ sendAt?: string,
4691
+ sentAt?: string,
4692
+ sentTo?: string[],
4693
+ /** When it was skipped, expired or dropped, and why. */
4694
+ closedAt?: string,
4695
+ closedReason?: string,
4696
+ /** An admin changed the description or recipients. */
4697
+ edited?: boolean,
4650
4698
  };
4651
4699
 
4652
4700
  export type CustomerTask = {