Compare commits

..

18 Commits

Author SHA1 Message Date
kevin 16abc30b9f Merge branch 'develop' into feat/276-lister-expeditions-terminees
# Conflicts:
#	CHANGELOG.md
2026-02-12 09:58:16 +01:00
kevin 7e2f23c6b6 Merge remote-tracking branch 'origin/develop' into feat/276-lister-expeditions-terminees
# Conflicts:
#	CHANGELOG.md
2026-02-12 09:24:56 +01:00
kevin 886b90215a feat : lister les expeditions terminees 2026-02-12 08:58:29 +01:00
kevin 265e85b8f4 Merge branch 'refs/heads/develop' into feat/276-lister-expeditions-terminees 2026-02-12 08:57:48 +01:00
kevin b4e024590e feat : changelog 2026-02-12 08:30:34 +01:00
kevin 74af5d30ba feat : ajout d'une page de creation d'une expedition 2026-02-12 08:19:47 +01:00
kevin b905cb66aa Merge branch 'refs/heads/develop' into feat/271-expedition-etape-1
# Conflicts:
#	CHANGELOG.md
2026-02-12 08:18:17 +01:00
kevin 5f4139fde3 feat : ajout d'une page de creation d'une expedition 2026-02-11 16:12:33 +01:00
kevin 0181d72144 Merge branch 'develop' into feat/271-expedition-etape-1 2026-02-11 08:03:12 +01:00
kevin bffdc88701 feat : creer une nouvelle expedtion (WIP) 2026-02-10 16:16:05 +01:00
kevin 42c5a3b2d2 Merge branch 'develop' into feat/271-expedition-etape-1
# Conflicts:
#	.idea/data_source_mapping.xml
#	src/Entity/Carrier.php
2026-02-10 08:59:24 +01:00
Matteo 28d5bc7599 Merge remote-tracking branch 'refs/remotes/origin/develop' into feat/271-expedition-etape-1
# Conflicts:
#	.idea/workspace.xml
2026-02-05 10:47:05 +01:00
Matteo 69d047fca0 feat : #271 -Créer une nouvelle expédition 2026-02-05 09:10:52 +01:00
Matteo ba4375f609 feat : Expedition dev back-end WIP 2026-02-04 16:58:55 +01:00
Matteo e249d44e78 feat : mise à jour du bon de réception WIP 2026-02-03 17:34:35 +01:00
Matteo e8189a4d04 feat : mise à jour du bon de réception WIP 2026-02-03 17:32:39 +01:00
Matteo 081c2ef403 feat : mise à jour du bon de réception WIP 2026-02-03 17:16:47 +01:00
Matteo 5fd2ab8470 feat : mise à jour du bon de réception wip 2026-02-03 17:16:19 +01:00
23 changed files with 150 additions and 374 deletions
-1
View File
@@ -43,7 +43,6 @@ Ajouter dans le fichier .env du frontend
* [#313] Admin modification creation fournisseur
* [#275] Lister les expéditions en attente
* [#276] Lister les expéditions terminées
* [#324] Creation page admin listing clients
### Changed
+1 -1
View File
@@ -1,2 +1,2 @@
parameters:
app.version: '0.0.42'
app.version: '0.0.41'
@@ -29,7 +29,7 @@
<button
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
@click="goNext"
>Valider
>Peser
</button>
</div>
</template>
@@ -119,7 +119,7 @@
<button
type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end"
>Valider
>Peser
</button>
</div>
</form>
@@ -342,7 +342,7 @@ onMounted(async () => {
// Ajuste driver/vehicle quand le transporteur change (logique LIOT)
watch(
() => [form.supplierId, form.addressId, suppliers.value],
() => [form.supplierId, suppliers.value],
() => {
if (!form.supplierId) {
form.addressId = ''
@@ -359,11 +359,7 @@ watch(
(address) => String(address.id) === form.addressId
)
if (!matches) {
if (supplierAddresses.value.length === 1) {
form.addressId = String(supplierAddresses.value[0].id)
} else {
form.addressId = ''
}
form.addressId = ''
}
},
{immediate: true}
@@ -67,7 +67,7 @@
<button
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
@click="goNext"
>Valider
>Peser
</button>
</div>
</template>
@@ -26,7 +26,7 @@
v-if="displayWeight !== null && !showGenerateReceipt"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] ml-4"
@click="saveWeight"
>Valider</button>
>Valider la pesée</button>
<button
v-if="showGenerateReceipt"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] ml-4"
@@ -36,7 +36,7 @@
</template>
<script setup lang="ts">
import {computed, onMounted} from 'vue'
import { computed } from 'vue'
import { storeToRefs } from 'pinia'
import { useWeighing } from '~/composables/useWeighing'
import { usePdfPrinter } from '~/composables/usePdfPrinter'
@@ -94,7 +94,7 @@ const printReceipt = async () => {
// Récupère le poids dès l'arrivée sur l'écran
onMounted(() => {
if (displayWeight.value === null) {
if (false === displayWeight.value) {
fetchWeight()
}
})
@@ -1,80 +1,79 @@
<template>
<form @submit.prevent="validate">
<div class="flex flex-col items-center gap-16">
<div class="flex flex-col items-center gap-16">
<div
class="flex flex-col gap-16 items-center w-full">
<UiTextInput
id="merchandise-type"
v-model="selectedMerchandiseTypeId"
label="Type de marchandises"
:value="reception.merchandiseType?.label"
wrapper-class="w-[550px]"
:disabled="true"
/>
<div
class="flex flex-col gap-16 items-center w-full">
v-if="merchandiseTypeId && isAutres"
class="flex flex-col w-full max-w-[550px]"
>
<UiTextInput
id="merchandise-type"
v-model="selectedMerchandiseTypeId"
label="Type de marchandises"
:value="reception.merchandiseType?.label"
wrapper-class="w-[550px]"
:disabled="true"
id="merchandise-detail"
:disabled="!auth.isAdmin"
v-model="merchandiseDetail"
label="Préciser"
placeholder="Précisions complémentaires"
:maxlength="255"
/>
</div>
<div
v-if="merchandiseTypeId && !isGranule"
class="flex gap-4 w-[550px] justify-evenly"
>
<div
v-if="merchandiseTypeId && isAutres"
class="flex flex-col w-full max-w-[550px]"
v-for="building in buildings"
:key="building.id"
>
<UiTextInput
id="merchandise-detail"
<UiCheckbox
v-model="selectedBuildingIds"
:value="String(building.id)"
:label="building.label"
:disabled="!auth.isAdmin"
v-model="merchandiseDetail"
label="Préciser"
placeholder="Précisions complémentaires"
:maxlength="255"
label-class="text-xl"
/>
</div>
</div>
<div
v-if="merchandiseTypeId && !isGranule"
class="flex gap-4 w-[550px] justify-evenly"
>
<div
v-for="building in buildings"
:key="building.id"
>
<UiCheckbox
v-model="selectedBuildingIds"
:value="String(building.id)"
:label="building.label"
:disabled="!auth.isAdmin"
label-class="text-xl"
/>
</div>
</div>
<div
v-if="merchandiseTypeId && isGranule"
class="flex flex-col gap-10 w-full max-w-[1100px]"
>
<div class="grid grid-cols-1 gap-10 md:grid-cols-4">
<div v-for="type in pelletTypes" :key="type.id" class="flex flex-col gap-4">
<p class="font-bold uppercase">{{ type.label }}</p>
<div
v-for="building in buildings"
:key="building.id"
class="flex items-center gap-2 text-lg"
>
<UiCheckbox
v-model="selectedPelletBuildingIds[String(type.id)]"
:value="String(building.id)"
:label="building.label"
:disabled="!auth.isAdmin"
label-class="text-lg"
/>
</div>
<div
v-if="merchandiseTypeId && isGranule"
class="flex flex-col gap-10 w-full max-w-[1100px]"
>
<div class="grid grid-cols-1 gap-10 md:grid-cols-4">
<div v-for="type in pelletTypes" :key="type.id" class="flex flex-col gap-4">
<p class="font-bold uppercase">{{ type.label }}</p>
<div
v-for="building in buildings"
:key="building.id"
class="flex items-center gap-2 text-lg"
>
<UiCheckbox
v-model="selectedPelletBuildingIds[String(type.id)]"
:value="String(building.id)"
:label="building.label"
:disabled="!auth.isAdmin"
label-class="text-lg"
/>
</div>
</div>
</div>
</div>
<button
v-if="auth.isAdmin"
type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
:disabled="!auth.isAdmin"
>Valider
</button>
</div>
<button
type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
:disabled="!auth.isAdmin"
>Valider
</button>
</div>
</form>
</template>
+11 -39
View File
@@ -1,42 +1,27 @@
<template>
<form @submit.prevent="validate">
<div class="grid grid-cols-2 gap-x-40 gap-y-8 mb-8">
<UiTextInput
label="Dsd"
class="col-start-2"
v-model="form.weights[0].dsd"
:disabled="!auth.isAdmin"
/>
<UiDateInput
label="Date pesée"
v-model="form.weights[0].weighedAt"
:disabled="!auth.isAdmin"
/>
</div>
<div class="grid grid-cols-2 gap-x-40 mb-16">
<div class="grid grid-cols-2 gap-x-40 gap-y-8 mb-16">
<UiNumberInput
label="Pesée à vide"
labelClass="font-bold uppercase text-xl"
v-model="form.weights[0].weight"
wrapper-class="col-start-1 row-start-1"
:disabled="!auth.isAdmin"
:min="0"
/>
<UiNumberInput
label="Pesée à plein"
labelClass="font-bold uppercase text-xl"
v-model="form.weights[1].weight"
wrapper-class="col-start-2 row-start-1"
:disabled="!auth.isAdmin"
:min="0"
/>
</div>
<div class="flex justify-center">
<button
v-if="auth.isAdmin"
type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
:disabled="!auth.isAdmin"
>
Valider
</button>
@@ -47,7 +32,7 @@
<script setup lang="ts">
import type {ReceptionFormWeight} from '~/services/dto/reception-data'
import {getReception} from '~/services/reception'
import { getReception } from '~/services/reception'
import {updateWeight} from "~/services/weight";
import {useAuthStore} from "~/stores/auth";
@@ -60,8 +45,8 @@ const auth = useAuthStore()
const form = reactive({
weights: [
{id: 0, type: 'tare' as const, weight: 0, dsd: null, weighedAt: null},
{id: 0, type: 'gross' as const, weight: 0, dsd: null, weighedAt: null}
{ id: 0, type: 'tare' as const, weight: 0 },
{ id: 0, type: 'gross' as const, weight: 0 }
]
})
@@ -69,8 +54,8 @@ const hydrateFromReception = (reception: ReceptionFormWeight) => {
const tare = reception.weights.find(weight => weight.type === 'tare')
const gross = reception.weights.find(weight => weight.type === 'gross')
if (tare) form.weights[0] = {...form.weights[0], ...tare}
if (gross) form.weights[1] = {...form.weights[1], ...gross}
if (tare) form.weights[0] = { ...tare }
if (gross) form.weights[1] = { ...gross }
}
onMounted(async () => {
@@ -79,24 +64,11 @@ onMounted(async () => {
})
async function validate() {
const sharedDsd =
form.weights[0].dsd === null || form.weights[0].dsd === undefined || form.weights[0].dsd === ''
? null
: Number(form.weights[0].dsd)
const sharedWeighedAt =
form.weights[0].weighedAt === null || form.weights[0].weighedAt === undefined || form.weights[0].weighedAt === ''
? null
: form.weights[0].weighedAt
for (const weight of form.weights) {
if (weight.id) {
await updateWeight(weight.id, {
weight: weight.weight,
dsd: Number.isFinite(sharedDsd) ? sharedDsd : null,
weighedAt: sharedWeighedAt
})
await updateWeight(weight.id, {weight: weight.weight})
}
}
}
</script>
@@ -23,14 +23,14 @@
/>
<!-- Type d'expédition -->
<div class="col-start-1 row-start-4">
<label class="font-bold uppercase text-xl mb-2">
<label class="font-bold uppercase text-xl mb-2 block">
Type d'expédition
</label>
<div class="grid grid-cols-2 gap-x-8">
<div
v-for="type in bovineShipment"
:key="type.id"
class="mt-2 flex flex-row gap-6"
class="mt-8 flex flex-row gap-6"
>
<UiNumberInput
:label="type.label"
@@ -344,7 +344,7 @@ watch(
)
// Ajuste driver/vehicle quand le transporteur change (logique LIOT)
watch(
() => [form.customerId, form.addressId, customers.value],
() => [form.customerId, customers.value],
() => {
if (!form.customerId) {
form.addressId = ''
@@ -361,11 +361,7 @@ watch(
(address) => String(address.id) === form.addressId
)
if (!matches) {
if (customerAddresses.value.length === 1) {
form.addressId = String(customerAddresses.value[0].id)
} else {
form.addressId = ''
}
form.addressId = ''
}
},
{immediate: true}
+2 -2
View File
@@ -3,7 +3,7 @@
<label
v-if="label"
:for="id"
class="text-xl flex items-center"
class="text-xl text-bold flex items-center"
:class="labelClass"
>
<span
@@ -25,7 +25,7 @@
:step="step"
:disabled="disabled"
v-bind="attrs"
class="border-b border-black text-xl bg-transparent w-16"
class="border-b border-black text-xl bg-transparent w-12"
:class="[
isEmpty ? 'text-neutral-400' : 'text-black',
disabled ? 'cursor-not-allowed' : 'cursor-text',
+11 -43
View File
@@ -24,64 +24,34 @@
<aside class="bg-primary-500 text-white min-h-0 flex flex-col justify-between">
<div class="flex flex-col gap-4 p-4 font-bold text-xl">
<!-- Liste des liens à ajouter ci-dessous -->
<NuxtLink
to="/admin/dashboard"
custom v-slot="{ href, navigate, isExactActive }">
<a :href="href"
@click="navigate"
:class="isExactActive ? 'opacity-100' : 'opacity-50'">
Tableau de bord
</a>
<NuxtLink to="/admin/dashboard">
Tableau de bord
</NuxtLink>
<NuxtLink
to="/admin/supplier/supplier-list"
custom v-slot="{ href, navigate }">
<a :href="href"
@click="navigate"
:class="route.path.startsWith('/admin/supplier') ? 'opacity-100' : 'opacity-50'">
Fournisseur
</a>
<NuxtLink to="/admin/supplier/supplier-list">
Fournisseur
</NuxtLink>
<NuxtLink
to="/admin/carrier/carrier-list"
custom v-slot="{ href, navigate }">
<a :href="href"
@click="navigate"
:class="route.path.startsWith('/admin/carrier') ? 'opacity-100' : 'opacity-50'">
Transporteur
</a>
<NuxtLink to="/admin/carrier/carrier-list">
Transporteur
</NuxtLink>
<NuxtLink to="/admin/user/list" custom v-slot="{ href, navigate }">
<a
:href="href"
@click="navigate"
:class="route.path.startsWith('/admin/user') ? 'opacity-100' : 'opacity-50'"
>
Utilisateurs
</a>
</NuxtLink>
<NuxtLink to="/admin/customer/customer-list">
Client
<NuxtLink to="/admin/user/list">
Utilisateurs
</NuxtLink>
</div>
<div class="p-4">
<p class="font-bold text-white text-left">v{{ version }}</p>
<button
@click="handleLogout"
class="w-full bg-red-600 hover:bg-red-700 py-2 rounded font-bold"
>
Déconnexion
</button>
<p class="font-bold text-white text-center pt-2">
v{{ version }}
</p>
</div>
</aside>
<main class="min-h-0 overflow-auto px-12 py-12 ">
<div class="w-full ">
<slot/>
<slot />
</div>
</main>
</div>
@@ -93,9 +63,7 @@
import {useAuthStore} from '~/stores/auth'
const auth = useAuthStore()
const {version} = useAppVersion()
const route = useRoute()
const { version } = useAppVersion()
const handleLogout = async () => {
try {
await auth.logout()
+4 -5
View File
@@ -1,6 +1,6 @@
<template>
<div class="min-h-screen text-neutral-900 grid grid-rows-[85px,1fr]">
<header class="w-full border-b border-neutral-200 bg-primary-500">
<div class="min-h-screen bg-white text-neutral-900">
<header class="w-full border-b border-neutral-200 bg-primary-500">
<div class="flex w-full items-center justify-center px-6 py-4">
<button
type="button"
@@ -21,13 +21,12 @@
</a>
</NuxtLink>
<NuxtLink
to="/admin/dashboard" custom v-slot="{ href, navigate, isExactActive }"
to="/admin/dashboard" custom v-slot="{ href, navigate, isActive }"
v-if="auth.isAdmin"
>
<a
:href="href"
@click="navigate"
:class="isExactActive ? 'opacity-100' : 'opacity-50'"
>
Admin
</a>
@@ -101,7 +100,7 @@
</aside>
</transition>
</header>
<main class="mx-auto w-full max-w-[1280px]">
<main class="mx-auto w-full max-w-[1280px] pb-0">
<slot/>
</main>
<footer class="w-full mt-8 bg-primary-500 p-6">
-12
View File
@@ -1,12 +0,0 @@
<template>
</template>
<script setup lang="ts">
definePageMeta({layout: "admin"})
const route = useRoute()
const router = useRouter()
const auth = useAuthStore()
</script>
@@ -1,112 +0,0 @@
<template>
<div class="flex items-center justify-between">
<h1 class="text-3xl font-bold uppercase">Client</h1>
<NuxtLink
to="/admin/customer"
class="flex items-center justify-center text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
:class="auth.isAdmin ? '' : 'cursor-not-allowed opacity-60'"
@click="handleAddClick"
>
Ajouter
</NuxtLink>
</div>
<div v-if="auth.isAdmin" class="mt-6 border border-slate-200 mb-16">
<div class="max-h-96 overflow-y-auto">
<div
class="sticky top-0 z-10 grid grid-cols-7 gap-4 bg-slate-100 px-4 py-3 text-sm font-semibold uppercase tracking-wide"
>
<div>Nom</div>
<div>Code</div>
<div>Rue</div>
<div>Complément</div>
<div>Code Postal</div>
<div>Ville</div>
<div>Pays</div>
</div>
<div v-if="customerList.length === 0" class="px-4 py-6 text-slate-400">
Aucun fournisseur.
</div>
<div v-for="customer in customerList" :key="customer.id">
<div
v-if="!customer.addresses || customer.addresses.length === 0"
class="grid grid-cols-7 border-t gap-4 px-4 py-2 hover:bg-slate-50 cursor-pointer"
@click="goToCustomer(customer.id)"
>
<div class="truncate">{{ customer.label }}</div>
<div class="truncate">{{ customer.code }}</div>
<div class="col-span-1">Pas d'adresse</div>
<div class="uppercase truncate">{{"—"}}</div>
<div class="uppercase truncate">{{"—"}}</div>
<div class="uppercase truncate">{{"—"}}</div>
<div class="uppercase truncate">{{"—"}}</div>
</div>
<template v-else-if="customer.addresses.length > 0">
<div
v-for="(address, idx) in customer.addresses"
:key="address.id ?? `${customer.id}-${idx}-${address.street}-${address.postalCode}`"
class="grid grid-cols-7 hover:bg-slate-50 border-t gap-4 px-4 py-2 cursor-pointer"
:class="idx > 0 ? 'pl-4 border-l-4 border-l-slate-200 bg-slate-50' : ''"
@click="goToCustomer(customer.id)"
>
<div class="truncate">
{{ idx === 0 ? customer.label : "" }}
</div>
<div class="truncate">{{ idx === 0 ? customer.code : "" }}</div>
<div class="truncate">{{ address.street || "" }}</div>
<div class="truncate">{{ address.street2 || "" }}</div>
<div>{{ address.postalCode || "" }}</div>
<div class="uppercase truncate">{{ address.city || "" }}</div>
<div class="uppercase truncate">{{ address.countryCode || "" }}</div>
</div>
</template>
<template v-else>
<div
class="grid grid-cols-7 hover:bg-slate-50 border-t gap-4 px-4 py-2 cursor-pointer"
@click="goToCustomer(customer.id)"
>
<div class="truncate">{{ customer.label }}</div>
<div class="truncate">{{ customer.code }}</div>
<div class="col-span-5 text-slate-400">
Adresses non chargées
</div>
</div>
</template>
</div>
</div>
</div>
<div v-else class="mt-6 border border-slate-200 mb-16 px-4 py-6 text-slate-400">
Accès réservé aux administrateurs.
</div>
</template>
<script setup lang="ts">
import { getCustomerList } from "~/services/customer"
import type { CustomerData } from "~/services/dto/customer-data"
import { useAuthStore } from "~/stores/auth"
definePageMeta({ layout: "admin" })
const customerList = ref<CustomerData[]>([])
const router = useRouter()
const auth = useAuthStore()
const goToCustomer = (id: number) => {
if (!auth.isAdmin) return
router.push(`/admin/customer/${id}`)
}
const handleAddClick = (event: Event) => {
if (auth.isAdmin) return
event.preventDefault()
}
onMounted(async () => {
if (!auth.isAdmin) return
customerList.value = await getCustomerList()
})
</script>
+5 -8
View File
@@ -1,6 +1,6 @@
<template>
<form @submit.prevent="validate">
<div class="flex items-center justify-between">
<div class="flex items-center justify-between gap-10">
<h1 class="text-3xl font-bold uppercase">
{{ supplierId ? "Modifications du fournisseur" : "Ajout d'un fournisseur" }}
</h1>
@@ -14,13 +14,13 @@
</button>
</div>
<div class="grid grid-cols-2 gap-y-8 gap-x-80 mb-10 py-12">
<div class="grid grid-cols-2 gap-y-16 gap-x-12 mb-10 py-12 border-b border-black ">
<UiTextInput id="supplier-name" v-model="form.name" label="Nom du fournisseur" :disabled="!auth.isAdmin"/>
<UiTextInput id="supplier-email" v-model="form.email" label="Email" :disabled="!auth.isAdmin"/>
<UiTextInput id="supplier-phone" v-model="form.phone" label="Téléphone" :disabled="!auth.isAdmin"/>
</div>
<div class="mx-24 mb-4 py-6 border-t border-black"></div>
<div class="flex items-center justify-between mb-4 py-6 border-t border-black"></div>
<div class="flex items-center justify-between mb-4">
<h2 class="text-3xl font-bold uppercase">Adresses fournisseur</h2>
<button
@@ -179,17 +179,14 @@ async function validate() {
email,
phone,
}
let targetId: number | null = null
if (supplierId.value !== null) {
await updateSupplier(supplierId.value, supplierPayload)
targetId = supplierId.value
} else {
const created = await createSupplier(supplierPayload)
targetId = created.id
await createSupplier(supplierPayload)
}
await router.push(`/admin/supplier/${targetId}`)
await router.push("/admin/supplier/supplier-list")
} finally {
isLoading.value = false
}
@@ -1,6 +1,6 @@
<template>
<div class="flex items-center justify-between">
<h1 class="text-3xl font-bold uppercase">Liste des fournisseurs</h1>
<h1 class="text-3xl font-bold uppercase">Fournisseurs</h1>
<NuxtLink
to="/admin/supplier"
class="flex items-center justify-center text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
+3 -5
View File
@@ -45,7 +45,7 @@ definePageMeta({
import {computed, reactive, ref, watch} from 'vue'
import {ROLE} from '~/utils/constants'
import {createUser, updateUser, getUser} from '~/services/auth'
import type {UserData, UserFormData, UserPayload} from '~/services/dto/user-data'
import type {UserData, UserFormData} from '~/services/dto/user-data'
const route = useRoute()
const router = useRouter()
@@ -105,12 +105,10 @@ async function validate() {
const normalizedRole = form.role.trim()
const normalizedPassword = form.password.trim()
const basePayload: UserPayload = {
const basePayload = {
username: normalizedUsername,
roles: normalizedRole ? [normalizedRole] : undefined,
}
if (normalizedPassword) {
basePayload.password = normalizedPassword
password: normalizedPassword || undefined
}
if (userId.value) {
+1 -1
View File
@@ -1,6 +1,6 @@
<template>
<div>
<div class="flex justify-between h-[52px] mt-6 mb-[80px]">
<div class="flex justify-between h-[52px] mb-[80px]">
<div class="flex flex-1 mr-16">
<UiStepper
:labels="RECEPTION_STEP_LABELS"
+31 -52
View File
@@ -1,10 +1,16 @@
<template>
<form @submit.prevent="validate">
<div class="flex items-center justify-between mt-12 mb-8 ">
<h1 class="font-bold text-5xl uppercase">Réception {{ receptionLoad?.identificationNumber }}</h1>
<div class="flex items-center justify-between mt-8 mb-8 ">
<h1 class="font-bold text-5xl uppercase">Réception {{receptionLoad?.identificationNumber}}</h1>
<button
type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end"
:disabled="!auth.isAdmin"
>Enregistrer
</button>
</div>
<div class="grid grid-cols-2 items-start gap-y-8 gap-x-40 mb-12">
<div class="grid grid-cols-2 items-start gap-y-8 gap-x-40 mb-16">
<!-- Nom de l'utilisateur -->
<UiSelect
id="reception-user"
@@ -114,50 +120,28 @@
wrapper-class="col-start-2 row-start-4"
/>
</div>
<div class="flex justify-center mb-2">
<button
v-if="auth.isAdmin"
type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] mb-16"
>
Enregistrer
</button>
<div class="grid grid-cols-2 items-start gap-y-8 gap-x-40 mb-16">
<h1 class="font-bold text-5xl uppercase col-start-1 row-start-1" @click="isBtWeight = true" >pesées</h1>
<h1 class="font-bold text-5xl uppercase col-start-2 row-start-1" @click="isBtWeight = false">{{isMerchandise ? "Marchandises" : "Bovins"}}</h1>
</div>
<div class="flex justify-evenly gap-y-8 gap-x-40 mb-8 border-b border-slate-400">
<h1
class="font-bold text-3xl uppercase col-start-1 row-start-1 cursor-pointer"
:class="activeTab === 'weights' ? 'underline' : ''"
@click="activeTab = 'weights'"
>
pesées
</h1>
<h1
class="font-bold text-3xl uppercase col-start-2 row-start-1 cursor-pointer"
:class="activeTab === 'merchandise' ? 'underline' : ''"
@click="activeTab = 'merchandise'"
>
{{ isMerchandise ? "Marchandise" : "Bovins" }}
</h1>
</div>
<update-weight
v-if="isBtWeight"
:idReception="idReception"
:disabled="!auth.isAdmin"
/>
<update-weight
v-if="activeTab === 'weights'"
:idReception="idReception"
:disabled="!auth.isAdmin"
/>
<update-merchandise
v-else-if="isMerchandise"
:idReception="idReception"
:disabled="!auth.isAdmin"
/>
<update-merchandise
v-else-if="activeTab === 'merchandise' && isMerchandise"
:idReception="idReception"
:disabled="!auth.isAdmin"
/>
<update-bovin
v-else
:idReception="idReception"
:disabled="!auth.isAdmin"
/>
<update-bovin
v-else
:idReception="idReception"
:disabled="!auth.isAdmin"
/>
</form>
</template>
@@ -184,7 +168,6 @@ import UpdateWeight from "~/components/reception/update-weight.vue";
import UpdateMerchandise from "~/components/reception/update-merchandise.vue";
import UpdateBovin from "~/components/reception/update-bovin.vue";
const activeTab = ref<'weights' | 'merchandise'>('weights')
const router = useRouter()
const receptionStore = useReceptionStore()
const form = reactive<ReceptionFormData>({
@@ -266,7 +249,7 @@ const clearReceptionBovines = async (receptionIri: string) => {
}
}
const hydrateFromUser = (reception: ReceptionData | null) => {
const hydrateFromUser = (reception: ReceptionData | null)=> {
if (!reception) {
return
}
@@ -395,7 +378,7 @@ onMounted(async () => {
// Ajuste driver/vehicle quand le transporteur change (logique LIOT)
watch(
() => [form.supplierId, form.addressId, suppliers.value],
() => [form.supplierId, suppliers.value],
() => {
if (!form.supplierId) {
form.addressId = ''
@@ -412,11 +395,7 @@ watch(
(address) => String(address.id) === form.addressId
)
if (!matches) {
if (supplierAddresses.value.length === 1) {
form.addressId = String(supplierAddresses.value[0].id)
} else {
form.addressId = ''
}
form.addressId = ''
}
},
{immediate: true}
@@ -553,7 +532,7 @@ async function validate() {
}
if (idReception) {
const updated = await receptionStore.updateReception(idReception, {
const updated = await receptionStore.updateReception(idReception,{
...payload
})
if (updated) {
+1 -1
View File
@@ -1,6 +1,6 @@
<template>
<div>
<div class="flex justify-between h-[52px] mt-6 mb-[80px]">
<div class="flex justify-between h-[52px] mb-[80px]">
<div class="flex flex-1 mr-16">
<UiStepper
:labels="SHIPMENT_STEP_LABELS"
-2
View File
@@ -19,11 +19,9 @@ use Symfony\Component\Serializer\Attribute\Groups;
new Get(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['carrier:read']],
security: "is_granted('ROLE_USER')"
),
new GetCollection(
normalizationContext: ['groups' => ['carrier:read']],
security: "is_granted('ROLE_USER')"
),
new Post(
normalizationContext: ['groups' => ['carrier:read']],
+5 -2
View File
@@ -22,11 +22,14 @@ use Symfony\Component\Serializer\Attribute\Groups;
new Get(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['supplier:read']],
security: "is_granted('ROLE_USER')"
),
new GetCollection(
normalizationContext: ['groups' => ['supplier:read']],
security: "is_granted('ROLE_USER')"
),
new GetCollection(
uriTemplate: '/admin/suppliers',
normalizationContext: ['groups' => ['supplier:read']],
security: "is_granted('ROLE_ADMIN')"
),
new Post(
normalizationContext: ['groups' => ['supplier:read']],
+2 -6
View File
@@ -21,12 +21,8 @@ final class UserPasswordProcessor implements ProcessorInterface
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
{
if ($data instanceof User) {
$plain = $data->getPassword();
$previous = $context['previous_data'] ?? null;
if ($previous instanceof User && $plain === $previous->getPassword()) {
// Password not changed in payload: keep existing hash.
$data->setPassword($previous->getPassword());
} elseif ('' !== $plain) {
$plain = $data->getPassword();
if ('' !== $plain) {
$data->setPassword($this->hasher->hashPassword(
$data,
$plain