Commit ff3cc0c4 authored by Damien's avatar Damien
Browse files

Merge branch 'develop' into 'master'

Develop

See merge request maarch/MaarchCourrier!295
parents 1f2f90c5 69c555a5
......@@ -248,6 +248,7 @@ INSERT INTO contacts_parameters (id, identifier, mandatory, filling, searchable,
INSERT INTO contacts_parameters (id, identifier, mandatory, filling, searchable, displayable) VALUES (14, 'email', false, true, false, false);
INSERT INTO contacts_parameters (id, identifier, mandatory, filling, searchable, displayable) VALUES (15, 'phone', false, true, false, false);
INSERT INTO contacts_parameters (id, identifier, mandatory, filling, searchable, displayable) VALUES (16, 'notes', false, false, false, false);
INSERT INTO contacts_parameters (id, identifier, mandatory, filling, searchable, displayable) VALUES (17, 'sector', false, false, false, false);
INSERT INTO custom_fields (id, label, type, mode, "values") VALUES (1, 'Date de fin de contrat', 'date', 'form', '[]');
INSERT INTO custom_fields (id, label, type, mode, "values") VALUES (2, 'Adresse d''intervention', 'banAutocomplete', 'form', '[]');
......
......@@ -767,6 +767,7 @@ CREATE TABLE contacts
enabled boolean NOT NULL DEFAULT TRUE,
custom_fields jsonb DEFAULT '{}',
external_id jsonb DEFAULT '{}',
sector CHARACTER VARYING(256),
CONSTRAINT contacts_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
......@@ -1538,3 +1539,17 @@ CREATE TABLE tiles
CONSTRAINT tiles_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
CREATE TABLE address_sectors
(
id SERIAL NOT NULL,
address_number CHARACTER VARYING(256),
address_street CHARACTER VARYING(256),
address_postcode CHARACTER VARYING(256),
address_town CHARACTER VARYING(256),
label CHARACTER VARYING(256),
ban_id CHARACTER VARYING(256),
CONSTRAINT address_sectors_key UNIQUE (address_number, address_street, address_postcode, address_town),
CONSTRAINT address_sectors_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
......@@ -710,7 +710,7 @@ class ActionMethodController
if (!empty($listInstances[0])) {
$listInstances = $listInstances[0];
$set = ['process_date' => 'CURRENT_TIMESTAMP', 'process_comment' => _HAS_INTERRUPTED_WORKFLOW . ' (' . _VIA_ACTION . ' ' . $args['action']['label_action'] . ')'];
$set = ['process_date' => 'CURRENT_TIMESTAMP', 'process_comment' => _HAS_INTERRUPTED_WORKFLOW . ' (' . _VIA_ACTION . ' "' . $args['action']['label_action'] . '")'];
if ($listInstances['item_id'] != $GLOBALS['id']) {
$set['delegate'] = $GLOBALS['id'];
}
......@@ -731,7 +731,7 @@ class ActionMethodController
ListInstanceModel::update([
'set' => [
'process_date' => 'CURRENT_TIMESTAMP',
'process_comment' => _INTERRUPTED_WORKFLOW . ' (' . _VIA_ACTION . ' ' . $args['action']['label_action'] . ')'
'process_comment' => _INTERRUPTED_WORKFLOW . ' (' . _VIA_ACTION . ' "' . $args['action']['label_action'] . '")'
],
'where' => ['res_id = ?', 'difflist_type = ?', 'process_date is null'],
'data' => [$args['resId'], 'VISA_CIRCUIT']
......
......@@ -15,6 +15,7 @@ namespace Contact\controllers;
use AcknowledgementReceipt\models\AcknowledgementReceiptModel;
use Attachment\models\AttachmentModel;
use Contact\models\ContactAddressSectorModel;
use Contact\models\ContactCivilityModel;
use Contact\models\ContactCustomFieldListModel;
use Contact\models\ContactFillingModel;
......@@ -57,7 +58,8 @@ class ContactController
'addressCountry' => 'address_country',
'email' => 'email',
'phone' => 'phone',
'notes' => 'notes'
'notes' => 'notes',
'sector' => 'sector'
];
public function get(Request $request, Response $response)
......@@ -91,7 +93,7 @@ class ContactController
'select' => [
'id', 'firstname', 'lastname', 'company', 'address_number as "addressNumber"', 'address_street as "addressStreet"',
'address_additional1 as "addressAdditional1"', 'address_additional2 as "addressAdditional2"', 'address_postcode as "addressPostcode"',
'address_town as "addressTown"', 'address_country as "addressCountry"', 'enabled', 'count(1) OVER()'
'address_town as "addressTown"', 'address_country as "addressCountry"', 'enabled', 'sector', 'count(1) OVER()'
],
'where' => $requestData['where'] ?? null,
'data' => $requestData['data'] ?? null,
......@@ -168,6 +170,8 @@ class ContactController
$externalId = '{}';
}
$sector = ContactController::getAddressSector($body);
$id = ContactModel::create([
'civility' => $body['civility'] ?? null,
'firstname' => $body['firstname'] ?? null,
......@@ -189,7 +193,8 @@ class ContactController
'creator' => $GLOBALS['id'],
'enabled' => 'true',
'custom_fields' => !empty($body['customFields']) ? json_encode($body['customFields']) : '{}',
'external_id' => $externalId
'external_id' => $externalId,
'sector' => $sector['label'] ?? null
]);
$historyInfoContact = '';
......@@ -252,7 +257,8 @@ class ContactController
'creationDate' => $rawContact['creation_date'],
'modificationDate' => $rawContact['modification_date'],
'customFields' => !empty($rawContact['custom_fields']) ? json_decode($rawContact['custom_fields'], true) : null,
'externalId' => json_decode($rawContact['external_id'], true)
'externalId' => json_decode($rawContact['external_id'], true),
'sector' => $rawContact['sector']
];
if (!empty($rawContact['civility'])) {
......@@ -340,6 +346,8 @@ class ContactController
$externalId = '{}';
}
$sector = ContactController::getAddressSector($body);
ContactModel::update([
'set' => [
'civility' => $body['civility'] ?? null,
......@@ -361,7 +369,8 @@ class ContactController
'notes' => $body['notes'] ?? null,
'modification_date' => 'CURRENT_TIMESTAMP',
'custom_fields' => !empty($body['customFields']) ? json_encode($body['customFields']) : null,
'external_id' => $externalId
'external_id' => $externalId,
'sector' => $sector['label'] ?? null
],
'where' => ['id = ?'],
'data' => [$args['id']]
......@@ -1134,6 +1143,7 @@ class ContactController
'enabled' => 'enabled',
'customFields' => 'custom_fields',
'externalId' => 'external_id',
'sector' => 'sector'
];
$contactCustoms = ContactCustomFieldListModel::get(['select' => ['id']]);
......@@ -1745,7 +1755,10 @@ class ContactController
$address.= $args['contact']['address_town'] . ' ';
}
if (!empty($args['contact']['address_country'])) {
$address.= $args['contact']['address_country'];
$address.= $args['contact']['address_country'] . ' ';
}
if (!empty($args['contact']['sector'])) {
$address .= $args['contact']['sector'];
}
$contactName = '';
......@@ -1860,6 +1873,9 @@ class ContactController
if (in_array('notes', $displayableStdParameters)) {
$contact['notes'] = $rawContact['notes'];
}
if (in_array('sector', $displayableStdParameters)) {
$contact['sector'] = $rawContact['sector'];
}
if (!empty($displayableCstParameters)) {
$contact['customFields'] = [];
......@@ -1909,4 +1925,52 @@ class ContactController
return $contactsUsed;
}
private static function getAddressSector(array $args)
{
ValidatorModel::stringType($args, ['addressNumber', 'addressStreet', 'addressPostcode', 'addressTown']);
$where = [];
$data = [];
if (!empty($args['addressNumber'])) {
$where[] = 'address_number = ?';
$data[] = strtoupper($args['addressNumber']);
} else {
$where[] = 'address_number is null';
}
if (!empty($args['addressStreet'])) {
$where[] = 'address_street = ?';
$data[] = strtoupper($args['addressStreet']);
} else {
$where[] = 'address_street is null';
}
if (!empty($args['addressPostcode'])) {
$where[] = 'address_postcode = ?';
$data[] = strtoupper($args['addressPostcode']);
} else {
$where[] = 'address_postcode is null';
}
if (!empty($args['addressTown'])) {
$where[] = 'address_town = ?';
$data[] = strtoupper($args['addressTown']);
} else {
$where[] = 'address_town is null';
}
$sector = ContactAddressSectorModel::get([
'select' => ['*'],
'where' => $where,
'data' => $data
]);
if (empty($sector[0])) {
return null;
}
return $sector[0];
}
}
<?php
/**
* Copyright Maarch since 2008 under licence GPLv3.
* See LICENCE.txt file at the root folder for more details.
* This file is part of Maarch software.
*
*/
/**
* @brief Contact Address Sector Model
* @author dev@maarch.org
*/
namespace Contact\models;
use SrcCore\models\DatabaseModel;
use SrcCore\models\ValidatorModel;
class ContactAddressSectorModel
{
public static function get(array $args)
{
ValidatorModel::notEmpty($args, ['select']);
ValidatorModel::arrayType($args, ['select', 'where', 'data', 'orderBy']);
ValidatorModel::intType($args, ['limit']);
$sectors = DatabaseModel::select([
'select' => $args['select'],
'table' => ['address_sectors'],
'where' => empty($args['where']) ? [] : $args['where'],
'data' => empty($args['data']) ? [] : $args['data'],
'order_by' => empty($args['orderBy']) ? [] : $args['orderBy'],
'offset' => empty($args['offset']) ? 0 : $args['offset'],
'limit' => empty($args['limit']) ? 0 : $args['limit']
]);
return $sectors;
}
public static function getById(array $args)
{
ValidatorModel::notEmpty($args, ['id', 'select']);
ValidatorModel::intVal($args, ['id']);
ValidatorModel::arrayType($args, ['select']);
$sector = DatabaseModel::select([
'select' => $args['select'],
'table' => ['address_sectors'],
'where' => ['id = ?'],
'data' => [$args['id']]
]);
if (empty($sector[0])) {
return [];
}
return $sector[0];
}
public static function create(array $args)
{
ValidatorModel::notEmpty($args, ['label', 'abbreviation']);
ValidatorModel::stringType($args, ['label', 'abbreviation']);
$nextSequenceId = DatabaseModel::getNextSequenceValue(['sequenceId' => 'address_sectors_id_seq']);
DatabaseModel::insert([
'table' => 'address_sectors',
'columnsValues' => [
'id' => $nextSequenceId,
'label' => $args['label'],
'abbreviation' => $args['abbreviation']
]
]);
return $nextSequenceId;
}
public static function update(array $args)
{
ValidatorModel::notEmpty($args, ['set' ,'where', 'data']);
ValidatorModel::arrayType($args, ['set', 'where', 'data']);
DatabaseModel::update([
'table' => 'address_sectors',
'set' => $args['set'],
'where' => $args['where'],
'data' => $args['data']
]);
return true;
}
public static function delete(array $args)
{
ValidatorModel::notEmpty($args, ['where', 'data']);
ValidatorModel::arrayType($args, ['where', 'data']);
DatabaseModel::delete([
'table' => 'address_sectors',
'where' => $args['where'],
'data' => $args['data']
]);
return true;
}
}
......@@ -778,7 +778,7 @@ class SummarySheetController
$pdf->Cell($specialWidth * 3, 20, _USERS, 1, 0, 'L', false);
$pdf->Cell($specialWidth, 20, _ACTION_DATE, 1, 1, 'L', false);
foreach ($users as $keyUser => $user) {
$pdf->Cell($specialWidth * 3, 20, $keyUser + 1 . ". {$user['user']}", 1, 0, 'L', false);
$pdf->MultiCell($specialWidth * 3, 20, $keyUser + 1 . ". {$user['user']}", 1, 'L', false, 0,'', '', true, 0, false, true, 20, 'M', true);
$pdf->Cell($specialWidth, 20, $user['date'], 1, 1, 'L', false);
}
}
......
......@@ -578,7 +578,7 @@ export class ActionsService implements OnDestroy {
const dialogRef = this.dialog.open(SendExternalSignatoryBookActionComponent, {
panelClass: 'maarch-modal',
disableClose: true,
width: '500px',
width: '580px',
data: this.setDatasActionToSend()
});
dialogRef.afterClosed().pipe(
......
......@@ -2,7 +2,7 @@
<div class="fieldsetdContainer" style="flex:2">
<h2>{{'lang.visaWorkflow' | translate}} :</h2>
<div class="fieldsetdContent">
<app-external-visa-workflow #appExternalVisaWorkflow [adminMode]="true" [injectDatas]="injectDatasParam"></app-external-visa-workflow >
<app-external-visa-workflow #appExternalVisaWorkflow [adminMode]="true" [resId]="resIds.length === 1 ? resIds[0] : null" [injectDatas]="injectDatasParam"></app-external-visa-workflow >
<div *ngIf="appExternalVisaWorkflow.checkExternalSignatoryBook().length > 0"
class="alert-message alert-message-danger" role="alert">
<b>{{appExternalVisaWorkflow.checkExternalSignatoryBook().join(', ')}}</b>
......
......@@ -18,6 +18,7 @@ export class MaarchParaphComponent implements OnInit {
@ViewChild('appExternalVisaWorkflow', { static: true }) appExternalVisaWorkflow: ExternalVisaWorkflowComponent;
@Input() resIds: number[] = [];
@Input() resourcesToSign: any[] = [];
@Input() additionalsInfos: any;
@Input() externalSignatoryBookDatas: any;
......
......@@ -44,6 +44,7 @@
[externalSignatoryBookDatas]="externalSignatoryBookDatas">
</app-fast-paraph>
<app-maarch-paraph #maarchParapheur *ngIf="signatoryBookEnabled=='maarchParapheur'"
[resIds]="data.resIds"
[resourcesToSign]="resourcesToSign"
[additionalsInfos]="additionalsInfos"
[externalSignatoryBookDatas]="externalSignatoryBookDatas">
......
......@@ -275,7 +275,7 @@
</button>
</mat-list-item>
<ng-container
*ngIf="unit.id === 'address' && addressBANMode && ['addressAdditional1', 'addressAdditional2'].indexOf(field.id) > -1">
*ngIf="unit.id === 'address' && addressBANMode && ['addressAdditional1', 'addressAdditional2', 'sector'].indexOf(field.id) > -1">
<mat-list-item class="contact-item">
<p mat-line class="contact-content" *ngIf="field.display">
<mat-form-field>
......
......@@ -255,6 +255,17 @@ export class ContactsFormComponent implements OnInit {
filling: false,
values: []
},
{
id: 'sector',
unit: 'address',
label: this.translate.instant('lang.contactsParameters_sector'),
type: 'string',
control: new FormControl({value: '', disabled: true}),
required: false,
display: true,
filling: false,
values: []
},
{
id: 'communicationMeans',
unit: 'maarch2maarch',
......
......@@ -138,7 +138,7 @@ import { SignatureBookComponent } from './signature-book.component';
import { VisaWorkflowModalComponent } from './visa/modal/visa-workflow-modal.component';
import { ExternalVisaWorkflowComponent } from './visa/externalVisaWorkflow/external-visa-workflow.component';
import { ProfileContactsGroupsComponent } from './profile/contacts-groups/profile-contacts-groups.component';
import { CreateUserOtpComponent } from './visa/externalVisaWorkflow/createUserOtp/create-user-otp.component';
import { CreateExternalUserComponent } from './visa/externalVisaWorkflow/createExternalUser/create-external-user.component';
import { EditorOptionComponent } from './profile/parameters/editorOption/editor-option.component';
import { BasketColorComponent } from './profile/parameters/basketsColor/basket-color.component';
......@@ -295,7 +295,7 @@ export class MyHammerConfig extends HammerGestureConfig {
ProfileHistoryComponent,
ProfileOtherPluginComponent,
AddinOutlookConfigurationModalComponent,
CreateUserOtpComponent
CreateExternalUserComponent
],
exports : [
SharedModule
......
......@@ -73,6 +73,8 @@
{{option.addressTown}} </p>
<p mat-line class="contact-content" *ngIf="!empty(option.addressCountry)"
[title]="option.addressCountry"> {{option.addressCountry}} </p>
<p mat-line class="contact-content" *ngIf="!empty(option.sector)"
[title]="option.sector"> {{option.sector}} </p>
</mat-list-item>
<mat-list-item class="contact-item" *ngIf="!empty(option.notes)">
<mat-icon mat-list-icon class="contact-group far fa-sticky-note" [title]="'lang.note' | translate">
......
......@@ -76,6 +76,11 @@
<p mat-line class="contact-content" *ngIf="!functionsService.empty(contact.addressCountry)"
[class.newData]="isNewValue('addressCountry')"> {{contact.addressCountry}} </p>
</mat-list-item>
<mat-list-item class="contact-item" *ngIf="!functionsService.empty(contact.sector)">
<mat-icon mat-list-icon class="contact-group fas fa-map-marked-alt" [title]="'lang.contactsParameters_sector' | translate">
</mat-icon>
<p mat-line class="contact-content"> {{contact.sector}}</p>
</mat-list-item>
</mat-list>
<mat-expansion-panel *ngIf="!emptyOtherInfo(contact)" [expanded]="selectable">
<mat-expansion-panel-header>
......
......@@ -12,7 +12,7 @@
</div>
<div class="actions-indexing-form">
<ng-container
*ngIf="actionsList.length > 0 && indexingForm !== undefined && selectedAction !== undefined">
*ngIf="actionsListLoaded && actionsList.length > 0 && indexingForm !== undefined && selectedAction !== undefined">
<button mat-button class="button-form-primary" [disabled]="selectedAction.id === 0"
[matMenuTriggerFor]="menu" style="width:350px;margin-right:20px;"
[title]="selectedAction.label">
......@@ -52,7 +52,7 @@
<mat-icon class="fa fa-check"></mat-icon>
</button>
</ng-container>
<div class="emptyAction" *ngIf="actionsList.length === 0"
<div class="emptyAction" *ngIf="actionsListLoaded && actionsList.length === 0"
[innerHTML]="'lang.noAvailableAction' | translate"></div>
</div>
</ng-container>
......@@ -95,4 +95,4 @@
autoFocus="false">
<app-indexation-attachments-list #appIndexationAttachmentsList></app-indexation-attachments-list>
</mat-sidenav>
</mat-sidenav-container>
\ No newline at end of file
</mat-sidenav-container>
......@@ -13,9 +13,9 @@ import { AppService } from '@service/app.service';
import { IndexingFormComponent } from './indexing-form/indexing-form.component';
import { tap, finalize, catchError, map, filter, take } from 'rxjs/operators';
import { DocumentViewerComponent } from '../viewer/document-viewer.component';
import { ConfirmComponent } from '../../plugins/modal/confirm.component';
import { ConfirmComponent } from '@plugins/modal/confirm.component';
import { ActionsService } from '../actions/actions.service';
import { SortPipe } from '../../plugins/sorting.pipe';
import { SortPipe } from '@plugins/sorting.pipe';
import { FunctionsService } from '@service/functions.service';
import { of, Subscription } from 'rxjs';
import { SelectIndexingModelComponent } from './select-indexing-model/select-indexing-model.component';
......@@ -46,6 +46,7 @@ export class IndexationComponent implements OnInit, OnDestroy {
currentGroupId: number;
actionsList: any[] = [];
actionsListLoaded: boolean = false;
selectedAction: any = {
id: 0,
label: '',
......@@ -136,6 +137,7 @@ export class IndexationComponent implements OnInit, OnDestroy {
tap((data: any) => {
this.selectedAction = data.actions[0];
this.actionsList = data.actions;
this.actionsListLoaded = true;
}),
finalize(() => this.loading = false),
catchError((err: any) => {
......
......@@ -155,7 +155,7 @@
</ng-template>
</div>
<div class="actions-indexing-form" *ngIf="!detailMode">
<ng-container *ngIf="actionsList.length > 0 && selectedAction !== undefined">
<ng-container *ngIf="actionsListLoaded && actionsList.length > 0 && selectedAction !== undefined">
<button mat-button class="button-form-primary" [disabled]="selectedAction.id === 0"
[matMenuTriggerFor]="menu" style="width:350px;margin-right:20px;" [title]="selectedAction.label">
<span class="menu-label" [innerHTML]="selectedAction.label">
......@@ -190,7 +190,7 @@
<mat-icon class="fa fa-check"></mat-icon>
</button>
</ng-container>
<div class="emptyAction" *ngIf="actionsList.length === 0"
<div class="emptyAction" *ngIf="actionsListLoaded && actionsList.length === 0"
[innerHTML]="'lang.noAvailableActionProcess' | translate"></div>
</div>
</ng-template>
......
......@@ -15,7 +15,7 @@ import { ActionsService } from '../actions/actions.service';
import { tap, catchError, map, finalize, filter, take } from 'rxjs/operators';
import { DocumentViewerComponent } from '../viewer/document-viewer.component';
import { IndexingFormComponent } from '../indexation/indexing-form/indexing-form.component';
import { ConfirmComponent } from '../../plugins/modal/confirm.component';
import { ConfirmComponent } from '@plugins/modal/confirm.component';
import { ContactResourceModalComponent } from '../contact/contact-resource/modal/contact-resource-modal.component';
import { DiffusionsListComponent } from '../diffusions/diffusions-list.component';
......@@ -57,6 +57,7 @@ export class ProcessComponent implements OnInit, OnDestroy {
isMailing: boolean = false;
isFromSearch: boolean = false;
actionsList: any[] = [];
actionsListLoaded: boolean = false;
currentUserId: number = null;
currentBasketId: number = null;
currentGroupId: number = null;
......@@ -282,6 +283,7 @@ export class ProcessComponent implements OnInit, OnDestroy {
tap((data: any) => {
this.selectedAction = data.actions[0];
this.actionsList = data.actions;
this.actionsListLoaded = true;
}),
catchError((err: any) => {
this.notify.handleErrors(err);
......
......@@ -281,7 +281,11 @@ export class SentResourceListComponent implements OnInit {
tap(() => {
this.refreshEmailList();
setTimeout(() => {
this.refreshWaitingElements();
this.refreshWaitingElements(1);
setTimeout(() => {
this.dataSource = new MatTableDataSource(this.sentResources);
this.dataSource.sort = this.sort;
}, 0);
}, 5000);
}),
catchError((err: any) => {
......@@ -316,32 +320,34 @@ export class SentResourceListComponent implements OnInit {
}
}
refreshWaitingElements() {
this.sentResources.forEach((draftElement: any) => {
if (draftElement.status == 'WAITING' && draftElement.type == 'email') {
this.http.get(`../rest/emails/${draftElement.id}`).pipe(
tap((data: any) => {
if (data.status == 'SENT' || data.status == 'ERROR') {
if (data.status == 'SENT') {
this.notify.success(this.translate.instant('lang.emailSent'));
} else {
this.notify.error(this.translate.instant('lang.emailCannotSent'));
}
this.sentResources.forEach((element: any, key: number) => {
if (element.id == draftElement.id && element.type == 'email') {
this.sentResources[key].status = data.status;
this.sentResources[key].sendDate = data.sendDate;
refreshWaitingElements(countTry: number) {
if (countTry < 6) {
this.sentResources.forEach((draftElement: any) => {
if (draftElement.status == 'WAITING' && draftElement.type == 'email') {
this.http.get(`../rest/emails/${draftElement.id}`).pipe(
tap((data: any) => {
if (data.status == 'SENT' || data.status == 'ERROR') {
if (data.status == 'SENT') {
this.notify.success(this.translate.instant('lang.emailSent'));
} else {
this.notify.error(this.translate.instant('lang.emailCannotSent'));
}
});
}
})
).subscribe();
}
});
setTimeout(() => {
this.dataSource = new MatTableDataSource(this.sentResources);