com.gst.portfolio.meeting.service.MeetingWritePlatformServiceJpaRepositoryImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.gst.portfolio.meeting.service.MeetingWritePlatformServiceJpaRepositoryImpl.java

Source

/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package com.gst.portfolio.meeting.service;

import static com.gst.portfolio.collectionsheet.CollectionSheetConstants.isTransactionDateOnNonMeetingDateParamName;
import static com.gst.portfolio.collectionsheet.CollectionSheetConstants.transactionDateParamName;
import static com.gst.portfolio.meeting.MeetingApiConstants.attendanceTypeParamName;
import static com.gst.portfolio.meeting.MeetingApiConstants.calendarIdParamName;
import static com.gst.portfolio.meeting.MeetingApiConstants.clientIdParamName;
import static com.gst.portfolio.meeting.MeetingApiConstants.clientsAttendanceParamName;
import static com.gst.portfolio.meeting.MeetingApiConstants.meetingDateParamName;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Map;

import com.gst.infrastructure.configuration.domain.ConfigurationDomainService;
import com.gst.infrastructure.core.api.JsonCommand;
import com.gst.infrastructure.core.data.CommandProcessingResult;
import com.gst.infrastructure.core.data.CommandProcessingResultBuilder;
import com.gst.infrastructure.core.exception.PlatformDataIntegrityException;
import com.gst.infrastructure.core.serialization.FromJsonHelper;
import com.gst.portfolio.calendar.domain.Calendar;
import com.gst.portfolio.calendar.domain.CalendarEntityType;
import com.gst.portfolio.calendar.domain.CalendarInstance;
import com.gst.portfolio.calendar.domain.CalendarInstanceRepository;
import com.gst.portfolio.calendar.domain.CalendarRepository;
import com.gst.portfolio.calendar.exception.CalendarInstanceNotFoundException;
import com.gst.portfolio.calendar.exception.CalendarNotFoundException;
import com.gst.portfolio.client.domain.Client;
import com.gst.portfolio.client.domain.ClientRepositoryWrapper;
import com.gst.portfolio.group.domain.Group;
import com.gst.portfolio.group.domain.GroupRepository;
import com.gst.portfolio.group.exception.ClientNotInGroupException;
import com.gst.portfolio.meeting.attendance.domain.ClientAttendance;
import com.gst.portfolio.meeting.data.MeetingDataValidator;
import com.gst.portfolio.meeting.domain.Meeting;
import com.gst.portfolio.meeting.domain.MeetingRepository;
import com.gst.portfolio.meeting.domain.MeetingRepositoryWrapper;
import org.joda.time.LocalDate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

@Service
public class MeetingWritePlatformServiceJpaRepositoryImpl implements MeetingWritePlatformService {

    private final MeetingRepositoryWrapper meetingRepositoryWrapper;
    private final MeetingRepository meetingRepository;
    private final MeetingDataValidator meetingDataValidator;
    private final CalendarInstanceRepository calendarInstanceRepository;
    private final CalendarRepository calendarRepository;
    private final ClientRepositoryWrapper clientRepositoryWrapper;
    private final GroupRepository groupRepository;
    private final FromJsonHelper fromApiJsonHelper;
    private final ConfigurationDomainService configurationDomainService;

    @Autowired
    public MeetingWritePlatformServiceJpaRepositoryImpl(final MeetingRepositoryWrapper meetingRepositoryWrapper,
            final MeetingRepository meetingRepository, final MeetingDataValidator meetingDataValidator,
            final CalendarInstanceRepository calendarInstanceRepository,
            final CalendarRepository calendarRepository, final ClientRepositoryWrapper clientRepositoryWrapper,
            final GroupRepository groupRepository, final FromJsonHelper fromApiJsonHelper,
            final ConfigurationDomainService configurationDomainService) {
        this.meetingRepositoryWrapper = meetingRepositoryWrapper;
        this.meetingRepository = meetingRepository;
        this.meetingDataValidator = meetingDataValidator;
        this.calendarInstanceRepository = calendarInstanceRepository;
        this.calendarRepository = calendarRepository;
        this.clientRepositoryWrapper = clientRepositoryWrapper;
        this.groupRepository = groupRepository;
        this.fromApiJsonHelper = fromApiJsonHelper;
        this.configurationDomainService = configurationDomainService;
    }

    @Override
    public CommandProcessingResult createMeeting(final JsonCommand command) {

        this.meetingDataValidator.validateForCreate(command);

        final Date meetingDate = command.DateValueOfParameterNamed(meetingDateParamName);
        final Boolean isTransactionDateOnNonMeetingDate = false;
        /*Boolean isSkipRepaymentOnFirstMonth = false;
        Integer numberOfDays = 0;
        boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService.isSkippingMeetingOnFirstDayOfMonthEnabled();
        if(isSkipRepaymentOnFirstMonthEnabled){
        isSkipRepaymentOnFirstMonth = isLoanRepaymentsSyncWithMeeting(loan.group(), calendar);
        if(isSkipRepaymentOnFirstMonth) { numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate().intValue(); } 
        }*/

        try {
            final CalendarInstance calendarInstance = getCalendarInstance(command);
            // create new meeting
            Boolean isSkipRepaymentOnFirstMonth = false;
            Integer numberOfDays = 0;
            boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService
                    .isSkippingMeetingOnFirstDayOfMonthEnabled();
            if (isSkipRepaymentOnFirstMonthEnabled) {
                if (calendarInstance != null) {
                    isSkipRepaymentOnFirstMonth = true;
                }
                if (isSkipRepaymentOnFirstMonth) {
                    numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate()
                            .intValue();
                }
            }
            final Meeting newMeeting = Meeting.createNew(calendarInstance, meetingDate,
                    isTransactionDateOnNonMeetingDate, isSkipRepaymentOnFirstMonth, numberOfDays);

            final Collection<ClientAttendance> clientsAttendance = getClientsAttendance(newMeeting, command);
            if (clientsAttendance != null && !clientsAttendance.isEmpty()) {
                newMeeting.associateClientsAttendance(clientsAttendance);
            }
            // save meeting details
            this.meetingRepositoryWrapper.save(newMeeting);
            final Long groupId = newMeeting.isGroupEntity() ? newMeeting.entityId() : null;
            return new CommandProcessingResultBuilder() //
                    .withEntityId(newMeeting.getId()) //
                    .withGroupId(groupId).build();

        } catch (final DataIntegrityViolationException dve) {
            handleMeetingDataIntegrityIssues(meetingDate, dve);
            return new CommandProcessingResultBuilder() //
                    .build();
        }
    }

    private CalendarInstance getCalendarInstance(final JsonCommand command) {

        final Long calendarId = command.longValueOfParameterNamed(calendarIdParamName);
        final Calendar calendarForUpdate = this.calendarRepository.findOne(calendarId);
        if (calendarForUpdate == null) {
            throw new CalendarNotFoundException(calendarId);
        }

        Long entityId = null;// command.getSupportedEntityId();
        CalendarEntityType entityType = CalendarEntityType.INVALID;// CalendarEntityType.valueOf(command.getSupportedEntityType().toUpperCase());
        if (command.getLoanId() != null) {
            entityId = command.getLoanId();
            entityType = CalendarEntityType.LOANS;
        } else if (command.getClientId() != null) {
            entityId = command.getClientId();
            entityType = CalendarEntityType.CLIENTS;
        } else if (command.getGroupId() != null) {
            entityId = command.getGroupId();
            entityType = CalendarEntityType.GROUPS;
            /*
             * If group is within a center then center entityType should be
             * passed for retrieving CalendarInstance.
             */
            final Group group = this.groupRepository.findOne(entityId);
            if (group.isCenter()) {
                entityType = CalendarEntityType.CENTERS;
            } else if (group.isChildGroup()) {
                entityType = CalendarEntityType.CENTERS;
                entityId = group.getParent().getId();
            }
        }

        final CalendarInstance calendarInstance = this.calendarInstanceRepository
                .findByCalendarIdAndEntityIdAndEntityTypeId(calendarForUpdate.getId(), entityId,
                        entityType.getValue());
        if (calendarInstance == null) {
            final String postFix = "for." + entityType.name().toLowerCase() + "not.found";
            final String defaultUserMessage = "No Calendar Instance details found for group with identifier "
                    + entityId + " and calendar with identifier " + calendarId;
            throw new CalendarInstanceNotFoundException(postFix, defaultUserMessage, entityId, calendarId);
        }
        return calendarInstance;
    }

    private Collection<ClientAttendance> getClientsAttendance(final Meeting meeting, final JsonCommand command) {
        final Collection<ClientAttendance> clientsAttendance = new ArrayList<>();

        Collection<Group> childGroups = null;
        if (meeting.isCenterEntity()) {
            childGroups = this.groupRepository.findByParentId(meeting.entityId());
        }

        final String json = command.json();
        final JsonElement element = this.fromApiJsonHelper.parse(json);
        final JsonObject topLevelJsonElement = element.getAsJsonObject();
        if (element.isJsonObject()) {
            if (topLevelJsonElement.has(clientsAttendanceParamName)
                    && topLevelJsonElement.get(clientsAttendanceParamName).isJsonArray()) {
                final JsonArray array = topLevelJsonElement.get(clientsAttendanceParamName).getAsJsonArray();
                for (int i = 0; i < array.size(); i++) {
                    final JsonObject attendanceElement = array.get(i).getAsJsonObject();
                    final Long clientId = this.fromApiJsonHelper.extractLongNamed(clientIdParamName,
                            attendanceElement);
                    final Integer attendanceTypeId = this.fromApiJsonHelper
                            .extractIntegerSansLocaleNamed(attendanceTypeParamName, attendanceElement);

                    final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId, true);

                    if (meeting.isGroupEntity() && !client.isChildOfGroup(meeting.entityId())) {
                        throw new ClientNotInGroupException(clientId, meeting.entityId());
                    } else if (meeting.isCenterEntity()) {
                        if (childGroups != null && !childGroups.isEmpty()) {
                            boolean isChildClient = false;
                            for (final Group group : childGroups) {
                                if (group.isChildClient(clientId)) {
                                    isChildClient = true;
                                    break;
                                }
                            }
                            if (!isChildClient) {
                                final String defaultUserMessage = "Client with identifier " + clientId
                                        + " is not in center " + meeting.entityId();
                                throw new ClientNotInGroupException("client.not.in.center", defaultUserMessage,
                                        clientId, meeting.entityId());
                            }
                        }
                    }

                    final ClientAttendance clientAttendance = ClientAttendance.createClientAttendance(client,
                            meeting, attendanceTypeId);
                    clientsAttendance.add(clientAttendance);
                }
            }
        }
        return clientsAttendance;
    }

    @Override
    public CommandProcessingResult updateMeeting(final JsonCommand command) {
        this.meetingDataValidator.validateForUpdate(command);

        final CalendarInstance calendarInstance = getCalendarInstance(command);

        // create new meeting
        Boolean isSkipRepaymentOnFirstMonth = false;

        Integer numberOfDays = 0;
        boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService
                .isSkippingMeetingOnFirstDayOfMonthEnabled();
        if (isSkipRepaymentOnFirstMonthEnabled) {
            if (calendarInstance != null) {
                isSkipRepaymentOnFirstMonth = true;
                numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate()
                        .intValue();
            }
        }
        final Meeting meetingForUpdate = this.meetingRepositoryWrapper
                .findOneWithNotFoundDetection(command.entityId());
        final Map<String, Object> changes = meetingForUpdate.update(command, isSkipRepaymentOnFirstMonth,
                numberOfDays);

        try {
            if (!changes.isEmpty()) {
                this.meetingRepositoryWrapper.saveAndFlush(meetingForUpdate);
            }
        } catch (final DataIntegrityViolationException dve) {
            handleMeetingDataIntegrityIssues(meetingForUpdate.getMeetingDate(), dve);
            return new CommandProcessingResultBuilder() //
                    .build();
        }
        final Long groupId = meetingForUpdate.isGroupEntity() ? meetingForUpdate.entityId() : null;
        return new CommandProcessingResultBuilder() //
                .withEntityId(meetingForUpdate.getId()) //
                .withGroupId(groupId) //
                .with(changes) //
                .build();
    }

    @Override
    public CommandProcessingResult deleteMeeting(final Long meetingId) {
        final Meeting meetingForDelete = this.meetingRepositoryWrapper.findOneWithNotFoundDetection(meetingId);
        this.meetingRepositoryWrapper.delete(meetingForDelete);
        return new CommandProcessingResultBuilder() //
                .withEntityId(meetingId) //
                .build();
    }

    @Override
    public CommandProcessingResult saveOrUpdateAttendance(final JsonCommand command) {
        this.meetingDataValidator.validateForUpdateAttendance(command);

        final Meeting meetingForUpdate = this.meetingRepositoryWrapper
                .findOneWithNotFoundDetection(command.entityId());
        final Collection<ClientAttendance> clientsAttendance = getClientsAttendance(meetingForUpdate, command);
        final Map<String, Object> changes = meetingForUpdate.updateAttendance(clientsAttendance);

        this.meetingRepositoryWrapper.saveAndFlush(meetingForUpdate);
        final Long groupId = meetingForUpdate.isGroupEntity() ? meetingForUpdate.entityId() : null;
        return new CommandProcessingResultBuilder() //
                .withEntityId(meetingForUpdate.getId()) //
                .withGroupId(groupId) //
                .with(changes) //
                .build();
    }

    private void handleMeetingDataIntegrityIssues(final Date meetingDate,
            final DataIntegrityViolationException dve) {
        final Throwable realCause = dve.getMostSpecificCause();
        if (realCause.getMessage().contains("unique_calendar_instance_id_meeting_date")) {
            final LocalDate meetingDateLocal = LocalDate.fromDateFields(meetingDate);
            throw new PlatformDataIntegrityException("error.msg.meeting.duplicate",
                    "A meeting with date '" + meetingDateLocal + "' already exists", meetingDateParamName,
                    meetingDateLocal);
        }

        throw new PlatformDataIntegrityException("error.msg.meeting.unknown.data.integrity.issue",
                "Unknown data integrity issue with resource: " + realCause.getMessage());
    }

    @Override
    public void updateCollectionSheetAttendance(final JsonCommand command) {
        final Date meetingDate = command.DateValueOfParameterNamed(transactionDateParamName);
        final Boolean isTransactionDateOnNonMeetingDate = command
                .booleanPrimitiveValueOfParameterNamed(isTransactionDateOnNonMeetingDateParamName);

        try {
            final CalendarInstance calendarInstance = getCalendarInstance(command);

            final Meeting meeting = this.meetingRepository
                    .findByCalendarInstanceIdAndMeetingDate(calendarInstance.getId(), meetingDate);
            Boolean isSkipRepaymentOnFirstMonth = false;
            Integer numberOfDays = 0;
            boolean isSkipRepaymentOnFirstMonthEnabled = configurationDomainService
                    .isSkippingMeetingOnFirstDayOfMonthEnabled();
            if (isSkipRepaymentOnFirstMonthEnabled) {
                isSkipRepaymentOnFirstMonth = true;
                if (isSkipRepaymentOnFirstMonth) {
                    numberOfDays = configurationDomainService.retreivePeroidInNumberOfDaysForSkipMeetingDate()
                            .intValue();
                }
            }
            // create new meeting
            final Meeting newMeeting = (meeting != null) ? meeting
                    : Meeting.createNew(calendarInstance, meetingDate, isTransactionDateOnNonMeetingDate,
                            isSkipRepaymentOnFirstMonth, numberOfDays);

            final Collection<ClientAttendance> clientsAttendance = getClientsAttendance(newMeeting, command);
            if (clientsAttendance != null && !clientsAttendance.isEmpty()) {
                newMeeting.updateAttendance(clientsAttendance);
            }
            // save meeting details
            this.meetingRepositoryWrapper.save(newMeeting);
        } catch (final DataIntegrityViolationException dve) {
            handleMeetingDataIntegrityIssues(meetingDate, dve);
        }

    }

}