Build a Budget App Project

Could somebody please say what is wrong with my code? I cant pass the last test which is about creating spend chart. Withdrawal percentages calculated correctly, and all spacings seem to be in place. What is wrong here?

class Category:
    def __init__(self, name):
        self.name = name
        self.ledger = []

    def deposit(self, amount, description=""):
        self.ledger.append({"amount": amount, "description": description})

    def withdraw(self, amount, description=""):
        if self.check_funds(amount):
            self.ledger.append({"amount": -amount, "description": description})
            return True
        else:
            return False

    def get_balance(self):
        balance = 0
        for transaction in self.ledger:
            balance += transaction['amount']    
        return balance

    def check_funds(self, amount):
        return amount <= self.get_balance()

    def transfer(self, amount, destination_category):
        if self.check_funds(amount):
            self.withdraw(amount, f"Transfer to {destination_category.name}")
            destination_category.deposit(amount, f"Transfer from {self.name}")
            return True
        else:
            return False

    def __str__(self):
        # Customize the string representation to include more details
        lines = [center_title(self.name)]
        for transaction in self.ledger:
            description = transaction['description'][:23]
            amount = '{:.2f}'.format(transaction['amount'])
            lines.append(f"{description.ljust(23)}{amount.rjust(7)}")
        lines.append(f"Total: {self.get_balance()}")
        return '\n'.join(lines)

def center_title(title, line_width=30):
    title_length = len(title)
    left_padding = (line_width - title_length) // 2
    right_padding = line_width - title_length - left_padding
    return '*' * left_padding + title + '*' * right_padding

def create_spend_chart(categories):
    category_withdrawals = {}

    # Calculate withdrawals for each category
    for category in categories:
        withdrawals = 0
        for transaction in category.ledger:
            amount = transaction['amount']
            if amount < 0:
                withdrawals += -amount  # Add the amount spent (negative for withdrawals)
        category_withdrawals[category.name] = withdrawals

    # Calculate total withdrawals across all categories
    total_withdrawals = sum(category_withdrawals.values())

    # Calculate percentages spent for each category based on withdrawals
    category_percentages = {}
    for name, withdrawals in category_withdrawals.items():
        category_percentages[name] = (withdrawals / total_withdrawals) * 100 if total_withdrawals > 0 else 0

    # Generate the chart body
    chart_str = "Percentage spent by category\n"
    for i in range(100, -1, -10):
        line = f"{i:3}| "
        for name in category_percentages:
            percent = category_percentages[name]
            if percent >= i:
                line += "o  "
            else:
                line += "   "
        chart_str += line + "\n"

    # Print the horizontal line at the bottom of the chart
    chart_str += "    " + "-" * (len(category_percentages) * 3 + 1) + "\n"

    # Print category names vertically
    max_name_length = max(len(name) for name in category_percentages)
    for i in range(max_name_length):
        line = "     "
        for name in category_percentages:
            if i < len(name):
                line += name[i] + "  "
            else:
                line += "   "
        chart_str += line + "\n"

    return chart_str



food = Category("Food")
food.deposit(1000, "deposit")
food.withdraw(500.00, "groceries")

clothing = Category("Clothing")
clothing.deposit(1000, "deposit")
clothing.withdraw(100.00, "buying new clothes")

auto = Category("Auto")
auto.deposit(1000, "deposit")
auto.withdraw(200.00, "fuel")

food.transfer(200, clothing)


categories = [food, clothing, auto]
chart_str = create_spend_chart(categories)

print(clothing)
print(chart_str)
AssertionError: 'Perc[364 chars]         m  \n           e  \n           n  \n           t  \n' 
             != 'Perc[364 chars]         m  \n           e  \n           n  \n           t  '

the first line is your code, there is a small difference with the second line, the expected value

1 Like

Am I missing a new line at the end?

the opposite, you have an unexpected new line at the end. The first line is yours, the second is the expected

1 Like

Oh, exactly! Thank you!

I can’t figure out where to remove \n? If I remove in one of the functions, everything falls apart. Do I need to create an if statement with the condition adding \n everywhere but if it is the last line then don’t add \n?

it seems you have a plan, why don’t you try?

1 Like

I used rstrip(“\n”) on chart_str to remove the last \n and passed this exam! Thank you very much for your help!

2 Likes

I am having a similar issue. My output seems to be fine but I failed the last test. The only sense I could make from the assertion error was that the expected characters (297) are less than mine (299). I am definitely missing something which I need help to spot.

my code:

class Category:

    def __init__(self, category):
        self.category = category
        self.ledger = []
        self.balance = 0

    def display_category(self):
        display = ""
        display += f"{self.category.center(30, '*')}\n"
        for expense in self.ledger:
            display += expense["description"][:23].ljust(23) + str("%.2f" % expense["amount"])[:7].rjust(7)
            display += "\n"
        display += f"Total: " + str(self.balance)
        return display

    def __str__(self):
        return self.display_category()

    def check_funds(self, amount):
        if amount > self.balance:
            return False
        else:
            return True
    
    def deposit(self, amount, description = ""):
        self.balance += amount 
        self.ledger.append(
            {
            "amount" : amount,
            "description" : description
            }
            )

    def withdraw(self, amount, description = ""):
        if self.check_funds(amount):
            self.ledger.append(
                {
                "amount" : amount * -1,
                "description" : description
                }
                )
            self.balance -=amount
            return True
        else:
            return False

    def transfer(self, amount, cate):
        if self.check_funds(amount):
            self.withdraw(amount, f"Transfer to {cate.category}")
            cate.deposit(amount, f"Transfer from {self.category}")
            return True
        else: return False

    def get_balance(self):
        return self.balance
    
      

def create_spend_chart(categories):
    chart = ""
    def get_percentage_spent(category):
        total_amount_spent = 0
        total_deposit = 0
        for i in range(len(category.ledger)):
                if category.ledger[i]["amount"] < 0:
                    total_amount_spent += category.ledger[i]["amount"]
                else:
                    total_deposit += category.ledger[i]["amount"]
        percentage_spent = int(round((abs(total_amount_spent) * 100) / total_deposit, -1))
        return percentage_spent

    def print_bar(dictionary, percentage):
        line = ""
        for item in dictionary:
            if percentage > dictionary[item]:
                line += "   "
            elif percentage <= dictionary[item]:
                line += "o  "
        return line


    percentage_spent = {
        cat.category: get_percentage_spent(cat) for cat in categories
    }


    chart += "Percentage spent by category\n"
    for percentage in range(100, -10, -10):
        chart += (str(percentage) + "|").rjust(4) + " " + print_bar(percentage_spent, percentage) + "\n"
    dash_length = (len(categories) * 3) + 1 
    dashes = "    "
    for _ in range(dash_length):
        dashes += "-" 
    chart += dashes + "\n"


    index = 0
    cat = [len(item.category) for item in categories]
    
    while index < max(cat):
        line = "     "
        for item in categories:
            if item.category[-1] == item.category[0] and len(item.category) == 1:
                if item.category == "_":
                    line += " "
                else:
                    line += item.category[index]
                    item = "_" 
            else:
                try: 
                   line += item.category[index] + "  "
                except IndexError:
                    line += "   "
        index += 1
        chart += line + "\n"
    #print(percentage_spent)
    return chart
        



categories = []
food = Category("Food")
clothing = Category("Clothing")
home = Category("Hommie")
edu = Category("Educationiskey")

food.deposit(1000, "deposit")
food.withdraw(10.15, "groceries")
food.withdraw(15.89, "restaurant and more food for dessert")
food.transfer(50, clothing)
food.transfer(150, home)

home.deposit(200, "deposit")
home.withdraw(20, "furniture")
home.withdraw(30, "kitchenware")
home.transfer(40, edu)

edu.deposit(300, "initial deposit")
edu.withdraw(150, "books")
edu.withdraw(20, "sch uniform")
edu.transfer(20, clothing)

clothing.withdraw(15, "shoes")

categories.append(food)
categories.append(clothing)
categories.append(home)
categories.append(edu)

print(food)
print(create_spend_chart(categories))


type or paste code here

It appears I cant yet figure out how to paste my output but anyone can try my code. Please someone give me a clue to what I am missing.

If you have a question about a specific challenge as it relates to your written code for that challenge and need some help, click the Ask for Help button located on the challenge (it looks like a question mark). This button only appears if you have tried to submit an answer at least three times.

The Ask for Help button will create a new topic with all code you have written and include a link to the challenge also. You will still be able to ask any questions in the post before submitting it to the forum.

Thank you.