From 49a9f7c430d68c8c6444274b609db6029e1e2f22 Mon Sep 17 00:00:00 2001 From: Ilyass Date: Wed, 29 Jul 2026 20:50:52 +0200 Subject: [PATCH 1/4] Back cdr : Endpoint to get total of validated payments --- app/modules/cdr/cruds_cdr.py | 46 ++++++++++++++++++++++++++- app/modules/cdr/endpoints_cdr.py | 54 ++++++++++++++++++++++++++++++++ app/modules/cdr/schemas_cdr.py | 4 +++ 3 files changed, 103 insertions(+), 1 deletion(-) diff --git a/app/modules/cdr/cruds_cdr.py b/app/modules/cdr/cruds_cdr.py index 4d0c33063b..a75b4dd94c 100644 --- a/app/modules/cdr/cruds_cdr.py +++ b/app/modules/cdr/cruds_cdr.py @@ -1,7 +1,7 @@ from collections.abc import Sequence from uuid import UUID -from sqlalchemy import delete, select, update +from sqlalchemy import delete, select, update, func from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import noload, selectinload @@ -797,6 +797,50 @@ async def delete_payment( ), ) +async def get_payment_products_by_seller( + db: AsyncSession, +): + result = (await db.execute( + select( + models_cdr.Seller.name, + func.sum(models_cdr.ProductVariant.price * models_cdr.Purchase.quantity).label("total_amount") + ) + .join(models_cdr.CdrProduct, models_cdr.Seller.id == models_cdr.CdrProduct.seller_id) + .join(models_cdr.ProductVariant, models_cdr.ProductVariant.product_id == models_cdr.CdrProduct.id) + .join(models_cdr.Purchase, models_cdr.Purchase.product_variant_id == models_cdr.ProductVariant.id) + .where(models_cdr.Purchase.validated == True) + .group_by(models_cdr.Seller.id) + ) + ) + + return [ + schemas_cdr.TotalPurchaseValidatedBySeller( + total_validated=row.total_amount, + name=row.name, + ) + for row in result.all() + ] + +async def get_total_payment_types( + db: AsyncSession, +): + result = (await db.execute( + select( + models_cdr.Payment.payment_type, + func.sum(models_cdr.Payment.total).label("total") + ) + .group_by(models_cdr.Payment.payment_type) + ) + ) + + return [ + schemas_cdr.PaymentBase( + total=row.total, + payment_type=row.payment_type, + ) + for row in result.all() + ] + def create_action( db: AsyncSession, diff --git a/app/modules/cdr/endpoints_cdr.py b/app/modules/cdr/endpoints_cdr.py index d4af676047..725ac15ed8 100644 --- a/app/modules/cdr/endpoints_cdr.py +++ b/app/modules/cdr/endpoints_cdr.py @@ -2623,6 +2623,60 @@ async def delete_curriculum_membership( ) +@module.router.get( + "/cdr/users/total_payments_by_seller/", + response_model=list[schemas_cdr.PaymentComplete], + status_code=200, +) +async def get_total_payments( + db: AsyncSession = Depends(get_db), + user: models_users.CoreUser = Depends( + is_user_allowed_to([CdrPermissions.manage_cdr]), + ), +): + """ + Get a user's payments. + + **User must a CDR Admin to use this endpoint** + """ + if not ( + await has_user_permission(user, CdrPermissions.manage_cdr_cdr, db) + ): + raise HTTPException( + status_code=403, + detail="You're not allowed to see this.", + ) + return await cruds_cdr.get_payment_products_by_sell( + db=db, + ) + +@module.router.get( + "/cdr/users/total_payments/", + response_model=list[schemas_cdr.TotalPurchaseValidatedBySeller], + status_code=200, +) +async def get_total_payments( + db: AsyncSession = Depends(get_db), + user: models_users.CoreUser = Depends( + is_user_allowed_to([CdrPermissions.manage_cdr]), + ), +): + """ + Get a user's payments. + + **User must a CDR Admin to use this endpoint** + """ + if not ( + await has_user_permission(user, CdrPermissions.manage_cdr_cdr, db) + ): + raise HTTPException( + status_code=403, + detail="You're not allowed to see this.", + ) + return await cruds_cdr.get_total_payment_types( + db=db, + ) + @module.router.get( "/cdr/users/{user_id}/payments/", response_model=list[schemas_cdr.PaymentComplete], diff --git a/app/modules/cdr/schemas_cdr.py b/app/modules/cdr/schemas_cdr.py index 4571809c6b..d300908421 100644 --- a/app/modules/cdr/schemas_cdr.py +++ b/app/modules/cdr/schemas_cdr.py @@ -331,3 +331,7 @@ class BatchValidation(BaseModel): user_emails: list[str] product_variant_id: UUID validated: bool + +class TotalPurchaseValidatedBySeller(BaseModel): + name : str + total_validated: int \ No newline at end of file From 7377cd17f8900e739f547bd30acc84b0b253b84b Mon Sep 17 00:00:00 2001 From: Ilyass Date: Wed, 29 Jul 2026 21:00:49 +0200 Subject: [PATCH 2/4] Adding the year of cdr as a param in the endpoint --- app/modules/cdr/cruds_cdr.py | 9 ++++++--- app/modules/cdr/endpoints_cdr.py | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/app/modules/cdr/cruds_cdr.py b/app/modules/cdr/cruds_cdr.py index a75b4dd94c..3e2154923b 100644 --- a/app/modules/cdr/cruds_cdr.py +++ b/app/modules/cdr/cruds_cdr.py @@ -799,7 +799,8 @@ async def delete_payment( async def get_payment_products_by_seller( db: AsyncSession, -): + cdr_year: int, +) -> list[schemas_cdr.TotalPurchaseValidatedBySeller]: result = (await db.execute( select( models_cdr.Seller.name, @@ -808,7 +809,7 @@ async def get_payment_products_by_seller( .join(models_cdr.CdrProduct, models_cdr.Seller.id == models_cdr.CdrProduct.seller_id) .join(models_cdr.ProductVariant, models_cdr.ProductVariant.product_id == models_cdr.CdrProduct.id) .join(models_cdr.Purchase, models_cdr.Purchase.product_variant_id == models_cdr.ProductVariant.id) - .where(models_cdr.Purchase.validated == True) + .where(models_cdr.Purchase.validated == True and models_cdr.ProductVariant.year == cdr_year) .group_by(models_cdr.Seller.id) ) ) @@ -823,12 +824,14 @@ async def get_payment_products_by_seller( async def get_total_payment_types( db: AsyncSession, -): + cdr_year: int, +) -> list[schemas_cdr.PaymentBase]: result = (await db.execute( select( models_cdr.Payment.payment_type, func.sum(models_cdr.Payment.total).label("total") ) + .where(models_cdr.Payment.year == cdr_year) .group_by(models_cdr.Payment.payment_type) ) ) diff --git a/app/modules/cdr/endpoints_cdr.py b/app/modules/cdr/endpoints_cdr.py index 725ac15ed8..7891e54984 100644 --- a/app/modules/cdr/endpoints_cdr.py +++ b/app/modules/cdr/endpoints_cdr.py @@ -2633,6 +2633,7 @@ async def get_total_payments( user: models_users.CoreUser = Depends( is_user_allowed_to([CdrPermissions.manage_cdr]), ), + cdr_year: coredata_cdr.CdrYear = Depends(get_current_cdr_year), ): """ Get a user's payments. @@ -2648,6 +2649,7 @@ async def get_total_payments( ) return await cruds_cdr.get_payment_products_by_sell( db=db, + cdr_year=cdr_year.year ) @module.router.get( @@ -2660,6 +2662,7 @@ async def get_total_payments( user: models_users.CoreUser = Depends( is_user_allowed_to([CdrPermissions.manage_cdr]), ), + cdr_year: coredata_cdr.CdrYear = Depends(get_current_cdr_year), ): """ Get a user's payments. @@ -2675,6 +2678,7 @@ async def get_total_payments( ) return await cruds_cdr.get_total_payment_types( db=db, + cdr_year=cdr_year.year ) @module.router.get( From 97f147ac27ef2713aeb9dc99f2f6293c8649f36a Mon Sep 17 00:00:00 2001 From: Ilyass Date: Wed, 29 Jul 2026 21:05:54 +0200 Subject: [PATCH 3/4] Lint and ruff format --- app/modules/cdr/cruds_cdr.py | 62 +++++++++++++++++++------------- app/modules/cdr/endpoints_cdr.py | 22 ++++++------ app/modules/cdr/schemas_cdr.py | 5 +-- 3 files changed, 51 insertions(+), 38 deletions(-) diff --git a/app/modules/cdr/cruds_cdr.py b/app/modules/cdr/cruds_cdr.py index 3e2154923b..404af870ea 100644 --- a/app/modules/cdr/cruds_cdr.py +++ b/app/modules/cdr/cruds_cdr.py @@ -1,7 +1,7 @@ from collections.abc import Sequence from uuid import UUID -from sqlalchemy import delete, select, update, func +from sqlalchemy import delete, func, select, update from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import noload, selectinload @@ -797,23 +797,37 @@ async def delete_payment( ), ) + async def get_payment_products_by_seller( db: AsyncSession, cdr_year: int, ) -> list[schemas_cdr.TotalPurchaseValidatedBySeller]: - result = (await db.execute( - select( - models_cdr.Seller.name, - func.sum(models_cdr.ProductVariant.price * models_cdr.Purchase.quantity).label("total_amount") - ) - .join(models_cdr.CdrProduct, models_cdr.Seller.id == models_cdr.CdrProduct.seller_id) - .join(models_cdr.ProductVariant, models_cdr.ProductVariant.product_id == models_cdr.CdrProduct.id) - .join(models_cdr.Purchase, models_cdr.Purchase.product_variant_id == models_cdr.ProductVariant.id) - .where(models_cdr.Purchase.validated == True and models_cdr.ProductVariant.year == cdr_year) - .group_by(models_cdr.Seller.id) - ) - ) - + result = await db.execute( + select( + models_cdr.Seller.name, + func.sum( + models_cdr.ProductVariant.price * models_cdr.Purchase.quantity, + ).label("total_amount"), + ) + .join( + models_cdr.CdrProduct, + models_cdr.Seller.id == models_cdr.CdrProduct.seller_id, + ) + .join( + models_cdr.ProductVariant, + models_cdr.ProductVariant.product_id == models_cdr.CdrProduct.id, + ) + .join( + models_cdr.Purchase, + models_cdr.Purchase.product_variant_id == models_cdr.ProductVariant.id, + ) + .where( + models_cdr.Purchase.validated + and models_cdr.ProductVariant.year == cdr_year, + ) + .group_by(models_cdr.Seller.id), + ) + return [ schemas_cdr.TotalPurchaseValidatedBySeller( total_validated=row.total_amount, @@ -822,20 +836,20 @@ async def get_payment_products_by_seller( for row in result.all() ] + async def get_total_payment_types( db: AsyncSession, cdr_year: int, ) -> list[schemas_cdr.PaymentBase]: - result = (await db.execute( - select( - models_cdr.Payment.payment_type, - func.sum(models_cdr.Payment.total).label("total") - ) - .where(models_cdr.Payment.year == cdr_year) - .group_by(models_cdr.Payment.payment_type) - ) - ) - + result = await db.execute( + select( + models_cdr.Payment.payment_type, + func.sum(models_cdr.Payment.total).label("total"), + ) + .where(models_cdr.Payment.year == cdr_year) + .group_by(models_cdr.Payment.payment_type), + ) + return [ schemas_cdr.PaymentBase( total=row.total, diff --git a/app/modules/cdr/endpoints_cdr.py b/app/modules/cdr/endpoints_cdr.py index 7891e54984..e9cad7e158 100644 --- a/app/modules/cdr/endpoints_cdr.py +++ b/app/modules/cdr/endpoints_cdr.py @@ -2628,7 +2628,7 @@ async def delete_curriculum_membership( response_model=list[schemas_cdr.PaymentComplete], status_code=200, ) -async def get_total_payments( +async def get_total_payments_by_seller( db: AsyncSession = Depends(get_db), user: models_users.CoreUser = Depends( is_user_allowed_to([CdrPermissions.manage_cdr]), @@ -2636,22 +2636,21 @@ async def get_total_payments( cdr_year: coredata_cdr.CdrYear = Depends(get_current_cdr_year), ): """ - Get a user's payments. + Get the total of payments done in the CDR by each seller. **User must a CDR Admin to use this endpoint** """ - if not ( - await has_user_permission(user, CdrPermissions.manage_cdr_cdr, db) - ): + if not (await has_user_permission(user, CdrPermissions.manage_cdr_cdr, db)): raise HTTPException( status_code=403, detail="You're not allowed to see this.", ) - return await cruds_cdr.get_payment_products_by_sell( + return await cruds_cdr.get_payment_products_by_seller( db=db, - cdr_year=cdr_year.year + cdr_year=cdr_year.year, ) + @module.router.get( "/cdr/users/total_payments/", response_model=list[schemas_cdr.TotalPurchaseValidatedBySeller], @@ -2665,22 +2664,21 @@ async def get_total_payments( cdr_year: coredata_cdr.CdrYear = Depends(get_current_cdr_year), ): """ - Get a user's payments. + Get the total of payments done in the CDR. **User must a CDR Admin to use this endpoint** """ - if not ( - await has_user_permission(user, CdrPermissions.manage_cdr_cdr, db) - ): + if not (await has_user_permission(user, CdrPermissions.manage_cdr_cdr, db)): raise HTTPException( status_code=403, detail="You're not allowed to see this.", ) return await cruds_cdr.get_total_payment_types( db=db, - cdr_year=cdr_year.year + cdr_year=cdr_year.year, ) + @module.router.get( "/cdr/users/{user_id}/payments/", response_model=list[schemas_cdr.PaymentComplete], diff --git a/app/modules/cdr/schemas_cdr.py b/app/modules/cdr/schemas_cdr.py index d300908421..b6cae89813 100644 --- a/app/modules/cdr/schemas_cdr.py +++ b/app/modules/cdr/schemas_cdr.py @@ -332,6 +332,7 @@ class BatchValidation(BaseModel): product_variant_id: UUID validated: bool + class TotalPurchaseValidatedBySeller(BaseModel): - name : str - total_validated: int \ No newline at end of file + name: str + total_validated: int From 4de76e02df79277d865d0384f5bae467800146cd Mon Sep 17 00:00:00 2001 From: Ilyass Date: Wed, 29 Jul 2026 21:27:27 +0200 Subject: [PATCH 4/4] modified: app/modules/cdr/endpoints_cdr.py --- app/modules/cdr/endpoints_cdr.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/modules/cdr/endpoints_cdr.py b/app/modules/cdr/endpoints_cdr.py index e9cad7e158..4fa7a6d9a1 100644 --- a/app/modules/cdr/endpoints_cdr.py +++ b/app/modules/cdr/endpoints_cdr.py @@ -2640,7 +2640,7 @@ async def get_total_payments_by_seller( **User must a CDR Admin to use this endpoint** """ - if not (await has_user_permission(user, CdrPermissions.manage_cdr_cdr, db)): + if not (await has_user_permission(user, CdrPermissions.manage_cdr, db)): raise HTTPException( status_code=403, detail="You're not allowed to see this.", @@ -2668,7 +2668,7 @@ async def get_total_payments( **User must a CDR Admin to use this endpoint** """ - if not (await has_user_permission(user, CdrPermissions.manage_cdr_cdr, db)): + if not (await has_user_permission(user, CdrPermissions.manage_cdr, db)): raise HTTPException( status_code=403, detail="You're not allowed to see this.",