from json import JSONDecodeError
import json
#Function to add an expense to the list of expenses
def add_expense(expenses, category, description, amount):
expenses.append({"category": category, "description": description, "amount": amount})
print(f"Added expense: {description}. Amount {amount}$")
# Fucntion to allocate savings from the budget
def allocate_savings(budget, percentage, total_savings):
if percentage < 0 or percentage > 100:
raise ValueError("Please enter a value between 0 and 100.")
else:
new_savings = (percentage / 100) * budget
total_savings += new_savings
budget -= new_savings
print(f"{percentage}% allocated for savings: {new_savings}$. Total Savings: {total_savings}$ ")
return budget, total_savings
# Function to get the total expenses
def get_total_expenses(expenses):
return sum(expense["amount"] for expense in expenses)
# Function to get the balance after expenses
def get_balance(budget, expenses):
return budget - get_total_expenses(expenses)
# Function to show budget details
def show_budget_details(initial_budget, budget, expenses, filepath, total_savings):
total_spent = get_total_expenses(expenses)
remaining_budget = get_balance(budget, expenses)
print(f"Initial Budget: {initial_budget}$")
print(f"Budget after savings: {budget}$")
print("Expenses: ")
for expense in expenses:
category = expense.get('category')
description = expense.get('description')
amount = expense.get('amount')
print(f"{category}: {amount}$ in {description}")
print(f"Total Spent: {total_spent}$")
print(f"Remaining Budget: {remaining_budget}$")
save_budget_details(filepath, initial_budget, budget, expenses, total_savings, remaining_budget, total_spent)
#Function to load budget data from a file
def load_budget_data(filepath):
try:
with open(filepath, 'r') as file:
data = json.load(file)
# Filter only dictionary sections?
sections = [section for section in data if isinstance(section, dict)]
if sections:
last_section = sections[-1]
else:
last_section = {}
initial_budget = last_section.get("Initial Budget", 0) # Ensure consistent key naming
formatted_expenses = last_section.get("Expenses", []) # Load expenses as a list of dictionatries
expenses = [{"category": expense["category"], "description": expense["description"],
"amount": expense["amount"]} for expense in formatted_expenses]
total_expenses = get_total_expenses(expenses)
remaining_budget = last_section.get("Remaining Budget", initial_budget - total_expenses)
total_savings = last_section.get("Total Savings", 0) # Initializing totoal_savings
return initial_budget, remaining_budget, expenses, total_savings, total_expenses
except (FileNotFoundError, JSONDecodeError):
return 0, 0, [], 0, 0 # Return default value if the file doesnt exist or is empty/curroptede
# Function to save budget details to a file
def save_budget_details(filepath, initial_budget, budget, expenses, total_savings, remaining_budget, total_spent):
# convert expenses to a list of dictionaries
formatted_expenses = [{"category": expense["category"], "description": expense["description"],
"amount": expense["amount"]} for expense in expenses]
data = {
'Initial Budget': initial_budget,
'Budget After Savings': budget,
'Expenses': formatted_expenses,
'Total Savings': total_savings,
'Total Spent': total_spent,
'Remaining Budget': remaining_budget
}
try:
with open(filepath, 'r+') as file:
existing_data = json.load(file)
if isinstance(existing_data, list):
if existing_data and isinstance(existing_data[-1], dict):
existing_data[-1] = data
else:
existing_data.append(data)
else:
existing_data = [data]
file.seek(0)
json.dump(existing_data, file, indent=4)
file.truncate() # Ensure the file is truncated to remov
except (FileNotFoundError, JSONDecodeError):
with open(filepath, 'w') as file:
json.dump([data], file, indent=4)
print("Budget details saved to file.")
# Function to append an expense
def append_expense(expenses, filepath, expense, initial_budget):
try:
with open(filepath, 'r+') as file:
data = json.load(file)
# append expense to in-memory list
expenses.append(expense)
total_spent = get_total_expenses(expenses)
remaining_budget = get_balance(initial_budget, expenses)
# Update JSON data
if isinstance(data, list) and data and isinstance(data[-1], dict):
last_section = data[-1]
if "Expenses" in last_section:
last_section["Expenses"].append(expense)
last_section["Total Spent"] = total_spent
last_section["Remaining Budget"] = remaining_budget
else:
print("No 'Expense' key in the last section")
file.seek(0)
json.dump(data, file, indent=4)
file.truncate() # Ensure the file is truncated to remove any remaining data
else:
print("Invalid data structure in file")
except (FileNotFoundError, json.JSONDecodeError):
print("Error reading the file or decoding JSON")
def add_bill(expenses, filepath, initial_budget):
while True:
description = input("nEnter bill description: ")
try:
amount = float(input("Enter bill amount: "))
expense = {"category": "Bills", "description": description, "amount": amount}
append_expense(expenses, filepath, expense, initial_budget)
print("Expense added successfully!")
break
except ValueError as e:
print(f"Please enter a valid numeric amount. {e}")
def add_necessary_expense(expenses, filepath, initial_budget):
while True:
description = input("Enter necessary expense description: ")
try:
amount = float(input("Enter amount: "))
expense = {"category": "Necessities", "description": description, "amount": amount}
append_expense(expenses, filepath, expense, initial_budget)
print("Expense added successfully!")
break
except ValueError as e:
print(f"Please enter a valid numeric amount. {e}")
def add_luxury_expense(expenses, filepath, initial_budget):
while True:
description = input("nEnter luxury expense description: ")
try:
amount = float(input("Enter amount: "))
expense = {"category": "Luxuries", "description": description, "amount": amount}
append_expense(expenses, filepath, expense, initial_budget)
print("Expense added succesfully!")
break
except ValueError as e:
print(f"Please enter a valid numeric amount. {e}")
def add_new_budget(filepath, remaining_budget, total_savings):
# get the new budget from the user
new_budget = float(input("Enter your budget: "))
# Calculate new initital budget
new_initial_budget = remaining_budget + new_budget
data = {
'Initial Budget': new_initial_budget,
'Budget After Savings': new_initial_budget,
'Expenses': [],
'Total Savings': total_savings,
'Total Spent': 0,
'Remaining Budget': new_initial_budget
}
try:
with open(filepath, 'r+') as file:
# Load existing data from file
try:
file_data = json.load(file)
except JSONDecodeError:
file_data = []
# Define the Divider
divider = {"divider": "=" * 50 + "nNew Sectionn" + "=" * 50}
# Add divider if file_data is not empty
if file_data:
file_data.append(divider)
# Save the updated budget details to the file
file_data.append(data)
file.seek(0)
json.dump(file_data, file, indent=4)
file.truncate() # Ensure the file is truncated to remove any remaining data
print("New budget added successfully")
except (FileNotFoundError, JSONDecodeError):
with open(filepath, 'w') as file:
json.dump([data], file, indent=4)
return new_initial_budget, new_initial_budget, [], total_savings, 0
# Function to handle the main application logic
def main():
print("nWelcome to the Budget App")
filepath = 'budget_data_v83.json' #Define the path of your JASON file
initial_budget, budget, expenses, total_savings, total_expenses = load_budget_data(filepath)
menu_shown = False
while True:
if not menu_shown:
print("nWhat would you like to do?")
print("1. Add a new Budget")
print("2. Allocate Savings %")
print("3. Add expenses")
print("4. Show budget details")
print("5. Exit")
menu_shown = True
choice = input("nEnter your choice (1/2/3/4/5): ")
if choice == "1":
initial_budget, budget, expenses, total_savings, total_expenses = add_new_budget(filepath, budget, total_savings)
elif choice == "2":
if budget <= 0:
print("Not enough in the budget for saving. Please add to the budget first.")
else:
try:
percentage = float(input("nEnter percentage for saving: "))
budget, total_savings = allocate_savings(budget, percentage, total_savings)
print("Savings allocated sucessfully!")
total_spent = get_total_expenses(expenses)
remaining_budget = get_balance(budget, expenses)
save_budget_details(filepath, initial_budget, budget, expenses, total_savings, remaining_budget, total_spent)
except ValueError:
print("Please enter a valid percentage.")
elif choice == "3":
if budget <= 0:
print("Not enough in the budget!")
else:
while True:
print("nAdd Expenses: ")
print("1. Add Bills: ")
print("2. Add Necessary expenses: ")
print("3. Add Luxury expenses: ")
print("4. Return to main menu")
expense_choice = input("Pick an option (1/2/3/4): ")
if expense_choice == "1":
add_bill(expenses, filepath, initial_budget)
elif expense_choice == "2":
add_necessary_expense(expenses, filepath, initial_budget)
elif expense_choice == "3":
add_luxury_expense(expenses, filepath, initial_budget)
elif expense_choice == "4":
print("Returning to main menu...")
break
else:
print("Invalid choice. Please choose again")
elif choice == "4":
show_budget_details(initial_budget, budget, expenses, filepath, total_savings)
elif choice == "5":
print("nExiting Budgeting App. Goodbye!!!")
break
else:
print("Invalid choice, please choose again.")
if __name__ == "__main__":
main()
When I add a new budget, the initial budget for the new budgeting section should be the previous remaining budget plus the new budget amount added, without considering the total expenses. However, my code tends to add the total expenses to the new initial budget as well. So for example, if I were to have 50 spent on say, internet bill as expenses, and I have 750 in remaining budget, when adding a new budget of 250, I expect the 250 + previous remining budget of 750 which should lead to a new initial budget of 1000 in the new budget section. Instead I get 1050. please help figure out which part of my code is responsible for this and how do I fix it. Thanks so much!
Arrogant_Samurai is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.