From 90d763babca6865d88a66e6fce2ac80541ac418f Mon Sep 17 00:00:00 2001
From: Guillaume Heurtier <guillaume.heurtier@maarch.org>
Date: Tue, 1 Sep 2020 17:24:38 +0200
Subject: [PATCH] FEAT #14004 TIME 3:45 begin ar reception front

---
 .../controllers/RegisteredMailController.php  | 14 ++-
 .../administration-routing.module.ts          |  2 +
 .../administration/administration.module.ts   |  2 +
 .../acknowledgement-reception.component.html  | 68 +++++++++++++
 .../acknowledgement-reception.component.ts    | 95 +++++++++++++++++++
 .../registered-mail-list.component.ts         |  5 +
 src/lang/lang-en.json                         | 14 ++-
 src/lang/lang-fr.json                         | 14 ++-
 8 files changed, 207 insertions(+), 7 deletions(-)
 create mode 100644 src/frontend/app/administration/registered-mail/acknowledgement-reception/acknowledgement-reception.component.html
 create mode 100644 src/frontend/app/administration/registered-mail/acknowledgement-reception/acknowledgement-reception.component.ts

diff --git a/src/app/registeredMail/controllers/RegisteredMailController.php b/src/app/registeredMail/controllers/RegisteredMailController.php
index ae7b541fd65..3446eb4a240 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 Parameter\models\ParameterModel;
 use Contact\controllers\ContactController;
 use Contact\models\ContactModel;
 use RegisteredMail\models\RegisteredMailModel;
@@ -127,8 +128,6 @@ class RegisteredMailController
             return $response->withStatus(400)->withJson(['errors' => 'Body number is empty or not a string']);
         } elseif (!preg_match("/(2C|2D|RW) ([0-9]{3} [0-9]{3} [0-9]{4}) ([0-9])/", $body['number'])) {
             return $response->withStatus(400)->withJson(['errors' => 'Body number is not valid']);
-        } elseif (!empty($body['status']) && !Validator::stringType()->length(1, 10)->validate($body['status'])) {
-            return $response->withStatus(400)->withJson(['errors' => 'Body status is not a string']);
         }
 
         $number = substr($body['number'], 3, 12);
@@ -142,9 +141,12 @@ class RegisteredMailController
         if (empty($registeredMail)) {
             return $response->withStatus(400)->withJson(['errors' => 'Registered mail number not found']);
         }
+        $registeredMail = $registeredMail[0];
 
         if ($body['type'] == 'distributed') {
             $set = ['received_date' => 'CURRENT_TIMESTAMP'];
+            $status = ParameterModel::getById(['select' => ['param_value_string'], 'id' => 'registeredMailDistributedStatus']);
+            $status = $status['param_value_string'];
         } else {
             if (!Validator::stringType()->notEmpty()->validate($body['returnReason'])) {
                 return $response->withStatus(400)->withJson(['errors' => 'Body returnReason is empty or not a string']);
@@ -154,11 +156,13 @@ class RegisteredMailController
             $receivedDate = new \DateTime($body['receivedDate']);
             $today = new \DateTime();
             $today->setTime(00, 00, 00);
-            if ($receivedDate < $today) {
+            if ($receivedDate > $today) {
                 return ['errors' => "Body receivedDate is not a valid date"];
             }
 
             $set = ['received_date' => $body['receivedDate'], 'return_reason' => $body['returnReason'], 'return_reason_other' => $body['returnReasonOther'] ?? null];
+            $status = ParameterModel::getById(['select' => ['param_value_string'], 'id' => 'registeredMailNotDistributedStatus']);
+            $status = $status['param_value_string'];
         }
 
         RegisteredMailModel::update([
@@ -166,9 +170,9 @@ class RegisteredMailController
             'where' => ['id = ?'],
             'data'  => [$registeredMail['id']]
         ]);
-        if (!empty($body['status'])) {
+        if (!empty($status)) {
             ResModel::update([
-                'set'   => ['status' => $body['status']],
+                'set'   => ['status' => $status],
                 'where' => ['res_id = ?'],
                 'data'  => [$registeredMail['res_id']]
             ]);
diff --git a/src/frontend/app/administration/administration-routing.module.ts b/src/frontend/app/administration/administration-routing.module.ts
index 5a0d0a34a39..0fa1fbe0d73 100755
--- a/src/frontend/app/administration/administration-routing.module.ts
+++ b/src/frontend/app/administration/administration-routing.module.ts
@@ -53,6 +53,7 @@ import { IssuingSiteListComponent } from './registered-mail/issuing-site/issuing
 import { IssuingSiteComponent } from './registered-mail/issuing-site/issuing-site.component';
 import { RegisteredMailListComponent } from './registered-mail/registered-mail-list.component';
 import { RegisteredMailComponent } from './registered-mail/registered-mail.component';
+import {AcknowledgementReceptionComponent} from './registered-mail/acknowledgement-reception/acknowledgement-reception.component';
 
 @NgModule({
     imports: [
@@ -122,6 +123,7 @@ import { RegisteredMailComponent } from './registered-mail/registered-mail.compo
             { path: 'alfresco/new', canActivate: [AppGuard], component: AlfrescoAdministrationComponent },
             { path: 'alfresco/:id', canActivate: [AppGuard], component: AlfrescoAdministrationComponent },
             { path: 'registeredMails', canActivate: [AppGuard], component: RegisteredMailListComponent },
+            { path: 'registeredMails/acknowledgement', canActivate: [AppGuard], component: AcknowledgementReceptionComponent },
             { path: 'registeredMails/new', canActivate: [AppGuard], component: RegisteredMailComponent },
             { path: 'registeredMails/:id', canActivate: [AppGuard], component: RegisteredMailComponent },
             { path: 'issuingSites', canActivate: [AppGuard], component: IssuingSiteListComponent },
diff --git a/src/frontend/app/administration/administration.module.ts b/src/frontend/app/administration/administration.module.ts
index 4afcf9bee0c..b221059a406 100755
--- a/src/frontend/app/administration/administration.module.ts
+++ b/src/frontend/app/administration/administration.module.ts
@@ -75,6 +75,7 @@ import { RegisteredMailComponent } from './registered-mail/registered-mail.compo
 import { IssuingSiteListComponent } from './registered-mail/issuing-site/issuing-site-list.component';
 import { IssuingSiteComponent } from './registered-mail/issuing-site/issuing-site.component';
 import { RegisteredMailListComponent } from './registered-mail/registered-mail-list.component';
+import { AcknowledgementReceptionComponent } from './registered-mail/acknowledgement-reception/acknowledgement-reception.component';
 
 
 @NgModule({
@@ -158,6 +159,7 @@ import { RegisteredMailListComponent } from './registered-mail/registered-mail-l
         IssuingSiteListComponent,
         IssuingSiteComponent,
         RegisteredMailListComponent,
+        AcknowledgementReceptionComponent
     ],
     entryComponents: [
         AccountLinkComponent,
diff --git a/src/frontend/app/administration/registered-mail/acknowledgement-reception/acknowledgement-reception.component.html b/src/frontend/app/administration/registered-mail/acknowledgement-reception/acknowledgement-reception.component.html
new file mode 100644
index 00000000000..be00b52049c
--- /dev/null
+++ b/src/frontend/app/administration/registered-mail/acknowledgement-reception/acknowledgement-reception.component.html
@@ -0,0 +1,68 @@
+<mat-sidenav-container autosize class="maarch-container">
+    <mat-sidenav-content>
+        <div class="bg-head">
+            <div class="bg-head-title" [class.customContainerRight]="appService.getViewMode()">
+                <div class="bg-head-title-label">
+                    <header-left></header-left>
+                </div>
+                <div class="bg-head-title-tool">
+                    <header-right></header-right>
+                </div>
+            </div>
+            <div class="bg-head-content" [class.fullContainer]="appService.getViewMode()">
+            </div>
+        </div>
+        <div class="container" [class.fullContainer]="appService.getViewMode()">
+            <div class="container-content">
+                <div *ngIf="loading" style="display:flex;height:100%;">
+                    <mat-spinner style="margin:auto;"></mat-spinner>
+                </div>
+                <mat-card *ngIf="!loading" class="card-app-content">
+                    <form style="display: contents;" [formGroup]="adminFormGroup">
+                        <div>
+                            <mat-form-field>
+                                <mat-select [(ngModel)]="type" required 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"
+                                       [placeholder]="this.translate.instant('lang.chooseDate')" [max]="today" readonly style="cursor:pointer;" formControlName="receivedDate" required>
+                                <mat-datepicker-toggle matSuffix [for]="picker" *ngIf="!receivedDate">
+                                </mat-datepicker-toggle>
+                                <mat-datepicker #picker></mat-datepicker>
+                                <button mat-button color="warn" matSuffix mat-icon-button *ngIf="receivedDate"
+                                        (click)="$event.stopPropagation();receivedDate = null;" [title]="this.translate.instant('lang.eraseValue')">
+                                    <mat-icon color="warn" class="fa fa-calendar-times">
+                                    </mat-icon>
+                                </button>
+                            </mat-form-field>
+
+                            <mat-form-field *ngIf="type === 'notDistributed'" >
+                                <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 value="{{'lang.others' | translate}}">{{'lang.others' | translate}}</mat-option>
+                                </mat-select>
+                            </mat-form-field>
+                            <mat-form-field *ngIf="type === 'notDistributed' && reason === this.translate.instant('lang.others')">
+                                <mat-label>{{'lang.precise' | translate}}</mat-label>
+                                <input matInput name="returnReasonOther" formControlName="returnReasonOther" [(ngModel)]="reasonOther">
+                            </mat-form-field>
+                        </div>
+                    </form>
+                </mat-card>
+            </div>
+        </div>
+    </mat-sidenav-content>
+</mat-sidenav-container>
diff --git a/src/frontend/app/administration/registered-mail/acknowledgement-reception/acknowledgement-reception.component.ts b/src/frontend/app/administration/registered-mail/acknowledgement-reception/acknowledgement-reception.component.ts
new file mode 100644
index 00000000000..782a6171098
--- /dev/null
+++ b/src/frontend/app/administration/registered-mail/acknowledgement-reception/acknowledgement-reception.component.ts
@@ -0,0 +1,95 @@
+import { Component, OnInit } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import {FormBuilder, FormGroup, ValidatorFn, Validators} from '@angular/forms';
+import {catchError, tap} from 'rxjs/operators';
+import { of } from 'rxjs/internal/observable/of';
+import { NotificationService } from '../../../../service/notification/notification.service';
+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';
+
+@Component({
+    selector: 'app-acknowledgement-reception',
+    templateUrl: 'acknowledgement-reception.component.html'
+})
+
+export class AcknowledgementReceptionComponent implements OnInit {
+
+    loading: boolean = false;
+
+    type: any;
+    number: any;
+    receivedDate: any;
+    reason: any;
+    reasonOther: any;
+
+    today: Date = new Date();
+
+    adminFormGroup: FormGroup;
+
+    constructor(
+        public http: HttpClient,
+        private notify: NotificationService,
+        private headerService: HeaderService,
+        public functions: FunctionsService,
+        public appService: AppService,
+        public translate: TranslateService,
+        private _formBuilder: FormBuilder,
+        private route: ActivatedRoute
+    ) {
+
+    }
+
+    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;
+        });
+    }
+
+    receiveAcknowledgement() {
+        const data = {
+            type: this.type,
+            number: this.number,
+            receivedDate: this.receivedDate,
+            returnReason: this.reason,
+            returnReasonOther: this.reasonOther
+        };
+
+        if (this.type === 'distributed') {
+            if (!this.adminFormGroup.get('number').valid) {
+                this.notify.error(this.translate.instant('lang.fieldsNotValid'));
+                return;
+            }
+        } else {
+            if (!this.adminFormGroup.get('number').valid || !this.adminFormGroup.get('receivedDate').valid || !this.adminFormGroup.get('returnReason').valid) {
+                this.notify.error(this.translate.instant('lang.fieldsNotValid'));
+                return;
+            }
+        }
+
+        this.http.put('../rest/registeredMails/acknowledgement', data).pipe(
+            tap(() => {
+                this.type = '';
+                this.number = '';
+                this.receivedDate = '';
+                this.reason = '';
+                this.reasonOther = '';
+            }),
+            catchError((err) => {
+                this.notify.handleSoftErrors(err);
+                return of(false);
+            })
+        ).subscribe();
+    }
+}
diff --git a/src/frontend/app/administration/registered-mail/registered-mail-list.component.ts b/src/frontend/app/administration/registered-mail/registered-mail-list.component.ts
index ca923b09422..34c1d68fdca 100644
--- a/src/frontend/app/administration/registered-mail/registered-mail-list.component.ts
+++ b/src/frontend/app/administration/registered-mail/registered-mail-list.component.ts
@@ -32,6 +32,11 @@ export class RegisteredMailListComponent implements OnInit {
             route: '/administration/issuingSites',
             label: this.translate.instant('lang.issuingSites'),
             current: false
+        }, {
+            icon: 'fas fa-warehouse',
+            route: '/administration/registeredMails/acknowledgement',
+            label: 'Réception AR',
+            current: false
         },
     ];
 
diff --git a/src/lang/lang-en.json b/src/lang/lang-en.json
index 4515d5da310..ac7a1390797 100644
--- a/src/lang/lang-en.json
+++ b/src/lang/lang-en.json
@@ -1919,5 +1919,17 @@
     "rangeStartLargerThanRangeEnd": "Range start cannot be larger than range end",
     "trackingNumberAlreadyUsed": "Tracking number is already used",
     "rangeOverlaps": "Range overlaps another range",
-    "siteIsUsedByActiveRange": "Cannot delete issuing site : site is used by an active range"
+    "siteIsUsedByActiveRange": "Cannot delete issuing site : site is used by an active range",
+    "fieldsNotValid": "Fields are invalid",
+    "arReception": "AR reception",
+    "returnType": "Return type",
+    "registeredMailDistributed": "Registered mail distributed",
+    "registeredMailNotDistributed": "Registered mail not distributed",
+    "registeredMailReceivedDate": "Date of receipt",
+    "precise": "Precise :",
+    "returnReason": "Reason of return",
+    "returnReasonCannotAccess": "Access or address error",
+    "returnReasonNotClaimed": "Mail not claimed",
+    "returnReasonRejected": "Mail rejected by recipient",
+    "returnReasonUnknown": "Recipient unknown at this address"
 }
diff --git a/src/lang/lang-fr.json b/src/lang/lang-fr.json
index 8d65b1a4b5b..e9b9c41ab3b 100644
--- a/src/lang/lang-fr.json
+++ b/src/lang/lang-fr.json
@@ -1951,5 +1951,17 @@
     "rangeStartLargerThanRangeEnd": "Le début de la plage ne peut pas être plus grand que la fin de la plage",
     "trackingNumberAlreadyUsed": "Le numéro de suivi est déjà utilisé",
     "rangeOverlaps": "La plage chevauche une autre plage",
-    "siteIsUsedByActiveRange": "Impossible de supprimer le site émetteur : le site est utilisé par une plage active"
+    "siteIsUsedByActiveRange": "Impossible de supprimer le site émetteur : le site est utilisé par une plage active",
+    "fieldsNotValid": "Les données saisies sont invalides",
+    "arReception": "Réception des AR",
+    "returnType": "Type de retour",
+    "registeredMailDistributed": "Recommandé distribué",
+    "registeredMailNotDistributed": "Recommandé non distribué",
+    "registeredMailReceivedDate": "Date de réception",
+    "precise": "Précisez :",
+    "returnReason": "Motif de retour",
+    "returnReasonCannotAccess": "Défaut d'accès ou d'adressage",
+    "returnReasonNotClaimed": "Pli avisé et non réclamé",
+    "returnReasonRejected": "Pli refusé par le destinataire",
+    "returnReasonUnknown": "Destinataire inconnu à l'adresse"
 }
-- 
GitLab