Merge pull request 'release/1.0.1' (#22) from release/1.0.1 into main

Reviewed-on: #22
main V1.0.1
Frédérik Benoist 2024-01-27 12:31:39 +01:00
commit 60c5d0ee7f
35 changed files with 1948 additions and 45 deletions

4
auto-imports.d.ts vendored
View File

@ -125,7 +125,9 @@ declare global {
const registerPlugins_: typeof import('./src/@core/utils/plugins')['registerPlugins_']
const requiredValidator: typeof import('./src/@core/utils/validators')['requiredValidator']
const resolveComponent: typeof import('vue')['resolveComponent']
const resolveOrderStatus: typeof import('./src/utils/order')['resolveOrderStatus']
const resolveRef: typeof import('@vueuse/core')['resolveRef']
const resolveStatus: typeof import('./src/utils/order')['resolveStatus']
const resolveUnref: typeof import('@vueuse/core')['resolveUnref']
const resolveVuetifyTheme: typeof import('./src/@core/utils/vuetify')['resolveVuetifyTheme']
const setActivePinia: typeof import('pinia')['setActivePinia']
@ -480,6 +482,7 @@ declare module 'vue' {
readonly registerPlugins: UnwrapRef<typeof import('./src/@core/utils/plugins')['registerPlugins']>
readonly requiredValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['requiredValidator']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly resolveOrderStatus: UnwrapRef<typeof import('./src/utils/order')['resolveOrderStatus']>
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']>
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']>
readonly resolveVuetifyTheme: UnwrapRef<typeof import('./src/@core/utils/vuetify')['resolveVuetifyTheme']>
@ -824,6 +827,7 @@ declare module '@vue/runtime-core' {
readonly registerPlugins: UnwrapRef<typeof import('./src/@core/utils/plugins')['registerPlugins']>
readonly requiredValidator: UnwrapRef<typeof import('./src/@core/utils/validators')['requiredValidator']>
readonly resolveComponent: UnwrapRef<typeof import('vue')['resolveComponent']>
readonly resolveOrderStatus: UnwrapRef<typeof import('./src/utils/order')['resolveOrderStatus']>
readonly resolveRef: UnwrapRef<typeof import('@vueuse/core')['resolveRef']>
readonly resolveUnref: UnwrapRef<typeof import('@vueuse/core')['resolveUnref']>
readonly resolveVuetifyTheme: UnwrapRef<typeof import('./src/@core/utils/vuetify')['resolveVuetifyTheme']>

64
dependencies.txt Executable file
View File

@ -0,0 +1,64 @@
# Dépendances avec les liens npm et GitHub
## Dépendances de développement
- @antfu/eslint-config-vue : [npm](https://www.npmjs.com/package/@antfu/eslint-config-vue), [GitHub](https://github.com/antfu/eslint-config) - Configuration ESLint pour les projets Vue.js
- @antfu/utils : [npm](https://www.npmjs.com/package/@antfu/utils), [GitHub](https://github.com/antfu/utils) - Utilitaires utiles pour le développement avec Vite
- @fullcalendar/core : [npm](https://www.npmjs.com/package/@fullcalendar/core), [GitHub](https://github.com/fullcalendar/fullcalendar) - Bibliothèque de calendrier complète pour les applications web
- @fullcalendar/daygrid : [npm](https://www.npmjs.com/package/@fullcalendar/daygrid), [GitHub](https://github.com/fullcalendar/daygrid) - Extension de grille de jours pour FullCalendar
- @fullcalendar/interaction : [npm](https://www.npmjs.com/package/@fullcalendar/interaction), [GitHub](https://github.com/fullcalendar/interaction) - Prise en charge de l'interaction utilisateur pour FullCalendar
- @fullcalendar/list : [npm](https://www.npmjs.com/package/@fullcalendar/list), [GitHub](https://github.com/fullcalendar/list) - Extension de liste pour FullCalendar
- @fullcalendar/timegrid : [npm](https://www.npmjs.com/package/@fullcalendar/timegrid), [GitHub](https://github.com/fullcalendar/timegrid) - Extension de grille temporelle pour FullCalendar
- @fullcalendar/vue3 : [npm](https://www.npmjs.com/package/@fullcalendar/vue3), [GitHub](https://github.com/fullcalendar/vue) - Intégration Vue 3 pour FullCalendar
- @iconify-json/mdi : [npm](https://www.npmjs.com/package/@iconify-json/mdi), [GitHub](https://github.com/iconify/iconify-json) - Bibliothèque d'icônes Material Design pour Iconify
- @iconify/tools : [npm](https://www.npmjs.com/package/@iconify/tools), [GitHub](https://github.com/iconify/iconify-tools) - Outils pour travailler avec Iconify
- @iconify/utils : [npm](https://www.npmjs.com/package/@iconify/utils), [GitHub](https://github.com/iconify/iconify-utils) - Utilitaires pour Iconify
- @iconify/vue : [npm](https://www.npmjs.com/package/@iconify/vue), [GitHub](https://github.com/iconify/iconify-vue) - Composant Vue pour Iconify
- @intlify/unplugin-vue-i18n : [npm](https://www.npmjs.com/package/@intlify/unplugin-vue-i18n), [GitHub](https://github.com/intlify/unplugin) - Plugin Vue I18n pour Vite
- @tabler/icons : [npm](https://www.npmjs.com/package/@tabler/icons), [GitHub](https://github.com/tabler/tabler-icons) - Bibliothèque d'icônes Tabler
- @tiptap/extension-character-count : [npm](https://www.npmjs.com/package/@tiptap/extension-character-count), [GitHub](https://github.com/ueberdosis/tiptap) - Extension pour compter le nombre de caractères dans Tiptap
- @tiptap/extension-placeholder : [npm](https://www.npmjs.com/package/@tiptap/extension-placeholder), [GitHub](https://github.com/ueberdosis/tiptap) - Extension de l'indicateur de position dans Tiptap
- @tiptap/extension-subscript : [npm](https://www.npmjs.com/package/@tiptap/extension-subscript), [GitHub](https://github.com/ueberdosis/tiptap) - Extension pour le texte en indice dans Tiptap
- @tiptap/extension-superscript : [npm](https://www.npmjs.com/package/@tiptap/extension-superscript), [GitHub](https://github.com/ueberdosis/tiptap) - Extension pour le texte en exposant dans Tiptap
- @tiptap/extension-underline : [npm](https://www.npmjs.com/package/@tiptap/extension-underline), [GitHub](https://github.com/ueberdosis/tiptap) - Extension pour souligner le texte dans Tiptap
- @types/mapbox-gl : [npm](https://www.npmjs.com/package/@types/mapbox-gl), [GitHub](https://github.com/DefinitelyTyped/DefinitelyTyped) - Types TypeScript pour Mapbox GL
- @types/node : [npm](https://www.npmjs.com/package/@types/node), [GitHub](https://github.com/DefinitelyTyped/DefinitelyTyped) - Types TypeScript pour Node.js
- @types/webfontloader : [npm](https://www.npmjs.com/package/@types/webfontloader), [GitHub](https://github.com/DefinitelyTyped/DefinitelyTyped) - Types TypeScript pour WebFontLoader
- @typescript-eslint/eslint-plugin : [npm](https://www.npmjs.com/package/@typescript-eslint/eslint-plugin), [GitHub](https://github.com/typescript-eslint/typescript-eslint) - Plugin ESLint pour TypeScript
- @typescript-eslint/parser : [npm](https://www.npmjs.com/package/@typescript-eslint/parser), [GitHub](https://github.com/typescript-eslint/typescript-eslint) - Analyseur ESLint pour TypeScript
- @videojs-player/vue : [npm](https://www.npmjs.com/package/@videojs-player/vue), [GitHub](https://github.com/videojs/theater) - Composant Vue pour Video.js
- @vitejs/plugin-vue : [npm](https://www.npmjs.com/package/@vitejs/plugin-vue), [GitHub](https://github.com/vitejs/vite)
- @vitejs/plugin-vue-jsx : [npm](https://www.npmjs.com/package/@vitejs/plugin-vue-jsx), [GitHub](https://github.com/vitejs/vite)
- date-fns : [npm](https://www.npmjs.com/package/date-fns), [GitHub](https://github.com/date-fns/date-fns) - Bibliothèque JavaScript moderne de manipulation de dates
- eslint : [npm](https://www.npmjs.com/package/eslint), [GitHub](https://github.com/eslint/eslint) - Linter JavaScript/TypeScript
- eslint-config-airbnb-base : [npm](https://www.npmjs.com/package/eslint-config-airbnb-base), [GitHub](https://github.com/airbnb/javascript) - Configuration ESLint pour les règles Airbnb (base)
- eslint-import-resolver-typescript : [npm](https://www.npmjs.com/package/eslint-import-resolver-typescript), [GitHub](https://github.com/alexgorbatchev/eslint-import-resolver-typescript) - Résolveur d'importation ESLint pour TypeScript
- eslint-plugin-case-police : [npm](https://www.npmjs.com/package/eslint-plugin-case-police), [GitHub](https://github.com/antfu/eslint-plugin-case-police) - Plugin ESLint pour l'ajustement de casse dans le code
- eslint-plugin-import : [npm](https://www.npmjs.com/package/eslint-plugin-import), [GitHub](https://github.com/benmosher/eslint-plugin-import) - Plugin ESLint pour les règles d'importation
- eslint-plugin-promise : [npm](https://www.npmjs.com/package/eslint-plugin-promise), [GitHub](https://github.com/xjamundx/eslint-plugin-promise) - Plugin ESLint pour les règles liées aux promesses
- eslint-plugin-regex : [npm](https://www.npmjs.com/package/eslint-plugin-regex), [GitHub](https://github.com/ota-meshi/eslint-plugin-regex) - Plugin ESLint pour les règles de regex
- eslint-plugin-sonarjs : [npm](https://www.npmjs.com/package/eslint-plugin-sonarjs), [GitHub](https://github.com/SonarSource/eslint-plugin-sonarjs) - Plugin ESLint pour les règles SonarJS
- eslint-plugin-unicorn : [npm](https://www.npmjs.com/package/eslint-plugin-unicorn), [GitHub](https://github.com/sindresorhus/eslint-plugin-unicorn) - Plugin ESLint pour des règles diverses et utiles
- eslint-plugin-vue : [npm](https://www.npmjs.com/package/eslint-plugin-vue), [GitHub](https://github.com/vuejs/eslint-plugin-vue) - Plugin ESLint pour les règles Vue.js
- msw : [npm](https://www.npmjs.com/package/msw), [GitHub](https://github.com/mswjs/msw) - Outil de simulation de requêtes HTTP pour les tests
- postcss-html : [npm](https://www.npmjs.com/package/postcss-html), [GitHub](https://github.com/yisar/postcss-html) - Plugin PostCSS pour traiter les fichiers HTML en CSS
- postcss-scss : [npm](https://www.npmjs.com/package/postcss-scss), [GitHub](https://github.com/postcss/postcss-scss) - Plugin PostCSS pour la syntaxe SCSS
- sass : [npm](https://www.npmjs.com/package/sass), [GitHub](https://github.com/sass/sass) - Préprocesseur CSS Sass
- stylelint : [npm](https://www.npmjs.com/package/stylelint), [GitHub](https://github.com/stylelint/stylelint) - Linter pour les feuilles de style CSS/SCSS
- stylelint-codeguide : [npm](https://www.npmjs.com/package/stylelint-codeguide), [GitHub](https://github.com/kristerkari/stylelint-codeguide) - Guide de style et configuration Stylelint
- stylelint-config-idiomatic-order : [npm](https://www.npmjs.com/package/stylelint-config-idiomatic-order), [GitHub](https://github.com/ream88/stylelint-config-idiomatic-order) - Configuration Stylelint avec un ordre idiomatique
- stylelint-config-standard-scss : [npm](https://www.npmjs.com/package/stylelint-config-standard-scss), [GitHub](https://github.com/kristerkari/stylelint-config-standard-scss) - Configuration Stylelint pour SCSS basée sur les règles standard
- stylelint-use-logical-spec : [npm](https://www.npmjs.com/package/stylelint-use-logical-spec), [GitHub](https://github.com/iKettles/stylelint-use-logical-spec) - Plugin Stylelint pour promouvoir l'utilisation de spécifications logiques
- tsx : [npm](https://www.npmjs.com/package/tsx), [GitHub](https://github.com/windicss/tsx) - Plugin WindiCSS pour la prise en charge de JSX/TSX
- type-fest : [npm](https://www.npmjs.com/package/type-fest), [GitHub](https://github.com/sindresorhus/type-fest) - Collection de types TypeScript utiles
- typescript : [npm](https://www.npmjs.com/package/typescript), [GitHub](https://github.com/microsoft/TypeScript) - Langage de programmation TypeScript
- unplugin-auto-import : [npm](https://www.npmjs.com/package/unplugin-auto-import), [GitHub](https://github.com/antfu/unplugin-auto-import) - Plugin Vite pour l'importation automatique
- unplugin-vue-components : [npm](https://www.npmjs.com/package/unplugin-vue-components), [GitHub](https://github.com/antfu/unplugin) - Plugin Vite pour la gestion des composants Vue
- unplugin-vue-router : [npm](https://www.npmjs.com/package/unplugin-vue-router), [GitHub](https://github.com/antfu/unplugin-vue-router) - Plugin Vite pour Vue Router
- video.js : [npm](https://www.npmjs.com/package/video.js), [GitHub](https://github.com/videojs/video.js) - Bibliothèque de lecteur vidéo JavaScript
- vite : [npm](https://www.npmjs.com/package/vite), [GitHub](https://github.com/vitejs/vite) - Constructeur d'outils rapide pour le développement web moderne
- 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-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-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-flatpickr-component": "11.0.3",
"vue-i18n": "^9.5.0",
"vue-json-pretty": "^2.3.0",
"vue-prism-component": "^2.0.0",
"vue-router": "^4.2.5",
"vue3-apexcharts": "^1.4.4",

View File

@ -115,6 +115,9 @@ dependencies:
vue-i18n:
specifier: ^9.5.0
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:
specifier: ^2.0.0
version: 2.0.0
@ -7978,6 +7981,15 @@ packages:
'@vue/devtools-api': 6.5.1
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:
resolution: {integrity: sha512-1ofrL+GCZOv4HqtX5W3EgkhSAgadSeuD8FDTXbwhLy8kS+28RCR8t2S5VTeM9U/peAaXLBpSgRt3J25ao8KTeg==}
dev: false

View File

@ -111,6 +111,7 @@ const { copy, copied } = useClipboard({ source: computed(() => props.code[prefer
</template>
<style lang="scss">
/* stylelint-disable-next-line scss/load-no-partial-leading-underscore */
@use "@styles/variables/_vuetify.scss";
:not(pre) > code[class*="language-"],

View File

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

176
src/models/Order.ts Normal file
View File

@ -0,0 +1,176 @@
export interface OrderListStatistics {
title: string
value: number
icon: string
}
export interface OrderList {
total: number
statistics: OrderListStatistics[]
orders: Order[]
}
interface meta {
id: number
model: string
}
interface statusData {
code: string
title: string
}
interface transaction {
transactionTypeId: number
transactionDate: Date
transactionNo: string
transactionTypeDescription: string
}
interface Common {
orderId: string
requestingLocationCd: string
requestingSystemCd: string
customerId: string
status: string
submitOrdMsg: string
fdateCreation: Date
consumed: boolean
shipforpickupLocationCd: string
shipforpickupSystemCd: string
statusData: statusData
transaction: transaction
}
interface Lines {
lineOrderId: number
lineItemNo: number
orderId: string
requestId: number
lineItemOms: string
itemId: string
orderedLineQty: number
status: string
transactionDate: Date
shippingAgent: string
trackingNumber: string
fulfillmentId: string
cartonNumber: string
fdateCreation: Date
consumed: boolean
}
interface History {
statusId: number
Id: number
status: string
transactionDate: Date
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 {
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

@ -23,6 +23,13 @@ export default [
{
title: 'OBI',
icon: { icon: 'tabler-shopping-bag-check' },
children: [
{
title: 'Orders list',
to: { name: 'obi-order-list' },
icon: { icon: 'tabler-bug' },
},
],
},
{
title: 'Dotsoft',

View File

@ -23,6 +23,13 @@ export default [
{
title: 'OBI',
icon: { icon: 'tabler-shopping-bag-check' },
children: [
{
title: 'Orders',
to: { name: 'obi-order-list' },
icon: { icon: 'tabler-bug' },
},
],
},
{
title: 'Dotsoft',

View File

@ -302,6 +302,7 @@ const exportEXCEL = () => {
:items-per-page="options.itemsPerPage"
:page="options.page"
:options="options"
density="compact"
/>
</VCol>
</Vcard>

View File

@ -0,0 +1,133 @@
<script setup lang="ts">
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()
const route = useRoute('obi-order-details-id')
const orderData = ref<Order>()
const orderTab = ref(null)
const tabs = [
{ title: t('General') },
{ title: t('Preparation') },
{ title: t('Receipt') },
{ title: t('Flow') },
]
const { data, error, execute: fetchOrder } = await useApi<Order>(`/obi/order/${route.params.id}`)
const handleData = () => {
if (error.value)
console.log(error.value)
else if (data.value)
orderData.value = data.value
}
const refreshData = async () => {
await fetchOrder()
handleData()
}
handleData()
</script>
<template>
<VBreadcrumbs
class="px-0 py-2"
:items="[
{ title: t('Home'), to: { name: 'root' } },
{ title: t('Order list'), to: { name: 'obi-order-list' } },
{ title: `#${route.params.id}` },
]"
/>
<div>
<!-- 👉 Header -->
<div class="d-flex justify-space-between align-center flex-wrap gap-y-4 mb-6">
<div
v-if="orderData"
class="d-flex gap-2 align-center mb-0 flex-wrap"
>
<h4 class="text-h3 font-weight-medium">
#{{ orderData.common.orderId }}
</h4>
<div class="d-flex gap-2">
<VChip
label
size="x-large"
v-bind="resolveOrderStatus(orderData.common.statusData.code)"
/>
<VChip
label
size="x-large"
:color="orderData.common.consumed ? 'success' : 'error'"
>
{{ orderData.common.consumed ? 'Consumed' : 'Not consumed' }}
</VChip>
</div>
</div>
<div v-else>
Order not found ...
</div>
<!-- 👉 Reload button -->
<div class="d-flex gap-4">
<VBtn
variant="tonal"
color="primary"
@click="refreshData"
>
{{ t("Reload") }}
</VBtn>
</div>
</div>
<!-- 👉 Order -->
<VRow v-if="orderData">
<VCol
cols="12"
md="5"
lg="4"
>
<OrderPanel :order-data="orderData" />
</VCol>
<VCol
cols="12"
md="7"
lg="8"
>
<VTabs
v-model="orderTab"
class="v-tabs-pill mb-3 disable-tab-transition"
>
<VTab
v-for="tab in tabs"
:key="tab.title"
>
<span>{{ tab.title }}</span>
</VTab>
</VTabs>
<VWindow
v-model="orderTab"
class="disable-tab-transition"
:touch="false"
>
<!-- 👉 General -->
<VWindowItem>
<OrderTabGeneral :order-data="orderData" />
</VWindowItem>
<!-- 👉 Preparation -->
<VWindowItem>
<OrderTabPreparation :order-data="orderData" />
</VWindowItem>
<!-- 👉 Reception -->
<VWindowItem>
<OrderTabReception :order-data="orderData" />
</VWindowItem>
</VWindow>
</VCol>
</VRow>
</div>
</template>

View File

@ -0,0 +1,411 @@
<script setup lang="ts">
import { endOfMonth, format, startOfDay, startOfMonth, subDays, subMonths } from 'date-fns'
import { VDataTableServer } from 'vuetify/labs/VDataTable'
import { paginationMeta } from '@api-utils/paginationMeta'
const { t } = useI18n()
// Data table Headers
const headers = [
{ title: 'Id', key: 'meta.id' },
{ title: t('Order'), key: 'common.orderId' },
{ title: t('Date'), key: 'common.transaction.transactionDate' },
{ title: t('Status'), key: 'common.statusData.code' },
{ title: t('Type'), key: 'common.transaction.transactionTypeDescription' },
]
const selectedStatus = ref()
const status = [
'canceled',
'complete',
'fulfilled',
'intransit',
'intransit polled',
'new_order',
'open',
'polled',
'received',
'unfulfillable',
]
const selectedType = ref()
const type = [
{ id: 'PICKUP', title: 'Pickup Order' },
{ id: 'DELIVERY', title: 'Delivery Order' },
{ id: 'SHIPTOSTORE', title: 'Ship-to-Store Order' },
{ id: 'RETAILPICKUP', title: 'Retail Pickup Order' },
{ id: 'SHIPFORPICKUP', title: 'Ship-for-Pickup Order' },
{ id: 'UNKNOWN', title: 'unknown transaction type' },
]
const searchQuery = ref('')
// Data table options
const itemsPerPage = ref(10)
const page = ref(1)
const sortBy = ref('request_id')
const orderBy = ref('desc')
const beginDate = ref<Date | null>(null)
const endDate = ref<Date | null>(null)
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 updateOptions = (options: any) => {
page.value = options.page
// updateOptions was called systematically by VDataTableServer with an empty object
if (options.sortBy[0]?.key) {
sortBy.value = sortByMapping(options.sortBy[0].key)
orderBy.value = options.sortBy[0].order
}
}
const { data: ordersData } = await useApi<any>(createUrl('/obi/order',
{
query: {
q: searchQuery,
page,
itemsPerPage,
sortBy,
orderBy,
status: selectedStatus,
type: selectedType,
minDate: beginDate,
maxDate: endDate,
},
},
))
const widgetData = computed(() => ordersData.value.statistics)
const orders = computed(() => ordersData.value.orders)
const totalOrder = computed(() => ordersData.value.total)
watch(beginDate, newBeginDate => {
if (endDate.value && newBeginDate !== null && newBeginDate > endDate.value)
endDate.value = newBeginDate
})
watch(endDate, newEndDate => {
if (beginDate.value && newEndDate !== null && newEndDate < beginDate.value)
beginDate.value = newEndDate
})
const selectLastMonth = () => {
beginDate.value = startOfMonth(subMonths(new Date(), 1))
endDate.value = endOfMonth(subMonths(new Date(), 1))
}
const selectThisMonth = () => {
const today = new Date()
const firstDayOfMonth = startOfMonth(today)
const lastDayOfMonth = endOfMonth(today)
beginDate.value = firstDayOfMonth
endDate.value = today < lastDayOfMonth ? today : lastDayOfMonth
}
const selectLast7Days = () => {
beginDate.value = startOfDay(subDays(new Date(), 6))
endDate.value = startOfDay(new Date())
}
const selectToday = () => {
beginDate.value = startOfDay(new Date())
endDate.value = startOfDay(new Date())
}
const clearDates = () => {
beginDate.value = null
endDate.value = null
}
</script>
<template>
<VBreadcrumbs
class="px-0 py-2"
:items="[
{ title: t('Home'), to: { name: 'root' } },
{ title: t('Order list') },
]"
/>
<div>
<VCard class="mb-6">
<!-- 👉 Widgets -->
<VCardText>
<VRow>
<template
v-for="(data, id) in widgetData"
:key="id"
>
<VCol
cols="12"
sm="6"
md="2"
class="px-6"
>
<div
class="d-flex justify-space-between"
:class="$vuetify.display.xs
? 'product-widget'
: $vuetify.display.sm
? id < 2 ? 'product-widget' : ''
: ''"
>
<div class="d-flex flex-column gap-y-1">
<h4 class="text-h4">
{{ data.value }}
</h4>
<VChip
v-bind="resolveOrderStatus(data.title)"
variant="tonal"
label
size="default"
/>
</div>
<VAvatar
variant="tonal"
rounded
size="38"
>
<VIcon
:icon="data.icon"
size="28"
/>
</VAvatar>
</div>
</VCol>
<VDivider
v-if="$vuetify.display.mdAndUp ? id !== widgetData.length - 1
: $vuetify.display.smAndUp ? id % 2 === 0
: false"
vertical
inset
length="55"
/>
</template>
</VRow>
</VCardText>
</VCard>
<VCard
:title="$t('Filters')"
class="mb-6"
>
<VCardText>
<VRow>
<!-- 👉 Select Status -->
<VCol
cols="12"
sm="4"
>
<AppSelect
v-model="selectedStatus"
:placeholder="$t('Status')"
:items="status"
clearable
clear-icon="tabler-x"
/>
</VCol>
<!-- 👉 Select Type -->
<VCol
cols="12"
sm="4"
>
<AppSelect
v-model="selectedType"
:placeholder="$t('Type')"
:items="type"
clearable
clear-icon="tabler-x"
item-text="title"
item-value="id"
/>
</VCol>
</VRow>
<VRow>
<VCol
cols="12"
sm="4"
>
<!-- 👉 Begin Date -->
<AppDateTimePicker
v-model="beginDate"
:placeholder="$t('Date begin')"
:config="{ altFormat: 'J M Y', altInput: true, dateFormat: 'Ymd' }"
/>
</VCol>
<VCol
cols="12"
sm="4"
>
<!-- 👉 End Date -->
<AppDateTimePicker
v-model="endDate"
:placeholder="$t('Date end')"
:config="{ altFormat: 'J M Y', altInput: true, dateFormat: 'Ymd' }"
/>
</VCol>
<VCol
cols="12"
sm="4"
>
<VBtn
variant="text"
@click="selectLastMonth"
>
{{ $t('Last month') }}
</VBtn>
<VBtn
variant="text"
@click="selectThisMonth"
>
{{ $t('This month') }}
</VBtn>
<VBtn
variant="text"
@click="selectLast7Days"
>
{{ $t('Last 7 days') }}
</VBtn>
<VBtn
variant="text"
@click="selectToday"
>
{{ $t('Today') }}
</VBtn>
<VBtn
variant="text"
@click="clearDates"
>
{{ $t('All') }}
</VBtn>
</VCol>
</VRow>
</VCardText>
</VCard>
<!-- 👉 Order Table -->
<VCard>
<!-- 👉 Filters -->
<VCardText>
<div class="d-flex justify-sm-space-between justify-start flex-wrap gap-4">
<VTextField
v-model="searchQuery"
density="compact"
:placeholder="$t('Search')"
style=" max-inline-size: 200px; min-inline-size: 200px;"
/>
<div class="d-flex gap-x-4 align-center">
<AppSelect
v-model="itemsPerPage"
style="min-inline-size: 6.25rem;"
:items="[5, 10, 20, 50, 100]"
/>
<VBtn
variant="tonal"
color="secondary"
prepend-icon="tabler-screen-share"
text="Export"
append-icon="tabler-chevron-down"
/>
</div>
</div>
</VCardText>
<VDivider />
<!-- 👉 Order Table -->
<VDataTableServer
v-model:items-per-page="itemsPerPage"
v-model:page="page"
v-model:sort-desc="orderBy"
v-model:sort-by:="sortBy"
:headers="headers"
:items="orders"
:items-length="totalOrder"
class="text-no-wrap"
density="compact"
@update:options="updateOptions"
>
<!-- Order ID -->
<template #item.common.orderId="{ item }">
<RouterLink
:to="{ name: 'obi-order-details-id', params: { id: item.meta.id } }"
class="font-weight-medium"
>
#{{ item.common.orderId }}
</RouterLink>
</template>
<!-- Date -->
<template #item.common.transaction.transactionDate="{ item }">
{{ format(item.common.transaction.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</template>
<!-- Status -->
<template #item.common.statusData.code="{ item }">
<VChip
v-bind="resolveOrderStatus(item.common.statusData.code)"
label
/>
</template>
<!-- pagination -->
<template #bottom>
<VDivider />
<div class="d-flex align-center justify-sm-space-between justify-center flex-wrap gap-3 pa-5 pt-3">
<p class="text-sm text-disabled mb-0">
{{ paginationMeta({ page, itemsPerPage }, totalOrder) }}
</p>
<VPagination
v-model="page"
:length="Math.ceil(totalOrder / itemsPerPage)"
:total-visible="$vuetify.display.xs ? 1 : Math.min(Math.ceil(totalOrder / itemsPerPage), 5)"
>
<template #prev="slotProps">
<VBtn
variant="tonal"
color="default"
v-bind="slotProps"
:icon="false"
>
{{ $t('$vuetify.pagination.ariaLabel.previous') }}
</VBtn>
</template>
<template #next="slotProps">
<VBtn
variant="tonal"
color="default"
v-bind="slotProps"
:icon="false"
>
{{ $t('$vuetify.pagination.ariaLabel.next') }}
</VBtn>
</template>
</VPagination>
</div>
</template>
</VDataTableServer>
</VCard>
</div>
</template>

View File

@ -14,7 +14,7 @@ const headers = computed(() => [
{ title: 'Pos', key: 'nbcaisses' },
{ title: 'IP', key: 'ip_master', sortable: false },
{ title: t('Phone'), key: 'telephone', sortable: false },
{ title: t('Brand'), key: 'enseigne' },
{ title: t('Sign'), key: 'enseigne' },
{ title: t('Country'), key: 'pays' },
{ title: '', key: 'actions', sortable: false },
])
@ -206,7 +206,7 @@ watch(route, (to, from) => {
>
<AppSelect
v-model="selectedBrand"
:placeholder="$t('Brand')"
:placeholder="$t('Sign')"
:items="brand"
clearable
clear-icon="tabler-x"
@ -275,6 +275,7 @@ watch(route, (to, from) => {
:items-per-page="stStoreList.itemsPerPage"
:page="stStoreList.currentPage"
:sort-by="stStoreList.getSortBy()"
density="compact"
@update:sort-by="sortBy => { stStoreList.setSortBy(sortBy[0]?.key) ; stStoreList.setSortOrder(sortBy[0]?.order) }"
@update:items-per-page="itemsPerPage => { stStoreList.setItemsPerPage(itemsPerPage) }"
@update:page="page => { stStoreList.setCurrentPage(page) }"

View File

@ -1,6 +1,7 @@
export const paginationMeta = <T extends { page: number; itemsPerPage: number }>(options: T, total: number) => {
const start = (options.page - 1) * options.itemsPerPage + 1
const end = Math.min(options.page * options.itemsPerPage, total)
const { t } = useI18n()
return `Showing ${total === 0 ? 0 : start} to ${end} of ${total} entries`
return `${t('Showing')} ${total === 0 ? 0 : start} ${t('to')} ${end} ${t('of')} ${total} ${t('entries')}`
}

View File

@ -70,6 +70,62 @@
"Dates range error": "With a date range, a text of at least 5 characters must be specified",
"Close": "Close",
"Connect to invidual POS": "Connect to invidual POS",
"Sign": "Sign",
"Order list": "قائمة الطلبات",
"Status": "الحالة",
"Type": "النوع",
"Last month": "الشهر الماضي",
"This month": "هذا الشهر",
"Last 7 days": "آخر 7 أيام",
"Today": "اليوم",
"All": "الكل",
"Date begin": "Date begin",
"Date end": "Date end",
"Order": "الطلب",
"showing": "Showing",
"to": "to",
"of": "of",
"entries": "entries",
"Consumed": "Consumed",
"Created": "Created",
"Qty": "Qty",
"General": "General",
"Preparation": "Preparation",
"Receipt": "Receipt",
"Order lines": "Order lines",
"Transaction date history": "Transaction date history",
"Creation date history": "Creation date history",
"Status order history": "Status order history",
"Order was": "Order was",
"Your order has been": "Your order has been",
"Order line was": "Order line was",
"successfully": "successfully",
"OMS": "OMS",
"OMS Partner": "OMS Partner",
"Transaction details": "Transaction details",
"Last status": "Last status",
"Added": "Added",
"Modified": "Modified",
"Transaction": "Transaction",
"Open order": "Open order",
"Origin request": "Origin request",
"Cust Id": "Cust Id",
"Ship for Pickup": "Ship for Pickup",
"Order transaction": "Order transaction",
"Order Details": "Order Details",
"Package": "Package",
"Tracking": "Tracking",
"Cd": "Cd",
"Weight": "Weight",
"N°Exp": "N°Exp",
"Carrier": "Carrier",
"URL": "URL",
"Restocking": "Restocking",
"REMOTE CONTROL": "REMOTE CONTROL",
"EXTERNAL LINK": "EXTERNAL LINK",
"Note: Click on the button below to access DOTSOFT Back-office": "Note: Click on the button below to access DOTSOFT Back-office",
"Open Back-office": "Open Back-office",
"Mount drive": "Mount drive",
"---------------------------": "---------------------------",
"UI Elements": "عناصر واجهة المستخدم",
"Forms & Tables": "النماذج والجداول",
@ -210,7 +266,6 @@
"Ecommerce": "التجارة الإلكترونية",
"Product": "المنتج",
"Category": "الفئة",
"Order": "طلب",
"Details": "تفاصيل",
"Customer": "الزبون",
"Manage Review": "إدارة المراجعة",

View File

@ -70,6 +70,62 @@
"Dates range error": "With a date range, a text of at least 5 characters must be specified",
"Close": "Close",
"Connect to invidual POS": "Connect to invidual POS",
"Orders list": "Orders list",
"Sign": "Sign",
"Status": "Status",
"Type": "Type",
"Last month": "Last month",
"This month": "This month",
"Last 7 days": "Last 7 days",
"Today": "Today",
"All": "All",
"Date begin": "Date begin",
"Date end": "Date end",
"Order": "Order",
"Showing": "Showing",
"to": "to",
"of": "of",
"entries": "entries",
"Consumed": "Consumed",
"Created": "Created",
"Qty": "Qty",
"Preparation": "Preparation",
"Receipt": "Réception",
"Order lines": "Order lines",
"Status history": "Status history",
"Transaction date history": "Transaction date history",
"Creation date history": "Creation date history",
"Status order history": "Status order history",
"Order was": "Order was",
"Order has been": "Order has been",
"Order line was": "Order line was",
"successfully": "successfully",
"OMS": "OMS",
"OMS Partner": "OMS Partner",
"Transaction details": "Transaction details",
"Last status": "Last status",
"Added": "Added",
"Modified": "Modified",
"Transaction": "Transaction",
"Open order": "Open order",
"Origin request": "Origin request",
"Cust Id": "Cust Id",
"Ship for Pickup": "Ship for Pickup",
"Order transaction": "Order transaction",
"Order Details": "Order Details",
"Package": "Package",
"Tracking": "Tracking",
"Cd": "Cd",
"Weight": "Weight",
"N°Exp": "N°Exp",
"Carrier": "Carrier",
"URL": "URL",
"Restocking": "Restocking",
"REMOTE CONTROL": "REMOTE CONTROL",
"EXTERNAL LINK": "EXTERNAL LINK",
"Note: Click on the button below to access DOTSOFT Back-office": "Note: Click on the button below to access DOTSOFT Back-office",
"Open Back-office": "Open Back-office",
"Mount drive": "Mount drive",
"---------------------------": "---------------------------",
"UI Elements": "UI Elements",
"Forms & Tables": "Forms & Tables",
@ -216,7 +272,6 @@
"Swiper": "Swiper",
"Product": "Product",
"Category": "Category",
"Order": "Order",
"Details": "Details",
"Customer": "Customer",
"Manage Review": "Manage Review",

View File

@ -70,6 +70,63 @@
"Dates range error": "Dans le cas d'une plage de dates, un texte d'au moins 5 caractères doit être spécifié.",
"Close": "Fermer",
"Connect to invidual POS": "Connexion à une caisse individuelle",
"Orders list": "Liste des commandes",
"Sign": "Enseigne",
"Order list": "Liste des commandes",
"Status": "Statut",
"Type": "Type",
"Last month": "Mois dernier",
"This month": "Ce mois",
"Last 7 days": "7 derniers jours",
"Today": "Aujourd'hui",
"All": "Tous",
"Date begin": "Date début",
"Date end": "Date fin",
"Order": "Commande",
"Showing": "Affichage",
"to": "à",
"of": "parmi",
"entries": "entrées",
"Consumed": "Consumed",
"Created": "Créé",
"Qty": "Qté",
"Preparation": "Preparation",
"Receipt": "Réception",
"Order lines": "Lignes de commande",
"Status history": "Histo. statuts",
"Transaction date history": "Histo. dates transaction",
"Creation date history": "Histo. dates création",
"Status order history": "Historique statuts commande",
"Order was": "Commande a été",
"Order has been": "Commande a été",
"Order line was": "Ligne a été",
"successfully": "avec succès",
"OMS": "OMS",
"OMS Partner": "Partenaire OMS",
"Transaction details": "Détails transaction",
"Last status": "Dernier statut",
"Added": "Ajouté",
"Modified": "Modifié",
"Transaction": "Transaction",
"Open order": "Commande",
"Origin request": "Origine",
"Cust Id": "Id client",
"Ship for Pickup": "Ship for Pickup",
"Order transaction": "Transaction commande",
"Order Details": "Details commande",
"Package": "Colis",
"Tracking": "Tracking",
"Cd": "Cd",
"Weight": "Poids",
"N°Exp": "N°Exp",
"Carrier": "Transport",
"URL": "URL",
"Restocking": "Restocking",
"REMOTE CONTROL": "CONTROLE A DISTANCE",
"EXTERNAL LINK": "LIEN EXTERNE",
"Note: Click on the button below to access DOTSOFT Back-office": "Note: Cliquez sur le bouton ci-dessous pour accéder au Back-office DOTSOFT",
"Open Back-office": "Ouvrir DOTSOFT",
"Mount drive": "Monter lecteur",
"---------------------------": "---------------------------",
"UI Elements": "ÉLÉMENTS DE L'UI",
"Forms & Tables": "Formulaires et tableaux",
@ -212,7 +269,6 @@
"Ecommerce": "Commerce électronique",
"Product": "Produit",
"Category": "Catégorie",
"Order": "Ordre",
"Details": "Détails",
"Customer": "Client",
"Manage Review": "Gérer la revue",
@ -250,7 +306,7 @@
"dataFooter": {
"itemsPerPageText": "Objets par page:",
"itemsPerPageAll": "Tout",
"pageText": "{0}-{1} of {2}",
"pageText": "{0}-{1} de {2}",
"firstPage": "Première page",
"prevPage": "Page précédente",
"nextPage": "Page suivante",

View File

@ -6,10 +6,13 @@
/**
* you need to import the some interfaces
*/
import ar from '@/plugins/i18n/locales/ar.json';
import en from '@/plugins/i18n/locales/en.json';
import fr from '@/plugins/i18n/locales/fr.json';
import 'vue-i18n';
type LocaleMessage = typeof en
type LocaleMessage = typeof en & typeof fr & typeof ar;
declare module 'vue-i18n' {
export interface DefineLocaleMessage extends LocaleMessage {

View File

@ -1,10 +1,13 @@
import { deepMerge } from '@antfu/utils'
import type { App } from 'vue'
import { useI18n } from 'vue-i18n'
import { createVuetify } from 'vuetify'
import { VBtn } from 'vuetify/components/VBtn'
import { createVueI18nAdapter } from 'vuetify/locale/adapters/vue-i18n'
import defaults from './defaults'
import { icons } from './icons'
import { staticPrimaryColor, themes } from './theme'
import { getI18n } from '@/plugins/i18n/index'
// Styles
import { cookieRef } from '@/@layouts/stores/config'
@ -37,7 +40,9 @@ export default function (app: App) {
defaults,
icons,
theme: optionTheme,
locale: {
adapter: createVueI18nAdapter({ i18n: getI18n(), useI18n }),
},
})
app.use(vuetify)

12
src/utils/order.ts Normal file
View File

@ -0,0 +1,12 @@
export const resolveOrderStatus = (status: string) => {
if (status === 'received' || 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 === 'canceled' || status === 'unfulfillable')
return { text: status, color: 'error' }
else
return { text: status, color: 'primary' }
}

View File

@ -0,0 +1,241 @@
<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>()
const { t } = useI18n()
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">
{{ $t('OMS') }}
</h6>
<p class="mb-2">
{{ $t('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">
{{ $t('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">{{ $t('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">{{ $t('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">{{ $t('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"
>
{{ $t('Transaction') }}
</VBtn>
</VCardText>
</VCol>
<VCol
v-if="omsData"
cols="6"
class="text-right"
>
<VCardText class="pa-4">
<VBtn
class="mt-0"
@click="openOmsOrderPage"
>
{{ $t('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>{{ t("Order transaction") }}</VToolbarTitle>
<VSpacer />
<VToolbarItems>
<VBtn
variant="text"
@click="OrderMessageDialogVisible = false"
>
{{ t("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

@ -0,0 +1,105 @@
<script setup lang="ts">
import { format } from 'date-fns'
import type { Order } from '@/models/Order'
import OrderOms from '@/views/pages/order/view/OrderOms.vue'
const props = defineProps<Props>()
interface Props {
orderData: Order
}
</script>
<template>
<VRow>
<VCol cols="12">
<VCard
v-if="props.orderData"
class="mb-4"
>
<!-- 👉 Order Details -->
<VCardText>
<div class="text-disabled text-uppercase text-sm">
{{ $t('Order Details') }}
</div>
<VList class="card-list mt-2">
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Origin request') }}:</span>
<span>
{{ props.orderData.common.requestingLocationCd }} / {{ props.orderData.common.requestingSystemCd }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Cust Id') }}:</span>
<span>
{{ props.orderData.common.customerId }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Created') }}:</span>
<span>
{{ format(props.orderData.common.fdateCreation, "EEEE d MMMM yyyy HH:mm:ss") }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Ship for Pickup') }}:</span>
<span>
{{ props.orderData.common.shipforpickupLocationCd }} / {{ props.orderData.common.shipforpickupSystemCd }}
</span>
</div>
</VListItem>
</VList>
<div class="text-disabled text-uppercase mt-4 text-sm">
{{ $t('Transaction') }}
</div>
<VList class="card-list mt-2">
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">No:</span>
<span>
{{ props.orderData.common.transaction.transactionNo }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Date:</span>
<span>
{{ format(props.orderData.common.transaction.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">Type:</span>
<span>
{{ props.orderData.common.transaction.transactionTypeDescription }}
</span>
</div>
</VListItem>
</VList>
</VCardText>
</VCard>
<!-- 👉 OMS Proximis -->
<OrderOms :order-data="orderData" />
</VCol>
</VRow>
</template>
<style lang="scss">
.card-list {
--v-card-list-gap: 0.75rem;
}
.text-capitalize {
text-transform: capitalize !important;
}
</style>

View File

@ -0,0 +1,164 @@
<script setup lang="ts">
import { format } from 'date-fns'
import { VDataTable } from 'vuetify/labs/VDataTable'
import type { Order } from '@/models/Order'
const props = defineProps<Props>()
const { t } = useI18n()
interface Props {
orderData: Order
}
const headers = computed(() => [
{ title: '', key: 'data-table-expand' },
{ title: '#', key: 'lineItemNo' },
{ title: t('Item'), key: 'itemId' },
{ title: t('Qty'), key: 'orderedLineQty' },
{ title: t('Date'), key: 'transactionDate' },
{ title: t('Status'), key: 'status' },
{ title: t('Consumed'), key: 'consumed' },
])
</script>
<template>
<!-- 👉 Order Details -->
<VCard class="mb-6">
<VCardItem>
<template #title>
<h5 class="text-h5">
{{ $t('Order lines') }}
</h5>
</template>
</VCardItem>
<VDivider />
<VDataTable
:headers="headers"
:items="props.orderData.lines"
density="compact"
class="text-no-wrap"
expand-on-click
>
<template #item.lineItemNo="{ item }">
<VChip
variant="tonal"
label
>
{{ item.lineItemNo }}
</VChip>
</template>
<template #item.status="{ item }">
<VChip
variant="outlined"
label
>
{{ item.status }}
</VChip>
</template>
<!-- Expanded Row Data -->
<template #expanded-row="slotProps">
<td :colspan="headers.length">
<VCardText>
<VTimeline
truncate-line="both"
align="start"
side="end"
line-color="primary"
density="compact"
class="v-timeline-density-compact"
>
<template
v-for="(historyItem, index) in slotProps.item.history"
:key="index"
>
<VTimelineItem
dot-color="primary"
size="x-small"
>
<div class="d-flex justify-space-between align-center">
<div class="app-timeline-title">
<VChip
variant="outlined"
label
>
{{ historyItem.status }}
</VChip>
(Id#{{ historyItem.statusId }})
</div>
<div class="app-timeline-meta">
{{ format(historyItem.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</div>
</div>
</VTimelineItem>
</template>
</VTimeline>
</VCardText>
</td>
</template>
<template #item.transactionDate="{ item }">
{{ format(new Date(item.transactionDate), 'dd/MM/yyyy HH:mm:ss') }}
</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 }">
{{ format(new Date(item.fdateCreation), 'dd/MM/yyyy HH:mm:ss') }}
</template>
<template #bottom />
</VDataTable>
</VCard>
<!-- 👉 Order History -->
<VCard :title="$t('Status order history')">
<VCardText>
<VTimeline
truncate-line="both"
align="start"
side="end"
line-color="primary"
density="compact"
class="v-timeline-density-compact"
>
<template
v-for="(historyItem, index) in props.orderData.history"
:key="index"
>
<VTimelineItem
dot-color="primary"
size="x-small"
>
<div class="d-flex justify-space-between align-center">
<div class="app-timeline-title">
<VChip
variant="outlined"
label
>
{{ historyItem.status }}
</VChip>
(Id#{{ historyItem.statusId }})
</div>
<div class="app-timeline-meta">
{{ format(historyItem.transactionDate, "EEEE d MMMM yyyy HH:mm:ss") }}
</div>
</div>
</VTimelineItem>
</template>
</VTimeline>
</VCardText>
</VCard>
</template>

View File

@ -0,0 +1,184 @@
<script setup lang="ts">
import { format } from 'date-fns'
import type { Order } from '@/models/Order'
// eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
const props = defineProps<Props>()
// eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
const { t } = useI18n()
interface Props {
orderData: Order
}
const panelStatus = ref(0)
</script>
<template>
<!-- 👉 Preparations -->
<VExpansionPanels
v-model="panelStatus"
variant="accordion"
>
<template v-if="orderData.preparations && orderData.preparations.length > 0">
<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>
Prep #{{ index + 1 }} /
<VChip
v-bind="resolveOrderStatus(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">{{ $t('N°Exp') }}:</span>
<span>
{{ preparationLine.numeroExpedition }}
</span>
</div>
</VListItem>
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Cd') }}:</span>
<span>
{{ preparationLine.fulfillmentSystemCd }} / {{ preparationLine.fulfillmentLocationCd }}
</span>
</div>
</VListItem>
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Qty') }}:</span>
<span>
{{ preparationLine.validatedFulfillQty }} / {{ preparationLine.fulfillQty }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Carrier') }}:</span>
<span>
{{ preparationLine.carrier }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Tracking') }}:</span>
<span>
{{ preparationLine.trackingCode }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('URL') }}:</span>
<span>
<a
v-if="preparationLine.trackingUrl"
:href="preparationLine.trackingUrl"
target="_blank"
rel="noopener noreferrer"
style="text-decoration: underline;"
>Link</a>
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Restocking') }}:</span>
<span>
{{ preparationLine.restockingCode }}
</span>
</div>
</VListItem>
<VListItem>
<VChip
v-bind="resolveOrderStatus(preparationLine.status)"
variant="tonal"
label
size="x-small"
/>
{{ format(section.transactionDate, "dd/MM/yyyy HH:mm:ss") }}
</VListItem>
</VList>
</VCardText>
</VCard>
</VCol>
</template>
</VRow>
</div>
</VExpansionPanelText>
</VExpansionPanel>
</template>
<div
v-else
class="text-h4"
>
No preparation available
</div>
</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,162 @@
<script setup lang="ts">
import { format } from 'date-fns'
import type { Order } from '@/models/Order'
// eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
const props = defineProps<Props>()
// eslint-disable-next-line unused-imports/no-unused-vars, @typescript-eslint/no-unused-vars
const { t } = useI18n()
interface Props {
orderData: Order
}
const panelStatus = ref(0)
</script>
<template>
<!-- 👉 Receptions -->
<VExpansionPanels
v-model="panelStatus"
variant="accordion"
>
<template v-if="orderData.receptions && orderData.receptions.length > 0">
<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>
Recep #{{ index + 1 }} /
<VChip
v-bind="resolveOrderStatus(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">{{ $t('Package') }}:</span>
<span>
{{ receptionLine.colisId }}
</span>
</div>
</VListItem>
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Cd') }}:</span>
<span>
{{ receptionLine.intransitSystemCd }} / {{ receptionLine.intransitLocationCd }}
</span>
</div>
</VListItem>
<VListItem cla>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Qty') }}:</span>
<span>
{{ receptionLine.validatedIntransitQty }} / {{ receptionLine.intransitQty }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Tracking') }}:</span>
<span>
{{ receptionLine.trackingNumber }}
</span>
</div>
</VListItem>
<VListItem>
<div class="text-body-1">
<span class="font-weight-bold me-2">{{ $t('Weight') }}:</span>
<span>
{{ receptionLine.orderLineShipWeight }}
</span>
</div>
</VListItem>
<VListItem>
<VChip
v-bind="resolveOrderStatus(receptionLine.status)"
variant="tonal"
label
size="x-small"
/>
{{ format(section.transactionDate, "dd/MM/yyyy HH:mm:ss") }}
</VListItem>
</VList>
</VCardText>
</VCard>
</VCol>
</template>
</VRow>
</div>
</VExpansionPanelText>
</VExpansionPanel>
</template>
<div
v-else
class="text-h4"
>
No reception available
</div>
</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

@ -24,10 +24,17 @@ const props = defineProps<Props>()
<VChip
label
size="small"
class="text-capitalize"
class="text-capitalize me-1"
>
{{ pos.ip }}
</VChip>
<VChip
label
size="small"
class="text-capitalize"
>
{{ pos.version }}
</VChip>
/
<VChip
label

View File

@ -26,15 +26,10 @@ const fetchData = async () => {
}
watchEffect(() => {
// eslint-disable-next-line sonarjs/no-collapsible-if
if (props.item)
// eslint-disable-next-line curly
if (!(props.item.trim() === ''))
fetchData()
if (route.query.dbHost && props.item && !(props.item.trim() === ''))
fetchData()
})
// const { t } = useI18n()
const headers = computed(() => [
{ title: t('ITEM_ID'), key: 'itemId' },
{ title: t('LEVEL'), key: 'itemLevelCode' },

View File

@ -30,15 +30,10 @@ const fetchData = async () => {
}
watchEffect(() => {
// eslint-disable-next-line sonarjs/no-collapsible-if
if (props.item)
// eslint-disable-next-line curly
if (!(props.item.trim() === ''))
fetchData()
if (route.query.dbHost && props.item && !(props.item.trim() === ''))
fetchData()
})
// const { t } = useI18n()
const headers = computed(() => [
{ title: t('ITEM_ID'), key: 'itemId' },
{ title: 'LEVEL', key: 'level' },

View File

@ -30,15 +30,10 @@ const fetchData = async () => {
}
watchEffect(() => {
// eslint-disable-next-line sonarjs/no-collapsible-if
if (props.item)
// eslint-disable-next-line curly
if (!(props.item.trim() === ''))
fetchData()
if (route.query.dbHost && props.item && !(props.item.trim() === ''))
fetchData()
})
// const { t } = useI18n()
const headers = computed(() => [
{ title: t('ITEM_ID'), key: 'itemId' },
{ title: t('LEVEL'), key: 'level' },

View File

@ -26,15 +26,10 @@ const fetchData = async () => {
}
watchEffect(() => {
// eslint-disable-next-line sonarjs/no-collapsible-if
if (props.item)
// eslint-disable-next-line curly
if (!(props.item.trim() === ''))
fetchData()
if (route.query.dbHost && props.item && !(props.item.trim() === ''))
fetchData()
})
// const { t } = useI18n()
const headers = computed(() => [
{ title: t('ITEM_ID'), key: 'itemId' },
{ title: 'LOCATION', key: 'invLocationId' },

View File

@ -4,6 +4,10 @@ import type { StoreData } from '@/models/storeData'
import logoVNC from '@images/misc/remote_128.png'
const props = defineProps<Props>()
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { t } = useI18n()
const drive = ['M:', 'N:', 'O:', 'P:', 'Q:', 'R:', 'S:', 'T:']
const selectedProtocol = ref('hdpos')
@ -40,6 +44,12 @@ const mountDrive = (ip: string, drive: string) => {
window.open(url, '_blank')
}
const openBO = () => {
const url = `http://aspf.adic.lan/site/login/login.asp?dataid=1&validated=1&input_login=caisse${localStoreData.value.store.id_structure}-20&input_password=caisse&id_caisse=20`
window.open(url, '_blank')
}
</script>
<template>
@ -48,11 +58,11 @@ const mountDrive = (ip: string, drive: string) => {
cols="12"
md="6"
>
<VCard
flat
border
>
<VCard>
<VCardText>
<p>
{{ $t('REMOTE CONTROL') }}
</p>
<VCardText class="text-center d-flex align-center justify-left">
<img
:src="logoVNC"
@ -116,14 +126,14 @@ const mountDrive = (ip: string, drive: string) => {
color="primary"
@click="mountDrive(caisse.ip, caisse.drive)"
>
Mount drive {{ caisse.drive }}
{{ $t('Mount drive') }} {{ caisse.drive }}
</VBtn>
<VBtn
v-else
disabled
color="primary"
>
Mount drive
{{ $t('Mount drive') }}
</VBtn>
</VCol>
</VRow>
@ -132,5 +142,30 @@ const mountDrive = (ip: string, drive: string) => {
</VCardText>
</VCard>
</VCol>
<VCol
cols="12"
md="6"
>
<VCard>
<!-- 👉 BO access Link -->
<VCardText>
<p>
{{ $t('EXTERNAL LINK') }}
<VAlert
color="warning"
variant="tonal"
class="mb-5 mt-4"
>
{{ $t('Note: Click on the button below to access DOTSOFT Back-office') }}
</VAlert>
</p>
<div>
<VBtn @click="openBO">
{{ $t('Open Back-office') }}
</VBtn>
</div>
</VCardText>
</VCard>
</VCol>
</VRow>
</template>

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: {

2
typed-router.d.ts vendored
View File

@ -43,6 +43,8 @@ declare module 'vue-router/auto/routes' {
'$error': RouteRecordInfo<'$error', '/:error(.*)', { error: ParamValue<true> }, { error: ParamValue<false> }>,
'flux-bl-not-sent': RouteRecordInfo<'flux-bl-not-sent', '/flux/bl/not_sent', Record<never, never>, Record<never, never>>,
'login': RouteRecordInfo<'login', '/login', Record<never, never>, Record<never, never>>,
'obi-order-details-id': RouteRecordInfo<'obi-order-details-id', '/obi/order/details/:id', { id: ParamValue<true> }, { id: ParamValue<false> }>,
'obi-order-list': RouteRecordInfo<'obi-order-list', '/obi/order/list', Record<never, never>, Record<never, never>>,
'store-details': RouteRecordInfo<'store-details', '/store/details', Record<never, never>, Record<never, never>>,
'store-list': RouteRecordInfo<'store-list', '/store/list', Record<never, never>, Record<never, never>>,
'xadmin-log': RouteRecordInfo<'xadmin-log', '/xadmin/log', Record<never, never>, Record<never, never>>,