placementt-core 1.400.1255 → 1.400.1256
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.
- package/lib/bulkEngagement.d.ts +45 -4
- package/lib/bulkEngagement.js +74 -11
- package/lib/bulkEngagement.js.map +1 -1
- package/lib/bulkEngagement.test.js +47 -0
- package/lib/bulkEngagement.test.js.map +1 -1
- package/lib/renewals.d.ts +2 -4
- package/lib/renewals.js +3 -5
- package/lib/renewals.js.map +1 -1
- package/package.json +1 -1
- package/src/bulkEngagement.test.ts +59 -1
- package/src/bulkEngagement.ts +96 -11
- package/src/renewals.ts +2 -5
package/lib/bulkEngagement.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { InstituteData } from "./typeDefinitions";
|
|
1
|
+
import { CohortData, ExternalEvent, InstituteData } from "./typeDefinitions";
|
|
2
2
|
import { ResolvedProducts } from "./productResolver";
|
|
3
|
+
import { SurveyCycle } from "./surveys/types";
|
|
3
4
|
/**
|
|
4
5
|
* Bulk engagement emails: one admin email template, sent now to many schools.
|
|
5
6
|
* The admin decides what goes out and when; this only suggests which schools
|
|
@@ -31,6 +32,35 @@ export declare const BULK_TEST_RECIPIENT = "tom@careerthread.co.uk";
|
|
|
31
32
|
export declare const BULK_TEST_SCHOOLS = 3;
|
|
32
33
|
/** A school that had this email this recently isn't suggested it again. */
|
|
33
34
|
export declare const RECENTLY_SENT_DAYS = 60;
|
|
35
|
+
/**
|
|
36
|
+
* What a school has confirmed for this academic year or later. Drafts don't
|
|
37
|
+
* count: autoCreateCohorts starts a blank cohort for every recurring group
|
|
38
|
+
* each year, whether or not the school goes on to use it.
|
|
39
|
+
*/
|
|
40
|
+
export type BulkYearSetup = {
|
|
41
|
+
cohorts: number;
|
|
42
|
+
surveys: number;
|
|
43
|
+
events: number;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Counts what a school has confirmed for the current academic year or later,
|
|
47
|
+
* for checks like the renewal emails'.
|
|
48
|
+
*
|
|
49
|
+
* Each is counted once staff have finished it, and still counts after it ends:
|
|
50
|
+
* - A cohort that has been activated, for this year. One made by hand before
|
|
51
|
+
* cohorts carried `academicYear` is placed by its placement end date.
|
|
52
|
+
* - A survey that isn't a draft.
|
|
53
|
+
* - An event past its setup stages, on or after 1 September.
|
|
54
|
+
*
|
|
55
|
+
* @param {object} docs the school's cohorts, survey cycles and events.
|
|
56
|
+
* @param {Date} now the current time.
|
|
57
|
+
* @return {BulkYearSetup} how many of each.
|
|
58
|
+
*/
|
|
59
|
+
export declare const bulkYearSetup: (docs: {
|
|
60
|
+
cohorts: Partial<Pick<CohortData, "stage" | "academicYear" | "endPlacements">>[];
|
|
61
|
+
surveyCycles: Partial<Pick<SurveyCycle, "status" | "academicYear">>[];
|
|
62
|
+
events: Partial<Pick<ExternalEvent, "stage" | "startDate" | "endDate">>[];
|
|
63
|
+
}, now: Date) => BulkYearSetup;
|
|
34
64
|
export type BulkEngagementSchool = {
|
|
35
65
|
institute: InstituteData;
|
|
36
66
|
products: ResolvedProducts;
|
|
@@ -43,6 +73,8 @@ export type BulkEngagementSchool = {
|
|
|
43
73
|
nextOnboardingTemplate?: string;
|
|
44
74
|
/** ISO date this email last went to the school, if it has. */
|
|
45
75
|
lastSent?: string;
|
|
76
|
+
/** What it has confirmed for the year, for the checks that ask. Absent means unknown. */
|
|
77
|
+
yearSetup?: BulkYearSetup;
|
|
46
78
|
};
|
|
47
79
|
export type BulkEngagementSuggestion = {
|
|
48
80
|
/** Ticked to start with in the send popup. */
|
|
@@ -51,12 +83,21 @@ export type BulkEngagementSuggestion = {
|
|
|
51
83
|
reason?: string;
|
|
52
84
|
flags: BulkEngagementFlag[];
|
|
53
85
|
};
|
|
86
|
+
/** Whether an email suits a school, and why, for the admin. */
|
|
87
|
+
export type BulkTemplateCheck = (school: BulkEngagementSchool) => {
|
|
88
|
+
suggested: boolean;
|
|
89
|
+
reason?: string;
|
|
90
|
+
};
|
|
91
|
+
/** The check for each email with its own rule for who it suits. Add an email here to give it one. */
|
|
92
|
+
export declare const BULK_TEMPLATE_CHECKS: {
|
|
93
|
+
[templateKey: string]: BulkTemplateCheck;
|
|
94
|
+
};
|
|
54
95
|
/**
|
|
55
96
|
* Whether one email suits one school, and what is missing for it.
|
|
56
97
|
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
98
|
+
* The email's check in BULK_TEMPLATE_CHECKS decides, or failing that whether
|
|
99
|
+
* it is the school's next onboarding step. Nothing is suggested to a school
|
|
100
|
+
* with no one to send to, or that had the email in the last 60 days.
|
|
60
101
|
*
|
|
61
102
|
* @param {string} templateKey the admin email template.
|
|
62
103
|
* @param {BulkEngagementSchool} school the school.
|
package/lib/bulkEngagement.js
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.bulkSentAgo = exports.matchesBulkFilters = exports.bulkEngagementSuggestion = exports.RECENTLY_SENT_DAYS = exports.BULK_TEST_SCHOOLS = exports.BULK_TEST_RECIPIENT = exports.BULK_ENGAGEMENT_PRODUCT_LABELS = exports.BULK_ENGAGEMENT_PRODUCTS = exports.BULK_ENGAGEMENT_PACKAGE_LABELS = exports.BULK_ENGAGEMENT_BLOCKING_FLAGS = exports.BULK_ENGAGEMENT_FLAG_LABELS = void 0;
|
|
3
|
+
exports.bulkSentAgo = exports.matchesBulkFilters = exports.bulkEngagementSuggestion = exports.BULK_TEMPLATE_CHECKS = exports.bulkYearSetup = exports.RECENTLY_SENT_DAYS = exports.BULK_TEST_SCHOOLS = exports.BULK_TEST_RECIPIENT = exports.BULK_ENGAGEMENT_PRODUCT_LABELS = exports.BULK_ENGAGEMENT_PRODUCTS = exports.BULK_ENGAGEMENT_PACKAGE_LABELS = exports.BULK_ENGAGEMENT_BLOCKING_FLAGS = exports.BULK_ENGAGEMENT_FLAG_LABELS = void 0;
|
|
4
4
|
const renewals_1 = require("./renewals");
|
|
5
5
|
const constants_1 = require("./constants");
|
|
6
6
|
const outreachRules_1 = require("./outreachRules");
|
|
7
|
+
const schedule_1 = require("./surveys/schedule");
|
|
7
8
|
exports.BULK_ENGAGEMENT_FLAG_LABELS = {
|
|
8
9
|
noContacts: "No one to send to",
|
|
9
10
|
noRenewalDate: "No renewal date",
|
|
@@ -32,19 +33,84 @@ exports.BULK_TEST_RECIPIENT = "tom@careerthread.co.uk";
|
|
|
32
33
|
exports.BULK_TEST_SCHOOLS = 3;
|
|
33
34
|
/** A school that had this email this recently isn't suggested it again. */
|
|
34
35
|
exports.RECENTLY_SENT_DAYS = 60;
|
|
36
|
+
/**
|
|
37
|
+
* Counts what a school has confirmed for the current academic year or later,
|
|
38
|
+
* for checks like the renewal emails'.
|
|
39
|
+
*
|
|
40
|
+
* Each is counted once staff have finished it, and still counts after it ends:
|
|
41
|
+
* - A cohort that has been activated, for this year. One made by hand before
|
|
42
|
+
* cohorts carried `academicYear` is placed by its placement end date.
|
|
43
|
+
* - A survey that isn't a draft.
|
|
44
|
+
* - An event past its setup stages, on or after 1 September.
|
|
45
|
+
*
|
|
46
|
+
* @param {object} docs the school's cohorts, survey cycles and events.
|
|
47
|
+
* @param {Date} now the current time.
|
|
48
|
+
* @return {BulkYearSetup} how many of each.
|
|
49
|
+
*/
|
|
50
|
+
const bulkYearSetup = (docs, now) => {
|
|
51
|
+
const year = (0, schedule_1.academicYearOf)(now);
|
|
52
|
+
const yearStart = `${(0, schedule_1.currentAcademicStartYear)(now)}-09-01`;
|
|
53
|
+
return {
|
|
54
|
+
cohorts: docs.cohorts.filter((c) => ["created", "archived"].includes(c.stage || "") &&
|
|
55
|
+
(c.academicYear ? (0, schedule_1.normaliseAcademicYear)(c.academicYear) >= year : (c.endPlacements || "") >= yearStart)).length,
|
|
56
|
+
surveys: docs.surveyCycles.filter((c) => c.status !== "draft" && (c.academicYear || "") >= year).length,
|
|
57
|
+
events: docs.events.filter((e) => ["preEvent", "created"].includes(e.stage || "") &&
|
|
58
|
+
(e.endDate || e.startDate || "") >= yearStart).length,
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
exports.bulkYearSetup = bulkYearSetup;
|
|
62
|
+
/**
|
|
63
|
+
* Lists what a school has confirmed, for the admin.
|
|
64
|
+
*
|
|
65
|
+
* @param {BulkYearSetup} setup what it has confirmed.
|
|
66
|
+
* @return {string} "2 cohorts, 1 survey", or "" if nothing.
|
|
67
|
+
*/
|
|
68
|
+
const describeYearSetup = ({ cohorts, surveys, events }) => [[cohorts, "cohort"], [surveys, "survey"], [events, "event"]]
|
|
69
|
+
.filter(([n]) => n)
|
|
70
|
+
.map(([n, noun]) => `${n} ${noun}${n === 1 ? "" : "s"}`)
|
|
71
|
+
.join(", ");
|
|
72
|
+
/**
|
|
73
|
+
* Suggests a renewal email to a paying school with nothing confirmed for this
|
|
74
|
+
* academic year. A school running cohorts, surveys or events is already using
|
|
75
|
+
* the platform, and doesn't need asking about launching it.
|
|
76
|
+
*
|
|
77
|
+
* @param {BulkEngagementSchool} school the school.
|
|
78
|
+
* @return {object} whether to suggest it, and why.
|
|
79
|
+
*/
|
|
80
|
+
const notSetUpForYear = ({ institute, products, now, yearSetup }) => {
|
|
81
|
+
if (!(0, renewals_1.renewalInfo)({ institute, products, now }).applies)
|
|
82
|
+
return { suggested: false };
|
|
83
|
+
const confirmed = yearSetup ? describeYearSetup(yearSetup) : "";
|
|
84
|
+
const year = (0, schedule_1.academicYearOf)(now);
|
|
85
|
+
if (confirmed)
|
|
86
|
+
return { suggested: false, reason: `Set up for ${year}: ${confirmed}` };
|
|
87
|
+
return { suggested: true, reason: yearSetup ? `Paying customer, nothing set up for ${year}` : "Paying customer" };
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* Suggests an email to schools whose next onboarding step it is. What any
|
|
91
|
+
* email without its own check uses.
|
|
92
|
+
*
|
|
93
|
+
* @param {string} templateKey the email.
|
|
94
|
+
* @return {BulkTemplateCheck} the check.
|
|
95
|
+
*/
|
|
96
|
+
const isNextOnboardingStep = (templateKey) => ({ nextOnboardingTemplate }) => nextOnboardingTemplate === templateKey ? { suggested: true, reason: "Their next onboarding step" } : { suggested: false };
|
|
97
|
+
/** The check for each email with its own rule for who it suits. Add an email here to give it one. */
|
|
98
|
+
exports.BULK_TEMPLATE_CHECKS = {
|
|
99
|
+
engagementRenewalCheckIn: notSetUpForYear,
|
|
100
|
+
};
|
|
35
101
|
/**
|
|
36
102
|
* Whether one email suits one school, and what is missing for it.
|
|
37
103
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
104
|
+
* The email's check in BULK_TEMPLATE_CHECKS decides, or failing that whether
|
|
105
|
+
* it is the school's next onboarding step. Nothing is suggested to a school
|
|
106
|
+
* with no one to send to, or that had the email in the last 60 days.
|
|
41
107
|
*
|
|
42
108
|
* @param {string} templateKey the admin email template.
|
|
43
109
|
* @param {BulkEngagementSchool} school the school.
|
|
44
110
|
* @return {BulkEngagementSuggestion} whether to suggest it, why, and its flags.
|
|
45
111
|
*/
|
|
46
112
|
const bulkEngagementSuggestion = (templateKey, school) => {
|
|
47
|
-
const { institute, products, now, contactCount, hasQuote,
|
|
113
|
+
const { institute, products, now, contactCount, hasQuote, lastSent } = school;
|
|
48
114
|
const params = constants_1.emailTemplates[templateKey]?.params || [];
|
|
49
115
|
const renewal = (0, renewals_1.renewalInfo)({ institute, products, now });
|
|
50
116
|
const recent = Boolean(lastSent) && now.getTime() - Date.parse(lastSent) < exports.RECENTLY_SENT_DAYS * 86400000;
|
|
@@ -59,12 +125,9 @@ const bulkEngagementSuggestion = (templateKey, school) => {
|
|
|
59
125
|
flags.push("noFinanceContact");
|
|
60
126
|
if (recent)
|
|
61
127
|
flags.push("sentRecently");
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
if (!renewals_1.RENEWAL_EMAIL_TEMPLATES.includes(templateKey))
|
|
66
|
-
return nextOnboardingTemplate === templateKey ? { suggested: true, reason: "Their next onboarding step", flags } : none;
|
|
67
|
-
return renewal.applies ? { suggested: true, reason: "Paying customer", flags } : none;
|
|
128
|
+
const { suggested, reason } = (exports.BULK_TEMPLATE_CHECKS[templateKey] || isNextOnboardingStep(templateKey))(school);
|
|
129
|
+
const blocked = recent || flags.some((f) => exports.BULK_ENGAGEMENT_BLOCKING_FLAGS.includes(f));
|
|
130
|
+
return { suggested: suggested && !blocked, ...(reason ? { reason } : {}), flags };
|
|
68
131
|
};
|
|
69
132
|
exports.bulkEngagementSuggestion = bulkEngagementSuggestion;
|
|
70
133
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulkEngagement.js","sourceRoot":"","sources":["../src/bulkEngagement.ts"],"names":[],"mappings":";;;AAEA,
|
|
1
|
+
{"version":3,"file":"bulkEngagement.js","sourceRoot":"","sources":["../src/bulkEngagement.ts"],"names":[],"mappings":"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"}
|
|
@@ -22,12 +22,21 @@ const suggest = (templateKey, institute, date, extra = {}) => (0, bulkEngagement
|
|
|
22
22
|
hasQuote: extra.hasQuote ?? true,
|
|
23
23
|
nextOnboardingTemplate: extra.nextOnboardingTemplate,
|
|
24
24
|
lastSent: extra.lastSent,
|
|
25
|
+
yearSetup: extra.yearSetup,
|
|
25
26
|
});
|
|
26
27
|
describe("bulk engagement suggestions", () => {
|
|
27
28
|
it("suggests the check-in to every paying school, date or not", () => {
|
|
28
29
|
expect(suggest("engagementRenewalCheckIn", school("2027-06-10"), "2026-11-04")).toMatchObject({ suggested: true, reason: "Paying customer" });
|
|
29
30
|
expect(suggest("engagementRenewalCheckIn", school(), "2026-11-04").suggested).toBe(true);
|
|
30
31
|
});
|
|
32
|
+
it("doesn't suggest the check-in to a school with something confirmed for the year", () => {
|
|
33
|
+
const set = suggest("engagementRenewalCheckIn", school("2027-06-10"), "2026-11-04", { yearSetup: { cohorts: 2, surveys: 1, events: 0 } });
|
|
34
|
+
expect(set).toEqual({ suggested: false, reason: "Set up for 2026-27: 2 cohorts, 1 survey", flags: [] });
|
|
35
|
+
});
|
|
36
|
+
it("suggests the check-in to a school with nothing confirmed for the year", () => {
|
|
37
|
+
expect(suggest("engagementRenewalCheckIn", school("2027-06-10"), "2026-11-04", { yearSetup: { cohorts: 0, surveys: 0, events: 0 } }))
|
|
38
|
+
.toMatchObject({ suggested: true, reason: "Paying customer, nothing set up for 2026-27" });
|
|
39
|
+
});
|
|
31
40
|
it("leaves out hub schools", () => {
|
|
32
41
|
expect(suggest("engagementRenewalCheckIn", school("2027-01-10", { package: "careersSchool" }), "2026-11-04").suggested).toBe(false);
|
|
33
42
|
});
|
|
@@ -48,6 +57,44 @@ describe("bulk engagement suggestions", () => {
|
|
|
48
57
|
expect(suggest("engagementPickFeatures", school(), "2026-11-04", { nextOnboardingTemplate: "engagementPlanYear" }).suggested).toBe(false);
|
|
49
58
|
});
|
|
50
59
|
});
|
|
60
|
+
describe("bulkYearSetup", () => {
|
|
61
|
+
const now = new Date("2026-11-04T09:00:00Z");
|
|
62
|
+
const count = (docs) => (0, bulkEngagement_1.bulkYearSetup)({ cohorts: [], surveyCycles: [], events: [], ...docs }, now);
|
|
63
|
+
it("doesn't count the blank draft cohort made each year", () => {
|
|
64
|
+
expect(count({ cohorts: [{ stage: "name", academicYear: "2026/27", endPlacements: "" }] }).cohorts).toBe(0);
|
|
65
|
+
});
|
|
66
|
+
it("counts an activated cohort for this year or later, even once archived", () => {
|
|
67
|
+
expect(count({ cohorts: [
|
|
68
|
+
{ stage: "created", academicYear: "2026/27" },
|
|
69
|
+
{ stage: "created", academicYear: "2027/28" },
|
|
70
|
+
{ stage: "archived", academicYear: "2026/27" },
|
|
71
|
+
{ stage: "created", academicYear: "2025/26" },
|
|
72
|
+
] }).cohorts).toBe(3);
|
|
73
|
+
});
|
|
74
|
+
it("places a cohort with no academic year by when its placements end", () => {
|
|
75
|
+
expect(count({ cohorts: [
|
|
76
|
+
{ stage: "created", endPlacements: "2027-07-01" },
|
|
77
|
+
{ stage: "created", endPlacements: "2026-07-01" },
|
|
78
|
+
] }).cohorts).toBe(1);
|
|
79
|
+
});
|
|
80
|
+
it("counts surveys that aren't drafts, this year or later", () => {
|
|
81
|
+
expect(count({ surveyCycles: [
|
|
82
|
+
{ status: "scheduled", academicYear: "2026-27" },
|
|
83
|
+
{ status: "closed", academicYear: "2026-27" },
|
|
84
|
+
{ status: "active", academicYear: "2027-28" },
|
|
85
|
+
{ status: "draft", academicYear: "2026-27" },
|
|
86
|
+
{ status: "closed", academicYear: "2025-26" },
|
|
87
|
+
] }).surveys).toBe(3);
|
|
88
|
+
});
|
|
89
|
+
it("counts events past setup, on or after 1 September", () => {
|
|
90
|
+
expect(count({ events: [
|
|
91
|
+
{ stage: "created", startDate: "2026-12-01" },
|
|
92
|
+
{ stage: "preEvent", startDate: "2026-09-20", endDate: "2026-09-21" },
|
|
93
|
+
{ stage: "basicDetails", startDate: "2026-12-01" },
|
|
94
|
+
{ stage: "created", startDate: "2026-06-01" },
|
|
95
|
+
] }).events).toBe(2);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
51
98
|
describe("matchesBulkFilters", () => {
|
|
52
99
|
const trust = { package: "institutes-two", products: ["wex", "destinations"] };
|
|
53
100
|
const hub = { package: "careersHub", products: ["employerEvents"] };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bulkEngagement.test.js","sourceRoot":"","sources":["../src/bulkEngagement.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"bulkEngagement.test.js","sourceRoot":"","sources":["../src/bulkEngagement.test.ts"],"names":[],"mappings":"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"}
|
package/lib/renewals.d.ts
CHANGED
|
@@ -3,16 +3,14 @@ import { ResolvedProducts } from "./productResolver";
|
|
|
3
3
|
/**
|
|
4
4
|
* Renewals for paying schools and trusts: their renewal date and how far off
|
|
5
5
|
* it is. Nothing here sends or schedules anything. Tom sends the renewal
|
|
6
|
-
* emails himself, when he chooses, from Send bulk email (
|
|
7
|
-
*
|
|
6
|
+
* emails himself, when he chooses, from Send bulk email (BULK_TEMPLATE_CHECKS
|
|
7
|
+
* in bulkEngagement.ts says which schools each one suits).
|
|
8
8
|
*
|
|
9
9
|
* Renewed means Tom moved `cs.renewalDate` on a year. Hubs are billed by hand
|
|
10
10
|
* each September and are left out.
|
|
11
11
|
*
|
|
12
12
|
* Pure: the caller reads the institute and the clock and hands them in.
|
|
13
13
|
*/
|
|
14
|
-
/** The renewal emails, suggested to every paying school. */
|
|
15
|
-
export declare const RENEWAL_EMAIL_TEMPLATES: string[];
|
|
16
14
|
/** Renewal emails about money, which copy in the finance contact as well. None at the moment. */
|
|
17
15
|
export declare const RENEWAL_FINANCE_TEMPLATES: string[];
|
|
18
16
|
export type RenewalInfo = {
|
package/lib/renewals.js
CHANGED
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.renewalInfo = exports.hasRenewal = exports.RENEWAL_FINANCE_TEMPLATES =
|
|
3
|
+
exports.renewalInfo = exports.hasRenewal = exports.RENEWAL_FINANCE_TEMPLATES = void 0;
|
|
4
4
|
const outreachRules_1 = require("./outreachRules");
|
|
5
5
|
/**
|
|
6
6
|
* Renewals for paying schools and trusts: their renewal date and how far off
|
|
7
7
|
* it is. Nothing here sends or schedules anything. Tom sends the renewal
|
|
8
|
-
* emails himself, when he chooses, from Send bulk email (
|
|
9
|
-
*
|
|
8
|
+
* emails himself, when he chooses, from Send bulk email (BULK_TEMPLATE_CHECKS
|
|
9
|
+
* in bulkEngagement.ts says which schools each one suits).
|
|
10
10
|
*
|
|
11
11
|
* Renewed means Tom moved `cs.renewalDate` on a year. Hubs are billed by hand
|
|
12
12
|
* each September and are left out.
|
|
13
13
|
*
|
|
14
14
|
* Pure: the caller reads the institute and the clock and hands them in.
|
|
15
15
|
*/
|
|
16
|
-
/** The renewal emails, suggested to every paying school. */
|
|
17
|
-
exports.RENEWAL_EMAIL_TEMPLATES = ["engagementRenewalCheckIn"];
|
|
18
16
|
/** Renewal emails about money, which copy in the finance contact as well. None at the moment. */
|
|
19
17
|
exports.RENEWAL_FINANCE_TEMPLATES = [];
|
|
20
18
|
const DAY_MS = 86400000;
|
package/lib/renewals.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renewals.js","sourceRoot":"","sources":["../src/renewals.ts"],"names":[],"mappings":";;;AAEA,mDAA0C;AAE1C;;;;;;;;;;GAUG;AAEH,
|
|
1
|
+
{"version":3,"file":"renewals.js","sourceRoot":"","sources":["../src/renewals.ts"],"names":[],"mappings":";;;AAEA,mDAA0C;AAE1C;;;;;;;;;;GAUG;AAEH,iGAAiG;AACpF,QAAA,yBAAyB,GAAa,EAAE,CAAC;AAWtD,MAAM,MAAM,GAAG,QAAQ,CAAC;AAExB,MAAM,OAAO,GAAG,CAAC,GAAW,EAAU,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,YAAY,CAAC,CAAC;AAExE;;;;;GAKG;AACH,MAAM,UAAU,GAAG,CAAC,SAAwB,EAAoB,EAAE;IAC9D,MAAM,IAAI,GAAG,SAAS,CAAC,EAAE,EAAE,WAAqG,CAAC;IACjI,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACvD,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,IAAA,yBAAS,EAAC,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IACvE,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC;IAC9C,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,IAAA,yBAAS,EAAC,IAAI,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACnF,CAAC,CAAC;AAEF;;;;;;GAMG;AACI,MAAM,UAAU,GAAG,CAAC,SAAwB,EAAE,QAA0B,EAAW,EAAE,CACxF,CAAC,QAAQ,CAAC,KAAK,IAAI,CAAC,QAAQ,CAAC,WAAW,IAAI,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,IAAI;IAChF,CAAC,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,EAAE,EAAE,eAAe,KAAK,SAAS;IACrE,CAAC,gBAAgB,EAAE,gBAAgB,CAAC,CAAC,QAAQ,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;AAHxD,QAAA,UAAU,cAG8C;AAErE;;;;;GAKG;AACI,MAAM,WAAW,GAAG,CAAC,EAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAoE,EAAe,EAAE;IACtI,IAAI,CAAC,IAAA,kBAAU,EAAC,SAAS,EAAE,QAAQ,CAAC;QAAE,OAAO,EAAC,OAAO,EAAE,KAAK,EAAC,CAAC;IAC9D,MAAM,WAAW,GAAG,UAAU,CAAC,SAAS,CAAC,CAAC;IAC1C,IAAI,CAAC,WAAW;QAAE,OAAO,EAAC,OAAO,EAAE,IAAI,EAAC,CAAC;IACzC,OAAO,EAAC,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,aAAa,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAA,yBAAS,EAAC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,EAAC,CAAC;AAC9H,CAAC,CAAC;AALW,QAAA,WAAW,eAKtB"}
|
package/package.json
CHANGED
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
BULK_ENGAGEMENT_PRODUCTS,
|
|
9
9
|
BULK_ENGAGEMENT_PRODUCT_LABELS,
|
|
10
10
|
BULK_TEST_SCHOOLS,
|
|
11
|
+
BulkYearSetup,
|
|
11
12
|
bulkEngagementSuggestion,
|
|
12
13
|
bulkSentAgo,
|
|
14
|
+
bulkYearSetup,
|
|
13
15
|
matchesBulkFilters,
|
|
14
16
|
} from "./bulkEngagement";
|
|
15
17
|
import {engagementCallables} from "./callables/engagement";
|
|
@@ -23,7 +25,7 @@ const school = (renewalDate?: string, overrides: Partial<InstituteData> = {}): I
|
|
|
23
25
|
...overrides,
|
|
24
26
|
} as unknown as InstituteData);
|
|
25
27
|
|
|
26
|
-
const suggest = (templateKey: string, institute: InstituteData, date: string, extra: {contactCount?: number, hasQuote?: boolean, nextOnboardingTemplate?: string, lastSent?: string} = {}) =>
|
|
28
|
+
const suggest = (templateKey: string, institute: InstituteData, date: string, extra: {contactCount?: number, hasQuote?: boolean, nextOnboardingTemplate?: string, lastSent?: string, yearSetup?: BulkYearSetup} = {}) =>
|
|
27
29
|
bulkEngagementSuggestion(templateKey, {
|
|
28
30
|
institute,
|
|
29
31
|
products: resolveProducts(institute),
|
|
@@ -32,6 +34,7 @@ const suggest = (templateKey: string, institute: InstituteData, date: string, ex
|
|
|
32
34
|
hasQuote: extra.hasQuote ?? true,
|
|
33
35
|
nextOnboardingTemplate: extra.nextOnboardingTemplate,
|
|
34
36
|
lastSent: extra.lastSent,
|
|
37
|
+
yearSetup: extra.yearSetup,
|
|
35
38
|
});
|
|
36
39
|
|
|
37
40
|
describe("bulk engagement suggestions", () => {
|
|
@@ -40,6 +43,16 @@ describe("bulk engagement suggestions", () => {
|
|
|
40
43
|
expect(suggest("engagementRenewalCheckIn", school(), "2026-11-04").suggested).toBe(true);
|
|
41
44
|
});
|
|
42
45
|
|
|
46
|
+
it("doesn't suggest the check-in to a school with something confirmed for the year", () => {
|
|
47
|
+
const set = suggest("engagementRenewalCheckIn", school("2027-06-10"), "2026-11-04", {yearSetup: {cohorts: 2, surveys: 1, events: 0}});
|
|
48
|
+
expect(set).toEqual({suggested: false, reason: "Set up for 2026-27: 2 cohorts, 1 survey", flags: []});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("suggests the check-in to a school with nothing confirmed for the year", () => {
|
|
52
|
+
expect(suggest("engagementRenewalCheckIn", school("2027-06-10"), "2026-11-04", {yearSetup: {cohorts: 0, surveys: 0, events: 0}}))
|
|
53
|
+
.toMatchObject({suggested: true, reason: "Paying customer, nothing set up for 2026-27"});
|
|
54
|
+
});
|
|
55
|
+
|
|
43
56
|
it("leaves out hub schools", () => {
|
|
44
57
|
expect(suggest("engagementRenewalCheckIn", school("2027-01-10", {package: "careersSchool"}), "2026-11-04").suggested).toBe(false);
|
|
45
58
|
});
|
|
@@ -65,6 +78,51 @@ describe("bulk engagement suggestions", () => {
|
|
|
65
78
|
});
|
|
66
79
|
});
|
|
67
80
|
|
|
81
|
+
describe("bulkYearSetup", () => {
|
|
82
|
+
const now = new Date("2026-11-04T09:00:00Z");
|
|
83
|
+
const count = (docs: Partial<Parameters<typeof bulkYearSetup>[0]>) =>
|
|
84
|
+
bulkYearSetup({cohorts: [], surveyCycles: [], events: [], ...docs}, now);
|
|
85
|
+
|
|
86
|
+
it("doesn't count the blank draft cohort made each year", () => {
|
|
87
|
+
expect(count({cohorts: [{stage: "name", academicYear: "2026/27", endPlacements: ""}]}).cohorts).toBe(0);
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("counts an activated cohort for this year or later, even once archived", () => {
|
|
91
|
+
expect(count({cohorts: [
|
|
92
|
+
{stage: "created", academicYear: "2026/27"},
|
|
93
|
+
{stage: "created", academicYear: "2027/28"},
|
|
94
|
+
{stage: "archived", academicYear: "2026/27"},
|
|
95
|
+
{stage: "created", academicYear: "2025/26"},
|
|
96
|
+
]}).cohorts).toBe(3);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("places a cohort with no academic year by when its placements end", () => {
|
|
100
|
+
expect(count({cohorts: [
|
|
101
|
+
{stage: "created", endPlacements: "2027-07-01"},
|
|
102
|
+
{stage: "created", endPlacements: "2026-07-01"},
|
|
103
|
+
]}).cohorts).toBe(1);
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("counts surveys that aren't drafts, this year or later", () => {
|
|
107
|
+
expect(count({surveyCycles: [
|
|
108
|
+
{status: "scheduled", academicYear: "2026-27"},
|
|
109
|
+
{status: "closed", academicYear: "2026-27"},
|
|
110
|
+
{status: "active", academicYear: "2027-28"},
|
|
111
|
+
{status: "draft", academicYear: "2026-27"},
|
|
112
|
+
{status: "closed", academicYear: "2025-26"},
|
|
113
|
+
]}).surveys).toBe(3);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("counts events past setup, on or after 1 September", () => {
|
|
117
|
+
expect(count({events: [
|
|
118
|
+
{stage: "created", startDate: "2026-12-01"},
|
|
119
|
+
{stage: "preEvent", startDate: "2026-09-20", endDate: "2026-09-21"},
|
|
120
|
+
{stage: "basicDetails", startDate: "2026-12-01"},
|
|
121
|
+
{stage: "created", startDate: "2026-06-01"},
|
|
122
|
+
]}).events).toBe(2);
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
|
|
68
126
|
describe("matchesBulkFilters", () => {
|
|
69
127
|
const trust = {package: "institutes-two", products: ["wex", "destinations"]};
|
|
70
128
|
const hub = {package: "careersHub", products: ["employerEvents"]};
|
package/src/bulkEngagement.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {InstituteData} from "./typeDefinitions";
|
|
1
|
+
import {CohortData, ExternalEvent, InstituteData} from "./typeDefinitions";
|
|
2
2
|
import {ResolvedProducts} from "./productResolver";
|
|
3
|
-
import {
|
|
3
|
+
import {RENEWAL_FINANCE_TEMPLATES, renewalInfo} from "./renewals";
|
|
4
4
|
import {emailTemplates} from "./constants";
|
|
5
5
|
import {londonYmd} from "./outreachRules";
|
|
6
|
+
import {academicYearOf, currentAcademicStartYear, normaliseAcademicYear} from "./surveys/schedule";
|
|
7
|
+
import {SurveyCycle} from "./surveys/types";
|
|
6
8
|
|
|
7
9
|
/**
|
|
8
10
|
* Bulk engagement emails: one admin email template, sent now to many schools.
|
|
@@ -57,6 +59,43 @@ export const BULK_TEST_SCHOOLS = 3;
|
|
|
57
59
|
/** A school that had this email this recently isn't suggested it again. */
|
|
58
60
|
export const RECENTLY_SENT_DAYS = 60;
|
|
59
61
|
|
|
62
|
+
/**
|
|
63
|
+
* What a school has confirmed for this academic year or later. Drafts don't
|
|
64
|
+
* count: autoCreateCohorts starts a blank cohort for every recurring group
|
|
65
|
+
* each year, whether or not the school goes on to use it.
|
|
66
|
+
*/
|
|
67
|
+
export type BulkYearSetup = {cohorts: number, surveys: number, events: number};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Counts what a school has confirmed for the current academic year or later,
|
|
71
|
+
* for checks like the renewal emails'.
|
|
72
|
+
*
|
|
73
|
+
* Each is counted once staff have finished it, and still counts after it ends:
|
|
74
|
+
* - A cohort that has been activated, for this year. One made by hand before
|
|
75
|
+
* cohorts carried `academicYear` is placed by its placement end date.
|
|
76
|
+
* - A survey that isn't a draft.
|
|
77
|
+
* - An event past its setup stages, on or after 1 September.
|
|
78
|
+
*
|
|
79
|
+
* @param {object} docs the school's cohorts, survey cycles and events.
|
|
80
|
+
* @param {Date} now the current time.
|
|
81
|
+
* @return {BulkYearSetup} how many of each.
|
|
82
|
+
*/
|
|
83
|
+
export const bulkYearSetup = (docs: {
|
|
84
|
+
cohorts: Partial<Pick<CohortData, "stage"|"academicYear"|"endPlacements">>[],
|
|
85
|
+
surveyCycles: Partial<Pick<SurveyCycle, "status"|"academicYear">>[],
|
|
86
|
+
events: Partial<Pick<ExternalEvent, "stage"|"startDate"|"endDate">>[],
|
|
87
|
+
}, now: Date): BulkYearSetup => {
|
|
88
|
+
const year = academicYearOf(now);
|
|
89
|
+
const yearStart = `${currentAcademicStartYear(now)}-09-01`;
|
|
90
|
+
return {
|
|
91
|
+
cohorts: docs.cohorts.filter((c) => ["created", "archived"].includes(c.stage || "") &&
|
|
92
|
+
(c.academicYear ? normaliseAcademicYear(c.academicYear) >= year : (c.endPlacements || "") >= yearStart)).length,
|
|
93
|
+
surveys: docs.surveyCycles.filter((c) => c.status !== "draft" && (c.academicYear || "") >= year).length,
|
|
94
|
+
events: docs.events.filter((e) => ["preEvent", "created"].includes(e.stage || "") &&
|
|
95
|
+
(e.endDate || e.startDate || "") >= yearStart).length,
|
|
96
|
+
};
|
|
97
|
+
};
|
|
98
|
+
|
|
60
99
|
export type BulkEngagementSchool = {
|
|
61
100
|
institute: InstituteData,
|
|
62
101
|
products: ResolvedProducts,
|
|
@@ -69,6 +108,8 @@ export type BulkEngagementSchool = {
|
|
|
69
108
|
nextOnboardingTemplate?: string,
|
|
70
109
|
/** ISO date this email last went to the school, if it has. */
|
|
71
110
|
lastSent?: string,
|
|
111
|
+
/** What it has confirmed for the year, for the checks that ask. Absent means unknown. */
|
|
112
|
+
yearSetup?: BulkYearSetup,
|
|
72
113
|
};
|
|
73
114
|
|
|
74
115
|
export type BulkEngagementSuggestion = {
|
|
@@ -79,19 +120,65 @@ export type BulkEngagementSuggestion = {
|
|
|
79
120
|
flags: BulkEngagementFlag[],
|
|
80
121
|
};
|
|
81
122
|
|
|
123
|
+
/** Whether an email suits a school, and why, for the admin. */
|
|
124
|
+
export type BulkTemplateCheck = (school: BulkEngagementSchool) => {suggested: boolean, reason?: string};
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Lists what a school has confirmed, for the admin.
|
|
128
|
+
*
|
|
129
|
+
* @param {BulkYearSetup} setup what it has confirmed.
|
|
130
|
+
* @return {string} "2 cohorts, 1 survey", or "" if nothing.
|
|
131
|
+
*/
|
|
132
|
+
const describeYearSetup = ({cohorts, surveys, events}: BulkYearSetup): string =>
|
|
133
|
+
([[cohorts, "cohort"], [surveys, "survey"], [events, "event"]] as [number, string][])
|
|
134
|
+
.filter(([n]) => n)
|
|
135
|
+
.map(([n, noun]) => `${n} ${noun}${n === 1 ? "" : "s"}`)
|
|
136
|
+
.join(", ");
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Suggests a renewal email to a paying school with nothing confirmed for this
|
|
140
|
+
* academic year. A school running cohorts, surveys or events is already using
|
|
141
|
+
* the platform, and doesn't need asking about launching it.
|
|
142
|
+
*
|
|
143
|
+
* @param {BulkEngagementSchool} school the school.
|
|
144
|
+
* @return {object} whether to suggest it, and why.
|
|
145
|
+
*/
|
|
146
|
+
const notSetUpForYear: BulkTemplateCheck = ({institute, products, now, yearSetup}) => {
|
|
147
|
+
if (!renewalInfo({institute, products, now}).applies) return {suggested: false};
|
|
148
|
+
const confirmed = yearSetup ? describeYearSetup(yearSetup) : "";
|
|
149
|
+
const year = academicYearOf(now);
|
|
150
|
+
if (confirmed) return {suggested: false, reason: `Set up for ${year}: ${confirmed}`};
|
|
151
|
+
return {suggested: true, reason: yearSetup ? `Paying customer, nothing set up for ${year}` : "Paying customer"};
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Suggests an email to schools whose next onboarding step it is. What any
|
|
156
|
+
* email without its own check uses.
|
|
157
|
+
*
|
|
158
|
+
* @param {string} templateKey the email.
|
|
159
|
+
* @return {BulkTemplateCheck} the check.
|
|
160
|
+
*/
|
|
161
|
+
const isNextOnboardingStep = (templateKey: string): BulkTemplateCheck => ({nextOnboardingTemplate}) =>
|
|
162
|
+
nextOnboardingTemplate === templateKey ? {suggested: true, reason: "Their next onboarding step"} : {suggested: false};
|
|
163
|
+
|
|
164
|
+
/** The check for each email with its own rule for who it suits. Add an email here to give it one. */
|
|
165
|
+
export const BULK_TEMPLATE_CHECKS: {[templateKey: string]: BulkTemplateCheck} = {
|
|
166
|
+
engagementRenewalCheckIn: notSetUpForYear,
|
|
167
|
+
};
|
|
168
|
+
|
|
82
169
|
/**
|
|
83
170
|
* Whether one email suits one school, and what is missing for it.
|
|
84
171
|
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
172
|
+
* The email's check in BULK_TEMPLATE_CHECKS decides, or failing that whether
|
|
173
|
+
* it is the school's next onboarding step. Nothing is suggested to a school
|
|
174
|
+
* with no one to send to, or that had the email in the last 60 days.
|
|
88
175
|
*
|
|
89
176
|
* @param {string} templateKey the admin email template.
|
|
90
177
|
* @param {BulkEngagementSchool} school the school.
|
|
91
178
|
* @return {BulkEngagementSuggestion} whether to suggest it, why, and its flags.
|
|
92
179
|
*/
|
|
93
180
|
export const bulkEngagementSuggestion = (templateKey: string, school: BulkEngagementSchool): BulkEngagementSuggestion => {
|
|
94
|
-
const {institute, products, now, contactCount, hasQuote,
|
|
181
|
+
const {institute, products, now, contactCount, hasQuote, lastSent} = school;
|
|
95
182
|
const params = emailTemplates[templateKey]?.params || [];
|
|
96
183
|
const renewal = renewalInfo({institute, products, now});
|
|
97
184
|
const recent = Boolean(lastSent) && now.getTime() - Date.parse(lastSent as string) < RECENTLY_SENT_DAYS * 86400000;
|
|
@@ -103,11 +190,9 @@ export const bulkEngagementSuggestion = (templateKey: string, school: BulkEngage
|
|
|
103
190
|
if (RENEWAL_FINANCE_TEMPLATES.includes(templateKey) && !institute.financeContact) flags.push("noFinanceContact");
|
|
104
191
|
if (recent) flags.push("sentRecently");
|
|
105
192
|
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
if (!RENEWAL_EMAIL_TEMPLATES.includes(templateKey)) return nextOnboardingTemplate === templateKey ? {suggested: true, reason: "Their next onboarding step", flags} : none;
|
|
110
|
-
return renewal.applies ? {suggested: true, reason: "Paying customer", flags} : none;
|
|
193
|
+
const {suggested, reason} = (BULK_TEMPLATE_CHECKS[templateKey] || isNextOnboardingStep(templateKey))(school);
|
|
194
|
+
const blocked = recent || flags.some((f) => BULK_ENGAGEMENT_BLOCKING_FLAGS.includes(f));
|
|
195
|
+
return {suggested: suggested && !blocked, ...(reason ? {reason} : {}), flags};
|
|
111
196
|
};
|
|
112
197
|
|
|
113
198
|
/**
|
package/src/renewals.ts
CHANGED
|
@@ -5,8 +5,8 @@ import {londonYmd} from "./outreachRules";
|
|
|
5
5
|
/**
|
|
6
6
|
* Renewals for paying schools and trusts: their renewal date and how far off
|
|
7
7
|
* it is. Nothing here sends or schedules anything. Tom sends the renewal
|
|
8
|
-
* emails himself, when he chooses, from Send bulk email (
|
|
9
|
-
*
|
|
8
|
+
* emails himself, when he chooses, from Send bulk email (BULK_TEMPLATE_CHECKS
|
|
9
|
+
* in bulkEngagement.ts says which schools each one suits).
|
|
10
10
|
*
|
|
11
11
|
* Renewed means Tom moved `cs.renewalDate` on a year. Hubs are billed by hand
|
|
12
12
|
* each September and are left out.
|
|
@@ -14,9 +14,6 @@ import {londonYmd} from "./outreachRules";
|
|
|
14
14
|
* Pure: the caller reads the institute and the clock and hands them in.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
/** The renewal emails, suggested to every paying school. */
|
|
18
|
-
export const RENEWAL_EMAIL_TEMPLATES = ["engagementRenewalCheckIn"];
|
|
19
|
-
|
|
20
17
|
/** Renewal emails about money, which copy in the finance contact as well. None at the moment. */
|
|
21
18
|
export const RENEWAL_FINANCE_TEMPLATES: string[] = [];
|
|
22
19
|
|