Skip to content

Commit a42d593

Browse files
committed
feature: Refactor organization status retrieval in DashboardService and enhance unit tests for improved clarity and functionality
1 parent 76ac3b7 commit a42d593

2 files changed

Lines changed: 192 additions & 26 deletions

File tree

apps/dolly-backend/src/main/java/no/nav/dolly/service/DashboardService.java

Lines changed: 30 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -125,38 +125,42 @@ public Flux<DashboardOrganisasjonerDTO> getOrganisasjonerStatus() {
125125
.flatMapMany(oppslag -> bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert()
126126
.groupBy(OrganisasjonFragment::getInterval)
127127
.flatMap(Flux::collectList)
128-
.flatMap(fragments -> {
129-
var organisasjoner = new HashMap<String, Set<String>>();
130-
fragments.forEach(fragment -> {
131-
var orgNummer = oppslag.getT2().get(fragment.getBrukerid());
132-
organisasjoner.computeIfAbsent(orgNummer, _ -> new HashSet<>())
133-
.add(fragment.getBrukerid());
134-
});
135-
return Mono.just(organisasjoner)
136-
.zipWith(Mono.just(fragments.getFirst().getInterval()));
137-
})
138-
.map(organisasjoner -> DashboardOrganisasjonerDTO.builder()
139-
.interval(organisasjoner.getT2())
140-
.organisasjoner(organisasjoner.getT1().entrySet().stream()
141-
.map(entry -> new DashboardOrganisasjonerDTO.Entry(
142-
entry.getKey(),
143-
oppslag.getT1().getOrDefault(entry.getKey(), Altinn3TilgangDTO.builder()
144-
.navn("Ukjent organisasjon")
145-
.build())
146-
.getNavn(),
147-
oppslag.getT1().getOrDefault(entry.getKey(), Altinn3TilgangDTO.builder()
148-
.organisasjonsform("Ukjent organisasjonsform")
149-
.build())
150-
.getOrganisasjonsform(),
151-
entry.getValue().size()))
128+
.flatMap(fragments -> Mono.just(
129+
Tuples.of(groupFragmentsByOrganisasjon(fragments, oppslag.getT2()), fragments.getFirst().getInterval())))
130+
.map(tuple -> DashboardOrganisasjonerDTO.builder()
131+
.interval(tuple.getT2())
132+
.organisasjoner(tuple.getT1().entrySet().stream()
133+
.map(entry -> toOrganisasjonEntry(entry.getKey(), entry.getValue(), oppslag.getT1()))
152134
.sorted(Comparator.comparing(DashboardOrganisasjonerDTO.Entry::getNavn))
153135
.toList())
154-
.totaltAntallOrganisasjoner(organisasjoner.getT1().size())
155-
.totaltUnikeBrukere((int) organisasjoner.getT1().values().stream()
136+
.totaltAntallOrganisasjoner(tuple.getT1().size())
137+
.totaltUnikeBrukere((int) tuple.getT1().values().stream()
156138
.flatMap(Set::stream)
157139
.distinct()
158140
.count())
159141
.build()))
160142
.sort(Comparator.comparing(DashboardOrganisasjonerDTO::getInterval).reversed());
161143
}
144+
145+
private static Map<String, Set<String>> groupFragmentsByOrganisasjon(List<OrganisasjonFragment> fragments,
146+
Map<String, String> brukerToOrgnummer) {
147+
148+
var grouped = new HashMap<String, Set<String>>();
149+
fragments.forEach(fragment -> {
150+
var orgNummer = brukerToOrgnummer.get(fragment.getBrukerid());
151+
grouped.computeIfAbsent(orgNummer, _ -> new HashSet<>()).add(fragment.getBrukerid());
152+
});
153+
return grouped;
154+
}
155+
156+
private static DashboardOrganisasjonerDTO.Entry toOrganisasjonEntry(String orgNummer,
157+
Set<String> brukere,
158+
Map<String, Altinn3TilgangDTO> organisasjonerOppslag) {
159+
160+
var info = organisasjonerOppslag.getOrDefault(orgNummer, Altinn3TilgangDTO.builder()
161+
.navn("Ukjent organisasjon")
162+
.organisasjonsform("Ukjent organisasjonsform")
163+
.build());
164+
return new DashboardOrganisasjonerDTO.Entry(orgNummer, info.getNavn(), info.getOrganisasjonsform(), brukere.size());
165+
}
162166
}

apps/dolly-backend/src/test/java/no/nav/dolly/service/DashboardServiceTest.java

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package no.nav.dolly.service;
22

3+
import no.nav.dolly.consumer.altinn3.Altinn3TilgangServiceConsumer;
4+
import no.nav.dolly.consumer.altinn3.dto.Altinn3TilgangDTO;
5+
import no.nav.dolly.consumer.brukerservice.BrukerServiceConsumer;
6+
import no.nav.dolly.consumer.brukerservice.dto.BrukerDTO;
37
import no.nav.dolly.consumer.teamkatalog.TeamkatalogConsumer;
48
import no.nav.dolly.consumer.teamkatalog.dto.TeamkatalogDTO;
9+
import no.nav.dolly.domain.dto.DashboardOrganisasjonerDTO;
510
import no.nav.dolly.domain.dto.DashboardTeamsDTO;
611
import no.nav.dolly.domain.jpa.Bruker;
712
import no.nav.dolly.domain.projection.BestillingerFragment;
13+
import no.nav.dolly.domain.projection.OrganisasjonFragment;
814
import no.nav.dolly.domain.projection.TeamFragment;
915
import no.nav.dolly.repository.BestillingRepository;
1016
import no.nav.dolly.repository.BrukerRepository;
@@ -31,6 +37,12 @@ class DashboardServiceTest {
3137
private static final String INTERVAL_1 = "2024-01";
3238
private static final String INTERVAL_2 = "2024-02";
3339

40+
@Mock
41+
private Altinn3TilgangServiceConsumer altinn3TilgangServiceConsumer;
42+
43+
@Mock
44+
private BrukerServiceConsumer brukerServiceConsumer;
45+
3446
@Mock
3547
private BestillingRepository bestillingRepository;
3648

@@ -263,6 +275,149 @@ void shouldSortTeamsStatusByIntervalDescending() {
263275
assertThat(results.get(1).getInterval()).isEqualTo(INTERVAL_1);
264276
}
265277

278+
// ── getOrganisasjonerStatus ──────────────────────────────────────────────
279+
280+
@Test
281+
void shouldReturnEmptyOrganisasjonerWhenNoFragments() {
282+
when(altinn3TilgangServiceConsumer.getOrganisasjoner()).thenReturn(Flux.empty());
283+
when(brukerServiceConsumer.getAlleBrukere()).thenReturn(Flux.empty());
284+
when(bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert()).thenReturn(Flux.empty());
285+
286+
StepVerifier.create(dashboardService.getOrganisasjonerStatus())
287+
.verifyComplete();
288+
}
289+
290+
@Test
291+
void shouldResolveOrganisasjonNavnFromAltinn3Oppslag() {
292+
when(altinn3TilgangServiceConsumer.getOrganisasjoner()).thenReturn(Flux.just(
293+
Altinn3TilgangDTO.builder()
294+
.organisasjonsnummer("123456789")
295+
.navn("Firma AS")
296+
.organisasjonsform("AS")
297+
.build()
298+
));
299+
when(brukerServiceConsumer.getAlleBrukere()).thenReturn(Flux.just(
300+
BrukerDTO.builder().id("bruker1").organisasjonsnummer("123456789").build()
301+
));
302+
when(bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert())
303+
.thenReturn(Flux.just(organisasjonFragment(INTERVAL_1, "bruker1")));
304+
305+
StepVerifier.create(dashboardService.getOrganisasjonerStatus())
306+
.assertNext(dto -> {
307+
assertThat(dto.getOrganisasjoner()).hasSize(1);
308+
var entry = dto.getOrganisasjoner().getFirst();
309+
assertThat(entry.getOrganisasjonsnummer()).isEqualTo("123456789");
310+
assertThat(entry.getNavn()).isEqualTo("Firma AS");
311+
assertThat(entry.getOrganisasjonsform()).isEqualTo("AS");
312+
assertThat(entry.getUnikeBrukere()).isEqualTo(1);
313+
})
314+
.verifyComplete();
315+
}
316+
317+
@Test
318+
void shouldFallbackToUkjentWhenOrganisasjonNotInAltinn3() {
319+
when(altinn3TilgangServiceConsumer.getOrganisasjoner()).thenReturn(Flux.empty());
320+
when(brukerServiceConsumer.getAlleBrukere()).thenReturn(Flux.just(
321+
BrukerDTO.builder().id("bruker1").organisasjonsnummer("999999999").build()
322+
));
323+
when(bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert())
324+
.thenReturn(Flux.just(organisasjonFragment(INTERVAL_1, "bruker1")));
325+
326+
StepVerifier.create(dashboardService.getOrganisasjonerStatus())
327+
.assertNext(dto -> {
328+
var entry = dto.getOrganisasjoner().getFirst();
329+
assertThat(entry.getNavn()).isEqualTo("Ukjent organisasjon");
330+
assertThat(entry.getOrganisasjonsform()).isEqualTo("Ukjent organisasjonsform");
331+
})
332+
.verifyComplete();
333+
}
334+
335+
@Test
336+
void shouldCountUniqueUsersPerOrganisasjon() {
337+
when(altinn3TilgangServiceConsumer.getOrganisasjoner()).thenReturn(Flux.empty());
338+
when(brukerServiceConsumer.getAlleBrukere()).thenReturn(Flux.just(
339+
BrukerDTO.builder().id("bruker1").organisasjonsnummer("111111111").build(),
340+
BrukerDTO.builder().id("bruker2").organisasjonsnummer("111111111").build()
341+
));
342+
when(bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert())
343+
.thenReturn(Flux.just(
344+
organisasjonFragment(INTERVAL_1, "bruker1"),
345+
organisasjonFragment(INTERVAL_1, "bruker1"),
346+
organisasjonFragment(INTERVAL_1, "bruker2")
347+
));
348+
349+
StepVerifier.create(dashboardService.getOrganisasjonerStatus())
350+
.assertNext(dto -> {
351+
assertThat(dto.getTotaltUnikeBrukere()).isEqualTo(2);
352+
assertThat(dto.getOrganisasjoner().getFirst().getUnikeBrukere()).isEqualTo(2);
353+
})
354+
.verifyComplete();
355+
}
356+
357+
@Test
358+
void shouldGroupOrganisasjonFragmentsByIntervalIntoSeparateDtos() {
359+
when(altinn3TilgangServiceConsumer.getOrganisasjoner()).thenReturn(Flux.empty());
360+
when(brukerServiceConsumer.getAlleBrukere()).thenReturn(Flux.just(
361+
BrukerDTO.builder().id("bruker1").organisasjonsnummer("111111111").build(),
362+
BrukerDTO.builder().id("bruker2").organisasjonsnummer("222222222").build()
363+
));
364+
when(bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert())
365+
.thenReturn(Flux.just(
366+
organisasjonFragment(INTERVAL_1, "bruker1"),
367+
organisasjonFragment(INTERVAL_2, "bruker2")
368+
));
369+
370+
StepVerifier.create(dashboardService.getOrganisasjonerStatus())
371+
.assertNext(dto -> assertThat(dto.getInterval()).isEqualTo(INTERVAL_2))
372+
.assertNext(dto -> assertThat(dto.getInterval()).isEqualTo(INTERVAL_1))
373+
.verifyComplete();
374+
}
375+
376+
@Test
377+
void shouldSortOrganisasjonerStatusByIntervalDescending() {
378+
when(altinn3TilgangServiceConsumer.getOrganisasjoner()).thenReturn(Flux.empty());
379+
when(brukerServiceConsumer.getAlleBrukere()).thenReturn(Flux.just(
380+
BrukerDTO.builder().id("bruker1").organisasjonsnummer("111111111").build(),
381+
BrukerDTO.builder().id("bruker2").organisasjonsnummer("222222222").build()
382+
));
383+
when(bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert())
384+
.thenReturn(Flux.just(
385+
organisasjonFragment(INTERVAL_1, "bruker1"),
386+
organisasjonFragment(INTERVAL_2, "bruker2")
387+
));
388+
389+
var results = dashboardService.getOrganisasjonerStatus().collectList().block();
390+
assertThat(results).isNotNull();
391+
assertThat(results.get(0).getInterval()).isEqualTo(INTERVAL_2);
392+
assertThat(results.get(1).getInterval()).isEqualTo(INTERVAL_1);
393+
}
394+
395+
@Test
396+
void shouldSortOrganisasjonerByNavnAlphabetically() {
397+
when(altinn3TilgangServiceConsumer.getOrganisasjoner()).thenReturn(Flux.just(
398+
Altinn3TilgangDTO.builder().organisasjonsnummer("111").navn("Zebra AS").organisasjonsform("AS").build(),
399+
Altinn3TilgangDTO.builder().organisasjonsnummer("222").navn("Alpha AS").organisasjonsform("AS").build()
400+
));
401+
when(brukerServiceConsumer.getAlleBrukere()).thenReturn(Flux.just(
402+
BrukerDTO.builder().id("bruker1").organisasjonsnummer("111").build(),
403+
BrukerDTO.builder().id("bruker2").organisasjonsnummer("222").build()
404+
));
405+
when(bestillingRepository.findBestillingerForOrganisasjonerOrderBySistOppdatert())
406+
.thenReturn(Flux.just(
407+
organisasjonFragment(INTERVAL_1, "bruker1"),
408+
organisasjonFragment(INTERVAL_1, "bruker2")
409+
));
410+
411+
StepVerifier.create(dashboardService.getOrganisasjonerStatus())
412+
.assertNext(dto -> {
413+
var names = dto.getOrganisasjoner().stream()
414+
.map(DashboardOrganisasjonerDTO.Entry::getNavn)
415+
.toList();
416+
assertThat(names).containsExactly("Alpha AS", "Zebra AS");
417+
})
418+
.verifyComplete();
419+
}
420+
266421
// ── helpers ──────────────────────────────────────────────────────────────
267422

268423
private static BestillingerFragment fragment(LocalDate dato, Long personer,
@@ -284,4 +439,11 @@ private static TeamFragment teamFragment(String interval, String epost) {
284439
.epost(epost)
285440
.build();
286441
}
442+
443+
private static OrganisasjonFragment organisasjonFragment(String interval, String brukerid) {
444+
return OrganisasjonFragment.builder()
445+
.interval(interval)
446+
.brukerid(brukerid)
447+
.build();
448+
}
287449
}

0 commit comments

Comments
 (0)