@cyc-seattle/platform 1.30.0 → 1.32.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/README.md CHANGED
@@ -107,9 +107,11 @@ GitHub environment that holds its identity and state bucket:
107
107
  | Run by hand, from a branch | `ci`, then `dev` |
108
108
  | Run by hand, from `main` | `prod-preview`, then `prod` |
109
109
 
110
- Dev is shared, so only the merge queue deploys to it, one PR at a time (#69, #80). The queue
111
- requires `dev-passed`, so a PR merges only once its dev deploy and the integration tests pass, and
112
- `main` gets the exact commit the queue tested. A queued PR of only docs or CI skips `dev`. To try a
110
+ Dev is shared, so only the merge queue deploys to it (#69, #80). PRs queued together deploy and
111
+ test as one batch: each queued PR's run skips dev when a newer PR is queued behind it, and the newest
112
+ tests them all. The queue requires `dev-passed`, so a batch merges only once its dev deploy and the
113
+ integration tests pass, and `main` gets the exact commit the queue tested, in one push. If the
114
+ newest PR fails, the queue drops it and the rest of the batch deploys without it. A queued PR of only docs or CI skips `dev`. To try a
113
115
  branch on dev before queueing it, run `gh workflow run pull-request.yml --ref <branch>`.
114
116
 
115
117
  `prod-preview` runs `mise run preview` as `deploy-runner` and writes the diff to the job summary.
@@ -7,7 +7,7 @@ export function scheduleActivities(ctx) {
7
7
  const trips = new Map(ctx.data.plan_trips.map((t) => [t.id, t]));
8
8
  const closed = new Map();
9
9
  for (const c of ctx.data.plan_closed_dates ?? []) {
10
- // The club's closed days are the Operations Plan's, not an area's.
10
+ // The closed days are the Operations Plan's, not an area's.
11
11
  if (ctx.planOfVersion.get(c.version_id)?.kind === "program_area") {
12
12
  ctx.warn("closed_date_in_area_plan", `${c.name} is a closed day in a program area's plan, so it's ignored`, c.key);
13
13
  continue;
@@ -32,7 +32,7 @@ export function scheduleActivities(ctx) {
32
32
  const span = start !== null && end !== null ? end - start : 0;
33
33
  const closedFor = closed.get(activity.date);
34
34
  if (closedFor !== undefined && activity.kind !== "travel") {
35
- ctx.warn("closed_date", `${offering.name} has an activity on ${activity.date}, when the club is closed for ${closedFor}`, activity.key);
35
+ ctx.warn("closed_date", `${offering.name} has an activity on ${activity.date}, a closed day: ${closedFor}`, activity.key);
36
36
  }
37
37
  const usesBoats = activity.kind !== "travel" && activity.uses_boats;
38
38
  result.push({
@@ -66,14 +66,6 @@ function checkAreas(ctx) {
66
66
  ctx.warn("offering_in_wrong_plan", `Offering ${offering.name} of ${product.name} is in ${where}`, offering.key);
67
67
  }
68
68
  }
69
- const operations = new Set(ctx.data.plan_versions.filter((v) => ctx.planOfVersion.get(v.id)?.kind === "operations").map((v) => v.id));
70
- for (const version of ctx.data.plan_versions) {
71
- const pinned = version.operations_version_id;
72
- if (pinned == null || operations.size === 0 || operations.has(pinned))
73
- continue;
74
- const area = ctx.areas.get(ctx.planOfVersion.get(version.id)?.program_area_id ?? "");
75
- ctx.warn("other_operations_version", `${area?.name ?? "A program area"}'s plan was saved with a different Operations Plan version from the one it's calculated with`, version.id);
76
- }
77
69
  }
78
70
  /** Each salaried position's year: its salary, where its hours went, and its hourly wages and bonus. */
79
71
  function summarizePositions(ctx, coaching, charged, bonuses, doubleBooked) {
@@ -23,7 +23,7 @@ export interface Product {
23
23
  /** Every program has one; merchandise, storage and charters have none. */
24
24
  program_area_id: Id | null;
25
25
  }
26
- /** A part of the club's programs, such as Summer, with its revenue account. */
26
+ /** A part of the organization's programs, such as Summer, with its revenue account. */
27
27
  export interface ProgramArea {
28
28
  id: Id;
29
29
  name: string;
@@ -83,8 +83,6 @@ export interface Plan {
83
83
  export interface PlanVersion {
84
84
  id: Id;
85
85
  plan_id: Id;
86
- /** A saved area plan's: the Operations Plan version it was saved with. */
87
- operations_version_id?: Id | null;
88
86
  }
89
87
  export type ActivityKind = "practice" | "regatta" | "clinic" | "travel";
90
88
  export interface PlanOffering extends Versioned {
@@ -265,7 +263,7 @@ export interface PlanRevenueCharge extends Versioned {
265
263
  excluded_from_mtdc: boolean;
266
264
  note: string | null;
267
265
  }
268
- /** A day the club is closed, such as Labor Day. */
266
+ /** A day the organization is closed, such as Labor Day. */
269
267
  export interface PlanClosedDate extends Versioned {
270
268
  date: DateString;
271
269
  name: string;
@@ -3,6 +3,7 @@ export interface Schema {
3
3
  accounts: Accounts[];
4
4
  audit_findings: AuditFindings[];
5
5
  boat_classes: BoatClasses[];
6
+ catalog_offerings: CatalogOfferings[];
6
7
  clubspot_camps: ClubspotCamps[];
7
8
  clubspot_classes: ClubspotClasses[];
8
9
  clubspot_custom_field_definitions: ClubspotCustomFieldDefinitions[];
@@ -27,7 +28,6 @@ export interface Schema {
27
28
  organization_cost_accounts: OrganizationCostAccounts[];
28
29
  organizations: Organizations[];
29
30
  people: People[];
30
- plan_activations: PlanActivations[];
31
31
  plan_activities: PlanActivities[];
32
32
  plan_activity_block_rules: PlanActivityBlockRules[];
33
33
  plan_activity_resources: PlanActivityResources[];
@@ -45,7 +45,6 @@ export interface Schema {
45
45
  plan_result_lines: PlanResultLines[];
46
46
  plan_result_pnl: PlanResultPnl[];
47
47
  plan_result_positions: PlanResultPositions[];
48
- plan_result_versions: PlanResultVersions[];
49
48
  plan_result_warnings: PlanResultWarnings[];
50
49
  plan_results: PlanResults[];
51
50
  plan_revenue_charges: PlanRevenueCharges[];
@@ -67,6 +66,7 @@ export interface Schema {
67
66
  resource_kinds: ResourceKinds[];
68
67
  sync_runs: SyncRuns[];
69
68
  sync_tasks: SyncTasks[];
69
+ version_set_activations: VersionSetActivations[];
70
70
  version_set_members: VersionSetMembers[];
71
71
  version_sets: VersionSets[];
72
72
  }
@@ -109,6 +109,14 @@ export interface BoatClasses {
109
109
  /** Dry-storage area one boat takes. */
110
110
  footprint_sq_ft: string | null;
111
111
  }
112
+ /** 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. */
113
+ export interface CatalogOfferings {
114
+ id: string;
115
+ /** The program it's an offering of. */
116
+ program_id: string | Programs;
117
+ /** Which offering of the program, such as "fall practices" or "week 3". */
118
+ name: string;
119
+ }
112
120
  /** A dated event, such as a season's race team. Copied from Clubspot, so edit it there. */
113
121
  export interface ClubspotCamps {
114
122
  /** Clubspot's own ID for this row. */
@@ -339,6 +347,8 @@ export interface GoogleGroups {
339
347
  description: string | null;
340
348
  /** Set when the group no longer exists in Google Workspace, and cleared if it comes back. */
341
349
  archived: boolean;
350
+ /** The programs that use this group. */
351
+ programs: (string | Programs)[];
342
352
  }
343
353
  export interface GroupMembers {
344
354
  id: string;
@@ -433,18 +443,6 @@ export interface People {
433
443
  /** The person's own Directus login, if they have one. Usually empty. */
434
444
  directus_user_id: string | null;
435
445
  }
436
- /** Each time a saved version was made active. A plan's newest activation is its active version. */
437
- export interface PlanActivations {
438
- id: string;
439
- plan_id: string | Plans;
440
- /** A saved version of the plan. */
441
- version_id: string | PlanVersions;
442
- /** Set when the version is made active. */
443
- activated_at: string;
444
- activated_by: string | null;
445
- /** Set when the version is made active. The plan's active version is the one with the highest. */
446
- sequence: number;
447
- }
448
446
  /** One dated activity, such as a practice, a regatta day, or a travel day. */
449
447
  export interface PlanActivities {
450
448
  id: string;
@@ -549,7 +547,7 @@ export interface PlanBudgetLines {
549
547
  account_id: string | Accounts;
550
548
  function: "program" | "management" | "fundraising" | null;
551
549
  cost_center_type: "offering" | "product" | "program_area" | "pool" | "org";
552
- /** Who the cost is charged to: copy the Key from an offering or a pool, or a product's ID from the end of its page's web address. Leave empty for the whole club. */
550
+ /** Who the cost is charged to: copy the Key from an offering or a pool, or a product's ID from the end of its page's web address. Leave empty for the whole organization. */
553
551
  cost_center_key: string | null;
554
552
  /** In cents: 12500 is $125.00. */
555
553
  amount_cents: number;
@@ -558,7 +556,7 @@ export interface PlanBudgetLines {
558
556
  excluded_from_mtdc: boolean;
559
557
  note: string | null;
560
558
  }
561
- /** A day the club is closed, such as Labor Day. The P&L warns about an activity on one. */
559
+ /** A day the organization is closed, such as Labor Day. The P&L warns about an activity on one. */
562
560
  export interface PlanClosedDates {
563
561
  id: string;
564
562
  /** The version this row belongs to. */
@@ -578,7 +576,7 @@ export interface PlanLaborLines {
578
576
  key: string;
579
577
  name: string;
580
578
  cost_center_type: "offering" | "product" | "program_area" | "pool" | "org";
581
- /** Who the cost is charged to: copy the Key from an offering or a pool, or a product's ID from the end of its page's web address. Leave empty for the whole club. */
579
+ /** Who the cost is charged to: copy the Key from an offering or a pool, or a product's ID from the end of its page's web address. Leave empty for the whole organization. */
582
580
  cost_center_key: string | null;
583
581
  /** Who does the work: copy the Key from a staff level in the Operations Plan. */
584
582
  staff_level_key: string;
@@ -607,6 +605,8 @@ export interface PlanOfferings {
607
605
  /** Stays the same across versions. Copy it where another row asks for this one's Key. */
608
606
  key: string;
609
607
  product_id: string | Products;
608
+ /** Which of the program's catalog offerings this is, such as "J-Pod · fall practices". It's how Clubspot's sign-ups find it, in every Financial Plan. */
609
+ catalog_offering_id: string | CatalogOfferings | null;
610
610
  name: string;
611
611
  season_term: string | null;
612
612
  starts_on: string;
@@ -649,7 +649,7 @@ export interface PlanPools {
649
649
  key: string;
650
650
  name: string;
651
651
  }
652
- /** The year's rates. One row at most in each version. */
652
+ /** The year's rates. One row at most in each copy. */
653
653
  export interface PlanRates {
654
654
  id: string;
655
655
  /** The version this row belongs to. */
@@ -686,11 +686,9 @@ export interface PlanResources {
686
686
  /** Set for a rental, whose cost is left out of modified total direct costs (MTDC). */
687
687
  excluded_from_mtdc: boolean;
688
688
  }
689
- /** Each cost and revenue line in a saved version's P&L. Worked out when the version was saved, and never changed. */
689
+ /** Each cost and revenue line in a saved Financial Plan's P&L. Worked out when it was saved, and never changed. */
690
690
  export interface PlanResultLines {
691
691
  id: string;
692
- /** The saved version these results are for, if they aren't a club plan's. */
693
- version_id: string | PlanVersions | null;
694
692
  cost_center_type: "offering" | "product" | "program_area" | "pool" | "org";
695
693
  cost_center_key: string | null;
696
694
  cost_center_name: string;
@@ -701,18 +699,16 @@ export interface PlanResultLines {
701
699
  /** The engine's key for the line. */
702
700
  line: string;
703
701
  explanation: string | null;
704
- /** The club plan these results are for, if they aren't a version's. */
705
- version_set_id: string | VersionSets | null;
706
- /** In a club plan's results, the plan that holds what it's charged to. */
702
+ /** The Financial Plan these results are for. */
703
+ version_set_id: string | VersionSets;
704
+ /** The plan in the Financial Plan that holds what it's charged to. */
707
705
  version_set_member_id: string | VersionSetMembers | null;
708
706
  /** What the line is, in plain words, such as G&A share: Payroll tax. */
709
707
  line_name: string | null;
710
708
  }
711
- /** A saved version's P&L for each offering, product, and program area. Worked out when the version was saved, and never changed. */
709
+ /** A saved Financial Plan's P&L for each offering, product, and program area. Worked out when it was saved, and never changed. */
712
710
  export interface PlanResultPnl {
713
711
  id: string;
714
- /** The saved version these results are for, if they aren't a club plan's. */
715
- version_id: string | PlanVersions | null;
716
712
  level: "offering" | "product" | "program_area";
717
713
  subject_key: string;
718
714
  name: string;
@@ -727,16 +723,14 @@ export interface PlanResultPnl {
727
723
  enrollment: number;
728
724
  days: number;
729
725
  sailor_days: number;
730
- /** The club plan these results are for, if they aren't a version's. */
731
- version_set_id: string | VersionSets | null;
732
- /** In a club plan's results, the plan that holds what it's charged to. */
726
+ /** The Financial Plan these results are for. */
727
+ version_set_id: string | VersionSets;
728
+ /** The plan in the Financial Plan that holds what it's charged to. */
733
729
  version_set_member_id: string | VersionSetMembers | null;
734
730
  }
735
- /** Each salaried position's pay for the year, in a saved version. Worked out when the version was saved, and never changed. */
731
+ /** Each salaried position's pay for the year, in a saved Financial Plan. Worked out when it was saved, and never changed. */
736
732
  export interface PlanResultPositions {
737
733
  id: string;
738
- /** The saved version these results are for, if they aren't a club plan's. */
739
- version_id: string | PlanVersions | null;
740
734
  position_key: string;
741
735
  name: string;
742
736
  /** In cents: 12500 is $125.00. */
@@ -756,38 +750,26 @@ export interface PlanResultPositions {
756
750
  total_pay_cents: number;
757
751
  /** The year's payroll tax on the total pay. In cents: 12500 is $125.00. */
758
752
  payroll_tax_cents: number;
759
- /** The club plan these results are for, if they aren't a version's. */
760
- version_set_id: string | VersionSets | null;
753
+ /** The Financial Plan these results are for. */
754
+ version_set_id: string | VersionSets;
761
755
  /** Hours another coach would cover while this position coaches two or more groups at once: for three groups at once, two coaches. */
762
756
  double_booked_hours: string | null;
763
757
  /** Dates this position coaches two or more groups at once. */
764
758
  double_booked_dates: number | null;
765
759
  }
766
- /** The other saved versions a version's results were worked out with. Worked out when the version was saved, and never changed. */
767
- export interface PlanResultVersions {
768
- id: string;
769
- /** The saved version these results are for. */
770
- version_id: string | PlanVersions;
771
- /** Another saved version in the club's plan when this one was saved. */
772
- calculated_with_id: string | PlanVersions;
773
- }
774
- /** What the P&L warned about when a version was saved. Worked out when the version was saved, and never changed. */
760
+ /** What the P&L warned about when a Financial Plan was saved. Worked out when it was saved, and never changed. */
775
761
  export interface PlanResultWarnings {
776
762
  id: string;
777
- /** The saved version these results are for, if they aren't a club plan's. */
778
- version_id: string | PlanVersions | null;
779
763
  /** The kind of warning. */
780
764
  code: string;
781
765
  message: string;
782
766
  subject_key: string | null;
783
- /** The club plan these results are for, if they aren't a version's. */
784
- version_set_id: string | VersionSets | null;
767
+ /** The Financial Plan these results are for. */
768
+ version_set_id: string | VersionSets;
785
769
  }
786
- /** A saved version's club-wide totals. Worked out when the version was saved, and never changed. */
770
+ /** A saved Financial Plan's totals for the organization. Worked out when it was saved, and never changed. */
787
771
  export interface PlanResults {
788
772
  id: string;
789
- /** The saved version these results are for, if they aren't a club plan's. */
790
- version_id: string | PlanVersions | null;
791
773
  calculated_at: string;
792
774
  /** In cents: 12500 is $125.00. */
793
775
  operating_revenue_cents: number;
@@ -805,8 +787,8 @@ export interface PlanResults {
805
787
  capital_cents: number;
806
788
  /** Operating net, plus fundraising net, less capital. In cents: 12500 is $125.00. */
807
789
  total_cents: number;
808
- /** The club plan these results are for, if they aren't a version's. */
809
- version_set_id: string | VersionSets | null;
790
+ /** The Financial Plan these results are for. */
791
+ version_set_id: string | VersionSets;
810
792
  }
811
793
  /** A charge set as a share of each offering's revenue, such as scholarships or card fees. Operations Plan only. */
812
794
  export interface PlanRevenueCharges {
@@ -890,43 +872,39 @@ export interface PlanTrips {
890
872
  airfare_cents: number | null;
891
873
  miles: number | null;
892
874
  }
893
- /** A plan's draft, or a version saved from it, which never changes. */
875
+ /** One plan's copy in one Financial Plan, with every row it holds. It's saved with its Financial Plan, and then never changes. */
894
876
  export interface PlanVersions {
895
877
  id: string;
896
878
  plan_id: string | Plans;
897
- /** The saved version this draft started from. */
879
+ /** The copy this one was made from, in the Financial Plan this one's started from. */
898
880
  parent_version_id: string | PlanVersions | null;
899
- /** Saving a draft sets this to saved. A saved version never changes, even for an admin. */
881
+ /** Saved with its Financial Plan. A saved copy never changes, even for an admin. */
900
882
  status: "draft" | "saved";
901
883
  /** What changed in this version. */
902
884
  message: string | null;
903
- /** Set when the version is saved. */
885
+ /** Set when its Financial Plan is saved. */
904
886
  saved_by: string | null;
905
- /** Set when the version is saved. */
887
+ /** Set when its Financial Plan is saved. */
906
888
  saved_at: string | null;
907
889
  /** The version of the planning engine that calculated its numbers. Required to save. */
908
890
  platform_version: string | null;
909
- /** For a program area's plan: the saved Operations Plan version its numbers were calculated with, for the same organization and year. Required to save. Empty for the Operations Plan. */
910
- operations_version_id: string | PlanVersions | null;
911
891
  /** What you want that the plan's numbers don't capture, for your AI to fill in. For example: every Monday, Wednesday and Friday, except on SPS school holidays, from 4pm until dusk. */
912
892
  rules: string | null;
913
- /** What the P&L showed when this version was saved, worked out a moment after it's saved. A saved version with none means working them out failed, and an admin can fill them in. */
914
- results: (string | PlanResults)[];
915
893
  }
916
- /** One part of the club's plan: a program area's plan, or the Operations Plan. */
894
+ /** One part of a Financial Plan: a program area's Program Plan, or the Operations Plan. */
917
895
  export interface Plans {
918
896
  id: string;
919
897
  kind: "program_area" | "operations";
920
898
  /** The program area the plan is for. Empty for the Operations Plan. */
921
899
  program_area_id: string | ProgramAreas | null;
922
- /** The organization the plan is for. Can't change once the plan has a saved version. */
900
+ /** The organization the plan is for. Can't change once the plan has a saved copy. */
923
901
  organization_id: string | Organizations;
924
- /** The plan year. Fiscal year N ends in calendar year N. Can't change once the plan has a saved version. */
902
+ /** The plan year. Fiscal year N ends in calendar year N. Can't change once the plan has a saved copy. */
925
903
  fiscal_year: number;
926
904
  name: string;
927
- /** A plan with a saved version can't be deleted, so archive it instead. */
905
+ /** A plan with a saved copy can't be deleted, so archive it instead. */
928
906
  archived: boolean;
929
- /** The plan's draft and saved versions. */
907
+ /** The plan's copy in each Financial Plan. */
930
908
  versions: (string | PlanVersions)[];
931
909
  }
932
910
  /** A lasting thing the club sells. A program also has a row in Programs. */
@@ -1052,33 +1030,49 @@ export interface SyncTasks {
1052
1030
  /** Set once the task has failed too many times. It keeps retrying; this flags it for staff. */
1053
1031
  needs_attention: boolean;
1054
1032
  }
1055
- /** One plan's version in a club plan. Set when the club plan is saved, and never changed. */
1033
+ /** Each time a saved Financial Plan was marked active. The newest one for an organization and year is the active one. */
1034
+ export interface VersionSetActivations {
1035
+ id: string;
1036
+ /** A saved Financial Plan. */
1037
+ version_set_id: string | VersionSets;
1038
+ /** Set when it's marked active. */
1039
+ activated_at: string | null;
1040
+ activated_by: string | null;
1041
+ /** Set when it's marked active. The active Financial Plan for a year is the one with the highest. */
1042
+ sequence: number;
1043
+ }
1044
+ /** One plan in a Financial Plan: the copy of the plan it holds. Add or remove one only while the Financial Plan is a draft. */
1056
1045
  export interface VersionSetMembers {
1057
1046
  id: string;
1058
1047
  version_set_id: string | VersionSets;
1059
- plan_id: string | Plans;
1060
- /** The plan's active version when the club plan was saved. */
1048
+ /** Filled in from the plan copy. */
1049
+ plan_id: string | Plans | null;
1050
+ /** The plan's copy in this Financial Plan. It's in no other Financial Plan. */
1061
1051
  version_id: string | PlanVersions;
1062
1052
  }
1063
- /** The club's plan for a year, saved: the active Operations Plan version and each program area's, with the P&L they make together. Saved when it's added, and never changed. */
1053
+ /** The organization's plan for a year: one Operations Plan, and a Program Plan for any of the program areas, with the P&L they make together. Change its plans while it's a draft. Saving it saves them all, and then it never changes, apart from its note. Pick a parent when you add one, and its plans are copied in. */
1064
1054
  export interface VersionSets {
1065
1055
  id: string;
1066
- /** The organization the club plan is for. */
1056
+ /** The organization the Financial Plan is for. */
1067
1057
  organization_id: string | Organizations;
1068
- /** The year the club plan is for. */
1058
+ /** The year the Financial Plan is for. */
1069
1059
  fiscal_year: number;
1070
1060
  /** Such as 2027 budget as adopted. */
1071
1061
  name: string;
1072
- /** Why it was saved. */
1062
+ /** What it was for, such as "Reviewed with the board". You can change it after it's saved. */
1073
1063
  message: string | null;
1074
- /** Set when the club plan is saved. */
1064
+ /** Set it to saved to save the Financial Plan and all its plans. A saved Financial Plan never changes, apart from its note. */
1065
+ status: "draft" | "saved";
1066
+ /** The Financial Plan this one started as a copy of. Pick it when you add this one, and its plans are copied in. */
1067
+ parent_id: string | VersionSets | null;
1068
+ /** Set when the Financial Plan is saved. */
1075
1069
  saved_by: string | null;
1076
- /** Set when the club plan is saved. */
1070
+ /** Set when the Financial Plan is saved. */
1077
1071
  saved_at: string | null;
1078
1072
  /** The version of the planning engine that calculated its numbers. */
1079
1073
  platform_version: string | null;
1080
- /** The active version of each plan when the club plan was saved. */
1074
+ /** Each plan in the Financial Plan. Add or remove one only while it's a draft. */
1081
1075
  members: (string | VersionSetMembers)[];
1082
- /** What the club's P&L showed when it was saved, worked out a moment after. A club plan with none means working them out failed, and an admin can fill them in. */
1076
+ /** What the organization's P&L showed when it was saved, worked out a moment after. A Financial Plan with none means working them out failed, and an admin can fill them in. */
1083
1077
  results: (string | PlanResults)[];
1084
1078
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cyc-seattle/platform",
3
- "version": "1.30.0",
3
+ "version": "1.32.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",