@cyc-seattle/platform 1.48.0 → 1.50.0
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/dist/planning/context.d.ts +1 -1
- package/dist/planning/context.js +2 -3
- package/dist/planning/staffing.d.ts +11 -3
- package/dist/planning/staffing.js +73 -71
- package/dist/planning/types.d.ts +40 -35
- package/dist/schema/index.d.ts +59 -64
- package/package.json +1 -1
|
@@ -18,7 +18,7 @@ export interface Entry {
|
|
|
18
18
|
line_name: string;
|
|
19
19
|
explanation: string;
|
|
20
20
|
stage: Stage;
|
|
21
|
-
/** How much of the amount MTDC counts: 0 when
|
|
21
|
+
/** How much of the amount MTDC counts: 1, or 0 when it leaves MTDC, such as a boat charter. */
|
|
22
22
|
mtdc_share: number;
|
|
23
23
|
/** Whether it's wages, which payroll tax is charged on. */
|
|
24
24
|
wages: boolean;
|
package/dist/planning/context.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
/** The warnings about what the blocks are given, or when they run. The rest are about the data. */
|
|
2
2
|
const ALLOCATION_WARNINGS = new Set([
|
|
3
3
|
"over_inventory_boats",
|
|
4
|
-
"over_inventory_resource",
|
|
5
4
|
"over_capacity",
|
|
6
5
|
"unallocated_activity",
|
|
7
6
|
"closed_date",
|
|
@@ -12,9 +11,9 @@ const COST_TYPES = {
|
|
|
12
11
|
coach_wages: "coach wages",
|
|
13
12
|
salaries: "salaries",
|
|
14
13
|
payroll_tax: "payroll tax",
|
|
15
|
-
ribs: "
|
|
14
|
+
ribs: "coach boats",
|
|
16
15
|
boat_maintenance: "boat maintenance",
|
|
17
|
-
resources: "
|
|
16
|
+
resources: "boat charters",
|
|
18
17
|
travel: "travel",
|
|
19
18
|
cogs: "cost of goods sold",
|
|
20
19
|
};
|
|
@@ -43,9 +43,17 @@ export declare class Staffing {
|
|
|
43
43
|
* Boats count the ones sailors bring.
|
|
44
44
|
*/
|
|
45
45
|
private checkCapacity;
|
|
46
|
+
/** Books a cost on a block, split among its activities by their offerings' sailors. */
|
|
47
|
+
private book;
|
|
46
48
|
/**
|
|
47
|
-
*
|
|
48
|
-
* blocks
|
|
49
|
+
* Charges each boat class's charter rate once a day, for the most of its boats chartered at once
|
|
50
|
+
* that day, shared among the blocks that charter them by how many each does. A charter is a rental,
|
|
51
|
+
* so it's left out of MTDC (2 CFR 200.1).
|
|
52
|
+
*/
|
|
53
|
+
private bookCharters;
|
|
54
|
+
/**
|
|
55
|
+
* Warns when more of the organization's boats of one class are given to blocks at once on a date
|
|
56
|
+
* than it has that day on the asset list. Boats it charters, or sailors bring, don't count.
|
|
49
57
|
*/
|
|
50
58
|
private checkInventory;
|
|
51
59
|
/**
|
|
@@ -53,7 +61,7 @@ export declare class Staffing {
|
|
|
53
61
|
* both. Returns each position's double-booked hours and dates.
|
|
54
62
|
*/
|
|
55
63
|
private checkDoubleBooked;
|
|
56
|
-
/** Costs every block's staff
|
|
64
|
+
/** Costs every block's staff and boats, and checks them against the limits. */
|
|
57
65
|
run(scheduled: ScheduledActivity[]): {
|
|
58
66
|
activities: ComputedActivity[];
|
|
59
67
|
coaching: SalariedCoaching[];
|
|
@@ -61,7 +61,6 @@ export class Staffing {
|
|
|
61
61
|
blocks(scheduled) {
|
|
62
62
|
const { data } = this.ctx;
|
|
63
63
|
const staff = groupBy(data.plan_block_staff, (r) => r.block_id);
|
|
64
|
-
const resources = groupBy(data.plan_block_resources, (r) => r.block_id);
|
|
65
64
|
const boats = groupBy(data.plan_block_boats, (r) => r.block_id);
|
|
66
65
|
const rows = new Map(data.plan_activity_blocks.map((b) => [b.id, b]));
|
|
67
66
|
const members = new Map();
|
|
@@ -103,7 +102,6 @@ export class Staffing {
|
|
|
103
102
|
Math.max(0, ...list.map((a) => a.stored.putaway_minutes ?? 0)),
|
|
104
103
|
on_water_minutes: set.length > 0 ? Math.max(...set) : sailingMinutes,
|
|
105
104
|
staff: staff.get(id) ?? [],
|
|
106
|
-
resources: resources.get(id) ?? [],
|
|
107
105
|
boats: boats.get(id) ?? [],
|
|
108
106
|
shares: new Map(list.map((a) => [a, share(a)])),
|
|
109
107
|
});
|
|
@@ -171,12 +169,13 @@ export class Staffing {
|
|
|
171
169
|
const classes = new Map(ctx.data.boat_classes.map((c) => [c.id, c]));
|
|
172
170
|
let seats = 0;
|
|
173
171
|
for (const b of block.boats) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
172
|
+
// A coach boat's class takes 0, without a warning.
|
|
173
|
+
const perBoat = classes.get(b.boat_class_id)?.max_capacity;
|
|
174
|
+
if (perBoat == null) {
|
|
175
|
+
this.warnOnce("no_max_capacity", `${classes.get(b.boat_class_id)?.name ?? b.boat_class_id} has no max capacity. Add it to check that the boats hold every sailor`, b.boat_class_id, scope);
|
|
177
176
|
continue;
|
|
178
177
|
}
|
|
179
|
-
seats += (b.count + (b.sailor_owned ?? 0)) * perBoat;
|
|
178
|
+
seats += (b.count + (b.chartered ?? 0) + (b.sailor_owned ?? 0)) * perBoat;
|
|
180
179
|
}
|
|
181
180
|
if (sailors > seats) {
|
|
182
181
|
ctx.warn("over_capacity", seats === 0
|
|
@@ -184,28 +183,79 @@ export class Staffing {
|
|
|
184
183
|
: `${has} ${countOf(sailors, "sailor")}, but the boats hold only ${seats}`, block.row.key, scope);
|
|
185
184
|
}
|
|
186
185
|
}
|
|
186
|
+
/** Books a cost on a block, split among its activities by their offerings' sailors. */
|
|
187
|
+
book(block, account, amount, line, name, explanation, mtdcShare = 1, wages = false) {
|
|
188
|
+
if (amount === 0 || account === undefined)
|
|
189
|
+
return;
|
|
190
|
+
for (const [a, share] of block.shares) {
|
|
191
|
+
this.ctx.book({
|
|
192
|
+
cost_center_type: "offering",
|
|
193
|
+
cost_center_key: a.offering.key,
|
|
194
|
+
account_id: account,
|
|
195
|
+
function: this.ctx.functionFor(account, null, "offering"),
|
|
196
|
+
amount: amount * share,
|
|
197
|
+
line_key: `${line}:${a.offering.key}`,
|
|
198
|
+
line_name: name,
|
|
199
|
+
explanation,
|
|
200
|
+
mtdc_share: mtdcShare,
|
|
201
|
+
wages,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Charges each boat class's charter rate once a day, for the most of its boats chartered at once
|
|
207
|
+
* that day, shared among the blocks that charter them by how many each does. A charter is a rental,
|
|
208
|
+
* so it's left out of MTDC (2 CFR 200.1).
|
|
209
|
+
*/
|
|
210
|
+
bookCharters(blocks) {
|
|
211
|
+
const { ctx } = this;
|
|
212
|
+
const rates = new Map(ctx.data.plan_boat_rates.map((r) => [r.boat_class_id, r]));
|
|
213
|
+
const classes = new Map(ctx.data.boat_classes.map((c) => [c.id, c]));
|
|
214
|
+
for (const list of groupBy(blocks, (b) => b.row.date).values()) {
|
|
215
|
+
const chartered = list.flatMap((block) => block.boats.flatMap((b) => ((b.chartered ?? 0) > 0 ? [{ block, id: b.boat_class_id, n: b.chartered }] : [])));
|
|
216
|
+
for (const [id, uses] of groupBy(chartered, (c) => c.id)) {
|
|
217
|
+
const name = classes.get(id)?.name ?? id;
|
|
218
|
+
const rate = rates.get(id)?.charter_per_day_cents;
|
|
219
|
+
if (rate == null) {
|
|
220
|
+
for (const { block } of uses) {
|
|
221
|
+
this.warnOnce("no_charter_rate", `${block.row.name} charters ${pluralOf(name)}, but the Operations Plan has no charter rate for them, so they cost nothing`, id, { version_id: block.row.version_id, date: block.row.date });
|
|
222
|
+
}
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
const day = mostAtOnce(uses).total * rate;
|
|
226
|
+
const total = sum(uses.map((u) => u.n));
|
|
227
|
+
for (const { block, n } of uses) {
|
|
228
|
+
this.book(block, ctx.costAccount("resources"), (day * n) / total, `charters:${id}`, `Boat charters: ${name}`, "The most boats of the class chartered at once that day × the class's charter rate", 0);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
187
233
|
/**
|
|
188
|
-
* Warns when the organization's boats of one class
|
|
189
|
-
*
|
|
234
|
+
* Warns when more of the organization's boats of one class are given to blocks at once on a date
|
|
235
|
+
* than it has that day on the asset list. Boats it charters, or sailors bring, don't count.
|
|
190
236
|
*/
|
|
191
237
|
checkInventory(blocks) {
|
|
192
238
|
const { ctx } = this;
|
|
193
239
|
const dates = groupBy(blocks, (b) => b.row.date);
|
|
194
240
|
const classes = new Map(ctx.data.boat_classes.map((c) => [c.id, c]));
|
|
195
|
-
const
|
|
196
|
-
const
|
|
241
|
+
const assets = new Map(ctx.data.assets.map((a) => [a.id, a]));
|
|
242
|
+
const boats = ctx.data.boats.flatMap((b) => {
|
|
243
|
+
const asset = assets.get(b.asset_id);
|
|
244
|
+
return asset === undefined ? [] : [{ asset, boat_class_id: b.boat_class_id }];
|
|
245
|
+
});
|
|
197
246
|
const organization = ctx.data.organization.name;
|
|
198
247
|
for (const [date, list] of dates) {
|
|
248
|
+
const has = (a) => (a.acquired_on == null || a.acquired_on <= date) && (a.disposed_on == null || date < a.disposed_on);
|
|
199
249
|
const check = (code, what, have, used) => {
|
|
200
|
-
if (have == null)
|
|
201
|
-
return;
|
|
202
250
|
const out = list.flatMap((b) => (used(b) > 0 ? [{ block: b, n: used(b) }] : []));
|
|
203
251
|
const peak = mostAtOnce(out);
|
|
204
252
|
if (peak.total <= have)
|
|
205
253
|
return;
|
|
254
|
+
const only = have === 0 ? "none" : `only ${have}`;
|
|
255
|
+
const count = countOf(peak.total, what);
|
|
206
256
|
const message = peak.at.length === 1
|
|
207
|
-
? `${
|
|
208
|
-
: `${
|
|
257
|
+
? `${count} out at once for ${offeringsOf(peak.at[0].block)}, but ${organization} has ${only}`
|
|
258
|
+
: `${count} out at once, but ${organization} has ${only}: ${listOf(peak.at.map(({ block, n }) => `${n} for ${offeringsOf(block)}`))}`;
|
|
209
259
|
for (const version of new Set(peak.at.map(({ block }) => block.row.version_id))) {
|
|
210
260
|
ctx.warn(code, message, what, {
|
|
211
261
|
version_id: version,
|
|
@@ -215,17 +265,8 @@ export class Staffing {
|
|
|
215
265
|
};
|
|
216
266
|
const classIds = new Set(list.flatMap((b) => b.boats.filter((x) => x.count > 0).map((x) => x.boat_class_id)));
|
|
217
267
|
for (const id of classIds) {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
this.warnOnce("no_fleet_quantity", `The Operations Plan doesn't say how many ${pluralOf(classes.get(id)?.name ?? id)} ${organization} has. Add it to check that there are enough`, id, { version_id: b.row.version_id, date });
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
check("over_inventory_boats", classes.get(id)?.name ?? id, fleet.get(id), (b) => sum(b.boats.filter((x) => x.boat_class_id === id).map((x) => x.count)));
|
|
224
|
-
}
|
|
225
|
-
const resourceKeys = new Set(list.flatMap((b) => b.resources.map((x) => x.resource_key)));
|
|
226
|
-
for (const key of resourceKeys) {
|
|
227
|
-
const resource = resources.get(key);
|
|
228
|
-
check("over_inventory_resource", resource?.name ?? key, resource?.quantity, (b) => sum(b.resources.filter((x) => x.resource_key === key).map((x) => x.quantity)));
|
|
268
|
+
const have = boats.filter((b) => b.boat_class_id === id && has(b.asset)).length;
|
|
269
|
+
check("over_inventory_boats", classes.get(id)?.name ?? id, have, (b) => sum(b.boats.filter((x) => x.boat_class_id === id).map((x) => x.count)));
|
|
229
270
|
}
|
|
230
271
|
}
|
|
231
272
|
}
|
|
@@ -260,7 +301,7 @@ export class Staffing {
|
|
|
260
301
|
}
|
|
261
302
|
return result;
|
|
262
303
|
}
|
|
263
|
-
/** Costs every block's staff
|
|
304
|
+
/** Costs every block's staff and boats, and checks them against the limits. */
|
|
264
305
|
run(scheduled) {
|
|
265
306
|
const { ctx } = this;
|
|
266
307
|
const blocks = this.blocks(scheduled);
|
|
@@ -274,37 +315,14 @@ export class Staffing {
|
|
|
274
315
|
const coaching = [];
|
|
275
316
|
const levels = new Map(ctx.data.plan_staff_levels.map((l) => [l.key, l]));
|
|
276
317
|
const positions = new Map(ctx.data.plan_salaried_positions.map((p) => [p.key, p]));
|
|
277
|
-
const resources = new Map(ctx.data.plan_resources.map((r) => [r.key, r]));
|
|
278
318
|
const boatClasses = new Map(ctx.data.boat_classes.map((c) => [c.id, c]));
|
|
279
319
|
const boatRates = new Map(ctx.data.plan_boat_rates.map((r) => [r.boat_class_id, r]));
|
|
280
|
-
const ribKind = ctx.data.rib_resource_kind_id;
|
|
281
320
|
const given = new Map();
|
|
282
321
|
for (const block of byDate(blocks)) {
|
|
283
322
|
const scope = { version_id: block.row.version_id, date: block.row.date };
|
|
284
323
|
const paidHours = block.paid_minutes / 60;
|
|
285
324
|
const waterHours = block.on_water_minutes / 60;
|
|
286
|
-
|
|
287
|
-
const book = (type, amount, line, name, explanation, mtdcShare = 1) => {
|
|
288
|
-
if (amount === 0)
|
|
289
|
-
return;
|
|
290
|
-
const account = ctx.costAccount(type);
|
|
291
|
-
if (account === undefined)
|
|
292
|
-
return;
|
|
293
|
-
for (const [a, share] of block.shares) {
|
|
294
|
-
ctx.book({
|
|
295
|
-
cost_center_type: "offering",
|
|
296
|
-
cost_center_key: a.offering.key,
|
|
297
|
-
account_id: account,
|
|
298
|
-
function: ctx.functionFor(account, null, "offering"),
|
|
299
|
-
amount: amount * share,
|
|
300
|
-
line_key: `${line}:${a.offering.key}`,
|
|
301
|
-
line_name: name,
|
|
302
|
-
explanation,
|
|
303
|
-
mtdc_share: mtdcShare,
|
|
304
|
-
wages: type === "coach_wages",
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
};
|
|
325
|
+
const book = (type, amount, line, name, explanation) => this.book(block, ctx.costAccount(type), amount, line, name, explanation, 1, type === "coach_wages");
|
|
308
326
|
let wages = 0;
|
|
309
327
|
for (const s of block.staff) {
|
|
310
328
|
if (s.count <= 0)
|
|
@@ -350,32 +368,20 @@ export class Staffing {
|
|
|
350
368
|
wages += s.count * paidHours * (level.hourly_rate_cents ?? 0);
|
|
351
369
|
}
|
|
352
370
|
book("coach_wages", wages, "coach_wages", "Coach wages", "Staff × paid hours × each one's hourly rate");
|
|
353
|
-
let ribs = 0;
|
|
354
|
-
for (const use of block.resources) {
|
|
355
|
-
const resource = resources.get(use.resource_key);
|
|
356
|
-
if (resource === undefined) {
|
|
357
|
-
this.warnOnce("unknown_resource", `${block.row.name} uses resource ${use.resource_key}, which isn't in the plan`, use.resource_key, scope);
|
|
358
|
-
continue;
|
|
359
|
-
}
|
|
360
|
-
const rib = ribKind != null && resource.resource_kind_id === ribKind;
|
|
361
|
-
if (rib)
|
|
362
|
-
ribs += use.quantity;
|
|
363
|
-
const hours = use.hours ?? (rib ? waterHours : paidHours);
|
|
364
|
-
const cost = use.quantity * (hours * hourlyCost(resource) + (resource.cost_per_day_cents ?? 0));
|
|
365
|
-
book(rib ? "ribs" : "resources", cost, rib ? "ribs" : `resource:${resource.key}`, rib ? "RIBs" : resource.name, `${resource.name}: quantity × hours × hourly cost, plus a day rate`, resource.excluded_from_mtdc ? 0 : 1);
|
|
366
|
-
}
|
|
367
371
|
for (const b of block.boats) {
|
|
368
372
|
const rate = boatRates.get(b.boat_class_id);
|
|
369
373
|
if (rate === undefined || b.count <= 0 || waterHours <= 0)
|
|
370
374
|
continue;
|
|
371
|
-
|
|
375
|
+
const boatClass = boatClasses.get(b.boat_class_id);
|
|
376
|
+
this.book(block, boatClass?.account_id ?? ctx.costAccount("boat_maintenance"), b.count * waterHours * (rate.maintenance_per_boat_hour_cents + (rate.fuel_per_hour_cents ?? 0)), `boats:${b.boat_class_id}`, `Boats: ${boatClass?.name ?? "boats"}`, "The organization's boats × on-water hours × the class's fuel and upkeep");
|
|
372
377
|
}
|
|
373
378
|
const coaches = sum(block.staff.map((s) => s.count));
|
|
374
|
-
const boats = sum(block.boats.map((b) => b.count));
|
|
379
|
+
const boats = sum(block.boats.map((b) => b.count + (b.chartered ?? 0)));
|
|
375
380
|
for (const [a, share] of block.shares) {
|
|
376
|
-
given.set(a, { coaches: coaches * share,
|
|
381
|
+
given.set(a, { coaches: coaches * share, boats: boats * share });
|
|
377
382
|
}
|
|
378
383
|
}
|
|
384
|
+
this.bookCharters(byDate(blocks));
|
|
379
385
|
this.bookTrips(blocks, scheduled);
|
|
380
386
|
return {
|
|
381
387
|
coaching,
|
|
@@ -391,7 +397,6 @@ export class Staffing {
|
|
|
391
397
|
on_water_minutes: a.on_water_minutes,
|
|
392
398
|
uses_boats: a.uses_boats,
|
|
393
399
|
coaches: given.get(a)?.coaches ?? 0,
|
|
394
|
-
ribs: given.get(a)?.ribs ?? 0,
|
|
395
400
|
boats: given.get(a)?.boats ?? 0,
|
|
396
401
|
block_id: blocks.has(a.stored.block_id ?? "") ? a.stored.block_id : null,
|
|
397
402
|
})),
|
|
@@ -508,9 +513,6 @@ function extraCoachMinutes(list) {
|
|
|
508
513
|
}
|
|
509
514
|
return minutes;
|
|
510
515
|
}
|
|
511
|
-
function hourlyCost(r) {
|
|
512
|
-
return (r.cost_per_hour_cents ?? 0) + (r.fuel_per_hour_cents ?? 0) + (r.maintenance_per_hour_cents ?? 0);
|
|
513
|
-
}
|
|
514
516
|
export function round2(n) {
|
|
515
517
|
return Math.round(n * 100) / 100;
|
|
516
518
|
}
|
package/dist/planning/types.d.ts
CHANGED
|
@@ -52,12 +52,27 @@ export interface QualificationCover {
|
|
|
52
52
|
export interface BoatClass {
|
|
53
53
|
id: Id;
|
|
54
54
|
name: string;
|
|
55
|
-
|
|
55
|
+
/** The most sailors one boat can safely take. */
|
|
56
|
+
max_capacity: number | null;
|
|
56
57
|
footprint_sq_ft: number | null;
|
|
58
|
+
/** Where its own boats' fuel and upkeep are booked; empty for the boat maintenance cost type's. */
|
|
59
|
+
account_id?: Id | null;
|
|
57
60
|
}
|
|
58
|
-
|
|
61
|
+
/** Something the organization owns: a sailboat, a powerboat, a motor, or other equipment. */
|
|
62
|
+
export interface Asset {
|
|
59
63
|
id: Id;
|
|
60
|
-
|
|
64
|
+
kind: "sailboat" | "powerboat" | "motor" | "other";
|
|
65
|
+
name: string | null;
|
|
66
|
+
/** The day the organization got it, or expects to; empty counts it from the start. */
|
|
67
|
+
acquired_on: DateString | null;
|
|
68
|
+
/** The day it stopped being the organization's; empty while it still is. */
|
|
69
|
+
disposed_on: DateString | null;
|
|
70
|
+
}
|
|
71
|
+
/** A sailboat or powerboat asset's class. */
|
|
72
|
+
export interface Boat {
|
|
73
|
+
id: Id;
|
|
74
|
+
asset_id: Id;
|
|
75
|
+
boat_class_id: Id;
|
|
61
76
|
}
|
|
62
77
|
export interface Organization {
|
|
63
78
|
id: Id;
|
|
@@ -88,7 +103,8 @@ export type ActivityKind = "practice" | "regatta" | "clinic" | "travel";
|
|
|
88
103
|
export interface PlanOffering extends Versioned {
|
|
89
104
|
product_id: Id;
|
|
90
105
|
name: string;
|
|
91
|
-
|
|
106
|
+
/** A `plan_terms` key in the Operations Plan, or none. */
|
|
107
|
+
term_key: Id | null;
|
|
92
108
|
starts_on: DateString;
|
|
93
109
|
ends_on: DateString;
|
|
94
110
|
capacity: number | null;
|
|
@@ -133,7 +149,7 @@ export interface PlanActivity extends Versioned {
|
|
|
133
149
|
/** The block it's staffed in, if any. */
|
|
134
150
|
block_id: Id | null;
|
|
135
151
|
}
|
|
136
|
-
/** Activities on one date that share their staff
|
|
152
|
+
/** Activities on one date that share their staff and boats. */
|
|
137
153
|
export interface PlanActivityBlock extends Versioned {
|
|
138
154
|
date: DateString;
|
|
139
155
|
name: string;
|
|
@@ -149,21 +165,13 @@ export interface PlanBlockStaff extends Versioned {
|
|
|
149
165
|
/** How a salaried position is paid for the block: out of its salary (the default), or by the hour at its own rate. */
|
|
150
166
|
pay: "salary" | "hourly" | null;
|
|
151
167
|
}
|
|
152
|
-
/**
|
|
153
|
-
export interface PlanBlockResource extends Versioned {
|
|
154
|
-
block_id: Id;
|
|
155
|
-
/** A `plan_resources` key. */
|
|
156
|
-
resource_key: Id;
|
|
157
|
-
quantity: number;
|
|
158
|
-
/** Hours each is used; empty for the block's time on the water (RIBs) or its paid time (the rest). */
|
|
159
|
-
hours: number | null;
|
|
160
|
-
}
|
|
161
|
-
/** Boats of one class on a block: the organization's, and the ones sailors bring. */
|
|
168
|
+
/** Boats of one class on a block: the organization's, the ones it charters, and the ones sailors bring. */
|
|
162
169
|
export interface PlanBlockBoats extends Versioned {
|
|
163
170
|
block_id: Id;
|
|
164
171
|
boat_class_id: Id;
|
|
165
172
|
count: number;
|
|
166
173
|
sailor_owned: number | null;
|
|
174
|
+
chartered?: number | null;
|
|
167
175
|
}
|
|
168
176
|
export interface PlanLaborLine extends Versioned {
|
|
169
177
|
name: string;
|
|
@@ -230,22 +238,15 @@ export interface PlanSalariedBooking extends Versioned {
|
|
|
230
238
|
kind: "management";
|
|
231
239
|
hours: number;
|
|
232
240
|
}
|
|
233
|
-
|
|
234
|
-
resource_kind_id: Id;
|
|
235
|
-
name: string;
|
|
236
|
-
quantity: number | null;
|
|
237
|
-
cost_per_hour_cents: number | null;
|
|
238
|
-
cost_per_day_cents: number | null;
|
|
239
|
-
fuel_per_hour_cents: number | null;
|
|
240
|
-
maintenance_per_hour_cents: number | null;
|
|
241
|
-
/** Set for a rental, whose cost leaves MTDC. */
|
|
242
|
-
excluded_from_mtdc: boolean;
|
|
243
|
-
}
|
|
241
|
+
/** A boat class's rates for the year. */
|
|
244
242
|
export interface PlanBoatRate extends Versioned {
|
|
245
243
|
boat_class_id: Id;
|
|
244
|
+
/** Upkeep for each hour one of the organization's boats of the class is on the water. */
|
|
246
245
|
maintenance_per_boat_hour_cents: number;
|
|
247
|
-
/**
|
|
248
|
-
|
|
246
|
+
/** Fuel for each hour one is on the water. */
|
|
247
|
+
fuel_per_hour_cents?: number | null;
|
|
248
|
+
/** What one costs to charter for a day. */
|
|
249
|
+
charter_per_day_cents?: number | null;
|
|
249
250
|
}
|
|
250
251
|
/** A group of shared costs, such as G&A, divided among all of the plan's offerings by MTDC. */
|
|
251
252
|
export interface PlanPool extends Versioned {
|
|
@@ -281,21 +282,27 @@ export interface PlanClosedDate extends Versioned {
|
|
|
281
282
|
date: DateString;
|
|
282
283
|
name: string;
|
|
283
284
|
}
|
|
285
|
+
/** A planning period in the Operations Plan, such as Summer 2027, which an offering can be in. */
|
|
286
|
+
export interface PlanTerm extends Versioned {
|
|
287
|
+
name: string;
|
|
288
|
+
starts_on: DateString;
|
|
289
|
+
ends_on: DateString;
|
|
290
|
+
}
|
|
284
291
|
/** The catalog plus every row of the plan versions being calculated. */
|
|
285
292
|
export interface PlanData {
|
|
286
293
|
/** The plan year. Fiscal year N ends in calendar year N. */
|
|
287
294
|
fiscal_year: number;
|
|
288
295
|
organization: Organization;
|
|
289
296
|
organization_cost_accounts: OrganizationCostAccount[];
|
|
290
|
-
/** The resource kind whose `plan_resources` price RIB hours. */
|
|
291
|
-
rib_resource_kind_id: Id | null;
|
|
292
297
|
products: Product[];
|
|
293
298
|
program_areas: ProgramArea[];
|
|
294
299
|
accounts: Account[];
|
|
295
300
|
qualifications: Qualification[];
|
|
296
301
|
qualification_covers: QualificationCover[];
|
|
297
302
|
boat_classes: BoatClass[];
|
|
298
|
-
|
|
303
|
+
/** The asset list, with its boats, which the engine counts by class on each day. */
|
|
304
|
+
assets: Asset[];
|
|
305
|
+
boats: Boat[];
|
|
299
306
|
/** The plans and versions being calculated, so the engine can tell which plan each offering is in. */
|
|
300
307
|
plans: Plan[];
|
|
301
308
|
plan_versions: PlanVersion[];
|
|
@@ -305,7 +312,6 @@ export interface PlanData {
|
|
|
305
312
|
plan_activities: PlanActivity[];
|
|
306
313
|
plan_activity_blocks: PlanActivityBlock[];
|
|
307
314
|
plan_block_staff: PlanBlockStaff[];
|
|
308
|
-
plan_block_resources: PlanBlockResource[];
|
|
309
315
|
plan_block_boats: PlanBlockBoats[];
|
|
310
316
|
plan_labor_lines: PlanLaborLine[];
|
|
311
317
|
plan_budget_lines: PlanBudgetLine[];
|
|
@@ -314,13 +320,13 @@ export interface PlanData {
|
|
|
314
320
|
plan_staff_levels: PlanStaffLevel[];
|
|
315
321
|
plan_salaried_positions: PlanSalariedPosition[];
|
|
316
322
|
plan_salaried_bookings: PlanSalariedBooking[];
|
|
317
|
-
plan_resources: PlanResource[];
|
|
318
323
|
plan_boat_rates: PlanBoatRate[];
|
|
319
324
|
plan_pools: PlanPool[];
|
|
320
325
|
plan_bonus_owners: PlanBonusOwner[];
|
|
321
326
|
plan_bonus_owner_products: PlanBonusOwnerProduct[];
|
|
322
327
|
plan_closed_dates?: PlanClosedDate[];
|
|
323
328
|
plan_capital_items?: PlanCapitalItem[];
|
|
329
|
+
plan_terms?: PlanTerm[];
|
|
324
330
|
}
|
|
325
331
|
/** One line of cost or revenue for the plan year, on one offering, product, pool or the organization. */
|
|
326
332
|
export interface CostLine {
|
|
@@ -370,9 +376,8 @@ export interface ComputedActivity {
|
|
|
370
376
|
paid_minutes: number;
|
|
371
377
|
on_water_minutes: number;
|
|
372
378
|
uses_boats: boolean;
|
|
373
|
-
/** Its share of its block's staff,
|
|
379
|
+
/** Its share of its block's staff and boats, the organization's and chartered, by its sailors. */
|
|
374
380
|
coaches: number;
|
|
375
|
-
ribs: number;
|
|
376
381
|
boats: number;
|
|
377
382
|
block_id: Id | null;
|
|
378
383
|
}
|
package/dist/schema/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/** Every collection, for `createDirectus<Schema>()`. */
|
|
2
2
|
export interface Schema {
|
|
3
3
|
accounts: Accounts[];
|
|
4
|
+
assets: Assets[];
|
|
4
5
|
audit_findings: AuditFindings[];
|
|
5
6
|
boat_classes: BoatClasses[];
|
|
6
7
|
boats: Boats[];
|
|
@@ -33,7 +34,6 @@ export interface Schema {
|
|
|
33
34
|
plan_activities: PlanActivities[];
|
|
34
35
|
plan_activity_blocks: PlanActivityBlocks[];
|
|
35
36
|
plan_block_boats: PlanBlockBoats[];
|
|
36
|
-
plan_block_resources: PlanBlockResources[];
|
|
37
37
|
plan_block_staff: PlanBlockStaff[];
|
|
38
38
|
plan_boat_rates: PlanBoatRates[];
|
|
39
39
|
plan_bonus_owner_products: PlanBonusOwnerProducts[];
|
|
@@ -46,7 +46,6 @@ export interface Schema {
|
|
|
46
46
|
plan_pools: PlanPools[];
|
|
47
47
|
plan_programs: PlanPrograms[];
|
|
48
48
|
plan_rates: PlanRates[];
|
|
49
|
-
plan_resources: PlanResources[];
|
|
50
49
|
plan_result_capital: PlanResultCapital[];
|
|
51
50
|
plan_result_lines: PlanResultLines[];
|
|
52
51
|
plan_result_pnl: PlanResultPnl[];
|
|
@@ -57,6 +56,7 @@ export interface Schema {
|
|
|
57
56
|
plan_salaried_bookings: PlanSalariedBookings[];
|
|
58
57
|
plan_salaried_positions: PlanSalariedPositions[];
|
|
59
58
|
plan_staff_levels: PlanStaffLevels[];
|
|
59
|
+
plan_terms: PlanTerms[];
|
|
60
60
|
plan_trips: PlanTrips[];
|
|
61
61
|
plan_versions: PlanVersions[];
|
|
62
62
|
plans: Plans[];
|
|
@@ -69,7 +69,6 @@ export interface Schema {
|
|
|
69
69
|
qualification_covers: QualificationCovers[];
|
|
70
70
|
qualifications: Qualifications[];
|
|
71
71
|
registrations: Registrations[];
|
|
72
|
-
resource_kinds: ResourceKinds[];
|
|
73
72
|
schools: Schools[];
|
|
74
73
|
sync_leases: SyncLeases[];
|
|
75
74
|
sync_runs: SyncRuns[];
|
|
@@ -114,6 +113,31 @@ export interface Accounts {
|
|
|
114
113
|
/** Kept for history, and closed to new lines. */
|
|
115
114
|
retired: boolean;
|
|
116
115
|
}
|
|
116
|
+
/** Each boat, motor and piece of equipment CSC owns: sailboats, powerboats such as the coach boats, motors, and others such as trailers. Planning counts the boats of each class CSC has on each day. */
|
|
117
|
+
export interface Assets {
|
|
118
|
+
id: string;
|
|
119
|
+
/** A sailboat or powerboat also needs a row in Boats. Directus can't check that, so keep them matching. */
|
|
120
|
+
kind: "sailboat" | "powerboat" | "motor" | "other";
|
|
121
|
+
/** Its name, if it has one, such as Scooter or the van. */
|
|
122
|
+
name: string | null;
|
|
123
|
+
/** This asset's boat details, if it is a sailboat or powerboat. */
|
|
124
|
+
boats: (string | Boats)[];
|
|
125
|
+
/** Who made it, such as Zodiac or Yamaha. */
|
|
126
|
+
make: string | null;
|
|
127
|
+
/** Its model. A boat's model is its boat class, in Boats. */
|
|
128
|
+
model: string | null;
|
|
129
|
+
/** The number that identifies it: a boat's hull number (HIN), a vehicle's VIN, or a serial number. */
|
|
130
|
+
identifier: string | null;
|
|
131
|
+
/** The state registration number, such as WN 1234 AB, if it has one. */
|
|
132
|
+
registration_number: string | null;
|
|
133
|
+
/** Its book value, as in QuickBooks account 1500. In cents: 12500 is $125.00. */
|
|
134
|
+
value_cents: number | null;
|
|
135
|
+
/** The day CSC got it, or expects to. Planning counts it from this day; empty counts it from the start. */
|
|
136
|
+
acquired_on: string | null;
|
|
137
|
+
/** The day CSC sold, scrapped, or gave it away. Planning stops counting it on this day. Empty while CSC still has it. */
|
|
138
|
+
disposed_on: string | null;
|
|
139
|
+
note: string | null;
|
|
140
|
+
}
|
|
117
141
|
/** Something a sync noticed but didn't fix. A dismissed finding stays dismissed on later runs. */
|
|
118
142
|
export interface AuditFindings {
|
|
119
143
|
id: string;
|
|
@@ -132,28 +156,22 @@ export interface AuditFindings {
|
|
|
132
156
|
export interface BoatClasses {
|
|
133
157
|
id: string;
|
|
134
158
|
name: string;
|
|
135
|
-
|
|
159
|
+
/** The most sailors one boat can safely take, such as 4 in an FJ. 0 for a coach boat. */
|
|
160
|
+
max_capacity: number;
|
|
136
161
|
/** Dry-storage area one boat takes. */
|
|
137
162
|
footprint_sq_ft: string | null;
|
|
163
|
+
/** Where the fuel and upkeep of CSC's own boats of the class are booked, such as Coach boats for a RIB. Empty books them to boat maintenance. */
|
|
164
|
+
account_id: string | Accounts | null;
|
|
138
165
|
}
|
|
139
|
-
/**
|
|
166
|
+
/** A boat's own details, sail or power: its class and sail number. Sailors' own boats aren't listed here. */
|
|
140
167
|
export interface Boats {
|
|
141
168
|
id: string;
|
|
169
|
+
/** The asset this boat is. Its kind must be Sailboat or Powerboat. */
|
|
170
|
+
asset_id: string | Assets;
|
|
171
|
+
/** Such as Opti, 420, or RIB. */
|
|
142
172
|
boat_class_id: string | BoatClasses;
|
|
143
|
-
/**
|
|
144
|
-
name: string | null;
|
|
173
|
+
/** A sailboat's, if it has one. */
|
|
145
174
|
sail_number: string | null;
|
|
146
|
-
/** The hull identification number on the transom, if it's known. */
|
|
147
|
-
hull_number: string | null;
|
|
148
|
-
/** What the boat is worth. In cents: 12500 is $125.00. */
|
|
149
|
-
value_cents: number | null;
|
|
150
|
-
/** The day CSC got the boat. */
|
|
151
|
-
acquired_on: string | null;
|
|
152
|
-
/** The day the boat first sailed in a program. */
|
|
153
|
-
in_service_on: string | null;
|
|
154
|
-
/** The day CSC stopped using the boat. Empty while it's still in use. */
|
|
155
|
-
retired_on: string | null;
|
|
156
|
-
note: string | null;
|
|
157
175
|
}
|
|
158
176
|
/** An offering of a program that plans and Clubspot both point to, such as "J-Pod · fall practices" or "Summer camp · week 3". Each Financial Plan sets its own price, schedule, and size for it, and Clubspot's offerings are linked to it. */
|
|
159
177
|
export interface CatalogOfferings {
|
|
@@ -557,20 +575,8 @@ export interface PlanBlockBoats {
|
|
|
557
575
|
count: number;
|
|
558
576
|
/** How many boats sailors bring. They cost nothing and don't count against the organization's. */
|
|
559
577
|
sailor_owned: number | null;
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
export interface PlanBlockResources {
|
|
563
|
-
id: string;
|
|
564
|
-
/** The version this row belongs to. */
|
|
565
|
-
version_id: string | PlanVersions;
|
|
566
|
-
/** Stays the same across versions. Copy it where another row asks for this one's Key. */
|
|
567
|
-
key: string;
|
|
568
|
-
block_id: string | PlanActivityBlocks;
|
|
569
|
-
/** The resource it uses: copy the Key from a resource in the Operations Plan. */
|
|
570
|
-
resource_key: string;
|
|
571
|
-
quantity: string;
|
|
572
|
-
/** Hours each is used. Leave it empty for the block's time on the water (RIBs) or its paid time (other equipment). */
|
|
573
|
-
hours: string | null;
|
|
578
|
+
/** How many boats of the class the block charters. They cost the class's charter rate for each day, and don't count against the organization's. */
|
|
579
|
+
chartered: number | null;
|
|
574
580
|
}
|
|
575
581
|
/** Who coaches a block: a number of staff at one staff level, or a salaried position. */
|
|
576
582
|
export interface PlanBlockStaff {
|
|
@@ -597,10 +603,12 @@ export interface PlanBoatRates {
|
|
|
597
603
|
/** Stays the same across versions. Copy it where another row asks for this one's Key. */
|
|
598
604
|
key: string;
|
|
599
605
|
boat_class_id: string | BoatClasses;
|
|
600
|
-
/** In cents: 12500 is $125.00. */
|
|
606
|
+
/** Upkeep for each hour one of CSC's boats of the class is on the water. In cents: 12500 is $125.00. */
|
|
601
607
|
maintenance_per_boat_hour_cents: number;
|
|
602
|
-
/**
|
|
603
|
-
|
|
608
|
+
/** Fuel for each hour one of CSC's boats of the class is on the water. In cents: 12500 is $125.00. */
|
|
609
|
+
fuel_per_hour_cents: number | null;
|
|
610
|
+
/** What one boat of the class costs to charter for a day. In cents: 12500 is $125.00. */
|
|
611
|
+
charter_per_day_cents: number | null;
|
|
604
612
|
}
|
|
605
613
|
/** The products a bonus owner owns. */
|
|
606
614
|
export interface PlanBonusOwnerProducts {
|
|
@@ -706,7 +714,8 @@ export interface PlanOfferings {
|
|
|
706
714
|
key: string;
|
|
707
715
|
product_id: string | Products;
|
|
708
716
|
name: string;
|
|
709
|
-
|
|
717
|
+
/** The term it runs in: copy the Key from a term in the Operations Plan. Leave it empty for an offering in no term. */
|
|
718
|
+
term_key: string | null;
|
|
710
719
|
starts_on: string;
|
|
711
720
|
ends_on: string;
|
|
712
721
|
capacity: number | null;
|
|
@@ -758,29 +767,6 @@ export interface PlanRates {
|
|
|
758
767
|
lodging_per_night_cents: number | null;
|
|
759
768
|
/** In cents: 12500 is $125.00. */
|
|
760
769
|
mileage_rate_cents: number | null;
|
|
761
|
-
/** The kind of resource whose cost prices coach boat (RIB) hours. */
|
|
762
|
-
rib_resource_kind_id: string | ResourceKinds | null;
|
|
763
|
-
}
|
|
764
|
-
/** Equipment programs share, such as coach boats, and what an hour or a day of it costs. */
|
|
765
|
-
export interface PlanResources {
|
|
766
|
-
id: string;
|
|
767
|
-
/** The version this row belongs to. */
|
|
768
|
-
version_id: string | PlanVersions;
|
|
769
|
-
/** Stays the same across versions. Copy it where another row asks for this one's Key. */
|
|
770
|
-
key: string;
|
|
771
|
-
resource_kind_id: string | ResourceKinds;
|
|
772
|
-
name: string;
|
|
773
|
-
quantity: number | null;
|
|
774
|
-
/** In cents: 12500 is $125.00. */
|
|
775
|
-
cost_per_hour_cents: number | null;
|
|
776
|
-
/** In cents: 12500 is $125.00. */
|
|
777
|
-
cost_per_day_cents: number | null;
|
|
778
|
-
/** In cents: 12500 is $125.00. */
|
|
779
|
-
fuel_per_hour_cents: number | null;
|
|
780
|
-
/** In cents: 12500 is $125.00. */
|
|
781
|
-
maintenance_per_hour_cents: number | null;
|
|
782
|
-
/** Set for a rental, whose cost is left out of modified total direct costs (MTDC). */
|
|
783
|
-
excluded_from_mtdc: boolean;
|
|
784
770
|
}
|
|
785
771
|
/** The capital list in rank order, in a Financial Plan, with what the year's money covers. A draft's are worked out again a moment after each change to it, and a saved one's when it's saved, and then never change. */
|
|
786
772
|
export interface PlanResultCapital {
|
|
@@ -971,6 +957,20 @@ export interface PlanStaffLevels {
|
|
|
971
957
|
/** In cents: 12500 is $125.00. */
|
|
972
958
|
hourly_rate_cents: number | null;
|
|
973
959
|
}
|
|
960
|
+
/** A planning period, such as Summer 2027, with its start and end dates. An offering in a Program Plan can be in one of its Financial Plan's terms. */
|
|
961
|
+
export interface PlanTerms {
|
|
962
|
+
id: string;
|
|
963
|
+
/** The version this row belongs to. */
|
|
964
|
+
version_id: string | PlanVersions;
|
|
965
|
+
/** Stays the same across versions. Copy it where another row asks for this one's Key. */
|
|
966
|
+
key: string;
|
|
967
|
+
/** What it's called, such as Summer 2027. */
|
|
968
|
+
name: string;
|
|
969
|
+
/** Its first day. */
|
|
970
|
+
starts_on: string;
|
|
971
|
+
/** Its last day. */
|
|
972
|
+
ends_on: string;
|
|
973
|
+
}
|
|
974
974
|
/** A trip an offering travels for, such as an away regatta. */
|
|
975
975
|
export interface PlanTrips {
|
|
976
976
|
id: string;
|
|
@@ -1105,11 +1105,6 @@ export interface Registrations {
|
|
|
1105
1105
|
status: "confirmed" | "waitlist" | "cancelled";
|
|
1106
1106
|
clubspot_entry_id: string | ClubspotRegistrationEntries;
|
|
1107
1107
|
}
|
|
1108
|
-
/** A kind of shared resource, such as RIB or trailer. */
|
|
1109
|
-
export interface ResourceKinds {
|
|
1110
|
-
id: string;
|
|
1111
|
-
name: string;
|
|
1112
|
-
}
|
|
1113
1108
|
/** The schools a sailor can sail for, which families pick from. A school's other names match what families typed on their Clubspot forms. */
|
|
1114
1109
|
export interface Schools {
|
|
1115
1110
|
id: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cyc-seattle/platform",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.50.0",
|
|
4
4
|
"description": "Pulumi components for CYC's shared Google Cloud platform: WebService, the platform outputs reader, and the stacks that build the platform",
|
|
5
5
|
"author": "CYC Community Sailing Center",
|
|
6
6
|
"license": "Apache-2.0",
|