parent
1a0109bebd
commit
532e0a3288
|
|
@ -26,6 +26,12 @@ stripe_service = StripeServices()
|
||||||
# )
|
# )
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("/get-invoice", dependencies=[Depends(auth_required)])
|
||||||
|
async def get_invoice(req:Request):
|
||||||
|
invoice_url = await stripe_service.get_invoice(req.state.user)
|
||||||
|
return ApiResponse(data=invoice_url, message="Invoice URL retrieved successfully")
|
||||||
|
|
||||||
|
|
||||||
@router.post("/create-payment-session", dependencies=[Depends(auth_required)])
|
@router.post("/create-payment-session", dependencies=[Depends(auth_required)])
|
||||||
async def create_payment_session(req:Request):
|
async def create_payment_session(req:Request):
|
||||||
session = await stripe_service.create_payment_session(req.state.user)
|
session = await stripe_service.create_payment_session(req.state.user)
|
||||||
|
|
@ -33,4 +39,5 @@ async def create_payment_session(req:Request):
|
||||||
|
|
||||||
@router.post("/webhook")
|
@router.post("/webhook")
|
||||||
async def stripe_webhook(request: Request):
|
async def stripe_webhook(request: Request):
|
||||||
return await stripe_service.handle_webhook(request)
|
await stripe_service.handle_webhook(request)
|
||||||
|
return "OK"
|
||||||
|
|
@ -19,6 +19,7 @@ class ClinicStatus(Enum):
|
||||||
REQUESTED_DOC = "requested_doc"
|
REQUESTED_DOC = "requested_doc"
|
||||||
REJECTED = "rejected"
|
REJECTED = "rejected"
|
||||||
PAYMENT_DUE = "payment_due"
|
PAYMENT_DUE = "payment_due"
|
||||||
|
SUBSCRIPTION_ENDED = "subscription_ended"
|
||||||
|
|
||||||
class ClinicUserRoles(Enum):
|
class ClinicUserRoles(Enum):
|
||||||
DIRECTOR = "director"
|
DIRECTOR = "director"
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
"""updated_enums_clinic_status
|
||||||
|
|
||||||
|
Revision ID: 5ed8ac3d258c
|
||||||
|
Revises: a19fede0cdc6
|
||||||
|
Create Date: 2025-06-02 11:11:56.589321
|
||||||
|
|
||||||
|
"""
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = '5ed8ac3d258c'
|
||||||
|
down_revision: Union[str, None] = 'a19fede0cdc6'
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
"""Upgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
# Add new status to clinicstatus enum
|
||||||
|
op.execute("ALTER TYPE clinicstatus ADD VALUE IF NOT EXISTS 'SUBSCRIPTION_ENDED' AFTER 'PAYMENT_DUE'")
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
"""Downgrade schema."""
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
# Note: In PostgreSQL, you cannot directly remove an enum value.
|
||||||
|
# You would need to create a new enum type, update the column to use the new type,
|
||||||
|
# and then drop the old type. This is a complex operation and might not be needed.
|
||||||
|
# The upgrade will be reverted when applying previous migrations.
|
||||||
|
pass
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
from sqlalchemy import Column, Integer, String
|
||||||
|
from database import Base
|
||||||
|
from .CustomBase import CustomBase
|
||||||
|
|
||||||
|
class Subscriptions(Base, CustomBase):
|
||||||
|
__tablename__ = "subscriptions"
|
||||||
|
id = Column(Integer, primary_key=True, index=True)
|
||||||
|
session_id = Column(String(255), index=True)
|
||||||
|
customer_id = Column(String,index=True)
|
||||||
|
account_id = Column(String,index=True)
|
||||||
|
subscription_id = Column(String,index=True)
|
||||||
|
clinic_id = Column(Integer, index=True)
|
||||||
|
status = Column(String)
|
||||||
|
current_period_start = Column(String) # unix timestamp
|
||||||
|
current_period_end = Column(String) # unix timestamp
|
||||||
|
metadata_logs = Column(String)
|
||||||
|
|
@ -19,6 +19,7 @@ from .ClinicOffers import ClinicOffers
|
||||||
from .StripeUsers import StripeUsers
|
from .StripeUsers import StripeUsers
|
||||||
from .PaymentLogs import PaymentLogs
|
from .PaymentLogs import PaymentLogs
|
||||||
from .PaymentSessions import PaymentSessions
|
from .PaymentSessions import PaymentSessions
|
||||||
|
from .Subscriptions import Subscriptions
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"Users",
|
"Users",
|
||||||
|
|
@ -41,5 +42,6 @@ __all__ = [
|
||||||
"ClinicOffers",
|
"ClinicOffers",
|
||||||
"StripeUsers",
|
"StripeUsers",
|
||||||
"PaymentLogs",
|
"PaymentLogs",
|
||||||
"PaymentSessions"
|
"PaymentSessions",
|
||||||
|
"Subscriptions"
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,36 @@ class AuthService:
|
||||||
return token
|
return token
|
||||||
|
|
||||||
async def register(self, user_data: UserCreate, background_tasks=None):
|
async def register(self, user_data: UserCreate, background_tasks=None):
|
||||||
response = await self.user_service.create_user(user_data, background_tasks)
|
try:
|
||||||
|
resp = await self.user_service.create_user(user_data, background_tasks)
|
||||||
|
|
||||||
|
# Get the SQLAlchemy model instance
|
||||||
|
user_obj = resp["user"]
|
||||||
|
|
||||||
|
# create token with user data
|
||||||
|
user_data = {
|
||||||
|
"id": user_obj["id"],
|
||||||
|
"username": user_obj["username"],
|
||||||
|
"email": user_obj["email"],
|
||||||
|
"clinicRole": user_obj["clinicRole"],
|
||||||
|
"userType": user_obj["userType"],
|
||||||
|
"mobile": user_obj["mobile"],
|
||||||
|
"clinicId": user_obj["clinicId"]
|
||||||
|
}
|
||||||
|
token = create_jwt_token(user_data)
|
||||||
|
|
||||||
|
# Update response with token
|
||||||
|
resp["token"] = token
|
||||||
|
|
||||||
|
response = {
|
||||||
|
"url": resp.get("url"),
|
||||||
|
"token": token
|
||||||
|
}
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error registering user: {e}")
|
||||||
|
raise e
|
||||||
|
|
||||||
def blockEmailSNS(self, body: str):
|
def blockEmailSNS(self, body: str):
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -52,8 +52,8 @@ class ClinicServices:
|
||||||
count_query = text("""
|
count_query = text("""
|
||||||
SELECT
|
SELECT
|
||||||
COUNT(*) as total,
|
COUNT(*) as total,
|
||||||
COUNT(CASE WHEN status = 'ACTIVE' OR status = 'INACTIVE' THEN 1 END) as active,
|
COUNT(CASE WHEN status = 'ACTIVE' OR status = 'INACTIVE' OR 'SUBSCRIPTION_ENDED' THEN 1 END) as active,
|
||||||
COUNT(CASE WHEN status != 'ACTIVE' AND status != 'INACTIVE' THEN 1 END) as rejected
|
COUNT(CASE WHEN status != 'ACTIVE' AND status != 'INACTIVE' AND status != 'SUBSCRIPTION_ENDED' THEN 1 END) as rejected
|
||||||
FROM clinics
|
FROM clinics
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
@ -127,6 +127,8 @@ class ClinicServices:
|
||||||
finally:
|
finally:
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async def get_clinic_files(self, clinic_id: int):
|
async def get_clinic_files(self, clinic_id: int):
|
||||||
try:
|
try:
|
||||||
clinic_files = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
clinic_files = self.db.query(ClinicFileVerifications).filter(ClinicFileVerifications.clinic_id == clinic_id).first()
|
||||||
|
|
@ -166,7 +168,18 @@ class ClinicServices:
|
||||||
self.db.refresh(clinic)
|
self.db.refresh(clinic)
|
||||||
|
|
||||||
clinic_response = 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
|
|
||||||
|
# update clinic files
|
||||||
|
clinic_files = await self.get_clinic_files(clinic_id)
|
||||||
|
|
||||||
|
if clinic_data.abn_doc:
|
||||||
|
clinic_files.abn_doc_is_verified = None
|
||||||
|
if clinic_data.contract_doc:
|
||||||
|
clinic_files.contract_doc_is_verified = None
|
||||||
|
|
||||||
|
self.db.add(clinic_files)
|
||||||
|
self.db.commit()
|
||||||
|
self.db.refresh(clinic_files)
|
||||||
|
|
||||||
return clinic_response
|
return clinic_response
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
@ -202,7 +215,8 @@ class ClinicServices:
|
||||||
ClinicStatus.INACTIVE,
|
ClinicStatus.INACTIVE,
|
||||||
ClinicStatus.UNDER_REVIEW,
|
ClinicStatus.UNDER_REVIEW,
|
||||||
ClinicStatus.REJECTED,
|
ClinicStatus.REJECTED,
|
||||||
ClinicStatus.PAYMENT_DUE
|
ClinicStatus.PAYMENT_DUE,
|
||||||
|
ClinicStatus.SUBSCRIPTION_ENDED
|
||||||
])
|
])
|
||||||
).group_by(Clinics.status).all()
|
).group_by(Clinics.status).all()
|
||||||
|
|
||||||
|
|
@ -212,7 +226,7 @@ class ClinicServices:
|
||||||
"totalActiveClinics": 0,
|
"totalActiveClinics": 0,
|
||||||
"totalUnderReviewClinics": 0,
|
"totalUnderReviewClinics": 0,
|
||||||
"totalRejectedClinics": 0,
|
"totalRejectedClinics": 0,
|
||||||
"totalPaymentDueClinics": 0
|
"totalPaymentDueClinics": 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Map status values to their respective count keys
|
# Map status values to their respective count keys
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ from services.dashboardService import DashboardService
|
||||||
from exceptions.validation_exception import ValidationException
|
from exceptions.validation_exception import ValidationException
|
||||||
from exceptions.resource_not_found_exception import ResourceNotFoundException
|
from exceptions.resource_not_found_exception import ResourceNotFoundException
|
||||||
from exceptions.unauthorized_exception import UnauthorizedException
|
from exceptions.unauthorized_exception import UnauthorizedException
|
||||||
from models import Clinics,PaymentSessions
|
from models import Clinics,PaymentSessions, Subscriptions
|
||||||
import uuid
|
import uuid
|
||||||
from fastapi import Request
|
from fastapi import Request
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
@ -75,6 +75,42 @@ class StripeServices:
|
||||||
self.logger.error(f"Error deleting account: {e}")
|
self.logger.error(f"Error deleting account: {e}")
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
async def get_invoice(self, user):
|
||||||
|
try:
|
||||||
|
|
||||||
|
if user["userType"] != UserType.CLINIC_ADMIN:
|
||||||
|
raise UnauthorizedException("User is not authorized to perform this action")
|
||||||
|
|
||||||
|
clinic = self.db.query(Clinics).filter(Clinics.creator_id == user["id"]).first()
|
||||||
|
|
||||||
|
if not clinic:
|
||||||
|
raise ResourceNotFoundException("Clinic not found!")
|
||||||
|
|
||||||
|
customer = self.db.query(StripeUsers).filter(StripeUsers.user_id == user["id"]).first()
|
||||||
|
|
||||||
|
if not customer:
|
||||||
|
raise ResourceNotFoundException("Customer not found!")
|
||||||
|
|
||||||
|
subscription = self.db.query(Subscriptions).filter(Subscriptions.clinic_id == clinic.id, Subscriptions.customer_id == customer.customer_id, Subscriptions.status == "active").first()
|
||||||
|
|
||||||
|
if not subscription:
|
||||||
|
raise ResourceNotFoundException("Subscription not found!")
|
||||||
|
|
||||||
|
stripe_subscription = stripe.Subscription.retrieve(subscription.subscription_id)
|
||||||
|
|
||||||
|
invoice = stripe.Invoice.retrieve(
|
||||||
|
stripe_subscription["latest_invoice"]
|
||||||
|
)
|
||||||
|
return invoice.hosted_invoice_url
|
||||||
|
except stripe.error.StripeError as e:
|
||||||
|
self.logger.error(f"Error getting invoice: {e}")
|
||||||
|
raise
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error getting invoice: {e}")
|
||||||
|
raise
|
||||||
|
finally:
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
async def create_payment_session(self, user):
|
async def create_payment_session(self, user):
|
||||||
try:
|
try:
|
||||||
if user["userType"] != UserType.CLINIC_ADMIN:
|
if user["userType"] != UserType.CLINIC_ADMIN:
|
||||||
|
|
@ -106,9 +142,6 @@ class StripeServices:
|
||||||
fees_to_be["per_call_charges"] = clinic_offers.per_call_charges
|
fees_to_be["per_call_charges"] = clinic_offers.per_call_charges
|
||||||
fees_to_be["total"] = clinic_offers.setup_fees + fees_to_be["subscription_fees"] + clinic_offers.per_call_charges
|
fees_to_be["total"] = clinic_offers.setup_fees + fees_to_be["subscription_fees"] + clinic_offers.per_call_charges
|
||||||
|
|
||||||
# remove previouis payment session
|
|
||||||
self.db.query(PaymentSessions).filter(PaymentSessions.clinic_id == clinic["id"]).delete()
|
|
||||||
|
|
||||||
payment_link = await self.create_subscription_checkout(fees_to_be, clinic["id"], customer.account_id, customer.customer_id)
|
payment_link = await self.create_subscription_checkout(fees_to_be, clinic["id"], customer.account_id, customer.customer_id)
|
||||||
|
|
||||||
return payment_link.url
|
return payment_link.url
|
||||||
|
|
@ -138,8 +171,8 @@ class StripeServices:
|
||||||
expand=["payment_intent"],
|
expand=["payment_intent"],
|
||||||
mode="payment",
|
mode="payment",
|
||||||
payment_intent_data={"metadata": {"order_id": "1"}},
|
payment_intent_data={"metadata": {"order_id": "1"}},
|
||||||
success_url="http://54.79.156.66/",
|
success_url="http://54.79.156.66/auth/waiting",
|
||||||
cancel_url="http://54.79.156.66/",
|
cancel_url="http://54.79.156.66/auth/waiting",
|
||||||
metadata={"user_id": user_id},
|
metadata={"user_id": user_id},
|
||||||
)
|
)
|
||||||
return checkout_session
|
return checkout_session
|
||||||
|
|
@ -253,7 +286,6 @@ class StripeServices:
|
||||||
finally:
|
finally:
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
async def handle_webhook(self, request: Request):
|
async def handle_webhook(self, request: Request):
|
||||||
try:
|
try:
|
||||||
payload = await request.body()
|
payload = await request.body()
|
||||||
|
|
@ -262,24 +294,31 @@ class StripeServices:
|
||||||
)
|
)
|
||||||
self.logger.info(f"Stripe webhook event type: {event['type']}")
|
self.logger.info(f"Stripe webhook event type: {event['type']}")
|
||||||
|
|
||||||
if event["type"] == "invoice.payment_succeeded":
|
if event["type"] == "checkout.session.expired":
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if event["type"] == "checkout.session.async_payment_succeeded":
|
if event["type"] == "checkout.session.completed":
|
||||||
self.logger.info("Async payment succeeded")
|
|
||||||
|
|
||||||
elif event["type"] == "checkout.session.completed":
|
|
||||||
unique_clinic_id = event["data"]["object"]["metadata"]["unique_clinic_id"]
|
unique_clinic_id = event["data"]["object"]["metadata"]["unique_clinic_id"]
|
||||||
clinic_id = event["data"]["object"]["metadata"]["clinic_id"]
|
clinic_id = event["data"]["object"]["metadata"]["clinic_id"]
|
||||||
customer_id = event["data"]["object"]["metadata"]["customer_id"]
|
customer_id = event["data"]["object"]["metadata"]["customer_id"]
|
||||||
account_id = event["data"]["object"]["metadata"]["account_id"]
|
account_id = event["data"]["object"]["metadata"]["account_id"]
|
||||||
total = event["data"]["object"]["amount_total"]
|
total = event["data"]["object"]["amount_total"]
|
||||||
metadata = event["data"]["object"]["metadata"]
|
metadata = event["data"]["object"]["metadata"]
|
||||||
self.update_payment_log(unique_clinic_id, clinic_id, customer_id, account_id, total, metadata)
|
session_id = event["data"]["object"]["id"]
|
||||||
|
subscription_id = event["data"]["object"]["subscription"]
|
||||||
|
|
||||||
|
self._update_payment_log(unique_clinic_id, clinic_id, customer_id, account_id, total, metadata, session_id)
|
||||||
|
|
||||||
|
self._create_subscription_entry({
|
||||||
|
"clinic_id": clinic_id,
|
||||||
|
"customer_id": customer_id,
|
||||||
|
"account_id": account_id,
|
||||||
|
"session_id": session_id,
|
||||||
|
"subscription_id": subscription_id,
|
||||||
|
})
|
||||||
# TODO: handle subscription period end
|
# TODO: handle subscription period end
|
||||||
|
|
||||||
return event
|
return "OK"
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
self.logger.error(f"Invalid payload: {e}")
|
self.logger.error(f"Invalid payload: {e}")
|
||||||
except stripe.error.SignatureVerificationError as e:
|
except stripe.error.SignatureVerificationError as e:
|
||||||
|
|
@ -287,7 +326,7 @@ class StripeServices:
|
||||||
finally:
|
finally:
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
def update_payment_log(self, unique_clinic_id:str, clinic_id:int, customer_id:str, account_id:str, total:float, metadata:any):
|
def _update_payment_log(self, unique_clinic_id:str, clinic_id:int, customer_id:str, account_id:str, total:float, metadata:any, session_id:str):
|
||||||
try:
|
try:
|
||||||
self.db.query(PaymentSessions).filter(PaymentSessions.clinic_id == clinic_id).delete()
|
self.db.query(PaymentSessions).filter(PaymentSessions.clinic_id == clinic_id).delete()
|
||||||
|
|
||||||
|
|
@ -301,15 +340,48 @@ class StripeServices:
|
||||||
metadata_logs=json.dumps(metadata.to_dict())
|
metadata_logs=json.dumps(metadata.to_dict())
|
||||||
)
|
)
|
||||||
self.db.add(payment_log)
|
self.db.add(payment_log)
|
||||||
self.db.commit()
|
|
||||||
|
|
||||||
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
|
clinic = self.db.query(Clinics).filter(Clinics.id == clinic_id).first()
|
||||||
|
|
||||||
if clinic:
|
if clinic:
|
||||||
clinic.status = ClinicStatus.UNDER_REVIEW
|
clinic.status = ClinicStatus.UNDER_REVIEW
|
||||||
self.db.add(clinic)
|
self.db.add(clinic)
|
||||||
self.db.commit()
|
return
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error updating payment log: {e}")
|
self.logger.error(f"Error updating payment log: {e}")
|
||||||
finally:
|
finally:
|
||||||
|
self.db.commit()
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
|
def _create_subscription_entry(self,data:dict):
|
||||||
|
try:
|
||||||
|
|
||||||
|
subscription = stripe.Subscription.retrieve(data["subscription_id"])
|
||||||
|
|
||||||
|
new_subscription = Subscriptions(
|
||||||
|
clinic_id=data["clinic_id"],
|
||||||
|
customer_id=data["customer_id"],
|
||||||
|
account_id=data["account_id"],
|
||||||
|
session_id=data["session_id"],
|
||||||
|
subscription_id=data["subscription_id"],
|
||||||
|
status=subscription.status,
|
||||||
|
current_period_start=subscription["items"]["data"][0]["current_period_start"],
|
||||||
|
current_period_end=subscription["items"]["data"][0]["current_period_end"],
|
||||||
|
metadata_logs=json.dumps(subscription.metadata)
|
||||||
|
)
|
||||||
|
self.db.add(new_subscription)
|
||||||
|
|
||||||
|
payment_session = PaymentSessions(
|
||||||
|
session_id=data["session_id"],
|
||||||
|
customer_id=data["customer_id"],
|
||||||
|
clinic_id=data["clinic_id"],
|
||||||
|
status="paid"
|
||||||
|
)
|
||||||
|
self.db.add(payment_session)
|
||||||
|
return
|
||||||
|
except Exception as e:
|
||||||
|
self.logger.error(f"Error creating subscription entry: {e}")
|
||||||
|
finally:
|
||||||
|
self.db.commit()
|
||||||
|
self.db.close()
|
||||||
|
|
||||||
|
|
@ -156,7 +156,24 @@ class UserServices:
|
||||||
|
|
||||||
payment_link = await self.stripe_service.create_subscription_checkout(fees_to_be, new_clinic.id, stripe_account.id,stripe_customer.id)
|
payment_link = await self.stripe_service.create_subscription_checkout(fees_to_be, new_clinic.id, stripe_account.id,stripe_customer.id)
|
||||||
|
|
||||||
return payment_link.url
|
self.db.commit()
|
||||||
|
|
||||||
|
# Convert the user object to a dictionary before the session is closed
|
||||||
|
user_dict = {
|
||||||
|
"id": new_user.id,
|
||||||
|
"username": new_user.username,
|
||||||
|
"email": new_user.email,
|
||||||
|
"clinicRole": new_user.clinicRole,
|
||||||
|
"userType": new_user.userType,
|
||||||
|
"mobile": new_user.mobile,
|
||||||
|
"clinicId": new_clinic.id
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"url": payment_link.url,
|
||||||
|
"user": user_dict,
|
||||||
|
}
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"Error creating user: {str(e)}")
|
logger.error(f"Error creating user: {str(e)}")
|
||||||
# Rollback the transaction if any error occurs
|
# Rollback the transaction if any error occurs
|
||||||
|
|
@ -171,7 +188,6 @@ class UserServices:
|
||||||
# Use the centralized exception handler
|
# Use the centralized exception handler
|
||||||
DBExceptionHandler.handle_exception(e, context="creating user")
|
DBExceptionHandler.handle_exception(e, context="creating user")
|
||||||
finally:
|
finally:
|
||||||
self.db.commit()
|
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue