@t4dhg/mcp-factorial 7.0.1 → 8.2.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.
- package/README.md +321 -49
- package/dist/api/ats.d.ts +78 -0
- package/dist/api/ats.d.ts.map +1 -0
- package/dist/api/ats.js +173 -0
- package/dist/api/ats.js.map +1 -0
- package/dist/api/attendance.d.ts +27 -0
- package/dist/api/attendance.d.ts.map +1 -0
- package/dist/api/attendance.js +62 -0
- package/dist/api/attendance.js.map +1 -0
- package/dist/api/contracts.d.ts +40 -0
- package/dist/api/contracts.d.ts.map +1 -0
- package/dist/api/contracts.js +146 -0
- package/dist/api/contracts.js.map +1 -0
- package/dist/api/documents.d.ts +95 -0
- package/dist/api/documents.d.ts.map +1 -0
- package/dist/api/documents.js +265 -0
- package/dist/api/documents.js.map +1 -0
- package/dist/api/employees.d.ts +35 -0
- package/dist/api/employees.d.ts.map +1 -0
- package/dist/api/employees.js +116 -0
- package/dist/api/employees.js.map +1 -0
- package/dist/api/index.d.ts +22 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +36 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/job-catalog.d.ts +21 -0
- package/dist/api/job-catalog.d.ts.map +1 -0
- package/dist/api/job-catalog.js +34 -0
- package/dist/api/job-catalog.js.map +1 -0
- package/dist/api/locations.d.ts +26 -0
- package/dist/api/locations.d.ts.map +1 -0
- package/dist/api/locations.js +59 -0
- package/dist/api/locations.js.map +1 -0
- package/dist/api/payroll.d.ts +30 -0
- package/dist/api/payroll.d.ts.map +1 -0
- package/dist/api/payroll.js +68 -0
- package/dist/api/payroll.js.map +1 -0
- package/dist/api/projects.d.ts +82 -0
- package/dist/api/projects.d.ts.map +1 -0
- package/dist/api/projects.js +193 -0
- package/dist/api/projects.js.map +1 -0
- package/dist/api/shared.d.ts +12 -0
- package/dist/api/shared.d.ts.map +1 -0
- package/dist/api/shared.js +17 -0
- package/dist/api/shared.js.map +1 -0
- package/dist/api/teams.d.ts +26 -0
- package/dist/api/teams.d.ts.map +1 -0
- package/dist/api/teams.js +59 -0
- package/dist/api/teams.js.map +1 -0
- package/dist/api/time-off.d.ts +47 -0
- package/dist/api/time-off.d.ts.map +1 -0
- package/dist/api/time-off.js +112 -0
- package/dist/api/time-off.js.map +1 -0
- package/dist/api/training.d.ts +62 -0
- package/dist/api/training.d.ts.map +1 -0
- package/dist/api/training.js +147 -0
- package/dist/api/training.js.map +1 -0
- package/dist/api/work-areas.d.ts +30 -0
- package/dist/api/work-areas.d.ts.map +1 -0
- package/dist/api/work-areas.js +71 -0
- package/dist/api/work-areas.js.map +1 -0
- package/dist/api.d.ts +3 -434
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +3 -1154
- package/dist/api.js.map +1 -1
- package/dist/audit.d.ts +8 -3
- package/dist/audit.d.ts.map +1 -1
- package/dist/audit.js +8 -3
- package/dist/audit.js.map +1 -1
- package/dist/index.d.ts +6 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3701
- package/dist/index.js.map +1 -1
- package/dist/oauth.d.ts +63 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +143 -0
- package/dist/oauth.js.map +1 -0
- package/dist/schemas/ats.d.ts +326 -0
- package/dist/schemas/ats.d.ts.map +1 -0
- package/dist/schemas/ats.js +121 -0
- package/dist/schemas/ats.js.map +1 -0
- package/dist/schemas/documents.d.ts +78 -0
- package/dist/schemas/documents.d.ts.map +1 -0
- package/dist/schemas/documents.js +34 -0
- package/dist/schemas/documents.js.map +1 -0
- package/dist/schemas/employees.d.ts +528 -0
- package/dist/schemas/employees.d.ts.map +1 -0
- package/dist/schemas/employees.js +206 -0
- package/dist/schemas/employees.js.map +1 -0
- package/dist/schemas/index.d.ts +18 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +28 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/job-catalog.d.ts +57 -0
- package/dist/schemas/job-catalog.d.ts.map +1 -0
- package/dist/schemas/job-catalog.js +27 -0
- package/dist/schemas/job-catalog.js.map +1 -0
- package/dist/schemas/payroll.d.ts +98 -0
- package/dist/schemas/payroll.d.ts.map +1 -0
- package/dist/schemas/payroll.js +43 -0
- package/dist/schemas/payroll.js.map +1 -0
- package/dist/schemas/projects.d.ts +277 -0
- package/dist/schemas/projects.d.ts.map +1 -0
- package/dist/schemas/projects.js +114 -0
- package/dist/schemas/projects.js.map +1 -0
- package/dist/schemas/shared.d.ts +42 -0
- package/dist/schemas/shared.d.ts.map +1 -0
- package/dist/schemas/shared.js +65 -0
- package/dist/schemas/shared.js.map +1 -0
- package/dist/schemas/time-off.d.ts +286 -0
- package/dist/schemas/time-off.d.ts.map +1 -0
- package/dist/schemas/time-off.js +111 -0
- package/dist/schemas/time-off.js.map +1 -0
- package/dist/schemas/training.d.ts +223 -0
- package/dist/schemas/training.d.ts.map +1 -0
- package/dist/schemas/training.js +88 -0
- package/dist/schemas/training.js.map +1 -0
- package/dist/schemas/work-areas.d.ts +71 -0
- package/dist/schemas/work-areas.d.ts.map +1 -0
- package/dist/schemas/work-areas.js +30 -0
- package/dist/schemas/work-areas.js.map +1 -0
- package/dist/schemas.d.ts +4 -1879
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +4 -755
- package/dist/schemas.js.map +1 -1
- package/dist/tool-utils.d.ts +0 -14
- package/dist/tool-utils.d.ts.map +1 -1
- package/dist/tool-utils.js +5 -18
- package/dist/tool-utils.js.map +1 -1
- package/dist/tools/ats.d.ts +6 -0
- package/dist/tools/ats.d.ts.map +1 -0
- package/dist/tools/ats.js +206 -0
- package/dist/tools/ats.js.map +1 -0
- package/dist/tools/attendance.d.ts +6 -0
- package/dist/tools/attendance.d.ts.map +1 -0
- package/dist/tools/attendance.js +86 -0
- package/dist/tools/attendance.js.map +1 -0
- package/dist/tools/contracts.d.ts +6 -0
- package/dist/tools/contracts.d.ts.map +1 -0
- package/dist/tools/contracts.js +63 -0
- package/dist/tools/contracts.js.map +1 -0
- package/dist/tools/documents.d.ts +6 -0
- package/dist/tools/documents.d.ts.map +1 -0
- package/dist/tools/documents.js +135 -0
- package/dist/tools/documents.js.map +1 -0
- package/dist/tools/employees.d.ts +6 -0
- package/dist/tools/employees.d.ts.map +1 -0
- package/dist/tools/employees.js +125 -0
- package/dist/tools/employees.js.map +1 -0
- package/dist/tools/index.d.ts +17 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +221 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/job-catalog.d.ts +6 -0
- package/dist/tools/job-catalog.d.ts.map +1 -0
- package/dist/tools/job-catalog.js +39 -0
- package/dist/tools/job-catalog.js.map +1 -0
- package/dist/tools/locations.d.ts +6 -0
- package/dist/tools/locations.d.ts.map +1 -0
- package/dist/tools/locations.js +93 -0
- package/dist/tools/locations.js.map +1 -0
- package/dist/tools/payroll.d.ts +6 -0
- package/dist/tools/payroll.d.ts.map +1 -0
- package/dist/tools/payroll.js +76 -0
- package/dist/tools/payroll.js.map +1 -0
- package/dist/tools/projects.d.ts +6 -0
- package/dist/tools/projects.d.ts.map +1 -0
- package/dist/tools/projects.js +203 -0
- package/dist/tools/projects.js.map +1 -0
- package/dist/tools/shared.d.ts +84 -0
- package/dist/tools/shared.d.ts.map +1 -0
- package/dist/tools/shared.js +164 -0
- package/dist/tools/shared.js.map +1 -0
- package/dist/tools/teams.d.ts +6 -0
- package/dist/tools/teams.d.ts.map +1 -0
- package/dist/tools/teams.js +81 -0
- package/dist/tools/teams.js.map +1 -0
- package/dist/tools/time-off.d.ts +6 -0
- package/dist/tools/time-off.d.ts.map +1 -0
- package/dist/tools/time-off.js +144 -0
- package/dist/tools/time-off.js.map +1 -0
- package/dist/tools/training.d.ts +6 -0
- package/dist/tools/training.d.ts.map +1 -0
- package/dist/tools/training.js +160 -0
- package/dist/tools/training.js.map +1 -0
- package/dist/tools/work-areas.d.ts +6 -0
- package/dist/tools/work-areas.d.ts.map +1 -0
- package/dist/tools/work-areas.js +85 -0
- package/dist/tools/work-areas.js.map +1 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/utils.d.ts +35 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +97 -0
- package/dist/utils.js.map +1 -1
- package/dist/write-safety.d.ts +229 -2
- package/dist/write-safety.d.ts.map +1 -1
- package/dist/write-safety.js +42 -3
- package/dist/write-safety.js.map +1 -1
- package/llms.txt +2 -2
- package/package.json +2 -2
package/dist/api.js
CHANGED
|
@@ -2,1160 +2,9 @@
|
|
|
2
2
|
* FactorialHR API Client
|
|
3
3
|
*
|
|
4
4
|
* Provides access to FactorialHR API endpoints with caching, pagination, and retry logic.
|
|
5
|
-
*/
|
|
6
|
-
import { fetchList, fetchOne, postOne, patchOne, deleteOne, postAction } from './http-client.js';
|
|
7
|
-
import { cache, cached, CACHE_TTL, CacheManager } from './cache.js';
|
|
8
|
-
import { debug } from './config.js';
|
|
9
|
-
import { buildPaginationParams, paginateResponse, sliceForPagination, } from './pagination.js';
|
|
10
|
-
import { AuditAction, auditedOperation } from './audit.js';
|
|
11
|
-
import { validateId } from './utils.js';
|
|
12
|
-
import { ENDPOINTS, endpointWithId, endpointWithAction } from './endpoints.js';
|
|
13
|
-
import { NotFoundError } from './errors.js';
|
|
14
|
-
// ============================================================================
|
|
15
|
-
// Employee endpoints
|
|
16
|
-
// ============================================================================
|
|
17
|
-
/**
|
|
18
|
-
* List all employees with optional filtering and pagination
|
|
19
|
-
*/
|
|
20
|
-
export async function listEmployees(options) {
|
|
21
|
-
const params = buildPaginationParams(options);
|
|
22
|
-
const cacheKey = CacheManager.key('employees', options);
|
|
23
|
-
// For filtered requests, we need to fetch all and filter client-side
|
|
24
|
-
// because the API doesn't reliably filter
|
|
25
|
-
if (options?.team_id || options?.location_id) {
|
|
26
|
-
const allEmployees = await cached('employees:all', () => fetchList(ENDPOINTS.employees), CACHE_TTL.employees);
|
|
27
|
-
let filtered = allEmployees;
|
|
28
|
-
// Note: team_id filtering requires fetching teams separately (not on Employee object)
|
|
29
|
-
// TODO: Implement team filtering via teams endpoint if needed
|
|
30
|
-
if (options.location_id) {
|
|
31
|
-
filtered = filtered.filter(e => e.location_id === options.location_id);
|
|
32
|
-
}
|
|
33
|
-
return sliceForPagination(filtered, params);
|
|
34
|
-
}
|
|
35
|
-
// Without filters, use pagination directly
|
|
36
|
-
const employees = await cached(cacheKey, () => fetchList(ENDPOINTS.employees, { params }), CACHE_TTL.employees);
|
|
37
|
-
return paginateResponse(employees, params.page, params.limit);
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Get a specific employee by ID
|
|
41
5
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* if the direct endpoint fails or returns no data.
|
|
45
|
-
*/
|
|
46
|
-
export async function getEmployee(id) {
|
|
47
|
-
validateId(id, 'employee');
|
|
48
|
-
// Try the direct endpoint first
|
|
49
|
-
try {
|
|
50
|
-
const employee = await cached(`employee:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.employees, id)), CACHE_TTL.employees);
|
|
51
|
-
// If we got a valid employee, return it
|
|
52
|
-
if (employee) {
|
|
53
|
-
return employee;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
catch (error) {
|
|
57
|
-
// If direct fetch fails with NotFoundError, try fallback
|
|
58
|
-
// (other errors will be re-thrown below)
|
|
59
|
-
if (!(error instanceof NotFoundError)) {
|
|
60
|
-
throw error;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
// Fallback: Fetch all employees and filter (same approach as searchEmployees)
|
|
64
|
-
// This works around Factorial API limitations with the individual employee endpoint
|
|
65
|
-
const allEmployees = await cached('employees:all', () => fetchList(ENDPOINTS.employees), CACHE_TTL.employees);
|
|
66
|
-
const employee = allEmployees.find(emp => emp.id === id);
|
|
67
|
-
if (!employee) {
|
|
68
|
-
throw new Error(`Employee with ID ${id} not found.`);
|
|
69
|
-
}
|
|
70
|
-
return employee;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Search employees by name or email
|
|
74
|
-
*/
|
|
75
|
-
export async function searchEmployees(query) {
|
|
76
|
-
if (!query || query.trim().length < 2) {
|
|
77
|
-
throw new Error('Search query must be at least 2 characters long.');
|
|
78
|
-
}
|
|
79
|
-
const allEmployees = await cached('employees:all', () => fetchList(ENDPOINTS.employees), CACHE_TTL.employees);
|
|
80
|
-
const lowerQuery = query.toLowerCase().trim();
|
|
81
|
-
return allEmployees.filter(emp => emp.full_name?.toLowerCase().includes(lowerQuery) ||
|
|
82
|
-
emp.email?.toLowerCase().includes(lowerQuery) ||
|
|
83
|
-
emp.first_name?.toLowerCase().includes(lowerQuery) ||
|
|
84
|
-
emp.last_name?.toLowerCase().includes(lowerQuery));
|
|
85
|
-
}
|
|
86
|
-
// ============================================================================
|
|
87
|
-
// Team endpoints
|
|
88
|
-
// ============================================================================
|
|
89
|
-
/**
|
|
90
|
-
* List all teams
|
|
91
|
-
*/
|
|
92
|
-
export async function listTeams(options) {
|
|
93
|
-
const params = buildPaginationParams(options);
|
|
94
|
-
const cacheKey = CacheManager.key('teams', options);
|
|
95
|
-
const teams = await cached(cacheKey, () => fetchList(ENDPOINTS.teams), CACHE_TTL.teams);
|
|
96
|
-
return sliceForPagination(teams, params);
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Get a specific team by ID
|
|
100
|
-
*/
|
|
101
|
-
export async function getTeam(id) {
|
|
102
|
-
validateId(id, 'team');
|
|
103
|
-
return cached(`team:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.teams, id)), CACHE_TTL.teams);
|
|
104
|
-
}
|
|
105
|
-
// ============================================================================
|
|
106
|
-
// Location endpoints
|
|
107
|
-
// ============================================================================
|
|
108
|
-
/**
|
|
109
|
-
* List all locations
|
|
110
|
-
*/
|
|
111
|
-
export async function listLocations(options) {
|
|
112
|
-
const params = buildPaginationParams(options);
|
|
113
|
-
const cacheKey = CacheManager.key('locations', options);
|
|
114
|
-
const locations = await cached(cacheKey, () => fetchList(ENDPOINTS.locations), CACHE_TTL.locations);
|
|
115
|
-
return sliceForPagination(locations, params);
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Get a specific location by ID
|
|
119
|
-
*/
|
|
120
|
-
export async function getLocation(id) {
|
|
121
|
-
validateId(id, 'location');
|
|
122
|
-
return cached(`location:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.locations, id)), CACHE_TTL.locations);
|
|
123
|
-
}
|
|
124
|
-
// ============================================================================
|
|
125
|
-
// Contract endpoints
|
|
126
|
-
// ============================================================================
|
|
127
|
-
/**
|
|
128
|
-
* List contracts, optionally filtered by employee ID
|
|
129
|
-
*/
|
|
130
|
-
export async function listContracts(employeeId, options) {
|
|
131
|
-
if (employeeId !== undefined) {
|
|
132
|
-
validateId(employeeId, 'employee');
|
|
133
|
-
}
|
|
134
|
-
const params = buildPaginationParams(options);
|
|
135
|
-
// Note: The API doesn't reliably filter by employee_id query param,
|
|
136
|
-
// so we fetch all contracts and filter client-side
|
|
137
|
-
const allContracts = await cached('contracts:all', () => fetchList(ENDPOINTS.contracts), CACHE_TTL.contracts);
|
|
138
|
-
const filtered = employeeId !== undefined
|
|
139
|
-
? allContracts.filter(c => c.employee_id === employeeId)
|
|
140
|
-
: allContracts;
|
|
141
|
-
return sliceForPagination(filtered, params);
|
|
142
|
-
}
|
|
143
|
-
// ============================================================================
|
|
144
|
-
// Time Off / Leave endpoints
|
|
145
|
-
// ============================================================================
|
|
146
|
-
/**
|
|
147
|
-
* List leaves with optional filtering
|
|
148
|
-
*/
|
|
149
|
-
export async function listLeaves(options) {
|
|
150
|
-
const params = buildPaginationParams(options);
|
|
151
|
-
const queryParams = {
|
|
152
|
-
page: params.page,
|
|
153
|
-
limit: params.limit,
|
|
154
|
-
};
|
|
155
|
-
if (options?.employee_id)
|
|
156
|
-
queryParams.employee_id = options.employee_id;
|
|
157
|
-
if (options?.status)
|
|
158
|
-
queryParams.status = options.status;
|
|
159
|
-
if (options?.start_on_gte)
|
|
160
|
-
queryParams.start_on_gte = options.start_on_gte;
|
|
161
|
-
if (options?.start_on_lte)
|
|
162
|
-
queryParams.start_on_lte = options.start_on_lte;
|
|
163
|
-
const leaves = await fetchList(ENDPOINTS.leaves, { params: queryParams });
|
|
164
|
-
return paginateResponse(leaves, params.page, params.limit);
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* Get a specific leave by ID
|
|
168
|
-
*/
|
|
169
|
-
export async function getLeave(id) {
|
|
170
|
-
validateId(id, 'leave');
|
|
171
|
-
return fetchOne(endpointWithId(ENDPOINTS.leaves, id));
|
|
172
|
-
}
|
|
173
|
-
/**
|
|
174
|
-
* List all leave types
|
|
175
|
-
*/
|
|
176
|
-
export async function listLeaveTypes() {
|
|
177
|
-
return cached('leave-types:all', () => fetchList(ENDPOINTS.leaveTypes), CACHE_TTL.leaves);
|
|
178
|
-
}
|
|
179
|
-
/**
|
|
180
|
-
* Get a specific leave type by ID
|
|
181
|
-
*/
|
|
182
|
-
export async function getLeaveType(id) {
|
|
183
|
-
validateId(id, 'leave type');
|
|
184
|
-
return fetchOne(endpointWithId(ENDPOINTS.leaveTypes, id));
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* List allowances with optional filtering by employee
|
|
188
|
-
*/
|
|
189
|
-
export async function listAllowances(options) {
|
|
190
|
-
const params = buildPaginationParams(options);
|
|
191
|
-
const queryParams = {
|
|
192
|
-
page: params.page,
|
|
193
|
-
limit: params.limit,
|
|
194
|
-
};
|
|
195
|
-
if (options?.employee_id)
|
|
196
|
-
queryParams.employee_id = options.employee_id;
|
|
197
|
-
const allowances = await fetchList(ENDPOINTS.allowances, { params: queryParams });
|
|
198
|
-
return paginateResponse(allowances, params.page, params.limit);
|
|
199
|
-
}
|
|
200
|
-
// ============================================================================
|
|
201
|
-
// Attendance / Shifts endpoints
|
|
202
|
-
// ============================================================================
|
|
203
|
-
/**
|
|
204
|
-
* List shifts with optional filtering
|
|
205
|
-
*/
|
|
206
|
-
export async function listShifts(options) {
|
|
207
|
-
const params = buildPaginationParams(options);
|
|
208
|
-
const queryParams = {
|
|
209
|
-
page: params.page,
|
|
210
|
-
limit: params.limit,
|
|
211
|
-
};
|
|
212
|
-
if (options?.employee_id)
|
|
213
|
-
queryParams.employee_id = options.employee_id;
|
|
214
|
-
if (options?.clock_in_gte)
|
|
215
|
-
queryParams.clock_in_gte = options.clock_in_gte;
|
|
216
|
-
if (options?.clock_in_lte)
|
|
217
|
-
queryParams.clock_in_lte = options.clock_in_lte;
|
|
218
|
-
const shifts = await fetchList(ENDPOINTS.shifts, { params: queryParams });
|
|
219
|
-
return paginateResponse(shifts, params.page, params.limit);
|
|
220
|
-
}
|
|
221
|
-
/**
|
|
222
|
-
* Get a specific shift by ID
|
|
223
|
-
*/
|
|
224
|
-
export async function getShift(id) {
|
|
225
|
-
validateId(id, 'shift');
|
|
226
|
-
return fetchOne(endpointWithId(ENDPOINTS.shifts, id));
|
|
227
|
-
}
|
|
228
|
-
// ============================================================================
|
|
229
|
-
// Document endpoints (Read-only)
|
|
230
|
-
// ============================================================================
|
|
231
|
-
/**
|
|
232
|
-
* List all folders
|
|
233
|
-
*/
|
|
234
|
-
export async function listFolders() {
|
|
235
|
-
return cached('folders:all', () => fetchList(ENDPOINTS.folders), CACHE_TTL.default);
|
|
236
|
-
}
|
|
237
|
-
/**
|
|
238
|
-
* Get a specific folder by ID
|
|
239
|
-
*/
|
|
240
|
-
export async function getFolder(id) {
|
|
241
|
-
validateId(id, 'folder');
|
|
242
|
-
return fetchOne(endpointWithId(ENDPOINTS.folders, id));
|
|
243
|
-
}
|
|
244
|
-
/**
|
|
245
|
-
* List documents with optional filtering by folder
|
|
246
|
-
*/
|
|
247
|
-
export async function listDocuments(options) {
|
|
248
|
-
const params = buildPaginationParams(options);
|
|
249
|
-
const queryParams = {
|
|
250
|
-
page: params.page,
|
|
251
|
-
limit: params.limit,
|
|
252
|
-
};
|
|
253
|
-
if (options?.folder_id)
|
|
254
|
-
queryParams.folder_id = options.folder_id;
|
|
255
|
-
// Handle employee_ids array parameter
|
|
256
|
-
// Factorial API expects: employee_ids[]=123&employee_ids[]=456
|
|
257
|
-
if (options?.employee_ids && options.employee_ids.length > 0) {
|
|
258
|
-
// We'll need to build the query string manually for array parameters
|
|
259
|
-
const employeeIdsParam = options.employee_ids.map(id => `employee_ids[]=${id}`).join('&');
|
|
260
|
-
const baseParams = new URLSearchParams(queryParams).toString();
|
|
261
|
-
const fullParams = baseParams ? `${baseParams}&${employeeIdsParam}` : employeeIdsParam;
|
|
262
|
-
// Make request with custom query string
|
|
263
|
-
const documents = await fetchList(`${ENDPOINTS.documents}?${fullParams}`);
|
|
264
|
-
debug(`listDocuments returned ${documents.length} documents`, {
|
|
265
|
-
sampleDocument: documents[0],
|
|
266
|
-
missingNames: documents.filter(d => !d.name).length,
|
|
267
|
-
});
|
|
268
|
-
return paginateResponse(documents, params.page, params.limit);
|
|
269
|
-
}
|
|
270
|
-
const documents = await fetchList(ENDPOINTS.documents, { params: queryParams });
|
|
271
|
-
debug(`listDocuments returned ${documents.length} documents`, {
|
|
272
|
-
sampleDocument: documents[0],
|
|
273
|
-
missingNames: documents.filter(d => !d.name).length,
|
|
274
|
-
});
|
|
275
|
-
return paginateResponse(documents, params.page, params.limit);
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Get a specific document by ID
|
|
279
|
-
*
|
|
280
|
-
* Note: The Factorial API's individual document endpoint (/documents/documents/{id})
|
|
281
|
-
* can be unreliable, similar to the employee endpoint. This function implements a fallback
|
|
282
|
-
* to listing all documents and filtering if the direct endpoint fails or returns no data.
|
|
283
|
-
*
|
|
284
|
-
* @param id - The document ID
|
|
285
|
-
* @returns The document object
|
|
286
|
-
* @throws Error if document is not found
|
|
287
|
-
*/
|
|
288
|
-
export async function getDocument(id) {
|
|
289
|
-
validateId(id, 'document');
|
|
290
|
-
// Try the direct endpoint first
|
|
291
|
-
try {
|
|
292
|
-
const document = await fetchOne(endpointWithId(ENDPOINTS.documents, id));
|
|
293
|
-
// If we got a valid document, return it
|
|
294
|
-
if (document) {
|
|
295
|
-
return document;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
catch (error) {
|
|
299
|
-
// If direct fetch fails with NotFoundError, try fallback
|
|
300
|
-
if (!(error instanceof NotFoundError)) {
|
|
301
|
-
throw error;
|
|
302
|
-
}
|
|
303
|
-
debug(`getDocument(${id}) - direct endpoint failed, using fallback`);
|
|
304
|
-
}
|
|
305
|
-
// Fallback: Fetch all documents and filter by ID
|
|
306
|
-
// This works around Factorial API limitations with the individual document endpoint
|
|
307
|
-
const allDocuments = await fetchList(ENDPOINTS.documents);
|
|
308
|
-
const document = allDocuments.find(doc => doc.id === id);
|
|
309
|
-
if (!document) {
|
|
310
|
-
throw new Error(`Document with ID ${id} not found.`);
|
|
311
|
-
}
|
|
312
|
-
return document;
|
|
313
|
-
}
|
|
314
|
-
// ============================================================================
|
|
315
|
-
// Job Catalog endpoints
|
|
316
|
-
// ============================================================================
|
|
317
|
-
/**
|
|
318
|
-
* List all job roles
|
|
319
|
-
*/
|
|
320
|
-
export async function listJobRoles() {
|
|
321
|
-
return cached('job-roles:all', () => fetchList(ENDPOINTS.jobRoles), CACHE_TTL.default);
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Get a specific job role by ID
|
|
325
|
-
*/
|
|
326
|
-
export async function getJobRole(id) {
|
|
327
|
-
validateId(id, 'job role');
|
|
328
|
-
return fetchOne(endpointWithId(ENDPOINTS.jobRoles, id));
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* List all job levels
|
|
332
|
-
*/
|
|
333
|
-
export async function listJobLevels() {
|
|
334
|
-
return cached('job-levels:all', () => fetchList(ENDPOINTS.jobLevels), CACHE_TTL.default);
|
|
335
|
-
}
|
|
336
|
-
/**
|
|
337
|
-
* Get a specific job level by ID
|
|
338
|
-
*/
|
|
339
|
-
export async function getJobLevel(id) {
|
|
340
|
-
validateId(id, 'job level');
|
|
341
|
-
return fetchOne(endpointWithId(ENDPOINTS.jobLevels, id));
|
|
342
|
-
}
|
|
343
|
-
// ============================================================================
|
|
344
|
-
// Cache utilities
|
|
345
|
-
// ============================================================================
|
|
346
|
-
/**
|
|
347
|
-
* Invalidate all cached data
|
|
348
|
-
*/
|
|
349
|
-
export function clearCache() {
|
|
350
|
-
cache.clear();
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Invalidate cached data for a specific resource type
|
|
354
|
-
*/
|
|
355
|
-
export function invalidateCache(resourceType) {
|
|
356
|
-
cache.invalidatePrefix(resourceType);
|
|
357
|
-
}
|
|
358
|
-
// ============================================================================
|
|
359
|
-
// WRITE OPERATIONS - Employee endpoints
|
|
360
|
-
// ============================================================================
|
|
361
|
-
/**
|
|
362
|
-
* Create a new employee
|
|
363
|
-
*/
|
|
364
|
-
export async function createEmployee(input) {
|
|
365
|
-
return auditedOperation(AuditAction.CREATE, 'employee', undefined, async () => {
|
|
366
|
-
const employee = await postOne(ENDPOINTS.employees, input);
|
|
367
|
-
cache.invalidatePrefix('employees');
|
|
368
|
-
return employee;
|
|
369
|
-
}, Object.fromEntries(Object.entries(input).map(([k, v]) => [k, { to: v }])));
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Update an existing employee
|
|
373
|
-
*/
|
|
374
|
-
export async function updateEmployee(id, input) {
|
|
375
|
-
validateId(id, 'employee');
|
|
376
|
-
return auditedOperation(AuditAction.UPDATE, 'employee', id, async () => {
|
|
377
|
-
const employee = await patchOne(endpointWithId(ENDPOINTS.employees, id), input);
|
|
378
|
-
cache.invalidate(`employee:${id}`);
|
|
379
|
-
cache.invalidatePrefix('employees');
|
|
380
|
-
return employee;
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
|
-
/**
|
|
384
|
-
* Terminate an employee (soft delete)
|
|
385
|
-
*/
|
|
386
|
-
export async function terminateEmployee(id, terminatedOn, reason) {
|
|
387
|
-
validateId(id, 'employee');
|
|
388
|
-
return auditedOperation(AuditAction.TERMINATE, 'employee', id, async () => {
|
|
389
|
-
const employee = await patchOne(endpointWithId(ENDPOINTS.employees, id), {
|
|
390
|
-
terminated_on: terminatedOn,
|
|
391
|
-
});
|
|
392
|
-
cache.invalidate(`employee:${id}`);
|
|
393
|
-
cache.invalidatePrefix('employees');
|
|
394
|
-
return employee;
|
|
395
|
-
}, { terminated_on: { to: terminatedOn }, reason: { to: reason } });
|
|
396
|
-
}
|
|
397
|
-
// ============================================================================
|
|
398
|
-
// WRITE OPERATIONS - Team endpoints
|
|
399
|
-
// ============================================================================
|
|
400
|
-
/**
|
|
401
|
-
* Create a new team
|
|
402
|
-
*/
|
|
403
|
-
export async function createTeam(input) {
|
|
404
|
-
return auditedOperation(AuditAction.CREATE, 'team', undefined, async () => {
|
|
405
|
-
const team = await postOne(ENDPOINTS.teams, input);
|
|
406
|
-
cache.invalidatePrefix('teams');
|
|
407
|
-
return team;
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
/**
|
|
411
|
-
* Update an existing team
|
|
412
|
-
*/
|
|
413
|
-
export async function updateTeam(id, input) {
|
|
414
|
-
validateId(id, 'team');
|
|
415
|
-
return auditedOperation(AuditAction.UPDATE, 'team', id, async () => {
|
|
416
|
-
const team = await patchOne(endpointWithId(ENDPOINTS.teams, id), input);
|
|
417
|
-
cache.invalidate(`team:${id}`);
|
|
418
|
-
cache.invalidatePrefix('teams');
|
|
419
|
-
return team;
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
/**
|
|
423
|
-
* Delete a team
|
|
424
|
-
*/
|
|
425
|
-
export async function deleteTeam(id) {
|
|
426
|
-
validateId(id, 'team');
|
|
427
|
-
return auditedOperation(AuditAction.DELETE, 'team', id, async () => {
|
|
428
|
-
await deleteOne(endpointWithId(ENDPOINTS.teams, id));
|
|
429
|
-
cache.invalidate(`team:${id}`);
|
|
430
|
-
cache.invalidatePrefix('teams');
|
|
431
|
-
});
|
|
432
|
-
}
|
|
433
|
-
// ============================================================================
|
|
434
|
-
// WRITE OPERATIONS - Location endpoints
|
|
435
|
-
// ============================================================================
|
|
436
|
-
/**
|
|
437
|
-
* Create a new location
|
|
438
|
-
*/
|
|
439
|
-
export async function createLocation(input) {
|
|
440
|
-
return auditedOperation(AuditAction.CREATE, 'location', undefined, async () => {
|
|
441
|
-
const location = await postOne(ENDPOINTS.locations, input);
|
|
442
|
-
cache.invalidatePrefix('locations');
|
|
443
|
-
return location;
|
|
444
|
-
});
|
|
445
|
-
}
|
|
446
|
-
/**
|
|
447
|
-
* Update an existing location
|
|
448
|
-
*/
|
|
449
|
-
export async function updateLocation(id, input) {
|
|
450
|
-
validateId(id, 'location');
|
|
451
|
-
return auditedOperation(AuditAction.UPDATE, 'location', id, async () => {
|
|
452
|
-
const location = await patchOne(endpointWithId(ENDPOINTS.locations, id), input);
|
|
453
|
-
cache.invalidate(`location:${id}`);
|
|
454
|
-
cache.invalidatePrefix('locations');
|
|
455
|
-
return location;
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
/**
|
|
459
|
-
* Delete a location
|
|
460
|
-
*/
|
|
461
|
-
export async function deleteLocation(id) {
|
|
462
|
-
validateId(id, 'location');
|
|
463
|
-
return auditedOperation(AuditAction.DELETE, 'location', id, async () => {
|
|
464
|
-
await deleteOne(endpointWithId(ENDPOINTS.locations, id));
|
|
465
|
-
cache.invalidate(`location:${id}`);
|
|
466
|
-
cache.invalidatePrefix('locations');
|
|
467
|
-
});
|
|
468
|
-
}
|
|
469
|
-
// ============================================================================
|
|
470
|
-
// WRITE OPERATIONS - Leave endpoints
|
|
471
|
-
// ============================================================================
|
|
472
|
-
/**
|
|
473
|
-
* Create a new leave request
|
|
474
|
-
*/
|
|
475
|
-
export async function createLeave(input) {
|
|
476
|
-
return auditedOperation(AuditAction.CREATE, 'leave', undefined, async () => {
|
|
477
|
-
const leave = await postOne(ENDPOINTS.leaves, input);
|
|
478
|
-
return leave;
|
|
479
|
-
});
|
|
480
|
-
}
|
|
481
|
-
/**
|
|
482
|
-
* Update a leave request
|
|
483
|
-
*/
|
|
484
|
-
export async function updateLeave(id, input) {
|
|
485
|
-
validateId(id, 'leave');
|
|
486
|
-
return auditedOperation(AuditAction.UPDATE, 'leave', id, async () => {
|
|
487
|
-
const leave = await patchOne(endpointWithId(ENDPOINTS.leaves, id), input);
|
|
488
|
-
return leave;
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
/**
|
|
492
|
-
* Cancel a leave request
|
|
493
|
-
*/
|
|
494
|
-
export async function cancelLeave(id) {
|
|
495
|
-
validateId(id, 'leave');
|
|
496
|
-
return auditedOperation(AuditAction.DELETE, 'leave', id, async () => {
|
|
497
|
-
await deleteOne(endpointWithId(ENDPOINTS.leaves, id));
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Approve a leave request
|
|
502
|
-
*/
|
|
503
|
-
export async function approveLeave(id, input) {
|
|
504
|
-
validateId(id, 'leave');
|
|
505
|
-
return auditedOperation(AuditAction.APPROVE, 'leave', id, async () => {
|
|
506
|
-
const leave = await postAction(endpointWithAction(ENDPOINTS.leaves, id, 'approve'), input || {});
|
|
507
|
-
return leave;
|
|
508
|
-
});
|
|
509
|
-
}
|
|
510
|
-
/**
|
|
511
|
-
* Reject a leave request
|
|
512
|
-
*/
|
|
513
|
-
export async function rejectLeave(id, input) {
|
|
514
|
-
validateId(id, 'leave');
|
|
515
|
-
return auditedOperation(AuditAction.REJECT, 'leave', id, async () => {
|
|
516
|
-
const leave = await postAction(endpointWithAction(ENDPOINTS.leaves, id, 'reject'), input || {});
|
|
517
|
-
return leave;
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
// ============================================================================
|
|
521
|
-
// WRITE OPERATIONS - Shift endpoints
|
|
522
|
-
// ============================================================================
|
|
523
|
-
/**
|
|
524
|
-
* Create a new shift
|
|
525
|
-
*/
|
|
526
|
-
export async function createShift(input) {
|
|
527
|
-
return auditedOperation(AuditAction.CREATE, 'shift', undefined, async () => {
|
|
528
|
-
const shift = await postOne(ENDPOINTS.shifts, input);
|
|
529
|
-
return shift;
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
/**
|
|
533
|
-
* Update a shift
|
|
534
|
-
*/
|
|
535
|
-
export async function updateShift(id, input) {
|
|
536
|
-
validateId(id, 'shift');
|
|
537
|
-
return auditedOperation(AuditAction.UPDATE, 'shift', id, async () => {
|
|
538
|
-
const shift = await patchOne(endpointWithId(ENDPOINTS.shifts, id), input);
|
|
539
|
-
return shift;
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
/**
|
|
543
|
-
* Delete a shift
|
|
544
|
-
*/
|
|
545
|
-
export async function deleteShift(id) {
|
|
546
|
-
validateId(id, 'shift');
|
|
547
|
-
return auditedOperation(AuditAction.DELETE, 'shift', id, async () => {
|
|
548
|
-
await deleteOne(endpointWithId(ENDPOINTS.shifts, id));
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
// ============================================================================
|
|
552
|
-
// Projects & Time Tracking - READ endpoints
|
|
553
|
-
// ============================================================================
|
|
554
|
-
/**
|
|
555
|
-
* List all projects
|
|
556
|
-
*/
|
|
557
|
-
export async function listProjects(options) {
|
|
558
|
-
const params = buildPaginationParams(options);
|
|
559
|
-
const projects = await cached(CacheManager.key('projects', options), () => fetchList(ENDPOINTS.projects), CACHE_TTL.default);
|
|
560
|
-
return sliceForPagination(projects, params);
|
|
561
|
-
}
|
|
562
|
-
/**
|
|
563
|
-
* Get a specific project by ID
|
|
564
|
-
*/
|
|
565
|
-
export async function getProject(id) {
|
|
566
|
-
validateId(id, 'project');
|
|
567
|
-
return cached(`project:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.projects, id)), CACHE_TTL.default);
|
|
568
|
-
}
|
|
569
|
-
/**
|
|
570
|
-
* List project tasks
|
|
571
|
-
*/
|
|
572
|
-
export async function listProjectTasks(projectId, options) {
|
|
573
|
-
const params = buildPaginationParams(options);
|
|
574
|
-
const queryParams = {};
|
|
575
|
-
if (projectId)
|
|
576
|
-
queryParams.project_ids = projectId;
|
|
577
|
-
const tasks = await fetchList(ENDPOINTS.projectTasks, {
|
|
578
|
-
params: queryParams,
|
|
579
|
-
});
|
|
580
|
-
return sliceForPagination(tasks, params);
|
|
581
|
-
}
|
|
582
|
-
/**
|
|
583
|
-
* Get a specific project task by ID
|
|
584
|
-
*/
|
|
585
|
-
export async function getProjectTask(id) {
|
|
586
|
-
validateId(id, 'task');
|
|
587
|
-
return fetchOne(endpointWithId(ENDPOINTS.projectTasks, id));
|
|
588
|
-
}
|
|
589
|
-
/**
|
|
590
|
-
* List project workers
|
|
591
|
-
*/
|
|
592
|
-
export async function listProjectWorkers(projectId, options) {
|
|
593
|
-
const params = buildPaginationParams(options);
|
|
594
|
-
const queryParams = {};
|
|
595
|
-
if (projectId)
|
|
596
|
-
queryParams.project_ids = projectId;
|
|
597
|
-
const workers = await fetchList(ENDPOINTS.projectWorkers, {
|
|
598
|
-
params: queryParams,
|
|
599
|
-
});
|
|
600
|
-
return sliceForPagination(workers, params);
|
|
601
|
-
}
|
|
602
|
-
/**
|
|
603
|
-
* Get a specific project worker by ID
|
|
604
|
-
*/
|
|
605
|
-
export async function getProjectWorker(id) {
|
|
606
|
-
validateId(id, 'project worker');
|
|
607
|
-
return fetchOne(endpointWithId(ENDPOINTS.projectWorkers, id));
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* List time records
|
|
611
|
-
*/
|
|
612
|
-
export async function listTimeRecords(projectWorkerId, options) {
|
|
613
|
-
const params = buildPaginationParams(options);
|
|
614
|
-
const queryParams = {};
|
|
615
|
-
if (projectWorkerId)
|
|
616
|
-
queryParams.project_workers_ids = projectWorkerId;
|
|
617
|
-
const records = await fetchList(ENDPOINTS.timeRecords, {
|
|
618
|
-
params: queryParams,
|
|
619
|
-
});
|
|
620
|
-
return sliceForPagination(records, params);
|
|
621
|
-
}
|
|
622
|
-
/**
|
|
623
|
-
* Get a specific time record by ID
|
|
624
|
-
*/
|
|
625
|
-
export async function getTimeRecord(id) {
|
|
626
|
-
validateId(id, 'time record');
|
|
627
|
-
return fetchOne(endpointWithId(ENDPOINTS.timeRecords, id));
|
|
628
|
-
}
|
|
629
|
-
// ============================================================================
|
|
630
|
-
// Projects & Time Tracking - WRITE endpoints
|
|
631
|
-
// ============================================================================
|
|
632
|
-
/**
|
|
633
|
-
* Create a new project
|
|
634
|
-
*/
|
|
635
|
-
export async function createProject(input) {
|
|
636
|
-
return auditedOperation(AuditAction.CREATE, 'project', undefined, async () => {
|
|
637
|
-
const project = await postOne(ENDPOINTS.projects, input);
|
|
638
|
-
cache.invalidatePrefix('projects');
|
|
639
|
-
return project;
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
/**
|
|
643
|
-
* Update a project
|
|
644
|
-
*/
|
|
645
|
-
export async function updateProject(id, input) {
|
|
646
|
-
validateId(id, 'project');
|
|
647
|
-
return auditedOperation(AuditAction.UPDATE, 'project', id, async () => {
|
|
648
|
-
const project = await patchOne(endpointWithId(ENDPOINTS.projects, id), input);
|
|
649
|
-
cache.invalidate(`project:${id}`);
|
|
650
|
-
cache.invalidatePrefix('projects');
|
|
651
|
-
return project;
|
|
652
|
-
});
|
|
653
|
-
}
|
|
654
|
-
/**
|
|
655
|
-
* Delete a project
|
|
656
|
-
*/
|
|
657
|
-
export async function deleteProject(id) {
|
|
658
|
-
validateId(id, 'project');
|
|
659
|
-
return auditedOperation(AuditAction.DELETE, 'project', id, async () => {
|
|
660
|
-
await deleteOne(endpointWithId(ENDPOINTS.projects, id));
|
|
661
|
-
cache.invalidate(`project:${id}`);
|
|
662
|
-
cache.invalidatePrefix('projects');
|
|
663
|
-
});
|
|
664
|
-
}
|
|
665
|
-
/**
|
|
666
|
-
* Create a project task
|
|
667
|
-
*/
|
|
668
|
-
export async function createProjectTask(input) {
|
|
669
|
-
return auditedOperation(AuditAction.CREATE, 'project_task', undefined, async () => {
|
|
670
|
-
return postOne(ENDPOINTS.projectTasks, input);
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
/**
|
|
674
|
-
* Update a project task
|
|
675
|
-
*/
|
|
676
|
-
export async function updateProjectTask(id, input) {
|
|
677
|
-
validateId(id, 'task');
|
|
678
|
-
return auditedOperation(AuditAction.UPDATE, 'project_task', id, async () => {
|
|
679
|
-
return patchOne(endpointWithId(ENDPOINTS.projectTasks, id), input);
|
|
680
|
-
});
|
|
681
|
-
}
|
|
682
|
-
/**
|
|
683
|
-
* Delete a project task
|
|
684
|
-
*/
|
|
685
|
-
export async function deleteProjectTask(id) {
|
|
686
|
-
validateId(id, 'task');
|
|
687
|
-
return auditedOperation(AuditAction.DELETE, 'project_task', id, async () => {
|
|
688
|
-
await deleteOne(endpointWithId(ENDPOINTS.projectTasks, id));
|
|
689
|
-
});
|
|
690
|
-
}
|
|
691
|
-
/**
|
|
692
|
-
* Assign a worker to a project
|
|
693
|
-
*/
|
|
694
|
-
export async function assignProjectWorker(input) {
|
|
695
|
-
return auditedOperation(AuditAction.ASSIGN, 'project_worker', undefined, async () => {
|
|
696
|
-
return postOne(ENDPOINTS.projectWorkers, input);
|
|
697
|
-
});
|
|
698
|
-
}
|
|
699
|
-
/**
|
|
700
|
-
* Remove a worker from a project
|
|
701
|
-
*/
|
|
702
|
-
export async function removeProjectWorker(id) {
|
|
703
|
-
validateId(id, 'project worker');
|
|
704
|
-
return auditedOperation(AuditAction.UNASSIGN, 'project_worker', id, async () => {
|
|
705
|
-
await deleteOne(endpointWithId(ENDPOINTS.projectWorkers, id));
|
|
706
|
-
});
|
|
707
|
-
}
|
|
708
|
-
/**
|
|
709
|
-
* Create a time record
|
|
710
|
-
*/
|
|
711
|
-
export async function createTimeRecord(input) {
|
|
712
|
-
return auditedOperation(AuditAction.CREATE, 'time_record', undefined, async () => {
|
|
713
|
-
return postOne(ENDPOINTS.timeRecords, input);
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
/**
|
|
717
|
-
* Update a time record
|
|
718
|
-
*/
|
|
719
|
-
export async function updateTimeRecord(id, input) {
|
|
720
|
-
validateId(id, 'time record');
|
|
721
|
-
return auditedOperation(AuditAction.UPDATE, 'time_record', id, async () => {
|
|
722
|
-
return patchOne(endpointWithId(ENDPOINTS.timeRecords, id), input);
|
|
723
|
-
});
|
|
724
|
-
}
|
|
725
|
-
/**
|
|
726
|
-
* Delete a time record
|
|
727
|
-
*/
|
|
728
|
-
export async function deleteTimeRecord(id) {
|
|
729
|
-
validateId(id, 'time record');
|
|
730
|
-
return auditedOperation(AuditAction.DELETE, 'time_record', id, async () => {
|
|
731
|
-
await deleteOne(endpointWithId(ENDPOINTS.timeRecords, id));
|
|
732
|
-
});
|
|
733
|
-
}
|
|
734
|
-
// ============================================================================
|
|
735
|
-
// Training & Development - READ endpoints
|
|
736
|
-
// ============================================================================
|
|
737
|
-
/**
|
|
738
|
-
* List all trainings
|
|
739
|
-
*/
|
|
740
|
-
export async function listTrainings(options) {
|
|
741
|
-
const params = buildPaginationParams(options);
|
|
742
|
-
const trainings = await cached(CacheManager.key('trainings', options), () => fetchList(ENDPOINTS.trainings), CACHE_TTL.default);
|
|
743
|
-
return sliceForPagination(trainings, params);
|
|
744
|
-
}
|
|
745
|
-
/**
|
|
746
|
-
* Get a specific training by ID
|
|
747
|
-
*/
|
|
748
|
-
export async function getTraining(id) {
|
|
749
|
-
validateId(id, 'training');
|
|
750
|
-
return cached(`training:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.trainings, id)), CACHE_TTL.default);
|
|
751
|
-
}
|
|
752
|
-
/**
|
|
753
|
-
* List training sessions
|
|
754
|
-
*/
|
|
755
|
-
export async function listTrainingSessions(trainingId, options) {
|
|
756
|
-
const params = buildPaginationParams(options);
|
|
757
|
-
const queryParams = {};
|
|
758
|
-
if (trainingId)
|
|
759
|
-
queryParams.training_id = trainingId;
|
|
760
|
-
const sessions = await fetchList(ENDPOINTS.trainingSessions, {
|
|
761
|
-
params: queryParams,
|
|
762
|
-
});
|
|
763
|
-
return sliceForPagination(sessions, params);
|
|
764
|
-
}
|
|
765
|
-
/**
|
|
766
|
-
* Get a specific training session by ID
|
|
767
|
-
*/
|
|
768
|
-
export async function getTrainingSession(id) {
|
|
769
|
-
validateId(id, 'session');
|
|
770
|
-
return fetchOne(endpointWithId(ENDPOINTS.trainingSessions, id));
|
|
771
|
-
}
|
|
772
|
-
/**
|
|
773
|
-
* List training enrollments
|
|
774
|
-
*/
|
|
775
|
-
export async function listTrainingEnrollments(trainingId, options) {
|
|
776
|
-
const params = buildPaginationParams(options);
|
|
777
|
-
const queryParams = {};
|
|
778
|
-
if (trainingId)
|
|
779
|
-
queryParams.training_id = trainingId;
|
|
780
|
-
const enrollments = await fetchList(ENDPOINTS.trainingMemberships, {
|
|
781
|
-
params: queryParams,
|
|
782
|
-
});
|
|
783
|
-
return sliceForPagination(enrollments, params);
|
|
784
|
-
}
|
|
785
|
-
/**
|
|
786
|
-
* Get a specific training enrollment by ID
|
|
787
|
-
*/
|
|
788
|
-
export async function getTrainingEnrollment(id) {
|
|
789
|
-
validateId(id, 'enrollment');
|
|
790
|
-
return fetchOne(endpointWithId(ENDPOINTS.trainingMemberships, id));
|
|
791
|
-
}
|
|
792
|
-
// ============================================================================
|
|
793
|
-
// Training & Development - WRITE endpoints
|
|
794
|
-
// ============================================================================
|
|
795
|
-
/**
|
|
796
|
-
* Create a training program
|
|
797
|
-
*/
|
|
798
|
-
export async function createTraining(input) {
|
|
799
|
-
return auditedOperation(AuditAction.CREATE, 'training', undefined, async () => {
|
|
800
|
-
const training = await postOne(ENDPOINTS.trainings, input);
|
|
801
|
-
cache.invalidatePrefix('trainings');
|
|
802
|
-
return training;
|
|
803
|
-
});
|
|
804
|
-
}
|
|
805
|
-
/**
|
|
806
|
-
* Update a training program
|
|
807
|
-
*/
|
|
808
|
-
export async function updateTraining(id, input) {
|
|
809
|
-
validateId(id, 'training');
|
|
810
|
-
return auditedOperation(AuditAction.UPDATE, 'training', id, async () => {
|
|
811
|
-
const training = await patchOne(endpointWithId(ENDPOINTS.trainings, id), input);
|
|
812
|
-
cache.invalidate(`training:${id}`);
|
|
813
|
-
cache.invalidatePrefix('trainings');
|
|
814
|
-
return training;
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
/**
|
|
818
|
-
* Delete a training program
|
|
819
|
-
*/
|
|
820
|
-
export async function deleteTraining(id) {
|
|
821
|
-
validateId(id, 'training');
|
|
822
|
-
return auditedOperation(AuditAction.DELETE, 'training', id, async () => {
|
|
823
|
-
await deleteOne(endpointWithId(ENDPOINTS.trainings, id));
|
|
824
|
-
cache.invalidate(`training:${id}`);
|
|
825
|
-
cache.invalidatePrefix('trainings');
|
|
826
|
-
});
|
|
827
|
-
}
|
|
828
|
-
/**
|
|
829
|
-
* Create a training session
|
|
830
|
-
*/
|
|
831
|
-
export async function createTrainingSession(input) {
|
|
832
|
-
return auditedOperation(AuditAction.CREATE, 'training_session', undefined, async () => {
|
|
833
|
-
return postOne(ENDPOINTS.trainingSessions, input);
|
|
834
|
-
});
|
|
835
|
-
}
|
|
836
|
-
/**
|
|
837
|
-
* Update a training session
|
|
838
|
-
*/
|
|
839
|
-
export async function updateTrainingSession(id, input) {
|
|
840
|
-
validateId(id, 'session');
|
|
841
|
-
return auditedOperation(AuditAction.UPDATE, 'training_session', id, async () => {
|
|
842
|
-
return patchOne(endpointWithId(ENDPOINTS.trainingSessions, id), input);
|
|
843
|
-
});
|
|
844
|
-
}
|
|
845
|
-
/**
|
|
846
|
-
* Delete a training session
|
|
847
|
-
*/
|
|
848
|
-
export async function deleteTrainingSession(id) {
|
|
849
|
-
validateId(id, 'session');
|
|
850
|
-
return auditedOperation(AuditAction.DELETE, 'training_session', id, async () => {
|
|
851
|
-
await deleteOne(endpointWithId(ENDPOINTS.trainingSessions, id));
|
|
852
|
-
});
|
|
853
|
-
}
|
|
854
|
-
/**
|
|
855
|
-
* Enroll an employee in a training
|
|
856
|
-
*/
|
|
857
|
-
export async function enrollInTraining(input) {
|
|
858
|
-
return auditedOperation(AuditAction.ASSIGN, 'training_enrollment', undefined, async () => {
|
|
859
|
-
return postOne(ENDPOINTS.trainingMemberships, input);
|
|
860
|
-
});
|
|
861
|
-
}
|
|
862
|
-
/**
|
|
863
|
-
* Remove enrollment from a training
|
|
864
|
-
*/
|
|
865
|
-
export async function unenrollFromTraining(id) {
|
|
866
|
-
validateId(id, 'enrollment');
|
|
867
|
-
return auditedOperation(AuditAction.UNASSIGN, 'training_enrollment', id, async () => {
|
|
868
|
-
await deleteOne(endpointWithId(ENDPOINTS.trainingMemberships, id));
|
|
869
|
-
});
|
|
870
|
-
}
|
|
871
|
-
// ============================================================================
|
|
872
|
-
// Work Areas - READ/WRITE endpoints
|
|
873
|
-
// ============================================================================
|
|
874
|
-
/**
|
|
875
|
-
* List all work areas
|
|
876
|
-
*/
|
|
877
|
-
export async function listWorkAreas(options) {
|
|
878
|
-
const params = buildPaginationParams(options);
|
|
879
|
-
const workAreas = await cached(CacheManager.key('work_areas', options), () => fetchList(ENDPOINTS.workAreas), CACHE_TTL.locations);
|
|
880
|
-
return sliceForPagination(workAreas, params);
|
|
881
|
-
}
|
|
882
|
-
/**
|
|
883
|
-
* Get a specific work area by ID
|
|
884
|
-
*/
|
|
885
|
-
export async function getWorkArea(id) {
|
|
886
|
-
validateId(id, 'work area');
|
|
887
|
-
return cached(`work_area:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.workAreas, id)), CACHE_TTL.locations);
|
|
888
|
-
}
|
|
889
|
-
/**
|
|
890
|
-
* Create a work area
|
|
891
|
-
*/
|
|
892
|
-
export async function createWorkArea(input) {
|
|
893
|
-
return auditedOperation(AuditAction.CREATE, 'work_area', undefined, async () => {
|
|
894
|
-
const workArea = await postOne(ENDPOINTS.workAreas, input);
|
|
895
|
-
cache.invalidatePrefix('work_areas');
|
|
896
|
-
return workArea;
|
|
897
|
-
});
|
|
898
|
-
}
|
|
899
|
-
/**
|
|
900
|
-
* Update a work area
|
|
901
|
-
*/
|
|
902
|
-
export async function updateWorkArea(id, input) {
|
|
903
|
-
validateId(id, 'work area');
|
|
904
|
-
return auditedOperation(AuditAction.UPDATE, 'work_area', id, async () => {
|
|
905
|
-
const workArea = await patchOne(endpointWithId(ENDPOINTS.workAreas, id), input);
|
|
906
|
-
cache.invalidate(`work_area:${id}`);
|
|
907
|
-
cache.invalidatePrefix('work_areas');
|
|
908
|
-
return workArea;
|
|
909
|
-
});
|
|
910
|
-
}
|
|
911
|
-
/**
|
|
912
|
-
* Archive a work area
|
|
913
|
-
*/
|
|
914
|
-
export async function archiveWorkArea(id) {
|
|
915
|
-
validateId(id, 'work area');
|
|
916
|
-
return auditedOperation(AuditAction.ARCHIVE, 'work_area', id, async () => {
|
|
917
|
-
const workArea = await postAction(endpointWithAction(ENDPOINTS.workAreas, id, 'archive'));
|
|
918
|
-
cache.invalidate(`work_area:${id}`);
|
|
919
|
-
cache.invalidatePrefix('work_areas');
|
|
920
|
-
return workArea;
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
/**
|
|
924
|
-
* Unarchive a work area
|
|
925
|
-
*/
|
|
926
|
-
export async function unarchiveWorkArea(id) {
|
|
927
|
-
validateId(id, 'work area');
|
|
928
|
-
return auditedOperation(AuditAction.UNARCHIVE, 'work_area', id, async () => {
|
|
929
|
-
const workArea = await postAction(endpointWithAction(ENDPOINTS.workAreas, id, 'unarchive'));
|
|
930
|
-
cache.invalidate(`work_area:${id}`);
|
|
931
|
-
cache.invalidatePrefix('work_areas');
|
|
932
|
-
return workArea;
|
|
933
|
-
});
|
|
934
|
-
}
|
|
935
|
-
// ============================================================================
|
|
936
|
-
// ATS (Recruiting) - READ endpoints
|
|
937
|
-
// ============================================================================
|
|
938
|
-
/**
|
|
939
|
-
* List all job postings
|
|
940
|
-
*/
|
|
941
|
-
export async function listJobPostings(options) {
|
|
942
|
-
const params = buildPaginationParams(options);
|
|
943
|
-
const postings = await cached(CacheManager.key('job_postings', options), () => fetchList(ENDPOINTS.jobPostings), CACHE_TTL.default);
|
|
944
|
-
return sliceForPagination(postings, params);
|
|
945
|
-
}
|
|
946
|
-
/**
|
|
947
|
-
* Get a specific job posting by ID
|
|
948
|
-
*/
|
|
949
|
-
export async function getJobPosting(id) {
|
|
950
|
-
validateId(id, 'job posting');
|
|
951
|
-
return cached(`job_posting:${id}`, () => fetchOne(endpointWithId(ENDPOINTS.jobPostings, id)), CACHE_TTL.default);
|
|
952
|
-
}
|
|
953
|
-
/**
|
|
954
|
-
* List all candidates
|
|
955
|
-
*/
|
|
956
|
-
export async function listCandidates(options) {
|
|
957
|
-
const params = buildPaginationParams(options);
|
|
958
|
-
const candidates = await fetchList(ENDPOINTS.candidates);
|
|
959
|
-
return sliceForPagination(candidates, params);
|
|
960
|
-
}
|
|
961
|
-
/**
|
|
962
|
-
* Get a specific candidate by ID
|
|
963
|
-
*/
|
|
964
|
-
export async function getCandidate(id) {
|
|
965
|
-
validateId(id, 'candidate');
|
|
966
|
-
return fetchOne(endpointWithId(ENDPOINTS.candidates, id));
|
|
967
|
-
}
|
|
968
|
-
/**
|
|
969
|
-
* List all applications
|
|
970
|
-
*/
|
|
971
|
-
export async function listApplications(jobPostingId, options) {
|
|
972
|
-
const params = buildPaginationParams(options);
|
|
973
|
-
const queryParams = {};
|
|
974
|
-
if (jobPostingId)
|
|
975
|
-
queryParams.job_posting_id = jobPostingId;
|
|
976
|
-
const applications = await fetchList(ENDPOINTS.applications, {
|
|
977
|
-
params: queryParams,
|
|
978
|
-
});
|
|
979
|
-
return sliceForPagination(applications, params);
|
|
980
|
-
}
|
|
981
|
-
/**
|
|
982
|
-
* Get a specific application by ID
|
|
983
|
-
*/
|
|
984
|
-
export async function getApplication(id) {
|
|
985
|
-
validateId(id, 'application');
|
|
986
|
-
return fetchOne(endpointWithId(ENDPOINTS.applications, id));
|
|
987
|
-
}
|
|
988
|
-
/**
|
|
989
|
-
* List all hiring stages
|
|
990
|
-
*/
|
|
991
|
-
export async function listHiringStages() {
|
|
992
|
-
return cached('hiring_stages:all', () => fetchList(ENDPOINTS.hiringStages), CACHE_TTL.default);
|
|
993
|
-
}
|
|
994
|
-
/**
|
|
995
|
-
* Get a specific hiring stage by ID
|
|
996
|
-
*/
|
|
997
|
-
export async function getHiringStage(id) {
|
|
998
|
-
validateId(id, 'hiring stage');
|
|
999
|
-
return fetchOne(endpointWithId(ENDPOINTS.hiringStages, id));
|
|
1000
|
-
}
|
|
1001
|
-
// ============================================================================
|
|
1002
|
-
// ATS (Recruiting) - WRITE endpoints
|
|
1003
|
-
// ============================================================================
|
|
1004
|
-
/**
|
|
1005
|
-
* Create a job posting
|
|
1006
|
-
*/
|
|
1007
|
-
export async function createJobPosting(input) {
|
|
1008
|
-
return auditedOperation(AuditAction.CREATE, 'job_posting', undefined, async () => {
|
|
1009
|
-
const posting = await postOne(ENDPOINTS.jobPostings, input);
|
|
1010
|
-
cache.invalidatePrefix('job_postings');
|
|
1011
|
-
return posting;
|
|
1012
|
-
});
|
|
1013
|
-
}
|
|
1014
|
-
/**
|
|
1015
|
-
* Update a job posting
|
|
1016
|
-
*/
|
|
1017
|
-
export async function updateJobPosting(id, input) {
|
|
1018
|
-
validateId(id, 'job posting');
|
|
1019
|
-
return auditedOperation(AuditAction.UPDATE, 'job_posting', id, async () => {
|
|
1020
|
-
const posting = await patchOne(endpointWithId(ENDPOINTS.jobPostings, id), input);
|
|
1021
|
-
cache.invalidate(`job_posting:${id}`);
|
|
1022
|
-
cache.invalidatePrefix('job_postings');
|
|
1023
|
-
return posting;
|
|
1024
|
-
});
|
|
1025
|
-
}
|
|
1026
|
-
/**
|
|
1027
|
-
* Delete a job posting
|
|
1028
|
-
*/
|
|
1029
|
-
export async function deleteJobPosting(id) {
|
|
1030
|
-
validateId(id, 'job posting');
|
|
1031
|
-
return auditedOperation(AuditAction.DELETE, 'job_posting', id, async () => {
|
|
1032
|
-
await deleteOne(endpointWithId(ENDPOINTS.jobPostings, id));
|
|
1033
|
-
cache.invalidate(`job_posting:${id}`);
|
|
1034
|
-
cache.invalidatePrefix('job_postings');
|
|
1035
|
-
});
|
|
1036
|
-
}
|
|
1037
|
-
/**
|
|
1038
|
-
* Create a candidate
|
|
1039
|
-
*/
|
|
1040
|
-
export async function createCandidate(input) {
|
|
1041
|
-
return auditedOperation(AuditAction.CREATE, 'candidate', undefined, async () => {
|
|
1042
|
-
return postOne(ENDPOINTS.candidates, input);
|
|
1043
|
-
});
|
|
1044
|
-
}
|
|
1045
|
-
/**
|
|
1046
|
-
* Update a candidate
|
|
1047
|
-
*/
|
|
1048
|
-
export async function updateCandidate(id, input) {
|
|
1049
|
-
validateId(id, 'candidate');
|
|
1050
|
-
return auditedOperation(AuditAction.UPDATE, 'candidate', id, async () => {
|
|
1051
|
-
return patchOne(endpointWithId(ENDPOINTS.candidates, id), input);
|
|
1052
|
-
});
|
|
1053
|
-
}
|
|
1054
|
-
/**
|
|
1055
|
-
* Delete a candidate
|
|
1056
|
-
*/
|
|
1057
|
-
export async function deleteCandidate(id) {
|
|
1058
|
-
validateId(id, 'candidate');
|
|
1059
|
-
return auditedOperation(AuditAction.DELETE, 'candidate', id, async () => {
|
|
1060
|
-
await deleteOne(endpointWithId(ENDPOINTS.candidates, id));
|
|
1061
|
-
});
|
|
1062
|
-
}
|
|
1063
|
-
/**
|
|
1064
|
-
* Create an application
|
|
1065
|
-
*/
|
|
1066
|
-
export async function createApplication(input) {
|
|
1067
|
-
return auditedOperation(AuditAction.CREATE, 'application', undefined, async () => {
|
|
1068
|
-
return postOne(ENDPOINTS.applications, input);
|
|
1069
|
-
});
|
|
1070
|
-
}
|
|
1071
|
-
/**
|
|
1072
|
-
* Update an application
|
|
1073
|
-
*/
|
|
1074
|
-
export async function updateApplication(id, input) {
|
|
1075
|
-
validateId(id, 'application');
|
|
1076
|
-
return auditedOperation(AuditAction.UPDATE, 'application', id, async () => {
|
|
1077
|
-
return patchOne(endpointWithId(ENDPOINTS.applications, id), input);
|
|
1078
|
-
});
|
|
1079
|
-
}
|
|
1080
|
-
/**
|
|
1081
|
-
* Delete an application
|
|
1082
|
-
*/
|
|
1083
|
-
export async function deleteApplication(id) {
|
|
1084
|
-
validateId(id, 'application');
|
|
1085
|
-
return auditedOperation(AuditAction.DELETE, 'application', id, async () => {
|
|
1086
|
-
await deleteOne(endpointWithId(ENDPOINTS.applications, id));
|
|
1087
|
-
});
|
|
1088
|
-
}
|
|
1089
|
-
/**
|
|
1090
|
-
* Advance an application to the next stage
|
|
1091
|
-
*/
|
|
1092
|
-
export async function advanceApplication(id) {
|
|
1093
|
-
validateId(id, 'application');
|
|
1094
|
-
return auditedOperation(AuditAction.UPDATE, 'application', id, async () => {
|
|
1095
|
-
return postAction(endpointWithAction(ENDPOINTS.applications, id, 'apply'));
|
|
1096
|
-
});
|
|
1097
|
-
}
|
|
1098
|
-
// ============================================================================
|
|
1099
|
-
// Payroll - READ-ONLY endpoints (sensitive data)
|
|
1100
|
-
// ============================================================================
|
|
1101
|
-
/**
|
|
1102
|
-
* List payroll supplements for an employee
|
|
1103
|
-
*/
|
|
1104
|
-
export async function listPayrollSupplements(employeeId, options) {
|
|
1105
|
-
const params = buildPaginationParams(options);
|
|
1106
|
-
const queryParams = {};
|
|
1107
|
-
if (employeeId)
|
|
1108
|
-
queryParams.employee_id = employeeId;
|
|
1109
|
-
const supplements = await fetchList(ENDPOINTS.payrollSupplements, {
|
|
1110
|
-
params: queryParams,
|
|
1111
|
-
});
|
|
1112
|
-
return sliceForPagination(supplements, params);
|
|
1113
|
-
}
|
|
1114
|
-
/**
|
|
1115
|
-
* Get a specific payroll supplement by ID
|
|
1116
|
-
*/
|
|
1117
|
-
export async function getPayrollSupplement(id) {
|
|
1118
|
-
validateId(id, 'supplement');
|
|
1119
|
-
return fetchOne(endpointWithId(ENDPOINTS.payrollSupplements, id));
|
|
1120
|
-
}
|
|
1121
|
-
/**
|
|
1122
|
-
* List tax identifiers
|
|
1123
|
-
*/
|
|
1124
|
-
export async function listTaxIdentifiers(employeeId, options) {
|
|
1125
|
-
const params = buildPaginationParams(options);
|
|
1126
|
-
const queryParams = {};
|
|
1127
|
-
if (employeeId)
|
|
1128
|
-
queryParams.employee_id = employeeId;
|
|
1129
|
-
const identifiers = await fetchList(ENDPOINTS.taxIdentifiers, {
|
|
1130
|
-
params: queryParams,
|
|
1131
|
-
});
|
|
1132
|
-
return sliceForPagination(identifiers, params);
|
|
1133
|
-
}
|
|
1134
|
-
/**
|
|
1135
|
-
* Get a specific tax identifier by ID
|
|
1136
|
-
*/
|
|
1137
|
-
export async function getTaxIdentifier(id) {
|
|
1138
|
-
validateId(id, 'tax identifier');
|
|
1139
|
-
return fetchOne(endpointWithId(ENDPOINTS.taxIdentifiers, id));
|
|
1140
|
-
}
|
|
1141
|
-
/**
|
|
1142
|
-
* List family situations
|
|
1143
|
-
*/
|
|
1144
|
-
export async function listFamilySituations(employeeId, options) {
|
|
1145
|
-
const params = buildPaginationParams(options);
|
|
1146
|
-
const queryParams = {};
|
|
1147
|
-
if (employeeId)
|
|
1148
|
-
queryParams.employee_id = employeeId;
|
|
1149
|
-
const situations = await fetchList(ENDPOINTS.familySituations, {
|
|
1150
|
-
params: queryParams,
|
|
1151
|
-
});
|
|
1152
|
-
return sliceForPagination(situations, params);
|
|
1153
|
-
}
|
|
1154
|
-
/**
|
|
1155
|
-
* Get a specific family situation by ID
|
|
6
|
+
* This file re-exports all API functions from the modular src/api/ directory.
|
|
7
|
+
* All API functions are now organized by domain for better maintainability.
|
|
1156
8
|
*/
|
|
1157
|
-
export
|
|
1158
|
-
validateId(id, 'family situation');
|
|
1159
|
-
return fetchOne(endpointWithId(ENDPOINTS.familySituations, id));
|
|
1160
|
-
}
|
|
9
|
+
export * from './api/index.js';
|
|
1161
10
|
//# sourceMappingURL=api.js.map
|