public FinancialAnalysis(LoanRequest loanRequest, VAT vat) { //The loan Request contains all the necessary data //to calculate a Financial Analysis. _loanRequest = loanRequest; _financeUtil = new ZiblerFinanceUtilities (); //Establish what loans are present foreach (Loan existingLoan in _loanRequest.Loans) { if (existingLoan.LoanType == LoanType.CapitalDeTrabajo) { _wrkngCptlAmrtztn = CreateAmortizationTable (existingLoan, vat); _wrkngCptlLoan = existingLoan; _financeUtil.AddAmortizationPaymentDates (_wrkngCptlAmrtztn.AmortizationTable, _wrkngCptlAmrtztn.StartDate, _wrkngCptlAmrtztn.PaymentFrequency, Country.Mexico); } if (existingLoan.LoanType == LoanType.Refaccionario) { _fxdAsstAmrtztn = CreateAmortizationTable (existingLoan, vat); _fxdAsstLoan = existingLoan; _financeUtil.AddAmortizationPaymentDates (_fxdAsstAmrtztn.AmortizationTable, _fxdAsstAmrtztn.StartDate, _fxdAsstAmrtztn.PaymentFrequency, Country.Mexico); } } }
/// <summary> /// Initializes a new instance of the <see cref="LoanStatement"/> class. /// </summary> /// <param name="loan">The loan.</param> /// <param name="stmntDate">The STMNT date.</param> /// <param name="vats">The vats.</param> public LoanStatement(Loan loan, DateTime stmntDate, IList<VAT> vats, IList<InterestRateValue> intrstRtVls) { _financeUtil = new ZiblerFinanceUtilities (); _loanStmntCalc = new LoanStatementCalc (loan, stmntDate, vats, intrstRtVls); _displayUserData = true; _loan = loan; _stmntDate = stmntDate; }
/// <summary> /// Initializes a new instance of the <see cref="LoanStatement"/> class. /// </summary> /// <param name="loan">The loan.</param> /// <param name="stmntDate">The STMNT date.</param> /// <param name="vats">The vats.</param> public LoanStatementCalc(Loan loan, DateTime stmntDate, IList<VAT> vats, IList<InterestRateValue> intrstRtVls) { _financeUtil = new ZiblerFinanceUtilities (); _pymntApplctnRcrd = new List<PaymentApplicationRecord> (); _loan = loan; _stmntDate = stmntDate; _vats = vats; _intrstRtVls = intrstRtVls; }
/// <summary> /// Adds a list of Loan commissions to a loan /// </summary> /// <param name="loanToUpdate">loanToUpdate</param> /// <param name="loanCommissions">loanCommissions</param> public void AddLoanApplicableCommissions(Loan loanToUpdate, IList<int> loanCommissions) { try { ILoanCommissionDAO loanCommissionDAO = _daoFactory.GetLoanCommissionDAO (); foreach (int loanCommissionId in loanCommissions) { LoanCommission loanCommission = loanCommissionDAO.FindById (loanCommissionId); if (loanCommission == null) { throw new ZiblerBusinessComponentsException ( Resources.LoanOperationsMsgLoanCommissionNotFound); } else { LoanApplicableCommission newCommission = new LoanApplicableCommission (); newCommission.Amount = loanCommission.Amount; newCommission.Concept = loanCommission.Concept; newCommission.RateOverAmount = loanCommission.RateOverAmount; //Make sure it does not have an existing commission foreach (LoanApplicableCommission loanAppComm in loanToUpdate.LoanApplicableCommissions) { if (loanAppComm.Concept == newCommission.Concept) { throw new ZiblerBusinessComponentsException ( Resources.LoanOperationsMsgLoanCommissionExistsInLoan); } } loanToUpdate.AddLoanApplicableCommission (newCommission); } } } /* 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> /// Adds a new Loan to a loan request /// </summary> /// <param name="financialInstitutionName">financialInstitution</param> /// <param name="loanRequest">loanRequest</param> /// <param name="workingCapitalLoan">workingCapitalLoan</param> /// <param name="interestRateId">interestRateId</param> /// <remarks>This function won't change the balances in the Credit lines. This is because /// when a new loan is created, the Loan Request has not been completed. I will only update /// the amounts once the Loan Request has been completed or when they update a Loan Amount and the /// loan request is completed.</remarks> public void CreateNewLoanInLoanRequest(string financialInstitutionName, LoanRequest loanRequest, Loan loan, int interestRateId) { try { IFinancialInstitutionDAO financialInstitutionDAO = _daoFactory.GetFinancialInstitutionDAO (); IInterestRateDAO interestRateDAO = _daoFactory.GetInterestRateDAO (); /* Check that the loan has a valid amount */ if (loan.LoanedAmount <= 0) { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgInvalidLoanAmount); } //First we determine if we need to use default values for the loan, //of if this values were provided. This values will only be provided //if the user has the authority to do so. //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); //TODO: If enforce //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 = loanRequest.Client; decimal maxTotalAmount = 0m; foreach (LoanRequest existingLoanRequest in client.LoanRequests) { //In theory all loan requests must be paid before they allow //the client to get another loan. The system checks for this before //allow them to register a new loan request, so technically I should //only be looking for Pagada. 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); } // 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 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) { //There no loan parameters setup for //the loan bracket if (loanParameterToUse == null) { 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; loan.DelayedDays = 0; //Now get the interest rate loan.InterestRate = loanParameterToUse.InterestRate; //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); } //Now that we have set the loan properties, we will add it to the //loan request. loanRequest.AddLoan (loan); } else { throw new ZiblerBusinessComponentsException ( String.Format ( Resources.LoanRequestOperationsMsgAmountOutOfBoundariesForBracket, minAmountAllowed.ToString ("C"), maxAmountAllowed.ToString ("C"))); } } 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 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; loan.DelayedDays = 0; //Now get the interest rate loan.InterestRate = existingParam.InterestRate; //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; } } if (defaultParamFound) { loanRequest.AddLoan (loan); } //There are no Default parameters else { throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgNoDefaultParameterExists); } } } else { //TODO: Add the loan applicable commissions //If values have been provided then we simply take the loan //and add it to the loan request. InterestRate interestRate = interestRateDAO.FindById (interestRateId); if (interestRate == null) { //No interest rate is available throw new ZiblerBusinessComponentsException ( Resources.LoanRequestOperationsMsgNoInterestRateExists); } loan.InterestRate = interestRate; loanRequest.AddLoan (loan); } } /* 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> /// 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> /// Sets the Loan request status based on the number of days this /// loan is delayed. /// </summary> /// <param name="loanRequest">LoanRequest to update</param> /// <param name="loan">Loan to be used for the update</param> /// <param name="stmntDate">Date to use to calculate the statement</param> /// <param name="vats">List of applicable VATS</param> /// <param name="intValues">List of applicable Interest Rate valus</param> /// <param name="nrmlzdDate">Normalized date used to set the next status update date.</param> /// <param name="firstPass">Is this the first time this function is called for the loans of a loan request?</param> public void SetLoanRequestStatus(LoanRequest loanRequest, Loan loan, DateTime stmntDate, IList<VAT> vats, IList<InterestRateValue> intValues, DateTime nrmlzdDate, bool firstPass) { try { DateTime nextUpdtDate = nrmlzdDate; /* Calculate the statement to today's day */ LoanStatement stmnt = new LoanStatement (loan, stmntDate, vats, intValues, false); /* Calculate the statement and determine how many days * behind is the loan. */ stmnt.GenerateStatement (); int delayedDays = stmnt.DelayedDays; /* Update the loan statement values stored in the DB */ loan.DelinquentVAT = stmnt.DelinquentVAT; loan.MoratoryInterests = stmnt.MoratoryInterests; loan.DelinquentInterests = stmnt.DelinquentInterests; loan.DelinquentPrincipal = stmnt.DelinquentPrincipal; loan.DelinquentBalance = stmnt.DelinquentBalance; loan.CurrentPrincipal = stmnt.CurrentPrincipal; loan.CurrentInterests = stmnt.CurrentInterests; loan.CurrentVAT = stmnt.CurrentVAT; loan.CurrentCommissions = stmnt.CurrentCommissions; loan.PaymentBalance = stmnt.PaymentBalance; loan.CurrentBalance = stmnt.CurrentBalance; loan.DelayedDays = delayedDays; /* Set the Loan Request Status accordingly. * * Corriente - No Delays * Vencida - Delayed 1 to 3 days (including day 3) * ExtraJudicial - Delayed 4 to 89 days * JudicialAltoRiesgo - Delayed 90 or more * */ if (delayedDays == 0) /* Corriente */ { /* If this is the first loan, set the loan request status */ if (firstPass) { /* Get the next payment date from the day * we calculated this update */ nextUpdtDate = nrmlzdDate; nextUpdtDate = stmnt.GetNextPayment (nrmlzdDate); /* Check one day after the next payment */ nextUpdtDate = nextUpdtDate.AddDays (1); loanRequest.LoanRequestStatus = LoanRequestStatus.Corriente; loanRequest.ContinueStatusUpdates = true; loanRequest.NextStatusUpdate = nextUpdtDate; } else { /* Corriente status takes presedence as long as this is not the first * pass and the following condition is TRUE */ if (loanRequest.LoanRequestStatus != LoanRequestStatus.Vencida && loanRequest.LoanRequestStatus != LoanRequestStatus.ExtraJudicial && loanRequest.LoanRequestStatus != LoanRequestStatus.JudicialAltoRiesgo) { /* Get the next payment date from the day * we calculated this update */ nextUpdtDate = nrmlzdDate; nextUpdtDate = stmnt.GetNextPayment (nrmlzdDate); /* Check one day after the next payment */ nextUpdtDate = nextUpdtDate.AddDays (1); loanRequest.LoanRequestStatus = LoanRequestStatus.Corriente; loanRequest.ContinueStatusUpdates = true; loanRequest.NextStatusUpdate = nextUpdtDate; } else { /* DO NOTHING */ } } } else if (delayedDays >= 1 && delayedDays <= Globals.VENCIDA) { if (firstPass) { nextUpdtDate = nrmlzdDate; nextUpdtDate = GetNextUpdateDate (nextUpdtDate); loanRequest.LoanRequestStatus = LoanRequestStatus.Vencida; loanRequest.ContinueStatusUpdates = true; loanRequest.NextStatusUpdate = nextUpdtDate; } else { /* Vencida status takes presedence as long as this is not the first * pass and the following condition is TRUE */ if (loanRequest.LoanRequestStatus != LoanRequestStatus.ExtraJudicial && loanRequest.LoanRequestStatus != LoanRequestStatus.JudicialAltoRiesgo) { nextUpdtDate = nrmlzdDate; nextUpdtDate = GetNextUpdateDate (nextUpdtDate); loanRequest.LoanRequestStatus = LoanRequestStatus.Vencida; loanRequest.ContinueStatusUpdates = true; loanRequest.NextStatusUpdate = nextUpdtDate; } else { /* DO NOTHING */ } } } else if (delayedDays > Globals.VENCIDA && delayedDays <= Globals.EXTRA_JUDICIAL) { if (firstPass) { nextUpdtDate = nrmlzdDate; nextUpdtDate = GetNextUpdateDate (nextUpdtDate); loanRequest.LoanRequestStatus = LoanRequestStatus.ExtraJudicial; loanRequest.ContinueStatusUpdates = true; loanRequest.NextStatusUpdate = nextUpdtDate; } else { /* ExtraJudicial status takes presedence as long as this is not the first * pass and the following condition is TRUE */ if (loanRequest.LoanRequestStatus != LoanRequestStatus.JudicialAltoRiesgo) { nextUpdtDate = nrmlzdDate; nextUpdtDate = GetNextUpdateDate (nextUpdtDate); loanRequest.LoanRequestStatus = LoanRequestStatus.ExtraJudicial; loanRequest.ContinueStatusUpdates = true; loanRequest.NextStatusUpdate = nextUpdtDate; } else { /* DO NOTHING */ } } } else if (delayedDays >= Globals.JUDICIAL_ALTO_RIESGO) { nextUpdtDate = nrmlzdDate; nextUpdtDate = GetNextUpdateDate (nextUpdtDate); /* JudicialAltoRiesgo takes presedence over every other state */ loanRequest.LoanRequestStatus = LoanRequestStatus.JudicialAltoRiesgo; /* We will stop updating if the delayed days is greater than 180 days */ if (delayedDays > Globals.MAX_UPDATE_DAYS) { loanRequest.ContinueStatusUpdates = false; } else { loanRequest.ContinueStatusUpdates = true; } loanRequest.NextStatusUpdate = nextUpdtDate; } } /* 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> /// Removes the given applicableCommissions /// </summary> /// <param name="loanToUpdate">loanToUpdate</param> /// <param name="applicableCommissions">applicableCommissions</param> public void RemoveLoanApplicableCommissions(Loan loanToUpdate, IList<int> applicableCommissions) { try { ILoanApplicableCommissionDAO loanApplicableCommissionDAO = _daoFactory.GetLoanApplicableCommissionDAO (); IList<LoanApplicableCommission> commissionsToRemove = new List<LoanApplicableCommission> (); foreach (int commissionId in applicableCommissions) { LoanApplicableCommission commision = loanApplicableCommissionDAO.FindById ( commissionId); if (commision == null) { throw new ZiblerBusinessComponentsException ( Resources.LoanOperationsMsgLoanApplicableCommissionNotFound); } else { commissionsToRemove.Add (commision); } } foreach (LoanApplicableCommission commToRemove in commissionsToRemove) { loanToUpdate.RemoveLoanApplicableCommission (commToRemove); } } /* 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> /// Gets the loan statement. /// </summary> /// <param name="financialInstitution">The financial institution.</param> /// <param name="loan">The loan.</param> /// <param name="statementDate">The statement date.</param> /// <returns>Loan Statement</returns> public LoanStatement GetLoanStatement(string financialInstitution, Loan loan, DateTime statementDate) { try { IFinancialInstitutionDAO financialInstitutionDAO = _daoFactory.GetFinancialInstitutionDAO (); IInterestRateValueDAO interestRateValueDAO = _daoFactory.GetInterestRateValueDAO (); IVatDAO vatDAO = _daoFactory.GetVatDAO (); if (loan == null) throw new ZiblerBusinessComponentsException (Resources.RecordNotFound); FinancialInstitution finInst = financialInstitutionDAO.GetFinancialInstitutionByName (financialInstitution); if (finInst == null) throw new ZiblerBusinessComponentsUnknownException (); /* Check the statement date is not before the start */ if (!DateUtilities.IsFirstDateGreaterOrEqualThanSecondDate ( Convert.ToDateTime (statementDate), Convert.ToDateTime (loan.StartDate))) { throw new ZiblerBusinessComponentsException ( Resources.LoanOperationsMsgStatementDateIsBeforeLoan); } if (loan.EndDate == null) throw new ZiblerBusinessComponentsUnknownException (); /* Get all the VATS within the range */ IList<VAT> vats = vatDAO.GetVATsForStatement (financialInstitution, Convert.ToDateTime (loan.StartDate), statementDate); /* Make sure there is at least one from the beginning of the loan */ bool vatFound = false; if (vats != null) { foreach (VAT vat in vats) { if (!DateUtilities.IsFirstDateGreaterThanSecondDate ( Convert.ToDateTime (vat.ValidFrom), Convert.ToDateTime (loan.StartDate))) { vatFound = true; break; } } } if (!vatFound) { throw new ZiblerBusinessComponentsException ( Resources.LoanOperationsMsgNoVATsInSystem); } /* Get the interest Rate Values */ IList<InterestRateValue> interestValues = interestRateValueDAO.GetInterestRateValuesForStatement (loan.InterestRate.Id, Convert.ToDateTime ( loan.StartDate), statementDate); /* Make sure there is at least one from the beginning of the loan */ bool intFound = false; if (interestValues != null) { foreach (InterestRateValue val in interestValues) { if (!DateUtilities.IsFirstDateGreaterThanSecondDate ( Convert.ToDateTime (val.ValidFrom), Convert.ToDateTime (loan.StartDate))) { intFound = true; break; } } } if (!intFound) { throw new ZiblerBusinessComponentsException ( Resources.LoanOperationsMsgNoInterestRateValu); } /* Generate the statement */ LoanStatement loanStatement = new LoanStatement (loan, statementDate, vats, interestValues); loanStatement.GenerateStatement (); return loanStatement; } /* 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; } }
public virtual void RemoveLoan(Loan loan) { Loans.Remove (loan); }
public virtual void AddLoan(Loan loan) { loan.LoanRequest = this; Loans.Add (loan); }