diff --git a/core/xml/actions_pages.xml b/core/xml/actions_pages.xml
index d37818eee11288abffd596b773c6598e26c9ece6..4deacefef65edc405d877f5f5de7ee347e6b7ed4 100755
--- a/core/xml/actions_pages.xml
+++ b/core/xml/actions_pages.xml
@@ -359,7 +359,7 @@ An action page is described in a ACTIONPAGE tag :
         <LABEL>_SEND_TO_AVIS_WF</LABEL>
         <NAME>send_to_avis</NAME>
         <DESC>_SEND_TO_AVIS_WF_DESC</DESC>
-        <component>sendToAvisAction</component>
+        <component>sendToOpinionCircuitAction</component>
         <ORIGIN>module</ORIGIN>
         <MODULE>avis</MODULE>
         <FLAG_CREATE>false</FLAG_CREATE>
diff --git a/migration/20.03/2003.sql b/migration/20.03/2003.sql
index a872f87b0dd54510fc160a3c11aea42289ca874a..4739eacbfc1b057f9e8d76622401ba0d7fd2ed07 100644
--- a/migration/20.03/2003.sql
+++ b/migration/20.03/2003.sql
@@ -92,8 +92,8 @@ UPDATE actions SET component = 'resetVisaAction' WHERE action_page = 'rejection_
 UPDATE actions SET component = 'interruptVisaAction' WHERE action_page = 'interrupt_visa';
 UPDATE actions SET component = 'sendSignatureBookAction' WHERE action_page IN ('send_to_visa', 'send_signed_docs');
 UPDATE actions SET component = 'continueVisaCircuitAction' WHERE action_page = 'visa_workflow';
-UPDATE actions SET component = 'sendToAvisAction' WHERE action_page = 'send_to_avis';
 UPDATE actions SET component = 'closeMailWithAttachmentsOrNotesAction' WHERE action_page = 'close_mail_with_attachment';
+UPDATE actions SET component = 'sendToOpinionCircuitAction' WHERE action_page = 'send_to_avis';
 UPDATE actions SET component = 'continueOpinionCircuitAction' WHERE action_page = 'avis_workflow';
 
 /* FOLDERS */
diff --git a/src/app/action/controllers/ActionMethodController.php b/src/app/action/controllers/ActionMethodController.php
index cf46d9699677e1d046d54a1502fa5a716b8b91a4..85452e274471bbfbdba0d5e9ef96d3fb70449e90 100644
--- a/src/app/action/controllers/ActionMethodController.php
+++ b/src/app/action/controllers/ActionMethodController.php
@@ -59,7 +59,7 @@ class ActionMethodController
         'rejectVisaBackToPreviousAction'        => 'rejectVisaBackToPrevious',
         'resetVisaAction'                       => 'resetVisa',
         'interruptVisaAction'                   => 'interruptVisa',
-        'sendToAvisAction'                      => 'sendToAvis',
+        'sendToOpinionCircuitAction'            => 'sendToOpinionCircuit',
         'continueOpinionCircuitAction'          => 'continueOpinionCircuit',
         'noConfirmAction'                       => null
     ];
@@ -535,7 +535,7 @@ class ActionMethodController
         return true;
     }
 
-    public static function sendToAvis(array $args)
+    public static function sendToOpinionCircuit(array $args)
     {
         ValidatorModel::notEmpty($args, ['resId']);
         ValidatorModel::intVal($args, ['resId']);
diff --git a/src/frontend/app/actions/actions.service.ts b/src/frontend/app/actions/actions.service.ts
index 6585b62af2d10eaaf72e827d19524667e6693380..67dd15744ef46af54198f334488f6548a2ed37bc 100644
--- a/src/frontend/app/actions/actions.service.ts
+++ b/src/frontend/app/actions/actions.service.ts
@@ -27,6 +27,7 @@ import { closeMailWithAttachmentsOrNotesActionComponent } from './close-mail-wit
 import { Router } from '@angular/router';
 import { SendSignatureBookActionComponent } from './visa-send-signature-book-action/send-signature-book-action.component';
 import { ContinueVisaCircuitActionComponent } from './visa-continue-circuit-action/continue-visa-circuit-action.component';
+import { SendAvisWorkflowComponent } from './avis-workflow-send-action/send-avis-workflow-action.component';
 
 @Injectable()
 export class ActionsService {
@@ -728,4 +729,26 @@ export class ActionsService {
             })
         ).subscribe();
     }
+
+    sendToOpinionCircuitAction(options: any = null) {
+        const dialogRef = this.dialog.open(SendAvisWorkflowComponent, {
+            autoFocus: false,
+            disableClose: true,
+            data: this.setDatasActionToSend()
+        });
+        dialogRef.afterClosed().pipe(
+            tap((data: any) => {
+                this.unlockResourceAfterActionModal(data);
+            }),
+            filter((data: string) => data === 'success'),
+            tap((result: any) => {
+                this.endAction(result);
+            }),
+            finalize(() => this.loading = false),
+            catchError((err: any) => {
+                this.notify.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
 }
diff --git a/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.html b/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.html
new file mode 100644
index 0000000000000000000000000000000000000000..54c812860cdc59b608b8fe43eece04178de4eee0
--- /dev/null
+++ b/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.html
@@ -0,0 +1,37 @@
+<h1 mat-dialog-title>{{data.action.label}}</h1>
+<div mat-dialog-content>
+    <div *ngIf="loading" class="loading" style="display:flex;height:100%;">
+        <mat-spinner style="margin:auto;"></mat-spinner>
+    </div>
+    <mat-sidenav-container autosize style="height:100%;">
+        <mat-sidenav-content style="background: white;padding:10px;">
+            <div>
+                {{lang.makeActionOn}}
+                <b *ngIf="data.resIds.length === 0" color="primary" class="highlight">{{lang.currentIndexingMail}}</b>
+                <b *ngIf="data.resIds.length == 1" color="primary" class="highlight">{{data.resource.chrono}}</b>
+                <b *ngIf="data.resIds.length > 1" color="primary" class="highlight">{{data.resIds.length}}
+                    {{lang.elements}}</b> ?
+            </div>
+            <div *ngIf="resourcesError.length > 0" class="alert-message alert-message-danger mailList" role="alert">
+                <p>
+                    {{lang.canNotMakeAction}} :
+                </p>
+                <ul>
+                    <li *ngFor="let ressource of resourcesError">
+                        <b>{{ressource.alt_identifier}}</b> : {{lang[ressource.reason]}}
+                    </li>
+                </ul>
+            </div>
+            <app-avis-workflow *ngIf="data.resIds.length == 1 || (!noResourceToProcess && data.resIds.length > 1)" [adminMode]="true" #appAvisWorkflow>
+            </app-avis-workflow>
+            <div style="padding-top: 10px;">
+                <app-note-editor #noteEditor [resIds]="data.resIds"></app-note-editor>
+            </div>
+        </mat-sidenav-content>
+    </mat-sidenav-container>
+</div>
+<div mat-dialog-actions class="actions">
+    <button mat-raised-button mat-button color="primary" [disabled]="loading || !isValidAction()"
+        (click)="onSubmit()">{{lang.validate}}</button>
+    <button mat-raised-button mat-button [disabled]="loading" [mat-dialog-close]="">{{lang.cancel}}</button>
+</div>
\ No newline at end of file
diff --git a/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.scss b/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.scss
new file mode 100644
index 0000000000000000000000000000000000000000..9424211bb4af9027d454165e7417bf86fb23c6eb
--- /dev/null
+++ b/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.scss
@@ -0,0 +1,128 @@
+@import '../../../css/vars.scss';
+
+.fullHeight {
+    height: 70vh;
+}
+
+.fullWidth {
+    width: 70vw;
+}
+
+.highlight {
+    font-size: 110%;
+}
+
+.loading {
+    display: flex;
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background: #ffffffb3;
+    z-index: 2;
+    overflow: hidden;
+}
+
+.mailList {
+    ul {
+        font-size: 12px;
+        max-height: 100px;
+        overflow: auto;
+        padding-left: 25px;
+        padding-right: 5px;
+        padding-bottom: 10px;
+        margin-top: 10px;
+    }
+
+    p {
+        //font-size: 18px;
+        margin: 0;
+        text-decoration: underline;
+    }
+
+    b {
+        font-size: 120%;
+    }
+}
+
+.formType {
+    align-items: center;
+    display: flex;
+    margin: 10px;
+    border-radius: 4px;
+    border: solid 1px #ccc;
+    position: relative;
+    padding: 10px;
+
+    &-title {
+        white-space: pre;
+        overflow: hidden;
+        max-width: 85%;
+        text-overflow: ellipsis;
+        z-index: 1;
+        font-size: 10px;
+        font-weight: bold;
+        background: white;
+        position: absolute;
+        top: -7px;
+        left: 10px;
+        padding: 0px;
+        margin: 0px;
+        color: #135f7f;
+    }
+
+    ::ng-deep.mat-form-field-suffix {
+        color: $secondary;
+        font-size: 15px;
+        top: 0;
+    }
+
+    ::ng-deep.mat-form-field-wrapper {
+        padding: 0;
+    }
+}
+
+.priceContent {
+    display: flex;
+    align-items: center;
+    justify-content: flex-end;
+    width: 100%;
+
+    &-label {
+        text-align: right;
+        color: $primary;
+        flex: 1;
+        justify-content: flex-end;
+        display: flex;
+        padding-right: 10px;
+    }
+
+    .mat-form-field {
+        width: 90px !important;
+
+        input {
+            font-weight: bold;
+            user-select: none;
+        }
+    }
+}
+
+.priceInfo {
+    padding-right: 20px;
+    font-size: 10px;
+    opacity: 0.5;
+    width: 100%;
+}
+
+.pjList {
+    display: flex;
+    width: 100%;
+    overflow: auto;
+    flex-direction: column;
+    background: #666;
+
+    img {
+        margin: 10px;
+    }
+}
\ No newline at end of file
diff --git a/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.ts b/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.ts
new file mode 100644
index 0000000000000000000000000000000000000000..a0239883639ac90af1496c67ac8fa8ade4745d5f
--- /dev/null
+++ b/src/frontend/app/actions/avis-workflow-send-action/send-avis-workflow-action.component.ts
@@ -0,0 +1,131 @@
+import { Component, OnInit, Inject, ViewChild } from '@angular/core';
+import { LANG } from '../../translate.component';
+import { NotificationService } from '../../notification.service';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+import { HttpClient } from '@angular/common/http';
+import { NoteEditorComponent } from '../../notes/note-editor.component';
+import { tap, finalize, catchError } from 'rxjs/operators';
+import { of } from 'rxjs';
+import { FunctionsService } from '../../../service/functions.service';
+import { AvisWorkflowComponent } from '../../avis/avis-workflow.component';
+
+@Component({
+    templateUrl: "send-avis-workflow-action.component.html",
+    styleUrls: ['send-avis-workflow-action.component.scss'],
+})
+export class SendAvisWorkflowComponent implements OnInit {
+
+    lang: any = LANG;
+    loading: boolean = false;
+
+    resourcesError: any[] = [];
+
+    noResourceToProcess: boolean = null;
+
+    @ViewChild('noteEditor', { static: true }) noteEditor: NoteEditorComponent;
+    @ViewChild('appAvisWorkflow', { static: false }) appAvisWorkflow: AvisWorkflowComponent;
+
+    constructor(
+        public http: HttpClient,
+        private notify: NotificationService,
+        public dialogRef: MatDialogRef<SendAvisWorkflowComponent>,
+        @Inject(MAT_DIALOG_DATA) public data: any,
+        public functions: FunctionsService) { }
+
+    async ngOnInit(): Promise<void> {        
+        if (this.data.resIds.length > 0) {
+            this.loading = true;
+            await this.checkAvisWorkflow();
+            this.loading = false;
+        }
+        if (this.data.resIds.length === 1) {
+            await this.appAvisWorkflow.loadWorkflow(this.data.resIds[0]);
+            if (this.appAvisWorkflow.emptyWorkflow()) {
+                this.appAvisWorkflow.loadDefaultWorkflow(this.data.resIds[0]);
+            }
+        }
+    }
+
+    checkAvisWorkflow() {
+        this.resourcesError = [];
+
+        // TO DO : WAIT BACK
+        return new Promise((resolve, reject) => {
+            this.http.post('../../rest/resourcesList/users/' + this.data.userId + '/groups/' + this.data.groupId + '/baskets/' + this.data.basketId + '/actions/' + this.data.action.id + '/checkSignatureBook', { resources: this.data.resIds })
+                .subscribe((data: any) => {
+                    if (!this.functions.empty(data.resourcesInformations.noAttachment)) {
+                        this.resourcesError = data.resourcesInformations.noAttachment;
+                    }
+                    this.noResourceToProcess = this.data.resIds.length === this.resourcesError.length;
+                    resolve(true);
+                }, (err: any) => {
+                    this.notify.handleSoftErrors(err);
+                });
+        });
+    }
+
+    async onSubmit() {
+        this.loading = true;
+        if (this.data.resIds.length === 0) {
+            let res = await this.indexDocument();
+            if (res) {
+                res = await this.appAvisWorkflow.saveAvisWorkflow(this.data.resIds);
+            }
+            if (res) {
+                this.executeAction(this.data.resIds);
+            }
+        } else {
+            const realResSelected: number[] = this.data.resIds.filter((resId: any) => this.resourcesError.map(resErr => resErr.res_id).indexOf(resId) === -1);
+
+            const res = await this.appAvisWorkflow.saveAvisWorkflow(realResSelected);
+
+            if (res) {
+                this.executeAction(realResSelected);
+            }
+        }
+        this.loading = false;
+    }
+
+    indexDocument() {
+        return new Promise((resolve, reject) => {
+            this.http.post('../../rest/resources', this.data.resource).pipe(
+                tap((data: any) => {
+                    this.data.resIds = [data.resId];
+                    resolve(true);
+                }),
+                catchError((err: any) => {
+                    this.notify.handleErrors(err);
+                    resolve(false);
+                    return of(false);
+                })
+            ).subscribe();
+        });
+    }
+
+    executeAction(realResSelected: number[]) {
+
+        this.http.put(this.data.processActionRoute, { resources: realResSelected, note: this.noteEditor.getNoteContent() }).pipe(
+            tap((data: any) => {
+                if (!data) {
+                    this.dialogRef.close('success');
+                }
+                if (data && data.errors != null) {
+                    this.notify.error(data.errors);
+                }
+            }),
+            finalize(() => this.loading = false),
+            catchError((err: any) => {
+                this.notify.handleErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+
+    isValidAction() {
+        if (!this.noResourceToProcess && this.appAvisWorkflow !== undefined && !this.appAvisWorkflow.emptyWorkflow() && !this.appAvisWorkflow.workflowEnd()) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+}
diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts
index b3425a5643ec0f6995ff093bccb8d7a96b32e33d..3e345ef6fce9760b7fedaf5db5763290fac6b01b 100755
--- a/src/frontend/app/app.module.ts
+++ b/src/frontend/app/app.module.ts
@@ -61,6 +61,7 @@ import { SendSignatureBookActionComponent }               from './actions/send-s
 import { ContinueVisaCircuitActionComponent }               from './actions/continue-visa-circuit-action/continue-visa-circuit-action.component';
 import { SendSignatureBookActionComponent }               from './actions/visa-send-signature-book-action/send-signature-book-action.component';
 import { ContinueVisaCircuitActionComponent }               from './actions/visa-continue-circuit-action/continue-visa-circuit-action.component';
+import { SendAvisWorkflowComponent }               from './actions/avis-workflow-send-action/send-avis-workflow-action.component';
 
 import { FiltersListComponent }                 from './list/filters/filters-list.component';
 import { FiltersToolComponent }                 from './list/filters/filters-tool.component';
@@ -155,6 +156,7 @@ import { AddAvisModelModalComponent } from './avis/addAvisModel/add-avis-model-m
         closeMailWithAttachmentsOrNotesActionComponent,
         SendSignatureBookActionComponent,
         ContinueVisaCircuitActionComponent,
+        SendAvisWorkflowComponent,
         ActionsListComponent,
         PrintSeparatorComponent,
         FolderPinnedComponent,
@@ -201,6 +203,7 @@ import { AddAvisModelModalComponent } from './avis/addAvisModel/add-avis-model-m
         RejectVisaBackToPrevousActionComponent,
         ResetVisaActionComponent,
         InterruptVisaActionComponent,
+        SendAvisWorkflowComponent,
         UpdateDepartureDateActionComponent,
         SendExternalSignatoryBookActionComponent,
         SendExternalNoteBookActionComponent,
diff --git a/src/frontend/app/avis/avis-workflow.component.ts b/src/frontend/app/avis/avis-workflow.component.ts
index 362b06e1178b1782878873d620879003ed6dd452..8cb910893ba53f49e86ef5f80731fa5fc6ef75f5 100644
--- a/src/frontend/app/avis/avis-workflow.component.ts
+++ b/src/frontend/app/avis/avis-workflow.component.ts
@@ -125,7 +125,9 @@ export class AvisWorkflowComponent implements OnInit {
     }
 
     async loadAvisModelList() {
-        await this.loadDefaultModel();
+        if (this.resId !== null) {
+            await this.loadDefaultModel();
+        }
 
         return new Promise((resolve, reject) => {
             this.http.get(`../../rest/availableCircuits?circuit=opinion`).pipe(
@@ -231,7 +233,8 @@ export class AvisWorkflowComponent implements OnInit {
         this.resId = resId;
         this.loading = true;
         this.avisWorkflow.items = [];
-        this.http.get("../../rest/resources/" + resId + "/opinionCircuit")
+        return new Promise((resolve, reject) => {
+            this.http.get("../../rest/resources/" + resId + "/opinionCircuit")
             .subscribe((data: any) => {
                 data.forEach((element: any) => {
                     this.avisWorkflow.items.push(
@@ -242,9 +245,35 @@ export class AvisWorkflowComponent implements OnInit {
                 });
                 this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items))
                 this.loading = false;
+                resolve(true);
             }, (err: any) => {
                 this.notify.handleErrors(err);
             });
+        });
+        
+    }
+
+    loadDefaultWorkflow(resId: number) {
+        this.loading = true;
+        this.avisWorkflow.items = [];
+        this.http.get("../../rest/resources/" + resId + "/defaultCircuit?circuit=opinion").pipe(
+            filter((data: any) => !this.functions.empty(data.circuit)),
+            tap((data: any) => {
+                data.circuit.items.forEach((element: any) => {
+                    this.avisWorkflow.items.push(
+                        {
+                            ...element,
+                            difflist_type: 'AVIS_CIRCUIT'
+                        });
+                });
+                this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items))
+            }),
+            finalize(() => this.loading = false),
+            catchError((err: any) => {
+                this.notify.handleSoftErrors(err);
+                return of(false);
+            })
+        ).subscribe();
     }
 
     deleteItem(index: number) {
@@ -263,10 +292,10 @@ export class AvisWorkflowComponent implements OnInit {
         return this.avisWorkflow.items;
     }
 
-    saveAvisWorkflow() {
+    saveAvisWorkflow(resIds: number[] = [this.resId]) {
         return new Promise((resolve, reject) => {
             if (this.avisWorkflow.items.length === 0) {
-                this.http.delete(`../../rest/resources/${this.resId}/circuits/opinionCircuit`).pipe(
+                this.http.delete(`../../rest/resources/${resIds[0]}/circuits/opinionCircuit`).pipe(
                     tap(() => {
                         this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items));
                         this.notify.success(this.lang.avisWorkflowDeleted);
@@ -278,7 +307,13 @@ export class AvisWorkflowComponent implements OnInit {
                     })
                 ).subscribe();
             } else {     
-                this.http.put(`../../rest/circuits/opinionCircuit`, {resources: [{ resId: this.resId, listInstances: this.avisWorkflow.items }]} ).pipe(
+                const arrAvis = resIds.map(resId => {
+                    return {
+                        resId: resId,
+                        listInstances: this.avisWorkflow.items
+                    }
+                });
+                this.http.put(`../../rest/circuits/opinionCircuit`, { resources: arrAvis }).pipe(
                     tap((data: any) => {
                         this.avisWorkflowClone = JSON.parse(JSON.stringify(this.avisWorkflow.items));
                         this.notify.success(this.lang.avisWorkflowUpdated);
@@ -328,6 +363,22 @@ export class AvisWorkflowComponent implements OnInit {
         }
     }
 
+    emptyWorkflow() {
+        if (this.avisWorkflow.items.length === 0) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    workflowEnd() {
+        if (this.avisWorkflow.items.filter((item: any) => !this.functions.empty(item.process_date)).length === this.avisWorkflow.items.length) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
     openPromptSaveModel() {
         const dialogRef = this.dialog.open(AddAvisModelModalComponent, { data: { avisWorkflow: this.avisWorkflow.items } });
 
diff --git a/src/frontend/app/visa/visa-workflow.component.ts b/src/frontend/app/visa/visa-workflow.component.ts
index a12975f2b3b6c376d930a975a269b55dc0d5ea08..6998ac09d1ec4026469e39af2081f241e632d9d2 100644
--- a/src/frontend/app/visa/visa-workflow.component.ts
+++ b/src/frontend/app/visa/visa-workflow.component.ts
@@ -136,7 +136,9 @@ export class VisaWorkflowComponent implements OnInit {
     }
 
     async loadVisaModelList() {
-        await this.loadDefaultModel();
+        if (this.resId !== null) {
+            await this.loadDefaultModel();
+        }
 
         return new Promise((resolve, reject) => {
             this.http.get(`../../rest/availableCircuits?circuit=visa`).pipe(