feat: clinic approval flow

This commit is contained in:
2025-05-19 19:03:58 +05:30
parent 205e423b56
commit a00c3884c4
18 changed files with 396 additions and 52 deletions
+137 -18
View File
@@ -1,51 +1,145 @@
from database import get_db
from sqlalchemy.orm import Session
from sqlalchemy.orm import Session, joinedload
from models import Clinics
from schemas.UpdateSchemas import ClinicUpdate
from schemas.UpdateSchemas import ClinicStatusUpdate, ClinicUpdate
from schemas.ResponseSchemas import Clinic
from typing import List
from typing import List, Literal, Union
from exceptions import ResourceNotFoundException
from enums.enums import ClinicStatus
from enums.enums import ClinicStatus, UserType
from exceptions.unauthorized_exception import UnauthorizedException
from interface.common_response import CommonResponse
from sqlalchemy import or_,func, case
from services.s3Service import get_signed_url
from models import ClinicFileVerifications
from schemas.BaseSchemas import ClinicFileVerificationBase
class ClinicServices:
def __init__(self):
self.db: Session = next(get_db())
def get_clinics(self, limit:int, offset:int) -> List[Clinic]:
clinics = self.db.query(Clinics).limit(limit).offset(offset).all()
def get_clinics(self, user, limit:int, offset:int, filter_type: Union[Literal["UNREGISTERED"], Literal["REGISTERED"]] = "UNREGISTERED", search:str = ""):
if user["userType"] != UserType.SUPER_ADMIN:
raise UnauthorizedException("You are not authorized to get clinics")
clinics_query = self.db.query(Clinics)
if filter_type == "UNREGISTERED":
clinics_query = clinics_query.filter(Clinics.status != ClinicStatus.ACTIVE)
elif filter_type == "REGISTERED":
clinics_query = clinics_query.filter(Clinics.status == ClinicStatus.ACTIVE)
if search:
clinics_query = clinics_query.filter(
or_(
Clinics.name.contains(search),
Clinics.email.contains(search),
Clinics.phone.contains(search),
Clinics.address.contains(search)
)
)
clinics = clinics_query.limit(limit).offset(offset).all()
# Get all counts in a single optimized query
from sqlalchemy import text
count_query = text("""
SELECT
COUNT(*) as total,
COUNT(CASE WHEN status = 'ACTIVE' THEN 1 END) as active,
COUNT(CASE WHEN status = 'REJECTED' THEN 1 END) as rejected
FROM clinics
""")
result = self.db.execute(count_query).first()
totalClinics = result.total or 0
totalRegisteredClinics = result.active or 0
totalRejectedClinics = result.rejected or 0
clinic_response = [Clinic(**clinic.__dict__.copy()) for clinic in clinics]
return clinic_response
for clinic in clinic_response:
clinic.logo = get_signed_url(clinic.logo) if clinic.logo else None
clinic_response_with_total = {
"clinics": clinic_response,
"totalRegisteredClinics": totalRegisteredClinics,
"totalRejectedClinics": totalRejectedClinics,
}
response = CommonResponse(data=clinic_response_with_total, total=totalClinics)
return response
def get_latest_clinic_id(self) -> int:
clinic = self.db.query(Clinics).order_by(Clinics.id.desc()).first()
return clinic.id if clinic else 0
def get_clinic_by_id(self, clinic_id: int) -> Clinic:
def get_clinic_by_id(self, clinic_id: int):
try:
clinic = self.db.query(Clinics).options(joinedload(Clinics.creator)).filter(Clinics.id == clinic_id).first()
if clinic is None:
raise ResourceNotFoundException("Clinic not found")
clinic_response = Clinic(**clinic.__dict__.copy())
clinic_response.logo = get_signed_url(clinic_response.logo) if clinic_response.logo else None
clinic_response.abn_doc = get_signed_url(clinic_response.abn_doc) if clinic_response.abn_doc else None
clinic_response.contract_doc = get_signed_url(clinic_response.contract_doc) if clinic_response.contract_doc else None
clinic_resp = {
"clinic": clinic_response,
"creator": {
"name": clinic.creator.username,
"email": clinic.creator.email,
"phone": clinic.creator.mobile,
"designation": clinic.creator.clinicRole
},
"clinic_files": self.get_clinic_files(clinic_id)
}
return clinic_resp
except Exception as e:
raise Exception(e)
def get_clinic_files(self, clinic_id: int):
clinic_files = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
if clinic_files is None:
raise ResourceNotFoundException("Clinic not found")
response = ClinicFileVerificationBase(**clinic_files.__dict__.copy())
return response
def update_clinic(self, user, clinic_id: int, clinic_data: ClinicUpdate):
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
if clinic is None:
raise ResourceNotFoundException("Clinic not found")
clinic_response = Clinic(**clinic.__dict__.copy())
return clinic_response
def update_clinic(self, clinic_id: int, clinic_data: ClinicUpdate):
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
if clinic is None:
raise ResourceNotFoundException("Clinic not found")
if clinic.creator_id != user["id"]:
raise UnauthorizedException("You are not authorized to update this clinic")
update_data = clinic_data.model_dump(exclude_unset=True)
for key, value in update_data.items():
setattr(clinic, key, value)
self.db.add(clinic)
self.db.commit()
self.db.refresh(clinic)
return Clinic(**clinic.__dict__.copy())
clinic_response = Clinic(**clinic.__dict__.copy())
clinic_response.logo = get_signed_url(clinic_response.logo) if clinic_response.logo else None
return clinic_response
def delete_clinic(self, clinic_id: int):
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
@@ -94,4 +188,29 @@ class ClinicServices:
if key:
counts[key] = count
return counts
return counts
def update_clinic_status(self, user, clinic_id: int, status: ClinicStatus):
if user["userType"] != UserType.SUPER_ADMIN:
raise UnauthorizedException("You are not authorized to update clinic status")
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
if clinic is None:
raise ResourceNotFoundException("Clinic not found")
clinic.status = status
self.db.add(clinic)
self.db.commit()
self.db.refresh(clinic)
clinic_response = Clinic(**clinic.__dict__.copy())
# if rejected then email to clinic creator
if clinic.status == ClinicStatus.REJECTED:
pass
return clinic_response
+60 -3
View File
@@ -1,17 +1,74 @@
from database import get_db
from services.clinicDoctorsServices import ClinicDoctorsServices
from services.clinicServices import ClinicServices
from schemas.BaseSchemas import SignupPricingMasterBase
from schemas.ResponseSchemas import SignupPricingMasterResponse
from models.SignupPricingMaster import SignupPricingMaster
from exceptions import UnauthorizedException
from enums.enums import UserType
from exceptions import ResourceNotFoundException
class DashboardService:
def __init__(self):
self.db = next(get_db())
self.clinicDoctorsServices = ClinicDoctorsServices()
self.clinicServices = ClinicServices()
def get_dashboard_counts(self, isSuperAdmin:bool):
def get_dashboard_counts(self, isSuperAdmin: bool):
if isSuperAdmin:
clinicCounts = self.clinicServices.get_clinic_count()
return clinicCounts
else:
clinicDoctorsCount = self.clinicDoctorsServices.get_doctor_status_count()
return clinicDoctorsCount
return clinicDoctorsCount
def update_signup_pricing_master(
self, user, pricing_data: SignupPricingMasterBase
):
if user["userType"] != UserType.SUPER_ADMIN:
raise UnauthorizedException(
"You are not authorized to update signup pricing master"
)
existing_pricing = self.db.query(SignupPricingMaster).first()
if existing_pricing is None:
# Create new record
new_pricing = SignupPricingMaster(
**pricing_data.model_dump()
)
self.db.add(new_pricing)
self.db.commit()
self.db.refresh(new_pricing)
response = SignupPricingMasterResponse(
**new_pricing.__dict__.copy()
)
return response
else:
# Update existing record with values from the request
existing_pricing.setup_fees = pricing_data.setup_fees
existing_pricing.subscription_fees = pricing_data.subscription_fees
existing_pricing.per_call_charges = pricing_data.per_call_charges
self.db.commit()
self.db.refresh(existing_pricing)
response = SignupPricingMasterResponse(
**existing_pricing.__dict__.copy()
)
return response
def get_signup_pricing_master(self):
signup_pricing_master = self.db.query(SignupPricingMaster).first()
if signup_pricing_master is None:
raise ResourceNotFoundException("Signup pricing master not found")
response = SignupPricingMasterResponse(
**signup_pricing_master.__dict__.copy()
)
return response
+15 -2
View File
@@ -11,10 +11,12 @@ from schemas.UpdateSchemas import UserUpdate
from exceptions.unauthorized_exception import UnauthorizedException
from interface.common_response import CommonResponse
from exceptions.business_exception import BusinessValidationException
from models import ClinicFileVerifications
from utils.password_utils import hash_password
from schemas.CreateSchemas import UserCreate
from exceptions.resource_not_found_exception import ResourceNotFoundException
from exceptions.db_exceptions import DBExceptionHandler
from sqlalchemy.orm import joinedload
class UserServices:
@@ -98,7 +100,19 @@ class UserServices:
# Add clinic to database
self.db.add(new_clinic)
self.db.flush()
# Create clinic files
clinic_files = ClinicFileVerifications(
clinic_id=new_clinic.id,
abn_doc_is_verified=False,
contract_doc_is_verified=False,
last_changed_by=new_user.id
)
# Add clinic files to database
self.db.add(clinic_files)
# Now commit both user and clinic in a single transaction
self.db.commit()
@@ -114,7 +128,6 @@ class UserServices:
def get_user(self, user_id) -> UserResponse:
try:
# Query the user by ID and explicitly load the created clinics relationship
from sqlalchemy.orm import joinedload
user = self.db.query(Users).options(joinedload(Users.created_clinics)).filter(Users.id == user_id).first()
if not user: