<repo_name>brandedux/atm-sim<file_sep>/The-ATM-Machine/Migrations/20180127122839_CreateDB.cs
﻿using Microsoft.EntityFrameworkCore.Migrations;
using System;
using System.Collections.Generic;

namespace TheATMMachine.Migrations
{
    public partial class CreateDB : Migration
    {
        protected override void Up(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.CreateTable(
                name: "Accounts",
                columns: table => new
                {
                    AccountId = table.Column<int>(nullable: false)
                        .Annotation("Sqlite:Autoincrement", true),
                    BankNumber = table.Column<int>(nullable: false),
                    Money = table.Column<int>(nullable: false),
                    Pincode = table.Column<int>(maxLength: 4, nullable: false)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Accounts", x => x.AccountId);
                });

            migrationBuilder.CreateTable(
                name: "Users",
                columns: table => new
                {
                    UserId = table.Column<int>(nullable: false)
                        .Annotation("Sqlite:Autoincrement", true),
                    AccountId = table.Column<int>(nullable: false),
                    Name = table.Column<string>(nullable: true),
                    Surname = table.Column<string>(nullable: true)
                },
                constraints: table =>
                {
                    table.PrimaryKey("PK_Users", x => x.UserId);
                    table.ForeignKey(
                        name: "FK_Users_Accounts_AccountId",
                        column: x => x.AccountId,
                        principalTable: "Accounts",
                        principalColumn: "AccountId",
                        onDelete: ReferentialAction.Cascade);
                });

            migrationBuilder.CreateIndex(
                name: "IX_Users_AccountId",
                table: "Users",
                column: "AccountId",
                unique: true);
        }

        protected override void Down(MigrationBuilder migrationBuilder)
        {
            migrationBuilder.DropTable(
                name: "Users");

            migrationBuilder.DropTable(
                name: "Accounts");
        }
    }
}
<file_sep>/The-ATM-Machine/Machine/Interface.cs
﻿using System;
using The_ATM_Machine.Queries;
using System.Threading;

namespace The_ATM_Machine {
    /// <summary>
    /// The ATM
    /// </summary>
    public class Machine {
        QueryAccess queryAccess = new QueryAccess();

        /// <summary>
        /// Menu when the user is not logged in, shows the login, create and exit options
        /// </summary>
        public void StartUpMenuOptions() {     
            while (true) {
                Thread.Sleep(2000);
                Console.Clear();
                Console.WriteLine("Welcome to the ATM \n Select one of the following options:");
                Console.WriteLine("Login: 1 \n Create a bank account: 2 \n Exit: 3");
                var answer = Console.ReadLine();
                switch (answer.ToLower()) {
                    case ("1"):
                        this.Login();
                        return;
                    case ("2"):
                        this.CreateBankAccount();
                        break;
                    case ("3"):
                        Environment.Exit(0);
                        return;
                    default:
                        Console.WriteLine("Error: choose a valid menu option");
                        break;
                }
            }
        }
        /// <summary>
        /// Menu when the user is logged in, shows the main options
        /// </summary>
        public void MainMenuOptions() {      
            while (true) {
                Thread.Sleep(2000);
                Console.Clear();
                Console.WriteLine("Main Menu \n Welcome {0}", LoggedInUser.Name);
                Console.WriteLine("Draw money: 1 \n Deposit: 2 \n Transfer money: 3 \n Change Pincode: 4 \n  Current balance: 5 \n Exit: 6");
                var answer = Console.ReadLine();
                switch (answer.ToLower()) {
                    case ("1"):
                        this.Withdraw();
                        break;
                    case ("2"):
                        this.Deposit();
                        break;
                    case ("3"):
                        this.Transfer();
                        break;
                    case ("4"):
                        this.ChangePincode();
                        break;
                    case ("5"):
                        this.SeeBalance();
                        break;
                    case ("6"):
                        Environment.Exit(0);
                        break;
                    default:
                        Console.WriteLine("Error: choose a valid menu option");
                        break;
                }
            }
        }
        /// <summary>
        /// This menu shows when the user enters invalid data
        /// </summary>
        /// <param name="backPredicate">the the method to call when the user chooses the back option</param>
        /// <param name="retryPredicate">the the method to call when the user chooses the retry option</param>
        private void BackRetryExit(Action backPredicate, Action retryPredicate) {
            Console.WriteLine("Retry: 1 \n Back: 2 \n Exit: 3");
            while (true) {
                var answer = Console.ReadLine();
                switch (answer.ToLower()) {
                    case ("1"):
                        retryPredicate();
                        return;
                    case ("2"):
                        backPredicate();
                        return;
                    case ("3"):
                        Environment.Exit(0);
                        return;
                    default:
                        Console.WriteLine("Error: select a valid menu option");
                        break;
                }
            }
        }
        /// <summary>
        /// The login menu
        /// </summary>
        private void Login() {
            Console.WriteLine("Login");
            Console.WriteLine("Enter your bank account number");
            var givenBanknumber = InputHandling.CheckNumber();
            if (queryAccess.accountTable.CheckIfBankNumberExists(givenBanknumber)) {
                var givenPincode = this.PincodeConfirmation("Enter your pincode");
                if(queryAccess.accountTable.IsPincodeCorrect(givenBanknumber, givenPincode)) {
                    Console.WriteLine("Successfully logged in");
                    var loggedInUser = queryAccess.user.GetUserInformation(givenBanknumber);
                    LoggedInUser.LogInUser(loggedInUser.Item1, loggedInUser.Item2);
                    return;
                    
                }
                Console.WriteLine("Error: The pincode is not correct");
            }
            else {
                Console.WriteLine("Error: the bank account number has not been found");
              
            }
            this.BackRetryExit(() => this.StartUpMenuOptions(), () => this.Login());
        }
        /// <summary>
        /// Create bank acount menu
        /// </summary>
        private void CreateBankAccount() {
            Console.WriteLine("Create Bank Account");
            Console.WriteLine("Type your name");
            var name = Console.ReadLine();
            Console.WriteLine("Type your surname");
            var surname = Console.ReadLine();
            Console.WriteLine("Type the bank account number that you would like to have");
            var bankNumber = this.CheckIfBankNumberExists(InputHandling.CheckNumber());
            var pincode = PincodeConfirmation("Type the pincode you would like to have");
            queryAccess.accountTable.AddAccount(new Account() { BankNumber = bankNumber, Money = 0, Pincode = pincode });
            queryAccess.user.AddUser(new User() { Name = name, Surname = surname, AccountId = queryAccess.accountTable.GetAccountId(bankNumber) });

            Console.WriteLine("Registered \n you can login now");
        }
        /// <summary>
        /// Used for the create bank account menu
        /// </summary>
        /// <param name="bankNumber">the banknumber that the user entered</param>
        /// <returns></returns>
        private int CheckIfBankNumberExists(int bankNumber) {
            while (true) {
                var doesBankAccountExist = queryAccess.accountTable.CheckIfBankNumberExists(bankNumber);
                    if (doesBankAccountExist) {
                        Console.WriteLine("Bank number already exists, try again:");
                        bankNumber = InputHandling.CheckNumber();
                    }
                    else {
                        return bankNumber;                      
                    }
                }
            }
        /// <summary>
        /// Checks if two inserted pincodes match and are correct
        /// </summary>
        /// <param name="message">message to display when the pincode confirmation screen is shown</param>
        /// <returns></returns>
        private int PincodeConfirmation(string message) {
            while (true) {
                Console.WriteLine(message);
                var firstPincode = InputHandling.CheckNumber();
                Console.WriteLine("Type your pincode again");
                var secondPincode = InputHandling.CheckNumber();
                if(firstPincode.ToString().Length != 4) {
                    Console.WriteLine("Error: the pincode needs to be 4 digits, try it again");
                }
                else if (firstPincode.Equals(secondPincode)) {
                    return firstPincode;
                }
                else {
                    Console.WriteLine("Error: the two entered pincodes didn't match, try it again");
                }
            }
        }
        /// <summary>
        /// The deposit menu
        /// </summary>
        private void Deposit() {
            Console.WriteLine("Deposit \n How much do you like to deposit?");
            var givenAmmount = InputHandling.CheckNumber();
            queryAccess.accountTable.ChangeBalance((a) => a.AccountId == LoggedInUser.AccountId, givenAmmount, (a) => a.Money += givenAmmount);
            Console.WriteLine("The money has been deposit");
            
        }
        /// <summary>
        /// The change pincode menu
        /// </summary>
        private void ChangePincode() {
            Console.WriteLine("Change Pincode");
            var choosenPincode = this.PincodeConfirmation("What would you like to change your pincode to?");
            queryAccess.accountTable.ChangePincode(LoggedInUser.AccountId, choosenPincode);
            Console.WriteLine("Pincode has been changed");
        }
        /// <summary>
        /// The Withdraw menu
        /// </summary>
        private void Withdraw() {
            Console.WriteLine("Withdraw \n How much do you like to draw?");
            var givenAmmount = InputHandling.CheckNumber();
            if(this.IsGivenAmmountHigherThanBalance(givenAmmount)) {
                queryAccess.accountTable.ChangeBalance((a) => a.AccountId == LoggedInUser.AccountId, givenAmmount, (a) => a.Money -= givenAmmount);
                Console.WriteLine("Money has been Withdrawn");
            }
            else {
                Console.WriteLine("Error: given ammount should be higher than the current balance");
                this.BackRetryExit(() => this.MainMenuOptions(), () => this.Withdraw());
            }
        }
        /// <summary>
        /// The transfer menu
        /// </summary>
        private void Transfer() {
            Console.WriteLine("Transfer \n To which account to transfer money?");
            var givenBankNumber = InputHandling.CheckNumber();
            if (this.queryAccess.accountTable.CheckIfBankNumberExists(givenBankNumber)) {
                Console.WriteLine("How much to deposit?");
                var givenAmmount = InputHandling.CheckNumber();
                if (this.IsGivenAmmountHigherThanBalance(givenAmmount)) {
                    this.queryAccess.accountTable.ChangeBalance((a) => a.BankNumber == givenBankNumber, givenAmmount, (a) => a.Money += givenAmmount);
                    this.queryAccess.accountTable.ChangeBalance((a) => a.AccountId == LoggedInUser.AccountId, givenAmmount, (a) => a.Money -= givenAmmount);
                    Console.WriteLine("Money has been transfered");
                    return;
                }
                else {
                    Console.WriteLine("Error: given ammount is lower than balance, current balance: {0}", LoggedInUser.Balance);
                    this.BackRetryExit(() => this.MainMenuOptions(), () => this.Transfer());
                    return;
                }
            }
            Console.WriteLine("Error: Bank number does not exist");
            this.BackRetryExit(() => this.MainMenuOptions(), () => this.Transfer());

        }
        /// <summary>
        /// Checks if the given ammount is higher than user's current balance
        /// </summary>
        /// <param name="ammount">ammount of money that has been typed by the user</param>
        /// <returns></returns>
        private bool IsGivenAmmountHigherThanBalance(int ammount) {
            if(ammount <= LoggedInUser.Balance && ammount > 0) {
                return true;
            }
            return false;
        }
        /// <summary>
        /// The menu for check balance
        /// </summary>
        private void SeeBalance() {
            Console.WriteLine("The current balance is: {0}", LoggedInUser.Balance);
        }
    }
}
<file_sep>/The-ATM-Machine/LoggedInUser/LoggedInUser.cs
﻿using The_ATM_Machine.Queries;

namespace The_ATM_Machine {
    /// <summary>
    /// Information about the logged in user
    /// </summary>
    public class LoggedInUser {
        private static int accountId; //id of the account Table
        private static string name;
        private static bool isUserLoggedIn = false;

        public static int AccountId { get => accountId; set => accountId = value; }
        public static string Name { get => name; set => name = value; }
        public static int Balance { get => new QueryAccess().accountTable.GetAccountInformation(accountId, (a) => a.Money); }
        public static int Pincode { get => new QueryAccess().accountTable.GetAccountInformation(accountId, (a) => a.Pincode);}

        private LoggedInUser() {
        }

        public static void LogInUser(string name, int accountId) {
            if (!isUserLoggedIn) {
                LoggedInUser.name = name;
                LoggedInUser.accountId = accountId;
                LoggedInUser.isUserLoggedIn = true;
            }
        }
    }
}
<file_sep>/The-ATM-Machine/Queries/AccountQueries.cs
﻿using System;
using System.Linq;

namespace The_ATM_Machine.Queries {
    /// <summary>
    /// Handles queries related to the account table
    /// </summary>
    public class AccountQueries {
        TheDatabase database = new TheDatabase();

        public bool CheckIfBankNumberExists(int bankNumber) {
            var res = database.database.Accounts.Where(a => a.BankNumber == bankNumber).FirstOrDefault();
            if(res == null) {
                return false;
            }
            return true;
        }
        public void AddAccount(Account account) {
            database.database.Accounts.Add(account);
            database.database.SaveChanges();
        }
        public int GetAccountId(int bankNumber) {
            var res = database.database.Accounts.Where(a => a.BankNumber == bankNumber).FirstOrDefault();
            return res.AccountId;
        }
        public bool IsPincodeCorrect(int bankNumber, int pincode) {
            var res = database.database.Accounts.Where(a => a.BankNumber == bankNumber).FirstOrDefault();
            if(res.Pincode == pincode) {
                return true;
            }
            return false;
        }
        public void ChangeBalance(Func<Account,bool> wherePredicate, int ammount, Action<Account> predicate) {
            var account = database.database.Accounts.Where(wherePredicate).FirstOrDefault();
            predicate(account);
            database.database.SaveChanges();
        }
        public void ChangePincode(int accountId, int pincode) {
            database.database.Accounts.Where(a => a.AccountId == accountId).FirstOrDefault().Pincode = pincode;
            database.database.SaveChanges();
        }
        public int GetAccountInformation(int accountId, Func<Account, dynamic> predicate) {
            var res = database.database.Accounts.Where((a) => a.AccountId == accountId).FirstOrDefault();
            return predicate(res);
        }
    }
}
<file_sep>/The-ATM-Machine/Queries/QueryAccess.cs
﻿namespace The_ATM_Machine.Queries {
    /// <summary>
    /// For access to both tables (the whole database)
    /// </summary>
    public class QueryAccess {
        public AccountQueries accountTable = new AccountQueries();
        public UserQueries user = new UserQueries();
    }
}
<file_sep>/The-ATM-Machine/Queries/Database.cs
﻿namespace The_ATM_Machine {
    public class TheDatabase {
        public DatabaseContext database;
        public TheDatabase() {
            database = new DatabaseContext();
        }
    }
}<file_sep>/The-ATM-Machine/Queries/Models.cs
﻿using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;

namespace The_ATM_Machine {
    public class DatabaseContext : DbContext {
        public DbSet<User> Users { get; set; }
        public DbSet<Account> Accounts { get; set; }
        protected override void OnConfiguring(DbContextOptionsBuilder op) {
            op.UseSqlite("Data Source=atmDB.db");
        }
    }
    public class User {
        public int UserId { get; set; }
        public string Name { get; set; }
        public string Surname { get; set; }
        public int AccountId { get; set; }
        public Account Account { get; set; }

    }
    public class Account {      
        public int AccountId { get; set; }
        public int BankNumber { get; set; }
        [MaxLength(4)]
        public int Pincode { get; set; }
        public int Money { get; set; }
        public User User { get; set; }
    }
}<file_sep>/README.md
# Personal project 
ATM (Automated teller machine)

# Features
- Login system
- Withdraw money and deposit money
- Check current balance
- Change pincode
- Transfer money to another bank account

![Screenshot](https://github.com/StefanPesic/ATM/blob/master/ATM.PNG)

# How to start
Run the client file.

# Type
- Console application

# Tools
- Entity Framework
- LINQ (Enumerable)
- SQLite database
<file_sep>/The-ATM-Machine/Queries/UserQueries.cs
﻿using System;
using System.Linq;

namespace The_ATM_Machine.Queries {
    /// <summary>
    /// Queries related to the user table
    /// </summary>
    public class UserQueries {
        TheDatabase database = new TheDatabase();

        public void AddUser(User user) {
            this.database.database.Users.Add(user);
            this.database.database.SaveChanges();
        }
        public Tuple<string,int,int> GetUserInformation(int bankNumber) {
            var res = database.database.Users.Join(database.database.Accounts, (u) => u.AccountId, (a) => a.AccountId, (ures, aRes) =>
            new Tuple<string,int,int>(ures.Name, aRes.AccountId, aRes.BankNumber))
            .Where((tables) => tables.Item3 == bankNumber).FirstOrDefault();
            return res;
        }
    }
}
<file_sep>/The-ATM-Machine/Machine/InputHandling.cs
﻿using System;

namespace The_ATM_Machine {
    /// <summary>
    /// Verifies if the number that has been typed by the user, is correct
    /// </summary>
    public class InputHandling { 
        public static int CheckNumber() {
            var givenNumber = 0;
            while (true) {
                var answer = Int32.TryParse(Console.ReadLine(), out givenNumber);
                if (answer && givenNumber > 0){
                    return givenNumber;
                }
                Console.WriteLine("Error: enter a valid number above the 0");
            }
        }
    }
}
<file_sep>/The-ATM-Machine/Client.cs
﻿namespace The_ATM_Machine {
    /// <summary>
    /// Start of the program
    /// </summary>
    public class Client {
        static void Main(string[] args) {
            var atm = new Machine();
            atm.StartUpMenuOptions(); //when the user is not logged in
            atm.MainMenuOptions(); //when the user is logged in
        }
    }
}
