This note is from 8 months ago. You're viewing content from a previous lesson.
At the start of every class, please:
Where: anywhere above if __name__ == '__main__':
Edit:
@app.route('/ping')
def ping():
return 'pong'
Done when: Visiting /ping shows pong.
Where: in index() route
Edit (add import and pass a var):
from datetime import datetime # already imported above
# ...
return render_template('index.html',
total_products=total_products,
low_stock_products=low_stock_products,
recent_sales=recent_sales,
low_stock_items=low_stock_items,
now=datetime.now().strftime('%Y-%m-%d %H:%M'))
Template hint: put {{ now }} somewhere visible.
Done when: The home page shows a timestamp.
Where: in /login POST, inside if user: block after setting session
Edit:
flash(f"Welcome, {user['username']}!", 'success')
Done when: After login, a green message says “Welcome, admin!”.
Where: in /inventory/add POST, right after you convert numbers
Edit:
if price < cost:
flash('Warning: price is below cost.', 'info')
(Still allows saving; it just warns.)
Done when: Adding a product with price < cost shows an info warning.
Where: in /inventory route, after existing filters
Edit:
low = request.args.get('low', '')
if low == '1':
query += " AND p.stock_quantity <= p.min_stock_level"
Usage: Visit /inventory?low=1.
Done when: Only low-stock products appear with ?low=1.
Where: in generate_transaction_id()
Edit:
import random
def generate_transaction_id():
timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
return f"TXN{timestamp}{random.randint(100,999)}"
Done when: Two quick checkouts don’t collide; IDs end with 3 random digits.
Where: in init_database() where default_categories is defined
Edit (add a tuple):
('Merch', 'Stickers, pins, mugs, and school swag'),
Done when: After deleting the DB (or running on a fresh DB), categories includes “Merch”.
(Existing INSERT OR IGNORE prevents duplicates.)
Where: near the top of the file (globals) and add a route
Edit:
APP_VERSION = "0.1.0"
@app.route('/version')
def version():
return APP_VERSION
Done when: Visiting /version shows 0.1.0.
Where: add a route anywhere above if __name__ == '__main__':
Edit:
@app.route('/me')
def me():
if not session.get('user_id'):
return jsonify({"logged_in": False})
return jsonify({
"logged_in": True,
"id": session['user_id'],
"username": session['username'],
"role": session['role']
})
Done when: /me returns JSON with your username when logged in, and {"logged_in": false} when not.
Where: in /inventory/add POST, after converting to numbers
Edit:
if price < 0 or cost < 0 or stock_quantity < 0 or min_stock_level < 0:
flash('Values cannot be negative.', 'error')
return redirect(url_for('add_product'))
Done when: Submitting a negative value shows an error and does not save.
Where: near other routes; add an error handler
Edit:
@app.errorhandler(404)
def not_found(e):
return render_template('404.html'), 404
Template hint: create templates/404.html with one line like Page not found.
Done when: Visiting a bad URL shows your custom 404 page.
Where: add a route that reuses your existing queries
Edit:
@app.route('/api/stats')
def api_stats():
if not session.get('user_id'):
return jsonify({"error": "login required"}), 401
conn = get_db_connection()
total_products = conn.execute("SELECT COUNT(*) FROM products").fetchone()[0]
total_sales = conn.execute("SELECT COUNT(*) FROM sales").fetchone()[0]
low_stock = conn.execute("SELECT COUNT(*) FROM products WHERE stock_quantity <= min_stock_level").fetchone()[0]
conn.close()
return jsonify({
"total_products": total_products,
"total_sales": total_sales,
"low_stock": low_stock
})
Done when: Visiting /api/stats while logged in returns a JSON object with those three counts.