@managemint-solutions/sdk 0.37.0 → 0.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -427,6 +427,7 @@ const types = await supabase.leaveTypes.list({ active: true });
427
427
  const annual = await supabase.leaveTypes.create({ name: 'Annual', description: null, default_days: 15, is_paid: true, requires_approval: true });
428
428
  await supabase.leaveTypes.remove(annual.mms_id); // hard delete; 409 once a request or entitlement references it
429
429
 
430
+ const taken = await supabase.leaveEntitlements.overlaps(userId, annual.mms_id, '2026-01-01', '2026-12-31'); // an entitlement of that type already covers part of the period
430
431
  const cover = await supabase.leaveEntitlements.findFor(userId, annual.mms_id, '2026-09-21'); // period + cap, or null = untracked
431
432
  const committed = await supabase.leaveRequests.sumDays(userId, annual.mms_id, cover, [LeaveRequestStatus.APPROVED, LeaveRequestStatus.PENDING]);
432
433
  const clash = await supabase.leaveRequests.overlaps(userId, '2026-09-21', '2026-09-25');
@@ -435,6 +436,7 @@ const request = await supabase.leaveRequests.create({ user_id: userId, leave_typ
435
436
  const reviewed = await supabase.leaveRequests.review(request.mms_id, { status: LeaveReviewDecision.APPROVED, reviewed_by: managerId, review_note: null }); // null = no longer pending
436
437
  const cancelled = await supabase.leaveRequests.cancel(request.mms_id, userId); // null = already closed
437
438
  const mine = await supabase.leaveRequests.list({ ...query, user_id: me }); // one list; user_id narrows it
439
+ const annualOnly = await supabase.leaveRequests.list({ ...query, leave_type_id: annual.mms_id }); // leave_type_id narrows it too
438
440
  const reports = await supabase.leaveRequests.list(query, { userIds: [me, ...(await supabase.users.idsManagedBy(me))] });
439
441
  ```
440
442
 
@@ -443,6 +445,9 @@ the request is still in the status they expect and resolve to `null` otherwise,
443
445
  cannot both decide the same request. The `leave_requests` table also carries an exclusion
444
446
  constraint so two overlapping live requests of one user cannot both be inserted in a race.
445
447
 
448
+ Notes, additional details and supporting files may attach to leave as well: their `entity`
449
+ accepts `leave_requests` and `leave_entitlements` alongside the CRM entity types.
450
+
446
451
  ## Public holidays
447
452
 
448
453
  The public-holiday calendar, `public_holidays`, on the caller's client as `supabase.publicHolidays`.
@@ -51,6 +51,7 @@ export declare class GetLeaveRequestsDto implements GetLeaveRequestsDtoType {
51
51
  readonly page: number;
52
52
  readonly page_size: number;
53
53
  readonly user_id?: string | null;
54
+ readonly leave_type_id?: string | null;
54
55
  readonly status?: LeaveRequestStatus | null;
55
56
  readonly start_date_after?: string | null;
56
57
  readonly start_date_before?: string | null;
package/dist/leave/dto.js CHANGED
@@ -249,6 +249,7 @@ class GetLeaveRequestsDto {
249
249
  page = 1;
250
250
  page_size = 10;
251
251
  user_id;
252
+ leave_type_id;
252
253
  status;
253
254
  start_date_after;
254
255
  start_date_before;
@@ -275,6 +276,12 @@ __decorate([
275
276
  (0, class_validator_1.IsUUID)('4', { message: 'Invalid user ID format' }),
276
277
  __metadata("design:type", Object)
277
278
  ], GetLeaveRequestsDto.prototype, "user_id", void 0);
279
+ __decorate([
280
+ (0, class_validator_1.IsOptional)(),
281
+ (0, validators_1.IsNullable)(),
282
+ (0, class_validator_1.IsUUID)('7', { message: 'Invalid leave type ID format' }),
283
+ __metadata("design:type", Object)
284
+ ], GetLeaveRequestsDto.prototype, "leave_type_id", void 0);
278
285
  __decorate([
279
286
  (0, class_validator_1.IsOptional)(),
280
287
  (0, validators_1.IsNullable)(),
@@ -29,6 +29,12 @@ export declare class LeaveEntitlementsResource {
29
29
  * table's exclusion constraint), so there is at most one.
30
30
  */
31
31
  findFor(userId: string, leaveTypeId: string, date: string): Promise<LeaveEntitlementCover | null>;
32
+ /**
33
+ * Whether `userId` already has an entitlement of `leaveTypeId` touching any day of
34
+ * `start`..`end`. The readable half of the rule; the table's exclusion constraint is the half
35
+ * that survives a race. `excludeId` leaves out the entitlement being edited.
36
+ */
37
+ overlaps(userId: string, leaveTypeId: string, start: string, end: string, excludeId?: string): Promise<boolean>;
32
38
  create(input: CreateLeaveEntitlementInput): Promise<LeaveEntitlementEntity>;
33
39
  update(leaveEntitlementId: string, input: UpdateLeaveEntitlementDto): Promise<LeaveEntitlementEntity>;
34
40
  /** Hard delete: the type simply becomes untracked for that user and period. */
@@ -94,6 +94,28 @@ class LeaveEntitlementsResource {
94
94
  const cover = data;
95
95
  return { ...cover, days_entitled: Number(cover.days_entitled) };
96
96
  }
97
+ /**
98
+ * Whether `userId` already has an entitlement of `leaveTypeId` touching any day of
99
+ * `start`..`end`. The readable half of the rule; the table's exclusion constraint is the half
100
+ * that survives a race. `excludeId` leaves out the entitlement being edited.
101
+ */
102
+ async overlaps(userId, leaveTypeId, start, end, excludeId) {
103
+ let overlapQuery = this.supabase
104
+ .from('leave_entitlements')
105
+ .select('mms_id', { count: 'exact', head: true })
106
+ .eq('organization_id', this.auth.organization_id)
107
+ .eq('user_id', userId)
108
+ .eq('leave_type_id', leaveTypeId)
109
+ .lte('period_start', end)
110
+ .gte('period_end', start);
111
+ if (excludeId) {
112
+ overlapQuery = overlapQuery.neq('mms_id', excludeId);
113
+ }
114
+ const { count, error } = await overlapQuery;
115
+ if (error)
116
+ throw (0, errors_1.mapPostgrestError)(error);
117
+ return (count ?? 0) > 0;
118
+ }
97
119
  async create(input) {
98
120
  const row = await this.table.insert({
99
121
  user_id: input.user_id,
@@ -60,6 +60,9 @@ class LeaveRequestsResource {
60
60
  if (query.user_id) {
61
61
  requestsQuery = requestsQuery.eq('user_id', query.user_id);
62
62
  }
63
+ if (query.leave_type_id) {
64
+ requestsQuery = requestsQuery.eq('leave_type_id', query.leave_type_id);
65
+ }
63
66
  if (query.status) {
64
67
  requestsQuery = requestsQuery.eq('status', query.status);
65
68
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@managemint-solutions/sdk",
3
- "version": "0.37.0",
3
+ "version": "0.38.0",
4
4
  "description": "Typed Supabase data-access SDK for ManageMint Solutions",
5
5
  "license": "UNLICENSED",
6
6
  "author": "Scott Bebington <scottbebington@gmail.com>",
@@ -51,7 +51,7 @@
51
51
  "testEnvironment": "node"
52
52
  },
53
53
  "dependencies": {
54
- "@managemint-solutions/entities": "^1.21.0"
54
+ "@managemint-solutions/entities": "^1.22.0"
55
55
  },
56
56
  "peerDependencies": {
57
57
  "@nestjs/common": "^11.0.0",