Budget + Transaction Tracker

#include <iostream>
#include <fstream>

std::string fileName;

struct transaction {std::string description; std::string category; std::string incomeorexpense; double amount; }; 
std::vector<transaction> transactions; // vector of type transaction to store all transactions

void add_transaction (transaction trans) {
    // takes in a transaction and adds it to the vector of all transactions
    transactions.push_back(trans); 
}

void view_transactions (){

    int transactionscount = 0;
    int expensescount = 0;
    int incomecount = 0;
    
    for (transaction t : transactions){
        transactionscount ++;

        if (t.incomeorexpense == "income"){
            incomecount++;
        }
        else if (t.incomeorexpense=="expense") {
            expensescount ++;
        }
    }

    if (transactionscount == 0) {
        std::cout << "\nThere are no transactions to display.\n";
    }
    else {
        std::cout<<"        TRANSACTIONS:       \n      ==============";

        if (expensescount > 0){
            std::cout << "\n      $ spent       \n___________________________";
            for (transaction t : transactions) {
                if (t.incomeorexpense =="expense"){
                    std::cout << "\nDescription:  " << t.description << "\nCategory:  " << t.category <<"\nAmount:   " << t.amount << "\n";
                }
            } 
        }

        if (incomecount > 0) {
            std::cout << "\n      $ earned       \n___________________________";
            for (transaction t : transactions) {
                if (t.incomeorexpense =="income"){
                    std::cout << "\nDescription:  " << t.description << "\nCategory:  " << t.category <<"\nAmount:   " << t.amount <<"\n";
                }
            } 
        }
    }
}

void savetofile (std::string fileName) {
    std::ofstream outFile;
    outFile.open(fileName+".txt"); // creates a file called transactions.txt and saves all transactions in the vector to it
    for (transaction t : transactions) {
        outFile << "\n" << t.description << " " << t.category << " "<< t.incomeorexpense<< " " << t.amount ;
    } 
    outFile.close();
}

void loadfromfile (std::string fileName) {
    std::ifstream inFile; // inFile reads from a file
    inFile.open(fileName+".txt");
    std::string line;
    int lines = 0;
    int count = 0;
    while (std::getline(inFile, line)) {
        lines++; // counts number of lines in text file
    }
    inFile.close();
    inFile.open(fileName+".txt");
    while (std::getline(inFile, line)){
        std::string d;
        std::string c;
        std::string i;
        double a;
        inFile >> d;
        inFile >> c;
        inFile>> i;
        inFile >> a;
        transaction temp = {d,c,i,a}; // adds each line to the struct in it's respective place
        add_transaction(temp);
    } 
    inFile.close();
}

bool sortByCategory (const transaction &a, const transaction &b) {
    // can be put into std::sort as a way to compare 2 categories alphabetically
    return a.category < b.category;
}

void displaycategoryinfo (std::string Category ){
    double total=0; 
    int numoftransactions=0; // for average calculation
    for (transaction t : transactions) {
        if (t.category == Category) {
            // ensures that the category is correct before adding it to calculations
            numoftransactions+=1;
            if (t.incomeorexpense== "income") {
                 total+=t.amount;
            }
           if (t.incomeorexpense=="expense") {
                total-=t.amount;
            }
        }
    }
    std::cout<<"The total spent/earned on " << Category << " is $" << total; 
    std::cout<<"\nThe average money spent/earned per transaction on " << Category << " is " << total/numoftransactions;
}

void displaystatistics (std::vector <transaction> transactions) {

    double totalspent = 0;
    double totalearned = 0;
    int positivetransactions=0;
    int negativetransactions =0; 

    for (transaction t: transactions){

        if (t.incomeorexpense == "income") { 
            // positive value (total spent)
            totalearned += t.amount;
            positivetransactions+=1;
        }
        else if (t.incomeorexpense == "expense") {
            // negative value (total earned)
            totalspent -= t.amount;
            negativetransactions+=1;
        }
    }
    std::cout << "\nTotal spent:  " << (totalspent) << "\nTotal earned:    " << totalearned;
    std::cout<< "\nAverage cost of an expense:   " << totalearned/positivetransactions;
    std::cout<< "\nAverage cost of money gained:   " << totalspent/negativetransactions;
    
}

void viewbudget(std::string budgettype, double goal){

    if (budgettype == "savingsgoal"){
       
        double total = 0;

        for (transaction t : transactions) {

            if (t.incomeorexpense == "income") {
                total+=t.amount;
            }
            if (t.incomeorexpense=="expense") {
                    total=total-t.amount;
                }
        }

        std::cout << "\nGoal: " << goal << "\nAmount saved: " << total;

        if (total == goal) {
            std::cout << "\nGreat job! You saved exactly how much you were supposed to!" ;
        }
        
        else if (total > goal) {
            std::cout << "\nAmazing job! You saved more than your savings goal! ";
        }

        else if (total == goal+15 | total == goal -15){
            std::cout << "\nYou were pretty close to your goal! Good job.";
        }

        else {
            std::cout << "\nYou did not reach your goal! Do better saving next time!";
        }
    }

    if (budgettype == "spendlim") {
        double total = 0;
        for (transaction t : transactions) {
            if (t.incomeorexpense == "expense") {
                total+=t.amount;
            }
        }
        std::cout << "\nGoal: " << goal << "\nAmount spent: " << total;

        if (total == goal) {
            std::cout << "\nGreat job! You didn't pass your spending goal!" ;
        }
        
        else if (total < goal) {
            std::cout << "\nAmazing job! You spent less than your goal! ";
        }

        else if (total == goal+15 ){
            std::cout << "\nYou were pretty close to your goal! Good job.";
        }

        else {
            std::cout << "\nYou spent too much money!!";
        }
    }

 }

int main (int argc, char**argv) {
    
    int answer1 = 0;
    double budgetgoal;
    std::string budgettype;

    std::cout << "\nHi there, welcome to the transaction and budget tracker!  ";
    std::cout << "\nBefore we begin, what kind of budget do you want?     ";
    std::cout << "\n1 - Spending limit\n2 - Overall savings goal\n----------\n"     ;
    while (answer1 != 1 && answer1 != 2){
        std::cin >> answer1;
        if (answer1 != 1 && answer1 != 2){
            std::cout << "Invalid entry... enter '1' or '2'.\n";
        }
    }

    if (answer1 == 1){
        std::cout << "\n\nWhat is your spending limit for this time period?     $";
        std::cin >> budgetgoal;
        budgettype = "spendlim";
    } 
    
    else if (answer1 == 2) {
        std::cout << "\nHow much do you want to save in this time period?   ";
        std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
        std::cin >> budgetgoal;
        budgettype = "savingsgoal";
    }

    std::cout <<"\n\nEnter the name of the file you would like to load or a new file you would like to create:  \n(no need to include '.txt'  )\n";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::getline(std::cin,fileName);
    loadfromfile(fileName);
    std::string ans;

    // Clear the input buffer up to a new line chaacter
    do{
        std::cout << "\n\nWhat do you want to do? (enter number) \n1 - add a transaction\n2 - view transactions\n3 - save transactions\n4 - display category info\n5 - display spending statistics\n6 - view budget \n7 - exit\n\n";
        std::getline(std::cin,ans);
        if (ans == "1") {

            std::string d;
            std::string c;
            std::string i;
            std::string x;
            double a;
            std::cout<< "\n-----------\n";
            std::cout << "Enter transaction description:  ";
            std::getline(std::cin,d);

            std::cout << "Enter transaction category:  ";
            std::getline(std::cin,c);

            std::cout << "\nWas this \n1 - income \n2 - expense ? \n(enter the #)    ";
            std::cin>>i;
            if (i != "1" && i != "2"){
                std::cout<< "invalid choice, try again";
            }
            else if (i == "1"){
               x = "income";
            }
            else if (i =="2") {
                x = "expense";
            }
            if (x =="income"){
                std::cout << "\nEnter money gained:  ";
            }
            else if (x =="expense"){
                std::cout <<"\nEnter money spent: ";
            }
            std::cin >> a;
            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            transaction trans = {d,c,x,a};
            add_transaction (trans);

            std::cout << "Transaction saved!\n";
        }

        if (ans == "2") {

            view_transactions();
        }

        if (ans == "3") {
            savetofile(fileName);
            std::cout << "Transactions saved!";
        }

        if (ans == "4") {
            std::string categorychoice;
            std::cout << "\nWhich category do you want to show?\n";
            
            std::sort(transactions.begin(), transactions.end(), sortByCategory);
            // will organize alphabetically so transactions with the same category are beside each other
            // easier to make sure that each category is only read once

            std::string temp;
            // will hold the value of the previous category to compare if they are the same

            for (transaction t : transactions) {
                //outputs all categories only once
                if (t.category != temp) {
                    std::cout << "- " << t.category << "\n";
                    temp = t.category;
                }
            }

            std::cout<<"\n";
            std::cin >> categorychoice;

            std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
            
            std::string isthatacategory="no";
            // will only be 'yes' if the category inputted is found in the vector of tranactions

            for (transaction t : transactions) {
                if (t.category == categorychoice) {
                    isthatacategory = "yes";
                }
            }

            if (isthatacategory=="yes"){
                displaycategoryinfo(categorychoice);
            }
            else {
                std::cout<<"\nNot a valid choice, try again.";
            }

        }
        
        if (ans =="5"){
            displaystatistics(transactions);
        }

        if (ans =="6"){
            viewbudget(budgettype, budgetgoal);
        }

    } while (ans!= "7");
}