- Database: Add Loan, LoanInstallment, PurchaseRequest, LeaveEntitlement, EmployeeContract models - Database: Extend Attendance with ZK Tico fields (sourceDeviceId, externalId, rawData) - Database: Add Employee.attendancePin for device mapping - Backend: HR admin - Loans, Purchase Requests, Leave entitlements, Employee contracts CRUD - Backend: Leave reject, bulk attendance sync (ZK Tico ready) - Backend: Employee Portal API - scoped by employeeId (loans, leaves, purchase-requests, attendance, salaries) - Frontend: Employee Portal - dashboard, loans, leave, purchase-requests, attendance, salaries - Frontend: HR Admin - new tabs for Leaves, Loans, Purchase Requests, Contracts (approve/reject) - Dashboard: Add My Portal link - No destructive schema changes; additive migrations only Made-with: Cursor
77 lines
4.4 KiB
TypeScript
77 lines
4.4 KiB
TypeScript
import { api } from '../api'
|
|
|
|
export const hrAdminAPI = {
|
|
// Leaves
|
|
getLeaves: async (params?: { employeeId?: string; status?: string; page?: number; pageSize?: number }) => {
|
|
const q = new URLSearchParams()
|
|
if (params?.employeeId) q.append('employeeId', params.employeeId)
|
|
if (params?.status) q.append('status', params.status)
|
|
if (params?.page) q.append('page', String(params.page))
|
|
if (params?.pageSize) q.append('pageSize', String(params.pageSize))
|
|
const res = await api.get(`/hr/leaves?${q}`)
|
|
return { leaves: res.data.data || [], pagination: res.data.pagination }
|
|
},
|
|
approveLeave: (id: string) => api.post(`/hr/leaves/${id}/approve`),
|
|
rejectLeave: (id: string, rejectedReason: string) => api.post(`/hr/leaves/${id}/reject`, { rejectedReason }),
|
|
|
|
// Loans
|
|
getLoans: async (params?: { employeeId?: string; status?: string; page?: number; pageSize?: number }) => {
|
|
const q = new URLSearchParams()
|
|
if (params?.employeeId) q.append('employeeId', params.employeeId)
|
|
if (params?.status) q.append('status', params.status)
|
|
if (params?.page) q.append('page', String(params.page))
|
|
if (params?.pageSize) q.append('pageSize', String(params.pageSize))
|
|
const res = await api.get(`/hr/loans?${q}`)
|
|
return { loans: res.data.data || [], pagination: res.data.pagination }
|
|
},
|
|
getLoanById: (id: string) => api.get(`/hr/loans/${id}`),
|
|
createLoan: (data: { employeeId: string; type: string; amount: number; installments?: number; reason?: string }) =>
|
|
api.post('/hr/loans', data),
|
|
approveLoan: (id: string, startDate?: string) => api.post(`/hr/loans/${id}/approve`, { startDate: startDate || new Date().toISOString().split('T')[0] }),
|
|
rejectLoan: (id: string, rejectedReason: string) => api.post(`/hr/loans/${id}/reject`, { rejectedReason }),
|
|
payInstallment: (loanId: string, installmentId: string, paidDate?: string) =>
|
|
api.post(`/hr/loans/${loanId}/pay-installment`, { installmentId, paidDate: paidDate || new Date().toISOString().split('T')[0] }),
|
|
|
|
// Purchase Requests
|
|
getPurchaseRequests: async (params?: { employeeId?: string; status?: string; page?: number; pageSize?: number }) => {
|
|
const q = new URLSearchParams()
|
|
if (params?.employeeId) q.append('employeeId', params.employeeId)
|
|
if (params?.status) q.append('status', params.status)
|
|
if (params?.page) q.append('page', String(params.page))
|
|
if (params?.pageSize) q.append('pageSize', String(params.pageSize))
|
|
const res = await api.get(`/hr/purchase-requests?${q}`)
|
|
return { purchaseRequests: res.data.data || [], pagination: res.data.pagination }
|
|
},
|
|
approvePurchaseRequest: (id: string) => api.post(`/hr/purchase-requests/${id}/approve`),
|
|
rejectPurchaseRequest: (id: string, rejectedReason: string) => api.post(`/hr/purchase-requests/${id}/reject`, { rejectedReason }),
|
|
|
|
// Leave Entitlements
|
|
getLeaveBalance: (employeeId: string, year?: number) => {
|
|
const q = year ? `?year=${year}` : ''
|
|
return api.get(`/hr/leave-balance/${employeeId}${q}`).then((r) => r.data.data)
|
|
},
|
|
getLeaveEntitlements: (params?: { employeeId?: string; year?: number }) => {
|
|
const q = new URLSearchParams()
|
|
if (params?.employeeId) q.append('employeeId', params.employeeId)
|
|
if (params?.year) q.append('year', String(params.year))
|
|
return api.get(`/hr/leave-entitlements?${q}`).then((r) => r.data.data)
|
|
},
|
|
upsertLeaveEntitlement: (data: { employeeId: string; year: number; leaveType: string; totalDays: number; carriedOver?: number; notes?: string }) =>
|
|
api.post('/hr/leave-entitlements', data),
|
|
|
|
// Employee Contracts
|
|
getContracts: async (params?: { employeeId?: string; status?: string; page?: number; pageSize?: number }) => {
|
|
const q = new URLSearchParams()
|
|
if (params?.employeeId) q.append('employeeId', params.employeeId)
|
|
if (params?.status) q.append('status', params.status)
|
|
if (params?.page) q.append('page', String(params.page))
|
|
if (params?.pageSize) q.append('pageSize', String(params.pageSize))
|
|
const res = await api.get(`/hr/contracts?${q}`)
|
|
return { contracts: res.data.data || [], pagination: res.data.pagination }
|
|
},
|
|
createContract: (data: { employeeId: string; type: string; startDate: string; endDate?: string; salary: number; documentUrl?: string; notes?: string }) =>
|
|
api.post('/hr/contracts', data),
|
|
updateContract: (id: string, data: Partial<{ type: string; endDate: string; salary: number; status: string; notes: string }>) =>
|
|
api.put(`/hr/contracts/${id}`, data),
|
|
}
|