示例#1
0
        }         // ToString

        public void Update(
            InterestData oDelta,
            InterestFreezePeriods ifp,
            BadPeriods bp,
            bool bAccountingMode,
            DateTime?oWriteOffDate
            )
        {
            if (bAccountingMode)
            {
                if (oWriteOffDate.HasValue)
                {
                    this.Interest = (this.Date < oWriteOffDate.Value) ? GetIfpInterest(ifp, oDelta) : 0;
                }
                else
                {
                    this.Interest = GetIfpInterest(ifp, oDelta);
                }
            }
            else               // i.e. normal mode
            {
                if (bp == null)
                {
                    this.Interest = GetIfpInterest(ifp, oDelta);
                }
                else
                {
                    this.Interest = bp.Contains(this.Date) ? 0 : GetIfpInterest(ifp, oDelta);
                }
            }     // if
        }         // Update
示例#2
0
        }         // FillFreezeIntervals

        private void FillCustomerStatuses()
        {
            CustomerStatusHistory = new CustomerStatusHistory(null, this.m_oDateEnd, this.m_oDB);

            foreach (KeyValuePair <int, List <CustomerStatusChange> > pair in CustomerStatusHistory.FullData.Data)
            {
                int nCustomerID = pair.Key;

                foreach (CustomerStatusChange csc in pair.Value)
                {
                    try {
                        bool bAlreadyHas = this.m_oBadPeriods.ContainsKey(nCustomerID);
                        bool bLastKnown  = !bAlreadyHas || this.m_oBadPeriods[nCustomerID].IsLastKnownGood;
                        bool bIsOldGood  = !BadPeriods.IsBad(csc.OldStatus);
                        bool bIsNewGood  = !BadPeriods.IsBad(csc.NewStatus);

                        if (bLastKnown != bIsOldGood)
                        {
                            Warn(
                                "Last known status is '{0}' while previous status is '{1}' for customer {2} on {3}.",
                                (bLastKnown ? "good" : "bad"),
                                (bIsOldGood ? "good" : "bad"),
                                nCustomerID,
                                csc.ChangeDate.ToString("MMM dd yyyy", CultureInfo.InvariantCulture)
                                );
                        }                         // if

                        if (bLastKnown != bIsNewGood)
                        {
                            if (bAlreadyHas)
                            {
                                this.m_oBadPeriods[nCustomerID].Add(csc.ChangeDate, !bIsNewGood);
                            }
                            else
                            {
                                this.m_oBadPeriods[nCustomerID] = new BadPeriods(csc.ChangeDate);
                            }
                        }                         // if
                    } catch (Exception e) {
                        Alert(e, "Failed to process customer status history entry.");
                    } // try
                }     // for each status change
            }         // for each customer
        }             // FillCustomerStatuses
示例#3
0
        }         // constructor

        /// <summary>
        /// Earned interest is a SUM(Pj * Ij) where the sum is taken on all the days during
        /// requested period when a loan could produce interest, Pj is a loan principal on
        /// specific day, Ij is an interest on that day.
        /// </summary>
        /// <param name="oDateStart">Requested period start date, inclusive.</param>
        /// <param name="oDateEnd">Requested period end date, exclusive.</param>
        /// <param name="ifp">Interest rate freeze periods.</param>
        /// <param name="bVerboseLogging">Log verbosity level.</param>
        /// <param name="nMode">Interest calculation mode.</param>
        /// <param name="bAccountingMode">How bad statuses and Write Off are treated.</param>
        /// <param name="oWriteOffDate">Date of the first customer's WriteOff status.</param>
        /// <param name="bp">List of customer's bad periods (i.e. when customer was in one of the bad statuses).</param>
        /// <returns>Earned interest for the period.</returns>
        public decimal Calculate(
            DateTime oDateStart,
            DateTime oDateEnd,
            InterestFreezePeriods ifp,
            bool bVerboseLogging,
            Reports.EarnedInterest.EarnedInterest.WorkingMode nMode,
            bool bAccountingMode,
            BadPeriods bp,
            DateTime?oWriteOffDate
            )
        {
            DateTime oFirstIncomeDay = this.IssueDate.AddDays(1);

            // A loan starts to produce interest on the next day.

            DateTime oDayOne = (oDateStart < oFirstIncomeDay) ? oFirstIncomeDay : oDateStart;

            // List of all the dates during requested period when a loan could produce interest.
            var oDaysList = new List <PrInterest>();

            for (DateTime d = oDayOne; d < oDateEnd; d = d.AddDays(1))
            {
                oDaysList.Add(new PrInterest(d, this.Amount));
            }

            if (oDaysList.Count == 0)
            {
                return(0);
            }

            DateTime oPrevDate = this.IssueDate;

            foreach (InterestData ida in this.Schedule.Values)
            {
                ida.PeriodLength = (ida.Date - oPrevDate).Days;
                oPrevDate        = ida.Date;
            }             // for each schedule

            oDaysList.ForEach(pri => {
                foreach (TransactionData t in this.Repayments.Values)
                {
                    pri.Update(t);
                }
            });             // for each day

            PrInterest[] days = oDaysList.Where(pri => pri.Principal > 0).ToArray();

            if (days.Length == 0)
            {
                LogAllDetails(
                    0,
                    "no dates found when the loan produced interest during report period",
                    days,
                    ifp,
                    bp,
                    bVerboseLogging,
                    bAccountingMode,
                    oWriteOffDate
                    );
                return(0);
            }             // if

            InterestData[] aryDates = this.Schedule.Values.ToArray();

            foreach (PrInterest pri in days)
            {
                InterestData oCurDayData = pri.Date > aryDates[aryDates.Length - 1].Date
                                        ? aryDates[aryDates.Length - 1]
                                        : aryDates.First(cdd => pri.Date <= cdd.Date);

                pri.Update(oCurDayData, ifp, bp, bAccountingMode, oWriteOffDate);
            }             // for

            decimal nEarnedInterest = days.Sum(pri => pri.Principal * pri.Interest);

            LogAllDetails(
                nEarnedInterest,
                "full details are below",
                days,
                ifp,
                bp,
                bVerboseLogging,
                bAccountingMode,
                oWriteOffDate
                );

            return(nEarnedInterest);
        }         // Calculate
示例#4
0
        }         // IfpToString

        private void LogAllDetails(
            decimal nEarnedInterest,
            string sMsg,
            IEnumerable <PrInterest> days,
            InterestFreezePeriods ifp,
            BadPeriods bp,
            bool bVerboseLogging,
            bool bAccountingMode,
            DateTime?oWriteOffDate
            )
        {
            if (!bVerboseLogging)
            {
                return;
            }

            if (string.IsNullOrWhiteSpace(sMsg))
            {
                sMsg = string.Empty;
            }
            else
            {
                sMsg = " - " + sMsg;
            }

            string sDaysList = (nEarnedInterest == 0)
                                ? "none"
                                : string.Join("\n\t", days.Select(pri => pri.ToString()).ToArray());

            string accountingModeName = bAccountingMode
                                ? "accounting mode (no interest earned after the first Write Off, other bad statuses are ignored)"
                                : "normal mode (no interest earned during bad periods, Write Off is considered as just another bad status)";

            this.log.Debug(
                "\n\nLoanID: {0} for customer {14}, {1} issued on {2} earned interest is {6}{11}.\n" +
                "Working mode: {15}\n" +
                "Write off date: {16}\n" +
                "Schedule ({7}):\n" +
                "\t{3}\n" +
                "Bad periods ({12}):\n" +
                "\t{13}\n" +
                "Freeze periods ({10}):\n" +
                "\t{9}\n" +
                "Transactions ({8}):\n" +
                "\t{4}\n" +
                "Per day:\n" +
                "\t{5}\n\n",
                this.loanID,
                this.Amount,
                this.IssueDate,
                string.Join("\n\t", this.Schedule.Values.Select(v => v.ToString()).ToArray()),
                string.Join("\n\t", this.Repayments.Values.Select(v => v.ToString()).ToArray()),
                sDaysList,
                nEarnedInterest,
                this.Schedule.Count,
                this.Repayments.Count,
                IfpToString(ifp),
                ifp == null ? 0 : ifp.Count,
                sMsg,
                bp == null ? 0 : bp.Count,
                bp == null ? "none" : bp.ToString(), this.CustomerID,
                accountingModeName,
                oWriteOffDate.HasValue ? oWriteOffDate.Value.ToString("MMM d yyyy", CultureInfo.InvariantCulture) : "none"
                );
        }         // LogAllDetails
示例#5
0
        }             // FillCustomerStatuses

        private SortedDictionary <int, decimal> ProcessLoans()
        {
            this.m_oDB.ForEachRowSafe(
                (sr, bRowsetStart) => {
                int nLoanID = sr[1];

                if (!this.m_oLoans.ContainsKey(nLoanID))
                {
                    if (VerboseLogging)
                    {
                        Debug("Ignoring loan id {0}", nLoanID);
                    }

                    return(ActionResult.Continue);
                }                         // if

                DateTime oDate = sr[2];

                decimal nValue = sr[3];

                switch ((string)sr[0])
                {
                case "0":
                    this.m_oLoans[nLoanID].Schedule[oDate] = new InterestData(oDate, nValue);

                    break;

                case "1":
                    if (nValue > 0)
                    {
                        this.m_oLoans[nLoanID].Repayments[oDate] = new TransactionData(oDate, nValue);
                    }

                    break;
                }                         // switch

                return(ActionResult.Continue);
            },
                "RptEarnedInterest_LoanDates",
                CommandSpecies.StoredProcedure
                );

            var oRes = new SortedDictionary <int, decimal>();

            foreach (KeyValuePair <int, LoanData> pair in this.m_oLoans)
            {
                InterestFreezePeriods ifp = this.m_oFreezePeriods.ContainsKey(pair.Key) ? this.m_oFreezePeriods[pair.Key] : null;

                BadPeriods bp            = null;
                DateTime?  oWriteOffDate = null;

                if (this.m_bAccountingMode)
                {
                    oWriteOffDate = CustomerStatusHistory.FullData.GetWriteOffDate(pair.Value.CustomerID);
                }
                else
                {
                    bp = this.m_oBadPeriods.ContainsKey(pair.Value.CustomerID) ? this.m_oBadPeriods[pair.Value.CustomerID] : null;
                }

                decimal nInterest = pair.Value.Calculate(this.m_oDateStart, this.m_oDateEnd,
                                                         ifp,
                                                         VerboseLogging, this.m_nMode, this.m_bAccountingMode,
                                                         bp,
                                                         oWriteOffDate
                                                         );

                if (nInterest > 0)
                {
                    oRes[pair.Key] = nInterest;
                }
            }             // foreach

            return(oRes);
        }         // ProcessLoans