diff --git a/app/components/ConstructeurLinksTable.vue b/app/components/ConstructeurLinksTable.vue new file mode 100644 index 0000000..b064f12 --- /dev/null +++ b/app/components/ConstructeurLinksTable.vue @@ -0,0 +1,91 @@ + + + + + + Fournisseur + Réf. fournisseur + + + + + + + {{ getConstructeurName(link) }} + + {{ getConstructeurContact(link) }} + + + + + {{ link.supplierReference || '—' }} + + + + + + + + + + + + + diff --git a/app/composables/useConstructeurLinks.ts b/app/composables/useConstructeurLinks.ts new file mode 100644 index 0000000..fc656bb --- /dev/null +++ b/app/composables/useConstructeurLinks.ts @@ -0,0 +1,102 @@ +import { useApi } from '~/composables/useApi' +import type { ConstructeurLinkEntry } from '~/shared/constructeurUtils' + +type EntityType = 'machine' | 'piece' | 'composant' | 'product' + +const ENDPOINTS: Record = { + machine: '/machine_constructeur_links', + piece: '/piece_constructeur_links', + composant: '/composant_constructeur_links', + product: '/product_constructeur_links', +} + +const ENTITY_KEYS: Record = { + machine: 'machine', + piece: 'piece', + composant: 'composant', + product: 'product', +} + +const ENTITY_PLURALS: Record = { + machine: 'machines', + piece: 'pieces', + composant: 'composants', + product: 'products', +} + +export function useConstructeurLinks() { + const { get, post, patch, del } = useApi() + + const fetchLinks = async ( + entityType: EntityType, + entityId: string, + ): Promise => { + const endpoint = ENDPOINTS[entityType] + const key = ENTITY_KEYS[entityType] + const plural = ENTITY_PLURALS[entityType] + const result = await get(`${endpoint}?${key}=/api/${plural}/${entityId}`) + if (!result.success || !result.data) return [] + + const data = result.data as Record + const members = data['hydra:member'] ?? (Array.isArray(data) ? data : []) + if (!Array.isArray(members)) return [] + + return members.map((link: any) => ({ + linkId: link.id ?? (typeof link['@id'] === 'string' ? link['@id'].split('/').pop() : undefined), + constructeurId: typeof link.constructeur === 'string' + ? link.constructeur.split('/').pop()! + : link.constructeur?.id ?? '', + constructeur: typeof link.constructeur === 'object' ? link.constructeur : null, + supplierReference: link.supplierReference ?? null, + })) + } + + const syncLinks = async ( + entityType: EntityType, + entityId: string, + originalLinks: ConstructeurLinkEntry[], + formLinks: ConstructeurLinkEntry[], + ): Promise => { + const endpoint = ENDPOINTS[entityType] + const key = ENTITY_KEYS[entityType] + const plural = ENTITY_PLURALS[entityType] + const entityIri = `/api/${plural}/${entityId}` + + const originalMap = new Map(originalLinks.map(l => [l.constructeurId, l])) + const formMap = new Map(formLinks.map(l => [l.constructeurId, l])) + + const promises: Promise[] = [] + + // Delete removed links + for (const [cId, orig] of originalMap) { + if (!formMap.has(cId) && orig.linkId) { + promises.push(del(`${endpoint}/${orig.linkId}`)) + } + } + + // Create new links + for (const [cId, form] of formMap) { + if (!originalMap.has(cId)) { + promises.push(post(endpoint, { + [key]: entityIri, + constructeur: `/api/constructeurs/${cId}`, + supplierReference: form.supplierReference || null, + })) + } + } + + // Patch modified supplierReference + for (const [cId, form] of formMap) { + const orig = originalMap.get(cId) + if (orig?.linkId && (orig.supplierReference ?? null) !== (form.supplierReference ?? null)) { + promises.push(patch(`${endpoint}/${orig.linkId}`, { + supplierReference: form.supplierReference || null, + })) + } + } + + await Promise.allSettled(promises) + } + + return { fetchLinks, syncLinks } +} diff --git a/app/shared/constructeurUtils.ts b/app/shared/constructeurUtils.ts index 7082653..14c1e84 100644 --- a/app/shared/constructeurUtils.ts +++ b/app/shared/constructeurUtils.ts @@ -7,6 +7,32 @@ export interface ConstructeurSummary { phone?: string | null; } +export interface ConstructeurLinkEntry { + linkId?: string; + constructeurId: string; + constructeur?: ConstructeurSummary | null; + supplierReference: string | null; +} + +export const constructeurIdsFromLinks = (links: ConstructeurLinkEntry[]): string[] => + links.map(l => l.constructeurId).filter(Boolean); + +export const parseConstructeurLinksFromApi = ( + apiLinks: any[], +): ConstructeurLinkEntry[] => { + if (!Array.isArray(apiLinks)) return []; + return apiLinks + .filter(link => link && typeof link === 'object') + .map(link => ({ + linkId: link.id || (typeof link['@id'] === 'string' ? link['@id'].split('/').pop() : undefined), + constructeurId: typeof link.constructeur === 'string' + ? link.constructeur.split('/').pop()! + : link.constructeur?.id || '', + constructeur: typeof link.constructeur === 'object' ? link.constructeur : null, + supplierReference: link.supplierReference ?? null, + })); +}; + const isObject = (value: unknown): value is Record => Boolean(value) && typeof value === 'object' && !Array.isArray(value);