diff --git a/lang/fr.json b/lang/fr.json
index 3a8424aa276145ae09738cc8d94930a18c251c9e..172d2c6c36305c5111203b541a7e4eaa63940feb 100755
--- a/lang/fr.json
+++ b/lang/fr.json
@@ -473,6 +473,12 @@
 		"mailServerOffline": "Le serveur de messagerie est indisponible pour le moment, veuillez ré-essayer ultérieurement",
 		"mailServerOfflineMsg": "Le serveur de messagerie doit être <b>testé</b> et <b>opérationnel</b> pour : <b>{{action}}</b>",
 		"testAndValidate": "Tester et valider",
-		"receiveActivationNotification": "Recevoir le courriel d'activation"
+		"receiveActivationNotification": "Recevoir le courriel d'activation",
+		"newOtp": "Ajouter un OTP",
+		"otpUser": "Utilisateur OTP",
+		"notifyUserBy": "Notifier l'utilisateur par",
+		"phoneAlt": "Mobile",
+		"sms": "Sms",
+		"source": "Source"
 	}
 }
diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts
index 661f4cfa05324ca8431f8b51819aa8a7bcb6e505..011bd10f7a37278c15584a1b669cf8395648d735 100755
--- a/src/frontend/app/app.module.ts
+++ b/src/frontend/app/app.module.ts
@@ -53,13 +53,14 @@ import { MainDocumentDetailComponent } from './document/main-document-detail/mai
 import { AssociatedDocumentsComponent } from './document/associated-documents/associated-documents.component';
 import { UpdatePasswordComponent } from './login/updatePassword/updatePassword.component';
 import { PasswordModificationComponent } from './login/passwordModification/password-modification.component';
-import { VisaWorkflowModelsComponent } from './document/visa-workflow/models/visa-workflow-models.component';
 import { SearchComponent } from './search/search.component';
 import { SignaturePositionComponent } from './indexation/signature-position/signature-position.component';
 import { DevToolComponent } from './service/debug/dev-tool.component';
 import { DevLangComponent } from './service/debug/dev-lang.component';
 import { DocumentDateListComponent } from './documentDateList/document-date-list.component';
 import { DateOptionModalComponent } from './documentDateList/dateOption/date-option-modal.component';
+import { OtpCreateComponent } from './document/visa-workflow/otps/otp-create.component';
+import { OtpYousignComponent } from './document/visa-workflow/otps/yousign/otp-yousign.component';
 
 
 // ADMINISTRATION
@@ -140,7 +141,6 @@ registerLocaleData(localeFr, 'fr-FR');
         CheckConnectionComponent,
         CheckEmailConnectionComponent,
         IndexationComponent,
-        VisaWorkflowModelsComponent,
         SearchComponent,
         SignaturePositionComponent,
         DevToolComponent,
@@ -148,7 +148,9 @@ registerLocaleData(localeFr, 'fr-FR');
         SignatureMethodModalComponent,
         HistoryListComponent,
         DocumentDateListComponent,
-        DateOptionModalComponent
+        DateOptionModalComponent,
+        OtpCreateComponent,
+        OtpYousignComponent
     ],
     imports: [
         FormsModule,
diff --git a/src/frontend/app/document/visa-workflow/models/visa-workflow-models.component.html b/src/frontend/app/document/visa-workflow/models/visa-workflow-models.component.html
deleted file mode 100644
index 43a4eac100611b873504242d01407b5b894c373b..0000000000000000000000000000000000000000
--- a/src/frontend/app/document/visa-workflow/models/visa-workflow-models.component.html
+++ /dev/null
@@ -1,17 +0,0 @@
-<ion-list lines="none">
-    <ion-list-header>
-        <ion-label color="secondary">{{'lang.circuitModels' | translate}}</ion-label>
-    </ion-list-header>
-    <ion-item button *ngFor="let model of visaWorkflowModels" (click)="loadVisaWorkflow(model)">
-        <ion-label>{{model.title}}</ion-label>
-        <ion-buttons slot="end">
-            <ion-button fill="clear" slot="icon-only" shape="round" color="danger" (click)="$event.stopPropagation();removeModel(model)">
-                <ion-icon slot="icon-only" name="trash-outline"></ion-icon>
-            </ion-button>
-        </ion-buttons>
-    </ion-item>
-    <ion-item button (click)="createModel()" [disabled]="currentWorkflow.length === 0">
-        <ion-icon color="primary" slot="start" name="add-circle-outline"></ion-icon>
-        <ion-label color="primary">{{'lang.newTemplate' | translate}}</ion-label>
-    </ion-item>
-</ion-list>
\ No newline at end of file
diff --git a/src/frontend/app/document/visa-workflow/models/visa-workflow-models.component.scss b/src/frontend/app/document/visa-workflow/models/visa-workflow-models.component.scss
deleted file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..0000000000000000000000000000000000000000
diff --git a/src/frontend/app/document/visa-workflow/models/visa-workflow-models.component.ts b/src/frontend/app/document/visa-workflow/models/visa-workflow-models.component.ts
deleted file mode 100644
index 991ec474d654e408bb360ea8b265c671f69c3f2e..0000000000000000000000000000000000000000
--- a/src/frontend/app/document/visa-workflow/models/visa-workflow-models.component.ts
+++ /dev/null
@@ -1,153 +0,0 @@
-import { Component, Input, OnInit } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
-import { AlertController, PopoverController } from '@ionic/angular';
-import { NotificationService } from '../../../service/notification.service';
-import { catchError, tap } from 'rxjs/operators';
-import { of } from 'rxjs';
-import { AuthService } from '../../../service/auth.service';
-import { TranslateService } from '@ngx-translate/core';
-
-@Component({
-    selector: 'app-visa-workflow-models',
-    templateUrl: 'visa-workflow-models.component.html',
-    styleUrls: ['visa-workflow-models.component.scss'],
-})
-export class VisaWorkflowModelsComponent implements OnInit {
-
-    @Input() currentWorkflow: any[] = [];
-
-    visaWorkflowModels: any[] = [];
-
-    constructor(
-        public http: HttpClient,
-        private translate: TranslateService,
-        public popoverController: PopoverController,
-        public alertController: AlertController,
-        public notificationService: NotificationService,
-        public authService: AuthService
-    ) { }
-
-    ngOnInit(): void {
-        this.getVisaUserModels();
-    }
-
-    async createModel() {
-        const alert = await this.alertController.create({
-            header: this.translate.instant('lang.newTemplate'),
-            message: this.translate.instant('lang.newTemplateDesc'),
-            inputs: [
-                {
-                    name: 'title',
-                    type: 'text',
-                    placeholder: this.translate.instant('lang.label') + ' *',
-                },
-            ],
-            buttons: [
-                {
-                    text: this.translate.instant('lang.cancel'),
-                    role: 'cancel',
-                    handler: () => { }
-                }, {
-                    text: this.translate.instant('lang.validate'),
-                    handler: (data: any) => {
-                        if (data.title !== '') {
-                            this.saveModel(data.title);
-                            return true;
-                        } else {
-                            this.notificationService.error(this.translate.instant('lang.label') + ' ' + this.translate.instant('lang.mandatory'));
-                            return false;
-                        }
-                    }
-                }
-            ]
-        });
-
-        await alert.present();
-    }
-
-    saveModel(title: string) {
-        const objToSend: any = {
-            title: title,
-            items: this.currentWorkflow.map((item: any) => ({
-                userId: item.userId,
-                mode: this.authService.getWorkflowMode(item.role),
-                signatureMode: this.authService.getSignatureMode(item.role)
-            }))
-        };
-        this.http.post('../rest/workflowTemplates', objToSend).pipe(
-            tap((res: any) => {
-                this.notificationService.success('lang.modelCreated');
-                this.visaWorkflowModels.push({ id: res.id, title: title });
-            }),
-            catchError(err => {
-                this.notificationService.handleErrors(err);
-                return of(false);
-            })
-        ).subscribe();
-    }
-
-    async removeModel(model: any) {
-        const alert = await this.alertController.create({
-            header: this.translate.instant('lang.delete'),
-            message: this.translate.instant('lang.deleteTemplate'),
-            buttons: [
-                {
-                    text: this.translate.instant('lang.no'),
-                    role: 'cancel',
-                    handler: () => { }
-                }, {
-                    text: this.translate.instant('lang.yes'),
-                    handler: () => {
-                        this.http.delete(`../rest/workflowTemplates/${model.id}`).pipe(
-                            tap(() => {
-                                this.visaWorkflowModels = this.visaWorkflowModels.filter((item: any) => item.id !== model.id);
-                                this.notificationService.success(`Modèle ${model.title} supprimé`);
-                            }),
-                            catchError(err => {
-                                this.notificationService.handleErrors(err);
-                                return of(false);
-                            })
-                        ).subscribe();
-                    }
-                }
-            ]
-        });
-
-        await alert.present();
-    }
-
-    getVisaUserModels() {
-        this.http.get('../rest/workflowTemplates').pipe(
-            tap((data: any) => {
-                this.visaWorkflowModels = data.workflowTemplates;
-            }),
-            catchError(err => {
-                this.notificationService.handleErrors(err);
-                return of(false);
-            })
-        ).subscribe();
-    }
-
-    loadVisaWorkflow(model: any) {
-        this.http.get(`../rest/workflowTemplates/${model.id}`).pipe(
-            tap((data: any) => {
-                const workflows: any[] = data.workflowTemplate.items.map((item: any) => {
-                    const obj: any = {
-                        'userId': item.userId,
-                        'userDisplay': item.userLabel,
-                        'role': item.mode === 'visa' ? 'visa' : item.signatureMode,
-                        'processDate': null,
-                        'current': false,
-                        'modes': ['visa'].concat(item.userSignatureModes)
-                    };
-                    return obj;
-                });
-                this.popoverController.dismiss(workflows);
-            }),
-            catchError(err => {
-                this.notificationService.handleErrors(err);
-                return of(false);
-            })
-        ).subscribe();
-    }
-}
diff --git a/src/frontend/app/document/visa-workflow/otps/otp-create.component.html b/src/frontend/app/document/visa-workflow/otps/otp-create.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..66d8c5cf5afc403e1a9ad987a635701fd2b02a5f
--- /dev/null
+++ b/src/frontend/app/document/visa-workflow/otps/otp-create.component.html
@@ -0,0 +1,31 @@
+<ion-header [translucent]="true">
+    <ion-toolbar color="primary">
+        <ion-title>{{'lang.otpUser' | translate}}</ion-title>
+        <ion-buttons slot="end">
+            <ion-button (click)="dismissModal()">
+                <ion-icon slot="icon-only" name="close-outline"></ion-icon>
+            </ion-button>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-header>
+<ion-content>
+    <ion-card>
+        <ion-item>
+            <ion-label color="secondary">{{'lang.source' | translate}}</ion-label>
+            <ion-select [value]="currentSource.id" cancelText="{{'lang.cancel' | translate}}">
+                <ion-select-option *ngFor="let source of sources" [value]="source.id">
+                    {{source.label | translate}}</ion-select-option>
+            </ion-select>
+        </ion-item>
+    </ion-card>
+    <app-otp-yousign #appOtpYousign *ngIf="currentSource.type === 'yousign'"></app-otp-yousign>
+</ion-content>
+<ion-footer class="ion-no-border">
+    <ion-toolbar>
+        <ion-buttons class="ion-justify-content-center">
+            <ion-button type="submit" color="primary" (click)="onSubmit()" [disabled]="!isValid()">
+                <ion-label>{{'lang.save' | translate}}</ion-label>
+            </ion-button>
+        </ion-buttons>
+    </ion-toolbar>
+</ion-footer>
\ No newline at end of file
diff --git a/src/frontend/app/document/visa-workflow/otps/otp-create.component.scss b/src/frontend/app/document/visa-workflow/otps/otp-create.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..b6dd7ffb77756d3f8efc0b8dc80a2791f1c9ea5d
--- /dev/null
+++ b/src/frontend/app/document/visa-workflow/otps/otp-create.component.scss
@@ -0,0 +1,3 @@
+.my-custom-class {
+    --min-width: 400px;
+  }
\ No newline at end of file
diff --git a/src/frontend/app/document/visa-workflow/otps/otp-create.component.ts b/src/frontend/app/document/visa-workflow/otps/otp-create.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a6c96a48967d9cd09a5df6a5dda35bb24c92a8a7
--- /dev/null
+++ b/src/frontend/app/document/visa-workflow/otps/otp-create.component.ts
@@ -0,0 +1,66 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { NotificationService } from '../../../service/notification.service';
+import { AuthService } from '../../../service/auth.service';
+import { TranslateService } from '@ngx-translate/core';
+import { ModalController } from '@ionic/angular';
+import { OtpYousignComponent } from './yousign/otp-yousign.component';
+
+@Component({
+    selector: 'app-otp-create',
+    templateUrl: 'otp-create.component.html',
+    styleUrls: ['otp-create.component.scss'],
+})
+export class OtpCreateComponent implements OnInit {
+
+    @ViewChild('appOtpYousign', { static: false }) appOtpYousign: OtpYousignComponent;
+
+    sources: any[] = [];
+
+    currentSource: any = null;
+
+    constructor(
+        public http: HttpClient,
+        private translate: TranslateService,
+        public notificationService: NotificationService,
+        public authService: AuthService,
+        public modalController: ModalController
+    ) { }
+
+    ngOnInit(): void {
+        this.getConfig();
+    }
+
+    getConfig() {
+        // FOR TEST
+        this.sources = [
+            {
+                id: 1,
+                label: 'yousign',
+                type: 'yousign'
+            }
+        ];
+        this.currentSource = this.sources[0];
+        /* this.http.get(`../rest/???`).pipe(
+            tap((data: any) => {
+
+            }),
+            catchError(err => {
+                this.notificationService.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();*/
+    }
+
+    onSubmit() {
+        this.modalController.dismiss(this.appOtpYousign.getData());
+    }
+
+    dismissModal() {
+        this.modalController.dismiss('cancel');
+    }
+
+    isValid() {
+        return this.appOtpYousign?.isValid();
+    }
+}
diff --git a/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.html b/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..8d37833affd6f940051d86b4d0923aa29d29a15e
--- /dev/null
+++ b/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.html
@@ -0,0 +1,57 @@
+<form style="display: contents;" #otpForm="ngForm">
+    <ion-list lines="full" class="ion-no-margin">
+        <ion-item>
+            <ion-label color="secondary" position="floating">{{'lang.firstname' | translate}} *</ion-label>
+            <ion-input name="firstname" [maxlength]="128" [(ngModel)]="otp.firstname" placeholder="Alain" required>
+            </ion-input>
+        </ion-item>
+        <ion-item>
+            <ion-label color="secondary" position="floating">{{'lang.lastname' | translate}} *</ion-label>
+            <ion-input name="lastname" [maxlength]="128" [(ngModel)]="otp.lastname" placeholder="Dupont" required>
+            </ion-input>
+        </ion-item>
+        <ion-item>
+            <ion-label color="secondary" position="floating">{{'lang.phoneAlt' | translate}} <ng-container
+                    *ngIf="otp.mode === 'sms'">*</ng-container>
+            </ion-label>
+            <ion-input name="phone" pattern="^\+?[1-9]\d{1,14}$" [(ngModel)]="otp.phone" placeholder="+33646342143"
+                [required]="otp.mode === 'sms'"></ion-input>
+        </ion-item>
+        <ion-item>
+            <ion-label color="secondary" position="floating">{{'lang.email' | translate}} <ng-container
+                    *ngIf="otp.mode === 'email'">*</ng-container>
+            </ion-label>
+            <ion-input name="email" pattern="(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"
+                placeholder="alain.dupont@gmail.com" [(ngModel)]="otp.email" [required]="otp.mode === 'email'">
+            </ion-input>
+        </ion-item>
+    </ion-list>
+    <ion-list>
+        <ion-radio-group [(ngModel)]="otp.role" [value]="otp.role">
+            <ion-list-header>
+                <ion-label color="secondary">{{'lang.role' | translate}}</ion-label>
+            </ion-list-header>
+            <div style="display:flex;">
+                <ion-item *ngFor="let role of roles" style="flex:1;">
+                    <ion-label>{{'lang.' + role | translate}}</ion-label>
+                    <ion-radio slot="start" [value]="role"></ion-radio>
+                </ion-item>
+            </div>
+        </ion-radio-group>
+        <!--<ion-label color="secondary" position="floating">{{'lang.role' | translate}}</ion-label>
+        <ion-select name="mode" [(ngModel)]="otp.role" [value]="otp.role" cancelText="{{'lang.cancel' | translate}}">
+            <ion-select-option *ngFor="let role of roles" [value]="role">
+                {{'lang.' + role | translate}}</ion-select-option>
+        </ion-select>-->
+    </ion-list>
+    <ion-list>
+        <ion-item>
+            <ion-label color="secondary" position="floating">{{'lang.notifyUserBy' | translate}}</ion-label>
+            <ion-select name="mode" [(ngModel)]="otp.notify" [value]="otp.notify"
+                cancelText="{{'lang.cancel' | translate}}" [disabled]="notificationModes.length === 1">
+                <ion-select-option *ngFor="let mode of notificationModes" [value]="mode">
+                    {{'lang.' + mode | translate}}</ion-select-option>
+            </ion-select>
+        </ion-item>
+    </ion-list>
+</form>
\ No newline at end of file
diff --git a/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.scss b/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..3c297bb5fad493de5144d0b0141601b065ee74f0
--- /dev/null
+++ b/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.scss
@@ -0,0 +1,9 @@
+.item-interactive-disabled.sc-ion-label-md-h:not(.item-multiple-inputs), .item-interactive-disabled:not(.item-multiple-inputs) .sc-ion-label-md-h {
+    opacity: initial !important;
+}
+
+.error {
+    font-size: 10px;
+    padding: 5px;
+    color: var(--ion-color-danger);
+}
\ No newline at end of file
diff --git a/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.ts b/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..48f33845f23e23cc8bd77fbe78eeeca79d7307cd
--- /dev/null
+++ b/src/frontend/app/document/visa-workflow/otps/yousign/otp-yousign.component.ts
@@ -0,0 +1,66 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { NotificationService } from '../../../../service/notification.service';
+import { TranslateService } from '@ngx-translate/core';
+import { NgForm } from '@angular/forms';
+
+@Component({
+    selector: 'app-otp-yousign',
+    templateUrl: 'otp-yousign.component.html',
+    styleUrls: ['otp-yousign.component.scss'],
+})
+export class OtpYousignComponent implements OnInit {
+    @ViewChild('otpForm', { static: false }) otpForm: NgForm;
+
+    notificationModes: any[] = [];
+
+    roles: any[] = [
+        'otp_visa_yousign',
+        'otp_sign_yousign'
+    ];
+
+    otp: any = {
+        firstname: '',
+        lastname: '',
+        email: '',
+        phone: '',
+        notify: 'sms',
+        role: 'otp_sign_yousign'
+    };
+
+    constructor(
+        public http: HttpClient,
+        private translate: TranslateService,
+        public notificationService: NotificationService,
+    ) { }
+
+    ngOnInit(): void {
+        this.getConfig();
+    }
+
+    getConfig() {
+        // FOR TEST
+        this.notificationModes = [
+            'sms',
+            'email'
+        ];
+        this.otp.mode = this.notificationModes[0];
+        /* this.http.get(`../rest/???`).pipe(
+            tap((data: any) => {
+
+            }),
+            catchError(err => {
+                this.notificationService.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();*/
+    }
+
+    getData() {
+        return this.otp;
+    }
+
+    isValid() {
+        return this.otpForm.valid;
+    }
+}
diff --git a/src/frontend/app/document/visa-workflow/visa-workflow.component.html b/src/frontend/app/document/visa-workflow/visa-workflow.component.html
index 7865a96ae57ea65c58177da8e0b543da78efe20b..b3f01cf772cdfaee3b13b0b42b3ac386055838c4 100644
--- a/src/frontend/app/document/visa-workflow/visa-workflow.component.html
+++ b/src/frontend/app/document/visa-workflow/visa-workflow.component.html
@@ -14,11 +14,33 @@
             <ion-searchbar #searchInput [(ngModel)]="visaUsersSearchVal" [placeholder]="'lang.searchUser' | translate"
                 (ionChange)="getVisaUsers($event)" (ionFocus)="visaUsersSearchVal=''"></ion-searchbar>
             <ion-buttons slot="end">
-                <ion-button fill="clear" slot="icon-only" shape="round" color="primary"
-                    (click)="openVisaWorkflowModels($event)" [title]="'lang.circuitModels' | translate">
+                <ion-button fill="clear" slot="icon-only" shape="round" color="primary" [matMenuTriggerFor]="menu"
+                    [title]="'lang.circuitModels' | translate">
                     <ion-icon slot="icon-only" name="albums-outline"></ion-icon>
                 </ion-button>
             </ion-buttons>
+            <mat-menu #menu="matMenu">
+                <ion-item button (click)="openOtpModal()" lines="none">
+                    <ion-icon name="person-circle-outline" slot="start" color="primary"></ion-icon>
+                    <ion-label>{{'lang.newOtp' | translate}}</ion-label>
+                </ion-item>
+                <button mat-menu-item [matMenuTriggerFor]="model"
+                    (menuOpened)="getVisaUserModels()">{{'lang.circuitModels' | translate}}</button>
+            </mat-menu>
+            <mat-menu #model="matMenu">
+                <ion-item button lines="none" *ngFor="let model of visaWorkflowModels" (click)="loadVisaWorkflow(model)">
+                    <ion-label>{{model.title}}</ion-label>
+                    <ion-buttons slot="end">
+                        <ion-button fill="clear" slot="icon-only" shape="round" color="danger"
+                            (click)="$event.stopPropagation();removeModel(model)">
+                            <ion-icon slot="icon-only" name="trash-outline"></ion-icon>
+                        </ion-button>
+                    </ion-buttons>
+                </ion-item>
+                <ion-item button (click)="createModel()" [disabled]="visaWorkflow.length === 0">
+                    <ion-label>{{'lang.newTemplate' | translate}}</ion-label>
+                </ion-item>
+            </mat-menu>
         </ion-item>
         <ion-list *ngIf="visaUsersList.length > 0"
             style="position: absolute;z-index: 2;width: 100%;box-shadow: 0 4px 2px -2px gray;">
@@ -41,8 +63,7 @@
             <ion-reorder slot="start">
                 <ion-icon [title]="'lang.reorder' | translate" name="reorder-three" style="font-size: 30px;"></ion-icon>
             </ion-reorder>
-            <ion-avatar slot="start" class="avatar-user" style="cursor: grab;"
-                (click)="$event.stopPropagation();">
+            <ion-avatar slot="start" class="avatar-user" style="cursor: grab;" (click)="$event.stopPropagation();">
                 <img [src]="diffusion.userPicture">
             </ion-avatar>
             <ion-label>
@@ -56,7 +77,8 @@
                         interface="popover" [interfaceOptions]="customPopoverOptions"
                         [style.color]="getRole(diffusion.role)?.color" [disabled]="!editMode"
                         style="width: auto;max-width: 100%;padding-left:0px;">
-                        <ion-select-option [value]="mode" *ngFor="let mode of diffusion.modes" [disabled]="!isValidRole(i,mode, diffusion.role)">
+                        <ion-select-option [value]="mode" *ngFor="let mode of diffusion.modes"
+                            [disabled]="!isValidRole(i,mode, diffusion.role)">
                             {{'lang.' + mode + 'User' | translate}}
                         </ion-select-option>
                     </ion-select>
diff --git a/src/frontend/app/document/visa-workflow/visa-workflow.component.ts b/src/frontend/app/document/visa-workflow/visa-workflow.component.ts
index 04181496b66beb7f6ca3df9b494628d17e68a57a..a99c7ec7d41a8bd44eb5d97598711b85c3c92bdf 100644
--- a/src/frontend/app/document/visa-workflow/visa-workflow.component.ts
+++ b/src/frontend/app/document/visa-workflow/visa-workflow.component.ts
@@ -5,9 +5,10 @@ import { AuthService } from '../../service/auth.service';
 import { catchError, tap } from 'rxjs/operators';
 import { of } from 'rxjs';
 import { NotificationService } from '../../service/notification.service';
-import { IonReorderGroup, PopoverController } from '@ionic/angular';
-import { VisaWorkflowModelsComponent } from './models/visa-workflow-models.component';
+import { AlertController, IonReorderGroup, ModalController, PopoverController } from '@ionic/angular';
 import { ItemReorderEventDetail } from '@ionic/core';
+import { TranslateService } from '@ngx-translate/core';
+import { OtpCreateComponent } from './otps/otp-create.component';
 
 @Component({
     selector: 'app-visa-workflow',
@@ -29,13 +30,16 @@ export class VisaWorkflowComponent implements OnInit {
         header: 'Roles'
     };
     roles: any[] = [];
+    visaWorkflowModels: any[] = [];
 
     constructor(
         public http: HttpClient,
+        private translate: TranslateService,
+        public alertController: AlertController,
         public signaturesService: SignaturesContentService,
         public authService: AuthService,
         public notificationService: NotificationService,
-        public popoverController: PopoverController
+        public modalController: ModalController,
     ) { }
 
     ngOnInit(): void {
@@ -143,21 +147,26 @@ export class VisaWorkflowComponent implements OnInit {
         this.visaUsersList = [];
     }
 
-    async openVisaWorkflowModels(ev: any) {
-        const popover = await this.popoverController.create({
-            component: VisaWorkflowModelsComponent,
-            componentProps: { currentWorkflow: this.visaWorkflow },
-            event: ev,
+    async openOtpModal(ev: any) {
+        const modal = await this.modalController.create({
+            cssClass: 'my-custom-class',
+            component: OtpCreateComponent,
+            backdropDismiss: false,
         });
-        await popover.present();
+        await modal.present();
 
-        popover.onDidDismiss()
+        modal.onDidDismiss()
             .then((result: any) => {
-                if (result.role !== 'backdrop') {
-                    this.visaWorkflow = this.visaWorkflow.concat(result.data);
-                    this.visaWorkflow.forEach((element: any, index: number) => {
-                        this.getAvatarUser(index);
-                    });
+                if (typeof result.data === 'object') {
+                    const obj: any = {
+                        'userId': null,
+                        'userDisplay': `${result.data.firstname} ${result.data.lastname}`,
+                        'role': result.data.role,
+                        'processDate': null,
+                        'current': false,
+                        'modes': [result.data.role]
+                    };
+                    this.visaWorkflow.push(obj);
                 }
             });
     }
@@ -188,4 +197,127 @@ export class VisaWorkflowComponent implements OnInit {
             return true;
         }
     }
+
+    async createModel() {
+        const alert = await this.alertController.create({
+            header: this.translate.instant('lang.newTemplate'),
+            message: this.translate.instant('lang.newTemplateDesc'),
+            inputs: [
+                {
+                    name: 'title',
+                    type: 'text',
+                    placeholder: this.translate.instant('lang.label') + ' *',
+                },
+            ],
+            buttons: [
+                {
+                    text: this.translate.instant('lang.cancel'),
+                    role: 'cancel',
+                    handler: () => { }
+                }, {
+                    text: this.translate.instant('lang.validate'),
+                    handler: (data: any) => {
+                        if (data.title !== '') {
+                            this.saveModel(data.title);
+                            return true;
+                        } else {
+                            this.notificationService.error(this.translate.instant('lang.label') + ' ' + this.translate.instant('lang.mandatory'));
+                            return false;
+                        }
+                    }
+                }
+            ]
+        });
+
+        await alert.present();
+    }
+
+    saveModel(title: string) {
+        const objToSend: any = {
+            title: title,
+            items: this.visaWorkflow.map((item: any) => ({
+                userId: item.userId,
+                mode: this.authService.getWorkflowMode(item.role),
+                signatureMode: this.authService.getSignatureMode(item.role)
+            }))
+        };
+        this.http.post('../rest/workflowTemplates', objToSend).pipe(
+            tap((res: any) => {
+                this.notificationService.success('lang.modelCreated');
+                this.visaWorkflowModels.push({ id: res.id, title: title });
+            }),
+            catchError(err => {
+                this.notificationService.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    async removeModel(model: any) {
+        const alert = await this.alertController.create({
+            header: this.translate.instant('lang.delete'),
+            message: this.translate.instant('lang.deleteTemplate'),
+            buttons: [
+                {
+                    text: this.translate.instant('lang.no'),
+                    role: 'cancel',
+                    handler: () => { }
+                }, {
+                    text: this.translate.instant('lang.yes'),
+                    handler: () => {
+                        this.http.delete(`../rest/workflowTemplates/${model.id}`).pipe(
+                            tap(() => {
+                                this.visaWorkflowModels = this.visaWorkflowModels.filter((item: any) => item.id !== model.id);
+                                this.notificationService.success(`Modèle ${model.title} supprimé`);
+                            }),
+                            catchError(err => {
+                                this.notificationService.handleErrors(err);
+                                return of(false);
+                            })
+                        ).subscribe();
+                    }
+                }
+            ]
+        });
+
+        await alert.present();
+    }
+
+    loadVisaWorkflow(model: any) {
+        this.http.get(`../rest/workflowTemplates/${model.id}`).pipe(
+            tap((data: any) => {
+                const workflows: any[] = data.workflowTemplate.items.map((item: any) => {
+                    const obj: any = {
+                        'userId': item.userId,
+                        'userDisplay': item.userLabel,
+                        'role': item.mode === 'visa' ? 'visa' : item.signatureMode,
+                        'processDate': null,
+                        'current': false,
+                        'modes': ['visa'].concat(item.userSignatureModes)
+                    };
+                    return obj;
+                });
+                this.visaWorkflow = this.visaWorkflow.concat(workflows);
+                this.visaWorkflow.forEach((element: any, index: number) => {
+                    this.getAvatarUser(index);
+                });
+            }),
+            catchError(err => {
+                this.notificationService.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    getVisaUserModels() {
+        this.http.get('../rest/workflowTemplates').pipe(
+            tap((data: any) => {
+                this.visaWorkflowModels = data.workflowTemplates;
+            }),
+            catchError(err => {
+                this.notificationService.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
 }