feat: Order preparation and reception

feat/issue-3/obi
Frédérik Benoist 2024-01-15 00:23:43 +01:00
parent 7353016937
commit f3a986258b
7 changed files with 470 additions and 13 deletions

View File

@ -55,11 +55,88 @@ interface History {
fdateCreation: Date
}
export interface PreparationLines {
lineFulfillId: number
lineOrderId: number
prepIntId: number
orderId: string
requestId: number
transactionDate: Date
lineItemNo: number
itemId: string
lineItemOms: string
fulfillQty: number
validatedFulfillQty: number
fulfillmentSystemCd: string
fulfillmentLocationCd: string
status: string
numeroExpedition: string
seasonCode: string
finitionSpeciale: string
carrier: string
trackingCode: string
trackingUrl: string
fdateCreation: Date
fdateModification: Date
toOrlixConsumed: boolean
restockingCode: string
}
export interface Preparation {
prepIntId: number
prepId: number
orderId: string
requestId: number
transactionDate: Date
fulfillmentSystemCd: string
fulfillmentLocationCd: string
status: string
datePreparation: Date
fdateCreation: Date
lines: PreparationLines[]
}
export interface ReceptionLines {
lineIntransitId: number
intransitIntId: number
lineFulfillId: number
transactionDate: Date
lineItemNo: number
itemId: string
intransitQty: number
validatedIntransitQty: number
intransitSystemCd: string
intransitLocationCd: string
status: string
colisId: string
fdateCreation: Date
fdateReceipt: Date
orderLineShipWeight: number
trackingNumber: string
}
export interface Reception {
intransitIntId: number
intransitId: string
prepIntId: number
orderId: string
requestId: number
status: string
transactionDate: Date
intransitSystemCd: string
intransitLocationCd: string
fdateReceipt: Date
fdateCreation: Date
lines: ReceptionLines[]
}
export interface Order {
meta: meta
common: Common
lines: Lines[]
history: History[]
preparations: Preparation[]
receptions: Reception[]
}
export interface OrderOms {

View File

@ -2,6 +2,8 @@
import type { Order } from '@/models/Order'
import OrderPanel from '@/views/pages/order/view/OrderPanel.vue'
import OrderTabGeneral from '@/views/pages/order/view/OrderTabGeneralH.vue'
import OrderTabPreparation from '@/views/pages/order/view/OrderTabPreparationH.vue'
import OrderTabReception from '@/views/pages/order/view/OrderTabReceptionH.vue'
const { t } = useI18n()
@ -31,6 +33,19 @@ const refreshData = async () => {
}
handleData()
const resolveStatus = (status: string) => {
if (status === 'fulfilled')
return { text: status, color: 'success' }
else if (status === 'polled')
return { text: status, color: 'info' }
else if (status === 'intransit polled')
return { text: status, color: 'warning' }
else if (status === 'cancelled' || status === 'unfulfillable')
return { text: status, color: 'error' }
else
return { text: status, color: 'primary' }
}
</script>
<template>
@ -50,16 +65,14 @@ handleData()
class="d-flex gap-2 align-center mb-0 flex-wrap"
>
<h4 class="text-h3 font-weight-medium">
Order: {{ orderData.common.orderId }}
#{{ orderData.common.orderId }}
</h4>
<div class="d-flex gap-2">
<VChip
label
color="success"
size="x-large"
>
{{ orderData.common.statusData.code }}
</VChip>
v-bind="resolveStatus(orderData.common.statusData.code)"
/>
<VChip
label
size="x-large"
@ -118,6 +131,14 @@ handleData()
<VWindowItem>
<OrderTabGeneral :order-data="orderData" />
</VWindowItem>
<!-- 👉 Preparation -->
<VWindowItem>
<OrderTabPreparation :order-data="orderData" />
</VWindowItem>
<!-- 👉 Reception -->
<VWindowItem>
<OrderTabReception :order-data="orderData" />
</VWindowItem>
</VWindow>
</VCol>
</VRow>

View File

@ -41,15 +41,15 @@ const updateOptions = (options: any) => {
const resolveStatus = (status: string) => {
if (status === 'fulfilled')
return { text: 'fulfilled', color: 'success' }
else if (status === 'received')
return { text: 'received', color: 'primary' }
return { text: status, color: 'success' }
else if (status === 'polled')
return { text: status, color: 'info' }
else if (status === 'intransit polled')
return { text: 'intransit polled', color: 'info' }
else if (status === 'new_order')
return { text: 'new_order', color: 'warning' }
else
return { text: status, color: 'warning' }
else if (status === 'cancelled' || status === 'unfulfillable')
return { text: status, color: 'error' }
else
return { text: status, color: 'primary' }
}
const sortByMapping = (sortby: string) => {

View File

@ -43,6 +43,15 @@ const headers = computed(() => [
class="text-no-wrap"
expand-on-click
>
<template #item.lineItemNo="{ item }">
<VChip
variant="tonal"
label
>
{{ item.lineItemNo }}
</VChip>
</template>
<!-- Expanded Row Data -->
<template #expanded-row="slotProps">
<td :colspan="headers.length">
@ -104,6 +113,7 @@ const headers = computed(() => [
<template #bottom />
</VDataTable>
</VCard>
<!-- 👉 Order History -->
<VCard title="Status order history">
<VCardText>

View File

@ -0,0 +1,185 @@
<script setup lang="ts">
import { format } from 'date-fns'
import type { Order } from '@/models/Order'
const props = defineProps<Props>()
const { t } = useI18n()
interface Props {
orderData: Order
}
const resolveStatus = (status: string) => {
if (status === 'fulfilled')
return { text: status, color: 'success' }
else if (status === 'polled')
return { text: status, color: 'info' }
else if (status === 'intransit polled')
return { text: status, color: 'warning' }
else if (status === 'cancelled' || status === 'unfulfillable')
return { text: status, color: 'error' }
else
return { text: status, color: 'primary' }
}
const panelStatus = ref(0)
</script>
<template>
<!-- 👉 Preparations 06990018 -->
<VExpansionPanels
v-model="panelStatus"
variant="accordion"
>
<VExpansionPanel
v-for="(section, index) in orderData.preparations"
:key="index"
elevation="0"
>
<template #title>
<VCardText class="pa-sm-2">
<div class="d-flex justify-space-between align-center mb-4">
<div>
<VChip
v-bind="resolveStatus(section.status)"
variant="tonal"
label
size="default"
/>
{{ section.fulfillmentSystemCd }} / {{ section.fulfillmentLocationCd }}
</div>
<div class="d-flex">
<span class="text-body-1 text-disabled font-weight-medium"> {{ format(section.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}</span>
</div>
</div>
</vcardtext>
</template>
<VExpansionPanelText>
<!-- 👉 Preparation line -->
<div class="mb-6">
<VRow>
<template
v-for="preparationLine in orderData.preparations[index].lines"
:key="preparationLine.lineFulfillId"
>
<VCol
cols="12"
md="4"
sm="6"
>
<VCard
flat
border
>
<VCardText>
<div class="d-flex justify-space-between align-center mb-4">
<VChip
variant="tonal"
label
>
{{ preparationLine.lineItemOms }}
</VChip>
<div class="d-flex">
<span class="text-body-1 font-weight-medium align-center">
{{ preparationLine.itemId }} / {{ preparationLine.seasonCode }}
</span>
</div>
</div>
<VList class="card-list mt-1">
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">N°Exp:</span>
<span>
{{ preparationLine.numeroExpedition }}
</span>
</div>
</VListItem>
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">Cd:</span>
<span>
{{ preparationLine.fulfillmentSystemCd }} / {{ preparationLine.fulfillmentLocationCd }}
</span>
</div>
</VListItem>
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">Qty:</span>
<span>
{{ preparationLine.validatedFulfillQty }} / {{ preparationLine.fulfillQty }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Carrier:</span>
<span>
{{ preparationLine.carrier }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Tracking:</span>
<span>
{{ preparationLine.trackingCode }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">URL:</span>
<span>
<a
v-if="preparationLine.trackingUrl"
:href="preparationLine.trackingUrl"
target="_blank"
style="text-decoration: underline;"
>Link</a>
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Restocking:</span>
<span>
{{ preparationLine.restockingCode }}
</span>
</div>
</VListItem>
<VListItem>
<VChip
v-bind="resolveStatus(preparationLine.status)"
variant="tonal"
label
size="default"
/>
{{ format(section.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</VListItem>
</VList>
</VCardText>
</VCard>
</VCol>
</template>
</VRow>
</div>
</VExpansionPanelText>
</VExpansionPanel>
</VExpansionPanels>
</template>
<style lang="scss">
.v-expansion-panel-text__wrapper{
padding-block: 0.75rem !important;
padding-inline: 0.5rem !important;
}
.v-expansion-panel--active{
.v-expansion-panel-title{
border-block-end: 1px solid rgba(var(--v-theme-on-surface), 0.12) !important;
}
}
</style>

View File

@ -0,0 +1,164 @@
<script setup lang="ts">
import { format } from 'date-fns'
import type { Order } from '@/models/Order'
const props = defineProps<Props>()
const { t } = useI18n()
interface Props {
orderData: Order
}
const resolveStatus = (status: string) => {
if (status === 'fulfilled')
return { text: status, color: 'success' }
else if (status === 'polled')
return { text: status, color: 'info' }
else if (status === 'intransit polled')
return { text: status, color: 'warning' }
else if (status === 'cancelled' || status === 'unfulfillable')
return { text: status, color: 'error' }
else
return { text: status, color: 'primary' }
}
const panelStatus = ref(0)
</script>
<template>
<!-- 👉 Receptions -->
<VExpansionPanels
v-model="panelStatus"
variant="accordion"
>
<VExpansionPanel
v-for="(section, index) in orderData.receptions"
:key="index"
elevation="0"
>
<template #title>
<VCardText class="pa-sm-2">
<div class="d-flex justify-space-between align-center mb-4">
<div>
<VChip
v-bind="resolveStatus(section.status)"
variant="tonal"
label
size="default"
/>
{{ section.intransitSystemCd }} / {{ section.intransitLocationCd }}
</div>
<div class="d-flex">
<span class="text-body-1 text-disabled font-weight-medium"> {{ format(section.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}</span>
</div>
</div>
</vcardtext>
</template>
<VExpansionPanelText>
<!-- 👉 Reception lines -->
<div class="mb-6">
<VRow>
<template
v-for="receptionLine in orderData.receptions[index].lines"
:key="receptionLine.lineFulfillId"
>
<VCol
cols="12"
md="4"
sm="6"
>
<VCard
flat
border
>
<VCardText>
<div class="d-flex justify-space-between align-center mb-4">
<VChip
variant="tonal"
label
>
{{ receptionLine.lineItemNo }}
</VChip>
<div class="d-flex">
<span class="text-body-1 font-weight-medium align-center">
{{ receptionLine.itemId }}
</span>
</div>
</div>
<VList class="card-list mt-1">
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">Colis:</span>
<span>
{{ receptionLine.colisId }}
</span>
</div>
</VListItem>
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">Cd:</span>
<span>
{{ receptionLine.intransitSystemCd }} / {{ receptionLine.intransitLocationCd }}
</span>
</div>
</VListItem>
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">Qty:</span>
<span>
{{ receptionLine.validatedIntransitQty }} / {{ receptionLine.intransitQty }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Tracking:</span>
<span>
{{ receptionLine.trackingNumber }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Weight:</span>
<span>
{{ receptionLine.orderLineShipWeight }}
</span>
</div>
</VListItem>
<VListItem>
<VChip
v-bind="resolveStatus(receptionLine.status)"
variant="tonal"
label
size="default"
/>
{{ format(section.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</VListItem>
</VList>
</VCardText>
</VCard>
</VCol>
</template>
</VRow>
</div>
</VExpansionPanelText>
</VExpansionPanel>
</VExpansionPanels>
</template>
<style lang="scss">
.v-expansion-panel-text__wrapper{
padding-block: 0.75rem !important;
padding-inline: 0.5rem !important;
}
.v-expansion-panel--active{
.v-expansion-panel-title{
border-block-end: 1px solid rgba(var(--v-theme-on-surface), 0.12) !important;
}
}
</style>

View File

@ -12,7 +12,7 @@ export const { themeConfig, layoutConfig } = defineThemeConfig({
app: {
title: 'hdpos',
logo: h('div', { innerHTML: logo, style: 'line-height:0; color: rgb(var(--v-global-theme-primary))' }),
contentWidth: ContentWidth.Boxed,
contentWidth: ContentWidth.Fluid,
contentLayoutNav: AppContentLayoutNav.Horizontal,
overlayNavFromBreakpoint: breakpointsVuetify.md + 16, // 16 for scrollbar. Docs: https://next.vuetifyjs.com/en/features/display-and-platform/
i18n: {