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); }
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); }
public static Repayment ToRepayment(this RepaymentUpload upload) { return(new Repayment { Amount = upload.Amount, CustomerId = upload.CustomerId, SeasonId = upload.SeasonId, Date = upload.Date }); }
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); }
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); }
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); }
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); }
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); }
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); }
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); }
public IEnumerable <Repayment> submitPayment(RepaymentUpload repaymentUpload) { return(ProcessRepayment(repaymentUpload)); }