import { describe, expect, it } from 'vitest' import { canEditSupplier, categoryOptionsOf, contactOptionsOf, iriOf, mapAccountingDraft, mapAddressToDraft, mapAddressView, mapContactToDraft, mapRibToDraft, referentialOptionOf, showArchiveAction, showRestoreAction, siteOptionsOf, type SupplierDetail, } from '../supplierConsultation' describe('iriOf', () => { it('retourne l\'@id d\'une relation embarquee (objet)', () => { expect(iriOf({ '@id': '/api/payment_types/14', code: 'LCR' })).toBe('/api/payment_types/14') }) it('retourne la chaine telle quelle si la relation est deja un IRI', () => { expect(iriOf('/api/banks/3')).toBe('/api/banks/3') }) it('retourne null pour une relation absente (null / undefined / skip_null_values)', () => { expect(iriOf(null)).toBeNull() expect(iriOf(undefined)).toBeNull() }) }) describe('mapContactToDraft', () => { it('formate les telephones en XX XX XX XX XX et conserve l\'iri', () => { const draft = mapContactToDraft({ '@id': '/api/supplier_contacts/39', id: 39, firstName: 'Marie', lastName: 'Martin', jobTitle: 'Responsable achats', phonePrimary: '0612345678', email: 'marie.martin@seed.test', }) expect(draft.id).toBe(39) expect(draft.iri).toBe('/api/supplier_contacts/39') expect(draft.phonePrimary).toBe('06 12 34 56 78') expect(draft.hasSecondaryPhone).toBe(false) }) it('revele le 2e telephone quand phoneSecondary est present', () => { const draft = mapContactToDraft({ '@id': '/api/supplier_contacts/40', id: 40, phonePrimary: '0600000000', phoneSecondary: '0611111111', }) expect(draft.hasSecondaryPhone).toBe(true) expect(draft.phoneSecondary).toBe('06 11 11 11 11') }) }) describe('mapAddressToDraft', () => { it('mappe l\'enum addressType, les champs fournisseur et extrait les iris', () => { const draft = mapAddressToDraft({ '@id': '/api/supplier_addresses/33', id: 33, addressType: 'DEPART', country: 'France', postalCode: '86000', city: 'Poitiers', street: '12 rue des Acacias', bennes: 3, triageProvider: true, sites: [{ '@id': '/api/sites/87', name: 'Chatellerault', color: '#056CF2' }], categories: [{ '@id': '/api/categories/2279', code: 'NEGOCIANT' }], contacts: [{ '@id': '/api/supplier_contacts/39' }, '/api/supplier_contacts/41'], }) expect(draft.addressType).toBe('DEPART') expect(draft.siteIris).toEqual(['/api/sites/87']) expect(draft.categoryIris).toEqual(['/api/categories/2279']) expect(draft.contactIris).toEqual(['/api/supplier_contacts/39', '/api/supplier_contacts/41']) // bennes (entier) → chaine pour MalioInputNumber. expect(draft.bennes).toBe('3') expect(draft.triageProvider).toBe(true) expect(draft.city).toBe('Poitiers') expect(draft.country).toBe('France') }) it('tolere les champs absents (defauts : France, bennes « 0 », triage faux, type null)', () => { const draft = mapAddressToDraft({ '@id': '/api/supplier_addresses/9', id: 9 }) expect(draft.addressType).toBeNull() expect(draft.siteIris).toEqual([]) expect(draft.categoryIris).toEqual([]) expect(draft.contactIris).toEqual([]) expect(draft.country).toBe('France') expect(draft.bennes).toBe('0') expect(draft.triageProvider).toBe(false) }) }) describe('mapRibToDraft', () => { it('mappe label / bic / iban et l\'id serveur', () => { const draft = mapRibToDraft({ '@id': '/api/supplier_ribs/27', id: 27, label: 'Compte principal', bic: 'BNPAFRPPXXX', iban: 'FR14...' }) expect(draft).toEqual({ id: 27, label: 'Compte principal', bic: 'BNPAFRPPXXX', iban: 'FR14...' }) }) }) describe('mapAccountingDraft', () => { it('mappe les scalaires et resout les iris des referentiels embarques', () => { const acc = mapAccountingDraft({ '@id': '/api/suppliers/85', id: 85, siren: '123456789', accountNumber: 'F0001', nTva: 'FR00123456789', tvaMode: { '@id': '/api/tva_modes/30' }, paymentDelay: { '@id': '/api/payment_delays/11' }, paymentType: { '@id': '/api/payment_types/14', code: 'LCR' }, bank: { '@id': '/api/banks/3' }, } as SupplierDetail) expect(acc).toEqual({ siren: '123456789', accountNumber: 'F0001', nTva: 'FR00123456789', tvaModeIri: '/api/tva_modes/30', paymentDelayIri: '/api/payment_delays/11', paymentTypeIri: '/api/payment_types/14', bankIri: '/api/banks/3', }) }) it('renvoie des null quand les champs comptables sont absents (gating par omission, sans accounting.view)', () => { const acc = mapAccountingDraft({} as SupplierDetail) expect(acc).toEqual({ siren: null, accountNumber: null, nTva: null, tvaModeIri: null, paymentDelayIri: null, paymentTypeIri: null, bankIri: null, }) }) }) describe('options construites depuis l\'embed (role-independantes)', () => { it('categoryOptionsOf expose value=IRI, label=nom, code', () => { expect(categoryOptionsOf([{ '@id': '/api/categories/2279', name: 'Negociant', code: 'NEGOCIANT' }])).toEqual([ { value: '/api/categories/2279', label: 'Negociant', code: 'NEGOCIANT' }, ]) }) it('siteOptionsOf expose value=IRI, label=nom', () => { expect(siteOptionsOf([{ '@id': '/api/sites/87', name: 'Chatellerault', color: '#000' }])).toEqual([ { value: '/api/sites/87', label: 'Chatellerault' }, ]) }) it('contactOptionsOf compose le libelle (nom complet, sinon email)', () => { expect(contactOptionsOf([ { '@id': '/api/supplier_contacts/1', id: 1, firstName: 'Marie', lastName: 'Martin' }, { '@id': '/api/supplier_contacts/2', id: 2, email: 'a@b.fr' }, ])).toEqual([ { value: '/api/supplier_contacts/1', label: 'Marie Martin' }, { value: '/api/supplier_contacts/2', label: 'a@b.fr' }, ]) }) it('referentialOptionOf : option unique depuis l\'embed, vide pour IRI nu / absent', () => { expect(referentialOptionOf({ '@id': '/api/payment_types/14', label: 'LCR' })).toEqual([ { value: '/api/payment_types/14', label: 'LCR' }, ]) expect(referentialOptionOf('/api/banks/3')).toEqual([]) expect(referentialOptionOf(null)).toEqual([]) }) it('mapAddressView assemble brouillon + options propres a l\'adresse', () => { const view = mapAddressView({ '@id': '/api/supplier_addresses/33', id: 33, addressType: 'RENDU', city: 'Poitiers', sites: [{ '@id': '/api/sites/87', name: 'Chatellerault' }], categories: [{ '@id': '/api/categories/2279', name: 'Negociant', code: 'NEGOCIANT' }], }) expect(view.draft.id).toBe(33) expect(view.draft.addressType).toBe('RENDU') expect(view.siteOptions).toEqual([{ value: '/api/sites/87', label: 'Chatellerault' }]) expect(view.categoryOptions).toEqual([{ value: '/api/categories/2279', label: 'Negociant', code: 'NEGOCIANT' }]) }) }) describe('canEditSupplier', () => { const can = (granted: string[]) => (codes: string[]) => codes.some(c => granted.includes(c)) it('visible pour manage', () => { expect(canEditSupplier(can(['commercial.suppliers.manage']))).toBe(true) }) it('visible pour accounting.manage (role Compta)', () => { expect(canEditSupplier(can(['commercial.suppliers.accounting.manage']))).toBe(true) }) it('masque sans aucune des deux permissions (role Usine)', () => { expect(canEditSupplier(can(['commercial.suppliers.view']))).toBe(false) }) }) describe('showArchiveAction / showRestoreAction', () => { const can = (granted: string[]) => (code: string) => granted.includes(code) it('Archiver : visible avec la permission archive ET fournisseur non archive', () => { expect(showArchiveAction(can(['commercial.suppliers.archive']), false)).toBe(true) expect(showArchiveAction(can(['commercial.suppliers.archive']), true)).toBe(false) expect(showArchiveAction(can([]), false)).toBe(false) }) it('Restaurer : visible avec la permission archive ET fournisseur archive', () => { expect(showRestoreAction(can(['commercial.suppliers.archive']), true)).toBe(true) expect(showRestoreAction(can(['commercial.suppliers.archive']), false)).toBe(false) expect(showRestoreAction(can([]), true)).toBe(false) }) })