fix(timesheet): fix expense submit issue in timesheet. Fix save button missing in approval dialog.
This commit is contained in:
parent
450fc28782
commit
e8eb633810
|
|
@ -331,6 +331,8 @@ export default {
|
||||||
empty_list: 'No registered expenses',
|
empty_list: 'No registered expenses',
|
||||||
employee_comment: 'Comment',
|
employee_comment: 'Comment',
|
||||||
supervisor_comment: 'Supervisor note',
|
supervisor_comment: 'Supervisor note',
|
||||||
|
no_attachment: "no image attached",
|
||||||
|
temp_attachment_msg: "attachments are temporarily down, you can omit them from submissions and forward them to the finance department",
|
||||||
actions: {
|
actions: {
|
||||||
delete_confirm: "Delete this expense?",
|
delete_confirm: "Delete this expense?",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -331,6 +331,8 @@ export default {
|
||||||
empty_list: 'Aucun dépense enregistrée',
|
empty_list: 'Aucun dépense enregistrée',
|
||||||
employee_comment: 'Commentaire',
|
employee_comment: 'Commentaire',
|
||||||
supervisor_comment: 'Note du Superviseur',
|
supervisor_comment: 'Note du Superviseur',
|
||||||
|
no_attachment: "aucune pièce jointe",
|
||||||
|
temp_attachment_msg: "Les pièces jointes sont désactivés temporairement, vous pouvez laisser le champ vide et acheminez vos recus au département de la comptabilité",
|
||||||
actions: {
|
actions: {
|
||||||
delete_confirm: "Supprimer cette dépense?",
|
delete_confirm: "Supprimer cette dépense?",
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,9 @@
|
||||||
|
|
||||||
const requestExpenseCreationOrUpdate = async () => {
|
const requestExpenseCreationOrUpdate = async () => {
|
||||||
if (file.value)
|
if (file.value)
|
||||||
await expenses_api.upsertExpense(expenses_store.current_expense, file.value, employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL');
|
await expenses_api.upsertExpense(expenses_store.current_expense, 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');
|
||||||
|
|
||||||
expenses_store.is_showing_create_form = true;
|
expenses_store.is_showing_create_form = true;
|
||||||
expenses_store.mode = 'create';
|
expenses_store.mode = 'create';
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="column items-center q-pa-none">
|
<div class="column items-center q-pa-none">
|
||||||
|
<!-- title bar with close button -->
|
||||||
<div class="col row full-width bg-primary">
|
<div class="col row full-width bg-primary">
|
||||||
<q-item-label class="col text-h6 text-weight-bolder text-uppercase text-white q-py-sm q-px-md">
|
<q-item-label class="col text-h6 text-weight-bolder text-uppercase text-white q-py-sm q-px-md">
|
||||||
{{ $t('timesheet.expense.title') }}
|
{{ $t('timesheet.expense.title') }}
|
||||||
|
|
@ -41,6 +42,19 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- REMOVE: ONCE ATTACHMENTS ARE FULLY IMPLEMENTED -->
|
||||||
|
<div class="col-auto row bg-warning flex-center q-px-md q-py-xs full-width">
|
||||||
|
<q-icon
|
||||||
|
name="las la-exclamation-triangle"
|
||||||
|
size="md"
|
||||||
|
class="q-px-md"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<span class="text-bold text-center">
|
||||||
|
{{ $t('timesheet.expense.temp_attachment_msg') }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="col row flex-center full-width q-pt-sm q-px-md">
|
<div class="col row flex-center full-width q-pt-sm q-px-md">
|
||||||
<div class="col-auto row items-center q-px-md">
|
<div class="col-auto row items-center q-px-md">
|
||||||
<span
|
<span
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
>
|
>
|
||||||
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
import ExpenseDialogForm from 'src/modules/timesheets/components/expense-dialog-form.vue';
|
||||||
|
|
||||||
import { ref } from 'vue';
|
import { computed, ref } from 'vue';
|
||||||
import { useI18n } from 'vue-i18n';
|
import { useI18n } from 'vue-i18n';
|
||||||
import { date, Notify } from 'quasar';
|
import { date, Notify } from 'quasar';
|
||||||
import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
|
import { unwrapAndClone } from 'src/utils/unwrap-and-clone';
|
||||||
|
|
@ -28,6 +28,12 @@
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
const is_showing_update_form = ref(false);
|
const is_showing_update_form = ref(false);
|
||||||
|
|
||||||
|
// ========== computed ===================================
|
||||||
|
|
||||||
|
const attachmentButtonColor = computed(() => expense.value.attachment_name ?
|
||||||
|
(expense.value.is_approved ? 'white' : 'accent') :
|
||||||
|
'grey-5');
|
||||||
|
|
||||||
// ===================== methods =========================
|
// ===================== methods =========================
|
||||||
|
|
||||||
const requestExpenseDeletion = async () => {
|
const requestExpenseDeletion = async () => {
|
||||||
|
|
@ -46,7 +52,11 @@
|
||||||
expenses_store.current_expense = unwrapAndClone(expense.value);
|
expenses_store.current_expense = unwrapAndClone(expense.value);
|
||||||
expenses_store.current_expense.is_approved = !expenses_store.current_expense.is_approved;
|
expenses_store.current_expense.is_approved = !expenses_store.current_expense.is_approved;
|
||||||
|
|
||||||
const success = await expenses_store.upsertExpense(expenses_store.current_expense, timesheet_store.current_pay_period_overview?.email);
|
const success = await expenses_store.upsertExpense(
|
||||||
|
expenses_store.current_expense,
|
||||||
|
timesheet_store.current_pay_period_overview?.email
|
||||||
|
);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
expense.value.is_approved = !expense.value.is_approved;
|
expense.value.is_approved = !expense.value.is_approved;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -75,7 +85,6 @@
|
||||||
<div class="col-auto">
|
<div class="col-auto">
|
||||||
<q-icon
|
<q-icon
|
||||||
:name="getExpenseIcon(expense.type)"
|
:name="getExpenseIcon(expense.type)"
|
||||||
:color="expense.is_approved ? 'white' : ($q.dark.isActive ? 'white' : 'blue-grey-8')"
|
|
||||||
size="lg"
|
size="lg"
|
||||||
class="q-pr-md"
|
class="q-pr-md"
|
||||||
/>
|
/>
|
||||||
|
|
@ -117,14 +126,24 @@
|
||||||
<div class="col row items-center justify-start">
|
<div class="col row items-center justify-start">
|
||||||
<q-btn
|
<q-btn
|
||||||
push
|
push
|
||||||
:color="expense.is_approved ? 'white' : 'accent'"
|
:disable="expense.attachment_name === undefined"
|
||||||
|
:color="attachmentButtonColor"
|
||||||
:text-color="expense.is_approved ? 'accent' : 'white'"
|
:text-color="expense.is_approved ? 'accent' : 'white'"
|
||||||
class="col-auto q-px-sm q-mr-sm"
|
class="col-auto q-px-sm q-mr-sm"
|
||||||
icon="attach_file"
|
icon="attach_file"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<q-item-label class="col">
|
<q-item-label class="col">
|
||||||
attachment_name.jpg
|
<span v-if="expense.attachment_name">
|
||||||
|
{{ expense.attachment_name }}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span
|
||||||
|
v-else
|
||||||
|
class="text-italic text-blue-grey-5 text-uppercase"
|
||||||
|
>
|
||||||
|
{{ $t('timesheet.expense.no_attachment') }}
|
||||||
|
</span>
|
||||||
</q-item-label>
|
</q-item-label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@
|
||||||
if (file.value)
|
if (file.value)
|
||||||
await expenses_api.upsertExpense(
|
await expenses_api.upsertExpense(
|
||||||
expenses_store.current_expense,
|
expenses_store.current_expense,
|
||||||
file.value, employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL'
|
employeeEmail ?? auth_store.user?.email ?? 'MISSING_EMAIL',
|
||||||
|
file.value
|
||||||
);
|
);
|
||||||
|
|
||||||
emit('onUpdateClicked');
|
emit('onUpdateClicked');
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,6 @@
|
||||||
<!-- avatar type icon section -->
|
<!-- avatar type icon section -->
|
||||||
<q-icon
|
<q-icon
|
||||||
:name="getExpenseIcon(expense.type)"
|
:name="getExpenseIcon(expense.type)"
|
||||||
:color="expense.is_approved ? 'white' : ($q.dark.isActive ? 'white' : 'primary')"
|
|
||||||
size="lg"
|
size="lg"
|
||||||
class="col-auto q-pr-sm"
|
class="col-auto q-pr-sm"
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -81,13 +81,30 @@
|
||||||
<LoadingOverlay v-model="timesheet_store.is_loading" />
|
<LoadingOverlay v-model="timesheet_store.is_loading" />
|
||||||
|
|
||||||
<!-- label for approval mode to delimit that this is the timesheet -->
|
<!-- label for approval mode to delimit that this is the timesheet -->
|
||||||
<span
|
<div
|
||||||
v-if="mode === 'approval'"
|
v-if="mode === 'approval'"
|
||||||
class="col-auto text-uppercase text-bold text-h5"
|
class="col-auto row full-width q-px-xl"
|
||||||
>
|
>
|
||||||
|
<span class="col-auto text-uppercase text-bold text-h5">
|
||||||
{{ $t('timesheet.page_header') }}
|
{{ $t('timesheet.page_header') }}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<q-space />
|
||||||
|
|
||||||
|
<!-- desktop save timesheet changes button -->
|
||||||
|
<q-btn
|
||||||
|
v-if="!is_timesheets_approved && $q.screen.width > $q.screen.height"
|
||||||
|
push
|
||||||
|
rounded
|
||||||
|
:disable="timesheet_store.is_loading || has_shift_errors"
|
||||||
|
:color="timesheet_store.is_loading || has_shift_errors ? 'grey-5' : 'accent'"
|
||||||
|
icon="upload"
|
||||||
|
:label="$t('shared.label.save')"
|
||||||
|
:class="$q.platform.is.mobile && ($q.screen.width < $q.screen.height) ? 'full-width' : 'q-ml-md'"
|
||||||
|
@click="onClickSaveTimesheets"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
<!-- weekly overview -->
|
<!-- weekly overview -->
|
||||||
<div class="col-auto row q-px-lg full-width">
|
<div class="col-auto row q-px-lg full-width">
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,12 @@ export const useExpensesApi = () => {
|
||||||
const expenses_store = useExpensesStore();
|
const expenses_store = useExpensesStore();
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheet_store = useTimesheetStore();
|
||||||
|
|
||||||
const upsertExpense = async (expense: Expense, file: File, employee_email: string): Promise<string> => {
|
const upsertExpense = async (expense: Expense, employee_email: string, file?: File): Promise<string> => {
|
||||||
|
if (file) {
|
||||||
const presignedURL = expenses_store.uploadAttachment(file);
|
const presignedURL = expenses_store.uploadAttachment(file);
|
||||||
|
|
||||||
if (!presignedURL) return 'PRESIGN_FAILED';
|
if (!presignedURL) return 'PRESIGN_FAILED';
|
||||||
|
}
|
||||||
|
|
||||||
const success = await expenses_store.upsertExpense(expense, employee_email);
|
const success = await expenses_store.upsertExpense(expense, employee_email);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,31 +2,32 @@ import { useShiftStore } from "src/stores/shift-store";
|
||||||
import { useTimesheetStore } from "src/stores/timesheet-store";
|
import { useTimesheetStore } from "src/stores/timesheet-store";
|
||||||
|
|
||||||
export const useShiftApi = () => {
|
export const useShiftApi = () => {
|
||||||
const timesheet_store = useTimesheetStore();
|
const timesheetStore = useTimesheetStore();
|
||||||
const shift_store = useShiftStore();
|
const shift_store = useShiftStore();
|
||||||
|
|
||||||
const deleteShiftById = async (shift_id: number, employee_email?: string) => {
|
const deleteShiftById = async (shift_id: number, employee_email?: string) => {
|
||||||
timesheet_store.is_loading = true;
|
timesheetStore.is_loading = true;
|
||||||
const success = await shift_store.deleteShiftById(shift_id, employee_email);
|
const success = await shift_store.deleteShiftById(shift_id, employee_email);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
await timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
await timesheetStore.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
||||||
}
|
}
|
||||||
|
|
||||||
timesheet_store.is_loading = false;
|
timesheetStore.is_loading = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const saveShiftChanges = async (employee_email?: string) => {
|
const saveShiftChanges = async (employee_email?: string) => {
|
||||||
timesheet_store.is_loading = true;
|
timesheetStore.is_loading = true;
|
||||||
|
|
||||||
const update_success = await shift_store.updateShifts(employee_email);
|
const update_success = await shift_store.updateShifts(employee_email);
|
||||||
const create_success = await shift_store.createNewShifts(employee_email);
|
const create_success = await shift_store.createNewShifts(employee_email);
|
||||||
|
|
||||||
if (create_success || update_success){
|
if (create_success || update_success){
|
||||||
await timesheet_store.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
await timesheetStore.getTimesheetsByOptionalEmployeeEmail(employee_email);
|
||||||
|
await timesheetStore.getPaidTimeOffTotalsWithOptionalEmployeeEmail();
|
||||||
}
|
}
|
||||||
|
|
||||||
timesheet_store.is_loading = false;
|
timesheetStore.is_loading = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user