/// <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); } }
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)); } }
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)); } }