MukeshKapoor25 commited on
Commit
830a2d0
·
1 Parent(s): ab2d06d

appointments

Browse files
.env ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ MONGO_URI=mongodb+srv://appliedcommerce:xaqtoj-gikdaw-6giQdy@cluster0.qpc5d.mongodb.net/test??ssl=true&ssl_cert_reqs=CERT_NONE
2
+
3
+ CACHE_URI=redis-13158.c212.ap-south-1-1.ec2.redns.redis-cloud.com:13158
4
+
5
+ CACHE_K=Mi5bLjJHt5KFlGjnx04K269Dt2w7hdup
app/app.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI
2
+ from app.sql import connect_to_database, disconnect_from_database
3
+ from app.views.appointment_view import router as appointment_router
4
+
5
+ app = FastAPI(title="Bookings / Appointment Management")
6
+
7
+ @app.on_event("startup")
8
+ async def startup():
9
+ await connect_to_database()
10
+
11
+ @app.on_event("shutdown")
12
+ async def shutdown():
13
+ await disconnect_from_database()
14
+
15
+ app.include_router(appointment_router)
app/controllers/appointment_controller.py ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from app.services.appointment_service import create_new_appointment, reschedule_appointment
3
+ from app.models.appointment_model import Appointment
4
+
5
+ router = APIRouter()
6
+
7
+ @router.post("/appointments/")
8
+ async def create_appointment(appointment: Appointment):
9
+ return await create_new_appointment(appointment)
10
+
11
+ @router.put("/appointments/reschedule/{appointment_id}")
12
+ async def reschedule(appointment_id: str, new_date: str, new_time: str):
13
+ return await reschedule_appointment(appointment_id, new_date, new_time)
app/models/appointment_model.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pydantic import BaseModel, Field
2
+ from datetime import date, time, datetime
3
+ from typing import List
4
+ from enum import Enum
5
+ import sqlalchemy
6
+ from app.database import metadata
7
+
8
+ class AppointmentStatus(str, Enum):
9
+ confirmed = "confirmed"
10
+ rescheduled = "rescheduled"
11
+ canceled = "canceled"
12
+
13
+ class Service(BaseModel):
14
+ description: str
15
+ duration: int
16
+ price: float
17
+
18
+ class Appointment(BaseModel):
19
+ appointment_id: str
20
+ merchant_id: str
21
+ customer_id: str
22
+ appointment_date: date
23
+ appointment_time: time
24
+ status: AppointmentStatus
25
+ services: List[Service]
26
+ created_at: datetime = Field(default_factory=datetime.utcnow)
27
+ modified_at: datetime = Field(default_factory=datetime.utcnow)
28
+
29
+ appointment_table = sqlalchemy.Table(
30
+ "appointments",
31
+ metadata,
32
+ sqlalchemy.Column("appointment_id", sqlalchemy.String, primary_key=True),
33
+ sqlalchemy.Column("merchant_id", sqlalchemy.String),
34
+ sqlalchemy.Column("customer_id", sqlalchemy.String),
35
+ sqlalchemy.Column("appointment_date", sqlalchemy.Date, nullable=False),
36
+ sqlalchemy.Column("appointment_time", sqlalchemy.Time, nullable=False),
37
+ sqlalchemy.Column("status", sqlalchemy.String(20)),
38
+ sqlalchemy.Column("services", sqlalchemy.JSON),
39
+ sqlalchemy.Column("created_at", sqlalchemy.DateTime(timezone=True), default=datetime.utcnow),
40
+ sqlalchemy.Column("modified_at", sqlalchemy.DateTime(timezone=True), default=datetime.utcnow, onupdate=datetime.utcnow),
41
+ )
app/repositories/appointment_repository.py ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from app.models.appointment_model import appointment_table
2
+ from app.database import database
3
+
4
+ async def create_appointment(appointment_data: dict):
5
+ query = appointment_table.insert().values(**appointment_data)
6
+ return await database.execute(query)
7
+
8
+ async def update_appointment(appointment_id: str, update_data: dict):
9
+ query = (
10
+ appointment_table.update()
11
+ .where(appointment_table.c.appointment_id == appointment_id)
12
+ .values(**update_data)
13
+ )
14
+ return await database.execute(query)
15
+
16
+ async def get_appointment_by_id(appointment_id: str):
17
+ query = appointment_table.select().where(appointment_table.c.appointment_id == appointment_id)
18
+ return await database.fetch_one(query)
19
+
20
+ async def get_appointments_by_customer(customer_id: str):
21
+ query = appointment_table.select().where(appointment_table.c.customer_id == customer_id)
22
+ return await database.fetch_all(query)
23
+
24
+ async def get_appointments_by_merchant(merchant_id: str):
25
+ query = appointment_table.select().where(appointment_table.c.merchant_id == merchant_id)
26
+ return await database.fetch_all(query)
app/services/appointment_service.py ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from datetime import datetime, timezone
2
+ from fastapi import HTTPException
3
+ from app.repositories.appointment_repository import (
4
+ create_appointment,
5
+ update_appointment,
6
+ get_appointment_by_id,
7
+ )
8
+ from app.models.appointment_model import Appointment, AppointmentStatus
9
+
10
+ async def create_new_appointment(appointment: Appointment):
11
+ now = datetime.now(timezone.utc)
12
+ appointment_data = appointment.dict()
13
+ appointment_data["status"] = AppointmentStatus.confirmed
14
+ appointment_data["created_at"] = now
15
+ appointment_data["modified_at"] = now
16
+ await create_appointment(appointment_data)
17
+ return {"message": "Appointment created successfully"}
18
+
19
+ async def reschedule_appointment(appointment_id: str, new_date: datetime, new_time: datetime):
20
+ existing_appointment = await get_appointment_by_id(appointment_id)
21
+ if not existing_appointment:
22
+ raise HTTPException(status_code=404, detail="Appointment not found")
23
+
24
+ if existing_appointment["status"] == AppointmentStatus.canceled:
25
+ raise HTTPException(status_code=400, detail="Cannot reschedule a canceled appointment")
26
+
27
+ update_data = {
28
+ "appointment_date": new_date.date(),
29
+ "appointment_time": new_time.time(),
30
+ "status": AppointmentStatus.rescheduled,
31
+ "modified_at": datetime.now(timezone.utc),
32
+ }
33
+ await update_appointment(appointment_id, update_data)
34
+ return {"message": "Appointment rescheduled successfully"}
app/sql.py ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import logging
3
+ from dotenv import load_dotenv
4
+ import databases
5
+ import sqlalchemy
6
+
7
+ # Load environment variables from .env file
8
+ load_dotenv()
9
+
10
+ # Configure logging
11
+ logging.basicConfig(
12
+ level=logging.INFO,
13
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
14
+ )
15
+ logger = logging.getLogger(__name__)
16
+
17
+ # Load the DATABASE_URL from environment variables
18
+ DATABASE_URL = os.getenv("DATABASE_URI")
19
+
20
+ if not DATABASE_URL:
21
+ logger.error("DATABASE_URI not found in environment variables.")
22
+ raise ValueError("DATABASE_URI not found in environment variables. Ensure it is set in the .env file.")
23
+
24
+ # Initialize the database connection and metadata
25
+ try:
26
+ database = databases.Database(DATABASE_URL)
27
+ metadata = sqlalchemy.MetaData()
28
+ logger.info("Database connection initialized successfully.")
29
+ except Exception as e:
30
+ logger.error("Failed to initialize database connection: %s", e)
31
+ raise
32
+
33
+ # Helper function to initialize database
34
+ async def connect_to_database():
35
+ """
36
+ Connects to the database when the application starts.
37
+ """
38
+ try:
39
+ await database.connect()
40
+ logger.info("Successfully connected to the database.")
41
+ except Exception as e:
42
+ logger.error("Error connecting to the database: %s", e)
43
+ raise
44
+
45
+ # Helper function to disconnect database
46
+ async def disconnect_from_database():
47
+ """
48
+ Disconnects from the database when the application shuts down.
49
+ """
50
+ try:
51
+ await database.disconnect()
52
+ logger.info("Successfully disconnected from the database.")
53
+ except Exception as e:
54
+ logger.error("Error disconnecting from the database: %s", e)
55
+ raise
app/views/appointment_view.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ from fastapi import APIRouter
2
+ from app.controllers.appointment_controller import router as appointment_controller
3
+
4
+ router = APIRouter()
5
+ router.include_router(appointment_controller, prefix="/appointments", tags=["Appointments"])