Compare commits

..

25 Commits

Author SHA1 Message Date
tristan ca7aef08be style(transport) : tableau prix — réduit Adresse sites au profit d'Adresse livraisons (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m10s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-17 15:01:20 +02:00
tristan 5dc852c03e fix(transport) : tableau prix — corrige l'inversion Adresse sites / Adresse livraisons (ERP-170)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
2026-06-17 15:00:14 +02:00
tristan c3aae2e232 style(transport) : tableau prix — libellés colonnes + élargit Transporteurs/Adresse livraisons, réduit Forfait/Tonne/Indexation/État (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m3s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m35s
2026-06-17 14:55:28 +02:00
tristan 16fbbf0fc5 style(transport) : datatable qualimat table-fixed (radio étroit, colonnes égales) + icônes onglets prix/qualimat (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m3s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
2026-06-17 14:51:53 +02:00
tristan b0c5896c4c style(transport) : tableau prix consultation en table-fixed (colonnes à parts égales, contenant étroit) (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m6s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-17 14:45:48 +02:00
tristan 28f4548221 feat(transport) : consultation — contenant en radios lecture seule (aligné ajout/modif) (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m10s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m33s
2026-06-17 14:37:40 +02:00
tristan d446ba9bf4 feat(transport) : contenant du formulaire principal en radios centrés (Benne par défaut) (ERP-170)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m58s
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m25s
2026-06-17 14:34:46 +02:00
tristan 9c3aebf02e fix(transport) : consultation — disposition du bloc principal alignée sur l'ajout (LIOT, décharge col 3, affréter col 4) (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m3s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m30s
2026-06-17 14:26:13 +02:00
tristan b9acfc1f0d fix(transport) : indexation réellement plafonnée à 100 % — re-synchronise le champ amount contrôlé via :key (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m0s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m32s
2026-06-17 14:16:40 +02:00
tristan 55d2c877bd fix(transport) : volume m³ en champ texte décimal + indexation en montant % plafonné à 100 (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m16s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m35s
2026-06-17 14:11:24 +02:00
tristan f5a9159ff4 fix(transport) : tableau prix — en-tête « Contenant » sur la colonne de groupe (ERP-170)
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 1m52s
2026-06-17 11:55:52 +02:00
tristan 74b9b075dc fix(transport) : tableau prix — supprime la double bordure du bas + séparateur épais entre groupes Benne/Fond mouvant (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
2026-06-17 11:53:24 +02:00
tristan e913866a62 fix(transport) : tableau prix consultation — police/bordures/radius alignés MalioDataTable, colonne groupe en épine (ERP-170)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
2026-06-17 11:50:11 +02:00
tristan 104f97430f fix(transport) : name de radio unique par bloc prix (useId) — plus de groupe partagé entre blocs (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m18s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m52s
2026-06-17 11:44:41 +02:00
tristan eaaa312af4 fix(transport) : tableau prix consultation — cellule de groupe fusionnée (Fond Mouvant/Benne) + colonnes maquette (ERP-170)
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Has been cancelled
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Has been cancelled
2026-06-17 11:41:56 +02:00
tristan 68236956f1 feat(transport) : consultation + modification transporteur (ERP-170)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m20s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m54s
2026-06-17 11:35:14 +02:00
tristan 70320c85aa fix(transport) : pré-validation front du bloc prix — erreurs inline sous tous les champs requis (selects branche) (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m19s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m43s
2026-06-17 10:51:56 +02:00
tristan c07902f93b fix(transport) : bloc prix — radios sens/contenant/tarif horizontaux et centrés (h-12) en colonne 1 (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m54s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m29s
2026-06-17 10:31:52 +02:00
tristan 49125d61b0 fix(transport) : bloc prix par défaut (CLIENT), sens seul en ligne 1, payload omet scalaires vides (422 inline au lieu de 400) (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m0s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m26s
2026-06-17 10:24:32 +02:00
tristan 9ec7d78a4c fix(transport) : bloc prix — radios sans label de groupe, sens en colonne 1, défaut Benne/Forfait (ERP-169)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m54s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m22s
2026-06-17 10:14:55 +02:00
tristan d71153e628 feat(transport) : onglet prix transporteur (ERP-169)
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 1m33s
2026-06-17 10:05:27 +02:00
tristan 3322da35da fix(transport) : contact transporteur valide si prénom OU nom (alignement M1/M2/M3) (ERP-168)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m4s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m46s
2026-06-17 09:47:11 +02:00
tristan 074904ffce fix(transport) : règle « + Nouveau contact » alignée sur M1/M2/M3 (prénom OU nom) (ERP-168)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 2m57s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m25s
2026-06-17 09:34:38 +02:00
tristan 94db73b807 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
2026-06-17 09:28:03 +02:00
tristan 6a69d7cd23 feat(transport) : onglet adresses transporteur (ERP-167)
Pull Request — Quality gate / Backend (PHP CS + PHPUnit) (pull_request) Successful in 3m7s
Pull Request — Quality gate / Frontend (lint + Vitest + build) (pull_request) Successful in 1m24s
2026-06-17 09:15:56 +02:00
5 changed files with 24 additions and 50 deletions
@@ -412,23 +412,6 @@ describe('useCarrierForm — copie QUALIMAT (ERP-166)', () => {
)
})
it('après création : PATCH en échec → pas de copie locale (rollback) et retour false', async () => {
mockPost.mockResolvedValueOnce({ id: 9, name: 'X', certificationType: 'GMP_PLUS' })
mockPatch.mockRejectedValueOnce({ response: { status: 500, _data: {} } })
const form = useCarrierForm()
form.main.name = 'X'
form.main.certificationType = 'GMP_PLUS'
await form.submitMain()
const ok = await form.applyQualimatSelection(QUALIMAT_ROW)
// Échec serveur : l'UI ne doit pas refléter une intégration QUALIMAT non persistée.
expect(ok).toBe(false)
expect(form.main.name).toBe('X')
expect(form.main.certificationType).toBe('GMP_PLUS')
expect(form.main.qualimatCarrierIri).toBeNull()
})
it('buildMainPayload inclut qualimatCarrier + certificationType QUALIMAT après intégration', async () => {
const form = useCarrierForm()
form.main.name = 'Acme'
@@ -659,27 +659,10 @@ export function useCarrierForm() {
* § 2.5) : copie le nom, force la certification à « QUALIMAT » (lecture seule),
* pose la FK `qualimatCarrier` (IRI) et copie l'adresse (pour l'onglet Adresses).
* Si le transporteur existe déjà (post-POST, cas nominal de l'onglet), persiste
* d'abord la copie via un PATCH partiel `carrier:write:main` : la copie locale
* (nom, certification figée « QUALIMAT », FK, adresse) n'est appliquée qu'en cas
* de succès, pour ne pas laisser l'UI dans un état QUALIMAT non sauvegardé si le
* PATCH échoue. Retourne true si l'intégration a abouti.
* la copie via un PATCH partiel `carrier:write:main`. La copie locale a lieu
* dans tous les cas. Retourne true si l'intégration a abouti.
*/
async function applyQualimatSelection(row: QualimatCarrierRow): Promise<boolean> {
// Transporteur déjà créé : on persiste avant de refléter localement.
if (carrierId.value !== null) {
try {
await patchCarrier({
qualimatCarrier: row['@id'],
name: row.name,
certificationType: 'QUALIMAT',
})
}
catch (error) {
mainErrors.handleApiError(error, { fallbackMessage: t('transport.carriers.toast.error') })
return false
}
}
main.name = row.name ?? ''
main.certificationType = 'QUALIMAT'
main.qualimatCarrierIri = row['@id']
@@ -699,7 +682,23 @@ export function useCarrierForm() {
street: row.address || null,
streetComplement: null,
}]
return true
if (carrierId.value === null) {
return true
}
try {
await patchCarrier({
qualimatCarrier: row['@id'],
name: row.name,
certificationType: 'QUALIMAT',
})
return true
}
catch (error) {
mainErrors.handleApiError(error, { fallbackMessage: t('transport.carriers.toast.error') })
return false
}
}
/**
@@ -255,7 +255,6 @@ import {
showRestoreAction,
type CarrierPriceRead,
} from '~/modules/transport/utils/forms/carrierMappers'
import { extractApiErrorMessage } from '~/shared/utils/api'
interface SelectOption {
value: string
@@ -482,14 +481,8 @@ async function runToggleArchive(): Promise<void> {
: t('transport.carriers.toast.restoreSuccess'),
})
}
catch (err) {
// Surface le message back (ex. 409 « homonyme actif » à la restauration),
// propagé exprès par useCarrier ; fallback générique sinon.
const data = (err as { response?: { _data?: unknown } })?.response?._data
toast.error({
title: t('transport.carriers.toast.error'),
message: extractApiErrorMessage(data) || undefined,
})
catch {
toast.error({ title: t('transport.carriers.toast.error') })
}
}
@@ -5,7 +5,7 @@ describe('numberInput — saisie volume / indexation (ERP-170)', () => {
it('sanitizeDecimal : ne garde que chiffres + un seul point', () => {
expect(sanitizeDecimal('30')).toBe('30')
expect(sanitizeDecimal('30.5')).toBe('30.5')
expect(sanitizeDecimal('30,5 kg')).toBe('30.5') // virgule FR → point ; espace + lettres retirés
expect(sanitizeDecimal('30,5 kg')).toBe('305') // virgule + espace + lettres retirés
expect(sanitizeDecimal('1.2.3')).toBe('1.23') // un seul point conservé
expect(sanitizeDecimal('abc12.3x')).toBe('12.3')
expect(sanitizeDecimal('')).toBe('')
@@ -5,11 +5,10 @@
/**
* Restreint une saisie à un nombre décimal : chiffres + UN seul point (RG volume m³,
* « nombres avec des points » comme les autres modules). La virgule décimale FR est
* convertie en point (« 30,5 » → « 30.5 ») ; tout autre caractère est supprimé.
* « nombres avec des points » comme les autres modules). Supprime tout autre caractère.
*/
export function sanitizeDecimal(value: string): string {
let cleaned = (value ?? '').replace(/,/g, '.').replace(/[^0-9.]/g, '')
let cleaned = (value ?? '').replace(/[^0-9.]/g, '')
const dot = cleaned.indexOf('.')
if (dot !== -1) {
// Conserve le 1er point, retire les suivants.