195 lines
7.4 KiB
Vue
195 lines
7.4 KiB
Vue
<script setup>
|
|
import { computed, ref, watch } from "vue";
|
|
import { BSkeleton } from "buefy";
|
|
|
|
import { departments as loadedDepartments } from "@/components/pagination/departmentTabs.vue";
|
|
import { SessionUser } from "@/components/session/token/SessionUser.vue";
|
|
import DepartmentDashboardOverviewNavigation from "@/views/dashboards/departmentDashboard/other/displays/DepartmentDashboardOverviewNavigation.vue";
|
|
import { finished_loading, is_latest_fetch, is_loading, next_fetch_id } from "@/views/dashboards/departmentDashboard/other/displays/DepartmentsOverviewObject.vue";
|
|
import { selected_date, selected_date_to } from "@/views/dashboards/departmentDashboard/modules/daily-report/DepartmentDailyReportObject.vue";
|
|
import { buildOutsideHoursBreakdownText, buildOutsideHoursWarningText, createEmptyOutsideHours, normalizeOutsideHours } from "@/views/dashboards/departmentDashboard/modules/daily-report/outsideHours.js";
|
|
|
|
const props = defineProps({
|
|
departments: {
|
|
type: Array,
|
|
default: [],
|
|
required: true,
|
|
},
|
|
});
|
|
|
|
const income = ref(0);
|
|
const sales = ref(0);
|
|
const transactions = ref(0);
|
|
const washes = ref(0);
|
|
const outsideHours = ref(createEmptyOutsideHours());
|
|
|
|
const identifier = "DepartmentDailyReportThisWeek";
|
|
const departmentSelectionKey = computed(() => (
|
|
Array.isArray(props.departments)
|
|
? props.departments
|
|
.map((department) => Number(department?.id ?? department))
|
|
.filter((departmentId) => departmentId > 0)
|
|
.join(",")
|
|
: ""
|
|
));
|
|
|
|
const resetSummary = () => {
|
|
income.value = 0;
|
|
sales.value = 0;
|
|
transactions.value = 0;
|
|
washes.value = 0;
|
|
outsideHours.value = createEmptyOutsideHours();
|
|
};
|
|
|
|
const getTransactionsInSelection = async () => {
|
|
if (!Array.isArray(props.departments) || props.departments.length === 0) {
|
|
resetSummary();
|
|
return;
|
|
}
|
|
|
|
const fetch_id = next_fetch_id(identifier);
|
|
const tmp = {
|
|
income: 0,
|
|
sales: 0,
|
|
transactions: 0,
|
|
washes: 0,
|
|
outsideHours: createEmptyOutsideHours(),
|
|
};
|
|
|
|
for (const department of props.departments) {
|
|
// eslint-disable-next-line no-await-in-loop
|
|
await SessionUser.objects.department_daily_reports.functions.getTransactionCount(
|
|
department,
|
|
selected_date.value,
|
|
selected_date_to.value
|
|
).then((response) => {
|
|
if (!is_latest_fetch(fetch_id, identifier)) {
|
|
finished_loading(fetch_id, identifier);
|
|
return;
|
|
}
|
|
|
|
const payload = response?.data?.data || {};
|
|
const normalizedOutsideHours = normalizeOutsideHours(payload.outside_hours);
|
|
tmp.income += Number(payload.earnings ?? 0);
|
|
tmp.sales += Number(payload.products ?? 0);
|
|
tmp.transactions += Number(payload.quantity ?? 0);
|
|
tmp.washes += Number(payload.washes ?? 0);
|
|
tmp.outsideHours.total += normalizedOutsideHours.total;
|
|
tmp.outsideHours.by_source.orders += normalizedOutsideHours.by_source.orders;
|
|
tmp.outsideHours.by_source.xlvask += normalizedOutsideHours.by_source.xlvask;
|
|
tmp.outsideHours.by_source.selfserve += normalizedOutsideHours.by_source.selfserve;
|
|
tmp.outsideHours.has_missing_opening_hours = tmp.outsideHours.has_missing_opening_hours
|
|
|| normalizedOutsideHours.has_missing_opening_hours;
|
|
tmp.outsideHours.missing_department_ids = Array.from(new Set([
|
|
...tmp.outsideHours.missing_department_ids,
|
|
...normalizedOutsideHours.missing_department_ids,
|
|
]));
|
|
});
|
|
}
|
|
|
|
if (!is_latest_fetch(fetch_id, identifier)) {
|
|
finished_loading(fetch_id, identifier);
|
|
return;
|
|
}
|
|
|
|
income.value = tmp.income;
|
|
sales.value = tmp.sales;
|
|
transactions.value = tmp.transactions;
|
|
washes.value = tmp.washes;
|
|
outsideHours.value = tmp.outsideHours;
|
|
finished_loading(fetch_id, identifier);
|
|
};
|
|
|
|
watch([() => selected_date.value, () => selected_date_to.value, departmentSelectionKey], () => {
|
|
getTransactionsInSelection();
|
|
}, { immediate: true });
|
|
</script>
|
|
|
|
<template>
|
|
<div class="columns is-multiline is-vcentered">
|
|
<div class="column is-12">
|
|
<DepartmentDashboardOverviewNavigation />
|
|
</div>
|
|
</div>
|
|
<div class="columns is-multiline is-vcentered" data-testid="overview-summary-grid">
|
|
<div class="column is-12">
|
|
<div class="columns is-multiline is-vcentered">
|
|
<div class="column is-3">
|
|
<div class="box" data-testid="overview-summary-revenue">
|
|
<p class="subtitle is-6">
|
|
{{ $t("department_reports.revenue") }} {{ SessionUser.functions.date.isToday(selected_date) && SessionUser.functions.date.isToday(selected_date_to) ? $t("department_reports.today") : "" }}
|
|
</p>
|
|
<p class="title is-4">
|
|
<template v-if="is_loading(identifier)">
|
|
<b-skeleton :width="'100%'" :height="'1em'" />
|
|
</template>
|
|
<template v-else>
|
|
{{ SessionUser.functions.currency.toLocal(income) }}
|
|
</template>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="column is-3">
|
|
<div class="box" data-testid="overview-summary-avg-revenue">
|
|
<p class="subtitle is-6">
|
|
{{ $t("department_reports.avg_revenue_per_wash") }} {{ SessionUser.functions.date.isToday(selected_date) && SessionUser.functions.date.isToday(selected_date_to) ? $t("department_reports.today") : "" }}
|
|
</p>
|
|
<p class="title is-4">
|
|
<template v-if="is_loading(identifier)">
|
|
<b-skeleton :width="'100%'" :height="'1em'" />
|
|
</template>
|
|
<template v-else>
|
|
{{ SessionUser.functions.currency.toLocal((income / washes) || 0) }}
|
|
</template>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="column is-3">
|
|
<div class="box" data-testid="overview-summary-washes">
|
|
<p class="subtitle is-6">
|
|
{{ $t("department_reports.washes") }} {{ SessionUser.functions.date.isToday(selected_date) && SessionUser.functions.date.isToday(selected_date_to) ? $t("department_reports.today") : "" }}
|
|
</p>
|
|
<p class="title is-4">
|
|
<template v-if="is_loading(identifier)">
|
|
<b-skeleton :width="'100%'" :height="'1em'" />
|
|
</template>
|
|
<template v-else>
|
|
{{ washes }}
|
|
</template>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
<div class="column is-3">
|
|
<div class="box" data-testid="overview-summary-night-washes">
|
|
<p class="subtitle is-6">
|
|
{{ $t("admin.daily_report.reports.night_washes.title") }}
|
|
</p>
|
|
<p class="title is-4">
|
|
<template v-if="is_loading(identifier)">
|
|
<b-skeleton :width="'100%'" :height="'1em'" />
|
|
</template>
|
|
<template v-else>
|
|
<span data-testid="overview-summary-night-washes-total">{{ outsideHours.total }}</span>
|
|
</template>
|
|
</p>
|
|
<p class="is-size-7 has-text-grey-dark" data-testid="overview-summary-night-washes-breakdown">
|
|
{{ buildOutsideHoursBreakdownText(outsideHours, $t) }}
|
|
</p>
|
|
<p
|
|
v-if="buildOutsideHoursWarningText(outsideHours, loadedDepartments, $t)"
|
|
class="is-size-7 has-text-warning-dark mt-2"
|
|
data-testid="overview-summary-night-washes-warning"
|
|
>
|
|
{{ buildOutsideHoursWarningText(outsideHours, loadedDepartments, $t) }}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped>
|
|
|
|
</style>
|