From 5912216a89390d79cffdc92dee7c49033dc32cbc Mon Sep 17 00:00:00 2001 From: Matthieu Date: Fri, 13 Mar 2026 11:19:09 +0100 Subject: [PATCH] fix(piece) : persist slot quantity on blur and send prix as string - Save composant piece slot quantity via PATCH on blur - Pass slotId through hierarchy and selection entries - Send prix as string (not number) to match backend expectation - Show quantity in view mode when > 1 - Allow quantity edit for all pieces (not just root-level) Co-Authored-By: Claude Opus 4.6 --- app/components/PieceItem.vue | 8 +++++-- app/composables/useComponentEdit.ts | 23 ++++++++++++++++----- app/composables/useMachineDetailUpdates.ts | 19 +++++++++++------ app/composables/useMachineHierarchy.ts | 1 + app/pages/component/[id]/edit.vue | 2 ++ app/shared/model/definitionOverrides.ts | 4 ++-- app/shared/utils/structureSelectionUtils.ts | 2 ++ 7 files changed, 44 insertions(+), 15 deletions(-) diff --git a/app/components/PieceItem.vue b/app/components/PieceItem.vue index 9314673..9d6cd2b 100644 --- a/app/components/PieceItem.vue +++ b/app/components/PieceItem.vue @@ -69,7 +69,7 @@
-
+
@@ -82,6 +82,10 @@ @blur="updatePiece" />
+
+ Quantité: + {{ displayQuantity }} +
Référence: { let parsedPrice = null if (prixValue !== null && prixValue !== undefined && String(prixValue).trim().length > 0) { const numeric = Number(prixValue) - if (!Number.isNaN(numeric)) parsedPrice = numeric + if (!Number.isNaN(numeric)) parsedPrice = String(numeric) } const product = selectedProduct.value ? { ...selectedProduct.value } : null emit('update', { diff --git a/app/composables/useComponentEdit.ts b/app/composables/useComponentEdit.ts index 41f25df..38408d1 100644 --- a/app/composables/useComponentEdit.ts +++ b/app/composables/useComponentEdit.ts @@ -7,6 +7,7 @@ import { useProductTypes } from '~/composables/useProductTypes' import { usePieces } from '~/composables/usePieces' import { useProducts } from '~/composables/useProducts' import { useCustomFields } from '~/composables/useCustomFields' +import type { SelectionEntry } from '~/shared/utils/structureSelectionUtils' import { useApi } from '~/composables/useApi' import { useToast } from '~/composables/useToast' import { extractRelationId } from '~/shared/apiRelations' @@ -53,7 +54,7 @@ const historyFieldLabels: Record = { export function useComponentEdit(componentId: string) { const { canEdit } = usePermissions() const router = useRouter() - const { get } = useApi() + const { get, patch } = useApi() const { componentTypes, loadComponentTypes } = useComponentTypes() const { pieceTypes, loadPieceTypes } = usePieceTypes() const { productTypes, loadProductTypes } = useProductTypes() @@ -269,6 +270,21 @@ export function useComponentEdit(componentId: string) { } }) + const saveSlotQuantity = async (entry: SelectionEntry) => { + const slotId = entry.slotId + const quantity = typeof entry._definition?.quantity === 'number' + ? Math.max(1, entry._definition.quantity) + : null + if (!slotId || quantity === null) return + try { + await patch(`/composant-piece-slots/${slotId}`, { quantity }) + toast.showSuccess('Quantité mise à jour') + } + catch (error: any) { + toast.showError(error?.message || 'Erreur lors de la mise à jour de la quantité') + } + } + const submitEdition = async () => { if (!component.value) { return @@ -299,10 +315,6 @@ export function useComponentEdit(componentId: string) { payload.prix = null } - if (component.value.structure) { - payload.structure = component.value.structure - } - saving.value = true try { const result = await updateComposant(component.value.id, payload) @@ -457,6 +469,7 @@ export function useComponentEdit(componentId: string) { handleFilesAdded, refreshDocuments, submitEdition, + saveSlotQuantity, resolvePieceLabel, resolveProductLabel, resolveSubcomponentLabel, diff --git a/app/composables/useMachineDetailUpdates.ts b/app/composables/useMachineDetailUpdates.ts index 3b779f4..24074c3 100644 --- a/app/composables/useMachineDetailUpdates.ts +++ b/app/composables/useMachineDetailUpdates.ts @@ -110,18 +110,18 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) { const productId = updatedComponent.productId ? String(updatedComponent.productId) : null - const prix = + const prixStr = updatedComponent.prix !== null && updatedComponent.prix !== undefined && String(updatedComponent.prix).trim() !== '' - ? Number(updatedComponent.prix) + ? String(updatedComponent.prix) : null const result: any = await updateComposantApi(updatedComponent.id as string, { name: updatedComponent.name, reference: updatedComponent.reference, constructeurIds: cIds, - prix: Number.isNaN(prix) ? null : prix, + prix: prixStr, productId, } as any) if (result.success) { @@ -140,18 +140,18 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) { updatedPiece.constructeur, ) const productId = updatedPiece.productId ? String(updatedPiece.productId) : null - const prix = + const prixStr = updatedPiece.prix !== null && updatedPiece.prix !== undefined && String(updatedPiece.prix).trim() !== '' - ? Number(updatedPiece.prix) + ? String(updatedPiece.prix) : null const result: any = await updatePieceApi(updatedPiece.id as string, { name: updatedPiece.name, reference: updatedPiece.reference || null, constructeurIds: cIds, - prix: Number.isNaN(prix) ? null : prix, + prix: prixStr, productId, } as any) if (result.success) { @@ -181,6 +181,13 @@ export function useMachineDetailUpdates(deps: UseMachineDetailUpdatesDeps) { ) } } + + // Update slot quantity if this is a composant structure piece + const slotId = updatedPiece.slotId as string | null + const quantity = typeof updatedPiece.quantity === 'number' ? Math.max(1, updatedPiece.quantity) : null + if (slotId && quantity !== null) { + await apiPatch(`/composant-piece-slots/${slotId}`, { quantity }) + } } catch (error) { console.error('Erreur lors de la mise à jour de la pièce:', error) } diff --git a/app/composables/useMachineHierarchy.ts b/app/composables/useMachineHierarchy.ts index df7b28e..380faaf 100644 --- a/app/composables/useMachineHierarchy.ts +++ b/app/composables/useMachineHierarchy.ts @@ -237,6 +237,7 @@ export const buildMachineHierarchyFromLinks = ( constructeurs: resolved?.constructeurs || [], documents: [], quantity, + slotId: def.slotId || definition.slotId || null, typePieceId: resolved?.typePieceId || definition.typePieceId || def.typePieceId || null, typePiece: resolved?.typePiece || null, parentComponentLinkId: machineComponentLinkId, diff --git a/app/pages/component/[id]/edit.vue b/app/pages/component/[id]/edit.vue index 7d751cb..fff3470 100644 --- a/app/pages/component/[id]/edit.vue +++ b/app/pages/component/[id]/edit.vue @@ -179,6 +179,7 @@ placeholder="Qté" class="input input-bordered input-xs w-16 ml-auto" @input="entry._definition.quantity = Math.max(1, entry._definition.quantity || 1)" + @blur="saveSlotQuantity(entry)" /> @@ -319,6 +320,7 @@ const { removeDocument, handleFilesAdded, submitEdition, + saveSlotQuantity, resolvePieceLabel, resolveProductLabel, resolveSubcomponentLabel, diff --git a/app/shared/model/definitionOverrides.ts b/app/shared/model/definitionOverrides.ts index b309f52..5401bcd 100644 --- a/app/shared/model/definitionOverrides.ts +++ b/app/shared/model/definitionOverrides.ts @@ -4,7 +4,7 @@ export interface DefinitionOverridePayload { name?: string reference?: string constructeurIds?: string[] - prix?: number + prix?: string } export const sanitizeDefinitionOverrides = (definition: any): DefinitionOverridePayload | null => { @@ -41,7 +41,7 @@ export const sanitizeDefinitionOverrides = (definition: any): DefinitionOverride if (definition.prix !== undefined && definition.prix !== null && definition.prix !== '') { const parsed = Number(definition.prix) if (!Number.isNaN(parsed)) { - payload.prix = parsed + payload.prix = String(parsed) } } diff --git a/app/shared/utils/structureSelectionUtils.ts b/app/shared/utils/structureSelectionUtils.ts index b1bbd98..3eae918 100644 --- a/app/shared/utils/structureSelectionUtils.ts +++ b/app/shared/utils/structureSelectionUtils.ts @@ -4,6 +4,7 @@ export type SelectionEntry = { requirementLabel: string resolvedName: string quantity?: number + slotId?: string _definition?: Record } @@ -62,6 +63,7 @@ export function collectStructureSelections( requirementLabel: resolvers.resolvePieceLabel(definition), resolvedName: catalogPiece?.name || selectedId, quantity: typeof definition?.quantity === 'number' ? definition.quantity : undefined, + slotId: isNonEmptyString(entry?.slotId) ? entry.slotId : undefined, _definition: definition, }) })