feat(timesheet-approval): allow creation of expenses from employee details window
This commit is contained in:
parent
3156cee577
commit
67132857ac
|
|
@ -10,13 +10,18 @@
|
|||
import DetailsDialogChartExpenses from 'src/modules/timesheet-approval/components/details-dialog-chart-expenses.vue';
|
||||
import TimesheetWrapper from 'src/modules/timesheets/components/timesheet-wrapper.vue';
|
||||
import ExpenseDialogList from 'src/modules/timesheets/components/expense-dialog-list.vue';
|
||||
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
||||
import { useTimesheetApprovalApi } from '../composables/use-timesheet-approval-api';
|
||||
import { useShiftApi } from 'src/modules/timesheets/composables/use-shift-api';
|
||||
import { useExpensesStore } from 'src/stores/expense-store';
|
||||
import { Expense } from 'src/modules/timesheets/models/expense.models';
|
||||
import { date } from 'quasar';
|
||||
|
||||
// ========== state ========================================
|
||||
|
||||
const { t } = useI18n();
|
||||
const timesheetStore = useTimesheetStore();
|
||||
const expenseStore = useExpensesStore();
|
||||
const timesheetApprovalApi = useTimesheetApprovalApi();
|
||||
const shiftApi = useShiftApi();
|
||||
const isDialogOpen = ref(false);
|
||||
|
|
@ -24,11 +29,14 @@
|
|||
// ========== computed ========================================
|
||||
|
||||
const isApproved = computed(() => timesheetStore.timesheets.every(timesheet => timesheet.is_approved));
|
||||
|
||||
const approveButtonLabel = computed(() => isApproved.value ?
|
||||
t('shared.label.unlock') :
|
||||
t('shared.label.lock')
|
||||
);
|
||||
|
||||
const approveButtonIcon = computed(() => isApproved.value ? 'las la-lock' : 'las la-unlock');
|
||||
|
||||
const hasExpenses = computed(() => timesheetStore.timesheets.some(timesheet =>
|
||||
Object.values(timesheet.weekly_expenses).some(hours => hours > 0))
|
||||
);
|
||||
|
|
@ -49,6 +57,15 @@
|
|||
|
||||
const onClickSaveTimesheets = async () => {
|
||||
await shiftApi.saveShiftChanges(timesheetStore.current_pay_period_overview?.email);
|
||||
expenseStore.is_showing_create_form = false;
|
||||
}
|
||||
|
||||
const onClickExpenseCreate = () => {
|
||||
expenseStore.mode = 'create';
|
||||
if (timesheetStore.pay_period)
|
||||
expenseStore.current_expense = new Expense(timesheetStore.pay_period.period_start);
|
||||
else
|
||||
expenseStore.current_expense = new Expense(date.formatDate(new Date(), 'YYYY-MM-DD'));
|
||||
}
|
||||
</script>
|
||||
|
||||
|
|
@ -118,6 +135,7 @@
|
|||
<!-- employee pay period details using chart -->
|
||||
<div
|
||||
v-if="isDialogOpen"
|
||||
:key="hasExpenses ? 0 : 1"
|
||||
class="col-auto q-px-md no-wrap"
|
||||
:class="$q.platform.is.mobile ? 'column' : 'row'"
|
||||
>
|
||||
|
|
@ -129,12 +147,51 @@
|
|||
/>
|
||||
</div>
|
||||
|
||||
<div class="col-auto">
|
||||
<div class="col-auto column">
|
||||
<q-separator
|
||||
spaced
|
||||
size="4px"
|
||||
class="q-mx-md"
|
||||
/>
|
||||
|
||||
<ExpenseDialogList mode="approval" />
|
||||
|
||||
<q-expansion-item
|
||||
v-if="!isApproved"
|
||||
v-model="expenseStore.is_showing_create_form"
|
||||
hide-expand-icon
|
||||
:dense="!$q.platform.is.mobile"
|
||||
group="expenses"
|
||||
@show="onClickExpenseCreate()"
|
||||
header-class="bg-accent text-white q-mx-md rounded-5"
|
||||
>
|
||||
<template #header>
|
||||
<div class="row items-center">
|
||||
<q-icon
|
||||
name="add_circle_outline"
|
||||
size="md"
|
||||
class="col-auto"
|
||||
:class="expenseStore.is_showing_create_form ? 'invisible' : ''"
|
||||
/>
|
||||
|
||||
<span class="col-auto text-uppercase text-weight-bold text-h6 q-ml-xs q-mr-sm">
|
||||
{{ $t('timesheet.expense.add_expense') }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<ExpenseDialogForm :email="timesheetStore.current_pay_period_overview?.email"/>
|
||||
</q-expansion-item>
|
||||
|
||||
<q-separator
|
||||
spaced
|
||||
size="4px"
|
||||
class="q-mx-md"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- list of shifts -->
|
||||
<div class="col-auto">
|
||||
<div class="col-auto q-mt-md">
|
||||
<TimesheetWrapper
|
||||
mode="approval"
|
||||
:employee-email="timesheetStore.current_pay_period_overview?.email"
|
||||
|
|
|
|||
|
|
@ -20,6 +20,10 @@
|
|||
const expense = defineModel<Expense>({ default: new Expense(new Date().toISOString().slice(0, 10)) })
|
||||
const file = defineModel<File>('file');
|
||||
|
||||
const {email} = defineProps<{
|
||||
email?: string | undefined;
|
||||
}>();
|
||||
|
||||
const { t } = useI18n();
|
||||
const ui_store = useUiStore();
|
||||
const timesheet_store = useTimesheetStore();
|
||||
|
|
@ -60,9 +64,16 @@
|
|||
|
||||
const requestExpenseCreationOrUpdate = async () => {
|
||||
if (file.value)
|
||||
await expenses_api.upsertExpense(expenses_store.current_expense, employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL', file.value);
|
||||
await expenses_api.upsertExpense(
|
||||
expenses_store.current_expense,
|
||||
email ?? employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL',
|
||||
file.value
|
||||
);
|
||||
else
|
||||
await expenses_api.upsertExpense(expenses_store.current_expense, employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL');
|
||||
await expenses_api.upsertExpense(
|
||||
expenses_store.current_expense,
|
||||
email ?? employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL'
|
||||
);
|
||||
|
||||
expenses_store.is_showing_create_form = true;
|
||||
expenses_store.mode = 'create';
|
||||
|
|
|
|||
|
|
@ -211,7 +211,7 @@
|
|||
backdrop-filter="blur(6px)"
|
||||
>
|
||||
<div
|
||||
class="column flex-center q-pa-md bg-secondary shadow-24 rounded-10"
|
||||
class="column flex-center q-pa-md bg-dark shadow-24 rounded-10"
|
||||
style="border: 2px solid var(--q-accent);"
|
||||
>
|
||||
<span class="col-auto text-h6 text-bold text-uppercase">{{
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export const useExpensesApi = () => {
|
|||
expense.attachment_name = file.name;
|
||||
}
|
||||
}
|
||||
|
||||
console.log('employee email provided for expense: ', employee_email)
|
||||
const success = await expenses_store.upsertExpense(expense, employee_email);
|
||||
|
||||
if (success) {
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ import type { BackendResponse } from "src/modules/shared/models/backend-response
|
|||
import type { AttachmentPresignedURLResponse, Expense } from "src/modules/timesheets/models/expense.models";
|
||||
|
||||
export const ExpenseService = {
|
||||
createExpense: async (expense: Expense): Promise<{ success: boolean, data: Expense, error?: unknown }> => {
|
||||
const response = await api.post('expense/create', expense);
|
||||
createExpense: async (expense: Expense, email?: string): Promise<{ success: boolean, data: Expense, error?: unknown }> => {
|
||||
const response = await api.post(`expense/create${email ? '?employee_email=' + email : ''}`, expense);
|
||||
return response.data;
|
||||
},
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export const useExpensesStore = defineStore('expenses', () => {
|
|||
const upsertExpense = async (expense: Expense, email?: string): Promise<boolean> => {
|
||||
try {
|
||||
if (expense.id < 0) {
|
||||
const data = await ExpenseService.createExpense(expense);
|
||||
const data = await ExpenseService.createExpense(expense, email);
|
||||
return data.success;
|
||||
}
|
||||
const data = await ExpenseService.updateExpense(expense, email);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user