@movalib/movalib-commons 1.68.32 → 1.68.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,263 @@
1
+ # Feature — Création / Modification de forfaits (Catalogue)
2
+
3
+ ## Périmètre de ce ticket
4
+
5
+ **Dans le scope**
6
+ - Nouveau point d'entrée "AJOUTER" sur la page catalogue (Produit / Service / **Forfait**)
7
+ - Écran de création **et** d'édition d'un forfait (CRUD complet sur l'entité Package)
8
+ - Validation de cohérence TTC + répartition de l'écart (prorata / manuelle)
9
+ - Affectation du compte comptable de regroupement pièces
10
+
11
+ **Hors scope (ticket suivant, ne rien implémenter ici)**
12
+ - Ajout d'un forfait sur un devis / facture (`packageIds` en query param sur `updateInvoice`/`updateQuote`)
13
+ - `packageComponentId` sur les lignes COMMENT du document
14
+ - Sortie de stock à la finalisation
15
+ - Table analytique `document_packages`
16
+
17
+ ---
18
+
19
+ ## Contexte métier
20
+
21
+ Aujourd'hui 100% du CA est catégorisé soit en Prestation de service, soit en Vente de marchandise → comptablement faux, risque en cas de contrôle fiscal. Le forfait permet de vendre un montant TTC global avec une composition cohérente, **sans afficher le détail quantités/prix** au client (légal tant qu'une description des produits est présente sur le document), tout en **ventilant pièces / MO sur deux comptes comptables distincts** (contrainte Sinao : une ligne = un seul compte comptable).
22
+
23
+ ---
24
+
25
+ ## Stack (rappel — réutiliser l'existant, pas de réinvention)
26
+ - React + TS, Vite, MUI v6, TanStack Query v5, Formik
27
+ - Composants partagés : `@movalib/movalib-commons`
28
+ - **Liste forfaits** : même mécanique que la page Catalogue (liste paginée + recherche).
29
+ - **Tableau composants** : **AG Grid** (déjà en place dans la solution). S'inspirer fortement de `panelOrder` / `contentTable` pour la structure du grid (colonnes, cell renderers/editors, gestion des lignes).
30
+ - **Recherche/chargement produit** : utiliser `<CatalogSearchBase ... />` (comme à la création de document), pas de nouveau composant de recherche.
31
+ - Montants : **tout en centimes** côté API. Convertir à l'affichage uniquement (helpers existants type `truncTo4` / format euro).
32
+
33
+ ---
34
+
35
+ ## API backend disponible
36
+
37
+ Préfixe : `/api/billing/{garageId}/packages`
38
+
39
+ | Méthode | URL | Description |
40
+ |---------|-----|-------------|
41
+ | GET | `/{garageId}/packages?search=&page=0&limit=20` | Liste paginée |
42
+ | GET | `/{garageId}/packages/{packageId}` | Détail + composants (renvoie `components[].id` = UUID) |
43
+ | POST | `/{garageId}/packages` | Création |
44
+ | PATCH | `/{garageId}/packages/{packageId}` | Modification |
45
+ | DELETE | `/{garageId}/packages/{packageId}` | Suppression |
46
+
47
+ ### Body POST / PATCH
48
+
49
+ ```json
50
+ {
51
+ "reference": "FORFAIT-VIDANGE-01",
52
+ "label": "Forfait vidange complète",
53
+ "amountCents": 8000,
54
+ "amountInclVatCents": 9600,
55
+ "vatRate": 20.00,
56
+ "accountId": 42,
57
+ "components": [
58
+ {
59
+ "catalogId": 101,
60
+ "reference": "HUI-MOT-5W30",
61
+ "label": "Huile moteur 5W30 - 5L",
62
+ "quantity": 1,
63
+ "amountCents": 3500,
64
+ "amountInclVatCents": 4200,
65
+ "vatRate": 20.00,
66
+ "index": 0
67
+ }
68
+ ],
69
+ "labor": {
70
+ "serviceId": 55,
71
+ "reference": "MO-VIDANGE",
72
+ "label": "Main d'œuvre vidange",
73
+ "quantity": 1,
74
+ "amountCents": 3500,
75
+ "amountInclVatCents": 4200,
76
+ "vatRate": 20.00
77
+ }
78
+ }
79
+ ```
80
+
81
+ **Contrainte back (à valider aussi côté front avant submit) :**
82
+ `Σ(components.amountInclVatCents) + labor.amountInclVatCents === amountInclVatCents`
83
+
84
+ ---
85
+
86
+ ## Modèle de données front
87
+
88
+ Même pattern que les autres entités : classes `class-transformer` avec `@Expose`, instanciation via `plainToInstance` exposée en statique `JsonToObject` / `JsonToObjects`.
89
+
90
+ > Le payload du endpoint `packages` est déjà en **camelCase** (cf. body API), donc pas de remapping `@Expose({ name: "..." })` à priori — `@Expose()` simple suffit. Si le back renvoie finalement du snake_case, ajouter les `name` comme sur `Account`.
91
+ > **Important** : les sous-objets (`components[]`, `labor`) ont besoin de `@Type(() => …)` pour être hydratés en instances (sinon ils restent en plain objects).
92
+
93
+ ```ts
94
+ import { Expose, Type, plainToInstance } from "class-transformer";
95
+
96
+ export type PackageComponentKind = "PRODUCT" | "COMMENT";
97
+
98
+ export class PackageComponent {
99
+ @Expose() id?: string; // UUID, présent en GET (édition), absent en création
100
+ @Expose() kind!: PackageComponentKind; // discriminant front (cf. question ouverte)
101
+ @Expose() catalogId?: number; // PRODUCT uniquement
102
+ @Expose() reference?: string;
103
+ @Expose() label!: string; // surchargeable ; seul champ requis pour COMMENT
104
+ @Expose() quantity?: number; // PRODUCT
105
+ @Expose() amountCents?: number; // PRODUCT, surchargeable (HT)
106
+ @Expose() amountInclVatCents?: number; // PRODUCT, surchargeable (TTC)
107
+ @Expose() vatRate?: number; // non éditable (hérité du produit)
108
+ @Expose() index!: number;
109
+
110
+ static JsonToObject(json: any): PackageComponent {
111
+ return plainToInstance(PackageComponent, json);
112
+ }
113
+
114
+ static JsonToObjects(json: any[]): PackageComponent[] {
115
+ return plainToInstance(PackageComponent, json);
116
+ }
117
+ }
118
+
119
+ export class PackageLabor {
120
+ @Expose() serviceId!: number;
121
+ @Expose() reference!: string;
122
+ @Expose() label!: string; // surchargeable
123
+ @Expose() quantity!: number;
124
+ @Expose() amountCents!: number; // surchargeable (HT)
125
+ @Expose() amountInclVatCents!: number; // surchargeable (TTC)
126
+ @Expose() vatRate!: number; // non éditable (hérité du service)
127
+
128
+ static JsonToObject(json: any): PackageLabor {
129
+ return plainToInstance(PackageLabor, json);
130
+ }
131
+ }
132
+
133
+ export class Package {
134
+ @Expose() id?: string;
135
+ @Expose() reference!: string;
136
+ @Expose() label!: string;
137
+ @Expose() amountCents!: number; // HT forfait (saisi)
138
+ @Expose() amountInclVatCents!: number; // TTC forfait (auto = HT * 1.20)
139
+ @Expose() vatRate!: number; // 20 par défaut
140
+ @Expose() accountId!: number; // compte comptable regroupement pièces
141
+
142
+ @Expose()
143
+ @Type(() => PackageComponent)
144
+ components!: PackageComponent[];
145
+
146
+ @Expose()
147
+ @Type(() => PackageLabor)
148
+ labor?: PackageLabor | null;
149
+
150
+ static JsonToObject(json: any): Package {
151
+ return plainToInstance(Package, json);
152
+ }
153
+
154
+ static JsonToObjects(json: any[]): Package[] {
155
+ return plainToInstance(Package, json);
156
+ }
157
+ }
158
+ ```
159
+
160
+ > **Pour le POST/PATCH** : le camelCase étant identique côté front et API, on envoie l'objet directement (retirer les champs purement front si le back ne les attend pas).
161
+
162
+ ### Représentation d'une ligne COMMENT (décision actée)
163
+ - **Discriminant front** : `kind: "PRODUCT" | "COMMENT"`.
164
+ - Une ligne **COMMENT** ne porte que `label` + `index`. Pas de `catalogId`, pas de `quantity`, pas de montants, pas de `vatRate`.
165
+ - **Payload** : envoyer `kind` dans l'objet composant. Côté back, une ligne COMMENT reste identifiable de façon redondante par `catalogId` absent/null + montants nuls — donc même si le back ignore `kind`, la distinction est sûre.
166
+ - À l'hydratation (GET), si `kind` n'est pas renvoyé par le back, le déduire : `catalogId == null → COMMENT`, sinon `PRODUCT`.
167
+ - Une ligne COMMENT compte pour **0** dans la cohérence TTC et dans le calcul de prorata (poids nul).
168
+
169
+ > Reste à aligner avec le back que `kind` est bien accepté/ignoré sans erreur — sinon basculer sur le mapping `catalogId: null` seul (la logique front ne change pas).
170
+
171
+ ---
172
+
173
+ ## Spécification UI
174
+
175
+ ### 1. Point d'entrée — page dédiée "Forfaits" + dialog create/edit
176
+ Créer une **page à part entière "Forfaits"**, calquée sur la page **Catalogue** (même layout, liste paginée + recherche, branchée sur `GET /{garageId}/packages`).
177
+ - Bouton **"Créer forfait"** → ouvre la **dialog** de création (en-tête + grid composants + MO).
178
+ - **Clic sur une ligne forfait** → ouvre la **même dialog** en **mode édition** (`GET /{garageId}/packages/{packageId}` pour hydrater).
179
+ - Une seule dialog pour création et édition (le mode dépend de la présence d'un `id`).
180
+
181
+ ### 2. En-tête du forfait
182
+ - **Référence** (texte, requis)
183
+ - **Nom** (texte, requis)
184
+ - **Montant HT** (saisi)
185
+ - **Montant TTC** (calculé auto = HT × 1,20, lecture seule, TVA 20%)
186
+
187
+ ### 3. Tableau des composants — **AG Grid** (pièces OU commentaires)
188
+ - Grid **AG Grid**, structure calquée sur `panelOrder` / `contentTable` (colonnes, cell renderers/editors, ajout/suppression de lignes, gestion d'index).
189
+ - Recherche/ajout produit via **`<CatalogSearchBase ... />`** (même usage qu'à la création de document) → au choix d'un produit, ajout d'une ligne dans le grid.
190
+ - Colonnes : désignation, quantité, PU HT, PU TTC, TVA (lecture seule).
191
+ - **Surcharge** possible : désignation, montant HT et/ou TTC. La TVA reste non éditable.
192
+ - Bouton **"Ajouter une ligne (produit)"** (via `CatalogSearchBase`).
193
+ - Bouton **"Ajouter un commentaire"** → ligne de type COMMENT (désignation seule, pas de montant).
194
+ - Suppression de ligne ; maintenir `index` cohérent après ajout/suppression/réordonnancement.
195
+
196
+ ### 4. Encart Main d'œuvre (MO)
197
+ - Sélecteur de service **filtré sur le type MO**
198
+ - **Une seule MO autorisée** (pas de tableau, un encart unique ; remplacement si on en re-sélectionne une)
199
+ - Surcharge possible : désignation, montant HT et/ou TTC. TVA non éditable.
200
+
201
+ ### 5. Pré-comptabilité
202
+ - **Compte comptable de regroupement** (pièces) attaché à la référence du forfait → `accountId`. Sélecteur de compte.
203
+ - La MO n'a pas de sélecteur ici : elle se ventile sur le compte déjà défini au catalogue pour ce service.
204
+ - **Picto info-bulle** : « Les pièces vendues sous un forfait doivent être catégorisées au sein d'un même compte comptable. »
205
+
206
+ ---
207
+
208
+ ## Règles métier
209
+
210
+ ### Cohérence TTC (blocage)
211
+ Le total TTC saisi (Σ composants TTC + MO TTC) doit être **strictement égal** au TTC du forfait.
212
+ - Si écart ≠ 0 → afficher l'écart à répartir + picto warning, **bloquer la sauvegarde**.
213
+ - Picto warning, tooltip exact :
214
+ > « Le total TTC doit correspondre au prix de vente TTC de votre forfait. La répartition automatique de l'écart se fait au prorata du poids de chaque ligne. »
215
+
216
+ ### Répartition de l'écart
217
+ - **Manuelle** : l'utilisateur ajuste les montants ligne à ligne jusqu'à écart = 0.
218
+ - **Automatique** : prorata du poids TTC de chaque ligne (composants + MO).
219
+
220
+ ```
221
+ poids_ligne = ligne.amountInclVatCents / Σ(toutes lignes TTC)
222
+ ajustement_ligne = round(ecart * poids_ligne)
223
+ ```
224
+
225
+ > ⚠️ **Arrondi centimes** : la somme des `round()` peut différer de l'écart d'1 centime (reste). Appliquer la méthode du plus grand reste (largest remainder) ou affecter le centime résiduel à la ligne au plus gros poids, pour garantir `Σ après répartition === amountInclVatCents` exactement. Recalculer le HT de chaque ligne à partir du TTC ajusté et de sa TVA pour rester cohérent.
226
+
227
+ ### Conversions
228
+ - Saisie en euros à l'écran, stockage/envoi en centimes. Aucun float en transit.
229
+ - TTC forfait = HT × (1 + vatRate/100), vatRate = 20 par défaut.
230
+
231
+ ---
232
+
233
+ ## Points d'attention
234
+ - **Édition** : au GET, les `components[].id` (UUID) reviennent — les conserver dans le state et les renvoyer en PATCH (ne pas les regénérer).
235
+ - Mutations via TanStack Query (`useMutation`) + invalidation de la liste catalogue/forfaits au succès.
236
+ - Réutiliser les helpers de format/troncature existants plutôt que d'en réécrire.
237
+ - Valider la cohérence TTC côté front **avant** l'appel pour éviter le 4xx back (mais ne pas se reposer dessus : gérer aussi l'erreur back).
238
+
239
+ ---
240
+
241
+ ## Plan d'implémentation (ordre conseillé)
242
+
243
+ Avancer incrémentalement, chaque étape testable avant la suivante.
244
+
245
+ 1. **Service / entités** — Classes `class-transformer` (`Package`, `PackageComponent`, `PackageLabor`) + service API (`getPackages`, `getPackage`, `createPackage`, `updatePackage`, `deletePackage`) calqué sur les services existants. Hooks TanStack Query (`useQuery` liste/détail, `useMutation` create/update/delete).
246
+
247
+ 2. **Page liste "Forfaits"** — Nouvelle route + entrée de nav, layout calqué sur Catalogue. Liste paginée + recherche (`GET .../packages`), colonnes : référence, nom, montant HT, montant TTC. Pagination/recherche branchées.
248
+
249
+ 3. **Bouton "Créer forfait" + ouverture dialog** — Bouton sur la page liste → ouvre la dialog vide (mode création). Clic sur une ligne → ouvre la dialog hydratée via `getPackage` (mode édition, déduit de la présence d'`id`).
250
+
251
+ 4. **Dialog create/edit — squelette** — Structure de la dialog avec Formik : en-tête (référence, nom, montant HT, montant TTC auto = HT × 1,20 lecture seule). Boutons Annuler / Enregistrer (save encore désactivé). Pas encore de grid ni MO.
252
+
253
+ 5. **Grid composants (AG Grid)** — Intégrer le grid calqué sur `panelOrder` / `contentTable`. Colonnes désignation / qté / PU HT / PU TTC / TVA (lecture seule). Ajout via `<CatalogSearchBase />`, bouton "Ajouter un commentaire" (ligne COMMENT), suppression de ligne, gestion de l'`index`. Surcharge désignation / HT / TTC (TVA verrouillée).
254
+
255
+ 6. **Encart Main d'œuvre** — Sélecteur service filtré type MO, une seule MO (remplacement si re-sélection), surcharge désignation / HT / TTC (TVA verrouillée).
256
+
257
+ 7. **Pré-comptabilité** — Sélecteur de compte comptable de regroupement pièces (`accountId`) + picto info-bulle. (Rappel : la MO se ventile sur son compte catalogue, pas de sélecteur ici.)
258
+
259
+ 8. **Cohérence TTC + répartition écart** — Calcul du total TTC (composants + MO, COMMENT = 0), affichage de l'écart + picto warning, blocage de la sauvegarde si écart ≠ 0. Répartition manuelle, puis répartition automatique au prorata (avec gestion du reste d'arrondi en centimes).
260
+
261
+ 9. **Mapping payload + branchement mutations** — Mapper le state front → body POST/PATCH (centimes, `kind`/COMMENT, retrait des champs front non attendus), brancher save sur create/update, invalider la liste au succès, gérer les erreurs back. Conserver les UUID `components[].id` en édition.
262
+
263
+ 10. **Suppression** — Action de suppression depuis la liste (ou la dialog) via `deletePackage` + invalidation.
@@ -0,0 +1,159 @@
1
+ # reCAPTCHA Enterprise — intégration React + TypeScript (Vite)
2
+
3
+ ## Prérequis
4
+
5
+ - Projet React + TypeScript avec Vite
6
+ - Une clé de site reCAPTCHA Enterprise (Google Cloud Console → reCAPTCHA Enterprise)
7
+
8
+ ---
9
+
10
+ ## 1. Variable d'environnement
11
+
12
+ Dans `.env` (et `.env.production`, `.env.demo` selon vos modes) :
13
+
14
+ ```env
15
+ VITE_RECAPTCHA_SITE_KEY=votre_clé_de_site_ici
16
+ ```
17
+
18
+ ---
19
+
20
+ ## 2. Helper `src/helpers/recaptcha.ts`
21
+
22
+ Créez ce fichier tel quel :
23
+
24
+ ```typescript
25
+ declare global {
26
+ interface Window {
27
+ grecaptcha?: {
28
+ enterprise: {
29
+ ready: (cb: () => void) => void;
30
+ execute: (siteKey: string, opts: { action: string }) => Promise<string>;
31
+ };
32
+ };
33
+ }
34
+ }
35
+
36
+ const SITE_KEY = import.meta.env.VITE_RECAPTCHA_SITE_KEY as string;
37
+
38
+ let resolveReady!: () => void;
39
+ const scriptReady = new Promise<void>(resolve => { resolveReady = resolve; });
40
+
41
+ /** À appeler une seule fois au démarrage de l'app. */
42
+ export function loadRecaptcha(): void {
43
+ if (!SITE_KEY) {
44
+ console.warn("VITE_RECAPTCHA_SITE_KEY manquante");
45
+ resolveReady();
46
+ return;
47
+ }
48
+ const existing = document.getElementById("recaptcha-enterprise");
49
+ if (existing) {
50
+ if (window.grecaptcha?.enterprise) resolveReady();
51
+ else existing.addEventListener('load', resolveReady, { once: true });
52
+ return;
53
+ }
54
+ const s = document.createElement("script");
55
+ s.id = "recaptcha-enterprise";
56
+ s.src = `https://www.google.com/recaptcha/enterprise.js?render=${SITE_KEY}`;
57
+ s.async = true;
58
+ s.onload = resolveReady;
59
+ document.head.appendChild(s);
60
+ }
61
+
62
+ /**
63
+ * Génère un token reCAPTCHA pour l'action donnée.
64
+ * Attend automatiquement que le script soit chargé avant d'exécuter.
65
+ * Token à usage unique, validité ~2 minutes.
66
+ */
67
+ export function executeRecaptcha(action: string): Promise<string> {
68
+ return scriptReady.then(() => new Promise((resolve, reject) => {
69
+ const grecaptcha = window.grecaptcha?.enterprise;
70
+ if (!grecaptcha) {
71
+ reject(new Error("reCAPTCHA non chargé"));
72
+ return;
73
+ }
74
+ grecaptcha.ready(() => {
75
+ grecaptcha.execute(SITE_KEY, { action }).then(resolve).catch(reject);
76
+ });
77
+ }));
78
+ }
79
+
80
+ export {};
81
+ ```
82
+
83
+ ### Pourquoi `scriptReady` ?
84
+
85
+ Le script est injecté avec `async`, donc il se charge en arrière-plan. Sans cette `Promise`, un composant monté directement depuis un lien externe (ex. lien email d'activation de compte) peut appeler `executeRecaptcha` avant que `window.grecaptcha` soit disponible — résultat : erreur silencieuse et action bloquée. `scriptReady` sert de verrou : `executeRecaptcha` attend que `loadRecaptcha` ait confirmé le chargement avant de s'exécuter.
86
+
87
+ ---
88
+
89
+ ## 3. Appel au démarrage dans `App.tsx`
90
+
91
+ Appelez `loadRecaptcha()` **en dehors** du composant React, au niveau module, pour garantir l'injection du script dès le chargement du bundle :
92
+
93
+ ```typescript
94
+ import { loadRecaptcha } from './helpers/recaptcha';
95
+
96
+ loadRecaptcha(); // ← avant la définition du composant App
97
+
98
+ const App = () => {
99
+ return (
100
+ // ...
101
+ );
102
+ };
103
+ ```
104
+
105
+ ---
106
+
107
+ ## 4. Utilisation dans un composant
108
+
109
+ ```typescript
110
+ import { executeRecaptcha } from '../helpers/recaptcha';
111
+
112
+ const handleSubmit = async () => {
113
+ let recaptchaToken = "";
114
+ try {
115
+ recaptchaToken = await executeRecaptcha('nom_action'); // ex: 'login', 'signup', 'validateAccount'
116
+ } catch (e) {
117
+ console.error(e);
118
+ // Informer l'utilisateur que la vérification de sécurité est indisponible
119
+ return;
120
+ }
121
+
122
+ // Passer recaptchaToken à votre API
123
+ await monService.maRequete(payload, recaptchaToken);
124
+ };
125
+ ```
126
+
127
+ Les noms d'actions sont libres mais doivent être déclarés dans Google Cloud Console pour apparaître dans les rapports reCAPTCHA.
128
+
129
+ ---
130
+
131
+ ## 5. Côté API (rappel)
132
+
133
+ Le backend doit valider le token auprès de l'endpoint Google :
134
+
135
+ ```
136
+ POST https://recaptchaenterprise.googleapis.com/v1/projects/{PROJECT_ID}/assessments?key={API_KEY}
137
+ ```
138
+
139
+ Avec le body :
140
+ ```json
141
+ {
142
+ "event": {
143
+ "token": "<token reçu>",
144
+ "siteKey": "<votre clé de site>",
145
+ "expectedAction": "nom_action"
146
+ }
147
+ }
148
+ ```
149
+
150
+ ---
151
+
152
+ ## Checklist rapide
153
+
154
+ - [ ] Clé de site ajoutée dans `.env`
155
+ - [ ] `src/helpers/recaptcha.ts` créé
156
+ - [ ] `loadRecaptcha()` appelé au niveau module dans `App.tsx`
157
+ - [ ] Chaque action sensible appelle `executeRecaptcha('action')` avec try/catch
158
+ - [ ] Le token est transmis à l'API backend
159
+ - [ ] Le backend valide le token côté serveur
@@ -0,0 +1,8 @@
1
+ {
2
+ "env": {
3
+ "CLAUDE_CODE_USE_BEDROCK": "1",
4
+ "AWS_PROFILE": "default",
5
+ "AWS_REGION": "eu-west-3",
6
+ "ANTHROPIC_MODEL": "eu.anthropic.claude-sonnet-4-6"
7
+ }
8
+ }
@@ -0,0 +1,12 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(git ls-tree *)",
5
+ "Bash(npx tsc *)",
6
+ "Bash(grep -v \"^--$\")",
7
+ "Bash(git checkout *)",
8
+ "Bash(rm -rf /Users/juliendezerable/Documents/GitHub/movalib-pro/src/components/catalog)",
9
+ "Bash(git *)"
10
+ ]
11
+ }
12
+ }
package/dist/index.d.ts CHANGED
@@ -33,6 +33,7 @@ export { default as Absence } from "./src/models/Absence";
33
33
  export { default as Address } from "./src/models/Address";
34
34
  export { default as CategoryPrestation } from "./src/models/CategoryPrestation";
35
35
  export { default as Customer } from "./src/models/Customer";
36
+ export type { EmailVerification } from "./src/models/EmailVerification";
36
37
  export { default as Document } from "./src/models/Document";
37
38
  export { default as Employee } from "./src/models/Employee";
38
39
  export { default as Event, } from "./src/models/Event";
@@ -1,5 +1,6 @@
1
1
  import { CustomerType } from "../helpers/Enums";
2
2
  import Address from "./Address";
3
+ import { EmailVerification } from "./EmailVerification";
3
4
  import Role from "./Role";
4
5
  import User from "./User";
5
6
  import Vehicle from "./Vehicle";
@@ -36,6 +37,7 @@ export default class Customer extends User {
36
37
  paymentPeriod?: number;
37
38
  billingEmail?: string;
38
39
  additionalEmails?: string;
40
+ emailVerification?: EmailVerification;
39
41
  constructor(id: string, roles: Role[] | undefined, firstname: string | undefined, lastname: string | undefined, avatar: string | undefined, addresses: Address[] | undefined, vehicles: Vehicle[], email: string | undefined, turnover: {
40
42
  key: string;
41
43
  value: number;
@@ -0,0 +1,13 @@
1
+ export interface EmailVerification {
2
+ email: string;
3
+ reason: string | null;
4
+ verificationResult: string;
5
+ sendex: number;
6
+ role: boolean;
7
+ disposable: boolean;
8
+ acceptAll: boolean;
9
+ verifiedAt: string | null;
10
+ bounceEventType: string | null;
11
+ bounceReason: string | null;
12
+ bouncedAt: string | null;
13
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/index.ts CHANGED
@@ -47,6 +47,7 @@ export { default as Absence } from "./src/models/Absence";
47
47
  export { default as Address } from "./src/models/Address";
48
48
  export { default as CategoryPrestation } from "./src/models/CategoryPrestation";
49
49
  export { default as Customer } from "./src/models/Customer";
50
+ export type { EmailVerification } from "./src/models/EmailVerification";
50
51
  export { default as Document } from "./src/models/Document";
51
52
  export { default as Employee } from "./src/models/Employee";
52
53
  export { default as Event, } from "./src/models/Event";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@movalib/movalib-commons",
3
- "version": "1.68.32",
3
+ "version": "1.68.33",
4
4
  "description": "Bibliothèque d'objets communs à l'ensemble des projets React de Movalib",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,5 +1,6 @@
1
1
  import { CustomerType } from "../helpers/Enums";
2
2
  import Address from "./Address";
3
+ import { EmailVerification } from "./EmailVerification";
3
4
  import Role from "./Role";
4
5
  import User from "./User";
5
6
  import Vehicle from "./Vehicle";
@@ -37,7 +38,8 @@ export default class Customer extends User {
37
38
  discountRate?:number;
38
39
  paymentPeriod?:number;
39
40
  billingEmail?:string;
40
- additionalEmails?:string
41
+ additionalEmails?:string;
42
+ emailVerification?: EmailVerification;
41
43
  constructor(
42
44
  id: string,
43
45
  roles: Role[] = [],
@@ -0,0 +1,13 @@
1
+ export interface EmailVerification {
2
+ email: string;
3
+ reason: string | null;
4
+ verificationResult: string;
5
+ sendex: number;
6
+ role: boolean;
7
+ disposable: boolean;
8
+ acceptAll: boolean;
9
+ verifiedAt: string | null;
10
+ bounceEventType: string | null;
11
+ bounceReason: string | null;
12
+ bouncedAt: string | null;
13
+ }