protected virtual void OnDebtDealReceived(
     object o_debtDealsRegister, DebtDealReceivedEventData evData
     )
 {
     this.UpdateTotalsPerPerson(evData);
     this.UpdateStatisticsPerPerson(evData);
 }
示例#2
0
        private void SetIdsOfPeopleWhoCreditedMaxHistoricalTotal(
            AchieversDoc achieversDoc,
            DebtDealReceivedEventData evData
            )
        {
            HashSet <string> previousIds = this.currentAchieversDoc
                                           .HistoricallyCreditedMaxTotalPersonIds;
            var result = new HashSet <string>(1 + previousIds?.Count ?? 0);

            decimal initialMax = 0;

            if (previousIds != null && previousIds.Count > 0)
            {
                initialMax = GetDbTotalForPerson(previousIds.First());
            }

            if (evData.Analysis.IsPayback == false)
            {
                decimal newGiverTotal
                    = GetDbTotalForPerson(evData.Deal.GiverId);

                if (newGiverTotal > initialMax &&
                    newGiverTotal > DebtConstants.MaxZeroEquivalent
                    )
                {
                    result.Add(evData.Deal.GiverId);
                }
                else
                if (Math.Abs(newGiverTotal - initialMax)
                    <= DebtConstants.ValueRelativeError * initialMax
                    &&
                    initialMax > DebtConstants.MaxZeroEquivalent
                    )
                {
                    if (previousIds != null)
                    {
                        result.UnionWith(previousIds);
                    }
                    result.Add(evData.Deal.GiverId);
                }
            }

            if (result.Count == 0 && previousIds != null)
            {
                result.UnionWith(previousIds);
            }

            achieversDoc.HistoricallyCreditedMaxTotalPersonIds
                = result.Count > 0 ? result : null;

            decimal GetDbTotalForPerson(string personId)
            {
                return(this.dbc.CurrentTotalsPerPerson
                       .Where(ct => ct.PersonId == personId)
                       .Select(ct => ct.HistoricallyCreditedInTotal)
                       .FirstOrDefault());
            }
        }
        private void UpdateStatisticsPerPerson(
            DebtDealReceivedEventData evData
            )
        {
            if (evData.Analysis.IsPayback)
            {
                return;
            }

            /*
             *     *** Notes on parallel execution ***
             *
             *  Need to consider:
             *      * parallel changes of:
             *          + takerStatistics from CurrentStatisticsPerPerson table
             *          + takerTotals from CurrentTotalsPerPerson table
             *
             *  Result - serialize for operations with the same takerId in:
             *              + CurrentStatisticsPerPerson table
             *              + CurrentTotalsPerPerson table
             */

            string takerId = evData.Deal.TakerId;

            PersonTotalsRow takerTotals
                = this.rdbc.CurrentTotalsPerPerson
                  .Where(ct => ct.PersonId == takerId)
                  .FirstOrDefault()
                  ?? new PersonTotalsRow();
            PersonStatisticsRow takerStatistics
                = this.dbc.CurrentStatisticsPerPerson
                  .Where(s => s.PersonId == takerId)
                  .FirstOrDefault()
                  ?? new PersonStatisticsRow();

            takerStatistics.PersonId = takerId;
            takerStatistics.HistoricalDebtAverageThroughCasesOfTaking
                = takerTotals.HistoricallyOwedInTotal
                  / takerTotals.HistoricalCountOfCreditsTaken;

            if (this.dbc.CurrentStatisticsPerPerson
                .Count(s => s.PersonId == takerId) == 0
                )
            {
                this.dbc.CurrentStatisticsPerPerson.Add(takerStatistics);
            }

            this.dbc.SaveChanges();
        }
示例#4
0
        protected virtual void OnDebtDealReceived(
            object o_debtDealsRegister, DebtDealReceivedEventData evData
            )
        {
            var newDoc = new AchieversDoc()
            {
                Id = ObjectId.GenerateNewId()
            };

            this.SetIdsOfPeopleWithMaxTotalDueDebts(newDoc, evData);
            this.SetIdsOfPeopleWhoCreditedMaxHistoricalTotal(newDoc, evData);
            this.SetIdsOfBestDebtorsByRepaidFractionThenTotal(newDoc, evData);

            if (this.IsDocumentContentDifferent(newDoc, this.currentAchieversDoc))
            {
                this.SaveDocumentInDB(newDoc);

                PeopleStatisticsDocumentRow achieversDocRow
                    = this.dbc.CurrentPeopleStatisticsDocuments
                      .Where(sd => sd.DocumentName == AchieversDoc.Name)
                      .FirstOrDefault();
                bool shouldAddNewRow = false;
                if (achieversDocRow == null)
                {
                    shouldAddNewRow = true;
                    achieversDocRow = new PeopleStatisticsDocumentRow();
                }

                achieversDocRow.DocumentName = AchieversDoc.Name;
                achieversDocRow.DocumentId   = newDoc.Id.ToString();

                if (shouldAddNewRow)
                {
                    this.dbc.CurrentPeopleStatisticsDocuments
                    .Add(achieversDocRow);
                }

                this.dbc.SaveChanges();

                this.currentAchieversDoc = newDoc;
            }

            // keep execution serialized until DebtDealAdded event is handled.
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="evData"></param>
        /// <returns>new taker totals</returns>
        private void UpdateTotalsPerPerson(DebtDealReceivedEventData evData)
        {
            /*
             *     *** Notes on parallel execution ***
             *
             *  Need to consider:
             *      * parallel changes of the same
             *        giverTotals and takerTotals red from
             *        CurrentTotalsPerPerson table.
             *
             *      * parallel attempts to add new totals
             *        for the same giver or taker.
             *
             *  Result - serialize for operations in CurrentTotalsPerPerson
             *           table with the same giverId or takerId.
             */

            DebtDealRow deal = evData.Deal;

            PersonTotalsRow giverTotals
                = this.dbc.CurrentTotalsPerPerson
                  .Where(ct => ct.PersonId == deal.GiverId)
                  .FirstOrDefault()
                  ?? new PersonTotalsRow();

            giverTotals.PersonId = deal.GiverId;

            PersonTotalsRow takerTotals
                = this.dbc.CurrentTotalsPerPerson
                  .Where(ct => ct.PersonId == deal.TakerId)
                  .FirstOrDefault()
                  ?? new PersonTotalsRow();

            takerTotals.PersonId = deal.TakerId;

            if (evData.Analysis.IsPayback)
            {
                giverTotals.DueDebtsTotal = Math.Max(
                    0, giverTotals.DueDebtsTotal - deal.Amount);
            }
            else
            {
                giverTotals.HistoricallyCreditedInTotal += deal.Amount;
                takerTotals.DueDebtsTotal           += deal.Amount;
                takerTotals.HistoricallyOwedInTotal += deal.Amount;
                takerTotals.HistoricalCountOfCreditsTaken++;
            }

            if (this.dbc.CurrentTotalsPerPerson
                .Count(ct => ct.PersonId == deal.GiverId) == 0
                )
            {
                this.dbc.CurrentTotalsPerPerson.Add(giverTotals);
            }

            if (this.dbc.CurrentTotalsPerPerson
                .Count(ct => ct.PersonId == deal.TakerId) == 0
                )
            {
                this.dbc.CurrentTotalsPerPerson.Add(takerTotals);
            }

            this.dbc.SaveChanges();
        }
示例#6
0
        protected virtual void OnDebtDealReceived(
            object o_debtDealsRegister, DebtDealReceivedEventData evData
            )
        {
            /*
             *     *** Notes on parallel execution ***
             *
             * Similar to DebtDealsRegister Add method,
             * consider only these cases:
             *
             *  two unique involved id-s:
             *      * same giver, same taker
             *      * D1.giver = D2.taker, D1.taker = D2.giver
             *
             *  Need to consider parallel changes of the same debt
             *  in CurrentDebts table.
             *
             *  Result - serialize always when
             *  two deals have only two unique involved id-s.
             */

            DebtDealRow deal = evData.Deal;
            DebtRow     initialGiverDebtToTaker
                = this.dbc.CurrentDebts.Where(cd =>
                                              cd.CreditorId == deal.TakerId &&
                                              cd.DebtorId == deal.GiverId).FirstOrDefault();

            if (initialGiverDebtToTaker == null)
            {
                initialGiverDebtToTaker = new DebtRow {
                    CreditorId = deal.TakerId, DebtorId = deal.GiverId
                }
            }
            ;

            DebtRow initialTakerDebtToGiver
                = this.dbc.CurrentDebts.Where(cd =>
                                              cd.CreditorId == deal.GiverId &&
                                              cd.DebtorId == deal.TakerId).FirstOrDefault();

            if (initialTakerDebtToGiver == null)
            {
                initialTakerDebtToGiver = new DebtRow {
                    CreditorId = deal.GiverId, DebtorId = deal.TakerId
                }
            }
            ;

            DebtRow debtToChange;

            if (evData.Analysis.IsPayback)
            {
                debtToChange = initialGiverDebtToTaker;
            }
            else
            {
                debtToChange = initialTakerDebtToGiver;
            }

            decimal initialDebtAmount = debtToChange?.DebtTotal ?? 0m;
            decimal resultingDebtAmount;

            if (evData.Analysis.IsPayback)
            {
                resultingDebtAmount = Math.Max(0m,
                                               initialDebtAmount - deal.Amount);
            }
            else
            {
                resultingDebtAmount = initialDebtAmount + deal.Amount;
            }

            debtToChange.DebtTotal = resultingDebtAmount;

            if (resultingDebtAmount > DebtConstants.MaxZeroEquivalent)
            {
                if (this.dbc.CurrentDebts.Count(cd =>
                                                cd.CreditorId == debtToChange.CreditorId &&
                                                cd.DebtorId == debtToChange.DebtorId
                                                )
                    == 0
                    )
                {
                    this.dbc.CurrentDebts.Add(debtToChange);
                }
            }
            else
            {
                this.dbc.CurrentDebts.Remove(debtToChange);
            }

            this.dbc.SaveChanges();
        }
示例#7
0
        private void SetIdsOfBestDebtorsByRepaidFractionThenTotal(
            AchieversDoc achieversDoc,
            DebtDealReceivedEventData evData
            )
        {
            if (evData.Analysis.IsPayback != true)
            {
                return;
            }

            var previousIds = this.currentAchieversDoc
                              .BestDebtorIdsByRepaidFractionThenTotal;
            var potentialBestDebtors = new HashSet <string>(
                1 + previousIds?.Count ?? 0)
            {
                evData.Deal.GiverId
            };

            if (previousIds != null)
            {
                potentialBestDebtors.UnionWith(previousIds);
            }

            HashSet <string> result = GetBestDebtors(potentialBestDebtors);

            achieversDoc.BestDebtorIdsByRepaidFractionThenTotal
                = result.Count > 0 ? result : null;

            HashSet <string> GetBestDebtors(HashSet <string> input)
            {
                if (input.Count == 0)
                {
                    return(input);
                }

                var table
                    = input.Select(id =>
                                   new {
                    Id = id,
                    RepaidFraction
                        = this.personDebtsRegister
                          .GetRepaidFraction(id),
                    HistoricallyOwedInTotal
                        = this.personDebtsRegister
                          .GetTotals(id).HistoricallyOwedInTotal
                })
                      .OrderByDescending(r => r.RepaidFraction ?? 0)
                      .ThenByDescending(r => r.HistoricallyOwedInTotal);

                var     firstBestRow = table.First();
                decimal bestRFValue  = firstBestRow.RepaidFraction.Value;
                decimal maxTotal     = firstBestRow.HistoricallyOwedInTotal;

                if (bestRFValue <= DebtConstants.ValueRelativeError ||
                    maxTotal <= DebtConstants.MaxZeroEquivalent
                    )
                {
                    return(new HashSet <string>(0));
                }

                return(table
                       .Where(r =>
                              r.RepaidFraction == bestRFValue &&
                              r.HistoricallyOwedInTotal == maxTotal)
                       .Select(r => r.Id).ToHashSet());
            }
        }
示例#8
0
        private void SetIdsOfPeopleWithMaxTotalDueDebts(
            AchieversDoc achieversDoc,
            DebtDealReceivedEventData evData
            )
        {
            HashSet <string> previousIds
                = this.currentAchieversDoc.MaxDueDebtsTotalPersonIds;
            var result = new HashSet <string>(1 + previousIds?.Count ?? 0);

            decimal initialMax = 0;

            if (previousIds != null && previousIds.Count > 0)
            {
                initialMax = GetDbDueDebtsTotalForPerson(previousIds.First());
            }

            if (evData.Analysis.IsPayback == false)
            {
                decimal newTakerDebtsTotal
                    = GetDbDueDebtsTotalForPerson(evData.Deal.TakerId);

                if (newTakerDebtsTotal > initialMax &&
                    newTakerDebtsTotal > DebtConstants.MaxZeroEquivalent
                    )
                {
                    result.Add(evData.Deal.TakerId);
                }
                else
                if (Math.Abs(newTakerDebtsTotal - initialMax)
                    <= DebtConstants.ValueRelativeError * initialMax
                    &&
                    initialMax > DebtConstants.MaxZeroEquivalent
                    )
                {
                    if (previousIds != null)
                    {
                        result.UnionWith(previousIds);
                    }
                    result.Add(evData.Deal.TakerId);
                }
            }
            else if (previousIds != null &&
                     previousIds.Count == 1 &&
                     previousIds.Contains(evData.Deal.GiverId)
                     )
            {
                decimal newMaxTotal = 0;
                foreach (PersonTotalsRow t in
                         this.rdbc.CurrentTotalsPerPerson
                         .OrderByDescending(ct => ct.DueDebtsTotal)
                         )
                {
                    if (t.DueDebtsTotal <= DebtConstants.MaxZeroEquivalent)
                    {
                        break;
                    }

                    if (result.Count == 0)
                    {
                        result.Add(t.PersonId);
                        newMaxTotal = t.DueDebtsTotal;
                        continue;
                    }

                    if (t.DueDebtsTotal - newMaxTotal
                        <= DebtConstants.ValueRelativeError * newMaxTotal
                        )
                    {
                        result.Add(t.PersonId);
                    }
                    else
                    {
                        break;
                    }
                }
            }

            achieversDoc.MaxDueDebtsTotalPersonIds
                = result.Count > 0 ? result : null;

            decimal GetDbDueDebtsTotalForPerson(string personId)
            {
                return(this.dbc.CurrentTotalsPerPerson
                       .Where(ct => ct.PersonId == personId)
                       .Select(ct => ct.DueDebtsTotal)
                       .FirstOrDefault());
            }
        }