import type { RequestFn } from "./utils"; export type PayrollLineKind = | "earning" | "adjustment_credit" | "adjustment_debit" | "deduction" | "payment"; export type PayrollPeriodSummary = { code: string; name: string; date_from: string; date_to: string; pay_date: string | null; }; export type PayrollAcknowledgement = { viewed_at: string | null; acknowledged_at: string | null; disputed_at: string | null; }; export type PayrollPaymentConfirmation = { confirmed_at: string; confirmed_by: { id: number; display_name: string; }; }; export type PayrollStatementSummary = { public_id: string; period: PayrollPeriodSummary; revision: number; published_at: string; currency: string; payable: string; acknowledgement: PayrollAcknowledgement | null; payment_confirmation: PayrollPaymentConfirmation | null; can_confirm_payment: boolean; }; export type PayrollStatementLine = { code: string; label: string; kind: PayrollLineKind; amount: string; source_period_from: string | null; source_period_to: string | null; is_retro: boolean; is_automatic_carryover: boolean; calculated: boolean; }; export type PayrollStatement = PayrollStatementSummary & { point_delta: string | null; gross_before_adjustments: string; adjustment_total: string; gross_total: string; deduction_total: string; net_pay: string; payment_total: string; opening_balance: string; closing_balance: string; lines: PayrollStatementLine[]; }; export type PayrollStatementPage = { count: number; next: string | null; previous: string | null; results: PayrollStatementSummary[]; }; export type PayrollOwnWorkRecord = { id: number; period_id: number; target_points: string; target_points_overridden: boolean; actual_points: string; revision: number; status: PayrollApprovalStatus; status_label: string; lock_version: number; replaces_id: number | null; reason: string; source: string; created_at: string; updated_at: string; approved_at: string | null; }; export type PayrollOwnDailyWorkEntry = { id: number; period_id: number; work_date: string; target_points: string; actual_points: string; note: string; lock_version: number; created_at: string; updated_at: string; }; export type PayrollOwnWorkPeriod = PayrollPeriodSummary & { id: number; status: PayrollPeriodStatus; status_label: string; editable: boolean; record: PayrollOwnWorkRecord | null; summary: { target_points: string; actual_points: string; target_source: "saved_record" | "individual_schedule" | "standard_schedule" | "default_schedule"; workdays_count: number; }; }; export type PayrollOwnDailyWorkWorkspace = { daily_target_points: string; selected_period_id: number | null; periods: PayrollOwnWorkPeriod[]; entries: PayrollOwnDailyWorkEntry[]; }; export type PayrollOwnDailyWorkWrite = { period_id: number; work_date: string; actual_points: string; note: string; expected_lock_version?: number; }; export type PayrollOwnDailyWorkSaveResult = { operation: "created" | "updated" | "unchanged"; entry: PayrollOwnDailyWorkEntry; record: PayrollOwnWorkRecord; }; export type PayrollApprovalStatus = "draft" | "approved" | "voided"; export type PayrollPeriodStatus = "open" | "calculated" | "review" | "approved" | "published" | "closed"; export type PayrollRunStatus = "calculated" | "review" | "approved" | "published" | "returned" | "superseded"; export type PayrollAdminUserRef = { id: number; display_name: string; }; export type PayrollAdminEmployee = PayrollAdminUserRef & { position: string | null; department?: string | null; }; export type PayrollInputHistoryKind = "rates" | "work" | "inputs"; export type PayrollInputHistoryEvent = { id: number; record_id: number; action: string; action_label: string; subject: string; employee: PayrollAdminEmployee; actor: PayrollAdminUserRef | null; created_at: string; }; export type PayrollManagementAccessCandidate = { id: number; first_name: string; last_name: string; patronymic: string; email: string; display_name: string; avatar: string | null; }; export type PayrollManagementAccessSettings = { restricted: boolean; management_user_ids: number[]; management_user_count: number; candidates: PayrollManagementAccessCandidate[]; }; export type PayrollAdminPeriod = PayrollPeriodSummary & { id: number; currency: string; status: PayrollPeriodStatus; lock_version: number; current_run_id: number | null; automatic_input_copy?: PayrollInputCopyResult | null; }; export type PayrollAdminRun = { id: number; period_id: number; revision: number; status: PayrollRunStatus; employee_count: number; gross_total?: string | null; deduction_total?: string | null; payable_total?: string | null; requested_by: PayrollAdminUserRef; requested_at: string; approved_by: PayrollAdminUserRef | null; approved_at: string | null; published_by: PayrollAdminUserRef | null; published_at: string | null; recalculation_reason: string; }; export type PayrollAdminPermissions = { full_access: boolean; manage_inputs: boolean; approve_inputs: boolean; override_approval: boolean; calculate: boolean; approve_run: boolean; publish: boolean; view_all: boolean; audit: boolean; }; export type PayrollReadinessGroup = { ready: boolean; total: number; approved: number; draft: number; missing_employee_ids?: number[]; }; export type PayrollCalculationBlocker = { code: string; message: string; employee_id?: number; employee_ids?: number[]; employee_count?: number; count?: number; details?: Record; }; export type PayrollAdminWorkspace = { permissions: PayrollAdminPermissions; access_settings: { restricted: boolean; management_user_count: number; can_configure: boolean; }; employees: PayrollAdminEmployee[]; rate_employees: PayrollAdminEmployee[]; components: PayrollComponent[]; periods: PayrollAdminPeriod[]; selected_period: PayrollAdminPeriod | null; readiness: { rates: PayrollReadinessGroup; work_records: PayrollReadinessGroup; input_lines: Pick; calculation: { ready: boolean; blockers: PayrollCalculationBlocker[]; }; }; current_run: PayrollAdminRun | null; runs: PayrollAdminRun[]; summary: { employee_count: number; gross_total: string | null; deduction_total: string | null; payable_total: string | null; } | null; pending_approvals: { rates: number; work_records: number; input_lines: number; }; carryovers: PayrollCarryoverSummary; }; export type PayrollCarryoverDirection = "company_owes" | "employee_owes"; export type PayrollCarryoverStatus = "pending" | "transferred" | "cancelled"; export type PayrollCarryoverPeriod = { id: number; code: string; name: string; date_from: string; date_to: string; currency: string; }; export type PayrollCarryoverSummary = { outgoing: number; incoming: number; pending: number; }; export type PayrollCarryover = { id: number; source_period: PayrollCarryoverPeriod; target_period: PayrollCarryoverPeriod | null; employee: PayrollAdminEmployee; direction: PayrollCarryoverDirection; direction_label: string; amount: string; reason: string; status: PayrollCarryoverStatus; status_label: string; generated_input_line_id: number | null; created_by: PayrollAdminUserRef; created_at: string; transferred_at: string | null; cancelled_at: string | null; can_cancel: boolean; }; export type PayrollCarryoverWorkspace = { period_id: number; summary: PayrollCarryoverSummary; outgoing: PayrollCarryover[]; incoming: PayrollCarryover[]; }; export type PayrollCarryoverLedgerEntry = { id: number; period: PayrollCarryoverPeriod; employee: PayrollAdminEmployee; component: PayrollComponent; amount: string; raw_contribution: string; contribution: string; reason: string; status: PayrollApprovalStatus; status_label: string; include_in_carryover: boolean; counts_in_balance: boolean; created_by: PayrollAdminUserRef; created_at: string; }; export type PayrollCarryoverLedger = { period_id: number; currency: string; summary: { included_count: number; excluded_count: number; company_owes: string; employee_owes: string; balance: string; }; entries: PayrollCarryoverLedgerEntry[]; }; export type PayrollCarryoverWrite = { employee_id: number; direction: PayrollCarryoverDirection; amount: string; reason: string; }; export type PayrollCompleteWorkflowResult = { period: PayrollAdminPeriod; run: PayrollAdminRun; completed_steps: string[]; }; export type PayrollPeriodTableStatus = "calculated" | "ready" | "draft" | "incomplete"; export type PayrollPeriodTableComponent = { code: string; label: string; kind: PayrollLineKind; display_order: number; }; export type PayrollCellCommentAuthor = { id: number; first_name: string; last_name: string; patronymic: string; email: string; phone_number: string; display_name: string; full_name: string; avatar: string | null; }; export type PayrollCellComment = { id: number; author: PayrollCellCommentAuthor; text: string; created_at: string; }; export type PayrollCellCommentSummary = { employee_id: number; column_id: string; count: number; latest_at: string; }; export type PayrollPeriodTableRow = { employee: PayrollAdminEmployee & { first_name: string; last_name: string; patronymic: string; is_active: boolean; }; status: PayrollPeriodTableStatus; rate_status: PayrollApprovalStatus | null; work_status: PayrollApprovalStatus | null; rate_amount: string | null; in_norm_point_rate: string | null; point_rate: string | null; target_points: string | null; target_points_automatic: boolean; target_points_source: string; attendance_points: string | null; personnel_points: string; actual_points: string | null; point_delta: string | null; point_amount: string | null; component_amounts: Record; totals_preliminary: boolean; gross_before_adjustments: string | null; adjustment_total: string | null; gross_total: string | null; deduction_total: string | null; net_pay: string | null; payment_total: string | null; payable: string | null; opening_balance: string; closing_balance: string; payment_confirmation: { confirmed_at: string; confirmed_by: PayrollAdminUserRef; } | null; }; export type PayrollPeriodTableCarryoverSummary = { employee_id: number; count: number; company_owes: string; employee_owes: string; pending: number; }; export type PayrollPeriodTable = { period_id: number; period_status: PayrollPeriodStatus; currency: string; calculation_rules: { ruleset_id: string; version: string; effective_from: string; effective_to: string | null; point_policy: "disabled" | "excess_only" | "proportional_with_excess"; money_quantum: string; rounding: "ROUND_HALF_UP" | "ROUND_HALF_EVEN" | "ROUND_DOWN"; allow_negative_payable: boolean; }; run: Pick | null; component_columns: PayrollPeriodTableComponent[]; cell_comments: PayrollCellCommentSummary[]; carryovers: PayrollPeriodTableCarryoverSummary[]; rows: PayrollPeriodTableRow[]; summary: { employee_count: number; calculated_count: number; ready_count: number; draft_count: number; incomplete_count: number; preliminary_count: number; gross_total: string | null; deduction_total: string | null; payable_total: string | null; }; }; export type PayrollPaymentConfirmationResult = { statement_id: number; employee_id: number; confirmed: boolean; confirmed_at: string | null; confirmed_by: PayrollAdminUserRef | null; }; export type PayrollPointBreakdownDay = { date: string; is_workday: boolean; attendance_points: string | null; personnel_points: string | null; work_points: string | null; attendance_record: { id: number; arrival_time: string | null; departure_time: string | null; work_hours: number | null; expected_hours: number | null; status_label: string; issues: string[]; is_manually_edited: boolean; } | null; personnel_detail: { state: { status: string; label: string; expects_attendance: boolean; }; actions: Array<{ id: number; action: string; label: string; date: string; date_to: string | null; comment: string; source_request_id: number | null; }>; requests: Array<{ id: number; type: string; type_label: string; title: string; status: string; status_label: string; date_from: string | null; date_to: string | null; comment: string; }>; }; work_entry: { id: number; target_points: string | null; actual_points: string | null; note: string; created_at: string; updated_at: string; } | null; }; export type PayrollPointBreakdown = { period: { id: number; name: string; date_from: string; date_to: string; }; employee: PayrollAdminEmployee & { is_active: boolean }; target_points: string | null; actual_points: string | null; undated_work_points: string | null; undated_work_record: { id: number; actual_points: string | null; note: string; created_at: string; updated_at: string; } | null; work_points_mode: "daily_entries" | "unavailable"; dates: PayrollPointBreakdownDay[]; }; export type PayrollComponent = { id: string; code: string; name: string; kind: PayrollLineKind; kind_label: string; requires_reason: boolean; is_active: boolean; display_order: number; }; export type PayrollAdminPayRate = { id: number; employee_id?: number; employee: PayrollAdminEmployee; rate_code: string; amount: string; point_rate: string | null; currency: string; effective_from: string; revision: number; status: PayrollApprovalStatus; reason: string; lock_version: number; created_by: PayrollAdminUserRef; created_at: string; approved_by: PayrollAdminUserRef | null; approved_at: string | null; }; export type PayrollAdminWorkRecord = { id: number; period_id: number; employee_id?: number; employee: PayrollAdminEmployee; target_points: string; target_points_overridden: boolean; actual_points: string; expected_point_amount: string | null; expected_gross: string | null; expected_recalculated_gross: string | null; expected_payable: string | null; revision: number; status: PayrollApprovalStatus; source?: string; replaces_id?: number | null; reason: string; lock_version: number; created_by: PayrollAdminUserRef; created_at: string; approved_by: PayrollAdminUserRef | null; approved_at: string | null; }; export type PayrollAttendanceWorkMode = "missing_only" | "replace_existing"; export type PayrollAttendanceWorkAction = | "create" | "update" | "revise" | "unchanged" | "skip" | "blocked"; export type PayrollAttendanceWorkIssue = { code: string; message: string; }; export type PayrollAttendanceWorkModeSummary = { create: number; update: number; revise: number; unchanged: number; skip: number; blocked: number; changes: number; }; export type PayrollAttendanceExistingWorkRecord = { id: number; revision: number; status: PayrollApprovalStatus; source?: string; target_points: string; actual_points: string; created_by?: PayrollAdminUserRef; }; export type PayrollAttendanceWorkPreviewItem = { employee: PayrollAdminEmployee; target_points: string; actual_points: string; daily_target_points: string; expected_hours: string; worked_hours: string; attendance_days: number; effective_workdays: number; technical_issue_days: number; warnings: PayrollAttendanceWorkIssue[]; blockers: PayrollAttendanceWorkIssue[]; existing_record: PayrollAttendanceExistingWorkRecord | null; actions: Record; }; export type PayrollAttendanceWorkPreview = { period_id: number; generated_at: string; preview_token: string; policy: { code: string; label: string; description: string; formula: string; daily_target_points: string; }; summary: { attendance_employees: number; existing: number; blocked: number; modes: Record; }; items: PayrollAttendanceWorkPreviewItem[]; }; export type PayrollAttendanceWorkApplyPayload = { mode: PayrollAttendanceWorkMode; preview_token: string; expected_period_lock_version: number; reason: string; }; export type PayrollAttendanceWorkApplyResult = { mode: PayrollAttendanceWorkMode; summary: { created: number; updated: number; revised: number; unchanged: number; skipped: number; blocked: number; }; records: PayrollAdminWorkRecord[]; }; export type PayrollWorkbookImportMode = "skip_existing" | "replace_existing"; export type PayrollWorkbookImportEmployee = PayrollAdminEmployee & { is_active: boolean; }; export type PayrollWorkbookImportRow = { row_key: string; sheet_name: string; row_number: number; source_name: string; match_status: "matched" | "ambiguous" | "unmatched"; matched_employee_id: number | null; candidate_employee_ids: number[]; entry_count: number; points_total: string; existing_count: number; existing_period_record: boolean; invalid_cells: Array<{ date: string; message: string }>; entries: Array<{ date: string; points: string }>; }; export type PayrollWorkbookImportPreview = { file_name: string; file_hash: string; period_id: number; period_lock_version: number; blocks: Array<{ sheet_name: string; year: number; month: number }>; employees: PayrollWorkbookImportEmployee[]; rows: PayrollWorkbookImportRow[]; summary: { rows: number; matched: number; needs_mapping: number; entries: number; existing: number; invalid: number; }; }; export type PayrollWorkbookImportResult = { mode: PayrollWorkbookImportMode; summary: { created: number; replaced: number; unchanged: number; skipped: number; }; record_ids: number[]; }; export type PayrollInputCopyEmployeeScope = "all" | "active" | "selected"; export type PayrollInputCopyExistingMode = "skip" | "replace"; export type PayrollInputCopyPreview = { source_period: PayrollAdminPeriod; target_period: PayrollAdminPeriod; summary: { eligible_lines: number; employees: number; active_employees: number; }; components: Array; employees: Array; existing_component_counts: Record; }>; configuration: { saved: boolean; component_codes: string[]; employee_scope: PayrollInputCopyEmployeeScope; employee_ids: number[]; existing_mode: PayrollInputCopyExistingMode; auto_apply_on_period_creation: boolean; }; }; export type PayrollInputCopyWrite = { source_period_id: number; component_codes: string[]; employee_scope: PayrollInputCopyEmployeeScope; employee_ids: number[]; existing_mode: PayrollInputCopyExistingMode; expected_period_lock_version: number; idempotency_key: string; remember_configuration: boolean; auto_apply_on_period_creation: boolean; }; export type PayrollInputCopyResult = { source_period_id: number; target_period_id: number; summary: { created: number; employees: number; skipped: number; replaced_cells: number; voided: number; }; record_ids: number[]; idempotent_replay: boolean; }; export type PayrollAdminInputLine = { id: number; period_id: number; employee: PayrollAdminEmployee; employee_id?: number; component: PayrollComponent; component_code: string; amount: string; relates_to_period_id: number | null; relates_to_period: PayrollCarryoverPeriod | null; is_automatic_carryover: boolean; include_in_carryover: boolean; reason: string; status: PayrollApprovalStatus; lock_version: number; created_by: PayrollAdminUserRef; created_at: string; approved_by: PayrollAdminUserRef | null; approved_at: string | null; }; export type PayrollAdminPage = { count: number; next: string | null; previous: string | null; results: T[]; }; export type PayrollAdminListPayload = PayrollAdminPage | T[]; export type PayrollPeriodWrite = { code: string; name: string; date_from: string; date_to: string; pay_date: string | null; currency: string; }; export type PayrollPayRateWrite = { employee_id: number; rate_code: string; amount: string; point_rate: string | null; currency: string; effective_from: string; reason: string; }; export type PayrollBulkPointRateMode = "fixed" | "in_norm"; export type PayrollBulkPointRateWrite = { employee_ids: number[]; mode: PayrollBulkPointRateMode; point_rate?: string | null; reason: string; }; export type PayrollBulkPointRateResult = { mode: PayrollBulkPointRateMode; point_rate: string | null; summary: { selected_employees: number; updated_drafts: number; created_revisions: number; unchanged: number; skipped: number; }; }; export type PayrollBulkPayRateWrite = { employee_ids: number[]; amount: string; effective_from: string; reason: string; }; export type PayrollBulkPayRateResult = { amount: string; effective_from: string; summary: { selected_employees: number; created_drafts: number; updated_drafts: number; created_revisions: number; unchanged: number; skipped: number; }; }; export type PayrollBulkTargetPointsMode = "fixed" | "automatic"; export type PayrollBulkTargetPointsWrite = { employee_ids: number[]; mode: PayrollBulkTargetPointsMode; target_points?: string | null; reason: string; }; export type PayrollBulkTargetPointsResult = { mode: PayrollBulkTargetPointsMode; target_points: string | null; summary: { selected_employees: number; created_drafts: number; updated_drafts: number; created_revisions: number; unchanged: number; skipped: number; }; }; export type PayrollApproveDraftsResult = { period_id: number; summary: { rates: number; work_records: number; input_lines: number; total: number; }; }; export type PayrollWorkRecordWrite = { period_id: number; employee_id: number; target_points?: string | null; actual_points: string; expected_point_amount?: string | null; expected_gross?: string | null; expected_recalculated_gross?: string | null; expected_payable?: string | null; reason: string; }; export type PayrollInputLineWrite = { period_id: number; employee_id: number; component_code: string; amount: string; relates_to_period_id?: number | null; reason: string; }; type PayrollAdminListParams = { period_id?: number; search?: string; status?: PayrollApprovalStatus | ""; }; const adminPrefix = "/api/v1/finance/payroll/admin"; function buildQuery(params: Record): string { const search = new URLSearchParams(); Object.entries(params).forEach(([key, value]) => { if (value !== undefined && value !== null && value !== "") search.set(key, String(value)); }); const query = search.toString(); return query ? `?${query}` : ""; } function jsonOptions(method: "POST" | "PATCH", payload: object = {}): RequestInit { return { method, body: JSON.stringify(payload) }; } export function createFinanceApi(request: RequestFn) { return { getMyPayrollStatements: (): Promise => request("/api/v1/finance/payroll/me/statements/?page_size=100"), getMyPayrollStatement: (publicId: string): Promise => request(`/api/v1/finance/payroll/me/statements/${encodeURIComponent(publicId)}/`), acknowledgeMyPayrollStatement: (publicId: string): Promise => request( `/api/v1/finance/payroll/me/statements/${encodeURIComponent(publicId)}/acknowledge/`, { method: "POST" }, ), setMyPayrollStatementPaymentConfirmation: ( publicId: string, confirmed: boolean, ): Promise<{ payment_confirmation: PayrollPaymentConfirmation | null }> => request( `/api/v1/finance/payroll/me/statements/${encodeURIComponent(publicId)}/payment-confirmation/`, jsonOptions("POST", { confirmed }), ), getMyPayrollDailyWork: (periodId?: number): Promise => request(`/api/v1/finance/payroll/me/work-records/${buildQuery({ period_id: periodId })}`), saveMyPayrollDailyWorkEntry: ( payload: PayrollOwnDailyWorkWrite, ): Promise => request( "/api/v1/finance/payroll/me/work-records/", jsonOptions("POST", payload), ), getPayrollManagementAccessSettings: (): Promise => request("/api/v1/finance/payroll/management-access/"), updatePayrollManagementAccessSettings: ( managementUserIds: number[], ): Promise => request( "/api/v1/finance/payroll/management-access/", jsonOptions("PATCH", { management_user_ids: managementUserIds }), ), getPayrollAdminWorkspace: (periodId?: number): Promise => request(`${adminPrefix}/workspace/${buildQuery({ period_id: periodId })}`), getPayrollAdminPeriods: (): Promise> => request(`${adminPrefix}/periods/`), getPayrollAdminPeriodTable: (periodId: number): Promise => request(`${adminPrefix}/periods/${periodId}/table/`), setPayrollAdminPaymentConfirmation: ( periodId: number, employeeId: number, confirmed: boolean, ): Promise => request( `${adminPrefix}/periods/${periodId}/employees/${employeeId}/payment-confirmation/`, jsonOptions("POST", { confirmed }), ), getPayrollAdminCarryovers: (periodId: number): Promise => request(`${adminPrefix}/periods/${periodId}/carryovers/`), setPayrollAdminInputLineCarryoverInclusion: ( lineId: number, included: boolean, ): Promise<{ id: number; include_in_carryover: boolean; message: string }> => request( `${adminPrefix}/input-lines/${lineId}/carryover-inclusion/`, jsonOptions("PATCH", { included }), ), createPayrollAdminCarryover: ( periodId: number, payload: PayrollCarryoverWrite, ): Promise => request( `${adminPrefix}/periods/${periodId}/carryovers/`, jsonOptions("POST", payload), ), cancelPayrollAdminCarryover: (carryoverId: number): Promise => request( `${adminPrefix}/carryovers/${carryoverId}/`, { method: "DELETE" }, ), getPayrollAdminCellComments: ( periodId: number, employeeId: number, columnId: string, ): Promise => request(`${adminPrefix}/periods/${periodId}/employees/${employeeId}/cells/${encodeURIComponent(columnId)}/comments/`), addPayrollAdminCellComment: ( periodId: number, employeeId: number, columnId: string, text: string, ): Promise => request( `${adminPrefix}/periods/${periodId}/employees/${employeeId}/cells/${encodeURIComponent(columnId)}/comments/`, jsonOptions("POST", { text }), ), deletePayrollAdminCellComment: ( periodId: number, employeeId: number, columnId: string, commentId: number, ): Promise => request( `${adminPrefix}/periods/${periodId}/employees/${employeeId}/cells/${encodeURIComponent(columnId)}/comments/${commentId}/`, { method: "DELETE" }, ), getPayrollAdminPointBreakdown: ( periodId: number, employeeId: number, ): Promise => request(`${adminPrefix}/periods/${periodId}/employees/${employeeId}/point-breakdown/`), createPayrollAdminPeriod: (payload: PayrollPeriodWrite): Promise => request(`${adminPrefix}/periods/`, jsonOptions("POST", payload)), updatePayrollAdminPeriod: ( periodId: number, payload: Partial & { expected_lock_version: number }, ): Promise => request(`${adminPrefix}/periods/${periodId}/`, jsonOptions("PATCH", payload)), getPayrollAdminPayRates: (params: PayrollAdminListParams = {}): Promise> => request(`${adminPrefix}/pay-rates/${buildQuery({ ...params, page_size: 200 })}`), getPayrollAdminInputHistory: ( periodId: number, kind: PayrollInputHistoryKind, ): Promise => request(`${adminPrefix}/history/${buildQuery({ period_id: periodId, kind })}`), createPayrollAdminPayRate: (payload: PayrollPayRateWrite): Promise => request(`${adminPrefix}/pay-rates/`, jsonOptions("POST", payload)), updatePayrollAdminPayRate: ( rateId: number, payload: Partial> & { expected_lock_version: number }, ): Promise => request(`${adminPrefix}/pay-rates/${rateId}/`, jsonOptions("PATCH", payload)), approvePayrollAdminPayRate: (rateId: number, expectedLockVersion: number): Promise => request(`${adminPrefix}/pay-rates/${rateId}/approve/`, jsonOptions("POST", { expected_lock_version: expectedLockVersion })), revisePayrollAdminPayRate: (rateId: number, reason: string): Promise => request(`${adminPrefix}/pay-rates/${rateId}/revise/`, jsonOptions("POST", { reason })), bulkCreatePayrollAdminPayRates: ( periodId: number, payload: PayrollBulkPayRateWrite, ): Promise => request(`${adminPrefix}/periods/${periodId}/bulk-pay-rate/`, jsonOptions("POST", payload)), bulkSetPayrollAdminPointRate: ( periodId: number, payload: PayrollBulkPointRateWrite, ): Promise => request(`${adminPrefix}/periods/${periodId}/bulk-point-rate/`, jsonOptions("POST", payload)), bulkSetPayrollAdminTargetPoints: ( periodId: number, payload: PayrollBulkTargetPointsWrite, ): Promise => request(`${adminPrefix}/periods/${periodId}/bulk-target-points/`, jsonOptions("POST", payload)), getPayrollAdminInputCopyPreview: ( periodId: number, sourcePeriodId: number, ): Promise => request(`${adminPrefix}/periods/${periodId}/copy-input-lines/${buildQuery({ source_period_id: sourcePeriodId })}`), copyPayrollAdminInputLines: ( periodId: number, payload: PayrollInputCopyWrite, ): Promise => request(`${adminPrefix}/periods/${periodId}/copy-input-lines/`, jsonOptions("POST", payload)), approveAllPayrollAdminDrafts: (periodId: number): Promise => request(`${adminPrefix}/periods/${periodId}/approve-drafts/`, jsonOptions("POST")), getPayrollAdminWorkRecords: (params: PayrollAdminListParams = {}): Promise> => request(`${adminPrefix}/work-records/${buildQuery({ ...params, page_size: 200 })}`), createPayrollAdminWorkRecord: (payload: PayrollWorkRecordWrite): Promise => request(`${adminPrefix}/work-records/`, jsonOptions("POST", payload)), updatePayrollAdminWorkRecord: ( recordId: number, payload: Partial> & { expected_lock_version: number }, ): Promise => request(`${adminPrefix}/work-records/${recordId}/`, jsonOptions("PATCH", payload)), approvePayrollAdminWorkRecord: (recordId: number, expectedLockVersion: number): Promise => request(`${adminPrefix}/work-records/${recordId}/approve/`, jsonOptions("POST", { expected_lock_version: expectedLockVersion })), revisePayrollAdminWorkRecord: (recordId: number, reason: string): Promise => request(`${adminPrefix}/work-records/${recordId}/revise/`, jsonOptions("POST", { reason })), getPayrollAdminAttendanceWorkPreview: (periodId: number): Promise => request(`${adminPrefix}/periods/${periodId}/attendance-work-records/`), applyPayrollAdminAttendanceWork: ( periodId: number, payload: PayrollAttendanceWorkApplyPayload, ): Promise => request( `${adminPrefix}/periods/${periodId}/attendance-work-records/`, jsonOptions("POST", payload), ), previewPayrollAdminWorkbookImport: ( periodId: number, file: File, ): Promise => { const body = new FormData(); body.append("file", file); return request(`${adminPrefix}/periods/${periodId}/workbook-import/preview/`, { method: "POST", body, }); }, applyPayrollAdminWorkbookImport: ( periodId: number, payload: { file: File; mode: PayrollWorkbookImportMode; mappings: Record; expected_file_hash: string; expected_period_lock_version: number; }, ): Promise => { const body = new FormData(); body.append("file", payload.file); body.append("mode", payload.mode); body.append("mappings", JSON.stringify(payload.mappings)); body.append("expected_file_hash", payload.expected_file_hash); body.append("expected_period_lock_version", String(payload.expected_period_lock_version)); return request(`${adminPrefix}/periods/${periodId}/workbook-import/apply/`, { method: "POST", body, }); }, getPayrollAdminInputLines: (params: PayrollAdminListParams = {}): Promise> => request(`${adminPrefix}/input-lines/${buildQuery({ ...params, page_size: 200 })}`), createPayrollAdminInputLine: (payload: PayrollInputLineWrite): Promise => request(`${adminPrefix}/input-lines/`, jsonOptions("POST", payload)), updatePayrollAdminInputLine: ( lineId: number, payload: Partial> & { expected_lock_version: number }, ): Promise => request(`${adminPrefix}/input-lines/${lineId}/`, jsonOptions("PATCH", payload)), clearPayrollAdminComponentCell: ( periodId: number, payload: { employee_id: number; component_code: string }, ): Promise<{ draft: number; approved: number; total: number }> => request(`${adminPrefix}/periods/${periodId}/component-cell/clear/`, jsonOptions("POST", payload)), setPayrollAdminComponentCell: ( periodId: number, payload: { employee_id: number; component_code: string; amount: string }, ): Promise => request(`${adminPrefix}/periods/${periodId}/component-cell/set/`, jsonOptions("POST", payload)), approvePayrollAdminInputLine: (lineId: number, expectedLockVersion: number): Promise => request(`${adminPrefix}/input-lines/${lineId}/approve/`, jsonOptions("POST", { expected_lock_version: expectedLockVersion })), calculatePayrollAdminPeriod: ( periodId: number, payload: { idempotency_key: string; recalculation_reason: string; expected_lock_version: number }, ): Promise => request(`${adminPrefix}/periods/${periodId}/calculate/`, jsonOptions("POST", payload)), completePayrollAdminPeriodWorkflow: ( periodId: number, payload: { idempotency_key: string; recalculation_reason: string; expected_lock_version: number }, ): Promise => request(`${adminPrefix}/periods/${periodId}/complete-workflow/`, jsonOptions("POST", payload)), submitPayrollAdminRunForReview: (runId: number): Promise => request(`${adminPrefix}/runs/${runId}/submit-review/`, jsonOptions("POST")), returnPayrollAdminRun: (runId: number, reason: string): Promise => request(`${adminPrefix}/runs/${runId}/return/`, jsonOptions("POST", { reason })), approvePayrollAdminRun: (runId: number): Promise => request(`${adminPrefix}/runs/${runId}/approve/`, jsonOptions("POST")), publishPayrollAdminRun: (runId: number): Promise => request(`${adminPrefix}/runs/${runId}/publish/`, jsonOptions("POST")), closePayrollAdminPeriod: (periodId: number): Promise => request(`${adminPrefix}/periods/${periodId}/close/`, jsonOptions("POST")), }; }