|

Personal Budget Planner

Spread the love

Project Description

Create a C++ console application to help users manage their personal finances by recording income and expenses, categorizing transactions, and generating summary reports. The system should support the following features:

  • Transaction Representation: Implement a Transaction class containing:
    • transactionID (int): a unique identifier for each transaction.
    • date (std::string): date of the transaction (YYYY-MM-DD).
    • description (std::string): brief note (e.g., “Groceries”, “Salary”).
    • amount (double): positive for income, negative for expense.
    • category (std::string): classification (e.g., “Food”, “Utilities”, “Salary”).
    • Method display(): outputs transaction details.
  • BudgetManager: A BudgetManager class to manage transactions and summaries:
    • addTransaction(date, desc, amount, category): registers a new transaction with a unique ID.
    • removeTransaction(transactionID): deletes a transaction by its ID.
    • getTransactionsByDate(date): returns all transactions on a given date.
    • getTransactionsByCategory(category): returns all transactions in a specific category.
    • generateMonthlyReport(month): calculates total income, total expenses, and net balance for a given month (format “YYYY-MM”).
    • displayAllTransactions(): lists every recorded transaction.
  • Behavioral Requirements:
    • Validate inputs: dates must follow YYYY-MM-DD; amounts cannot be zero.
    • Store transactions in a container of std::vector<std::unique_ptr> for exclusive ownership and automated cleanup.
    • Assign transactionID automatically, incrementing with each addition.

Solution :

Transaction class
#include <iostream>
#include <vector>
#include <memory>
#include <algorithm>
#include <string>
#include <map>

// Transaction class models individual income or expense entries
class Transaction {
public:
    int transactionID;         // Unique identifier
    std::string date;          // YYYY-MM-DD
    std::string description;   // Note about transaction
    double amount;             // Positive = income, negative = expense
    std::string category;      // Category name

    // Constructor initializes all fields
    Transaction(int id, const std::string& d, const std::string& desc,
                double amt, const std::string& cat)
        : transactionID(id), date(d), description(desc), amount(amt), category(cat) {}

    // Display transaction details
    void display() const {
        std::cout << "ID: " << transactionID
                  << " | " << date
                  << " | " << description
                  << " | " << (amount < 0 ? "-" : "+") << std::abs(amount)
                  << " | " << category << "\n";
    }
};
BudgetManager class
// BudgetManager class handles all transactions and reporting
class BudgetManager {
    std::vector<std::unique_ptr<Transaction>> transactions;
    int nextID = 1;  // Tracks next transactionID

public:
    // Add a new transaction
    void addTransaction(const std::string& date,
                        const std::string& desc,
                        double amount,
                        const std::string& category) {
        if (date.empty() || desc.empty() || amount == 0.0) {
            std::cerr << "Invalid transaction data\n";
            return;
        }
        // Create and store new Transaction
        transactions.push_back(
            std::make_unique<Transaction>(nextID++, date, desc, amount, category)
        );
        std::cout << "Transaction added (ID: " << nextID - 1 << ")\n";
    }

    // Remove transaction by ID
    bool removeTransaction(int id) {
        auto it = std::remove_if(transactions.begin(), transactions.end(),
            [&](const auto& t) { return t->transactionID == id; });
        if (it == transactions.end()) {
            std::cerr << "Transaction ID " << id << " not found\n";
            return false;
        }
        transactions.erase(it, transactions.end());
        std::cout << "Removed transaction ID " << id << "\n";
        return true;
    }

    // Get all transactions on a specific date
    std::vector<Transaction*> getTransactionsByDate(const std::string& date) const {
        std::vector<Transaction*> result;
        for (const auto& t : transactions) {
            if (t->date == date) result.push_back(t.get());
        }
        return result;
    }

    // Get all transactions in a given category
    std::vector<Transaction*> getTransactionsByCategory(const std::string& category) const {
        std::vector<Transaction*> result;
        for (const auto& t : transactions) {
            if (t->category == category) result.push_back(t.get());
        }
        return result;
    }

    // Generate report for a specific month (YYYY-MM)
    void generateMonthlyReport(const std::string& month) const {
        double income = 0.0, expenses = 0.0;
        for (const auto& t : transactions) {
            if (t->date.rfind(month, 0) == 0) {  // date starts with month
                if (t->amount > 0) income += t->amount;
                else expenses += std::abs(t->amount);
            }
        }
        double net = income - expenses;
        std::cout << "\nReport for " << month << ":\n"
                  << "Total Income: +" << income << "\n"
                  << "Total Expenses: -" << expenses << "\n"
                  << "Net Balance: " << (net < 0 ? "-" : "+") << std::abs(net) << "\n";
    }

    // Display all recorded transactions
    void displayAllTransactions() const {
        std::cout << "\nAll Transactions:\n";
        for (const auto& t : transactions) t->display();
    }
};
Example usage
// Example usage
int main() {
    BudgetManager bm;
    bm.addTransaction("2025-05-01", "Salary", 3000.00, "Income");  // Income
    bm.addTransaction("2025-05-02", "Rent", -1200.00, "Housing");  // Expense
    bm.addTransaction("2025-05-03", "Groceries", -150.45, "Food");

    bm.displayAllTransactions();
    bm.generateMonthlyReport("2025-05");
    bm.removeTransaction(2);  // Remove rent
    bm.displayAllTransactions();
    return 0;
}

Detailed Explanation of Logic

The BudgetManager stores each Transaction in a std::vector<std::unique_ptr<Transaction>>, ensuring exclusive ownership and automatic cleanup. Every addition increments nextID to assign unique transactionIDs.

  • Adding Transactions: Validates nonempty date and description, and nonzero amount. Creates a new Transaction via std::make_unique, then pushes it onto the vector.
  • Removing Transactions: Uses std::remove_if to locate entries matching the given transactionID, erases them, and reports success or failure.
  • Querying: getTransactionsByDate and getTransactionsByCategory iterate over the vector, compare the relevant field, and return raw Transaction* pointers for non-owning access.
  • Reporting: generateMonthlyReport checks each date string prefix against the target month (rfind(month, 0)), sums positive amounts as income and absolute values of negatives as expenses, then computes and displays net balance.
  • Display Routine: displayAllTransactions loops through every stored pointer, invoking display() for clean output.

Similar Posts