import { uniqueConstructeurIds, resolveConstructeurs, formatConstructeurContact, } from '~/shared/constructeurUtils' const currencyFormatter = new Intl.NumberFormat('fr-FR', { style: 'currency', currency: 'EUR', currencyDisplay: 'narrowSymbol', }) const formatCurrency = (value) => { if (value === undefined || value === null || value === '') { return null } const number = Number(value) if (Number.isNaN(number)) { return null } return currencyFormatter.format(number) } const formatSize = (size) => { if (size === undefined || size === null) { return '—' } if (size === 0) { return '0 B' } const units = ['B', 'KB', 'MB', 'GB'] const index = Math.min(units.length - 1, Math.floor(Math.log(size) / Math.log(1024))) const formatted = size / Math.pow(1024, index) return `${formatted.toFixed(1)} ${units[index]}` } const renderPrintField = (label, value, fallback = '—') => { const display = value !== undefined && value !== null && value !== '' ? value : fallback return `` } const renderPrintCustomFields = (fields = [], title, sectionClass = 'print-section') => { if (!fields.length) { return '' } const items = fields .map(field => ``) .join('') return `

${title}

` } const renderPrintDocuments = (documents = [], title, sectionClass = 'print-section') => { if (!documents.length) { return '' } const rows = documents .map(doc => `${doc.name}${doc.type}${doc.size}`) .join('') return `

${title}

${rows}
` } const renderPrintProductSummary = (product, title = 'Produit catalogue', sectionClass = 'print-piece-section') => { if (!product) { return '' } const infoEntries = [ { label: 'Nom', value: product.name || '—' }, { label: 'Référence', value: product.reference || '—' }, { label: 'Catégorie', value: product.typeName || '—' }, { label: 'Prix indicatif', value: product.supplierPrice || '—', }, { label: 'Fournisseur(s)', value: product.constructeurs?.length ? product.constructeurs.map((constructeur) => constructeur.name).filter(Boolean).join(', ') || '—' : '—', }, ] const infoMarkup = infoEntries .map((field) => ``) .join('') const customFieldsBlock = product.customFields?.length ? renderPrintCustomFields(product.customFields, 'Champs personnalisés du produit', 'print-subsection') : '' const documentsBlock = product.documents?.length ? renderPrintDocuments(product.documents, 'Documents du produit', 'print-subsection') : '' return `

${title}

${customFieldsBlock} ${documentsBlock}
` } const renderPrintPieces = ( pieces = [], title = 'Pièces indépendantes', sectionClass = 'print-section print-section--pieces' ) => { if (!pieces.length) { return '' } const cards = pieces .map((piece, idx) => { const indexLabel = piece.indexPath ? piece.indexPath.join('.') : `${idx + 1}` const constructeurBadges = (piece.constructeurs || []) .map((constructeur, badgeIdx) => { const suffix = piece.constructeurs.length > 1 ? ` ${badgeIdx + 1}` : '' return `Fournisseur${suffix}: ${constructeur.name}` }) .join('') const customFields = (piece.customFields || []) .filter(field => field.value && field.value !== '—' && field.value !== '') .map( field => `
  • ${field.label} ${field.value}
  • ` ) .join('') const customFieldsBlock = customFields ? `` : '' const documentsBlock = (piece.documents || []).length ? `` : '' const productBlock = renderPrintProductSummary(piece.product, 'Produit catalogue') return ` ` }) .join('') return `

    ${title}

    ` } const renderPrintComponents = (components = [], depth = 0, indexPath = []) => { if (!components.length) { return '' } return components .map((component, idx) => { const badges = [] if (component.constructeurs?.length) { const label = component.constructeurs.map((constructeur, badgeIdx) => { const suffix = component.constructeurs.length > 1 ? ` ${badgeIdx + 1}` : '' return `Constructeur${suffix}: ${constructeur.name}` }) badges.push(...label) } const sectionClass = `print-section print-section--component print-section-depth-${Math.min(depth, 3)}` const currentIndex = [...indexPath, idx + 1] const indexLabel = currentIndex.join('.') const productBlock = renderPrintProductSummary(component.product, 'Produit catalogue', 'print-section print-subsection print-section--product') return `

    ${indexLabel} Composant : ${component.name}

    ${component.description ? `` : ''} ${badges.length ? `
    ${badges.map(badge => `${badge}`).join('')}
    ` : ''} ${productBlock} ${renderPrintCustomFields( component.customFields, 'Champs personnalisés', 'print-section print-subsection print-section--custom-fields' )} ${renderPrintPieces( (component.pieces || []).map((piece, pieceIdx) => ({ ...piece, indexPath: [...currentIndex, pieceIdx + 1] })), 'Pièces du composant', 'print-section print-subsection print-section--pieces' )} ${renderPrintDocuments( component.documents, 'Documents du composant', 'print-section print-subsection print-section--documents' )} ${renderPrintComponents(component.subComponents || [], depth + 1, currentIndex)}
    ` }) .join('') } const normalizeDocuments = (docs = []) => { return docs.map(doc => ({ id: doc.id, name: doc.name || doc.filename || 'Document', type: doc.mimeType || doc.type || '—', size: formatSize(doc.size) })) } const normalizeCustomFields = (values = []) => { return values.map(value => ({ id: value.id, label: value.customField?.name || 'Champ', value: value.value || '—' })) } const normalizeConstructeur = (constructeur) => { if (!constructeur) { return null } const contact = formatConstructeurContact(constructeur) return { id: constructeur.id || null, name: constructeur.name || '—', contact: contact || '—' } } const normalizeConstructeurList = (...sources) => { const ids = uniqueConstructeurIds(...sources) const pools = sources .flatMap((source) => { if (Array.isArray(source)) { if (source.length && typeof source[0] === 'object') { return [source] } return [] } if (source && typeof source === 'object' && 'id' in source) { return [[source]] } return [] }) .filter(Boolean) const resolved = resolveConstructeurs(ids, ...pools) return resolved .map(normalizeConstructeur) .filter(Boolean) } const normalizeProduct = (product) => { if (!product) { return null } const constructeurs = normalizeConstructeurList( product.constructeurs, product.constructeur, product.constructeurIds, product.constructeurId, ) return { id: product.id || null, name: product.name || 'Produit sans nom', reference: product.reference || '', supplierPrice: formatCurrency(product.supplierPrice), typeName: product.typeProduct?.name || null, constructeurs, customFields: normalizeCustomFields(product.customFieldValues || []), documents: normalizeDocuments(product.documents || []), } } const normalizePiece = piece => { const rawProduct = piece.product || null const constructeurs = normalizeConstructeurList( piece.constructeurs, piece.constructeur, piece.originalPiece?.constructeurs, piece.originalPiece?.constructeur, piece.constructeurIds, piece.constructeurId, rawProduct?.constructeurs, rawProduct?.constructeur, rawProduct?.constructeurIds, rawProduct?.constructeurId, ) const product = normalizeProduct(rawProduct) return { id: piece.id, name: piece.name || 'Pièce sans nom', description: piece.description || '', reference: piece.reference || '', customFields: normalizeCustomFields(piece.customFieldValues || []), documents: normalizeDocuments(piece.documents || []), constructeurs, constructeur: constructeurs[0] || null, product, indexPath: piece.indexPath || null } } const normalizeComponent = component => { const rawProduct = component.product || null const constructeurs = normalizeConstructeurList( component.constructeurs, component.constructeur, component.originalComposant?.constructeurs, component.originalComposant?.constructeur, component.constructeurIds, component.constructeurId, rawProduct?.constructeurs, rawProduct?.constructeur, rawProduct?.constructeurIds, rawProduct?.constructeurId, ) const product = normalizeProduct(rawProduct) return { id: component.id, name: component.name || 'Composant sans nom', description: component.description || '', customFields: normalizeCustomFields(component.customFieldValues || []), documents: normalizeDocuments(component.documents || []), pieces: (component.pieces || []).map(normalizePiece), subComponents: (component.sousComposants || component.subComponents || []).map(normalizeComponent), constructeurs, constructeur: constructeurs[0] || null, product, } } export const buildMachinePrintContext = ({ machine, machineName, machineReference, machinePieces = [], components = [], selection }) => { const selectionState = selection || {} const machineSelection = selectionState.machine || {} const componentSelection = selectionState.components || {} const pieceSelection = selectionState.pieces || {} const includeMachineInfo = machineSelection.info !== false const includeMachineCustomFields = machineSelection.customFields !== false const includeMachineDocuments = machineSelection.documents !== false const isComponentSelected = (id) => { if (!id) { return true } if (Object.prototype.hasOwnProperty.call(componentSelection, id)) { return componentSelection[id] } return true } const isPieceSelected = (id) => { if (!id) { return true } if (Object.prototype.hasOwnProperty.call(pieceSelection, id)) { return pieceSelection[id] } return true } const machineBadges = [] if (machine?.site?.name) { machineBadges.push(`Site: ${machine.site.name}`) } if (machineReference) { machineBadges.push(`Ref: ${machineReference}`) } const machineConstructeurs = normalizeConstructeurList( machine?.constructeurs, machine?.constructeur, machine?.constructeurIds, machine?.constructeurId, ) const machineConstructeurNames = machineConstructeurs.length ? machineConstructeurs.map((constructeur) => constructeur.name).join(', ') : '' const machineConstructeurContacts = machineConstructeurs.length ? machineConstructeurs .map((constructeur) => constructeur.contact) .filter(Boolean) .join(' • ') : '' const normalizedPieces = machinePieces .map(normalizePiece) .filter(piece => isPieceSelected(piece.id)) .map((piece, idx) => ({ ...piece, indexPath: [idx + 1] })) const normalizedComponents = components.map(normalizeComponent) const filterComponentTree = (component) => { const filteredPieces = (component.pieces || []).filter(piece => isPieceSelected(piece.id)) const filteredSubComponents = (component.subComponents || []) .map(filterComponentTree) .filter(Boolean) const includeSelf = isComponentSelected(component.id) const shouldInclude = includeSelf || filteredPieces.length > 0 || filteredSubComponents.length > 0 if (!shouldInclude) { return null } return { ...component, pieces: filteredPieces, subComponents: filteredSubComponents } } const filteredComponents = normalizedComponents .map(filterComponentTree) .filter(Boolean) return { generatedAt: new Date().toLocaleString('fr-FR'), machine: { id: machine?.id || null, name: machineName, description: machine?.description || '', reference: machineReference, site: machine?.site?.name || '', badges: machineBadges, constructeurs: machineConstructeurs, constructeur: machineConstructeurs[0] || null, constructeurNames: machineConstructeurNames, constructeurContacts: machineConstructeurContacts, includeInfo: includeMachineInfo, customFields: includeMachineCustomFields ? normalizeCustomFields(machine?.customFieldValues || []) : [], documents: includeMachineDocuments ? normalizeDocuments(machine?.documents || []) : [] }, components: filteredComponents, pieces: normalizedPieces } } export const buildMachinePrintHtml = (context, styles) => { const title = context.machine.name ? `Impression - ${context.machine.name}` : 'Impression machine' const badgesHtml = context.machine.badges .map(badge => `${badge}`) .join('') const sections = [] sections.push(` `) if (context.machine.includeInfo) { sections.push(` `) } const customFieldsSection = renderPrintCustomFields( context.machine.customFields, 'Champs personnalisés de la machine', 'print-section print-section--custom-fields' ) if (customFieldsSection) { sections.push(customFieldsSection) } const documentsSection = renderPrintDocuments( context.machine.documents, 'Documents liés à la machine', 'print-section print-section--documents' ) if (documentsSection) { sections.push(documentsSection) } const componentsSection = renderPrintComponents(context.components) if (componentsSection) { sections.push(componentsSection) } const piecesSection = renderPrintPieces( context.pieces, 'Pièces indépendantes', 'print-section print-section--pieces' ) if (piecesSection) { sections.push(piecesSection) } sections.push(` `) const content = sections.join('\n') return ` ${title} ${styles} ` }