From 80eb0f0a9f00b7f0b1150707fa3aa8998d9a6eb8 Mon Sep 17 00:00:00 2001
From: Guillaume Heurtier <guillaume.heurtier@maarch.org>
Date: Wed, 2 Sep 2020 19:24:06 +0200
Subject: [PATCH] FEAT #14004 TIME 2:30 fix ar reception after cr

---
 migration/20.10/2010.sql                      |  6 ++
 .../controllers/RegisteredMailController.php  | 10 ++-
 .../acknowledgement-reception.component.html  | 51 ++++++++++---
 .../acknowledgement-reception.component.ts    | 71 +++++++++++++------
 src/lang/lang-en.json                         |  4 +-
 src/lang/lang-fr.json                         |  4 +-
 6 files changed, 112 insertions(+), 34 deletions(-)

diff --git a/migration/20.10/2010.sql b/migration/20.10/2010.sql
index dfaca3d864e..39ef9d2c959 100755
--- a/migration/20.10/2010.sql
+++ b/migration/20.10/2010.sql
@@ -251,10 +251,16 @@ CREATE TABLE IF NOT EXISTS registered_mail_resources (
 
 DELETE FROM parameters WHERE id = 'last_deposit_id';
 INSERT INTO parameters (id, param_value_int) VALUES ('last_deposit_id', 0);
+DELETE FROM parameters WHERE id = 'registeredMailNotDistributedStatus';
+INSERT INTO parameters (id, param_value_string) VALUES ('registeredMailNotDistributedStatus', 'PND');
+DELETE FROM parameters WHERE id = 'registeredMailDistributedStatus';
+INSERT INTO parameters (id, param_value_string) VALUES ('registeredMailDistributedStatus', 'DSTRIBUTED');
 
 DELETE FROM parameters WHERE id = 'traffic_record_summary_sheet';
 INSERT INTO parameters (id, description, param_value_string) VALUES ('traffic_record_summary_sheet', 'Module circulation pour la fiche de liaison', '');
 
+-- TODO statuses ar reception
+
 /* RE CREATE VIEWS */
 CREATE OR REPLACE VIEW res_view_letterbox AS
 SELECT r.res_id,
diff --git a/src/app/registeredMail/controllers/RegisteredMailController.php b/src/app/registeredMail/controllers/RegisteredMailController.php
index 3446eb4a240..4c3b3ba9386 100644
--- a/src/app/registeredMail/controllers/RegisteredMailController.php
+++ b/src/app/registeredMail/controllers/RegisteredMailController.php
@@ -14,6 +14,7 @@
 namespace RegisteredMail\controllers;
 
 use Com\Tecnick\Barcode\Barcode;
+use Group\controllers\PrivilegeController;
 use Parameter\models\ParameterModel;
 use Contact\controllers\ContactController;
 use Contact\models\ContactModel;
@@ -120,6 +121,10 @@ class RegisteredMailController
 
     public function receiveAcknowledgement(Request $request, Response $response)
     {
+        if (!PrivilegeController::hasPrivilege(['privilegeId' => 'registered_mail_receive_ar', 'userId' => $GLOBALS['id']])) {
+            return $response->withStatus(403)->withJson(['errors' => 'Service forbidden']);
+        }
+
         $body = $request->getParsedBody();
 
         if (!Validator::stringType()->notEmpty()->validate($body['type']) && !in_array($body['type'], ['distributed', 'notDistributed'])) {
@@ -134,7 +139,7 @@ class RegisteredMailController
         $number = str_replace(' ', '', $number);
 
         $registeredMail = RegisteredMailModel::get([
-            'select' => ['id', 'res_id'],
+            'select' => ['id', 'res_id', 'received_date'],
             'where'  => ['number = ?'],
             'data'   => [$number]
         ]);
@@ -142,6 +147,9 @@ class RegisteredMailController
             return $response->withStatus(400)->withJson(['errors' => 'Registered mail number not found']);
         }
         $registeredMail = $registeredMail[0];
+        if (!empty($registeredMail['received_date'])) {
+            return $response->withStatus(400)->withJson(['errors' => 'Registered mail was already received', 'lang' => 'arAlreadyReceived']);
+        }
 
         if ($body['type'] == 'distributed') {
             $set = ['received_date' => 'CURRENT_TIMESTAMP'];
diff --git a/src/frontend/app/registeredMails/acknowledgement-reception/acknowledgement-reception.component.html b/src/frontend/app/registeredMails/acknowledgement-reception/acknowledgement-reception.component.html
index be00b52049c..5b47fa3ecfa 100644
--- a/src/frontend/app/registeredMails/acknowledgement-reception/acknowledgement-reception.component.html
+++ b/src/frontend/app/registeredMails/acknowledgement-reception/acknowledgement-reception.component.html
@@ -21,17 +21,12 @@
                     <form style="display: contents;" [formGroup]="adminFormGroup">
                         <div>
                             <mat-form-field>
-                                <mat-select [(ngModel)]="type" required placeholder="{{'lang.returnType' | translate}}" formControlName="type">
+                                <mat-select [(ngModel)]="type" (ngModelChange)="changeType($event)" placeholder="{{'lang.returnType' | translate}}" formControlName="type">
                                     <mat-option [value]="'distributed'">{{'lang.registeredMailDistributed' | translate}}</mat-option>
                                     <mat-option [value]="'notDistributed'">{{'lang.registeredMailNotDistributed' | translate}}</mat-option>
                                 </mat-select>
                             </mat-form-field>
 
-                            <mat-form-field>
-                                <mat-label>{{'lang.registeredMailNumber' | translate}}</mat-label>
-                                <input type="text" matInput required (change)="receiveAcknowledgement()" [(ngModel)]="number" formControlName="number">
-                            </mat-form-field>
-
                             <mat-form-field  *ngIf="type === 'notDistributed'" (click)="picker.open()" appearance="outline" style="cursor:pointer;margin-top: 10px;">
                                 <mat-label>{{'lang.registeredMailReceivedDate' | translate}}</mat-label>
                                 <input matInput [(ngModel)]="receivedDate" [matDatepicker]="picker"
@@ -47,11 +42,9 @@
                             </mat-form-field>
 
                             <mat-form-field *ngIf="type === 'notDistributed'" >
+                                <!-- sort -->
                                 <mat-select [(ngModel)]="reason" formControlName="returnReason" placeholder="{{'lang.returnReason' | translate}}" required>
-                                    <mat-option value="{{'lang.returnReasonCannotAccess' | translate}}">{{'lang.returnReasonCannotAccess' | translate}}</mat-option>
-                                    <mat-option value="{{'lang.returnReasonNotClaimed' | translate}}">{{'lang.returnReasonNotClaimed' | translate}}</mat-option>
-                                    <mat-option value="{{'lang.returnReasonRejected' | translate}}">{{'lang.returnReasonRejected' | translate}}</mat-option>
-                                    <mat-option value="{{'lang.returnReasonUnknown' | translate}}">{{'lang.returnReasonUnknown' | translate}}</mat-option>
+                                    <mat-option *ngFor="let reason of returnReasons" [value]="reason">{{reason}}</mat-option>
                                     <mat-option value="{{'lang.others' | translate}}">{{'lang.others' | translate}}</mat-option>
                                 </mat-select>
                             </mat-form-field>
@@ -59,8 +52,46 @@
                                 <mat-label>{{'lang.precise' | translate}}</mat-label>
                                 <input matInput name="returnReasonOther" formControlName="returnReasonOther" [(ngModel)]="reasonOther">
                             </mat-form-field>
+
+                            <mat-form-field>
+                                <mat-label>{{'lang.registeredMailNumber' | translate}}</mat-label>
+                                <input #numberInput type="text" matInput required (change)="receiveAcknowledgement()" [(ngModel)]="number" formControlName="number">
+                            </mat-form-field>
+
+                            <div style="text-align:center;">
+                                <button mat-raised-button color="primary" type="button" (click)="receiveAcknowledgement()"
+                                        [disabled]="!adminFormGroup.valid">{{'lang.validate' | translate}}</button>
+                            </div>
                         </div>
                     </form>
+
+                    <mat-table #table [dataSource]="dataSource">
+                        <ng-container matColumnDef="type">
+                            <mat-header-cell *matHeaderCellDef>{{'lang.returnType' | translate}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element">
+                                {{(element.type === 'distributed' ? ('lang.registeredMailDistributed' | translate) : ('lang.registeredMailNotDistributed' | translate))}}
+                            </mat-cell>
+                        </ng-container>
+                        <ng-container matColumnDef="number">
+                            <mat-header-cell *matHeaderCellDef>{{'lang.registeredMailNumber' | translate}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element"> {{element.number}} </mat-cell>
+                        </ng-container>
+                        <ng-container matColumnDef="receivedDate">
+                            <mat-header-cell *matHeaderCellDef>{{'lang.registeredMailReceivedDate' | translate}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element"> {{element.receivedDate}} </mat-cell>
+                        </ng-container>
+                        <ng-container matColumnDef="returnReason">
+                            <mat-header-cell *matHeaderCellDef>{{'lang.returnReason' | translate}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element">{{element.returnReason}} </mat-cell>
+                        </ng-container>
+                        <ng-container matColumnDef="returnReasonOther">
+                            <mat-header-cell *matHeaderCellDef>{{'lang.others' | translate}}</mat-header-cell>
+                            <mat-cell *matCellDef="let element">{{element.returnReasonOther}} </mat-cell>
+                        </ng-container>
+
+                        <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+                        <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
+                    </mat-table>
                 </mat-card>
             </div>
         </div>
diff --git a/src/frontend/app/registeredMails/acknowledgement-reception/acknowledgement-reception.component.ts b/src/frontend/app/registeredMails/acknowledgement-reception/acknowledgement-reception.component.ts
index 7db3e6e2b12..ceb2533de50 100644
--- a/src/frontend/app/registeredMails/acknowledgement-reception/acknowledgement-reception.component.ts
+++ b/src/frontend/app/registeredMails/acknowledgement-reception/acknowledgement-reception.component.ts
@@ -1,4 +1,4 @@
-import { Component, OnInit } from '@angular/core';
+import {Component, ElementRef, OnInit, ViewChild} from '@angular/core';
 import { HttpClient } from '@angular/common/http';
 import {FormBuilder, FormGroup, ValidatorFn, Validators} from '@angular/forms';
 import {catchError, tap} from 'rxjs/operators';
@@ -8,7 +8,7 @@ import { HeaderService } from '../../../service/header.service';
 import { FunctionsService } from '../../../service/functions.service';
 import {AppService} from '../../../service/app.service';
 import {TranslateService} from '@ngx-translate/core';
-import {ActivatedRoute} from '@angular/router';
+import {MatTableDataSource} from '@angular/material/table';
 
 @Component({
     selector: 'app-acknowledgement-reception',
@@ -19,16 +19,29 @@ export class AcknowledgementReceptionComponent implements OnInit {
 
     loading: boolean = false;
 
+    today: Date = new Date();
+
     type: any;
     number: any;
-    receivedDate: any;
+    receivedDate: any = this.today;
     reason: any;
-    reasonOther: any;
 
-    today: Date = new Date();
+    reasonOther: any;
 
     adminFormGroup: FormGroup;
 
+    dataSource: MatTableDataSource<any>;
+    displayedColumns = ['type', 'number', 'receivedDate', 'returnReason', 'returnReasonOther'];
+
+    returnReasons = [
+        this.translate.instant('lang.returnReasonCannotAccess'),
+        this.translate.instant('lang.returnReasonNotClaimed'),
+        this.translate.instant('lang.returnReasonRejected'),
+        this.translate.instant('lang.returnReasonUnknown')
+    ];
+
+    @ViewChild('numberInput', { static: false }) numberInput: ElementRef;
+
     constructor(
         public http: HttpClient,
         private notify: NotificationService,
@@ -36,32 +49,31 @@ export class AcknowledgementReceptionComponent implements OnInit {
         public functions: FunctionsService,
         public appService: AppService,
         public translate: TranslateService,
-        private _formBuilder: FormBuilder,
-        private route: ActivatedRoute
+        private _formBuilder: FormBuilder
     ) {
 
     }
 
     ngOnInit() {
-        this.route.params.subscribe(async () => {
-            this.headerService.setHeader(this.translate.instant('lang.arReception'));
-            const validatorNumber: ValidatorFn[] = [Validators.pattern(/(2C|2D|RW) ([0-9]{3} [0-9]{3} [0-9]{4}) ([0-9])/), Validators.required];
-            this.adminFormGroup = this._formBuilder.group({
-                type:              ['', Validators.required],
-                number:            ['', validatorNumber],
-                receivedDate:      ['', Validators.required],
-                returnReason:      ['', Validators.required],
-                returnReasonOther: ['', Validators.required]
-            });
-            this.loading = false;
+        this.headerService.setHeader(this.translate.instant('lang.arReception'));
+        const validatorNumber: ValidatorFn[] = [Validators.pattern(/(2C|2D|RW) ([0-9]{3} [0-9]{3} [0-9]{4}) ([0-9])/), Validators.required];
+        this.adminFormGroup = this._formBuilder.group({
+            type:              ['', Validators.required],
+            number:            ['', validatorNumber],
+            receivedDate:      ['', Validators.required],
+            returnReason:      ['', Validators.required],
+            returnReasonOther: ['']
         });
+        this.loading = false;
+        this.dataSource = new MatTableDataSource([]);
+        this.returnReasons.sort();
     }
 
     receiveAcknowledgement() {
         const data = {
             type: this.type,
             number: this.number,
-            receivedDate: this.receivedDate,
+            receivedDate: this.functions.formatDateObjectToDateString(this.receivedDate),
             returnReason: this.reason,
             returnReasonOther: this.reasonOther
         };
@@ -76,13 +88,22 @@ export class AcknowledgementReceptionComponent implements OnInit {
                 this.notify.error(this.translate.instant('lang.fieldsNotValid'));
                 return;
             }
+            if (this.reason === this.translate.instant('lang.others') && this.functions.empty(this.reasonOther)) {
+                this.notify.error(this.translate.instant('lang.fieldsNotValid'));
+                return;
+            }
         }
 
         this.http.put('../rest/registeredMails/acknowledgement', data).pipe(
             tap(() => {
-                this.type = '';
+                this.notify.success(this.translate.instant('lang.arReceived'));
+
+                const receivedList = this.dataSource.data;
+                receivedList.unshift(data);
+                this.dataSource.data = receivedList;
+
                 this.number = '';
-                this.receivedDate = '';
+                this.receivedDate = this.today;
                 this.reason = '';
                 this.reasonOther = '';
             }),
@@ -92,4 +113,12 @@ export class AcknowledgementReceptionComponent implements OnInit {
             })
         ).subscribe();
     }
+
+    changeType(type: any) {
+        setTimeout(() => {
+            if (type === 'distributed') {
+                this.numberInput.nativeElement.focus();
+            }
+        }, 0);
+    }
 }
diff --git a/src/lang/lang-en.json b/src/lang/lang-en.json
index fe8b7d10136..38fca883245 100644
--- a/src/lang/lang-en.json
+++ b/src/lang/lang-en.json
@@ -1933,5 +1933,7 @@
     "returnReasonCannotAccess": "Access or address error",
     "returnReasonNotClaimed": "Mail not claimed",
     "returnReasonRejected": "Mail rejected by recipient",
-    "returnReasonUnknown": "Recipient unknown at this address"
+    "returnReasonUnknown": "Recipient unknown at this address",
+    "arReceived": "AR received",
+    "arAlreadyReceived": "This AR has already been received"
 }
diff --git a/src/lang/lang-fr.json b/src/lang/lang-fr.json
index 880f8278008..26f4d47718e 100644
--- a/src/lang/lang-fr.json
+++ b/src/lang/lang-fr.json
@@ -1971,5 +1971,7 @@
     "maileva": "Maileva",
     "acknowlegdmentReceipt": "Accusé de réception",
     "externalSignatoryBook": "Parapheur externe",
-    "dispositListGeneratedMsg": "Le recommandé a été imprimé dans un <b>descriptif de pli</b>, vous ne pouvez pas modifier les données."
+    "dispositListGeneratedMsg": "Le recommandé a été imprimé dans un <b>descriptif de pli</b>, vous ne pouvez pas modifier les données.",
+    "arReceived": "AR réceptionné",
+    "arAlreadyReceived": "Cet AR a déjà été reçu"
 }
-- 
GitLab