From e162aebded52803083fa88fca65d9139f9937f9c Mon Sep 17 00:00:00 2001
From: Alex ORLUC <alex.orluc@maarch.org>
Date: Mon, 10 Sep 2018 09:54:25 +0200
Subject: [PATCH] feat continue components basket list

---
 .../Views/basket-list.component.html          |  20 +-
 apps/maarch_entreprise/css/engine.css         |   4 +
 .../js/angular/app/app-material.module.ts     |   5 +-
 .../js/angular/app/app.module.ts              |  12 +-
 .../app/basket/basket-list.component.ts       | 238 ++++++++++++++----
 .../js/angular/lang/lang-en.ts                |   2 +
 .../js/angular/lang/lang-fr.ts                |   2 +
 .../controllers/AttachmentController.php      |  12 +
 .../models/AttachmentModelAbstract.php        |  17 ++
 .../controllers/ListInstanceController.php    |  42 ++++
 .../models/ListInstanceModelAbstract.php      |  66 +++++
 src/app/note/models/NoteModelAbstract.php     |  16 +-
 12 files changed, 362 insertions(+), 74 deletions(-)

diff --git a/apps/maarch_entreprise/Views/basket-list.component.html b/apps/maarch_entreprise/Views/basket-list.component.html
index 60bb1ac7431..3365770f68e 100644
--- a/apps/maarch_entreprise/Views/basket-list.component.html
+++ b/apps/maarch_entreprise/Views/basket-list.component.html
@@ -74,8 +74,8 @@
                                 &nbsp;
                             </div>
                             <div *ngIf="!mobileMode && (row.folder_name || row.case_label)">
-                                <span *ngIf="row.folder_name" class="label label-default" style="background-color:rgba(0,0,0,0.4);margin-left: 5px;margin-right: 5px;" title="Dossier"><i class="fa fa-folder"></i> {{row.folder_name}}</span>
-                                <span *ngIf="row.case_label" class="label label-default" style="background-color:rgba(0,0,0,0.4);margin-left: 5px;margin-right: 5px;" title="Affaire"><i class="fa fa-suitcase"></i> {{row.case_label}}</span>
+                                <span *ngIf="row.folder_name" class="label label-default" style="background-color:rgba(0,0,0,0.2);margin-left: 5px;margin-right: 5px;" title="Dossier"><i class="fa fa-folder"></i> {{row.folder_name}}</span>
+                                <span *ngIf="row.case_label" class="label label-default" style="background-color:rgba(0,0,0,0.2);margin-left: 5px;margin-right: 5px;" title="Affaire"><i class="fa fa-suitcase"></i> {{row.case_label}}</span>
                             </div>
                             <!--<div>
                                 <button mat-stroked-button color="primary" style="margin:5px;line-height: 20px;width: 150px;overflow: hidden;text-overflow: ellipsis;">réponse du zpfezk zekf opezf</button>
@@ -120,26 +120,32 @@
                                 <i class="fa fa-lock" title="date de clôture"></i>&nbsp;
                                 <span title='{{row.closing_date | date : "le dd/MM/y à HH:mm"}}'>{{row.closing_date | timeAgo}}</span>
                             </div>
-                            <div>
-                                <button mat-icon-button>
+                            <div style="white-space:normal;">
+                                <button mat-icon-button (click)="openAttachSheet(row)">
+                                    <mat-icon color="primary" class="fa fa-paperclip"></mat-icon>
+                                </button>
+                                <button mat-icon-button (click)="openBottomSheet(row)">
                                     <mat-icon color="primary" class="fa fa-sticky-note"></mat-icon>
                                 </button>
                                 <button mat-icon-button (click)="goTo(row);">
                                     <mat-icon color="primary" class="fa fa-eye"></mat-icon>
                                 </button>
-                                <button mat-icon-button>
+                                <button mat-icon-button (click)="openDiffusionSheet(row)">
                                     <mat-icon color="primary" class="fa fa-share-alt"></mat-icon>
                                 </button>
+                                <button mat-icon-button (click)="goToDetail(row);">
+                                    <mat-icon color="primary" class="fa fa-info-circle"></mat-icon>
+                                </button>
                             </div>
                         </td>
                     </ng-container>
 
-                    <tr mat-row *matRowDef="let row; columns: displayedColumnsBasket;"></tr>
+                    <tr mat-row *matRowDef="let row; columns: displayedColumnsBasket;" (click)="test();"></tr>
                 </table>
                 <div class="mat-paginator" style="min-height:48px;min-height: 48px;display: flex;justify-content: end;align-items: center;padding-right: 20px;">{{resultsLength}} {{lang.entries}}</div>
             </mat-card>
         </mat-sidenav-content>
-        <mat-sidenav #snav2 [mode]="mobileQuery.matches ? 'over' : 'side'" [fixedInViewport]="mobileQuery.matches" fixedTopGap="56"
+        <mat-sidenav #snav2 mode="over" [fixedInViewport]="mobileQuery.matches" fixedTopGap="56"
             position='end' [opened]="mobileQuery.matches ? false : false" style="overflow-x:hidden;" [ngStyle]="{'width': mobileMode ? '80%' : '40%'}">
             <div *ngIf="innerHtml" [innerHTML]="innerHtml" style="height: 100%;overflow: hidden;"></div>
         </mat-sidenav>
diff --git a/apps/maarch_entreprise/css/engine.css b/apps/maarch_entreprise/css/engine.css
index 610d8421528..fe2595e537b 100755
--- a/apps/maarch_entreprise/css/engine.css
+++ b/apps/maarch_entreprise/css/engine.css
@@ -372,4 +372,8 @@ h1.admin-app-name {
 
 #searchInput .mat-form-field-label {
     opacity: 0.5;
+}
+
+.note-width-bottom-sheet{
+    width: 400px;
 }
\ No newline at end of file
diff --git a/apps/maarch_entreprise/js/angular/app/app-material.module.ts b/apps/maarch_entreprise/js/angular/app/app-material.module.ts
index 24842c4b9d1..e7bc37e4366 100644
--- a/apps/maarch_entreprise/js/angular/app/app-material.module.ts
+++ b/apps/maarch_entreprise/js/angular/app/app-material.module.ts
@@ -81,7 +81,8 @@ import {
     MatStepperModule,
     MatRadioModule,
     MatSliderModule,
-    MatBadgeModule
+    MatBadgeModule,
+    MatBottomSheetModule
 } from '@angular/material';
 
 import { CdkTableModule } from '@angular/cdk/table';
@@ -120,6 +121,7 @@ import { getFrenchPaginatorIntl } from './french-paginator-intl';
         MatRadioModule,
         MatSliderModule,
         MatBadgeModule,
+        MatBottomSheetModule,
         DndModule.forRoot()
     ],
     exports: [
@@ -154,6 +156,7 @@ import { getFrenchPaginatorIntl } from './french-paginator-intl';
         MatRadioModule,
         MatSliderModule,
         MatBadgeModule,
+        MatBottomSheetModule,
         DndModule
     ],
     providers: [
diff --git a/apps/maarch_entreprise/js/angular/app/app.module.ts b/apps/maarch_entreprise/js/angular/app/app.module.ts
index 4f730d68b53..77796e91460 100755
--- a/apps/maarch_entreprise/js/angular/app/app.module.ts
+++ b/apps/maarch_entreprise/js/angular/app/app.module.ts
@@ -12,7 +12,7 @@ import { AdministrationModule }                 from './administration/administr
 import { ProfileComponent }                     from './profile.component';
 import { AboutUsComponent }                     from './about-us.component';
 import { HomeComponent }                        from './home.component';
-import { BasketListComponent }                  from './basket/basket-list.component';
+import { BasketListComponent, BottomSheetNoteList, BottomSheetAttachmentList, BottomSheetDiffusionList }  from './basket/basket-list.component';
 import { PasswordModificationComponent, InfoChangePasswordModalComponent, }        from './password-modification.component';
 import { SignatureBookComponent, SafeUrlPipe }  from './signature-book.component';
 import { SaveNumericPackageComponent }          from './save-numeric-package.component';
@@ -37,12 +37,18 @@ import { ActivateUserComponent }                from './activate-user.component'
         CustomSnackbarComponent,
         ConfirmModalComponent,
         InfoChangePasswordModalComponent,
-        ActivateUserComponent
+        ActivateUserComponent,
+        BottomSheetNoteList,
+        BottomSheetAttachmentList,
+        BottomSheetDiffusionList
     ],
     entryComponents: [
         CustomSnackbarComponent,
         ConfirmModalComponent,
-        InfoChangePasswordModalComponent
+        InfoChangePasswordModalComponent,
+        BottomSheetNoteList,
+        BottomSheetAttachmentList,
+        BottomSheetDiffusionList
     ],
     bootstrap: [AppComponent]
 })
diff --git a/apps/maarch_entreprise/js/angular/app/basket/basket-list.component.ts b/apps/maarch_entreprise/js/angular/app/basket/basket-list.component.ts
index 564af5ddda7..eae4d1fe6c4 100644
--- a/apps/maarch_entreprise/js/angular/app/basket/basket-list.component.ts
+++ b/apps/maarch_entreprise/js/angular/app/basket/basket-list.component.ts
@@ -1,10 +1,10 @@
-import { ChangeDetectorRef, Component, OnInit, ViewChild, QueryList, ViewChildren } from '@angular/core';
+import { ChangeDetectorRef, Component, OnInit, ViewChild, QueryList, ViewChildren, Inject } from '@angular/core';
 import { MediaMatcher } from '@angular/cdk/layout';
 import { HttpClient } from '@angular/common/http';
 import { LANG } from '../translate.component';
-import { merge, Observable, of as observableOf} from 'rxjs';
+import { merge, Observable, of as observableOf } from 'rxjs';
 import { NotificationService } from '../notification.service';
-import { MatDialog, MatSidenav, MatExpansionPanel, MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
+import { MatDialog, MatSidenav, MatExpansionPanel, MatTableDataSource, MatPaginator, MatSort, MatBottomSheet, MatBottomSheetRef, MAT_BOTTOM_SHEET_DATA } from '@angular/material';
 
 import { DomSanitizer, SafeHtml } from '@angular/platform-browser';
 import { startWith, switchMap, map, catchError } from 'rxjs/operators';
@@ -22,12 +22,12 @@ export class BasketListComponent implements OnInit {
 
     private _mobileQueryListener: () => void;
     mobileQuery: MediaQueryList;
-    mobileMode: boolean   = false;
+    mobileMode: boolean = false;
     coreUrl: string;
     lang: any = LANG;
 
     loading: boolean = false;
-    docUrl : string = '';
+    docUrl: string = '';
     public innerHtml: SafeHtml;
     basketUrl: string;
     homeData: any;
@@ -35,7 +35,7 @@ export class BasketListComponent implements OnInit {
 
     @ViewChild('snav') sidenavLeft: MatSidenav;
     @ViewChild('snav2') sidenavRight: MatSidenav;
-    
+
 
     displayedColumnsBasket: string[] = ['res_id', 'subject', 'contact_society', 'creation_date'];
 
@@ -45,7 +45,7 @@ export class BasketListComponent implements OnInit {
     isLoadingResults = true;
     @ViewChild(MatPaginator) paginator: MatPaginator;
     @ViewChild('tableBasketListSort') sort: MatSort;
-    constructor(changeDetectorRef: ChangeDetectorRef, private route: ActivatedRoute, media: MediaMatcher, public http: HttpClient, public dialog: MatDialog, private sanitizer: DomSanitizer) {
+    constructor(changeDetectorRef: ChangeDetectorRef, private route: ActivatedRoute, media: MediaMatcher, public http: HttpClient, public dialog: MatDialog, private sanitizer: DomSanitizer, private bottomSheet: MatBottomSheet) {
         this.mobileMode = angularGlobals.mobileMode;
         $j("link[href='merged_css.php']").remove();
         this.mobileQuery = media.matchMedia('(max-width: 768px)');
@@ -63,70 +63,94 @@ export class BasketListComponent implements OnInit {
         }
 
         this.http.get(this.coreUrl + "rest/home")
-        .subscribe((data: any) => {
-            this.homeData = data;
-        });
+            .subscribe((data: any) => {
+                this.homeData = data;
+            });
 
 
         this.route.params.subscribe(params => {
-            this.basketUrl = this.coreUrl + 'rest/resources/groups/'+params['groupSerialId']+'/baskets/'+params['basketId'];
+            this.basketUrl = this.coreUrl + 'rest/resources/groups/' + params['groupSerialId'] + '/baskets/' + params['basketId'];
             this.http.get(this.coreUrl + "rest/baskets/" + params['basketId'])
-            .subscribe((data: any) => {
-                window['MainHeaderComponent'].refreshTitle(data.basket.basket_name);
-                window['MainHeaderComponent'].setSnav(this.sidenavLeft);
-                window['MainHeaderComponent'].setSnavRight(null);
-                this.exampleDatabase = new ExampleHttpDao(this.http);
-
-        // If the user changes the sort order, reset back to the first page.
-        this.paginator.pageIndex = 0;
-        this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
-
-        merge(this.sort.sortChange, this.paginator.page)
-            .pipe(
-                startWith({}),
-                switchMap(() => {
-                    this.isLoadingResults = true;
-                    return this.exampleDatabase!.getRepoIssues(
-                        this.sort.active, this.sort.direction, this.paginator.pageIndex, this.basketUrl);
-                }),
-                map(data => {
-                    // Flip flag to show that loading has finished.
-                    this.isLoadingResults = false;
-                    this.resultsLength = data.number;
-
-                    return data.resources;
-                }),
-                catchError(() => {
-                    this.isLoadingResults = false;
-                    return observableOf([]);
-                })
-            ).subscribe(data => this.data = data);
-
-            }, () => {
-                location.href = "index.php";
-            });   
+                .subscribe((data: any) => {
+                    window['MainHeaderComponent'].refreshTitle(data.basket.basket_name);
+                    window['MainHeaderComponent'].setSnav(this.sidenavLeft);
+                    window['MainHeaderComponent'].setSnavRight(null);
+                    this.exampleDatabase = new ExampleHttpDao(this.http);
+
+                    // If the user changes the sort order, reset back to the first page.
+                    this.paginator.pageIndex = 0;
+                    this.sort.sortChange.subscribe(() => this.paginator.pageIndex = 0);
+
+                    merge(this.sort.sortChange, this.paginator.page)
+                        .pipe(
+                            startWith({}),
+                            switchMap(() => {
+                                this.isLoadingResults = true;
+                                return this.exampleDatabase!.getRepoIssues(
+                                    this.sort.active, this.sort.direction, this.paginator.pageIndex, this.basketUrl);
+                            }),
+                            map(data => {
+                                // Flip flag to show that loading has finished.
+                                this.isLoadingResults = false;
+                                this.resultsLength = data.number;
+
+                                return data.resources;
+                            }),
+                            catchError(() => {
+                                this.isLoadingResults = false;
+                                return observableOf([]);
+                            })
+                        ).subscribe(data => this.data = data);
+
+                }, () => {
+                    location.href = "index.php";
+                });
         });
 
 
     }
 
-    goTo(row:any){
-        if (this.docUrl == this.coreUrl+'rest/res/'+row.res_id+'/content' && this.sidenavRight.opened) {
+    goTo(row: any) {
+        if (this.docUrl == this.coreUrl + 'rest/res/' + row.res_id + '/content' && this.sidenavRight.opened) {
             this.sidenavRight.close();
         } else {
-            this.docUrl = this.coreUrl+'rest/res/'+row.res_id+'/content';
+            this.docUrl = this.coreUrl + 'rest/res/' + row.res_id + '/content';
             this.innerHtml = this.sanitizer.bypassSecurityTrustHtml(
-                "<object style='height:100%;width:100%;' data='" + this.docUrl + "' type='application/pdf' class='embed-responsive-item'>" +
-                "<div>Le document "+row.res_id+" ne peut pas être chargé</div>" +
-                "</object>");  
+                "<iframe style='height:100%;width:100%;' src='" + this.docUrl + "' class='embed-responsive-item'>" +
+                "</iframe>");
             this.sidenavRight.open();
         }
     }
 
-    goToDetail(row:any){
-        location.href = "index.php?page=details&dir=indexing_searching&id="+row.res_id;
+    goToDetail(row: any) {
+        location.href = "index.php?page=details&dir=indexing_searching&id=" + row.res_id;
+    }
+
+    openBottomSheet(row: any): void {
+        this.bottomSheet.open(BottomSheetNoteList, {
+            data: { resId: row.res_id, chrono: row.alt_identifier },
+            panelClass: 'note-width-bottom-sheet'
+        });
+    }
+
+    openAttachSheet(row: any): void {
+        this.bottomSheet.open(BottomSheetAttachmentList, {
+            data: { resId: row.res_id, chrono: row.alt_identifier },
+        });
     }
 
+    openDiffusionSheet(row: any): void {
+        this.bottomSheet.open(BottomSheetDiffusionList, {
+            data: { resId: row.res_id, chrono: row.alt_identifier },
+        });
+    }
+
+    test () {
+        this.http.post("index.php?display=true&page=manage_action&module=core",{})
+            .subscribe((data: any) => {
+                console.log(data);
+            });
+    }
 }
 export interface BasketList {
     resources: any[];
@@ -138,10 +162,114 @@ export class ExampleHttpDao {
 
     constructor(private http: HttpClient) { }
 
-    getRepoIssues(sort: string, order: string, page: number, href :string): Observable<BasketList> {
+    getRepoIssues(sort: string, order: string, page: number, href: string): Observable<BasketList> {
         let offset = page * 10;
         const requestUrl = `${href}?limit=10&offset=${offset}`;
 
         return this.http.get<BasketList>(requestUrl);
     }
-}
\ No newline at end of file
+}
+
+@Component({
+    templateUrl: '../../../../Views/note-list.component.html',
+})
+export class BottomSheetNoteList {
+    coreUrl: string;
+    lang: any = LANG;
+    notes: any;
+    loading: boolean = true;
+
+    constructor(public http: HttpClient, private bottomSheetRef: MatBottomSheetRef<BottomSheetNoteList>, @Inject(MAT_BOTTOM_SHEET_DATA) public data: any) { }
+
+    ngOnInit(): void {
+
+
+    }
+    ngAfterViewInit() {
+        this.coreUrl = angularGlobals.coreUrl;
+        this.http.get(this.coreUrl + "rest/res/" + this.data.resId + "/notes")
+            .subscribe((data: any) => {
+                this.notes = data;
+                this.loading = false;
+            });
+    }
+}
+
+
+@Component({
+    templateUrl: '../../../../Views/attachment-list.component.html',
+})
+export class BottomSheetAttachmentList {
+    coreUrl: string;
+    lang: any = LANG;
+    attachments: any;
+    attachmentTypes: any;
+    loading: boolean = true;
+
+    constructor(public http: HttpClient, private bottomSheetRef: MatBottomSheetRef<BottomSheetAttachmentList>, @Inject(MAT_BOTTOM_SHEET_DATA) public data: any) { }
+
+    ngOnInit(): void {
+
+
+    }
+    ngAfterViewInit() {
+        this.coreUrl = angularGlobals.coreUrl;
+        this.http.get(this.coreUrl + "rest/res/" + this.data.resId + "/attachments")
+            .subscribe((data: any) => {
+                this.attachments = data.attachments;
+                this.attachmentTypes = data.attachment_types;
+                this.loading = false;
+            });
+    }
+}
+
+@Component({
+    templateUrl: '../../../../Views/diffusion-list.component.html',
+})
+export class BottomSheetDiffusionList {
+    coreUrl: string;
+    lang: any = LANG;
+    listinstance: any = [];
+    visaCircuit: any;
+    avisCircuit: any;
+    roles: any = [];
+    loading: boolean = true;
+    tabVisaCircuit: boolean = false;
+    tabAvisCircuit: boolean = false;
+
+    constructor(public http: HttpClient, private bottomSheetRef: MatBottomSheetRef<BottomSheetDiffusionList>, @Inject(MAT_BOTTOM_SHEET_DATA) public data: any) { }
+
+    ngOnInit(): void {
+
+
+    }
+    ngAfterViewInit() {
+        this.coreUrl = angularGlobals.coreUrl;
+        this.http.get(this.coreUrl + "rest/res/" + this.data.resId + "/listinstance")
+            .subscribe((data: any) => {
+                if (data != null) {
+                    this.roles = Object.keys(data);
+                    this.listinstance = data;
+                }
+
+                this.http.get(this.coreUrl + "rest/res/" + this.data.resId + "/visaCircuit")
+                    .subscribe((data: any) => {
+                        this.visaCircuit = data;
+                        if (this.visaCircuit.length > 0) {
+                            this.tabVisaCircuit = true;
+                        }
+
+                        this.http.get(this.coreUrl + "rest/res/" + this.data.resId + "/avisCircuit")
+                            .subscribe((data: any) => {
+                                this.avisCircuit = data;
+                                if (this.avisCircuit.length > 0) {
+                                    this.tabAvisCircuit = true;
+                                }
+                                this.loading = false;
+                            });
+                    });
+            });
+    }
+}
+
+
diff --git a/apps/maarch_entreprise/js/angular/lang/lang-en.ts b/apps/maarch_entreprise/js/angular/lang/lang-en.ts
index 00e6a58f87f..63e0cf871b3 100755
--- a/apps/maarch_entreprise/js/angular/lang/lang-en.ts
+++ b/apps/maarch_entreprise/js/angular/lang/lang-en.ts
@@ -617,5 +617,7 @@ export const LANG_EN = {
     "outgoing"                          : "Outgoing",
     "internal"                          : "Internal",
     "menu"                              : "Menu",
+    "visaUser"                          : "Visa",
+    "signUser"                          : "Signatory",
 
 };
diff --git a/apps/maarch_entreprise/js/angular/lang/lang-fr.ts b/apps/maarch_entreprise/js/angular/lang/lang-fr.ts
index bcbfcd7e1be..e97829e7fff 100755
--- a/apps/maarch_entreprise/js/angular/lang/lang-fr.ts
+++ b/apps/maarch_entreprise/js/angular/lang/lang-fr.ts
@@ -643,4 +643,6 @@ export const LANG_FR = {
     "outgoing"                          : "Courrier départ",
     "internal"                          : "Courrier interne",
     "menu"                              : "Menu",
+    "visaUser"                          : "Viseur",
+    "signUser"                          : "Signataire",
 };
diff --git a/src/app/attachment/controllers/AttachmentController.php b/src/app/attachment/controllers/AttachmentController.php
index 6703dc800f2..e613548da37 100644
--- a/src/app/attachment/controllers/AttachmentController.php
+++ b/src/app/attachment/controllers/AttachmentController.php
@@ -27,6 +27,18 @@ use Convert\controllers\ConvertPdfController;
 
 class AttachmentController
 {
+    public function getAttachmentsListById(Request $request, Response $response, array $aArgs)
+    {
+        if (!Validator::intVal()->validate($aArgs['resId']) || !ResController::hasRightByResId(['resId' => $aArgs['resId'], 'userId' => $GLOBALS['userId']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
+        }
+
+        $attachments = AttachmentModel::getListByResIdMaster(['id' => $aArgs['resId']]);
+        $attachmentTypes = AttachmentModel::getAttachmentsTypesByXML();
+
+        return $response->withJson(['attachments'  => $attachments, 'attachment_types'  => $attachmentTypes]);
+    }
+
     public function setInSignatureBook(Request $request, Response $response, array $aArgs)
     {
         //TODO Controle de droit de modification de cet attachment
diff --git a/src/app/attachment/models/AttachmentModelAbstract.php b/src/app/attachment/models/AttachmentModelAbstract.php
index ff02efb1592..d273f273dfc 100644
--- a/src/app/attachment/models/AttachmentModelAbstract.php
+++ b/src/app/attachment/models/AttachmentModelAbstract.php
@@ -64,6 +64,23 @@ abstract class AttachmentModelAbstract
         return $aAttachment[0];
     }
 
+    public static function getListByResIdMaster(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['id']);
+        ValidatorModel::intVal($aArgs, ['id']);
+
+        $aAttachments = DatabaseModel::select([
+            'select'    => empty($aArgs['select']) ? ['res_id', 'res_attachments.identifier', 'title', 'format', 'creation_date', 'doc_date as update_date', 'validation_date as return_date', 'effective_date as real_return_date', 'u.firstname as firstname_updated', 'u.lastname as lastname_updated', 'relation', 'docserver_id', 'path', 'filename', 'fingerprint', 'filesize', 'label_status as status', 'attachment_type', 'dest_contact_id', 'dest_address_id', 'ut.firstname as firstname_typist', 'ut.lastname as lastname_typist'] : $aArgs['select'],
+            'table'     => ['res_attachments','users ut', 'status', 'users u'],
+            'left_join' => ['res_attachments.typist = ut.user_id', 'res_attachments.status = status.id', 'res_attachments.updated_by = u.user_id'],
+            'where'     => ['res_id_master = ?', 'res_attachments.status not in (?,?)', 'attachment_type not in (?,?)'],
+            'data'      => [$aArgs['id'], 'OBS', 'DEL', 'converted_pdf', 'printed_folder'],
+            'order_by'  => empty($aArgs['orderBy']) ? ['res_id DESC'] : $aArgs['orderBy'],
+        ]);
+
+        return $aAttachments;
+    }
+
     public static function create(array $aArgs)
     {
         ValidatorModel::notEmpty($aArgs, ['format', 'typist', 'creation_date', 'docserver_id', 'path', 'filename', 'fingerprint', 'filesize', 'status']);
diff --git a/src/app/entity/controllers/ListInstanceController.php b/src/app/entity/controllers/ListInstanceController.php
index fac58864c95..71701e9638d 100644
--- a/src/app/entity/controllers/ListInstanceController.php
+++ b/src/app/entity/controllers/ListInstanceController.php
@@ -17,6 +17,9 @@ namespace Entity\controllers;
 use Entity\models\ListInstanceModel;
 use Slim\Http\Request;
 use Slim\Http\Response;
+use Respect\Validation\Validator;
+use Resource\controllers\ResController;
+use Entity\models\EntityModel;
 
 class ListInstanceController
 {
@@ -26,4 +29,43 @@ class ListInstanceController
 
         return $response->withJson($listinstance);
     }
+
+    public function getListByResId(Request $request, Response $response, array $aArgs)
+    {
+        if (!Validator::intVal()->validate($aArgs['resId']) || !ResController::hasRightByResId(['resId' => $aArgs['resId'], 'userId' => $GLOBALS['userId']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
+        }
+        $listinstances = ListInstanceModel::getListByResId(['select' => ['listinstance_id', 'sequence', 'CASE WHEN item_mode=\'cc\' THEN \'copy\' ELSE item_mode END', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment', 'signatory', 'requested_signature'], 'id' => $aArgs['resId']]);
+        
+        $roles = EntityModel::getRoles();
+        
+        foreach ($listinstances as $key2 => $listinstance) {
+            foreach ($roles as $key => $role) {
+                if ($role['id'] == $listinstance['item_mode']) {
+                    $listinstancesFormat[$role['label']][] = $listinstance;
+                }
+            }
+        }
+        return $response->withJson($listinstancesFormat);
+    }
+
+    public function getVisaCircuitByResId(Request $request, Response $response, array $aArgs)
+    {
+        if (!Validator::intVal()->validate($aArgs['resId']) || !ResController::hasRightByResId(['resId' => $aArgs['resId'], 'userId' => $GLOBALS['userId']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
+        }
+        $listinstances = ListInstanceModel::getVisaCircuitByResId(['select' => ['listinstance_id', 'sequence', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment', 'signatory', 'requested_signature'], 'id' => $aArgs['resId']]);
+        
+        return $response->withJson($listinstances);
+    }
+
+    public function getAvisCircuitByResId(Request $request, Response $response, array $aArgs)
+    {
+        if (!Validator::intVal()->validate($aArgs['resId']) || !ResController::hasRightByResId(['resId' => $aArgs['resId'], 'userId' => $GLOBALS['userId']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Document out of perimeter']);
+        }
+        $listinstances = ListInstanceModel::getAvisCircuitByResId(['select' => ['listinstance_id', 'sequence', 'item_id', 'item_type', 'firstname as item_firstname', 'lastname as item_lastname', 'entity_label as item_entity', 'viewed', 'process_date', 'process_comment'], 'id' => $aArgs['resId']]);
+        
+        return $response->withJson($listinstances);
+    }
 }
diff --git a/src/app/entity/models/ListInstanceModelAbstract.php b/src/app/entity/models/ListInstanceModelAbstract.php
index c85c7a5dce4..b02aa570060 100644
--- a/src/app/entity/models/ListInstanceModelAbstract.php
+++ b/src/app/entity/models/ListInstanceModelAbstract.php
@@ -57,6 +57,72 @@ abstract class ListInstanceModelAbstract
         return $aListinstance[0];
     }
 
+    public static function getListByResId(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['id']);
+        ValidatorModel::intVal($aArgs, ['id']);
+        ValidatorModel::arrayType($aArgs, ['select']);
+
+        $aListinstance = DatabaseModel::select([
+            'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
+            'table'     => ['listinstance', 'users', 'users_entities', 'entities'],
+            'left_join' => ['listinstance.item_id = users.user_id', 'users_entities.user_id = users.user_id', 'entities.entity_id = users_entities.entity_id'],
+            'where'     => ['res_id = ?', 'item_type = ?', 'difflist_type = ?', 'primary_entity = ?'],
+            'data'      => [$aArgs['id'], 'user_id', 'entity_id', 'Y'],
+            'order_by'  => ['listinstance_id ASC'],
+        ]);
+
+        unset($aArgs['select'][5]);
+        unset($aArgs['select'][6]);
+
+        $aListinstance2 = DatabaseModel::select([
+            'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
+            'table'     => ['listinstance', 'entities'],
+            'left_join' => ['listinstance.item_id = entities.entity_id'],
+            'where'     => ['res_id = ?', 'item_type = ?', 'difflist_type = ?'],
+            'data'      => [$aArgs['id'], 'entity_id', 'entity_id'],
+            'order_by'  => ['listinstance_id ASC'],
+        ]);
+
+        return array_merge($aListinstance, $aListinstance2);
+    }
+
+    public static function getVisaCircuitByResId(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['id']);
+        ValidatorModel::intVal($aArgs, ['id']);
+        ValidatorModel::arrayType($aArgs, ['select']);
+
+        $aListinstance = DatabaseModel::select([
+            'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
+            'table'     => ['listinstance', 'users', 'users_entities', 'entities'],
+            'left_join' => ['listinstance.item_id = users.user_id', 'users_entities.user_id = users.user_id', 'entities.entity_id = users_entities.entity_id'],
+            'where'     => ['res_id = ?', 'item_type = ?', 'difflist_type = ?', 'primary_entity = ?'],
+            'data'      => [$aArgs['id'], 'user_id', 'VISA_CIRCUIT', 'Y'],
+            'order_by'  => ['listinstance_id ASC'],
+        ]);
+
+        return $aListinstance;
+    }
+
+    public static function getAvisCircuitByResId(array $aArgs)
+    {
+        ValidatorModel::notEmpty($aArgs, ['id']);
+        ValidatorModel::intVal($aArgs, ['id']);
+        ValidatorModel::arrayType($aArgs, ['select']);
+
+        $aListinstance = DatabaseModel::select([
+            'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
+            'table'     => ['listinstance', 'users', 'users_entities', 'entities'],
+            'left_join' => ['listinstance.item_id = users.user_id', 'users_entities.user_id = users.user_id', 'entities.entity_id = users_entities.entity_id'],
+            'where'     => ['res_id = ?', 'item_type = ?', 'difflist_type = ?', 'primary_entity = ?'],
+            'data'      => [$aArgs['id'], 'user_id', 'AVIS_CIRCUIT', 'Y'],
+            'order_by'  => ['listinstance_id ASC'],
+        ]);
+
+        return $aListinstance;
+    }
+
     public static function create(array $aArgs)
     {
         ValidatorModel::notEmpty($aArgs, ['res_id']);
diff --git a/src/app/note/models/NoteModelAbstract.php b/src/app/note/models/NoteModelAbstract.php
index 2d3b9b838fb..ebb726630e6 100644
--- a/src/app/note/models/NoteModelAbstract.php
+++ b/src/app/note/models/NoteModelAbstract.php
@@ -94,13 +94,12 @@ abstract class NoteModelAbstract
         //get notes
         $aReturn = DatabaseModel::select([
             'select'    => empty($aArgs['select']) ? ['*'] : $aArgs['select'],
-            'table'     => ['notes', 'users', 'users_entities'],
-            'left_join' => ['notes.user_id = users.user_id', 'users.user_id = users_entities.user_id'],
+            'table'     => ['notes', 'users', 'users_entities', 'entities'],
+            'left_join' => ['notes.user_id = users.user_id', 'users.user_id = users_entities.user_id', 'users_entities.entity_id = entities.entity_id'],
             'where'     => ['notes.identifier = ?', 'users_entities.primary_entity=\'Y\''],
             'data'      => [$aArgs['resId']],
             'order_by'  => empty($aArgs['orderBy']) ? ['date_note'] : $aArgs['orderBy']
         ]);
-
         $tmpNoteId = [];
         foreach ($aReturn as $value) {
             $tmpNoteId[] = $value['id'];
@@ -110,21 +109,22 @@ abstract class NoteModelAbstract
         if (!empty($tmpNoteId)) {
             $tmpEntitiesRestriction = [];
             $entities = DatabaseModel::select([
-                'select'   => ['note_id', 'item_id'],
-                'table'    => ['note_entities'],
+                'select'   => ['note_id', 'item_id', 'short_label'],
+                'table'    => ['note_entities', 'entities'],
+                'left_join' => ['note_entities.item_id = entities.entity_id'],
                 'where'    => ['note_id in (?)'],
                 'data'     => [$tmpNoteId],
-                'order_by' => ['item_id']
+                'order_by' => ['short_label']
             ]);
 
             foreach ($entities as $key => $value) {
-                $tmpEntitiesRestriction[$value['note_id']][] = $value['item_id'];
+                $tmpEntitiesRestriction[$value['note_id']][] = $value['short_label'];
             }
         }
 
         foreach ($aReturn as $key => $value) {
             if (!empty($tmpEntitiesRestriction[$value['id']])) {
-                $aReturn[$key]['entities_restriction'] = implode(", ", $tmpEntitiesRestriction[$value['id']]);
+                $aReturn[$key]['entities_restriction'] = $tmpEntitiesRestriction[$value['id']];
             }
         }
 
-- 
GitLab