feat: obi visualization

feat/issue-3/obi
Frédérik Benoist 2024-01-13 06:47:33 +01:00
parent 5419bb538e
commit 7353016937
12 changed files with 390 additions and 106 deletions

View File

@ -59,5 +59,6 @@
- vite-plugin-vue-devtools : [npm](https://www.npmjs.com/package/vite-plugin-vue-devtools), [GitHub](https://github.com/antfu/vite-plugin-vue-devtools) - Plugin Vite pour intégrer les outils de développement Vue.js - vite-plugin-vue-devtools : [npm](https://www.npmjs.com/package/vite-plugin-vue-devtools), [GitHub](https://github.com/antfu/vite-plugin-vue-devtools) - Plugin Vite pour intégrer les outils de développement Vue.js
- vite-plugin-vue-layouts : [npm](https://www.npmjs.com/package/vite-plugin-vue-layouts), [GitHub](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) - Plugin Vite pour la gestion des mises en page Vue.js - vite-plugin-vue-layouts : [npm](https://www.npmjs.com/package/vite-plugin-vue-layouts), [GitHub](https://github.com/JohnCampionJr/vite-plugin-vue-layouts) - Plugin Vite pour la gestion des mises en page Vue.js
- vite-plugin-vuetify : [npm](https://www.npmjs.com/package/vite-plugin-vuetify), [GitHub](https://github.com/antfu/vite-plugin-vuetify) - Plugin Vite pour l'intégration de Vuetify - vite-plugin-vuetify : [npm](https://www.npmjs.com/package/vite-plugin-vuetify), [GitHub](https://github.com/antfu/vite-plugin-vuetify) - Plugin Vite pour l'intégration de Vuetify
- vue-json-pretty : [npm](https://www.npmjs.com/package/vue-json-pretty), [GitHub](https://github.com/leezng/vue-json-pretty) - A pretty-print JSON Vue-component
- vue-shepherd : [npm](https://www.npmjs.com/package/vue-shepherd), [GitHub](https://github.com/hipstersmoothie/vue-shepherd) - Tour de guide pour les applications Vue.js - vue-shepherd : [npm](https://www.npmjs.com/package/vue-shepherd), [GitHub](https://github.com/hipstersmoothie/vue-shepherd) - Tour de guide pour les applications Vue.js
- vue-tsc : [npm](https://www.npmjs.com/package/vue-tsc), [GitHub](https://github.com/johnsoncodehk/vue-tsc) - Plugin TypeScript pour la compilation de fichiers `.vue` - vue-tsc : [npm](https://www.npmjs.com/package/vue-tsc), [GitHub](https://github.com/johnsoncodehk/vue-tsc) - Plugin TypeScript pour la compilation de fichiers `.vue`

View File

@ -47,6 +47,7 @@
"vue-chartjs": "^5.2.0", "vue-chartjs": "^5.2.0",
"vue-flatpickr-component": "11.0.3", "vue-flatpickr-component": "11.0.3",
"vue-i18n": "^9.5.0", "vue-i18n": "^9.5.0",
"vue-json-pretty": "^2.3.0",
"vue-prism-component": "^2.0.0", "vue-prism-component": "^2.0.0",
"vue-router": "^4.2.5", "vue-router": "^4.2.5",
"vue3-apexcharts": "^1.4.4", "vue3-apexcharts": "^1.4.4",

View File

@ -115,6 +115,9 @@ dependencies:
vue-i18n: vue-i18n:
specifier: ^9.5.0 specifier: ^9.5.0
version: 9.6.5(vue@3.3.8) version: 9.6.5(vue@3.3.8)
vue-json-pretty:
specifier: ^2.3.0
version: 2.3.0(vue@3.3.8)
vue-prism-component: vue-prism-component:
specifier: ^2.0.0 specifier: ^2.0.0
version: 2.0.0 version: 2.0.0
@ -7978,6 +7981,15 @@ packages:
'@vue/devtools-api': 6.5.1 '@vue/devtools-api': 6.5.1
vue: 3.3.8(typescript@5.2.2) vue: 3.3.8(typescript@5.2.2)
/vue-json-pretty@2.3.0(vue@3.3.8):
resolution: {integrity: sha512-iBul6Xg7vZfMV2MQC/gGtzbyg8FLk6cJ8KG91f37UEkQyXqHg91VQJ24bDBXNVuOSP04BUKxWagD3V2N/WEy0g==}
engines: {node: '>= 10.0.0', npm: '>= 5.0.0'}
peerDependencies:
vue: '>=3.0.0'
dependencies:
vue: 3.3.8(typescript@5.2.2)
dev: false
/vue-prism-component@2.0.0: /vue-prism-component@2.0.0:
resolution: {integrity: sha512-1ofrL+GCZOv4HqtX5W3EgkhSAgadSeuD8FDTXbwhLy8kS+28RCR8t2S5VTeM9U/peAaXLBpSgRt3J25ao8KTeg==} resolution: {integrity: sha512-1ofrL+GCZOv4HqtX5W3EgkhSAgadSeuD8FDTXbwhLy8kS+28RCR8t2S5VTeM9U/peAaXLBpSgRt3J25ao8KTeg==}
dev: false dev: false

View File

@ -1,4 +1,6 @@
import { useStorage } from '@vueuse/core' import { useStorage } from '@vueuse/core'
import { setDefaultOptions } from 'date-fns'
import { enUS, fr } from 'date-fns/locale'
import flatpickr from 'flatpickr' import flatpickr from 'flatpickr'
import { French } from 'flatpickr/dist/l10n/fr' import { French } from 'flatpickr/dist/l10n/fr'
import { useTheme } from 'vuetify' import { useTheme } from 'vuetify'
@ -19,10 +21,14 @@ const _syncAppRtl = () => {
if (locale.value === 'fr') { if (locale.value === 'fr') {
if (flatpickr.l10ns.fr) if (flatpickr.l10ns.fr)
flatpickr.localize(French) flatpickr.localize(French)
setDefaultOptions({ locale: fr })
} }
else { else {
if (flatpickr.l10ns.en) if (flatpickr.l10ns.en)
flatpickr.localize(flatpickr.l10ns.en) flatpickr.localize(flatpickr.l10ns.en)
setDefaultOptions({ locale: enUS })
} }
// watch and change lang attribute of html on language change // watch and change lang attribute of html on language change
@ -39,10 +45,14 @@ const _syncAppRtl = () => {
if (storedLang.value === 'fr') { if (storedLang.value === 'fr') {
if (flatpickr.l10ns.fr) if (flatpickr.l10ns.fr)
flatpickr.localize(flatpickr.l10ns.fr) flatpickr.localize(flatpickr.l10ns.fr)
setDefaultOptions({ locale: fr })
} }
else { else {
if (flatpickr.l10ns.en) if (flatpickr.l10ns.en)
flatpickr.localize(flatpickr.l10ns.en) flatpickr.localize(flatpickr.l10ns.en)
setDefaultOptions({ locale: enUS })
} }
// set isAppRtl value based on selected language // set isAppRtl value based on selected language

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -38,5 +38,13 @@ export const useApi = createFetch({
return { data: parsedData, response } return { data: parsedData, response }
}, },
onFetchError(ctx) {
const errorData = ctx.data ? JSON.parse(ctx.data) : { title: 'Hunter x Hunter' }
const status = ctx.response ? ctx.response.status : 'unknown'
ctx.error = { status, error: errorData.error || errorData.title }
return ctx
},
}, },
}) })

View File

@ -12,9 +12,6 @@ interface transaction {
transactionDate: Date transactionDate: Date
transactionNo: string transactionNo: string
transactionTypeDescription: string transactionTypeDescription: string
transactionSubtotal: number
transactionTax: number
transactionTotal: number
} }
interface Common { interface Common {
@ -22,8 +19,6 @@ interface Common {
requestingLocationCd: string requestingLocationCd: string
requestingSystemCd: string requestingSystemCd: string
customerId: string customerId: string
customerFirstName: string
customerLastName: string
status: string status: string
submitOrdMsg: string submitOrdMsg: string
fdateCreation: Date fdateCreation: Date
@ -66,3 +61,26 @@ export interface Order {
lines: Lines[] lines: Lines[]
history: History[] history: History[]
} }
export interface OrderOms {
common: OrderOmsCommon
oms: Proximis
}
export interface OrderOmsCommon {
urlApp: string
}
export interface Proximis {
item: ProximisItem
}
export interface ProximisItem {
id: number
modificationDate: Date
code: string
fulfillSystem: string
creationDate: Date
fulfillStoreCode: string
status: string
}

View File

@ -16,12 +16,21 @@ const tabs = [
{ title: 'Flow' }, { title: 'Flow' },
] ]
const { data, error } = await useApi<Order>(`/obi/order/${route.params.id}`) const { data, error, execute: fetchOrder } = await useApi<Order>(`/obi/order/${route.params.id}`)
if (error.value) const handleData = () => {
console.log(error.value) if (error.value)
else if (data.value) console.log(error.value)
orderData.value = data.value else if (data.value)
orderData.value = data.value
}
const refreshData = async () => {
await fetchOrder()
handleData()
}
handleData()
</script> </script>
<template> <template>
@ -36,33 +45,40 @@ else if (data.value)
<div> <div>
<!-- 👉 Header --> <!-- 👉 Header -->
<div class="d-flex justify-space-between align-center flex-wrap gap-y-4 mb-6"> <div class="d-flex justify-space-between align-center flex-wrap gap-y-4 mb-6">
<div> <div
<div class="d-flex gap-2 align-center mb-0 flex-wrap"> v-if="orderData"
<h4 class="text-h3 font-weight-medium"> class="d-flex gap-2 align-center mb-0 flex-wrap"
Order Id: {{ orderData && orderData.common.orderId }} >
</h4> <h4 class="text-h3 font-weight-medium">
<div class="d-flex gap-2"> Order: {{ orderData.common.orderId }}
<VChip </h4>
label <div class="d-flex gap-2">
color="success" <VChip
size="x-large" label
> color="success"
{{ orderData && orderData.common.statusData.code }} size="x-large"
</VChip> >
<VChip {{ orderData.common.statusData.code }}
label </VChip>
size="x-large" <VChip
:color="orderData && orderData.common.consumed ? 'success' : 'error'" label
> size="x-large"
{{ orderData && orderData.common.consumed ? 'Consumed' : 'Not consumed' }} :color="orderData.common.consumed ? 'success' : 'error'"
</VChip> >
</div> {{ orderData.common.consumed ? 'Consumed' : 'Not consumed' }}
</VChip>
</div> </div>
</div> </div>
<div v-else>
Order not found ...
</div>
<!-- 👉 Reload button -->
<div class="d-flex gap-4"> <div class="d-flex gap-4">
<VBtn <VBtn
variant="tonal" variant="tonal"
color="primary" color="primary"
@click="refreshData"
> >
Reload Reload
</VBtn> </VBtn>

View File

@ -1,4 +1,5 @@
<script setup lang="ts"> <script setup lang="ts">
import { format } from 'date-fns'
import { VDataTableServer } from 'vuetify/labs/VDataTable' import { VDataTableServer } from 'vuetify/labs/VDataTable'
import { paginationMeta } from '@api-utils/paginationMeta' import { paginationMeta } from '@api-utils/paginationMeta'
@ -16,8 +17,8 @@ const searchQuery = ref('')
// Data table options // Data table options
const itemsPerPage = ref(10) const itemsPerPage = ref(10)
const page = ref(1) const page = ref(1)
const sortBy = ref() const sortBy = ref('meta.id')
const orderBy = ref() const orderBy = ref('desc')
// Data table Headers // Data table Headers
const headers = [ const headers = [
@ -28,11 +29,14 @@ const headers = [
{ title: 'Type', key: 'common.transaction.transactionTypeDescription' }, { title: 'Type', key: 'common.transaction.transactionTypeDescription' },
] ]
// Update data table options
const updateOptions = (options: any) => { const updateOptions = (options: any) => {
page.value = options.page page.value = options.page
sortBy.value = options.sortBy[0]?.key
orderBy.value = options.sortBy[0]?.order // updateOptions was called systematically by VDataTableServer with an empty object
if (options.sortBy[0]?.key) {
sortBy.value = options.sortBy[0].key
orderBy.value = options.sortBy[0].order
}
} }
const resolveStatus = (status: string) => { const resolveStatus = (status: string) => {
@ -48,13 +52,25 @@ const resolveStatus = (status: string) => {
return { text: status, color: 'error' } return { text: status, color: 'error' }
} }
const sortByMapping = (sortby: string) => {
const headerMapping: { [key: string]: string } = {
'meta.id': 'request_id',
'common.orderId': 'order_id',
'common.transaction.transactionDate': 'transaction_date',
'common.statusData.code': 'status',
'common.transaction.transactionTypeDescription': 'transaction_type_description',
}
return headerMapping[sortby] || sortby
}
const { data: ordersData } = await useApi<any>(createUrl('/obi/order', const { data: ordersData } = await useApi<any>(createUrl('/obi/order',
{ {
query: { query: {
q: searchQuery, q: searchQuery,
page, page,
itemsPerPage, itemsPerPage,
sortBy, sortBy: sortByMapping(sortBy.value),
orderBy, orderBy,
}, },
}, },
@ -164,6 +180,8 @@ const totalOrder = computed(() => ordersData.value.total)
<VDataTableServer <VDataTableServer
v-model:items-per-page="itemsPerPage" v-model:items-per-page="itemsPerPage"
v-model:page="page" v-model:page="page"
v-model:sort-desc="orderBy"
v-model:sort-by:="sortBy"
:headers="headers" :headers="headers"
:items="orders" :items="orders"
:items-length="totalOrder" :items-length="totalOrder"
@ -181,6 +199,11 @@ const totalOrder = computed(() => ordersData.value.total)
</RouterLink> </RouterLink>
</template> </template>
<!-- Date -->
<template #item.common.transaction.transactionDate="{ item }">
{{ format(item.common.transaction.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</template>
<!-- Status --> <!-- Status -->
<template #item.common.statusData.code="{ item }"> <template #item.common.statusData.code="{ item }">
<VChip <VChip

View File

@ -0,0 +1,239 @@
<script setup lang="ts">
import { format } from 'date-fns'
import VueJsonPretty from 'vue-json-pretty'
import type { Order, OrderOms } from '@/models/Order'
import logoProximis from '@images/misc/logo-proximis.png'
import 'vue-json-pretty/lib/styles.css'
const props = defineProps<Props>()
interface Props {
orderData: Order
}
const omsData = ref<OrderOms>()
const omsError = ref()
const OrderMessageDialogVisible = ref(false)
const OrderMessageData = ref()
const { data: apiDataOms, error: apiErrorOms } = await useApi<any>(`/proximis/project/fulfillment/${props.orderData.common.orderId}`)
if (apiErrorOms.value)
omsError.value = `${apiErrorOms.value.status} - ${apiErrorOms.value.error}`
else
omsData.value = apiDataOms.value
const openOrderMessageDialog = async (): Promise<void> => {
const { data: apiDataMessage, error: apiErrorMessage } = await useApi<any>(`/obi/order/${props.orderData.meta.id}/orderMessage`)
if (apiErrorMessage.value) {
OrderMessageData.value = `${apiErrorMessage.value.status} - ${apiErrorMessage.value.error}`
OrderMessageDialogVisible.value = true
}
else {
OrderMessageData.value = apiDataMessage.value
OrderMessageDialogVisible.value = true
}
}
const openOmsOrderPage = (): void => {
// Check if omsData is defined before accessing its value property
if (omsData.value) {
const url = `${omsData.value.common.urlApp}/ua.php/orderManager/Order/${omsData.value.oms.item.id}`
window.open(url, '_blank')
}
else {
// Handle the case when omsData is not defined
console.error('omsData is not defined')
}
}
</script>
<template>
<!-- 👉 Proximis -->
<VCard>
<VRow no-gutters>
<VCol cols="6">
<VCardText class="pa-4">
<h6 class="text-lg text-no-wrap font-weight-medium">
Proximis
</h6>
<p class="mb-2">
OMS Partner
</p>
</VCardText>
</VCol>
<VCol
cols="6"
class="text-right"
>
<VCardText class="pa-3">
<VImg
:src="logoProximis"
height="50"
/>
</VCardText>
</VCol>
<VCol cols="12">
<VCardText>
<div v-if="omsData">
<VList class="card-list mt-0">
<div class="text-disabled text-uppercase text-sm">
Transaction details
</div>
<VListItem>
<div class="text-body-1 mt-2">
<span class="font-weight-bold me-2">Id:</span>
<span>
{{ omsData.oms.item.id }} / {{ omsData.oms.item.code }}
</span>
</div>
</VListItem>
</VList>
<VList class="card-list mt-2">
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Last status:</span>
<span>
{{ omsData.oms.item.status }}
</span>
</div>
</VListItem>
</VList>
<VList class="card-list mt-2">
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Added:</span>
<span>
{{ format(omsData.oms.item.modificationDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</span>
</div>
</VListItem>
</VList>
<VList class="card-list mt-2">
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">fulfillSystem:</span>
<span>
{{ omsData.oms.item.fulfillSystem }} / {{ omsData.oms.item.fulfillStoreCode }}
</span>
</div>
</VListItem>
</VList>
<VList class="card-list mt-2">
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Modified:</span>
<span>
{{ format(omsData.oms.item.creationDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</span>
</div>
</VListItem>
</VList>
</div>
<div v-else>
Error: {{ omsError }}
</div>
</VCardText>
</VCol>
<VDivider />
<VCol cols="6">
<VCardText class="pa-4">
<VBtn
class="mt-0"
@click="openOrderMessageDialog"
>
Transaction
</VBtn>
</VCardText>
</VCol>
<VCol
v-if="omsData"
cols="6"
class="text-right"
>
<VCardText class="pa-4">
<VBtn
class="mt-0"
@click="openOmsOrderPage"
>
Open order
</VBtn>
</VCardText>
</VCol>
</VRow>
</VCard>
<VDialog
v-model="OrderMessageDialogVisible"
fullscreen
:scrim="false"
transition="dialog-bottom-transition"
>
<!-- Dialog Content -->
<VCard>
<!-- Toolbar -->
<div>
<VToolbar color="primary">
<VBtn
icon
variant="plain"
@click="OrderMessageDialogVisible = false"
>
<VIcon
color="white"
icon="tabler-x"
/>
</VBtn>
<VToolbarTitle>Order transaction</VToolbarTitle>
<VSpacer />
<VToolbarItems>
<VBtn
variant="text"
@click="OrderMessageDialogVisible = false"
>
Close
</VBtn>
</VToolbarItems>
</VToolbar>
</div>
<!-- pretty json viewer -->
<VCardText>
<VueJsonPretty
:show-length="false"
show-line-number
show-icon
:show-line="false"
:data="OrderMessageData"
/>
</VCardText>
</VCard>
</VDialog>
</template>
<style lang="scss">
.dialog-bottom-transition-enter-active,
.dialog-bottom-transition-leave-active {
transition: transform 0.2s ease-in-out;
}
.full-screen-dialog-list{
.v-list-item[tabindex="-2"].v-list-item--active{
.v-list-item-action{
.v-icon{
color: #fff;
}
}
}
}
</style>

View File

@ -1,17 +1,10 @@
import { propsToCopy } from '@iconify/utils/lib/icon-set/get-icons';
<script setup lang="ts"> <script setup lang="ts">
import { format } from 'date-fns' import { format } from 'date-fns'
import type { Order } from '@/models/Order' import type { Order } from '@/models/Order'
import OrderOms from '@/views/pages/order/view/OrderOms.vue'
const props = defineProps<Props>() const props = defineProps<Props>()
const resolveConsumed = (consumed: boolean) => {
if (consumed)
return { text: 'Consumed', color: 'success' }
else
return { text: 'Not consumed', color: 'error' }
}
interface Props { interface Props {
orderData: Order orderData: Order
} }
@ -19,9 +12,11 @@ interface Props {
<template> <template>
<VRow> <VRow>
<!-- SECTION Order -->
<VCol cols="12"> <VCol cols="12">
<VCard v-if="props.orderData"> <VCard
v-if="props.orderData"
class="mb-4"
>
<!-- 👉 Order Details --> <!-- 👉 Order Details -->
<VCardText> <VCardText>
<div class="text-disabled text-uppercase text-sm"> <div class="text-disabled text-uppercase text-sm">
@ -44,19 +39,11 @@ interface Props {
</span> </span>
</div> </div>
</VListItem> </VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Cust. name:</span>
<span>
{{ props.orderData.common.customerLastName }} {{ props.orderData.common.customerFirstName }}
</span>
</div>
</VListItem>
<VListItem> <VListItem>
<div class="text-body-1"> <div class="text-body-1">
<span class="font-weight-bold me-2">Date creation:</span> <span class="font-weight-bold me-2">Date creation:</span>
<span> <span>
{{ format(props.orderData.common.fdateCreation, "yyyy-MM-dd HH:mm:ss") }} {{ format(props.orderData.common.fdateCreation, "EEEE d MMMM yyyy HH:mm:ss") }}
</span> </span>
</div> </div>
</VListItem> </VListItem>
@ -85,7 +72,7 @@ interface Props {
<div class="text-body-1"> <div class="text-body-1">
<span class="font-weight-bold me-2">Date:</span> <span class="font-weight-bold me-2">Date:</span>
<span> <span>
{{ format(props.orderData.common.transaction.transactionDate, "yyyy-MM-dd HH:mm:ss") }} {{ format(props.orderData.common.transaction.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</span> </span>
</div> </div>
</VListItem> </VListItem>
@ -99,30 +86,15 @@ interface Props {
</VListItem> </VListItem>
</VList> </VList>
</VCardText> </VCardText>
<VCardText class="text-center">
<VBtn>
Edit XML Details
</VBtn>
</VCardText>
<VCardText class="text-center">
<VBtn>
Proximis
</VBtn>
</VCardText>
<VCardText class="text-center">
<VBtn>
SQL Obi
</VBtn>
</VCardText>
</VCard> </VCard>
<!-- 👉 OMS Proximis -->
<OrderOms :order-data="orderData" />
</VCol> </VCol>
</vrow> </VRow>
</template> </template>
<style lang="scss" scoped> <style lang="scss">
.card-list { .card-list {
--v-card-list-gap: 0.75rem; --v-card-list-gap: 0.75rem;
} }

View File

@ -18,6 +18,7 @@ const headers = computed(() => [
{ title: t('Qty'), key: 'orderedLineQty' }, { title: t('Qty'), key: 'orderedLineQty' },
{ title: t('Date'), key: 'transactionDate' }, { title: t('Date'), key: 'transactionDate' },
{ title: t('Status'), key: 'status' }, { title: t('Status'), key: 'status' },
{ title: t('Consumed'), key: 'consumed' },
{ title: t('Created'), key: 'fdateCreation' }, { title: t('Created'), key: 'fdateCreation' },
]) ])
</script> </script>
@ -39,7 +40,7 @@ const headers = computed(() => [
:headers="headers" :headers="headers"
:items="props.orderData.lines" :items="props.orderData.lines"
density="compact" density="compact"
class="text-no-wrap dt-row-striped" class="text-no-wrap"
expand-on-click expand-on-click
> >
<!-- Expanded Row Data --> <!-- Expanded Row Data -->
@ -86,42 +87,25 @@ const headers = computed(() => [
{{ format(new Date(item.transactionDate), 'dd/MM/yyyy HH:mm:ss') }} {{ format(new Date(item.transactionDate), 'dd/MM/yyyy HH:mm:ss') }}
</template> </template>
<template #item.consumed="{ item }">
<VChip
label
size="x-small"
:color="item.consumed ? 'success' : 'error'"
>
{{ item.consumed ? 'Consumed' : 'Not consumed' }}
</VChip>
</template>
<template #item.fdateCreation="{ item }"> <template #item.fdateCreation="{ item }">
{{ format(new Date(item.fdateCreation), 'dd/MM/yyyy HH:mm:ss') }} {{ format(new Date(item.fdateCreation), 'dd/MM/yyyy HH:mm:ss') }}
</template> </template>
<template #bottom /> <template #bottom />
</VDataTable> </VDataTable>
<VDivider />
<VCardText>
<div class="d-flex align-end flex-column">
<table class="text-high-emphasis">
<tbody>
<tr>
<td class="text-high-emphasis font-weight-medium">
Tax:
</td>
<td style="text-align: end;">
{{ parseFloat(orderData.common.transaction.transactionTax.toString()).toFixed(2) }}
</td>
</tr>
<tr>
<td class="text-high-emphasis font-weight-medium">
Total:
</td>
<td style="text-align: end;">
{{ parseFloat(orderData.common.transaction.transactionTotal.toString()).toFixed(2) }}
</td>
</tr>
</tbody>
</table>
</div>
</VCardText>
</VCard> </VCard>
<!-- 👉 Order History --> <!-- 👉 Order History -->
<VCard title="Order History"> <VCard title="Status order history">
<VCardText> <VCardText>
<VTimeline <VTimeline
truncate-line="both" truncate-line="both"