170 lines
5.6 KiB
TypeScript
170 lines
5.6 KiB
TypeScript
import { api } from "src/boot/axios";
|
|
import { isProxy, toRaw } from "vue";
|
|
import { normalizeExpense, validateExpenseUI } from "../../utils/expenses-validators";
|
|
import type { ExpenseType } from "../../types/expense.types";
|
|
import { ExpensesApiError } from "../../types/expense-validation.interface";
|
|
import type {
|
|
ExpensePayload,
|
|
PayPeriodExpenses,
|
|
TimesheetExpense,
|
|
UpsertExpensesBody,
|
|
UpsertExpensesResponse
|
|
} from "../../types/expense.interfaces";
|
|
|
|
/* eslint-disable */
|
|
const toPlain = <T extends object>(obj:T): T => {
|
|
const raw = isProxy(obj) ? toRaw(obj) : obj;
|
|
if( typeof (globalThis as any).structuredClone === 'function') {
|
|
return (globalThis as any).structuredClone(raw);
|
|
}
|
|
return JSON.parse(JSON.stringify(raw));
|
|
};
|
|
|
|
const normalizePayload = (expense: ExpensePayload): ExpensePayload => {
|
|
const exp = normalizeExpense(expense as unknown as TimesheetExpense);
|
|
const out: ExpensePayload = {
|
|
date: exp.date,
|
|
type: exp.type as ExpenseType,
|
|
comment: exp.comment || '',
|
|
};
|
|
if(typeof exp.amount === 'number') out.amount = exp.amount;
|
|
if(typeof exp.mileage === 'number') out.mileage = exp.mileage;
|
|
return out;
|
|
}
|
|
|
|
//GET by email, year and period no
|
|
export const getPayPeriodExpenses = async (
|
|
email: string,
|
|
pay_year: number,
|
|
pay_period_no: number
|
|
) : Promise<PayPeriodExpenses> => {
|
|
const encoded_email = encodeURIComponent(email);
|
|
const encoded_year = encodeURIComponent(String(pay_year));
|
|
const encoded_pay_period_no = encodeURIComponent(String(pay_period_no));
|
|
|
|
try {
|
|
const { data } = await api.get<PayPeriodExpenses>(`/expenses/${encoded_email}/${encoded_year}/${encoded_pay_period_no}`);
|
|
|
|
const items = Array.isArray(data.expenses) ? data.expenses.map(normalizeExpense) : [];
|
|
return {
|
|
...data,
|
|
expenses: items,
|
|
};
|
|
} catch(err:any) {
|
|
const status_code: number = err?.response?.status ?? 500;
|
|
const data = err?.response?.data ?? {};
|
|
throw new ExpensesApiError({
|
|
status_code,
|
|
error_code: data.error_code,
|
|
message: data.message || data.error || err.message,
|
|
context: data.context,
|
|
});
|
|
}
|
|
};
|
|
|
|
//PUT by email, year and period no
|
|
export const putPayPeriodExpenses = async (
|
|
email: string,
|
|
pay_year: number,
|
|
pay_period_no: number,
|
|
expenses: TimesheetExpense[]
|
|
): Promise<PayPeriodExpenses> => {
|
|
const encoded_email = encodeURIComponent(email);
|
|
const encoded_year = encodeURIComponent(String(pay_year));
|
|
const encoded_pay_period_no = encodeURIComponent(String(pay_period_no));
|
|
|
|
const plain = Array.isArray(expenses) ? expenses.map(toPlain): [];
|
|
|
|
const normalized: ExpensePayload[] = plain.map((exp) => {
|
|
const norm = normalizeExpense(exp as TimesheetExpense);
|
|
validateExpenseUI(norm, 'expense_item');
|
|
return normalizePayload(norm as unknown as ExpensePayload);
|
|
});
|
|
|
|
const body: UpsertExpensesBody = {expenses: normalized};
|
|
|
|
try {
|
|
const { data } = await api.put<UpsertExpensesResponse>(
|
|
`/expenses/${encoded_email}/${encoded_year}/${encoded_pay_period_no}`,
|
|
body,
|
|
{ headers: {'Content-Type': 'application/json'}}
|
|
);
|
|
|
|
const items = Array.isArray(data?.data?.expenses)
|
|
? data.data.expenses.map(normalizeExpense)
|
|
: [];
|
|
return {
|
|
...(data?.data ?? {
|
|
pay_period_no,
|
|
pay_year,
|
|
employee_email: email,
|
|
is_approved: false,
|
|
expenses: [],
|
|
totals: {amount: 0, mileage: 0},
|
|
}),
|
|
expenses: items,
|
|
};
|
|
} catch (err: any) {
|
|
const status_code: number = err?.response?.status ?? 500;
|
|
const data = err?.response?.data ?? {};
|
|
throw new ExpensesApiError({
|
|
status_code,
|
|
error_code: data.error_code,
|
|
message: data.message || data.error || err.message,
|
|
context: data.context,
|
|
});
|
|
}
|
|
};
|
|
|
|
export const postPayPeriodExpenses = async (
|
|
email: string,
|
|
pay_year: number,
|
|
pay_period_no: number,
|
|
new_expenses: TimesheetExpense[]
|
|
): Promise<PayPeriodExpenses> => {
|
|
const encoded_email = encodeURIComponent(email);
|
|
const encoded_year = encodeURIComponent(String(pay_year));
|
|
const encoded_pp = encodeURIComponent(String(pay_period_no));
|
|
|
|
const plain = Array.isArray(new_expenses) ? new_expenses.map(toPlain) : [];
|
|
const normalized: ExpensePayload[] = plain.map((exp) => {
|
|
const norm = normalizeExpense(exp as TimesheetExpense);
|
|
validateExpenseUI(norm, 'expense_item');
|
|
return normalizePayload(norm as unknown as ExpensePayload);
|
|
});
|
|
|
|
const body: UpsertExpensesBody = { expenses: normalized };
|
|
|
|
try {
|
|
const { data } = await api.post<UpsertExpensesResponse>(
|
|
`/expenses/${encoded_email}/${encoded_year}/${encoded_pp}`,
|
|
body,
|
|
{ headers: { 'content-type': 'application/json' } }
|
|
);
|
|
const items = Array.isArray(data?.data?.expenses)
|
|
? data.data.expenses.map(normalizeExpense)
|
|
: [];
|
|
return {
|
|
...(data?.data ?? {
|
|
pay_period_no,
|
|
pay_year,
|
|
employee_email: email,
|
|
is_approved: false,
|
|
expenses: [],
|
|
totals: { amount: 0, mileage: 0 },
|
|
}),
|
|
expenses: items,
|
|
};
|
|
} catch (err: any) {
|
|
const status_code: number = err?.response?.status ?? 500;
|
|
const data = err?.response?.data ?? {};
|
|
throw new ExpensesApiError({
|
|
status_code,
|
|
error_code: data.error_code,
|
|
message: data.message || data.error || err.message,
|
|
context: data.context,
|
|
});
|
|
}
|
|
};
|
|
|