@managemint-solutions/entities 1.19.0 → 1.21.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.
@@ -18,6 +18,9 @@ export declare enum AuditTrailEntityType {
18
18
  PROJECTS = "projects",
19
19
  TASKS = "tasks",
20
20
  TIMESHEETS = "timesheets",
21
+ LEAVE_TYPES = "leave_types",
22
+ LEAVE_ENTITLEMENTS = "leave_entitlements",
23
+ LEAVE_REQUESTS = "leave_requests",
21
24
  BILLING_TRANSACTIONS = "billing_transactions",
22
25
  INVOICE = "invoices",
23
26
  NOTIFICATION = "notifications"
@@ -23,6 +23,9 @@ var AuditTrailEntityType;
23
23
  AuditTrailEntityType["PROJECTS"] = "projects";
24
24
  AuditTrailEntityType["TASKS"] = "tasks";
25
25
  AuditTrailEntityType["TIMESHEETS"] = "timesheets";
26
+ AuditTrailEntityType["LEAVE_TYPES"] = "leave_types";
27
+ AuditTrailEntityType["LEAVE_ENTITLEMENTS"] = "leave_entitlements";
28
+ AuditTrailEntityType["LEAVE_REQUESTS"] = "leave_requests";
26
29
  AuditTrailEntityType["BILLING_TRANSACTIONS"] = "billing_transactions";
27
30
  AuditTrailEntityType["INVOICE"] = "invoices";
28
31
  AuditTrailEntityType["NOTIFICATION"] = "notifications";
@@ -0,0 +1,89 @@
1
+ import { LeaveRequestStatus, LeaveReviewDecision } from '../enum';
2
+ /**
3
+ * The wire shapes of the leave routes. The api runs a global ValidationPipe with
4
+ * `forbidNonWhitelisted`, so every field a route accepts is declared here and mirrored by
5
+ * the sdk's class-validator DTO. Dates travel as `YYYY-MM-DD` strings.
6
+ *
7
+ * Body fields are required keys: a field that may be empty is sent as `null`, never left
8
+ * out, so a payload always says what it means. Only query-string filters are optional.
9
+ */
10
+ export type LeaveTypeIdDto = {
11
+ leaveTypeId: string;
12
+ };
13
+ export type GetLeaveTypesDto = {
14
+ /** Omitted = every type; true/false filters on the flag. */
15
+ active?: boolean | null;
16
+ };
17
+ export type CreateLeaveTypeDto = {
18
+ name: string;
19
+ description: string | null;
20
+ default_days: number;
21
+ is_paid: boolean;
22
+ requires_approval: boolean;
23
+ };
24
+ export type UpdateLeaveTypeDto = {
25
+ name: string;
26
+ description: string | null;
27
+ default_days: number;
28
+ is_paid: boolean;
29
+ requires_approval: boolean;
30
+ active: boolean;
31
+ };
32
+ export type LeaveEntitlementIdDto = {
33
+ leaveEntitlementId: string;
34
+ };
35
+ export type GetLeaveEntitlementsDto = {
36
+ page: number;
37
+ page_size: number;
38
+ user_id?: string | null;
39
+ leave_type_id?: string | null;
40
+ /** Keep only entitlements whose period contains this date. */
41
+ as_of?: string | null;
42
+ };
43
+ export type CreateLeaveEntitlementDto = {
44
+ user_id: string;
45
+ leave_type_id: string;
46
+ days_entitled: number;
47
+ /** Null = the organization's current leave year. */
48
+ period_start: string | null;
49
+ /** Null = one year after `period_start`, less a day. */
50
+ period_end: string | null;
51
+ notes: string | null;
52
+ };
53
+ export type UpdateLeaveEntitlementDto = {
54
+ days_entitled: number;
55
+ period_end: string;
56
+ notes: string | null;
57
+ };
58
+ export type LeaveRequestIdDto = {
59
+ leaveRequestId: string;
60
+ };
61
+ /** One list for everyone: `user_id` narrows it (to yourself, say); the api scopes what is visible. */
62
+ export type GetLeaveRequestsDto = {
63
+ page: number;
64
+ page_size: number;
65
+ user_id?: string | null;
66
+ status?: LeaveRequestStatus | null;
67
+ start_date_after?: string | null;
68
+ start_date_before?: string | null;
69
+ };
70
+ /** Always the caller's own request: there is no `user_id` to file on someone's behalf. */
71
+ export type CreateLeaveRequestDto = {
72
+ leave_type_id: string;
73
+ start_date: string;
74
+ end_date: string;
75
+ is_half_day: boolean;
76
+ reason: string | null;
77
+ };
78
+ /** Only a pending request can be edited; the days are recounted from what is sent. */
79
+ export type UpdateLeaveRequestDto = {
80
+ leave_type_id: string;
81
+ start_date: string;
82
+ end_date: string;
83
+ is_half_day: boolean;
84
+ reason: string | null;
85
+ };
86
+ export type ReviewLeaveRequestDto = {
87
+ status: LeaveReviewDecision;
88
+ review_note: string | null;
89
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ /**
2
+ * The lifecycle of a leave request. Stored as text on `leave_requests.status` and validated
3
+ * here, never by a Postgres enum. `pending` moves to any of the other three; `approved` may
4
+ * still be cancelled (a future booking the employee no longer needs); `rejected` and
5
+ * `cancelled` are terminal.
6
+ */
7
+ export declare enum LeaveRequestStatus {
8
+ PENDING = "pending",
9
+ APPROVED = "approved",
10
+ REJECTED = "rejected",
11
+ CANCELLED = "cancelled"
12
+ }
13
+ /** The two outcomes a reviewer may give a pending request. */
14
+ export declare enum LeaveReviewDecision {
15
+ APPROVED = "approved",
16
+ REJECTED = "rejected"
17
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LeaveReviewDecision = exports.LeaveRequestStatus = void 0;
4
+ /**
5
+ * The lifecycle of a leave request. Stored as text on `leave_requests.status` and validated
6
+ * here, never by a Postgres enum. `pending` moves to any of the other three; `approved` may
7
+ * still be cancelled (a future booking the employee no longer needs); `rejected` and
8
+ * `cancelled` are terminal.
9
+ */
10
+ var LeaveRequestStatus;
11
+ (function (LeaveRequestStatus) {
12
+ LeaveRequestStatus["PENDING"] = "pending";
13
+ LeaveRequestStatus["APPROVED"] = "approved";
14
+ LeaveRequestStatus["REJECTED"] = "rejected";
15
+ LeaveRequestStatus["CANCELLED"] = "cancelled";
16
+ })(LeaveRequestStatus || (exports.LeaveRequestStatus = LeaveRequestStatus = {}));
17
+ /** The two outcomes a reviewer may give a pending request. */
18
+ var LeaveReviewDecision;
19
+ (function (LeaveReviewDecision) {
20
+ LeaveReviewDecision["APPROVED"] = "approved";
21
+ LeaveReviewDecision["REJECTED"] = "rejected";
22
+ })(LeaveReviewDecision || (exports.LeaveReviewDecision = LeaveReviewDecision = {}));
@@ -0,0 +1,79 @@
1
+ import { LeaveRequestStatus } from './enum';
2
+ import { UserIdentity } from '../users';
3
+ export * from './enum';
4
+ /**
5
+ * Leave, the first slice of the HR module: leave types, per-user entitlements and leave
6
+ * requests. Every date below is a calendar date (`YYYY-MM-DD`), never a timestamp - leave is
7
+ * booked by day, and the columns are `date` in Postgres. The public-holiday calendar the
8
+ * day count reads lives in `../public-holidays`.
9
+ */
10
+ export type LeaveTypeIdentity = {
11
+ mms_id: string;
12
+ name: string;
13
+ };
14
+ export type LeaveTypeEntity = {
15
+ mms_id: string;
16
+ created_at: string;
17
+ created_by: UserIdentity | null;
18
+ updated_at: string | null;
19
+ last_updated_by: UserIdentity | null;
20
+ name: string;
21
+ description: string | null;
22
+ /** The days a full year of this type is worth - the suggested entitlement. */
23
+ default_days: number;
24
+ is_paid: boolean;
25
+ /** False auto-approves a request on submission. */
26
+ requires_approval: boolean;
27
+ /** An inactive type keeps its history but cannot be chosen for new requests. */
28
+ active: boolean;
29
+ };
30
+ /** The window an entitlement covers - normally the organization's leave year. */
31
+ export type LeavePeriod = {
32
+ period_start: string;
33
+ period_end: string;
34
+ };
35
+ export type LeaveEntitlementEntity = LeavePeriod & {
36
+ mms_id: string;
37
+ created_at: string;
38
+ created_by: UserIdentity | null;
39
+ updated_at: string | null;
40
+ last_updated_by: UserIdentity | null;
41
+ user: UserIdentity;
42
+ leave_type: LeaveTypeIdentity;
43
+ days_entitled: number;
44
+ notes: string | null;
45
+ /**
46
+ * Computed on read, never stored: the approved and pending requests of this user and
47
+ * type whose start date falls inside the period. `days_remaining` already subtracts both.
48
+ */
49
+ days_used: number;
50
+ days_pending: number;
51
+ days_remaining: number;
52
+ };
53
+ export type LeaveRequestEntity = {
54
+ mms_id: string;
55
+ created_at: string;
56
+ created_by: UserIdentity | null;
57
+ updated_at: string | null;
58
+ last_updated_by: UserIdentity | null;
59
+ user: UserIdentity;
60
+ leave_type: LeaveTypeIdentity;
61
+ start_date: string;
62
+ end_date: string;
63
+ /** Only for a single-day request; halves its `days`. */
64
+ is_half_day: boolean;
65
+ /**
66
+ * Working days (Monday to Friday, less the organization's public holidays) as counted
67
+ * when the request was submitted or last edited. A snapshot: a holiday added afterwards
68
+ * does not rewrite approved history.
69
+ */
70
+ days: number;
71
+ reason: string | null;
72
+ status: LeaveRequestStatus;
73
+ /** Null on an auto-approved request (`requires_approval` was false). */
74
+ reviewed_by: UserIdentity | null;
75
+ reviewed_at: string | null;
76
+ review_note: string | null;
77
+ cancelled_by: UserIdentity | null;
78
+ cancelled_at: string | null;
79
+ };
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./enum"), exports);
@@ -8,6 +8,7 @@
8
8
  */
9
9
  export declare const MODULE_KEYS: {
10
10
  readonly CRM: "CRM";
11
+ readonly HR: "HR";
11
12
  };
12
13
  /**
13
14
  * A row of the billing_modules catalog: one row per sellable module, no pricing.
@@ -11,4 +11,5 @@ exports.MODULE_KEYS = void 0;
11
11
  */
12
12
  exports.MODULE_KEYS = {
13
13
  CRM: 'CRM',
14
+ HR: 'HR',
14
15
  };
@@ -13,6 +13,9 @@ export declare enum NotificationType {
13
13
  PROJECT_MANAGER_ASSIGNED = "project_manager_assigned",
14
14
  PAYMENT_FAILED = "payment_failed",
15
15
  INVOICE_PAID = "invoice_paid",
16
+ LEAVE_REQUEST_SUBMITTED = "leave_request_submitted",
17
+ LEAVE_REQUEST_APPROVED = "leave_request_approved",
18
+ LEAVE_REQUEST_REJECTED = "leave_request_rejected",
16
19
  SIGNUP_CONFIRMATION = "signup_confirmation",
17
20
  PASSWORD_RECOVERY = "password_recovery"
18
21
  }
@@ -21,6 +21,9 @@ var NotificationType;
21
21
  NotificationType["PROJECT_MANAGER_ASSIGNED"] = "project_manager_assigned";
22
22
  NotificationType["PAYMENT_FAILED"] = "payment_failed";
23
23
  NotificationType["INVOICE_PAID"] = "invoice_paid";
24
+ NotificationType["LEAVE_REQUEST_SUBMITTED"] = "leave_request_submitted";
25
+ NotificationType["LEAVE_REQUEST_APPROVED"] = "leave_request_approved";
26
+ NotificationType["LEAVE_REQUEST_REJECTED"] = "leave_request_rejected";
24
27
  NotificationType["SIGNUP_CONFIRMATION"] = "signup_confirmation";
25
28
  NotificationType["PASSWORD_RECOVERY"] = "password_recovery";
26
29
  })(NotificationType || (exports.NotificationType = NotificationType = {}));
@@ -0,0 +1,5 @@
1
+ /** The one route, a read. There is no body DTO: the calendar is edited in Supabase Studio. */
2
+ export type GetPublicHolidaysDto = {
3
+ /** Omitted = every holiday on record. */
4
+ year?: number | null;
5
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The public-holiday calendar: the dates that are not working days when a leave request's
3
+ * days are counted. Global, like configs - a holiday is a fact about the country, not a
4
+ * tenant, so every organization reads the same list. Read-only through the api; the rows
5
+ * are maintained in Supabase Studio and carry no author stamps and no audit trail.
6
+ */
7
+ export type PublicHolidayEntity = {
8
+ mms_id: string;
9
+ created_at: string;
10
+ name: string;
11
+ date: string;
12
+ /**
13
+ * Null means the holiday applies to everyone and shortens a request. A faith-specific
14
+ * holiday (several may share a date) is on the calendar only, since nothing yet records
15
+ * which employees observe it.
16
+ */
17
+ religion: string | null;
18
+ notes: string | null;
19
+ };
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -1,20 +1,19 @@
1
1
  /**
2
- * The contract for the portal's edge cache of each member's own `GET /users/me`.
2
+ * The contract for the portal's Redis cache of each member's own `GET /users/me`.
3
3
  *
4
- * The portal owns the cache (Upstash Redis through the sdk cache subpath, one entry per
5
- * member, written on a miss); the api never reads it and only invalidates tags after a write. Both sides import
6
- * these so a change to the shape or the tagging is one edit.
4
+ * One hash per organization, `profiles:v1:<organization_id>`, with one field per member
5
+ * named by their `mms_id` and holding their `LoggedInUser`. The portal writes a field on a
6
+ * miss; the api never reads the hash and only deletes a field (a member's write) or the
7
+ * whole hash (a write that changes every member's profile). Both sides build the key from
8
+ * these constants - the builder itself lives in `@managemint-solutions/sdk/cache`.
7
9
  */
8
- /** Bump when the LoggedInUser wire shape changes; old entries simply stop matching. */
9
- export declare const USER_ME_CACHE_VERSION = "v1";
10
- /** The hard ceiling on how stale a cached profile may be, in seconds (one day). */
11
- export declare const USER_ME_CACHE_TTL_SECONDS = 86400;
12
- /** The cache key of one member's LoggedInUser blob. Portal-internal; versioned here. */
13
- export declare const userMeCacheKey: (mmsId: string) => string;
14
- /** Expiring this tag drops one member's blob - every write to that member's row or permissions. */
15
- export declare const userCacheTag: (mmsId: string) => string;
10
+ /** Bump when the LoggedInUser wire shape changes; old hashes simply stop matching. */
11
+ export declare const PROFILE_CACHE_VERSION = "v1";
12
+ /** The hash key is this prefix followed by the organization's `mms_id`. */
13
+ export declare const PROFILE_CACHE_KEY_PREFIX = "profiles:v1:";
16
14
  /**
17
- * Expiring this tag drops every member's blob in the organization - a write that changes
18
- * what all of them see (the module set folded into their permissions).
15
+ * The hard ceiling on how stale a cached profile may be, in seconds (one day). Set once,
16
+ * when a hash is first written, so an organization's whole cache re-reads once a day
17
+ * however busy it is.
19
18
  */
20
- export declare const organizationCacheTag: (organizationId: string) => string;
19
+ export declare const PROFILE_CACHE_TTL_SECONDS = 86400;
@@ -1,26 +1,22 @@
1
1
  "use strict";
2
2
  /**
3
- * The contract for the portal's edge cache of each member's own `GET /users/me`.
3
+ * The contract for the portal's Redis cache of each member's own `GET /users/me`.
4
4
  *
5
- * The portal owns the cache (Upstash Redis through the sdk cache subpath, one entry per
6
- * member, written on a miss); the api never reads it and only invalidates tags after a write. Both sides import
7
- * these so a change to the shape or the tagging is one edit.
5
+ * One hash per organization, `profiles:v1:<organization_id>`, with one field per member
6
+ * named by their `mms_id` and holding their `LoggedInUser`. The portal writes a field on a
7
+ * miss; the api never reads the hash and only deletes a field (a member's write) or the
8
+ * whole hash (a write that changes every member's profile). Both sides build the key from
9
+ * these constants - the builder itself lives in `@managemint-solutions/sdk/cache`.
8
10
  */
9
11
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.organizationCacheTag = exports.userCacheTag = exports.userMeCacheKey = exports.USER_ME_CACHE_TTL_SECONDS = exports.USER_ME_CACHE_VERSION = void 0;
11
- /** Bump when the LoggedInUser wire shape changes; old entries simply stop matching. */
12
- exports.USER_ME_CACHE_VERSION = 'v1';
13
- /** The hard ceiling on how stale a cached profile may be, in seconds (one day). */
14
- exports.USER_ME_CACHE_TTL_SECONDS = 86400;
15
- /** The cache key of one member's LoggedInUser blob. Portal-internal; versioned here. */
16
- const userMeCacheKey = (mmsId) => `user:me:${exports.USER_ME_CACHE_VERSION}:${mmsId}`;
17
- exports.userMeCacheKey = userMeCacheKey;
18
- /** Expiring this tag drops one member's blob - every write to that member's row or permissions. */
19
- const userCacheTag = (mmsId) => `user:${mmsId}`;
20
- exports.userCacheTag = userCacheTag;
12
+ exports.PROFILE_CACHE_TTL_SECONDS = exports.PROFILE_CACHE_KEY_PREFIX = exports.PROFILE_CACHE_VERSION = void 0;
13
+ /** Bump when the LoggedInUser wire shape changes; old hashes simply stop matching. */
14
+ exports.PROFILE_CACHE_VERSION = 'v1';
15
+ /** The hash key is this prefix followed by the organization's `mms_id`. */
16
+ exports.PROFILE_CACHE_KEY_PREFIX = `profiles:${exports.PROFILE_CACHE_VERSION}:`;
21
17
  /**
22
- * Expiring this tag drops every member's blob in the organization - a write that changes
23
- * what all of them see (the module set folded into their permissions).
18
+ * The hard ceiling on how stale a cached profile may be, in seconds (one day). Set once,
19
+ * when a hash is first written, so an organization's whole cache re-reads once a day
20
+ * however busy it is.
24
21
  */
25
- const organizationCacheTag = (organizationId) => `org:${organizationId}`;
26
- exports.organizationCacheTag = organizationCacheTag;
22
+ exports.PROFILE_CACHE_TTL_SECONDS = 86400;
@@ -138,6 +138,9 @@ export interface Permissions {
138
138
  project_budgets: CrudPermission;
139
139
  tasks: CrudPermission;
140
140
  invoices: Omit<CrudPermission, 'create' | 'update' | 'delete'>;
141
+ leave_types: CrudPermission;
142
+ leave_entitlements: CrudPermission;
143
+ leave_requests: CrudPermission;
141
144
  users: CrudPermission;
142
145
  user_permissions: Omit<CrudPermission, 'create' | 'delete'>;
143
146
  organizations: Omit<CrudPermission, 'create' | 'delete'>;
@@ -11,6 +11,18 @@ export type UpdatePermissionsDto = {
11
11
  read_tasks: boolean;
12
12
  update_tasks: boolean;
13
13
  delete_tasks: boolean;
14
+ create_leave: boolean;
15
+ read_leave: boolean;
16
+ update_leave: boolean;
17
+ delete_leave: boolean;
18
+ create_leave_types: boolean;
19
+ read_leave_types: boolean;
20
+ update_leave_types: boolean;
21
+ delete_leave_types: boolean;
22
+ create_leave_requests: boolean;
23
+ read_leave_requests: boolean;
24
+ update_leave_requests: boolean;
25
+ delete_leave_requests: boolean;
14
26
  read_invoices: boolean;
15
27
  create_users: boolean;
16
28
  read_users: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@managemint-solutions/entities",
3
- "version": "1.19.0",
3
+ "version": "1.21.0",
4
4
  "description": "Entity types used by both the api and portal",
5
5
  "homepage": "https://github.com/ManageMint-Solutions/managemint-solutions-entities#readme",
6
6
  "bugs": {