@happyvertical/smrt-timesheets 0.57.36 → 0.57.38

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.
Files changed (34) hide show
  1. package/dist/attendance/correction-models.d.ts +2 -2
  2. package/dist/attendance/correction-models.d.ts.map +1 -1
  3. package/dist/attendance/models.d.ts +5 -5
  4. package/dist/attendance/models.d.ts.map +1 -1
  5. package/dist/attendance.js +2 -2
  6. package/dist/chunks/{attendance-CWyi7Q-t.js → attendance-C_hWJJze.js} +3 -3
  7. package/dist/chunks/{attendance-CWyi7Q-t.js.map → attendance-C_hWJJze.js.map} +1 -1
  8. package/dist/chunks/{attendance-zF-wCzSW.js → attendance-ClXOMLAM.js} +5 -5
  9. package/dist/chunks/attendance-ClXOMLAM.js.map +1 -0
  10. package/dist/chunks/{models-CRnsNezh.js → models-D0VhW-5I.js} +16 -16
  11. package/dist/chunks/models-D0VhW-5I.js.map +1 -0
  12. package/dist/chunks/{rollup-Btay4E5L.js → rollup-CPCl0Xxi.js} +9 -9
  13. package/dist/chunks/rollup-CPCl0Xxi.js.map +1 -0
  14. package/dist/chunks/service-time-entry-De3Y9_ho.js +286 -0
  15. package/dist/chunks/service-time-entry-De3Y9_ho.js.map +1 -0
  16. package/dist/chunks/{time-entry-actions-Dn89JX6L.js → time-entry-actions-CMNPO8kR.js} +6 -6
  17. package/dist/chunks/time-entry-actions-CMNPO8kR.js.map +1 -0
  18. package/dist/index.js +5 -5
  19. package/dist/manifest.json +78 -12
  20. package/dist/models/service-snapshots.d.ts +3 -3
  21. package/dist/models/service-snapshots.d.ts.map +1 -1
  22. package/dist/models/service-time-entry.d.ts +2 -2
  23. package/dist/models/service-time-entry.d.ts.map +1 -1
  24. package/dist/rollup/models.d.ts +4 -4
  25. package/dist/rollup/models.d.ts.map +1 -1
  26. package/dist/rollup.js +1 -1
  27. package/dist/smrt-knowledge.json +36 -3
  28. package/package.json +8 -8
  29. package/dist/chunks/attendance-zF-wCzSW.js.map +0 -1
  30. package/dist/chunks/models-CRnsNezh.js.map +0 -1
  31. package/dist/chunks/rollup-Btay4E5L.js.map +0 -1
  32. package/dist/chunks/service-time-entry-Bd3NQr90.js +0 -286
  33. package/dist/chunks/service-time-entry-Bd3NQr90.js.map +0 -1
  34. package/dist/chunks/time-entry-actions-Dn89JX6L.js.map +0 -1
@@ -1,4 +1,4 @@
1
- import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
1
+ import { SmrtCollection, SmrtObject, type SmrtSaveOptions } from '@happyvertical/smrt-core';
2
2
  /** What a correction did. Punch kinds target the punch itself. */
3
3
  export declare const ATTENDANCE_CORRECTION_KINDS: readonly ["punch.corrected", "punch.added", "break.added", "break.changed", "break.removed", "segment.added", "segment.changed", "segment.removed"];
4
4
  export type AttendanceCorrectionKind = (typeof ATTENDANCE_CORRECTION_KINDS)[number];
@@ -29,7 +29,7 @@ export declare class AttendanceCorrection extends SmrtObject {
29
29
  getBefore<T = Record<string, unknown>>(): T | null;
30
30
  /** The values after the change, or null for a removal. */
31
31
  getAfter<T = Record<string, unknown>>(): T | null;
32
- save(): Promise<this>;
32
+ save(options?: SmrtSaveOptions): Promise<this>;
33
33
  delete(): Promise<void>;
34
34
  }
35
35
  /** The correction ledger. */
@@ -1 +1 @@
1
- {"version":3,"file":"correction-models.d.ts","sourceRoot":"","sources":["../../src/attendance/correction-models.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,cAAc,EACd,UAAU,EAEX,MAAM,0BAA0B,CAAC;AAMlC,kEAAkE;AAClE,eAAO,MAAM,2BAA2B,qJAS9B,CAAC;AACX,MAAM,MAAM,wBAAwB,GAClC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAc/C;;;;;;GAMG;AACH,qBAkBa,oBAAqB,SAAQ,UAAU;IACtC,QAAQ,SAAM;IAC1B,gCAAgC;IAEhC,gBAAgB,SAAM;IACtB,+BAA+B;IAE/B,cAAc,SAAM;IACK,IAAI,EAAE,wBAAwB,CAAqB;IAC/C,OAAO,SAAM;IAC1C,6EAA6E;IAC7E,QAAQ,SAAM;IACW,WAAW,SAAU;IACrB,UAAU,SAAU;IACpB,MAAM,SAAM;IACrC,uBAAuB,UAAS;IAChC,cAAc,EAAE,IAAI,GAAG,IAAI,CAAQ;IAEnC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE9C,6DAA6D;IAC7D,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI;IAGlD,0DAA0D;IAC1D,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI;IAIlC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAsDrB,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvC;AAED,6BAA6B;AAC7B,qBAAa,8BAA+B,SAAQ,cAAc,CAAC,oBAAoB,CAAC;IACtF,MAAM,CAAC,QAAQ,CAAC,UAAU,8BAAwB;CACnD"}
1
+ {"version":3,"file":"correction-models.d.ts","sourceRoot":"","sources":["../../src/attendance/correction-models.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,cAAc,EACd,UAAU,EACV,KAAK,eAAe,EAErB,MAAM,0BAA0B,CAAC;AAMlC,kEAAkE;AAClE,eAAO,MAAM,2BAA2B,qJAS9B,CAAC;AACX,MAAM,MAAM,wBAAwB,GAClC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAc/C;;;;;;GAMG;AACH,qBAkBa,oBAAqB,SAAQ,UAAU;IACtC,QAAQ,SAAM;IAC1B,gCAAgC;IAEhC,gBAAgB,SAAM;IACtB,+BAA+B;IAE/B,cAAc,SAAM;IACK,IAAI,EAAE,wBAAwB,CAAqB;IAC/C,OAAO,SAAM;IAC1C,6EAA6E;IAC7E,QAAQ,SAAM;IACW,WAAW,SAAU;IACrB,UAAU,SAAU;IACpB,MAAM,SAAM;IACrC,uBAAuB,UAAS;IAChC,cAAc,EAAE,IAAI,GAAG,IAAI,CAAQ;IAEnC,uBAAuB,EAAE,MAAM,GAAG,IAAI,CAAQ;IAE9C,6DAA6D;IAC7D,SAAS,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI;IAGlD,0DAA0D;IAC1D,QAAQ,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG,IAAI;IAIlC,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;IAsD9C,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAGvC;AAED,6BAA6B;AAC7B,qBAAa,8BAA+B,SAAQ,cAAc,CAAC,oBAAoB,CAAC;IACtF,MAAM,CAAC,QAAQ,CAAC,UAAU,8BAAwB;CACnD"}
@@ -1,4 +1,4 @@
1
- import { SmrtCollection, SmrtObject } from '@happyvertical/smrt-core';
1
+ import { SmrtCollection, SmrtObject, type SmrtSaveOptions } from '@happyvertical/smrt-core';
2
2
  /** A tenant-scoped interval of attendance, independent of billable work. */
3
3
  export declare class AttendancePunch extends SmrtObject {
4
4
  tenantId: string;
@@ -19,7 +19,7 @@ export declare class AttendancePunch extends SmrtObject {
19
19
  serviceTimeEntryId: string | null;
20
20
  /** Unique while open; closed rows retain independent non-null slots on every dialect. */
21
21
  openSlot: string;
22
- save(): Promise<this>;
22
+ save(options?: SmrtSaveOptions): Promise<this>;
23
23
  private saveConsistent;
24
24
  }
25
25
  /** A paid or unpaid break inside one attendance punch. */
@@ -32,7 +32,7 @@ export declare class AttendanceBreak extends SmrtObject {
32
32
  /** Optional short consumer-owned label (`meal`, `rest`, ...); `''` when unspecified. */
33
33
  kind: string;
34
34
  openSlot: string;
35
- save(): Promise<this>;
35
+ save(options?: SmrtSaveOptions): Promise<this>;
36
36
  private saveConsistent;
37
37
  delete(): Promise<void>;
38
38
  }
@@ -73,7 +73,7 @@ export declare class AttendanceSegment extends SmrtObject {
73
73
  /** Set when a replay time policy asked for review of this segment's boundary. */
74
74
  reviewRequired: boolean;
75
75
  openSlot: string;
76
- save(): Promise<this>;
76
+ save(options?: SmrtSaveOptions): Promise<this>;
77
77
  private saveConsistent;
78
78
  delete(): Promise<void>;
79
79
  }
@@ -100,7 +100,7 @@ export declare class AttendanceReplay extends SmrtObject {
100
100
  getOutcome(): AttendanceReplayOutcome;
101
101
  /** Store the JSON representation of a validated success or refusal. */
102
102
  setOutcome(value: AttendanceReplayOutcome): void;
103
- save(): Promise<this>;
103
+ save(options?: SmrtSaveOptions): Promise<this>;
104
104
  }
105
105
  /** Punches for attendance and period rollup. */
106
106
  export declare class AttendancePunchCollection extends SmrtCollection<AttendancePunch> {
@@ -1 +1 @@
1
- {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/attendance/models.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"models.d.ts","sourceRoot":"","sources":["../../src/attendance/models.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,cAAc,EACd,UAAU,EACV,KAAK,eAAe,EAGrB,MAAM,0BAA0B,CAAC;AA6BlC,4EAA4E;AAC5E,qBAmBa,eAAgB,SAAQ,UAAU;IACjC,QAAQ,SAAM;IAC+B,SAAS,SAAM;IACxE,SAAS,EAAE,IAAI,CAAc;IAC7B,OAAO,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC5B,eAAe,SAAK;IACpB,kBAAkB,SAAK;IACvB,cAAc,UAAS;IACvB,qFAAqF;IACrF,eAAe,SAAM;IACrB,eAAe,UAAS;IACxB,uGAAuG;IACvG,MAAM,SAAM;IACZ,4FAA4F;IAC5F,aAAa,SAAM;IACnB,WAAW,SAAM;IAEmC,kBAAkB,EAClE,MAAM,GACN,IAAI,CAAQ;IAChB,yFAAyF;IAC9D,QAAQ,SAAM;IAE1B,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;YAM/C,cAAc;CA6G7B;AAED,0DAA0D;AAC1D,qBAca,eAAgB,SAAQ,UAAU;IACjC,QAAQ,SAAM;IACG,OAAO,SAAM;IAC1C,SAAS,EAAE,IAAI,CAAc;IAC7B,OAAO,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC5B,IAAI,UAAS;IACb,wFAAwF;IACxF,IAAI,SAAM;IACiB,QAAQ,SAAM;IAE1B,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;YAM/C,cAAc;IAgFb,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAgBvC;AAED,QAAA,MAAM,qBAAqB,kDAAmD,CAAC;AAC/E,uDAAuD;AACvD,MAAM,MAAM,4BAA4B,GACpC,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,GACtC,EAAE,CAAC;AAEP;;;;;;GAMG;AACH,qBA0Ba,iBAAkB,SAAQ,UAAU;IACnC,QAAQ,SAAM;IACG,OAAO,SAAM;IAC1C;;;;OAIG;IACsD,SAAS,SAAM;IACxE,2EAA2E;IAC3E,WAAW,SAAM;IACjB,SAAS,SAAM;IACf,6EAA6E;IAC7E,WAAW,SAAM;IACjB,SAAS,SAAM;IACf,0CAA0C;IAC1C,IAAI,SAAM;IACV,WAAW,SAAM;IACjB,SAAS,EAAE,IAAI,CAAc;IAC7B,OAAO,EAAE,IAAI,GAAG,IAAI,CAAQ;IAC5B,0DAA0D;IAC1D,eAAe,SAAK;IACpB,4EAA4E;IAC5E,YAAY,EAAE,4BAA4B,CAAM;IAChD,iFAAiF;IACjF,cAAc,UAAS;IACI,QAAQ,SAAM;IAE1B,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;YAM/C,cAAc;IA8Fb,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;CAgBvC;AAED,uEAAuE;AACvE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,yDAAyD;IACzD,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAwBD,+EAA+E;AAC/E,qBAQa,gBAAiB,SAAQ,UAAU;IAClC,QAAQ,SAAM;IACe,SAAS,SAAM;IAC/B,OAAO,SAAM;IACb,OAAO,SAAQ;IAExC,qFAAqF;IACrF,UAAU,IAAI,uBAAuB;IAOrC,uEAAuE;IACvE,UAAU,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI;IAMjC,IAAI,CAAC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC;CAI9D;AAED,gDAAgD;AAChD,qBAAa,yBAA0B,SAAQ,cAAc,CAAC,eAAe,CAAC;IAC5E,MAAM,CAAC,QAAQ,CAAC,UAAU,yBAAmB;CAC9C;AACD,4DAA4D;AAC5D,qBAAa,yBAA0B,SAAQ,cAAc,CAAC,eAAe,CAAC;IAC5E,MAAM,CAAC,QAAQ,CAAC,UAAU,yBAAmB;CAC9C;AACD,2DAA2D;AAC3D,qBAAa,2BAA4B,SAAQ,cAAc,CAAC,iBAAiB,CAAC;IAChF,MAAM,CAAC,QAAQ,CAAC,UAAU,2BAAqB;CAChD;AACD,sCAAsC;AACtC,qBAAa,0BAA2B,SAAQ,cAAc,CAAC,gBAAgB,CAAC;IAC9E,MAAM,CAAC,QAAQ,CAAC,UAAU,0BAAoB;CAC/C"}
@@ -1,3 +1,3 @@
1
- import { a as AttendanceReplay, c as AttendanceSegmentCollection, i as AttendancePunchCollection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, s as AttendanceSegment, t as AttendanceBreak } from "./chunks/models-CRnsNezh.js";
2
- import { a as continueSegment, c as openSegment, d as validateAttendanceWork, f as ATTENDANCE_CORRECTION_KINDS, i as closeOpenSegment, l as replaceSegment, m as AttendanceCorrectionCollection, n as AttendanceService, o as endSegment, p as AttendanceCorrection, r as beginSegment, s as listSegments, t as AttendanceCorrectionService, u as AttendanceConflict } from "./chunks/attendance-zF-wCzSW.js";
1
+ import { a as AttendanceReplay, c as AttendanceSegmentCollection, i as AttendancePunchCollection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, s as AttendanceSegment, t as AttendanceBreak } from "./chunks/models-D0VhW-5I.js";
2
+ import { a as continueSegment, c as openSegment, d as validateAttendanceWork, f as ATTENDANCE_CORRECTION_KINDS, i as closeOpenSegment, l as replaceSegment, m as AttendanceCorrectionCollection, n as AttendanceService, o as endSegment, p as AttendanceCorrection, r as beginSegment, s as listSegments, t as AttendanceCorrectionService, u as AttendanceConflict } from "./chunks/attendance-ClXOMLAM.js";
3
3
  export { ATTENDANCE_CORRECTION_KINDS, AttendanceBreak, AttendanceBreakCollection, AttendanceConflict, AttendanceCorrection, AttendanceCorrectionCollection, AttendanceCorrectionService, AttendancePunch, AttendancePunchCollection, AttendanceReplay, AttendanceReplayCollection, AttendanceSegment, AttendanceSegmentCollection, AttendanceService, beginSegment, closeOpenSegment, continueSegment, endSegment, listSegments, openSegment, replaceSegment, validateAttendanceWork };
@@ -1,5 +1,5 @@
1
- import { i as AttendancePunchCollection, n as AttendanceBreakCollection } from "./models-CRnsNezh.js";
2
- import { i as integer, n as attributeSource, r as instant } from "./rollup-Btay4E5L.js";
1
+ import { i as AttendancePunchCollection, n as AttendanceBreakCollection } from "./models-D0VhW-5I.js";
2
+ import { i as integer, n as attributeSource, r as instant } from "./rollup-CPCl0Xxi.js";
3
3
  //#region src/rollup/attendance.ts
4
4
  async function attendanceSources(db, actor, period, attribution = "clip") {
5
5
  const punches = await AttendancePunchCollection.create({ db });
@@ -57,4 +57,4 @@ async function attendanceSources(db, actor, period, attribution = "clip") {
57
57
  //#endregion
58
58
  export { attendanceSources };
59
59
 
60
- //# sourceMappingURL=attendance-CWyi7Q-t.js.map
60
+ //# sourceMappingURL=attendance-C_hWJJze.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"attendance-CWyi7Q-t.js","names":[],"sources":["../../src/rollup/attendance.ts"],"sourcesContent":["import type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n AttendanceBreakCollection,\n AttendancePunchCollection,\n} from '../attendance/models.js';\nimport { attributeSource, instant, integer } from './calculation.js';\nimport type {\n RollupAttribution,\n TimecardActor,\n TimecardPeriod,\n TimecardSource,\n} from './types.js';\n\n/** Optional attendance reader. Called on the rollup's transaction executor. */\nexport async function attendanceSources(\n db: DatabaseInterface,\n actor: TimecardActor,\n period: TimecardPeriod,\n attribution: RollupAttribution = 'clip',\n): Promise<{ sources: TimecardSource[]; linkedEntryIds: Set<string> }> {\n const punches = await AttendancePunchCollection.create({ db });\n const breaks = await AttendanceBreakCollection.create({ db });\n const sources: TimecardSource[] = [];\n const linkedEntryIds = new Set<string>();\n for (const punch of await punches.list({ where: { ...actor } })) {\n // A linked punch is authoritative even when pending review: never count its\n // evidence entry behind the review gate, or outside the punch's period.\n if (punch.serviceTimeEntryId) linkedEntryIds.add(punch.serviceTimeEntryId);\n if (!punch.endedAt || punch.reviewRequired) continue;\n const start = instant(punch.startedAt);\n const end = instant(punch.endedAt);\n if (end < start) throw new Error('Invalid attendance interval.');\n let cursor = start;\n let unpaidMs = 0;\n const spans: [number, number][] = [];\n for (const pause of await breaks.list({\n where: { tenantId: actor.tenantId, punchId: punch.id },\n orderBy: 'started_at ASC',\n })) {\n if (!pause.endedAt)\n throw new Error('Closed attendance has an open break.');\n const left = instant(pause.startedAt);\n const right = instant(pause.endedAt);\n if (left < cursor || right < left || right > end)\n throw new Error('Invalid or overlapping attendance breaks.');\n if (!pause.paid) {\n spans.push([cursor, left]);\n unpaidMs += right - left;\n } else {\n spans.push([cursor, right]);\n }\n cursor = right;\n }\n spans.push([cursor, end]);\n const net = Math.round((end - start - unpaidMs) / 1000);\n if (integer(punch.durationSeconds) !== net)\n throw new Error('Attendance duration does not match its breaks.');\n // Round elapsed paid prefixes once, preserving conservation across breaks.\n let paidMs = 0;\n for (const [left, right] of spans) {\n const seconds =\n Math.round((paidMs + right - left) / 1000) - Math.round(paidMs / 1000);\n paidMs += right - left;\n const source = attributeSource(\n {\n kind: 'attendance',\n id: String(punch.id),\n startsAt: new Date(left).toISOString(),\n endsAt: new Date(right).toISOString(),\n seconds,\n },\n period,\n attribution,\n start,\n );\n if (source?.seconds) sources.push(source);\n }\n }\n return { sources, linkedEntryIds };\n}\n"],"mappings":";;;AAcA,eAAsB,kBACpB,IACA,OACA,QACA,cAAiC,QACoC;CACrE,MAAM,UAAU,MAAM,0BAA0B,OAAO,EAAE,GAAG,CAAC;CAC7D,MAAM,SAAS,MAAM,0BAA0B,OAAO,EAAE,GAAG,CAAC;CAC5D,MAAM,UAA4B,CAAC;CACnC,MAAM,iCAAiB,IAAI,IAAY;CACvC,KAAA,MAAW,SAAS,MAAM,QAAQ,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG;EAG/D,IAAI,MAAM,oBAAoB,eAAe,IAAI,MAAM,kBAAkB;EACzE,IAAI,CAAC,MAAM,WAAW,MAAM,gBAAgB;EAC5C,MAAM,QAAQ,QAAQ,MAAM,SAAS;EACrC,MAAM,MAAM,QAAQ,MAAM,OAAO;EACjC,IAAI,MAAM,OAAO,MAAM,IAAI,MAAM,8BAA8B;EAC/D,IAAI,SAAS;EACb,IAAI,WAAW;EACf,MAAM,QAA4B,CAAC;EACnC,KAAA,MAAW,SAAS,MAAM,OAAO,KAAK;GACpC,OAAO;IAAE,UAAU,MAAM;IAAU,SAAS,MAAM;GAAG;GACrD,SAAS;EACX,CAAC,GAAG;GACF,IAAI,CAAC,MAAM,SACT,MAAM,IAAI,MAAM,sCAAsC;GACxD,MAAM,OAAO,QAAQ,MAAM,SAAS;GACpC,MAAM,QAAQ,QAAQ,MAAM,OAAO;GACnC,IAAI,OAAO,UAAU,QAAQ,QAAQ,QAAQ,KAC3C,MAAM,IAAI,MAAM,2CAA2C;GAC7D,IAAI,CAAC,MAAM,MAAM;IACf,MAAM,KAAK,CAAC,QAAQ,IAAI,CAAC;IACzB,YAAY,QAAQ;GACtB,OACE,MAAM,KAAK,CAAC,QAAQ,KAAK,CAAC;GAE5B,SAAS;EACX;EACA,MAAM,KAAK,CAAC,QAAQ,GAAG,CAAC;EACxB,MAAM,MAAM,KAAK,OAAO,MAAM,QAAQ,YAAY,GAAI;EACtD,IAAI,QAAQ,MAAM,eAAe,MAAM,KACrC,MAAM,IAAI,MAAM,gDAAgD;EAElE,IAAI,SAAS;EACb,KAAA,MAAW,CAAC,MAAM,UAAU,OAAO;GACjC,MAAM,UACJ,KAAK,OAAO,SAAS,QAAQ,QAAQ,GAAI,IAAI,KAAK,MAAM,SAAS,GAAI;GACvE,UAAU,QAAQ;GAClB,MAAM,SAAS,gBACb;IACE,MAAM;IACN,IAAI,OAAO,MAAM,EAAE;IACnB,UAAU,IAAI,KAAK,IAAI,CAAA,CAAE,YAAY;IACrC,QAAQ,IAAI,KAAK,KAAK,CAAA,CAAE,YAAY;IACpC;GACF,GACA,QACA,aACA,KACF;GACA,IAAI,QAAQ,SAAS,QAAQ,KAAK,MAAM;EAC1C;CACF;CACA,OAAO;EAAE;EAAS;CAAe;AACnC"}
1
+ {"version":3,"file":"attendance-C_hWJJze.js","names":[],"sources":["../../src/rollup/attendance.ts"],"sourcesContent":["import type { DatabaseInterface } from '@happyvertical/sql';\nimport {\n AttendanceBreakCollection,\n AttendancePunchCollection,\n} from '../attendance/models.js';\nimport { attributeSource, instant, integer } from './calculation.js';\nimport type {\n RollupAttribution,\n TimecardActor,\n TimecardPeriod,\n TimecardSource,\n} from './types.js';\n\n/** Optional attendance reader. Called on the rollup's transaction executor. */\nexport async function attendanceSources(\n db: DatabaseInterface,\n actor: TimecardActor,\n period: TimecardPeriod,\n attribution: RollupAttribution = 'clip',\n): Promise<{ sources: TimecardSource[]; linkedEntryIds: Set<string> }> {\n const punches = await AttendancePunchCollection.create({ db });\n const breaks = await AttendanceBreakCollection.create({ db });\n const sources: TimecardSource[] = [];\n const linkedEntryIds = new Set<string>();\n for (const punch of await punches.list({ where: { ...actor } })) {\n // A linked punch is authoritative even when pending review: never count its\n // evidence entry behind the review gate, or outside the punch's period.\n if (punch.serviceTimeEntryId) linkedEntryIds.add(punch.serviceTimeEntryId);\n if (!punch.endedAt || punch.reviewRequired) continue;\n const start = instant(punch.startedAt);\n const end = instant(punch.endedAt);\n if (end < start) throw new Error('Invalid attendance interval.');\n let cursor = start;\n let unpaidMs = 0;\n const spans: [number, number][] = [];\n for (const pause of await breaks.list({\n where: { tenantId: actor.tenantId, punchId: punch.id },\n orderBy: 'started_at ASC',\n })) {\n if (!pause.endedAt)\n throw new Error('Closed attendance has an open break.');\n const left = instant(pause.startedAt);\n const right = instant(pause.endedAt);\n if (left < cursor || right < left || right > end)\n throw new Error('Invalid or overlapping attendance breaks.');\n if (!pause.paid) {\n spans.push([cursor, left]);\n unpaidMs += right - left;\n } else {\n spans.push([cursor, right]);\n }\n cursor = right;\n }\n spans.push([cursor, end]);\n const net = Math.round((end - start - unpaidMs) / 1000);\n if (integer(punch.durationSeconds) !== net)\n throw new Error('Attendance duration does not match its breaks.');\n // Round elapsed paid prefixes once, preserving conservation across breaks.\n let paidMs = 0;\n for (const [left, right] of spans) {\n const seconds =\n Math.round((paidMs + right - left) / 1000) - Math.round(paidMs / 1000);\n paidMs += right - left;\n const source = attributeSource(\n {\n kind: 'attendance',\n id: String(punch.id),\n startsAt: new Date(left).toISOString(),\n endsAt: new Date(right).toISOString(),\n seconds,\n },\n period,\n attribution,\n start,\n );\n if (source?.seconds) sources.push(source);\n }\n }\n return { sources, linkedEntryIds };\n}\n"],"mappings":";;;AAcA,eAAsB,kBACpB,IACA,OACA,QACA,cAAiC,QACoC;CACrE,MAAM,UAAU,MAAM,0BAA0B,OAAO,EAAE,GAAG,CAAC;CAC7D,MAAM,SAAS,MAAM,0BAA0B,OAAO,EAAE,GAAG,CAAC;CAC5D,MAAM,UAA4B,CAAC;CACnC,MAAM,iCAAiB,IAAI,IAAY;CACvC,KAAA,MAAW,SAAS,MAAM,QAAQ,KAAK,EAAE,OAAO,EAAE,GAAG,MAAM,EAAE,CAAC,GAAG;EAG/D,IAAI,MAAM,oBAAoB,eAAe,IAAI,MAAM,kBAAkB;EACzE,IAAI,CAAC,MAAM,WAAW,MAAM,gBAAgB;EAC5C,MAAM,QAAQ,QAAQ,MAAM,SAAS;EACrC,MAAM,MAAM,QAAQ,MAAM,OAAO;EACjC,IAAI,MAAM,OAAO,MAAM,IAAI,MAAM,8BAA8B;EAC/D,IAAI,SAAS;EACb,IAAI,WAAW;EACf,MAAM,QAA4B,CAAC;EACnC,KAAA,MAAW,SAAS,MAAM,OAAO,KAAK;GACpC,OAAO;IAAE,UAAU,MAAM;IAAU,SAAS,MAAM;GAAG;GACrD,SAAS;EACX,CAAC,GAAG;GACF,IAAI,CAAC,MAAM,SACT,MAAM,IAAI,MAAM,sCAAsC;GACxD,MAAM,OAAO,QAAQ,MAAM,SAAS;GACpC,MAAM,QAAQ,QAAQ,MAAM,OAAO;GACnC,IAAI,OAAO,UAAU,QAAQ,QAAQ,QAAQ,KAC3C,MAAM,IAAI,MAAM,2CAA2C;GAC7D,IAAI,CAAC,MAAM,MAAM;IACf,MAAM,KAAK,CAAC,QAAQ,IAAI,CAAC;IACzB,YAAY,QAAQ;GACtB,OACE,MAAM,KAAK,CAAC,QAAQ,KAAK,CAAC;GAE5B,SAAS;EACX;EACA,MAAM,KAAK,CAAC,QAAQ,GAAG,CAAC;EACxB,MAAM,MAAM,KAAK,OAAO,MAAM,QAAQ,YAAY,GAAI;EACtD,IAAI,QAAQ,MAAM,eAAe,MAAM,KACrC,MAAM,IAAI,MAAM,gDAAgD;EAElE,IAAI,SAAS;EACb,KAAA,MAAW,CAAC,MAAM,UAAU,OAAO;GACjC,MAAM,UACJ,KAAK,OAAO,SAAS,QAAQ,QAAQ,GAAI,IAAI,KAAK,MAAM,SAAS,GAAI;GACvE,UAAU,QAAQ;GAClB,MAAM,SAAS,gBACb;IACE,MAAM;IACN,IAAI,OAAO,MAAM,EAAE;IACnB,UAAU,IAAI,KAAK,IAAI,CAAA,CAAE,YAAY;IACrC,QAAQ,IAAI,KAAK,KAAK,CAAA,CAAE,YAAY;IACpC;GACF,GACA,QACA,aACA,KACF;GACA,IAAI,QAAQ,SAAS,QAAQ,KAAK,MAAM;EAC1C;CACF;CACA,OAAO;EAAE;EAAS;CAAe;AACnC"}
@@ -1,5 +1,5 @@
1
- import { i as ServiceTimeEntryCollection, o as parseTimesheetJson } from "./service-time-entry-Bd3NQr90.js";
2
- import { c as AttendanceSegmentCollection, d as persistAutoClose, f as persistCorrection, i as AttendancePunchCollection, l as deleteCorrection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, s as AttendanceSegment, t as AttendanceBreak, u as isCorrectionWrite } from "./models-CRnsNezh.js";
1
+ import { i as ServiceTimeEntryCollection, o as parseTimesheetJson } from "./service-time-entry-De3Y9_ho.js";
2
+ import { c as AttendanceSegmentCollection, d as persistAutoClose, f as persistCorrection, i as AttendancePunchCollection, l as deleteCorrection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, s as AttendanceSegment, t as AttendanceBreak, u as isCorrectionWrite } from "./models-D0VhW-5I.js";
3
3
  import { SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, isEmbeddedDatabase, isPostgresDatabase, smrt, withEmbeddedWriteTransaction } from "@happyvertical/smrt-core";
4
4
  import { TenantScoped, getTenantId, tenantId, withTenant } from "@happyvertical/smrt-tenancy";
5
5
  //#region src/attendance/correction-models.ts
@@ -61,7 +61,7 @@ var AttendanceCorrection = class extends SmrtObject {
61
61
  getAfter() {
62
62
  return parseTimesheetJson(this.afterState, null);
63
63
  }
64
- async save() {
64
+ async save(options) {
65
65
  if (!isCorrectionWrite(this)) throw new Error("Attendance corrections are writable only through AttendanceCorrectionService.");
66
66
  if (!this.tenantId || !this.subjectProfileId || !this.actorProfileId || !this.punchId || !this.targetId || !ATTENDANCE_CORRECTION_KINDS.includes(this.kind) || typeof this.reason !== "string" || !this.reason.trim() || typeof this.acknowledgementRequired !== "boolean") throw new Error("Invalid attendance correction.");
67
67
  for (const json of [this.beforeState, this.afterState]) JSON.parse(json);
@@ -77,7 +77,7 @@ var AttendanceCorrection = class extends SmrtObject {
77
77
  if (IMMUTABLE_COLUMNS.some((column) => prior[column] !== row[camel(column)]) || Boolean(prior.acknowledgement_required) !== this.acknowledgementRequired || prior.acknowledged_at && (new Date(prior.acknowledged_at).getTime() !== this.acknowledgedAt?.getTime() || prior.acknowledged_by_profile_id !== this.acknowledgedByProfileId)) throw new Error("Attendance corrections are append-only; only a first acknowledgement may change.");
78
78
  }
79
79
  this.id ??= crypto.randomUUID();
80
- return super.save();
80
+ return super.save(options);
81
81
  }
82
82
  async delete() {
83
83
  throw new Error("Attendance correction history cannot be deleted.");
@@ -1397,4 +1397,4 @@ var AttendanceCorrectionService = class {
1397
1397
  //#endregion
1398
1398
  export { continueSegment as a, openSegment as c, validateAttendanceWork as d, ATTENDANCE_CORRECTION_KINDS as f, closeOpenSegment as i, replaceSegment as l, AttendanceCorrectionCollection as m, AttendanceService as n, endSegment as o, AttendanceCorrection as p, beginSegment as r, listSegments as s, AttendanceCorrectionService as t, AttendanceConflict as u };
1399
1399
 
1400
- //# sourceMappingURL=attendance-zF-wCzSW.js.map
1400
+ //# sourceMappingURL=attendance-ClXOMLAM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attendance-ClXOMLAM.js","names":["unpaidMilliseconds","outcome"],"sources":["../../src/attendance/correction-models.ts","../../src/attendance/context.ts","../../src/attendance/segments.ts","../../src/attendance/service.ts","../../src/attendance/correction-service.ts"],"sourcesContent":["import {\n crossPackageRef,\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n type SmrtSaveOptions,\n smrt,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\nimport { parseTimesheetJson } from '../models/json.js';\nimport { AttendancePunch } from './models.js';\nimport { isCorrectionWrite } from './write.js';\n\n/** What a correction did. Punch kinds target the punch itself. */\nexport const ATTENDANCE_CORRECTION_KINDS = [\n 'punch.corrected',\n 'punch.added',\n 'break.added',\n 'break.changed',\n 'break.removed',\n 'segment.added',\n 'segment.changed',\n 'segment.removed',\n] as const;\nexport type AttendanceCorrectionKind =\n (typeof ATTENDANCE_CORRECTION_KINDS)[number];\n\nconst IMMUTABLE_COLUMNS = [\n 'tenant_id',\n 'subject_profile_id',\n 'actor_profile_id',\n 'kind',\n 'punch_id',\n 'target_id',\n 'before_state',\n 'after_state',\n 'reason',\n] as const;\n\n/**\n * One append-only change to closed attendance: who changed whose time, why, and\n * the before/after values as JSON (`null` for an addition's before or a\n * removal's after). Written only by `AttendanceCorrectionService`, in the same\n * transaction as the change. After insert only the acknowledgement may be set,\n * once, by the subject; rows are never deleted.\n */\n@TenantScoped({ mode: 'required' })\n@smrt({\n tableName: 'attendance_corrections',\n sensitive: true,\n indexes: [\n {\n name: 'attendance_corrections_punch_idx',\n columns: ['tenantId', 'punchId'],\n },\n {\n name: 'attendance_corrections_subject_idx',\n columns: ['tenantId', 'subjectProfileId'],\n },\n ],\n api: { include: [] },\n cli: { include: [] },\n mcp: { include: [] },\n})\nexport class AttendanceCorrection extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-timesheets\";\n @tenantId() tenantId = '';\n /** Whose time was corrected. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n subjectProfileId = '';\n /** Who made the correction. */\n @crossPackageRef('@happyvertical/smrt-profiles:Profile')\n actorProfileId = '';\n @field({ type: 'text' }) kind: AttendanceCorrectionKind = 'punch.corrected';\n @foreignKey(AttendancePunch) punchId = '';\n /** The break or segment id for those kinds; the punch id for punch kinds. */\n targetId = '';\n @field({ type: 'text' }) beforeState = 'null';\n @field({ type: 'text' }) afterState = 'null';\n @field({ type: 'text' }) reason = '';\n acknowledgementRequired = false;\n acknowledgedAt: Date | null = null;\n @crossPackageRef('@happyvertical/smrt-profiles:Profile', { nullable: true })\n acknowledgedByProfileId: string | null = null;\n\n /** The values before the change, or null for an addition. */\n getBefore<T = Record<string, unknown>>(): T | null {\n return parseTimesheetJson<T | null>(this.beforeState, null);\n }\n /** The values after the change, or null for a removal. */\n getAfter<T = Record<string, unknown>>(): T | null {\n return parseTimesheetJson<T | null>(this.afterState, null);\n }\n\n override async save(options?: SmrtSaveOptions): Promise<this> {\n // Insert and acknowledgement are both service-only: a generic save() or\n // collection create() must not fabricate or countersign ledger history.\n if (!isCorrectionWrite(this))\n throw new Error(\n 'Attendance corrections are writable only through AttendanceCorrectionService.',\n );\n if (\n !this.tenantId ||\n !this.subjectProfileId ||\n !this.actorProfileId ||\n !this.punchId ||\n !this.targetId ||\n !ATTENDANCE_CORRECTION_KINDS.includes(this.kind) ||\n typeof this.reason !== 'string' ||\n !this.reason.trim() ||\n typeof this.acknowledgementRequired !== 'boolean'\n )\n throw new Error('Invalid attendance correction.');\n for (const json of [this.beforeState, this.afterState]) JSON.parse(json);\n if (!!this.acknowledgedAt !== !!this.acknowledgedByProfileId)\n throw new Error('Acknowledgement needs both a time and a profile.');\n if (this.acknowledgedAt) {\n if (!this.acknowledgementRequired)\n throw new Error('This correction does not require acknowledgement.');\n if (this.acknowledgedByProfileId !== this.subjectProfileId)\n throw new Error('Only the subject can acknowledge a correction.');\n }\n const prior = this.id\n ? await this.db.get(this.tableName, { id: this.id })\n : null;\n if (prior) {\n const row = this as unknown as Record<string, unknown>;\n const camel = (column: string) =>\n column.replace(/_([a-z])/g, (_, c: string) => c.toUpperCase());\n if (\n IMMUTABLE_COLUMNS.some(\n (column) => prior[column] !== row[camel(column)],\n ) ||\n Boolean(prior.acknowledgement_required) !==\n this.acknowledgementRequired ||\n (prior.acknowledged_at &&\n (new Date(prior.acknowledged_at as string).getTime() !==\n this.acknowledgedAt?.getTime() ||\n prior.acknowledged_by_profile_id !== this.acknowledgedByProfileId))\n )\n throw new Error(\n 'Attendance corrections are append-only; only a first acknowledgement may change.',\n );\n }\n this.id ??= crypto.randomUUID();\n return super.save(options);\n }\n\n override async delete(): Promise<void> {\n throw new Error('Attendance correction history cannot be deleted.');\n }\n}\n\n/** The correction ledger. */\nexport class AttendanceCorrectionCollection extends SmrtCollection<AttendanceCorrection> {\n static readonly _itemClass = AttendanceCorrection;\n}\n","import { isPostgresDatabase } from '@happyvertical/smrt-core';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport type {\n AttendanceBreakCollection,\n AttendancePunchCollection,\n AttendanceReplayCollection,\n AttendanceSegmentCollection,\n} from './models.js';\n\n/** Resolve these identifiers from the authenticated session, never from tap input. */\nexport interface AttendanceActor {\n tenantId: string;\n profileId: string;\n}\n/**\n * Explicit work attribution for a closed punch's draft evidence entry or for a\n * running work segment. `taskRefType`/`taskRefId` (both or neither) name an\n * optional second reference such as an operation; `kind` is an optional short\n * consumer lane label.\n */\nexport interface AttendanceWork {\n workRefType: string;\n workRefId: string;\n description: string;\n taskRefType?: string;\n taskRefId?: string;\n kind?: string;\n}\n\n/**\n * Where a punch was captured: a consumer-owned type (for example a class name\n * such as a station or tablet) and that device's id. Both or neither.\n */\nexport interface AttendanceDeviceRef {\n type: string;\n id: string;\n}\n\n/** Optional provenance recorded when a punch opens. */\nexport interface AttendancePunchOptions {\n /** Short consumer-owned label such as `device`, `web`, `import`, `correction`. */\n source?: string;\n /** The device that captured the punch. */\n device?: AttendanceDeviceRef;\n}\n\n/** Optional detail recorded when a break starts. */\nexport interface AttendanceBreakOptions {\n /** Short consumer-owned label such as `meal` or `rest`. */\n kind?: string;\n}\n\nconst MAX_LABEL = 64;\n\n/** Validate an optional short label (`source`, `kind`, device type); returns the stored form. */\nexport function attendanceLabel(value: unknown, name: string): string {\n if (value === undefined || value === null) return '';\n if (\n typeof value !== 'string' ||\n value !== value.trim() ||\n value.length > MAX_LABEL\n )\n throw new AttendanceConflict(\n `${name} must be a trimmed string of at most ${MAX_LABEL} characters.`,\n 'invalid',\n );\n return value;\n}\n\n/** Validate punch provenance; returns the stored column values. */\nexport function attendanceProvenance(options?: AttendancePunchOptions): {\n source: string;\n deviceRefType: string;\n deviceRefId: string;\n} {\n const source = attendanceLabel(options?.source, 'source');\n const device = options?.device;\n if (device !== undefined && (!device || typeof device !== 'object'))\n throw new AttendanceConflict('device must be { type, id }.', 'invalid');\n const deviceRefType = attendanceLabel(device?.type, 'device.type');\n const deviceRefId = attendanceLabel(device?.id, 'device.id');\n if (!!deviceRefType !== !!deviceRefId)\n throw new AttendanceConflict(\n 'device.type and device.id must be provided together.',\n 'invalid',\n );\n return { source, deviceRefType, deviceRefId };\n}\n\n/** Expected state conflict, distinct from retryable database failures. */\nexport class AttendanceConflict extends Error {\n /**\n * Stable machine-readable reason (see {@link AttendanceRefusalCode}); stored\n * on a refused replay outcome so a device screen can say why.\n */\n readonly code: AttendanceRefusalCode;\n constructor(message: string, code: AttendanceRefusalCode = 'conflict') {\n super(message);\n this.code = code;\n }\n}\n\n/**\n * Built-in refusal codes. Consumers may store any other string through the\n * `refusalCode` replay hook.\n */\nexport type AttendanceRefusalCode =\n | 'conflict'\n | 'invalid'\n | 'predates_committed'\n | 'punch_open'\n | 'no_open_punch'\n | 'break_open'\n | 'no_open_break'\n | 'during_break'\n | 'work_open'\n | 'no_open_work'\n | 'no_resumable_work'\n | (string & {});\n\n/**\n * Collections bound to one transaction executor. Handed to\n * `AttendanceService.withTransaction` callbacks and to the segment helpers so\n * corrections and replay can compose several mutations atomically.\n */\nexport type AttendanceContext = {\n db: DatabaseInterface;\n punches: AttendancePunchCollection;\n breaks: AttendanceBreakCollection;\n segments: AttendanceSegmentCollection;\n replays: AttendanceReplayCollection;\n};\n\n/** Validate a work reference; throws {@link AttendanceConflict}. */\nexport function validateAttendanceWork(work: AttendanceWork): void {\n if (\n !work ||\n typeof work.workRefType !== 'string' ||\n !work.workRefType ||\n typeof work.workRefId !== 'string' ||\n !work.workRefId ||\n typeof work.description !== 'string'\n )\n throw new AttendanceConflict(\n 'A complete work reference and description are required.',\n );\n for (const key of ['taskRefType', 'taskRefId', 'kind'] as const)\n if (work[key] !== undefined && typeof work[key] !== 'string')\n throw new AttendanceConflict(`${key} must be a string.`);\n if (!!work.taskRefType !== !!work.taskRefId)\n throw new AttendanceConflict(\n 'taskRefType and taskRefId must be provided together.',\n );\n}\n\n/** Canonicalize a tenant/profile id: PostgreSQL requires UUIDs, other adapters take it verbatim. */\nexport function attendanceIdentity(\n db: DatabaseInterface,\n value: string,\n): string {\n if (!isPostgresDatabase(db)) return value;\n const hex = value.replace(/[{}-]/g, '').toLowerCase();\n if (!/^[0-9a-f]{32}$/.test(hex))\n throw new Error('PostgreSQL attendance identities must be UUIDs.');\n return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;\n}\n","import {\n AttendanceConflict,\n type AttendanceContext,\n type AttendanceWork,\n validateAttendanceWork,\n} from './context.js';\nimport type {\n AttendancePunch,\n AttendanceSegment,\n AttendanceSegmentCloseReason,\n} from './models.js';\n\n/*\n * Segment transitions on an already-open punch, run on the caller's transaction\n * context. `AttendanceService` composes them; corrections and replay call them\n * inside `AttendanceService.withTransaction`. Callers own the actor lock and\n * punch lookup; these helpers own break and one-open-segment rules.\n */\n\n/** The open segment of a punch, or null. */\nexport async function openSegment(\n tx: AttendanceContext,\n punch: AttendancePunch,\n): Promise<AttendanceSegment | null> {\n const [segment] = await tx.segments.list({\n where: { tenantId: punch.tenantId, punchId: punch.id, endedAt: null },\n limit: 1,\n });\n return segment ?? null;\n}\n\n/** All segments of a punch, oldest first. */\nexport async function listSegments(\n tx: AttendanceContext,\n punch: AttendancePunch,\n): Promise<AttendanceSegment[]> {\n return tx.segments.list({\n where: { tenantId: punch.tenantId, punchId: punch.id },\n orderBy: 'started_at ASC',\n });\n}\n\n/** Close the punch's open segment, if any. Returns it, or null when none was open. */\nexport async function closeOpenSegment(\n tx: AttendanceContext,\n punch: AttendancePunch,\n at: Date,\n reason: Exclude<AttendanceSegmentCloseReason, ''>,\n): Promise<AttendanceSegment | null> {\n const segment = await openSegment(tx, punch);\n if (!segment) return null;\n if (at < segment.startedAt)\n throw new AttendanceConflict('Segment cannot end before it starts.');\n segment.endedAt = at;\n segment.closedReason = reason;\n await segment.save();\n return segment;\n}\n\n/** Open a segment; refuses while a break or another segment is open. */\nexport async function beginSegment(\n tx: AttendanceContext,\n punch: AttendancePunch,\n at: Date,\n work: AttendanceWork,\n): Promise<AttendanceSegment> {\n validateAttendanceWork(work);\n if (punch.endedAt) throw new AttendanceConflict('Punch is closed.');\n const breaks = await tx.breaks.list({\n where: { tenantId: punch.tenantId, punchId: punch.id },\n });\n if (breaks.some((b) => !b.endedAt))\n throw new AttendanceConflict(\n 'Cannot work during an open break.',\n 'during_break',\n );\n if (await openSegment(tx, punch))\n throw new AttendanceConflict(\n 'A work segment is already open.',\n 'work_open',\n );\n return tx.segments.create({\n tenantId: punch.tenantId,\n punchId: punch.id ?? undefined,\n profileId: punch.profileId,\n workRefType: work.workRefType,\n workRefId: work.workRefId,\n taskRefType: work.taskRefType ?? '',\n taskRefId: work.taskRefId ?? '',\n kind: work.kind ?? '',\n description: work.description,\n startedAt: at,\n _insertOnly: true,\n });\n}\n\n/** Atomically close the open segment and open the next at the same instant. */\nexport async function replaceSegment(\n tx: AttendanceContext,\n punch: AttendancePunch,\n at: Date,\n work: AttendanceWork,\n): Promise<AttendanceSegment> {\n validateAttendanceWork(work);\n if (!(await closeOpenSegment(tx, punch, at, 'switch')))\n throw new AttendanceConflict(\n 'No open work segment to switch.',\n 'no_open_work',\n );\n return beginSegment(tx, punch, at, work);\n}\n\n/** Close the open segment (`stop`); refuses when none is open. */\nexport async function endSegment(\n tx: AttendanceContext,\n punch: AttendancePunch,\n at: Date,\n): Promise<AttendanceSegment> {\n const segment = await closeOpenSegment(tx, punch, at, 'stop');\n if (!segment)\n throw new AttendanceConflict('No open work segment.', 'no_open_work');\n return segment;\n}\n\n/**\n * Reopen the work a break interrupted: a new segment with the same references\n * as the latest segment, which must have been closed by `startBreak`.\n */\nexport async function continueSegment(\n tx: AttendanceContext,\n punch: AttendancePunch,\n at: Date,\n): Promise<AttendanceSegment> {\n const all = await listSegments(tx, punch);\n const last = all[all.length - 1];\n // Only the latest break may be the one that interrupted the work: a later,\n // idle break (taken after the work was left unresumed) must not reopen it.\n const breaks = await tx.breaks.list({\n where: { tenantId: punch.tenantId, punchId: punch.id },\n orderBy: 'started_at DESC',\n limit: 1,\n });\n if (\n last?.closedReason !== 'break' ||\n !last.endedAt ||\n last.endedAt.getTime() !== breaks[0]?.startedAt.getTime()\n )\n throw new AttendanceConflict(\n 'No work interrupted by a break to resume.',\n 'no_resumable_work',\n );\n return beginSegment(tx, punch, at, last);\n}\n","import {\n isEmbeddedDatabase,\n isPostgresDatabase,\n withEmbeddedWriteTransaction,\n} from '@happyvertical/smrt-core';\nimport { getTenantId, withTenant } from '@happyvertical/smrt-tenancy';\nimport type { DatabaseInterface } from '@happyvertical/sql';\nimport { parseTimesheetJson } from '../models/json.js';\nimport { ServiceTimeEntryCollection } from '../models/service-time-entry.js';\nimport {\n type AttendanceActor,\n type AttendanceBreakOptions,\n AttendanceConflict,\n type AttendanceContext,\n type AttendanceDeviceRef,\n type AttendancePunchOptions,\n type AttendanceRefusalCode,\n type AttendanceWork,\n attendanceIdentity,\n attendanceLabel,\n attendanceProvenance,\n validateAttendanceWork,\n} from './context.js';\nimport {\n AttendanceBreakCollection,\n AttendancePunch,\n AttendancePunchCollection,\n AttendanceReplayCollection,\n type AttendanceReplayOutcome,\n AttendanceSegment,\n AttendanceSegmentCollection,\n} from './models.js';\nimport {\n beginSegment,\n closeOpenSegment,\n continueSegment,\n endSegment,\n listSegments,\n openSegment,\n replaceSegment,\n} from './segments.js';\nimport { persistAutoClose } from './write.js';\n\n/** Whether stored evidence metadata carries this work's task reference and kind. */\nfunction sameAttribution(metadata: string, work: AttendanceWork): boolean {\n const stored = parseTimesheetJson<Record<string, unknown>>(metadata, {});\n return (\n (stored.taskRefType ?? '') === (work.taskRefType ?? '') &&\n (stored.taskRefId ?? '') === (work.taskRefId ?? '') &&\n (stored.kind ?? '') === (work.kind ?? '')\n );\n}\n\nexport {\n type AttendanceActor,\n type AttendanceBreakOptions,\n AttendanceConflict,\n type AttendanceContext,\n type AttendanceDeviceRef,\n type AttendancePunchOptions,\n type AttendanceRefusalCode,\n type AttendanceWork,\n validateAttendanceWork,\n} from './context.js';\nexport type { AttendanceReplayOutcome } from './models.js';\nexport * from './segments.js';\n\n/** Offline command with a durable client-generated identifier and device timestamp. */\nexport interface AttendanceTap {\n clientId: string;\n at: string;\n action: AttendanceTapAction;\n paid?: boolean;\n /** Required by `startWork` and `switchWork`; also links evidence on `punchOut`. */\n work?: AttendanceWork;\n /** Recorded on the punch by `punchIn`; hashed with the tap. */\n source?: string;\n /** Recorded on the punch by `punchIn`; hashed with the tap. */\n device?: AttendanceDeviceRef;\n /** Recorded on the break by `startBreak`; hashed with the tap. */\n kind?: string;\n}\n\n/** Punch and break actions plus the work-segment actions (`stopWork` is \"pause\"). */\nexport type AttendanceTapAction =\n | 'punchIn'\n | 'punchOut'\n | 'startBreak'\n | 'endBreak'\n | 'startWork'\n | 'switchWork'\n | 'stopWork'\n | 'resumeWork';\n\nconst TAP_ACTIONS: readonly string[] = [\n 'punchIn',\n 'punchOut',\n 'startBreak',\n 'endBreak',\n 'startWork',\n 'switchWork',\n 'stopWork',\n 'resumeWork',\n];\n\n/** What a time policy sees for one tap that has not been replayed yet. */\nexport interface AttendanceTimeInput {\n /** The tap exactly as sent. */\n tap: AttendanceTap;\n /** The tap's device time. */\n deviceAt: Date;\n /** When the server received the batch. */\n serverNow: Date;\n /** `serverNow - deviceAt` in milliseconds: how long the tap waited. */\n waitedMs: number;\n /** The trusted actor the tap replays for. */\n actor: AttendanceActor;\n}\n\n/** The effective time a policy chose, and whether a person should look at it. */\nexport interface AttendanceResolvedTime {\n at: Date;\n /**\n * Whether a person should review the result. Applies to the punch (default\n * true when omitted) and, when true, the resulting work segment. False does\n * not clear a punch's existing review requirement; use a reviewed correction.\n */\n reviewRequired?: boolean;\n /** Marks the punch offline (default true); false never clears an earlier flag. */\n recordedOffline?: boolean;\n}\n\n/** Why a consumer refuses or rewrites the stored reason of a refused tap. */\nexport interface AttendanceRefusal {\n code: AttendanceRefusalCode;\n /** Replaces the default message when given. */\n message?: string;\n}\n\n/** A resolved auto-close deadline and, optionally, why the punch closed then. */\nexport interface AttendanceAutoCloseDecision {\n deadline: Date;\n /** Recorded as `autoCloseReason` (1 to 200 characters); defaults to `deadline`. */\n reason?: string;\n}\n\n/**\n * Fixed maximum open seconds, or a per-punch resolver returning the deadline\n * (a Date or a decision) or null to leave the punch open.\n */\nexport type AttendanceAutoCloseDeadline =\n | number\n | ((\n punch: AttendancePunch,\n ) =>\n | Date\n | AttendanceAutoCloseDecision\n | null\n | undefined\n | Promise<Date | AttendanceAutoCloseDecision | null | undefined>);\n\nexport interface AttendanceReplayOptions {\n /**\n * Choose each tap's effective time (for example the device time inside a\n * window, else the server arrival time). The receipt still hashes the tap as\n * sent, so retries with the same clientId match; the resolved time is what is\n * stored. Called once per tap that has no receipt yet, inside its transaction.\n */\n resolveAt?: (\n input: AttendanceTimeInput,\n ) => AttendanceResolvedTime | Promise<AttendanceResolvedTime>;\n /** Clock for `serverNow`; defaults to `new Date()` per tap. */\n now?: () => Date;\n /**\n * Name the stored code (and optionally message) of a refused tap. Without it,\n * the refusal's own `AttendanceConflict.code` is stored.\n */\n refusal?: (\n tap: AttendanceTap,\n error: AttendanceConflict,\n ) => AttendanceRefusal | undefined | void;\n}\n\ntype Context = AttendanceContext;\n\n/**\n * Attendance mutations bound to a trusted tenant/profile. Applications authorize\n * the actor before constructing this service. Each transition is atomic; all\n * participating collections use the transaction executor. PostgreSQL serializes\n * this actor with an advisory lock; embedded adapters serialize writers.\n */\nexport class AttendanceService {\n constructor(\n private readonly db: DatabaseInterface,\n private readonly actor: AttendanceActor,\n ) {\n if (!actor.tenantId || !actor.profileId)\n throw new Error('Attendance requires a trusted tenant/profile actor.');\n this.actor = {\n tenantId: this.identity(actor.tenantId),\n profileId: this.identity(actor.profileId),\n };\n }\n\n private identity(value: string): string {\n return attendanceIdentity(this.db, value);\n }\n\n /**\n * Run `operation` in the actor's serialized attendance transaction. The\n * context's collections share the executor, so corrections and replay can\n * compose several attendance mutations (with the segment helpers) atomically.\n * Results that are punches or segments are re-read after commit.\n */\n async withTransaction<T>(\n operation: (context: AttendanceContext) => Promise<T>,\n ): Promise<T> {\n return this.transact(operation);\n }\n\n private async transact<T>(\n operation: (context: Context) => Promise<T>,\n ): Promise<T> {\n const current = getTenantId();\n if (current && this.identity(current) !== this.actor.tenantId)\n throw new Error('Attendance actor differs from active tenant.');\n return withTenant({ tenantId: this.actor.tenantId }, async () => {\n const result = await withEmbeddedWriteTransaction(\n this.db,\n isEmbeddedDatabase(this.db),\n async (db) => {\n if (isPostgresDatabase(db))\n await db.query(\n 'SELECT pg_advisory_xact_lock(hashtextextended($1, 0))',\n JSON.stringify([\n 'smrt.attendance',\n this.actor.tenantId,\n this.actor.profileId,\n ]),\n );\n return operation({\n db,\n punches: await AttendancePunchCollection.create({ db }),\n breaks: await AttendanceBreakCollection.create({ db }),\n segments: await AttendanceSegmentCollection.create({ db }),\n replays: await AttendanceReplayCollection.create({ db }),\n });\n },\n true,\n );\n if (result instanceof AttendancePunch) {\n const punches = await AttendancePunchCollection.create({ db: this.db });\n const [fresh] = await punches.list({\n where: { ...this.actor, id: result.id },\n limit: 1,\n });\n if (!fresh) throw new Error('Committed attendance punch disappeared.');\n return fresh as T;\n }\n if (result instanceof AttendanceSegment) {\n const segments = await AttendanceSegmentCollection.create({\n db: this.db,\n });\n const [fresh] = await segments.list({\n where: { tenantId: this.actor.tenantId, id: result.id },\n limit: 1,\n });\n if (!fresh)\n throw new Error('Committed attendance segment disappeared.');\n return fresh as T;\n }\n return result;\n });\n }\n\n private date(at: Date): Date {\n if (!(at instanceof Date) || !Number.isFinite(at.getTime()))\n throw new AttendanceConflict(\n 'Attendance timestamps must be valid dates.',\n );\n return at;\n }\n\n private async open(tx: Context): Promise<AttendancePunch> {\n const [punch] = await tx.punches.list({\n where: { ...this.actor, endedAt: null },\n limit: 1,\n });\n if (!punch) throw new AttendanceConflict('No open punch.', 'no_open_punch');\n return punch;\n }\n\n private async chronological(tx: Context, at: Date): Promise<void> {\n const open = await tx.punches.list({\n where: { ...this.actor, endedAt: null },\n limit: 1,\n });\n const rows = open.length\n ? open\n : await tx.punches.list({\n where: { ...this.actor },\n orderBy: 'ended_at DESC',\n limit: 1,\n });\n if (!rows.length) return;\n const punch = rows[0];\n const breaks = await tx.breaks.list({\n where: { tenantId: this.actor.tenantId, punchId: punch.id },\n });\n const segments = await tx.segments.list({\n where: { tenantId: this.actor.tenantId, punchId: punch.id },\n });\n const latest = Math.max(\n punch.startedAt.getTime(),\n ...segments.flatMap((g) => [\n g.startedAt.getTime(),\n g.endedAt?.getTime() ?? 0,\n ]),\n punch.endedAt?.getTime() ?? 0,\n ...breaks.flatMap((b) => [\n b.startedAt.getTime(),\n b.endedAt?.getTime() ?? 0,\n ]),\n );\n if (at.getTime() < latest)\n throw new AttendanceConflict(\n 'Tap predates committed attendance; manual review required.',\n 'predates_committed',\n );\n }\n\n /** Open one punch; the database unique slot also protects direct model writers. */\n async punchIn(\n at = new Date(),\n options?: AttendancePunchOptions,\n ): Promise<AttendancePunch> {\n const meta = attendanceProvenance(options);\n return this.transact((tx) =>\n this.transition(tx, 'punchIn', this.date(at), false, undefined, false, {\n ...meta,\n kind: '',\n }),\n );\n }\n /** Close the punch and any active break; optionally create linked draft evidence. */\n async punchOut(at: Date, work?: AttendanceWork): Promise<AttendancePunch> {\n return this.transact((tx) =>\n this.transition(tx, 'punchOut', this.date(at), false, work),\n );\n }\n /** Begin a break; paid defaults false and must be explicitly configured by the caller. */\n async startBreak(\n at: Date,\n paid = false,\n options?: AttendanceBreakOptions,\n ): Promise<AttendancePunch> {\n const kind = attendanceLabel(options?.kind, 'kind');\n return this.transact((tx) =>\n this.transition(tx, 'startBreak', this.date(at), paid, undefined, false, {\n ...attendanceProvenance(),\n kind,\n }),\n );\n }\n /**\n * End the current break. With `{ resumeWork: true }` the work interrupted by\n * `startBreak` resumes at the same instant, atomically with the break end.\n */\n async endBreak(\n at: Date,\n options?: { resumeWork?: boolean },\n ): Promise<AttendancePunch> {\n return this.transact((tx) =>\n this.transition(\n tx,\n 'endBreak',\n this.date(at),\n false,\n undefined,\n options?.resumeWork,\n ),\n );\n }\n\n /** Open a work segment in the open punch; refuses during a break or while one is open. */\n async startWork(at: Date, work: AttendanceWork): Promise<AttendanceSegment> {\n return this.transact(async (tx) => {\n validateAttendanceWork(work);\n await this.chronological(tx, this.date(at));\n return beginSegment(tx, await this.open(tx), at, work);\n });\n }\n /** Atomically close the open segment and open the next one at `at`. */\n async switchWork(at: Date, work: AttendanceWork): Promise<AttendanceSegment> {\n return this.transact(async (tx) => {\n validateAttendanceWork(work);\n await this.chronological(tx, this.date(at));\n return replaceSegment(tx, await this.open(tx), at, work);\n });\n }\n /** Close the open segment without starting another. */\n async stopWork(at: Date): Promise<AttendanceSegment> {\n return this.transact(async (tx) => {\n await this.chronological(tx, this.date(at));\n return endSegment(tx, await this.open(tx), at);\n });\n }\n /** Reopen the work a break interrupted (the latest segment must have closed on `startBreak`). */\n async resumeWork(at: Date): Promise<AttendanceSegment> {\n return this.transact(async (tx) => {\n await this.chronological(tx, this.date(at));\n return continueSegment(tx, await this.open(tx), at);\n });\n }\n /** The open work segment of the actor's open punch, or null. */\n async currentWork(): Promise<AttendanceSegment | null> {\n return this.transact(async (tx) => {\n const [punch] = await tx.punches.list({\n where: { ...this.actor, endedAt: null },\n limit: 1,\n });\n return punch ? openSegment(tx, punch) : null;\n });\n }\n /** Work segments of one of the actor's punches, oldest first. */\n async segments(punchId: string): Promise<AttendanceSegment[]> {\n return this.transact(async (tx) => {\n const [punch] = await tx.punches.list({\n where: { ...this.actor, id: punchId },\n limit: 1,\n });\n if (!punch) throw new AttendanceConflict('Punch not found for actor.');\n return listSegments(tx, punch);\n });\n }\n\n private async transition(\n tx: Context,\n action: AttendanceTap['action'],\n at: Date,\n paid = false,\n work?: AttendanceWork,\n resumeWork = false,\n meta: ReturnType<typeof attendanceProvenance> & { kind: string } = {\n ...attendanceProvenance(),\n kind: '',\n },\n ): Promise<AttendancePunch> {\n await this.chronological(tx, at);\n if (action === 'punchIn') {\n if (\n (\n await tx.punches.list({\n where: { ...this.actor, endedAt: null },\n limit: 1,\n })\n ).length\n )\n throw new AttendanceConflict('A punch is already open.', 'punch_open');\n return tx.punches.create({\n ...this.actor,\n startedAt: at,\n source: meta.source,\n deviceRefType: meta.deviceRefType,\n deviceRefId: meta.deviceRefId,\n _insertOnly: true,\n });\n }\n const punch = await this.open(tx);\n const breaks = await tx.breaks.list({\n where: { tenantId: this.actor.tenantId, punchId: punch.id },\n });\n const active = breaks.find((b) => !b.endedAt);\n if (action === 'startBreak') {\n if (active)\n throw new AttendanceConflict('A break is already open.', 'break_open');\n if (typeof paid !== 'boolean')\n throw new AttendanceConflict('paid must be boolean.');\n await closeOpenSegment(tx, punch, at, 'break');\n await tx.breaks.create({\n tenantId: this.actor.tenantId,\n punchId: punch.id ?? undefined,\n startedAt: at,\n paid,\n kind: meta.kind,\n _insertOnly: true,\n });\n return punch;\n }\n if (action !== 'endBreak' && action !== 'punchOut')\n throw new AttendanceConflict('Unknown attendance action.');\n if (action === 'endBreak' && !active)\n throw new AttendanceConflict('No open break.', 'no_open_break');\n if (action === 'punchOut' && work) {\n this.validateWork(work);\n const unpaidMilliseconds = breaks\n .filter((b) => !b.paid)\n .reduce(\n (sum, b) => sum + (b.endedAt ?? at).getTime() - b.startedAt.getTime(),\n 0,\n );\n if (\n Math.round(\n (at.getTime() - punch.startedAt.getTime() - unpaidMilliseconds) /\n 1000,\n ) <= 0\n )\n throw new AttendanceConflict(\n 'Only closed punches with positive duration can produce service evidence.',\n );\n }\n if (active) {\n active.endedAt = at;\n await active.save();\n }\n if (action === 'endBreak') {\n if (resumeWork) await continueSegment(tx, punch, at);\n return punch;\n }\n await closeOpenSegment(tx, punch, at, 'punchOut');\n punch.endedAt = at;\n const unpaidMilliseconds = breaks\n .filter((b) => !b.paid)\n .reduce(\n (sum, b) => sum + b.endedAt!.getTime() - b.startedAt.getTime(),\n 0,\n );\n punch.unpaidBreakSeconds = Math.round(unpaidMilliseconds / 1000);\n punch.durationSeconds = Math.round(\n (at.getTime() - punch.startedAt.getTime() - unpaidMilliseconds) / 1000,\n );\n await punch.save();\n if (work) await this.link(tx, punch, work);\n return punch;\n }\n\n /** Run one replayed tap on `tx`; work actions share the punch changes' transaction. */\n private async apply(\n tx: Context,\n tap: AttendanceTap,\n at: Date,\n ): Promise<{ punch: AttendancePunch; segment?: AttendanceSegment }> {\n const work = (): AttendanceWork => {\n if (!tap.work)\n throw new AttendanceConflict('Work is required.', 'invalid');\n return tap.work;\n };\n let segment: AttendanceSegment;\n switch (tap.action) {\n case 'startWork':\n await this.chronological(tx, at);\n segment = await beginSegment(tx, await this.open(tx), at, work());\n break;\n case 'switchWork':\n await this.chronological(tx, at);\n segment = await replaceSegment(tx, await this.open(tx), at, work());\n break;\n case 'stopWork':\n await this.chronological(tx, at);\n segment = await endSegment(tx, await this.open(tx), at);\n break;\n case 'resumeWork':\n await this.chronological(tx, at);\n segment = await continueSegment(tx, await this.open(tx), at);\n break;\n default:\n return {\n punch: await this.transition(\n tx,\n tap.action,\n at,\n tap.paid,\n tap.work,\n false,\n {\n ...attendanceProvenance({\n source: tap.source,\n device: tap.device,\n }),\n kind: attendanceLabel(tap.kind, 'kind'),\n },\n ),\n };\n }\n const [punch] = await tx.punches.list({\n where: { ...this.actor, id: segment.punchId },\n limit: 1,\n });\n return { punch, segment };\n }\n\n private validateWork(work: AttendanceWork): void {\n validateAttendanceWork(work);\n }\n\n private async link(\n tx: Context,\n punch: AttendancePunch,\n work: AttendanceWork,\n ): Promise<void> {\n this.validateWork(work);\n if (!punch.endedAt || punch.durationSeconds <= 0)\n throw new AttendanceConflict(\n 'Only closed punches with positive duration can produce service evidence.',\n );\n const entries = await ServiceTimeEntryCollection.create({ db: tx.db });\n if (punch.serviceTimeEntryId) {\n const [existing] = await entries.list({\n where: { id: punch.serviceTimeEntryId, tenantId: this.actor.tenantId },\n limit: 1,\n });\n if (\n !existing ||\n existing.workRefType !== work.workRefType ||\n existing.workRefId !== work.workRefId ||\n existing.description !== work.description ||\n !sameAttribution(existing.metadata, work)\n )\n throw new AttendanceConflict('Punch already linked to different work.');\n return;\n }\n const entry = await entries.create({\n tenantId: this.actor.tenantId,\n participantKind: 'human',\n participantProfileId: this.actor.profileId,\n workRefType: work.workRefType,\n workRefId: work.workRefId,\n description: work.description,\n source: 'timer',\n startedAt: punch.startedAt,\n endedAt: punch.endedAt,\n durationSeconds: punch.durationSeconds,\n status: 'draft',\n metadata: JSON.stringify({\n attendancePunchId: punch.id,\n ...(work.taskRefType\n ? { taskRefType: work.taskRefType, taskRefId: work.taskRefId }\n : {}),\n ...(work.kind ? { kind: work.kind } : {}),\n }),\n _insertOnly: true,\n });\n if (!entry.id) throw new Error('Saved service entry has no id.');\n punch.serviceTimeEntryId = entry.id;\n await punch.save();\n }\n\n /** Idempotently link a closed, owned punch to draft service evidence. */\n async linkServiceTimeEntry(\n punchId: string,\n work: AttendanceWork,\n ): Promise<AttendancePunch> {\n return this.transact(async (tx) => {\n const [punch] = await tx.punches.list({\n where: { ...this.actor, id: punchId },\n limit: 1,\n });\n if (!punch) throw new AttendanceConflict('Punch not found for actor.');\n await this.link(tx, punch, work);\n return punch;\n });\n }\n\n /**\n * Close the open punch once its deadline has passed, flagging it for review.\n * `deadline` is either a fixed maximum open duration in seconds (closing at\n * `startedAt + seconds`, reason `maxDuration`) or a resolver called with the\n * open punch that returns its deadline (a `Date`, or `{ deadline, reason }`),\n * or null to leave it open. The consumer owns time zones and shop-day rules.\n * The open work segment and break close at the deadline; returns the closed\n * punch, or null when nothing was due.\n */\n async autoClose(\n now: Date,\n deadline: AttendanceAutoCloseDeadline,\n ): Promise<AttendancePunch | null> {\n this.date(now);\n if (\n typeof deadline !== 'function' &&\n (!Number.isSafeInteger(deadline) || deadline <= 0)\n )\n throw new AttendanceConflict(\n 'maxOpenSeconds must be a positive integer.',\n );\n return this.transact(async (tx) => {\n const [punch] = await tx.punches.list({\n where: { ...this.actor, endedAt: null },\n limit: 1,\n });\n if (!punch) return null;\n let at: Date;\n let reason = 'maxDuration';\n if (typeof deadline === 'function') {\n const resolved = await deadline(punch);\n if (resolved === null || resolved === undefined) return null;\n const decision =\n resolved instanceof Date ? { deadline: resolved } : resolved;\n at = decision.deadline;\n if (!(at instanceof Date) || !Number.isFinite(at.getTime()))\n throw new AttendanceConflict('Auto-close deadline is invalid.');\n if (at < punch.startedAt)\n throw new AttendanceConflict(\n 'Auto-close deadline predates the punch.',\n );\n reason = decision.reason ?? 'deadline';\n if (typeof reason !== 'string' || !reason.trim() || reason.length > 200)\n throw new AttendanceConflict(\n 'Auto-close reason must be 1 to 200 characters.',\n );\n } else {\n at = new Date(punch.startedAt.getTime() + deadline * 1000);\n }\n if (at > now) return null;\n // Do not truncate a later committed break. The conflict requires manual review.\n const closed = await this.transition(tx, 'punchOut', at);\n closed.reviewRequired = true;\n closed.autoCloseReason = reason;\n await persistAutoClose(closed);\n return closed;\n });\n }\n\n /**\n * Replay device timestamps in order (ties use clientId). Committed attendance\n * wins: stale/state-conflicting taps get durable refusals; identical retries\n * return the same outcome, changed payloads using a key are rejected. A\n * database failure rolls back its tap and receipt and remains retryable.\n */\n async replay(\n taps: readonly AttendanceTap[],\n options: AttendanceReplayOptions = {},\n ): Promise<AttendanceReplayOutcome[]> {\n for (const tap of taps) {\n if (\n !tap ||\n typeof tap.at !== 'string' ||\n typeof tap.clientId !== 'string' ||\n !tap.clientId ||\n !TAP_ACTIONS.includes(tap.action)\n )\n throw new AttendanceConflict('Malformed attendance tap.');\n this.date(new Date(tap.at));\n if (tap.work !== undefined) this.validateWork(tap.work);\n if (\n (tap.action === 'startWork' || tap.action === 'switchWork') &&\n tap.work === undefined\n )\n throw new AttendanceConflict('Malformed attendance tap.');\n if (tap.paid !== undefined && typeof tap.paid !== 'boolean')\n throw new AttendanceConflict('paid must be boolean.');\n attendanceProvenance({ source: tap.source, device: tap.device });\n attendanceLabel(tap.kind, 'kind');\n }\n const ordered = [...taps].sort(\n (a, b) =>\n Date.parse(a.at) - Date.parse(b.at) ||\n (a.clientId < b.clientId ? -1 : a.clientId > b.clientId ? 1 : 0),\n );\n const outcomes: AttendanceReplayOutcome[] = [];\n for (const tap of ordered)\n outcomes.push(\n await this.transact(async (tx) => {\n const replayKey = JSON.stringify([\n this.actor.tenantId,\n this.actor.profileId,\n tap.clientId,\n ]);\n const content = JSON.stringify([\n tap.action,\n new Date(tap.at).toISOString(),\n tap.paid ?? false,\n tap.work?.workRefType ?? null,\n tap.work?.workRefId ?? null,\n tap.work?.description ?? null,\n ...(tap.work?.taskRefType || tap.work?.kind\n ? [\n tap.work.taskRefType ?? null,\n tap.work.taskRefId ?? null,\n tap.work.kind ?? null,\n ]\n : []),\n // Provenance joins the hash only when present, so receipts of taps\n // that carry none are unchanged.\n ...(tap.source || tap.device || tap.kind\n ? [\n {\n source: tap.source ?? '',\n deviceType: tap.device?.type ?? '',\n deviceId: tap.device?.id ?? '',\n kind: tap.kind ?? '',\n },\n ]\n : []),\n ]);\n const [receipt] = await tx.replays.list({\n where: { tenantId: this.actor.tenantId, replayKey },\n limit: 1,\n });\n if (receipt) {\n if (receipt.content !== content)\n throw new AttendanceConflict(\n 'Client id reused with different content.',\n );\n const outcome = receipt.getOutcome();\n if (outcome.clientId !== tap.clientId)\n throw new Error(\n 'Stored attendance receipt belongs to another client id.',\n );\n return outcome;\n }\n const deviceAt = new Date(tap.at);\n let at = deviceAt;\n let review = false;\n let punchReview = true;\n let offline = true;\n if (options.resolveAt) {\n const serverNow = this.date(options.now?.() ?? new Date());\n const resolved = await options.resolveAt({\n tap,\n deviceAt,\n serverNow,\n waitedMs: serverNow.getTime() - deviceAt.getTime(),\n actor: { ...this.actor },\n });\n if (\n !resolved ||\n !(resolved.at instanceof Date) ||\n !Number.isFinite(resolved.at.getTime())\n )\n throw new Error('resolveAt must return a valid date.');\n at = resolved.at;\n review = resolved.reviewRequired === true;\n punchReview = resolved.reviewRequired !== false;\n offline = resolved.recordedOffline !== false;\n }\n let outcome: AttendanceReplayOutcome;\n try {\n // Domain refusals are validated before the first write. Adapters with\n // savepoints isolate the tap; every failure remains in the outer atomic scope.\n // Any database failure escapes and rolls back the entire transaction.\n outcome = await withEmbeddedWriteTransaction(\n tx.db,\n isEmbeddedDatabase(tx.db),\n async (db) => {\n const inner = {\n db,\n punches: await AttendancePunchCollection.create({ db }),\n breaks: await AttendanceBreakCollection.create({ db }),\n segments: await AttendanceSegmentCollection.create({ db }),\n replays: tx.replays,\n };\n const { punch, segment } = await this.apply(inner, tap, at);\n punch.recordedOffline ||= offline;\n punch.reviewRequired ||= punchReview;\n await punch.save();\n if (segment && review) {\n segment.reviewRequired = true;\n await segment.save();\n }\n return {\n clientId: tap.clientId,\n punchId: punch.id!,\n ...(segment ? { segmentId: segment.id! } : {}),\n ...(at.getTime() !== deviceAt.getTime()\n ? { resolvedAt: at.toISOString() }\n : {}),\n };\n },\n true,\n );\n } catch (error) {\n if (!(error instanceof AttendanceConflict)) throw error;\n const custom = options.refusal?.(tap, error) || undefined;\n outcome = {\n clientId: tap.clientId,\n error: custom?.message || error.message,\n code: custom?.code || error.code,\n };\n }\n await tx.replays.create({\n tenantId: this.actor.tenantId,\n replayKey,\n content,\n outcome: JSON.stringify(outcome),\n _insertOnly: true,\n });\n return outcome;\n }),\n );\n return outcomes;\n }\n}\n","import type { DatabaseInterface } from '@happyvertical/sql';\nimport { ServiceTimeEntryCollection } from '../models/service-time-entry.js';\nimport {\n type AttendanceActor,\n AttendanceConflict,\n type AttendanceContext,\n type AttendancePunchOptions,\n type AttendanceWork,\n attendanceIdentity,\n attendanceLabel,\n attendanceProvenance,\n validateAttendanceWork,\n} from './context.js';\nimport {\n AttendanceCorrection,\n AttendanceCorrectionCollection,\n type AttendanceCorrectionKind,\n} from './correction-models.js';\nimport {\n AttendanceBreak,\n type AttendancePunch,\n AttendanceSegment,\n} from './models.js';\nimport { AttendanceService } from './service.js';\nimport { deleteCorrection, persistCorrection } from './write.js';\n\n/** A closed time range a correction touches, for period-lock checks. */\nexport interface AttendanceCorrectionInterval {\n startsAt: Date;\n endsAt: Date;\n}\n\n/**\n * Optional period lock, run on the correction's transaction before any write.\n * Return a message to refuse the correction (for example \"overlaps a confirmed\n * timecard\"), or null to allow it. `confirmedTimecardGuard` in `./rollup` is the\n * ready-made one.\n */\nexport type AttendanceCorrectionGuard = (\n tx: AttendanceContext,\n subject: AttendanceActor,\n intervals: readonly AttendanceCorrectionInterval[],\n) => Promise<string | null>;\n\nexport interface AttendanceCorrectionOptions {\n guard?: AttendanceCorrectionGuard;\n}\n\n/** Fields every correction carries. */\nexport interface AttendanceCorrectionRequest {\n /** Whose time is being corrected. */\n subjectProfileId: string;\n /** Required, non-blank. Stored verbatim (trimmed) on the ledger row. */\n reason: string;\n /** When true the subject must `acknowledge()` the correction. */\n acknowledgementRequired?: boolean;\n}\n\nexport interface CorrectPunchInput extends AttendanceCorrectionRequest {\n punchId: string;\n startedAt?: Date;\n endedAt?: Date;\n}\nexport interface AddPunchInput\n extends AttendanceCorrectionRequest,\n AttendancePunchOptions {\n startedAt: Date;\n endedAt: Date;\n open?: false;\n}\n/** A closed break to record inside an added open punch. */\nexport interface AddPunchBreak {\n startedAt: Date;\n endedAt: Date;\n paid?: boolean;\n kind?: string;\n}\n/** A closed work segment to record inside an added open punch. */\nexport interface AddPunchSegment {\n startedAt: Date;\n endedAt: Date;\n work: AttendanceWork;\n}\n/**\n * Adds a punch that is still open, with the closed breaks and segments that\n * happened since it began. Refused if the subject already has an open punch.\n * The open break or segment, if any, stays with `AttendanceService`.\n */\nexport interface AddOpenPunchInput\n extends AttendanceCorrectionRequest,\n AttendancePunchOptions {\n open: true;\n startedAt: Date;\n endedAt?: undefined;\n breaks?: readonly AddPunchBreak[];\n segments?: readonly AddPunchSegment[];\n}\n/** Adds a break when `breakId` is absent; otherwise changes that break. */\nexport interface SaveBreakInput extends AttendanceCorrectionRequest {\n punchId: string;\n breakId?: string;\n startedAt?: Date;\n endedAt?: Date;\n paid?: boolean;\n /** Short consumer-owned label (for example `meal`); omit to keep, `''` to clear. */\n kind?: string;\n}\nexport interface RemoveBreakInput extends AttendanceCorrectionRequest {\n breakId: string;\n}\n/**\n * Adds a segment when `segmentId` is absent (`startedAt`, `endedAt` and `work`\n * are then required); otherwise changes that segment, keeping what is omitted.\n */\nexport interface SaveSegmentInput extends AttendanceCorrectionRequest {\n punchId: string;\n segmentId?: string;\n startedAt?: Date;\n endedAt?: Date;\n work?: AttendanceWork;\n}\nexport interface RemoveSegmentInput extends AttendanceCorrectionRequest {\n segmentId: string;\n}\n\ntype Recorder = (\n kind: AttendanceCorrectionKind,\n punch: AttendancePunch,\n targetId: string,\n before: object | null,\n after: object | null,\n) => Promise<string>;\n\ninterface Layout {\n startsAt: number;\n endsAt: number;\n breaks: { startedAt: Date; endedAt: Date; paid: boolean }[];\n segments: { startedAt: Date; endedAt: Date }[];\n}\n\n/** Stands in for \"not yet ended\" when validating a layout around an open interval. */\nconst FOREVER = new Date(8.64e15);\n\nconst iso = (d: Date | null) => (d ? d.toISOString() : null);\nconst punchState = (p: AttendancePunch) => ({\n startedAt: iso(p.startedAt),\n endedAt: iso(p.endedAt),\n durationSeconds: p.durationSeconds,\n unpaidBreakSeconds: p.unpaidBreakSeconds,\n reviewRequired: p.reviewRequired,\n ...(p.source ? { source: p.source } : {}),\n ...(p.deviceRefType\n ? { deviceRefType: p.deviceRefType, deviceRefId: p.deviceRefId }\n : {}),\n});\nconst breakState = (b: AttendanceBreak) => ({\n startedAt: iso(b.startedAt),\n endedAt: iso(b.endedAt),\n paid: b.paid,\n ...(b.kind ? { kind: b.kind } : {}),\n});\nconst segmentState = (s: AttendanceSegment) => ({\n startedAt: iso(s.startedAt),\n endedAt: iso(s.endedAt),\n workRefType: s.workRefType,\n workRefId: s.workRefId,\n taskRefType: s.taskRefType,\n taskRefId: s.taskRefId,\n kind: s.kind,\n description: s.description,\n durationSeconds: s.durationSeconds,\n closedReason: s.closedReason,\n});\n\nfunction instant(value: Date | undefined, name: string): Date {\n if (!(value instanceof Date) || !Number.isFinite(value.getTime()))\n throw new AttendanceConflict(`${name} must be a valid date.`);\n return value;\n}\n\nfunction overlapping(\n a: { start: number; end: number },\n b: { start: number; end: number },\n): boolean {\n return a.start < b.end && b.start < a.end;\n}\n\nfunction validateLayout(layout: Layout): void {\n const inside = (r: { startedAt: Date; endedAt: Date }) =>\n r.endedAt.getTime() >= r.startedAt.getTime() &&\n r.startedAt.getTime() >= layout.startsAt &&\n r.endedAt.getTime() <= layout.endsAt;\n if (!layout.breaks.every(inside))\n throw new AttendanceConflict(\n 'A break must be an interval inside its punch.',\n );\n if (!layout.segments.every(inside))\n throw new AttendanceConflict(\n 'A work segment must be an interval inside its punch.',\n );\n const span = (r: { startedAt: Date; endedAt: Date }) => ({\n start: r.startedAt.getTime(),\n end: r.endedAt.getTime(),\n });\n const sets = [layout.breaks, layout.segments];\n for (const set of sets)\n for (let i = 0; i < set.length; i++)\n for (let j = i + 1; j < set.length; j++)\n if (overlapping(span(set[i]), span(set[j])))\n throw new AttendanceConflict(\n set === layout.breaks\n ? 'Breaks must not overlap.'\n : 'Work segments must not overlap.',\n );\n for (const b of layout.breaks)\n for (const s of layout.segments)\n if (overlapping(span(b), span(s)))\n throw new AttendanceConflict(\n 'A work segment must not overlap a break.',\n );\n}\n\n/**\n * Corrections to closed attendance, with a paper trail.\n *\n * `actor` is who makes the change; each request names the `subjectProfileId`\n * whose time it is. The application authorizes the actor (and decides whether\n * they may correct this subject) before constructing the service, exactly as\n * for `AttendanceService`. This service is the only path that may change a\n * closed punch, break or segment: each method validates the resulting layout\n * (everything inside its punch, no overlapping breaks, segments or punches,\n * no segment across a break), recomputes `durationSeconds` and\n * `unpaidBreakSeconds`, keeps a still-draft linked service entry in step, and\n * appends an `AttendanceCorrection` row, all in one transaction serialized with\n * the subject's own taps. An open punch accepts three corrections only: its\n * `startedAt`, closed breaks and segments inside it, and `addPunch({ open:\n * true })`; closing it and the open break or segment stay with\n * `AttendanceService`.\n */\nexport class AttendanceCorrectionService {\n private readonly actor: AttendanceActor;\n constructor(\n private readonly db: DatabaseInterface,\n actor: AttendanceActor,\n private readonly options: AttendanceCorrectionOptions = {},\n ) {\n if (!actor?.tenantId || !actor.profileId)\n throw new Error('Corrections require a trusted tenant/profile actor.');\n this.actor = {\n tenantId: attendanceIdentity(db, actor.tenantId),\n profileId: attendanceIdentity(db, actor.profileId),\n };\n }\n\n /**\n * Change a closed punch's start and/or end. A reviewed punch no longer needs\n * review. An open punch may change `startedAt` only: it cannot be closed\n * here, and its start cannot move past its earliest break or segment.\n */\n async correctPunch(input: CorrectPunchInput): Promise<AttendanceCorrection> {\n return this.run(input, async (tx, subject, record) => {\n const punch = await this.anyPunch(tx, subject, input.punchId);\n const before = punchState(punch);\n if (!punch.endedAt)\n return this.correctOpenStart(tx, subject, record, punch, input, before);\n const startedAt =\n input.startedAt === undefined\n ? punch.startedAt\n : instant(input.startedAt, 'startedAt');\n const endedAt =\n input.endedAt === undefined\n ? punch.endedAt!\n : instant(input.endedAt, 'endedAt');\n if (endedAt <= startedAt)\n throw new AttendanceConflict('A punch must end after it starts.');\n const children = await this.children(tx, punch);\n validateLayout(this.layout(startedAt, endedAt, children));\n for (const other of await tx.punches.list({\n where: { tenantId: subject.tenantId, profileId: subject.profileId },\n }))\n if (\n other.id !== punch.id &&\n overlapping(\n { start: startedAt.getTime(), end: endedAt.getTime() },\n {\n start: other.startedAt.getTime(),\n end: other.endedAt?.getTime() ?? Number.POSITIVE_INFINITY,\n },\n )\n )\n throw new AttendanceConflict('Punches must not overlap.');\n await this.guard(tx, subject, [\n { startsAt: punch.startedAt, endsAt: punch.endedAt! },\n { startsAt: startedAt, endsAt: endedAt },\n ]);\n const entry = await this.editableEntry(tx, punch);\n punch.startedAt = startedAt;\n punch.endedAt = endedAt;\n punch.reviewRequired = false;\n await this.settle(tx, punch, children.breaks, entry);\n return record(\n 'punch.corrected',\n punch,\n punch.id!,\n before,\n punchState(punch),\n );\n });\n }\n\n /**\n * Record a missed punch retroactively: a closed interval, or with\n * `{ open: true }` one that is still running, carrying its closed breaks and\n * segments.\n */\n async addPunch(\n input: AddPunchInput | AddOpenPunchInput,\n ): Promise<AttendanceCorrection> {\n if (input.open === true) return this.addOpenPunch(input);\n return this.run(input, async (tx, subject, record) => {\n const startedAt = instant(input.startedAt, 'startedAt');\n const endedAt = instant(input.endedAt, 'endedAt');\n const meta = attendanceProvenance(input);\n if (endedAt <= startedAt)\n throw new AttendanceConflict('A punch must end after it starts.');\n for (const other of await tx.punches.list({\n where: { tenantId: subject.tenantId, profileId: subject.profileId },\n }))\n if (\n overlapping(\n { start: startedAt.getTime(), end: endedAt.getTime() },\n {\n start: other.startedAt.getTime(),\n end: other.endedAt?.getTime() ?? Number.POSITIVE_INFINITY,\n },\n )\n )\n throw new AttendanceConflict('Punches must not overlap.');\n await this.guard(tx, subject, [{ startsAt: startedAt, endsAt: endedAt }]);\n const punch = await tx.punches.create({\n tenantId: subject.tenantId,\n profileId: subject.profileId,\n startedAt,\n endedAt,\n durationSeconds: Math.round(\n (endedAt.getTime() - startedAt.getTime()) / 1000,\n ),\n ...meta,\n _insertOnly: true,\n });\n return record('punch.added', punch, punch.id!, null, punchState(punch));\n });\n }\n\n /** Add a closed break to a punch, or change one (times and/or paid). */\n async saveBreak(input: SaveBreakInput): Promise<AttendanceCorrection> {\n return this.run(input, async (tx, subject, record) => {\n const punch = await this.anyPunch(tx, subject, input.punchId);\n const children = await this.children(tx, punch);\n const existing = input.breakId\n ? children.breaks.find((b) => b.id === input.breakId)\n : undefined;\n if (input.breakId && !existing)\n throw new AttendanceConflict('Break not found in that punch.');\n if (existing && !existing.endedAt)\n throw new AttendanceConflict(\n 'The open break is changed through AttendanceService.',\n );\n if (\n !existing &&\n (input.startedAt === undefined || input.endedAt === undefined)\n )\n throw new AttendanceConflict(\n 'A new break needs startedAt and endedAt.',\n );\n if (input.paid !== undefined && typeof input.paid !== 'boolean')\n throw new AttendanceConflict('paid must be boolean.');\n const next = {\n startedAt: instant(input.startedAt ?? existing?.startedAt, 'startedAt'),\n endedAt: instant(\n input.endedAt ?? existing?.endedAt ?? undefined,\n 'endedAt',\n ),\n paid: input.paid ?? existing?.paid ?? false,\n kind:\n input.kind === undefined\n ? (existing?.kind ?? '')\n : attendanceLabel(input.kind, 'kind'),\n };\n const rest = children.breaks.filter((b) => b !== existing);\n validateLayout(\n this.layout(punch.startedAt, punch.endedAt, {\n breaks: [...rest, next as unknown as AttendanceBreak],\n segments: children.segments,\n }),\n );\n await this.guard(tx, subject, [this.span(punch)]);\n const entry = await this.editableEntry(tx, punch);\n const before = existing ? breakState(existing) : null;\n let target: AttendanceBreak;\n if (existing) {\n existing.startedAt = next.startedAt;\n existing.endedAt = next.endedAt;\n existing.paid = next.paid;\n existing.kind = next.kind;\n await persistCorrection(existing);\n target = existing;\n } else {\n target = await new AttendanceBreak({\n db: tx.db,\n id: crypto.randomUUID(),\n _skipLoad: true,\n }).initialize();\n Object.assign(target, {\n tenantId: subject.tenantId,\n punchId: punch.id ?? undefined,\n ...next,\n });\n await persistCorrection(target);\n }\n await this.settle(tx, punch, [...rest, target], entry);\n return record(\n existing ? 'break.changed' : 'break.added',\n punch,\n target.id!,\n before,\n breakState(target),\n );\n });\n }\n\n /** Remove a closed break from a punch. */\n async removeBreak(input: RemoveBreakInput): Promise<AttendanceCorrection> {\n return this.run(input, async (tx, subject, record) => {\n const [target] = await tx.breaks.list({\n where: { tenantId: subject.tenantId, id: input.breakId },\n limit: 1,\n });\n if (!target) throw new AttendanceConflict('Break not found.');\n if (!target.endedAt)\n throw new AttendanceConflict(\n 'The open break is ended through AttendanceService.',\n );\n const punch = await this.anyPunch(tx, subject, target.punchId);\n const children = await this.children(tx, punch);\n await this.guard(tx, subject, [this.span(punch)]);\n const entry = await this.editableEntry(tx, punch);\n const before = breakState(target);\n await deleteCorrection(target);\n await this.settle(\n tx,\n punch,\n children.breaks.filter((b) => b.id !== target.id),\n entry,\n );\n return record('break.removed', punch, target.id!, before, null);\n });\n }\n\n /** Add a closed work segment to a punch, or change one (times and/or work attribution). */\n async saveSegment(input: SaveSegmentInput): Promise<AttendanceCorrection> {\n return this.run(input, async (tx, subject, record) => {\n const punch = await this.anyPunch(tx, subject, input.punchId);\n const children = await this.children(tx, punch);\n const existing = input.segmentId\n ? children.segments.find((s) => s.id === input.segmentId)\n : undefined;\n if (input.segmentId && !existing)\n throw new AttendanceConflict('Work segment not found in that punch.');\n if (existing && !existing.endedAt)\n throw new AttendanceConflict(\n 'The open work segment is changed through AttendanceService.',\n );\n if (\n !existing &&\n (input.startedAt === undefined ||\n input.endedAt === undefined ||\n !input.work)\n )\n throw new AttendanceConflict(\n 'A new work segment needs startedAt, endedAt and work.',\n );\n if (input.work) validateAttendanceWork(input.work);\n const next = {\n startedAt: instant(input.startedAt ?? existing?.startedAt, 'startedAt'),\n endedAt: instant(\n input.endedAt ?? existing?.endedAt ?? undefined,\n 'endedAt',\n ),\n };\n const rest = children.segments.filter((s) => s !== existing);\n validateLayout(\n this.layout(punch.startedAt, punch.endedAt, {\n breaks: children.breaks,\n segments: [...rest, next as unknown as AttendanceSegment],\n }),\n );\n await this.guard(tx, subject, [this.span(punch)]);\n const before = existing ? segmentState(existing) : null;\n let target: AttendanceSegment;\n if (existing) {\n existing.startedAt = next.startedAt;\n existing.endedAt = next.endedAt;\n if (input.work) this.attribute(existing, input.work);\n await persistCorrection(existing);\n target = existing;\n } else {\n target = await new AttendanceSegment({\n db: tx.db,\n id: crypto.randomUUID(),\n _skipLoad: true,\n }).initialize();\n Object.assign(target, {\n tenantId: subject.tenantId,\n punchId: punch.id ?? undefined,\n profileId: punch.profileId,\n workRefType: input.work!.workRefType,\n workRefId: input.work!.workRefId,\n taskRefType: input.work!.taskRefType ?? '',\n taskRefId: input.work!.taskRefId ?? '',\n kind: input.work!.kind ?? '',\n description: input.work!.description,\n ...next,\n closedReason: 'stop',\n });\n await persistCorrection(target);\n }\n return record(\n existing ? 'segment.changed' : 'segment.added',\n punch,\n target.id!,\n before,\n segmentState(target),\n );\n });\n }\n\n /** Remove a closed work segment from a punch. */\n async removeSegment(\n input: RemoveSegmentInput,\n ): Promise<AttendanceCorrection> {\n return this.run(input, async (tx, subject, record) => {\n const [target] = await tx.segments.list({\n where: { tenantId: subject.tenantId, id: input.segmentId },\n limit: 1,\n });\n if (!target) throw new AttendanceConflict('Work segment not found.');\n if (!target.endedAt)\n throw new AttendanceConflict(\n 'The open work segment is stopped through AttendanceService.',\n );\n const punch = await this.anyPunch(tx, subject, target.punchId);\n await this.guard(tx, subject, [this.span(punch)]);\n const before = segmentState(target);\n await deleteCorrection(target);\n return record('segment.removed', punch, target.id!, before, null);\n });\n }\n\n /**\n * The subject confirms they have seen a correction that required it. Only\n * the subject (this service's actor) may; it can be done once.\n */\n async acknowledge(\n correctionId: string,\n at: Date = new Date(),\n ): Promise<AttendanceCorrection> {\n instant(at, 'at');\n const id = await this.attendance(this.actor.profileId).withTransaction(\n async (tx) => {\n const ledger = await AttendanceCorrectionCollection.create({\n db: tx.db,\n });\n const [row] = await ledger.list({\n where: { tenantId: this.actor.tenantId, id: correctionId },\n limit: 1,\n });\n if (!row) throw new AttendanceConflict('Correction not found.');\n if (row.subjectProfileId !== this.actor.profileId)\n throw new AttendanceConflict(\n 'Only the subject can acknowledge a correction.',\n );\n if (!row.acknowledgementRequired)\n throw new AttendanceConflict(\n 'This correction does not require acknowledgement.',\n );\n if (row.acknowledgedAt)\n throw new AttendanceConflict('Correction already acknowledged.');\n row.acknowledgedAt = at;\n row.acknowledgedByProfileId = this.actor.profileId;\n await persistCorrection(row);\n return row.id!;\n },\n );\n return this.read(id);\n }\n\n /** Corrections to one punch, oldest first. */\n async listForPunch(punchId: string): Promise<AttendanceCorrection[]> {\n return this.attendance(this.actor.profileId).withTransaction(\n async (tx) =>\n await (await AttendanceCorrectionCollection.create({ db: tx.db })).list(\n {\n where: { tenantId: this.actor.tenantId, punchId },\n orderBy: 'created_at ASC',\n },\n ),\n );\n }\n\n /** Corrections of the actor's own time that still await their acknowledgement. */\n async pendingAcknowledgements(): Promise<AttendanceCorrection[]> {\n return this.attendance(this.actor.profileId).withTransaction(async (tx) =>\n (\n await (\n await AttendanceCorrectionCollection.create({ db: tx.db })\n ).list({\n where: {\n tenantId: this.actor.tenantId,\n subjectProfileId: this.actor.profileId,\n },\n orderBy: 'created_at ASC',\n })\n ).filter((row) => row.acknowledgementRequired && !row.acknowledgedAt),\n );\n }\n\n /** The range a correction touches, for period-lock checks: an open punch runs to now. */\n private span(punch: AttendancePunch): AttendanceCorrectionInterval {\n const now = new Date();\n return {\n startsAt: punch.startedAt,\n endsAt: punch.endedAt ?? (now > punch.startedAt ? now : punch.startedAt),\n };\n }\n\n private async openPunchOf(\n tx: AttendanceContext,\n subject: AttendanceActor,\n ): Promise<boolean> {\n return (\n (\n await tx.punches.list({\n where: {\n tenantId: subject.tenantId,\n profileId: subject.profileId,\n endedAt: null,\n },\n limit: 1,\n })\n ).length > 0\n );\n }\n\n private async correctOpenStart(\n tx: AttendanceContext,\n subject: AttendanceActor,\n record: Recorder,\n punch: AttendancePunch,\n input: CorrectPunchInput,\n before: object,\n ): Promise<string> {\n if (input.endedAt !== undefined)\n throw new AttendanceConflict(\n 'An open punch cannot be closed by a correction; use AttendanceService.',\n );\n if (input.startedAt === undefined)\n throw new AttendanceConflict('An open punch is corrected by startedAt.');\n const startedAt = instant(input.startedAt, 'startedAt');\n const children = await this.children(tx, punch);\n validateLayout(this.layout(startedAt, null, children));\n for (const other of await tx.punches.list({\n where: { tenantId: subject.tenantId, profileId: subject.profileId },\n }))\n if (\n other.id !== punch.id &&\n overlapping(\n { start: startedAt.getTime(), end: FOREVER.getTime() },\n {\n start: other.startedAt.getTime(),\n end: other.endedAt?.getTime() ?? FOREVER.getTime(),\n },\n )\n )\n throw new AttendanceConflict('Punches must not overlap.');\n const earliest = punch.startedAt < startedAt ? punch.startedAt : startedAt;\n await this.guard(tx, subject, [\n { startsAt: earliest, endsAt: this.span(punch).endsAt },\n ]);\n punch.startedAt = startedAt;\n punch.reviewRequired = false;\n await this.settle(tx, punch, children.breaks, null);\n return record(\n 'punch.corrected',\n punch,\n punch.id!,\n before,\n punchState(punch),\n );\n }\n\n private async addOpenPunch(\n input: AddOpenPunchInput,\n ): Promise<AttendanceCorrection> {\n return this.run(input, async (tx, subject, record) => {\n const startedAt = instant(input.startedAt, 'startedAt');\n const meta = attendanceProvenance(input);\n if (input.endedAt !== undefined)\n throw new AttendanceConflict('An open punch has no endedAt.');\n if (await this.openPunchOf(tx, subject))\n throw new AttendanceConflict('A punch is already open.', 'punch_open');\n const breaks = (input.breaks ?? []).map((b) => ({\n startedAt: instant(b.startedAt, 'startedAt'),\n endedAt: instant(b.endedAt, 'endedAt'),\n paid: b.paid ?? false,\n kind: attendanceLabel(b.kind, 'kind'),\n }));\n for (const b of input.breaks ?? [])\n if (b.paid !== undefined && typeof b.paid !== 'boolean')\n throw new AttendanceConflict('paid must be boolean.');\n const segments = (input.segments ?? []).map((g) => {\n validateAttendanceWork(g.work);\n return {\n startedAt: instant(g.startedAt, 'startedAt'),\n endedAt: instant(g.endedAt, 'endedAt'),\n work: g.work,\n };\n });\n validateLayout({\n startsAt: startedAt.getTime(),\n endsAt: FOREVER.getTime(),\n breaks,\n segments,\n });\n for (const other of await tx.punches.list({\n where: { tenantId: subject.tenantId, profileId: subject.profileId },\n }))\n if (\n overlapping(\n { start: startedAt.getTime(), end: FOREVER.getTime() },\n {\n start: other.startedAt.getTime(),\n end: other.endedAt?.getTime() ?? FOREVER.getTime(),\n },\n )\n )\n throw new AttendanceConflict('Punches must not overlap.');\n const now = new Date();\n await this.guard(tx, subject, [\n { startsAt: startedAt, endsAt: now > startedAt ? now : startedAt },\n ]);\n const punch = await tx.punches.create({\n tenantId: subject.tenantId,\n profileId: subject.profileId,\n startedAt,\n ...meta,\n _insertOnly: true,\n });\n for (const b of breaks) {\n const row = await new AttendanceBreak({\n db: tx.db,\n id: crypto.randomUUID(),\n _skipLoad: true,\n }).initialize();\n Object.assign(row, {\n tenantId: subject.tenantId,\n punchId: punch.id ?? undefined,\n ...b,\n });\n await persistCorrection(row);\n }\n const segmentStates: ReturnType<typeof segmentState>[] = [];\n for (const g of segments) {\n const row = await new AttendanceSegment({\n db: tx.db,\n id: crypto.randomUUID(),\n _skipLoad: true,\n }).initialize();\n Object.assign(row, {\n tenantId: subject.tenantId,\n punchId: punch.id ?? undefined,\n profileId: punch.profileId,\n workRefType: g.work.workRefType,\n workRefId: g.work.workRefId,\n taskRefType: g.work.taskRefType ?? '',\n taskRefId: g.work.taskRefId ?? '',\n kind: g.work.kind ?? '',\n description: g.work.description,\n startedAt: g.startedAt,\n endedAt: g.endedAt,\n closedReason: 'stop',\n });\n await persistCorrection(row);\n segmentStates.push(segmentState(row));\n }\n return record('punch.added', punch, punch.id!, null, {\n ...punchState(punch),\n ...(breaks.length\n ? {\n breaks: breaks.map((b) => ({\n startedAt: iso(b.startedAt),\n endedAt: iso(b.endedAt),\n paid: b.paid,\n ...(b.kind ? { kind: b.kind } : {}),\n })),\n }\n : {}),\n ...(segmentStates.length ? { segments: segmentStates } : {}),\n });\n });\n }\n\n private attendance(subjectProfileId: string): AttendanceService {\n return new AttendanceService(this.db, {\n tenantId: this.actor.tenantId,\n profileId: subjectProfileId,\n });\n }\n\n private async read(id: string): Promise<AttendanceCorrection> {\n return this.attendance(this.actor.profileId).withTransaction(async (tx) => {\n const [row] = await (\n await AttendanceCorrectionCollection.create({ db: tx.db })\n ).list({ where: { tenantId: this.actor.tenantId, id }, limit: 1 });\n if (!row) throw new Error('Committed attendance correction disappeared.');\n return row;\n });\n }\n\n private async run(\n request: AttendanceCorrectionRequest,\n operation: (\n tx: AttendanceContext,\n subject: AttendanceActor,\n record: Recorder,\n ) => Promise<string>,\n ): Promise<AttendanceCorrection> {\n const reason =\n typeof request.reason === 'string' ? request.reason.trim() : '';\n if (!reason) throw new AttendanceConflict('A correction needs a reason.');\n if (\n request.acknowledgementRequired !== undefined &&\n typeof request.acknowledgementRequired !== 'boolean'\n )\n throw new AttendanceConflict('acknowledgementRequired must be boolean.');\n if (!request.subjectProfileId)\n throw new AttendanceConflict('A correction needs a subject.');\n const subject: AttendanceActor = {\n tenantId: this.actor.tenantId,\n profileId: attendanceIdentity(this.db, request.subjectProfileId),\n };\n const id = await this.attendance(subject.profileId).withTransaction(\n async (tx) => {\n // Initialise the ledger table binding on this executor before writing.\n await AttendanceCorrectionCollection.create({ db: tx.db });\n return operation(\n tx,\n subject,\n async (kind, punch, targetId, before, after) => {\n const row = await new AttendanceCorrection({\n db: tx.db,\n id: crypto.randomUUID(),\n _skipLoad: true,\n }).initialize();\n Object.assign(row, {\n tenantId: subject.tenantId,\n subjectProfileId: subject.profileId,\n actorProfileId: this.actor.profileId,\n kind,\n punchId: punch.id ?? undefined,\n targetId,\n beforeState: JSON.stringify(before),\n afterState: JSON.stringify(after),\n reason,\n acknowledgementRequired: request.acknowledgementRequired ?? false,\n });\n await persistCorrection(row);\n return row.id!;\n },\n );\n },\n );\n return this.read(id);\n }\n\n private async anyPunch(\n tx: AttendanceContext,\n subject: AttendanceActor,\n punchId: string,\n ): Promise<AttendancePunch> {\n const [punch] = await tx.punches.list({\n where: {\n tenantId: subject.tenantId,\n profileId: subject.profileId,\n id: punchId,\n },\n limit: 1,\n });\n if (!punch) throw new AttendanceConflict('Punch not found for subject.');\n return punch;\n }\n\n private async children(tx: AttendanceContext, punch: AttendancePunch) {\n const where = { tenantId: punch.tenantId, punchId: punch.id };\n const breaks = await tx.breaks.list({ where, orderBy: 'started_at ASC' });\n const segments = await tx.segments.list({\n where,\n orderBy: 'started_at ASC',\n });\n if (\n punch.endedAt &&\n (breaks.some((b) => !b.endedAt) || segments.some((s) => !s.endedAt))\n )\n throw new AttendanceConflict(\n 'Closed punch has an open break or segment.',\n );\n return { breaks, segments };\n }\n\n private layout(\n startedAt: Date,\n endedAt: Date | null,\n children: {\n breaks: readonly AttendanceBreak[];\n segments: readonly AttendanceSegment[];\n },\n ): Layout {\n return {\n startsAt: startedAt.getTime(),\n endsAt: endedAt ? endedAt.getTime() : FOREVER.getTime(),\n breaks: children.breaks.map((b) => ({\n startedAt: b.startedAt,\n endedAt: b.endedAt ?? FOREVER,\n paid: b.paid,\n })),\n segments: children.segments.map((s) => ({\n startedAt: s.startedAt,\n endedAt: s.endedAt ?? FOREVER,\n })),\n };\n }\n\n private attribute(segment: AttendanceSegment, work: AttendanceWork): void {\n segment.workRefType = work.workRefType;\n segment.workRefId = work.workRefId;\n segment.taskRefType = work.taskRefType ?? '';\n segment.taskRefId = work.taskRefId ?? '';\n segment.kind = work.kind ?? '';\n segment.description = work.description;\n }\n\n private async guard(\n tx: AttendanceContext,\n subject: AttendanceActor,\n intervals: readonly AttendanceCorrectionInterval[],\n ): Promise<void> {\n const refusal = await this.options.guard?.(tx, subject, intervals);\n if (refusal) throw new AttendanceConflict(refusal);\n }\n\n /** The punch's still-draft evidence entry, refusing when it is no longer editable. */\n private async editableEntry(tx: AttendanceContext, punch: AttendancePunch) {\n if (!punch.serviceTimeEntryId) return null;\n const entries = await ServiceTimeEntryCollection.create({ db: tx.db });\n const [entry] = await entries.list({\n where: { id: punch.serviceTimeEntryId, tenantId: punch.tenantId },\n limit: 1,\n });\n if (!entry) return null;\n if (entry.status !== 'draft')\n throw new AttendanceConflict(\n `Linked service evidence is ${entry.status}; correct it with ServiceEvidenceService first.`,\n );\n return entry;\n }\n\n /** Recompute the punch's durations from its breaks and persist it and its draft entry. */\n private async settle(\n tx: AttendanceContext,\n punch: AttendancePunch,\n breaks: readonly AttendanceBreak[],\n entry: Awaited<ReturnType<AttendanceCorrectionService['editableEntry']>>,\n ): Promise<void> {\n // An open punch's durations are fixed when it closes (`punchOut`).\n if (!punch.endedAt) {\n await persistCorrection(punch);\n return;\n }\n const unpaidMs = breaks\n .filter((b) => !b.paid)\n .reduce(\n (sum, b) => sum + b.endedAt!.getTime() - b.startedAt.getTime(),\n 0,\n );\n punch.unpaidBreakSeconds = Math.round(unpaidMs / 1000);\n punch.durationSeconds = Math.round(\n (punch.endedAt!.getTime() - punch.startedAt.getTime() - unpaidMs) / 1000,\n );\n await persistCorrection(punch);\n if (entry) {\n entry.startedAt = punch.startedAt;\n entry.endedAt = punch.endedAt;\n entry.durationSeconds = punch.durationSeconds;\n await entry.save();\n }\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { o as parseTimesheetJson } from "./service-time-entry-Bd3NQr90.js";
1
+ import { o as parseTimesheetJson } from "./service-time-entry-De3Y9_ho.js";
2
2
  import { SmrtCollection, SmrtObject, crossPackageRef, field, foreignKey, isEmbeddedDatabase, isPostgresDatabase, smrt, withEmbeddedWriteTransaction } from "@happyvertical/smrt-core";
3
3
  import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
4
4
  //#region src/attendance/write.ts
@@ -77,10 +77,10 @@ var AttendancePunch = class extends SmrtObject {
77
77
  deviceRefId = "";
78
78
  serviceTimeEntryId = null;
79
79
  openSlot = "";
80
- async save() {
81
- return saveWithPunchLock(this, this.id, this.tenantId, () => this.saveConsistent());
80
+ async save(options) {
81
+ return saveWithPunchLock(this, this.id, this.tenantId, () => this.saveConsistent(options));
82
82
  }
83
- async saveConsistent() {
83
+ async saveConsistent(options) {
84
84
  if (!this.tenantId || !this.profileId) throw new Error("Attendance requires tenantId and profileId.");
85
85
  if (!Number.isFinite(this.startedAt?.getTime()) || this.endedAt && (!Number.isFinite(this.endedAt.getTime()) || this.endedAt < this.startedAt)) throw new Error("Invalid attendance interval.");
86
86
  if (![this.durationSeconds, this.unpaidBreakSeconds].every((value) => Number.isSafeInteger(value) && value >= 0)) throw new Error("Attendance durations must be nonnegative safe integer seconds.");
@@ -107,7 +107,7 @@ var AttendancePunch = class extends SmrtObject {
107
107
  }
108
108
  this.id ??= crypto.randomUUID();
109
109
  this.openSlot = this.endedAt ? JSON.stringify(["closed", this.id]) : "open";
110
- return super.save();
110
+ return super.save(options);
111
111
  }
112
112
  };
113
113
  __publicField(AttendancePunch, "__smrtPackage__", "@happyvertical/smrt-timesheets");
@@ -153,10 +153,10 @@ var AttendanceBreak = class extends SmrtObject {
153
153
  /** Optional short consumer-owned label (`meal`, `rest`, ...); `''` when unspecified. */
154
154
  kind = "";
155
155
  openSlot = "";
156
- async save() {
157
- return saveWithPunchLock(this, this.punchId, this.tenantId, () => this.saveConsistent());
156
+ async save(options) {
157
+ return saveWithPunchLock(this, this.punchId, this.tenantId, () => this.saveConsistent(options));
158
158
  }
159
- async saveConsistent() {
159
+ async saveConsistent(options) {
160
160
  this.kind ??= "";
161
161
  if (!this.tenantId || !this.punchId || typeof this.paid !== "boolean" || typeof this.kind !== "string" || this.kind.length > 64 || this.kind !== this.kind.trim()) throw new Error("Invalid attendance break.");
162
162
  if (!Number.isFinite(this.startedAt?.getTime()) || this.endedAt && (!Number.isFinite(this.endedAt.getTime()) || this.endedAt < this.startedAt)) throw new Error("Invalid attendance break interval.");
@@ -178,7 +178,7 @@ var AttendanceBreak = class extends SmrtObject {
178
178
  })).some((row) => brStart < (row.ended_at ? new Date(row.ended_at).getTime() : Number.POSITIVE_INFINITY) && brEnd > new Date(row.started_at).getTime())) throw new Error("Break must not overlap a work segment.");
179
179
  this.id ??= crypto.randomUUID();
180
180
  this.openSlot = this.endedAt ? JSON.stringify(["closed", this.id]) : "open";
181
- return super.save();
181
+ return super.save(options);
182
182
  }
183
183
  async delete() {
184
184
  await saveWithPunchLock(this, this.punchId, this.tenantId, async () => {
@@ -236,10 +236,10 @@ var AttendanceSegment = class extends SmrtObject {
236
236
  /** Set when a replay time policy asked for review of this segment's boundary. */
237
237
  reviewRequired = false;
238
238
  openSlot = "";
239
- async save() {
240
- return saveWithPunchLock(this, this.punchId, this.tenantId, () => this.saveConsistent());
239
+ async save(options) {
240
+ return saveWithPunchLock(this, this.punchId, this.tenantId, () => this.saveConsistent(options));
241
241
  }
242
- async saveConsistent() {
242
+ async saveConsistent(options) {
243
243
  if (!this.tenantId || !this.punchId || !this.workRefType || !this.workRefId || !!this.taskRefType !== !!this.taskRefId) throw new Error("Invalid attendance work segment.");
244
244
  if (!Number.isFinite(this.startedAt?.getTime()) || this.endedAt && (!Number.isFinite(this.endedAt.getTime()) || this.endedAt < this.startedAt)) throw new Error("Invalid attendance segment interval.");
245
245
  if (!this.endedAt !== !this.closedReason) throw new Error("A segment has a close reason exactly when it is closed.");
@@ -267,7 +267,7 @@ var AttendanceSegment = class extends SmrtObject {
267
267
  this.durationSeconds = this.endedAt ? Math.round((end - start) / 1e3) : 0;
268
268
  this.id ??= crypto.randomUUID();
269
269
  this.openSlot = this.endedAt ? JSON.stringify(["closed", this.id]) : "open";
270
- return super.save();
270
+ return super.save(options);
271
271
  }
272
272
  async delete() {
273
273
  await saveWithPunchLock(this, this.punchId, this.tenantId, async () => {
@@ -345,9 +345,9 @@ var AttendanceReplay = class extends SmrtObject {
345
345
  if (!validReplayOutcome(value)) throw new Error("Invalid attendance replay outcome.");
346
346
  this.outcome = JSON.stringify(value);
347
347
  }
348
- async save() {
348
+ async save(options) {
349
349
  this.getOutcome();
350
- return super.save();
350
+ return super.save(options);
351
351
  }
352
352
  };
353
353
  __publicField(AttendanceReplay, "__smrtPackage__", "@happyvertical/smrt-timesheets");
@@ -380,4 +380,4 @@ var AttendanceReplayCollection = class extends SmrtCollection {
380
380
  //#endregion
381
381
  export { AttendanceReplay as a, AttendanceSegmentCollection as c, persistAutoClose as d, persistCorrection as f, AttendancePunchCollection as i, deleteCorrection as l, AttendanceBreakCollection as n, AttendanceReplayCollection as o, AttendancePunch as r, AttendanceSegment as s, AttendanceBreak as t, isCorrectionWrite as u };
382
382
 
383
- //# sourceMappingURL=models-CRnsNezh.js.map
383
+ //# sourceMappingURL=models-D0VhW-5I.js.map