feat(transport) : onglet contacts transporteur (ERP-168)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m9s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m40s

This commit is contained in:
2026-06-17 09:28:03 +02:00
parent 6a69d7cd23
commit 94db73b807
7 changed files with 487 additions and 5 deletions
@@ -0,0 +1,54 @@
/**
* Helpers purs de l'onglet Contact transporteur (M4 Transport, ERP-168) — miroir
* de `providerContact.ts` (M3), avec deux spécificités M4 :
* - RG-4.08 : un bloc est valide dès qu'AU MOINS UN champ est rempli (n'importe
* lequel) — ≠ M3 qui n'exigeait que le nom.
* - les téléphones partent au back dans le tableau virtuel `phones` (max 2),
* pas en `phonePrimary` / `phoneSecondary` (mappés par le CarrierContactProcessor).
* Testables sans Vue ni API.
*/
import type { CarrierContactFormDraft } from '~/modules/transport/types/carrierForm'
/** Vrai si une chaîne porte au moins un caractère non-espace. */
function isFilled(value: string | null | undefined): boolean {
return value !== null && value !== undefined && value.trim() !== ''
}
/**
* RG-4.08 : un bloc Contact est VIDE tant qu'aucun de ses champs n'est rempli
* (prénom / nom / fonction / téléphone(s) / email). Sert le gating « + Nouveau
* contact » (on n'ajoute pas de bloc tant que le précédent est vide) et reflète la
* garde back (CarrierContactProcessor + CHECK chk_carrier_contact_filled).
*/
export function isCarrierContactBlank(contact: CarrierContactFormDraft): boolean {
return ![
contact.firstName,
contact.lastName,
contact.jobTitle,
contact.phonePrimary,
contact.phoneSecondary,
contact.email,
].some(isFilled)
}
/**
* Payload de la sous-ressource contacts (groupe `carrier:write:contacts`). Les
* chaînes vides partent à null (le serveur normalise/trim). Les téléphones sont
* regroupés dans le tableau `phones` (numéros non vides, max 2 — RG-4.08) ; le 2e
* numéro n'est inclus que s'il a été révélé (`hasSecondaryPhone`).
*/
export function buildCarrierContactPayload(contact: CarrierContactFormDraft): Record<string, unknown> {
const phones = [
contact.phonePrimary,
contact.hasSecondaryPhone ? contact.phoneSecondary : null,
].filter((phone): phone is string => isFilled(phone))
return {
firstName: contact.firstName || null,
lastName: contact.lastName || null,
jobTitle: contact.jobTitle || null,
email: contact.email || null,
phones,
}
}