import type { CommandContext } from "@tailor-platform/erp-kit/core"; import type { Transaction } from "../generated/kysely-tailordb"; /** * Approval-module dependency seams for the Timecard wrapper commands (ADR-003). * * These are intentionally minimal structural signatures rather than the approval * module's own exported types: the time-tracking module stays free of approval's * kysely table types, and the app composition layer (which owns both modules) is * where the real approval commands/queries are adapted onto these seams. Every * function runs against the SAME transaction the wrapper command was handed, so * the mirrored approval rows are written in the wrapper's transaction (ADR-003). */ // The erp-kit Result discriminated union, narrowed to what the wrappers read. type Result = { ok: true; value: T } | { ok: false; error: { code: string } }; export interface ApprovalRequestRef { id: string; requesterId: string; } export type RoleQuorum = "ANY" | "ALL"; export interface CreateApprovalRequestFn { ( db: Transaction, input: { name: string; purpose: string; targetEntityType: string; targetEntityId: string; steps: Array<{ stepOrder: number; name: string; minimumApprovals?: number; assignees: Array<{ userId?: string; roleId?: string; required?: boolean; roleQuorum?: RoleQuorum; }>; }>; }, ctx: CommandContext, ): Promise>; } export interface ListUsersByRoleFn { ( db: Transaction, input: { roleId: string }, ctx: CommandContext, ): Promise }>>; } export interface GetActiveApprovalRequestFn { ( db: Transaction, input: { targetEntityType: string; targetEntityId: string }, ): Promise>; } /** * App-provided lookup: the id of the PENDING ApprovalStepAssignee row the given * user owns on the request's active (IN_PROGRESS) step, or null if the user is * not an active assignee. The approval module exposes no query returning this id * (only listApprovalRequestsForApprover, which returns request ids), so the app * composition supplies it from the approval tables it has kysely types for. */ export interface FindPendingApproverAssigneeFn { ( db: Transaction, args: { approvalRequestId: string; userId: string }, ): Promise<{ approvalStepAssigneeId: string } | null>; } export interface ApproveApprovalStepFn { ( db: Transaction, input: { approvalStepAssigneeId: string; comment?: string }, ctx: CommandContext, ): Promise>; } export interface WithdrawApprovalRequestFn { ( db: Transaction, input: { approvalRequestId: string; comment?: string }, ctx: CommandContext, ): Promise>; } export interface SendBackApprovalStepFn { ( db: Transaction, input: { approvalStepAssigneeId: string; reason: string }, ctx: CommandContext, ): Promise>; } export interface CancelApprovalRequestFn { ( db: Transaction, input: { approvalRequestId: string; reason: string }, ctx: CommandContext, ): Promise>; } // Raw approval-module error codes the wrappers re-map to their own error classes. export const APPROVAL_NOT_ACTIVE_ASSIGNEE = "APPROVAL_NOT_ACTIVE_ASSIGNEE"; export const APPROVAL_SELF_DECISION_NOT_ALLOWED = "APPROVAL_SELF_DECISION_NOT_ALLOWED"; export const TIMECARD_TARGET_ENTITY_TYPE = "Timecard";