diff --git a/openapi/openapi.json b/openapi/openapi.json index 2333cb3b3..ee0d613a0 100644 --- a/openapi/openapi.json +++ b/openapi/openapi.json @@ -1201,7 +1201,7 @@ ], "responses": { "200": { - "description": "Created", + "description": "OK", "headers": { "X-Request-Id": { "description": "This header identifies the call", @@ -1451,6 +1451,163 @@ } ] }, + "/brokers/{brokercode}/station-maintenances/summary": { + "get": { + "tags": [ + "Creditor Institutions" + ], + "summary": "Get the hours' summary of stations' maintenance for the specified broker", + "operationId": "getBrokerMaintenancesSummary", + "parameters": [ + { + "name": "brokercode", + "in": "path", + "description": "Broker's tax code", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "maintenanceYear", + "in": "query", + "description": "Year of maintenance (yyyy)", + "required": true, + "schema": { + "maxLength": 4, + "minLength": 4, + "type": "string" + }, + "example": 2024 + } + ], + "responses": { + "200": { + "description": "OK", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MaintenanceHoursSummaryResource" + } + } + } + }, + "400": { + "description": "Bad Request", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemJson" + } + } + } + }, + "401": { + "description": "Unauthorized", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + } + }, + "403": { + "description": "Forbidden", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Not Found", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemJson" + } + } + } + }, + "429": { + "description": "Too many requests", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Service unavailable", + "headers": { + "X-Request-Id": { + "description": "This header identifies the call", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ProblemJson" + } + } + } + } + }, + "security": [ + { + "ApiKey": [] + }, + { + "Authorization": [] + } + ] + }, + "parameters": [ + { + "name": "X-Request-Id", + "in": "header", + "description": "This header identifies the call, if not passed it is self-generated. This ID is returned in the response.", + "schema": { + "type": "string" + } + } + ] + }, "/brokers/{brokercode}/station-maintenances/{maintenanceid}": { "put": { "tags": [ @@ -1491,7 +1648,7 @@ }, "responses": { "200": { - "description": "Created", + "description": "OK", "headers": { "X-Request-Id": { "description": "This header identifies the call", @@ -20490,6 +20647,38 @@ "$ref": "#/components/schemas/PageInfo" } } + }, + "MaintenanceHoursSummaryResource": { + "required": [ + "annual_hours_limit", + "extra_hours", + "remaining_hours", + "scheduled_hours", + "used_hours" + ], + "type": "object", + "properties": { + "used_hours": { + "type": "string", + "description": "Count of used maintenance's hours" + }, + "scheduled_hours": { + "type": "string", + "description": "Count of scheduled maintenance's hours" + }, + "remaining_hours": { + "type": "string", + "description": "Count of remaining maintenance's hours before annual limit" + }, + "extra_hours": { + "type": "string", + "description": "Count of maintenance's hours that exceed annual limit" + }, + "annual_hours_limit": { + "type": "string", + "description": "Annual limit of maintenance hours" + } + } } }, "securitySchemes": { diff --git a/src/main/java/it/gov/pagopa/apiconfig/core/controller/StationMaintenanceController.java b/src/main/java/it/gov/pagopa/apiconfig/core/controller/StationMaintenanceController.java index ea104c7e3..47aa6015f 100644 --- a/src/main/java/it/gov/pagopa/apiconfig/core/controller/StationMaintenanceController.java +++ b/src/main/java/it/gov/pagopa/apiconfig/core/controller/StationMaintenanceController.java @@ -10,6 +10,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import it.gov.pagopa.apiconfig.core.model.ProblemJson; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.CreateStationMaintenance; +import it.gov.pagopa.apiconfig.core.model.stationmaintenance.MaintenanceHoursSummaryResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.StationMaintenanceListResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.StationMaintenanceResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.UpdateStationMaintenance; @@ -35,6 +36,7 @@ import javax.validation.constraints.NotNull; import javax.validation.constraints.Positive; import javax.validation.constraints.PositiveOrZero; +import javax.validation.constraints.Size; import java.time.OffsetDateTime; @RestController @@ -53,7 +55,7 @@ public StationMaintenanceController(StationMaintenanceService stationMaintenance @Operation(summary = "Get a paginated list of station's maintenance for the specified broker", security = {@SecurityRequirement(name = "ApiKey"), @SecurityRequirement(name = "Authorization")}) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Created", + @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = StationMaintenanceListResource.class))), @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ProblemJson.class))), @@ -118,7 +120,7 @@ public ResponseEntity createStationMaintenance( @Operation(summary = "Update a maintenance for the specified station", security = {@SecurityRequirement(name = "ApiKey"), @SecurityRequirement(name = "Authorization")}) @ApiResponses(value = { - @ApiResponse(responseCode = "200", description = "Created", + @ApiResponse(responseCode = "200", description = "OK", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = StationMaintenanceResource.class))), @ApiResponse(responseCode = "400", description = "Bad Request", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ProblemJson.class))), @@ -141,4 +143,27 @@ public ResponseEntity updateStationMaintenance( updateStationMaintenance(brokerCode, maintenanceId, updateStationMaintenance) ); } + + @Operation(summary = "Get the hours' summary of stations' maintenance for the specified broker", + security = {@SecurityRequirement(name = "ApiKey"), @SecurityRequirement(name = "Authorization")}) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "OK", + content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = MaintenanceHoursSummaryResource.class))), + @ApiResponse(responseCode = "400", description = "Bad Request", + content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ProblemJson.class))), + @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(schema = @Schema())), + @ApiResponse(responseCode = "403", description = "Forbidden", content = @Content(schema = @Schema())), + @ApiResponse(responseCode = "404", description = "Not Found", + content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ProblemJson.class))), + @ApiResponse(responseCode = "429", description = "Too many requests", content = @Content(schema = @Schema())), + @ApiResponse(responseCode = "500", description = "Service unavailable", + content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ProblemJson.class))) + }) + @GetMapping(value = "/{brokercode}/station-maintenances/summary", produces = {MediaType.APPLICATION_JSON_VALUE}) + public ResponseEntity getBrokerMaintenancesSummary( + @Parameter(description = "Broker's tax code") @PathVariable("brokercode") String brokerCode, + @Parameter(description = "Year of maintenance (yyyy)", example = "2024") @RequestParam @Size(min = 4, max = 4) String maintenanceYear + ) { + return ResponseEntity.ok(this.stationMaintenanceService.getBrokerMaintenancesSummary(brokerCode, maintenanceYear)); + } } diff --git a/src/main/java/it/gov/pagopa/apiconfig/core/model/stationmaintenance/MaintenanceHoursSummaryResource.java b/src/main/java/it/gov/pagopa/apiconfig/core/model/stationmaintenance/MaintenanceHoursSummaryResource.java new file mode 100644 index 000000000..6386504c4 --- /dev/null +++ b/src/main/java/it/gov/pagopa/apiconfig/core/model/stationmaintenance/MaintenanceHoursSummaryResource.java @@ -0,0 +1,47 @@ +package it.gov.pagopa.apiconfig.core.model.stationmaintenance; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import javax.validation.constraints.NotNull; + +/** + * Model class that hold the hours' summary of stations' maintenance for a specific broker + */ +@Getter +@Setter +@Builder +@AllArgsConstructor +@NoArgsConstructor +public class MaintenanceHoursSummaryResource { + + @JsonProperty("used_hours") + @Schema(description = "Count of used maintenance's hours", required = true) + @NotNull + private String usedHours; + + @JsonProperty("scheduled_hours") + @Schema(description = "Count of scheduled maintenance's hours", required = true) + @NotNull + private String scheduledHours; + + @JsonProperty("remaining_hours") + @Schema(description = "Count of remaining maintenance's hours before annual limit", required = true) + @NotNull + private String remainingHours; + + @JsonProperty("extra_hours") + @Schema(description = "Count of maintenance's hours that exceed annual limit", required = true) + @NotNull + private String extraHours; + + @JsonProperty("annual_hours_limit") + @Schema(description = "Annual limit of maintenance hours", required = true) + @NotNull + private String annualHoursLimit; +} \ No newline at end of file diff --git a/src/main/java/it/gov/pagopa/apiconfig/core/model/stationmaintenance/StationMaintenanceResource.java b/src/main/java/it/gov/pagopa/apiconfig/core/model/stationmaintenance/StationMaintenanceResource.java index 972c33ff6..407989b63 100644 --- a/src/main/java/it/gov/pagopa/apiconfig/core/model/stationmaintenance/StationMaintenanceResource.java +++ b/src/main/java/it/gov/pagopa/apiconfig/core/model/stationmaintenance/StationMaintenanceResource.java @@ -17,7 +17,7 @@ import java.time.OffsetDateTime; /** - * Model class the response for station's maintenance APIs + * Model class of the response for station's maintenance APIs */ @Getter @Setter diff --git a/src/main/java/it/gov/pagopa/apiconfig/core/service/StationMaintenanceService.java b/src/main/java/it/gov/pagopa/apiconfig/core/service/StationMaintenanceService.java index 88554a63a..2ffb711c8 100644 --- a/src/main/java/it/gov/pagopa/apiconfig/core/service/StationMaintenanceService.java +++ b/src/main/java/it/gov/pagopa/apiconfig/core/service/StationMaintenanceService.java @@ -4,6 +4,7 @@ import it.gov.pagopa.apiconfig.core.exception.AppException; import it.gov.pagopa.apiconfig.core.model.PageInfo; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.CreateStationMaintenance; +import it.gov.pagopa.apiconfig.core.model.stationmaintenance.MaintenanceHoursSummaryResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.StationMaintenanceListResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.StationMaintenanceResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.UpdateStationMaintenance; @@ -16,12 +17,14 @@ import it.gov.pagopa.apiconfig.starter.repository.StazioniRepository; import org.modelmapper.ModelMapper; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; +import java.math.BigDecimal; import java.time.OffsetDateTime; import java.time.temporal.ChronoUnit; import java.util.List; @@ -35,18 +38,24 @@ public class StationMaintenanceService { private final StationMaintenanceSummaryViewRepository summaryViewRepository; private final StazioniRepository stationRepository; private final ModelMapper mapper; + private final Double annualHoursLimit; + private final Double minimumSchedulingNoticeHours; @Autowired public StationMaintenanceService( ExtendedStationMaintenanceRepository stationMaintenanceRepository, StationMaintenanceSummaryViewRepository summaryViewRepository, StazioniRepository stationRepository, - ModelMapper mapper + ModelMapper mapper, + @Value("${station.maintenance.annual-hours-limit}") Double annualHoursLimit, + @Value("${station.maintenance.minimum-scheduling-notice-hours}") Double minimumSchedulingNoticeHours ) { this.stationMaintenanceRepository = stationMaintenanceRepository; this.summaryViewRepository = summaryViewRepository; this.stationRepository = stationRepository; this.mapper = mapper; + this.annualHoursLimit = annualHoursLimit; + this.minimumSchedulingNoticeHours = minimumSchedulingNoticeHours; } /** @@ -54,7 +63,7 @@ public StationMaintenanceService( *

* Before the creation of the maintenance checks if all the requirements are matched: *

    - *
  • the startDateTime is after 72h from the creation date time + *
  • the startDateTime is after {@link #minimumSchedulingNoticeHours} from the creation date time *
  • startDateTime and endDateTime are valid only if they are rounded to a 15-minute interval * (seconds and milliseconds are truncated) *
  • startDateTime < endDateTime @@ -79,7 +88,7 @@ public StationMaintenanceResource createStationMaintenance( if (isNotRoundedTo15Minutes(startDateTime) || isNotRoundedTo15Minutes(endDateTime)) { throw new AppException(AppError.MAINTENANCE_DATE_TIME_INTERVAL_NOT_VALID, "Date time are not rounded to 15 minutes"); } - if (computeDateDifferenceInHours(now, startDateTime) < 72) { + if (computeDateDifferenceInHours(now, startDateTime) < minimumSchedulingNoticeHours) { throw new AppException(AppError.MAINTENANCE_START_DATE_TIME_NOT_VALID); } if (!endDateTime.isAfter(startDateTime)) { @@ -109,7 +118,7 @@ public StationMaintenanceResource createStationMaintenance( *
* Otherwise, perform the following checks: *
    - *
  • the startDateTime is after 72h from the creation date time + *
  • the startDateTime is after {@link #minimumSchedulingNoticeHours} from the creation date time *
  • startDateTime and endDateTime are valid only if they are rounded to a 15-minute interval * (seconds and milliseconds are truncated) *
  • startDateTime < endDateTime @@ -144,7 +153,7 @@ public StationMaintenanceResource updateStationMaintenance( } /** - * Retrieve a paginated list of station maintenance for the specified broker with the specified filters. + * Retrieve a paginated list of station maintenance for the specified broker with the provided filters. * * @param brokerCode broker's tax code * @param stationCode station's code @@ -189,6 +198,40 @@ public StationMaintenanceListResource getStationMaintenances( .build(); } + /** + * Retrieve the maintenance's hours summary of the specified broker for the provided year + * + * @param brokerCode broker's tax code + * @param maintenanceYear year of maintenance for the summary + * @return the summary + */ + public MaintenanceHoursSummaryResource getBrokerMaintenancesSummary(String brokerCode, String maintenanceYear) { + StationMaintenanceSummaryView maintenanceSummary = this.summaryViewRepository.findById( + StationMaintenanceSummaryId.builder() + .maintenanceYear(maintenanceYear) + .brokerCode(brokerCode) + .build() + ).orElseThrow(() -> new AppException(AppError.MAINTENANCE_SUMMARY_NOT_FOUND, brokerCode, maintenanceYear)); + + Double usedHours = maintenanceSummary.getUsedHours(); + Double scheduledHours = maintenanceSummary.getScheduledHours(); + double remainingHours = 0; + double extraHours = 0; + if (usedHours + scheduledHours < annualHoursLimit) { + remainingHours = annualHoursLimit - (scheduledHours + usedHours); + } else { + extraHours = (scheduledHours + usedHours) - annualHoursLimit; + } + + return MaintenanceHoursSummaryResource.builder() + .usedHours(transformHoursToStringFormat(usedHours)) + .scheduledHours(transformHoursToStringFormat(scheduledHours)) + .remainingHours(transformHoursToStringFormat(remainingHours)) + .extraHours(transformHoursToStringFormat(extraHours)) + .annualHoursLimit(transformHoursToStringFormat(annualHoursLimit)) + .build(); + } + private StationMaintenance updateScheduledStationMaintenance( String brokerCode, OffsetDateTime now, @@ -205,7 +248,7 @@ private StationMaintenance updateScheduledStationMaintenance( if (isNotRoundedTo15Minutes(newStartDateTime) || isNotRoundedTo15Minutes(newEndDateTime)) { throw new AppException(AppError.MAINTENANCE_DATE_TIME_INTERVAL_NOT_VALID, "Date time are not rounded to 15 minutes"); } - if (computeDateDifferenceInHours(now, newStartDateTime) < 72) { + if (computeDateDifferenceInHours(now, newStartDateTime) < minimumSchedulingNoticeHours) { throw new AppException(AppError.MAINTENANCE_START_DATE_TIME_NOT_VALID); } if (!newEndDateTime.isAfter(newStartDateTime)) { @@ -225,7 +268,7 @@ private StationMaintenance updateScheduledStationMaintenance( : oldStationMaintenance.getStandIn(); double oldScheduledHours = computeDateDifferenceInHours(oldStationMaintenance.getStartDateTime(), oldStationMaintenance.getEndDateTime()); // force standIn flag to true when the used has already consumed all the available hours for this year - if (isAnnualHoursLimitExceededForUser(brokerCode, now, newStartDateTime, newEndDateTime, oldScheduledHours)) { + if (isAnnualHoursLimitExceededForUser(brokerCode, newStartDateTime, newEndDateTime, oldScheduledHours, String.valueOf(now.getYear()))) { standIn = true; } @@ -271,7 +314,7 @@ private StationMaintenance buildStationMaintenance( ) { boolean standIn = createStationMaintenance.getStandIn(); // force standIn flag to true when the used has already consumed all the available hours for this year - if (isAnnualHoursLimitExceededForUser(brokerCode, now, startDateTime, endDateTime, 0)) { + if (isAnnualHoursLimitExceededForUser(brokerCode, startDateTime, endDateTime, 0, String.valueOf(now.getYear()))) { standIn = true; } @@ -294,22 +337,21 @@ private Stazioni getStationByStationCode(String stationCode) { private boolean isAnnualHoursLimitExceededForUser( String brokerCode, - OffsetDateTime now, OffsetDateTime startDateTime, OffsetDateTime endDateTime, - double oldScheduledHours + double oldScheduledHours, + String maintenanceYear ) { StationMaintenanceSummaryView maintenanceSummary = this.summaryViewRepository.findById( StationMaintenanceSummaryId.builder() - .maintenanceYear(String.valueOf(now.getYear())) + .maintenanceYear(maintenanceYear) .brokerCode(brokerCode) .build() - ).orElseThrow(() -> new AppException(AppError.MAINTENANCE_SUMMARY_NOT_FOUND, brokerCode, "")); + ).orElseThrow(() -> new AppException(AppError.MAINTENANCE_SUMMARY_NOT_FOUND, brokerCode, maintenanceYear)); double consumedHours = maintenanceSummary.getUsedHours() + maintenanceSummary.getScheduledHours(); double newHoursToBeScheduled = computeDateDifferenceInHours(startDateTime, endDateTime); - return (consumedHours - oldScheduledHours + newHoursToBeScheduled) > 36; - + return (consumedHours - oldScheduledHours + newHoursToBeScheduled) > annualHoursLimit; } private boolean hasOverlappingMaintenance( @@ -329,4 +371,25 @@ private boolean hasOverlappingMaintenance( private boolean isNotRoundedTo15Minutes(OffsetDateTime dateTime) { return dateTime.getMinute() % 15 != 0; } + + private String transformHoursToStringFormat(Double hours) { + if (hours == 0) { + return "0"; + } + BigDecimal bigDecimal = new BigDecimal(String.valueOf(hours)); + int intValue = bigDecimal.intValue(); + BigDecimal decimal = bigDecimal.subtract(new BigDecimal(intValue)); + + if (decimal.compareTo(BigDecimal.valueOf(0.25)) == 0) { + return String.format("%s:15", intValue); + } + if (decimal.compareTo(BigDecimal.valueOf(0.50)) == 0) { + return String.format("%s:30", intValue); + } + if (decimal.compareTo(BigDecimal.valueOf(0.75)) == 0) { + return String.format("%s:45", intValue); + } + return String.valueOf(intValue); + } + } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 9b930f134..e523e91b3 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -109,3 +109,7 @@ iban.labels.cup=0201138TS spring.cache.type=caffeine spring.cache.caffeine.spec=maximumSize=${CACHE_SIZE:1000}, expireAfterAccess=${CACHE_EXPIRATION_TIME:10m} cache.enabled=${CACHE_ENABLED:true} + +# STATION MAINTENANCE +station.maintenance.annual-hours-limit=${STATION_MAINTENANCE_ANNUAL_HOURS_LIMIT:36} +station.maintenance.minimum-scheduling-notice-hours=${STATION_MAINTENANCE_MINIMUM_SCHEDULING_NOTICE_HOURS:72} \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/apiconfig/core/controller/StationMaintenanceControllerTest.java b/src/test/java/it/gov/pagopa/apiconfig/core/controller/StationMaintenanceControllerTest.java index f99d77233..f1d08394a 100644 --- a/src/test/java/it/gov/pagopa/apiconfig/core/controller/StationMaintenanceControllerTest.java +++ b/src/test/java/it/gov/pagopa/apiconfig/core/controller/StationMaintenanceControllerTest.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import it.gov.pagopa.apiconfig.core.model.PageInfo; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.CreateStationMaintenance; +import it.gov.pagopa.apiconfig.core.model.stationmaintenance.MaintenanceHoursSummaryResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.StationMaintenanceListResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.StationMaintenanceResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.UpdateStationMaintenance; @@ -90,6 +91,23 @@ void getStationMaintenancesTest() throws Exception { .andExpect(content().contentType(MediaType.APPLICATION_JSON)); } + @Test + void getBrokerMaintenancesSummaryTest() throws Exception { + when(stationMaintenanceService.getBrokerMaintenancesSummary(anyString(), anyString())) + .thenReturn(MaintenanceHoursSummaryResource.builder() + .usedHours("2") + .scheduledHours("3") + .remainingHours("31") + .extraHours("0") + .annualHoursLimit("36") + .build()); + + mockMvc.perform(get("/brokers/{brokercode}/station-maintenances/summary", BROKER_CODE) + .param("maintenanceYear", "2024") + ).andExpect(status().is2xxSuccessful()) + .andExpect(content().contentType(MediaType.APPLICATION_JSON)); + } + private StationMaintenanceResource buildMaintenanceResource() { return StationMaintenanceResource.builder() .maintenanceId(123L) diff --git a/src/test/java/it/gov/pagopa/apiconfig/core/service/StationMaintenanceServiceTest.java b/src/test/java/it/gov/pagopa/apiconfig/core/service/StationMaintenanceServiceTest.java index de1d42346..950d6622e 100644 --- a/src/test/java/it/gov/pagopa/apiconfig/core/service/StationMaintenanceServiceTest.java +++ b/src/test/java/it/gov/pagopa/apiconfig/core/service/StationMaintenanceServiceTest.java @@ -4,12 +4,14 @@ import it.gov.pagopa.apiconfig.core.exception.AppError; import it.gov.pagopa.apiconfig.core.exception.AppException; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.CreateStationMaintenance; +import it.gov.pagopa.apiconfig.core.model.stationmaintenance.MaintenanceHoursSummaryResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.StationMaintenanceListResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.StationMaintenanceResource; import it.gov.pagopa.apiconfig.core.model.stationmaintenance.UpdateStationMaintenance; import it.gov.pagopa.apiconfig.core.repository.ExtendedStationMaintenanceRepository; import it.gov.pagopa.apiconfig.starter.entity.IntermediariPa; import it.gov.pagopa.apiconfig.starter.entity.StationMaintenance; +import it.gov.pagopa.apiconfig.starter.entity.StationMaintenanceSummaryId; import it.gov.pagopa.apiconfig.starter.entity.StationMaintenanceSummaryView; import it.gov.pagopa.apiconfig.starter.entity.Stazioni; import it.gov.pagopa.apiconfig.starter.repository.StationMaintenanceSummaryViewRepository; @@ -613,7 +615,6 @@ void getStationMaintenancesSuccess() { any() )).thenReturn(new PageImpl<>(list)); - StationMaintenanceListResource result = assertDoesNotThrow(() -> sut.getStationMaintenances( BROKER_CODE, @@ -630,6 +631,71 @@ void getStationMaintenancesSuccess() { assertEquals(list.size(), result.getPageInfo().getItemsFound()); } + @Test + void getBrokerMaintenancesSummarySuccessWithoutExtra() { + StationMaintenanceSummaryView summaryView = StationMaintenanceSummaryView.builder() + .usedHours(10.25) + .scheduledHours(2.50) + .build(); + when(summaryViewRepository.findById( + StationMaintenanceSummaryId.builder() + .brokerCode(BROKER_CODE) + .maintenanceYear("2024") + .build()) + ).thenReturn(Optional.of(summaryView)); + + MaintenanceHoursSummaryResource result = assertDoesNotThrow(() -> + sut.getBrokerMaintenancesSummary(BROKER_CODE, "2024")); + + assertNotNull(result); + assertEquals("10:15", result.getUsedHours()); + assertEquals("2:30", result.getScheduledHours()); + assertEquals("23:15", result.getRemainingHours()); + assertEquals("0", result.getExtraHours()); + assertEquals("36", result.getAnnualHoursLimit()); + } + + @Test + void getBrokerMaintenancesSummarySuccessWithExtra() { + StationMaintenanceSummaryView summaryView = StationMaintenanceSummaryView.builder() + .usedHours(35.25) + .scheduledHours(10.50) + .build(); + when(summaryViewRepository.findById( + StationMaintenanceSummaryId.builder() + .brokerCode(BROKER_CODE) + .maintenanceYear("2024") + .build()) + ).thenReturn(Optional.of(summaryView)); + + MaintenanceHoursSummaryResource result = assertDoesNotThrow(() -> + sut.getBrokerMaintenancesSummary(BROKER_CODE, "2024")); + + assertNotNull(result); + assertEquals("35:15", result.getUsedHours()); + assertEquals("10:30", result.getScheduledHours()); + assertEquals("0", result.getRemainingHours()); + assertEquals("9:45", result.getExtraHours()); + assertEquals("36", result.getAnnualHoursLimit()); + } + + @Test + void getBrokerMaintenancesSummaryFailNotFound() { + when(summaryViewRepository.findById( + StationMaintenanceSummaryId.builder() + .brokerCode(BROKER_CODE) + .maintenanceYear("2024") + .build()) + ).thenReturn(Optional.empty()); + + AppException e = assertThrows(AppException.class, () -> + sut.getBrokerMaintenancesSummary(BROKER_CODE, "2024")); + + assertNotNull(e); + assertEquals(AppError.MAINTENANCE_SUMMARY_NOT_FOUND.httpStatus, e.getHttpStatus()); + assertEquals(AppError.MAINTENANCE_SUMMARY_NOT_FOUND.title, e.getTitle()); + } + private StationMaintenanceSummaryView buildSummaryViewNotExtra() { return StationMaintenanceSummaryView.builder() .scheduledHours(10.0) diff --git a/src/test/resources/application.properties b/src/test/resources/application.properties index 43f3e082f..17456d8ca 100644 --- a/src/test/resources/application.properties +++ b/src/test/resources/application.properties @@ -69,3 +69,7 @@ iban.abi.poste=07601 # IBAN LABELS iban.labels.aca=testAca iban.labels.cup=testCup + +# STATION MAINTENANCE +station.maintenance.annual-hours-limit=${STATION_MAINTENANCE_ANNUAL_HOURS_LIMIT:36} +station.maintenance.minimum-scheduling-notice-hours=${STATION_MAINTENANCE_MINIMUM_SCHEDULING_NOTICE_HOURS:72} \ No newline at end of file