public async Task <IActionResult> PostRepayDocument([FromBody] FinanceLoanRepayDocumentCreateContext createContext) { if (!ModelState.IsValid) { HIHAPIUtility.HandleModalStateError(ModelState); } // Checks // Check 0: Input data check if (createContext.HomeID <= 0 || createContext.LoanTemplateDocumentID <= 0 || createContext.DocumentInfo == null || createContext.DocumentInfo.DocType != FinanceDocumentType.DocType_Repay) { throw new BadRequestException("Invalid inputted data"); } // Check 1: User String usrName = String.Empty; try { usrName = HIHAPIUtility.GetUserID(this); if (String.IsNullOrEmpty(usrName)) { throw new UnauthorizedAccessException(); } } catch { throw new UnauthorizedAccessException(); } // Check 1: Home ID var hms = _context.HomeMembers.Where(p => p.HomeID == createContext.HomeID && p.User == usrName).Count(); if (hms <= 0) { throw new UnauthorizedAccessException(); } // Check 2: Template doc var docLoanTmp = _context.FinanceTmpLoanDocument .Where(p => p.DocumentID == createContext.LoanTemplateDocumentID) .FirstOrDefault(); if (docLoanTmp == null || docLoanTmp.ReferenceDocumentID > 0) { throw new BadRequestException("Invalid loan template ID or doc has been posted"); } if (!docLoanTmp.ControlCenterID.HasValue && !docLoanTmp.OrderID.HasValue) { throw new BadRequestException("Tmp doc lack of control center or order"); } if (docLoanTmp.TransactionAmount == 0) { throw new BadRequestException("Tmp doc lack of amount"); } // Check 3: Account var loanAccountHeader = _context.FinanceAccount.Where(p => p.ID == docLoanTmp.AccountID).FirstOrDefault(); if (loanAccountHeader == null || loanAccountHeader.Status != (Byte)FinanceAccountStatus.Normal || !(loanAccountHeader.CategoryID == FinanceAccountCategory.AccountCategory_BorrowFrom || loanAccountHeader.CategoryID == FinanceAccountCategory.AccountCategory_LendTo) ) { throw new BadRequestException("Account not exist or account has wrong status or account has wrong category"); } var loanAccountExtra = _context.FinanceAccountExtraLoan.Where(p => p.AccountID == loanAccountHeader.ID).FirstOrDefault(); if (loanAccountExtra == null) { throw new BadRequestException("Account is not a valid loan account"); } // Check 4: Check amounts int ninvaliditems = 0; Decimal acntBalance = 0M; // Balance var acntBalInfo = _context.FinanceReporAccountGroupAndExpenseView.Where(p => p.AccountID == loanAccountHeader.ID).ToList(); if (acntBalInfo.Count > 0) { acntBalance = 0; acntBalInfo.ForEach(action => { if (action.IsExpense) { acntBalance += action.Balance; } else { acntBalance += action.Balance; } }); } else { throw new BadRequestException("No balance"); } // Only four tran. types are allowed if (loanAccountHeader.CategoryID == FinanceAccountCategory.AccountCategory_BorrowFrom) { ninvaliditems = createContext.DocumentInfo.Items.Where(item => item.TranType != FinanceTransactionType.TranType_InterestOut && item.TranType != FinanceTransactionType.TranType_RepaymentOut && item.TranType != FinanceTransactionType.TranType_RepaymentIn) .Count(); } else if (loanAccountHeader.CategoryID == FinanceAccountCategory.AccountCategory_LendTo) { ninvaliditems = createContext.DocumentInfo.Items.Where(item => item.TranType != FinanceTransactionType.TranType_InterestIn && item.TranType != FinanceTransactionType.TranType_RepaymentOut && item.TranType != FinanceTransactionType.TranType_RepaymentIn) .Count(); } if (ninvaliditems > 0) { throw new BadRequestException("Items with invalid tran type"); } // Check the amount decimal totalOut = createContext.DocumentInfo.Items .Where(item => item.TranType == FinanceTransactionType.TranType_RepaymentOut) .Sum(item2 => item2.TranAmount); decimal totalIn = createContext.DocumentInfo.Items .Where(item => item.TranType == FinanceTransactionType.TranType_RepaymentIn) .Sum(item2 => item2.TranAmount); //decimal totalintOut = repaydoc.Items.Where(item => (item.TranType == FinanceTranTypeViewModel.TranType_InterestOut)).Sum(item2 => item2.TranAmount); // New account balance if (loanAccountHeader.CategoryID == FinanceAccountCategory.AccountCategory_LendTo) { acntBalance -= totalOut; } else if (loanAccountHeader.CategoryID == FinanceAccountCategory.AccountCategory_BorrowFrom) { acntBalance += totalIn; } if (totalOut != totalIn) { throw new BadRequestException("Amount is not equal!"); } // The post here is: // 1. Post a repayment document with the content from this template doc // 2. Update the template doc with REFDOCID // 3. If the account balance is zero, close the account; // Database update var errorString = ""; var errorOccur = false; var origdocid = 0; FinanceDocument findoc = null; using (var transaction = _context.Database.BeginTransaction()) { try { // 1. Create the document createContext.DocumentInfo.Createdby = usrName; createContext.DocumentInfo.CreatedAt = DateTime.Now; var docEntity = _context.FinanceDocument.Add(createContext.DocumentInfo); _context.SaveChanges(); origdocid = docEntity.Entity.ID; // 2. Update the tmp doc docLoanTmp.ReferenceDocumentID = origdocid; docLoanTmp.UpdatedAt = DateTime.Now; docLoanTmp.Updatedby = usrName; _context.FinanceTmpLoanDocument.Update(docLoanTmp); _context.SaveChanges(); // 3. In case balance is zero, update the account status if (Decimal.Compare(acntBalance, 0) == 0) { loanAccountHeader.Status = (Byte)FinanceAccountStatus.Closed; loanAccountHeader.Updatedby = usrName; loanAccountHeader.UpdatedAt = DateTime.Now; _context.FinanceAccount.Update(loanAccountHeader); _context.SaveChanges(); } findoc = docEntity.Entity; await transaction.CommitAsync(); } catch (Exception exp) { errorOccur = true; errorString = exp.Message; transaction.Rollback(); } } if (errorOccur) { throw new DBOperationException(errorString); } return(Created(findoc)); }
public async Task TestCase1_InterestFree(int hid, string currency, string user, short doctype) { var context = this.fixture.GetCurrentDataContext(); // 0. Prepare the context for current home if (hid == DataSetupUtility.Home1ID) { fixture.InitHome1TestData(context); } else if (hid == DataSetupUtility.Home2ID) { fixture.InitHome2TestData(context); } else if (hid == DataSetupUtility.Home3ID) { fixture.InitHome3TestData(context); } else if (hid == DataSetupUtility.Home4ID) { fixture.InitHome4TestData(context); } else if (hid == DataSetupUtility.Home5ID) { fixture.InitHome5TestData(context); } var account = context.FinanceAccount.Where(p => p.HomeID == hid && p.Status != (Byte)FinanceAccountStatus.Closed).FirstOrDefault(); var cc = context.FinanceControlCenter.Where(p => p.HomeID == hid).FirstOrDefault(); // 1. Create first Loan docs. var control = new FinanceDocumentsController(context); var userclaim = DataSetupUtility.GetClaimForUser(user); var httpctx = UnitTestUtility.GetDefaultHttpContext(provider, userclaim); control.ControllerContext = new ControllerContext() { HttpContext = httpctx }; // 1a. Prepare data var dpcontext = new FinanceLoanDocumentCreateContext(); dpcontext.DocumentInfo = new FinanceDocument() { HomeID = hid, DocType = doctype, TranCurr = currency, Desp = "Test 1" }; var item = new FinanceDocumentItem() { DocumentHeader = dpcontext.DocumentInfo, ItemID = 1, Desp = "Item 1.1", TranType = doctype == FinanceDocumentType.DocType_BorrowFrom ? FinanceTransactionType.TranType_BorrowFrom : FinanceTransactionType.TranType_LendTo, TranAmount = 1200, AccountID = account.ID, ControlCenterID = cc.ID, }; dpcontext.DocumentInfo.Items.Add(item); dpcontext.AccountInfo = new FinanceAccount() { HomeID = hid, Name = "Account_8" + ".1", CategoryID = doctype == FinanceDocumentType.DocType_BorrowFrom ? FinanceAccountCategory.AccountCategory_BorrowFrom : FinanceAccountCategory.AccountCategory_LendTo, Owner = user, Status = (Byte)FinanceAccountStatus.Normal, }; var startdate = new DateTime(2020, 1, 10); var enddate = new DateTime(2021, 1, 10); dpcontext.AccountInfo.ExtraLoan = new FinanceAccountExtraLoan() { StartDate = startdate, EndDate = enddate, TotalMonths = 12, RepaymentMethod = LoanRepaymentMethod.EqualPrincipal, InterestFree = true, }; var rsts = CommonUtility.WorkoutRepeatedDatesWithAmountAndInterest(new RepeatDatesWithAmountAndInterestCalInput { RepaymentMethod = dpcontext.AccountInfo.ExtraLoan.RepaymentMethod.Value, InterestFreeLoan = dpcontext.AccountInfo.ExtraLoan.InterestFree.Value, StartDate = dpcontext.AccountInfo.ExtraLoan.StartDate, TotalAmount = 1200, EndDate = dpcontext.AccountInfo.ExtraLoan.EndDate, TotalMonths = dpcontext.AccountInfo.ExtraLoan.TotalMonths.Value, FirstRepayDate = new DateTime(2020, 2, 15) }); var tmpdocid = 1; foreach (var rst in rsts) { var tmpdoc = new FinanceTmpLoanDocument { DocumentID = tmpdocid++, TransactionAmount = rst.TranAmount, InterestAmount = rst.InterestAmount, TransactionDate = rst.TranDate, HomeID = hid, ControlCenterID = item.ControlCenterID, OrderID = item.OrderID, Description = item.Desp, }; dpcontext.AccountInfo.ExtraLoan.LoanTmpDocs.Add(tmpdoc); } var resp = await control.PostLoanDocument(dpcontext); var doc = Assert.IsType <CreatedODataResult <FinanceDocument> >(resp).Entity; documentsCreated.Add(doc.ID); var loanacntid = -1; foreach (var docitem in doc.Items) { if (docitem.AccountID != account.ID) { loanacntid = docitem.AccountID; accountsCreated.Add(loanacntid); } } Assert.True(doc.Items.Count == 2); // 2. Switch to second controller var tmpcontrol = new FinanceTmpLoanDocumentsController(context); tmpcontrol.ControllerContext = new ControllerContext() { HttpContext = httpctx }; var tmpdocs = tmpcontrol.Get(); Assert.NotEmpty(tmpdocs); Assert.Equal(rsts.Count, tmpdocs.Count()); var dpdocs = tmpdocs.Cast <FinanceTmpLoanDocument>(); // 3. Create repay document foreach (var dpdoc in dpdocs) { var contxt = new FinanceLoanRepayDocumentCreateContext(); contxt.HomeID = hid; contxt.LoanTemplateDocumentID = dpdoc.DocumentID; contxt.DocumentInfo = new FinanceDocument { DocType = FinanceDocumentType.DocType_Repay, HomeID = hid, Desp = dpdoc.Description, TranCurr = currency, }; contxt.DocumentInfo.Items.Add(new FinanceDocumentItem { ItemID = 1, AccountID = dpdoc.AccountID, TranAmount = dpdoc.TransactionAmount, ControlCenterID = dpdoc.ControlCenterID, OrderID = dpdoc.OrderID, TranType = doctype == FinanceDocumentType.DocType_BorrowFrom ? FinanceTransactionType.TranType_RepaymentIn : FinanceTransactionType.TranType_RepaymentOut, }); contxt.DocumentInfo.Items.Add(new FinanceDocumentItem { ItemID = 2, AccountID = account.ID, TranAmount = dpdoc.TransactionAmount, ControlCenterID = dpdoc.ControlCenterID, OrderID = dpdoc.OrderID, TranType = doctype == FinanceDocumentType.DocType_BorrowFrom ? FinanceTransactionType.TranType_RepaymentOut : FinanceTransactionType.TranType_RepaymentIn, }); var repaydocresp = await tmpcontrol.PostRepayDocument(contxt); var repaydoc = Assert.IsType <CreatedODataResult <FinanceDocument> >(repaydocresp); Assert.True(repaydoc.Entity.ID > 0); documentsCreated.Add(repaydoc.Entity.ID); // Check in the database var dpdocInDB = context.FinanceTmpLoanDocument.Where(p => p.DocumentID == dpdoc.DocumentID).SingleOrDefault(); Assert.NotNull(dpdocInDB); Assert.NotNull(dpdocInDB.ReferenceDocumentID); } // 4. Now the account shall be closed automatically var account2 = context.FinanceAccount.Where(p => p.HomeID == hid && p.ID == loanacntid).FirstOrDefault(); Assert.True(account2.Status == (Byte)FinanceAccountStatus.Closed); // Last, clear all created objects CleanupCreatedEntries(); await context.DisposeAsync(); }