@substrat-run/engine-absence 0.0.0 → 0.1.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/index.d.ts +313 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +645 -0
- package/dist/index.js.map +1 -0
- package/package.json +12 -12
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type EntityRef } from '@substrat-run/contracts';
|
|
3
|
+
import { type ModuleRegistration, type OperationContext } from '@substrat-run/kernel';
|
|
4
|
+
export declare const PERM: {
|
|
5
|
+
read: string & z.$brand<"PermissionKey">;
|
|
6
|
+
request: string & z.$brand<"PermissionKey">;
|
|
7
|
+
approve: string & z.$brand<"PermissionKey">;
|
|
8
|
+
configure: string & z.$brand<"PermissionKey">;
|
|
9
|
+
};
|
|
10
|
+
export declare const absenceManifest: {
|
|
11
|
+
id: string & z.$brand<"ModuleId">;
|
|
12
|
+
version: string;
|
|
13
|
+
kernelContract: string;
|
|
14
|
+
permissions: {
|
|
15
|
+
key: string & z.$brand<"PermissionKey">;
|
|
16
|
+
description: string;
|
|
17
|
+
}[];
|
|
18
|
+
events: {
|
|
19
|
+
emits: {
|
|
20
|
+
type: string;
|
|
21
|
+
schemaVersion: number;
|
|
22
|
+
}[];
|
|
23
|
+
consumes: {
|
|
24
|
+
type: string;
|
|
25
|
+
schemaVersion: number;
|
|
26
|
+
}[];
|
|
27
|
+
};
|
|
28
|
+
migrations: {
|
|
29
|
+
journalDir: string;
|
|
30
|
+
compatibleFrom: string;
|
|
31
|
+
};
|
|
32
|
+
attachmentTargets: {
|
|
33
|
+
entityType: string;
|
|
34
|
+
readPermission: string & z.$brand<"PermissionKey">;
|
|
35
|
+
writePermission?: (string & z.$brand<"PermissionKey">) | undefined;
|
|
36
|
+
}[];
|
|
37
|
+
entityRelations?: {
|
|
38
|
+
entityType: string;
|
|
39
|
+
parentType: string;
|
|
40
|
+
}[] | undefined;
|
|
41
|
+
guards?: {
|
|
42
|
+
before: string;
|
|
43
|
+
predicate: string;
|
|
44
|
+
config: Record<string, unknown>;
|
|
45
|
+
}[] | undefined;
|
|
46
|
+
schedules?: {
|
|
47
|
+
operation: string;
|
|
48
|
+
cadence: {
|
|
49
|
+
everyMinutes: number;
|
|
50
|
+
};
|
|
51
|
+
input?: Record<string, unknown> | undefined;
|
|
52
|
+
permissions: (string & z.$brand<"PermissionKey">)[];
|
|
53
|
+
}[] | undefined;
|
|
54
|
+
withdraws?: string[] | undefined;
|
|
55
|
+
entitlementKey: string;
|
|
56
|
+
envSpec?: {
|
|
57
|
+
key: string;
|
|
58
|
+
label?: string | undefined;
|
|
59
|
+
description: string;
|
|
60
|
+
placeholder?: string | undefined;
|
|
61
|
+
required: boolean;
|
|
62
|
+
secret: boolean;
|
|
63
|
+
default?: string | undefined;
|
|
64
|
+
group?: string | undefined;
|
|
65
|
+
}[] | undefined;
|
|
66
|
+
ownerGrants?: (string & z.$brand<"PermissionKey">)[] | undefined;
|
|
67
|
+
entitlements?: string[] | undefined;
|
|
68
|
+
provides?: string[] | undefined;
|
|
69
|
+
requires?: string[] | undefined;
|
|
70
|
+
api?: string | undefined;
|
|
71
|
+
searchables?: {
|
|
72
|
+
entityType: string;
|
|
73
|
+
fields: string[];
|
|
74
|
+
}[] | undefined;
|
|
75
|
+
ui?: {
|
|
76
|
+
routes?: {
|
|
77
|
+
path: string;
|
|
78
|
+
screen: string;
|
|
79
|
+
permission: string & z.$brand<"PermissionKey">;
|
|
80
|
+
}[] | undefined;
|
|
81
|
+
nav?: {
|
|
82
|
+
label: string;
|
|
83
|
+
icon?: string | undefined;
|
|
84
|
+
to: string;
|
|
85
|
+
permission: string & z.$brand<"PermissionKey">;
|
|
86
|
+
}[] | undefined;
|
|
87
|
+
entityViews?: {
|
|
88
|
+
entityType: string;
|
|
89
|
+
view: string;
|
|
90
|
+
}[] | undefined;
|
|
91
|
+
widgets?: {
|
|
92
|
+
slot: string;
|
|
93
|
+
component: string;
|
|
94
|
+
permission: string & z.$brand<"PermissionKey">;
|
|
95
|
+
}[] | undefined;
|
|
96
|
+
settingsPanels?: {
|
|
97
|
+
label: string;
|
|
98
|
+
component: string;
|
|
99
|
+
permission: string & z.$brand<"PermissionKey">;
|
|
100
|
+
}[] | undefined;
|
|
101
|
+
} | undefined;
|
|
102
|
+
};
|
|
103
|
+
export declare const absenceMigrations: {
|
|
104
|
+
version: string;
|
|
105
|
+
sql: string;
|
|
106
|
+
}[];
|
|
107
|
+
/** Every write names its subject: the vertical's opaque noun + the erasure key. */
|
|
108
|
+
export declare const absenceSubject: z.ZodObject<{
|
|
109
|
+
ref: z.ZodObject<{
|
|
110
|
+
entityType: z.ZodString;
|
|
111
|
+
entityId: z.ZodString;
|
|
112
|
+
}, z.core.$strip>;
|
|
113
|
+
dataSubjectId: z.core.$ZodBranded<z.ZodString, "DataSubjectId", "out">;
|
|
114
|
+
}, z.core.$strip>;
|
|
115
|
+
export type AbsenceSubject = z.infer<typeof absenceSubject>;
|
|
116
|
+
export interface LeaveType {
|
|
117
|
+
key: string;
|
|
118
|
+
floor: string;
|
|
119
|
+
active: boolean;
|
|
120
|
+
createdAt: string;
|
|
121
|
+
}
|
|
122
|
+
interface EntryRow {
|
|
123
|
+
id: string;
|
|
124
|
+
subject_type: string;
|
|
125
|
+
subject_id: string;
|
|
126
|
+
data_subject_id: string;
|
|
127
|
+
leave_type_key: string;
|
|
128
|
+
entry_kind: 'accrual' | 'booking' | 'correction' | 'carryover' | 'reversal';
|
|
129
|
+
delta: string;
|
|
130
|
+
effective_date: string;
|
|
131
|
+
request_id: string | null;
|
|
132
|
+
note: string | null;
|
|
133
|
+
created_by: string;
|
|
134
|
+
created_at: string;
|
|
135
|
+
}
|
|
136
|
+
export interface AbsenceEntry {
|
|
137
|
+
id: string;
|
|
138
|
+
subject: EntityRef;
|
|
139
|
+
leaveTypeKey: string;
|
|
140
|
+
entryKind: EntryRow['entry_kind'];
|
|
141
|
+
delta: string;
|
|
142
|
+
effectiveDate: string;
|
|
143
|
+
requestId: string | null;
|
|
144
|
+
note: string | null;
|
|
145
|
+
createdBy: string;
|
|
146
|
+
createdAt: string;
|
|
147
|
+
}
|
|
148
|
+
interface RequestRow {
|
|
149
|
+
id: string;
|
|
150
|
+
subject_type: string;
|
|
151
|
+
subject_id: string;
|
|
152
|
+
data_subject_id: string;
|
|
153
|
+
leave_type_key: string;
|
|
154
|
+
start_date: string;
|
|
155
|
+
end_date: string;
|
|
156
|
+
days: string;
|
|
157
|
+
status: 'requested' | 'approved' | 'rejected' | 'cancelled';
|
|
158
|
+
note: string | null;
|
|
159
|
+
decided_by: string | null;
|
|
160
|
+
decided_at: string | null;
|
|
161
|
+
created_by: string;
|
|
162
|
+
created_at: string;
|
|
163
|
+
}
|
|
164
|
+
export interface AbsenceRequest {
|
|
165
|
+
id: string;
|
|
166
|
+
subject: EntityRef;
|
|
167
|
+
leaveTypeKey: string;
|
|
168
|
+
startDate: string;
|
|
169
|
+
endDate: string;
|
|
170
|
+
days: string;
|
|
171
|
+
status: RequestRow['status'];
|
|
172
|
+
note: string | null;
|
|
173
|
+
decidedBy: string | null;
|
|
174
|
+
decidedAt: string | null;
|
|
175
|
+
createdBy: string;
|
|
176
|
+
createdAt: string;
|
|
177
|
+
}
|
|
178
|
+
export declare const configureLeaveTypeInput: z.ZodObject<{
|
|
179
|
+
key: z.ZodString;
|
|
180
|
+
floor: z.ZodOptional<z.ZodString>;
|
|
181
|
+
active: z.ZodOptional<z.ZodBoolean>;
|
|
182
|
+
}, z.core.$strip>;
|
|
183
|
+
export type ConfigureLeaveTypeInput = z.infer<typeof configureLeaveTypeInput>;
|
|
184
|
+
export declare function configureLeaveType(ctx: OperationContext, rawInput: ConfigureLeaveTypeInput): LeaveType;
|
|
185
|
+
export declare function listLeaveTypes(ctx: OperationContext): LeaveType[];
|
|
186
|
+
/**
|
|
187
|
+
* The one write that bypasses the request flow, restricted to accrual /
|
|
188
|
+
* correction / carryover — 'booking' and 'reversal' are mintable only through
|
|
189
|
+
* decideAbsence/cancelAbsence, which is what makes "only an approved request
|
|
190
|
+
* touches the ledger" a construction rather than a convention.
|
|
191
|
+
*
|
|
192
|
+
* No floor check here: a correction is the administrator's escape hatch, and
|
|
193
|
+
* accrual/carryover only ever add. The floor guards bookings (D-D).
|
|
194
|
+
*/
|
|
195
|
+
export declare const recordEntryInput: z.ZodObject<{
|
|
196
|
+
subject: z.ZodObject<{
|
|
197
|
+
ref: z.ZodObject<{
|
|
198
|
+
entityType: z.ZodString;
|
|
199
|
+
entityId: z.ZodString;
|
|
200
|
+
}, z.core.$strip>;
|
|
201
|
+
dataSubjectId: z.core.$ZodBranded<z.ZodString, "DataSubjectId", "out">;
|
|
202
|
+
}, z.core.$strip>;
|
|
203
|
+
leaveTypeKey: z.ZodString;
|
|
204
|
+
entryKind: z.ZodEnum<{
|
|
205
|
+
accrual: "accrual";
|
|
206
|
+
carryover: "carryover";
|
|
207
|
+
correction: "correction";
|
|
208
|
+
}>;
|
|
209
|
+
delta: z.ZodString;
|
|
210
|
+
effectiveDate: z.ZodString;
|
|
211
|
+
note: z.ZodOptional<z.ZodString>;
|
|
212
|
+
}, z.core.$strip>;
|
|
213
|
+
export type RecordEntryInput = z.infer<typeof recordEntryInput>;
|
|
214
|
+
export declare function recordEntry(ctx: OperationContext, rawInput: RecordEntryInput): AbsenceEntry;
|
|
215
|
+
/** Balance = pure fold over entries with effective_date <= asOf. No counter exists. */
|
|
216
|
+
export declare function balanceAsOf(ctx: OperationContext, input: {
|
|
217
|
+
subject: EntityRef;
|
|
218
|
+
leaveTypeKey: string;
|
|
219
|
+
asOf?: string;
|
|
220
|
+
}): string;
|
|
221
|
+
export declare const requestAbsenceInput: z.ZodObject<{
|
|
222
|
+
subject: z.ZodObject<{
|
|
223
|
+
ref: z.ZodObject<{
|
|
224
|
+
entityType: z.ZodString;
|
|
225
|
+
entityId: z.ZodString;
|
|
226
|
+
}, z.core.$strip>;
|
|
227
|
+
dataSubjectId: z.core.$ZodBranded<z.ZodString, "DataSubjectId", "out">;
|
|
228
|
+
}, z.core.$strip>;
|
|
229
|
+
leaveTypeKey: z.ZodString;
|
|
230
|
+
startDate: z.ZodString;
|
|
231
|
+
endDate: z.ZodString;
|
|
232
|
+
days: z.ZodString;
|
|
233
|
+
note: z.ZodOptional<z.ZodString>;
|
|
234
|
+
}, z.core.$strip>;
|
|
235
|
+
export type RequestAbsenceInput = z.infer<typeof requestAbsenceInput>;
|
|
236
|
+
export declare function requestAbsence(ctx: OperationContext, rawInput: RequestAbsenceInput): AbsenceRequest;
|
|
237
|
+
export declare const decideAbsenceInput: z.ZodObject<{
|
|
238
|
+
requestId: z.ZodString;
|
|
239
|
+
decision: z.ZodEnum<{
|
|
240
|
+
approve: "approve";
|
|
241
|
+
reject: "reject";
|
|
242
|
+
}>;
|
|
243
|
+
note: z.ZodOptional<z.ZodString>;
|
|
244
|
+
}, z.core.$strip>;
|
|
245
|
+
export type DecideAbsenceInput = z.infer<typeof decideAbsenceInput>;
|
|
246
|
+
export declare function decideAbsence(ctx: OperationContext, rawInput: DecideAbsenceInput): {
|
|
247
|
+
request: AbsenceRequest;
|
|
248
|
+
booking: AbsenceEntry | null;
|
|
249
|
+
};
|
|
250
|
+
/**
|
|
251
|
+
* requested → cancelled (withdraw; no ledger touch), or approved → cancelled
|
|
252
|
+
* with a COMPENSATING reversal entry — "Hugo came back" is a new entry, never
|
|
253
|
+
* an edit (D-E). Rejected/cancelled rows are terminal.
|
|
254
|
+
*/
|
|
255
|
+
export declare const cancelAbsenceInput: z.ZodObject<{
|
|
256
|
+
requestId: z.ZodString;
|
|
257
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
258
|
+
}, z.core.$strip>;
|
|
259
|
+
export type CancelAbsenceInput = z.infer<typeof cancelAbsenceInput>;
|
|
260
|
+
export declare function cancelAbsence(ctx: OperationContext, rawInput: CancelAbsenceInput): {
|
|
261
|
+
request: AbsenceRequest;
|
|
262
|
+
reversal: AbsenceEntry | null;
|
|
263
|
+
};
|
|
264
|
+
/**
|
|
265
|
+
* A DATE-TRIGGERED rule with no caller but the passage of time (#383): a
|
|
266
|
+
* request still 'requested' once its start date has passed can no longer be
|
|
267
|
+
* approved, so the platform sweep cancels it — attributed to the schedule
|
|
268
|
+
* (`{ system }`), never to a manager who never touched it. Idempotent (only
|
|
269
|
+
* 'requested' rows past their start) and paged (a bounded batch per pass).
|
|
270
|
+
*/
|
|
271
|
+
export declare function expireStaleRequests(ctx: OperationContext): {
|
|
272
|
+
expired: number;
|
|
273
|
+
};
|
|
274
|
+
export declare function listRequests(ctx: OperationContext, input?: {
|
|
275
|
+
subject?: EntityRef;
|
|
276
|
+
status?: RequestRow['status'];
|
|
277
|
+
}): AbsenceRequest[];
|
|
278
|
+
export declare function listEntries(ctx: OperationContext, input: {
|
|
279
|
+
subject: EntityRef;
|
|
280
|
+
leaveTypeKey?: string;
|
|
281
|
+
}): AbsenceEntry[];
|
|
282
|
+
/**
|
|
283
|
+
* Cross-subject window read — the payroll/export composition: "all bookings in
|
|
284
|
+
* this pay period", regardless of subject. In-scope only (no default binding):
|
|
285
|
+
* the callers are vertical exports that hold their own permission gate.
|
|
286
|
+
*/
|
|
287
|
+
export declare function entriesInWindow(ctx: OperationContext, input: {
|
|
288
|
+
from: string;
|
|
289
|
+
to: string;
|
|
290
|
+
entryKind?: EntryRow['entry_kind'];
|
|
291
|
+
}): AbsenceEntry[];
|
|
292
|
+
export interface AbsenceDay {
|
|
293
|
+
date: string;
|
|
294
|
+
leaveTypeKey: string;
|
|
295
|
+
requestId: string;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* The planner's read (D-C): every calendar day in an APPROVED request's
|
|
299
|
+
* inclusive range, clamped to [from, to]. The verdict is "an approved absence
|
|
300
|
+
* covers this date" — the engine does not know weekends or red days; the
|
|
301
|
+
* vertical composes this with its own holiday calendar.
|
|
302
|
+
*/
|
|
303
|
+
export declare function availability(ctx: OperationContext, input: {
|
|
304
|
+
subject: EntityRef;
|
|
305
|
+
from: string;
|
|
306
|
+
to: string;
|
|
307
|
+
}): {
|
|
308
|
+
days: AbsenceDay[];
|
|
309
|
+
requests: AbsenceRequest[];
|
|
310
|
+
};
|
|
311
|
+
export declare const absenceModule: ModuleRegistration;
|
|
312
|
+
export {};
|
|
313
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,645 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { addDecimal, compareDecimal, dataSubjectId, entityRef, moduleManifest, permissionKey, } from '@substrat-run/contracts';
|
|
3
|
+
import { assertAllowed, ulid, } from '@substrat-run/kernel';
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// The absence engine (docs/design/engine-absence.md). Owns an APPEND-ONLY entry
|
|
6
|
+
// ledger over an OPAQUE subject ref, balance-as-of-date as a pure fold, a
|
|
7
|
+
// per-leave-type balance floor, and the approval state machine that is the only
|
|
8
|
+
// mint for 'booking' and 'reversal' entries.
|
|
9
|
+
//
|
|
10
|
+
// It knows NOTHING about who a subject is (the vertical owns the directory),
|
|
11
|
+
// nor about weekends, red days, holiday calendars, accrual formulas, carryover
|
|
12
|
+
// caps, or what 'vab' means — all vertical policy. The `days` decimal on a
|
|
13
|
+
// request is vertical-computed; the engine folds it, it never derives it.
|
|
14
|
+
// Dates are calendar days, INCLUSIVE on both ends (absence is day-shaped) —
|
|
15
|
+
// deliberately unlike engine-booking's half-open instants.
|
|
16
|
+
// ============================================================================
|
|
17
|
+
export const PERM = {
|
|
18
|
+
read: permissionKey.parse('absence:read'),
|
|
19
|
+
request: permissionKey.parse('absence:request'),
|
|
20
|
+
approve: permissionKey.parse('absence:approve'),
|
|
21
|
+
configure: permissionKey.parse('absence:configure'),
|
|
22
|
+
};
|
|
23
|
+
export const absenceManifest = moduleManifest.parse({
|
|
24
|
+
id: '@substrat-run/engine-absence',
|
|
25
|
+
version: '0.0.1',
|
|
26
|
+
kernelContract: '^0.0.1',
|
|
27
|
+
permissions: [
|
|
28
|
+
{ key: 'absence:read', description: 'Read balances, requests, entries and availability' },
|
|
29
|
+
{ key: 'absence:request', description: 'Request absence (entity-narrowed: for one subject)' },
|
|
30
|
+
{ key: 'absence:approve', description: 'Decide requests; cancel an approved absence' },
|
|
31
|
+
{ key: 'absence:configure', description: 'Configure leave types; record accrual/correction/carryover entries' },
|
|
32
|
+
],
|
|
33
|
+
events: {
|
|
34
|
+
emits: [
|
|
35
|
+
{ type: 'absence.leave-type-configured', schemaVersion: 1 },
|
|
36
|
+
{ type: 'absence.entry-recorded', schemaVersion: 1 },
|
|
37
|
+
{ type: 'absence.requested', schemaVersion: 1 },
|
|
38
|
+
{ type: 'absence.decided', schemaVersion: 1 },
|
|
39
|
+
{ type: 'absence.cancelled', schemaVersion: 1 },
|
|
40
|
+
{ type: 'absence.expired', schemaVersion: 1 },
|
|
41
|
+
],
|
|
42
|
+
consumes: [],
|
|
43
|
+
},
|
|
44
|
+
migrations: { journalDir: './migrations', compatibleFrom: '0.0.1' },
|
|
45
|
+
attachmentTargets: [],
|
|
46
|
+
entityRelations: [],
|
|
47
|
+
entitlementKey: 'absence',
|
|
48
|
+
// A request still 'requested' past its start date can no longer be approved —
|
|
49
|
+
// a date-triggered rule (#383): the sweep cancels it under the system actor,
|
|
50
|
+
// never under a manager who never touched it.
|
|
51
|
+
schedules: [
|
|
52
|
+
{
|
|
53
|
+
operation: 'absence/expire-stale',
|
|
54
|
+
cadence: { everyMinutes: 1440 },
|
|
55
|
+
permissions: ['absence:approve'],
|
|
56
|
+
},
|
|
57
|
+
],
|
|
58
|
+
});
|
|
59
|
+
export const absenceMigrations = [
|
|
60
|
+
{
|
|
61
|
+
version: '0001-init',
|
|
62
|
+
sql: `
|
|
63
|
+
CREATE TABLE absence_leave_types (
|
|
64
|
+
key TEXT PRIMARY KEY,
|
|
65
|
+
floor TEXT NOT NULL DEFAULT '0',
|
|
66
|
+
active INTEGER NOT NULL DEFAULT 1,
|
|
67
|
+
created_at TEXT NOT NULL
|
|
68
|
+
);
|
|
69
|
+
CREATE TABLE absence_ledger (
|
|
70
|
+
id TEXT PRIMARY KEY,
|
|
71
|
+
subject_type TEXT NOT NULL,
|
|
72
|
+
subject_id TEXT NOT NULL,
|
|
73
|
+
data_subject_id TEXT NOT NULL,
|
|
74
|
+
leave_type_key TEXT NOT NULL,
|
|
75
|
+
entry_kind TEXT NOT NULL CHECK (entry_kind IN
|
|
76
|
+
('accrual','booking','correction','carryover','reversal')),
|
|
77
|
+
delta TEXT NOT NULL,
|
|
78
|
+
effective_date TEXT NOT NULL,
|
|
79
|
+
request_id TEXT,
|
|
80
|
+
note TEXT,
|
|
81
|
+
created_by TEXT NOT NULL,
|
|
82
|
+
created_at TEXT NOT NULL
|
|
83
|
+
);
|
|
84
|
+
CREATE TABLE absence_requests (
|
|
85
|
+
id TEXT PRIMARY KEY,
|
|
86
|
+
subject_type TEXT NOT NULL,
|
|
87
|
+
subject_id TEXT NOT NULL,
|
|
88
|
+
data_subject_id TEXT NOT NULL,
|
|
89
|
+
leave_type_key TEXT NOT NULL,
|
|
90
|
+
start_date TEXT NOT NULL,
|
|
91
|
+
end_date TEXT NOT NULL,
|
|
92
|
+
days TEXT NOT NULL,
|
|
93
|
+
status TEXT NOT NULL CHECK (status IN
|
|
94
|
+
('requested','approved','rejected','cancelled')),
|
|
95
|
+
note TEXT,
|
|
96
|
+
decided_by TEXT,
|
|
97
|
+
decided_at TEXT,
|
|
98
|
+
created_by TEXT NOT NULL,
|
|
99
|
+
created_at TEXT NOT NULL
|
|
100
|
+
);
|
|
101
|
+
`,
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Schemas & shapes
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
const isoDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, 'must be YYYY-MM-DD');
|
|
108
|
+
const posDecimal = z.string().regex(/^\d+(\.\d{1,6})?$/, 'must be a non-negative decimal');
|
|
109
|
+
const signedDecimal = z.string().regex(/^-?\d+(\.\d{1,6})?$/, 'must be a decimal');
|
|
110
|
+
/** Every write names its subject: the vertical's opaque noun + the erasure key. */
|
|
111
|
+
export const absenceSubject = z.object({
|
|
112
|
+
ref: entityRef,
|
|
113
|
+
dataSubjectId,
|
|
114
|
+
});
|
|
115
|
+
const toEntry = (r) => ({
|
|
116
|
+
id: r.id,
|
|
117
|
+
subject: { entityType: r.subject_type, entityId: r.subject_id },
|
|
118
|
+
leaveTypeKey: r.leave_type_key,
|
|
119
|
+
entryKind: r.entry_kind,
|
|
120
|
+
delta: r.delta,
|
|
121
|
+
effectiveDate: r.effective_date,
|
|
122
|
+
requestId: r.request_id,
|
|
123
|
+
note: r.note,
|
|
124
|
+
createdBy: r.created_by,
|
|
125
|
+
createdAt: r.created_at,
|
|
126
|
+
});
|
|
127
|
+
const toRequest = (r) => ({
|
|
128
|
+
id: r.id,
|
|
129
|
+
subject: { entityType: r.subject_type, entityId: r.subject_id },
|
|
130
|
+
leaveTypeKey: r.leave_type_key,
|
|
131
|
+
startDate: r.start_date,
|
|
132
|
+
endDate: r.end_date,
|
|
133
|
+
days: r.days,
|
|
134
|
+
status: r.status,
|
|
135
|
+
note: r.note,
|
|
136
|
+
decidedBy: r.decided_by,
|
|
137
|
+
decidedAt: r.decided_at,
|
|
138
|
+
createdBy: r.created_by,
|
|
139
|
+
createdAt: r.created_at,
|
|
140
|
+
});
|
|
141
|
+
const toLeaveType = (r) => ({
|
|
142
|
+
key: r.key,
|
|
143
|
+
floor: r.floor,
|
|
144
|
+
active: r.active === 1,
|
|
145
|
+
createdAt: r.created_at,
|
|
146
|
+
});
|
|
147
|
+
/** Negate a signed decimal string ('5' → '-5', '-5' → '5', '0' → '0'). */
|
|
148
|
+
const negate = (d) => compareDecimal(d, '0') === 0 ? '0' : d.startsWith('-') ? d.slice(1) : `-${d}`;
|
|
149
|
+
function getRequestRow(ctx, requestId) {
|
|
150
|
+
const row = ctx.sql.query('SELECT * FROM absence_requests WHERE id = ?', [
|
|
151
|
+
requestId,
|
|
152
|
+
])[0];
|
|
153
|
+
if (!row)
|
|
154
|
+
throw new Error(`absence request not found: ${requestId}`);
|
|
155
|
+
return row;
|
|
156
|
+
}
|
|
157
|
+
function getLeaveTypeRow(ctx, key) {
|
|
158
|
+
const row = ctx.sql.query('SELECT * FROM absence_leave_types WHERE key = ?', [
|
|
159
|
+
key,
|
|
160
|
+
])[0];
|
|
161
|
+
if (!row)
|
|
162
|
+
throw new Error(`leave type not found: ${key}`);
|
|
163
|
+
return row;
|
|
164
|
+
}
|
|
165
|
+
function getEntryRow(ctx, id) {
|
|
166
|
+
return ctx.sql.query('SELECT * FROM absence_ledger WHERE id = ?', [id])[0];
|
|
167
|
+
}
|
|
168
|
+
const subjectRefOf = (r) => ({
|
|
169
|
+
entityType: r.subject_type,
|
|
170
|
+
entityId: r.subject_id,
|
|
171
|
+
});
|
|
172
|
+
function insertEntry(ctx, input) {
|
|
173
|
+
const id = ulid();
|
|
174
|
+
ctx.sql.exec(`INSERT INTO absence_ledger
|
|
175
|
+
(id, subject_type, subject_id, data_subject_id, leave_type_key,
|
|
176
|
+
entry_kind, delta, effective_date, request_id, note, created_by, created_at)
|
|
177
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
178
|
+
id,
|
|
179
|
+
input.subject.ref.entityType,
|
|
180
|
+
input.subject.ref.entityId,
|
|
181
|
+
input.subject.dataSubjectId,
|
|
182
|
+
input.leaveTypeKey,
|
|
183
|
+
input.entryKind,
|
|
184
|
+
input.delta,
|
|
185
|
+
input.effectiveDate,
|
|
186
|
+
input.requestId ?? null,
|
|
187
|
+
input.note ?? null,
|
|
188
|
+
ctx.principal,
|
|
189
|
+
new Date().toISOString(),
|
|
190
|
+
]);
|
|
191
|
+
const entry = toEntry(getEntryRow(ctx, id));
|
|
192
|
+
ctx.emit({
|
|
193
|
+
type: 'absence.entry-recorded',
|
|
194
|
+
schemaVersion: 1,
|
|
195
|
+
entity: input.subject.ref,
|
|
196
|
+
piiClass: 'pseudonymous',
|
|
197
|
+
subjectId: input.subject.dataSubjectId,
|
|
198
|
+
payload: {
|
|
199
|
+
entryId: id,
|
|
200
|
+
subject: input.subject.ref,
|
|
201
|
+
leaveTypeKey: input.leaveTypeKey,
|
|
202
|
+
entryKind: input.entryKind,
|
|
203
|
+
delta: input.delta,
|
|
204
|
+
effectiveDate: input.effectiveDate,
|
|
205
|
+
requestId: input.requestId ?? null,
|
|
206
|
+
},
|
|
207
|
+
});
|
|
208
|
+
return entry;
|
|
209
|
+
}
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
// In-scope functions (K-16) — composable from vertical operations, same
|
|
212
|
+
// transaction. The registered operations below are their default bindings.
|
|
213
|
+
// The CALLER is responsible for the permission check.
|
|
214
|
+
// ---------------------------------------------------------------------------
|
|
215
|
+
export const configureLeaveTypeInput = z.object({
|
|
216
|
+
key: z.string().min(1),
|
|
217
|
+
floor: signedDecimal.optional(),
|
|
218
|
+
active: z.boolean().optional(),
|
|
219
|
+
});
|
|
220
|
+
export function configureLeaveType(ctx, rawInput) {
|
|
221
|
+
const input = configureLeaveTypeInput.parse(rawInput);
|
|
222
|
+
ctx.sql.exec(`INSERT INTO absence_leave_types (key, floor, active, created_at)
|
|
223
|
+
VALUES (?, ?, ?, ?)
|
|
224
|
+
ON CONFLICT(key) DO UPDATE SET
|
|
225
|
+
floor = COALESCE(?, floor),
|
|
226
|
+
active = COALESCE(?, active)`, [
|
|
227
|
+
input.key,
|
|
228
|
+
input.floor ?? '0',
|
|
229
|
+
input.active === false ? 0 : 1,
|
|
230
|
+
new Date().toISOString(),
|
|
231
|
+
input.floor ?? null,
|
|
232
|
+
input.active === undefined ? null : input.active ? 1 : 0,
|
|
233
|
+
]);
|
|
234
|
+
const row = getLeaveTypeRow(ctx, input.key);
|
|
235
|
+
ctx.emit({
|
|
236
|
+
type: 'absence.leave-type-configured',
|
|
237
|
+
schemaVersion: 1,
|
|
238
|
+
entity: { entityType: 'absence-leave-type', entityId: input.key },
|
|
239
|
+
piiClass: 'none',
|
|
240
|
+
payload: { key: row.key, floor: row.floor, active: row.active === 1 },
|
|
241
|
+
});
|
|
242
|
+
return toLeaveType(row);
|
|
243
|
+
}
|
|
244
|
+
export function listLeaveTypes(ctx) {
|
|
245
|
+
return ctx.sql
|
|
246
|
+
.query('SELECT * FROM absence_leave_types ORDER BY key')
|
|
247
|
+
.map(toLeaveType);
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* The one write that bypasses the request flow, restricted to accrual /
|
|
251
|
+
* correction / carryover — 'booking' and 'reversal' are mintable only through
|
|
252
|
+
* decideAbsence/cancelAbsence, which is what makes "only an approved request
|
|
253
|
+
* touches the ledger" a construction rather than a convention.
|
|
254
|
+
*
|
|
255
|
+
* No floor check here: a correction is the administrator's escape hatch, and
|
|
256
|
+
* accrual/carryover only ever add. The floor guards bookings (D-D).
|
|
257
|
+
*/
|
|
258
|
+
export const recordEntryInput = z.object({
|
|
259
|
+
subject: absenceSubject,
|
|
260
|
+
leaveTypeKey: z.string().min(1),
|
|
261
|
+
entryKind: z.enum(['accrual', 'correction', 'carryover']),
|
|
262
|
+
delta: signedDecimal,
|
|
263
|
+
effectiveDate: isoDate,
|
|
264
|
+
note: z.string().optional(),
|
|
265
|
+
});
|
|
266
|
+
export function recordEntry(ctx, rawInput) {
|
|
267
|
+
const input = recordEntryInput.parse(rawInput);
|
|
268
|
+
getLeaveTypeRow(ctx, input.leaveTypeKey);
|
|
269
|
+
return insertEntry(ctx, input);
|
|
270
|
+
}
|
|
271
|
+
/** Balance = pure fold over entries with effective_date <= asOf. No counter exists. */
|
|
272
|
+
export function balanceAsOf(ctx, input) {
|
|
273
|
+
const asOf = input.asOf === undefined ? undefined : isoDate.parse(input.asOf);
|
|
274
|
+
const rows = asOf
|
|
275
|
+
? ctx.sql.query(`SELECT delta FROM absence_ledger
|
|
276
|
+
WHERE subject_type = ? AND subject_id = ? AND leave_type_key = ? AND effective_date <= ?`, [input.subject.entityType, input.subject.entityId, input.leaveTypeKey, asOf])
|
|
277
|
+
: ctx.sql.query(`SELECT delta FROM absence_ledger
|
|
278
|
+
WHERE subject_type = ? AND subject_id = ? AND leave_type_key = ?`, [input.subject.entityType, input.subject.entityId, input.leaveTypeKey]);
|
|
279
|
+
return rows.reduce((sum, r) => addDecimal(sum, r.delta), '0');
|
|
280
|
+
}
|
|
281
|
+
export const requestAbsenceInput = z.object({
|
|
282
|
+
subject: absenceSubject,
|
|
283
|
+
leaveTypeKey: z.string().min(1),
|
|
284
|
+
startDate: isoDate,
|
|
285
|
+
endDate: isoDate,
|
|
286
|
+
days: posDecimal.refine((d) => compareDecimal(d, '0') > 0, 'days must be positive'),
|
|
287
|
+
note: z.string().optional(),
|
|
288
|
+
});
|
|
289
|
+
export function requestAbsence(ctx, rawInput) {
|
|
290
|
+
const input = requestAbsenceInput.parse(rawInput);
|
|
291
|
+
if (input.endDate < input.startDate) {
|
|
292
|
+
throw new Error(`endDate ${input.endDate} precedes startDate ${input.startDate}`);
|
|
293
|
+
}
|
|
294
|
+
const leaveType = getLeaveTypeRow(ctx, input.leaveTypeKey);
|
|
295
|
+
if (leaveType.active !== 1) {
|
|
296
|
+
throw new Error(`leave type '${input.leaveTypeKey}' is inactive`);
|
|
297
|
+
}
|
|
298
|
+
const id = ulid();
|
|
299
|
+
ctx.sql.exec(`INSERT INTO absence_requests
|
|
300
|
+
(id, subject_type, subject_id, data_subject_id, leave_type_key,
|
|
301
|
+
start_date, end_date, days, status, note, created_by, created_at)
|
|
302
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'requested', ?, ?, ?)`, [
|
|
303
|
+
id,
|
|
304
|
+
input.subject.ref.entityType,
|
|
305
|
+
input.subject.ref.entityId,
|
|
306
|
+
input.subject.dataSubjectId,
|
|
307
|
+
input.leaveTypeKey,
|
|
308
|
+
input.startDate,
|
|
309
|
+
input.endDate,
|
|
310
|
+
input.days,
|
|
311
|
+
input.note ?? null,
|
|
312
|
+
ctx.principal,
|
|
313
|
+
new Date().toISOString(),
|
|
314
|
+
]);
|
|
315
|
+
ctx.emit({
|
|
316
|
+
type: 'absence.requested',
|
|
317
|
+
schemaVersion: 1,
|
|
318
|
+
entity: input.subject.ref,
|
|
319
|
+
piiClass: 'pseudonymous',
|
|
320
|
+
subjectId: input.subject.dataSubjectId,
|
|
321
|
+
payload: {
|
|
322
|
+
requestId: id,
|
|
323
|
+
subject: input.subject.ref,
|
|
324
|
+
leaveTypeKey: input.leaveTypeKey,
|
|
325
|
+
startDate: input.startDate,
|
|
326
|
+
endDate: input.endDate,
|
|
327
|
+
days: input.days,
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
return toRequest(getRequestRow(ctx, id));
|
|
331
|
+
}
|
|
332
|
+
export const decideAbsenceInput = z.object({
|
|
333
|
+
requestId: z.string().min(1),
|
|
334
|
+
decision: z.enum(['approve', 'reject']),
|
|
335
|
+
note: z.string().optional(),
|
|
336
|
+
});
|
|
337
|
+
export function decideAbsence(ctx, rawInput) {
|
|
338
|
+
const input = decideAbsenceInput.parse(rawInput);
|
|
339
|
+
const req = getRequestRow(ctx, input.requestId);
|
|
340
|
+
// The state machine cannot skip: only a 'requested' absence can be decided.
|
|
341
|
+
if (req.status !== 'requested') {
|
|
342
|
+
throw new Error(`absence request ${req.id} is '${req.status}' — only a requested absence can be decided`);
|
|
343
|
+
}
|
|
344
|
+
const now = new Date().toISOString();
|
|
345
|
+
const subject = {
|
|
346
|
+
ref: subjectRefOf(req),
|
|
347
|
+
dataSubjectId: dataSubjectId.parse(req.data_subject_id),
|
|
348
|
+
};
|
|
349
|
+
if (input.decision === 'reject') {
|
|
350
|
+
ctx.sql.exec(`UPDATE absence_requests SET status = 'rejected', decided_by = ?, decided_at = ?, note = COALESCE(?, note) WHERE id = ?`, [ctx.principal, now, input.note ?? null, req.id]);
|
|
351
|
+
ctx.emit({
|
|
352
|
+
type: 'absence.decided',
|
|
353
|
+
schemaVersion: 1,
|
|
354
|
+
entity: subject.ref,
|
|
355
|
+
piiClass: 'pseudonymous',
|
|
356
|
+
subjectId: subject.dataSubjectId,
|
|
357
|
+
payload: {
|
|
358
|
+
requestId: req.id,
|
|
359
|
+
subject: subject.ref,
|
|
360
|
+
leaveTypeKey: req.leave_type_key,
|
|
361
|
+
decision: 'rejected',
|
|
362
|
+
bookingId: null,
|
|
363
|
+
},
|
|
364
|
+
});
|
|
365
|
+
return { request: toRequest(getRequestRow(ctx, req.id)), booking: null };
|
|
366
|
+
}
|
|
367
|
+
// Approve. Re-fold at decision time — the world may have changed since the
|
|
368
|
+
// request. A booking that would take the fold below the type's floor is
|
|
369
|
+
// rejected by the engine, not the UI (D-D).
|
|
370
|
+
const leaveType = getLeaveTypeRow(ctx, req.leave_type_key);
|
|
371
|
+
const balance = balanceAsOf(ctx, { subject: subject.ref, leaveTypeKey: req.leave_type_key });
|
|
372
|
+
if (compareDecimal(addDecimal(balance, negate(req.days)), leaveType.floor) < 0) {
|
|
373
|
+
throw new Error(`insufficient balance: ${balance} day(s) of '${req.leave_type_key}' (floor ${leaveType.floor}), request needs ${req.days}`);
|
|
374
|
+
}
|
|
375
|
+
const booking = insertEntry(ctx, {
|
|
376
|
+
subject,
|
|
377
|
+
leaveTypeKey: req.leave_type_key,
|
|
378
|
+
entryKind: 'booking',
|
|
379
|
+
delta: negate(req.days),
|
|
380
|
+
effectiveDate: req.start_date,
|
|
381
|
+
requestId: req.id,
|
|
382
|
+
note: input.note,
|
|
383
|
+
});
|
|
384
|
+
ctx.sql.exec(`UPDATE absence_requests SET status = 'approved', decided_by = ?, decided_at = ? WHERE id = ?`, [ctx.principal, now, req.id]);
|
|
385
|
+
ctx.emit({
|
|
386
|
+
type: 'absence.decided',
|
|
387
|
+
schemaVersion: 1,
|
|
388
|
+
entity: subject.ref,
|
|
389
|
+
piiClass: 'pseudonymous',
|
|
390
|
+
subjectId: subject.dataSubjectId,
|
|
391
|
+
payload: {
|
|
392
|
+
requestId: req.id,
|
|
393
|
+
subject: subject.ref,
|
|
394
|
+
leaveTypeKey: req.leave_type_key,
|
|
395
|
+
decision: 'approved',
|
|
396
|
+
bookingId: booking.id,
|
|
397
|
+
days: req.days,
|
|
398
|
+
startDate: req.start_date,
|
|
399
|
+
endDate: req.end_date,
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
return { request: toRequest(getRequestRow(ctx, req.id)), booking };
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* requested → cancelled (withdraw; no ledger touch), or approved → cancelled
|
|
406
|
+
* with a COMPENSATING reversal entry — "Hugo came back" is a new entry, never
|
|
407
|
+
* an edit (D-E). Rejected/cancelled rows are terminal.
|
|
408
|
+
*/
|
|
409
|
+
export const cancelAbsenceInput = z.object({
|
|
410
|
+
requestId: z.string().min(1),
|
|
411
|
+
reason: z.string().optional(),
|
|
412
|
+
});
|
|
413
|
+
export function cancelAbsence(ctx, rawInput) {
|
|
414
|
+
const input = cancelAbsenceInput.parse(rawInput);
|
|
415
|
+
const req = getRequestRow(ctx, input.requestId);
|
|
416
|
+
if (req.status !== 'requested' && req.status !== 'approved') {
|
|
417
|
+
throw new Error(`absence request ${req.id} is '${req.status}' — only requested or approved can be cancelled`);
|
|
418
|
+
}
|
|
419
|
+
const now = new Date().toISOString();
|
|
420
|
+
const subject = {
|
|
421
|
+
ref: subjectRefOf(req),
|
|
422
|
+
dataSubjectId: dataSubjectId.parse(req.data_subject_id),
|
|
423
|
+
};
|
|
424
|
+
let reversal = null;
|
|
425
|
+
if (req.status === 'approved') {
|
|
426
|
+
const booking = ctx.sql.query(`SELECT * FROM absence_ledger WHERE request_id = ? AND entry_kind = 'booking'`, [req.id])[0];
|
|
427
|
+
if (!booking)
|
|
428
|
+
throw new Error(`approved request ${req.id} has no booking entry — ledger integrity violated`);
|
|
429
|
+
reversal = insertEntry(ctx, {
|
|
430
|
+
subject,
|
|
431
|
+
leaveTypeKey: req.leave_type_key,
|
|
432
|
+
entryKind: 'reversal',
|
|
433
|
+
delta: negate(booking.delta),
|
|
434
|
+
effectiveDate: booking.effective_date,
|
|
435
|
+
requestId: req.id,
|
|
436
|
+
note: input.reason,
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
ctx.sql.exec(`UPDATE absence_requests SET status = 'cancelled', decided_at = ?, note = COALESCE(?, note) WHERE id = ?`, [now, input.reason ?? null, req.id]);
|
|
440
|
+
ctx.emit({
|
|
441
|
+
type: 'absence.cancelled',
|
|
442
|
+
schemaVersion: 1,
|
|
443
|
+
entity: subject.ref,
|
|
444
|
+
piiClass: 'pseudonymous',
|
|
445
|
+
subjectId: subject.dataSubjectId,
|
|
446
|
+
payload: {
|
|
447
|
+
requestId: req.id,
|
|
448
|
+
subject: subject.ref,
|
|
449
|
+
leaveTypeKey: req.leave_type_key,
|
|
450
|
+
priorStatus: req.status,
|
|
451
|
+
reversalId: reversal?.id ?? null,
|
|
452
|
+
},
|
|
453
|
+
});
|
|
454
|
+
return { request: toRequest(getRequestRow(ctx, req.id)), reversal };
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* A DATE-TRIGGERED rule with no caller but the passage of time (#383): a
|
|
458
|
+
* request still 'requested' once its start date has passed can no longer be
|
|
459
|
+
* approved, so the platform sweep cancels it — attributed to the schedule
|
|
460
|
+
* (`{ system }`), never to a manager who never touched it. Idempotent (only
|
|
461
|
+
* 'requested' rows past their start) and paged (a bounded batch per pass).
|
|
462
|
+
*/
|
|
463
|
+
export function expireStaleRequests(ctx) {
|
|
464
|
+
const today = new Date().toISOString().slice(0, 10);
|
|
465
|
+
const stale = ctx.sql.query(`SELECT * FROM absence_requests
|
|
466
|
+
WHERE status = 'requested' AND start_date < ?
|
|
467
|
+
ORDER BY start_date LIMIT 100`, [today]);
|
|
468
|
+
const now = new Date().toISOString();
|
|
469
|
+
for (const req of stale) {
|
|
470
|
+
ctx.sql.exec(`UPDATE absence_requests
|
|
471
|
+
SET status = 'cancelled', decided_at = ?,
|
|
472
|
+
note = COALESCE(note, 'auto-expired: start date passed before approval')
|
|
473
|
+
WHERE id = ?`, [now, req.id]);
|
|
474
|
+
ctx.emit({
|
|
475
|
+
type: 'absence.expired',
|
|
476
|
+
schemaVersion: 1,
|
|
477
|
+
entity: subjectRefOf(req),
|
|
478
|
+
piiClass: 'pseudonymous',
|
|
479
|
+
subjectId: dataSubjectId.parse(req.data_subject_id),
|
|
480
|
+
payload: { requestId: req.id, subject: subjectRefOf(req), startDate: req.start_date },
|
|
481
|
+
});
|
|
482
|
+
}
|
|
483
|
+
return { expired: stale.length };
|
|
484
|
+
}
|
|
485
|
+
// ---------------------------------------------------------------------------
|
|
486
|
+
// Reads
|
|
487
|
+
// ---------------------------------------------------------------------------
|
|
488
|
+
export function listRequests(ctx, input) {
|
|
489
|
+
const where = [];
|
|
490
|
+
const params = [];
|
|
491
|
+
if (input?.subject) {
|
|
492
|
+
where.push('subject_type = ? AND subject_id = ?');
|
|
493
|
+
params.push(input.subject.entityType, input.subject.entityId);
|
|
494
|
+
}
|
|
495
|
+
if (input?.status) {
|
|
496
|
+
where.push('status = ?');
|
|
497
|
+
params.push(input.status);
|
|
498
|
+
}
|
|
499
|
+
const sql = `SELECT * FROM absence_requests${where.length ? ` WHERE ${where.join(' AND ')}` : ''} ORDER BY created_at DESC, id DESC`;
|
|
500
|
+
return ctx.sql.query(sql, params).map(toRequest);
|
|
501
|
+
}
|
|
502
|
+
export function listEntries(ctx, input) {
|
|
503
|
+
const rows = input.leaveTypeKey
|
|
504
|
+
? ctx.sql.query(`SELECT * FROM absence_ledger
|
|
505
|
+
WHERE subject_type = ? AND subject_id = ? AND leave_type_key = ?
|
|
506
|
+
ORDER BY effective_date, id`, [input.subject.entityType, input.subject.entityId, input.leaveTypeKey])
|
|
507
|
+
: ctx.sql.query(`SELECT * FROM absence_ledger
|
|
508
|
+
WHERE subject_type = ? AND subject_id = ?
|
|
509
|
+
ORDER BY effective_date, id`, [input.subject.entityType, input.subject.entityId]);
|
|
510
|
+
return rows.map(toEntry);
|
|
511
|
+
}
|
|
512
|
+
/**
|
|
513
|
+
* Cross-subject window read — the payroll/export composition: "all bookings in
|
|
514
|
+
* this pay period", regardless of subject. In-scope only (no default binding):
|
|
515
|
+
* the callers are vertical exports that hold their own permission gate.
|
|
516
|
+
*/
|
|
517
|
+
export function entriesInWindow(ctx, input) {
|
|
518
|
+
const from = isoDate.parse(input.from);
|
|
519
|
+
const to = isoDate.parse(input.to);
|
|
520
|
+
const rows = input.entryKind
|
|
521
|
+
? ctx.sql.query(`SELECT * FROM absence_ledger
|
|
522
|
+
WHERE effective_date >= ? AND effective_date <= ? AND entry_kind = ?
|
|
523
|
+
ORDER BY subject_id, effective_date, id`, [from, to, input.entryKind])
|
|
524
|
+
: ctx.sql.query(`SELECT * FROM absence_ledger
|
|
525
|
+
WHERE effective_date >= ? AND effective_date <= ?
|
|
526
|
+
ORDER BY subject_id, effective_date, id`, [from, to]);
|
|
527
|
+
return rows.map(toEntry);
|
|
528
|
+
}
|
|
529
|
+
/** Walk YYYY-MM-DD dates inclusively without timezone drift (UTC arithmetic). */
|
|
530
|
+
function* eachDate(from, to) {
|
|
531
|
+
const end = Date.UTC(Number(to.slice(0, 4)), Number(to.slice(5, 7)) - 1, Number(to.slice(8, 10)));
|
|
532
|
+
let cur = Date.UTC(Number(from.slice(0, 4)), Number(from.slice(5, 7)) - 1, Number(from.slice(8, 10)));
|
|
533
|
+
while (cur <= end) {
|
|
534
|
+
yield new Date(cur).toISOString().slice(0, 10);
|
|
535
|
+
cur += 86_400_000;
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
/**
|
|
539
|
+
* The planner's read (D-C): every calendar day in an APPROVED request's
|
|
540
|
+
* inclusive range, clamped to [from, to]. The verdict is "an approved absence
|
|
541
|
+
* covers this date" — the engine does not know weekends or red days; the
|
|
542
|
+
* vertical composes this with its own holiday calendar.
|
|
543
|
+
*/
|
|
544
|
+
export function availability(ctx, input) {
|
|
545
|
+
const from = isoDate.parse(input.from);
|
|
546
|
+
const to = isoDate.parse(input.to);
|
|
547
|
+
if (to < from)
|
|
548
|
+
throw new Error(`to ${to} precedes from ${from}`);
|
|
549
|
+
const rows = ctx.sql.query(`SELECT * FROM absence_requests
|
|
550
|
+
WHERE subject_type = ? AND subject_id = ? AND status = 'approved'
|
|
551
|
+
AND start_date <= ? AND end_date >= ?
|
|
552
|
+
ORDER BY start_date, id`, [input.subject.entityType, input.subject.entityId, to, from]);
|
|
553
|
+
const days = [];
|
|
554
|
+
for (const req of rows) {
|
|
555
|
+
const start = req.start_date < from ? from : req.start_date;
|
|
556
|
+
const end = req.end_date > to ? to : req.end_date;
|
|
557
|
+
for (const date of eachDate(start, end)) {
|
|
558
|
+
days.push({ date, leaveTypeKey: req.leave_type_key, requestId: req.id });
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
return { days, requests: rows.map(toRequest) };
|
|
562
|
+
}
|
|
563
|
+
// ---------------------------------------------------------------------------
|
|
564
|
+
// Default operation bindings — each starts with the permission check.
|
|
565
|
+
// ---------------------------------------------------------------------------
|
|
566
|
+
const configureLeaveTypeOp = async (ctx, input) => {
|
|
567
|
+
assertAllowed(await ctx.check(PERM.configure));
|
|
568
|
+
return configureLeaveType(ctx, input);
|
|
569
|
+
};
|
|
570
|
+
const listLeaveTypesOp = async (ctx) => {
|
|
571
|
+
assertAllowed(await ctx.check(PERM.read));
|
|
572
|
+
return listLeaveTypes(ctx);
|
|
573
|
+
};
|
|
574
|
+
const recordEntryOp = async (ctx, input) => {
|
|
575
|
+
assertAllowed(await ctx.check(PERM.configure));
|
|
576
|
+
return recordEntry(ctx, input);
|
|
577
|
+
};
|
|
578
|
+
const requestOp = async (ctx, raw) => {
|
|
579
|
+
const input = requestAbsenceInput.parse(raw);
|
|
580
|
+
// Entity-narrowed: a subject requests for THEMSELVES through a grant on their
|
|
581
|
+
// own ref, holding no role; an unnarrowed holder may request for anyone.
|
|
582
|
+
assertAllowed(await ctx.check(PERM.request, input.subject.ref));
|
|
583
|
+
return requestAbsence(ctx, input);
|
|
584
|
+
};
|
|
585
|
+
const decideOp = async (ctx, input) => {
|
|
586
|
+
assertAllowed(await ctx.check(PERM.approve));
|
|
587
|
+
return decideAbsence(ctx, input);
|
|
588
|
+
};
|
|
589
|
+
const cancelOp = async (ctx, raw) => {
|
|
590
|
+
const input = cancelAbsenceInput.parse(raw);
|
|
591
|
+
// An approver cancels anything cancellable; the subject may WITHDRAW their
|
|
592
|
+
// own still-requested row through the same entity-narrowed grant they
|
|
593
|
+
// requested with.
|
|
594
|
+
const asApprover = await ctx.check(PERM.approve);
|
|
595
|
+
if (!asApprover.allowed) {
|
|
596
|
+
const req = getRequestRow(ctx, input.requestId);
|
|
597
|
+
if (req.status !== 'requested')
|
|
598
|
+
assertAllowed(asApprover);
|
|
599
|
+
assertAllowed(await ctx.check(PERM.request, subjectRefOf(req)));
|
|
600
|
+
}
|
|
601
|
+
return cancelAbsence(ctx, input);
|
|
602
|
+
};
|
|
603
|
+
const expireStaleOp = async (ctx) => {
|
|
604
|
+
assertAllowed(await ctx.check(PERM.approve));
|
|
605
|
+
return expireStaleRequests(ctx);
|
|
606
|
+
};
|
|
607
|
+
const balanceOp = async (ctx, input) => {
|
|
608
|
+
assertAllowed(await ctx.check(PERM.read, entityRef.parse(input.subject)));
|
|
609
|
+
return { balance: balanceAsOf(ctx, input) };
|
|
610
|
+
};
|
|
611
|
+
const availabilityOp = async (ctx, input) => {
|
|
612
|
+
assertAllowed(await ctx.check(PERM.read, entityRef.parse(input.subject)));
|
|
613
|
+
return availability(ctx, input);
|
|
614
|
+
};
|
|
615
|
+
const listRequestsOp = async (ctx, input) => {
|
|
616
|
+
if (input?.subject) {
|
|
617
|
+
assertAllowed(await ctx.check(PERM.read, entityRef.parse(input.subject)));
|
|
618
|
+
}
|
|
619
|
+
else {
|
|
620
|
+
assertAllowed(await ctx.check(PERM.read));
|
|
621
|
+
}
|
|
622
|
+
return listRequests(ctx, input);
|
|
623
|
+
};
|
|
624
|
+
const listEntriesOp = async (ctx, input) => {
|
|
625
|
+
assertAllowed(await ctx.check(PERM.read, entityRef.parse(input.subject)));
|
|
626
|
+
return listEntries(ctx, input);
|
|
627
|
+
};
|
|
628
|
+
export const absenceModule = {
|
|
629
|
+
manifest: absenceManifest,
|
|
630
|
+
migrations: absenceMigrations,
|
|
631
|
+
operations: {
|
|
632
|
+
'absence/configure-leave-type': configureLeaveTypeOp,
|
|
633
|
+
'absence/list-leave-types': listLeaveTypesOp,
|
|
634
|
+
'absence/record-entry': recordEntryOp,
|
|
635
|
+
'absence/request': requestOp,
|
|
636
|
+
'absence/decide': decideOp,
|
|
637
|
+
'absence/cancel': cancelOp,
|
|
638
|
+
'absence/expire-stale': expireStaleOp,
|
|
639
|
+
'absence/balance': balanceOp,
|
|
640
|
+
'absence/availability': availabilityOp,
|
|
641
|
+
'absence/list-requests': listRequestsOp,
|
|
642
|
+
'absence/list-entries': listEntriesOp,
|
|
643
|
+
},
|
|
644
|
+
};
|
|
645
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrat-run/engine-absence",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.0",
|
|
4
4
|
"description": "Substrat engine: approved absence — an append-only entry ledger over an opaque subject, balance as a fold, approval as a state machine",
|
|
5
5
|
"license": "AGPL-3.0-only",
|
|
6
6
|
"repository": {
|
|
@@ -24,19 +24,19 @@
|
|
|
24
24
|
"publishConfig": {
|
|
25
25
|
"access": "public"
|
|
26
26
|
},
|
|
27
|
-
"scripts": {
|
|
28
|
-
"build": "tsc -p tsconfig.json",
|
|
29
|
-
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|
|
30
|
-
"test": "vitest run"
|
|
31
|
-
},
|
|
32
27
|
"dependencies": {
|
|
33
|
-
"
|
|
34
|
-
"@substrat-run/
|
|
35
|
-
"
|
|
28
|
+
"zod": "^4.4.3",
|
|
29
|
+
"@substrat-run/contracts": "^0.65.0",
|
|
30
|
+
"@substrat-run/kernel": "^0.65.0"
|
|
36
31
|
},
|
|
37
32
|
"devDependencies": {
|
|
38
33
|
"typescript": "^7.0.0",
|
|
39
|
-
"
|
|
40
|
-
"
|
|
34
|
+
"vitest": "^3.0.0",
|
|
35
|
+
"@substrat-run/engine-test-kit": "^0.0.63"
|
|
36
|
+
},
|
|
37
|
+
"scripts": {
|
|
38
|
+
"build": "tsc -p tsconfig.json",
|
|
39
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|
|
40
|
+
"test": "vitest run"
|
|
41
41
|
}
|
|
42
|
-
}
|
|
42
|
+
}
|