/** * Accounting Service API client — real backend only. * Base: NEXT_PUBLIC_ACCOUNTING_API_URL (default http://localhost:8002) * Always sends Authorization + X-Tenant-ID. */ import { getStoredToken, getValidAccessToken, refreshSession } from "@/lib/auth"; const ACCOUNTING_BASE = typeof window !== "undefined" ? "/api/accounting" : process.env.ACCOUNTING_SERVICE_URL || process.env.NEXT_PUBLIC_ACCOUNTING_API_URL || "http://localhost:8002"; export class AccountingApiError extends Error { constructor( public status: number, public code: string, message: string ) { super(message); this.name = "AccountingApiError"; } } type RequestOptions = RequestInit & { tenantId: string; auth?: boolean }; async function request(path: string, options: RequestOptions): Promise { const { tenantId, auth = true, headers: customHeaders, ...init } = options; const headers = new Headers(customHeaders); headers.set("Content-Type", "application/json"); headers.set("X-Tenant-ID", tenantId); if (auth) { const token = (await getValidAccessToken()) || getStoredToken(); if (token) headers.set("Authorization", `Bearer ${token}`); } const url = path.startsWith("http") ? path : `${ACCOUNTING_BASE.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`; let res: Response; try { res = await fetch(url, { ...init, headers }); } catch (err) { const detail = err instanceof Error ? err.message : "network_error"; throw new Error( `اتصال به سرویس حسابداری برقرار نشد (${url}) — ${detail}` ); } if (res.status === 401 && auth) { const refreshed = await refreshSession(); if (refreshed) { headers.set("Authorization", `Bearer ${refreshed}`); res = await fetch(url, { ...init, headers }); } } if (!res.ok) { const body = await res.json().catch(() => ({})); throw new AccountingApiError( res.status, body?.error?.code || "unknown_error", body?.error?.message || res.statusText ); } if (res.status === 204) return undefined as T; return res.json() as Promise; } export type ChartOfAccounts = { id: string; tenant_id: string; name: string; code: string; description: string | null; is_default: boolean; is_active: boolean; created_at: string; }; export type Account = { id: string; tenant_id: string; chart_id: string; parent_id?: string | null; code: string; name: string; account_type: string; account_category: string; level: number; is_group: boolean; is_postable: boolean; status: string; description?: string | null; created_at: string; }; export type Currency = { id: string; tenant_id: string; code: string; name: string; symbol: string | null; is_base: boolean; is_active: boolean; }; export type FiscalYear = { id: string; tenant_id: string; name: string; start_date: string; end_date: string; is_current: boolean; is_closed: boolean; }; export type FiscalPeriod = { id: string; tenant_id: string; fiscal_year_id: string; name: string; period_number: number; start_date: string; end_date: string; status: string; is_current: boolean; }; export type CostCenter = { id: string; tenant_id: string; code: string; name: string; parent_id?: string | null; is_active: boolean; }; export type Project = { id: string; tenant_id: string; code: string; name: string; start_date?: string | null; end_date?: string | null; is_active: boolean; }; export type VoucherLine = { id: string; line_number: number; account_id: string; debit: string; credit: string; description: string | null; cost_center_id?: string | null; project_id?: string | null; }; export type Voucher = { id: string; tenant_id: string; fiscal_period_id: string; voucher_number: string; voucher_date: string; status: string; description: string | null; total_debit: string; total_credit: string; posted_at: string | null; lines: VoucherLine[]; }; export type LedgerBalance = { account_id: string; fiscal_period_id: string; opening_balance: string; debit_total: string; credit_total: string; closing_balance: string; current_balance: string; }; export type SetupStatus = { has_chart: boolean; has_accounts: boolean; has_currency: boolean; has_base_currency: boolean; has_fiscal_year: boolean; has_fiscal_period: boolean; has_cash_box: boolean; has_customer: boolean; has_voucher: boolean; completed_steps: number; total_steps: number; percent: number; }; export type CoaTemplate = { id: string; name: string; description: string; business_type: string; accounts: { code: string; name: string; account_type: string; account_category: string; level: number; is_group: boolean; is_postable: boolean; parent_code?: string | null; }[]; }; export type HealthResponse = { status: string; service: string; version: string; }; function qs(params?: Record) { if (!params) return ""; const sp = new URLSearchParams(); Object.entries(params).forEach(([k, v]) => { if (v !== undefined && v !== null && v !== "") sp.set(k, String(v)); }); const s = sp.toString(); return s ? `?${s}` : ""; } export const accountingApi = { health: () => fetch(`${ACCOUNTING_BASE}/health`).then((r) => r.json() as Promise), setup: { status: (tenantId: string) => request("/api/v1/setup/status", { tenantId }), }, charts: { list: (tenantId: string, page = 1, pageSize = 50) => request(`/api/v1/accounts/charts${qs({ page, page_size: pageSize })}`, { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/accounts/charts/${id}`, { tenantId }), create: ( tenantId: string, body: { name: string; code: string; description?: string; is_default?: boolean } ) => request("/api/v1/accounts/charts", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; description: string; is_default: boolean; is_active: boolean }> ) => request(`/api/v1/accounts/charts/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), archive: (tenantId: string, id: string) => request(`/api/v1/accounts/charts/${id}/archive`, { tenantId, method: "POST", }), }, templates: { list: (tenantId: string) => request("/api/v1/accounts/templates", { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/accounts/templates/${id}`, { tenantId }), import: ( tenantId: string, templateId: string, body: { chart_id?: string; chart_name?: string; chart_code?: string } ) => request(`/api/v1/accounts/templates/${templateId}/import`, { tenantId, method: "POST", body: JSON.stringify(body), }), }, accounts: { list: (tenantId: string, page = 1, pageSize = 100, chartId?: string) => request( `/api/v1/accounts${qs({ page, page_size: Math.min(pageSize, 500), chart_id: chartId })}`, { tenantId } ), get: (tenantId: string, id: string) => request(`/api/v1/accounts/${id}`, { tenantId }), create: ( tenantId: string, body: { chart_id: string; code: string; name: string; account_type: string; account_category: string; level?: number; is_group?: boolean; is_postable?: boolean; parent_id?: string | null; description?: string; } ) => request("/api/v1/accounts", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; account_type: string; account_category: string; level: number; is_group: boolean; is_postable: boolean; parent_id: string | null; description: string; status: string; }> ) => request(`/api/v1/accounts/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), archive: (tenantId: string, id: string) => request(`/api/v1/accounts/${id}/archive`, { tenantId, method: "POST" }), }, currencies: { list: (tenantId: string) => request(`/api/v1/accounts/currencies${qs({ page_size: 100 })}`, { tenantId }), create: ( tenantId: string, body: { code: string; name: string; symbol?: string; decimal_places?: number; is_base?: boolean } ) => request("/api/v1/accounts/currencies", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; symbol: string; is_base: boolean; is_active: boolean }> ) => request(`/api/v1/accounts/currencies/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), setBase: (tenantId: string, id: string) => request(`/api/v1/accounts/currencies/${id}/set-base`, { tenantId, method: "POST", }), archive: (tenantId: string, id: string) => request(`/api/v1/accounts/currencies/${id}/archive`, { tenantId, method: "POST", }), }, costCenters: { list: (tenantId: string) => request(`/api/v1/accounts/cost-centers${qs({ page_size: 100 })}`, { tenantId }), create: (tenantId: string, body: { code: string; name: string; parent_id?: string | null }) => request("/api/v1/accounts/cost-centers", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; parent_id: string | null; is_active: boolean }> ) => request(`/api/v1/accounts/cost-centers/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), archive: (tenantId: string, id: string) => request(`/api/v1/accounts/cost-centers/${id}/archive`, { tenantId, method: "POST", }), }, projects: { list: (tenantId: string) => request(`/api/v1/accounts/projects${qs({ page_size: 100 })}`, { tenantId }), create: ( tenantId: string, body: { code: string; name: string; start_date?: string; end_date?: string } ) => request("/api/v1/accounts/projects", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; start_date: string | null; end_date: string | null; is_active: boolean }> ) => request(`/api/v1/accounts/projects/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), archive: (tenantId: string, id: string) => request(`/api/v1/accounts/projects/${id}/archive`, { tenantId, method: "POST", }), }, fiscal: { listYears: (tenantId: string) => request("/api/v1/fiscal/years", { tenantId }), createYear: ( tenantId: string, body: { name: string; start_date: string; end_date: string; is_current?: boolean } ) => request("/api/v1/fiscal/years", { tenantId, method: "POST", body: JSON.stringify(body), }), updateYear: ( tenantId: string, id: string, body: Partial<{ name: string; start_date: string; end_date: string; is_current: boolean }> ) => request(`/api/v1/fiscal/years/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), setCurrentYear: (tenantId: string, id: string) => request(`/api/v1/fiscal/years/${id}/set-current`, { tenantId, method: "POST", }), closeYear: (tenantId: string, id: string) => request(`/api/v1/fiscal/years/${id}/close`, { tenantId, method: "POST" }), generatePeriods: (tenantId: string, id: string) => request(`/api/v1/fiscal/years/${id}/generate-periods`, { tenantId, method: "POST", }), listPeriods: (tenantId: string) => request("/api/v1/fiscal/periods", { tenantId }), createPeriod: ( tenantId: string, body: { fiscal_year_id: string; name: string; period_number: number; start_date: string; end_date: string; is_current?: boolean; } ) => request("/api/v1/fiscal/periods", { tenantId, method: "POST", body: JSON.stringify(body), }), updatePeriod: ( tenantId: string, id: string, body: Partial<{ name: string; start_date: string; end_date: string; is_current: boolean; status: string }> ) => request(`/api/v1/fiscal/periods/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), setCurrentPeriod: (tenantId: string, id: string) => request(`/api/v1/fiscal/periods/${id}/set-current`, { tenantId, method: "POST", }), lockPeriod: (tenantId: string, id: string) => request(`/api/v1/fiscal/periods/${id}/lock`, { tenantId, method: "POST" }), closePeriod: (tenantId: string, id: string) => request(`/api/v1/fiscal/periods/${id}/close`, { tenantId, method: "POST" }), reopenPeriod: (tenantId: string, id: string) => request(`/api/v1/fiscal/periods/${id}/reopen`, { tenantId, method: "POST" }), }, vouchers: { list: (tenantId: string, page = 1, pageSize = 50) => request(`/api/v1/posting/vouchers${qs({ page, page_size: pageSize })}`, { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/posting/vouchers/${id}`, { tenantId }), create: ( tenantId: string, body: { fiscal_period_id: string; voucher_number: string; voucher_date: string; description?: string; reference_number?: string; source_module?: string; lines: { account_id: string; debit: string; credit: string; description?: string; cost_center_id?: string | null; project_id?: string | null; }[]; } ) => request("/api/v1/posting/vouchers", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: { voucher_date?: string; description?: string; reference_number?: string; lines?: { account_id: string; debit: string; credit: string; description?: string; cost_center_id?: string | null; project_id?: string | null; }[]; } ) => request(`/api/v1/posting/vouchers/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), validate: (tenantId: string, id: string) => request(`/api/v1/posting/vouchers/${id}/validate`, { tenantId, method: "POST" }), post: (tenantId: string, id: string, source_module?: string) => request(`/api/v1/posting/vouchers/${id}/post`, { tenantId, method: "POST", body: JSON.stringify({ source_module }), }), reverse: (tenantId: string, id: string) => request(`/api/v1/posting/vouchers/${id}/reverse`, { tenantId, method: "POST", body: JSON.stringify({}), }), cancel: (tenantId: string, id: string) => request(`/api/v1/posting/vouchers/${id}/cancel`, { tenantId, method: "POST" }), auditLogs: (tenantId: string) => request< { id: string; operation: string; actor_user_id: string; voucher_number: string | null; resource_type: string; resource_id: string; created_at: string; }[] >("/api/v1/posting/audit-logs", { tenantId }), }, ledger: { balances: (tenantId: string, fiscalPeriodId: string) => request( `/api/v1/ledger/balances${qs({ fiscal_period_id: fiscalPeriodId })}`, { tenantId } ), trialBalance: (tenantId: string, fiscalPeriodId: string) => request<{ fiscal_period_id: string; total_debit: string; total_credit: string; difference: string; is_balanced: boolean; }>(`/api/v1/ledger/trial-balance${qs({ fiscal_period_id: fiscalPeriodId })}`, { tenantId, method: "POST", }), recalculate: (tenantId: string, fiscalPeriodId: string) => request<{ recalculated_accounts: number }>( `/api/v1/ledger/recalculate${qs({ fiscal_period_id: fiscalPeriodId })}`, { tenantId, method: "POST" } ), }, reporting: { trialBalance: (tenantId: string, fiscalPeriodId: string) => request<{ id: string; report_type: string; data: unknown }>( `/api/v1/reporting/trial-balance${qs({ fiscal_period_id: fiscalPeriodId })}`, { tenantId, method: "POST" } ), balanceSheet: (tenantId: string, fiscalPeriodId: string) => request<{ id: string; data: unknown }>( `/api/v1/reporting/balance-sheet${qs({ fiscal_period_id: fiscalPeriodId })}`, { tenantId, method: "POST" } ), incomeStatement: (tenantId: string, fiscalPeriodId: string) => request<{ id: string; data: unknown }>( `/api/v1/reporting/income-statement${qs({ fiscal_period_id: fiscalPeriodId })}`, { tenantId, method: "POST" } ), export: (tenantId: string, reportId: string, export_format: "json" | "csv" | "pdf" = "json") => request<{ id: string; format: string; file_path: string | null }>( `/api/v1/reporting/reports/${reportId}/export`, { tenantId, method: "POST", body: JSON.stringify({ export_format }) } ), }, treasury: { listCashBoxes: (tenantId: string) => request< { id: string; tenant_id: string; code: string; name: string; current_balance: string; is_active: boolean }[] >("/api/v1/treasury/cash-boxes", { tenantId }), createCashBox: ( tenantId: string, body: { code: string; name: string; opening_balance?: string } ) => request<{ id: string }>("/api/v1/treasury/cash-boxes", { tenantId, method: "POST", body: JSON.stringify(body), }), updateCashBox: (tenantId: string, id: string, body: { name?: string; is_active?: boolean }) => request<{ id: string }>(`/api/v1/treasury/cash-boxes/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), listBanks: (tenantId: string) => request<{ id: string; code: string; name: string; is_active: boolean }[]>( "/api/v1/treasury/banks", { tenantId } ), createBank: (tenantId: string, body: { code: string; name: string }) => request<{ id: string }>("/api/v1/treasury/banks", { tenantId, method: "POST", body: JSON.stringify(body), }), listBankAccounts: (tenantId: string) => request< { id: string; bank_id: string; account_number: string; iban: string | null; is_active: boolean }[] >("/api/v1/treasury/bank-accounts", { tenantId }), createBankAccount: ( tenantId: string, body: { bank_id: string; account_number: string; iban?: string } ) => request<{ id: string }>("/api/v1/treasury/bank-accounts", { tenantId, method: "POST", body: JSON.stringify(body), }), cashReceipt: ( tenantId: string, body: { cash_box_id: string; amount: string; debit_account_id: string; credit_account_id: string; description?: string; transaction_date?: string; } ) => request<{ id: string; voucher_id: string }>("/api/v1/treasury/cash-receipts", { tenantId, method: "POST", body: JSON.stringify(body), }), listCheques: (tenantId: string) => request< { id: string; cheque_number: string; amount: string; issue_date: string; due_date: string | null; status: string; is_incoming: boolean; payee: string | null; }[] >("/api/v1/treasury/cheques", { tenantId }), createCheque: ( tenantId: string, body: { cheque_number: string; amount: string; issue_date: string; due_date?: string; is_incoming?: boolean; payee?: string; bank_account_id?: string; status?: string; } ) => request<{ id: string; cheque_number: string }>("/api/v1/treasury/cheques", { tenantId, method: "POST", body: JSON.stringify(body), }), listTransfers: (tenantId: string) => request< { id: string; transfer_date: string; amount: string; from_type: string; from_id: string; to_type: string; to_id: string; description: string | null; }[] >("/api/v1/treasury/transfers", { tenantId }), createTransfer: ( tenantId: string, body: { transfer_date: string; amount: string; from_type: string; from_id: string; to_type: string; to_id: string; description?: string; } ) => request<{ id: string }>("/api/v1/treasury/transfers", { tenantId, method: "POST", body: JSON.stringify(body), }), listReceipts: (tenantId: string) => request< { id: string; receipt_number: string; receipt_date: string; amount: string; payment_method: string; description: string | null; }[] >("/api/v1/treasury/receipts", { tenantId }), createReceipt: ( tenantId: string, body: { receipt_number: string; receipt_date: string; amount: string; payment_method?: string; cash_box_id?: string; bank_account_id?: string; description?: string; } ) => request<{ id: string }>("/api/v1/treasury/receipts", { tenantId, method: "POST", body: JSON.stringify(body), }), listPayments: (tenantId: string) => request< { id: string; payment_number: string; payment_date: string; amount: string; payment_method: string; description: string | null; }[] >("/api/v1/treasury/payments", { tenantId }), createPayment: ( tenantId: string, body: { payment_number: string; payment_date: string; amount: string; payment_method?: string; cash_box_id?: string; bank_account_id?: string; description?: string; } ) => request<{ id: string }>("/api/v1/treasury/payments", { tenantId, method: "POST", body: JSON.stringify(body), }), listReconciliations: (tenantId: string) => request< { id: string; bank_account_id: string; statement_date: string; statement_balance: string; book_balance: string; difference: string; status: string; }[] >("/api/v1/treasury/reconciliations", { tenantId }), createReconciliation: ( tenantId: string, body: { bank_account_id: string; statement_date: string; statement_balance: string; book_balance: string; } ) => request<{ id: string; difference: string }>("/api/v1/treasury/reconciliations", { tenantId, method: "POST", body: JSON.stringify(body), }), }, ops: { listDocuments: (tenantId: string, module?: string, docType?: string) => { const q = new URLSearchParams(); if (module) q.set("module", module); if (docType) q.set("doc_type", docType); const qs = q.toString(); return request< { id: string; tenant_id: string; module: string; doc_type: string; number: string; doc_date: string; party_name: string | null; amount: string; status: string; description: string | null; }[] >(`/api/v1/ops/documents${qs ? `?${qs}` : ""}`, { tenantId }); }, createDocument: ( tenantId: string, body: { module: string; doc_type: string; number: string; doc_date: string; party_name?: string; party_id?: string; amount?: string; status?: string; description?: string; meta_json?: string; } ) => request<{ id: string }>("/api/v1/ops/documents", { tenantId, method: "POST", body: JSON.stringify(body), }), confirmDocument: (tenantId: string, id: string) => request<{ id: string; status: string }>(`/api/v1/ops/documents/${id}/confirm`, { tenantId, method: "POST", body: JSON.stringify({}), }), listItems: (tenantId: string) => request< { id: string; code: string; name: string; item_type: string; unit: string; quantity_on_hand: string; unit_cost: string; is_active: boolean; }[] >("/api/v1/ops/items", { tenantId }), createItem: ( tenantId: string, body: { code: string; name: string; item_type?: string; unit?: string; quantity_on_hand?: string; unit_cost?: string; } ) => request<{ id: string }>("/api/v1/ops/items", { tenantId, method: "POST", body: JSON.stringify(body), }), listWarehouses: (tenantId: string) => request<{ id: string; code: string; name: string; is_active: boolean }[]>( "/api/v1/ops/warehouses", { tenantId } ), createWarehouse: (tenantId: string, body: { code: string; name: string }) => request<{ id: string }>("/api/v1/ops/warehouses", { tenantId, method: "POST", body: JSON.stringify(body), }), }, customers: { list: (tenantId: string) => request< { id: string; tenant_id: string; code: string; name: string; outstanding_balance: string; is_active: boolean }[] >("/api/v1/ar-ap/customers", { tenantId }), get: (tenantId: string, id: string) => request<{ id: string; code: string; name: string; outstanding_balance: string; is_active: boolean; }>(`/api/v1/ar-ap/customers/${id}`, { tenantId }), create: (tenantId: string, body: { code: string; name: string; credit_limit?: string }) => request<{ id: string; code: string; name: string }>("/api/v1/ar-ap/customers", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: { name?: string; credit_limit?: string | null; is_active?: boolean } ) => request<{ id: string }>(`/api/v1/ar-ap/customers/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), aging: (tenantId: string, id: string) => request<{ current: string; days_1_30: string; days_31_60: string; days_61_90: string; days_90_plus: string; total: string; }>(`/api/v1/ar-ap/customers/${id}/aging`, { tenantId }), listInvoices: (tenantId: string, customerId?: string) => request< { id: string; customer_id: string; invoice_number: string; invoice_date: string; due_date: string | null; total_amount: string; remaining_amount: string; status: string; }[] >(`/api/v1/ar-ap/receivable-invoices${qs({ customer_id: customerId })}`, { tenantId }), createInvoice: ( tenantId: string, body: { customer_id: string; invoice_number: string; invoice_date: string; due_date?: string; total_amount: string; } ) => request<{ id: string }>("/api/v1/ar-ap/receivable-invoices", { tenantId, method: "POST", body: JSON.stringify(body), }), }, suppliers: { list: (tenantId: string) => request< { id: string; code: string; name: string; outstanding_balance: string; is_active: boolean }[] >("/api/v1/ar-ap/suppliers", { tenantId }), create: (tenantId: string, body: { code: string; name: string }) => request<{ id: string; code: string; name: string }>("/api/v1/ar-ap/suppliers", { tenantId, method: "POST", body: JSON.stringify(body), }), }, assets: { list: (tenantId: string) => request<{ id: string; code: string; name: string; status: string }[]>("/api/v1/assets/assets", { tenantId, }), listCategories: (tenantId: string) => request<{ id: string; code: string; name: string; default_useful_life_months: number }[]>( "/api/v1/assets/categories", { tenantId } ), createCategory: ( tenantId: string, body: { code: string; name: string; default_useful_life_months?: number } ) => request<{ id: string }>("/api/v1/assets/categories", { tenantId, method: "POST", body: JSON.stringify(body), }), create: ( tenantId: string, body: { code: string; name: string; category_id?: string; acquisition_cost?: string; residual_value?: string; } ) => request<{ id: string; code: string }>("/api/v1/assets/assets", { tenantId, method: "POST", body: JSON.stringify(body), }), activate: (tenantId: string, id: string) => request<{ id: string; status: string }>(`/api/v1/assets/assets/${id}/activate`, { tenantId, method: "POST", }), depreciate: ( tenantId: string, id: string, body: { expense_account_id: string; accumulated_account_id: string } ) => request<{ id: string; amount: string; voucher_id: string }>( `/api/v1/assets/assets/${id}/depreciate`, { tenantId, method: "POST", body: JSON.stringify(body) } ), schedule: (tenantId: string, id: string) => request<{ schedule: unknown[] }>(`/api/v1/assets/assets/${id}/depreciation-schedule`, { tenantId, }), }, payroll: { listEmployees: (tenantId: string) => request<{ id: string; code: string; name: string }[]>("/api/v1/payroll/employees", { tenantId, }), createEmployee: ( tenantId: string, body: { employee_code: string; first_name: string; last_name: string; base_salary?: string; department_id?: string; } ) => request<{ id: string; employee_code: string }>("/api/v1/payroll/employees", { tenantId, method: "POST", body: JSON.stringify(body), }), listDepartments: (tenantId: string) => request<{ id: string; code: string; name: string }[]>("/api/v1/payroll/departments", { tenantId, }), createDepartment: (tenantId: string, body: { code: string; name: string }) => request<{ id: string }>("/api/v1/payroll/departments", { tenantId, method: "POST", body: JSON.stringify(body), }), listPeriods: (tenantId: string) => request<{ id: string; name: string; start_date: string; end_date: string; status: string }[]>( "/api/v1/payroll/periods", { tenantId } ), createPeriod: ( tenantId: string, body: { name: string; start_date: string; end_date: string } ) => request<{ id: string }>("/api/v1/payroll/periods", { tenantId, method: "POST", body: JSON.stringify(body), }), calculate: (tenantId: string, body: { payroll_period_id: string; employee_id: string }) => request<{ id: string; gross_salary: string; net_salary: string; status: string }>( "/api/v1/payroll/calculate", { tenantId, method: "POST", body: JSON.stringify(body) } ), post: (tenantId: string, payrollId: string) => request<{ id: string; status: string; voucher_id: string }>( `/api/v1/payroll/payrolls/${payrollId}/post`, { tenantId, method: "POST", body: JSON.stringify({}) } ), }, compliance: { listAudit: (tenantId: string) => request< { id: string; action: string; resource_type: string; actor_user_id: string; created_at: string }[] >("/api/v1/compliance/audit-records", { tenantId }), listPolicies: (tenantId: string) => request<{ id: string; code: string; name: string; policy_type: string; is_active: boolean }[]>( "/api/v1/compliance/policies", { tenantId } ), createPolicy: ( tenantId: string, body: { code: string; name: string; policy_type: string; rules_config: string; country_code?: string } ) => request<{ id: string }>("/api/v1/compliance/policies", { tenantId, method: "POST", body: JSON.stringify(body), }), }, };