placementt-core 1.300.1055 → 1.300.1057
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/index.d.ts +1 -0
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/pricing.d.ts +41 -2
- package/lib/pricing.js +37 -3
- package/lib/pricing.js.map +1 -1
- package/lib/pricing.test.js +37 -0
- package/lib/pricing.test.js.map +1 -1
- package/lib/typeDefinitions.d.ts +5 -0
- package/lib/workflowBands.d.ts +33 -0
- package/lib/workflowBands.js +78 -0
- package/lib/workflowBands.js.map +1 -0
- package/lib/workflowBands.test.d.ts +1 -0
- package/lib/workflowBands.test.js +97 -0
- package/lib/workflowBands.test.js.map +1 -0
- package/package.json +1 -1
- package/src/index.ts +1 -0
- package/src/pricing.test.ts +48 -1
- package/src/pricing.ts +63 -5
- package/src/typeDefinitions.ts +5 -2
- package/src/workflowBands.test.ts +111 -0
- package/src/workflowBands.ts +82 -0
package/lib/index.d.ts
CHANGED
|
@@ -29,6 +29,7 @@ export * from "./tutorialTips";
|
|
|
29
29
|
export * from "./constants";
|
|
30
30
|
export * from "./dataViewerReload";
|
|
31
31
|
export * from "./hooks";
|
|
32
|
+
export * from "./workflowBands";
|
|
32
33
|
export * from "./util";
|
|
33
34
|
export * from "./images/GatsbyBenchmarks";
|
|
34
35
|
export * from "./databaseTypes";
|
package/lib/index.js
CHANGED
|
@@ -49,6 +49,7 @@ __exportStar(require("./tutorialTips"), exports);
|
|
|
49
49
|
__exportStar(require("./constants"), exports);
|
|
50
50
|
__exportStar(require("./dataViewerReload"), exports);
|
|
51
51
|
__exportStar(require("./hooks"), exports);
|
|
52
|
+
__exportStar(require("./workflowBands"), exports);
|
|
52
53
|
__exportStar(require("./util"), exports);
|
|
53
54
|
__exportStar(require("./images/GatsbyBenchmarks"), exports);
|
|
54
55
|
__exportStar(require("./databaseTypes"), exports);
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,sDAAoC;AACpC,gEAA8C;AAC9C,0DAAwC;AACxC,2DAAyC;AACzC,kDAAgC;AAChC,uDAAqC;AACrC,4DAA0C;AAC1C,2DAAyC;AAEzC,oDAAkC;AAClC,8CAA4B;AAC5B,kDAAgC;AAChC,kDAAgC;AAChC,qDAAmC;AACnC,mDAAiC;AACjC,qDAAmC;AACnC,mDAAiC;AACjC,+CAA6B;AAC7B,wCAAsB;AACtB,oDAAkC;AAClC,4CAA0B;AAC1B,2CAAyB;AACzB,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,iDAA+B;AAC/B,2DAAyC;AACzC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,qDAAmC;AACnC,0CAAwB;AACxB,yCAAuB;AACvB,4DAA0C;AAC1C,kDAAgC;AAChC,iDAA+B;AAC/B,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAiD;AACjD,yEAAuD;AACvD,kEAAgD;AAChD,kEAAgD;AAChD,oEAAkD;AAClD,yGAAuF;AACvF,0GAAwF;AACxF,+FAA6E;AAC7E,4DAA0C;AAC1C,oEAAkD;AAClD,iEAA+C;AAC/C,gEAA8C;AAC9C,2EAAyD;AACzD,6CAA2B;AAC3B,+CAA6B;AAC7B,8CAA4B;AAC5B,6DAAuE;AAA9D,2IAAA,OAAO,OAAuB"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AACA,sDAAoC;AACpC,gEAA8C;AAC9C,0DAAwC;AACxC,2DAAyC;AACzC,kDAAgC;AAChC,uDAAqC;AACrC,4DAA0C;AAC1C,2DAAyC;AAEzC,oDAAkC;AAClC,8CAA4B;AAC5B,kDAAgC;AAChC,kDAAgC;AAChC,qDAAmC;AACnC,mDAAiC;AACjC,qDAAmC;AACnC,mDAAiC;AACjC,+CAA6B;AAC7B,wCAAsB;AACtB,oDAAkC;AAClC,4CAA0B;AAC1B,2CAAyB;AACzB,kDAAgC;AAChC,uDAAqC;AACrC,kDAAgC;AAChC,iDAA+B;AAC/B,2DAAyC;AACzC,uDAAqC;AACrC,iDAA+B;AAC/B,8CAA4B;AAC5B,qDAAmC;AACnC,0CAAwB;AACxB,kDAAgC;AAChC,yCAAuB;AACvB,4DAA0C;AAC1C,kDAAgC;AAChC,iDAA+B;AAC/B,2CAAyB;AACzB,4DAA0C;AAC1C,oEAAiD;AACjD,yEAAuD;AACvD,kEAAgD;AAChD,kEAAgD;AAChD,oEAAkD;AAClD,yGAAuF;AACvF,0GAAwF;AACxF,+FAA6E;AAC7E,4DAA0C;AAC1C,oEAAkD;AAClD,iEAA+C;AAC/C,gEAA8C;AAC9C,2EAAyD;AACzD,6CAA2B;AAC3B,+CAA6B;AAC7B,8CAA4B;AAC5B,6DAAuE;AAA9D,2IAAA,OAAO,OAAuB"}
|
package/lib/pricing.d.ts
CHANGED
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
* a partial-product discount — that is how the pricing sheet has it, and it is
|
|
13
13
|
* why `partialProductDiscount` names those two rather than being one number.
|
|
14
14
|
*
|
|
15
|
+
* A trust is quoted as one account on its combined roll, and earns a discount
|
|
16
|
+
* on the whole quote for the number of schools it brings on — a smaller one
|
|
17
|
+
* below the threshold, a larger one at or above it.
|
|
18
|
+
*
|
|
15
19
|
* Every figure lives in `PricingConfig` so it can be stored in Firestore and
|
|
16
20
|
* adjusted without a deploy. `DEFAULT_PRICING_CONFIG` is the fallback and the
|
|
17
21
|
* seed for that document.
|
|
@@ -43,6 +47,15 @@ export type PricingConfig = {
|
|
|
43
47
|
};
|
|
44
48
|
/** Taken off the whole quote when a school takes the full platform. */
|
|
45
49
|
fullPlatformDiscount: number;
|
|
50
|
+
/** Taken off the whole quote for a trust, on how many schools it brings. */
|
|
51
|
+
trust: {
|
|
52
|
+
/** Schools at which the larger discount takes over. */
|
|
53
|
+
threshold: number;
|
|
54
|
+
/** Fraction off a trust below the threshold. */
|
|
55
|
+
discount: number;
|
|
56
|
+
/** Fraction off a trust at or above it. */
|
|
57
|
+
largeDiscount: number;
|
|
58
|
+
};
|
|
46
59
|
/** Careers hubs are a flat platform fee plus a fee for each school. */
|
|
47
60
|
hub: {
|
|
48
61
|
baseFee: number;
|
|
@@ -68,6 +81,8 @@ export type SchoolPricingInput = {
|
|
|
68
81
|
destinationsDiscount?: boolean;
|
|
69
82
|
/** Discount the whole quote, for a school taking the full platform. */
|
|
70
83
|
fullPlatformDiscount?: boolean;
|
|
84
|
+
/** Schools in the trust being quoted. Two or more earns a trust discount. */
|
|
85
|
+
schools?: number;
|
|
71
86
|
/** A negotiated discount off the whole quote, as a fraction (0.1 = 10% off).
|
|
72
87
|
* Taken after the full-platform discount and before the minimum fee. */
|
|
73
88
|
bespokeDiscount?: number;
|
|
@@ -101,7 +116,11 @@ export type SchoolPricingResult = {
|
|
|
101
116
|
subtotal: number;
|
|
102
117
|
/** £ taken off the subtotal by the full-platform discount. */
|
|
103
118
|
fullPlatformDiscountApplied: number;
|
|
104
|
-
/** £ taken off by the
|
|
119
|
+
/** £ taken off by the trust discount, after the full-platform one. */
|
|
120
|
+
trustDiscountApplied: number;
|
|
121
|
+
/** The rate that trust discount was taken at, as a fraction. */
|
|
122
|
+
trustDiscountRate: number;
|
|
123
|
+
/** £ taken off by the negotiated discount, after the trust one. */
|
|
105
124
|
bespokeDiscountApplied: number;
|
|
106
125
|
/** True when the minimum fee, not the products, set the price. */
|
|
107
126
|
minFeeApplied: boolean;
|
|
@@ -115,6 +134,17 @@ export type HubPricingResult = {
|
|
|
115
134
|
schoolFees: number;
|
|
116
135
|
total: number;
|
|
117
136
|
};
|
|
137
|
+
/**
|
|
138
|
+
* What a trust comes off its quote for its size.
|
|
139
|
+
*
|
|
140
|
+
* A trust is more than one school, so a count below two is a single school and
|
|
141
|
+
* earns nothing — the discount is for bringing schools with you.
|
|
142
|
+
*
|
|
143
|
+
* @param {number} [schools] schools in the trust.
|
|
144
|
+
* @param {object} [config] the figures to price with. Defaults to the 2026 sheet.
|
|
145
|
+
* @return {number} the discount, as a fraction of the quote.
|
|
146
|
+
*/
|
|
147
|
+
export declare function trustDiscountRate(schools?: number, config?: PricingConfig): number;
|
|
118
148
|
/**
|
|
119
149
|
* Price a school, trust or hub-school quote.
|
|
120
150
|
*
|
|
@@ -165,6 +195,8 @@ export type InstitutePricing = {
|
|
|
165
195
|
discountReason?: string;
|
|
166
196
|
/** A price agreed with the customer, which replaces the calculated one. */
|
|
167
197
|
quoteOverride?: number;
|
|
198
|
+
/** Schools in the trust, which set its discount. Trust accounts only. */
|
|
199
|
+
schools?: number;
|
|
168
200
|
/** Schools on the hub. Hub accounts only. */
|
|
169
201
|
hubSchools?: number;
|
|
170
202
|
/** The quote as last saved, for the customer to see. */
|
|
@@ -178,6 +210,9 @@ export type InstituteQuote = {
|
|
|
178
210
|
/** The lines added up, before any whole-quote discount. */
|
|
179
211
|
subtotal: number;
|
|
180
212
|
fullPlatformDiscountApplied: number;
|
|
213
|
+
trustDiscountApplied: number;
|
|
214
|
+
/** The rate the trust discount was taken at, as a fraction. */
|
|
215
|
+
trustDiscountRate: number;
|
|
181
216
|
bespokeDiscountApplied: number;
|
|
182
217
|
minFeeApplied: boolean;
|
|
183
218
|
overrideApplied: boolean;
|
|
@@ -209,9 +244,12 @@ export type InstituteQuoteInput = {
|
|
|
209
244
|
events?: boolean;
|
|
210
245
|
destinations?: boolean;
|
|
211
246
|
isHub?: boolean;
|
|
247
|
+
isTrust?: boolean;
|
|
212
248
|
};
|
|
213
249
|
/** The institute's roll, when the agreed terms don't name one. */
|
|
214
250
|
students?: number;
|
|
251
|
+
/** Schools in the trust, when the agreed terms don't name a number. */
|
|
252
|
+
schools?: number;
|
|
215
253
|
/** Schools on the hub, when the agreed terms don't name a number. */
|
|
216
254
|
hubSchools?: number;
|
|
217
255
|
/** The terms agreed with this customer. */
|
|
@@ -243,7 +281,8 @@ export declare function hubQuote(schools: number, pricing?: InstitutePricing, co
|
|
|
243
281
|
*
|
|
244
282
|
* The products come from `resolveProducts` rather than the raw flags, so a trust
|
|
245
283
|
* is priced on the union of its schools' products the same way it is gated on
|
|
246
|
-
* them
|
|
284
|
+
* them, and it is a trust — not any school with a number against it — that earns
|
|
285
|
+
* the trust discount. A year group with no placements agreed is a year group not on work
|
|
247
286
|
* experience — except where the institute has work experience and neither year
|
|
248
287
|
* group has been filled in, which is a quote waiting to be finished rather than
|
|
249
288
|
* a school not taking the product, so Y10 is charged at zero to say so.
|
package/lib/pricing.js
CHANGED
|
@@ -13,12 +13,17 @@
|
|
|
13
13
|
* a partial-product discount — that is how the pricing sheet has it, and it is
|
|
14
14
|
* why `partialProductDiscount` names those two rather than being one number.
|
|
15
15
|
*
|
|
16
|
+
* A trust is quoted as one account on its combined roll, and earns a discount
|
|
17
|
+
* on the whole quote for the number of schools it brings on — a smaller one
|
|
18
|
+
* below the threshold, a larger one at or above it.
|
|
19
|
+
*
|
|
16
20
|
* Every figure lives in `PricingConfig` so it can be stored in Firestore and
|
|
17
21
|
* adjusted without a deploy. `DEFAULT_PRICING_CONFIG` is the fallback and the
|
|
18
22
|
* seed for that document.
|
|
19
23
|
*/
|
|
20
24
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
25
|
exports.PRICING_CONFIG_PATH = exports.DEFAULT_PRICING_CONFIG = void 0;
|
|
26
|
+
exports.trustDiscountRate = trustDiscountRate;
|
|
22
27
|
exports.calculateSchoolPrice = calculateSchoolPrice;
|
|
23
28
|
exports.calculateHubPrice = calculateHubPrice;
|
|
24
29
|
exports.mergePricingConfig = mergePricingConfig;
|
|
@@ -37,6 +42,7 @@ exports.DEFAULT_PRICING_CONFIG = {
|
|
|
37
42
|
],
|
|
38
43
|
partialProductDiscount: { events: 0.2, destinations: 0.2 },
|
|
39
44
|
fullPlatformDiscount: 0.2,
|
|
45
|
+
trust: { threshold: 10, discount: 0.05, largeDiscount: 0.1 },
|
|
40
46
|
hub: { baseFee: 2000, perSchoolFee: 150 },
|
|
41
47
|
};
|
|
42
48
|
/** Where the adjustable copy of the config lives. */
|
|
@@ -79,6 +85,22 @@ function graduated(quantity, bands) {
|
|
|
79
85
|
const sum = (values) => values.reduce((total, value) => total + value, 0);
|
|
80
86
|
const clampFraction = (value) => Math.min(Math.max(value || 0, 0), 1);
|
|
81
87
|
const bandsTotal = (bands) => sum(bands.map((b) => b.amount));
|
|
88
|
+
/**
|
|
89
|
+
* What a trust comes off its quote for its size.
|
|
90
|
+
*
|
|
91
|
+
* A trust is more than one school, so a count below two is a single school and
|
|
92
|
+
* earns nothing — the discount is for bringing schools with you.
|
|
93
|
+
*
|
|
94
|
+
* @param {number} [schools] schools in the trust.
|
|
95
|
+
* @param {object} [config] the figures to price with. Defaults to the 2026 sheet.
|
|
96
|
+
* @return {number} the discount, as a fraction of the quote.
|
|
97
|
+
*/
|
|
98
|
+
function trustDiscountRate(schools, config = exports.DEFAULT_PRICING_CONFIG) {
|
|
99
|
+
const count = schools || 0;
|
|
100
|
+
if (count < 2)
|
|
101
|
+
return 0;
|
|
102
|
+
return count >= config.trust.threshold ? config.trust.largeDiscount : config.trust.discount;
|
|
103
|
+
}
|
|
82
104
|
/**
|
|
83
105
|
* Price a school, trust or hub-school quote.
|
|
84
106
|
*
|
|
@@ -115,14 +137,18 @@ function calculateSchoolPrice(input, config = exports.DEFAULT_PRICING_CONFIG) {
|
|
|
115
137
|
addPerStudent("destinations", "Destinations", input.destinations, input.destinationsDiscount);
|
|
116
138
|
const subtotal = sum(lines.map((l) => l.amount));
|
|
117
139
|
const discounted = input.fullPlatformDiscount ? subtotal * (1 - config.fullPlatformDiscount) : subtotal;
|
|
118
|
-
const
|
|
140
|
+
const trustRate = trustDiscountRate(input.schools, config);
|
|
141
|
+
const trusted = discounted * (1 - trustRate);
|
|
142
|
+
const negotiated = trusted * (1 - clampFraction(input.bespokeDiscount));
|
|
119
143
|
const floored = Math.max(negotiated, config.minFee);
|
|
120
144
|
const overridden = input.quoteOverride !== undefined && input.quoteOverride >= 0;
|
|
121
145
|
return {
|
|
122
146
|
lines,
|
|
123
147
|
subtotal,
|
|
124
148
|
fullPlatformDiscountApplied: subtotal - discounted,
|
|
125
|
-
|
|
149
|
+
trustDiscountApplied: discounted - trusted,
|
|
150
|
+
trustDiscountRate: trustRate,
|
|
151
|
+
bespokeDiscountApplied: trusted - negotiated,
|
|
126
152
|
// An agreed price is the price, so neither the floor nor the discounts
|
|
127
153
|
// are what set it — they are only reported when the calculation stands.
|
|
128
154
|
minFeeApplied: !overridden && floored > negotiated,
|
|
@@ -161,6 +187,7 @@ function mergePricingConfig(stored) {
|
|
|
161
187
|
tiers: stored.tiers?.length ? stored.tiers.map((t, i) => ({ ...(d.tiers[i] || d.tiers[d.tiers.length - 1]), ...t })) : d.tiers,
|
|
162
188
|
partialProductDiscount: { ...d.partialProductDiscount, ...stored.partialProductDiscount },
|
|
163
189
|
fullPlatformDiscount: stored.fullPlatformDiscount ?? d.fullPlatformDiscount,
|
|
190
|
+
trust: { ...d.trust, ...stored.trust },
|
|
164
191
|
hub: { ...d.hub, ...stored.hub },
|
|
165
192
|
};
|
|
166
193
|
}
|
|
@@ -207,6 +234,9 @@ function hubQuote(schools, pricing, config = exports.DEFAULT_PRICING_CONFIG) {
|
|
|
207
234
|
lines,
|
|
208
235
|
subtotal: hub.total,
|
|
209
236
|
fullPlatformDiscountApplied: 0,
|
|
237
|
+
// A hub is already priced on its schools, so it has no trust discount.
|
|
238
|
+
trustDiscountApplied: 0,
|
|
239
|
+
trustDiscountRate: 0,
|
|
210
240
|
bespokeDiscountApplied: hub.total - negotiated,
|
|
211
241
|
minFeeApplied: false,
|
|
212
242
|
overrideApplied: overridden,
|
|
@@ -218,7 +248,8 @@ function hubQuote(schools, pricing, config = exports.DEFAULT_PRICING_CONFIG) {
|
|
|
218
248
|
*
|
|
219
249
|
* The products come from `resolveProducts` rather than the raw flags, so a trust
|
|
220
250
|
* is priced on the union of its schools' products the same way it is gated on
|
|
221
|
-
* them
|
|
251
|
+
* them, and it is a trust — not any school with a number against it — that earns
|
|
252
|
+
* the trust discount. A year group with no placements agreed is a year group not on work
|
|
222
253
|
* experience — except where the institute has work experience and neither year
|
|
223
254
|
* group has been filled in, which is a quote waiting to be finished rather than
|
|
224
255
|
* a school not taking the product, so Y10 is charged at zero to say so.
|
|
@@ -236,6 +267,9 @@ function instituteQuote(input, config = exports.DEFAULT_PRICING_CONFIG) {
|
|
|
236
267
|
const noYearGroupQuoted = pricing?.wexY10 === undefined && pricing?.wexY12 === undefined;
|
|
237
268
|
return schoolQuote({
|
|
238
269
|
students: pricing?.students ?? input.students,
|
|
270
|
+
// Only a trust is quoted on a school count, so a single school can never
|
|
271
|
+
// pick up the discount by having a stray number agreed against it.
|
|
272
|
+
schools: input.products.isTrust ? (pricing?.schools ?? input.schools) : undefined,
|
|
239
273
|
wexY10: wex ? (noYearGroupQuoted ? 0 : pricing?.wexY10) : undefined,
|
|
240
274
|
wexY12: wex ? pricing?.wexY12 : undefined,
|
|
241
275
|
events: Boolean(input.products.events),
|
package/lib/pricing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pricing.js","sourceRoot":"","sources":["../src/pricing.ts"],"names":[],"mappings":"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"}
|
package/lib/pricing.test.js
CHANGED
|
@@ -116,6 +116,43 @@ describe("mergePricingConfig", () => {
|
|
|
116
116
|
expect(merged.tiers[2]).toEqual(pricing_1.DEFAULT_PRICING_CONFIG.tiers[2]);
|
|
117
117
|
});
|
|
118
118
|
});
|
|
119
|
+
describe("the trust discount", () => {
|
|
120
|
+
const trust = (schools) => ({ students: 10000, events: true, destinations: true, schools });
|
|
121
|
+
it("gives a trust under ten schools 5% off the whole quote", () => {
|
|
122
|
+
const result = (0, pricing_1.calculateSchoolPrice)(trust(9));
|
|
123
|
+
const plain = (0, pricing_1.calculateSchoolPrice)({ ...trust(9), schools: undefined });
|
|
124
|
+
expect(result.trustDiscountRate).toBe(0.05);
|
|
125
|
+
expect(result.total).toBeCloseTo(plain.total * 0.95, 6);
|
|
126
|
+
expect(result.trustDiscountApplied).toBeCloseTo(plain.total * 0.05, 6);
|
|
127
|
+
});
|
|
128
|
+
it("gives a trust of ten schools or more 10%", () => {
|
|
129
|
+
expect((0, pricing_1.calculateSchoolPrice)(trust(10)).trustDiscountRate).toBe(0.1);
|
|
130
|
+
expect((0, pricing_1.calculateSchoolPrice)(trust(40)).trustDiscountRate).toBe(0.1);
|
|
131
|
+
});
|
|
132
|
+
it("gives a single school nothing, however it is counted", () => {
|
|
133
|
+
expect((0, pricing_1.trustDiscountRate)(undefined)).toBe(0);
|
|
134
|
+
expect((0, pricing_1.trustDiscountRate)(0)).toBe(0);
|
|
135
|
+
expect((0, pricing_1.trustDiscountRate)(1)).toBe(0);
|
|
136
|
+
});
|
|
137
|
+
it("is taken after the full-platform discount and before the negotiated one", () => {
|
|
138
|
+
const input = {
|
|
139
|
+
students: 10000, wexY10: 500, events: true, destinations: true,
|
|
140
|
+
fullPlatformDiscount: true, schools: 12, bespokeDiscount: 0.1,
|
|
141
|
+
};
|
|
142
|
+
const result = (0, pricing_1.calculateSchoolPrice)(input);
|
|
143
|
+
const expected = result.subtotal * 0.8 * 0.9 * 0.9;
|
|
144
|
+
expect(result.total).toBeCloseTo(expected, 6);
|
|
145
|
+
expect(result.trustDiscountApplied).toBeCloseTo(result.subtotal * 0.8 * 0.1, 6);
|
|
146
|
+
});
|
|
147
|
+
it("only reaches an institute that is actually a trust", () => {
|
|
148
|
+
const priced = (isTrust) => (0, pricing_1.instituteQuote)({
|
|
149
|
+
products: { events: true, isTrust },
|
|
150
|
+
students: 10000,
|
|
151
|
+
pricing: { schools: 12 },
|
|
152
|
+
}).total;
|
|
153
|
+
expect(priced(true)).toBeCloseTo(priced(false) * 0.9, 6);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
119
156
|
describe("the negotiated terms", () => {
|
|
120
157
|
it("takes the bespoke discount after the full-platform one", () => {
|
|
121
158
|
const base = { students: 2000, events: true, destinations: true, fullPlatformDiscount: true };
|
package/lib/pricing.test.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pricing.test.js","sourceRoot":"","sources":["../src/pricing.test.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pricing.test.js","sourceRoot":"","sources":["../src/pricing.test.ts"],"names":[],"mappings":"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"}
|
package/lib/typeDefinitions.d.ts
CHANGED
|
@@ -48,6 +48,10 @@ export type Products = "institutes" | "providers" | "students" | "admin";
|
|
|
48
48
|
export type StudentPlacementData = {
|
|
49
49
|
title: string;
|
|
50
50
|
reqUserType: "Students" | "Staff" | "Provider" | "Parent";
|
|
51
|
+
reqUserTypes?: ("Students" | "Staff" | "Provider" | "Parent")[];
|
|
52
|
+
/** Set while a completion is claiming the band's single advance, so two
|
|
53
|
+
* parties finishing at once cannot both move the placement on. */
|
|
54
|
+
advancingFrom?: number;
|
|
51
55
|
lastStageChange?: string;
|
|
52
56
|
uid: string;
|
|
53
57
|
startDate: string;
|
|
@@ -751,6 +755,7 @@ export type WorkflowStage = {
|
|
|
751
755
|
y: number;
|
|
752
756
|
};
|
|
753
757
|
userType?: "Students" | "Staff" | "Provider" | "Parent";
|
|
758
|
+
concurrentWithNext?: boolean;
|
|
754
759
|
forms?: string[];
|
|
755
760
|
files?: string[];
|
|
756
761
|
deadline?: string;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { WorkflowStage } from "./typeDefinitions";
|
|
2
|
+
/**
|
|
3
|
+
* Concurrent sign-off bands.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately free of any firebase import so it can be unit tested and pulled
|
|
6
|
+
* into the backend, the external review payload and the staff UI alike.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* The stage that starts the concurrent band `stageId` belongs to.
|
|
10
|
+
*
|
|
11
|
+
* A band is a run of stages chained by their first button where every stage but
|
|
12
|
+
* the last carries `concurrentWithNext`. The head is the stage a placement's
|
|
13
|
+
* `status` points at while the band is open, which is what lets `status` stay a
|
|
14
|
+
* single number: the band only changes who we ask, not where the placement is.
|
|
15
|
+
*/
|
|
16
|
+
export declare const getBandHead: (workflow: WorkflowStage[], stageId: number) => WorkflowStage | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* Every stage that runs at the same time as `stageId`, in workflow order.
|
|
19
|
+
*
|
|
20
|
+
* Returns just the stage itself when nothing is marked concurrent, so callers can
|
|
21
|
+
* use this unconditionally and existing workflows behave exactly as before.
|
|
22
|
+
*/
|
|
23
|
+
export declare const getConcurrentBand: (workflow: WorkflowStage[], stageId: number) => WorkflowStage[];
|
|
24
|
+
/** True when the workflow asks more than one party at this point. */
|
|
25
|
+
export declare const isConcurrentBand: (workflow: WorkflowStage[], stageId: number) => boolean;
|
|
26
|
+
/** The band's stages that nobody has signed off yet. */
|
|
27
|
+
export declare const getBandOutstanding: (band: WorkflowStage[], completedStages?: number[]) => WorkflowStage[];
|
|
28
|
+
/** Distinct user types the band is still waiting on, in workflow order. */
|
|
29
|
+
export declare const getBandOutstandingUserTypes: (band: WorkflowStage[], completedStages?: number[]) => NonNullable<"Students" | "Staff" | "Provider" | "Parent" | undefined>[];
|
|
30
|
+
/** Where the placement goes once every stage in the band is signed off. */
|
|
31
|
+
export declare const getBandExitStageId: (band: WorkflowStage[]) => number | undefined;
|
|
32
|
+
/** The label to show staff for a band, e.g. "Employer review & parental consent". */
|
|
33
|
+
export declare const getBandName: (band: WorkflowStage[]) => string;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getBandName = exports.getBandExitStageId = exports.getBandOutstandingUserTypes = exports.getBandOutstanding = exports.isConcurrentBand = exports.getConcurrentBand = exports.getBandHead = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Concurrent sign-off bands.
|
|
6
|
+
*
|
|
7
|
+
* Deliberately free of any firebase import so it can be unit tested and pulled
|
|
8
|
+
* into the backend, the external review payload and the staff UI alike.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* The stage that starts the concurrent band `stageId` belongs to.
|
|
12
|
+
*
|
|
13
|
+
* A band is a run of stages chained by their first button where every stage but
|
|
14
|
+
* the last carries `concurrentWithNext`. The head is the stage a placement's
|
|
15
|
+
* `status` points at while the band is open, which is what lets `status` stay a
|
|
16
|
+
* single number: the band only changes who we ask, not where the placement is.
|
|
17
|
+
*/
|
|
18
|
+
const getBandHead = (workflow, stageId) => {
|
|
19
|
+
let stage = workflow.find((s) => s.id === stageId);
|
|
20
|
+
if (!stage)
|
|
21
|
+
return undefined;
|
|
22
|
+
const visited = new Set([stage.id]);
|
|
23
|
+
for (;;) {
|
|
24
|
+
const previous = workflow.find((s) => s.concurrentWithNext && s.buttons?.[0]?.id === stage?.id);
|
|
25
|
+
// No flagged predecessor means we are already at the head.
|
|
26
|
+
if (!previous || visited.has(previous.id))
|
|
27
|
+
return stage;
|
|
28
|
+
visited.add(previous.id);
|
|
29
|
+
stage = previous;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
exports.getBandHead = getBandHead;
|
|
33
|
+
/**
|
|
34
|
+
* Every stage that runs at the same time as `stageId`, in workflow order.
|
|
35
|
+
*
|
|
36
|
+
* Returns just the stage itself when nothing is marked concurrent, so callers can
|
|
37
|
+
* use this unconditionally and existing workflows behave exactly as before.
|
|
38
|
+
*/
|
|
39
|
+
const getConcurrentBand = (workflow, stageId) => {
|
|
40
|
+
const head = (0, exports.getBandHead)(workflow, stageId);
|
|
41
|
+
if (!head)
|
|
42
|
+
return [];
|
|
43
|
+
const band = [head];
|
|
44
|
+
const visited = new Set([head.id]);
|
|
45
|
+
let stage = head;
|
|
46
|
+
while (stage?.concurrentWithNext) {
|
|
47
|
+
const nextId = stage.buttons?.[0]?.id;
|
|
48
|
+
// A flagged stage with nowhere to go, or a loop, ends the band rather
|
|
49
|
+
// than stranding the caller.
|
|
50
|
+
if (nextId === undefined || visited.has(nextId))
|
|
51
|
+
break;
|
|
52
|
+
stage = workflow.find((s) => s.id === nextId);
|
|
53
|
+
if (!stage)
|
|
54
|
+
break;
|
|
55
|
+
visited.add(stage.id);
|
|
56
|
+
band.push(stage);
|
|
57
|
+
}
|
|
58
|
+
return band;
|
|
59
|
+
};
|
|
60
|
+
exports.getConcurrentBand = getConcurrentBand;
|
|
61
|
+
/** True when the workflow asks more than one party at this point. */
|
|
62
|
+
const isConcurrentBand = (workflow, stageId) => (0, exports.getConcurrentBand)(workflow, stageId).length > 1;
|
|
63
|
+
exports.isConcurrentBand = isConcurrentBand;
|
|
64
|
+
/** The band's stages that nobody has signed off yet. */
|
|
65
|
+
const getBandOutstanding = (band, completedStages = []) => band.filter((stage) => !completedStages.includes(stage.id));
|
|
66
|
+
exports.getBandOutstanding = getBandOutstanding;
|
|
67
|
+
/** Distinct user types the band is still waiting on, in workflow order. */
|
|
68
|
+
const getBandOutstandingUserTypes = (band, completedStages = []) => (0, exports.getBandOutstanding)(band, completedStages)
|
|
69
|
+
.map((stage) => stage.userType)
|
|
70
|
+
.filter((userType, i, all) => Boolean(userType) && all.indexOf(userType) === i);
|
|
71
|
+
exports.getBandOutstandingUserTypes = getBandOutstandingUserTypes;
|
|
72
|
+
/** Where the placement goes once every stage in the band is signed off. */
|
|
73
|
+
const getBandExitStageId = (band) => band[band.length - 1]?.buttons?.[0]?.id;
|
|
74
|
+
exports.getBandExitStageId = getBandExitStageId;
|
|
75
|
+
/** The label to show staff for a band, e.g. "Employer review & parental consent". */
|
|
76
|
+
const getBandName = (band) => band.map((stage) => stage.name).join(" & ");
|
|
77
|
+
exports.getBandName = getBandName;
|
|
78
|
+
//# sourceMappingURL=workflowBands.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflowBands.js","sourceRoot":"","sources":["../src/workflowBands.ts"],"names":[],"mappings":";;;AAEA;;;;;GAKG;AAEH;;;;;;;GAOG;AACI,MAAM,WAAW,GAAG,CAAC,QAAyB,EAAE,OAAe,EAA2B,EAAE;IAC/F,IAAI,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,CAAC;IACnD,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAE7B,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;IAE5C,SAAS,CAAC;QACN,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kBAAkB,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,KAAK,EAAE,EAAE,CAAC,CAAC;QAChG,2DAA2D;QAC3D,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAAE,OAAO,KAAK,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACzB,KAAK,GAAG,QAAQ,CAAC;IACrB,CAAC;AACL,CAAC,CAAC;AAbW,QAAA,WAAW,eAatB;AAEF;;;;;GAKG;AACI,MAAM,iBAAiB,GAAG,CAAC,QAAyB,EAAE,OAAe,EAAmB,EAAE;IAC7F,MAAM,IAAI,GAAG,IAAA,mBAAW,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC5C,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,MAAM,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;IACpB,MAAM,OAAO,GAAG,IAAI,GAAG,CAAS,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAE3C,IAAI,KAAK,GAA4B,IAAI,CAAC;IAC1C,OAAO,KAAK,EAAE,kBAAkB,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAqB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;QACxD,sEAAsE;QACtE,6BAA6B;QAC7B,IAAI,MAAM,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAM;QACvD,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,MAAM,CAAC,CAAC;QAC9C,IAAI,CAAC,KAAK;YAAE,MAAM;QAClB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACtB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,CAAC;AAChB,CAAC,CAAC;AApBW,QAAA,iBAAiB,qBAoB5B;AAEF,qEAAqE;AAC9D,MAAM,gBAAgB,GAAG,CAAC,QAAyB,EAAE,OAAe,EAAE,EAAE,CAC3E,IAAA,yBAAiB,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AADvC,QAAA,gBAAgB,oBACuB;AAEpD,wDAAwD;AACjD,MAAM,kBAAkB,GAAG,CAAC,IAAqB,EAAE,kBAA4B,EAAE,EAAE,EAAE,CACxF,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC;AADnD,QAAA,kBAAkB,sBACiC;AAEhE,2EAA2E;AACpE,MAAM,2BAA2B,GAAG,CAAC,IAAqB,EAAE,kBAA4B,EAAE,EAAE,EAAE,CACjG,IAAA,0BAAkB,EAAC,IAAI,EAAE,eAAe,CAAC;KACpC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC;KAC9B,MAAM,CAAC,CAAC,QAAQ,EAAE,CAAC,EAAE,GAAG,EAAsD,EAAE,CAC7E,OAAO,CAAC,QAAQ,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;AAJjD,QAAA,2BAA2B,+BAIsB;AAE9D,2EAA2E;AACpE,MAAM,kBAAkB,GAAG,CAAC,IAAqB,EAAE,EAAE,CACxD,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC;AAD/B,QAAA,kBAAkB,sBACa;AAE5C,qFAAqF;AAC9E,MAAM,WAAW,GAAG,CAAC,IAAqB,EAAE,EAAE,CACjD,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AADnC,QAAA,WAAW,eACwB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const workflowBands_1 = require("./workflowBands");
|
|
4
|
+
describe("Concurrent bands", () => {
|
|
5
|
+
// A typical work experience chain: staff check, then employer review, then
|
|
6
|
+
// parental consent, then the placement start stage.
|
|
7
|
+
const stage = (id, userType, next, concurrentWithNext) => ({
|
|
8
|
+
id,
|
|
9
|
+
name: `Stage ${id}`,
|
|
10
|
+
userType,
|
|
11
|
+
concurrentWithNext,
|
|
12
|
+
buttons: next === undefined ? [] : [{ id: next, name: "Continue", required: true }],
|
|
13
|
+
});
|
|
14
|
+
const sequential = [
|
|
15
|
+
stage(1, "Students", 2),
|
|
16
|
+
stage(2, "Staff", 3),
|
|
17
|
+
stage(3, "Provider", 4),
|
|
18
|
+
stage(4, "Parent", 6),
|
|
19
|
+
stage(6, undefined),
|
|
20
|
+
];
|
|
21
|
+
// Same workflow, but employer review and parental consent run together.
|
|
22
|
+
const banded = [
|
|
23
|
+
stage(1, "Students", 2),
|
|
24
|
+
stage(2, "Staff", 3),
|
|
25
|
+
stage(3, "Provider", 4, true),
|
|
26
|
+
stage(4, "Parent", 6),
|
|
27
|
+
stage(6, undefined),
|
|
28
|
+
];
|
|
29
|
+
it("returns just the stage when nothing is marked concurrent", () => {
|
|
30
|
+
expect((0, workflowBands_1.getConcurrentBand)(sequential, 3).map((s) => s.id)).toEqual([3]);
|
|
31
|
+
expect((0, workflowBands_1.getConcurrentBand)(sequential, 4).map((s) => s.id)).toEqual([4]);
|
|
32
|
+
expect((0, workflowBands_1.isConcurrentBand)(sequential, 3)).toBe(false);
|
|
33
|
+
});
|
|
34
|
+
it("resolves the same band from any member", () => {
|
|
35
|
+
expect((0, workflowBands_1.getConcurrentBand)(banded, 3).map((s) => s.id)).toEqual([3, 4]);
|
|
36
|
+
expect((0, workflowBands_1.getConcurrentBand)(banded, 4).map((s) => s.id)).toEqual([3, 4]);
|
|
37
|
+
expect((0, workflowBands_1.isConcurrentBand)(banded, 3)).toBe(true);
|
|
38
|
+
});
|
|
39
|
+
it("resolves a band of three from the middle", () => {
|
|
40
|
+
const three = [
|
|
41
|
+
stage(2, "Staff", 3, true),
|
|
42
|
+
stage(3, "Provider", 4, true),
|
|
43
|
+
stage(4, "Parent", 6),
|
|
44
|
+
stage(6, undefined),
|
|
45
|
+
];
|
|
46
|
+
expect((0, workflowBands_1.getConcurrentBand)(three, 3).map((s) => s.id)).toEqual([2, 3, 4]);
|
|
47
|
+
expect((0, workflowBands_1.getBandHead)(three, 4)?.id).toEqual(2);
|
|
48
|
+
});
|
|
49
|
+
it("does not pull in the stage after the band", () => {
|
|
50
|
+
expect((0, workflowBands_1.getConcurrentBand)(banded, 3).some((s) => s.id === 6)).toBe(false);
|
|
51
|
+
expect((0, workflowBands_1.getBandExitStageId)((0, workflowBands_1.getConcurrentBand)(banded, 3))).toEqual(6);
|
|
52
|
+
});
|
|
53
|
+
it("terminates on a cycle", () => {
|
|
54
|
+
// The builder stops a school authoring this, but a hand-edited workflow
|
|
55
|
+
// must not hang or repeat a stage. A cycle has no real head, so only the
|
|
56
|
+
// membership is meaningful here, not the order.
|
|
57
|
+
const looped = [
|
|
58
|
+
stage(3, "Provider", 4, true),
|
|
59
|
+
stage(4, "Parent", 3, true),
|
|
60
|
+
];
|
|
61
|
+
const ids = (0, workflowBands_1.getConcurrentBand)(looped, 3).map((s) => s.id);
|
|
62
|
+
expect(ids.slice().sort()).toEqual([3, 4]);
|
|
63
|
+
expect(new Set(ids).size).toEqual(ids.length);
|
|
64
|
+
});
|
|
65
|
+
it("terminates when a flagged stage points nowhere", () => {
|
|
66
|
+
const dangling = [stage(3, "Provider", undefined, true)];
|
|
67
|
+
expect((0, workflowBands_1.getConcurrentBand)(dangling, 3).map((s) => s.id)).toEqual([3]);
|
|
68
|
+
});
|
|
69
|
+
it("returns nothing for a stage that is not in the workflow", () => {
|
|
70
|
+
expect((0, workflowBands_1.getConcurrentBand)(banded, 99)).toEqual([]);
|
|
71
|
+
});
|
|
72
|
+
it("reports what the band is still waiting on", () => {
|
|
73
|
+
const band = (0, workflowBands_1.getConcurrentBand)(banded, 3);
|
|
74
|
+
expect((0, workflowBands_1.getBandOutstanding)(band, []).map((s) => s.id)).toEqual([3, 4]);
|
|
75
|
+
expect((0, workflowBands_1.getBandOutstandingUserTypes)(band, [])).toEqual(["Provider", "Parent"]);
|
|
76
|
+
// The employer has signed off, so only the parent is still owed.
|
|
77
|
+
expect((0, workflowBands_1.getBandOutstanding)(band, [3]).map((s) => s.id)).toEqual([4]);
|
|
78
|
+
expect((0, workflowBands_1.getBandOutstandingUserTypes)(band, [3])).toEqual(["Parent"]);
|
|
79
|
+
expect((0, workflowBands_1.getBandOutstanding)(band, [3, 4])).toEqual([]);
|
|
80
|
+
expect((0, workflowBands_1.getBandOutstandingUserTypes)(band, [3, 4])).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
it("does not repeat a user type that owns two stages in the band", () => {
|
|
83
|
+
const twoProviderStages = [
|
|
84
|
+
stage(3, "Provider", 4, true),
|
|
85
|
+
stage(4, "Provider", 5, true),
|
|
86
|
+
stage(5, "Parent", 6),
|
|
87
|
+
stage(6, undefined),
|
|
88
|
+
];
|
|
89
|
+
const band = (0, workflowBands_1.getConcurrentBand)(twoProviderStages, 3);
|
|
90
|
+
expect((0, workflowBands_1.getBandOutstandingUserTypes)(band, [])).toEqual(["Provider", "Parent"]);
|
|
91
|
+
});
|
|
92
|
+
it("names the band for staff", () => {
|
|
93
|
+
expect((0, workflowBands_1.getBandName)((0, workflowBands_1.getConcurrentBand)(banded, 3))).toEqual("Stage 3 & Stage 4");
|
|
94
|
+
expect((0, workflowBands_1.getBandName)((0, workflowBands_1.getConcurrentBand)(sequential, 3))).toEqual("Stage 3");
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
//# sourceMappingURL=workflowBands.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflowBands.test.js","sourceRoot":"","sources":["../src/workflowBands.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -31,6 +31,7 @@ export * from "./tutorialTips";
|
|
|
31
31
|
export * from "./constants";
|
|
32
32
|
export * from "./dataViewerReload";
|
|
33
33
|
export * from "./hooks";
|
|
34
|
+
export * from "./workflowBands";
|
|
34
35
|
export * from "./util";
|
|
35
36
|
export * from "./images/GatsbyBenchmarks";
|
|
36
37
|
export * from "./databaseTypes";
|
package/src/pricing.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {calculateHubPrice, calculateSchoolPrice, DEFAULT_PRICING_CONFIG, InstituteQuoteInput, instituteQuote, mergePricingConfig, quoteSnapshot, SchoolPricingInput} from "./pricing";
|
|
1
|
+
import {calculateHubPrice, calculateSchoolPrice, DEFAULT_PRICING_CONFIG, InstituteQuoteInput, instituteQuote, mergePricingConfig, quoteSnapshot, SchoolPricingInput, trustDiscountRate} from "./pricing";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* The worked examples from the 2026 pricing sheet, kept here as the contract:
|
|
@@ -146,6 +146,53 @@ describe("mergePricingConfig", () => {
|
|
|
146
146
|
});
|
|
147
147
|
});
|
|
148
148
|
|
|
149
|
+
describe("the trust discount", () => {
|
|
150
|
+
const trust = (schools: number): SchoolPricingInput =>
|
|
151
|
+
({students: 10000, events: true, destinations: true, schools});
|
|
152
|
+
|
|
153
|
+
it("gives a trust under ten schools 5% off the whole quote", () => {
|
|
154
|
+
const result = calculateSchoolPrice(trust(9));
|
|
155
|
+
const plain = calculateSchoolPrice({...trust(9), schools: undefined});
|
|
156
|
+
|
|
157
|
+
expect(result.trustDiscountRate).toBe(0.05);
|
|
158
|
+
expect(result.total).toBeCloseTo(plain.total * 0.95, 6);
|
|
159
|
+
expect(result.trustDiscountApplied).toBeCloseTo(plain.total * 0.05, 6);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("gives a trust of ten schools or more 10%", () => {
|
|
163
|
+
expect(calculateSchoolPrice(trust(10)).trustDiscountRate).toBe(0.1);
|
|
164
|
+
expect(calculateSchoolPrice(trust(40)).trustDiscountRate).toBe(0.1);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("gives a single school nothing, however it is counted", () => {
|
|
168
|
+
expect(trustDiscountRate(undefined)).toBe(0);
|
|
169
|
+
expect(trustDiscountRate(0)).toBe(0);
|
|
170
|
+
expect(trustDiscountRate(1)).toBe(0);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it("is taken after the full-platform discount and before the negotiated one", () => {
|
|
174
|
+
const input: SchoolPricingInput = {
|
|
175
|
+
students: 10000, wexY10: 500, events: true, destinations: true,
|
|
176
|
+
fullPlatformDiscount: true, schools: 12, bespokeDiscount: 0.1,
|
|
177
|
+
};
|
|
178
|
+
const result = calculateSchoolPrice(input);
|
|
179
|
+
const expected = result.subtotal * 0.8 * 0.9 * 0.9;
|
|
180
|
+
|
|
181
|
+
expect(result.total).toBeCloseTo(expected, 6);
|
|
182
|
+
expect(result.trustDiscountApplied).toBeCloseTo(result.subtotal * 0.8 * 0.1, 6);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it("only reaches an institute that is actually a trust", () => {
|
|
186
|
+
const priced = (isTrust: boolean) => instituteQuote({
|
|
187
|
+
products: {events: true, isTrust},
|
|
188
|
+
students: 10000,
|
|
189
|
+
pricing: {schools: 12},
|
|
190
|
+
}).total;
|
|
191
|
+
|
|
192
|
+
expect(priced(true)).toBeCloseTo(priced(false) * 0.9, 6);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
149
196
|
describe("the negotiated terms", () => {
|
|
150
197
|
it("takes the bespoke discount after the full-platform one", () => {
|
|
151
198
|
const base: SchoolPricingInput = {students: 2000, events: true, destinations: true, fullPlatformDiscount: true};
|
package/src/pricing.ts
CHANGED
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
* a partial-product discount — that is how the pricing sheet has it, and it is
|
|
13
13
|
* why `partialProductDiscount` names those two rather than being one number.
|
|
14
14
|
*
|
|
15
|
+
* A trust is quoted as one account on its combined roll, and earns a discount
|
|
16
|
+
* on the whole quote for the number of schools it brings on — a smaller one
|
|
17
|
+
* below the threshold, a larger one at or above it.
|
|
18
|
+
*
|
|
15
19
|
* Every figure lives in `PricingConfig` so it can be stored in Firestore and
|
|
16
20
|
* adjusted without a deploy. `DEFAULT_PRICING_CONFIG` is the fallback and the
|
|
17
21
|
* seed for that document.
|
|
@@ -42,6 +46,15 @@ export type PricingConfig = {
|
|
|
42
46
|
partialProductDiscount: {events: number, destinations: number},
|
|
43
47
|
/** Taken off the whole quote when a school takes the full platform. */
|
|
44
48
|
fullPlatformDiscount: number,
|
|
49
|
+
/** Taken off the whole quote for a trust, on how many schools it brings. */
|
|
50
|
+
trust: {
|
|
51
|
+
/** Schools at which the larger discount takes over. */
|
|
52
|
+
threshold: number,
|
|
53
|
+
/** Fraction off a trust below the threshold. */
|
|
54
|
+
discount: number,
|
|
55
|
+
/** Fraction off a trust at or above it. */
|
|
56
|
+
largeDiscount: number,
|
|
57
|
+
},
|
|
45
58
|
/** Careers hubs are a flat platform fee plus a fee for each school. */
|
|
46
59
|
hub: {baseFee: number, perSchoolFee: number},
|
|
47
60
|
};
|
|
@@ -57,6 +70,7 @@ export const DEFAULT_PRICING_CONFIG: PricingConfig = {
|
|
|
57
70
|
],
|
|
58
71
|
partialProductDiscount: {events: 0.2, destinations: 0.2},
|
|
59
72
|
fullPlatformDiscount: 0.2,
|
|
73
|
+
trust: {threshold: 10, discount: 0.05, largeDiscount: 0.1},
|
|
60
74
|
hub: {baseFee: 2000, perSchoolFee: 150},
|
|
61
75
|
};
|
|
62
76
|
|
|
@@ -78,6 +92,8 @@ export type SchoolPricingInput = {
|
|
|
78
92
|
destinationsDiscount?: boolean,
|
|
79
93
|
/** Discount the whole quote, for a school taking the full platform. */
|
|
80
94
|
fullPlatformDiscount?: boolean,
|
|
95
|
+
/** Schools in the trust being quoted. Two or more earns a trust discount. */
|
|
96
|
+
schools?: number,
|
|
81
97
|
/** A negotiated discount off the whole quote, as a fraction (0.1 = 10% off).
|
|
82
98
|
* Taken after the full-platform discount and before the minimum fee. */
|
|
83
99
|
bespokeDiscount?: number,
|
|
@@ -116,7 +132,11 @@ export type SchoolPricingResult = {
|
|
|
116
132
|
subtotal: number,
|
|
117
133
|
/** £ taken off the subtotal by the full-platform discount. */
|
|
118
134
|
fullPlatformDiscountApplied: number,
|
|
119
|
-
/** £ taken off by the
|
|
135
|
+
/** £ taken off by the trust discount, after the full-platform one. */
|
|
136
|
+
trustDiscountApplied: number,
|
|
137
|
+
/** The rate that trust discount was taken at, as a fraction. */
|
|
138
|
+
trustDiscountRate: number,
|
|
139
|
+
/** £ taken off by the negotiated discount, after the trust one. */
|
|
120
140
|
bespokeDiscountApplied: number,
|
|
121
141
|
/** True when the minimum fee, not the products, set the price. */
|
|
122
142
|
minFeeApplied: boolean,
|
|
@@ -175,6 +195,25 @@ const clampFraction = (value?: number) => Math.min(Math.max(value || 0, 0), 1);
|
|
|
175
195
|
|
|
176
196
|
const bandsTotal = (bands: PricingBand[]) => sum(bands.map((b) => b.amount));
|
|
177
197
|
|
|
198
|
+
/**
|
|
199
|
+
* What a trust comes off its quote for its size.
|
|
200
|
+
*
|
|
201
|
+
* A trust is more than one school, so a count below two is a single school and
|
|
202
|
+
* earns nothing — the discount is for bringing schools with you.
|
|
203
|
+
*
|
|
204
|
+
* @param {number} [schools] schools in the trust.
|
|
205
|
+
* @param {object} [config] the figures to price with. Defaults to the 2026 sheet.
|
|
206
|
+
* @return {number} the discount, as a fraction of the quote.
|
|
207
|
+
*/
|
|
208
|
+
export function trustDiscountRate(
|
|
209
|
+
schools?: number,
|
|
210
|
+
config: PricingConfig = DEFAULT_PRICING_CONFIG,
|
|
211
|
+
): number {
|
|
212
|
+
const count = schools || 0;
|
|
213
|
+
if (count < 2) return 0;
|
|
214
|
+
return count >= config.trust.threshold ? config.trust.largeDiscount : config.trust.discount;
|
|
215
|
+
}
|
|
216
|
+
|
|
178
217
|
/**
|
|
179
218
|
* Price a school, trust or hub-school quote.
|
|
180
219
|
*
|
|
@@ -218,7 +257,9 @@ export function calculateSchoolPrice(
|
|
|
218
257
|
|
|
219
258
|
const subtotal = sum(lines.map((l) => l.amount));
|
|
220
259
|
const discounted = input.fullPlatformDiscount ? subtotal * (1 - config.fullPlatformDiscount) : subtotal;
|
|
221
|
-
const
|
|
260
|
+
const trustRate = trustDiscountRate(input.schools, config);
|
|
261
|
+
const trusted = discounted * (1 - trustRate);
|
|
262
|
+
const negotiated = trusted * (1 - clampFraction(input.bespokeDiscount));
|
|
222
263
|
const floored = Math.max(negotiated, config.minFee);
|
|
223
264
|
const overridden = input.quoteOverride !== undefined && input.quoteOverride >= 0;
|
|
224
265
|
|
|
@@ -226,7 +267,9 @@ export function calculateSchoolPrice(
|
|
|
226
267
|
lines,
|
|
227
268
|
subtotal,
|
|
228
269
|
fullPlatformDiscountApplied: subtotal - discounted,
|
|
229
|
-
|
|
270
|
+
trustDiscountApplied: discounted - trusted,
|
|
271
|
+
trustDiscountRate: trustRate,
|
|
272
|
+
bespokeDiscountApplied: trusted - negotiated,
|
|
230
273
|
// An agreed price is the price, so neither the floor nor the discounts
|
|
231
274
|
// are what set it — they are only reported when the calculation stands.
|
|
232
275
|
minFeeApplied: !overridden && floored > negotiated,
|
|
@@ -270,6 +313,7 @@ export function mergePricingConfig(stored?: Partial<PricingConfig>): PricingConf
|
|
|
270
313
|
tiers: stored.tiers?.length ? stored.tiers.map((t, i) => ({...(d.tiers[i] || d.tiers[d.tiers.length - 1]), ...t})) : d.tiers,
|
|
271
314
|
partialProductDiscount: {...d.partialProductDiscount, ...stored.partialProductDiscount},
|
|
272
315
|
fullPlatformDiscount: stored.fullPlatformDiscount ?? d.fullPlatformDiscount,
|
|
316
|
+
trust: {...d.trust, ...stored.trust},
|
|
273
317
|
hub: {...d.hub, ...stored.hub},
|
|
274
318
|
};
|
|
275
319
|
}
|
|
@@ -309,6 +353,8 @@ export type InstitutePricing = {
|
|
|
309
353
|
discountReason?: string,
|
|
310
354
|
/** A price agreed with the customer, which replaces the calculated one. */
|
|
311
355
|
quoteOverride?: number,
|
|
356
|
+
/** Schools in the trust, which set its discount. Trust accounts only. */
|
|
357
|
+
schools?: number,
|
|
312
358
|
/** Schools on the hub. Hub accounts only. */
|
|
313
359
|
hubSchools?: number,
|
|
314
360
|
/** The quote as last saved, for the customer to see. */
|
|
@@ -323,6 +369,9 @@ export type InstituteQuote = {
|
|
|
323
369
|
/** The lines added up, before any whole-quote discount. */
|
|
324
370
|
subtotal: number,
|
|
325
371
|
fullPlatformDiscountApplied: number,
|
|
372
|
+
trustDiscountApplied: number,
|
|
373
|
+
/** The rate the trust discount was taken at, as a fraction. */
|
|
374
|
+
trustDiscountRate: number,
|
|
326
375
|
bespokeDiscountApplied: number,
|
|
327
376
|
minFeeApplied: boolean,
|
|
328
377
|
overrideApplied: boolean,
|
|
@@ -347,9 +396,11 @@ export type InstituteQuoteSnapshot = {
|
|
|
347
396
|
/** What the quote needs to know about the institute being priced. */
|
|
348
397
|
export type InstituteQuoteInput = {
|
|
349
398
|
/** What the institute has, as resolved by `resolveProducts`. */
|
|
350
|
-
products: {wex?: boolean, events?: boolean, destinations?: boolean, isHub?: boolean},
|
|
399
|
+
products: {wex?: boolean, events?: boolean, destinations?: boolean, isHub?: boolean, isTrust?: boolean},
|
|
351
400
|
/** The institute's roll, when the agreed terms don't name one. */
|
|
352
401
|
students?: number,
|
|
402
|
+
/** Schools in the trust, when the agreed terms don't name a number. */
|
|
403
|
+
schools?: number,
|
|
353
404
|
/** Schools on the hub, when the agreed terms don't name a number. */
|
|
354
405
|
hubSchools?: number,
|
|
355
406
|
/** The terms agreed with this customer. */
|
|
@@ -410,6 +461,9 @@ export function hubQuote(
|
|
|
410
461
|
lines,
|
|
411
462
|
subtotal: hub.total,
|
|
412
463
|
fullPlatformDiscountApplied: 0,
|
|
464
|
+
// A hub is already priced on its schools, so it has no trust discount.
|
|
465
|
+
trustDiscountApplied: 0,
|
|
466
|
+
trustDiscountRate: 0,
|
|
413
467
|
bespokeDiscountApplied: hub.total - negotiated,
|
|
414
468
|
minFeeApplied: false,
|
|
415
469
|
overrideApplied: overridden,
|
|
@@ -422,7 +476,8 @@ export function hubQuote(
|
|
|
422
476
|
*
|
|
423
477
|
* The products come from `resolveProducts` rather than the raw flags, so a trust
|
|
424
478
|
* is priced on the union of its schools' products the same way it is gated on
|
|
425
|
-
* them
|
|
479
|
+
* them, and it is a trust — not any school with a number against it — that earns
|
|
480
|
+
* the trust discount. A year group with no placements agreed is a year group not on work
|
|
426
481
|
* experience — except where the institute has work experience and neither year
|
|
427
482
|
* group has been filled in, which is a quote waiting to be finished rather than
|
|
428
483
|
* a school not taking the product, so Y10 is charged at zero to say so.
|
|
@@ -446,6 +501,9 @@ export function instituteQuote(
|
|
|
446
501
|
|
|
447
502
|
return schoolQuote({
|
|
448
503
|
students: pricing?.students ?? input.students,
|
|
504
|
+
// Only a trust is quoted on a school count, so a single school can never
|
|
505
|
+
// pick up the discount by having a stray number agreed against it.
|
|
506
|
+
schools: input.products.isTrust ? (pricing?.schools ?? input.schools) : undefined,
|
|
449
507
|
wexY10: wex ? (noYearGroupQuoted ? 0 : pricing?.wexY10) : undefined,
|
|
450
508
|
wexY12: wex ? pricing?.wexY12 : undefined,
|
|
451
509
|
events: Boolean(input.products.events),
|
package/src/typeDefinitions.ts
CHANGED
|
@@ -36,6 +36,10 @@ export type Products = "institutes"|"providers"|"students"|"admin";
|
|
|
36
36
|
export type StudentPlacementData = {
|
|
37
37
|
title: string,
|
|
38
38
|
reqUserType: "Students" | "Staff" | "Provider" | "Parent",
|
|
39
|
+
reqUserTypes?: ("Students" | "Staff" | "Provider" | "Parent")[],
|
|
40
|
+
/** Set while a completion is claiming the band's single advance, so two
|
|
41
|
+
* parties finishing at once cannot both move the placement on. */
|
|
42
|
+
advancingFrom?: number,
|
|
39
43
|
lastStageChange?: string // yyyy-mm-dd Set every time a stage changes!
|
|
40
44
|
uid: string,
|
|
41
45
|
startDate: string,
|
|
@@ -65,8 +69,6 @@ export type StudentPlacementData = {
|
|
|
65
69
|
locality: string,
|
|
66
70
|
postal_code: string,
|
|
67
71
|
remote?: boolean;
|
|
68
|
-
// The employer contact for this placement is the student's parent or
|
|
69
|
-
// guardian, so parent and employer sign-off are the same person.
|
|
70
72
|
parentIsEmployer?: boolean;
|
|
71
73
|
what3Words?: string,
|
|
72
74
|
country: string,
|
|
@@ -756,6 +758,7 @@ export type WorkflowStage = {
|
|
|
756
758
|
buttons?: {id: number, name: string|false, description?: string, required: boolean}[],
|
|
757
759
|
pos?: { x: number, y: number },
|
|
758
760
|
userType?: "Students" | "Staff" | "Provider" | "Parent",
|
|
761
|
+
concurrentWithNext?: boolean,
|
|
759
762
|
forms?: string[],
|
|
760
763
|
files?: string[],
|
|
761
764
|
deadline?: string,
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import {getBandExitStageId, getBandHead, getBandName, getBandOutstanding,
|
|
2
|
+
getBandOutstandingUserTypes, getConcurrentBand, isConcurrentBand} from "./workflowBands";
|
|
3
|
+
import {WorkflowStage} from "./typeDefinitions";
|
|
4
|
+
|
|
5
|
+
describe("Concurrent bands", () => {
|
|
6
|
+
// A typical work experience chain: staff check, then employer review, then
|
|
7
|
+
// parental consent, then the placement start stage.
|
|
8
|
+
const stage = (id: number, userType: WorkflowStage["userType"], next?: number, concurrentWithNext?: boolean): WorkflowStage => ({
|
|
9
|
+
id,
|
|
10
|
+
name: `Stage ${id}`,
|
|
11
|
+
userType,
|
|
12
|
+
concurrentWithNext,
|
|
13
|
+
buttons: next === undefined ? [] : [{id: next, name: "Continue", required: true}],
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const sequential: WorkflowStage[] = [
|
|
17
|
+
stage(1, "Students", 2),
|
|
18
|
+
stage(2, "Staff", 3),
|
|
19
|
+
stage(3, "Provider", 4),
|
|
20
|
+
stage(4, "Parent", 6),
|
|
21
|
+
stage(6, undefined),
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
// Same workflow, but employer review and parental consent run together.
|
|
25
|
+
const banded: WorkflowStage[] = [
|
|
26
|
+
stage(1, "Students", 2),
|
|
27
|
+
stage(2, "Staff", 3),
|
|
28
|
+
stage(3, "Provider", 4, true),
|
|
29
|
+
stage(4, "Parent", 6),
|
|
30
|
+
stage(6, undefined),
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
it("returns just the stage when nothing is marked concurrent", () => {
|
|
34
|
+
expect(getConcurrentBand(sequential, 3).map((s) => s.id)).toEqual([3]);
|
|
35
|
+
expect(getConcurrentBand(sequential, 4).map((s) => s.id)).toEqual([4]);
|
|
36
|
+
expect(isConcurrentBand(sequential, 3)).toBe(false);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it("resolves the same band from any member", () => {
|
|
40
|
+
expect(getConcurrentBand(banded, 3).map((s) => s.id)).toEqual([3, 4]);
|
|
41
|
+
expect(getConcurrentBand(banded, 4).map((s) => s.id)).toEqual([3, 4]);
|
|
42
|
+
expect(isConcurrentBand(banded, 3)).toBe(true);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("resolves a band of three from the middle", () => {
|
|
46
|
+
const three: WorkflowStage[] = [
|
|
47
|
+
stage(2, "Staff", 3, true),
|
|
48
|
+
stage(3, "Provider", 4, true),
|
|
49
|
+
stage(4, "Parent", 6),
|
|
50
|
+
stage(6, undefined),
|
|
51
|
+
];
|
|
52
|
+
expect(getConcurrentBand(three, 3).map((s) => s.id)).toEqual([2, 3, 4]);
|
|
53
|
+
expect(getBandHead(three, 4)?.id).toEqual(2);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("does not pull in the stage after the band", () => {
|
|
57
|
+
expect(getConcurrentBand(banded, 3).some((s) => s.id === 6)).toBe(false);
|
|
58
|
+
expect(getBandExitStageId(getConcurrentBand(banded, 3))).toEqual(6);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("terminates on a cycle", () => {
|
|
62
|
+
// The builder stops a school authoring this, but a hand-edited workflow
|
|
63
|
+
// must not hang or repeat a stage. A cycle has no real head, so only the
|
|
64
|
+
// membership is meaningful here, not the order.
|
|
65
|
+
const looped: WorkflowStage[] = [
|
|
66
|
+
stage(3, "Provider", 4, true),
|
|
67
|
+
stage(4, "Parent", 3, true),
|
|
68
|
+
];
|
|
69
|
+
const ids = getConcurrentBand(looped, 3).map((s) => s.id);
|
|
70
|
+
expect(ids.slice().sort()).toEqual([3, 4]);
|
|
71
|
+
expect(new Set(ids).size).toEqual(ids.length);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("terminates when a flagged stage points nowhere", () => {
|
|
75
|
+
const dangling: WorkflowStage[] = [stage(3, "Provider", undefined, true)];
|
|
76
|
+
expect(getConcurrentBand(dangling, 3).map((s) => s.id)).toEqual([3]);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it("returns nothing for a stage that is not in the workflow", () => {
|
|
80
|
+
expect(getConcurrentBand(banded, 99)).toEqual([]);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("reports what the band is still waiting on", () => {
|
|
84
|
+
const band = getConcurrentBand(banded, 3);
|
|
85
|
+
expect(getBandOutstanding(band, []).map((s) => s.id)).toEqual([3, 4]);
|
|
86
|
+
expect(getBandOutstandingUserTypes(band, [])).toEqual(["Provider", "Parent"]);
|
|
87
|
+
|
|
88
|
+
// The employer has signed off, so only the parent is still owed.
|
|
89
|
+
expect(getBandOutstanding(band, [3]).map((s) => s.id)).toEqual([4]);
|
|
90
|
+
expect(getBandOutstandingUserTypes(band, [3])).toEqual(["Parent"]);
|
|
91
|
+
|
|
92
|
+
expect(getBandOutstanding(band, [3, 4])).toEqual([]);
|
|
93
|
+
expect(getBandOutstandingUserTypes(band, [3, 4])).toEqual([]);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("does not repeat a user type that owns two stages in the band", () => {
|
|
97
|
+
const twoProviderStages: WorkflowStage[] = [
|
|
98
|
+
stage(3, "Provider", 4, true),
|
|
99
|
+
stage(4, "Provider", 5, true),
|
|
100
|
+
stage(5, "Parent", 6),
|
|
101
|
+
stage(6, undefined),
|
|
102
|
+
];
|
|
103
|
+
const band = getConcurrentBand(twoProviderStages, 3);
|
|
104
|
+
expect(getBandOutstandingUserTypes(band, [])).toEqual(["Provider", "Parent"]);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("names the band for staff", () => {
|
|
108
|
+
expect(getBandName(getConcurrentBand(banded, 3))).toEqual("Stage 3 & Stage 4");
|
|
109
|
+
expect(getBandName(getConcurrentBand(sequential, 3))).toEqual("Stage 3");
|
|
110
|
+
});
|
|
111
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {WorkflowStage} from "./typeDefinitions";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Concurrent sign-off bands.
|
|
5
|
+
*
|
|
6
|
+
* Deliberately free of any firebase import so it can be unit tested and pulled
|
|
7
|
+
* into the backend, the external review payload and the staff UI alike.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The stage that starts the concurrent band `stageId` belongs to.
|
|
12
|
+
*
|
|
13
|
+
* A band is a run of stages chained by their first button where every stage but
|
|
14
|
+
* the last carries `concurrentWithNext`. The head is the stage a placement's
|
|
15
|
+
* `status` points at while the band is open, which is what lets `status` stay a
|
|
16
|
+
* single number: the band only changes who we ask, not where the placement is.
|
|
17
|
+
*/
|
|
18
|
+
export const getBandHead = (workflow: WorkflowStage[], stageId: number): WorkflowStage|undefined => {
|
|
19
|
+
let stage = workflow.find((s) => s.id === stageId);
|
|
20
|
+
if (!stage) return undefined;
|
|
21
|
+
|
|
22
|
+
const visited = new Set<number>([stage.id]);
|
|
23
|
+
|
|
24
|
+
for (;;) {
|
|
25
|
+
const previous = workflow.find((s) => s.concurrentWithNext && s.buttons?.[0]?.id === stage?.id);
|
|
26
|
+
// No flagged predecessor means we are already at the head.
|
|
27
|
+
if (!previous || visited.has(previous.id)) return stage;
|
|
28
|
+
visited.add(previous.id);
|
|
29
|
+
stage = previous;
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Every stage that runs at the same time as `stageId`, in workflow order.
|
|
35
|
+
*
|
|
36
|
+
* Returns just the stage itself when nothing is marked concurrent, so callers can
|
|
37
|
+
* use this unconditionally and existing workflows behave exactly as before.
|
|
38
|
+
*/
|
|
39
|
+
export const getConcurrentBand = (workflow: WorkflowStage[], stageId: number): WorkflowStage[] => {
|
|
40
|
+
const head = getBandHead(workflow, stageId);
|
|
41
|
+
if (!head) return [];
|
|
42
|
+
|
|
43
|
+
const band = [head];
|
|
44
|
+
const visited = new Set<number>([head.id]);
|
|
45
|
+
|
|
46
|
+
let stage: WorkflowStage|undefined = head;
|
|
47
|
+
while (stage?.concurrentWithNext) {
|
|
48
|
+
const nextId: number|undefined = stage.buttons?.[0]?.id;
|
|
49
|
+
// A flagged stage with nowhere to go, or a loop, ends the band rather
|
|
50
|
+
// than stranding the caller.
|
|
51
|
+
if (nextId === undefined || visited.has(nextId)) break;
|
|
52
|
+
stage = workflow.find((s) => s.id === nextId);
|
|
53
|
+
if (!stage) break;
|
|
54
|
+
visited.add(stage.id);
|
|
55
|
+
band.push(stage);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return band;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
/** True when the workflow asks more than one party at this point. */
|
|
62
|
+
export const isConcurrentBand = (workflow: WorkflowStage[], stageId: number) =>
|
|
63
|
+
getConcurrentBand(workflow, stageId).length > 1;
|
|
64
|
+
|
|
65
|
+
/** The band's stages that nobody has signed off yet. */
|
|
66
|
+
export const getBandOutstanding = (band: WorkflowStage[], completedStages: number[] = []) =>
|
|
67
|
+
band.filter((stage) => !completedStages.includes(stage.id));
|
|
68
|
+
|
|
69
|
+
/** Distinct user types the band is still waiting on, in workflow order. */
|
|
70
|
+
export const getBandOutstandingUserTypes = (band: WorkflowStage[], completedStages: number[] = []) =>
|
|
71
|
+
getBandOutstanding(band, completedStages)
|
|
72
|
+
.map((stage) => stage.userType)
|
|
73
|
+
.filter((userType, i, all): userType is NonNullable<WorkflowStage["userType"]> =>
|
|
74
|
+
Boolean(userType) && all.indexOf(userType) === i);
|
|
75
|
+
|
|
76
|
+
/** Where the placement goes once every stage in the band is signed off. */
|
|
77
|
+
export const getBandExitStageId = (band: WorkflowStage[]) =>
|
|
78
|
+
band[band.length - 1]?.buttons?.[0]?.id;
|
|
79
|
+
|
|
80
|
+
/** The label to show staff for a band, e.g. "Employer review & parental consent". */
|
|
81
|
+
export const getBandName = (band: WorkflowStage[]) =>
|
|
82
|
+
band.map((stage) => stage.name).join(" & ");
|