[#325] Corrections diverses #26

Merged
tristan merged 4 commits from fix/325-corrections-diverses into develop 2026-02-13 08:10:34 +00:00
19 changed files with 245 additions and 149 deletions
Showing only changes of commit e591a98c85 - Show all commits

View File

@@ -29,7 +29,7 @@
<button <button
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]" class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
@click="goNext" @click="goNext"
>Peser >Valider
</button> </button>
</div> </div>
</template> </template>

View File

@@ -119,7 +119,7 @@
<button <button
type="submit" type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end" class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end"
>Peser >Valider
</button> </button>
</div> </div>
</form> </form>
@@ -342,7 +342,7 @@ onMounted(async () => {
// Ajuste driver/vehicle quand le transporteur change (logique LIOT) // Ajuste driver/vehicle quand le transporteur change (logique LIOT)
watch( watch(
() => [form.supplierId, suppliers.value], () => [form.supplierId, form.addressId, suppliers.value],
() => { () => {
if (!form.supplierId) { if (!form.supplierId) {
form.addressId = '' form.addressId = ''
@@ -359,7 +359,11 @@ watch(
(address) => String(address.id) === form.addressId (address) => String(address.id) === form.addressId
) )
if (!matches) { if (!matches) {
form.addressId = '' if (supplierAddresses.value.length === 1) {
form.addressId = String(supplierAddresses.value[0].id)
} else {
form.addressId = ''
}
} }
}, },
{immediate: true} {immediate: true}

View File

@@ -67,7 +67,7 @@
<button <button
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]" class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
@click="goNext" @click="goNext"
>Peser >Valider
</button> </button>
</div> </div>
</template> </template>

View File

@@ -26,7 +26,7 @@
v-if="displayWeight !== null && !showGenerateReceipt" v-if="displayWeight !== null && !showGenerateReceipt"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] ml-4" class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] ml-4"
@click="saveWeight" @click="saveWeight"
>Valider la pesée</button> >Valider</button>
<button <button
v-if="showGenerateReceipt" v-if="showGenerateReceipt"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] ml-4" class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] ml-4"
@@ -36,7 +36,7 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import {computed, onMounted} from 'vue'
import { storeToRefs } from 'pinia' import { storeToRefs } from 'pinia'
import { useWeighing } from '~/composables/useWeighing' import { useWeighing } from '~/composables/useWeighing'
import { usePdfPrinter } from '~/composables/usePdfPrinter' 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 // Récupère le poids dès l'arrivée sur l'écran
onMounted(() => { onMounted(() => {
if (false === displayWeight.value) { if (displayWeight.value === null) {
fetchWeight() fetchWeight()
} }
}) })

View File

@@ -1,79 +1,80 @@
<template> <template>
<form @submit.prevent="validate"> <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 <div
v-if="merchandiseTypeId && isAutres" class="flex flex-col gap-16 items-center w-full">
class="flex flex-col w-full max-w-[550px]"
>
<UiTextInput <UiTextInput
id="merchandise-detail" id="merchandise-type"
:disabled="!auth.isAdmin" v-model="selectedMerchandiseTypeId"
v-model="merchandiseDetail" label="Type de marchandises"
label="Préciser" :value="reception.merchandiseType?.label"
placeholder="Précisions complémentaires" wrapper-class="w-[550px]"
:maxlength="255" :disabled="true"
/> />
</div>
<div
v-if="merchandiseTypeId && !isGranule"
class="flex gap-4 w-[550px] justify-evenly"
>
<div <div
v-for="building in buildings" v-if="merchandiseTypeId && isAutres"
:key="building.id" class="flex flex-col w-full max-w-[550px]"
> >
<UiCheckbox <UiTextInput
v-model="selectedBuildingIds" id="merchandise-detail"
:value="String(building.id)"
:label="building.label"
:disabled="!auth.isAdmin" :disabled="!auth.isAdmin"
label-class="text-xl" v-model="merchandiseDetail"
label="Préciser"
placeholder="Précisions complémentaires"
:maxlength="255"
/> />
</div> </div>
</div>
<div <div
v-if="merchandiseTypeId && isGranule" v-if="merchandiseTypeId && !isGranule"
class="flex flex-col gap-10 w-full max-w-[1100px]" class="flex gap-4 w-[550px] justify-evenly"
> >
<div class="grid grid-cols-1 gap-10 md:grid-cols-4"> <div
<div v-for="type in pelletTypes" :key="type.id" class="flex flex-col gap-4"> v-for="building in buildings"
<p class="font-bold uppercase">{{ type.label }}</p> :key="building.id"
<div >
v-for="building in buildings" <UiCheckbox
:key="building.id" v-model="selectedBuildingIds"
class="flex items-center gap-2 text-lg" :value="String(building.id)"
> :label="building.label"
<UiCheckbox :disabled="!auth.isAdmin"
v-model="selectedPelletBuildingIds[String(type.id)]" label-class="text-xl"
:value="String(building.id)" />
:label="building.label" </div>
:disabled="!auth.isAdmin" </div>
label-class="text-lg"
/> <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> </div>
</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> </div>
<button
type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
:disabled="!auth.isAdmin"
>Valider
</button>
</div>
</form> </form>
</template> </template>

View File

@@ -1,27 +1,42 @@
<template> <template>
<form @submit.prevent="validate"> <form @submit.prevent="validate">
<div class="grid grid-cols-2 gap-x-40 gap-y-8 mb-8">
<div class="grid grid-cols-2 gap-x-40 gap-y-8 mb-16"> <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">
<UiNumberInput <UiNumberInput
label="Pesée à vide" label="Pesée à vide"
labelClass="font-bold uppercase text-xl"
v-model="form.weights[0].weight" v-model="form.weights[0].weight"
wrapper-class="col-start-1 row-start-1"
:disabled="!auth.isAdmin" :disabled="!auth.isAdmin"
:min="0"
/> />
<UiNumberInput <UiNumberInput
label="Pesée à plein" label="Pesée à plein"
labelClass="font-bold uppercase text-xl"
v-model="form.weights[1].weight" v-model="form.weights[1].weight"
wrapper-class="col-start-2 row-start-1"
:disabled="!auth.isAdmin" :disabled="!auth.isAdmin"
:min="0"
/> />
</div> </div>
<div class="flex justify-center"> <div class="flex justify-center">
<button <button
v-if="auth.isAdmin"
type="submit" type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]" class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"
:disabled="!auth.isAdmin"
> >
Valider Valider
</button> </button>
@@ -32,7 +47,7 @@
<script setup lang="ts"> <script setup lang="ts">
import type {ReceptionFormWeight} from '~/services/dto/reception-data' import type {ReceptionFormWeight} from '~/services/dto/reception-data'
import { getReception } from '~/services/reception' import {getReception} from '~/services/reception'
import {updateWeight} from "~/services/weight"; import {updateWeight} from "~/services/weight";
import {useAuthStore} from "~/stores/auth"; import {useAuthStore} from "~/stores/auth";
@@ -45,8 +60,8 @@ const auth = useAuthStore()
const form = reactive({ const form = reactive({
weights: [ weights: [
{ id: 0, type: 'tare' as const, weight: 0 }, {id: 0, type: 'tare' as const, weight: 0, dsd: null, weighedAt: null},
{ id: 0, type: 'gross' as const, weight: 0 } {id: 0, type: 'gross' as const, weight: 0, dsd: null, weighedAt: null}
] ]
}) })
@@ -54,8 +69,8 @@ const hydrateFromReception = (reception: ReceptionFormWeight) => {
const tare = reception.weights.find(weight => weight.type === 'tare') const tare = reception.weights.find(weight => weight.type === 'tare')
const gross = reception.weights.find(weight => weight.type === 'gross') const gross = reception.weights.find(weight => weight.type === 'gross')
if (tare) form.weights[0] = { ...tare } if (tare) form.weights[0] = {...form.weights[0], ...tare}
if (gross) form.weights[1] = { ...gross } if (gross) form.weights[1] = {...form.weights[1], ...gross}
} }
onMounted(async () => { onMounted(async () => {
@@ -64,11 +79,24 @@ onMounted(async () => {
}) })
async function validate() { 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) { for (const weight of form.weights) {
if (weight.id) { if (weight.id) {
await updateWeight(weight.id, {weight: weight.weight}) await updateWeight(weight.id, {
weight: weight.weight,
dsd: Number.isFinite(sharedDsd) ? sharedDsd : null,
weighedAt: sharedWeighedAt
})
} }
} }
} }
</script> </script>

View File

@@ -23,14 +23,14 @@
/> />
<!-- Type d'expédition --> <!-- Type d'expédition -->
<div class="col-start-1 row-start-4"> <div class="col-start-1 row-start-4">
<label class="font-bold uppercase text-xl mb-2 block"> <label class="font-bold uppercase text-xl mb-2">
Type d'expédition Type d'expédition
</label> </label>
<div class="grid grid-cols-2 gap-x-8"> <div class="grid grid-cols-2 gap-x-8">
<div <div
v-for="type in bovineShipment" v-for="type in bovineShipment"
:key="type.id" :key="type.id"
class="mt-8 flex flex-row gap-6" class="mt-2 flex flex-row gap-6"
> >
<UiNumberInput <UiNumberInput
:label="type.label" :label="type.label"
@@ -344,7 +344,7 @@ watch(
) )
// Ajuste driver/vehicle quand le transporteur change (logique LIOT) // Ajuste driver/vehicle quand le transporteur change (logique LIOT)
watch( watch(
() => [form.customerId, customers.value], () => [form.customerId, form.addressId, customers.value],
() => { () => {
if (!form.customerId) { if (!form.customerId) {
form.addressId = '' form.addressId = ''
@@ -361,7 +361,11 @@ watch(
(address) => String(address.id) === form.addressId (address) => String(address.id) === form.addressId
) )
if (!matches) { if (!matches) {
form.addressId = '' if (customerAddresses.value.length === 1) {
form.addressId = String(customerAddresses.value[0].id)
} else {
form.addressId = ''
}
} }
}, },
{immediate: true} {immediate: true}

View File

@@ -3,7 +3,7 @@
<label <label
v-if="label" v-if="label"
:for="id" :for="id"
class="text-xl text-bold flex items-center" class="text-xl flex items-center"
:class="labelClass" :class="labelClass"
> >
<span <span
@@ -25,7 +25,7 @@
:step="step" :step="step"
:disabled="disabled" :disabled="disabled"
v-bind="attrs" v-bind="attrs"
class="border-b border-black text-xl bg-transparent w-12" class="border-b border-black text-xl bg-transparent w-16"
:class="[ :class="[
isEmpty ? 'text-neutral-400' : 'text-black', isEmpty ? 'text-neutral-400' : 'text-black',
disabled ? 'cursor-not-allowed' : 'cursor-text', disabled ? 'cursor-not-allowed' : 'cursor-text',

View File

@@ -24,17 +24,41 @@
<aside class="bg-primary-500 text-white min-h-0 flex flex-col justify-between"> <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"> <div class="flex flex-col gap-4 p-4 font-bold text-xl">
<!-- Liste des liens à ajouter ci-dessous --> <!-- Liste des liens à ajouter ci-dessous -->
<NuxtLink to="/admin/dashboard"> <NuxtLink
Tableau de bord 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> </NuxtLink>
<NuxtLink to="/admin/supplier/supplier-list"> <NuxtLink
Fournisseur 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> </NuxtLink>
<NuxtLink to="/admin/carrier/carrier-list"> <NuxtLink
Transporteur 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> </NuxtLink>
<NuxtLink to="/admin/user/list"> <NuxtLink to="/admin/user/list" custom v-slot="{ href, navigate }">
Utilisateurs <a
:href="href"
@click="navigate"
:class="route.path.startsWith('/admin/user') ? 'opacity-100' : 'opacity-50'"
>
Utilisateurs
</a>
</NuxtLink> </NuxtLink>
<NuxtLink to="/admin/customer/customer-list"> <NuxtLink to="/admin/customer/customer-list">
Client Client
@@ -42,19 +66,22 @@
</div> </div>
<div class="p-4"> <div class="p-4">
<p class="font-bold text-white text-left">v{{ version }}</p>
<button <button
@click="handleLogout" @click="handleLogout"
class="w-full bg-red-600 hover:bg-red-700 py-2 rounded font-bold" class="w-full bg-red-600 hover:bg-red-700 py-2 rounded font-bold"
> >
Déconnexion Déconnexion
</button> </button>
<p class="font-bold text-white text-center pt-2">
v{{ version }}
</p>
</div> </div>
</aside> </aside>
<main class="min-h-0 overflow-auto px-12 py-12 "> <main class="min-h-0 overflow-auto px-12 py-12 ">
<div class="w-full "> <div class="w-full ">
<slot /> <slot/>
</div> </div>
</main> </main>
</div> </div>
@@ -66,7 +93,9 @@
import {useAuthStore} from '~/stores/auth' import {useAuthStore} from '~/stores/auth'
const auth = useAuthStore() const auth = useAuthStore()
const { version } = useAppVersion() const {version} = useAppVersion()
const route = useRoute()
const handleLogout = async () => { const handleLogout = async () => {
try { try {
await auth.logout() await auth.logout()

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="min-h-screen bg-white text-neutral-900"> <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"> <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"> <div class="flex w-full items-center justify-center px-6 py-4">
<button <button
type="button" type="button"
@@ -21,12 +21,13 @@
</a> </a>
</NuxtLink> </NuxtLink>
<NuxtLink <NuxtLink
to="/admin/dashboard" custom v-slot="{ href, navigate, isActive }" to="/admin/dashboard" custom v-slot="{ href, navigate, isExactActive }"
v-if="auth.isAdmin" v-if="auth.isAdmin"
> >
<a <a
:href="href" :href="href"
@click="navigate" @click="navigate"
:class="isExactActive ? 'opacity-100' : 'opacity-50'"
> >
Admin Admin
</a> </a>
@@ -100,7 +101,7 @@
</aside> </aside>
</transition> </transition>
</header> </header>
<main class="mx-auto w-full max-w-[1280px] pb-0"> <main class="mx-auto w-full max-w-[1280px]">
<slot/> <slot/>
</main> </main>
<footer class="w-full mt-8 bg-primary-500 p-6"> <footer class="w-full mt-8 bg-primary-500 p-6">

View File

@@ -1,6 +1,6 @@
<template> <template>
<form @submit.prevent="validate"> <form @submit.prevent="validate">
<div class="flex items-center justify-between gap-10"> <div class="flex items-center justify-between">
<h1 class="text-3xl font-bold uppercase"> <h1 class="text-3xl font-bold uppercase">
{{ supplierId ? "Modifications du fournisseur" : "Ajout d'un fournisseur" }} {{ supplierId ? "Modifications du fournisseur" : "Ajout d'un fournisseur" }}
</h1> </h1>
@@ -14,13 +14,13 @@
</button> </button>
</div> </div>
<div class="grid grid-cols-2 gap-y-16 gap-x-12 mb-10 py-12 border-b border-black "> <div class="grid grid-cols-2 gap-y-8 gap-x-80 mb-10 py-12">
<UiTextInput id="supplier-name" v-model="form.name" label="Nom du fournisseur" :disabled="!auth.isAdmin"/> <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-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"/> <UiTextInput id="supplier-phone" v-model="form.phone" label="Téléphone" :disabled="!auth.isAdmin"/>
</div> </div>
<div class="flex items-center justify-between mb-4 py-6 border-t border-black"></div> <div class="mx-24 mb-4 py-6 border-t border-black"></div>
<div class="flex items-center justify-between mb-4"> <div class="flex items-center justify-between mb-4">
<h2 class="text-3xl font-bold uppercase">Adresses fournisseur</h2> <h2 class="text-3xl font-bold uppercase">Adresses fournisseur</h2>
<button <button
@@ -179,14 +179,17 @@ async function validate() {
email, email,
phone, phone,
} }
let targetId: number | null = null
if (supplierId.value !== null) { if (supplierId.value !== null) {
await updateSupplier(supplierId.value, supplierPayload) await updateSupplier(supplierId.value, supplierPayload)
targetId = supplierId.value
} else { } else {
await createSupplier(supplierPayload) const created = await createSupplier(supplierPayload)
targetId = created.id
} }
await router.push("/admin/supplier/supplier-list") await router.push(`/admin/supplier/${targetId}`)
} finally { } finally {
isLoading.value = false isLoading.value = false
} }

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="flex items-center justify-between"> <div class="flex items-center justify-between">
<h1 class="text-3xl font-bold uppercase">Fournisseurs</h1> <h1 class="text-3xl font-bold uppercase">Liste des fournisseurs</h1>
<NuxtLink <NuxtLink
to="/admin/supplier" to="/admin/supplier"
class="flex items-center justify-center text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]" class="flex items-center justify-center text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px]"

View File

@@ -45,7 +45,7 @@ definePageMeta({
import {computed, reactive, ref, watch} from 'vue' import {computed, reactive, ref, watch} from 'vue'
import {ROLE} from '~/utils/constants' import {ROLE} from '~/utils/constants'
import {createUser, updateUser, getUser} from '~/services/auth' import {createUser, updateUser, getUser} from '~/services/auth'
import type {UserData, UserFormData} from '~/services/dto/user-data' import type {UserData, UserFormData, UserPayload} from '~/services/dto/user-data'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@@ -105,10 +105,12 @@ async function validate() {
const normalizedRole = form.role.trim() const normalizedRole = form.role.trim()
const normalizedPassword = form.password.trim() const normalizedPassword = form.password.trim()
const basePayload = { const basePayload: UserPayload = {
username: normalizedUsername, username: normalizedUsername,
roles: normalizedRole ? [normalizedRole] : undefined, roles: normalizedRole ? [normalizedRole] : undefined,
password: normalizedPassword || undefined }
if (normalizedPassword) {
basePayload.password = normalizedPassword
} }
if (userId.value) { if (userId.value) {

View File

@@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div class="flex justify-between h-[52px] mb-[80px]"> <div class="flex justify-between h-[52px] mt-6 mb-[80px]">
<div class="flex flex-1 mr-16"> <div class="flex flex-1 mr-16">
<UiStepper <UiStepper
:labels="RECEPTION_STEP_LABELS" :labels="RECEPTION_STEP_LABELS"

View File

@@ -1,16 +1,10 @@
<template> <template>
<form @submit.prevent="validate"> <form @submit.prevent="validate">
<div class="flex items-center justify-between mt-8 mb-8 "> <div class="flex items-center justify-between mt-12 mb-8 ">
<h1 class="font-bold text-5xl uppercase">Réception {{receptionLoad?.identificationNumber}}</h1> <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>
<div class="grid grid-cols-2 items-start gap-y-8 gap-x-40 mb-16"> <div class="grid grid-cols-2 items-start gap-y-8 gap-x-40 mb-12">
<!-- Nom de l'utilisateur --> <!-- Nom de l'utilisateur -->
<UiSelect <UiSelect
id="reception-user" id="reception-user"
@@ -120,28 +114,50 @@
wrapper-class="col-start-2 row-start-4" wrapper-class="col-start-2 row-start-4"
/> />
</div> </div>
<div class="grid grid-cols-2 items-start gap-y-8 gap-x-40 mb-16"> <div class="flex justify-center mb-2">
<h1 class="font-bold text-5xl uppercase col-start-1 row-start-1" @click="isBtWeight = true" >pesées</h1> <button
<h1 class="font-bold text-5xl uppercase col-start-2 row-start-1" @click="isBtWeight = false">{{isMerchandise ? "Marchandises" : "Bovins"}}</h1> v-if="auth.isAdmin"
type="submit"
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] mb-16"
>
Enregistrer
</button>
</div> </div>
<update-weight <div class="flex justify-evenly gap-y-8 gap-x-40 mb-8 border-b border-slate-400">
v-if="isBtWeight" <h1
:idReception="idReception" class="font-bold text-3xl uppercase col-start-1 row-start-1 cursor-pointer"
:disabled="!auth.isAdmin" :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-merchandise <update-weight
v-else-if="isMerchandise" v-if="activeTab === 'weights'"
:idReception="idReception" :idReception="idReception"
:disabled="!auth.isAdmin" :disabled="!auth.isAdmin"
/> />
<update-bovin <update-merchandise
v-else v-else-if="activeTab === 'merchandise' && isMerchandise"
:idReception="idReception" :idReception="idReception"
:disabled="!auth.isAdmin" :disabled="!auth.isAdmin"
/> />
<update-bovin
v-else
:idReception="idReception"
:disabled="!auth.isAdmin"
/>
</form> </form>
</template> </template>
@@ -168,6 +184,7 @@ import UpdateWeight from "~/components/reception/update-weight.vue";
import UpdateMerchandise from "~/components/reception/update-merchandise.vue"; import UpdateMerchandise from "~/components/reception/update-merchandise.vue";
import UpdateBovin from "~/components/reception/update-bovin.vue"; import UpdateBovin from "~/components/reception/update-bovin.vue";
const activeTab = ref<'weights' | 'merchandise'>('weights')
const router = useRouter() const router = useRouter()
const receptionStore = useReceptionStore() const receptionStore = useReceptionStore()
const form = reactive<ReceptionFormData>({ const form = reactive<ReceptionFormData>({
@@ -249,7 +266,7 @@ const clearReceptionBovines = async (receptionIri: string) => {
} }
} }
const hydrateFromUser = (reception: ReceptionData | null)=> { const hydrateFromUser = (reception: ReceptionData | null) => {
if (!reception) { if (!reception) {
return return
} }
@@ -378,7 +395,7 @@ onMounted(async () => {
// Ajuste driver/vehicle quand le transporteur change (logique LIOT) // Ajuste driver/vehicle quand le transporteur change (logique LIOT)
watch( watch(
() => [form.supplierId, suppliers.value], () => [form.supplierId, form.addressId, suppliers.value],
() => { () => {
if (!form.supplierId) { if (!form.supplierId) {
form.addressId = '' form.addressId = ''
@@ -395,7 +412,11 @@ watch(
(address) => String(address.id) === form.addressId (address) => String(address.id) === form.addressId
) )
if (!matches) { if (!matches) {
form.addressId = '' if (supplierAddresses.value.length === 1) {
form.addressId = String(supplierAddresses.value[0].id)
} else {
form.addressId = ''
}
} }
}, },
{immediate: true} {immediate: true}
@@ -532,7 +553,7 @@ async function validate() {
} }
if (idReception) { if (idReception) {
const updated = await receptionStore.updateReception(idReception,{ const updated = await receptionStore.updateReception(idReception, {
...payload ...payload
}) })
if (updated) { if (updated) {

View File

@@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div class="flex justify-between h-[52px] mb-[80px]"> <div class="flex justify-between h-[52px] mt-6 mb-[80px]">
<div class="flex flex-1 mr-16"> <div class="flex flex-1 mr-16">
<UiStepper <UiStepper
:labels="SHIPMENT_STEP_LABELS" :labels="SHIPMENT_STEP_LABELS"

View File

@@ -19,9 +19,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
new Get( new Get(
requirements: ['id' => '\d+'], requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['carrier:read']], normalizationContext: ['groups' => ['carrier:read']],
security: "is_granted('ROLE_USER')"
), ),
new GetCollection( new GetCollection(
normalizationContext: ['groups' => ['carrier:read']], normalizationContext: ['groups' => ['carrier:read']],
security: "is_granted('ROLE_USER')"
), ),
new Post( new Post(
normalizationContext: ['groups' => ['carrier:read']], normalizationContext: ['groups' => ['carrier:read']],

View File

@@ -22,14 +22,11 @@ use Symfony\Component\Serializer\Attribute\Groups;
new Get( new Get(
requirements: ['id' => '\d+'], requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['supplier:read']], normalizationContext: ['groups' => ['supplier:read']],
security: "is_granted('ROLE_USER')"
), ),
new GetCollection( new GetCollection(
normalizationContext: ['groups' => ['supplier:read']], normalizationContext: ['groups' => ['supplier:read']],
), security: "is_granted('ROLE_USER')"

C'est bien un role admin qu'il faut ici

C'est bien un role admin qu'il faut ici
new GetCollection(
uriTemplate: '/admin/suppliers',
normalizationContext: ['groups' => ['supplier:read']],
security: "is_granted('ROLE_ADMIN')"
), ),
new Post( new Post(
normalizationContext: ['groups' => ['supplier:read']], normalizationContext: ['groups' => ['supplier:read']],

View File

@@ -21,8 +21,12 @@ final class UserPasswordProcessor implements ProcessorInterface
public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed public function process(mixed $data, Operation $operation, array $uriVariables = [], array $context = []): mixed
{ {
if ($data instanceof User) { if ($data instanceof User) {
$plain = $data->getPassword(); $plain = $data->getPassword();
if ('' !== $plain) { $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) {
$data->setPassword($this->hasher->hashPassword( $data->setPassword($this->hasher->hashPassword(
$data, $data,
$plain $plain