diff --git a/app/components/TypeEditForm.vue b/app/components/TypeEditForm.vue index 18191e3..f6a6ba1 100644 --- a/app/components/TypeEditForm.vue +++ b/app/components/TypeEditForm.vue @@ -62,19 +62,30 @@ const deepClone = value => JSON.parse(JSON.stringify(value)) const createFieldKey = () => `cf-${Math.random().toString(16).slice(2)}-${Date.now()}` +const normalizeCustomField = (field = {}, index = 0) => { + const clone = deepClone(field) + if (clone.type === 'select') { + if (typeof clone.optionsText !== 'string' || !clone.optionsText.length) { + if (Array.isArray(clone.options)) { + clone.optionsText = clone.options.map(option => String(option).trim()).filter(Boolean).join('\n') + } else { + clone.optionsText = '' + } + } + } + const currentOrder = + typeof clone?.orderIndex === 'number' ? clone.orderIndex : index + clone.orderIndex = currentOrder + if (typeof clone?.__key !== 'string' || !clone.__key) { + clone.__key = createFieldKey() + } + return clone +} + const withNormalizedOrder = (items = []) => { if (!Array.isArray(items)) { return [] } return items - .map((item, index) => { - const clone = deepClone(item) - const currentOrder = - typeof clone?.orderIndex === 'number' ? clone.orderIndex : index - clone.orderIndex = currentOrder - if (typeof clone?.__key !== 'string' || !clone.__key) { - clone.__key = createFieldKey() - } - return clone - }) + .map((item, index) => normalizeCustomField(item, index)) .sort((a, b) => (a.orderIndex ?? 0) - (b.orderIndex ?? 0)) .map((item, index) => ({ ...item, orderIndex: index })) } diff --git a/app/components/TypeEditPieceRequirementsSection.vue b/app/components/TypeEditPieceRequirementsSection.vue index 1ba9486..9d530f0 100644 --- a/app/components/TypeEditPieceRequirementsSection.vue +++ b/app/components/TypeEditPieceRequirementsSection.vue @@ -12,7 +12,7 @@ diff --git a/app/components/common/SearchSelect.vue b/app/components/common/SearchSelect.vue index b4e8f63..ebc1248 100644 --- a/app/components/common/SearchSelect.vue +++ b/app/components/common/SearchSelect.vue @@ -184,11 +184,13 @@ watch( watch( baseOptions, - () => { - if (!openDropdown.value) { - searchTerm.value = selectedOption.value ? resolveLabel(selectedOption.value) : searchTerm.value + (newOptions) => { + console.log('[SearchSelect] baseOptions changed, count:', newOptions.length, 'modelValue:', props.modelValue, 'selectedOption:', selectedOption.value?.id) + if (!openDropdown.value && selectedOption.value) { + searchTerm.value = resolveLabel(selectedOption.value) } - } + }, + { deep: true } ) watch(openDropdown, (isOpen) => { diff --git a/app/composables/useMachineTypesApi.js b/app/composables/useMachineTypesApi.js index 83f47fa..5712f60 100644 --- a/app/composables/useMachineTypesApi.js +++ b/app/composables/useMachineTypesApi.js @@ -10,18 +10,28 @@ const normalizeRequirementList = (value, relationKey) => { if (!Array.isArray(value)) { return [] } - return value.map((entry) => { + return value.map((entry, index) => { if (!entry || typeof entry !== 'object') { return entry } const normalized = { ...entry } + const relationField = relationKey.replace('Id', '') + const relationValue = normalized[relationField] + console.log(`[normalizeRequirementList] Entry ${index}:`, { + relationKey, + relationField, + hasRelationKey: !!normalized[relationKey], + relationValue, + relationValueType: typeof relationValue + }) if (relationKey && !normalized[relationKey]) { - const relationValue = normalized[relationKey.replace('Id', '')] const relationId = extractRelationId(relationValue) + console.log(`[normalizeRequirementList] Extracted ID:`, relationId) if (relationId) { normalized[relationKey] = relationId } } + console.log(`[normalizeRequirementList] Normalized entry:`, normalized) return normalized }) } @@ -56,7 +66,7 @@ const extractCollection = (payload) => { export function useMachineTypesApi () { const { showSuccess, showError, showInfo } = useToast() - const { get, post, patch, delete: del } = useApi() + const { get, post, put, delete: del } = useApi() const loadMachineTypes = async () => { loading.value = true @@ -94,7 +104,7 @@ export function useMachineTypesApi () { const updateMachineType = async (id, typeData) => { loading.value = true try { - const result = await patch(`/type_machines/${id}`, typeData) + const result = await put(`/type_machines/${id}`, typeData) if (result.success) { const normalized = normalizeMachineType(result.data) const index = machineTypes.value.findIndex(type => type.id === id) @@ -130,19 +140,28 @@ export function useMachineTypesApi () { } } - const getMachineTypeById = async (id) => { - // D'abord chercher dans le cache local - const localType = machineTypes.value.find(type => type.id === id) - if (localType) { - return { success: true, data: localType } + const getMachineTypeById = async (id, forceRefresh = false) => { + // D'abord chercher dans le cache local (sauf si forceRefresh) + if (!forceRefresh) { + const localType = machineTypes.value.find(type => type.id === id) + if (localType) { + return { success: true, data: localType } + } } - // Si pas trouvé localement, récupérer depuis l'API + // Récupérer depuis l'API try { const result = await get(`/type_machines/${id}`) if (result.success) { - // Ajouter au cache local - machineTypes.value.push(normalizeMachineType(result.data)) + const normalized = normalizeMachineType(result.data) + // Mettre à jour le cache local + const index = machineTypes.value.findIndex(type => type.id === id) + if (index !== -1) { + machineTypes.value[index] = normalized + } else { + machineTypes.value.push(normalized) + } + return { success: true, data: normalized } } return result } catch (error) { diff --git a/app/pages/component/[id]/edit.vue b/app/pages/component/[id]/edit.vue index f6743ac..b43c711 100644 --- a/app/pages/component/[id]/edit.vue +++ b/app/pages/component/[id]/edit.vue @@ -594,6 +594,15 @@ const selectedTypeStructure = computed(() => { return structure ? normalizeStructureForEditor(structure) : null }) +const refreshCustomFieldInputs = ( + structureOverride?: ComponentModelStructure | null, + valuesOverride?: any[] | null, +) => { + const structure = structureOverride ?? selectedTypeStructure.value ?? null + const values = valuesOverride ?? component.value?.customFieldValues ?? null + customFieldInputs.value = buildCustomFieldInputs(structure, values) +} + const requiredCustomFieldsFilled = computed(() => customFieldInputs.value.every((field) => { if (!field.required) { @@ -641,6 +650,7 @@ const fetchComponent = async () => { const customValues = await getCustomFieldValuesByEntity('composant', result.data.id) if (customValues.success && Array.isArray(customValues.data)) { component.value.customFieldValues = customValues.data + refreshCustomFieldInputs(undefined, customValues.data) } } else { component.value = null @@ -677,10 +687,7 @@ watch( void ensureConstructeurs(editionForm.constructeurIds) } - customFieldInputs.value = buildCustomFieldInputs( - currentStructure, - currentComponent.customFieldValues, - ) + refreshCustomFieldInputs(currentStructure, currentComponent.customFieldValues) initialized = true }, @@ -691,10 +698,7 @@ watch(selectedTypeStructure, (currentStructure) => { if (!component.value) { return } - customFieldInputs.value = buildCustomFieldInputs( - currentStructure, - component.value.customFieldValues, - ) + refreshCustomFieldInputs(currentStructure, component.value.customFieldValues) }) const submitEdition = async () => { @@ -719,7 +723,7 @@ const submitEdition = async () => { if (rawPrice) { const parsed = Number(rawPrice) if (!Number.isNaN(parsed)) { - payload.prix = parsed + payload.prix = String(parsed) } } else { payload.prix = null diff --git a/app/pages/component/create.vue b/app/pages/component/create.vue index baa27f6..db90535 100644 --- a/app/pages/component/create.vue +++ b/app/pages/component/create.vue @@ -870,7 +870,7 @@ const submitCreation = async () => { if (rawPrice) { const parsed = Number(rawPrice) if (!Number.isNaN(parsed)) { - payload.prix = parsed + payload.prix = String(parsed) } } diff --git a/app/pages/machine-skeleton/new.vue b/app/pages/machine-skeleton/new.vue index 0e7a666..7799828 100644 --- a/app/pages/machine-skeleton/new.vue +++ b/app/pages/machine-skeleton/new.vue @@ -86,6 +86,7 @@ import { ref, computed, onMounted } from 'vue' import { useMachineTypesApi } from '~/composables/useMachineTypesApi' import { useToast } from '~/composables/useToast' +import { extractRelationId } from '~/shared/apiRelations' import IconLucidePlus from '~icons/lucide/plus' import IconLucideClipboardList from '~icons/lucide/clipboard-list' import IconLucideList from '~icons/lucide/list' @@ -142,6 +143,20 @@ const parseOptions = (field = {}) => { return [] } +const toModelTypeIri = (value) => { + if (!value) { + return undefined + } + if (typeof value === 'string' && value.startsWith('/api/model_types/')) { + return value + } + const relationId = extractRelationId(value) + if (relationId) { + return `/api/model_types/${relationId}` + } + return typeof value === 'string' ? `/api/model_types/${value}` : undefined +} + const normalizeCustomFields = (fields = []) => fields .filter(field => field?.name && field.name.trim() !== '') @@ -165,9 +180,9 @@ const toIntegerOrNull = (value, fallback = null) => { const normalizeComponentRequirements = (requirements = []) => requirements - .filter(req => req?.typeComposantId) + .filter(req => req?.typeComposantId || req?.typeComposant) .map((req, index) => ({ - typeComposantId: req.typeComposantId, + typeComposant: toModelTypeIri(req.typeComposantId || req.typeComposant), label: req.label?.trim() ? req.label.trim() : undefined, minCount: toIntegerOrNull(req.minCount, 1), maxCount: toIntegerOrNull(req.maxCount, null), @@ -180,9 +195,9 @@ const normalizeComponentRequirements = (requirements = []) => const normalizePieceRequirements = (requirements = []) => requirements - .filter(req => req?.typePieceId) + .filter(req => req?.typePieceId || req?.typePiece) .map((req, index) => ({ - typePieceId: req.typePieceId, + typePiece: toModelTypeIri(req.typePieceId || req.typePiece), label: req.label?.trim() ? req.label.trim() : undefined, minCount: toIntegerOrNull(req.minCount, 0), maxCount: toIntegerOrNull(req.maxCount, null), @@ -195,9 +210,9 @@ const normalizePieceRequirements = (requirements = []) => const normalizeProductRequirements = (requirements = []) => requirements - .filter(req => req?.typeProductId) + .filter(req => req?.typeProductId || req?.typeProduct) .map((req, index) => ({ - typeProductId: req.typeProductId, + typeProduct: toModelTypeIri(req.typeProductId || req.typeProduct), label: req.label?.trim() ? req.label.trim() : undefined, minCount: toIntegerOrNull(req.minCount, 0), maxCount: toIntegerOrNull(req.maxCount, null), diff --git a/app/pages/pieces/[id]/edit.vue b/app/pages/pieces/[id]/edit.vue index cacec87..5df0bed 100644 --- a/app/pages/pieces/[id]/edit.vue +++ b/app/pages/pieces/[id]/edit.vue @@ -154,26 +154,26 @@ /> - + Squelette sélectionné - {{ selectedType.description || 'Ce squelette définit la structure et les champs personnalisés de la pièce.' }} + {{ selectedType?.description || 'Ce squelette définit la structure et les champs personnalisés de la pièce.' }} - {{ formatPieceStructurePreview(selectedType.structure) }} + {{ formatPieceStructurePreview(resolvedStructure) }} - + Consulter le détail du squelette - + Champs personnalisés - + {{ field.name }} : {{ field.value }} @@ -395,12 +395,14 @@ import { useApi } from '~/composables/useApi' import { useToast } from '~/composables/useToast' import { useDocuments } from '~/composables/useDocuments' import { useConstructeurs } from '~/composables/useConstructeurs' +import { extractRelationId } from '~/shared/apiRelations' import { getFileIcon } from '~/utils/fileIcons' import { canPreviewDocument, isImageDocument, isPdfDocument } from '~/utils/documentPreview' import { formatPieceStructurePreview } from '~/shared/modelUtils' import { uniqueConstructeurIds } from '~/shared/constructeurUtils' import type { PieceModelProduct, PieceModelStructure } from '~/shared/types/inventory' import type { ModelType } from '~/services/modelTypes' +import { getModelType } from '~/services/modelTypes' interface PieceCatalogType extends ModelType { structure: PieceModelStructure | null @@ -424,7 +426,7 @@ const router = useRouter() const { get } = useApi() const { pieceTypes, loadPieceTypes } = usePieceTypes() const { updatePiece } = usePieces() -const { upsertCustomFieldValue, updateCustomFieldValue } = useCustomFields() +const { upsertCustomFieldValue, updateCustomFieldValue, getCustomFieldValuesByEntity } = useCustomFields() const toast = useToast() const { loadDocumentsByPiece, uploadDocuments, deleteDocument } = useDocuments() const { ensureConstructeurs } = useConstructeurs() @@ -440,6 +442,7 @@ const previewDocument = ref(null) const previewVisible = ref(false) const selectedTypeId = ref('') +const pieceTypeDetails = ref(null) const editionForm = reactive({ name: '' as string, reference: '' as string, @@ -451,6 +454,18 @@ const editionForm = reactive({ const customFieldInputs = ref([]) const documentIcon = (doc: any) => getFileIcon({ name: doc?.filename || doc?.name, mime: doc?.mimeType }) +const resolvedStructure = computed(() => + pieceTypeDetails.value?.structure ?? selectedType.value?.structure ?? null, +) + +const refreshCustomFieldInputs = ( + structureOverride?: PieceModelStructure | null, + valuesOverride?: any[] | null, +) => { + const structure = structureOverride ?? resolvedStructure.value ?? null + const values = valuesOverride ?? piece.value?.customFieldValues ?? null + customFieldInputs.value = buildCustomFieldInputs(structure, values) +} const formatSize = (size: number | null | undefined) => { if (size === null || size === undefined) { return '—' @@ -578,7 +593,7 @@ const selectedType = computed(() => { }) const structureProducts = computed(() => - getStructureProducts(selectedType.value?.structure ?? null), + getStructureProducts(resolvedStructure.value), ) const requiresProductSelection = computed(() => structureProducts.value.length > 0) @@ -659,12 +674,37 @@ const fetchPiece = async () => { if (result.success) { piece.value = result.data pieceDocuments.value = Array.isArray(result.data?.documents) ? result.data.documents : [] + const customValues = await getCustomFieldValuesByEntity('piece', result.data.id) + if (customValues.success && Array.isArray(customValues.data)) { + piece.value.customFieldValues = customValues.data + refreshCustomFieldInputs(undefined, customValues.data) + } + await loadPieceTypeDetails(result.data) } else { piece.value = null pieceDocuments.value = [] } } +const loadPieceTypeDetails = async (currentPiece: any) => { + const typeId = currentPiece?.typePieceId + || extractRelationId(currentPiece?.typePiece) + || '' + if (!typeId) { + pieceTypeDetails.value = null + return + } + try { + const type = await getModelType(typeId) + if (type && typeof type === 'object') { + pieceTypeDetails.value = type + refreshCustomFieldInputs(type.structure ?? null, currentPiece?.customFieldValues ?? null) + } + } catch (error) { + pieceTypeDetails.value = null + } +} + let initialized = false watch( @@ -674,7 +714,13 @@ watch( return } - selectedTypeId.value = currentPiece.typePieceId || '' + const resolvedTypeId = currentPiece.typePieceId + || extractRelationId(currentPiece.typePiece) + || '' + if (resolvedTypeId && !currentPiece.typePieceId) { + currentPiece.typePieceId = resolvedTypeId + } + selectedTypeId.value = resolvedTypeId editionForm.name = currentPiece.name || '' editionForm.reference = currentPiece.reference || '' @@ -689,10 +735,7 @@ watch( void ensureConstructeurs(editionForm.constructeurIds) } - customFieldInputs.value = buildCustomFieldInputs( - currentType?.structure ?? null, - currentPiece.customFieldValues, - ) + refreshCustomFieldInputs(currentType?.structure ?? null, currentPiece.customFieldValues) initialized = true }, @@ -703,10 +746,16 @@ watch(selectedType, (currentType) => { if (!piece.value || !currentType) { return } - customFieldInputs.value = buildCustomFieldInputs( - currentType.structure, - piece.value.customFieldValues, - ) + if (!pieceTypeDetails.value) { + refreshCustomFieldInputs(currentType.structure, piece.value.customFieldValues) + } +}) + +watch(resolvedStructure, (currentStructure) => { + if (!piece.value) { + return + } + refreshCustomFieldInputs(currentStructure, piece.value.customFieldValues) }) const submitEdition = async () => { @@ -744,7 +793,7 @@ const submitEdition = async () => { if (rawPrice) { const parsed = Number(rawPrice) if (!Number.isNaN(parsed)) { - payload.prix = parsed + payload.prix = String(parsed) } } else { payload.prix = null diff --git a/app/pages/pieces/create.vue b/app/pages/pieces/create.vue index 5750858..950c65d 100644 --- a/app/pages/pieces/create.vue +++ b/app/pages/pieces/create.vue @@ -504,7 +504,7 @@ const submitCreation = async () => { if (rawPrice) { const parsed = Number(rawPrice) if (!Number.isNaN(parsed)) { - payload.prix = parsed + payload.prix = String(parsed) } } diff --git a/app/pages/product/[id]/edit.vue b/app/pages/product/[id]/edit.vue index 0fda70e..7c2fc2b 100644 --- a/app/pages/product/[id]/edit.vue +++ b/app/pages/product/[id]/edit.vue @@ -352,7 +352,7 @@ const route = useRoute() const router = useRouter() const toast = useToast() const { getProduct, updateProduct } = useProducts() -const { upsertCustomFieldValue, updateCustomFieldValue } = useCustomFields() +const { upsertCustomFieldValue, updateCustomFieldValue, getCustomFieldValuesByEntity } = useCustomFields() const { loadDocumentsByProduct, uploadDocuments: uploadProductDocuments, @@ -373,6 +373,15 @@ const productDocuments = ref([]) const previewDocument = ref(null) const previewVisible = ref(false) +const refreshCustomFieldInputs = ( + structureOverride?: ProductModelStructure | null, + valuesOverride?: any[] | null, +) => { + const nextStructure = structureOverride ?? structure.value ?? null + const nextValues = valuesOverride ?? product.value?.customFieldValues ?? null + customFieldInputs.value = buildCustomFieldInputs(nextStructure, nextValues) +} + const editionForm = reactive({ name: '' as string, reference: '' as string, @@ -493,6 +502,11 @@ const loadProduct = async () => { product.value = result.data productDocuments.value = Array.isArray(result.data?.documents) ? result.data.documents : [] await loadProductType() + const customValues = await getCustomFieldValuesByEntity('product', result.data.id) + if (customValues.success && Array.isArray(customValues.data)) { + product.value.customFieldValues = customValues.data + refreshCustomFieldInputs(undefined, customValues.data) + } await hydrateForm() await refreshDocuments() } else { @@ -582,7 +596,7 @@ const hydrateForm = async () => { editionForm.supplierPrice = product.value.supplierPrice !== null && product.value.supplierPrice !== undefined ? String(product.value.supplierPrice) : '' - customFieldInputs.value = buildCustomFieldInputs(structure.value, product.value.customFieldValues) + refreshCustomFieldInputs(structure.value, product.value.customFieldValues) if (editionForm.constructeurIds.length) { await ensureConstructeurs(editionForm.constructeurIds) } @@ -691,11 +705,13 @@ const submitEdition = async () => { constructeurIds, } - const rawPrice = editionForm.supplierPrice.trim() - payload.supplierPrice = rawPrice + const rawPrice = typeof editionForm.supplierPrice === 'string' + ? editionForm.supplierPrice.trim() + : editionForm.supplierPrice + payload.supplierPrice = rawPrice !== '' && rawPrice !== null && rawPrice !== undefined ? Number.isNaN(Number(rawPrice)) ? null - : Number(rawPrice) + : String(Number(rawPrice)) : null saving.value = true @@ -730,20 +746,29 @@ const saveCustomFieldValues = async (productId: string) => { continue } - if (!field.customFieldId) { - continue - } + const metadata = field.customFieldId + ? undefined + : { customFieldName: field.name, customFieldType: field.type, customFieldRequired: field.required } const result = await upsertCustomFieldValue( field.customFieldId, 'product', productId, String(value ?? ''), - { customFieldName: field.name, customFieldType: field.type, customFieldRequired: field.required }, + metadata, ) if (!result.success) { failed.push(field.name) + } else { + const createdValue = result.data + if (createdValue?.id) { + field.customFieldValueId = createdValue.id + } + const resolvedId = createdValue?.customField?.id || field.customFieldId + if (resolvedId) { + field.customFieldId = resolvedId + } } } return failed diff --git a/app/pages/product/create.vue b/app/pages/product/create.vue index 791dda5..6b950ff 100644 --- a/app/pages/product/create.vue +++ b/app/pages/product/create.vue @@ -425,11 +425,13 @@ const buildPayload = () => { payload.constructeurIds = uniqueConstructeurIds(creationForm.constructeurIds) - const rawPrice = creationForm.supplierPrice.trim() - if (rawPrice) { + const rawPrice = typeof creationForm.supplierPrice === 'string' + ? creationForm.supplierPrice.trim() + : creationForm.supplierPrice + if (rawPrice !== '' && rawPrice !== null && rawPrice !== undefined) { const parsed = Number(rawPrice) if (!Number.isNaN(parsed)) { - payload.supplierPrice = parsed + payload.supplierPrice = String(parsed) } } @@ -486,19 +488,31 @@ const submitCreation = async () => { const saveCustomFieldValues = async (productId: string) => { const failed: string[] = [] for (const field of customFieldInputs.value) { - if (!field.customFieldId || !field.name) { + if (!field.name) { continue } const value = field.value ?? '' + const metadata = field.customFieldId + ? undefined + : { customFieldName: field.name, customFieldType: field.type, customFieldRequired: field.required } const result = await upsertCustomFieldValue( field.customFieldId, 'product', productId, String(value ?? ''), - { customFieldName: field.name, customFieldType: field.type, customFieldRequired: field.required }, + metadata, ) if (!result.success) { failed.push(field.name) + } else { + const createdValue = result.data + if (createdValue?.id) { + field.customFieldValueId = createdValue.id + } + const resolvedId = createdValue?.customField?.id || field.customFieldId + if (resolvedId) { + field.customFieldId = resolvedId + } } } return failed diff --git a/app/pages/type/edit/[id].vue b/app/pages/type/edit/[id].vue index 824b9db..df14c07 100644 --- a/app/pages/type/edit/[id].vue +++ b/app/pages/type/edit/[id].vue @@ -52,6 +52,7 @@ import { ref, onMounted } from 'vue' import { useRoute, useRouter } from 'vue-router' import { useMachineTypesApi } from '~/composables/useMachineTypesApi' import { useToast } from '~/composables/useToast' +import { extractRelationId } from '~/shared/apiRelations' const route = useRoute() const router = useRouter() @@ -90,6 +91,20 @@ const parseOptions = (field = {}) => { return [] } +const toModelTypeIri = (value) => { + if (!value) { + return undefined + } + if (typeof value === 'string' && value.startsWith('/api/model_types/')) { + return value + } + const relationId = extractRelationId(value) + if (relationId) { + return `/api/model_types/${relationId}` + } + return typeof value === 'string' ? `/api/model_types/${value}` : undefined +} + const normalizeCustomFields = (fields = []) => fields .filter(field => field?.name && field.name.trim() !== '') @@ -113,9 +128,9 @@ const toIntegerOrNull = (value, fallback = null) => { const normalizeComponentRequirements = (requirements = []) => requirements - .filter(req => req?.typeComposantId) + .filter(req => req?.typeComposantId || req?.typeComposant) .map((req, index) => ({ - typeComposantId: req.typeComposantId, + typeComposant: toModelTypeIri(req.typeComposantId || req.typeComposant), label: req.label?.trim() ? req.label.trim() : undefined, minCount: toIntegerOrNull(req.minCount, 1), maxCount: toIntegerOrNull(req.maxCount, null), @@ -128,9 +143,9 @@ const normalizeComponentRequirements = (requirements = []) => const normalizePieceRequirements = (requirements = []) => requirements - .filter(req => req?.typePieceId) + .filter(req => req?.typePieceId || req?.typePiece) .map((req, index) => ({ - typePieceId: req.typePieceId, + typePiece: toModelTypeIri(req.typePieceId || req.typePiece), label: req.label?.trim() ? req.label.trim() : undefined, minCount: toIntegerOrNull(req.minCount, 0), maxCount: toIntegerOrNull(req.maxCount, null), @@ -143,9 +158,9 @@ const normalizePieceRequirements = (requirements = []) => const normalizeProductRequirements = (requirements = []) => requirements - .filter(req => req?.typeProductId) + .filter(req => req?.typeProductId || req?.typeProduct) .map((req, index) => ({ - typeProductId: req.typeProductId, + typeProduct: toModelTypeIri(req.typeProductId || req.typeProduct), label: req.label?.trim() ? req.label.trim() : undefined, minCount: toIntegerOrNull(req.minCount, 0), maxCount: toIntegerOrNull(req.maxCount, null), @@ -194,7 +209,7 @@ onMounted(async () => { console.log('=== EDIT TYPE PAGE LOADING ===') console.log('Loading type with ID:', typeId) - const result = await getMachineTypeById(typeId) + const result = await getMachineTypeById(typeId, true) console.log('API Result:', result) if (result.success) { diff --git a/app/shared/constructeurUtils.ts b/app/shared/constructeurUtils.ts index 0ebc386..1ec3733 100644 --- a/app/shared/constructeurUtils.ts +++ b/app/shared/constructeurUtils.ts @@ -117,21 +117,48 @@ export const formatConstructeurContact = ( export const buildConstructeurRequestPayload = >( payload: T, ): T & { constructeurs?: string[] } => { - const ids = uniqueConstructeurIds( + const collected = new Set(uniqueConstructeurIds( payload?.constructeurIds, payload?.constructeurId, payload?.constructeur, payload?.constructeurs, - ); + )); + + if (!collected.size) { + const fallbackLists = [ + payload?.constructeurIds, + payload?.constructeurs, + ]; + fallbackLists.forEach((list) => { + if (!Array.isArray(list)) { + return; + } + list.forEach((item) => { + if (typeof item === 'string') { + const id = toStringId(item); + if (id) { + collected.add(id); + } + return; + } + if (isObject(item) && typeof item.id === 'string') { + collected.add(item.id); + } + }); + }); + } + + const ids = Array.from(collected); const next = { ...payload } as Record; - if (ids.length) { - next.constructeurs = ids.map((id) => `/api/constructeurs/${id}`); - } delete next.constructeurId; delete next.constructeur; delete next.constructeurs; delete next.constructeurIds; + if (ids.length) { + next.constructeurs = ids.map((id) => `/api/constructeurs/${id}`); + } + return next as T & { constructeurs?: string[] }; }; diff --git a/nuxt.config.ts b/nuxt.config.ts index 8a66009..89f61fe 100644 --- a/nuxt.config.ts +++ b/nuxt.config.ts @@ -5,7 +5,7 @@ export default defineNuxtConfig({ devtools: { enabled: true }, devServer: { host: '0.0.0.0', - port: 3001 + port: 3000 }, modules: [ [
- {{ selectedType.description || 'Ce squelette définit la structure et les champs personnalisés de la pièce.' }} + {{ selectedType?.description || 'Ce squelette définit la structure et les champs personnalisés de la pièce.' }}