// Copyright © 2015 HSL <https://www.hsl.fi> // This program is dual-licensed under the EUPL v1.2 and AGPLv3 licenses. package fi.hsl.parkandride.itest; import com.google.common.collect.ImmutableMap; import com.jayway.restassured.response.Response; import fi.hsl.parkandride.back.RegionDao; import fi.hsl.parkandride.core.back.FacilityHistoryRepository; import fi.hsl.parkandride.core.back.FacilityRepository; import fi.hsl.parkandride.core.domain.*; import fi.hsl.parkandride.core.service.FacilityHistoryService; import fi.hsl.parkandride.core.service.reporting.ReportParameters; import org.geolatte.geom.DimensionalFlag; import org.geolatte.geom.PointSequence; import org.geolatte.geom.Polygon; import org.geolatte.geom.codec.sqlserver.CountingPointSequenceBuilder; import org.geolatte.geom.crs.CrsId; import org.joda.time.DateTime; import org.joda.time.LocalDate; import org.junit.Before; import org.junit.Test; import javax.inject.Inject; import java.util.AbstractMap; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.stream.Stream; import static com.google.common.collect.Lists.newArrayList; import static fi.hsl.parkandride.core.domain.CapacityType.*; import static fi.hsl.parkandride.core.domain.Usage.COMMERCIAL; import static fi.hsl.parkandride.core.domain.Usage.PARK_AND_RIDE; import static fi.hsl.parkandride.test.DateTimeTestUtils.withDate; import static fi.hsl.parkandride.util.MapUtils.consumingEntry; import static java.util.Arrays.asList; import static java.util.Collections.*; import static java.util.stream.Collectors.joining; import static org.apache.commons.lang3.RandomUtils.nextInt; import static org.assertj.core.api.Assertions.assertThat; import static org.joda.time.DateTimeConstants.MONDAY; public class MaxUtilizationReportITest extends AbstractReportingITest { private static final String MAX_UTILIZATION = "MaxUtilization"; // Day 15 to ensure that weekdays stay in the same month private static final int UNAVAILABLE_COLUMN = 6; private static final String REGION_FOR_DUMMY_HUB = "Helsinki"; private static final String EXCEPTIONAL_SITUATION_TEXT = "Huom! Ajanjaksolla ollut poikkeustilanne"; private static final PointSequence PORNAINEN_LOCATION = new CountingPointSequenceBuilder(DimensionalFlag.d2D, CrsId.parse("EPSG:4326")) .add(25.36814469146677d, 60.47434669678006d) .add(25.36260861206003d, 60.4754675875692d) .add(25.364840209960423d, 60.47694795002815d) .add(25.368831336974583d, 60.47656729184641d) .add(25.36814469146677d, 60.47434669678006d) .toPointSequence(); private static final Polygon PORNAINEN_POLYGON = new Polygon(PORNAINEN_LOCATION); @Inject FacilityHistoryRepository facilityHistoryRepository; @Inject FacilityHistoryService facilityHistoryService; @Inject FacilityRepository facilityRepository; @Inject RegionDao regionDao; // --------------------- // MAX UTILIZATION REPORT // --------------------- @Before @Override public void initialize() { // Needed to ensure history linearity withDate(initial, () -> { this.initFixture(); // Clear the unavailable capacities history facility1.status = FacilityStatus.IN_OPERATION; facility2.status = FacilityStatus.IN_OPERATION; facility1.unavailableCapacities = newArrayList(); facility2.unavailableCapacities = newArrayList(); facilityRepository.updateFacility(facility1.id, facility1); facilityRepository.updateFacility(facility2.id, facility2); }); facility1 = facilityRepository.getFacility(facility1.id); facility2 = facilityRepository.getFacility(facility2.id); } @Test public void report_MaxUtilization_calculatedCorrectly() { // From specs // Käyttäjä on valinnut 3 päivän ajanjakson tarkasteltavaksi. Jokaiselta päivältä etsitään maksimitäyttöaste (vähiten vapaita paikkoja tarjolla). // Ma - 70%; Ti - 100%; Ke - 80% // Näistä lasketaan keskimääräinen maksimitäyttöaste päivätyypeittäin. Valitulla jaksolla vain arkipäiviä, joten saadaan tulokseksi, // että keskimääräinen maksimitäyttöaste arkena oli (70% + 100% + 80%) / 3 = 83,33% // Fac1 + Fac2 total capacity = 100 -> easy facilityService.registerUtilization(facility1.id, asList( // Only the "min available space" rows are taken into account utilize(CAR, 0, mon, facility1), utilize(CAR, 0, tue, facility1), utilize(CAR, 0, wed, facility1), // These are left out, no effect on the calculation utilize(CAR, nextInt(10, 50), mon.plusMinutes(1), facility1), utilize(CAR, nextInt(10, 50), tue.plusMinutes(1), facility1), utilize(CAR, nextInt(10, 50), wed.plusMinutes(1), facility1) ), apiUser); facilityService.registerUtilization(facility2.id, asList( // Only the "min available space" rows are taken into account utilize(CAR, 30, mon, facility2), utilize(CAR, 0, tue, facility2), utilize(CAR, 20, wed, facility2), // These are left out, no effect on the calculation utilize(CAR, nextInt(30, 50), mon.plusMinutes(1), facility2), utilize(CAR, nextInt(30, 50), tue.plusMinutes(1), facility2), utilize(CAR, nextInt(30, 50), wed.plusMinutes(1), facility2) ), apiUser2); final ReportParameters params = baseParams(); params.startDate = mon.toLocalDate(); params.endDate = wed.plusDays(1).toLocalDate(); final Response whenPostingToReportUrl = postToReportUrl(params, MAX_UTILIZATION, adminUser); // Only one row checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 100, 0, 0.8333) ); } @Test public void report_MaxUtilization_asOperator() { // Record mock usage data addMockMaxUtilizations(facility1, apiUser); addMockMaxUtilizations(facility2, apiUser2); final Response whenPostingToReportUrl = postToReportUrl(baseParams(), MAX_UTILIZATION, operator1User); // If this succeeds, the response was a valid excel file withWorkbook(whenPostingToReportUrl, workbook -> { assertThat(getSheetNames(workbook)).containsExactly("Tiivistelmäraportti", "Selite"); checkSheetContents(workbook, 0, headers(), hubRow(operator1, PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 50, 0, 1.0), hubRow(operator1, PARK_AND_RIDE, CAR, DayType.SATURDAY, 50, 0, 0.5), hubRow(operator1, PARK_AND_RIDE, CAR, DayType.SUNDAY, 50, 0, 0.2) ); }); } @Test public void report_MaxUtilization_asAdmin() { // Record mock usage data addMockMaxUtilizations(facility1, apiUser); addMockMaxUtilizations(facility2, apiUser2); final Response whenPostingToReportUrl = postToReportUrl(baseParams(), MAX_UTILIZATION, adminUser); checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 100, 0, 1.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 100, 0, 0.5), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SUNDAY, 100, 0, 0.2) ); } @Test public void report_MaxUtilization_excludeDatesByExceptionalStatus() { addMockMaxUtilizations(facility1, apiUser, 50, 50, 50); addMockMaxUtilizations(facility2, apiUser2, 0, 0, 0); // Sun-Tue -> Inactive; Tue-Mon -> Closed facilityHistoryRepository.updateStatusHistory(mon.minusDays(1).toDateTime(), facility1.id, FacilityStatus.INACTIVE, new MultilingualString("")); facilityHistoryRepository.updateStatusHistory(tue.toDateTime(), facility1.id, FacilityStatus.TEMPORARILY_CLOSED, new MultilingualString("")); facilityHistoryRepository.updateStatusHistory(sun.plusDays(1).toDateTime(), facility1.id, FacilityStatus.IN_OPERATION, new MultilingualString("")); final Response whenPostingToReportUrl = postToReportUrl(baseParams(), MAX_UTILIZATION, adminUser); // All 100 places, since facility 1 + facility 2 are calculated regardless of status // 100% utilization, since facility 2 is fully utilized every day checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 100, 0, 1.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 100, 0, 1.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SUNDAY, 100, 0, 1.0) ); } @Test public void report_MaxUtilization_allExcluded() { addMockMaxUtilizations(facility1, apiUser, 50, 50, 50); addMockMaxUtilizations(facility2, apiUser2, 50, 50, 50); facilityHistoryRepository.updateStatusHistory(mon.minusDays(1).toDateTime(), facility1.id, FacilityStatus.INACTIVE, new MultilingualString("")); facilityHistoryRepository.updateStatusHistory(sun.plusDays(1).toDateTime(), facility1.id, FacilityStatus.IN_OPERATION, new MultilingualString("")); facilityHistoryRepository.updateStatusHistory(mon.minusDays(1).toDateTime(), facility2.id, FacilityStatus.INACTIVE, new MultilingualString("")); facilityHistoryRepository.updateStatusHistory(sun.plusDays(1).toDateTime(), facility2.id, FacilityStatus.IN_OPERATION, new MultilingualString("")); final Response whenPostingToReportUrl = postToReportUrl(baseParams(), MAX_UTILIZATION, adminUser); checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 100, 0, 0.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 100, 0, 0.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SUNDAY, 100, 0, 0.0) ); } @Test public void report_MaxUtilization_unavailableCapacities() { addMockMaxUtilizations(facility1, apiUser, 0, 0, 0); facilityHistoryRepository.updateCapacityHistory(mon, facility1.id, facility1.builtCapacity, singletonList(new UnavailableCapacity(CAR, PARK_AND_RIDE, 10))); facilityHistoryRepository.updateCapacityHistory(tue, facility1.id, facility1.builtCapacity, singletonList(new UnavailableCapacity(CAR, PARK_AND_RIDE, 15))); facilityHistoryRepository.updateCapacityHistory(wed, facility1.id, facility1.builtCapacity, singletonList(new UnavailableCapacity(CAR, PARK_AND_RIDE, 5))); facilityHistoryRepository.updateCapacityHistory(fri, facility1.id, facility1.builtCapacity, singletonList(new UnavailableCapacity(CAR, PARK_AND_RIDE, 7))); facilityHistoryRepository.updateCapacityHistory(sat.withTime(18, 0, 0, 0), facility1.id, facility1.builtCapacity, emptyList()); final Response whenPostingToReportUrl = postToReportUrl(baseParams(), MAX_UTILIZATION, adminUser); checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 50, 15, 1.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 50, 7, 1.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SUNDAY, 50, 0, 1.0) ); } @Test public void report_MaxUtilization_unavailableCapacities_withLotsOfData() { Facility f = withDate(DateTime.parse("2015-08-01T00:00:00.000"), () -> { final Facility fac = dummies.createFacility(operator1.id, facility1.contacts); fac.status = FacilityStatus.IN_OPERATION; return facilityRepository.getFacility(facilityRepository.insertFacility(fac)); }); hub.facilityIds = singleton(f.id); hubService.updateHub(hub.id, hub, adminUser); Stream.of( mockUnavailable("2015-09-01T01:00:00.000", 1), mockUnavailable("2015-09-25T06:30:00.000", 0), mockUnavailable("2015-09-27T06:30:00.000", 0), mockUnavailable("2015-10-02T07:50:00.000", 5), mockUnavailable("2015-10-03T07:50:00.000", 10), mockUnavailable("2015-10-04T07:50:00.000", 49), mockUnavailable("2015-10-09T06:01:00.000", 10), mockUnavailable("2015-10-10T06:01:00.000", 1), mockUnavailable("2015-10-11T06:01:00.000", 0), mockUnavailable("2015-10-16T06:15:00.000", 1), mockUnavailable("2015-10-16T07:15:00.000", 10), mockUnavailable("2015-10-16T08:30:00.000", 19), mockUnavailable("2015-10-16T09:00:00.000", 1), mockUnavailable("2015-10-17T07:59:00.000", 20), mockUnavailable("2015-10-18T07:59:00.000", 19), mockUnavailable("2015-10-23T07:00:00.000", 5), mockUnavailable("2015-10-24T07:00:00.000", 5), mockUnavailable("2015-10-25T07:00:00.000", 40), mockUnavailable("2015-10-30T09:59:00.000", 0) ).forEachOrdered(consumingEntry((date, uc) -> { withDate(date, () -> { f.unavailableCapacities = singletonList(uc); facilityRepository.updateFacility(f.id, f); }); })); facilityService.registerUtilization(f.id, asList( mockUtilize(f, "2015-09-25T08:37:26", 0), mockUtilize(f, "2015-09-26T08:35:26", 1), mockUtilize(f, "2015-09-27T08:37:26", 20), mockUtilize(f, "2015-09-28T08:37:26", 20), mockUtilize(f, "2015-09-29T08:37:26", 21), mockUtilize(f, "2015-09-30T08:37:26", 21), mockUtilize(f, "2015-10-01T08:37:26", 21), mockUtilize(f, "2015-10-02T08:37:26", 5), mockUtilize(f, "2015-10-03T08:37:26", 4), mockUtilize(f, "2015-10-04T08:37:26", 1), mockUtilize(f, "2015-10-05T08:37:26", 21), mockUtilize(f, "2015-10-06T08:37:26", 21), mockUtilize(f, "2015-10-07T08:37:26", 21), mockUtilize(f, "2015-10-08T08:37:26", 21), mockUtilize(f, "2015-10-09T08:30:26", 15), mockUtilize(f, "2015-10-09T08:57:26", 10), mockUtilize(f, "2015-10-09T09:37:26", 25), mockUtilize(f, "2015-10-09T10:37:26", 5), mockUtilize(f, "2015-10-09T11:37:26", 20), mockUtilize(f, "2015-10-10T08:37:26", 30), mockUtilize(f, "2015-10-11T08:37:26", 30), mockUtilize(f, "2015-10-12T08:37:26", 21), mockUtilize(f, "2015-10-13T08:37:26", 21), mockUtilize(f, "2015-10-14T08:37:26", 21), mockUtilize(f, "2015-10-15T08:37:26", 21), mockUtilize(f, "2015-10-16T08:37:26", 20), mockUtilize(f, "2015-10-17T08:37:26", 3), mockUtilize(f, "2015-10-18T08:37:26", 1), mockUtilize(f, "2015-10-19T08:37:26", 15), mockUtilize(f, "2015-10-20T08:37:26", 15), mockUtilize(f, "2015-10-21T08:37:26", 15), mockUtilize(f, "2015-10-22T08:37:26", 15), mockUtilize(f, "2015-10-23T08:37:26", 10), mockUtilize(f, "2015-10-24T08:37:26", 5), mockUtilize(f, "2015-10-25T07:37:26", 30), mockUtilize(f, "2015-10-26T07:37:26", 5), mockUtilize(f, "2015-10-27T07:37:26", 5), mockUtilize(f, "2015-10-28T07:37:26", 5), mockUtilize(f, "2015-10-29T07:37:26", 5), mockUtilize(f, "2015-10-30T07:37:26", 25) ), apiUser); final ReportParameters params = baseParams(); params.startDate = new LocalDate("2015-10-01"); params.endDate = new LocalDate("2015-10-30"); final Response whenPostingToReportUrl = postToReportUrl(params, MAX_UTILIZATION, adminUser); // Assert correct values as tested manually withWorkbook(whenPostingToReportUrl, wb -> { assertThat(getDataFromColumn(wb.getSheetAt(0), UNAVAILABLE_COLUMN)) .containsExactly("Tilapäisesti poissa käytöstä", "49", "20", "49"); }); } @Test public void testThat_startAndEndDateAreInclusive() { final ReportParameters params = baseParams(); params.startDate = new LocalDate(2015, 10, 1); // Thursday params.endDate = new LocalDate(2015, 10, 31); // Saturday facilityService.registerUtilization(facility1.id, asList( utilize(CAR, 10, params.startDate.toDateTimeAtCurrentTime(), facility1), utilize(CAR, 20, params.endDate.toDateTimeAtCurrentTime(), facility1) ), apiUser); facilityService.registerUtilization(facility2.id, asList( utilize(CAR, 0, params.startDate.toDateTimeAtCurrentTime(), facility2), utilize(CAR, 0, params.endDate.toDateTimeAtCurrentTime(), facility2) ), apiUser2); final Response whenPostingToReportUrl = postToReportUrl(params, MAX_UTILIZATION, adminUser); checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 100, 0, 0.9), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 100, 0, 0.8) ); } private Utilization mockUtilize(Facility f, String date, int spaces) { return utilize(CAR, spaces, DateTime.parse(date), f); } private Map.Entry<DateTime, UnavailableCapacity> mockUnavailable(String date, int val) { return new AbstractMap.SimpleImmutableEntry<>(DateTime.parse(date), new UnavailableCapacity(CAR, PARK_AND_RIDE, val)); } @Test public void report_MaxUtilization_changingCapacity() { withDate(fri, () -> { facility1.builtCapacity = ImmutableMap.of(CAR, 100); facilityRepository.updateFacility(facility1.id, facility1); }); addMockMaxUtilizations(facility1, apiUser, 50, 50, 50); addMockMaxUtilizations(facility2, apiUser2, 0, 50, 10); // Monday = 1 - ((50 + 0) / ( 50 + 50)) = 50% // Saturday = 1 - ((50 + 50) / ( 100 + 50)) = 33.33% // Sunday = 1 - ((50 + 10) / ( 100 + 50)) = 40% final Response whenPostingToReportUrl = postToReportUrl(baseParams(), MAX_UTILIZATION, adminUser); checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 150, 0, 0.5), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 150, 0, 0.3333), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SUNDAY, 150, 0, 0.6) ); } @Test public void report_MaxUtilization_exceptionalSituation() { addMockMaxUtilizations(facility1, apiUser, 0, 0, 0); addMockMaxUtilizations(facility2, apiUser2, 0, 0, 0); withDate(sat.withTime(7, 0, 0, 0), () -> { facility2.status = FacilityStatus.EXCEPTIONAL_SITUATION; facilityRepository.updateFacility(facility2.id, facility2); }); final Response whenPostingToReportUrl = postToReportUrl(baseParams(), MAX_UTILIZATION, adminUser); checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 100, 0, 1.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 100, 0, 1.0, true), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SUNDAY, 100, 0, 1.0, true) ); } @Test public void report_MaxUtilization_multiplePricingAndUsages() { withDate(initial.plusDays(1), () -> { facility1.status = FacilityStatus.IN_OPERATION; facility1.builtCapacity = ImmutableMap.of(CAR, 100, ELECTRIC_CAR, 10); facility1.pricing = asList( new Pricing(CAR, PARK_AND_RIDE, 100, DayType.BUSINESS_DAY, "00", "24", null), new Pricing(CAR, PARK_AND_RIDE, 100, DayType.SATURDAY, "00", "24", null), new Pricing(CAR, PARK_AND_RIDE, 100, DayType.SUNDAY, "00", "24", null), new Pricing(CAR, COMMERCIAL, 50, DayType.BUSINESS_DAY, "00", "24", "1 ege"), new Pricing(CAR, COMMERCIAL, 50, DayType.SATURDAY, "00", "24", "1 ege"), new Pricing(CAR, COMMERCIAL, 50, DayType.SUNDAY, "00", "24", "1 ege"), new Pricing(ELECTRIC_CAR, COMMERCIAL, 10, DayType.BUSINESS_DAY, "00", "24", "1 ege"), new Pricing(ELECTRIC_CAR, COMMERCIAL, 10, DayType.SATURDAY, "00", "24", "1 ege"), new Pricing(ELECTRIC_CAR, COMMERCIAL, 10, DayType.SUNDAY, "00", "24", "1 ege") ); facility2.builtCapacity = ImmutableMap.of(CAR, 50); facility2.pricing = asList( new Pricing(CAR, PARK_AND_RIDE, 50, DayType.BUSINESS_DAY, "00", "24", null), new Pricing(CAR, PARK_AND_RIDE, 50, DayType.SATURDAY, "00", "24", null), new Pricing(CAR, PARK_AND_RIDE, 50, DayType.SUNDAY, "00", "24", null) ); facilityRepository.updateFacility(facility1.id, facility1); facilityRepository.updateFacility(facility2.id, facility2); facility1 = facilityRepository.getFacility(facility1.id); facility2 = facilityRepository.getFacility(facility2.id); }); addMockMaxUtilizations(facility1, apiUser, 15, 30, 45, CAR, PARK_AND_RIDE); addMockMaxUtilizations(facility1, apiUser, 10, 20, 30, CAR, COMMERCIAL); addMockMaxUtilizations(facility1, apiUser, 2, 4, 5, ELECTRIC_CAR, COMMERCIAL); addMockMaxUtilizations(facility2, apiUser2, 0, 0, 0); final Response whenPostingToReportUrl = whenPostingToReportUrl(baseParams(), MAX_UTILIZATION, adminUser); checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 150, 0, 0.9), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 150, 0, 0.8), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SUNDAY, 150, 0, 0.7), hubRow(asList(operator1, operator2), COMMERCIAL, CAR, DayType.BUSINESS_DAY, 100, 0, 0.9), hubRow(asList(operator1, operator2), COMMERCIAL, CAR, DayType.SATURDAY, 100, 0, 0.8), hubRow(asList(operator1, operator2), COMMERCIAL, CAR, DayType.SUNDAY, 100, 0, 0.7), hubRow(asList(operator1, operator2), COMMERCIAL, ELECTRIC_CAR, DayType.BUSINESS_DAY, 10, 0, 0.8), hubRow(asList(operator1, operator2), COMMERCIAL, ELECTRIC_CAR, DayType.SATURDAY, 10, 0, 0.6), hubRow(asList(operator1, operator2), COMMERCIAL, ELECTRIC_CAR, DayType.SUNDAY, 10, 0, 0.5) ); } @Test public void report_MaxUtilization_facilitiesNotInAnyHub() { Facility facility = withDate(initial, () -> { Facility f = dummies.createFacility(operator1.id, facility1.contacts); f.status = FacilityStatus.IN_OPERATION; f.builtCapacity = ImmutableMap.of(CAR, 100); f.unavailableCapacities = emptyList(); f.location = PORNAINEN_POLYGON; return facilityRepository.getFacility(facilityRepository.insertFacility(f)); }); addMockMaxUtilizations(facility, apiUser, 0, 25, 50); addMockMaxUtilizations(facility1, apiUser, 0, 0, 0); addMockMaxUtilizations(facility2, apiUser2, 0, 0, 0); final Response whenPostingToReportUrl = whenPostingToReportUrl(baseParams(), MAX_UTILIZATION, adminUser); checkSheetContents(whenPostingToReportUrl, 0, headers(), hubRow(facility.name.fi,"Pornainen",singletonList(operator1), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 100, 0, 1.0, false), hubRow(facility.name.fi,"Pornainen",singletonList(operator1), PARK_AND_RIDE, CAR, DayType.SATURDAY, 100, 0, 0.75, false), hubRow(facility.name.fi,"Pornainen",singletonList(operator1), PARK_AND_RIDE, CAR, DayType.SUNDAY, 100, 0, 0.5, false), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.BUSINESS_DAY, 100, 0, 1.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SATURDAY, 100, 0, 1.0), hubRow(asList(operator1, operator2), PARK_AND_RIDE, CAR, DayType.SUNDAY, 100, 0, 1.0) ); } private List<String> headers() { return asList("Alueen nimi", "Kunta", "Operaattori", "Käyttötapa", "Ajoneuvotyyppi", "Pysäköintipaikkojen määrä", "Tilapäisesti poissa käytöstä", "Päivätyyppi", "Keskimääräinen maksimitäyttöaste", "" ); } private void addMockMaxUtilizations(Facility f, User apiUser) { final Integer capacity = f.builtCapacity.get(CAR); // 50/50 = 100% business day // 25/50 = 50% Saturday // 10/50 = 20% Sunday addMockMaxUtilizations(f, apiUser, 0, capacity - (capacity / 2), capacity - (capacity / 5)); } private void addMockMaxUtilizations(Facility f, User apiUser, int businessDay, int saturday, int sunday) { addMockMaxUtilizations(f, apiUser, businessDay, saturday, sunday, CAR, PARK_AND_RIDE); } private void addMockMaxUtilizations(Facility f, User apiUser, int businessDay, int saturday, int sunday, CapacityType capacityType, Usage usage) { facilityService.registerUtilization(f.id, asList( utilize(capacityType, usage, businessDay, mon, f), utilize(capacityType, usage, saturday, sat, f), utilize(capacityType, usage, sunday, sun, f), // BICYCLE_SECURE_SPACE does not exist in built capacity, should not fail utilize(BICYCLE_SECURE_SPACE, 0, baseDate.withDayOfWeek(MONDAY), f) ), apiUser); } private List<String> hubRow(Operator operator, Usage usage, CapacityType type, DayType dayType, Integer totalCapacity, Integer unavailableCapacity, Double percentage) { return hubRow(singletonList(operator), usage, type, dayType, totalCapacity, unavailableCapacity, percentage); } private List<String> hubRow(List<Operator> operators, Usage usage, CapacityType type, DayType dayType, Integer totalCapacity, Integer unavailableCapacity, Double percentage) { return hubRow(operators, usage, type, dayType, totalCapacity, unavailableCapacity, percentage, false); } private List<String> hubRow(List<Operator> operators, Usage usage, CapacityType type, DayType dayType, Integer totalCapacity, Integer unavailableCapacity, Double percentage, boolean hasHadExceptionalSituation) { return hubRow(hub.name.fi, REGION_FOR_DUMMY_HUB, operators, usage, type, dayType, totalCapacity, unavailableCapacity, percentage, hasHadExceptionalSituation); } private List<String> hubRow(String hubName, String region, List<Operator> operators, Usage usage, CapacityType type, DayType dayType, Integer totalCapacity, Integer unavailableCapacity, Double percentage, boolean hasHadExceptionalSituation) { return asList( hubName, region, operators.stream().map(o -> o.name.fi).collect(joining(", ")), translationService.translate(usage), translationService.translate(type), totalCapacity.toString(), unavailableCapacity.toString(), translationService.translate(dayType), String.format(Locale.ENGLISH, "%.2f %%", percentage * 100.0), hasHadExceptionalSituation ? EXCEPTIONAL_SITUATION_TEXT : "" ); } }