:( buy handles valid purchase
Cause
expected to find "112.00" in page, but it wasn't found
Log
sending GET request to /signin
sending POST request to /login
sending POST request to /buy
sending POST request to /buy
checking that "112.00" is in page
After buying stock user should be redirected to index page, where total value of stocks purchased or grand total(cash + portfolio value) is shown. I show both. I don’t know what to do next.
index route code in app.py
@app.route("/")
@login_required
def index():
"""Show portfolio of stocks"""
user_id = session["user_id"]
user_info = db.execute("SELECT username, cash FROM users where id = ?", user_id)
# Get necessary data from database
user_info[0]["grand_total"] = user_info[0]["cash"]
user_stocks = db.execute(
"""
SELECT
stock_symbol,
SUM(quantity) AS quantity,
ROUND(AVG(transaction_amount), 2) AS avg_price,
transaction_type,
ROUND(SUM(transaction_amount * quantity), 2) AS total_transaction_amount
FROM
users_stocks
INNER JOIN stocks ON users_stocks.stock_id = stocks.stock_id
WHERE
user_id = ?
GROUP BY
stock_symbol, transaction_type
ORDER BY
stock_symbol, transaction_type ASC""",
user_id,
)
if not user_stocks:
return render_template(
"/index.html", stocks=[], user_info=user_info, totals=[], grand_total = 0
)
for i in range(len(user_stocks)):
current_info = lookup(user_stocks[i]["stock_symbol"])
if current_info:
current_price = current_info["price"]
user_stocks[i]["current_price"] = current_price
user_stocks[i]["total_current_value"] = (
user_stocks[i]["quantity"] * current_price
)
if user_stocks[i]["transaction_type"] == "s":
user_stocks[i - 1]["total_transaction_amount"] -= user_stocks[i][
"total_transaction_amount"
]
user_stocks[i - 1]["quantity"] -= user_stocks[i]["quantity"]
user_stocks[i - 1]["total_current_value"] -= user_stocks[i]["total_current_value"]
stocks = []
quantities = []
averages = []
stocks_value = 0
totals = {"quantity": 0, "weighted_avg": 0, "total_value": 0, "total_paid": 0}
for stock in user_stocks:
if stock["transaction_type"] == "b" and stock["quantity"] != 0:
stocks.append(stock)
stocks_value += stock["total_current_value"]
totals["quantity"] += stock["quantity"]
totals["total_value"] += stock["total_current_value"]
totals["total_paid"] += stock["total_transaction_amount"]
quantities.append(stock["quantity"])
averages.append(stock["avg_price"])
weighted_avg = np.average(averages, weights=quantities)
totals["weighted_avg"] = weighted_avg
print("n", stocks, "n")
print(totals)
grand_total = totals['total_value'] + user_info[0]['cash']
return render_template(
"/index.html", stocks=stocks, user_info=user_info,
stocks_value=stocks_value, totals=totals, grand_total=grand_total
)
HTML
{% extends "layout.html" %} {% block head %}
<link rel="stylesheet" href="../static/index.css" />
{% endblock head %} {% block main %}
<h2>Profile</h2>
<div class="infoBar">
<div>
Hello, {{ user_info[0]['username'] }}
<a href="/changePassword" class="btn btn-primary btn-sm">change password</a>
</div>
<div>
Cash Blance: {{ user_info[0]['cash'] | usd }}
<a href="/addcash" class="btn btn-primary btn-sm">Add Cash</a>
</div>
{% if totals %}
<div>Portfolio Value: {{ totals['total_value'] | usd }}</div>
<div>Grand Total: {{ grand_total | usd }}</div>
{% else %}
<div>Portfolio Value: 0</div>
{% endif %}
</div>
{% if stocks %}
<div class="table-responsive">
<table class="table table-primary">
<thead>
<tr>
<th scope="col">Symbol</th>
<th scope="col">Average Paid</th>
<th scope="col">Quantity</th>
<th scope="col">Total Paid</th>
<th scope="col">Current Price</th>
<th scope="col">Value today</th>
<th scope="col">Sell</th>
</tr>
</thead>
<br />
<tbody>
{% for stock in stocks %} {% if stock['quantity'] != 0 %}
<tr class="table-info">
<td>{{ stock['stock_symbol'] }}</td>
<td>{{ stock['avg_price'] | usd }}</td>
<td>{{ stock['quantity'] }}</td>
<td>{{stock['total_transaction_amount']|usd}}</td>
<td>{{ stock['current_price'] | usd }}</td>
<td>{{stock["total_current_value"]|usd}}</td>
<td>
<form action="/sell" method="post">
<input
type="hidden"
name="stock_select"
id="stock_select"
value="{{
stock['stock_symbol'] }}"
/>
<input
type="hidden"
name="quantity"
id="quantity"
value="{{
stock['quantity'] }}"
/>
<button type="submit" class="btn btn-primary btn- sm">
Sell {{ stock['quantity'] }}
</button>
</form>
</td>
</tr>
{% endif %} {% endfor %} {% if totals %}
<tr>
<td>TOTAL</td>
<td>{{ totals['weighted_avg'] | usd }}</td>
<td>{{ totals['quantity'] }}</td>
<td>{{ totals['total_paid'] | usd }}</td>
<td></td>
<td>{{ totals['total_value'] | usd }}</td>
<td>
<a href="/sell" class="btn btn-primary btn-sm">sell</a>
</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>Cash</td>
<td>{{ user_info[0]['cash'] | usd }}</td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>TOTAL</td>
<td>{{ grand_total| usd }}</td>
</tr>
{% endif %}
</tbody>
</table>
</div>
{% else %}
<br />
<h3>You don't have any stocks</h3>
<br />
{% endif %} {% endblock main %}
/buy route
@app.route("/buy", methods=["GET", "POST"])
@login_required
def buy():
"""Buy shares of stock"""
if request.method == "POST":
# verify stock and quantity
user_symbol = request.form.get("symbol")
stock_quantity = request.form.get("shares")
if "." in stock_quantity:
return apology("Input must be integer")
try:
stock_quantity = int(stock_quantity)
except:
return apology("Input must be numeric")
if not user_symbol:
return apology("Please specify stock symbol")
elif not stock_quantity:
return apology("Please indicate quantity")
elif stock_quantity <= 0:
return apology("you must input positive number")
# Check if provided stock symbol exists
user_symbol = user_symbol.upper()
stock_info = lookup(user_symbol)
if stock_info:
stock_price = stock_info["price"]
stock_symbol = stock_info["symbol"]
db_stock_id = db.execute("""
SELECT stock_id
FROM stocks
WHERE stock_symbol = ?""",
stock_symbol)
if not db_stock_id:
return apology(f"Stock {user_symbol} not found")
else:
return apology(f"Stock {user_symbol} not found")
# Update users cash balance
user_id = session["user_id"]
user_cash = db.execute("SELECT cash FROM users WHERE id = ?", user_id)
if user_cash:
current_user_cash = float(user_cash[0]["cash"])
stock_quantity = int(stock_quantity)
total_for_stocks = stock_price * stock_quantity
updated_user_cash = round(current_user_cash - total_for_stocks, 2)
if updated_user_cash < 0:
return apology("Not enough money on the balance")
db.execute(
"UPDATE users SET cash = ? WHERE id = ?", updated_user_cash, user_id
)
current_datetime = datetime.now()
current_time = current_datetime.strftime("%H:%M:%S")
current_date = current_datetime.date()
# Add stock purchase to database
db.execute(
"""INSERT INTO
users_stocks (user_id, stock_id,
transaction_amount, quantity,
transaction_type, date, time)
VALUES(?, ?, ?, ?, ?, ?, ?)""",
user_id,
db_stock_id[0]["stock_id"],
stock_price,
stock_quantity,
"b",
current_date,
current_time,
)
return redirect("/")
# pass info to populate purchase history table
user_id = session["user_id"]
user_stocks = db.execute(
"""SELECT stock_symbol, transaction_amount, quantity, date, time, transaction_type
FROM users_stocks
INNER JOIN stocks ON users_stocks.stock_id = stocks.stock_id
WHERE user_id = ? AND transaction_type = 'b'
ORDER BY date DESC, time DESC
LIMIT 10""",
user_id,
)
current_stocks = {}
for stock in user_stocks:
if stock["stock_symbol"] not in current_stocks:
current_stock_info = lookup(stock["stock_symbol"])
if current_stock_info:
current_price = current_stock_info["price"]
current_stocks[current_stock_info["symbol"]] = current_price
return render_template(
"buy.html", user_stocks=user_stocks, current_stocks=current_stocks
)
/login route
@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":
username = request.form.get("username")
password = request.form.get("password")
# Ensure username was submitted
if not username:
return apology("must provide username", 403)
# Ensure password was submitted
elif not password:
return apology("must provide password", 403)
# Query database for username
rows = db.execute("SELECT * FROM users WHERE username = ?", username)
# Ensure username exists and password is correct
if len(rows) != 1 or not check_password_hash(rows[0]["hash"], password):
return apology("invalid username and/or password", 403)
# 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")
I tried placing portfolio value(total value of stocks) and grand total(portfolio value + users cash) in several places, but check still can not find value. Also, money is formatted with " | usd" everywhere.
2
Answers
I figured it out. Problem was in buy function. CS50 check was testing with stock which was not in my database(106328 stocks). So, I added check to buy function.
Functionality added.
After getting stock info from yahoo, If stock is not in database, add stock symbol to database.
In the code there is a table named
stocks
. It is apparently used to store the stock symbol. However, there is no INSERT to create the row.buy
will not work for a newly registered because it will return an apology when program tries to selectstock_id
fromstocks
table. (check50
uses the newly registered user). You should be able to reproduce the result by registering a new user and then executing a buy.