コード例 #1
0
        public async Task UploadWithSeasonIdAmountLessThanDebt()
        {
            var mockRepaymentUpload = new RepaymentUpload
            {
                CustomerId = 1,
                SeasonId   = 2,
                Amount     = 100,
                Date       = DateTime.Now
            };


            var repayments = await _repaymentService.ProcessUpload(mockRepaymentUpload);

            Assert.NotNull(repayments);
            Assert.Single(repayments);

            var repayment = repayments.First();

            Assert.Equal(mockRepaymentUpload.Amount, repayment.Amount);
            Assert.Equal(mockRepaymentUpload.CustomerId, repayment.CustomerId);
            Assert.Equal(mockRepaymentUpload.SeasonId, repayment.SeasonId);

            var summaryAfterUpload = await _dbContext.CustomerSummaries
                                     .FirstOrDefaultAsync(cs =>
                                                          cs.CustomerId == mockRepaymentUpload.CustomerId && cs.SeasonId == mockRepaymentUpload.SeasonId);


            Assert.Equal(800, summaryAfterUpload.TotalRepaid);
        }
コード例 #2
0
        private async Task <List <Repayment> > ProcessUploadWithoutSeasonId(RepaymentUpload repaymentUpload)
        {
            var customerSummaries =
                await _customerSummaryRepository.GetOutstandingByCustomerId(repaymentUpload.CustomerId);

            var repayments = new List <Repayment>();

            if (customerSummaries.Count <= 0)
            {
                repayments.Add(await ProcessUploadToLastDebt(repaymentUpload));
                return(repayments);
            }

            var linkedList = new LinkedList <CustomerSummary>(customerSummaries);

            var current  = linkedList.First;
            var amount   = repaymentUpload.Amount;
            int?parentId = null;

            while (current != null && amount > 0)
            {
                var cs     = current.Value;
                var result = DoAdjustment(new AdjustmentInput(amount, cs.TotalCredit - cs.TotalRepaid,
                                                              cs.CustomerId, repaymentUpload.Date, cs.SeasonId, parentId));

                if (result.RemainingAmount <= 0 || current == linkedList.Last)
                {
                    cs.TotalRepaid += amount;
                    repayments.Add(result.Repayment);
                    _customerSummaryRepository.Update(cs);
                    break;
                }

                amount = result.RemainingAmount;
                if (!parentId.HasValue)
                {
                    await _appDbContext.SaveChangesAsync();

                    parentId = result.Repayment.Id;
                }

                repayments.Add(result.Repayment);
                if (amount > 0)
                {
                    cs.TotalRepaid = cs.TotalCredit;
                    _customerSummaryRepository.Update(cs);
                    result = DoAdjustment(new AdjustmentInput(-amount, null, cs.CustomerId, repaymentUpload.Date,
                                                              cs.SeasonId,
                                                              parentId));
                    repayments.Add(result.Repayment);
                }

                current = current.Next;
            }

            return(repayments);
        }
コード例 #3
0
 public static Repayment ToRepayment(this RepaymentUpload upload)
 {
     return(new Repayment
     {
         Amount = upload.Amount,
         CustomerId = upload.CustomerId,
         SeasonId = upload.SeasonId,
         Date = upload.Date
     });
 }
コード例 #4
0
        private async Task <Repayment> ProcessUploadToLastDebt(RepaymentUpload repaymentUpload)
        {
            var customerSummary =
                await _customerSummaryRepository.GetLastByCustomerId(repaymentUpload.CustomerId);

            customerSummary.TotalRepaid += repaymentUpload.Amount;
            _customerSummaryRepository.Update(customerSummary);
            var repayment = repaymentUpload.ToRepaymentWithSeasonId(customerSummary.SeasonId);

            _repaymentRepository.Add(repayment);
            _appDbContext.RepaymentUploads.Add(repaymentUpload);
            return(repayment);
        }
コード例 #5
0
        private Repayment CreateRepaymentRecord(RepaymentUpload repayment, decimal amount, int parentId)
        {
            var record = new Repayment
            {
                CustomerId = repayment.CustomerId,
                SeasonId   = (int)repayment.SeasonId,
                Date       = repayment.Date,
                Amount     = amount,
                ParentId   = parentId
            };

            _repaymentRepository.Insert(record);

            return(record);
        }
コード例 #6
0
        public async Task <List <Repayment> > ProcessUpload(RepaymentUpload repaymentUpload)
        {
            var repayments = new List <Repayment>();

            if (repaymentUpload.SeasonId.HasValue)
            {
                repayments.Add(await ProcessUploadWithSeasonId(repaymentUpload));
            }
            else
            {
                repayments.AddRange(await ProcessUploadWithoutSeasonId(repaymentUpload));
            }

            _repaymentRepository.Add(repayments.GetRange(1, repayments.Count - 1));
            _repaymentUploadRepository.Add(repaymentUpload);
            await _appDbContext.SaveChangesAsync();

            return(repayments);
        }
コード例 #7
0
        public async Task UploadWithoutSeasonIdWhenNoOutstandingDebt()
        {
            var mockRepaymentUpload = new RepaymentUpload
            {
                CustomerId = 4,
                Amount     = 500,
                Date       = DateTime.Now
            };

            var repayments = await _repaymentService.ProcessUpload(mockRepaymentUpload);

            Assert.NotNull(repayments);
            Assert.Single(repayments);


            Assert.Equal(500, repayments[0].Amount);
            Assert.Null(repayments[0].ParentId);
            Assert.Equal(2, repayments[0].SeasonId);

            var summaryAfterUpload = await _dbContext.CustomerSummaries
                                     .FirstOrDefaultAsync(cs => cs.CustomerId == 4 && cs.SeasonId == 2);

            Assert.Equal(800, summaryAfterUpload.TotalRepaid);
        }
コード例 #8
0
        public async Task UploadWithoutSeasonIdAmountGreaterThanDebtExpectedOverflow()
        {
            var mockRepaymentUpload = new RepaymentUpload
            {
                CustomerId = 3,
                Amount     = 500,
                Date       = DateTime.Now
            };

            var repayments = await _repaymentService.ProcessUpload(mockRepaymentUpload);

            Assert.NotNull(repayments);
            Assert.Single(repayments);


            Assert.Equal(500, repayments[0].Amount);
            Assert.Null(repayments[0].ParentId);
            Assert.Equal(1, repayments[0].SeasonId);

            var summaryAfterUpload = await _dbContext.CustomerSummaries
                                     .FirstOrDefaultAsync(cs => cs.CustomerId == 3 && cs.SeasonId == 1);

            Assert.Equal(1500, summaryAfterUpload.TotalRepaid);
        }
コード例 #9
0
        public async Task UploadWithoutSeasonIdAmountGreaterThanDebt()
        {
            var mockRepaymentUpload = new RepaymentUpload
            {
                CustomerId = 1,
                Amount     = 2000,
                Date       = DateTime.Now
            };

            var repayments = await _repaymentService.ProcessUpload(mockRepaymentUpload);

            Assert.NotNull(repayments);
            Assert.Equal(3, repayments.Count);


            Assert.Equal(2000, repayments[0].Amount);
            Assert.Null(repayments[0].ParentId);
            Assert.Equal(1, repayments[0].SeasonId);

            Assert.Equal(-1200, repayments[1].Amount);
            Assert.Equal(repayments[0].Id, repayments[1].ParentId);
            Assert.Equal(1, repayments[1].SeasonId);

            Assert.Equal(1200, repayments[2].Amount);
            Assert.Equal(repayments[0].Id, repayments[2].ParentId);
            Assert.Equal(2, repayments[2].SeasonId);

            var summaryAfterUploads = await _dbContext.CustomerSummaries
                                      .Where(cs => cs.CustomerId == 1)
                                      .OrderBy(cs => cs.Season.StartDate)
                                      .ToListAsync();

            Assert.Equal(2, summaryAfterUploads.Count);
            Assert.Equal(1000, summaryAfterUploads[0].TotalRepaid);
            Assert.Equal(1900, summaryAfterUploads[1].TotalRepaid);
        }
コード例 #10
0
        private List <Repayment> ProcessRepayment(RepaymentUpload upload)
        {
            decimal balance      = upload.Amount;
            int     lastParentId = 0;
            var     repayments   = new List <Repayment>();

            // The Overide - Handle specified season
            var a = upload.SeasonId.Equals(0);

            if (!upload.SeasonId.Equals(null) && !upload.SeasonId.Equals(0))
            {
                //create repayment record
                var payment = CreateRepaymentRecord(upload, upload.Amount, 0);
                repayments.Add(payment);
                //update customer summary
                UpdateCustomerSummary(upload.CustomerId, (int)upload.SeasonId, upload.Amount);
            }
            else
            {
                //get customer summary with outstanding repayments
                var customerSummaries = _customerSummaryRepository.GetByCustomerId(upload.CustomerId).Where(s => s.TotalCredit > s.TotalRepaid)
                                        .OrderBy(o => o.SeasonId).ToList();

                //Cascade the payments while balance > 0
                foreach (var customerSummary in customerSummaries)
                {
                    //Check amount owed
                    var amountOwed = CheckAmountOwed(customerSummary);

                    //create repayment record
                    upload.SeasonId = customerSummary.SeasonId;
                    var payment = CreateRepaymentRecord(upload, balance, lastParentId);
                    repayments.Add(payment);
                    lastParentId = payment.Id;

                    //deduction record if exists
                    if (balance > amountOwed)
                    {
                        // deduction record
                        decimal deduction       = amountOwed - balance;
                        var     deductionRecord = CreateRepaymentRecord(upload, deduction, lastParentId);
                        lastParentId = deductionRecord.Id;

                        //update customer summary
                        UpdateCustomerSummary(upload.CustomerId, customerSummary.SeasonId, amountOwed);
                    }
                    else
                    {
                        //update customer summary
                        UpdateCustomerSummary(upload.CustomerId, customerSummary.SeasonId, balance);
                    }
                    balance -= amountOwed;
                    if (balance < 0)
                    {
                        break;
                    }
                }
                // The overpaid
                if (balance > 0)
                {
                    //get latest season
                    var seasons = _seasonRepository.GetAll().OrderBy(o => o.Id).ToList();
                    var season  = seasons.OrderByDescending(i => i.Id).FirstOrDefault();
                    //update customer summary
                    UpdateCustomerSummary(upload.CustomerId, season.Id, balance);
                }
            }

            return(repayments);
        }
コード例 #11
0
 public IEnumerable <Repayment> submitPayment(RepaymentUpload repaymentUpload)
 {
     return(ProcessRepayment(repaymentUpload));
 }