Skip to content
Snippets Groups Projects
Commit b5a692b8 authored by Alex ORLUC's avatar Alex ORLUC
Browse files

FEAT #14002 TIME 1 front registered mail import + add alias path

parent b3f4a7f4
No related branches found
No related tags found
No related merge requests found
......@@ -79,6 +79,9 @@ import { LinkedResourceListComponent } from './linkedResource/linked-resource-li
import { InternationalizationModule } from '../service/translate/internationalization.module';
import { TranslateService } from '@ngx-translate/core';
import { RegisteredMailImportComponent } from '@appRoot/registeredMail/import/registered-mail-import.component';
@NgModule({
imports: [
CommonModule,
......@@ -100,6 +103,7 @@ import { TranslateService } from '@ngx-translate/core';
SearchHomeComponent,
BasketHomeComponent,
IndexingGroupModalComponent,
RegisteredMailImportComponent,
SmdFabSpeedDialComponent,
SmdFabSpeedDialTrigger,
SmdFabSpeedDialActions,
......@@ -186,6 +190,7 @@ import { TranslateService } from '@ngx-translate/core';
providers: [],
entryComponents: [
IndexingGroupModalComponent,
RegisteredMailImportComponent,
AlertComponent,
ConfirmComponent
],
......
<div class="bg-head-title-tool">
<!--<form *ngIf="!hideSearch" ngNoForm style="height: 40px;" name="choose_query" id="choose_query" method="post"
action="index.php?display=true&amp;dir=indexing_searching&amp;page=search_adv_result">
<input type="hidden" name="meta[]" value="baskets_clause#baskets_clause#select_simple">
<input type="hidden" name="meta[]" value="welcome#welcome#welcome">
<input type="hidden" name="baskets_clause" value="true">
<mat-form-field floatLabel="never" style="width:100%;margin-top: -3px;margin-left:-13px;font-size: 12px;" *ngIf="privilegeService.hasCurrentUserPrivilege('adv_search_mlb')">
<input #searchInput="matInput" matInput type="text" (blur)="hideSearch = !hideSearch" name="welcome" title="{{'lang.searchMails' | translate}}" placeholder="{{'lang.searchMails' | translate}}">
<button mat-icon-button matSuffix *ngIf="!appService.getViewMode()" style="opacity:0.5;">
<mat-icon class="fa fa-search" style="font-size:22px;"></mat-icon>
</button>
</mat-form-field>
<input #searchHome type="submit" name="submit" value="" style="display:none;">
</form>
<button title="{{'lang.quickSearchInfo' | translate}} : {{'lang.quickSearchTarget' | translate}}" (click)="showSearchInput()" mat-icon-button *ngIf="hideSearch && privilegeService.hasCurrentUserPrivilege('adv_search_mlb')"
style="opacity:0.5;">
<mat-icon class="fa fa-search" style="font-size:22px;"></mat-icon>
</button>-->
<form *ngIf="hideSearchBar()" (ngSubmit)="goTo()" #criteriaFormUp="ngForm">
<mat-form-field floatLabel="never" class="basket-search">
<input class="metaSearch" type="text" matInput
......
......@@ -10,6 +10,8 @@ import { AppService } from '../../service/app.service';
import { PrivilegeService } from '../../service/privileges.service';
import { FunctionsService } from '../../service/functions.service';
import { AuthService } from '../../service/auth.service';
import { RegisteredMailImportComponent } from '@appRoot/registeredMail/import/registered-mail-import.component';
@Component({
selector: 'header-right',
......@@ -47,7 +49,18 @@ export class HeaderRightComponent implements OnInit {
this.config = { panelClass: 'maarch-modal', data: { indexingGroups: shortcut.groups, link: shortcut.route } };
this.dialogRef = this.dialog.open(IndexingGroupModalComponent, this.config);
} else if (shortcut.angular === true) {
this.router.navigate([shortcut.route]);
const component = shortcut.route.split('__');
if (component.length === 2) {
this.dialog.open(RegisteredMailImportComponent, {
disableClose: true,
width: '99vw',
maxWidth: '99vw',
panelClass: 'maarch-full-height-modal'
});
} else {
this.router.navigate([shortcut.route]);
}
} else {
location.href = shortcut.route;
}
......
<div class="mat-dialog-content-container">
<h1 mat-dialog-title>{{'lang.importRegisteredMails' | translate}}</h1>
<div mat-dialog-content>
<mat-toolbar class="import-tool" [class.hide]="csvData.length === 0 || loading">
<span style="flex:1;">
<mat-slide-toggle color="primary" [checked]="hasHeader" (change)="toggleHeader()">
{{'lang.csvHeader' | translate}}
</mat-slide-toggle>
</span>
<span style="flex:1;text-align: center;"><i class="fa fa-users"
color="primary"></i>&nbsp;{{'lang.registeredMails' | translate}} : <b
color="primary">{{countAll}}</b>
</span>
</mat-toolbar>
<ng-container *ngIf="loading; else elseTemplate">
<div class="loader">
<mat-spinner></mat-spinner>
</div>
</ng-container>
<ng-template #elseTemplate>
<input type="file" name="files[]" #uploadFile id="uploadFile" (change)="uploadCsv($event)" accept=".csv"
style="display: none;">
<div *ngIf="csvData.length === 0" appUploadFileDragDrop (click)="uploadFile.click()"
(onFileDropped)="dndUploadFile($event)" class="dndFile">
<div>
{{'lang.dndFileCsvDesc' | translate}}
<mat-form-field appearance="outline" style="font-size:14px;" (click)="$event.stopPropagation()">
<mat-label>{{'lang.delimiter' | translate}}</mat-label>
<mat-select [(ngModel)]="currentDelimiter" (click)="$event.stopPropagation()">
<mat-option *ngFor="let delimiter of delimiters" [value]="delimiter">
{{delimiter === '\t' ? 'TAB' : delimiter}}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
<div class="row" style="margin: 0px;">
<div class="col-md-12">
<mat-paginator #paginator [length]="100" [hidePageSize]="true" [pageSize]="10">
</mat-paginator>
</div>
</div>
<div style="width:100%;box-shadow: inset 0px 0px 5px 0px rgba(0,0,0,0.75);padding:10px;">
<div style="overflow: auto;">
<mat-table *ngIf="csvData.length > 0" #table [dataSource]="dataSource"
[style.width.px]="contactColumns.length * 300">
<ng-container *ngFor="let column of contactColumns;let i=index;">
<ng-container [matColumnDef]="column.id">
<mat-header-cell *matHeaderCellDef style="padding-left: 5px;padding-right: 5px;">
<ng-container *ngIf="!column.form; else elseTemplate">
<i class="fas fa-database" color="primary"
[title]="'lang.dbColumn' | translate"></i>&nbsp;<b color="primary"
[title]="'lang.dbColumn' | translate">{{column.label}}</b>
&nbsp;<i class="fas fa-arrows-alt-h"></i>&nbsp;
<i class="fas fa-file-csv" [title]="'lang.csvColumn' | translate"></i>&nbsp;
<mat-form-field [title]="'lang.csvColumn' | translate"
(click)="$event.stopPropagation()" style="width: 80px !important;">
<mat-select [(ngModel)]="associatedColmuns[column.id]"
(selectionChange)="changeColumn(column, $event.value)">
<mat-option value=""></mat-option>
<mat-option *ngFor="let col of csvColumns" [value]="col">
{{col}}
</mat-option>
</mat-select>
</mat-form-field>
</ng-container>
<ng-template #elseTemplate>
<i class="fas fa-database" color="primary"
[title]="'lang.dbColumn' | translate"></i>&nbsp;<b color="primary"
[title]="'lang.dbColumn' | translate">{{column.label}}</b>
&nbsp;<i class="fas fa-arrows-alt-h"></i>&nbsp;
<i class="fas fa-file-csv" [title]="'lang.csvColumn' | translate"></i>&nbsp;
<mat-form-field [title]="'lang.csvColumn' | translate"
(click)="$event.stopPropagation()" style="width: 80px !important;">
<mat-select [(ngModel)]="associatedColmuns[column.id]"
(selectionChange)="changeColumn(column, $event.value)">
<mat-option *ngFor="let val of column.values" [value]="val">
{{val.label}}
</mat-option>
</mat-select>
</mat-form-field>
</ng-template>
</mat-header-cell>
<mat-cell *matCellDef="let element" style="padding-left: 5px;padding-right: 5px;">
<ng-container
*ngIf="column.emptyValueMode && functionsService.empty(element[column.id]); else elseTemplate">
<i style="opacity: 0.5;">{{'lang.emptyValue' | translate}}</i>
</ng-container>
<ng-template #elseTemplate>
{{element[column.id]}}
</ng-template>
</mat-cell>
</ng-container>
</ng-container>
<mat-header-row *matHeaderRowDef="getcontactColumnsIds()"></mat-header-row>
<mat-row *matRowDef="let row; columns: getcontactColumnsIds();"></mat-row>
</mat-table>
</div>
</div>
</ng-template>
</div>
<span class="divider-modal"></span>
<div mat-dialog-actions class="actions">
<button mat-raised-button mat-button *ngIf="csvData.length > 0" color="primary" [disabled]="loading"
(click)="onSubmit()">{{'lang.validate' | translate}}</button>
<button mat-raised-button mat-button [disabled]="loading"
[mat-dialog-close]="">{{'lang.cancel' | translate }}</button>
</div>
</div>
\ No newline at end of file
@import '../../../css/vars.scss';
.loader {
display: flex;
height: 100%;
align-items: center;
justify-content: center;
}
.hide {
display: none;
}
.import-tool {
font-size: 14px;
}
.dndFile {
height: 100%;
display: flex;
align-items: center;
margin: 0px;
justify-content: center;
font-size: 30px;
opacity: 0.5 !important;
cursor: pointer;
}
\ No newline at end of file
import { Component, OnInit, Inject, ViewChild } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { NotificationService } from '../../../service/notification/notification.service';
import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material/dialog';
import { TranslateService } from '@ngx-translate/core';
import { MatTableDataSource } from '@angular/material/table';
import { FunctionsService } from '../../../service/functions.service';
import { ConfirmComponent } from '../../../plugins/modal/confirm.component';
import { filter, exhaustMap, tap, catchError, map } from 'rxjs/operators';
import { of } from 'rxjs/internal/observable/of';
import { AlertComponent } from '../../../plugins/modal/alert.component';
import { LocalStorageService } from '../../../service/local-storage.service';
import { HeaderService } from '../../../service/header.service';
import { MatPaginator } from '@angular/material/paginator';
import { Papa } from 'ngx-papaparse';
import { IndexingFieldsService } from '@service/indexing-fields.service';
@Component({
templateUrl: 'registered-mail-import.component.html',
styleUrls: ['registered-mail-import.component.scss']
})
export class RegisteredMailImportComponent implements OnInit {
loading: boolean = false;
contactColumns: any[] = [
{
id: 'registeredMail_reference',
label: this.translate.instant('lang.registeredMailReference'),
},
{
id: 'company',
label: this.translate.instant('lang.contactsParameters_company'),
},
{
id: 'civility',
label: this.translate.instant('lang.contactsParameters_civility'),
},
{
id: 'firstname',
label: this.translate.instant('lang.contactsParameters_firstname'),
},
{
id: 'lastname',
label: this.translate.instant('lang.contactsParameters_lastname'),
},
{
id: 'department',
label: this.translate.instant('lang.contactsParameters_department'),
},
{
id: 'addressAdditional1',
label: this.translate.instant('lang.contactsParameters_addressAdditional1'),
},
{
id: 'addressNumber',
label: this.translate.instant('lang.contactsParameters_addressNumber'),
},
{
id: 'addressStreet',
label: this.translate.instant('lang.contactsParameters_addressStreet'),
},
{
id: 'addressAdditional2',
label: this.translate.instant('lang.contactsParameters_addressAdditional2'),
},
{
id: 'addressPostcode',
label: this.translate.instant('lang.contactsParameters_addressPostcode'),
},
{
id: 'addressTown',
label: this.translate.instant('lang.contactsParameters_addressTown'),
},
{
id: 'addressCountry',
label: this.translate.instant('lang.contactsParameters_addressCountry'),
},
];
csvColumns: string[] = [
];
delimiters = [';', ',', '\t'];
currentDelimiter = ';';
associatedColmuns: any = {};
dataSource = new MatTableDataSource(null);
hasHeader: boolean = true;
csvData: any[] = [];
contactData: any[] = [];
countAll: number = 0;
countAdd: number = 0;
countUp: number = 0;
@ViewChild(MatPaginator, { static: false }) paginator: MatPaginator;
constructor(
public translate: TranslateService,
public http: HttpClient,
private notify: NotificationService,
public functionsService: FunctionsService,
private localStorage: LocalStorageService,
private headerService: HeaderService,
public dialog: MatDialog,
public dialogRef: MatDialogRef<RegisteredMailImportComponent>,
private papa: Papa,
public indexingFields: IndexingFieldsService,
@Inject(MAT_DIALOG_DATA) public data: any,
) {
}
ngOnInit(): void {
['registeredMail_warranty', 'registeredMail_type', 'departureDate', 'registeredMail_letter'].forEach(element => {
console.log(element);
const field = this.indexingFields.getField(element);
this.contactColumns.unshift({
id: field.identifier,
label: field.label,
values: field.values,
form: true
});
});
console.log(this.contactColumns);
this.setConfiguration();
// this.initCustomFields();
}
getcontactColumnsIds() {
return this.contactColumns.map(col => col.id);
}
/*initCustomFields() {
this.http.get(`../rest/contactsCustomFields`).pipe(
map((data: any) => {
data = data.customFields.map(custom => {
return {
id: `contactCustomField_${custom.id}`,
label: custom.label,
type: custom.type
};
});
return data;
}),
tap((customFields) => {
this.contactColumns = this.contactColumns.concat(customFields);
}),
catchError((err: any) => {
this.notify.handleSoftErrors(err);
return of(false);
})
).subscribe();
}*/
changeColumn(coldb: any, colCsv: string) {
this.contactData = [];
for (let index = this.hasHeader ? 1 : 0; index < this.csvData.length; index++) {
const data = this.csvData[index];
const objContact = {};
this.contactColumns.forEach(key => {
objContact[key.id] = coldb === key.id ? data[this.csvColumns.filter(col => col === colCsv)[0]] : data[this.associatedColmuns[key.id]];
});
this.contactData.push(objContact);
}
this.countAdd = this.csvData.filter((data: any, index: number) => index > 0 && this.functionsService.empty(data[this.associatedColmuns['id']])).length;
this.countUp = this.csvData.filter((data: any, index: number) => index > 0 && !this.functionsService.empty(data[this.associatedColmuns['id']])).length;
setTimeout(() => {
this.dataSource = new MatTableDataSource(this.contactData);
this.dataSource.paginator = this.paginator;
}, 0);
}
uploadCsv(fileInput: any) {
if (fileInput.target.files && fileInput.target.files[0] && (fileInput.target.files[0].type === 'text/csv' || fileInput.target.files[0].type === 'application/vnd.ms-excel')) {
this.loading = true;
let rawCsv = [];
const reader = new FileReader();
reader.readAsText(fileInput.target.files[0]);
reader.onload = (value: any) => {
this.papa.parse(value.target.result, {
complete: (result) => {
// console.log('Parsed: ', result);
rawCsv = result.data;
rawCsv = rawCsv.filter(data => data.length === rawCsv[0].length);
let dataCol = [];
let objData = {};
this.setCsvColumns(rawCsv[0]);
this.countAll = this.hasHeader ? rawCsv.length - 1 : rawCsv.length;
for (let index = 0; index < rawCsv.length; index++) {
objData = {};
dataCol = rawCsv[index];
dataCol.forEach((element: any, index2: number) => {
objData[this.csvColumns[index2]] = element;
});
this.csvData.push(objData);
}
this.initData();
this.countAdd = this.csvData.filter((data: any, index: number) => index > 0 && this.functionsService.empty(data[this.associatedColmuns['id']])).length;
this.countUp = this.csvData.filter((data: any, index: number) => index > 0 && !this.functionsService.empty(data[this.associatedColmuns['id']])).length;
this.localStorage.save(`importContactFields_${this.headerService.user.id}`, this.currentDelimiter);
this.loading = false;
}
});
};
} else {
this.dialog.open(AlertComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { title: this.translate.instant('lang.notAllowedExtension') + ' !', msg: this.translate.instant('lang.file') + ' : <b>' + fileInput.target.files[0].name + '</b>, ' + this.translate.instant('lang.type') + ' : <b>' + fileInput.target.files[0].type + '</b><br/><br/><u>' + this.translate.instant('lang.allowedExtensions') + '</u> : <br/>' + 'text/csv' } });
}
}
setCsvColumns(headerData: string[] = null) {
if (headerData.filter(col => this.functionsService.empty(col)).length > 0) {
this.csvColumns = Object.keys(headerData).map((val, index) => `${index}`);
} else {
this.csvColumns = headerData;
}
}
toggleHeader() {
this.hasHeader = !this.hasHeader;
this.countAll = this.hasHeader ? this.csvData.length - 1 : this.csvData.length;
if (this.hasHeader) {
this.countAdd = this.csvData.filter((data: any, index: number) => index > 0 && this.functionsService.empty(data[this.associatedColmuns['id']])).length;
this.countUp = this.csvData.filter((data: any, index: number) => index > 0 && !this.functionsService.empty(data[this.associatedColmuns['id']])).length;
} else {
this.countAdd = this.csvData.filter((data: any, index: number) => this.functionsService.empty(data[this.associatedColmuns['id']])).length;
this.countUp = this.csvData.filter((data: any, index: number) => !this.functionsService.empty(data[this.associatedColmuns['id']])).length;
}
this.initData();
}
initData() {
this.contactData = [];
for (let index = this.hasHeader ? 1 : 0; index < this.csvData.length; index++) {
const data = this.csvData[index];
const objContact = {};
this.contactColumns.forEach((key, indexCol) => {
const indexCsvCol = this.csvColumns.indexOf(key.label);
this.associatedColmuns[key.id] = indexCsvCol > -1 ? this.csvColumns[indexCsvCol] : '';
objContact[key.id] = indexCsvCol > -1 ? data[this.csvColumns[indexCsvCol]] : '';
});
this.contactData.push(objContact);
}
setTimeout(() => {
this.dataSource = new MatTableDataSource(this.contactData);
this.dataSource.paginator = this.paginator;
}, 0);
}
dndUploadFile(event: any) {
const fileInput = {
target: {
files: [
event[0]
]
}
};
this.uploadCsv(fileInput);
}
onSubmit() {
const dataToSend: any[] = [];
let confirmText = '';
this.translate.get('lang.confirmImportContacts', { 0: this.countAll }).subscribe((res: string) => {
confirmText = `${res} ?<br/><br/>`;
// confirmText += `<ul><li><b>${this.countAdd}</b> ${this.translate.instant('lang.additions')}</li><li><b>${this.countUp}</b> ${this.translate.instant('lang.modifications')}</li></ul>`;
});
let dialogRef = this.dialog.open(ConfirmComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { title: this.translate.instant('lang.import'), msg: confirmText } });
dialogRef.afterClosed().pipe(
filter((data: string) => data === 'ok'),
tap(() => {
this.loading = true;
this.csvData.forEach((element: any, index: number) => {
if ((this.hasHeader && index > 0) || !this.hasHeader) {
const objContact = {};
this.contactColumns.forEach((key) => {
if (element[this.associatedColmuns[key.id]] === undefined) {
objContact[key.id] = '';
} else {
objContact[key.id] = element[this.associatedColmuns[key.id]];
}
});
dataToSend.push(objContact);
}
});
console.log(dataToSend);
}),
/*exhaustMap(() => this.http.put(`../rest/contacts/import`, { contacts: dataToSend })),
tap((data: any) => {
let textModal = '';
if (data.errors.count > 0) {
textModal += `<br/>${data.errors.count} ${this.translate.instant('lang.withErrors')} : <ul>`;
data.errors.details.forEach(element => {
textModal += `<li> ${this.translate.instant('lang.' + element.lang, { 0: element.langParam })} (${this.translate.instant('lang.line')} : ${this.hasHeader ? element.index + 2 : element.index + 1})</li>`;
});
textModal += '</ul>';
}
dialogRef = this.dialog.open(AlertComponent, { panelClass: 'maarch-modal', autoFocus: false, disableClose: true, data: { title: this.translate.instant('lang.import'), msg: '<b>' + data.success + '</b> / <b>' + this.countAll + '</b> ' + this.translate.instant('lang.importedContacts') + '.' + textModal } });
}),
exhaustMap(() => dialogRef.afterClosed()),*/
tap(() => {
this.dialogRef.close('success');
}),
catchError((err: any) => {
this.loading = false;
this.notify.handleSoftErrors(err);
return of(false);
})
).subscribe();
}
setConfiguration() {
if (this.localStorage.get(`importContactFields_${this.headerService.user.id}`) !== null) {
this.currentDelimiter = this.localStorage.get(`importContactFields_${this.headerService.user.id}`);
}
}
}
......@@ -530,6 +530,16 @@ export class PrivilegeService {
'unit': 'registeredMails',
'angular': true,
'shortcut': false
},
{
'id': 'registered_mail_mass_import',
'label': 'lang.importRegisteredMails',
'comment': 'lang.importRegisteredMails',
'route': 'administration/contact/list/import/contact-import.component__modal',
'style': 'fas fa-dolly-flatbed',
'unit': 'registeredMails',
'angular': true,
'shortcut': false
}
];
......
......@@ -3,6 +3,14 @@
"compilerOptions": {
"outDir": "../out-tsc/app",
"baseUrl": "../../apps/maarch_entreprise/",
"paths": {
"@appRoot/*": [
"../../src/frontend/app/*"
],
"@service/*": [
"../../src/frontend/service/*"
]
}
},
"files": [
"main.ts",
......
......@@ -14,10 +14,18 @@
"lib": [
"es2018",
"dom"
]
],
"paths": {
"@appRoot/*": [
"./app/*"
],
"@service/*": [
"./service/*"
]
}
},
"angularCompilerOptions": {
"fullTemplateTypeCheck": true,
"strictInjectionParameters": true
}
}
\ No newline at end of file
}
......@@ -2014,5 +2014,6 @@
"contactInput" : "Champ contact",
"issuingSiteSample": "MAARCH - Nanterre",
"registeredMailReferenceSample": "01/01/2020 - Ma référence",
"registeredMailRecipientSample": "MAARCH-LES-BAINS PATRICIA PETIT"
"registeredMailRecipientSample": "MAARCH-LES-BAINS PATRICIA PETIT",
"importRegisteredMails": "Importer des recommandés"
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment