示例#1
0
        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();
        }