diff --git a/src/modules/timesheets/components/expenses/expense-crud-dialog-form.vue b/src/modules/timesheets/components/expenses/expense-crud-dialog-form.vue index ba79884..8ffeb3a 100644 --- a/src/modules/timesheets/components/expenses/expense-crud-dialog-form.vue +++ b/src/modules/timesheets/components/expenses/expense-crud-dialog-form.vue @@ -2,15 +2,16 @@ setup lang="ts" > - import type { ExpenseType, Expense } from 'src/modules/timesheets/models/expense.models'; import { ref } from 'vue'; + import { useExpensesStore } from 'src/stores/expense-store'; + import type { ExpenseType, Expense } from 'src/modules/timesheets/models/expense.models'; + const expense_store = useExpensesStore(); const files = defineModel('files'); const is_navigator_open = ref(false); //------------------ props ------------------ - defineProps<{ - + defineProps<{ type_options: { label: string; value: ExpenseType }[]; show_amount: boolean; is_readonly: boolean; @@ -35,7 +36,7 @@
{{ $t('timesheet.expense.add_expense') }} @@ -44,7 +45,7 @@ - + @@ -73,7 +74,7 @@ diff --git a/src/modules/timesheets/components/expenses/expense-crud-dialog-list.vue b/src/modules/timesheets/components/expenses/expense-crud-dialog-list.vue index b16b310..9e5f12b 100644 --- a/src/modules/timesheets/components/expenses/expense-crud-dialog-list.vue +++ b/src/modules/timesheets/components/expenses/expense-crud-dialog-list.vue @@ -2,13 +2,14 @@ import type { TimesheetExpense } from '../../types/expense.interfaces'; import { expenseTypeIcon } from '../../utils/expense.util'; /* eslint-disable */ -const props = defineProps<{ +defineProps<{ items: TimesheetExpense[]; is_readonly: boolean; }>(); -const emit = defineEmits<{ +defineEmits<{ (e: 'remove', index: number): void; + (e: 'edit' , index: number): void; }>(); @@ -36,7 +37,12 @@ const emit = defineEmits<{ - {{ expense.mileage?.toFixed(1) }} km + + {{ expense.amount?.toFixed(2) }} $ @@ -78,7 +84,20 @@ const emit = defineEmits<{ {{ expense.supervisor_comment }} - + + + + + + @@ -89,7 +108,7 @@ const emit = defineEmits<{ size="xs" color="negative" icon="close" - @click="emit('remove', index)" + @click="$emit('remove', index)" /> diff --git a/src/modules/timesheets/components/expenses/timesheet-details-expenses.vue b/src/modules/timesheets/components/expenses/timesheet-details-expenses.vue new file mode 100644 index 0000000..40ba68a --- /dev/null +++ b/src/modules/timesheets/components/expenses/timesheet-details-expenses.vue @@ -0,0 +1,267 @@ + + + \ No newline at end of file diff --git a/src/modules/timesheets/composables/api/use-expense-api.ts b/src/modules/timesheets/composables/api/use-expense-api.ts index f4aa15d..4bcc01c 100644 --- a/src/modules/timesheets/composables/api/use-expense-api.ts +++ b/src/modules/timesheets/composables/api/use-expense-api.ts @@ -1,109 +1,41 @@ -import { useTimesheetStore } from "src/stores/timesheet-store"; -import { useExpenseItems } from "src/modules/timesheets/composables/use-expense-items"; -import { normalizeExpense, validateExpenseUI } from "../../utils/expenses-validators"; -import type { ExpensesApiError } from "src/modules/timesheets/models/expense.validation"; -import type { Expense, ExpenseType, PayPeriodExpenses } from "src/modules/timesheets/models/expense.models"; +import { normalizeObject } from "src/utils/normalize-object"; +import { useExpensesStore } from "src/stores/expense-store"; +import { expense_validation_schema, type ExpensesApiError } from "src/modules/timesheets/models/expense.validation"; +import type { Expense, UpsertExpense } from "src/modules/timesheets/models/expense.models"; -const { pay_period } = useTimesheetStore(); -const expense_items = useExpenseItems(draft); +export const useExpensesApi = () => { + const expenses_store = useExpensesStore(); -//PUT by employee_email, year and period no -export const putPayPeriodExpensesByEmployeeEmail = async (employee_email: string, expenses: Expense[]): Promise => { - const encoded_email = encodeURIComponent(employee_email); - const encoded_year = encodeURIComponent(String(pay_period.pay_year)); - const encoded_pay_period_no = encodeURIComponent(String(pay_period.pay_period_no)); + const toUpsertExpense = (obj: { + old_expense?: Expense; + new_expense?: Expense; + }) => obj as UpsertExpense; - const flat_expenses = expenses.map(expenses): []; - - const normalized: Expense[] = 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( - // `/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: employee_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, + const createExpenseByEmployeeEmail = async (employee_email: string): Promise => { + const upsert_expense = toUpsertExpense({ + new_expense: normalizeObject(expenses_store.current_expense, expense_validation_schema), }); - } -}; - -export const postPayPeriodExpenses = async ( - employee_email: string, - pay_year: number, - pay_period_no: number, - new_expenses: TimesheetExpense[] -): Promise => { - const encoded_email = encodeURIComponent(employee_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( - `/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: employee_email, - is_approved: false, - expenses: [], - totals: { amount: 0, mileage: 0 }, - }), - expenses: items, + await expenses_store.upsertOrDeleteExpensesByEmployeeEmail(employee_email, upsert_expense); }; - } 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, - }); - } -}; + const updateExpenseByEmployeeEmail = async (employee_email: string): Promise => { + const upsert_expense = toUpsertExpense({ + old_expense: normalizeObject(expenses_store.initial_expense, expense_validation_schema), + new_expense: normalizeObject(expenses_store.current_expense, expense_validation_schema), + }); + await expenses_store.upsertOrDeleteExpensesByEmployeeEmail(employee_email, upsert_expense); + }; + + const deleteExpenseByEmployeeEmail = async (employee_email: string): Promise => { + const upsert_expense = toUpsertExpense({ + old_expense: normalizeObject(expenses_store.initial_expense, expense_validation_schema), + }); + await expenses_store.upsertOrDeleteExpensesByEmployeeEmail(employee_email, upsert_expense); + }; + + return { + createExpenseByEmployeeEmail, + updateExpenseByEmployeeEmail, + deleteExpenseByEmployeeEmail, + }; +}; \ No newline at end of file diff --git a/src/modules/timesheets/models/expense.validation.ts b/src/modules/timesheets/models/expense.validation.ts index 11f8aa3..5fbe65a 100644 --- a/src/modules/timesheets/models/expense.validation.ts +++ b/src/modules/timesheets/models/expense.validation.ts @@ -42,7 +42,7 @@ export class ExpensesApiError extends ApiError { } }; -export const expense_normalizer: Normalizer = { +export const expense_validation_schema: Normalizer = { date: v => String(v ?? "1970-01-01").trim(), type: v => EXPENSE_TYPE.includes(v) ? v as ExpenseType : "EXPENSES", amount: v => typeof v === "number" ? v : undefined, diff --git a/src/modules/timesheets/models/ui.models.ts b/src/modules/timesheets/models/ui.models.ts index 3cf536d..69e3b22 100644 --- a/src/modules/timesheets/models/ui.models.ts +++ b/src/modules/timesheets/models/ui.models.ts @@ -1,4 +1,6 @@ export type PayPeriodLabel = { start_date: string; end_date: string; -}; \ No newline at end of file +}; + +export type UpsertAction = 'created' | 'updated' | 'deleted'; \ No newline at end of file diff --git a/src/modules/timesheets/utils/expense.util.ts b/src/modules/timesheets/utils/expense.util.ts index 7ccbb04..b81918b 100644 --- a/src/modules/timesheets/utils/expense.util.ts +++ b/src/modules/timesheets/utils/expense.util.ts @@ -5,9 +5,9 @@ export const normExpenseType = (type: unknown): string => String(type ?? '').trim().toUpperCase(); const icon_map: Record = { - MILEAGE: 'time_to_leave', - EXPENSES: 'receipt_long', - PER_DIEM: 'hotel', + MILEAGE: 'time_to_leave', + EXPENSES: 'receipt_long', + PER_DIEM: 'hotel', PRIME_GARDE: 'admin_panel_settings', }; @@ -34,11 +34,11 @@ export const computeExpenseTotals = (items: readonly Expense[]): ExpenseTotals = export const makeExpenseRules = (t: (key: string) => string, max_comment_char: number) => { const isPresent = (val: unknown) => val !== undefined && val !== null && val !== ''; - const typeRequired = (val: unknown) => (!!val) || t('timesheet.expense.errors.type_required'); + const typeRequired = (val: unknown) => (!!val) || t('timesheet.expense.errors.type_required'); - const amountRequired = (val: unknown) => (isPresent(val)) || t('timesheet.expense.errors.amount_required_for_type'); + const amountRequired = (val: unknown) => (isPresent(val)) || t('timesheet.expense.errors.amount_required_for_type'); - const mileageRequired = (val: unknown) => (isPresent(val)) || t('timesheet.expense.errors.mileage_required_for_type'); + const mileageRequired = (val: unknown) => (isPresent(val)) || t('timesheet.expense.errors.mileage_required_for_type'); const commentRequired = (val: unknown) => (String(val ?? '').trim().length > 0) || t('timesheet.expense.errors.comment_required'); @@ -51,14 +51,4 @@ export const makeExpenseRules = (t: (key: string) => string, max_comment_char: n commentRequired, commentTooLong, }; -}; - -//------------------ saving payload ------------------ -export const buildExpenseSavePayload = (args: PayPeriodExpenses): PayPeriodExpenses => ({ - pay_period_no: args.pay_period_no, - pay_year: args.pay_year, - employee_email: args.employee_email, - is_approved: args.is_approved ?? false, - expenses: args.expenses, - totals: computeExpenseTotals(args.expenses), -}); \ No newline at end of file +}; \ No newline at end of file diff --git a/src/modules/timesheets/utils/expenses-validators.ts b/src/modules/timesheets/utils/expenses-validators.ts index c1146d1..24fd181 100644 --- a/src/modules/timesheets/utils/expenses-validators.ts +++ b/src/modules/timesheets/utils/expenses-validators.ts @@ -1,127 +1,130 @@ -import { COMMENT_MAX_LENGTH, DATE_FORMAT_PATTERN } from "src/modules/timesheets/constants/expense.constants"; -import { ExpensesValidationError } from "src/modules/timesheets/models/expense.validation"; -import { type Expense, type ExpenseType, TYPES_WITH_AMOUNT_ONLY, TYPES_WITH_MILEAGE_ONLY } from "src/modules/timesheets/models/expense.models"; +// import { COMMENT_MAX_LENGTH, DATE_FORMAT_PATTERN } from "src/modules/timesheets/constants/expense.constants"; +// import { ExpensesValidationError } from "src/modules/timesheets/models/expense.validation"; +// import { type Expense, type ExpenseType, TYPES_WITH_AMOUNT_ONLY, TYPES_WITH_MILEAGE_ONLY } from "src/modules/timesheets/models/expense.models"; -//normalization helpers -export const toNumOrUndefined = (value: unknown): number | undefined => { - if(value === undefined || value === null || (typeof value === 'string' && value.trim() === '')) return undefined; - const num = Number(value); +// //normalization helpers +// export const toNumOrUndefined = (value: unknown): number | undefined => { +// if(value === undefined || value === null || (typeof value === 'string' && value.trim() === '')) return undefined; +// const num = Number(value); - return Number.isFinite(num) ? num : undefined; -}; +// return Number.isFinite(num) ? num : undefined; +// }; -export const normalizeComment = (input?: string): string | undefined => { - if(typeof input === 'undefined' || input === null) return undefined; - const trimmed = String(input).trim(); +// export const normalizeComment = (input?: string): string | undefined => { +// if(typeof input === 'undefined' || input === null) return undefined; +// const trimmed = String(input).trim(); - return trimmed.length ? trimmed : undefined; -}; +// return trimmed.length ? trimmed : undefined; +// }; -export const normalizeType = (input: string): string => (input ?? '').trim().toUpperCase(); +// export const normalizeType = (input: string): string => (input ?? '').trim().toUpperCase(); -export const normalizeExpense = (expense: Expense): Expense => { - const comment = normalizeComment(expense.comment); - const amount = toNumOrUndefined(expense.amount); - const mileage = toNumOrUndefined(expense.mileage); +// export const normalizeExpense = (expense: Expense): Expense => { +// const comment = normalizeComment(expense.comment); +// const amount = toNumOrUndefined(expense.amount); +// const mileage = toNumOrUndefined(expense.mileage); - return { - date: (expense.date ?? '').trim(), - type: normalizeType(expense.type), - ...(amount !== undefined ? { amount } : {}), - ...(mileage !== undefined ? { mileage } : {}), - ...(comment !== undefined ? { comment } : {}), - ...(typeof expense.supervisor_comment === 'string' && expense.supervisor_comment.trim().length - ? { supervisor_comment: expense.supervisor_comment.trim() } - : {}), - ...(typeof expense.is_approved === 'boolean' ? { is_approved: expense.is_approved }: {} ), - }; -}; +// return { +// date: (expense.date ?? '').trim(), +// type: normalizeType(expense.type), +// ...(amount !== undefined ? { amount } : {}), +// ...(mileage !== undefined ? { mileage } : {}), +// ...(comment !== undefined ? { comment } : {}), +// ...(typeof expense.supervisor_comment === 'string' && expense.supervisor_comment.trim().length +// ? { supervisor_comment: expense.supervisor_comment.trim() } +// : {}), +// ...(typeof expense.is_approved === 'boolean' ? { is_approved: expense.is_approved }: {} ), +// }; +// }; -//UI validation error messages -export const validateExpenseUI = (raw: Expense, label: string = 'expense'): void => { - const expense = normalizeExpense(raw); +// //UI validation error messages +// export const validateExpenseUI = (raw: Expense, label: string = 'expense'): void => { +// const expense = normalizeExpense(raw); - //Date input validation - if(!DATE_FORMAT_PATTERN.test(expense.date)) { - throw new ExpensesValidationError({ - status_code: 400, - message: 'timesheet.expense.errors.date_required_or_invalid', - context: { [label]: expense }, - }); - } +// //Date input validation +// if(!DATE_FORMAT_PATTERN.test(expense.date)) { +// throw new ExpensesValidationError({ +// status_code: 400, +// message: 'timesheet.expense.errors.date_required_or_invalid', +// context: { [label]: expense }, +// }); +// } - //comment input validation - if(!expense.comment) { - throw new ExpensesValidationError({ - status_code: 400, - message: 'timesheet.expense.errors.comment_required', - context: { [label]: expense }, - }) - } +// //comment input validation +// if(!expense.comment) { +// throw new ExpensesValidationError({ +// status_code: 400, +// message: 'timesheet.expense.errors.comment_required', +// context: { [label]: expense }, +// }) +// } - if((expense.comment.length ?? 0) > COMMENT_MAX_LENGTH) { - throw new ExpensesValidationError({ - status_code: 400, - message: 'timesheet.expense.errors.comment_too_long', - context: { [label]: { ...expense, comment_length: expense.comment?.length } }, - }); - } +// if((expense.comment.length ?? 0) > COMMENT_MAX_LENGTH) { +// throw new ExpensesValidationError({ +// status_code: 400, +// message: 'timesheet.expense.errors.comment_too_long', +// context: { [label]: { ...expense, comment_length: expense.comment?.length } }, +// }); +// } - //amount input validation - if(expense.amount !== undefined && expense.amount <= 0) { - throw new ExpensesValidationError({ - status_code: 400, - message: 'timesheet.expense.errors.amount_must_be_positive', - context: { [label]: expense }, - }); - } +// //amount input validation +// if(expense.amount !== undefined && expense.amount <= 0) { +// throw new ExpensesValidationError({ +// status_code: 400, +// message: 'timesheet.expense.errors.amount_must_be_positive', +// context: { [label]: expense }, +// }); +// } - //mileage input validation - if(expense.mileage !== undefined && expense.mileage <= 0) { - throw new ExpensesValidationError({ - status_code: 400, - message: 'timesheet.expense.errors.mileage_must_be_positive', - context: { [label]: expense }, - }); - } +// //mileage input validation +// if(expense.mileage !== undefined && expense.mileage <= 0) { +// throw new ExpensesValidationError({ +// status_code: 400, +// message: 'timesheet.expense.errors.mileage_must_be_positive', +// context: { [label]: expense }, +// }); +// } - //cross origin amount/mileage validation - const has_amount = typeof expense.amount === 'number' && expense.amount > 0; - const has_mileage = typeof expense.mileage === 'number' && expense.mileage > 0; +// //cross origin amount/mileage validation +// const has_amount = typeof expense.amount === 'number' && expense.amount > 0; +// const has_mileage = typeof expense.mileage === 'number' && expense.mileage > 0; - if(has_amount === has_mileage) { - throw new ExpensesValidationError({ - status_code: 400, - message: 'timesheet.expense.errors.amount_xor_mileage', - context: { [label]: expense }, - }); - } +// if(has_amount === has_mileage) { +// throw new ExpensesValidationError({ +// status_code: 400, +// message: 'timesheet.expense.errors.amount_xor_mileage', +// context: { [label]: expense }, +// }); +// } - //type constraint validation - const type = expense.type as ExpenseType; - if( TYPES_WITH_MILEAGE_ONLY.includes(type) && !has_mileage ) { - throw new ExpensesValidationError({ - status_code: 400, - message: 'timesheet.expense.errors.mileage_required_for_type', - context: { [label]: expense }, - }); - } - if(TYPES_WITH_AMOUNT_ONLY.includes(type) && !has_amount) { - throw new ExpensesValidationError({ - status_code: 400, - message: 'timesheet.expense.errors.amount_required_for_type', - context: { [label]: expense }, - }); - } -}; +// //type constraint validation +// const type = expense.type as ExpenseType; +// if( TYPES_WITH_MILEAGE_ONLY.includes(type) && !has_mileage ) { +// throw new ExpensesValidationError({ +// status_code: 400, +// message: 'timesheet.expense.errors.mileage_required_for_type', +// context: { [label]: expense }, +// }); +// } +// if(TYPES_WITH_AMOUNT_ONLY.includes(type) && !has_amount) { +// throw new ExpensesValidationError({ +// status_code: 400, +// message: 'timesheet.expense.errors.amount_required_for_type', +// context: { [label]: expense }, +// }); +// } +// }; +// <<<<<<< HEAD -//totals per pay-period -export const compute_expense_totals = (items: Expense[]) => items.reduce( - (acc, raw) => { - const expense = normalizeExpense(raw); - if(typeof expense.amount === 'number' && expense.amount > 0) acc.amount += expense.amount; - if(typeof expense.mileage === 'number' && expense.mileage > 0) acc.mileage += expense.mileage; - return acc; - }, - { amount: 0, mileage: 0 } -); +// //totals per pay-period +// export const compute_expense_totals = (items: Expense[]) => items.reduce( +// (acc, raw) => { +// const expense = normalizeExpense(raw); +// if(typeof expense.amount === 'number' && expense.amount > 0) acc.amount += expense.amount; +// if(typeof expense.mileage === 'number' && expense.mileage > 0) acc.mileage += expense.mileage; +// return acc; +// }, +// { amount: 0, mileage: 0 } +// ); +// ======= +// >>>>>>> 1bdbe021facc85fb50cff6c60053278695df6bdc diff --git a/src/stores/expense-store.ts b/src/stores/expense-store.ts index f4895d6..307ccf8 100644 --- a/src/stores/expense-store.ts +++ b/src/stores/expense-store.ts @@ -1,16 +1,21 @@ import { ref } from "vue"; import { defineStore } from "pinia"; import { useTimesheetStore } from "src/stores/timesheet-store"; -import import { default_expense, default_pay_period_expenses, type Expense, type PayPeriodExpenses } from "src/modules/timesheets/models/expense.models"; import { unwrapAndClone } from "src/utils/unwrap-and-clone"; +import { timesheetService } from "src/modules/timesheets/services/timesheet-service"; +import { ExpensesApiError } from "src/modules/timesheets/models/expense.validation"; const { pay_period } = useTimesheetStore(); +const encodeData = ( email: string, year: number, period_number: number ) => { + return { email: encodeURIComponent(email), year: encodeURIComponent(year), period_number: encodeURIComponent(period_number)}; +} + export const useExpensesStore = defineStore('expenses', () => { const is_open = ref(false); const is_loading = ref(false); - const current_expenses = ref(default_pay_period_expenses); + const pay_period_expenses = ref(default_pay_period_expenses); const current_expense = ref(default_expense); const initial_expense = ref(default_expense); const error = ref(null); @@ -20,40 +25,26 @@ export const useExpensesStore = defineStore('expenses', () => { error.value = e?.message || 'Unknown error'; }; - const open = async (employee_email: string) => { + const open = async (employee_email: string): Promise => { is_open.value = true; is_loading.value = true; error.value = null; - try { - const response = await getPayPeriodExpenses(employee_email, pay_period.pay_year, pay_period.pay_period_no,); - current_expenses.value = response; - initial_expenses.value = unwrapAndClone(response); - } catch (err) { - setErrorFrom(err); - current_expenses.value = default_pay_period_expenses; - initial_expenses.value = default_pay_period_expenses; - } finally { - is_loading.value = false; - } + await getPayPeriodExpensesByEmployeeEmail(employee_email); + is_loading.value = false; } - const getPayPeriodExpensesByEmployeeEmail = async (employee_email: string): Promise => { - const encoded_email = encodeURIComponent(employee_email); - const encoded_year = encodeURIComponent(String(pay_period.pay_year)); - const encoded_pay_period_no = encodeURIComponent(String(pay_period.pay_period_no)); - + const getPayPeriodExpensesByEmployeeEmail = async (employee_email: string): Promise => { + const encoded_data = encodeData(employee_email, pay_period.pay_year, pay_period.pay_period_no); + try { - const { data } = await api.get(`/expenses/${encoded_email}/${encoded_year}/${encoded_pay_period_no}`); - - const items = Array.isArray(data.expenses) ? data.expenses.map(normalizeExpense) : []; - return { - ...data, - expenses: items, - }; + const expenses = await timesheetService.getExpensesByPayPeriodAndEmployeeEmail(encoded_data.email, encoded_data.year, encoded_data.period_number); + pay_period_expenses.value = expenses; } catch(err:any) { const status_code: number = err?.response?.status ?? 500; const data = err?.response?.data ?? {}; + error.value = data.message || data.error || err.message; + throw new ExpensesApiError({ status_code, error_code: data.error_code, @@ -63,41 +54,16 @@ export const useExpensesStore = defineStore('expenses', () => { } }; - const onSave = () => { - try { - validateAll(); - reset(); - emit('save', buildExpenseSavePayload({ - pay_period_no: pay_period.pay_period_no, - pay_year: pay_period.pay_year, - employee_email: employeeEmail, - is_approved: false, - expenses: payload(), - })); - - } catch (err: any) { - emit('error', toExpensesError(err)); - } - }; - - const onFormSubmit = async () => { - try { - await validateAnd(async () => { - addFromDraft(); - reset(); - }); - } catch (err: any) { - emit('error', toExpensesError(err)); - } - }; - - const upsertOrDeletePayPeriodExpenseByEmployeeEmail = async (employee_email: string, expenses: Expense[]) => { + const upsertOrDeleteExpensesByEmployeeEmail = async (employee_email: string, expenses: Expense[]): Promise => { is_loading.value = true; error.value = null; try { - const updated = await putPayPeriodExpenses(employee_email, pay_period.pay_year, pay_period.pay_period_no, expenses); - pay_period_expenses.value = updated; + const encoded_data = encodeData(employee_email, pay_period.pay_year, pay_period.pay_period_no); + const payload = { is_approved: false, expenses }; + + const updated_expenses = await timesheetService.upsertOrDeleteExpensesByPayPeriodAndEmployeeEmail(encoded_data.email, encoded_data.year, encoded_data.period_number, payload); + pay_period_expenses.value.expenses = updated_expenses; is_open.value = false; } catch (err) { setErrorFrom(err); @@ -114,11 +80,13 @@ export const useExpensesStore = defineStore('expenses', () => { return { is_open, is_loading, - current_expenses, - initial_expenses, + pay_period_expenses, + current_expense, + initial_expense, error, open, - upsertOrDeletePayPeriodExpenseByEmployeeEmail, + getPayPeriodExpensesByEmployeeEmail, + upsertOrDeleteExpensesByEmployeeEmail, close, }; }); \ No newline at end of file