203 lines
6.4 KiB
Vue
203 lines
6.4 KiB
Vue
<template>
|
|
<form
|
|
v-if="receptionStore.current?.receptionType?.code === RECEPTION_TYPE_CODES.BOVINS"
|
|
class="flex flex-col gap-16"
|
|
@submit.prevent="goNext"
|
|
>
|
|
<h1 class="text-4xl uppercase font-bold text-primary-500">Sélection des races réceptionnées</h1>
|
|
<div
|
|
class="flex flex-row gap-8 items-center w-full">
|
|
<div
|
|
v-for="type in bovineType"
|
|
:key="type.id"
|
|
class="mt-8 flex flex-row mb-2 w-full">
|
|
<UiNumberInput
|
|
:id="type.id"
|
|
:label="type.label"
|
|
:code="type.code"
|
|
v-model="bovineQuantities[String(type.id)]"
|
|
:placeholder="0"
|
|
:min="0"
|
|
:max="10"
|
|
class="max-w-[150px]"
|
|
wrapper-class="gap-3"
|
|
/>
|
|
</div>
|
|
<div
|
|
class="mt-8 flex flex-row mb-2 gap-6">
|
|
<UiNumberInput
|
|
label="Autres"
|
|
v-model="otherQuantity"
|
|
class="max-w-[80px]"
|
|
wrapper-class="gap-3"
|
|
/>
|
|
</div>
|
|
</div>
|
|
<p class="text-red-500 text-sm" :class="showBovineError ? '' : 'invisible'">
|
|
Veuillez saisir au moins une race bovine.
|
|
</p>
|
|
<div class="flex justify-center">
|
|
<UiButton
|
|
type="submit"
|
|
class="text-xl uppercase bg-primary-500 text-white h-[50px] w-[272px] justify-self-end"
|
|
>Valider
|
|
</UiButton>
|
|
</div>
|
|
</form>
|
|
</template>
|
|
<script setup lang="ts">
|
|
import type {BovineTypeData} from "~/services/dto/bovine-type-data";
|
|
import {getBovineTypeList} from "~/services/bovine-type";
|
|
import {RECEPTION_TYPE_CODES} from "~/utils/constants";
|
|
import {useReceptionStore} from '~/stores/reception'
|
|
import {
|
|
createReceptionBovine,
|
|
deleteReceptionBovine,
|
|
getReceptionBovineList,
|
|
updateReceptionBovine
|
|
} from "~/services/reception-bovine";
|
|
import {computed, onMounted, reactive, ref, watch} from "vue";
|
|
|
|
const toast = useToast()
|
|
const isLoadingBovineType = ref(false)
|
|
const bovineType = ref<BovineTypeData[]>([])
|
|
const receptionStore = useReceptionStore()
|
|
const showBovineError = ref(false)
|
|
const bovineQuantities = reactive<Record<string, number | null>>({})
|
|
const otherQuantity = ref<number | null>(0)
|
|
const receptionId = computed(() => receptionStore.current?.id ?? null)
|
|
const receptionIri = computed(() =>
|
|
receptionId.value ? `/api/receptions/${receptionId.value}` : null
|
|
)
|
|
const totalBovines = computed(() => {
|
|
const base = Object.values(bovineQuantities).reduce((sum, value) => {
|
|
return sum + (value ?? 0)
|
|
}, 0)
|
|
return base + (otherQuantity.value ?? 0)
|
|
})
|
|
|
|
const loadBovineType = async () => {
|
|
isLoadingBovineType.value = true
|
|
try {
|
|
bovineType.value = await getBovineTypeList()
|
|
} finally {
|
|
isLoadingBovineType.value = false
|
|
}
|
|
}
|
|
|
|
onMounted(async () => {
|
|
await loadBovineType()
|
|
})
|
|
|
|
watch(
|
|
[() => receptionId.value, () => bovineType.value],
|
|
async ([id, types]) => {
|
|
if (!id || !receptionIri.value || types.length === 0) {
|
|
return
|
|
}
|
|
|
|
const selectionMap: Record<string, number | null> = {}
|
|
for (const type of types) {
|
|
selectionMap[String(type.id)] = 0
|
|
}
|
|
|
|
const existing = await getReceptionBovineList(receptionIri.value)
|
|
for (const selection of existing) {
|
|
const bovineTypeId = String(selection.bovineType.id)
|
|
selectionMap[bovineTypeId] = selection.quantity ?? 0
|
|
}
|
|
|
|
for (const key of Object.keys(bovineQuantities)) {
|
|
delete bovineQuantities[key]
|
|
}
|
|
Object.assign(bovineQuantities, selectionMap)
|
|
|
|
const existingOther = receptionStore.current?.bovineDetail
|
|
const parsedOther =
|
|
typeof existingOther === 'string' && existingOther.trim() !== ''
|
|
? Number(existingOther)
|
|
: 0
|
|
otherQuantity.value = Number.isFinite(parsedOther) ? parsedOther : 0
|
|
},
|
|
{immediate: true}
|
|
)
|
|
|
|
async function syncBovineSelections(receptionIri: string) {
|
|
const existing = await getReceptionBovineList(receptionIri)
|
|
const existingMap = new Map<string, { id: number; quantity: number | null }>()
|
|
|
|
for (const selection of existing) {
|
|
const bovineTypeId = String(selection.bovineType.id)
|
|
existingMap.set(bovineTypeId, {
|
|
id: selection.id,
|
|
quantity: selection.quantity ?? 0
|
|
})
|
|
}
|
|
|
|
// Supprime les entrées supprimées ou modifiées
|
|
for (const [bovineTypeId, entry] of existingMap.entries()) {
|
|
const selectedQuantity = bovineQuantities[bovineTypeId] ?? 0
|
|
if (!selectedQuantity) {
|
|
await deleteReceptionBovine(entry.id)
|
|
existingMap.delete(bovineTypeId)
|
|
continue
|
|
}
|
|
|
|
if (selectedQuantity !== entry.quantity) {
|
|
await updateReceptionBovine(entry.id, {quantity: selectedQuantity})
|
|
existingMap.set(bovineTypeId, {
|
|
id: entry.id,
|
|
quantity: selectedQuantity
|
|
})
|
|
}
|
|
}
|
|
|
|
// Crée les entrées manquantes
|
|
for (const [bovineTypeId, quantity] of Object.entries(bovineQuantities)) {
|
|
if (!quantity) {
|
|
continue
|
|
}
|
|
if (existingMap.has(bovineTypeId)) {
|
|
// Déjà à jour
|
|
continue
|
|
}
|
|
await createReceptionBovine({
|
|
reception: receptionIri,
|
|
bovineType: `/api/bovine_types/${bovineTypeId}`,
|
|
quantity
|
|
})
|
|
}
|
|
}
|
|
|
|
async function goNext() {
|
|
if (!receptionStore.current || !receptionIri.value) {
|
|
return
|
|
}
|
|
|
|
showBovineError.value = false
|
|
|
|
if (totalBovines.value === 0) {
|
|
showBovineError.value = true
|
|
return
|
|
}
|
|
|
|
if (totalBovines.value > 52) {
|
|
toast.error({
|
|
title: 'Erreur',
|
|
message: ('Le total des bovins ne peut pas dépasser 52.')
|
|
})
|
|
return
|
|
}
|
|
|
|
const nextStep = receptionStore.current.currentStep + 1
|
|
await syncBovineSelections(receptionIri.value)
|
|
|
|
await receptionStore.updateReception(receptionStore.current.id, {
|
|
merchandiseType: null,
|
|
merchandiseDetail: null,
|
|
bovineDetail: otherQuantity.value ? String(otherQuantity.value) : null,
|
|
currentStep: nextStep
|
|
})
|
|
}
|
|
</script>
|