|
|
|
|
@ -10,14 +10,39 @@ app = Flask(
|
|
|
|
|
|
|
|
|
|
@app.route("/") |
|
|
|
|
def index(): |
|
|
|
|
return """ |
|
|
|
|
<h1>OTB Billing</h1> |
|
|
|
|
<p>Version 0.0.8</p> |
|
|
|
|
<p><a href="/clients">Clients</a></p> |
|
|
|
|
<p><a href="/services">Services</a></p> |
|
|
|
|
<p><a href="/invoices">Invoices</a></p> |
|
|
|
|
<p><a href="/dbtest">DB Test</a></p> |
|
|
|
|
""" |
|
|
|
|
conn = get_db_connection() |
|
|
|
|
cursor = conn.cursor(dictionary=True) |
|
|
|
|
|
|
|
|
|
cursor.execute("SELECT COUNT(*) AS total_clients FROM clients") |
|
|
|
|
total_clients = cursor.fetchone()["total_clients"] |
|
|
|
|
|
|
|
|
|
cursor.execute("SELECT COUNT(*) AS active_services FROM services WHERE status = 'active'") |
|
|
|
|
active_services = cursor.fetchone()["active_services"] |
|
|
|
|
|
|
|
|
|
cursor.execute(""" |
|
|
|
|
SELECT COUNT(*) AS outstanding_invoices |
|
|
|
|
FROM invoices |
|
|
|
|
WHERE status IN ('pending', 'partial', 'overdue') |
|
|
|
|
""") |
|
|
|
|
outstanding_invoices = cursor.fetchone()["outstanding_invoices"] |
|
|
|
|
|
|
|
|
|
cursor.execute(""" |
|
|
|
|
SELECT COALESCE(SUM(payment_amount), 0) AS revenue_received |
|
|
|
|
FROM payments |
|
|
|
|
WHERE payment_status = 'confirmed' |
|
|
|
|
AND payment_currency = 'CAD' |
|
|
|
|
""") |
|
|
|
|
revenue_received = cursor.fetchone()["revenue_received"] |
|
|
|
|
|
|
|
|
|
conn.close() |
|
|
|
|
|
|
|
|
|
return render_template( |
|
|
|
|
"dashboard.html", |
|
|
|
|
total_clients=total_clients, |
|
|
|
|
active_services=active_services, |
|
|
|
|
outstanding_invoices=outstanding_invoices, |
|
|
|
|
revenue_received=revenue_received, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
@app.route("/dbtest") |
|
|
|
|
def dbtest(): |
|
|
|
|
@ -201,5 +226,99 @@ def new_invoice():
|
|
|
|
|
form_data={}, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
@app.route("/clients/new", methods=["GET", "POST"]) |
|
|
|
|
def new_client(): |
|
|
|
|
if request.method == "POST": |
|
|
|
|
company_name = request.form["company_name"] |
|
|
|
|
contact_name = request.form["contact_name"] |
|
|
|
|
email = request.form["email"] |
|
|
|
|
phone = request.form["phone"] |
|
|
|
|
|
|
|
|
|
conn = get_db_connection() |
|
|
|
|
cursor = conn.cursor(dictionary=True) |
|
|
|
|
cursor.execute("SELECT MAX(id) AS last_id FROM clients") |
|
|
|
|
result = cursor.fetchone() |
|
|
|
|
last_number = result["last_id"] if result["last_id"] else 0 |
|
|
|
|
|
|
|
|
|
client_code = generate_client_code(company_name, last_number) |
|
|
|
|
|
|
|
|
|
cursor = conn.cursor() |
|
|
|
|
cursor.execute( |
|
|
|
|
""" |
|
|
|
|
INSERT INTO clients |
|
|
|
|
(client_code, company_name, contact_name, email, phone) |
|
|
|
|
VALUES (%s, %s, %s, %s, %s) |
|
|
|
|
""", |
|
|
|
|
(client_code, company_name, contact_name, email, phone) |
|
|
|
|
) |
|
|
|
|
conn.commit() |
|
|
|
|
conn.close() |
|
|
|
|
|
|
|
|
|
return redirect("/clients") |
|
|
|
|
|
|
|
|
|
return render_template("clients/new.html") |
|
|
|
|
|
|
|
|
|
@app.route("/services/new", methods=["GET", "POST"]) |
|
|
|
|
def new_service(): |
|
|
|
|
conn = get_db_connection() |
|
|
|
|
cursor = conn.cursor(dictionary=True) |
|
|
|
|
|
|
|
|
|
if request.method == "POST": |
|
|
|
|
client_id = request.form["client_id"] |
|
|
|
|
service_name = request.form["service_name"] |
|
|
|
|
service_type = request.form["service_type"] |
|
|
|
|
billing_cycle = request.form["billing_cycle"] |
|
|
|
|
currency_code = request.form["currency_code"] |
|
|
|
|
recurring_amount = request.form["recurring_amount"] |
|
|
|
|
status = request.form["status"] |
|
|
|
|
start_date = request.form["start_date"] or None |
|
|
|
|
description = request.form["description"] |
|
|
|
|
|
|
|
|
|
cursor.execute("SELECT MAX(id) AS last_id FROM services") |
|
|
|
|
result = cursor.fetchone() |
|
|
|
|
last_number = result["last_id"] if result["last_id"] else 0 |
|
|
|
|
service_code = generate_service_code(service_name, last_number) |
|
|
|
|
|
|
|
|
|
insert_cursor = conn.cursor() |
|
|
|
|
insert_cursor.execute( |
|
|
|
|
""" |
|
|
|
|
INSERT INTO services |
|
|
|
|
( |
|
|
|
|
client_id, |
|
|
|
|
service_code, |
|
|
|
|
service_name, |
|
|
|
|
service_type, |
|
|
|
|
billing_cycle, |
|
|
|
|
status, |
|
|
|
|
currency_code, |
|
|
|
|
recurring_amount, |
|
|
|
|
start_date, |
|
|
|
|
description |
|
|
|
|
) |
|
|
|
|
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s) |
|
|
|
|
""", |
|
|
|
|
( |
|
|
|
|
client_id, |
|
|
|
|
service_code, |
|
|
|
|
service_name, |
|
|
|
|
service_type, |
|
|
|
|
billing_cycle, |
|
|
|
|
status, |
|
|
|
|
currency_code, |
|
|
|
|
recurring_amount, |
|
|
|
|
start_date, |
|
|
|
|
description |
|
|
|
|
) |
|
|
|
|
) |
|
|
|
|
conn.commit() |
|
|
|
|
conn.close() |
|
|
|
|
|
|
|
|
|
return redirect("/services") |
|
|
|
|
|
|
|
|
|
cursor.execute("SELECT id, client_code, company_name FROM clients ORDER BY company_name ASC") |
|
|
|
|
clients = cursor.fetchall() |
|
|
|
|
conn.close() |
|
|
|
|
return render_template("services/new.html", clients=clients) |
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
app.run(host="0.0.0.0", port=5050) |
|
|
|
|
|