/// <summary>
        /// Create a deposit transaction in db
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task <Response> MakeDepositAsync(CreateCashTransactionRequest request, CancellationToken cancellationToken = default)
        {
            var responseModel   = new ApiResponse <CashTransactionResponse>();
            var amountToDeposit = request.Amount;

            var dbContextTransaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);

            try
            {
                var toAccount = await _bankAccountRepo.FindByIBANAsync(request.To);

                if (toAccount == null)
                {
                    responseModel.AddError(ExceptionCreator.CreateNotFoundError(nameof(toAccount)));
                    return(responseModel);
                }

                //Add amount to recipient balance
                toAccount.Balance             += amountToDeposit;
                toAccount.AllowedBalanceToUse += amountToDeposit;

                //Update bank account
                await _bankAccountRepo.UpdateAsync(_dbContext, toAccount);

                //Add transaction to db & save changes
                await _cashTransactionsRepo.AddAsync(_dbContext, CreateCashTransaction(request, 0, toAccount.Balance));

                await dbContextTransaction.CommitAsync(cancellationToken);

                return(responseModel);
            }

            catch (Exception ex)
            {
                await dbContextTransaction.RollbackAsync(cancellationToken);

                responseModel.AddError(ExceptionCreator.CreateInternalServerError(ex.ToString()));

                return(responseModel);
            }
        }
        private CashTransaction CreateCashTransaction(CreateCashTransactionRequest request, decimal senderBalance, decimal recipientBalance)
        {
            const string BANKACCOUNTNO  = "000100000";
            var          isTransferFees = request.Type == CashTransactionType.CommissionFees;

            return(new CashTransaction()
            {
                Type = request.Type,
                From = request.From,
                To = !isTransferFees ? request.To : BANKACCOUNTNO,
                Amount = request.Amount,
                SenderRemainingBalance = senderBalance,

                RecipientRemainingBalance = recipientBalance,
                InitiatedBy = request.InitiatedBy,
                Description = request.Description,
                PaymentType = !isTransferFees ? request.PaymentType : PaymentType.ComissionFees,
                CreatedBy = _httpContextAccessor.HttpContext.User.Identity.Name,
                TransactionDate = request.TransactionDate,
                CreditCardNo = request.CreditCardNo ?? null,
                DebitCardNo = request.DebitCardNo ?? null
            });
        }
        /// <summary>
        /// Create an EFT Transfer transaction in db (from/to acoounts in different banks)
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task <Response> MakeEFTTransferAsync(CreateCashTransactionRequest request, CancellationToken cancellationToken = default)
        {
            var responseModel    = new ApiResponse <CashTransactionResponse>();
            var amountToTransfer = request.Amount;

            var dbContextTransaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);

            try
            {
                var senderAccount = await _bankAccountRepo.FindByIBANAsync(request.From);

                var recipientAccount = await _bankAccountRepo.FindByIBANAsync(request.To);

                if (senderAccount == null)
                {
                    responseModel.AddError(ExceptionCreator.CreateNotFoundError(nameof(senderAccount), "sender account not found"));
                    return(responseModel);
                }

                if (recipientAccount == null)
                {
                    responseModel.AddError(ExceptionCreator.CreateNotFoundError(nameof(recipientAccount), "recipient account not found"));
                    return(responseModel);
                }

                if (recipientAccount.Owner.FirstName != request.RecipeintFirstName || recipientAccount.Owner.LastName != request.RecipeintLastName)
                {
                    responseModel.AddError(ExceptionCreator.CreateBadRequestError(nameof(recipientAccount), "recipient name is not valid"));
                    return(responseModel);
                }

                if (amountToTransfer <= senderAccount.AllowedBalanceToUse)
                {
                    const double feesRate = 0.0015;
                    var          fees     = (double)amountToTransfer * feesRate;

                    //Deduct from sender account
                    senderAccount.Balance            -= amountToTransfer;
                    senderAccount.AllowedBalanceToUse = senderAccount.Balance;

                    await _bankAccountRepo.UpdateAsync(_dbContext, senderAccount);

                    //Deposit to recipient account
                    recipientAccount.Balance             += amountToTransfer;
                    recipientAccount.AllowedBalanceToUse += amountToTransfer;

                    await _bankAccountRepo.UpdateAsync(_dbContext, recipientAccount);


                    //Create & Save transaction into db
                    await _cashTransactionsRepo.AddAsync(_dbContext, CreateCashTransaction(request, senderAccount.Balance, recipientAccount.Balance));

                    //Deduct commission fees from sender account
                    senderAccount.Balance            -= (decimal)fees;
                    senderAccount.AllowedBalanceToUse = senderAccount.Balance;

                    //Update entity & Save it to db
                    await _bankAccountRepo.UpdateAsync(_dbContext, senderAccount);

                    //Modify request for commission fees transaction
                    request.Type   = CashTransactionType.CommissionFees;
                    request.Amount = (decimal)fees;

                    //Create & Save commission fees into db
                    await _cashTransactionsRepo.AddAsync(_dbContext, CreateCashTransaction(request, senderAccount.Balance, 0));

                    await dbContextTransaction.CommitAsync(cancellationToken);

                    return(responseModel);
                }
                else
                {
                    responseModel.AddError(ExceptionCreator.CreateBadRequestError("transfer", "not enough balance to complete transfer"));
                    return(responseModel);
                }
            }
            catch (Exception ex)
            {
                await dbContextTransaction.RollbackAsync(cancellationToken);

                responseModel.AddError(ExceptionCreator.CreateInternalServerError(ex.ToString()));

                return(responseModel);
            }
        }
        /// <summary>
        /// Create a Transfer transaction in db (between acoounts in the same bank)
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task <Response> MakeTransferAsync(CreateCashTransactionRequest request, CancellationToken cancellationToken = default)
        {
            var responseModel    = new ApiResponse <CashTransactionResponse>();
            var amountToTransfer = request.Amount;

            var dbContextTransaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);

            try
            {
                var senderAccount = await _bankAccountRepo.FindByIBANAsync(request.From);

                var recipientAccount = await _bankAccountRepo.FindByIBANAsync(request.To);

                if (senderAccount == null)
                {
                    responseModel.AddError(ExceptionCreator.CreateNotFoundError(nameof(senderAccount)));
                    return(responseModel);
                }

                if (recipientAccount == null)
                {
                    responseModel.AddError(ExceptionCreator.CreateNotFoundError(nameof(recipientAccount)));
                    return(responseModel);
                }

                if (amountToTransfer <= senderAccount.AllowedBalanceToUse)
                {
                    //Deduct from sender account
                    senderAccount.Balance             -= amountToTransfer;
                    senderAccount.AllowedBalanceToUse -= amountToTransfer;

                    //Update sender bank account
                    await _bankAccountRepo.UpdateAsync(_dbContext, senderAccount);

                    //Deposit to recipient account
                    recipientAccount.Balance         += amountToTransfer;
                    senderAccount.AllowedBalanceToUse = recipientAccount.Balance;

                    //Update recipient bank account
                    await _bankAccountRepo.UpdateAsync(_dbContext, recipientAccount);

                    //Create & Save transaction into db
                    await _cashTransactionsRepo.AddAsync(_dbContext, CreateCashTransaction(request, senderAccount.Balance, recipientAccount.Balance));

                    await dbContextTransaction.CommitAsync(cancellationToken);

                    return(responseModel);
                }
                else
                {
                    responseModel.AddError(ExceptionCreator.CreateBadRequestError("transfer", "not enough balance to complete transfer"));

                    return(responseModel);
                }
            }
            catch (Exception ex)
            {
                await dbContextTransaction.RollbackAsync(cancellationToken);

                responseModel.AddError(ExceptionCreator.CreateInternalServerError(ex.ToString()));

                return(responseModel);
            }
        }
        /// <summary>
        /// Create a withdrawal transaction in db
        /// </summary>
        /// <param name="request"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        public async Task <Response> MakeWithdrawalAsync(CreateCashTransactionRequest request, CancellationToken cancellationToken = default)
        {
            var responseModel    = new ApiResponse <CashTransactionResponse>();
            var amountToWithdraw = request.Amount;

            var dbContextTransaction = await _dbContext.Database.BeginTransactionAsync(cancellationToken);

            try
            {
                var fromAccount = await _bankAccountRepo.FindByIBANAsync(request.From);

                bool isBlocked = true;

                if (fromAccount == null)
                {
                    responseModel.AddError(ExceptionCreator.CreateNotFoundError(nameof(fromAccount)));
                    return(responseModel);
                }

                if (fromAccount.Type == AccountType.Savings)
                {
                    var deposits = await _cashTransactionsRepo.GetDepositsByIBANAsync(fromAccount.IBAN);

                    foreach (var deposit in deposits)
                    {
                        if (DateTime.UtcNow.Subtract(deposit.TransactionDate).TotalDays >= 180)
                        {
                            isBlocked = false;
                        }
                    }

                    if (isBlocked)
                    {
                        responseModel.AddError(ExceptionCreator.CreateUnprocessableEntityError(nameof(fromAccount), "deposit is blocked"));
                        return(responseModel);
                    }
                }

                if (amountToWithdraw <= fromAccount.AllowedBalanceToUse)
                {
                    fromAccount.Balance             -= amountToWithdraw;
                    fromAccount.AllowedBalanceToUse -= amountToWithdraw;

                    await _bankAccountRepo.UpdateAsync(_dbContext, fromAccount);

                    await _cashTransactionsRepo.AddAsync(_dbContext, CreateCashTransaction(request, fromAccount.Balance, 0));

                    await dbContextTransaction.CommitAsync();

                    return(responseModel);
                }
                else
                {
                    responseModel.AddError(ExceptionCreator.CreateBadRequestError(nameof(fromAccount), "balance is not enough to complete withdrawal"));

                    return(responseModel);
                }
            }

            catch (Exception ex)
            {
                await dbContextTransaction.RollbackAsync();

                responseModel.AddError(ExceptionCreator.CreateInternalServerError(ex.ToString()));

                return(responseModel);
            }
        }
Exemplo n.º 6
0
        public async Task <IActionResult> AddCashTransactionWithCreditOrDebitCard([FromBody] CreateCashTransactionRequest request,
                                                                                  CancellationToken cancellationToken = default)
        {
            try
            {
                var apiResponse = new Response();

                if (!string.IsNullOrEmpty(request.CreditCardNo))
                {
                    var creditCard = await _creditCardsService.GetCreditCardByAccountNoAsync(request.CreditCardNo, cancellationToken);

                    if (creditCard.Data == null)
                    {
                        apiResponse.AddError(ExceptionCreator.CreateNotFoundError($"Credit card No: {request.CreditCardNo} not found"));
                        return(NotFound(apiResponse));
                    }

                    if (request.PIN == null)
                    {
                        apiResponse.AddError(ExceptionCreator.CreateBadRequestError("PIN is not found "));
                        return(BadRequest(apiResponse));
                    }

                    if (!await _creditCardsService.ValidateCreditCardPINAsync(request.CreditCardNo, request.PIN))
                    {
                        apiResponse.AddError(ExceptionCreator.CreateBadRequestError($"Invalid PIN for Debit card of no: {request.DebitCardNo}"));
                        return(BadRequest(apiResponse));
                    }
                }

                else if (!string.IsNullOrEmpty(request.DebitCardNo))
                {
                    var debitCard = await _debitCardsService.GetDebitCardByDebitCardNoAsync(request.DebitCardNo, cancellationToken);

                    if (debitCard.Data == null)
                    {
                        apiResponse.AddError(ExceptionCreator.CreateNotFoundError($"Debit card No: {request.DebitCardNo} not found"));
                        return(NotFound(apiResponse));
                    }

                    if (request.PIN == null)
                    {
                        apiResponse.AddError(ExceptionCreator.CreateBadRequestError("PIN is not found "));
                        return(BadRequest(apiResponse));
                    }

                    if (!await _debitCardsService.ValidateDebitCardPINAsync(request.DebitCardNo, request.PIN, cancellationToken))
                    {
                        apiResponse.AddError(ExceptionCreator.CreateBadRequestError($"Invalid PIN for Debit card of no: {request.DebitCardNo}"));
                        return(BadRequest(apiResponse));
                    }
                }

                switch (request.Type)
                {
                case CashTransactionType.Deposit:
                    apiResponse = await _cashTransactionsService.MakeDepositAsync(request, cancellationToken);

                    break;

                case CashTransactionType.Withdrawal:
                    apiResponse = await _cashTransactionsService.MakeWithdrawalAsync(request, cancellationToken);

                    break;

                case CashTransactionType.Transfer:
                    apiResponse = await _cashTransactionsService.MakeTransferAsync(request, cancellationToken);

                    break;

                case CashTransactionType.EFT:
                    apiResponse = await _cashTransactionsService.MakeEFTTransferAsync(request, cancellationToken);

                    break;
                }


                if (apiResponse.Success)
                {
                    return(Ok(apiResponse));
                }

                else if (apiResponse.Errors[0].Code == StatusCodes.Status404NotFound)
                {
                    return(NotFound(apiResponse));
                }

                else if (apiResponse.Errors[0].Code == StatusCodes.Status422UnprocessableEntity)
                {
                    return(UnprocessableEntity(apiResponse));
                }


                return(BadRequest(apiResponse));
            }

            catch (Exception exception)
            {
                return(_actionResultMapper.Map(exception));
            }
        }
Exemplo n.º 7
0
        public async Task <IActionResult> AddCashTransaction([FromBody] CreateCashTransactionRequest request,
                                                             CancellationToken cancellationToken = default)
        {
            try
            {
                var apiResponse = new Response();

                var user = await _userManager.GetUserAsync(User);

                var customer = await _customerService.GetCustomerByIBANAsync(request.From, cancellationToken);

                if (customer == null)
                {
                    apiResponse.AddError(ExceptionCreator.CreateNotFoundError(nameof(customer)));
                    return(NotFound(apiResponse));
                }

                if (user.Id != customer?.Data?.UserId)
                {
                    apiResponse.AddError(ExceptionCreator.CreateBadRequestError(nameof(user), "user is not authorized to complete transaction"));
                    return(BadRequest(apiResponse));
                }

                switch (request.Type)
                {
                case CashTransactionType.Deposit:
                    apiResponse = await _cashTransactionsService.MakeDepositAsync(request, cancellationToken);

                    break;

                case CashTransactionType.Withdrawal:
                    apiResponse = await _cashTransactionsService.MakeWithdrawalAsync(request, cancellationToken);

                    break;

                case CashTransactionType.Transfer:
                    apiResponse = await _cashTransactionsService.MakeTransferAsync(request, cancellationToken);

                    break;

                case CashTransactionType.EFT:
                    apiResponse = await _cashTransactionsService.MakeEFTTransferAsync(request, cancellationToken);

                    break;
                }

                if (apiResponse.Success)
                {
                    return(Ok(apiResponse));
                }

                if (apiResponse.Errors[0].Code == StatusCodes.Status404NotFound)
                {
                    return(NotFound(apiResponse));
                }

                else if (apiResponse.Errors[0].Code == StatusCodes.Status422UnprocessableEntity)
                {
                    return(UnprocessableEntity(apiResponse));
                }


                return(BadRequest(apiResponse));
            }

            catch (Exception exception)
            {
                return(_actionResultMapper.Map(exception));
            }
        }