diff --git a/src/main/java/greenfirst/be/incentive/adapter/out/persistence/querydsl/IncentiveQuerydslRepository.java b/src/main/java/greenfirst/be/incentive/adapter/out/persistence/querydsl/IncentiveQuerydslRepository.java index 59aaedc..7823f58 100644 --- a/src/main/java/greenfirst/be/incentive/adapter/out/persistence/querydsl/IncentiveQuerydslRepository.java +++ b/src/main/java/greenfirst/be/incentive/adapter/out/persistence/querydsl/IncentiveQuerydslRepository.java @@ -18,7 +18,11 @@ import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Repository; +import java.math.BigDecimal; +import java.util.HashMap; import java.util.List; +import java.util.Map; +import java.util.UUID; @Slf4j @@ -105,4 +109,31 @@ public IncentiveListOutDto getIncentiveList(IncentiveListInDto inDto) { .build(); } + // 파트너 UUID 목록별 총 인센티브 합계 조회 (EARN/REVERSAL 포함, 순합) + public Map getTotalIncentiveByPartnerUuids(List partnerUuids) { + if (partnerUuids == null || partnerUuids.isEmpty()) { + return Map.of(); + } + + var totalIncentiveSum = qIncentive.totalIncentive.sum(); + + List tuples = queryFactory + .select(qIncentive.partnerUuid, totalIncentiveSum) + .from(qIncentive) + .where(qIncentive.partnerUuid.in(partnerUuids)) + .groupBy(qIncentive.partnerUuid) + .fetch(); + + Map result = new HashMap<>(); + for (Tuple tuple : tuples) { + UUID partnerUuid = tuple.get(qIncentive.partnerUuid); + BigDecimal totalIncentive = tuple.get(totalIncentiveSum); + if (partnerUuid != null) { + result.put(partnerUuid, totalIncentive == null ? BigDecimal.ZERO : totalIncentive); + } + } + + return result; + } + } diff --git a/src/main/java/greenfirst/be/incentive/adapter/out/persistence/repository/IncentiveQueryRepositoryImpl.java b/src/main/java/greenfirst/be/incentive/adapter/out/persistence/repository/IncentiveQueryRepositoryImpl.java index 0639918..65ef00c 100644 --- a/src/main/java/greenfirst/be/incentive/adapter/out/persistence/repository/IncentiveQueryRepositoryImpl.java +++ b/src/main/java/greenfirst/be/incentive/adapter/out/persistence/repository/IncentiveQueryRepositoryImpl.java @@ -16,7 +16,9 @@ import org.modelmapper.ModelMapper; import org.springframework.stereotype.Repository; +import java.math.BigDecimal; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -94,6 +96,13 @@ public List findByPartnerUuidAndIncentiveKind(UUID partnerUuid, Incen } + // 파트너 UUID 목록별 총 인센티브 합계 조회 (EARN/REVERSAL 포함, 순합) + @Override + public Map getTotalIncentiveByPartnerUuids(List partnerUuids) { + return incentiveQuerydslRepository.getTotalIncentiveByPartnerUuids(partnerUuids); + } + + // 이미 REVERSAL이 존재하는지 확인 (idempotency) @Override public boolean existsByReversalOfIncentiveId(Long originalIncentiveId) { diff --git a/src/main/java/greenfirst/be/incentive/application/port/out/IncentiveQueryRepository.java b/src/main/java/greenfirst/be/incentive/application/port/out/IncentiveQueryRepository.java index 0e9b6c7..cf3f95e 100644 --- a/src/main/java/greenfirst/be/incentive/application/port/out/IncentiveQueryRepository.java +++ b/src/main/java/greenfirst/be/incentive/application/port/out/IncentiveQueryRepository.java @@ -6,7 +6,9 @@ import greenfirst.be.incentive.domain.enums.IncentiveKind; import greenfirst.be.incentive.domain.model.Incentive; +import java.math.BigDecimal; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.UUID; @@ -34,6 +36,9 @@ public interface IncentiveQueryRepository { // 파트너 UUID + 인센티브 종류로 조회 List findByPartnerUuidAndIncentiveKind(UUID partnerUuid, IncentiveKind incentiveKind); + // 파트너 UUID 목록별 총 인센티브 합계 조회 (EARN/REVERSAL 포함, 순합) + Map getTotalIncentiveByPartnerUuids(List partnerUuids); + // 이미 REVERSAL이 존재하는지 확인 (idempotency) boolean existsByReversalOfIncentiveId(Long originalIncentiveId); diff --git a/src/main/java/greenfirst/be/user/adapter/in/web/controller/GetRelationshipDataController.java b/src/main/java/greenfirst/be/user/adapter/in/web/controller/GetRelationshipDataController.java index c3ebef6..2fe2c44 100644 --- a/src/main/java/greenfirst/be/user/adapter/in/web/controller/GetRelationshipDataController.java +++ b/src/main/java/greenfirst/be/user/adapter/in/web/controller/GetRelationshipDataController.java @@ -9,7 +9,6 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.modelmapper.ModelMapper; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @@ -27,8 +26,6 @@ public class GetRelationshipDataController { // facade private final PartnerRelationshipFacade partnerRelationshipFacade; - // util - private final ModelMapper modelMapper; /** @@ -47,7 +44,7 @@ public BaseResponse getPartnerRelationshipData(@Pat PartnerRelationshipOutDto outDto = partnerRelationshipFacade.getPartnerRelationshipData(partnerUuid); // result - PartnerRelationshipResponse response = modelMapper.map(outDto, PartnerRelationshipResponse.class); + PartnerRelationshipResponse response = PartnerRelationshipResponse.from(outDto); return new BaseResponse<>(response); } diff --git a/src/main/java/greenfirst/be/user/adapter/in/web/response/PartnerRelationshipResponse.java b/src/main/java/greenfirst/be/user/adapter/in/web/response/PartnerRelationshipResponse.java index 17324a8..64d0001 100644 --- a/src/main/java/greenfirst/be/user/adapter/in/web/response/PartnerRelationshipResponse.java +++ b/src/main/java/greenfirst/be/user/adapter/in/web/response/PartnerRelationshipResponse.java @@ -2,13 +2,18 @@ import greenfirst.be.user.application.dto.out.Level1DownlineData; +import greenfirst.be.user.application.dto.out.PartnerRelationshipOutDto; import greenfirst.be.user.application.dto.out.ReferrerData; +import lombok.Builder; import lombok.Getter; +import lombok.NoArgsConstructor; import java.util.List; +import java.util.Objects; @Getter +@NoArgsConstructor public class PartnerRelationshipResponse { /** @@ -21,4 +26,18 @@ public class PartnerRelationshipResponse { private ReferrerData referrerData; private List level1Downlines; + @Builder(toBuilder = true) + public PartnerRelationshipResponse(ReferrerData referrerData, List level1Downlines) { + this.referrerData = referrerData; + this.level1Downlines = level1Downlines; + } + + public static PartnerRelationshipResponse from(PartnerRelationshipOutDto outDto) { + Objects.requireNonNull(outDto, "partnerRelationshipOutDto must not be null"); + return PartnerRelationshipResponse.builder() + .referrerData(outDto.getReferrerData()) + .level1Downlines(outDto.getLevel1Downlines()) + .build(); + } + } diff --git a/src/main/java/greenfirst/be/user/adapter/out/persistence/repository/incentive/IncentiveTotalQueryPortImpl.java b/src/main/java/greenfirst/be/user/adapter/out/persistence/repository/incentive/IncentiveTotalQueryPortImpl.java new file mode 100644 index 0000000..ad3a107 --- /dev/null +++ b/src/main/java/greenfirst/be/user/adapter/out/persistence/repository/incentive/IncentiveTotalQueryPortImpl.java @@ -0,0 +1,26 @@ +package greenfirst.be.user.adapter.out.persistence.repository.incentive; + + +import greenfirst.be.incentive.application.port.out.IncentiveQueryRepository; +import greenfirst.be.user.application.port.out.incentive.IncentiveTotalQueryPort; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Repository; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.UUID; + + +@Repository +@RequiredArgsConstructor +public class IncentiveTotalQueryPortImpl implements IncentiveTotalQueryPort { + + private final IncentiveQueryRepository incentiveQueryRepository; + + @Override + public Map getTotalIncentiveByPartnerUuids(List partnerUuids) { + return incentiveQueryRepository.getTotalIncentiveByPartnerUuids(partnerUuids); + } + +} diff --git a/src/main/java/greenfirst/be/user/application/dto/out/PartnerData.java b/src/main/java/greenfirst/be/user/application/dto/out/PartnerData.java index e3d3701..d6b4d6d 100644 --- a/src/main/java/greenfirst/be/user/application/dto/out/PartnerData.java +++ b/src/main/java/greenfirst/be/user/application/dto/out/PartnerData.java @@ -6,6 +6,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; +import java.math.BigDecimal; import java.util.UUID; @@ -18,5 +19,6 @@ public class PartnerData { private UUID partnerUuid; private String partnerName; private String partnerPhoneNumber; + private BigDecimal totalIncentive; } diff --git a/src/main/java/greenfirst/be/user/application/facade/PartnerRelationshipFacade.java b/src/main/java/greenfirst/be/user/application/facade/PartnerRelationshipFacade.java index 5a18a4f..091ec49 100644 --- a/src/main/java/greenfirst/be/user/application/facade/PartnerRelationshipFacade.java +++ b/src/main/java/greenfirst/be/user/application/facade/PartnerRelationshipFacade.java @@ -7,6 +7,7 @@ import greenfirst.be.user.application.dto.out.PartnerData; import greenfirst.be.user.application.dto.out.PartnerRelationshipOutDto; import greenfirst.be.user.application.dto.out.ReferrerData; +import greenfirst.be.user.application.port.out.incentive.IncentiveTotalQueryPort; import greenfirst.be.user.application.service.GetPartnerRelationshipDataService; import greenfirst.be.user.application.service.GetUserDataService; import greenfirst.be.user.domain.model.PartnerRelationship; @@ -16,10 +17,12 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import java.math.BigDecimal; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.UUID; +import java.util.stream.Stream; @Slf4j @@ -30,6 +33,7 @@ public class PartnerRelationshipFacade { // service private final GetUserDataService getUserDataService; private final GetPartnerRelationshipDataService getPartnerRelationshipDataService; + private final IncentiveTotalQueryPort incentiveTotalQueryPort; // domain service private final PartnerRelationshipAssembler partnerRelationshipAssembler; @@ -107,8 +111,19 @@ private List getDownlinesData(UUID partnerUuid) { List level2Uuids = partnerRelationshipAssembler.extractAllLevel2DownlineUuids(level2RelationshipMap); List level2Partners = getUserDataService.getUsersByUuidInList(level2Uuids); + // 1차 + 2차 파트너 UUID 목록 합치기 + List allDownlineUuids = Stream.concat( + level1Partners.stream().map(Users::getUserUuid), + level2Partners.stream().map(Users::getUserUuid) + ) + .distinct() + .toList(); + + // 파트너별 총 인센티브 합계 조회 (EARN/REVERSAL 포함, 순합) + Map totalIncentiveByPartnerUuid = incentiveTotalQueryPort.getTotalIncentiveByPartnerUuids(allDownlineUuids); + // 1차, 2차 하위 파트너 매핑 - return this.mappingDownlinesData(level1Partners, level2Partners, level2RelationshipMap); + return this.mappingDownlinesData(level1Partners, level2Partners, level2RelationshipMap, totalIncentiveByPartnerUuid); } @@ -116,7 +131,8 @@ private List getDownlinesData(UUID partnerUuid) { private List mappingDownlinesData( List level1Partners, List level2Partners, - Map> level2RelationshipMap + Map> level2RelationshipMap, + Map totalIncentiveByPartnerUuid ) { // 2차 파트너 UUID -> Users 맵 생성 Map level2PartnerMap = partnerRelationshipAssembler.buildPartnerMap(level2Partners); @@ -130,13 +146,15 @@ private List mappingDownlinesData( .partnerUuid(level1Partner.getUserUuid()) .partnerName(level1Partner.getUserName()) .partnerPhoneNumber(level1Partner.getUserPhoneNumber()) + .totalIncentive(totalIncentiveByPartnerUuid.getOrDefault(level1Partner.getUserUuid(), BigDecimal.ZERO)) .build(); // 1차 파트너의 2차 하위 파트너 목록 조회 List level2Downlines = this.mapLevel2Downlines( level1Partner.getUserUuid(), level2RelationshipMap, - level2PartnerMap + level2PartnerMap, + totalIncentiveByPartnerUuid ); // Level1DownlineData 생성 @@ -150,7 +168,8 @@ private List mappingDownlinesData( private List mapLevel2Downlines( UUID level1PartnerUuid, Map> level2RelationshipMap, - Map level2PartnerMap + Map level2PartnerMap, + Map totalIncentiveByPartnerUuid ) { return level2RelationshipMap .getOrDefault(level1PartnerUuid, List.of()) // 1차 파트너 UUID에 해당하는 2차 관계 목록 조회 @@ -163,6 +182,7 @@ private List mapLevel2Downlines( .partnerUuid(user.getUserUuid()) .partnerName(user.getUserName()) .partnerPhoneNumber(user.getUserPhoneNumber()) + .totalIncentive(totalIncentiveByPartnerUuid.getOrDefault(user.getUserUuid(), BigDecimal.ZERO)) .build(); }) .toList(); diff --git a/src/main/java/greenfirst/be/user/application/port/out/incentive/IncentiveTotalQueryPort.java b/src/main/java/greenfirst/be/user/application/port/out/incentive/IncentiveTotalQueryPort.java new file mode 100644 index 0000000..afbf81a --- /dev/null +++ b/src/main/java/greenfirst/be/user/application/port/out/incentive/IncentiveTotalQueryPort.java @@ -0,0 +1,15 @@ +package greenfirst.be.user.application.port.out.incentive; + + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.UUID; + + +public interface IncentiveTotalQueryPort { + + // 파트너 UUID 목록별 총 인센티브 합계 조회 (EARN/REVERSAL 포함, 순합) + Map getTotalIncentiveByPartnerUuids(List partnerUuids); + +} diff --git a/src/test/java/greenfirst/be/incentive/application/IncentiveJobManagementServiceUnitTest.java b/src/test/java/greenfirst/be/incentive/application/IncentiveJobManagementServiceUnitTest.java index 6e10956..178e8f6 100644 --- a/src/test/java/greenfirst/be/incentive/application/IncentiveJobManagementServiceUnitTest.java +++ b/src/test/java/greenfirst/be/incentive/application/IncentiveJobManagementServiceUnitTest.java @@ -509,6 +509,11 @@ public List findByPartnerUuidAndIncentiveKind(UUID partnerUuid, Incen .toList(); } + @Override + public Map getTotalIncentiveByPartnerUuids(List partnerUuids) { + return Map.of(); + } + @Override public boolean existsByReversalOfIncentiveId(Long originalIncentiveId) { return storage.values().stream() diff --git a/src/test/java/greenfirst/be/user/application/facade/PartnerRelationshipFacadeUnitTest.java b/src/test/java/greenfirst/be/user/application/facade/PartnerRelationshipFacadeUnitTest.java new file mode 100644 index 0000000..577c1f9 --- /dev/null +++ b/src/test/java/greenfirst/be/user/application/facade/PartnerRelationshipFacadeUnitTest.java @@ -0,0 +1,182 @@ +package greenfirst.be.user.application.facade; + + +import greenfirst.be.user.application.dto.out.Level1DownlineData; +import greenfirst.be.user.application.dto.out.PartnerData; +import greenfirst.be.user.application.dto.out.PartnerRelationshipOutDto; +import greenfirst.be.user.application.port.out.incentive.IncentiveTotalQueryPort; +import greenfirst.be.user.application.service.GetPartnerRelationshipDataService; +import greenfirst.be.user.application.service.GetUserDataService; +import greenfirst.be.user.domain.model.PartnerRelationship; +import greenfirst.be.user.domain.model.Users; +import greenfirst.be.user.domain.service.PartnerRelationshipAssembler; +import greenfirst.be.users.fake.FakeIncentiveTotalQueryPort; +import greenfirst.be.users.fake.FakePartnerRelationshipQueryRepository; +import greenfirst.be.users.fake.FakeUserQueryRepository; +import greenfirst.be.users.fake.FakeUserVehicleQueryRepository; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.modelmapper.ModelMapper; + +import java.math.BigDecimal; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + + +@DisplayName("PartnerRelationshipFacade Unit Test") +class PartnerRelationshipFacadeUnitTest { + + private PartnerRelationshipFacade partnerRelationshipFacade; + private FakePartnerRelationshipQueryRepository fakePartnerRelationshipQueryRepository; + private FakeUserQueryRepository fakeUserQueryRepository; + private FakeUserVehicleQueryRepository fakeUserVehicleQueryRepository; + private FakeIncentiveTotalQueryPort fakeIncentiveTotalQueryPort; + + + @BeforeEach + void setUp() { + fakePartnerRelationshipQueryRepository = new FakePartnerRelationshipQueryRepository(); + fakeUserQueryRepository = new FakeUserQueryRepository(); + fakeUserVehicleQueryRepository = new FakeUserVehicleQueryRepository(); + fakeIncentiveTotalQueryPort = new FakeIncentiveTotalQueryPort(); + + fakePartnerRelationshipQueryRepository.clear(); + fakeUserQueryRepository.clear(); + fakeUserVehicleQueryRepository.clear(); + fakeIncentiveTotalQueryPort.clear(); + + GetPartnerRelationshipDataService getPartnerRelationshipDataService = + new GetPartnerRelationshipDataService(fakePartnerRelationshipQueryRepository); + GetUserDataService getUserDataService = new GetUserDataService( + fakeUserQueryRepository, + fakeUserVehicleQueryRepository, + new ModelMapper() + ); + PartnerRelationshipAssembler partnerRelationshipAssembler = new PartnerRelationshipAssembler(); + IncentiveTotalQueryPort incentiveTotalQueryPort = fakeIncentiveTotalQueryPort; + + partnerRelationshipFacade = new PartnerRelationshipFacade( + getUserDataService, + getPartnerRelationshipDataService, + incentiveTotalQueryPort, + partnerRelationshipAssembler + ); + } + + + @Test + @DisplayName("1차/2차 하위 파트너 각각의 총 인센티브 합계가 응답에 포함된다") + void getPartnerRelationshipData_includesTotalIncentiveForLevel1AndLevel2() { + // given + UUID partnerUuid = UUID.randomUUID(); + UUID level1AUuid = UUID.randomUUID(); + UUID level1BUuid = UUID.randomUUID(); + UUID level2CUuid = UUID.randomUUID(); + + fakePartnerRelationshipQueryRepository.save(PartnerRelationship.of(level1AUuid, partnerUuid)); + fakePartnerRelationshipQueryRepository.save(PartnerRelationship.of(level1BUuid, partnerUuid)); + fakePartnerRelationshipQueryRepository.save(PartnerRelationship.of(level2CUuid, level1AUuid)); + + Users level1A = Users.builder() + .id(1L) + .userUuid(level1AUuid) + .userName("level1A") + .userPhoneNumber("010-1111-1111") + .build(); + Users level1B = Users.builder() + .id(2L) + .userUuid(level1BUuid) + .userName("level1B") + .userPhoneNumber("010-2222-2222") + .build(); + Users level2C = Users.builder() + .id(3L) + .userUuid(level2CUuid) + .userName("level2C") + .userPhoneNumber("010-3333-3333") + .build(); + + fakeUserQueryRepository.addUser(level1A); + fakeUserQueryRepository.addUser(level1B); + fakeUserQueryRepository.addUser(level2C); + + fakeIncentiveTotalQueryPort.setTotals(Map.of( + level1AUuid, new BigDecimal("100.50"), + level1BUuid, new BigDecimal("200.00"), + level2CUuid, new BigDecimal("300.25") + )); + + // when + PartnerRelationshipOutDto result = partnerRelationshipFacade.getPartnerRelationshipData(partnerUuid); + + // then + assertThat(result.getLevel1Downlines()).hasSize(2); + + Level1DownlineData level1AData = findLevel1(result.getLevel1Downlines(), level1AUuid); + assertThat(level1AData.getPartner().getTotalIncentive()).isEqualByComparingTo("100.50"); + assertThat(level1AData.getLevel2Downlines()).hasSize(1); + PartnerData level2CData = level1AData.getLevel2Downlines().get(0); + assertThat(level2CData.getPartnerUuid()).isEqualTo(level2CUuid); + assertThat(level2CData.getTotalIncentive()).isEqualByComparingTo("300.25"); + + Level1DownlineData level1BData = findLevel1(result.getLevel1Downlines(), level1BUuid); + assertThat(level1BData.getPartner().getTotalIncentive()).isEqualByComparingTo("200.00"); + assertThat(level1BData.getLevel2Downlines()).isEmpty(); + } + + + @Test + @DisplayName("인센티브 합계가 없으면 0으로 내려간다") + void getPartnerRelationshipData_defaultsTotalIncentiveToZero() { + // given + UUID partnerUuid = UUID.randomUUID(); + UUID level1AUuid = UUID.randomUUID(); + UUID level2BUuid = UUID.randomUUID(); + + fakePartnerRelationshipQueryRepository.save(PartnerRelationship.of(level1AUuid, partnerUuid)); + fakePartnerRelationshipQueryRepository.save(PartnerRelationship.of(level2BUuid, level1AUuid)); + + Users level1A = Users.builder() + .id(1L) + .userUuid(level1AUuid) + .userName("level1A") + .userPhoneNumber("010-1111-1111") + .build(); + Users level2B = Users.builder() + .id(2L) + .userUuid(level2BUuid) + .userName("level2B") + .userPhoneNumber("010-2222-2222") + .build(); + + fakeUserQueryRepository.addUser(level1A); + fakeUserQueryRepository.addUser(level2B); + + fakeIncentiveTotalQueryPort.setTotals(Map.of( + level1AUuid, new BigDecimal("50.00") + )); + + // when + PartnerRelationshipOutDto result = partnerRelationshipFacade.getPartnerRelationshipData(partnerUuid); + + // then + Level1DownlineData level1AData = findLevel1(result.getLevel1Downlines(), level1AUuid); + assertThat(level1AData.getPartner().getTotalIncentive()).isEqualByComparingTo("50.00"); + assertThat(level1AData.getLevel2Downlines()).hasSize(1); + PartnerData level2BData = level1AData.getLevel2Downlines().get(0); + assertThat(level2BData.getTotalIncentive()).isEqualByComparingTo("0"); + } + + + private Level1DownlineData findLevel1(List level1Downlines, UUID targetUuid) { + return level1Downlines.stream() + .filter(data -> data.getPartner().getPartnerUuid().equals(targetUuid)) + .findFirst() + .orElseThrow(); + } + +} diff --git a/src/test/java/greenfirst/be/users/fake/FakeIncentiveTotalQueryPort.java b/src/test/java/greenfirst/be/users/fake/FakeIncentiveTotalQueryPort.java new file mode 100644 index 0000000..6996f30 --- /dev/null +++ b/src/test/java/greenfirst/be/users/fake/FakeIncentiveTotalQueryPort.java @@ -0,0 +1,49 @@ +package greenfirst.be.users.fake; + + +import greenfirst.be.user.application.port.out.incentive.IncentiveTotalQueryPort; + +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; + + +public class FakeIncentiveTotalQueryPort implements IncentiveTotalQueryPort { + + private final Map totals = new HashMap<>(); + private List lastRequestedUuids; + + @Override + public Map getTotalIncentiveByPartnerUuids(List partnerUuids) { + lastRequestedUuids = partnerUuids; + if (partnerUuids == null || partnerUuids.isEmpty()) { + return Map.of(); + } + Map result = new HashMap<>(); + for (UUID uuid : partnerUuids) { + if (totals.containsKey(uuid)) { + result.put(uuid, totals.get(uuid)); + } + } + return result; + } + + public void setTotals(Map totals) { + Objects.requireNonNull(totals, "totals must not be null"); + this.totals.clear(); + this.totals.putAll(totals); + } + + public List getLastRequestedUuids() { + return lastRequestedUuids; + } + + public void clear() { + totals.clear(); + lastRequestedUuids = null; + } + +}