Skip to content

Commit

Permalink
feat: code refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
kamajus committed Jan 11, 2025
1 parent 9e84388 commit fb683db
Show file tree
Hide file tree
Showing 16 changed files with 421 additions and 938 deletions.
13 changes: 0 additions & 13 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,14 +1 @@
API_KEY=your_api_key_here

FIREBASE_API_KEY=your_firebase_api_key_here
FIREBASE_DATABASE_URL=your_firebase_database_url_here
FIREBASE_APP_ID=your_firebase_app_id_here
FIREBASE_AUTH_DOMAIN=your_firebase_auth_domain_here
FIREBASE_CLIENT_EMAIL=your_firebase_client_email_here
FIREBASE_CLIENT_ID=your_firebase_client_id_here
FIREBASE_CLIENT_X509_CERT_URL=your_firebase_client_x509_cert_url_here
FIREBASE_MESSAGING_SENDER_ID=your_firebase_messaging_sender_id_here
FIREBASE_PRIVATE_KEY=your_firebase_private_key_here
FIREBASE_PRIVATE_KEY_ID=your_firebase_private_key_id_here
FIREBASE_PROJECT_ID=your_firebase_project_id_here
FIREBASE_STORAGE_BUCKET=your_firebase_storage_bucket_here
15 changes: 3 additions & 12 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,10 @@ jobs:
- name: Install Dependencies
run: poetry install

- name: Populate database with fake data
run: poetry run task seed

- name: Execute Tests
run: poetry run pytest
env:
API_KEY: ${{ secrets.API_KEY }}
FIREBASE_API_KEY: ${{ secrets.FIREBASE_API_KEY }}
FIREBASE_DATABASE_URL: ${{ secrets.FIREBASE_DATABASE_URL }}
FIREBASE_APP_ID: ${{ secrets.FIREBASE_APP_ID }}
FIREBASE_AUTH_DOMAIN: ${{ secrets.FIREBASE_AUTH_DOMAIN }}
FIREBASE_CLIENT_EMAIL: ${{ secrets.FIREBASE_CLIENT_EMAIL }}
FIREBASE_CLIENT_ID: ${{ secrets.FIREBASE_CLIENT_ID }}
FIREBASE_CLIENT_X509_CERT_URL: ${{ secrets.FIREBASE_CLIENT_X509_CERT_URL }}
FIREBASE_MESSAGING_SENDER_ID: ${{ secrets.FIREBASE_MESSAGING_SENDER_ID }}
FIREBASE_PRIVATE_KEY: ${{ secrets.FIREBASE_PRIVATE_KEY }}
FIREBASE_PRIVATE_KEY_ID: ${{ secrets.FIREBASE_PRIVATE_KEY_ID }}
FIREBASE_PROJECT_ID: ${{ secrets.FIREBASE_PROJECT_ID }}
FIREBASE_STORAGE_BUCKET: ${{ secrets.FIREBASE_STORAGE_BUCKET }}
40 changes: 0 additions & 40 deletions api/config/firebase.py

This file was deleted.

Empty file added api/database/__init__.py
Empty file.
45 changes: 45 additions & 0 deletions api/database/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import sqlite3

# Path to the schema file
SCHEMA_FILE = "./api/database/schema.sql"

# Path to the SQLite database file (it will be created if it doesn't exist)
DATABASE_PATH = "./api/database/database.db"


def execute(query, params=(), fetchall=False):
conn = sqlite3.connect(DATABASE_PATH)
conn.row_factory = sqlite3.Row # Enables row access by column name
cursor = conn.cursor()

if not fetchall:
data = cursor.execute(query, params).fetchone()
else:
data = cursor.execute(query, params).fetchall()

conn.commit()
conn.close()

return data


def connect():
try:
# Connect to SQLite database
conn = sqlite3.connect(DATABASE_PATH)
cursor = conn.cursor()
print("Connected to the database successfully!")

# Read the schema.sql file
with open(SCHEMA_FILE, "r") as file:
schema_sql = file.read()
# Execute the schema SQL script
cursor.executescript(schema_sql)
print("Schema executed successfully!")

# Commit changes and close the connection
conn.commit()
conn.close()
print("Database connection closed.")
except Exception as e:
print(f"An error occurred: {e}")
Binary file added api/database/database.db
Binary file not shown.
36 changes: 36 additions & 0 deletions api/database/schema.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
-- Table to store client information
CREATE TABLE IF NOT EXISTS Client (
client_id INTEGER PRIMARY KEY,
name VARCHAR(255) NOT NULL,
phone VARCHAR(20),
address VARCHAR(255)
);

-- Table to store invoice information
CREATE TABLE IF NOT EXISTS Invoice (
invoice_id INTEGER PRIMARY KEY,
client_id INTEGER NOT NULL,
reference VARCHAR(50) NOT NULL,
created_at DATE NOT NULL,
total_price DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (client_id) REFERENCES Client(client_id)
);

-- Table to store product information
CREATE TABLE IF NOT EXISTS Product (
product_id INTEGER PRIMARY KEY,
name VARCHAR(255) NOT NULL,
unit_price DECIMAL(10, 2) NOT NULL
);

-- Table to link products and invoices
CREATE TABLE IF NOT EXISTS InvoiceProduct (
invoice_product_id INTEGER PRIMARY KEY,
invoice_id INTEGER NOT NULL,
product_id INTEGER NOT NULL,
quantity INTEGER NOT NULL,
total_price DECIMAL(10, 2) NOT NULL,
FOREIGN KEY (invoice_id) REFERENCES Invoice(invoice_id),
FOREIGN KEY (product_id) REFERENCES Product(product_id)
);

74 changes: 74 additions & 0 deletions api/database/seed.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import os
import sqlite3
from datetime import datetime

from config import DATABASE_PATH, connect, execute


def seed_database():
try:
# Insert data into the Client table
execute(
"""
INSERT INTO Client (client_id, name, phone, address)
VALUES
(1, 'John Smith', '+33 xx3 x21 63x', 'ABC Street'),
(2, 'Davison Star', '+33 7xx 93x x05', 'DEF Street');
"""
)

# Insert data into the Product table
execute(
"""
INSERT INTO Product (product_id, name, unit_price)
VALUES
(1, 'Product A', 2500.00),
(2, 'Product B', 1500.00),
(3, 'Product C', 3500.00);
"""
)

# Insert data into the Invoice table with formatted dates
execute(
"""
INSERT INTO Invoice (invoice_id, client_id, reference, created_at, total_price)
VALUES
(1, 1, 'INV001', ?, 5000.00),
(2, 2, 'INV002', ?, 3500.00);
""",
(
datetime(2025, 1, 11, 10, 0, 0, 123456).strftime(
"%Y-%m-%dT%H:%M:%S.%fZ"
),
datetime(2025, 1, 12, 15, 30, 0, 654321).strftime(
"%Y-%m-%dT%H:%M:%S.%fZ"
),
),
)

# Insert data into the InvoiceProduct table (relating products to invoices)
execute(
"""
INSERT INTO InvoiceProduct (invoice_product_id, invoice_id, product_id, quantity, total_price)
VALUES
(1, 1, 1, 1, 2500.00),
(2, 1, 2, 1, 1500.00),
(3, 2, 2, 1, 1500.00),
(4, 2, 3, 1, 3500.00);
"""
)

print("Database seeded successfully!")

except sqlite3.Error as e:
print(f"Error occurred while seeding database: {e}")


# Run the seed function
if __name__ == "__main__":
# Delete db if exists
if os.path.exists(DATABASE_PATH):
os.remove(DATABASE_PATH)

connect()
seed_database()
128 changes: 83 additions & 45 deletions api/main.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,29 @@
from dotenv import load_dotenv

load_dotenv()
import datetime

import api.config.firebase
from fastapi import FastAPI, Security, HTTPException
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Security
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from firebase_admin import db
from api.utils.secure import get_api_key
from fastapi.templating import Jinja2Templates

from api.database.config import connect, execute
from api.settings import OUTPUT_FILENAME, TEMPLATE_CSS, TEMPLATE_HTML_PATH
from api.utils.invoice import render_template
from api.settings import *
from api.utils.secure import get_api_key

from fastapi.templating import Jinja2Templates
from fastapi.middleware.cors import CORSMiddleware
import datetime
# Load environment variables
load_dotenv()

# Database intialization
connect()

# CORS settings
origins = [
"https://cuddly-meme-jww47799jrj2q6v7-3000.app.github.dev",
"https://raciuscare.com",
"https://raciuscare.vercel.app",
"http://localhost",
"http://localhost:8080",
"http://localhost:3000",
]


app = FastAPI()
app.add_middleware(
CORSMiddleware,
Expand All @@ -36,45 +36,83 @@
templates = Jinja2Templates(directory="/tmp/")



@app.get("/invoice/{order_id}")
async def invoice(order_id: str, _=Security(get_api_key)):
ref = db.reference(f"/orders/{order_id}")
order = ref.get()
try:
# Query the Invoice table for the specific order_id
order = dict(execute("SELECT * FROM Invoice WHERE invoice_id = ?", (order_id,)))

if order == None:
raise HTTPException(
status_code=404, detail="O pedido pretendido não foi encontrado"
)
if order is None:
raise HTTPException(status_code=404, detail="Invoice not found")

context_data = ref.get()
context_data["order_id"] = order_id

data_string = context_data["createdAt"]
format = "%Y-%m-%dT%H:%M:%S.%fZ"
client = dict(
execute("SELECT * FROM Client WHERE client_id = ?", (order["client_id"],))
)

tt = datetime.datetime.strptime(data_string, format)
formatted_time = tt.strftime("%Y-%m-%d %H:%M")
invoice_products = execute(
"SELECT * from InvoiceProduct WHERE invoice_id = ?",
(order["invoice_id"],),
fetchall=True,
)

context_data["createdAt"] = formatted_time
template_html: str
products = []

for product in list(invoice_products):
product = dict(product)

product_data = dict(
execute(
"SELECT * FROM Product WHERE product_id = ?",
(product["product_id"],),
)
)

products.append(
{
"name": product_data["name"],
"unit_price": product_data["unit_price"],
"quantity": product["quantity"],
"total_price": product["total_price"],
}
)

tt = datetime.datetime.strptime(order["created_at"], "%Y-%m-%dT%H:%M:%S.%fZ")
order["created_at"] = tt.strftime("%Y-%m-%d %H:%M")

# Prepare template context data
context_data = {
"name": client["name"],
"phone": client["phone"],
"address": client["address"],
"reference": order["reference"],
"created_at": order["created_at"],
"products": products,
"total_price": order["total_price"],
}

# Read the HTML template
with open(TEMPLATE_HTML_PATH) as template:
template_html = template.read()

# Render the template
template_url = render_template(
template_html, context_data, TEMPLATE_CSS, OUTPUT_FILENAME
)

with open(TEMPLATE_HTML_PATH) as template:
template_html = template.read()
template_url = render_template(
template_html, context_data, TEMPLATE_CSS, OUTPUT_FILENAME
)
# Create the PDF response
response = FileResponse(
template_url,
media_type="application/pdf",
headers={"Content-Disposition": f"inline; filename={OUTPUT_FILENAME}"},
)
return response

response = FileResponse(
template_url,
media_type="application/pdf",
headers={
"Content-Disposition": f"inline; filename=${template_url.replace('/tmp', '')}"
},
)
return response
except Exception as e:
# Log the error and raise an HTTPException
print(f"Error fetching invoice: {e}")
raise HTTPException(status_code=500, detail="Internal Server Error")


@app.get("/")
def root(_=Security(get_api_key)):
return {"message": "Welcome to the RACIUS CARE INVOICE API!"}
return {"message": "Welcome back!"}
Loading

0 comments on commit fb683db

Please sign in to comment.