import { type CommonReservedFields, type NoReservedFields, defaultGqlPermission, defaultPermission, } from "@tailor-platform/erp-kit/core"; import { db, type TailorAnyDBField, type TailorAnyDBType } from "@tailor-platform/sdk"; // Lifecycle states (ADR-011 unification): no LeaveRequest.lifecycle.generated.ts exists yet, // hardcoded here to match the exact strings used across the command docs' Process Flow sections. // PENDING --(approveLeave)--> APPROVED --(requestLeaveCancel)--> CANCEL_PENDING --(approveLeaveCancel)--> CANCELLED // PENDING --(rejectLeave)--> REJECTED // PENDING --(withdrawLeave)--> CANCELLED // CANCEL_PENDING --(rejectLeaveCancel)--> APPROVED const LEAVE_REQUEST_STATUSES = [ "PENDING", "APPROVED", "REJECTED", "CANCELLED", "CANCEL_PENDING", ] as const; const builtins = (params: { workerType?: TailorAnyDBType; assignmentType?: TailorAnyDBType; userType?: TailorAnyDBType; }) => { // Cross-module FK: relation only when the foreign type is injected; plain uuid at codegen const workerId = db .uuid() .description( "Foreign key to the workforce Worker who filed this request (also the ledger owner)", ); const assignmentId = db .uuid() .description( 'Foreign key to the workforce Assignment effective on the target date, establishing the organizational "whose"', ); const resolvedBy = db .uuid({ optional: true }) .description("Foreign key to the user-management User who approved or rejected this request"); return { workerId: params.workerType ? workerId.relation({ type: "n-1", toward: { type: params.workerType, as: "worker" }, backward: "leaveRequests", }) : workerId, assignmentId: params.assignmentType ? assignmentId.relation({ type: "n-1", toward: { type: params.assignmentType, as: "assignment" }, backward: "leaveRequests", }) : assignmentId, // Cross-module reference by key (LeaveType catalog entry), not a FK relation leaveTypeKey: db .string() .description("Key of the LeaveType catalog entry selected for this request"), startDate: db.date().description("First date of the requested leave"), endDate: db.date().description("Last date of the requested leave"), reason: db.string().description("Mandatory, non-empty reason given by the requester"), // Lifecycle status (ADR-011): PENDING/APPROVED/REJECTED/CANCELLED/CANCEL_PENDING status: db.enum(LEAVE_REQUEST_STATUSES).description("Lifecycle status of the leave request"), resolvedAt: db .datetime({ optional: true }) .description("Timestamp of the approve/reject/cancel-decision resolution; set once resolved"), resolvedBy: params.userType ? resolvedBy.relation({ type: "n-1", toward: { type: params.userType, as: "resolvedByUser" }, backward: "resolvedLeaveRequests", }) : resolvedBy, // Links to the bundled approval module's ApprovalRequest mirroring the pending decision (ADR-003) targetEntityId: db .string() .description( "Id of the mirroring approval-module ApprovalRequest for the current pending decision", ), }; }; type ReservedFields = keyof ReturnType | CommonReservedFields; export interface CreateLeaveRequestTypeParams> { fields?: NoReservedFields; workerType?: TailorAnyDBType; assignmentType?: TailorAnyDBType; userType?: TailorAnyDBType; } export function createLeaveRequestType>( params: CreateLeaveRequestTypeParams, ) { return db .table("LeaveRequest", { ...builtins(params), ...((params.fields ?? {}) as F), ...db.fields.timestamps(), }) .permission(defaultPermission) .gqlPermission(defaultGqlPermission); } // Codegen instance with no cross-module types; real FKs injected via module.ts export const leaveRequest = createLeaveRequestType({});