/// <summary> /// Updates an existing loan in a loan request. /// </summary> /// <param name="financialInstitutionName">financialInstitution</param> /// <param name="workingCapitalLoan">workingCapitalLoan</param> /// <param name="interestRateId">interestRateId</param> /// <remarks>This function will update the Credit Line amounts only if the /// loan request has been completed.</remarks> public void UpdateLoanRequestLoanInformation(string financialInstitutionName, Loan loan, int interestRateId, int loanId, int loanVersion) { try { IFinancialInstitutionDAO financialInstitutionDAO = _daoFactory.GetFinancialInstitutionDAO (); IInterestRateDAO interestRateDAO = _daoFactory.GetInterestRateDAO (); ILoanDAO loanDAO = _daoFactory.GetLoanDAO (); //Before anything happens, lets verify the Id's match the given loan Id. if ((loan.Id != loanId) || (loan.Version != loanVersion)) { throw new ZiblerBusinessComponentsException (Resources.RecordNotFound); } /* Check that the loan has a valid amount */ if (loan.LoanedAmount <= 0) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgInvalidLoanAmount); } //If it is an Administrator, they may choose to leave the Start Date Blank //so the system will determine the Start Date automatically, however, they //may still want to override the default parameters, that is why I check for //the Interest Rate Id. Interest Rate Id won't be reported if they have not //selected one. if (loan.StartDate == null && interestRateId == 0) { FinancialInstitution financialInstitution = financialInstitutionDAO.GetFinancialInstitutionByName ( financialInstitutionName); //Look for the Loan Bracket. if (!financialInstitution.LoanBrackets.IsEmpty) { //We need to know what was the last request from the client //to whom the Loan Request belongs to. //TODO: It may be a better idea to calculate the max amount // using the database, rather than retrieven the records and // performing the operation here. Client client = loan.LoanRequest.Client; decimal maxTotalAmount = 0m; foreach (LoanRequest existingLoanRequest in client.LoanRequests) { /* Any loan request that has been approved is ok. The system allows * them to register loan requests even if they have not fully * paid the previous ones */ if (existingLoanRequest.LoanRequestStatus == LoanRequestStatus.Aprobada || existingLoanRequest.LoanRequestStatus == LoanRequestStatus.Corriente || existingLoanRequest.LoanRequestStatus == LoanRequestStatus.Vencida || existingLoanRequest.LoanRequestStatus == LoanRequestStatus.ExtraJudicial || existingLoanRequest.LoanRequestStatus == LoanRequestStatus.JudicialAltoRiesgo || existingLoanRequest.LoanRequestStatus == LoanRequestStatus.Pagada) { decimal loanReqTotalAmount = 0.0m; foreach (Loan existingLoan in existingLoanRequest.Loans) { loanReqTotalAmount = loanReqTotalAmount + existingLoan.LoanedAmount; } //If this is higher, then use it. if (loanReqTotalAmount > maxTotalAmount) maxTotalAmount = loanReqTotalAmount; } } //Order the loan brackets IList<LoanBracket> orderLoanBrackets = new List<LoanBracket> (); //Copy the list to a structure that will make it easier to work with. foreach (LoanBracket existingLoanBracket in financialInstitution.LoanBrackets) { orderLoanBrackets.Add (existingLoanBracket); } // TODO: Improve sorting algorithm // Sorting: Bubble Sort for (int i = orderLoanBrackets.Count - 1; i >= 0; i--) { for (int j = 1; j <= i; j++) { if (orderLoanBrackets[j - 1].MinimumAmount > orderLoanBrackets[j].MinimumAmount) { LoanBracket temp = orderLoanBrackets[j - 1]; orderLoanBrackets[j - 1] = orderLoanBrackets[j]; orderLoanBrackets[j] = temp; } } } decimal maxAmountAllowed = 0; decimal minAmountAllowed = 0; LoanParameter loanParameterToUse = null; //It is a new loan request, then use the lowest bracket if (maxTotalAmount <= 0) { //Take the first loan bracket. I would not be here //if there was not at least one bracket. maxAmountAllowed = orderLoanBrackets[0].MaximumAmount; minAmountAllowed = orderLoanBrackets[0].MinimumAmount; foreach (LoanParameter loanParamInBracket in orderLoanBrackets[0].LoanParameters) { if (loanParamInBracket.LoanType == loan.LoanType) { loanParameterToUse = loanParamInBracket; break; } } } else { bool bracketFound = false; //Search for the appropriate bracket. for (int i = 0; i < orderLoanBrackets.Count; i++) { decimal currentMaxAmnt = orderLoanBrackets[i].MaximumAmount; decimal currentMinAmnt = orderLoanBrackets[i].MinimumAmount; //If we have found the bracket for the maximum amount //the user has ever borrowed, then we step up to the next //bracket. if (maxTotalAmount <= currentMaxAmnt && maxTotalAmount >= currentMinAmnt) { //indicate we have found a bracket for the max amount //ever borrowd bracketFound = true; //If there is another Loan Bracket if (i + 1 <= orderLoanBrackets.Count) { maxAmountAllowed = orderLoanBrackets[i + 1].MaximumAmount; minAmountAllowed = orderLoanBrackets[i + 1].MinimumAmount; foreach (LoanParameter loanParamInBracket in orderLoanBrackets[i + 1].LoanParameters) { if (loanParamInBracket.LoanType == loan.LoanType) { loanParameterToUse = loanParamInBracket; break; } } } else { //If there are no more brackets //use this one. maxAmountAllowed = orderLoanBrackets[i].MaximumAmount; minAmountAllowed = orderLoanBrackets[i].MinimumAmount; foreach (LoanParameter loanParamInBracket in orderLoanBrackets[i].LoanParameters) { if (loanParamInBracket.LoanType == loan.LoanType) { loanParameterToUse = loanParamInBracket; break; } } } } } //If there are brackets registered in the system //but we could not find one which would fit the maximum //amount the client have ever requested then, we will simply //use the first one. We will then leave it up to an //administrator to change the loan amounts. if (!bracketFound) { //Take the first loan bracket. maxAmountAllowed = orderLoanBrackets[0].MaximumAmount; minAmountAllowed = orderLoanBrackets[0].MinimumAmount; foreach (LoanParameter loanParamInBracket in orderLoanBrackets[0].LoanParameters) { if (loanParamInBracket.LoanType == loan.LoanType) { loanParameterToUse = loanParamInBracket; break; } } } } //Now that we have the data we will use for max/min amounts //and parameters we have to run a check to make sure the user //is within the min and max parameters. decimal amntAlrdyRqsted = 0m; foreach (Loan requestLoan in loan.LoanRequest.Loans) { //Only account for the loans that are not the same. //other wise I will end up counting twice. if (requestLoan.Id != loan.Id) amntAlrdyRqsted = amntAlrdyRqsted + requestLoan.LoanedAmount; } decimal amntCheck = loan.LoanedAmount + amntAlrdyRqsted; //if we are within boundaries if (amntCheck <= maxAmountAllowed && amntCheck >= minAmountAllowed) { if (loanParameterToUse == null) //There no loan parameters setup for the loan bracket throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgNoParameterExistsForLoanBracket); //Setup the parameters for the loan. loan.AmortizationTableType = loanParameterToUse.AmortizationTableType; loan.GracePeriod = loanParameterToUse.GracePeriod; loan.GrossEarningsMargin = loanParameterToUse.GrossEarningsMargin; loan.NumberOfAmortizations = loanParameterToUse.NumberOfAmortizations; loan.OverdueRateFactor = loanParameterToUse.OverdueRateFactor; loan.OverdueRateAmount = loanParameterToUse.OverdueRateAmount; loan.PaymentFrequency = loanParameterToUse.PaymentFrequency; //Now get the interest rate loan.InterestRate = loanParameterToUse.InterestRate; /* Clear any previous commissions */ loan.ClearAllApplicableCommissions (); //Get the applicable commissions foreach (LoanCommission commissionToApply in loanParameterToUse.LoanCommissions) { LoanApplicableCommission newCommission = new LoanApplicableCommission (); newCommission.Amount = commissionToApply.Amount; newCommission.Concept = commissionToApply.Concept; newCommission.RateOverAmount = commissionToApply.RateOverAmount; loan.AddLoanApplicableCommission (newCommission); } } else { throw new ZiblerBusinessComponentsException ( String.Format ( Resources.LoanRequestOperationsMsgAmountOutOfBoundariesForBracket, minAmountAllowed.ToString ("C"), maxAmountAllowed.ToString ("C"))); } } /* There are no brackets */ else { bool defaultParamFound = false; //If the loan bracket was not found, look for the default parameters foreach (LoanParameter existingParam in financialInstitution.LoanParameters) { //Look for the default parameter for this type of loan. if (existingParam.IsDefault && existingParam.LoanType == loan.LoanType) { defaultParamFound = true; loan.AmortizationTableType = existingParam.AmortizationTableType; loan.GracePeriod = existingParam.GracePeriod; loan.GrossEarningsMargin = existingParam.GrossEarningsMargin; loan.NumberOfAmortizations = existingParam.NumberOfAmortizations; loan.OverdueRateFactor = existingParam.OverdueRateFactor; loan.OverdueRateAmount = existingParam.OverdueRateAmount; loan.PaymentFrequency = existingParam.PaymentFrequency; //Now get the interest rate loan.InterestRate = existingParam.InterestRate; /* Clear any applicable commissions */ loan.ClearAllApplicableCommissions (); //Get the applicable commissions foreach (LoanCommission commissionToApply in existingParam.LoanCommissions) { LoanApplicableCommission newCommission = new LoanApplicableCommission (); newCommission.Amount = commissionToApply.Amount; newCommission.Concept = commissionToApply.Concept; newCommission.RateOverAmount = commissionToApply.RateOverAmount; loan.AddLoanApplicableCommission (newCommission); } break; } } //There are no Default parameters if (!defaultParamFound) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgNoDefaultParameterExists); } } } /* Use the parameters entered by the user. */ else { InterestRate interestRate = interestRateDAO.FindById (interestRateId); //No interest rate is available if (interestRate == null) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgNoInterestRateExists); } loan.InterestRate = interestRate; } //After we have updated the loan information we need to update //the Credit Line amounts. //To do that we need to get the loan old amount first, to verify //if there is a new amount that we need to update. decimal oldAmount = loanDAO.GetOldLoanAmount (loan.Id); //If the amounts are different, then we will go ahead //and update the Credit Line. if (oldAmount != loan.LoanedAmount) { /* Update the loan request no matter what state it is. */ if (loan.LoanRequest.CreditLine != null) { CreditLine loanRequestCreditLine = loan.LoanRequest.CreditLine; //First we verify the status of the credit line. Only //active credit lines can be associated with LoanRequests if (loanRequestCreditLine.CreditLineStatus == CreditLineStatus.Suspendida) { throw new ZiblerBusinessComponentsException ( Resources.CreditLineOperationsMsgCreditLineMustBeActiveForAssociation); } /* Determine what values in the credit line to update based on the * status of the loan request */ if (loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.Capturada || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.Condicionada || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.EnCaptura || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.ExpedienteIntegrado) { //Restore credit line balance loanRequestCreditLine.AmountInRequestedLoans = loanRequestCreditLine.AmountInRequestedLoans - oldAmount; loanRequestCreditLine.AvailableAmount = loanRequestCreditLine.AvailableAmount + oldAmount; //If there is not enough money in the credit line to associate // we raise an exception indicating the problem. if (loanRequestCreditLine.AvailableAmount < loan.LoanedAmount) { throw new ZiblerBusinessComponentsException ( Resources.CreditLineOperationsMsgNotEnoughMoneyInCreditLine); } //Update credit line with new numbers. loanRequestCreditLine.AmountInRequestedLoans = loanRequestCreditLine.AmountInRequestedLoans + loan.LoanedAmount; loanRequestCreditLine.AvailableAmount = loanRequestCreditLine.AvailableAmount - loan.LoanedAmount; } else if (loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.Aprobada || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.Corriente || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.ExtraJudicial || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.JudicialAltoRiesgo || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.Vencida) { loanRequestCreditLine.AmountInAuthorizedLoans = loanRequestCreditLine.AmountInAuthorizedLoans - oldAmount; loanRequestCreditLine.AvailableAmount = loanRequestCreditLine.AvailableAmount + oldAmount; //If there is not enough money in the credit line to associate // we raise an exception indicating the problem. if (loanRequestCreditLine.AvailableAmount < loan.LoanedAmount) { throw new ZiblerBusinessComponentsException ( Resources.CreditLineOperationsMsgNotEnoughMoneyInCreditLine); } loanRequestCreditLine.AmountInAuthorizedLoans = loanRequestCreditLine.AmountInAuthorizedLoans + loan.LoanedAmount; loanRequestCreditLine.AvailableAmount = loanRequestCreditLine.AvailableAmount - loan.LoanedAmount; } } } /* Now lets update the payment schedule for the loan for those loans * that have been approved already */ if (loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.Aprobada || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.Corriente || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.ExtraJudicial || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.JudicialAltoRiesgo || loan.LoanRequest.LoanRequestStatus == LoanRequestStatus.Vencida) { //TODO: Should I do this here, or when they print the pagare. ZiblerFinanceUtilities util = new ZiblerFinanceUtilities (); AmortizationFactory amrtztnFctry = new AmortizationFactory (); if (loan.StartDate == null) loan.StartDate = loan.LoanRequest.LoanAuthorizationDate; else if (loan.StartDate != loan.LoanRequest.LoanAuthorizationDate) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgLoanStartDateAndAuthorizationDateAreNotEqual); } /* After setting the checks and setting the start date, then calculate the end * date */ /* Calculate the Last payment date for this loan */ DateTime endDate = util.GetPaymentNumberDate ( Convert.ToDateTime (loan.StartDate), loan.NumberOfAmortizations, loan.PaymentFrequency, Country.Mexico); loan.EndDate = endDate; /* Calculate the payments for this loan, and save them to the database. * This is to ease the report operations later */ Amortization amortization = amrtztnFctry.CreateAmortization ( loan.AmortizationTableType, loan.LoanedAmount, loan.NumberOfAmortizations, loan.PaymentFrequency, 0, loan.GracePeriod, loan.StartDate.Value, 0); //Calculate the amortization. amortization.CalculateAmortizationTable (); /* Add the payment dates */ util.AddAmortizationPaymentDates (amortization.AmortizationTable, amortization.StartDate, amortization.PaymentFrequency, Country.Mexico); /* Remove all payment schedules. This will guarantee that only * the correct information will be stored in the database */ loan.RemoveAllPaymentSchedules (); /* Add the Payment Schedule */ foreach (AmortizationEntry entry in amortization.AmortizationTable) { PaymentSchedule newSchedule = new PaymentSchedule (); newSchedule.PaymentDate = entry.Date; newSchedule.PaymentNumber = entry.Number; loan.AddPaymentSchedule (newSchedule); } } } /* If the exception was thrown here, just pass it up */ catch (ZiblerBusinessComponentsException ex) { throw; } /* Catch any Data Layer or other exception and throw an unkown exception */ catch (Exception ex) { ZiblerBusinessComponentsUnknownException exc = new ZiblerBusinessComponentsUnknownException (ex); /* Throw the new exception */ throw exc; } }
/// <summary> /// Creates an amortization table using the given parameters /// </summary> /// <param name="loan">loan</param> /// <param name="vat">vat</param> /// <returns>Amortization Table</returns> private Amortization CreateAmortizationTable(Loan loan, VAT vat) { AmortizationFactory amrtztnFctry = new AmortizationFactory (); Amortization amortization; //Before we continue, we need to get the applicable interest Rate. //note that this is only for the Analysis, and because of this, //then we will take the most active interest rate, if the loan request //has not been approved, or the approved date. DateTime? loanStartDate; if (loan.StartDate == null) loanStartDate = DateTime.Today; else loanStartDate = loan.StartDate; DateTime? selectedDate = null; decimal selectedInterest = 0.0m; //TODO: Note that this code, will get all the values applicable to an interest rate. // this may not be a big deal if they only register the value every month, // but it may cause a problem after a couple years if the register the values // every day. //Look for the interest RAte foreach (InterestRateValue value in loan.InterestRate.InterestRateValues) { DateTime? newDate = value.ValidFrom; bool newDateLessEqualLoanDate = !DateUtilities.IsFirstDateGreaterThanSecondDate (Convert.ToDateTime (newDate), Convert.ToDateTime (loanStartDate)); if (newDateLessEqualLoanDate) { if (selectedDate == null) { selectedDate = newDate; selectedInterest = value.Value; } else { bool isNewDateGreaterSelected = DateUtilities.IsFirstDateGreaterThanSecondDate (Convert.ToDateTime (newDate), Convert.ToDateTime ( selectedDate)); if (isNewDateGreaterSelected) { selectedDate = newDate; selectedInterest = value.Value; } } } } //Technically the selected date should never be null if (selectedDate == null) throw new ZiblerBusinessComponentsException ( Resources.LoanAnalysisMsgNoInterestRateAvailableCheckDates); //Add the Gross Earnings Margin (margen de intermediacion) to the //Interest Rate. decimal interestToUse = selectedInterest + loan.GrossEarningsMargin; amortization = amrtztnFctry.CreateAmortization (loan.AmortizationTableType, loan.LoanedAmount, loan.NumberOfAmortizations, loan.PaymentFrequency, interestToUse, loan.GracePeriod, Convert.ToDateTime (loanStartDate), vat.Value); //Calculate the amortization. amortization.CalculateAmortizationTable (); return amortization; }
/// <summary> /// Updates the information in the Loan Request /// </summary> /// <param name="loanRequest">Loan Request to update</param> /// <param name="financialInstitutionName">Financial institution</param> /// <remarks> /// IT IS ABSOLUTLY NECESSARY THAT AFTER A LOAN REQUEST HAS BEEN CANCELLED, /// REJECTED OR PAID, THEN THE SYSTEM WON'T ALLOW THEM TO UPDATE ANY DATA ON /// THE REQUEST. IN FACT THIS FUNCTION SHOULD NOT BE CALLED EVER AGAIN /// ON THE REQUEST, OTHERWISE THE CREDIT LINE AMOUNTS WILL NOT BE ACCURATE</remarks> public void UpdateLoanRequestInformation(string financialInstitutionName, LoanRequest loanRequest) { try { ICreditLineDAO creditLineDAO = _daoFactory.GetCreditLineDAO (); ILoanRequestDAO loanRequestDAO = _daoFactory.GetLoanRequestDAO (); IDepreciationForecastParametersDAO depreciationForecastParametersDAO = _daoFactory.GetDepreciationForecastParametersDAO (); IFinancialForecastParametersDAO financialForecastParametersDAO = _daoFactory.GetFinancialForecastParametersDAO (); IProjectFeasibilityParametersDAO projectFeasibilityParametersDAO = _daoFactory.GetProjectFeasibilityParametersDAO (); string oldTrackingCode = loanRequestDAO.GetOldTrackingCode (loanRequest.Id); //If the Request status has been changed to Aprobada LoanRequestStatus previousLoanRequestState = loanRequestDAO.GetLoanRequestOldStatus ( loanRequest.Id); /* Check the tracking code entered by the financial institution */ if (loanRequest.TrackingCode != null) { if (oldTrackingCode != loanRequest.TrackingCode) { //HACK: NOTE THAT I USE THE CLIENT OPERATIONS MESSAGE FOR THIS CHECK if (loanRequestDAO.TrackingCodeExists (financialInstitutionName, loanRequest.TrackingCode.Trim ())) { throw new ZiblerBusinessComponentsException ( Resources.ClientOperationsMsgLoanRequestTrackingCodeExists); } } } /* They have entered an authorization date, however the * loan request is not approved yet */ if (loanRequest.LoanRequestStatus != LoanRequestStatus.Aprobada && loanRequest.LoanRequestStatus != LoanRequestStatus.Corriente && loanRequest.LoanRequestStatus != LoanRequestStatus.Vencida && loanRequest.LoanRequestStatus != LoanRequestStatus.ExtraJudicial && loanRequest.LoanRequestStatus != LoanRequestStatus.JudicialAltoRiesgo && loanRequest.LoanRequestStatus != LoanRequestStatus.Pagada && loanRequest.LoanRequestStatus != LoanRequestStatus.Cancelada) { if (loanRequest.LoanAuthorizationDate != null) throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgLoanRequestHasAuthDateButNoApproved); } /* Indicates if the authorization date has changed */ bool authDateChanged = false; /* They marked the loan request approved or a status passed approved * so check and make sure they have entered an authorization date.*/ if (loanRequest.LoanRequestStatus == LoanRequestStatus.Aprobada || loanRequest.LoanRequestStatus == LoanRequestStatus.Corriente || loanRequest.LoanRequestStatus == LoanRequestStatus.ExtraJudicial || loanRequest.LoanRequestStatus == LoanRequestStatus.JudicialAltoRiesgo || loanRequest.LoanRequestStatus == LoanRequestStatus.Vencida) { if (loanRequest.LoanAuthorizationDate == null) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgNoAuthorizationDateProvided); } else { /* Get the old authorization date. We will use this to determine whether * or not they changed it */ DateTime? oldAuthDate = loanRequestDAO.GetLoanRequestOldAuthorizationDate ( loanRequest.Id); if (oldAuthDate != loanRequest.LoanAuthorizationDate) { authDateChanged = true; } } } /* Get the old amount */ decimal oldAmount = loanRequestDAO.GetLoanRequestOldTotalAmount ( loanRequest.Id); //Get the analysis parameters regardless if the loan request had them already //this is because they could have changed fron when the request was initialy //registered if (loanRequest.LoanRequestStatus == LoanRequestStatus.Aprobada || loanRequest.LoanRequestStatus == LoanRequestStatus.Capturada || loanRequest.LoanRequestStatus == LoanRequestStatus.ExpedienteIntegrado || loanRequest.LoanRequestStatus == LoanRequestStatus.Condicionada) { /* Get all the parameters for a financial institution */ //TODO: I don't expect anybody to have thousands of parameters // thus we can get them all. IList<DepreciationForecastParameters> depForecastParams = depreciationForecastParametersDAO.GetAllDepreciationForecasetParameters ( financialInstitutionName); /* Make sure they have registered the parameters */ if (depForecastParams.Count <= 0) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgDepreciationForecastParamsMissing); } DepreciationForecastParameters depParamToAssociate = null; //Look for the parameter that is applicable so we can associate it //to our loan request. foreach (DepreciationForecastParameters depForecastParam in depForecastParams) { DateTime paramDate = Convert.ToDateTime (depForecastParam.ValidFrom); //There is a posiblity that they have not assigned an Authorization date. //in that case we use todays date. DateTime? loanReqDate = null; if (loanRequest.LoanAuthorizationDate == null) loanReqDate = DateTime.Now; else loanReqDate = Convert.ToDateTime (loanRequest.LoanAuthorizationDate); if (DateUtilities.IsFirstDateGreaterOrEqualThanSecondDate ( Convert.ToDateTime (loanReqDate), paramDate)) { //The Current Parameter Date could apply to this loan Request. //Before we take it, we verify if we already have another date //in our paramToAssociate if (depParamToAssociate != null) { DateTime previousDate = Convert.ToDateTime ( depParamToAssociate.ValidFrom); if (DateUtilities.IsFirstDateGreaterOrEqualThanSecondDate ( paramDate, previousDate)) { //Take the new param depParamToAssociate = depForecastParam; } } else { depParamToAssociate = depForecastParam; } } } /* We could not find a parameter to associate */ if (depParamToAssociate == null) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgDepreciationForecastParamsWrongDate); } loanRequest.DepreciationForecastParameters = depParamToAssociate; //TODO: I don't expect anybody to have thousands of parameters // thus we can get them all. IList<FinancialForecastParameters> finForecastParams = financialForecastParametersDAO.GetAllFinancialForecasetParameters ( financialInstitutionName); /* Make sure they have registered the parameters */ if (finForecastParams.Count <= 0) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgFinancialForecastParamsMissing); } FinancialForecastParameters finForeParamToAssociate = null; //Look for the parameter that is applicable so we can associate it //to our loan request. foreach (FinancialForecastParameters finForecastParam in finForecastParams) { DateTime paramDate = Convert.ToDateTime (finForecastParam.ValidFrom); //There is a posiblity that they have not assigned an Authorization date. //in that case we use todays date. DateTime? loanReqDate = null; if (loanRequest.LoanAuthorizationDate == null) loanReqDate = DateTime.Now; else loanReqDate = Convert.ToDateTime (loanRequest.LoanAuthorizationDate); if (DateUtilities.IsFirstDateGreaterOrEqualThanSecondDate ( Convert.ToDateTime (loanReqDate), paramDate)) { //The Current Parameter Date could apply to this loan Request. //Before we take it, we verify if we already have another date //in our paramToAssociate if (finForeParamToAssociate != null) { DateTime previousDate = Convert.ToDateTime ( finForeParamToAssociate.ValidFrom); if (DateUtilities.IsFirstDateGreaterOrEqualThanSecondDate ( paramDate, previousDate)) { //Take the new param finForeParamToAssociate = finForecastParam; } } else { finForeParamToAssociate = finForecastParam; } } } /* We could not find a parameter to associate */ if (finForeParamToAssociate == null) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgFinancialForecastParamsWrongDate); } loanRequest.FinancialForecastParameters = finForeParamToAssociate; //TODO: I don't expect anybody to have thousands of parameters // thus we can get them all. IList<ProjectFeasibilityParameters> projFeasibilityParams = projectFeasibilityParametersDAO.GetAllProjectFeasibilityParameters ( financialInstitutionName); /* Make sure they have registered the parameters */ if (projFeasibilityParams.Count <= 0) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgProjectFeasibilityParamsMissing); } ProjectFeasibilityParameters projFeasParamToAssociate = null; //Look for the parameter that is applicable so we can associate it //to our loan request. foreach (ProjectFeasibilityParameters projFeasParam in projFeasibilityParams) { DateTime paramDate = Convert.ToDateTime (projFeasParam.ValidFrom); //There is a posiblity that they have not assigned an Authorization date. //in that case we use todays date. DateTime? loanReqDate = null; if (loanRequest.LoanAuthorizationDate == null) loanReqDate = DateTime.Now; else loanReqDate = Convert.ToDateTime (loanRequest.LoanAuthorizationDate); if (DateUtilities.IsFirstDateGreaterOrEqualThanSecondDate ( Convert.ToDateTime (loanReqDate), paramDate)) { //The Current Parameter Date could apply to this loan Request. //Before we take it, we verify if we already have another date //in our paramToAssociate if (projFeasParamToAssociate != null) { DateTime previousDate = Convert.ToDateTime ( projFeasParamToAssociate.ValidFrom); if (DateUtilities.IsFirstDateGreaterOrEqualThanSecondDate ( paramDate, previousDate)) { //Take the new param projFeasParamToAssociate = projFeasParam; } } else { projFeasParamToAssociate = projFeasParam; } } } /* We could not find a parameter to associate */ if (projFeasParamToAssociate == null) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgProjectFeasibilityParamsWrongDate); } loanRequest.ProjectFeasibilityParameters = projFeasParamToAssociate; /* Assign a credit line only if we have not done it before. * This is to avoid wrong balances in the credit line. * If the credit line has been assigned before, then we won't do anything * it will be up to the Administrator to change it if they need to. * * Note also that this method is called whenever the loan request is fully * captured in the system. This menas that the credit line balances * will be automatically updated whenever the loan request is first * captured. After this point, if the loan request status is changed * the credit line will also be updated. * */ //Get the default credit line and associate the Request //to the Credit line. //TODO: The following code is identical to the code contained in the // CreditLineOperations function: // public void AddLoanRequestsToCreditLine(CreditLine creditLineToUpdate, // IList<int> loanRequestIds) /* * The following rules are followed to determine how to calculate the amounts for the * credit line. * * If the Loan Request status is any of the following: * * -Cancelada * -Rechazada * -Pagada * -EnCaptura * * Then no update will be made to the balances in the Credit line. The update to the balance * will be performed when the LoanRequest status is changed to any of these. So we can * safely assume that if a loan request status is any of the above mention, it means that * the balance to its credit line has been updated. * * if the loan Request status is any of the following: * * -Capturada * -Expediente Integrado * -Condicionada * * then the total amount in loans will be added to the AmountInRequestedLoans * and substracted from the available amount. * * if the request status is any of the following: * * -Aprobada * -Corriente * -Vencida * -ExtraJudicial * -Judicial de Alto Riesgo * * then the total amount in loans will be added to the AmountInApprovedLoans * and substracted from the available amount * * */ CreditLine defaultCreditLine = creditLineDAO.GetDefaultCreditLine ( financialInstitutionName); //Now lets add the amounts from all the associated loans to this loanRequest decimal totalLoans = 0.0m; foreach (Loan loan in loanRequest.Loans) { totalLoans = totalLoans + loan.LoanedAmount; } if (loanRequest.LoanRequestStatus == LoanRequestStatus.Capturada || loanRequest.LoanRequestStatus == LoanRequestStatus.ExpedienteIntegrado || loanRequest.LoanRequestStatus == LoanRequestStatus.Condicionada) { /* If we have not previously assigned the Credit Line and the * default credit line exists then we go ahead and assign the * credit line and update balances. * Update the credit line status */ if (loanRequest.CreditLine == null && defaultCreditLine != null) { //If there is not enough money in the credit line to associate //the loan request then we raise an exception indicating the problem. if (defaultCreditLine.AvailableAmount < totalLoans) throw new ZiblerBusinessComponentsException ( Resources.CreditLineOperationsMsgNotEnoughMoneyInCreditLine); else //Otherwise { //Add the totalLoans amount to the Amount In Authorized Loans defaultCreditLine.AmountInRequestedLoans = defaultCreditLine.AmountInRequestedLoans + totalLoans; defaultCreditLine.AvailableAmount = defaultCreditLine.AvailableAmount - totalLoans; //Associate the Credit Line to the LoanRequest loanRequest.CreditLine = defaultCreditLine; } } else { /* DO NOTHING: * If either the credit line is not null or the * defulat credit line is null, then there is no * need to update the credit line, as it either does not exist * because they have not registered it or they did not buy * that part of the system, or it was assigned before * which means the values have been updated. */ } } /* If the loan request has been approved, then we need to update the * credit line mounts in case they updated the amounts in the loans */ else if (loanRequest.LoanRequestStatus == LoanRequestStatus.Aprobada || loanRequest.LoanRequestStatus == LoanRequestStatus.Corriente || loanRequest.LoanRequestStatus == LoanRequestStatus.ExtraJudicial || loanRequest.LoanRequestStatus == LoanRequestStatus.JudicialAltoRiesgo || loanRequest.LoanRequestStatus == LoanRequestStatus.Vencida) { /* At this point a credit line should have been assigned * to the loan request, so only perform the update if * the credit line was assigned to it */ if (loanRequest.CreditLine != null) { decimal totalAmount = 0.00m; foreach (Loan existingLoan in loanRequest.Loans) { totalAmount = totalAmount + existingLoan.LoanedAmount; } /* They have just approved the loan request */ if (loanRequest.LoanRequestStatus == LoanRequestStatus.Aprobada && previousLoanRequestState != loanRequest.LoanRequestStatus) { /* Update the credit line amounts */ loanRequest.CreditLine.AmountInRequestedLoans = loanRequest.CreditLine.AmountInRequestedLoans - oldAmount; loanRequest.CreditLine.AvailableAmount = loanRequest.CreditLine.AvailableAmount + oldAmount; /* Make sure there is enough money */ if (loanRequest.CreditLine.AvailableAmount < totalAmount) { throw new ZiblerBusinessComponentsException ( Resources.CreditLineOperationsMsgNotEnoughMoneyInCreditLine); } loanRequest.CreditLine.AmountInAuthorizedLoans = loanRequest.CreditLine.AmountInAuthorizedLoans + totalAmount; loanRequest.CreditLine.AvailableAmount = loanRequest.CreditLine.AvailableAmount - totalAmount; } /* The loan request has been approved already, we are just updating * it after it has been approved */ else { /* Update the credit line amounts */ loanRequest.CreditLine.AmountInAuthorizedLoans = loanRequest.CreditLine.AmountInAuthorizedLoans - oldAmount; loanRequest.CreditLine.AvailableAmount = loanRequest.CreditLine.AvailableAmount + oldAmount; /* Make sure there is enough money */ if (loanRequest.CreditLine.AvailableAmount < totalAmount) { throw new ZiblerBusinessComponentsException ( Resources.CreditLineOperationsMsgNotEnoughMoneyInCreditLine); } loanRequest.CreditLine.AmountInAuthorizedLoans = loanRequest.CreditLine.AmountInAuthorizedLoans + totalAmount; loanRequest.CreditLine.AvailableAmount = loanRequest.CreditLine.AvailableAmount - totalAmount; } } } } if (loanRequest.LoanRequestStatus == LoanRequestStatus.Aprobada || loanRequest.LoanRequestStatus == LoanRequestStatus.Corriente || loanRequest.LoanRequestStatus == LoanRequestStatus.ExtraJudicial || loanRequest.LoanRequestStatus == LoanRequestStatus.JudicialAltoRiesgo || loanRequest.LoanRequestStatus == LoanRequestStatus.Vencida) { //TODO: Should I do this here, or when they print the pagare. ZiblerFinanceUtilities util = new ZiblerFinanceUtilities (); AmortizationFactory amrtztnFctry = new AmortizationFactory (); //Finally we need to verify if a Start Date has been provided for the Loans //If it has, then we won't do anything, otherwise we will verify //if the loan is approved foreach (Loan existingLoan in loanRequest.Loans) { /* Make the loan start date, the same as the authorization date */ existingLoan.StartDate = loanRequest.LoanAuthorizationDate; /* After setting the checks and setting the start date, then calculate the end * date */ /* Calculate the Last payment date for this loan */ DateTime endDate = util.GetPaymentNumberDate ( Convert.ToDateTime (existingLoan.StartDate), existingLoan.NumberOfAmortizations, existingLoan.PaymentFrequency, Country.Mexico); existingLoan.EndDate = endDate; /* Calculate the payments for this loan, and save them to the database. * This is to ease the report operations later */ Amortization amortization = amrtztnFctry.CreateAmortization ( existingLoan.AmortizationTableType, existingLoan.LoanedAmount, existingLoan.NumberOfAmortizations, existingLoan.PaymentFrequency, 0, existingLoan.GracePeriod, existingLoan.StartDate.Value, 0); //Calculate the amortization. amortization.CalculateAmortizationTable (); /* Add the payment dates */ util.AddAmortizationPaymentDates (amortization.AmortizationTable, amortization.StartDate, amortization.PaymentFrequency, Country.Mexico); /* Remove all payment schedules. This will guarantee that only * the correct information will be stored in the database */ existingLoan.RemoveAllPaymentSchedules (); /* Add the Payment Schedule */ foreach (AmortizationEntry entry in amortization.AmortizationTable) { PaymentSchedule newSchedule = new PaymentSchedule (); newSchedule.PaymentDate = entry.Date; newSchedule.PaymentNumber = entry.Number; existingLoan.AddPaymentSchedule (newSchedule); } } } //If the loan request is in any of these final states, we have to make sure //we update the available amounts in the credit line associated to this loan request. /* * IT IS ABSOLUTLY NECESSARY THAT AFTER A LOAN REQUEST HAS BEEN CANCELLED, * REJECTED OR PAID, THEN THE SYSTEM WON'T ALLOW THEM TO UPDATE ANY DATA ON * THE REQUEST. IN FACT THIS FUNCTION SHOULD NOT BE CALLED EVER AGAIN * ON THE REQUEST, OTHERWISE THE CREDIT LINE AMOUNTS WILL NOT BE ACCURATE * */ //TODO: Again this could cause problems if there were no Credit Lines previously //registered. if (loanRequest.LoanRequestStatus == LoanRequestStatus.Cancelada || loanRequest.LoanRequestStatus == LoanRequestStatus.Rechazada || loanRequest.LoanRequestStatus == LoanRequestStatus.Pagada) { if (loanRequest.CreditLine != null) { decimal totalAmountInLoans = 0.0m; foreach (Loan loan in loanRequest.Loans) { totalAmountInLoans = totalAmountInLoans + loan.LoanedAmount; } //Now that we know how much we have borrowed. Lets update the Creditline //amounts. if (loanRequest.LoanRequestStatus == LoanRequestStatus.Pagada) { loanRequest.CreditLine.AmountInAuthorizedLoans = loanRequest.CreditLine.AmountInAuthorizedLoans - oldAmount; loanRequest.CreditLine.AvailableAmount = loanRequest.CreditLine.AvailableAmount + oldAmount; } else if (loanRequest.LoanRequestStatus == LoanRequestStatus.Rechazada) { loanRequest.CreditLine.AmountInRequestedLoans = loanRequest.CreditLine.AmountInRequestedLoans - oldAmount; loanRequest.CreditLine.AvailableAmount = loanRequest.CreditLine.AvailableAmount + oldAmount; } else if (loanRequest.LoanRequestStatus == LoanRequestStatus.Cancelada && (previousLoanRequestState == LoanRequestStatus.Aprobada || previousLoanRequestState == LoanRequestStatus.Corriente || previousLoanRequestState == LoanRequestStatus.Vencida || previousLoanRequestState == LoanRequestStatus.ExtraJudicial || previousLoanRequestState == LoanRequestStatus.JudicialAltoRiesgo)) { loanRequest.CreditLine.AmountInAuthorizedLoans = loanRequest.CreditLine.AmountInAuthorizedLoans - oldAmount; loanRequest.CreditLine.AvailableAmount = loanRequest.CreditLine.AvailableAmount + oldAmount; } else if (loanRequest.LoanRequestStatus == LoanRequestStatus.Cancelada && (previousLoanRequestState == LoanRequestStatus.Capturada || previousLoanRequestState == LoanRequestStatus.Condicionada || previousLoanRequestState == LoanRequestStatus.ExpedienteIntegrado)) { loanRequest.CreditLine.AmountInRequestedLoans = loanRequest.CreditLine.AmountInRequestedLoans - oldAmount; loanRequest.CreditLine.AvailableAmount = loanRequest.CreditLine.AvailableAmount + oldAmount; } } //If they just rejected the loan request, then we will go ahead //and update the rejection date if (loanRequest.LoanRequestStatus == LoanRequestStatus.Rechazada && previousLoanRequestState != LoanRequestStatus.Rechazada) { //If the date has not been provided then we use todays date. if (loanRequest.LoanRejectionDate == null) loanRequest.LoanRejectionDate = DateTime.Today; } //If they just cancelled the loan request, then we will go ahead //and update the cancelled date if (loanRequest.LoanRequestStatus == LoanRequestStatus.Cancelada && previousLoanRequestState != LoanRequestStatus.Cancelada) { if (loanRequest.LoanCancelledDate == null) loanRequest.LoanCancelledDate = DateTime.Today; } } } /* If the exception was thrown here, just pass it up */ catch (ZiblerBusinessComponentsException ex) { throw; } /* Catch any Data Layer or other exception and throw an unkown exception */ catch (Exception ex) { ZiblerBusinessComponentsUnknownException exc = new ZiblerBusinessComponentsUnknownException (ex); /* Throw the new exception */ throw exc; } }
/// <summary> /// Creates the amortization table. This function takes every amortization and /// calculates the payment based on the current Interest and VAT values. /// </summary> private void CreateAmortizationTable(ref Amortization amort) { try { AmortizationFactory amrtztnFctry = new AmortizationFactory (); amort = amrtztnFctry.CreateAmortization (_loan.AmortizationTableType, _loan.LoanedAmount, _loan.NumberOfAmortizations, _loan.PaymentFrequency, 0.0m, _loan.GracePeriod, Convert.ToDateTime (_loan.StartDate), 0.0m); //Calculate the amortization. amort.CalculateAmortizationTable (); //Add the dates _financeUtil.AddAmortizationPaymentDates (amort.AmortizationTable, amort.StartDate, amort.PaymentFrequency, Country.Mexico); } /* If the exception was thrown here, just pass it up */ catch (ZiblerBusinessComponentsException ex) { throw; } /* Catch any Data Layer or other exception and throw an unkown exception */ catch (Exception ex) { ZiblerBusinessComponentsUnknownException exc = new ZiblerBusinessComponentsUnknownException (ex); /* Throw the new exception */ throw exc; } }