import { type EmptyFields } from "@tailor-platform/erp-kit/core"; import type { TailorAnyDBField } from "@tailor-platform/sdk"; import type { TailorDBInsertable, TailorDBSelectable } from "@tailor-platform/sdk/kysely"; import type { TimeTrackingModule } from "../time-tracking"; import type { UserManagementModule } from "../user-management"; import type { WorkforceModule } from "../workforce"; import { approveLeave } from "./command/approveLeave.generated"; import { approveLeaveCancel } from "./command/approveLeaveCancel.generated"; import { createAccrualPlan } from "./command/createAccrualPlan.generated"; import { createLeaveType } from "./command/createLeaveType.generated"; import { deactivateLeaveType } from "./command/deactivateLeaveType.generated"; import { expireLeaveGrants } from "./command/expireLeaveGrants.generated"; import { grantLeave } from "./command/grantLeave.generated"; import { rejectLeave } from "./command/rejectLeave.generated"; import { rejectLeaveCancel } from "./command/rejectLeaveCancel.generated"; import { requestLeave } from "./command/requestLeave.generated"; import { requestLeaveCancel } from "./command/requestLeaveCancel.generated"; import { retireAccrualPlan } from "./command/retireAccrualPlan.generated"; import type { EvaluateGrantEligibility } from "./command/runAnniversaryLeaveGrants"; import { runAnniversaryLeaveGrants } from "./command/runAnniversaryLeaveGrants.generated"; import { updateAccrualPlan } from "./command/updateAccrualPlan.generated"; import { updateLeaveType } from "./command/updateLeaveType.generated"; import { withdrawLeave } from "./command/withdrawLeave.generated"; import { createAccrualPlanType, type CreateAccrualPlanTypeParams } from "./db/accrualPlan"; import { createLeaveConsumptionType } from "./db/leaveConsumption"; import { createLeaveGrantType } from "./db/leaveGrant"; import { createLeaveRequestType } from "./db/leaveRequest"; import { createLeaveTypeType } from "./db/leaveType"; import type { ApproveApprovalStepFn, CreateApprovalRequestFn, FindPendingApproverAssigneeFn, GetActiveApprovalRequestFn, ListUsersByRoleFn, SendBackApprovalStepFn, WithdrawApprovalRequestFn, } from "./lib/_approvalDeps"; import { getAccrualPlan } from "./query/getAccrualPlan.generated"; import { getAnnualLeaveRegister } from "./query/getAnnualLeaveRegister.generated"; import { getLeaveBalance } from "./query/getLeaveBalance.generated"; import { getLeaveGrant } from "./query/getLeaveGrant.generated"; import { getLeaveRequest } from "./query/getLeaveRequest.generated"; import { getLeaveType } from "./query/getLeaveType.generated"; import { getLeaveTypeByKey } from "./query/getLeaveTypeByKey.generated"; import { listAccrualPlansByLeaveType } from "./query/listAccrualPlansByLeaveType.generated"; import { listActiveAccrualPlans } from "./query/listActiveAccrualPlans.generated"; import { listActiveLeaveTypes } from "./query/listActiveLeaveTypes.generated"; import { listExpiringLeaveGrants } from "./query/listExpiringLeaveGrants.generated"; import { listLeaveConsumptionByGrant } from "./query/listLeaveConsumptionByGrant.generated"; import { listLeaveConsumptionByRequest } from "./query/listLeaveConsumptionByRequest.generated"; import { listLeaveGrantsByWorker } from "./query/listLeaveGrantsByWorker.generated"; import { listLeaveRequestsByWorker } from "./query/listLeaveRequestsByWorker.generated"; import { listLeaveTypes } from "./query/listLeaveTypes.generated"; import { listPendingLeaveApprovals } from "./query/listPendingLeaveApprovals.generated"; type UserManagementDB = UserManagementModule["db"]; type WorkforceDB = WorkforceModule["db"]; type WorkforceQueries = WorkforceModule["queries"]; type TimeTrackingQueries = TimeTrackingModule["queries"]; export interface DefineModuleParams = EmptyFields> { accrualPlan?: CreateAccrualPlanTypeParams; workforce: { db: { worker: WorkforceDB["worker"]; assignment: WorkforceDB["assignment"] }; // Injected workforce query seam: requestLeave validates the filed Assignment; grantLeave // validates the Worker; getEmploymentType validates an AccrualPlan's appliesToEmploymentTypeId. queries: Pick< WorkforceQueries, "getAssignment" | "getWorkerEmployment" | "getWorker" | "getEmploymentType" >; }; userManagement: { db: { user: UserManagementDB["user"] }; // listUsersByRole backs the NOT_ASSIGNEE deadlock pre-check in requestLeave (ADR-003). queries: { listUsersByRole: ListUsersByRoleFn }; }; // Injected time-tracking queries: aggregateWorkedDays backs the anniversary grant batch's // MIN_WORKED_DAYS gate (ADR-026 B1); getTimeEntryCodeByKey validates a LeaveType's // timeEntryCodeKey mapping at create/update time. timeTracking: { queries: Pick; }; /** * Optional application-owned eligibility policy for conditions stored in AccrualPlan custom * fields. The generic batch remains responsible for idempotency, tier calculation, and grants. * The evaluator is handed the effective plan ROW, so its custom fields are typed with * `TailorDBSelectable` (an unset optional field reads as null) rather than the create-input shape. */ grantEligibility?: { evaluate: EvaluateGrantEligibility>; }; /** * Bundled approval-module seam (ADR-003 wrapper). The app composition injects the approval * commands/queries and the leave-approver role id; `findPendingApproverAssignee` is app-provided * because the approval module exposes no query returning an assignee id. */ approval: { leaveApproverRoleId: string; commands: { createApprovalRequest: CreateApprovalRequestFn; approveApprovalStep: ApproveApprovalStepFn; sendBackApprovalStep: SendBackApprovalStepFn; withdrawApprovalRequest: WithdrawApprovalRequestFn; }; queries: { getActiveApprovalRequest: GetActiveApprovalRequestFn; }; findPendingApproverAssignee: FindPendingApproverAssigneeFn; }; } /* @__NO_SIDE_EFFECTS__ */ export const defineModule = = EmptyFields>( params: DefineModuleParams, ) => { const workerType = params.workforce.db.worker; const assignmentType = params.workforce.db.assignment; const userType = params.userManagement.db.user; const leaveType = createLeaveTypeType({}); const accrualPlan = createAccrualPlanType(params.accrualPlan ?? {}); const leaveGrant = createLeaveGrantType({ workerType }); const leaveRequest = createLeaveRequestType({ workerType, assignmentType, userType }); const leaveConsumption = createLeaveConsumptionType({}); return { db: { leaveType, accrualPlan, leaveGrant, leaveRequest, leaveConsumption, }, commands: { createLeaveType: createLeaveType({ getTimeEntryCodeByKey: params.timeTracking.queries.getTimeEntryCodeByKey, }), updateLeaveType: updateLeaveType({ getTimeEntryCodeByKey: params.timeTracking.queries.getTimeEntryCodeByKey, }), deactivateLeaveType: deactivateLeaveType(), createAccrualPlan: createAccrualPlan>({ getEmploymentType: params.workforce.queries.getEmploymentType, }), updateAccrualPlan: updateAccrualPlan>({ getEmploymentType: params.workforce.queries.getEmploymentType, }), retireAccrualPlan: retireAccrualPlan(), grantLeave: grantLeave({ getWorker: params.workforce.queries.getWorker }), expireLeaveGrants: expireLeaveGrants(), runAnniversaryLeaveGrants: runAnniversaryLeaveGrants>({ aggregateWorkedDays: params.timeTracking.queries.aggregateWorkedDays, evaluateGrantEligibility: params.grantEligibility?.evaluate, }), requestLeave: requestLeave({ getAssignment: params.workforce.queries.getAssignment, getWorkerEmployment: params.workforce.queries.getWorkerEmployment, leaveApproverRoleId: params.approval.leaveApproverRoleId, listUsersByRole: params.userManagement.queries.listUsersByRole, createApprovalRequest: params.approval.commands.createApprovalRequest, }), approveLeave: approveLeave({ getActiveApprovalRequest: params.approval.queries.getActiveApprovalRequest, findPendingApproverAssignee: params.approval.findPendingApproverAssignee, approveApprovalStep: params.approval.commands.approveApprovalStep, }), rejectLeave: rejectLeave({ getActiveApprovalRequest: params.approval.queries.getActiveApprovalRequest, findPendingApproverAssignee: params.approval.findPendingApproverAssignee, sendBackApprovalStep: params.approval.commands.sendBackApprovalStep, }), withdrawLeave: withdrawLeave({ getActiveApprovalRequest: params.approval.queries.getActiveApprovalRequest, withdrawApprovalRequest: params.approval.commands.withdrawApprovalRequest, }), requestLeaveCancel: requestLeaveCancel({ leaveApproverRoleId: params.approval.leaveApproverRoleId, listUsersByRole: params.userManagement.queries.listUsersByRole, createApprovalRequest: params.approval.commands.createApprovalRequest, }), approveLeaveCancel: approveLeaveCancel({ getActiveApprovalRequest: params.approval.queries.getActiveApprovalRequest, findPendingApproverAssignee: params.approval.findPendingApproverAssignee, approveApprovalStep: params.approval.commands.approveApprovalStep, }), rejectLeaveCancel: rejectLeaveCancel({ getActiveApprovalRequest: params.approval.queries.getActiveApprovalRequest, findPendingApproverAssignee: params.approval.findPendingApproverAssignee, sendBackApprovalStep: params.approval.commands.sendBackApprovalStep, }), }, queries: { getLeaveType, getLeaveTypeByKey, listLeaveTypes, listActiveLeaveTypes, getAccrualPlan, listAccrualPlansByLeaveType, listActiveAccrualPlans, getLeaveGrant, getLeaveBalance, getAnnualLeaveRegister, listLeaveGrantsByWorker, listExpiringLeaveGrants, getLeaveRequest, listLeaveRequestsByWorker, listPendingLeaveApprovals, listLeaveConsumptionByRequest, listLeaveConsumptionByGrant, }, }; }; /** EmptyFields-instantiated alias — use instead of `ReturnType`, which widens field generics to their constraint. */ export type LeaveManagementModule = ReturnType>;