/// <summary> /// Cancels last event from given contract, restores associated installment status. /// and restores Client(individual, corporate) status /// </summary> /// <param name="contract">Contract</param> /// <param name="pClient"></param> /// <param name="comment"> </param> /// <returns>Cancelled event</returns> public Event CancelLastEvent(Loan contract, IClient pClient, string comment) { using (SqlConnection conn = _loanManager.GetConnection()) using (SqlTransaction sqlTransaction = conn.BeginTransaction()) { Event cancelledEvent; try { Event evnt = contract.GetLastNonDeletedEvent(); if (null == evnt) throw new OpenCbsContractSaveException(OpenCbsContractSaveExceptionEnum.EventIsNull); if (!evnt.Cancelable) throw new OpenCbsContractSaveException(OpenCbsContractSaveExceptionEnum.EventNotCancelable); if (string.IsNullOrEmpty(comment)) throw new OpenCbsContractSaveException(OpenCbsContractSaveExceptionEnum.EventCommentIsEmpty); if (pClient is Person) evnt.ClientType = OClientTypes.Person; else if (pClient is Group) evnt.ClientType = OClientTypes.Group; else if (pClient is Corporate) evnt.ClientType = OClientTypes.Corporate; else if (pClient is Village) evnt.ClientType = OClientTypes.Village; var evntCopy = evnt.Copy(); evntCopy.Id = evnt.ParentId ?? evnt.Id; CallInterceptor(new Dictionary<string, object> { {"Loan", contract}, {"Event", evntCopy}, {"Deleted", true}, {"SqlTransaction", sqlTransaction} }); if (ApplicationSettings.GetInstance(User.CurrentUser.Md5).UseMandatorySavingAccount) { var id = 0; if (int.TryParse(evnt.Comment, out id)) ServicesProvider.GetInstance() .GetSavingServices() .DeleteEvent(new SavingWithdrawEvent() { Id = id, CancelDate = TimeProvider.Today }); } evnt.Comment = comment; evnt.CancelDate = TimeProvider.Now; // if event is loan close event, we delete it first if (evnt is LoanCloseEvent) { _ePs.CancelFireEvent(evnt, sqlTransaction, contract, contract.Product.Currency.Id); evnt.Deleted = true; evnt = contract.GetLastNonDeletedEvent(); if (pClient is Person) evnt.ClientType = OClientTypes.Person; else if (pClient is Group) evnt.ClientType = OClientTypes.Group; else if (pClient is Corporate) evnt.ClientType = OClientTypes.Corporate; else if (pClient is Village) evnt.ClientType = OClientTypes.Village; evnt.Comment = comment; evnt.CancelDate = TimeProvider.Now; } _ePs.CancelFireEvent(evnt, sqlTransaction, contract, contract.Product.Currency.Id); _ePs.UpdateCommentForLoanEvent(evnt, sqlTransaction); evnt.Deleted = true; //in case total repayment there could be several rep events foreach (RepaymentEvent evt in contract.Events.GetRepaymentEvents()) { if ((evt.ParentId == evnt.ParentId && evnt.ParentId != null) || (evt.Id == evnt.ParentId)) { evt.Deleted = true; evt.Comment = evnt.Comment; _ePs.UpdateCommentForLoanEvent(evt, sqlTransaction); } } if (evnt.Code == "ATR" || evnt.Code == "RBLE") { foreach (Event cie in contract.Events) { if (cie is CreditInsuranceEvent) if (cie.Deleted == false && cie.Code == "LCIP") { _ePs.CancelFireEvent(cie, sqlTransaction, contract, contract.Product.Currency.Id); cie.Deleted = true; } } } cancelledEvent = evnt; // Restore the installment status. UnarchiveInstallments(contract, cancelledEvent, sqlTransaction); contract.InstallmentList = _instalmentManager.SelectInstallments(contract.Id, sqlTransaction); contract.GivenTranches = _loanManager.SelectTranches(contract.Id, sqlTransaction); contract.NbOfInstallments = contract.InstallmentList.Count; //return interest rate after delete event contract.InterestRate = GetPreviousRate(contract); if (evnt is LoanDisbursmentEvent) { contract.Disbursed = false; } else if (evnt is RescheduleLoanEvent) { contract.Rescheduled = false; } else if (cancelledEvent is TrancheEvent) { contract.Amount = contract.Amount - (cancelledEvent as TrancheEvent).Amount; TrancheEvent trancheEventToDelete = new TrancheEvent(); foreach (var trancheEvent in contract.GivenTranches) { if (trancheEvent.Id == cancelledEvent.Id) { trancheEventToDelete = trancheEvent; } } contract.GivenTranches.Remove(trancheEventToDelete); if (contract.AllInstallmentsRepaid) { contract.ContractStatus = OContractStatus.Closed; contract.Closed = true; //Restore interest rate contract.InterestRate = contract.GivenTranches[contract.GivenTranches.Count - 1].InterestRate.Value; } } else if (cancelledEvent is RepaymentEvent) { //restor a person of the corporate _clientManager.RestorMemberOfGroupByEventId(cancelledEvent.Id, contract, sqlTransaction); contract.EscapedMember = null; if (cancelledEvent.RepaymentType == OPaymentType.TotalPayment) { if (contract.HasCompulsoryAmount()) { SavingEvent savingUnblockEvent = contract.CompulsorySavings.Events.FirstOrDefault( e => e.LoanEventId == cancelledEvent.Id); if (savingUnblockEvent != null) { _savingEventManager.DeleteSavingsEventByLoanEventId( cancelledEvent.ParentId ?? cancelledEvent.Id, sqlTransaction); savingUnblockEvent.Deleted = true; } } } } if (!contract.WrittenOff && !contract.AllInstallmentsRepaid) { contract.Closed = false; if (evnt is LoanDisbursmentEvent) contract.ContractStatus = OContractStatus.Validated; else { contract.ContractStatus = evnt is LoanValidationEvent ? OContractStatus.Pending : OContractStatus.Active; } } //come back after write off if (evnt is WriteOffEvent) { contract.WrittenOff = false; contract.ContractStatus = OContractStatus.Active; CreditInsuranceEvent lciw = contract.GetNotDeletedInsuranceWriteOff(); if (lciw != null) { _ePs.CancelFireEvent(lciw, sqlTransaction, contract, contract.Product.Currency.Id); lciw.Deleted = true; } } _loanManager.UpdateLoan(contract, sqlTransaction); FundingLineEvent flFundingLineEvent; if (cancelledEvent is LoanDisbursmentEvent) { if (contract.HasCompulsoryAmount()) { _savingEventManager.DeleteSavingsEventByLoanEventId( cancelledEvent.ParentId ?? cancelledEvent.Id, sqlTransaction); SavingBlockCompulsarySavingsEvent savingBlockEvent = contract.CompulsorySavings.GetBlockCompulsorySavingEvent(); savingBlockEvent.Deleted = true; } LoanDisbursmentEvent temp = (LoanDisbursmentEvent) cancelledEvent; flFundingLineEvent = new FundingLineEvent { Code = String.Concat("DE_", contract.Code), Type = OFundingLineEventTypes.Disbursment, Amount = temp.Amount, Movement = OBookingDirections.Debit, CreationDate = TimeProvider.Now, FundingLine = contract.FundingLine }; DeleteFundingLineEvent(ref contract, flFundingLineEvent, sqlTransaction); _clientManager.DecrementLoanCycleByContractId(contract.Id, sqlTransaction); // delete entry fee events foreach (Event contractEvent in contract.Events) { if (contractEvent.Deleted) continue; if (contractEvent is LoanEntryFeeEvent) { _ePs.CancelFireEvent(contractEvent, sqlTransaction, contract, contract.Product.Currency.Id); contractEvent.Deleted = true; CallInterceptor(new Dictionary<string, object> { {"Loan", contract}, {"Event", contractEvent}, {"Deleted", true}, {"SqlTransaction", sqlTransaction} }); } if (contractEvent is CreditInsuranceEvent) { _ePs.CancelFireEvent(contractEvent, sqlTransaction, contract, contract.Product.Currency.Id); contractEvent.Deleted = true; } } if (evnt.ClientType == OClientTypes.Person) { if (_econimcActivityServices.EconomicActivityLoanHistoryExists(contract.Id, pClient.Id, sqlTransaction)) _econimcActivityServices.UpdateDeletedEconomicActivityLoanHistory(contract.Id, pClient.Id, ((Person) pClient) .Activity.Id, sqlTransaction, true); } else if (evnt.ClientType == OClientTypes.Group) { foreach (Member member in ((Group) pClient).Members) { if (_econimcActivityServices.EconomicActivityLoanHistoryExists(contract.Id, member.Tiers.Id, sqlTransaction)) _econimcActivityServices.UpdateDeletedEconomicActivityLoanHistory(contract.Id, member.Tiers.Id, ((Person) member.Tiers) .Activity.Id, sqlTransaction, true); } } else if (evnt.ClientType == OClientTypes.Corporate) { if (_econimcActivityServices.EconomicActivityLoanHistoryExists(contract.Id, pClient.Id, sqlTransaction)) _econimcActivityServices.UpdateDeletedEconomicActivityLoanHistory(contract.Id, pClient.Id, ((Corporate) pClient) .Activity.Id, sqlTransaction, true); } } else if (cancelledEvent is RepaymentEvent) { RepaymentEvent temp = (RepaymentEvent) cancelledEvent; decimal amountCalc = (temp.Principal.HasValue ? temp.Principal.Value : 0) + (ApplicationSettings.GetInstance(_user != null ? _user.Md5 : ""). InterestsCreditedInFL ? ((temp.Interests.HasValue ? temp.Interests.Value : 0) + (temp.Penalties.HasValue ? temp.Penalties.Value : 0)) : 0); if (amountCalc > 0 || ApplicationSettings.GetInstance(_user != null ? _user.Md5 : "").InterestsCreditedInFL) { flFundingLineEvent = new FundingLineEvent { Code = String.Concat("RE_", contract.Code, "_INS_", temp.InstallmentNumber), Type = OFundingLineEventTypes.Repay, Amount = amountCalc, CreationDate = TimeProvider.Now, FundingLine = _fundingLineServices.SelectFundingLineById(contract.FundingLine.Id, sqlTransaction) }; //temporary line to check whether funding line has enough amount to debit repayment event flFundingLineEvent.Movement = OBookingDirections.Debit; _fundingLineServices.ApplyRulesAmountEventFundingLine(flFundingLineEvent); flFundingLineEvent.Movement = OBookingDirections.Credit; DeleteFundingLineEvent(ref contract, flFundingLineEvent, sqlTransaction); } } CancelSavingsEvent(cancelledEvent, sqlTransaction); sqlTransaction.Commit(); sqlTransaction.Dispose(); SetClientStatus(contract, pClient); } catch (Exception) { sqlTransaction.Rollback(); throw; } return cancelledEvent; } }