|
|
|
|
@ -12,7 +12,7 @@ app = Flask(
|
|
|
|
|
def index(): |
|
|
|
|
return """ |
|
|
|
|
<h1>OTB Billing</h1> |
|
|
|
|
<p>Version 0.0.7</p> |
|
|
|
|
<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> |
|
|
|
|
@ -44,25 +44,20 @@ def clients():
|
|
|
|
|
def services(): |
|
|
|
|
conn = get_db_connection() |
|
|
|
|
cursor = conn.cursor(dictionary=True) |
|
|
|
|
|
|
|
|
|
cursor.execute(""" |
|
|
|
|
SELECT s.*, c.client_code, c.company_name |
|
|
|
|
FROM services s |
|
|
|
|
JOIN clients c ON s.client_id = c.id |
|
|
|
|
ORDER BY s.id DESC |
|
|
|
|
""") |
|
|
|
|
|
|
|
|
|
services = cursor.fetchall() |
|
|
|
|
conn.close() |
|
|
|
|
|
|
|
|
|
return render_template("services/list.html", services=services) |
|
|
|
|
|
|
|
|
|
@app.route("/invoices") |
|
|
|
|
def invoices(): |
|
|
|
|
|
|
|
|
|
conn = get_db_connection() |
|
|
|
|
cursor = conn.cursor(dictionary=True) |
|
|
|
|
|
|
|
|
|
cursor.execute(""" |
|
|
|
|
SELECT |
|
|
|
|
i.*, |
|
|
|
|
@ -72,35 +67,85 @@ def invoices():
|
|
|
|
|
JOIN clients c ON i.client_id = c.id |
|
|
|
|
ORDER BY i.id DESC |
|
|
|
|
""") |
|
|
|
|
|
|
|
|
|
invoices = cursor.fetchall() |
|
|
|
|
conn.close() |
|
|
|
|
|
|
|
|
|
return render_template("invoices/list.html", invoices=invoices) |
|
|
|
|
|
|
|
|
|
@app.route("/invoices/new", methods=["GET","POST"]) |
|
|
|
|
@app.route("/invoices/new", methods=["GET", "POST"]) |
|
|
|
|
def new_invoice(): |
|
|
|
|
|
|
|
|
|
conn = get_db_connection() |
|
|
|
|
cursor = conn.cursor(dictionary=True) |
|
|
|
|
|
|
|
|
|
if request.method == "POST": |
|
|
|
|
client_id = request.form.get("client_id", "").strip() |
|
|
|
|
service_id = request.form.get("service_id", "").strip() |
|
|
|
|
currency_code = request.form.get("currency_code", "").strip() |
|
|
|
|
total_amount = request.form.get("total_amount", "").strip() |
|
|
|
|
due_at = request.form.get("due_at", "").strip() |
|
|
|
|
notes = request.form.get("notes", "").strip() |
|
|
|
|
|
|
|
|
|
errors = [] |
|
|
|
|
|
|
|
|
|
if not client_id: |
|
|
|
|
errors.append("Client is required.") |
|
|
|
|
if not service_id: |
|
|
|
|
errors.append("Service is required.") |
|
|
|
|
if not currency_code: |
|
|
|
|
errors.append("Currency is required.") |
|
|
|
|
if not total_amount: |
|
|
|
|
errors.append("Total amount is required.") |
|
|
|
|
if not due_at: |
|
|
|
|
errors.append("Due date is required.") |
|
|
|
|
|
|
|
|
|
if not errors: |
|
|
|
|
try: |
|
|
|
|
amount_value = float(total_amount) |
|
|
|
|
if amount_value <= 0: |
|
|
|
|
errors.append("Total amount must be greater than zero.") |
|
|
|
|
except ValueError: |
|
|
|
|
errors.append("Total amount must be a valid number.") |
|
|
|
|
|
|
|
|
|
if errors: |
|
|
|
|
cursor.execute(""" |
|
|
|
|
SELECT id, client_code, company_name |
|
|
|
|
FROM clients |
|
|
|
|
ORDER BY company_name |
|
|
|
|
""") |
|
|
|
|
clients = cursor.fetchall() |
|
|
|
|
|
|
|
|
|
client_id = request.form["client_id"] |
|
|
|
|
service_id = request.form["service_id"] |
|
|
|
|
currency_code = request.form["currency_code"] |
|
|
|
|
total_amount = request.form["total_amount"] |
|
|
|
|
due_at = request.form["due_at"] |
|
|
|
|
notes = request.form["notes"] |
|
|
|
|
cursor.execute(""" |
|
|
|
|
SELECT id, service_code, service_name |
|
|
|
|
FROM services |
|
|
|
|
ORDER BY service_name |
|
|
|
|
""") |
|
|
|
|
services = cursor.fetchall() |
|
|
|
|
|
|
|
|
|
cursor.execute("SELECT MAX(id) as last_id FROM invoices") |
|
|
|
|
conn.close() |
|
|
|
|
|
|
|
|
|
form_data = { |
|
|
|
|
"client_id": client_id, |
|
|
|
|
"service_id": service_id, |
|
|
|
|
"currency_code": currency_code, |
|
|
|
|
"total_amount": total_amount, |
|
|
|
|
"due_at": due_at, |
|
|
|
|
"notes": notes, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return render_template( |
|
|
|
|
"invoices/new.html", |
|
|
|
|
clients=clients, |
|
|
|
|
services=services, |
|
|
|
|
errors=errors, |
|
|
|
|
form_data=form_data, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
cursor.execute("SELECT MAX(id) AS last_id FROM invoices") |
|
|
|
|
result = cursor.fetchone() |
|
|
|
|
|
|
|
|
|
number = (result["last_id"] or 0) + 1 |
|
|
|
|
invoice_number = f"INV-{number:04d}" |
|
|
|
|
|
|
|
|
|
insert = conn.cursor() |
|
|
|
|
|
|
|
|
|
insert.execute(""" |
|
|
|
|
INSERT INTO invoices |
|
|
|
|
( |
|
|
|
|
@ -115,9 +160,8 @@ def new_invoice():
|
|
|
|
|
status, |
|
|
|
|
notes |
|
|
|
|
) |
|
|
|
|
VALUES (%s,%s,%s,%s,%s,%s,NOW(),%s,'pending',%s) |
|
|
|
|
""", |
|
|
|
|
( |
|
|
|
|
VALUES (%s, %s, %s, %s, %s, %s, NOW(), %s, 'pending', %s) |
|
|
|
|
""", ( |
|
|
|
|
client_id, |
|
|
|
|
service_id, |
|
|
|
|
invoice_number, |
|
|
|
|
@ -149,8 +193,13 @@ def new_invoice():
|
|
|
|
|
|
|
|
|
|
conn.close() |
|
|
|
|
|
|
|
|
|
return render_template("invoices/new.html", clients=clients, services=services) |
|
|
|
|
|
|
|
|
|
return render_template( |
|
|
|
|
"invoices/new.html", |
|
|
|
|
clients=clients, |
|
|
|
|
services=services, |
|
|
|
|
errors=[], |
|
|
|
|
form_data={}, |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
|
app.run(host="0.0.0.0", port=5050) |
|
|
|
|
|