diff --git a/apps/api/src/services/payments/payments_products.py b/apps/api/src/services/payments/payments_products.py index d0963fe0..ce2dede1 100644 --- a/apps/api/src/services/payments/payments_products.py +++ b/apps/api/src/services/payments/payments_products.py @@ -9,6 +9,7 @@ from src.db.payments.payments_products import ( PaymentsProductUpdate, PaymentsProductRead, ) +from src.db.payments.payments_users import PaymentStatusEnum, PaymentsUser from src.db.users import PublicUser, AnonymousUser from src.db.organizations import Organization from src.services.orgs.orgs import rbac_check @@ -138,6 +139,18 @@ async def delete_payments_product( if not product: raise HTTPException(status_code=404, detail="Payments product not found") + # Check if there are any payment users linked to this product + statement = select(PaymentsUser).where( + PaymentsUser.payment_product_id == product_id, + PaymentsUser.status.in_([PaymentStatusEnum.ACTIVE, PaymentStatusEnum.COMPLETED]) # type: ignore + ) + payment_users = db_session.exec(statement).all() + if payment_users: + raise HTTPException( + status_code=400, + detail="Cannot delete product because users have paid access to it." + ) + # Archive product in Stripe await archive_stripe_product(request, org_id, product.provider_product_id, current_user, db_session) diff --git a/apps/api/src/services/payments/payments_users.py b/apps/api/src/services/payments/payments_users.py index 077ab713..16af55a6 100644 --- a/apps/api/src/services/payments/payments_users.py +++ b/apps/api/src/services/payments/payments_users.py @@ -43,7 +43,7 @@ async def create_payment_user( stripe_customer=provider_data if provider_data else None, ) - # Check if user already has a payment user + # Check if user already has a payment user for this product statement = select(PaymentsUser).where( PaymentsUser.user_id == user_id, PaymentsUser.org_id == org_id, @@ -52,8 +52,12 @@ async def create_payment_user( existing_payment_user = db_session.exec(statement).first() if existing_payment_user: - if existing_payment_user.status == PaymentStatusEnum.PENDING: - # Delete existing pending payment + # If status is PENDING, CANCELLED, or FAILED, delete the existing record + if existing_payment_user.status in [ + PaymentStatusEnum.PENDING, + PaymentStatusEnum.CANCELLED, + PaymentStatusEnum.FAILED + ]: db_session.delete(existing_payment_user) db_session.commit() else: diff --git a/apps/api/src/services/payments/stripe.py b/apps/api/src/services/payments/stripe.py index 6154b9a0..b7c8643d 100644 --- a/apps/api/src/services/payments/stripe.py +++ b/apps/api/src/services/payments/stripe.py @@ -208,7 +208,7 @@ async def create_checkout_session( product_id=product_id, status=PaymentStatusEnum.PENDING, provider_data=customer, - current_user=current_user, + current_user=InternalUser(), db_session=db_session ) diff --git a/apps/web/app/orgs/[orgslug]/dash/user-account/owned/page.tsx b/apps/web/app/orgs/[orgslug]/dash/user-account/owned/page.tsx index f2b83c14..767db3cf 100644 --- a/apps/web/app/orgs/[orgslug]/dash/user-account/owned/page.tsx +++ b/apps/web/app/orgs/[orgslug]/dash/user-account/owned/page.tsx @@ -7,7 +7,7 @@ import useSWR from 'swr' import { getOwnedCourses } from '@services/payments/payments' import CourseThumbnail from '@components/Objects/Thumbnails/CourseThumbnail' import PageLoading from '@components/Objects/Loaders/PageLoading' -import { BookOpen } from 'lucide-react' +import { BookOpen, Package2 } from 'lucide-react' function OwnedCoursesPage() { const org = useOrg() as any @@ -24,9 +24,14 @@ function OwnedCoursesPage() { return (