/**
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*/
package org.mifosplatform.portfolio.collateral.service;
import java.util.Map;
import org.mifosplatform.infrastructure.codes.domain.CodeValue;
import org.mifosplatform.infrastructure.codes.domain.CodeValueRepositoryWrapper;
import org.mifosplatform.infrastructure.core.api.JsonCommand;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
import org.mifosplatform.portfolio.collateral.api.CollateralApiConstants;
import org.mifosplatform.portfolio.collateral.api.CollateralApiConstants.COLLATERAL_JSON_INPUT_PARAMS;
import org.mifosplatform.portfolio.collateral.command.CollateralCommand;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateral;
import org.mifosplatform.portfolio.collateral.domain.LoanCollateralRepository;
import org.mifosplatform.portfolio.collateral.exception.CollateralCannotBeCreatedException;
import org.mifosplatform.portfolio.collateral.exception.CollateralCannotBeCreatedException.LOAN_COLLATERAL_CANNOT_BE_CREATED_REASON;
import org.mifosplatform.portfolio.collateral.exception.CollateralCannotBeDeletedException;
import org.mifosplatform.portfolio.collateral.exception.CollateralCannotBeDeletedException.LOAN_COLLATERAL_CANNOT_BE_DELETED_REASON;
import org.mifosplatform.portfolio.collateral.exception.CollateralCannotBeUpdatedException;
import org.mifosplatform.portfolio.collateral.exception.CollateralCannotBeUpdatedException.LOAN_COLLATERAL_CANNOT_BE_UPDATED_REASON;
import org.mifosplatform.portfolio.collateral.exception.CollateralNotFoundException;
import org.mifosplatform.portfolio.collateral.serialization.CollateralCommandFromApiJsonDeserializer;
import org.mifosplatform.portfolio.loanaccount.domain.Loan;
import org.mifosplatform.portfolio.loanaccount.domain.LoanRepository;
import org.mifosplatform.portfolio.loanaccount.exception.LoanNotFoundException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
public class CollateralWritePlatformServiceJpaRepositoryImpl implements CollateralWritePlatformService {
private final static Logger logger = LoggerFactory.getLogger(CollateralWritePlatformServiceJpaRepositoryImpl.class);
private final PlatformSecurityContext context;
private final LoanRepository loanRepository;
private final LoanCollateralRepository collateralRepository;
private final CodeValueRepositoryWrapper codeValueRepository;
private final CollateralCommandFromApiJsonDeserializer collateralCommandFromApiJsonDeserializer;
@Autowired
public CollateralWritePlatformServiceJpaRepositoryImpl(final PlatformSecurityContext context, final LoanRepository loanRepository,
final LoanCollateralRepository collateralRepository, final CodeValueRepositoryWrapper codeValueRepository,
final CollateralCommandFromApiJsonDeserializer collateralCommandFromApiJsonDeserializer) {
this.context = context;
this.loanRepository = loanRepository;
this.collateralRepository = collateralRepository;
this.codeValueRepository = codeValueRepository;
this.collateralCommandFromApiJsonDeserializer = collateralCommandFromApiJsonDeserializer;
}
@Transactional
@Override
public CommandProcessingResult addCollateral(final Long loanId, final JsonCommand command) {
this.context.authenticatedUser();
final CollateralCommand collateralCommand = this.collateralCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
collateralCommand.validateForCreate();
try {
final Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); }
final CodeValue collateralType = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
CollateralApiConstants.COLLATERAL_CODE_NAME, collateralCommand.getCollateralTypeId());
final LoanCollateral collateral = LoanCollateral.fromJson(loan, collateralType, command);
/**
* Collaterals may be added only when the loan associated with them
* are yet to be approved
**/
if (!loan.status().isSubmittedAndPendingApproval()) { throw new CollateralCannotBeCreatedException(
LOAN_COLLATERAL_CANNOT_BE_CREATED_REASON.LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE, loan.getId()); }
this.collateralRepository.save(collateral);
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withLoanId(loan.getId())//
.withEntityId(collateral.getId()) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleCollateralDataIntegrityViolation(dve);
return CommandProcessingResult.empty();
}
}
@Transactional
@Override
public CommandProcessingResult updateCollateral(final Long loanId, final Long collateralId, final JsonCommand command) {
this.context.authenticatedUser();
final CollateralCommand collateralCommand = this.collateralCommandFromApiJsonDeserializer.commandFromApiJson(command.json());
collateralCommand.validateForUpdate();
final Long collateralTypeId = collateralCommand.getCollateralTypeId();
try {
final Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); }
CodeValue collateralType = null;
final LoanCollateral collateralForUpdate = this.collateralRepository.findOne(collateralId);
if (collateralForUpdate == null) { throw new CollateralNotFoundException(loanId, collateralId); }
final Map<String, Object> changes = collateralForUpdate.update(command);
if (changes.containsKey(COLLATERAL_JSON_INPUT_PARAMS.COLLATERAL_TYPE_ID.getValue())) {
collateralType = this.codeValueRepository.findOneByCodeNameAndIdWithNotFoundDetection(
CollateralApiConstants.COLLATERAL_CODE_NAME, collateralTypeId);
collateralForUpdate.setCollateralType(collateralType);
}
/**
* Collaterals may be updated only when the loan associated with
* them are yet to be approved
**/
if (!loan.status().isSubmittedAndPendingApproval()) { throw new CollateralCannotBeUpdatedException(
LOAN_COLLATERAL_CANNOT_BE_UPDATED_REASON.LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE, loan.getId()); }
if (!changes.isEmpty()) {
this.collateralRepository.saveAndFlush(collateralForUpdate);
}
return new CommandProcessingResultBuilder() //
.withCommandId(command.commandId()) //
.withLoanId(command.getLoanId())//
.withEntityId(collateralId) //
.with(changes) //
.build();
} catch (final DataIntegrityViolationException dve) {
handleCollateralDataIntegrityViolation(dve);
return new CommandProcessingResult(Long.valueOf(-1));
}
}
@Transactional
@Override
public CommandProcessingResult deleteCollateral(final Long loanId, final Long collateralId, final Long commandId) {
final Loan loan = this.loanRepository.findOne(loanId);
if (loan == null) { throw new LoanNotFoundException(loanId); }
final LoanCollateral collateral = this.collateralRepository.findByLoanIdAndId(loanId, collateralId);
if (collateral == null) { throw new CollateralNotFoundException(loanId, collateralId); }
/**
* Collaterals may be deleted only when the loan associated with them
* are yet to be approved
**/
if (!loan.status().isSubmittedAndPendingApproval()) { throw new CollateralCannotBeDeletedException(
LOAN_COLLATERAL_CANNOT_BE_DELETED_REASON.LOAN_NOT_IN_SUBMITTED_AND_PENDING_APPROVAL_STAGE, loanId, collateralId); }
loan.getCollateral().remove(collateral);
this.collateralRepository.delete(collateral);
return new CommandProcessingResultBuilder().withCommandId(commandId).withLoanId(loanId).withEntityId(collateralId).build();
}
private void handleCollateralDataIntegrityViolation(final DataIntegrityViolationException dve) {
logAsErrorUnexpectedDataIntegrityException(dve);
throw new PlatformDataIntegrityException("error.msg.collateral.unknown.data.integrity.issue",
"Unknown data integrity issue with resource.");
}
private void logAsErrorUnexpectedDataIntegrityException(final DataIntegrityViolationException dve) {
logger.error(dve.getMessage(), dve);
}
}