fix : correction de l'enregistrement des pesées sur l'admin

This commit is contained in:
2026-02-25 10:30:41 +01:00
parent 586f122e3b
commit 141f174d0a
4 changed files with 134 additions and 190 deletions

View File

@@ -2,11 +2,11 @@
<form>
<div class="grid grid-cols-3 gap-x-40 gap-y-8 mb-8">
<UiNumberInput
:key="weight.type"
:key="localWeight.type"
:label="'POIDS'"
labelClass="font-bold uppercase text-xl "
v-model="weight.weight"
:disabled="!auth.isAdmin"
v-model="localWeight.weight"
:disabled="!isAdmin"
:min="0"
:max="48000"
wrapper-class="flex-col"
@@ -14,16 +14,16 @@
<UiDateInput
label="Date pesée"
v-model="sharedWeightMeta.weighedAt"
:disabled="!auth.isAdmin"
v-model="localWeight.weighedAt"
:disabled="!isAdmin"
/>
<UiNumberInput
label="Dsd"
class="col-start-2"
labelClass="font-bold uppercase"
v-model="sharedWeightMeta.dsd"
:disabled="!auth.isAdmin"
v-model="localWeight.dsd"
:disabled="!isAdmin"
wrapper-class="flex-col"
/>
</div>
@@ -31,133 +31,33 @@
</template>
<script setup lang="ts">
import type {ReceptionFormWeight} from '~/services/dto/reception-data'
import {getReception} from '~/services/reception'
import {updateWeight} from "~/services/weight";
import {useAuthStore} from "~/stores/auth";
import {ref, watch} from "vue";
import type {WeightEntryData} from '~/services/dto/reception-data'
import {reactive, watch} from "vue";
const props = defineProps<{
idReception: number
weightType: string
isValidate: boolean
modelValue: WeightEntryData
isAdmin: boolean
}>()
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}
]
})
const emit = defineEmits<{
(event: 'update:modelValue', value: WeightEntryData): void
}>()
const idReception = props.idReception
const weightType = props.weightType
const auth = useAuthStore()
const weight = form.weights.find(w => w.type === weightType)
const initialWeight = ref<{ weight: number | null; dsd: number | null; weighedAt: string | null } | null>(null)
// DSD et date de pesée sont partagés entre tare et gross dans l'UI.
const sharedWeightMeta = reactive<{
dsd: number | string | null
weighedAt: string | null
}>({
dsd: null,
weighedAt: null
})
const normalizeMeta = () => {
const sharedDsd =
sharedWeightMeta.dsd === null || sharedWeightMeta.dsd === undefined || sharedWeightMeta.dsd === ''
? null
: Number(sharedWeightMeta.dsd)
const sharedWeighedAt =
sharedWeightMeta.weighedAt === null || sharedWeightMeta.weighedAt === undefined || sharedWeightMeta.weighedAt === ''
? null
: sharedWeightMeta.weighedAt
return {
dsd: Number.isFinite(sharedDsd) ? sharedDsd : null,
weighedAt: sharedWeighedAt
}
}
const hydrateFromReception = (reception: ReceptionFormWeight) => {
// On hydrate chaque ligne par son type (tare/gross), sans dépendre d'un index.
for (const receptionWeight of reception.weights) {
const formWeight = form.weights.find(weight => weight.type === receptionWeight.type)
if (formWeight) {
Object.assign(formWeight, receptionWeight)
}
}
// On récupère une valeur existante pour préremplir les champs partagés.
const weightWithMeta = reception.weights.find(weight =>
(weight.dsd !== null && weight.dsd !== undefined)
|| (weight.weighedAt !== null && weight.weighedAt !== undefined && weight.weighedAt !== '')
)
if (weightWithMeta) {
sharedWeightMeta.dsd = weightWithMeta.dsd ?? null
sharedWeightMeta.weighedAt = weightWithMeta.weighedAt ?? null
}
if (weight) {
const normalized = normalizeMeta()
initialWeight.value = {
weight: weight.weight ?? null,
dsd: normalized.dsd,
weighedAt: normalized.weighedAt
}
}
}
onMounted(async () => {
const reception = await getReception(idReception)
hydrateFromReception(reception)
})
const localWeight = reactive<WeightEntryData>({...props.modelValue})
watch(
() => props.isValidate,
async (val) => {
if (!val) return
await runValidate()
}
() => props.modelValue,
(value) => {
Object.assign(localWeight, value)
},
{deep: true}
)
const hasChanged = (current: { weight: number | null; dsd: number | null; weighedAt: string | null }) => {
if (!initialWeight.value) {
return true
}
return (
(current.weight ?? null) !== (initialWeight.value.weight ?? null) ||
(current.dsd ?? null) !== (initialWeight.value.dsd ?? null) ||
(current.weighedAt ?? null) !== (initialWeight.value.weighedAt ?? null)
)
}
const runValidate = async () => {
if (!weight?.id) {
return
}
const normalized = normalizeMeta()
const current = {
weight: weight.weight ?? null,
dsd: normalized.dsd,
weighedAt: normalized.weighedAt
}
if (!hasChanged(current)) {
return
}
await updateWeight(weight.id, {
weight: current.weight,
dsd: current.dsd,
weighedAt: current.weighedAt
})
initialWeight.value = current
}
watch(
localWeight,
(value) => {
emit('update:modelValue', {...value})
},
{deep: true}
)
</script>

View File

@@ -9,7 +9,6 @@
<h1 class="font-bold text-4xl col-start-1 row-start-1 text-primary-500 uppercase">Réception {{ form.identificationNumber }}</h1>
<Icon @click="printReceipt" name="mdi:printer-outline" size="44" class="cursor-pointer text-primary-500"/>
</div>
<!-- Nom de l'utilisateur -->
<UiSelect
id="reception-user"
@@ -137,15 +136,15 @@
<div class="flex justify-evenly gap-y-8 gap-x-41 mb-10 border-b border-primary-500/60">
<h1
class="font-bold text-3xl uppercase px-12 col-start-1 row-start-1 cursor-pointer "
:class="activeTab === 'weightsEmpty' ? 'border-b-[6px] border-primary-500 text-primary-500' : 'text-primary-500/50'"
@click="activeTab = 'weightsEmpty'"
:class="activeTab === 'weights' ? 'border-b-[6px] border-primary-500 text-primary-500' : 'text-primary-500/50'"
@click="activeTab = 'weights'"
>
pesée à plein
</h1>
<h1
class="font-bold text-3xl uppercase col-start-1 row-start-1 px-12 cursor-pointer "
:class="activeTab === 'weights' ? 'border-b-[6px] border-primary-500 text-primary-500 ' : 'text-primary-500/50'"
@click="activeTab = 'weights'"
:class="activeTab === 'weightsEmpty' ? 'border-b-[6px] border-primary-500 text-primary-500 ' : 'text-primary-500/50'"
@click="activeTab = 'weightsEmpty'"
>
pesée à vide
</h1>
@@ -157,22 +156,20 @@
{{ isMerchandise ? "Marchandise" : "Bovins" }}
</h1>
</div>
<div class="mb-12 ">
<update-weight
v-show="activeTab === 'weights'"
v-model="grossWeight"
v-if="grossWeight"
:isAdmin="auth.isAdmin"
/>
<update-weight
v-show="activeTab === 'weights'"
:idReception="idReception"
:weightType="'tare'"
:disabled="!auth.isAdmin"
:isValidate="isValid"
/>
<div class="mb-12 ">
<update-weight
v-show="activeTab === 'weightsEmpty'"
:idReception="idReception"
:weightType="'gross'"
:disabled="!auth.isAdmin"
:isValidate="isValid"
/>
<update-weight
v-show="activeTab === 'weightsEmpty'"
v-model="tareWeight"
v-if="tareWeight"
:isAdmin="auth.isAdmin"
/>
<update-merchandise
v-show="activeTab === 'merchandise' && isMerchandise"
@@ -221,7 +218,7 @@ import type {VehicleData} from '~/services/dto/vehicle-data'
import {getVehicleList} from '~/services/vehicle'
import {RECEPTION_TYPE_CODES, SUPPLIER_CODE} from "~/utils/constants";
import {deleteReceptionBovine, getReceptionBovineList,} from "~/services/reception-bovine";
import type {ReceptionData, ReceptionFormData} from "~/services/dto/reception-data";
import type {ReceptionData, ReceptionFormData, WeightEntryData} from "~/services/dto/reception-data";
import {getReception, updateReception} from "~/services/reception";
import UpdateWeight from "~/components/reception/update-weight.vue";
import UpdateMerchandise from "~/components/reception/update-merchandise.vue";
@@ -229,7 +226,7 @@ import UpdateBovin from "~/components/reception/update-bovin.vue";
import {getReceptionTypeList} from "~/services/reception-type";
import type {ReceptionTypeData} from "~/services/dto/reception-type-data";
import {computed} from "vue";
import {updateWeight} from "~/services/weight";
import {createWeight, updateWeight} from "~/services/weight";
import {deleteReceptionPelletBuilding, getReceptionPelletBuildingList} from "~/services/reception-pellet-building";
const form = reactive<ReceptionFormData>({
@@ -246,8 +243,18 @@ const form = reactive<ReceptionFormData>({
vehicleId: ''
})
const createEmptyWeightEntry = (type: 'gross' | 'tare'): WeightEntryData => ({
type,
dsd: null,
weight: null,
weighedAt: null
})
const grossWeight = ref<WeightEntryData>(createEmptyWeightEntry('gross'))
const tareWeight = ref<WeightEntryData>(createEmptyWeightEntry('tare'))
const { printPdf } = usePdfPrinter()
const activeTab = ref<'weightsEmpty' | 'weights' | 'merchandise'>('weightsEmpty')
const activeTab = ref<'weightsEmpty' | 'weights' | 'merchandise'>('weights')
const router = useRouter()
const receptionStore = useReceptionStore()
const allowAnyLicensePlate = ref(false)
@@ -377,6 +384,10 @@ const hydrateFromReception = (reception: ReceptionData | null) => {
form.receptionTypeId = reception?.receptionType?.id
? String(reception.receptionType.id)
: ''
const gross = reception.weights?.find((weight) => weight.type === 'gross') ?? null
const tare = reception.weights?.find((weight) => weight.type === 'tare') ?? null
grossWeight.value = gross ? {...gross} : createEmptyWeightEntry('gross')
tareWeight.value = tare ? {...tare} : createEmptyWeightEntry('tare')
isHydrating.value = false
syncMerchandiseFlag()
}
@@ -629,6 +640,30 @@ const printReceipt = async () => {
// Laisse le temps a la boite de dialogue d'impression de s'ouvrir.
await new Promise((resolve) => setTimeout(resolve, 600))
}
const saveWeightEntry = async (entry: WeightEntryData) => {
if (!idReception || entry.weight === null) {
return
}
const payload = {
type: entry.type,
dsd: entry.dsd ?? null,
weight: entry.weight,
weighedAt: entry.weighedAt ?? null
}
if (entry.id) {
await updateWeight(entry.id, payload)
return
}
await createWeight({
reception: `api/receptions/${idReception}`,
...payload
})
}
async function validate() {
const normalizedLicensePlate = form.licensePlate.trim()
const normalizedReceptionDate = form.receptionDate.trim()
@@ -683,6 +718,10 @@ async function validate() {
await receptionStore.updateReception(idReception, {
...payload
})
await saveWeightEntry(grossWeight.value)
await saveWeightEntry(tareWeight.value)
const refreshedReception = await getReception(idReception)
hydrateFromReception(refreshedReception)
if (isMerchandise.value) {
await clearReceptionBovines(idReception)

View File

@@ -44,6 +44,8 @@ export interface WeightEntryData {
export interface WeightFormData {
id: number
weight: number
weighedAt : string
dsd: number
type: 'gross' | 'tare'
}
@@ -80,6 +82,7 @@ export type ReceptionFormData = {
carrierId: string
driverId: string
vehicleId: string
weight?: ReceptionFormWeight | null
}
export type ReceptionFormWeight = {