1

Hi I am working on Cs50 2023/psets/9/finance/

I have looked at this problem and have rewritten the code multiple ways but can't get past this error in the check.

I think I have gotten too close to the problem can someone please have a look with fresh eyes? I would greatly appreciate it.

enter image description here

:( sell handles valid sale
Cause
expected to find "56.00" in page, but it wasn't found
Log
sending GET request to /signin
sending POST request to /login
sending POST request to /sell
checking that "56.00" is in page

-edit 14/12/2023

Hi have tried adding the return early for AAAA in the helper lookup function, and everything looks correct to me.

enter image description here

I've looked at the other posts regarding this such as pset7 finance ':( sell handles valid sale'

and so many others but I feel i might be too close to it now

I have added the |usd into my index.html

{% block main %}
   <table>
        <thead>
            <tr>
                <th>Symbol</th>
                <th>name</th>
                <th>Shares</th>
                <th>Price</th>
                <th>Total Value</th>
            </tr>
        </thead>
        <tbody>
            {% for stock in company%}
            <ul>
                    <tr>
                        <td>{{ stock.company_name }}</td>
                        <td>{{ stock.name }}</td>
                        <td>{{ stock.total_shares }}</td>
                        <td>{{ stock.price|usd }}</td>
                        <td>{{ (stock.price * stock.total_shares)|usd   }}</td>
                   </tr>

            </ul>
            {% endfor %}
            <tr>
                <td colspan="3"></td>
                <th>CASH</th>
                <td>{{ cash|usd }}</td>

            </tr>
            <tr>
                <td colspan="3"></td>
                <th>TOTAL</th>
                <td>{{ total_value|usd }}</td>
            </tr>

        </tbody>
    </table>
{% endblock %}

Here is my SQL schema

CREATE TABLE users (
      id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
      username TEXT NOT NULL, 
      hash TEXT NOT NULL,
      cash NUMERIC NOT NULL DEFAULT 10000.00);
CREATE TABLE sqlite_sequence(name,seq);
CREATE UNIQUE INDEX username ON users (username);
CREATE TABLE shareholders (
     id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
     shareholder_id INTEGER NOT NULL,
     Company_id INTEGER NOT NULL,
     shares NUMERIC NOT NULL DEFAULT 0,
     price NUMERIC NOT NULL,
     dt datetime default current_timestamp,
     FOREIGN KEY(shareholder_id) REFERENCES users(id),
     FOREIGN KEY(Company_id) REFERENCES companies(comp_id));
CREATE TABLE companies (
     comp_id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL UNIQUE,
     company_name TEXT NOT NULL UNIQUE);

Here is all my code for this project edited 14/12/2023 ran style50 again and adjusted formatting as directed

import os

from cs50 import SQL
from flask import Flask, flash, redirect, render_template, request, session
from flask_session import Session
from werkzeug.security import check_password_hash, generate_password_hash

from helpers import apology, login_required, lookup, usd


# Configure application
app = Flask(__name__)

# Custom filter
app.jinja_env.filters["usd"] = usd


# Configure session to use filesystem (instead of signed cookies)
app.config["SESSION_PERMANENT"] = False
app.config["SESSION_TYPE"] = "filesystem"
Session(app)

# Configure CS50 Library to use SQLite database
db = SQL("sqlite:///finance.db")


@app.after_request
def after_request(response):
    """Ensure responses aren't cached"""
    response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
    response.headers["Expires"] = 0
    response.headers["Pragma"] = "no-cache"
    return response


@app.route("/")
@login_required
def index():
    """Show portfolio of stocks"""

    user_id = session["user_id"]

    # company name and its shares
    company = db.execute(
        "SELECT Company_name, price, SUM(shares) AS total_shares FROM shareholders JOIN companies ON companies.Comp_id = shareholders.Company_id WHERE shareholder_id = ? GROUP BY Company_id HAVING total_shares > 0;",
        user_id,
    )

    # current cash
    cash = db.execute("SELECT cash FROM users WHERE id = ?", user_id)[0]["cash"]
    total_value = cash

    # current price of the shares using lookup()
    for stock in company:
        try:
            quote = lookup(stock["company_name"])
            stock["name"] = quote["name"]
            stock["price"] = quote["price"]
            stock["value"] = stock["price"] * stock["total_shares"]
            total_value += stock["value"]
        except:
            print("no company found")
            stock["name"] = stock["company_name"]
            stock["price"] = stock["price"]
            stock["value"] = stock["price"] * stock["total_shares"]
            total_value += stock["value"]

    print(company)
    return render_template(
        "index.html", company=company, cash=cash, total_value=total_value
    )


@app.route("/buy", methods=["GET", "POST"])
@login_required
def buy():
    """Buy shares of stock"""

    if request.method == "POST":
        symbol = request.form.get("symbol")
        company = lookup(symbol)
        if not symbol:
            return apology("Please enter Company Symbol", 400)
        elif not company:
            return apology("Invalid symbol", 400)

        try:
            share = int(request.form.get("shares"))
        except:
            return apology("shares must be and integer", 400)

        if share <= 0:
            return apology("Shares must be a positive integer!", 400)

        user_id = session["user_id"]
        cash = db.execute("SELECT cash FROM users WHERE id = ?", user_id)[0]["cash"]

        company_name = company["name"]
        company_price = company["price"]
        total_price = company_price * share

        if cash < total_price:
            return apology("insufficient funds", 400)
        else:
            try:
                comp_id = db.execute(
                    "SELECT comp_id FROM companies WHERE company_name = ?", company_name
                )[0]["comp_id"]

                db.execute(
                    "INSERT INTO shareholders (shareholder_id, Company_id, shares, price) VALUES (?,?,?,?)",
                    user_id,
                    comp_id,
                    share,
                    company_price,
                )

            except:
                db.execute(
                    "INSERT INTO companies (company_name) VALUES (?)", company_name
                )
                comp_id = db.execute(
                    "SELECT comp_id FROM companies WHERE company_name = ?", company_name
                )[0]["comp_id"]

                if not comp_id:
                    return apology("error", 7)
                db.execute(
                    "INSERT INTO shareholders (shareholder_id, Company_id, shares, price) VALUES (?,?,?,?)",
                    user_id,
                    comp_id,
                    share,
                    company_price,
                )
            db.execute(
                "UPDATE users SET cash = ? WHERE id = ?", cash - total_price, user_id
            )

        return redirect("/")
    else:
        return render_template("Buy.html")


@app.route("/history")
@login_required
def history():
    """Show history of transactions"""

    shareholder = db.execute(
        "SELECT company_name, shares, price, dt FROM shareholders JOIN companies ON companies.Comp_id = shareholders.Company_id WHERE shareholder_id = ? ORDER BY dt",
        session["user_id"],
    )

    return render_template(
        "history.html",
        shareholder=shareholder,
    )


@app.route("/login", methods=["GET", "POST"])
def login():
    """Log user in"""

    # Forget any user_id
    session.clear()

    # User reached route via POST (as by submitting a form via POST)
    if request.method == "POST":
        # Ensure username was submitted
        if not request.form.get("username"):
            return apology("must provide username", 400)

        # Ensure password was submitted
        elif not request.form.get("password"):
            return apology("must provide password", 400)

        # Query database for username
        rows = db.execute(
            "SELECT * FROM users WHERE username = ?", request.form.get("username")
        )

        # Ensure username exists and password is correct
        if len(rows) != 1 or not check_password_hash(
            rows[0]["hash"], request.form.get("password")
        ):
            return apology("invalid username and/or password", 400)

        # Remember which user has logged in
        session["user_id"] = rows[0]["id"]

        # Redirect user to home page
        return redirect("/")

    # User reached route via GET (as by clicking a link or via redirect)
    else:
        return render_template("login.html")


@app.route("/logout")
def logout():
    """Log user out"""

    # Forget any user_id
    session.clear()

    # Redirect user to login form
    return redirect("/")


@app.route("/quote", methods=["GET", "POST"])
@login_required
def quote():
    """Get stock quote."""

    if request.method == "POST":
        symbol = request.form.get("symbol")

        if not symbol:
            return apology("Please enter Company Symbol", 400)
        elif lookup(symbol) == None:
            return apology("No Company found", 400)
        company = lookup(symbol)

        return render_template("quoted.html", company=company)
    else:
        return render_template("quote.html")


@app.route("/register", methods=["GET", "POST"])
def register():
    """Register user"""
    if request.method == "POST":
        user = db.execute(
            "SELECT * FROM users WHERE username = (?)", request.form.get("username")
        )

        if not request.form.get("username"):
            return apology("must provide username", 400)

        if user:
            return apology("Username already taken", 400)

        # Ensure password was submitted
        if not request.form.get("password"):
            return apology("must provide password", 400)
        if not request.form.get("confirmation"):
            return apology("Must confirm password", 400)
        if request.form.get("password") != request.form.get("confirmation"):
            return apology("Passwords do not match", 400)

        name = request.form.get("username")
        password = request.form.get("password")
        password = generate_password_hash(password)
        db.execute("INSERT INTO users (username,hash) VALUES (?,?)", name, password)
        return redirect("/")
    else:
        return render_template("register.html")


@app.route("/sell", methods=["GET", "POST"])
@login_required
def sell():
    """Sell shares of stock"""
    user_id = session["user_id"]

    if request.method == "POST":
        company = request.form.get("symbol")
        shares = int(request.form.get("shares"))
        print(shares)
        print(company)
        if shares <= 0:
            return apology("Shares must be a positive integer!", 400)

        if not company:
            return apology("Select a symbol", 400)

        comp_price = lookup(company)["price"]
        price = shares * float(comp_price)

        result = db.execute(
            "SELECT SUM(shares) AS total_shares FROM shareholders JOIN companies ON companies.Comp_id = shareholders.Company_id WHERE shareholder_id = ? AND company_name = ? GROUP BY company_name",
            user_id,
            company,
        )
        if result:
            shares_owned = result[0]["total_shares"]
        else:
            shares_owned = 0

        if shares_owned < shares:
            return apology("not enough shares available", 400)

        current_cash = db.execute("SELECT cash FROM users WHERE id = ?", user_id)[0][
            "cash"
        ]
        db.execute(
            "UPDATE users SET cash = ? WHERE id = ?", current_cash + price, user_id
        )
        comp_id = db.execute(
            "SELECT comp_id FROM companies WHERE company_name = ?", company
        )[0]["comp_id"]
        db.execute(
            "INSERT INTO shareholders (shareholder_id, Company_id, shares, price) VALUES (?,?,?,?)",
            user_id,
            comp_id,
            -shares,
            comp_price,
        )
        return redirect("/")
    else:
        symbols = db.execute(
            "SELECT Company_name FROM shareholders JOIN companies ON companies.Comp_id = shareholders.Company_id WHERE shareholder_id = ? GROUP BY Company_id HAVING SUM(shares) > 0;",
            user_id,
        )
        return render_template("sell.html", companies=symbols)


15
  • please post the error in text and not a screen shot. will try to look at it later. Some of your exception handling definately looked off in the loop for stock in company you do a redundant assignment and some other questionable items. ill start putting in some feedback later tonight. i have to quickly do the finance exercise so im more familiar with how to make the most proper suggestions. Also strongly suggest running style50 on your python code and reposting it to make it easier to read.
    – UpAndAdam
    Commented Dec 13, 2023 at 16:28
  • what methods have you validated?
    – UpAndAdam
    Commented Dec 13, 2023 at 16:34
  • @UpAndAdam I don't understand could you clarify? as in what have I tried? I tried adding in the return specific info via the helper.py. I've confirmed the use of | usd in index
    – Leyzer
    Commented Dec 14, 2023 at 19:43
  • Not asking you what you have done to try to fix the code. I'm asking you what code paths have you verified working. What have you tested. I dont care if you add print outs or what, but have you verified that ANYTHING actually does what its supposed to do. Does BUY work? Does INVENTORY work? etc? I don't think you have actually gotten close enough to the problem because you have no idea where or what the problem is. You just know it isnt working. You need to do some testing, instead of just rewriting and rewriting code, figure out what actually is and isn't doing what you think it is
    – UpAndAdam
    Commented Dec 14, 2023 at 21:05
  • @UpAndAdam Yes everything works
    – Leyzer
    Commented Dec 14, 2023 at 21:11

1 Answer 1

1

Just a few things I'm finding so far that I can recommend:

  1. Might just be me, but i wouldn't use company_name as my company identifying feature for searches, I would use symbol or company_id only. Just a suggestion but for example there are multiple symbols for Google (goog, googl) so who the company name could be the same. Partially this is from working in the space, but also it's a good practice since you are keying your lookups (quote and calls to lookup) on symbol, so that should be what you would search on. And since it is unique, there is no need for a 'company_id' at all that isn't autogenerated, a sharper DB person would of course point out that you are right in using company_id an integer over a string for indexing and foreign key purposes so take my thought of eliminating it with a large grain of salt.

  2. You make some repeated calls to lookup that aren't needed in quote. Save the result of lookup to a variable, check if it's None or not as you do and if it's not None you have the value stored and don't have to call the API again. Not a HUGE deal but you generally want to avoid repeating computations / API calls when you can. Imagine if IEX started charging you per quote for example.

  3. You make a small but possibly critical mistake in your logic relating to point #1 in your sell logic, and probably your buy logic where you use the 'symbol' as the company_name in your db queries, again these can differ. Whichever you are using you should be consistent. If you ask for symbol and obtain symbol and lookup on symbol, then your db query should probably also be on symbol and not company_name.

1
  • Thank you for taking the time to have a look through the code. I went through each of the above steps you listed, I don't know which one fixed it but it works now. For #1 I realized that I misunderstood what they warned about the updated API in the brief and just put company name instead of Symbol so fixed that in code. added a symbol column in the DB #2 cleaned up multiple lookups. #3 fixed capitalization didn't look like it did anything but you're right to be more consistent. Once again thanks for taking the time to you help
    – Leyzer
    Commented Dec 24, 2023 at 3:22

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .