All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.brihaspathee.zeus.service.impl.AccountServiceImpl Maven / Gradle / Ivy

The newest version!
package com.brihaspathee.zeus.service.impl;

import com.brihaspathee.zeus.adapter.interfaces.MessageAdapter;
import com.brihaspathee.zeus.broker.message.AccountUpdateRequest;
import com.brihaspathee.zeus.broker.message.AccountUpdateResponse;
import com.brihaspathee.zeus.constants.EnrollmentSpanStatus;
import com.brihaspathee.zeus.domain.entity.Account;
import com.brihaspathee.zeus.domain.entity.EnrollmentSpan;
import com.brihaspathee.zeus.domain.entity.PayloadTracker;
import com.brihaspathee.zeus.domain.entity.Sponsor;
import com.brihaspathee.zeus.domain.repository.AccountRepository;
import com.brihaspathee.zeus.dto.account.*;
import com.brihaspathee.zeus.exception.AccountNotFoundException;
import com.brihaspathee.zeus.exception.MemberNotFoundException;
import com.brihaspathee.zeus.helper.interfaces.*;
import com.brihaspathee.zeus.mapper.interfaces.AccountMapper;
import com.brihaspathee.zeus.message.AccountValidationRequest;
import com.brihaspathee.zeus.service.interfaces.AccountService;
import com.brihaspathee.zeus.service.interfaces.MemberService;
import com.brihaspathee.zeus.util.ZeusRandomStringGenerator;
import com.brihaspathee.zeus.validator.interfaces.AccountValidator;
import com.brihaspathee.zeus.web.model.*;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

import java.nio.file.LinkOption;
import java.time.Duration;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * Created in Intellij IDEA
 * User: Balaji Varadharajan
 * Date: 20, April 2022
 * Time: 4:33 PM
 * Project: Zeus
 * Package Name: com.brihaspathee.zeus.service.impl
 * To change this template use File | Settings | File and Code Template
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AccountServiceImpl implements AccountService {

    /**
     * The account repository to perform CRUD operations
     */
    private final AccountRepository accountRepository;

    /**
     * Mapper to convert dto to entity and vice versa
     */
    private final AccountMapper accountMapper;

    /**
     * Enrollment span helper to perform operations on the enrollment span
     */
    private final EnrollmentSpanHelper enrollmentSpanHelper;

    /**
     * Premium span helper to perform operations on the premium span
     */
    private final PremiumSpanHelper premiumSpanHelper;

    /**
     * Broker helper to perform operations on the broker
     */
    private final BrokerHelper brokerHelper;

    /**
     * Sponsor helper to perform operations on the sponsor
     */
    private final SponsorHelper sponsorHelper;

    /**
     * Payer helper to perform operations on the payer
     */
    private final PayerHelper payerHelper;

    /**
     * The account validator instance to validate the account details before the changes are saved
     */
    private final AccountValidator accountValidator;

    /**
     * Member service to perform operations on the member entity
     */
    private final MemberService memberService;

    /**
     * Message Adapter to call the Kafka messaging topic
     */
    private final MessageAdapter messageAdapter;

    /**
     * Payload tracker helper instance
     */
    private final PayloadTrackerHelper payloadTrackerHelper;

    /**
     * Create a new account
     * @param accountDto
     * @return
     */
    @Override
    public AccountDto createAccount(AccountDto accountDto) throws JsonProcessingException {
        // todo validate the account details provided before saving the account
        // accountValidator.validateAccount(accountDto);
//        String validationMessageId = ZeusRandomStringGenerator.randomString(15);
//        log.info("validationMessageId:{}",validationMessageId);
//        messageAdapter.publishAccountValidationMessage(AccountValidationRequest.builder()
//                        .validationMessageId(validationMessageId)
//                        .accountDto(accountDto)
//                .build());
        // save the account to the repository
        final Account account = accountRepository.save(accountMapper.accountDtoToAccount(accountDto));
        accountDto.setAccountSK(account.getAccountSK());
        accountDto.getMembers().forEach(memberDto -> {
            memberDto.setAccountSK(account.getAccountSK());
            memberDto.setMemberSK(memberService.createMember(memberDto).getMemberSK());
        });
        enrollmentSpanHelper.saveEnrollmentSpans(accountDto);
        if(accountDto.getBrokers() != null && accountDto.getBrokers().size() > 0){
            accountDto.getBrokers().stream().forEach(brokerDto -> {
                brokerDto.setAccountSK(account.getAccountSK());
                UUID brokerSK = brokerHelper.createBroker(brokerDto, account).getBrokerSK();
                brokerDto.setBrokerSK(brokerSK);
            });
        }
        if(accountDto.getPayers() != null && accountDto.getPayers().size() > 0){
            accountDto.getPayers().stream().forEach(payerDto -> {
                payerDto.setAccountSK(account.getAccountSK());
                UUID payerSK = payerHelper.createPayer(payerDto, account).getPayerSK();
                payerDto.setPayerSK(payerSK);
            });
        }

        if(accountDto.getSponsors() != null && accountDto.getSponsors().size() > 0){
            accountDto.getSponsors().stream().forEach(sponsorDto -> {
                sponsorDto.setAccountSK(account.getAccountSK());
                UUID sponsorSK = sponsorHelper.createSponsor(sponsorDto, account).getSponsorSK();
                sponsorDto.setSponsorSK(sponsorSK);
            });
        }

        return accountDto;
    }

    /**
     * Update an existing account
     * @param accountDto
     * @return
     */
    @Override
    public AccountDto updateAccount(AccountDto accountDto) throws JsonProcessingException {
        log.info("Inside the update account method");
        // Check if the member has been updated
        memberService.saveMembers(accountDto);
        // Check if the enrollment span has been updated
        enrollmentSpanHelper.saveEnrollmentSpans(accountDto);
        // todo Check if the broker has been updated
        // todo Check if the sponsor has been updated
        // todo Check if the payer has been updated
        return accountDto;
    }

    /**
     * Get the details of the account using account mapper
     * @param accountNumber
     * @return
     */
    @Override
    public AccountDto getAccountByNumber(String accountNumber) {
        Account account = accountRepository.findAccountsByAccountNumber(accountNumber).orElse(null);
        log.info("Retrieved account:{}",account);
        if(account!=null){
            account.getMembers().forEach(member -> log.info("Height of the member:{}",String.valueOf(member.getHeight())));
            return accountMapper.accountToAccountDto(account);
        }else{
            return null;
        }

    }

    /**
     * Get all the accounts in the system
     * @return AccountList that contains all the accounts
     */
    @Override
    public AccountList getAllAccounts() {
        Set accounts = accountRepository.findAll().stream().collect(Collectors.toSet());
        Set accountDtos = accountMapper.accountToAccountDtos(accounts);
        AccountList accountList = AccountList.builder()
                .accountDtos(accountDtos)
                .build();
        return accountList;
    }

    /**
     * Process the account information
     * @param payloadTracker
     * @param accountDto
     * @return
     */
    @Override
    public Mono processAccount(PayloadTracker payloadTracker,
                                                      AccountDto accountDto) throws JsonProcessingException {

        String accountNumber = accountDto.getAccountNumber();
        UUID accountSK = accountDto.getAccountSK();
        log.info("Inside the account service for account:{}", accountNumber);
        if(accountSK == null){
            // If account sk is null, then the account needs to be created
            createAccount(accountDto);
        }else{
            // if account sk is not null, then the account needs to be updated
            updateAccount(accountDto);
        }
        AccountUpdateResponse accountUpdateResponse =
                constructAccountProcessingResponse(payloadTracker, accountDto);
        return Mono.just(accountUpdateResponse);
//        return Mono.just(accountUpdateResponse).delayElement(Duration.ofSeconds(30));
    }

    /**
     * Get enrollment span that matches the plan and group policy id
     * @param accountNumber
     * @param planId
     * @param groupPolicyId
     * @param startDate
     * @return
     */
    @Override
    public EnrollmentSpanDto getMatchingEnrollmentSpan(String accountNumber,
                                                       String planId,
                                                       String groupPolicyId,
                                                       LocalDate startDate) {
        AccountDto accountDto = getAccountByNumber(accountNumber);
        List enrollmentSpanDtos = accountDto.getEnrollmentSpans().stream().toList();
        Optional matchedEnrollmentSpan = enrollmentSpanDtos.stream().filter(enrollmentSpanDto -> {
            return enrollmentSpanDto.getPlanId().equals(planId) &&
                    enrollmentSpanDto.getGroupPolicyId().equals(groupPolicyId) &&
                    enrollmentSpanDto.getStartDate().isEqual(startDate);
        }).findFirst();
        enrollmentSpanDtos.stream().sorted(Comparator.comparing(EnrollmentSpanDto::getStartDate)).collect(Collectors.toList());
        if(matchedEnrollmentSpan.isPresent()){
            return matchedEnrollmentSpan.get();
        }
        return null;
    }

    /**
     * Get the enrollment span that is prior to the start date
     * @param accountNumber
     * @param startDate
     * @param matchCancelSpans
     * @return
     */
    @Override
    public EnrollmentSpanDto getPriorEnrollmentSpan(String accountNumber, LocalDate startDate, boolean matchCancelSpans) {
        AccountDto accountDto = getAccountByNumber(accountNumber);
        List enrollmentSpanDtos = accountDto.getEnrollmentSpans().stream().toList();
        enrollmentSpanDtos =
                enrollmentSpanDtos.stream()
                        .sorted(Comparator.comparing(EnrollmentSpanDto::getStartDate))
                        .collect(Collectors.toList());
        enrollmentSpanDtos =
                enrollmentSpanDtos.stream()
                        .takeWhile(
                                enrollmentSpanDto ->
                                        enrollmentSpanDto.getEndDate().isBefore(startDate))
                        .collect(Collectors.toList());
        if(!matchCancelSpans){
            enrollmentSpanDtos = removeCanceledSpans(enrollmentSpanDtos);
        }
        if(enrollmentSpanDtos != null && !enrollmentSpanDtos.isEmpty()){
            return enrollmentSpanDtos.getLast();
        }else {
            return null;
        }
    }

    /**
     * Get matching enrollment spans by the date
     * @param accountNumber
     * @param startDate
     * @param matchCancelSpans
     * @return
     */
    @Override
    public List getMatchingEnrollmentSpan(String accountNumber,
                                                             LocalDate startDate,
                                                             boolean matchCancelSpans) {
        AccountDto accountDto = getAccountByNumber(accountNumber);
        List enrollmentSpanDtos = accountDto.getEnrollmentSpans().stream().toList();
        enrollmentSpanDtos =
                enrollmentSpanDtos.stream()
                        .sorted(Comparator.comparing(EnrollmentSpanDto::getStartDate))
                        .collect(Collectors.toList());
        enrollmentSpanDtos = enrollmentSpanDtos.stream()
                .dropWhile(
                        enrollmentSpanDto ->
                                enrollmentSpanDto.getStartDate().isBefore(startDate))
                .collect(Collectors.toList());
        enrollmentSpanDtos = enrollmentSpanDtos.stream()
                .takeWhile(
                        enrollmentSpanDto ->
                                enrollmentSpanDto.getStartDate().getYear() == startDate.getYear())
                .collect(Collectors.toList());
        if(!matchCancelSpans){
            enrollmentSpanDtos = removeCanceledSpans(enrollmentSpanDtos);
        }
        if(enrollmentSpanDtos != null && enrollmentSpanDtos.size() > 0){
            return enrollmentSpanDtos;
        }
        return null;
    }

    /**
     * Get matching enrollment spans by the date if available else return the prior enrollment span
     * @param accountNumber
     * @param startDate
     * @param matchCancelSpans
     * @return
     */
    @Override
    public List getMatchingOrPriorEnrollmentSpan(String accountNumber,
                                                                    LocalDate startDate,
                                                                    boolean matchCancelSpans) {
        List enrollmentSpanDtos = getMatchingEnrollmentSpan(accountNumber, startDate, matchCancelSpans);
        if(enrollmentSpanDtos != null && enrollmentSpanDtos.size() > 0){
            return enrollmentSpanDtos;
        }else{
            EnrollmentSpanDto enrollmentSpanDto = getPriorEnrollmentSpan(accountNumber,
                    startDate, matchCancelSpans);
            if(enrollmentSpanDto != null){
                List priorEnrollmentSpanDto = new ArrayList<>();
                priorEnrollmentSpanDto.add(enrollmentSpanDto);
                return priorEnrollmentSpanDto;
            }
        }
        return null;
    }

    /**
     * Get accounts that match the exchange subscriber id and state type code
     * @param accountMatchParam
     * @return
     */
    @Override
    public AccountList getMatchingAccounts(AccountMatchParam accountMatchParam) {
        // The account list that will be returned
        // Initially there will be no accounts in the list
        AccountList accountList = AccountList.builder().build();
        // Check if the account number is present in the search
        // If account number is present, search for the account is using the account number
        // and return the account
        if(accountMatchParam.getAccountNumber() != null){
            AccountDto accountDto = getAccountByNumber(accountMatchParam.getAccountNumber());
            accountList.setAccountDtos(Set.of(accountDto));
            return accountList;
        }
        // If account number is not present then first try to find the account using exchange subscriber id and state
        if(accountMatchParam.getExchangeSubscriberId() != null &&
            accountMatchParam.getStateTypeCode() != null){
            accountList = getAccountByExchangeSubId(accountMatchParam);
        }
        // If no account is found using exchange subscriber id,
        // if SSN is provided in the search, see if an account can be found using SSN of the
        // primary subscriber
        if(accountList.getAccountDtos() == null || accountList.getAccountDtos().isEmpty()){
            getAccountBySSN(accountMatchParam, accountList);
        }
        // If no account is found using SSN or no SSN is provided, then
        // try to find an account using the first name, last name, gender and date of birth of the
        // primary subscriber
        if(accountList.getAccountDtos() ==null || accountList.getAccountDtos().isEmpty()){
            getAccountByNameAndDOB(accountMatchParam, accountList);
        }
        return accountList;
    }



    /**
     * Get account by name, date of birth and gender of the primary subscriber
     * @param accountMatchParam
     * @param accountList
     */
    private void getAccountByNameAndDOB(AccountMatchParam accountMatchParam, AccountList accountList) {
        if(accountMatchParam.getFirstName() !=null && accountMatchParam.getLastName() != null &&
            accountMatchParam.getGenderTypeCode() != null && accountMatchParam.getDateOfBirth() !=null){
            List memberDtos = memberService.getMembersByNameAndDOB(accountMatchParam.getFirstName(), accountMatchParam.getLastName(),
                    accountMatchParam.getGenderTypeCode(), accountMatchParam.getDateOfBirth());
            if(memberDtos!=null && !memberDtos.isEmpty()){
                Set accountDtos = memberDtos
                        .stream().map(this::getMemberAccount)
                        .collect(Collectors.toSet());
                accountList.setAccountDtos(accountDtos);
            }

        }
    }

    /**
     * Get account by matching with the SSN of the primary subscriber
     * @param accountMatchParam
     * @param accountList
     */
    private void getAccountBySSN(AccountMatchParam accountMatchParam, AccountList accountList) {
        if(accountMatchParam.getSocialSecurityNumber() != null){
            List memberDtos = memberService.getHOHBySSN(accountMatchParam.getSocialSecurityNumber());
            if(memberDtos!=null && !memberDtos.isEmpty()){
                Set accountDtos = memberDtos
                        .stream().map(this::getMemberAccount).collect(Collectors.toSet());
                accountList.setAccountDtos(accountDtos);
            }
        }
    }

    /**
     * Match account by ssn
     * @param ssn
     * @return
     */
    @Override
    public AccountList getAccountsBySSN(String ssn) {
        AccountList accountList = AccountList.builder().build();
        List memberDtos = memberService.getHOHBySSN(ssn);
        if(memberDtos!=null && !memberDtos.isEmpty()){
            Set accountDtos = memberDtos
                    .stream().map(this::getMemberAccount).collect(Collectors.toSet());
            accountList.setAccountDtos(accountDtos);
        }
        return accountList;
    }

    /**
     * Update the enrollment span status and paid through dates
     * @param enrollmentSpanDto
     */
    @Override
    public void updateEnrollmentSpan(EnrollmentSpanDto enrollmentSpanDto) {
        enrollmentSpanHelper.updateEnrollmentSpan(enrollmentSpanDto);
    }

    /**
     * Clean up the entire member management service database
     */
    @Override
    public void deleteAll() {
        accountRepository.deleteAll();
        payloadTrackerHelper.deleteAll();
    }


    /**
     * Get Member account from member dto
     * @param memberDto
     * @return
     */
    private AccountDto getMemberAccount(MemberDto memberDto) {
        Account account = accountRepository.findById(memberDto.getAccountSK()).orElse(null);
        if(account!=null){
            return accountMapper.accountToAccountDto(account);
        }else {
            return null;
        }
    }

    /**
     * Get the account that matches the exchange subscriber id
     * @param accountMatchParam
     * @return
     */
    private AccountList getAccountByExchangeSubId(AccountMatchParam accountMatchParam) {
        List enrollmentSpans = enrollmentSpanHelper
                .getMatchingEnrollmentSpan(accountMatchParam.getExchangeSubscriberId(),
                        accountMatchParam.getStateTypeCode());
        AccountList accountList = AccountList.builder().build();
        if(enrollmentSpans !=null && enrollmentSpans.size() > 0){
            if(enrollmentSpans.size() > 1){
                // This removes enrollment spans for the same account and keeps only one enrollment span per account
                enrollmentSpans = enrollmentSpans.stream()
                        .collect(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(enrollmentSpan -> {
                            Account account = enrollmentSpan.getAccount();
                            return account.getAccountSK();
                        })))).stream().toList();
            }
            Set accountDtos =
                    enrollmentSpans.stream()
                            .map(enrollmentSpan -> {
                                Account account = enrollmentSpan.getAccount();
                                return accountMapper.accountToAccountDto(account);
                            }).collect(Collectors.toSet());
            accountList.setAccountDtos(accountDtos);
        }
        return accountList;
    }

    /**
     * Remove canceled enrollment span from the list
     * @param enrollmentSpanDtos
     * @return
     */
    private List removeCanceledSpans(List enrollmentSpanDtos){
        return enrollmentSpanDtos.stream()
                .filter(
                        enrollmentSpanDto ->
                                !enrollmentSpanDto.getStatusTypeCode()
                                        .equals(EnrollmentSpanStatus.CANCELED.toString()))
                .collect(Collectors.toList());
    }

    /**
     * Construct the account processing response
     * @param payloadTracker
     * @param accountDto
     * @return
     */
    private AccountUpdateResponse constructAccountProcessingResponse(PayloadTracker payloadTracker,
                                                    AccountDto accountDto){
        return AccountUpdateResponse.builder()
                .responseId(ZeusRandomStringGenerator.randomString(15))
                .requestPayloadId(payloadTracker.getPayloadId())
                .accountNumber(accountDto.getAccountNumber())
                .build();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy