diff --git a/CHANGELOG.md b/CHANGELOG.md index c088e411e..5def72ccb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,12 +7,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [2.14.0] - UNRELEASED ### Added - Aggiunto piano ferie 15+2 - + - Aggiunto servizio REST per esportazione lista delle sedi + - Aggiunto campo externalId ai tipi di assenza + ### Changed - Corretta lista persone in Straordinario mensili gruppo, filtrando le persone non più affiliate - Cambiata la gestione dei codici 71D e seguenti con la stessa logica del 7M - Corretta possibilità di inserire più richieste di cambio reperibilità non ancora confermate nello stesso mese - + - Nell'esportazione via REST del riepilogo mensile dei dipendenti aggiunto nuovo campo externalId del tipo di assenza ## [2.13.0] - 2024-02-13 ### Added diff --git a/app/cnr/sync/dto/v3/AbsenceShowTerseDto.java b/app/cnr/sync/dto/v3/AbsenceShowTerseDto.java index 6b452e993..112688080 100644 --- a/app/cnr/sync/dto/v3/AbsenceShowTerseDto.java +++ b/app/cnr/sync/dto/v3/AbsenceShowTerseDto.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2023 Consiglio Nazionale delle Ricerche + * Copyright (C) 2024 Consiglio Nazionale delle Ricerche * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -14,7 +14,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - package cnr.sync.dto.v3; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -49,8 +48,9 @@ public class AbsenceShowTerseDto { private String justifiedType; private String note; private String externalId; + private String externalTypeId; private LocalDateTime updatedAt; - + @JsonIgnore @Inject static ModelMapper modelMapper; @@ -69,6 +69,7 @@ public static AbsenceShowTerseDto build(Absence absence) { absenceDto.setDate(JodaConverters.jodaToJavaLocalDate(absence.getAbsenceDate())); if (absence.getAbsenceType() != null) { absenceDto.setAbsenceTypeId(absence.getAbsenceType().getId()); + absenceDto.setExternalTypeId(absence.getAbsenceType().getExternalId()); } return absenceDto; } diff --git a/app/cnr/sync/dto/v3/OfficeShowTerseDto.java b/app/cnr/sync/dto/v3/OfficeShowTerseDto.java new file mode 100644 index 000000000..53fa2650b --- /dev/null +++ b/app/cnr/sync/dto/v3/OfficeShowTerseDto.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2024 Consiglio Nazionale delle Ricerche + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ +package cnr.sync.dto.v3; + +import cnr.sync.dto.v2.GroupShowDto; +import cnr.sync.dto.v2.PersonShowTerseDto; +import helpers.validators.PeriodEndDateCheck; +import java.time.LocalDateTime; +import javax.persistence.Column; +import javax.persistence.FetchType; +import javax.persistence.ManyToOne; +import javax.validation.constraints.NotNull; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.val; +import models.Institute; +import models.Office; +import models.Person; +import org.joda.time.LocalDate; +import org.modelmapper.ModelMapper; +import play.data.validation.CheckWith; +import play.data.validation.Required; +import play.data.validation.Unique; + +/** + * Dati esportati in Json per l'Ufficio. + * + * @author Cristian Lucchesi + * + */ +@ToString +@Data +public class OfficeShowTerseDto { + + private Long id; + private Long perseoId; + private String name; + + //Codice della sede, per esempio per la sede di Pisa è "044000" + private String code; + + //sedeId, serve per l'invio degli attestati, per esempio per la sede di Pisa è "223400" + private String codeId; + private String address; + private LocalDate joiningDate; + private LocalDate beginDate; + private LocalDate endDate; + + private Long instituteId; + private boolean headQuarter = false; + private LocalDateTime updatedAt; + + /** + * Nuova instanza di un OfficeShowTerseDto contenente i valori + * dell'oggetto Office passato. + */ + public static OfficeShowTerseDto build(Office office) { + ModelMapper modelMapper = new ModelMapper(); + modelMapper.getConfiguration().setAmbiguityIgnored(true); + val officeDto = modelMapper.map(office, OfficeShowTerseDto.class); + if (office.getInstitute() != null) { + officeDto.setInstituteId(office.getInstitute().getId()); + } + return officeDto; + } +} \ No newline at end of file diff --git a/app/cnr/sync/dto/v3/PersonDayShowDto.java b/app/cnr/sync/dto/v3/PersonDayShowDto.java index 5c1c17629..e4009e9b8 100644 --- a/app/cnr/sync/dto/v3/PersonDayShowDto.java +++ b/app/cnr/sync/dto/v3/PersonDayShowDto.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Consiglio Nazionale delle Ricerche + * Copyright (C) 2024 Consiglio Nazionale delle Ricerche * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -14,7 +14,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - package cnr.sync.dto.v3; import cnr.sync.dto.v2.PersonShowTerseDto; diff --git a/app/controllers/rest/v2/Groups.java b/app/controllers/rest/v2/Groups.java index 4a2f4a647..49d1f489f 100644 --- a/app/controllers/rest/v2/Groups.java +++ b/app/controllers/rest/v2/Groups.java @@ -26,6 +26,7 @@ import com.google.gson.GsonBuilder; import common.security.SecurityRules; import controllers.Resecure; +import controllers.rest.v3.Offices; import dao.GroupDao; import helpers.JsonResponse; import helpers.rest.RestUtils; diff --git a/app/controllers/rest/v2/Leaves.java b/app/controllers/rest/v2/Leaves.java index be550d438..b2388e431 100644 --- a/app/controllers/rest/v2/Leaves.java +++ b/app/controllers/rest/v2/Leaves.java @@ -25,6 +25,7 @@ import com.google.gson.GsonBuilder; import common.security.SecurityRules; import controllers.Resecure; +import controllers.rest.v3.Offices; import dao.AbsenceDao; import dao.PersonDao; import helpers.JodaConverters; diff --git a/app/controllers/rest/v2/Persons.java b/app/controllers/rest/v2/Persons.java index 57ec2e986..73f03f539 100644 --- a/app/controllers/rest/v2/Persons.java +++ b/app/controllers/rest/v2/Persons.java @@ -29,6 +29,7 @@ import common.security.SecurityRules; import controllers.Resecure; import controllers.Resecure.BasicAuth; +import controllers.rest.v3.Offices; import dao.PersonDao; import helpers.JodaConverters; import helpers.JsonResponse; diff --git a/app/controllers/rest/v2/WorkingTimeTypes.java b/app/controllers/rest/v2/WorkingTimeTypes.java index 0255c46dc..d70795d10 100644 --- a/app/controllers/rest/v2/WorkingTimeTypes.java +++ b/app/controllers/rest/v2/WorkingTimeTypes.java @@ -22,6 +22,7 @@ import com.google.gson.GsonBuilder; import common.security.SecurityRules; import controllers.Resecure; +import controllers.rest.v3.Offices; import dao.WorkingTimeTypeDao; import helpers.JsonResponse; import helpers.rest.RestUtils; diff --git a/app/controllers/rest/v3/BadgeReaders.java b/app/controllers/rest/v3/BadgeReaders.java index 009b5c67b..403850ca0 100644 --- a/app/controllers/rest/v3/BadgeReaders.java +++ b/app/controllers/rest/v3/BadgeReaders.java @@ -22,7 +22,6 @@ import com.google.gson.GsonBuilder; import common.security.SecurityRules; import controllers.Resecure; -import controllers.rest.v2.Offices; import dao.BadgeReaderDao; import helpers.JsonResponse; import helpers.rest.RestUtils; diff --git a/app/controllers/rest/v3/BadgeSystems.java b/app/controllers/rest/v3/BadgeSystems.java index d4442bb50..e73c3460b 100644 --- a/app/controllers/rest/v3/BadgeSystems.java +++ b/app/controllers/rest/v3/BadgeSystems.java @@ -22,7 +22,6 @@ import com.google.gson.GsonBuilder; import common.security.SecurityRules; import controllers.Resecure; -import controllers.rest.v2.Offices; import dao.BadgeSystemDao; import helpers.JsonResponse; import helpers.rest.RestUtils; diff --git a/app/controllers/rest/v3/Badges.java b/app/controllers/rest/v3/Badges.java index cf3bdac4c..263de6b1a 100644 --- a/app/controllers/rest/v3/Badges.java +++ b/app/controllers/rest/v3/Badges.java @@ -26,7 +26,6 @@ import com.google.gson.GsonBuilder; import common.security.SecurityRules; import controllers.Resecure; -import controllers.rest.v2.Offices; import controllers.rest.v2.Persons; import dao.BadgeDao; import dao.BadgeSystemDao; diff --git a/app/controllers/rest/v2/Offices.java b/app/controllers/rest/v3/Offices.java similarity index 59% rename from app/controllers/rest/v2/Offices.java rename to app/controllers/rest/v3/Offices.java index 5dc6bf0b3..c7f56fd27 100644 --- a/app/controllers/rest/v2/Offices.java +++ b/app/controllers/rest/v3/Offices.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Consiglio Nazionale delle Ricerche + * Copyright (C) 2024 Consiglio Nazionale delle Ricerche * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -14,15 +14,26 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +package controllers.rest.v3; -package controllers.rest.v2; - +import cnr.sync.dto.v3.OfficeShowTerseDto; +import com.beust.jcommander.internal.Lists; import com.google.common.base.Optional; +import com.google.gson.GsonBuilder; import common.security.SecurityRules; import controllers.Resecure; +import controllers.Resecure.BasicAuth; import dao.OfficeDao; +import helpers.JodaConverters; import helpers.JsonResponse; +import helpers.rest.RestUtils; +import helpers.rest.RestUtils.HttpMethod; +import it.cnr.iit.epas.DateUtility; +import java.time.LocalDate; +import java.util.List; +import java.util.stream.Collectors; import javax.inject.Inject; +import lombok.val; import lombok.extern.slf4j.Slf4j; import models.Office; import play.mvc.Controller; @@ -40,6 +51,38 @@ public class Offices extends Controller { static OfficeDao officeDao; @Inject static SecurityRules rules; + @Inject + static GsonBuilder gsonBuilder; + + /** + * Lista JSON delle persone che appartengono alla sede + * individuata con i parametri passati. + */ + @BasicAuth + public static void all(LocalDate atDate) { + RestUtils.checkMethod(request, HttpMethod.GET); + log.debug("rest.Offices::all atDate = {}", atDate); + List offices = Lists.newArrayList(); + if (atDate != null) { + offices = officeDao.allOffices(JodaConverters.javaToJodaLocalDate(atDate)); + } else { + offices = officeDao.allEnabledOffices(); + } + val list = + offices.stream().map(o -> OfficeShowTerseDto.build(o)).collect(Collectors.toList()); + renderJSON(gsonBuilder.create().toJson(list)); + } + + /** + * Restituisce il JSON con i dati dell'ufficio individuato con i parametri + * passati. + */ + public static void show(Long id, String code, String codeId) { + RestUtils.checkMethod(request, HttpMethod.GET); + val office = getOfficeFromRequest(id, code, codeId); + rules.checkIfPermitted(office); + renderJSON(gsonBuilder.create().toJson(OfficeShowTerseDto.build(office))); + } /** * Cerca l'ufficio in funzione dei parametri passati. diff --git a/app/controllers/rest/v3/PersonDays.java b/app/controllers/rest/v3/PersonDays.java index 7503ebd44..0c569a0f3 100755 --- a/app/controllers/rest/v3/PersonDays.java +++ b/app/controllers/rest/v3/PersonDays.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2022 Consiglio Nazionale delle Ricerche + * Copyright (C) 2024 Consiglio Nazionale delle Ricerche * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -14,7 +14,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - package controllers.rest.v3; import cnr.sync.dto.v2.PersonShowTerseDto; @@ -29,7 +28,6 @@ import common.security.SecurityRules; import controllers.PersonDays.MealTicketDecision; import controllers.Resecure; -import controllers.rest.v2.Offices; import controllers.rest.v2.Persons; import dao.PersonDao; import dao.PersonDayDao; @@ -43,8 +41,8 @@ import java.util.Set; import java.util.stream.Collectors; import javax.inject.Inject; -import lombok.extern.slf4j.Slf4j; import lombok.val; +import lombok.extern.slf4j.Slf4j; import manager.ConsistencyManager; import manager.PersonManager; import models.Office; @@ -120,7 +118,7 @@ public static void getMonthSituationByOffice(Long id, String code, String codeId } val office = Offices.getOfficeFromRequest(id, code, Strings.isNullOrEmpty(codeId) ? sedeId : codeId); - rules.checkIfPermitted(office); + rules.checkIfPermitted(office); org.joda.time.LocalDate date = new org.joda.time.LocalDate(year, month, 1); @@ -132,15 +130,15 @@ public static void getMonthSituationByOffice(Long id, String code, String codeId personDays.stream().collect(Collectors.groupingBy(PersonDay::getPerson)); List monthRecaps = Lists.newArrayList(); - personDayMap.forEach((p, pds) -> { - monthRecaps.add(PersonMonthRecapDto.builder() - .person(PersonShowTerseDto.build(p)) - .year(year).month(month) - .personDays( - pds.stream().map(pd -> PersonDayShowTerseDto.build(pd)) - .collect(Collectors.toList())) - .build()); - }); + personDayMap.forEach((p, pds) -> { + monthRecaps.add(PersonMonthRecapDto.builder() + .person(PersonShowTerseDto.build(p)) + .year(year).month(month) + .personDays( + pds.stream().map(pd -> PersonDayShowTerseDto.build(pd)) + .collect(Collectors.toList())) + .build()); + }); val gson = gsonBuilder.create(); renderJSON(gson.toJson(monthRecaps)); @@ -205,7 +203,7 @@ public static void getMonthSituationByPerson(Long id, String email, String eppn, .collect(Collectors.toList())) .build(); val gson = gsonBuilder.create(); - renderJSON(gson.toJson(monthRecap)); + renderJSON(gson.toJson(monthRecap)); } /** diff --git a/app/dao/OfficeDao.java b/app/dao/OfficeDao.java index 0199b4c38..45b1967dc 100755 --- a/app/dao/OfficeDao.java +++ b/app/dao/OfficeDao.java @@ -316,4 +316,11 @@ public List allEnabledOffices() { .or(office.endDate.after(LocalDate.now()))).fetch(); } + public List allOffices(LocalDate atDate) { + final QOffice office = QOffice.office; + BooleanBuilder conditions = new BooleanBuilder(office.beginDate.before(atDate)); + conditions.and(office.endDate.isNull().or(office.endDate.after(atDate))); + return queryFactory.selectFrom(office).where(conditions).fetch(); + } + } diff --git a/app/helpers/LocalDateJavaBinder.java b/app/helpers/LocalDateJavaBinder.java index f618439ca..78ac35297 100644 --- a/app/helpers/LocalDateJavaBinder.java +++ b/app/helpers/LocalDateJavaBinder.java @@ -33,7 +33,8 @@ public class LocalDateJavaBinder implements TypeBinder { //Questo formato è utilizzato nelle form HTML - static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy"); + static final String ITALIAN_DATE_PATTERN = "dd/MM/yyyy"; + static final DateTimeFormatter dtf = DateTimeFormatter.ofPattern(ITALIAN_DATE_PATTERN); @SuppressWarnings("rawtypes") @Override @@ -45,7 +46,7 @@ public Object bind(String name, Annotation[] annotations, String value, try { return LocalDate.parse(value, dtf); } catch (Exception ignored) { - log.debug("Exception during java LocalDate binding, value={}", value); + log.debug("Enable to bind java LocalDate using pattern {}, value={}", ITALIAN_DATE_PATTERN, value); } //Nei metodi REST le date vengono passate nel formato ISO return LocalDate.from(DateTimeFormatter.ISO_LOCAL_DATE.parse(value)); diff --git a/app/models/absences/AbsenceType.java b/app/models/absences/AbsenceType.java index b80ad5db6..757b30e2a 100755 --- a/app/models/absences/AbsenceType.java +++ b/app/models/absences/AbsenceType.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021 Consiglio Nazionale delle Ricerche + * Copyright (C) 2024 Consiglio Nazionale delle Ricerche * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as @@ -14,7 +14,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ - package models.absences; import com.google.common.base.Joiner; @@ -158,6 +157,9 @@ public class AbsenceType extends BaseModel { private boolean shiftCompatible; private boolean isRealAbsence = true; + + private String externalId; + // Metodi /** diff --git a/app/views/AbsenceGroups/editAbsenceType.html b/app/views/AbsenceGroups/editAbsenceType.html index 1db843d24..3e915c0fb 100755 --- a/app/views/AbsenceGroups/editAbsenceType.html +++ b/app/views/AbsenceGroups/editAbsenceType.html @@ -57,8 +57,10 @@ #{f.booleanRadio 'absenceType.reperibilityCompatible', custom_popover:'true' /} #{f.booleanRadio 'absenceType.shiftCompatible', custom_popover:'true' /} + #{f.input 'absenceType.externalId',custom_popover:'true' /} #{f.booleanRadio 'absenceType.toUpdate', custom_popover:'true' /} +
#{secure.check 'AbsenceGroups.saveAbsenceType' } diff --git a/conf/messages.it b/conf/messages.it index 9b2a22d45..564bb2a54 100755 --- a/conf/messages.it +++ b/conf/messages.it @@ -1536,6 +1536,8 @@ absenceType.timeForMealTicket=Considerato per buono pasto absenceType.justifiedTime=Minuti specificati nel tipo assenza absenceType.toUpdate=Aggiornamento stato assenza absenceType.mealTicketBehaviour =Comportamento per buono pasto +absenceType.externalId =External id +absenceType.externalId.popover =External id utilizzabile anche per il raggruppamento delle assenze per i timesheet absenceType.replacingTime=Minuti per completamento absenceType.used=Usato diff --git a/conf/permissions.drl b/conf/permissions.drl index 57446629b..b2919f451 100755 --- a/conf/permissions.drl +++ b/conf/permissions.drl @@ -4128,7 +4128,10 @@ when "rest.Absences.attachment", "rest.v3.AbsenceTypes.list", - "rest.v3.AbsenceTypes.show" + "rest.v3.AbsenceTypes.show", + + "rest.v3.Offices.all", + "rest.v3.Offices.show" ), granted == false) then diff --git a/db/evolutions/213.sql b/db/evolutions/213.sql new file mode 100644 index 000000000..e5f8c4407 --- /dev/null +++ b/db/evolutions/213.sql @@ -0,0 +1,9 @@ +# --- !Ups + +ALTER TABLE absence_types ADD COLUMN external_id TEXT; +ALTER TABLE absence_types_history ADD COLUMN external_id TEXT; + +# --- !Downs + +ALTER TABLE absence_types DROP COLUMN external_id; +ALTER TABLE absence_types_history DROP COLUMN external_id; \ No newline at end of file