public ChangedTransactionDetail closeAsWrittenOff(final JsonCommand command, final LoanLifecycleStateMachine loanLifecycleStateMachine,
final Map<String, Object> changes, final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
final AppUser currentUser, final ScheduleGeneratorDTO scheduleGeneratorDTO) {
final LoanRepaymentScheduleTransactionProcessor loanRepaymentScheduleTransactionProcessor = this.transactionProcessorFactory
.determineProcessor(this.transactionProcessingStrategy);
ChangedTransactionDetail changedTransactionDetail = closeDisbursements(scheduleGeneratorDTO,
loanRepaymentScheduleTransactionProcessor);
validateAccountStatus(LoanEvent.WRITE_OFF_OUTSTANDING);
final LoanStatus statusEnum = loanLifecycleStateMachine.transition(LoanEvent.WRITE_OFF_OUTSTANDING,
LoanStatus.fromInt(this.loanStatus));
LoanTransaction loanTransaction = null;
if (!statusEnum.hasStateOf(LoanStatus.fromInt(this.loanStatus))) {
this.loanStatus = statusEnum.getValue();
changes.put("status", LoanEnumerations.status(this.loanStatus));
existingTransactionIds.addAll(findExistingTransactionIds());
existingReversedTransactionIds.addAll(findExistingReversedTransactionIds());
final LocalDate writtenOffOnLocalDate = command.localDateValueOfParameterNamed("transactionDate");
final String txnExternalId = command.stringValueOfParameterNamedAllowingNull("externalId");
this.closedOnDate = writtenOffOnLocalDate.toDate();
this.writtenOffOnDate = writtenOffOnLocalDate.toDate();
this.closedBy = currentUser;
changes.put("closedOnDate", command.stringValueOfParameterNamed("transactionDate"));
changes.put("writtenOffOnDate", command.stringValueOfParameterNamed("transactionDate"));
if (writtenOffOnLocalDate.isBefore(getDisbursementDate())) {
final String errorMessage = "The date on which a loan is written off cannot be before the loan disbursement date: "
+ getDisbursementDate().toString();
throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.before.submittal.date", errorMessage,
writtenOffOnLocalDate, getDisbursementDate());
}
validateActivityNotBeforeClientOrGroupTransferDate(LoanEvent.WRITE_OFF_OUTSTANDING, writtenOffOnLocalDate);
if (writtenOffOnLocalDate.isAfter(DateUtils.getLocalDateOfTenant())) {
final String errorMessage = "The date on which a loan is written off cannot be in the future.";
throw new InvalidLoanStateTransitionException("writeoff", "cannot.be.a.future.date", errorMessage, writtenOffOnLocalDate);
}
loanTransaction = LoanTransaction.writeoff(this, getOffice(), writtenOffOnLocalDate, txnExternalId);
final boolean isLastTransaction = isChronologicallyLatestTransaction(loanTransaction, this.loanTransactions);
if (!isLastTransaction) {
final String errorMessage = "The date of the writeoff transaction must occur on or before previous transactions.";
throw new InvalidLoanStateTransitionException("writeoff", "must.occur.on.or.after.other.transaction.dates", errorMessage,
writtenOffOnLocalDate);
}
this.loanTransactions.add(loanTransaction);
loanRepaymentScheduleTransactionProcessor.handleWriteOff(loanTransaction, loanCurrency(), this.repaymentScheduleInstallments);
updateLoanSummaryDerivedFields();
}
if (changedTransactionDetail == null) {
changedTransactionDetail = new ChangedTransactionDetail();