Build a Budget App - Build a Budget App

Tell us what’s happening:

This is the Build a Budget App certification project. What exactly am I missing here? Looking at the terminal, it seems I have all the steps down, and it matches the example output pretty much exactly from what I can tell. Is there another tweak that needs to be made to satisfy the prompts. I’ll post my code so far, I’d appreciate if someone can point me in the right direction. Everything up until the create_spend_chart is working, it’s just steps 18 down that I can’t seem to get.

Your code so far

class Category:
    def __init__(self,name):
        self.name=name
        self.ledger=[]
        all_categories.append(self)
    def deposit(self,amount,description=''):
        self.ledger.append({'amount': amount, 'description': description})
    def withdraw(self,amount,description=''):
        if self.check_funds(amount)==True:
            self.ledger.append({'amount':-amount,'description':description})  
            return True
        else:
            return False
    def get_balance(self):
        Balance=0
        for ledger_dict in self.ledger:
            for amount in ledger_dict.values():
                if isinstance(amount,(int,float)):
                    Balance+=amount
        return Balance
    def transfer(self,amount,other):
        if self.check_funds(amount)==True:
            self.withdraw(amount,description=f'Transfer to {other.name}')
            other.deposit(amount,description=f'Transfer from {self.name}')
            return True
        else:
            return False
    def check_funds(self,amount):
        Balance=self.get_balance()
        if amount>Balance:
            return False
        else:
            return True
    def __str__(self):
        string=''
        balance=0
        #alt: string+=f'{self.name:*^30}'
        multi=round((30-len(self.name))/2)
        string+=f'*'*multi
        string+=f'{self.name}'
        if multi*2+len(self.name)==29:
            string+=f'*'*multi
            string+=f'*'
        else:
            string+=f'*'*multi
        string+=f'\n'
        for ledger_dict in self.ledger:
            for key,val in ledger_dict.items():
                if key=='amount':
                    if len(ledger_dict['description'])>23:
                        for i,l in enumerate(ledger_dict['description']):
                            if i<23:
                                string+=f'{l}'
                        string+=f'{"":<0}'
                    else:
                        string+=f'{ledger_dict["description"]:<23}'
                if key=='description':
                    if len(str(ledger_dict['amount']))>7:
                        for i,n in enumerate(str(ledger_dict['amount'])):
                            if i<7:
                                string+=f'{n}'
                        string+='\n'
                    else:
                        #alt: string+='{:>7.2f}'.format(ledger_dict["amount"])
                        #alt: string+='\n'
                        string+=f'{ledger_dict["amount"]:>7.2f}\n'
                    balance+=(ledger_dict['amount'])
        string+=f'Total: {balance:.2f}'
        return string


all_categories=[]
#list of all Category objects; must be called before creating class objects, so that initializer has soemthing to work with
categ=Category('Stuff')
categ.deposit(1000.07,'initial deposit')
categ.withdraw(100.05,'abcdefghijklmnopqrstuvw')
categ.withdraw(500.00,'good eatin\'')
categ.withdraw(200)
#print(categ.check_funds(100))
#print(categ.check_funds(1000))
#print(categ.get_balance())
food=Category('Food')
food.deposit(900, 'deposit')
food.withdraw(45., 'milk, cereal, eggs, bacon, bread')
#print(food.get_balance())
#print(food.transfer(1000,categ))
#print(food.withdraw(1000))
#print(
food.transfer(300,categ)
#)
supplies=Category('Supplies')
supplies.deposit(550,'initial')
supplies.withdraw(322,'grocery run')
print(categ)
print(food)
print(supplies)
others=Category('others')
others.deposit(200)
others.withdraw(50)



def create_spend_chart(categories):
    chart=''
    chart+=('Percentage spent by category\n')
    totalnum=0
    categnum_list=[]
    for category in categories:
        categnum=0
        for ledger_dict in category.ledger:
            for val in ledger_dict.values():
                if (isinstance(val,(float,int))) and val<0:
                    categnum+=val
                    totalnum+=val
        categnum_list.append(categnum)
    #this is counting neg. transfers as withdrawals

    percentages=[]
    for categnum in categnum_list:
        percentages.append(round(((categnum/totalnum)*100),-1))
    
    y_axis=[num for num in range(101)if num%10==0]
    y_axis.reverse()
    for num in y_axis:
        chart+=f'{num:4}| '
        for percentage in percentages:
            if not num>percentage:
                chart+='o  '
            else:
                chart+='   '
        chart+='\n'
    chart+=' '*5
    for category in categories:
        chart+=f'---'
    chart+='-\n'

    lenlist=[]
    for category in all_categories:
        lenlist.append(len(category.name))
    l=max(lenlist)
    numlist=[num for num in range(0,l+1)]
    n=0
    for num in numlist:
    #think invisible numbers on left margin of every row
        chart+=' '*6
        #this space exist in every row, for every 'number'
        for category in all_categories:
        #for each num, check the category for their names
            for num,c in zip(numlist,category.name):
                if num==n:
                    chart+=f'{c}  '
            #would enumerate be better? maybe...but regardless this makes sure only nth letter of each name is posted
            if n>=len(category.name):
                chart+='   '
            #needed for when categ name is out of letters to leave space instead and move to next column        
        chart+='\n'
        #head to next row and grab a new iterations of all the categ names
        n+=1
        #keeps track of what row we're heading to
    return chart

print(create_spend_chart(all_categories))

Your browser information:

User Agent is: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36

Challenge Information:

Build a Budget App - Build a Budget App

Github Link: freeCodeCamp/curriculum/challenges/english/blocks/lab-budget-app/5e44413e903586ffb414c94e.md at main · freeCodeCamp/freeCodeCamp · GitHub

where is all_categories coming from?

Hi @Gio0417 , here are a few other mistakes I have notice :

18, 20 and 21 tests are all related to the same problem : you have an extra space at the beginning. The 100| should be placed right after the new line, no extra spaces. Hint: Try changing these lines : chart+=f'{num:4}| '; chart+=' '*5; chart+=' '*6

19 is a bit tricky : you need to round down (for example, if you have 57, it will result in 50). Hint : Try using a function called math.floor, in the math library. Here’s a link. It doesn’t accept arguments like round however, I’ll help you further if you need. This is the method I chose though, I’m sure there are other ways.

22 is kinda obvious, you have a \n character at the end. Go check the strings functions part if you are really stuck, but I think you can figure it out.

I’m still working on 23 and 24, I have this error when you press f12 after solving all of above (including the one @ILM found):

I’m don’t really know what that means.

Anyways, hope this helped you, happy coding :grin:

Alright, made a few changes. First, the all_categories was a list I used to contain each object in the Category class, so that I can use as it as an argument for the create_spend_chart() function. I was testing my code outside of the function, by using it for the “for” statements and forgot to change it to just ‘categories’, the default argument, when putting it inside the actual function. Thanks for pointing that out, it fixed one of the steps.

Other changes I made were replacing the round function by importing floor from the math module to force it to only round down, and also I didn’t realize there was an extra space before the numbers on the y-axis, so I fixed it and adjusted the rest of the chart in turn. Plus, I had to adjust the function so that the new line part wasn’t added at the bottom of it. But yeah, I managed to figure it out, thanks for the help.

I saw the notification for this pop up as I was fixing the last thing I was stuck on, and I already found and used those exact solutions! But thanks anyway. 23 and 24 seems to be cleared up once everything else was in place, 23 in particular checked off when I used ILM’s fix, I think it was just reading the category names based off what was in the argument.