@happyvertical/smrt-timesheets 0.55.21 → 0.55.23

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 (30) hide show
  1. package/README.md +9 -0
  2. package/agents/labour-valuation.md +73 -0
  3. package/dist/attendance.js +2 -2
  4. package/dist/chunks/{attendance-OKyc1O4x.js → attendance-BVeStEBv.js} +3 -3
  5. package/dist/chunks/{attendance-OKyc1O4x.js.map → attendance-BVeStEBv.js.map} +1 -1
  6. package/dist/chunks/{models-B0NOh8I3.js → models-zU8Um7c2.js} +2 -2
  7. package/dist/chunks/{models-B0NOh8I3.js.map → models-zU8Um7c2.js.map} +1 -1
  8. package/dist/chunks/{rollup-2--s0AyP.js → rollup-U1IO_CMA.js} +3 -3
  9. package/dist/chunks/{rollup-2--s0AyP.js.map → rollup-U1IO_CMA.js.map} +1 -1
  10. package/dist/chunks/{service-time-entry-BY8UcnFk.js → service-time-entry-CBv-FF-W.js} +2 -2
  11. package/dist/chunks/{service-time-entry-BY8UcnFk.js.map → service-time-entry-CBv-FF-W.js.map} +1 -1
  12. package/dist/index.js +285 -8
  13. package/dist/index.js.map +1 -1
  14. package/dist/manifest.json +1 -1
  15. package/dist/rollup.js +1 -1
  16. package/dist/services/dated-labour-commercial-resolver.d.ts.map +1 -1
  17. package/dist/services/dated-percentage-labour-commercial-resolver.d.ts +36 -0
  18. package/dist/services/dated-percentage-labour-commercial-resolver.d.ts.map +1 -0
  19. package/dist/services/index.d.ts +2 -0
  20. package/dist/services/index.d.ts.map +1 -1
  21. package/dist/services/labour-math.d.ts +17 -0
  22. package/dist/services/labour-math.d.ts.map +1 -0
  23. package/dist/services/labour-valuation-reconciliation.d.ts +59 -0
  24. package/dist/services/labour-valuation-reconciliation.d.ts.map +1 -0
  25. package/dist/smrt-knowledge.json +3 -3
  26. package/dist/svelte/components/TimeEntryApprovalQueue.svelte +1 -1
  27. package/dist/svelte/components/TimeEntryCard.svelte +4 -4
  28. package/dist/svelte/components/TimeEntryList.svelte +3 -3
  29. package/dist/svelte/components/TimeSummary.svelte +1 -1
  30. package/package.json +6 -6
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { a as validateDurationHours, i as ServiceTimeEntryCollection, n as SERVICE_TIME_ENTRY_FROZEN_FIELDS, r as ServiceTimeEntry, t as SERVICE_DURATION_HOURS_EVIDENCE } from "./chunks/service-time-entry-BY8UcnFk.js";
2
- import { a as AttendanceReplay, i as AttendancePunchCollection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, t as AttendanceBreak } from "./chunks/models-B0NOh8I3.js";
1
+ import { a as validateDurationHours, i as ServiceTimeEntryCollection, n as SERVICE_TIME_ENTRY_FROZEN_FIELDS, r as ServiceTimeEntry, t as SERVICE_DURATION_HOURS_EVIDENCE } from "./chunks/service-time-entry-CBv-FF-W.js";
2
+ import { a as AttendanceReplay, i as AttendancePunchCollection, n as AttendanceBreakCollection, o as AttendanceReplayCollection, r as AttendancePunch, t as AttendanceBreak } from "./chunks/models-zU8Um7c2.js";
3
3
  import { SERVICE_TIME_ENTRY_STATUS_TRANSITIONS } from "./types.js";
4
4
  import { AttendanceConflict, AttendanceService } from "./attendance.js";
5
- import { a as PeriodTimecard, c as TimecardAdjustmentCollection, o as PeriodTimecardCollection, s as TimecardAdjustment, t as PeriodRollupService } from "./chunks/rollup-2--s0AyP.js";
5
+ import { a as PeriodTimecard, c as TimecardAdjustmentCollection, o as PeriodTimecardCollection, s as TimecardAdjustment, t as PeriodRollupService } from "./chunks/rollup-U1IO_CMA.js";
6
6
  import { TIMESHEETS_MODULE_META, TIMESHEETS_UI_SLOTS } from "./ui.js";
7
7
  import { SmrtCollection, SmrtObject, ValidationError, field, foreignKey, smrt } from "@happyvertical/smrt-core";
8
8
  import { TenantScoped, tenantId } from "@happyvertical/smrt-tenancy";
@@ -161,7 +161,7 @@ var ServiceCompensationSnapshotCollection = class extends SmrtCollection {
161
161
  static _itemClass = ServiceCompensationSnapshot;
162
162
  };
163
163
  //#endregion
164
- //#region src/services/dated-labour-commercial-resolver.ts
164
+ //#region src/services/labour-math.ts
165
165
  var MAX = BigInt(Number.MAX_SAFE_INTEGER);
166
166
  function decimal(value, label) {
167
167
  if (typeof value !== "string" || value.length > 40 || !/^\d+(?:\.\d{1,18})?$/.test(value)) throw new Error(`${label} must be nonnegative plain decimal text.`);
@@ -195,12 +195,54 @@ function rate(value) {
195
195
  }
196
196
  function amount(hours, hourly) {
197
197
  const value = decimal(hourly.rateMinor, "Hourly rate");
198
- const numerator = hours.numerator * value.numerator;
199
- const denominator = hours.denominator * value.denominator;
200
- const result = (2n * numerator + denominator) / (2n * denominator);
198
+ return rounded({
199
+ numerator: hours.numerator * value.numerator,
200
+ denominator: hours.denominator * value.denominator
201
+ });
202
+ }
203
+ function multiply(a, b) {
204
+ return {
205
+ numerator: a.numerator * b.numerator,
206
+ denominator: a.denominator * b.denominator
207
+ };
208
+ }
209
+ function add(a, b) {
210
+ const numerator = a.numerator * b.denominator + b.numerator * a.denominator;
211
+ const denominator = a.denominator * b.denominator;
212
+ let x = numerator;
213
+ let y = denominator;
214
+ while (y) {
215
+ const remainder = x % y;
216
+ x = y;
217
+ y = remainder;
218
+ }
219
+ return {
220
+ numerator: numerator / x,
221
+ denominator: denominator / x
222
+ };
223
+ }
224
+ function rounded(value) {
225
+ const result = (2n * value.numerator + value.denominator) / (2n * value.denominator);
201
226
  if (result > MAX) throw new Error("Labour amount exceeds safe integer minor units.");
202
227
  return Number(result);
203
228
  }
229
+ function quantity(value) {
230
+ if (!value || typeof value !== "object") throw new Error("Labour quantity is required.");
231
+ const q = value;
232
+ if (Object.keys(q).length !== 1) throw new Error("Ambiguous labour quantity.");
233
+ if ("hours" in q) {
234
+ const result = decimal(q.hours, "Duration hours");
235
+ if (result.numerator <= 0n) throw new Error("Duration hours must be positive.");
236
+ return result;
237
+ }
238
+ if (!Number.isSafeInteger(q.seconds) || q.seconds <= 0) throw new Error("Duration seconds must be a positive safe integer.");
239
+ return {
240
+ numerator: BigInt(q.seconds),
241
+ denominator: 3600n
242
+ };
243
+ }
244
+ //#endregion
245
+ //#region src/services/dated-labour-commercial-resolver.ts
204
246
  var DatedLabourCommercialResolver = class {
205
247
  input;
206
248
  selected;
@@ -318,6 +360,241 @@ var DatedLabourCommercialResolver = class {
318
360
  }
319
361
  };
320
362
  //#endregion
363
+ //#region src/services/dated-percentage-labour-commercial-resolver.ts
364
+ var DatedPercentageLabourCommercialResolver = class {
365
+ delegate;
366
+ selected;
367
+ constructor(input) {
368
+ if (!Array.isArray(input.schedule) || !input.schedule.length) throw new Error("A rate schedule is required.");
369
+ const schedule = input.schedule.map((period) => {
370
+ if ("burden" in period) throw new Error("Percentage and hourly burden are exclusive.");
371
+ const percent = period.burdenPercent;
372
+ if (!percent || typeof percent !== "object") throw new Error("Burden percentage is required.");
373
+ identity(percent.id, "Percentage id");
374
+ identity(percent.version, "Percentage version");
375
+ decimal(percent.percent, "Burden percent");
376
+ return {
377
+ ...period,
378
+ customer: { ...period.customer },
379
+ wage: { ...period.wage },
380
+ burdenPercent: {
381
+ id: percent.id,
382
+ version: percent.version,
383
+ percent: percent.percent
384
+ }
385
+ };
386
+ });
387
+ this.delegate = new DatedLabourCommercialResolver({
388
+ ...input,
389
+ schedule: schedule.map((period) => ({
390
+ effectiveFrom: period.effectiveFrom,
391
+ effectiveUntil: period.effectiveUntil,
392
+ currency: period.currency,
393
+ customer: period.customer,
394
+ wage: period.wage,
395
+ burden: {
396
+ id: period.burdenPercent.id,
397
+ version: period.burdenPercent.version,
398
+ rateMinor: "0"
399
+ }
400
+ }))
401
+ });
402
+ this.selected = schedule.find((period) => period.effectiveFrom <= input.workDate && (period.effectiveUntil === void 0 || input.workDate < period.effectiveUntil));
403
+ }
404
+ burden(entry) {
405
+ this.delegate.validateEntry(entry);
406
+ const hours = entry.durationHoursExact();
407
+ const q = quantity(hours === null ? { seconds: entry.durationSeconds } : { hours });
408
+ const percent = decimal(this.selected.burdenPercent.percent, "Burden percent");
409
+ const hourly = multiply(decimal(this.selected.wage.rateMinor, "Hourly wage"), {
410
+ numerator: percent.numerator,
411
+ denominator: percent.denominator * 100n
412
+ });
413
+ const wage = rounded(multiply(q, decimal(this.selected.wage.rateMinor, "Hourly wage")));
414
+ const burden = rounded(multiply(q, hourly));
415
+ if (BigInt(wage) + BigInt(burden) > MAX) throw new Error("Loaded labour cost exceeds safe integer minor units.");
416
+ return {
417
+ wage,
418
+ burden,
419
+ hourly
420
+ };
421
+ }
422
+ /** Validate all private amounts before any approval mutation. */
423
+ validateEntry(entry) {
424
+ this.burden(entry);
425
+ }
426
+ /** Customer terms remain the original additive resolver's public allowlist. */
427
+ async priceClient(entry) {
428
+ this.validateEntry(entry);
429
+ return this.delegate.priceClient(entry);
430
+ }
431
+ /** Exact derived hourly rational is provenance, never an intermediate rounded rate. */
432
+ async compensateProvider(entry) {
433
+ const result = this.burden(entry);
434
+ const original = await this.delegate.compensateProvider(entry);
435
+ const { burden: _unused, ...terms } = original.terms;
436
+ return {
437
+ ...original,
438
+ version: "dated-percentage-labour-v1",
439
+ terms: {
440
+ ...terms,
441
+ loadedCostMinor: result.wage + result.burden,
442
+ burdenPercent: {
443
+ ...this.selected.burdenPercent,
444
+ amount: result.burden
445
+ },
446
+ burdenBasis: {
447
+ wageId: this.selected.wage.id,
448
+ wageVersion: this.selected.wage.version,
449
+ hourlyNumerator: result.hourly.numerator.toString(),
450
+ hourlyDenominator: result.hourly.denominator.toString()
451
+ }
452
+ }
453
+ };
454
+ }
455
+ };
456
+ //#endregion
457
+ //#region src/services/labour-valuation-reconciliation.ts
458
+ function object(value) {
459
+ if (!value || typeof value !== "object" || Array.isArray(value)) throw new Error("Missing labour snapshot terms.");
460
+ return value;
461
+ }
462
+ function minor(value) {
463
+ if (!Number.isSafeInteger(value) || value < 0) throw new Error("Expected nonnegative safe integer labour amount.");
464
+ return value;
465
+ }
466
+ function exactEvidence(snapshot, currency) {
467
+ if (!snapshot || snapshot.currency !== currency) throw new Error("Labour evidence currency mismatch.");
468
+ if (!["dated-labour-v1", "dated-percentage-labour-v1"].includes(snapshot.version)) throw new Error("Unsupported labour calculation version.");
469
+ const terms = object(snapshot.terms);
470
+ if (terms.currency !== currency || terms.rounding !== "half-up-per-component" || typeof terms.billable !== "boolean") throw new Error("Unsupported or inconsistent labour terms.");
471
+ date(terms.workDate);
472
+ date(terms.effectiveFrom);
473
+ if (terms.workDate < terms.effectiveFrom) throw new Error("Labour date outside selected period.");
474
+ if (terms.effectiveUntil !== void 0) {
475
+ date(terms.effectiveUntil);
476
+ if (terms.workDate >= terms.effectiveUntil) throw new Error("Labour date outside selected period.");
477
+ }
478
+ const q = quantity(terms.quantity);
479
+ const wageTerms = object(terms.wage);
480
+ const wageRate = rate(wageTerms);
481
+ const wageHourly = decimal(wageRate.rateMinor, "Hourly wage");
482
+ const wageExact = multiply(q, wageHourly);
483
+ const wage = rounded(wageExact);
484
+ let burdenHourly;
485
+ let suppliedBurden;
486
+ if (snapshot.version === "dated-labour-v1") {
487
+ if ("burdenPercent" in terms || "burdenBasis" in terms) throw new Error("Ambiguous labour burden.");
488
+ const burdenTerms = object(terms.burden);
489
+ burdenHourly = decimal(rate(burdenTerms).rateMinor, "Hourly burden");
490
+ suppliedBurden = burdenTerms.amount;
491
+ } else {
492
+ if ("burden" in terms) throw new Error("Ambiguous labour burden.");
493
+ const percentTerms = object(terms.burdenPercent);
494
+ identity(percentTerms.id, "Percentage id");
495
+ identity(percentTerms.version, "Percentage version");
496
+ const percent = decimal(percentTerms.percent, "Burden percent");
497
+ burdenHourly = multiply(wageHourly, {
498
+ numerator: percent.numerator,
499
+ denominator: percent.denominator * 100n
500
+ });
501
+ const basis = object(terms.burdenBasis);
502
+ if (basis.wageId !== wageRate.id || basis.wageVersion !== wageRate.version || basis.hourlyNumerator !== burdenHourly.numerator.toString() || basis.hourlyDenominator !== burdenHourly.denominator.toString()) throw new Error("Percentage burden basis differs from retained terms.");
503
+ suppliedBurden = percentTerms.amount;
504
+ }
505
+ const burdenExact = multiply(q, burdenHourly);
506
+ const burden = rounded(burdenExact);
507
+ const canonical = BigInt(wage) + BigInt(burden);
508
+ if (canonical > MAX) throw new Error("Loaded labour cost exceeds safe integer minor units.");
509
+ if (minor(snapshot.amount) !== wage || minor(wageTerms.amount) !== wage || minor(suppliedBurden) !== burden || minor(terms.loadedCostMinor) !== Number(canonical)) throw new Error("Canonical labour snapshot does not reconcile with retained terms.");
510
+ return {
511
+ exact: add(wageExact, burdenExact),
512
+ canonical: Number(canonical)
513
+ };
514
+ }
515
+ function reconcileLabourValuation(input) {
516
+ identity(input.tenantId, "Tenant id");
517
+ identity(input.groupId, "Group id");
518
+ identity(input.groupVersion, "Group version");
519
+ if (typeof input.currency !== "string" || !/^[A-Z]{3}$/.test(input.currency)) throw new Error("Explicit currency is required.");
520
+ if (input.mode !== "half-up-exact-loaded-aggregate") throw new Error("Unsupported analytical labour mode.");
521
+ if (!Array.isArray(input.evidence) || input.evidence.length === 0 || input.evidence.length > 1e4) throw new Error("Supply between 1 and 10000 labour evidence records.");
522
+ const entries = /* @__PURE__ */ new Set();
523
+ const snapshots = /* @__PURE__ */ new Set();
524
+ const policies = /* @__PURE__ */ new Map();
525
+ const rates = /* @__PURE__ */ new Map();
526
+ let exact = {
527
+ numerator: 0n,
528
+ denominator: 1n
529
+ };
530
+ let canonical = 0n;
531
+ const evidence = [];
532
+ for (const item of input.evidence) {
533
+ if (!item || item.tenantId !== input.tenantId || item.groupId !== input.groupId || item.groupVersion !== input.groupVersion) throw new Error("Labour evidence tenant/group mismatch.");
534
+ identity(item.entryId, "Entry id");
535
+ identity(item.snapshotId, "Snapshot id");
536
+ identity(item.participantProfileId, "Worker id");
537
+ if (!item.snapshot || item.snapshot.id !== item.snapshotId || item.snapshot.timeEntryId !== item.entryId || item.snapshot.tenantId !== input.tenantId) throw new Error("Labour snapshot identity mismatch.");
538
+ if (entries.has(item.entryId) || snapshots.has(item.snapshotId)) throw new Error("Duplicate labour evidence.");
539
+ entries.add(item.entryId);
540
+ snapshots.add(item.snapshotId);
541
+ const policy = object(item.policy);
542
+ identity(policy.id, "Policy id");
543
+ identity(policy.version, "Policy version");
544
+ identity(policy.digest, "Policy digest");
545
+ const policyKey = JSON.stringify([policy.id, policy.version]);
546
+ if (policies.has(policyKey) && policies.get(policyKey) !== policy.digest) throw new Error("Conflicting labour policy revision.");
547
+ policies.set(policyKey, policy.digest);
548
+ const value = exactEvidence(item.snapshot, input.currency);
549
+ for (const kind of [
550
+ "wage",
551
+ "burden",
552
+ "burdenPercent"
553
+ ]) {
554
+ const terms = item.snapshot.terms[kind];
555
+ if (terms === void 0) continue;
556
+ const selected = object(terms);
557
+ const key = JSON.stringify([
558
+ item.participantProfileId,
559
+ kind,
560
+ selected.id,
561
+ selected.version
562
+ ]);
563
+ const rateValue = String(kind === "burdenPercent" ? selected.percent : selected.rateMinor);
564
+ if (rates.has(key) && rates.get(key) !== rateValue) throw new Error("Conflicting retained labour rate revision.");
565
+ rates.set(key, rateValue);
566
+ }
567
+ canonical += BigInt(value.canonical);
568
+ if (canonical > MAX) throw new Error("Canonical labour aggregate exceeds safe integer minor units.");
569
+ exact = add(exact, value.exact);
570
+ evidence.push({
571
+ entryId: item.entryId,
572
+ snapshotId: item.snapshotId,
573
+ participantProfileId: item.participantProfileId,
574
+ policy: {
575
+ id: policy.id,
576
+ version: policy.version,
577
+ digest: policy.digest
578
+ },
579
+ calculationVersion: item.snapshot.version
580
+ });
581
+ }
582
+ evidence.sort((a, b) => a.entryId < b.entryId ? -1 : a.entryId > b.entryId ? 1 : 0);
583
+ const analytical = rounded(exact);
584
+ return {
585
+ tenantId: input.tenantId,
586
+ currency: input.currency,
587
+ groupId: input.groupId,
588
+ groupVersion: input.groupVersion,
589
+ mode: input.mode,
590
+ version: "labour-valuation-reconciliation-v1",
591
+ canonicalCostMinor: Number(canonical),
592
+ analyticalCostMinor: analytical,
593
+ differenceMinor: analytical - Number(canonical),
594
+ evidence
595
+ };
596
+ }
597
+ //#endregion
321
598
  //#region src/services/service-evidence-service.ts
322
599
  var ServiceEvidenceService = class ServiceEvidenceService {
323
600
  constructor(entries, charges, compensation, commercial) {
@@ -492,6 +769,6 @@ async function deterministicSnapshotId(kind, timeEntryId) {
492
769
  ].join("-");
493
770
  }
494
771
  //#endregion
495
- export { AttendanceBreak, AttendanceBreakCollection, AttendanceConflict, AttendancePunch, AttendancePunchCollection, AttendanceReplay, AttendanceReplayCollection, AttendanceService, DatedLabourCommercialResolver, PeriodRollupService, PeriodTimecard, PeriodTimecardCollection, SERVICE_DURATION_HOURS_EVIDENCE, SERVICE_TIME_ENTRY_FROZEN_FIELDS, SERVICE_TIME_ENTRY_STATUS_TRANSITIONS, ServiceChargeSnapshot, ServiceChargeSnapshotCollection, ServiceCompensationSnapshot, ServiceCompensationSnapshotCollection, ServiceEvidenceService, ServiceTimeEntry, ServiceTimeEntryCollection, TIMESHEETS_MODULE_META, TIMESHEETS_UI_SLOTS, TimecardAdjustment, TimecardAdjustmentCollection };
772
+ export { AttendanceBreak, AttendanceBreakCollection, AttendanceConflict, AttendancePunch, AttendancePunchCollection, AttendanceReplay, AttendanceReplayCollection, AttendanceService, DatedLabourCommercialResolver, DatedPercentageLabourCommercialResolver, PeriodRollupService, PeriodTimecard, PeriodTimecardCollection, SERVICE_DURATION_HOURS_EVIDENCE, SERVICE_TIME_ENTRY_FROZEN_FIELDS, SERVICE_TIME_ENTRY_STATUS_TRANSITIONS, ServiceChargeSnapshot, ServiceChargeSnapshotCollection, ServiceCompensationSnapshot, ServiceCompensationSnapshotCollection, ServiceEvidenceService, ServiceTimeEntry, ServiceTimeEntryCollection, TIMESHEETS_MODULE_META, TIMESHEETS_UI_SLOTS, TimecardAdjustment, TimecardAdjustmentCollection, reconcileLabourValuation };
496
773
 
497
774
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/models/service-snapshots.ts","../src/services/dated-labour-commercial-resolver.ts","../src/services/service-evidence-service.ts"],"sourcesContent":["import {\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n smrt,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/**\n * Refuse an amount that is not a JavaScript-safe integer number of minor\n * units. SQLite stores `19.99` in an INTEGER column without complaint and\n * PostgreSQL rejects it only at the driver, so the model boundary is the one\n * place both engines (and every writer: collections, `ServiceEvidenceService`,\n * resolvers) get the same answer. Sign is not constrained here.\n */\nexport function assertSnapshotMinorUnits(model: string, amount: unknown): void {\n if (typeof amount !== 'number' || !Number.isSafeInteger(amount)) {\n throw new ValidationError(\n `${model}.amount must be a safe integer number of minor units (cents) — ` +\n `got ${String(amount)}. $19.99 is 1999.`,\n 'VALIDATION_INVALID_VALUE',\n {\n fieldName: 'amount',\n value: amount,\n expectedType: 'safe integer minor units',\n },\n );\n }\n}\n\nconst chargeSnapshot = new WeakMap<ServiceChargeSnapshot, string>();\nconst compensationSnapshot = new WeakMap<ServiceCompensationSnapshot, string>();\n\nasync function immutableCommercialSnapshot(\n object: SmrtObject,\n fields: string[],\n): Promise<string | null> {\n if (!object.id) return null;\n try {\n const row = await object.db.get(object.tableName, { id: object.id });\n if (!row) return null;\n return JSON.stringify(\n Object.fromEntries(\n fields.map((key) => [\n key,\n row[key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`)] ?? null,\n ]),\n ),\n );\n } catch {\n return null;\n }\n}\n\nfunction commercialSnapshot(\n object: Record<string, unknown>,\n fields: string[],\n): string {\n return JSON.stringify(\n Object.fromEntries(fields.map((key) => [key, object[key] ?? null])),\n );\n}\n\nconst CHARGE_FIELDS = [\n 'timeEntryId',\n 'amount',\n 'currency',\n 'pricingVersion',\n 'strategy',\n 'rateSnapshot',\n 'sourceChargeRef',\n];\nconst COMPENSATION_FIELDS = [\n 'timeEntryId',\n 'amount',\n 'currency',\n 'termsVersion',\n 'rateSnapshot',\n];\n\n/**\n * Immutable client-charge snapshot for one approved time entry. Money is\n * integer minor units, consistent with smrt-commerce (#2401).\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'service_charge_snapshots',\n // Moved from smrt-projects in #3288; stored references keep resolving.\n previousQualifiedNames: [\n '@happyvertical/smrt-projects:ServiceChargeSnapshot',\n ],\n conflictColumns: ['time_entry_id'],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class ServiceChargeSnapshot extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-timesheets\";\n @tenantId({ nullable: true }) tenantId: string | null = null;\n @foreignKey('ServiceTimeEntry', { required: true }) timeEntryId: string = '';\n /**\n * Client charge in **integer minor units** of {@link currency} — `$19.99` is\n * `1999`. The `= 0` initializer is load-bearing: SMRT maps an integer literal\n * to INTEGER and a decimal literal to DECIMAL (#2401).\n *\n * Copied verbatim from the upstream `ClientCharge.amount`, so the two carry\n * the same unit by construction; a split would land cents in a major-units\n * column with no error anywhere.\n */\n amount: number = 0;\n @field({ type: 'text' }) currency: string = 'USD';\n @field({ type: 'text' }) pricingVersion: string = '';\n @field({ type: 'text' }) strategy: string = '';\n @field({ type: 'text' }) rateSnapshot: string = '{}';\n @field({ type: 'text' }) sourceChargeRef: string = '';\n createdAt: Date = new Date();\n\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved())\n chargeSnapshot.set(\n this,\n commercialSnapshot(\n this as unknown as Record<string, unknown>,\n CHARGE_FIELDS,\n ),\n );\n return this;\n }\n\n override async save(): Promise<this> {\n assertSnapshotMinorUnits('ServiceChargeSnapshot', this.amount);\n const current = commercialSnapshot(\n this as unknown as Record<string, unknown>,\n CHARGE_FIELDS,\n );\n const prior =\n (await immutableCommercialSnapshot(this, CHARGE_FIELDS)) ??\n chargeSnapshot.get(this) ??\n null;\n if (prior && prior !== current)\n throw new Error(\n 'ServiceChargeSnapshot is immutable; append an upstream adjustment instead.',\n );\n const result = (await super.save()) as this;\n chargeSnapshot.set(this, current);\n return result;\n }\n}\n\n/**\n * Immutable provider-compensation snapshot for one approved time entry,\n * kept separate from the client charge so the margin is `charge - compensation`.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'service_compensation_snapshots',\n // Moved from smrt-projects in #3288; stored references keep resolving.\n previousQualifiedNames: [\n '@happyvertical/smrt-projects:ServiceCompensationSnapshot',\n ],\n conflictColumns: ['time_entry_id'],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class ServiceCompensationSnapshot extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-timesheets\";\n @tenantId({ nullable: true }) tenantId: string | null = null;\n @foreignKey('ServiceTimeEntry', { required: true }) timeEntryId: string = '';\n /**\n * Provider earning in **integer minor units** of {@link currency} (#2401).\n *\n * Converts with {@link ServiceChargeSnapshot.amount}: the delivery margin is\n * `charge - compensation`, so a mixed pair would make that subtraction\n * meaningless.\n */\n amount: number = 0;\n @field({ type: 'text' }) currency: string = 'USD';\n @field({ type: 'text' }) termsVersion: string = '';\n @field({ type: 'text' }) rateSnapshot: string = '{}';\n createdAt: Date = new Date();\n\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved())\n compensationSnapshot.set(\n this,\n commercialSnapshot(\n this as unknown as Record<string, unknown>,\n COMPENSATION_FIELDS,\n ),\n );\n return this;\n }\n\n override async save(): Promise<this> {\n assertSnapshotMinorUnits('ServiceCompensationSnapshot', this.amount);\n const current = commercialSnapshot(\n this as unknown as Record<string, unknown>,\n COMPENSATION_FIELDS,\n );\n const prior =\n (await immutableCommercialSnapshot(this, COMPENSATION_FIELDS)) ??\n compensationSnapshot.get(this) ??\n null;\n if (prior && prior !== current)\n throw new Error(\n 'ServiceCompensationSnapshot is immutable; create explicit settlement evidence instead.',\n );\n const result = (await super.save()) as this;\n compensationSnapshot.set(this, current);\n return result;\n }\n}\n\n/** Collection over `service_charge_snapshots`. */\nexport class ServiceChargeSnapshotCollection extends SmrtCollection<ServiceChargeSnapshot> {\n static readonly _itemClass = ServiceChargeSnapshot;\n}\n/** Collection over `service_compensation_snapshots`. */\nexport class ServiceCompensationSnapshotCollection extends SmrtCollection<ServiceCompensationSnapshot> {\n static readonly _itemClass = ServiceCompensationSnapshot;\n}\n","import type { ServiceTimeEntry } from '../models/service-time-entry.js';\nimport type {\n CommercialSnapshot,\n ServiceCommercialResolver,\n} from './service-evidence-service.js';\n\n/** Explicit hourly rate in currency minor units, with immutable host provenance. */\nexport interface DatedLabourRate {\n id: string;\n version: string;\n /** Nonnegative plain decimal text, at most 18 fractional digits. */\n rateMinor: string;\n}\n\n/** A half-open effective period. An omitted end means no upper bound. */\nexport interface DatedLabourRatePeriod {\n effectiveFrom: string;\n effectiveUntil?: string;\n currency: string;\n customer: DatedLabourRate;\n wage: DatedLabourRate;\n /** Additive hourly burden amount; never a percentage or statutory default. */\n burden: DatedLabourRate;\n}\n\n/**\n * Trusted host input: authorize this tenant, worker and schedule before use.\n * Dates are YYYY-MM-DD calendar dates, never inferred from process time.\n */\nexport interface DatedLabourCommercialInput {\n tenantId: string;\n participantProfileId: string;\n workDate: string;\n currency: string;\n billable: boolean;\n schedule: readonly DatedLabourRatePeriod[];\n}\n\ntype Rational = { numerator: bigint; denominator: bigint };\nconst MAX = BigInt(Number.MAX_SAFE_INTEGER);\n\nfunction decimal(value: string, label: string): Rational {\n if (\n typeof value !== 'string' ||\n value.length > 40 ||\n !/^\\d+(?:\\.\\d{1,18})?$/.test(value)\n )\n throw new Error(`${label} must be nonnegative plain decimal text.`);\n const [whole, fraction = ''] = value.split('.');\n const denominator = 10n ** BigInt(fraction.length);\n const numerator = BigInt(whole + fraction);\n if (numerator > MAX * denominator)\n throw new Error(`${label} exceeds the safe numeric range.`);\n return { numerator, denominator };\n}\n\nfunction date(value: string): void {\n if (\n typeof value !== 'string' ||\n !/^\\d{4}-\\d{2}-\\d{2}$/.test(value) ||\n value.startsWith('0000-')\n )\n throw new Error('Expected a valid YYYY-MM-DD calendar date.');\n const parsed = new Date(`${value}T00:00:00.000Z`);\n if (\n !Number.isFinite(parsed.getTime()) ||\n parsed.toISOString().slice(0, 10) !== value\n )\n throw new Error('Expected a valid YYYY-MM-DD calendar date.');\n}\n\nfunction identity(value: string, label: string): void {\n if (typeof value !== 'string' || !value.trim())\n throw new Error(`${label} is required.`);\n}\n\nfunction rate(value: DatedLabourRate): DatedLabourRate {\n if (!value || typeof value !== 'object') throw new Error('Rate is required.');\n identity(value.id, 'Rate id');\n identity(value.version, 'Rate version');\n decimal(value.rateMinor, 'Hourly rate');\n // Whitelist fields: never copy arbitrary host/private facts to client terms.\n return { id: value.id, version: value.version, rateMinor: value.rateMinor };\n}\n\nfunction amount(hours: Rational, hourly: DatedLabourRate): number {\n const value = decimal(hourly.rateMinor, 'Hourly rate');\n const numerator = hours.numerator * value.numerator;\n const denominator = hours.denominator * value.denominator;\n // Exact nonnegative half-up rounding, once per independent component.\n const result = (2n * numerator + denominator) / (2n * denominator);\n if (result > MAX)\n throw new Error('Labour amount exceeds safe integer minor units.');\n return Number(result);\n}\n\n/**\n * Opt-in effective-dated labour calculator behind ServiceCommercialResolver.\n * Copies selected authorized terms at construction. Retain those same terms\n * when reconstructing a resolver for an incomplete approval retry. Wage and\n * burden are rounded separately. Provider amount is wage only; their sum is\n * private loadedCostMinor. Neither appears in client terms.\n */\nexport class DatedLabourCommercialResolver\n implements ServiceCommercialResolver\n{\n private readonly input: Omit<DatedLabourCommercialInput, 'schedule'>;\n private readonly selected: DatedLabourRatePeriod;\n\n constructor(input: DatedLabourCommercialInput) {\n identity(input.tenantId, 'Tenant id');\n identity(input.participantProfileId, 'Worker profile id');\n date(input.workDate);\n if (\n typeof input.currency !== 'string' ||\n !/^[A-Z]{3}$/.test(input.currency)\n )\n throw new Error(\n 'Currency must be an explicit three-letter uppercase code.',\n );\n if (typeof input.billable !== 'boolean')\n throw new Error('Billable must be explicit.');\n if (!Array.isArray(input.schedule) || !input.schedule.length)\n throw new Error('A rate schedule is required.');\n const schedule = input.schedule\n .map((period) => {\n date(period.effectiveFrom);\n if (period.effectiveUntil !== undefined) {\n date(period.effectiveUntil);\n if (period.effectiveUntil <= period.effectiveFrom)\n throw new Error('Effective period must have positive length.');\n }\n if (period.currency !== input.currency)\n throw new Error('Rate schedule currency mismatch.');\n return {\n effectiveFrom: period.effectiveFrom,\n effectiveUntil: period.effectiveUntil,\n currency: period.currency,\n customer: rate(period.customer),\n wage: rate(period.wage),\n burden: rate(period.burden),\n };\n })\n .sort((a, b) => a.effectiveFrom.localeCompare(b.effectiveFrom));\n for (let i = 1; i < schedule.length; i++) {\n const previousEnd = schedule[i - 1].effectiveUntil;\n if (previousEnd === undefined || previousEnd > schedule[i].effectiveFrom)\n throw new Error('Overlapping or ambiguous rate schedule.');\n }\n const selected = schedule.find(\n (period) =>\n period.effectiveFrom <= input.workDate &&\n (period.effectiveUntil === undefined ||\n input.workDate < period.effectiveUntil),\n );\n if (!selected) throw new Error('No applicable labour rate for work date.');\n this.selected = selected;\n this.input = {\n tenantId: input.tenantId,\n participantProfileId: input.participantProfileId,\n workDate: input.workDate,\n currency: input.currency,\n billable: input.billable,\n };\n }\n\n private resolve(entry: ServiceTimeEntry) {\n if (\n entry.tenantId !== this.input.tenantId ||\n entry.participantKind !== 'human' ||\n entry.participantProfileId !== this.input.participantProfileId\n )\n throw new Error('Labour entry tenant/worker identity mismatch.');\n const text = entry.durationHoursExact();\n let hours: Rational;\n let quantity: { hours: string } | { seconds: number };\n if (text !== null) {\n if (entry.durationSeconds !== null || entry.startedAt || entry.endedAt)\n throw new Error('Ambiguous hours and measured duration.');\n hours = decimal(text, 'Duration hours');\n quantity = { hours: text };\n } else {\n const seconds = entry.durationSeconds;\n if (!Number.isSafeInteger(seconds) || seconds === null || seconds <= 0)\n throw new Error('Duration seconds must be a positive safe integer.');\n hours = { numerator: BigInt(seconds), denominator: 3600n };\n quantity = { seconds };\n }\n if (hours.numerator <= 0n)\n throw new Error('Duration hours must be positive.');\n const customer = amount(hours, this.selected.customer);\n const wage = amount(hours, this.selected.wage);\n const burden = amount(hours, this.selected.burden);\n if (BigInt(wage) + BigInt(burden) > MAX)\n throw new Error('Loaded labour cost exceeds safe integer minor units.');\n const common = {\n workDate: this.input.workDate,\n effectiveFrom: this.selected.effectiveFrom,\n ...(this.selected.effectiveUntil === undefined\n ? {}\n : { effectiveUntil: this.selected.effectiveUntil }),\n currency: this.input.currency,\n billable: this.input.billable,\n quantity,\n rounding: 'half-up-per-component',\n };\n return {\n client: {\n amount: this.input.billable ? customer : 0,\n currency: this.input.currency,\n version: 'dated-labour-v1',\n strategy: 'dated-hourly-labour',\n terms: { ...common, customer: { ...this.selected.customer } },\n },\n provider: {\n amount: wage,\n currency: this.input.currency,\n version: 'dated-labour-v1',\n terms: {\n ...common,\n loadedCostMinor: wage + burden,\n wage: { ...this.selected.wage, amount: wage },\n burden: { ...this.selected.burden, amount: burden },\n },\n },\n };\n }\n\n /** Validate both results before ServiceEvidenceService freezes an entry. */\n validateEntry(entry: ServiceTimeEntry): void {\n this.resolve(entry);\n }\n\n /** Client-only terms: no wage, burden or compensation rate provenance. */\n async priceClient(entry: ServiceTimeEntry): Promise<CommercialSnapshot> {\n return this.resolve(entry).client;\n }\n\n /** Provider earnings are wages; private terms also retain burden and loaded cost. */\n async compensateProvider(\n entry: ServiceTimeEntry,\n ): Promise<CommercialSnapshot> {\n return this.resolve(entry).provider;\n }\n}\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport {\n ServiceChargeSnapshotCollection,\n ServiceCompensationSnapshotCollection,\n} from '../models/service-snapshots.js';\nimport type { ServiceTimeEntry } from '../models/service-time-entry.js';\nimport {\n SERVICE_DURATION_HOURS_EVIDENCE,\n ServiceTimeEntryCollection,\n validateDurationHours,\n} from '../models/service-time-entry.js';\nimport type {\n ServiceEvidence,\n ServiceParticipantKind,\n ServiceTimeEntrySource,\n} from '../types.js';\n\n/**\n * Input for {@link ServiceEvidenceService.record}. The work reference is the\n * qualified class name and id of whatever the time was spent on.\n */\nexport interface RecordServiceTimeInput {\n tenantId?: string | null;\n workRefType?: string | null;\n workRefId?: string | null;\n participantKind: ServiceParticipantKind;\n participantProfileId?: string | null;\n agentRef?: string;\n source: ServiceTimeEntrySource;\n description: string;\n startedAt?: Date | null;\n endedAt?: Date | null;\n durationSeconds?: number | null;\n /** Exact positive decimal text; exclusive with seconds and timestamps. */\n durationHours?: string;\n evidence?: ServiceEvidence[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface CommercialSnapshot {\n /**\n * Integer minor units of `currency` — `$19.99` is `1999` (#2401).\n *\n * Written straight into `ServiceChargeSnapshot.amount` /\n * `ServiceCompensationSnapshot.amount`, INTEGER columns whose `save()`\n * refuses anything but a safe integer on every engine. A fractional\n * major-unit value (`19.99`) is rejected; a whole one (`150` for $150.00)\n * is not detectable and is stored 100× too small, so return minor units.\n */\n amount: number;\n currency?: string;\n version: string;\n strategy?: string;\n terms: Record<string, unknown>;\n sourceRef?: string;\n}\n\nexport interface ServiceCommercialResolver {\n /** Pure preflight: reject unsupported evidence before approval or snapshot writes. */\n validateEntry?(entry: ServiceTimeEntry): void | Promise<void>;\n priceClient(entry: ServiceTimeEntry): Promise<CommercialSnapshot>;\n compensateProvider(entry: ServiceTimeEntry): Promise<CommercialSnapshot>;\n}\n\n/**\n * Records, submits, approves, and corrects time entries. Approval writes one\n * immutable client-charge and one provider-compensation snapshot per entry;\n * a correction is a new entry pointing at the approved one, which flips to\n * `corrected` with its snapshots intact.\n */\nexport class ServiceEvidenceService {\n constructor(\n private readonly entries: ServiceTimeEntryCollection,\n private readonly charges: ServiceChargeSnapshotCollection,\n private readonly compensation: ServiceCompensationSnapshotCollection,\n private readonly commercial?: ServiceCommercialResolver,\n ) {}\n\n static async create(\n options: SmrtClassOptions = {},\n commercial?: ServiceCommercialResolver,\n ): Promise<ServiceEvidenceService> {\n const [entries, charges, compensation] = await Promise.all([\n ServiceTimeEntryCollection.create(options),\n ServiceChargeSnapshotCollection.create(options),\n ServiceCompensationSnapshotCollection.create(options),\n ]);\n return new ServiceEvidenceService(\n entries,\n charges,\n compensation,\n commercial,\n );\n }\n\n async record(input: RecordServiceTimeInput): Promise<ServiceTimeEntry> {\n if (!['timer', 'manual', 'import', 'agent'].includes(input.source))\n throw new Error('Unsupported service time source.');\n if (Boolean(input.workRefType) !== Boolean(input.workRefId))\n throw new Error('workRefType and workRefId must be provided together.');\n if (!(input.workRefType && input.workRefId))\n throw new Error('Service time requires a work reference.');\n if (input.participantKind === 'human' && !input.participantProfileId)\n throw new Error('Human service time requires participantProfileId.');\n if (input.participantKind === 'agent' && !input.agentRef)\n throw new Error('Agent service time requires agentRef.');\n if (input.source === 'timer' && (!input.startedAt || !input.endedAt))\n throw new Error('Timer service time requires startedAt and endedAt.');\n if (input.startedAt && input.endedAt && input.startedAt >= input.endedAt)\n throw new Error('Service time startedAt must be before endedAt.');\n const { durationHours, ...fields } = input;\n if (\n input.evidence?.some(\n (item) => item?.kind === SERVICE_DURATION_HOURS_EVIDENCE,\n )\n )\n throw new Error(\n 'Use durationHours to supply reserved decimal-hours evidence.',\n );\n const hours =\n durationHours === undefined ? null : validateDurationHours(durationHours);\n if (\n hours !== null &&\n (input.durationSeconds != null || input.startedAt || input.endedAt)\n )\n throw new Error(\n 'Decimal-hours-only service time cannot also supply seconds or timestamps.',\n );\n if (hours === null && input.durationSeconds === null)\n throw new Error('Null durationSeconds requires durationHours.');\n const duration =\n hours !== null\n ? null\n : (input.durationSeconds ??\n (input.startedAt && input.endedAt\n ? Math.round(\n (input.endedAt.getTime() - input.startedAt.getTime()) / 1000,\n )\n : 0));\n if (duration !== null && (!Number.isSafeInteger(duration) || duration <= 0))\n throw new Error(\n 'Service time durationSeconds must be a positive integer.',\n );\n const entry = await this.entries.create({\n ...fields,\n durationSeconds: duration,\n evidence: JSON.stringify([\n ...(input.evidence ?? []),\n ...(hours === null\n ? []\n : [{ kind: SERVICE_DURATION_HOURS_EVIDENCE, hours }]),\n ]),\n metadata: JSON.stringify(input.metadata ?? {}),\n status: 'draft',\n submittedAt: null,\n submittedByProfileId: null,\n approvedAt: null,\n approvedByProfileId: null,\n approvalPath: '',\n rejectedAt: null,\n rejectedByProfileId: null,\n rejectionReason: '',\n correctionOfId: null,\n });\n await entry.save();\n return entry;\n }\n\n async submit(\n entry: ServiceTimeEntry,\n profileId?: string,\n ): Promise<ServiceTimeEntry> {\n if (entry.status !== 'draft' && entry.status !== 'rejected')\n throw new Error('Only draft or rejected service time may be submitted.');\n entry.status = 'submitted';\n entry.submittedAt = new Date();\n entry.submittedByProfileId = profileId ?? null;\n return entry.save();\n }\n\n async approve(\n entry: ServiceTimeEntry,\n options: { actorProfileId?: string; approvalPath: string },\n ): Promise<ServiceTimeEntry> {\n if (entry.status !== 'submitted' && entry.status !== 'approved')\n throw new Error(\n 'Only submitted service time or an incomplete approval may be approved.',\n );\n if (!this.commercial)\n throw new Error(\n 'A ServiceCommercialResolver is required to approve service time.',\n );\n const timeEntryId = entry.id;\n if (!timeEntryId)\n throw new Error('ServiceTimeEntry must be saved before approval.');\n const existingCharge = (\n await this.charges.list({ where: { timeEntryId }, limit: 1 })\n )[0];\n const existingCompensation = (\n await this.compensation.list({ where: { timeEntryId }, limit: 1 })\n )[0];\n if (entry.status === 'approved' && existingCharge && existingCompensation)\n return entry;\n\n await this.commercial.validateEntry?.(entry);\n\n // Commit approval before either commercial resolver runs. The subscription\n // resolver creates an approved ClientCharge as part of priceClient(), so a\n // failed approval must never leave billable spend behind.\n if (entry.status === 'submitted') {\n entry.status = 'approved';\n entry.approvedAt = new Date();\n entry.approvedByProfileId = options.actorProfileId ?? null;\n entry.approvalPath = options.approvalPath;\n try {\n await entry.save();\n } catch (error) {\n const revisionConflict =\n error instanceof Error &&\n 'code' in error &&\n error.code === 'RUNTIME_REVISION_CONFLICT';\n if (!revisionConflict) throw error;\n const concurrent = await this.entries.get(timeEntryId);\n if (concurrent?.status !== 'approved') throw error;\n entry = concurrent;\n await this.commercial.validateEntry?.(entry);\n }\n }\n const provider = existingCompensation\n ? null\n : await this.commercial.compensateProvider(entry);\n if (provider) {\n const snapshotId = await deterministicSnapshotId(\n 'service-compensation-snapshot',\n timeEntryId,\n );\n try {\n await this.compensation.create({\n id: snapshotId,\n tenantId: entry.tenantId,\n timeEntryId,\n amount: provider.amount,\n currency: provider.currency ?? 'USD',\n termsVersion: provider.version,\n rateSnapshot: JSON.stringify(provider.terms),\n _insertOnly: true,\n });\n } catch (error) {\n const concurrent =\n (await this.compensation.get(snapshotId)) ??\n (\n await this.compensation.list({\n where: { timeEntryId },\n limit: 1,\n })\n )[0];\n if (!concurrent) throw error;\n }\n }\n const client = existingCharge\n ? null\n : await this.commercial.priceClient(entry);\n if (client) {\n const snapshotId = await deterministicSnapshotId(\n 'service-charge-snapshot',\n timeEntryId,\n );\n try {\n await this.charges.create({\n id: snapshotId,\n tenantId: entry.tenantId,\n timeEntryId,\n amount: client.amount,\n currency: client.currency ?? 'USD',\n pricingVersion: client.version,\n strategy: client.strategy ?? '',\n rateSnapshot: JSON.stringify(client.terms),\n sourceChargeRef: client.sourceRef ?? '',\n _insertOnly: true,\n });\n } catch (error) {\n const concurrent =\n (await this.charges.get(snapshotId)) ??\n (\n await this.charges.list({\n where: { timeEntryId },\n limit: 1,\n })\n )[0];\n if (!concurrent) throw error;\n }\n }\n return entry;\n }\n\n async correct(\n entry: ServiceTimeEntry,\n input: RecordServiceTimeInput,\n ): Promise<ServiceTimeEntry> {\n if (entry.status !== 'approved')\n throw new Error('Only approved service time may be corrected.');\n if (input.tenantId !== undefined && input.tenantId !== entry.tenantId) {\n throw new Error(\n 'Service time corrections must remain in the original tenant.',\n );\n }\n const correction = await this.record({\n ...input,\n tenantId: entry.tenantId,\n });\n correction.correctionOfId = entry.id ?? null;\n await correction.save();\n entry.status = 'corrected';\n await entry.save();\n return correction;\n }\n}\n\nasync function deterministicSnapshotId(\n kind: string,\n timeEntryId: string,\n): Promise<string> {\n const bytes = new TextEncoder().encode(JSON.stringify([kind, timeEntryId]));\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n const uuid = digest.slice(0, 16);\n uuid[6] = (uuid[6] & 0x0f) | 0x50;\n uuid[8] = (uuid[8] & 0x3f) | 0x80;\n const hex = Array.from(uuid, (byte) =>\n byte.toString(16).padStart(2, '0'),\n ).join('');\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20),\n ].join('-');\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/models/service-snapshots.ts","../src/services/labour-math.ts","../src/services/dated-labour-commercial-resolver.ts","../src/services/dated-percentage-labour-commercial-resolver.ts","../src/services/labour-valuation-reconciliation.ts","../src/services/service-evidence-service.ts"],"sourcesContent":["import {\n field,\n foreignKey,\n SmrtCollection,\n SmrtObject,\n smrt,\n ValidationError,\n} from '@happyvertical/smrt-core';\nimport { TenantScoped, tenantId } from '@happyvertical/smrt-tenancy';\n\n/**\n * Refuse an amount that is not a JavaScript-safe integer number of minor\n * units. SQLite stores `19.99` in an INTEGER column without complaint and\n * PostgreSQL rejects it only at the driver, so the model boundary is the one\n * place both engines (and every writer: collections, `ServiceEvidenceService`,\n * resolvers) get the same answer. Sign is not constrained here.\n */\nexport function assertSnapshotMinorUnits(model: string, amount: unknown): void {\n if (typeof amount !== 'number' || !Number.isSafeInteger(amount)) {\n throw new ValidationError(\n `${model}.amount must be a safe integer number of minor units (cents) — ` +\n `got ${String(amount)}. $19.99 is 1999.`,\n 'VALIDATION_INVALID_VALUE',\n {\n fieldName: 'amount',\n value: amount,\n expectedType: 'safe integer minor units',\n },\n );\n }\n}\n\nconst chargeSnapshot = new WeakMap<ServiceChargeSnapshot, string>();\nconst compensationSnapshot = new WeakMap<ServiceCompensationSnapshot, string>();\n\nasync function immutableCommercialSnapshot(\n object: SmrtObject,\n fields: string[],\n): Promise<string | null> {\n if (!object.id) return null;\n try {\n const row = await object.db.get(object.tableName, { id: object.id });\n if (!row) return null;\n return JSON.stringify(\n Object.fromEntries(\n fields.map((key) => [\n key,\n row[key.replace(/[A-Z]/g, (c) => `_${c.toLowerCase()}`)] ?? null,\n ]),\n ),\n );\n } catch {\n return null;\n }\n}\n\nfunction commercialSnapshot(\n object: Record<string, unknown>,\n fields: string[],\n): string {\n return JSON.stringify(\n Object.fromEntries(fields.map((key) => [key, object[key] ?? null])),\n );\n}\n\nconst CHARGE_FIELDS = [\n 'timeEntryId',\n 'amount',\n 'currency',\n 'pricingVersion',\n 'strategy',\n 'rateSnapshot',\n 'sourceChargeRef',\n];\nconst COMPENSATION_FIELDS = [\n 'timeEntryId',\n 'amount',\n 'currency',\n 'termsVersion',\n 'rateSnapshot',\n];\n\n/**\n * Immutable client-charge snapshot for one approved time entry. Money is\n * integer minor units, consistent with smrt-commerce (#2401).\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'service_charge_snapshots',\n // Moved from smrt-projects in #3288; stored references keep resolving.\n previousQualifiedNames: [\n '@happyvertical/smrt-projects:ServiceChargeSnapshot',\n ],\n conflictColumns: ['time_entry_id'],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class ServiceChargeSnapshot extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-timesheets\";\n @tenantId({ nullable: true }) tenantId: string | null = null;\n @foreignKey('ServiceTimeEntry', { required: true }) timeEntryId: string = '';\n /**\n * Client charge in **integer minor units** of {@link currency} — `$19.99` is\n * `1999`. The `= 0` initializer is load-bearing: SMRT maps an integer literal\n * to INTEGER and a decimal literal to DECIMAL (#2401).\n *\n * Copied verbatim from the upstream `ClientCharge.amount`, so the two carry\n * the same unit by construction; a split would land cents in a major-units\n * column with no error anywhere.\n */\n amount: number = 0;\n @field({ type: 'text' }) currency: string = 'USD';\n @field({ type: 'text' }) pricingVersion: string = '';\n @field({ type: 'text' }) strategy: string = '';\n @field({ type: 'text' }) rateSnapshot: string = '{}';\n @field({ type: 'text' }) sourceChargeRef: string = '';\n createdAt: Date = new Date();\n\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved())\n chargeSnapshot.set(\n this,\n commercialSnapshot(\n this as unknown as Record<string, unknown>,\n CHARGE_FIELDS,\n ),\n );\n return this;\n }\n\n override async save(): Promise<this> {\n assertSnapshotMinorUnits('ServiceChargeSnapshot', this.amount);\n const current = commercialSnapshot(\n this as unknown as Record<string, unknown>,\n CHARGE_FIELDS,\n );\n const prior =\n (await immutableCommercialSnapshot(this, CHARGE_FIELDS)) ??\n chargeSnapshot.get(this) ??\n null;\n if (prior && prior !== current)\n throw new Error(\n 'ServiceChargeSnapshot is immutable; append an upstream adjustment instead.',\n );\n const result = (await super.save()) as this;\n chargeSnapshot.set(this, current);\n return result;\n }\n}\n\n/**\n * Immutable provider-compensation snapshot for one approved time entry,\n * kept separate from the client charge so the margin is `charge - compensation`.\n */\n@TenantScoped({ mode: 'optional' })\n@smrt({\n tableName: 'service_compensation_snapshots',\n // Moved from smrt-projects in #3288; stored references keep resolving.\n previousQualifiedNames: [\n '@happyvertical/smrt-projects:ServiceCompensationSnapshot',\n ],\n conflictColumns: ['time_entry_id'],\n api: { include: ['list', 'get'] },\n cli: { include: ['list', 'get'] },\n mcp: { include: ['list', 'get'] },\n})\nexport class ServiceCompensationSnapshot extends SmrtObject { static __smrtPackage__ = \"@happyvertical/smrt-timesheets\";\n @tenantId({ nullable: true }) tenantId: string | null = null;\n @foreignKey('ServiceTimeEntry', { required: true }) timeEntryId: string = '';\n /**\n * Provider earning in **integer minor units** of {@link currency} (#2401).\n *\n * Converts with {@link ServiceChargeSnapshot.amount}: the delivery margin is\n * `charge - compensation`, so a mixed pair would make that subtraction\n * meaningless.\n */\n amount: number = 0;\n @field({ type: 'text' }) currency: string = 'USD';\n @field({ type: 'text' }) termsVersion: string = '';\n @field({ type: 'text' }) rateSnapshot: string = '{}';\n createdAt: Date = new Date();\n\n override async initialize(): Promise<this> {\n await super.initialize();\n if (await this.isSaved())\n compensationSnapshot.set(\n this,\n commercialSnapshot(\n this as unknown as Record<string, unknown>,\n COMPENSATION_FIELDS,\n ),\n );\n return this;\n }\n\n override async save(): Promise<this> {\n assertSnapshotMinorUnits('ServiceCompensationSnapshot', this.amount);\n const current = commercialSnapshot(\n this as unknown as Record<string, unknown>,\n COMPENSATION_FIELDS,\n );\n const prior =\n (await immutableCommercialSnapshot(this, COMPENSATION_FIELDS)) ??\n compensationSnapshot.get(this) ??\n null;\n if (prior && prior !== current)\n throw new Error(\n 'ServiceCompensationSnapshot is immutable; create explicit settlement evidence instead.',\n );\n const result = (await super.save()) as this;\n compensationSnapshot.set(this, current);\n return result;\n }\n}\n\n/** Collection over `service_charge_snapshots`. */\nexport class ServiceChargeSnapshotCollection extends SmrtCollection<ServiceChargeSnapshot> {\n static readonly _itemClass = ServiceChargeSnapshot;\n}\n/** Collection over `service_compensation_snapshots`. */\nexport class ServiceCompensationSnapshotCollection extends SmrtCollection<ServiceCompensationSnapshot> {\n static readonly _itemClass = ServiceCompensationSnapshot;\n}\n","import type { DatedLabourRate } from './dated-labour-commercial-resolver.js';\n\nexport type Rational = { numerator: bigint; denominator: bigint };\nexport const MAX = BigInt(Number.MAX_SAFE_INTEGER);\n\nexport function decimal(value: string, label: string): Rational {\n if (\n typeof value !== 'string' ||\n value.length > 40 ||\n !/^\\d+(?:\\.\\d{1,18})?$/.test(value)\n )\n throw new Error(`${label} must be nonnegative plain decimal text.`);\n const [whole, fraction = ''] = value.split('.');\n const denominator = 10n ** BigInt(fraction.length);\n const numerator = BigInt(whole + fraction);\n if (numerator > MAX * denominator)\n throw new Error(`${label} exceeds the safe numeric range.`);\n return { numerator, denominator };\n}\n\nexport function date(value: string): void {\n if (\n typeof value !== 'string' ||\n !/^\\d{4}-\\d{2}-\\d{2}$/.test(value) ||\n value.startsWith('0000-')\n )\n throw new Error('Expected a valid YYYY-MM-DD calendar date.');\n const parsed = new Date(`${value}T00:00:00.000Z`);\n if (\n !Number.isFinite(parsed.getTime()) ||\n parsed.toISOString().slice(0, 10) !== value\n )\n throw new Error('Expected a valid YYYY-MM-DD calendar date.');\n}\n\nexport function identity(value: string, label: string): void {\n if (typeof value !== 'string' || !value.trim())\n throw new Error(`${label} is required.`);\n}\n\nexport function rate(value: DatedLabourRate): DatedLabourRate {\n if (!value || typeof value !== 'object') throw new Error('Rate is required.');\n identity(value.id, 'Rate id');\n identity(value.version, 'Rate version');\n decimal(value.rateMinor, 'Hourly rate');\n // Whitelist fields: never copy arbitrary host/private facts to client terms.\n return { id: value.id, version: value.version, rateMinor: value.rateMinor };\n}\n\nexport function amount(hours: Rational, hourly: DatedLabourRate): number {\n const value = decimal(hourly.rateMinor, 'Hourly rate');\n const numerator = hours.numerator * value.numerator;\n const denominator = hours.denominator * value.denominator;\n // Exact nonnegative half-up rounding, once per independent component.\n return rounded({ numerator, denominator });\n}\n\n/** Exact arithmetic only; this internal module does not select host policy. */\nexport function multiply(a: Rational, b: Rational): Rational {\n return {\n numerator: a.numerator * b.numerator,\n denominator: a.denominator * b.denominator,\n };\n}\nexport function add(a: Rational, b: Rational): Rational {\n const numerator = a.numerator * b.denominator + b.numerator * a.denominator;\n const denominator = a.denominator * b.denominator;\n let x = numerator;\n let y = denominator;\n while (y) {\n const remainder = x % y;\n x = y;\n y = remainder;\n }\n return { numerator: numerator / x, denominator: denominator / x };\n}\nexport function rounded(value: Rational): number {\n const result =\n (2n * value.numerator + value.denominator) / (2n * value.denominator);\n if (result > MAX)\n throw new Error('Labour amount exceeds safe integer minor units.');\n return Number(result);\n}\nexport function quantity(value: unknown): Rational {\n if (!value || typeof value !== 'object')\n throw new Error('Labour quantity is required.');\n const q = value as Record<string, unknown>;\n if (Object.keys(q).length !== 1)\n throw new Error('Ambiguous labour quantity.');\n if ('hours' in q) {\n const result = decimal(q.hours as string, 'Duration hours');\n if (result.numerator <= 0n)\n throw new Error('Duration hours must be positive.');\n return result;\n }\n if (!Number.isSafeInteger(q.seconds) || (q.seconds as number) <= 0)\n throw new Error('Duration seconds must be a positive safe integer.');\n return { numerator: BigInt(q.seconds as number), denominator: 3600n };\n}\n","import type { ServiceTimeEntry } from '../models/service-time-entry.js';\nimport {\n amount,\n date,\n decimal,\n identity,\n MAX,\n type Rational,\n rate,\n} from './labour-math.js';\nimport type {\n CommercialSnapshot,\n ServiceCommercialResolver,\n} from './service-evidence-service.js';\n\n/** Explicit hourly rate in currency minor units, with immutable host provenance. */\nexport interface DatedLabourRate {\n id: string;\n version: string;\n /** Nonnegative plain decimal text, at most 18 fractional digits. */\n rateMinor: string;\n}\n\n/** A half-open effective period. An omitted end means no upper bound. */\nexport interface DatedLabourRatePeriod {\n effectiveFrom: string;\n effectiveUntil?: string;\n currency: string;\n customer: DatedLabourRate;\n wage: DatedLabourRate;\n /** Additive hourly burden amount; never a percentage or statutory default. */\n burden: DatedLabourRate;\n}\n\n/**\n * Trusted host input: authorize this tenant, worker and schedule before use.\n * Dates are YYYY-MM-DD calendar dates, never inferred from process time.\n */\nexport interface DatedLabourCommercialInput {\n tenantId: string;\n participantProfileId: string;\n workDate: string;\n currency: string;\n billable: boolean;\n schedule: readonly DatedLabourRatePeriod[];\n}\n\n/**\n * Opt-in effective-dated labour calculator behind ServiceCommercialResolver.\n * Copies selected authorized terms at construction. Retain those same terms\n * when reconstructing a resolver for an incomplete approval retry. Wage and\n * burden are rounded separately. Provider amount is wage only; their sum is\n * private loadedCostMinor. Neither appears in client terms.\n */\nexport class DatedLabourCommercialResolver\n implements ServiceCommercialResolver\n{\n private readonly input: Omit<DatedLabourCommercialInput, 'schedule'>;\n private readonly selected: DatedLabourRatePeriod;\n\n constructor(input: DatedLabourCommercialInput) {\n identity(input.tenantId, 'Tenant id');\n identity(input.participantProfileId, 'Worker profile id');\n date(input.workDate);\n if (\n typeof input.currency !== 'string' ||\n !/^[A-Z]{3}$/.test(input.currency)\n )\n throw new Error(\n 'Currency must be an explicit three-letter uppercase code.',\n );\n if (typeof input.billable !== 'boolean')\n throw new Error('Billable must be explicit.');\n if (!Array.isArray(input.schedule) || !input.schedule.length)\n throw new Error('A rate schedule is required.');\n const schedule = input.schedule\n .map((period) => {\n date(period.effectiveFrom);\n if (period.effectiveUntil !== undefined) {\n date(period.effectiveUntil);\n if (period.effectiveUntil <= period.effectiveFrom)\n throw new Error('Effective period must have positive length.');\n }\n if (period.currency !== input.currency)\n throw new Error('Rate schedule currency mismatch.');\n return {\n effectiveFrom: period.effectiveFrom,\n effectiveUntil: period.effectiveUntil,\n currency: period.currency,\n customer: rate(period.customer),\n wage: rate(period.wage),\n burden: rate(period.burden),\n };\n })\n .sort((a, b) => a.effectiveFrom.localeCompare(b.effectiveFrom));\n for (let i = 1; i < schedule.length; i++) {\n const previousEnd = schedule[i - 1].effectiveUntil;\n if (previousEnd === undefined || previousEnd > schedule[i].effectiveFrom)\n throw new Error('Overlapping or ambiguous rate schedule.');\n }\n const selected = schedule.find(\n (period) =>\n period.effectiveFrom <= input.workDate &&\n (period.effectiveUntil === undefined ||\n input.workDate < period.effectiveUntil),\n );\n if (!selected) throw new Error('No applicable labour rate for work date.');\n this.selected = selected;\n this.input = {\n tenantId: input.tenantId,\n participantProfileId: input.participantProfileId,\n workDate: input.workDate,\n currency: input.currency,\n billable: input.billable,\n };\n }\n\n private resolve(entry: ServiceTimeEntry) {\n if (\n entry.tenantId !== this.input.tenantId ||\n entry.participantKind !== 'human' ||\n entry.participantProfileId !== this.input.participantProfileId\n )\n throw new Error('Labour entry tenant/worker identity mismatch.');\n const text = entry.durationHoursExact();\n let hours: Rational;\n let quantity: { hours: string } | { seconds: number };\n if (text !== null) {\n if (entry.durationSeconds !== null || entry.startedAt || entry.endedAt)\n throw new Error('Ambiguous hours and measured duration.');\n hours = decimal(text, 'Duration hours');\n quantity = { hours: text };\n } else {\n const seconds = entry.durationSeconds;\n if (!Number.isSafeInteger(seconds) || seconds === null || seconds <= 0)\n throw new Error('Duration seconds must be a positive safe integer.');\n hours = { numerator: BigInt(seconds), denominator: 3600n };\n quantity = { seconds };\n }\n if (hours.numerator <= 0n)\n throw new Error('Duration hours must be positive.');\n const customer = amount(hours, this.selected.customer);\n const wage = amount(hours, this.selected.wage);\n const burden = amount(hours, this.selected.burden);\n if (BigInt(wage) + BigInt(burden) > MAX)\n throw new Error('Loaded labour cost exceeds safe integer minor units.');\n const common = {\n workDate: this.input.workDate,\n effectiveFrom: this.selected.effectiveFrom,\n ...(this.selected.effectiveUntil === undefined\n ? {}\n : { effectiveUntil: this.selected.effectiveUntil }),\n currency: this.input.currency,\n billable: this.input.billable,\n quantity,\n rounding: 'half-up-per-component',\n };\n return {\n client: {\n amount: this.input.billable ? customer : 0,\n currency: this.input.currency,\n version: 'dated-labour-v1',\n strategy: 'dated-hourly-labour',\n terms: { ...common, customer: { ...this.selected.customer } },\n },\n provider: {\n amount: wage,\n currency: this.input.currency,\n version: 'dated-labour-v1',\n terms: {\n ...common,\n loadedCostMinor: wage + burden,\n wage: { ...this.selected.wage, amount: wage },\n burden: { ...this.selected.burden, amount: burden },\n },\n },\n };\n }\n\n /** Validate both results before ServiceEvidenceService freezes an entry. */\n validateEntry(entry: ServiceTimeEntry): void {\n this.resolve(entry);\n }\n\n /** Client-only terms: no wage, burden or compensation rate provenance. */\n async priceClient(entry: ServiceTimeEntry): Promise<CommercialSnapshot> {\n return this.resolve(entry).client;\n }\n\n /** Provider earnings are wages; private terms also retain burden and loaded cost. */\n async compensateProvider(\n entry: ServiceTimeEntry,\n ): Promise<CommercialSnapshot> {\n return this.resolve(entry).provider;\n }\n}\n","import type { ServiceTimeEntry } from '../models/service-time-entry.js';\nimport {\n type DatedLabourCommercialInput,\n DatedLabourCommercialResolver,\n type DatedLabourRatePeriod,\n} from './dated-labour-commercial-resolver.js';\nimport {\n decimal,\n identity,\n MAX,\n multiply,\n quantity,\n rounded,\n} from './labour-math.js';\nimport type {\n CommercialSnapshot,\n ServiceCommercialResolver,\n} from './service-evidence-service.js';\n\n/** Explicit percentage points, not hourly minor units or a decimal fraction. */\nexport interface LabourBurdenPercent {\n id: string;\n version: string;\n /** Nonnegative plain decimal text, at most 18 fractional digits. */\n percent: string;\n}\n\n/** Percentage burden applied to the selected wage, without hourly rounding. */\nexport interface DatedPercentageLabourRatePeriod\n extends Omit<DatedLabourRatePeriod, 'burden'> {\n burdenPercent: LabourBurdenPercent;\n}\n\n/** Host-authorized immutable terms; host owns policy selection and input precision. */\nexport interface DatedPercentageLabourCommercialInput\n extends Omit<DatedLabourCommercialInput, 'schedule'> {\n schedule: readonly DatedPercentageLabourRatePeriod[];\n}\n\n/**\n * Opt-in percentage calculation. Existing additive resolver semantics are unchanged.\n * Copy and retain this same input for incomplete approval retries. Provider amount\n * is wage only; all burden provenance stays in the private compensation snapshot.\n */\nexport class DatedPercentageLabourCommercialResolver\n implements ServiceCommercialResolver\n{\n private readonly delegate: DatedLabourCommercialResolver;\n private readonly selected: DatedPercentageLabourRatePeriod;\n\n constructor(input: DatedPercentageLabourCommercialInput) {\n if (!Array.isArray(input.schedule) || !input.schedule.length)\n throw new Error('A rate schedule is required.');\n const schedule = input.schedule.map((period) => {\n if ('burden' in period)\n throw new Error('Percentage and hourly burden are exclusive.');\n const percent = period.burdenPercent;\n if (!percent || typeof percent !== 'object')\n throw new Error('Burden percentage is required.');\n identity(percent.id, 'Percentage id');\n identity(percent.version, 'Percentage version');\n decimal(percent.percent, 'Burden percent');\n return {\n ...period,\n customer: { ...period.customer },\n wage: { ...period.wage },\n burdenPercent: {\n id: percent.id,\n version: percent.version,\n percent: percent.percent,\n },\n };\n });\n // Reuse all established date, currency, rate, schedule and identity validation.\n this.delegate = new DatedLabourCommercialResolver({\n ...input,\n schedule: schedule.map((period) => ({\n effectiveFrom: period.effectiveFrom,\n effectiveUntil: period.effectiveUntil,\n currency: period.currency,\n customer: period.customer,\n wage: period.wage,\n burden: {\n id: period.burdenPercent.id,\n version: period.burdenPercent.version,\n rateMinor: '0',\n },\n })),\n });\n this.selected = schedule.find(\n (period) =>\n period.effectiveFrom <= input.workDate &&\n (period.effectiveUntil === undefined ||\n input.workDate < period.effectiveUntil),\n )!;\n }\n\n private burden(entry: ServiceTimeEntry) {\n this.delegate.validateEntry(entry);\n const hours = entry.durationHoursExact();\n const q = quantity(\n hours === null ? { seconds: entry.durationSeconds } : { hours },\n );\n const percent = decimal(\n this.selected.burdenPercent.percent,\n 'Burden percent',\n );\n const hourly = multiply(\n decimal(this.selected.wage.rateMinor, 'Hourly wage'),\n { numerator: percent.numerator, denominator: percent.denominator * 100n },\n );\n const wage = rounded(\n multiply(q, decimal(this.selected.wage.rateMinor, 'Hourly wage')),\n );\n const burden = rounded(multiply(q, hourly));\n if (BigInt(wage) + BigInt(burden) > MAX)\n throw new Error('Loaded labour cost exceeds safe integer minor units.');\n return { wage, burden, hourly };\n }\n\n /** Validate all private amounts before any approval mutation. */\n validateEntry(entry: ServiceTimeEntry): void {\n this.burden(entry);\n }\n\n /** Customer terms remain the original additive resolver's public allowlist. */\n async priceClient(entry: ServiceTimeEntry): Promise<CommercialSnapshot> {\n this.validateEntry(entry);\n return this.delegate.priceClient(entry);\n }\n\n /** Exact derived hourly rational is provenance, never an intermediate rounded rate. */\n async compensateProvider(\n entry: ServiceTimeEntry,\n ): Promise<CommercialSnapshot> {\n const result = this.burden(entry);\n const original = await this.delegate.compensateProvider(entry);\n const { burden: _unused, ...terms } = original.terms;\n return {\n ...original,\n version: 'dated-percentage-labour-v1',\n terms: {\n ...terms,\n loadedCostMinor: result.wage + result.burden,\n burdenPercent: {\n ...this.selected.burdenPercent,\n amount: result.burden,\n },\n burdenBasis: {\n wageId: this.selected.wage.id,\n wageVersion: this.selected.wage.version,\n hourlyNumerator: result.hourly.numerator.toString(),\n hourlyDenominator: result.hourly.denominator.toString(),\n },\n },\n };\n }\n}\n","import type { DatedLabourRate } from './dated-labour-commercial-resolver.js';\nimport {\n add,\n date,\n decimal,\n identity,\n MAX,\n multiply,\n quantity,\n type Rational,\n rate,\n rounded,\n} from './labour-math.js';\nimport type { CommercialSnapshot } from './service-evidence-service.js';\n\n/** Immutable host provenance. Digest equality detects conflicting supplied revisions, not authenticity. */\nexport interface LabourPolicyProvenance {\n id: string;\n version: string;\n digest: string;\n}\n\n/** Private approved compensation evidence, already authorized and selected by the host. */\nexport interface ApprovedLabourValuationEvidence {\n tenantId: string;\n participantProfileId: string;\n entryId: string;\n snapshotId: string;\n groupId: string;\n groupVersion: string;\n policy: LabourPolicyProvenance;\n snapshot: CommercialSnapshot & {\n id: string;\n tenantId: string;\n timeEntryId: string;\n };\n}\n\n/** Explicit analytical scope; membership is supplied evidence, never a database or authorization query. */\nexport interface LabourValuationReconciliationInput {\n tenantId: string;\n currency: string;\n groupId: string;\n groupVersion: string;\n mode: 'half-up-exact-loaded-aggregate';\n evidence: readonly ApprovedLabourValuationEvidence[];\n}\n\n/** Private analytical result. No returned amount is a posting instruction. */\nexport interface LabourValuationReconciliation {\n tenantId: string;\n currency: string;\n groupId: string;\n groupVersion: string;\n mode: 'half-up-exact-loaded-aggregate';\n version: 'labour-valuation-reconciliation-v1';\n canonicalCostMinor: number;\n analyticalCostMinor: number;\n /** Analytical minus canonical; may be negative although evidence cannot be. */\n differenceMinor: number;\n evidence: Array<{\n entryId: string;\n snapshotId: string;\n participantProfileId: string;\n policy: LabourPolicyProvenance;\n calculationVersion: string;\n }>;\n}\n\nfunction object(value: unknown): Record<string, unknown> {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n throw new Error('Missing labour snapshot terms.');\n return value as Record<string, unknown>;\n}\nfunction minor(value: unknown): number {\n if (!Number.isSafeInteger(value) || (value as number) < 0)\n throw new Error('Expected nonnegative safe integer labour amount.');\n return value as number;\n}\nfunction exactEvidence(\n snapshot: CommercialSnapshot,\n currency: string,\n): { exact: Rational; canonical: number } {\n if (!snapshot || snapshot.currency !== currency)\n throw new Error('Labour evidence currency mismatch.');\n if (\n !['dated-labour-v1', 'dated-percentage-labour-v1'].includes(\n snapshot.version,\n )\n )\n throw new Error('Unsupported labour calculation version.');\n const terms = object(snapshot.terms);\n if (\n terms.currency !== currency ||\n terms.rounding !== 'half-up-per-component' ||\n typeof terms.billable !== 'boolean'\n )\n throw new Error('Unsupported or inconsistent labour terms.');\n date(terms.workDate as string);\n date(terms.effectiveFrom as string);\n if ((terms.workDate as string) < (terms.effectiveFrom as string))\n throw new Error('Labour date outside selected period.');\n if (terms.effectiveUntil !== undefined) {\n date(terms.effectiveUntil as string);\n if ((terms.workDate as string) >= (terms.effectiveUntil as string))\n throw new Error('Labour date outside selected period.');\n }\n const q = quantity(terms.quantity);\n const wageTerms = object(terms.wage);\n const wageRate = rate(wageTerms as unknown as DatedLabourRate);\n const wageHourly = decimal(wageRate.rateMinor, 'Hourly wage');\n const wageExact = multiply(q, wageHourly);\n const wage = rounded(wageExact);\n let burdenHourly: Rational;\n let suppliedBurden: unknown;\n if (snapshot.version === 'dated-labour-v1') {\n if ('burdenPercent' in terms || 'burdenBasis' in terms)\n throw new Error('Ambiguous labour burden.');\n const burdenTerms = object(terms.burden);\n burdenHourly = decimal(\n rate(burdenTerms as unknown as DatedLabourRate).rateMinor,\n 'Hourly burden',\n );\n suppliedBurden = burdenTerms.amount;\n } else {\n if ('burden' in terms) throw new Error('Ambiguous labour burden.');\n const percentTerms = object(terms.burdenPercent);\n identity(percentTerms.id as string, 'Percentage id');\n identity(percentTerms.version as string, 'Percentage version');\n const percent = decimal(percentTerms.percent as string, 'Burden percent');\n burdenHourly = multiply(wageHourly, {\n numerator: percent.numerator,\n denominator: percent.denominator * 100n,\n });\n const basis = object(terms.burdenBasis);\n if (\n basis.wageId !== wageRate.id ||\n basis.wageVersion !== wageRate.version ||\n basis.hourlyNumerator !== burdenHourly.numerator.toString() ||\n basis.hourlyDenominator !== burdenHourly.denominator.toString()\n )\n throw new Error('Percentage burden basis differs from retained terms.');\n suppliedBurden = percentTerms.amount;\n }\n const burdenExact = multiply(q, burdenHourly);\n const burden = rounded(burdenExact);\n const canonical = BigInt(wage) + BigInt(burden);\n if (canonical > MAX)\n throw new Error('Loaded labour cost exceeds safe integer minor units.');\n if (\n minor(snapshot.amount) !== wage ||\n minor(wageTerms.amount) !== wage ||\n minor(suppliedBurden) !== burden ||\n minor(terms.loadedCostMinor) !== Number(canonical)\n )\n throw new Error(\n 'Canonical labour snapshot does not reconcile with retained terms.',\n );\n return { exact: add(wageExact, burdenExact), canonical: Number(canonical) };\n}\n\n/**\n * Reconcile immutable private evidence; never reprice or mutate posted facts.\n * The host must authorize every entry and exclude superseded/corrected evidence.\n * IDs/digests validate consistency of supplied data, not authenticity or access.\n * Reversals and mixed-sign evidence are unsupported; apply their own versioned contract.\n */\nexport function reconcileLabourValuation(\n input: LabourValuationReconciliationInput,\n): LabourValuationReconciliation {\n identity(input.tenantId, 'Tenant id');\n identity(input.groupId, 'Group id');\n identity(input.groupVersion, 'Group version');\n if (typeof input.currency !== 'string' || !/^[A-Z]{3}$/.test(input.currency))\n throw new Error('Explicit currency is required.');\n if (input.mode !== 'half-up-exact-loaded-aggregate')\n throw new Error('Unsupported analytical labour mode.');\n if (\n !Array.isArray(input.evidence) ||\n input.evidence.length === 0 ||\n input.evidence.length > 10000\n )\n throw new Error('Supply between 1 and 10000 labour evidence records.');\n const entries = new Set<string>();\n const snapshots = new Set<string>();\n const policies = new Map<string, string>();\n const rates = new Map<string, string>();\n let exact: Rational = { numerator: 0n, denominator: 1n };\n let canonical = 0n;\n const evidence: LabourValuationReconciliation['evidence'] = [];\n for (const item of input.evidence) {\n if (\n !item ||\n item.tenantId !== input.tenantId ||\n item.groupId !== input.groupId ||\n item.groupVersion !== input.groupVersion\n )\n throw new Error('Labour evidence tenant/group mismatch.');\n identity(item.entryId, 'Entry id');\n identity(item.snapshotId, 'Snapshot id');\n identity(item.participantProfileId, 'Worker id');\n if (\n !item.snapshot ||\n item.snapshot.id !== item.snapshotId ||\n item.snapshot.timeEntryId !== item.entryId ||\n item.snapshot.tenantId !== input.tenantId\n )\n throw new Error('Labour snapshot identity mismatch.');\n if (entries.has(item.entryId) || snapshots.has(item.snapshotId))\n throw new Error('Duplicate labour evidence.');\n entries.add(item.entryId);\n snapshots.add(item.snapshotId);\n const policy = object(item.policy);\n identity(policy.id as string, 'Policy id');\n identity(policy.version as string, 'Policy version');\n identity(policy.digest as string, 'Policy digest');\n const policyKey = JSON.stringify([policy.id, policy.version]);\n if (policies.has(policyKey) && policies.get(policyKey) !== policy.digest)\n throw new Error('Conflicting labour policy revision.');\n policies.set(policyKey, policy.digest as string);\n const value = exactEvidence(item.snapshot, input.currency);\n for (const kind of ['wage', 'burden', 'burdenPercent']) {\n const terms = item.snapshot.terms[kind];\n if (terms === undefined) continue;\n const selected = object(terms);\n const key = JSON.stringify([\n item.participantProfileId,\n kind,\n selected.id,\n selected.version,\n ]);\n const rateValue = String(\n kind === 'burdenPercent' ? selected.percent : selected.rateMinor,\n );\n if (rates.has(key) && rates.get(key) !== rateValue)\n throw new Error('Conflicting retained labour rate revision.');\n rates.set(key, rateValue);\n }\n canonical += BigInt(value.canonical);\n if (canonical > MAX)\n throw new Error(\n 'Canonical labour aggregate exceeds safe integer minor units.',\n );\n exact = add(exact, value.exact);\n evidence.push({\n entryId: item.entryId,\n snapshotId: item.snapshotId,\n participantProfileId: item.participantProfileId,\n policy: {\n id: policy.id as string,\n version: policy.version as string,\n digest: policy.digest as string,\n },\n calculationVersion: item.snapshot.version,\n });\n }\n // Stable ordinal ordering, independent of process locale and input permutation.\n evidence.sort((a, b) =>\n a.entryId < b.entryId ? -1 : a.entryId > b.entryId ? 1 : 0,\n );\n const analytical = rounded(exact);\n return {\n tenantId: input.tenantId,\n currency: input.currency,\n groupId: input.groupId,\n groupVersion: input.groupVersion,\n mode: input.mode,\n version: 'labour-valuation-reconciliation-v1',\n canonicalCostMinor: Number(canonical),\n analyticalCostMinor: analytical,\n differenceMinor: analytical - Number(canonical),\n evidence,\n };\n}\n","import type { SmrtClassOptions } from '@happyvertical/smrt-core';\nimport {\n ServiceChargeSnapshotCollection,\n ServiceCompensationSnapshotCollection,\n} from '../models/service-snapshots.js';\nimport type { ServiceTimeEntry } from '../models/service-time-entry.js';\nimport {\n SERVICE_DURATION_HOURS_EVIDENCE,\n ServiceTimeEntryCollection,\n validateDurationHours,\n} from '../models/service-time-entry.js';\nimport type {\n ServiceEvidence,\n ServiceParticipantKind,\n ServiceTimeEntrySource,\n} from '../types.js';\n\n/**\n * Input for {@link ServiceEvidenceService.record}. The work reference is the\n * qualified class name and id of whatever the time was spent on.\n */\nexport interface RecordServiceTimeInput {\n tenantId?: string | null;\n workRefType?: string | null;\n workRefId?: string | null;\n participantKind: ServiceParticipantKind;\n participantProfileId?: string | null;\n agentRef?: string;\n source: ServiceTimeEntrySource;\n description: string;\n startedAt?: Date | null;\n endedAt?: Date | null;\n durationSeconds?: number | null;\n /** Exact positive decimal text; exclusive with seconds and timestamps. */\n durationHours?: string;\n evidence?: ServiceEvidence[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface CommercialSnapshot {\n /**\n * Integer minor units of `currency` — `$19.99` is `1999` (#2401).\n *\n * Written straight into `ServiceChargeSnapshot.amount` /\n * `ServiceCompensationSnapshot.amount`, INTEGER columns whose `save()`\n * refuses anything but a safe integer on every engine. A fractional\n * major-unit value (`19.99`) is rejected; a whole one (`150` for $150.00)\n * is not detectable and is stored 100× too small, so return minor units.\n */\n amount: number;\n currency?: string;\n version: string;\n strategy?: string;\n terms: Record<string, unknown>;\n sourceRef?: string;\n}\n\nexport interface ServiceCommercialResolver {\n /** Pure preflight: reject unsupported evidence before approval or snapshot writes. */\n validateEntry?(entry: ServiceTimeEntry): void | Promise<void>;\n priceClient(entry: ServiceTimeEntry): Promise<CommercialSnapshot>;\n compensateProvider(entry: ServiceTimeEntry): Promise<CommercialSnapshot>;\n}\n\n/**\n * Records, submits, approves, and corrects time entries. Approval writes one\n * immutable client-charge and one provider-compensation snapshot per entry;\n * a correction is a new entry pointing at the approved one, which flips to\n * `corrected` with its snapshots intact.\n */\nexport class ServiceEvidenceService {\n constructor(\n private readonly entries: ServiceTimeEntryCollection,\n private readonly charges: ServiceChargeSnapshotCollection,\n private readonly compensation: ServiceCompensationSnapshotCollection,\n private readonly commercial?: ServiceCommercialResolver,\n ) {}\n\n static async create(\n options: SmrtClassOptions = {},\n commercial?: ServiceCommercialResolver,\n ): Promise<ServiceEvidenceService> {\n const [entries, charges, compensation] = await Promise.all([\n ServiceTimeEntryCollection.create(options),\n ServiceChargeSnapshotCollection.create(options),\n ServiceCompensationSnapshotCollection.create(options),\n ]);\n return new ServiceEvidenceService(\n entries,\n charges,\n compensation,\n commercial,\n );\n }\n\n async record(input: RecordServiceTimeInput): Promise<ServiceTimeEntry> {\n if (!['timer', 'manual', 'import', 'agent'].includes(input.source))\n throw new Error('Unsupported service time source.');\n if (Boolean(input.workRefType) !== Boolean(input.workRefId))\n throw new Error('workRefType and workRefId must be provided together.');\n if (!(input.workRefType && input.workRefId))\n throw new Error('Service time requires a work reference.');\n if (input.participantKind === 'human' && !input.participantProfileId)\n throw new Error('Human service time requires participantProfileId.');\n if (input.participantKind === 'agent' && !input.agentRef)\n throw new Error('Agent service time requires agentRef.');\n if (input.source === 'timer' && (!input.startedAt || !input.endedAt))\n throw new Error('Timer service time requires startedAt and endedAt.');\n if (input.startedAt && input.endedAt && input.startedAt >= input.endedAt)\n throw new Error('Service time startedAt must be before endedAt.');\n const { durationHours, ...fields } = input;\n if (\n input.evidence?.some(\n (item) => item?.kind === SERVICE_DURATION_HOURS_EVIDENCE,\n )\n )\n throw new Error(\n 'Use durationHours to supply reserved decimal-hours evidence.',\n );\n const hours =\n durationHours === undefined ? null : validateDurationHours(durationHours);\n if (\n hours !== null &&\n (input.durationSeconds != null || input.startedAt || input.endedAt)\n )\n throw new Error(\n 'Decimal-hours-only service time cannot also supply seconds or timestamps.',\n );\n if (hours === null && input.durationSeconds === null)\n throw new Error('Null durationSeconds requires durationHours.');\n const duration =\n hours !== null\n ? null\n : (input.durationSeconds ??\n (input.startedAt && input.endedAt\n ? Math.round(\n (input.endedAt.getTime() - input.startedAt.getTime()) / 1000,\n )\n : 0));\n if (duration !== null && (!Number.isSafeInteger(duration) || duration <= 0))\n throw new Error(\n 'Service time durationSeconds must be a positive integer.',\n );\n const entry = await this.entries.create({\n ...fields,\n durationSeconds: duration,\n evidence: JSON.stringify([\n ...(input.evidence ?? []),\n ...(hours === null\n ? []\n : [{ kind: SERVICE_DURATION_HOURS_EVIDENCE, hours }]),\n ]),\n metadata: JSON.stringify(input.metadata ?? {}),\n status: 'draft',\n submittedAt: null,\n submittedByProfileId: null,\n approvedAt: null,\n approvedByProfileId: null,\n approvalPath: '',\n rejectedAt: null,\n rejectedByProfileId: null,\n rejectionReason: '',\n correctionOfId: null,\n });\n await entry.save();\n return entry;\n }\n\n async submit(\n entry: ServiceTimeEntry,\n profileId?: string,\n ): Promise<ServiceTimeEntry> {\n if (entry.status !== 'draft' && entry.status !== 'rejected')\n throw new Error('Only draft or rejected service time may be submitted.');\n entry.status = 'submitted';\n entry.submittedAt = new Date();\n entry.submittedByProfileId = profileId ?? null;\n return entry.save();\n }\n\n async approve(\n entry: ServiceTimeEntry,\n options: { actorProfileId?: string; approvalPath: string },\n ): Promise<ServiceTimeEntry> {\n if (entry.status !== 'submitted' && entry.status !== 'approved')\n throw new Error(\n 'Only submitted service time or an incomplete approval may be approved.',\n );\n if (!this.commercial)\n throw new Error(\n 'A ServiceCommercialResolver is required to approve service time.',\n );\n const timeEntryId = entry.id;\n if (!timeEntryId)\n throw new Error('ServiceTimeEntry must be saved before approval.');\n const existingCharge = (\n await this.charges.list({ where: { timeEntryId }, limit: 1 })\n )[0];\n const existingCompensation = (\n await this.compensation.list({ where: { timeEntryId }, limit: 1 })\n )[0];\n if (entry.status === 'approved' && existingCharge && existingCompensation)\n return entry;\n\n await this.commercial.validateEntry?.(entry);\n\n // Commit approval before either commercial resolver runs. The subscription\n // resolver creates an approved ClientCharge as part of priceClient(), so a\n // failed approval must never leave billable spend behind.\n if (entry.status === 'submitted') {\n entry.status = 'approved';\n entry.approvedAt = new Date();\n entry.approvedByProfileId = options.actorProfileId ?? null;\n entry.approvalPath = options.approvalPath;\n try {\n await entry.save();\n } catch (error) {\n const revisionConflict =\n error instanceof Error &&\n 'code' in error &&\n error.code === 'RUNTIME_REVISION_CONFLICT';\n if (!revisionConflict) throw error;\n const concurrent = await this.entries.get(timeEntryId);\n if (concurrent?.status !== 'approved') throw error;\n entry = concurrent;\n await this.commercial.validateEntry?.(entry);\n }\n }\n const provider = existingCompensation\n ? null\n : await this.commercial.compensateProvider(entry);\n if (provider) {\n const snapshotId = await deterministicSnapshotId(\n 'service-compensation-snapshot',\n timeEntryId,\n );\n try {\n await this.compensation.create({\n id: snapshotId,\n tenantId: entry.tenantId,\n timeEntryId,\n amount: provider.amount,\n currency: provider.currency ?? 'USD',\n termsVersion: provider.version,\n rateSnapshot: JSON.stringify(provider.terms),\n _insertOnly: true,\n });\n } catch (error) {\n const concurrent =\n (await this.compensation.get(snapshotId)) ??\n (\n await this.compensation.list({\n where: { timeEntryId },\n limit: 1,\n })\n )[0];\n if (!concurrent) throw error;\n }\n }\n const client = existingCharge\n ? null\n : await this.commercial.priceClient(entry);\n if (client) {\n const snapshotId = await deterministicSnapshotId(\n 'service-charge-snapshot',\n timeEntryId,\n );\n try {\n await this.charges.create({\n id: snapshotId,\n tenantId: entry.tenantId,\n timeEntryId,\n amount: client.amount,\n currency: client.currency ?? 'USD',\n pricingVersion: client.version,\n strategy: client.strategy ?? '',\n rateSnapshot: JSON.stringify(client.terms),\n sourceChargeRef: client.sourceRef ?? '',\n _insertOnly: true,\n });\n } catch (error) {\n const concurrent =\n (await this.charges.get(snapshotId)) ??\n (\n await this.charges.list({\n where: { timeEntryId },\n limit: 1,\n })\n )[0];\n if (!concurrent) throw error;\n }\n }\n return entry;\n }\n\n async correct(\n entry: ServiceTimeEntry,\n input: RecordServiceTimeInput,\n ): Promise<ServiceTimeEntry> {\n if (entry.status !== 'approved')\n throw new Error('Only approved service time may be corrected.');\n if (input.tenantId !== undefined && input.tenantId !== entry.tenantId) {\n throw new Error(\n 'Service time corrections must remain in the original tenant.',\n );\n }\n const correction = await this.record({\n ...input,\n tenantId: entry.tenantId,\n });\n correction.correctionOfId = entry.id ?? null;\n await correction.save();\n entry.status = 'corrected';\n await entry.save();\n return correction;\n }\n}\n\nasync function deterministicSnapshotId(\n kind: string,\n timeEntryId: string,\n): Promise<string> {\n const bytes = new TextEncoder().encode(JSON.stringify([kind, timeEntryId]));\n const digest = new Uint8Array(await crypto.subtle.digest('SHA-256', bytes));\n const uuid = digest.slice(0, 16);\n uuid[6] = (uuid[6] & 0x0f) | 0x50;\n uuid[8] = (uuid[8] & 0x3f) | 0x80;\n const hex = Array.from(uuid, (byte) =>\n byte.toString(16).padStart(2, '0'),\n ).join('');\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20),\n ].join('-');\n}\n"],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  "version": "1.0.0",
3
3
  "timestamp": 0,
4
4
  "packageName": "@happyvertical/smrt-timesheets",
5
- "packageVersion": "0.55.21",
5
+ "packageVersion": "0.55.23",
6
6
  "objects": {
7
7
  "@happyvertical/smrt-timesheets:AttendancePunch": {
8
8
  "name": "attendancepunch",
package/dist/rollup.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as PeriodTimecard, c as TimecardAdjustmentCollection, o as PeriodTimecardCollection, s as TimecardAdjustment, t as PeriodRollupService } from "./chunks/rollup-2--s0AyP.js";
1
+ import { a as PeriodTimecard, c as TimecardAdjustmentCollection, o as PeriodTimecardCollection, s as TimecardAdjustment, t as PeriodRollupService } from "./chunks/rollup-U1IO_CMA.js";
2
2
  export { PeriodRollupService, PeriodTimecard, PeriodTimecardCollection, TimecardAdjustment, TimecardAdjustmentCollection };
@@ -1 +1 @@
1
- {"version":3,"file":"dated-labour-commercial-resolver.d.ts","sourceRoot":"","sources":["../../src/services/dated-labour-commercial-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACxE,OAAO,KAAK,EACV,kBAAkB,EAClB,yBAAyB,EAC1B,MAAM,+BAA+B,CAAC;AAEvC,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,yEAAyE;AACzE,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,8EAA8E;IAC9E,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC5C;AA4DD;;;;;;GAMG;AACH,qBAAa,6BACX,YAAW,yBAAyB;IAEpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+C;IACrE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;gBAErC,KAAK,EAAE,0BAA0B;IAyD7C,OAAO,CAAC,OAAO;IA8Df,4EAA4E;IAC5E,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAI5C,0EAA0E;IACpE,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIvE,qFAAqF;IAC/E,kBAAkB,CACtB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,kBAAkB,CAAC;CAG/B"}
1
+ {"version":3,"file":"dated-labour-commercial-resolver.d.ts","sourceRoot":"","sources":["../../src/services/dated-labour-commercial-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAUxE,OAAO,KAAK,EACV,kBAAkB,EAClB,yBAAyB,EAC1B,MAAM,+BAA+B,CAAC;AAEvC,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,yEAAyE;AACzE,MAAM,WAAW,qBAAqB;IACpC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,eAAe,CAAC;IAC1B,IAAI,EAAE,eAAe,CAAC;IACtB,8EAA8E;IAC9E,MAAM,EAAE,eAAe,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,0BAA0B;IACzC,QAAQ,EAAE,MAAM,CAAC;IACjB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,SAAS,qBAAqB,EAAE,CAAC;CAC5C;AAED;;;;;;GAMG;AACH,qBAAa,6BACX,YAAW,yBAAyB;IAEpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA+C;IACrE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAwB;gBAErC,KAAK,EAAE,0BAA0B;IAyD7C,OAAO,CAAC,OAAO;IA8Df,4EAA4E;IAC5E,aAAa,CAAC,KAAK,EAAE,gBAAgB,GAAG,IAAI;IAI5C,0EAA0E;IACpE,WAAW,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAIvE,qFAAqF;IAC/E,kBAAkB,CACtB,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,kBAAkB,CAAC;CAG/B"}