diff --git a/app/core/core_endpoints/endpoints_core.py b/app/core/core_endpoints/endpoints_core.py index 5af8b4e546..65bcbaad7e 100644 --- a/app/core/core_endpoints/endpoints_core.py +++ b/app/core/core_endpoints/endpoints_core.py @@ -1,7 +1,6 @@ -from os import path from pathlib import Path -from fastapi import APIRouter, Depends, HTTPException, Request +from fastapi import APIRouter, Depends, Request from fastapi.responses import FileResponse from app.core.core_endpoints import schemas_core @@ -10,6 +9,7 @@ get_settings, ) from app.types.module import CoreModule +from app.utils.tools import patch_identity_in_text router = APIRouter(tags=["Core"]) @@ -43,118 +43,133 @@ async def read_information( @router.get( "/privacy", - response_class=FileResponse, status_code=200, ) -async def read_privacy(): +async def read_privacy(settings: Settings = Depends(get_settings)): """ Return Hyperion privacy """ - return FileResponse("assets/privacy.txt") + return patch_identity_in_text( + Path("assets/privacy.txt").read_text(encoding="utf-8"), + settings, + ) @router.get( "/terms-and-conditions", - response_class=FileResponse, status_code=200, ) -async def read_terms_and_conditions(): +async def read_terms_and_conditions(settings: Settings = Depends(get_settings)): """ Return Hyperion terms and conditions pages """ - return FileResponse("assets/terms-and-conditions.txt") + return patch_identity_in_text( + Path("assets/terms-and-conditions.txt").read_text(encoding="utf-8"), + settings, + ) @router.get( - "/myeclpay-terms-of-service", - response_class=FileResponse, + "/mypayment-terms-of-service", status_code=200, ) -async def read_myeclpay_tos(): +async def read_mypayment_tos(settings: Settings = Depends(get_settings)): """ - Return MyECLPay latest ToS + Return MyPayment latest ToS """ - return FileResponse("assets/myeclpay-terms-of-service.txt") + return patch_identity_in_text( + Path("assets/mypayment-terms-of-service.txt").read_text(encoding="utf-8"), + settings, + ) @router.get( "/support", - response_class=FileResponse, status_code=200, ) -async def read_support(): +async def read_support(settings: Settings = Depends(get_settings)): """ Return Hyperion support """ - return FileResponse("assets/support.txt") + return patch_identity_in_text( + Path("assets/support.txt").read_text(encoding="utf-8"), + settings, + ) @router.get( "/security.txt", - response_class=FileResponse, status_code=200, ) -async def read_security_txt(): +async def read_security_txt(settings: Settings = Depends(get_settings)): """ Return Hyperion security.txt file """ - - return FileResponse("assets/security.txt") + return patch_identity_in_text( + Path("assets/security.txt").read_text(encoding="utf-8"), + settings, + ) @router.get( "/.well-known/security.txt", - response_class=FileResponse, status_code=200, ) -async def read_wellknown_security_txt(): +async def read_wellknown_security_txt(settings: Settings = Depends(get_settings)): """ Return Hyperion security.txt file """ - return FileResponse("assets/security.txt") + return patch_identity_in_text( + Path("assets/security.txt").read_text(encoding="utf-8"), + settings, + ) @router.get( "/robots.txt", - response_class=FileResponse, status_code=200, ) -async def read_robots_txt(): +async def read_robots_txt(settings: Settings = Depends(get_settings)): """ Return Hyperion robots.txt file """ - return FileResponse("assets/robots.txt") + return patch_identity_in_text( + Path("assets/robots.txt").read_text(encoding="utf-8"), + settings, + ) @router.get( - "/style/{file}.css", - response_class=FileResponse, + "/variables", + response_model=schemas_core.CoreVariables, status_code=200, ) -async def get_style_file( - file: str, -): +async def get_variables(settings: Settings = Depends(get_settings)): """ Return a style file from the assets folder """ - css_dir = "assets/style/" - css_path = f"{css_dir}{file}.css" - - # Security check (even if FastAPI parsing of path parameters does not allow path traversal) - if path.commonprefix( - (path.realpath(css_path), path.realpath(css_dir)), - ) != path.realpath(css_dir): - raise HTTPException(status_code=404, detail="File not found") - - if not Path(css_path).is_file(): - raise HTTPException(status_code=404, detail="File not found") - - return FileResponse(css_path) + return schemas_core.CoreVariables( + name=settings.school.application_name, + entity_name=settings.school.entity_name, + email_placeholder=settings.school.email_placeholder, + main_activation_form=settings.school.main_activation_form, + play_store_url=settings.school.play_store_url, + app_store_url=settings.school.app_store_url, + student_email_regex=settings.school.student_email_regex.pattern, + staff_email_regex=settings.school.staff_email_regex.pattern + if settings.school.staff_email_regex + else None, + former_student_email_regex=settings.school.former_student_email_regex.pattern + if settings.school.former_student_email_regex + else None, + # `as_hsl()` return a string in the format `hsl(hue saturation lightness)`, we need to convert it to `24.6 95% 53.1%` for TailwindCSS + primary_color=settings.school.primary_color.as_hsl()[4:-1], + ) @router.get( diff --git a/app/core/core_endpoints/schemas_core.py b/app/core/core_endpoints/schemas_core.py index e771f9cf88..e2356cd0a9 100644 --- a/app/core/core_endpoints/schemas_core.py +++ b/app/core/core_endpoints/schemas_core.py @@ -1,6 +1,10 @@ """Common schemas file for endpoint /users et /groups because it would cause circular import""" -from pydantic import BaseModel +from enum import Enum + +from pydantic import BaseModel, ConfigDict, Field + +from app.core.groups.groups_type import AccountType class CoreInformation(BaseModel): @@ -9,3 +13,53 @@ class CoreInformation(BaseModel): ready: bool version: str minimal_titan_version_code: int + + +class ModuleVisibility(BaseModel): + root: str + allowed_group_ids: list[str] + allowed_account_types: list[AccountType] + model_config = ConfigDict(from_attributes=True) + + +class ModuleVisibilityCreate(BaseModel): + root: str + allowed_group_id: str | None = None + allowed_account_type: AccountType | None = None + model_config = ConfigDict(from_attributes=True) + + +class ActivationFormField(Enum): + NICKNAME = "nickname" + BIRTHDATE = "birthdate" + PHONE = "phone" + PROMOTION = "promotion" + FLOOR = "floor" + + +class MainActivationForm(BaseModel): + fields: list[ActivationFormField] = Field( + description="List of fields that are to be asked in the main activation form", + ) + floor_choices: list[str] = Field( + description="List of choices for the floor field if it is asked", + default_factory=list, + ) + promotion_offset: int | None = None + + +class CoreVariables(BaseModel): + """Variables used by Hyperion""" + + name: str + entity_name: str + email_placeholder: str + main_activation_form: MainActivationForm + student_email_regex: str + staff_email_regex: str | None = None + former_student_email_regex: str | None = None + primary_color: str = Field( + description="Returned as an HSL triplet (ex: `24.6 95% 53.1%`)", + ) + play_store_url: str | None = None + app_store_url: str | None = None diff --git a/app/core/myeclpay/coredata_myeclpay.py b/app/core/myeclpay/coredata_myeclpay.py deleted file mode 100644 index 6b0944c31c..0000000000 --- a/app/core/myeclpay/coredata_myeclpay.py +++ /dev/null @@ -1,9 +0,0 @@ -from uuid import UUID - -from app.types.core_data import BaseCoreData - - -class MyECLPayBankAccountHolder(BaseCoreData): - """Bank account holder information for MyECLPay.""" - - holder_structure_id: UUID diff --git a/app/core/myeclpay/__init__.py b/app/core/mypayment/__init__.py similarity index 100% rename from app/core/myeclpay/__init__.py rename to app/core/mypayment/__init__.py diff --git a/app/core/mypayment/coredata_mypayment.py b/app/core/mypayment/coredata_mypayment.py new file mode 100644 index 0000000000..b9d8afb523 --- /dev/null +++ b/app/core/mypayment/coredata_mypayment.py @@ -0,0 +1,9 @@ +from uuid import UUID + +from app.types.core_data import BaseCoreData + + +class MyPaymentBankAccountHolder(BaseCoreData): + """Bank account holder information for MyPayment.""" + + holder_structure_id: UUID diff --git a/app/core/myeclpay/cruds_myeclpay.py b/app/core/mypayment/cruds_mypayment.py similarity index 65% rename from app/core/myeclpay/cruds_myeclpay.py rename to app/core/mypayment/cruds_mypayment.py index df05173084..2a8ac9a39b 100644 --- a/app/core/myeclpay/cruds_myeclpay.py +++ b/app/core/mypayment/cruds_mypayment.py @@ -6,14 +6,14 @@ from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import noload, selectinload -from app.core.myeclpay import models_myeclpay, schemas_myeclpay -from app.core.myeclpay.exceptions_myeclpay import WalletNotFoundOnUpdateError -from app.core.myeclpay.types_myeclpay import ( +from app.core.mypayment import models_mypayment, schemas_mypayment +from app.core.mypayment.exceptions_mypayment import WalletNotFoundOnUpdateError +from app.core.mypayment.types_mypayment import ( TransactionStatus, WalletDeviceStatus, WalletType, ) -from app.core.myeclpay.utils_myeclpay import ( +from app.core.mypayment.utils_mypayment import ( invoice_model_to_schema, refund_model_to_schema, structure_model_to_schema, @@ -22,11 +22,11 @@ async def create_structure( - structure: schemas_myeclpay.StructureSimple, + structure: schemas_mypayment.StructureSimple, db: AsyncSession, ) -> None: db.add( - models_myeclpay.Structure( + models_mypayment.Structure( id=structure.id, short_id=structure.short_id, name=structure.name, @@ -46,12 +46,12 @@ async def create_structure( async def update_structure( structure_id: UUID, - structure_update: schemas_myeclpay.StructureUpdate, + structure_update: schemas_mypayment.StructureUpdate, db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.Structure) - .where(models_myeclpay.Structure.id == structure_id) + update(models_mypayment.Structure) + .where(models_mypayment.Structure.id == structure_id) .values(**structure_update.model_dump(exclude_unset=True)), ) @@ -61,8 +61,8 @@ async def delete_structure( db: AsyncSession, ) -> None: await db.execute( - delete(models_myeclpay.Structure).where( - models_myeclpay.Structure.id == structure_id, + delete(models_mypayment.Structure).where( + models_mypayment.Structure.id == structure_id, ), ) @@ -75,7 +75,7 @@ async def init_structure_manager_transfer( db: AsyncSession, ) -> None: db.add( - models_myeclpay.StructureManagerTransfert( + models_mypayment.StructureManagerTransfert( structure_id=structure_id, user_id=user_id, valid_until=valid_until, @@ -87,10 +87,10 @@ async def init_structure_manager_transfer( async def get_structure_manager_transfer_by_secret( confirmation_token: str, db: AsyncSession, -) -> models_myeclpay.StructureManagerTransfert | None: +) -> models_mypayment.StructureManagerTransfert | None: result = await db.execute( - select(models_myeclpay.StructureManagerTransfert).where( - models_myeclpay.StructureManagerTransfert.confirmation_token + select(models_mypayment.StructureManagerTransfert).where( + models_mypayment.StructureManagerTransfert.confirmation_token == confirmation_token, ), ) @@ -102,8 +102,8 @@ async def delete_structure_manager_transfer_by_structure( db: AsyncSession, ) -> None: await db.execute( - delete(models_myeclpay.StructureManagerTransfert).where( - models_myeclpay.StructureManagerTransfert.structure_id == structure_id, + delete(models_mypayment.StructureManagerTransfert).where( + models_mypayment.StructureManagerTransfert.structure_id == structure_id, ), ) @@ -114,16 +114,16 @@ async def update_structure_manager( db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.Structure) - .where(models_myeclpay.Structure.id == structure_id) + update(models_mypayment.Structure) + .where(models_mypayment.Structure.id == structure_id) .values(manager_user_id=manager_user_id), ) async def get_structures( db: AsyncSession, -) -> Sequence[schemas_myeclpay.Structure]: - result = await db.execute(select(models_myeclpay.Structure)) +) -> Sequence[schemas_mypayment.Structure]: + result = await db.execute(select(models_mypayment.Structure)) return [ structure_model_to_schema(structure) for structure in result.scalars().all() ] @@ -132,12 +132,12 @@ async def get_structures( async def get_structure_by_id( structure_id: UUID, db: AsyncSession, -) -> schemas_myeclpay.Structure | None: +) -> schemas_mypayment.Structure | None: structure = ( ( await db.execute( - select(models_myeclpay.Structure).where( - models_myeclpay.Structure.id == structure_id, + select(models_mypayment.Structure).where( + models_mypayment.Structure.id == structure_id, ), ) ) @@ -148,7 +148,7 @@ async def get_structure_by_id( async def create_store( - store: models_myeclpay.Store, + store: models_mypayment.Store, db: AsyncSession, ) -> None: db.add(store) @@ -156,12 +156,12 @@ async def create_store( async def update_store( store_id: UUID, - store_update: schemas_myeclpay.StoreUpdate, + store_update: schemas_mypayment.StoreUpdate, db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.Store) - .where(models_myeclpay.Store.id == store_id) + update(models_mypayment.Store) + .where(models_mypayment.Store.id == store_id) .values(**store_update.model_dump(exclude_none=True)), ) @@ -171,24 +171,24 @@ async def delete_store( db: AsyncSession, ) -> None: await db.execute( - delete(models_myeclpay.Store).where(models_myeclpay.Store.id == store_id), + delete(models_mypayment.Store).where(models_mypayment.Store.id == store_id), ) async def get_stores( db: AsyncSession, -) -> Sequence[models_myeclpay.Store]: - result = await db.execute(select(models_myeclpay.Store)) +) -> Sequence[models_mypayment.Store]: + result = await db.execute(select(models_mypayment.Store)) return result.scalars().all() async def get_store_by_name( name: str, db: AsyncSession, -) -> models_myeclpay.Store | None: +) -> models_mypayment.Store | None: result = await db.execute( - select(models_myeclpay.Store).where( - models_myeclpay.Store.name == name, + select(models_mypayment.Store).where( + models_mypayment.Store.name == name, ), ) return result.scalars().first() @@ -197,10 +197,10 @@ async def get_store_by_name( async def get_stores_by_structure_id( db: AsyncSession, structure_id: UUID, -) -> Sequence[models_myeclpay.Store]: +) -> Sequence[models_mypayment.Store]: result = await db.execute( - select(models_myeclpay.Store).where( - models_myeclpay.Store.structure_id == structure_id, + select(models_mypayment.Store).where( + models_mypayment.Store.structure_id == structure_id, ), ) return result.scalars().all() @@ -215,7 +215,7 @@ async def create_seller( can_manage_sellers: bool, db: AsyncSession, ) -> None: - wallet = models_myeclpay.Seller( + wallet = models_mypayment.Seller( user_id=user_id, store_id=store_id, can_bank=can_bank, @@ -230,13 +230,13 @@ async def get_seller( user_id: str, store_id: UUID, db: AsyncSession, -) -> schemas_myeclpay.Seller | None: +) -> schemas_mypayment.Seller | None: result = ( ( await db.execute( - select(models_myeclpay.Seller).where( - models_myeclpay.Seller.user_id == user_id, - models_myeclpay.Seller.store_id == store_id, + select(models_mypayment.Seller).where( + models_mypayment.Seller.user_id == user_id, + models_mypayment.Seller.store_id == store_id, ), ) ) @@ -244,7 +244,7 @@ async def get_seller( .first() ) return ( - schemas_myeclpay.Seller( + schemas_mypayment.Seller( user_id=result.user_id, store_id=result.store_id, can_bank=result.can_bank, @@ -268,14 +268,14 @@ async def get_seller( async def get_sellers_by_store_id( store_id: UUID, db: AsyncSession, -) -> list[schemas_myeclpay.Seller]: +) -> list[schemas_mypayment.Seller]: result = await db.execute( - select(models_myeclpay.Seller).where( - models_myeclpay.Seller.store_id == store_id, + select(models_mypayment.Seller).where( + models_mypayment.Seller.store_id == store_id, ), ) return [ - schemas_myeclpay.Seller( + schemas_mypayment.Seller( user_id=seller.user_id, store_id=seller.store_id, can_bank=seller.can_bank, @@ -298,10 +298,10 @@ async def get_sellers_by_store_id( async def get_sellers_by_user_id( user_id: str, db: AsyncSession, -) -> Sequence[models_myeclpay.Seller]: +) -> Sequence[models_mypayment.Seller]: result = await db.execute( - select(models_myeclpay.Seller).where( - models_myeclpay.Seller.user_id == user_id, + select(models_mypayment.Seller).where( + models_mypayment.Seller.user_id == user_id, ), ) return result.scalars().all() @@ -310,14 +310,14 @@ async def get_sellers_by_user_id( async def update_seller( seller_user_id: str, store_id: UUID, - seller_update: schemas_myeclpay.SellerUpdate, + seller_update: schemas_mypayment.SellerUpdate, db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.Seller) + update(models_mypayment.Seller) .where( - models_myeclpay.Seller.user_id == seller_user_id, - models_myeclpay.Seller.store_id == store_id, + models_mypayment.Seller.user_id == seller_user_id, + models_mypayment.Seller.store_id == store_id, ) .values( **seller_update.model_dump(exclude_none=True), @@ -331,9 +331,9 @@ async def delete_seller( db: AsyncSession, ) -> None: await db.execute( - delete(models_myeclpay.Seller).where( - models_myeclpay.Seller.user_id == seller_user_id, - models_myeclpay.Seller.store_id == store_id, + delete(models_mypayment.Seller).where( + models_mypayment.Seller.user_id == seller_user_id, + models_mypayment.Seller.store_id == store_id, ), ) @@ -344,7 +344,7 @@ async def create_wallet( balance: int, db: AsyncSession, ) -> None: - wallet = models_myeclpay.Wallet( + wallet = models_mypayment.Wallet( id=wallet_id, type=wallet_type, balance=balance, @@ -354,10 +354,10 @@ async def create_wallet( async def get_wallets( db: AsyncSession, -) -> Sequence[schemas_myeclpay.WalletBase]: - result = await db.execute(select(models_myeclpay.Wallet)) +) -> Sequence[schemas_mypayment.WalletBase]: + result = await db.execute(select(models_mypayment.Wallet)) return [ - schemas_myeclpay.WalletBase( + schemas_mypayment.WalletBase( id=wallet.id, type=wallet.type, balance=wallet.balance, @@ -369,14 +369,14 @@ async def get_wallets( async def get_wallet( wallet_id: UUID, db: AsyncSession, -) -> models_myeclpay.Wallet | None: +) -> models_mypayment.Wallet | None: # We lock the wallet `for update` to prevent race conditions request = ( - select(models_myeclpay.Wallet) + select(models_mypayment.Wallet) .where( - models_myeclpay.Wallet.id == wallet_id, + models_mypayment.Wallet.id == wallet_id, ) - .with_for_update(of=models_myeclpay.Wallet) + .with_for_update(of=models_mypayment.Wallet) ) result = await db.execute(request) @@ -386,10 +386,10 @@ async def get_wallet( async def get_wallet_device( wallet_device_id: UUID, db: AsyncSession, -) -> models_myeclpay.WalletDevice | None: +) -> models_mypayment.WalletDevice | None: result = await db.execute( - select(models_myeclpay.WalletDevice).where( - models_myeclpay.WalletDevice.id == wallet_device_id, + select(models_mypayment.WalletDevice).where( + models_mypayment.WalletDevice.id == wallet_device_id, ), ) return result.scalars().first() @@ -398,10 +398,10 @@ async def get_wallet_device( async def get_wallet_devices_by_wallet_id( wallet_id: UUID, db: AsyncSession, -) -> Sequence[models_myeclpay.WalletDevice]: +) -> Sequence[models_mypayment.WalletDevice]: result = await db.execute( - select(models_myeclpay.WalletDevice).where( - models_myeclpay.WalletDevice.wallet_id == wallet_id, + select(models_mypayment.WalletDevice).where( + models_mypayment.WalletDevice.wallet_id == wallet_id, ), ) return result.scalars().all() @@ -410,17 +410,17 @@ async def get_wallet_devices_by_wallet_id( async def get_wallet_device_by_activation_token( activation_token: str, db: AsyncSession, -) -> models_myeclpay.WalletDevice | None: +) -> models_mypayment.WalletDevice | None: result = await db.execute( - select(models_myeclpay.WalletDevice).where( - models_myeclpay.WalletDevice.activation_token == activation_token, + select(models_mypayment.WalletDevice).where( + models_mypayment.WalletDevice.activation_token == activation_token, ), ) return result.scalars().first() async def create_wallet_device( - wallet_device: models_myeclpay.WalletDevice, + wallet_device: models_mypayment.WalletDevice, db: AsyncSession, ) -> None: db.add(wallet_device) @@ -432,8 +432,8 @@ async def update_wallet_device_status( db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.WalletDevice) - .where(models_myeclpay.WalletDevice.id == wallet_device_id) + update(models_mypayment.WalletDevice) + .where(models_mypayment.WalletDevice.id == wallet_device_id) .values(status=status), ) @@ -449,11 +449,11 @@ async def increment_wallet_balance( # Prevent a race condition by locking the wallet row # as we don't want the balance to be modified between the select and the update. request = ( - select(models_myeclpay.Wallet) - .where(models_myeclpay.Wallet.id == wallet_id) + select(models_mypayment.Wallet) + .where(models_mypayment.Wallet.id == wallet_id) .options( - noload(models_myeclpay.Wallet.store), - noload(models_myeclpay.Wallet.user), + noload(models_mypayment.Wallet.store), + noload(models_mypayment.Wallet.user), ) .with_for_update() ) @@ -472,7 +472,7 @@ async def create_user_payment( accepted_tos_version: int, db: AsyncSession, ) -> None: - user_payment = models_myeclpay.UserPayment( + user_payment = models_mypayment.UserPayment( user_id=user_id, wallet_id=wallet_id, accepted_tos_signature=accepted_tos_signature, @@ -488,8 +488,8 @@ async def update_user_payment( db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.UserPayment) - .where(models_myeclpay.UserPayment.user_id == user_id) + update(models_mypayment.UserPayment) + .where(models_mypayment.UserPayment.user_id == user_id) .values( accepted_tos_signature=accepted_tos_signature, accepted_tos_version=accepted_tos_version, @@ -500,22 +500,22 @@ async def update_user_payment( async def get_user_payment( user_id: str, db: AsyncSession, -) -> models_myeclpay.UserPayment | None: +) -> models_mypayment.UserPayment | None: result = await db.execute( - select(models_myeclpay.UserPayment).where( - models_myeclpay.UserPayment.user_id == user_id, + select(models_mypayment.UserPayment).where( + models_mypayment.UserPayment.user_id == user_id, ), ) return result.scalars().first() async def create_transaction( - transaction: schemas_myeclpay.TransactionBase, + transaction: schemas_mypayment.TransactionBase, debited_wallet_device_id: UUID, store_note: str | None, db: AsyncSession, ) -> None: - transaction_db = models_myeclpay.Transaction( + transaction_db = models_mypayment.Transaction( id=transaction.id, debited_wallet_id=transaction.debited_wallet_id, debited_wallet_device_id=debited_wallet_device_id, @@ -537,8 +537,8 @@ async def update_transaction_status( db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.Transaction) - .where(models_myeclpay.Transaction.id == transaction_id) + update(models_mypayment.Transaction) + .where(models_mypayment.Transaction.id == transaction_id) .values(status=status), ) @@ -546,24 +546,24 @@ async def update_transaction_status( async def get_transaction( transaction_id: UUID, db: AsyncSession, -) -> schemas_myeclpay.Transaction | None: +) -> schemas_mypayment.Transaction | None: # We lock the transaction `for update` to prevent # race conditions result = ( ( await db.execute( - select(models_myeclpay.Transaction) + select(models_mypayment.Transaction) .where( - models_myeclpay.Transaction.id == transaction_id, + models_mypayment.Transaction.id == transaction_id, ) - .with_for_update(of=models_myeclpay.Transaction), + .with_for_update(of=models_mypayment.Transaction), ) ) .scalars() .first() ) return ( - schemas_myeclpay.Transaction( + schemas_mypayment.Transaction( id=result.id, debited_wallet_id=result.debited_wallet_id, credited_wallet_id=result.credited_wallet_id, @@ -583,22 +583,22 @@ async def get_transactions( start_date: datetime | None = None, end_date: datetime | None = None, exclude_canceled: bool = False, -) -> Sequence[schemas_myeclpay.TransactionBase]: +) -> Sequence[schemas_mypayment.TransactionBase]: result = await db.execute( - select(models_myeclpay.Transaction).where( - models_myeclpay.Transaction.creation >= start_date + select(models_mypayment.Transaction).where( + models_mypayment.Transaction.creation >= start_date if start_date else and_(True), - models_myeclpay.Transaction.creation <= end_date + models_mypayment.Transaction.creation <= end_date if end_date else and_(True), - models_myeclpay.Transaction.status != TransactionStatus.CANCELED + models_mypayment.Transaction.status != TransactionStatus.CANCELED if exclude_canceled else and_(True), ), ) return [ - schemas_myeclpay.TransactionBase( + schemas_mypayment.TransactionBase( id=transaction.id, debited_wallet_id=transaction.debited_wallet_id, credited_wallet_id=transaction.credited_wallet_id, @@ -617,24 +617,24 @@ async def get_transactions_by_wallet_id( db: AsyncSession, start_datetime: datetime | None = None, end_datetime: datetime | None = None, -) -> Sequence[models_myeclpay.Transaction]: +) -> Sequence[models_mypayment.Transaction]: result = await db.execute( - select(models_myeclpay.Transaction) + select(models_mypayment.Transaction) .where( or_( - models_myeclpay.Transaction.debited_wallet_id == wallet_id, - models_myeclpay.Transaction.credited_wallet_id == wallet_id, + models_mypayment.Transaction.debited_wallet_id == wallet_id, + models_mypayment.Transaction.credited_wallet_id == wallet_id, ), - models_myeclpay.Transaction.creation >= start_datetime + models_mypayment.Transaction.creation >= start_datetime if start_datetime else and_(True), - models_myeclpay.Transaction.creation <= end_datetime + models_mypayment.Transaction.creation <= end_datetime if end_datetime else and_(True), ) .options( - selectinload(models_myeclpay.Transaction.debited_wallet), - selectinload(models_myeclpay.Transaction.credited_wallet), + selectinload(models_mypayment.Transaction.debited_wallet), + selectinload(models_mypayment.Transaction.credited_wallet), ), ) return result.scalars().all() @@ -645,31 +645,31 @@ async def get_transactions_and_sellers_by_wallet_id( db: AsyncSession, start_datetime: datetime | None = None, end_datetime: datetime | None = None, -) -> Sequence[tuple[models_myeclpay.Transaction, str | None]]: +) -> Sequence[tuple[models_mypayment.Transaction, str | None]]: result = await db.execute( select( - models_myeclpay.Transaction, + models_mypayment.Transaction, models_users.CoreUser, ) .outerjoin( models_users.CoreUser, - models_users.CoreUser.id == models_myeclpay.Transaction.seller_user_id, + models_users.CoreUser.id == models_mypayment.Transaction.seller_user_id, ) .where( or_( - models_myeclpay.Transaction.debited_wallet_id == wallet_id, - models_myeclpay.Transaction.credited_wallet_id == wallet_id, + models_mypayment.Transaction.debited_wallet_id == wallet_id, + models_mypayment.Transaction.credited_wallet_id == wallet_id, ), - models_myeclpay.Transaction.creation >= start_datetime + models_mypayment.Transaction.creation >= start_datetime if start_datetime else and_(True), - models_myeclpay.Transaction.creation <= end_datetime + models_mypayment.Transaction.creation <= end_datetime if end_datetime else and_(True), ) .options( - selectinload(models_myeclpay.Transaction.debited_wallet), - selectinload(models_myeclpay.Transaction.credited_wallet), + selectinload(models_mypayment.Transaction.debited_wallet), + selectinload(models_mypayment.Transaction.credited_wallet), ), ) @@ -686,16 +686,16 @@ async def get_transactions_and_sellers_by_wallet_id( async def get_transfers( db: AsyncSession, last_checked: datetime | None = None, -) -> Sequence[schemas_myeclpay.Transfer]: +) -> Sequence[schemas_mypayment.Transfer]: result = await db.execute( - select(models_myeclpay.Transfer).where( - models_myeclpay.Transfer.creation >= last_checked + select(models_mypayment.Transfer).where( + models_mypayment.Transfer.creation >= last_checked if last_checked else and_(True), ), ) return [ - schemas_myeclpay.Transfer( + schemas_mypayment.Transfer( id=transfer.id, type=transfer.type, transfer_identifier=transfer.transfer_identifier, @@ -710,10 +710,10 @@ async def get_transfers( async def create_transfer( - transfer: schemas_myeclpay.Transfer, + transfer: schemas_mypayment.Transfer, db: AsyncSession, ) -> None: - transfer_db = models_myeclpay.Transfer( + transfer_db = models_mypayment.Transfer( id=transfer.id, type=transfer.type, transfer_identifier=transfer.transfer_identifier, @@ -731,8 +731,8 @@ async def confirm_transfer( db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.Transfer) - .where(models_myeclpay.Transfer.id == transfer_id) + update(models_mypayment.Transfer) + .where(models_mypayment.Transfer.id == transfer_id) .values(confirmed=True), ) @@ -742,17 +742,17 @@ async def get_transfers_by_wallet_id( db: AsyncSession, start_datetime: datetime | None = None, end_datetime: datetime | None = None, -) -> Sequence[models_myeclpay.Transfer]: +) -> Sequence[models_mypayment.Transfer]: result = await db.execute( - select(models_myeclpay.Transfer) + select(models_mypayment.Transfer) .where( - models_myeclpay.Transfer.wallet_id == wallet_id, + models_mypayment.Transfer.wallet_id == wallet_id, ) .where( - models_myeclpay.Transfer.creation >= start_datetime + models_mypayment.Transfer.creation >= start_datetime if start_datetime else and_(True), - models_myeclpay.Transfer.creation <= end_datetime + models_mypayment.Transfer.creation <= end_datetime if end_datetime else and_(True), ), @@ -765,22 +765,22 @@ async def get_transfers_and_sellers_by_wallet_id( db: AsyncSession, start_datetime: datetime | None = None, end_datetime: datetime | None = None, -) -> Sequence[tuple[models_myeclpay.Transfer, str | None]]: +) -> Sequence[tuple[models_mypayment.Transfer, str | None]]: result = await db.execute( select( - models_myeclpay.Transfer, + models_mypayment.Transfer, models_users.CoreUser, ) .outerjoin( models_users.CoreUser, - models_users.CoreUser.id == models_myeclpay.Transfer.approver_user_id, + models_users.CoreUser.id == models_mypayment.Transfer.approver_user_id, ) .where( - models_myeclpay.Transfer.wallet_id == wallet_id, - models_myeclpay.Transfer.creation >= start_datetime + models_mypayment.Transfer.wallet_id == wallet_id, + models_mypayment.Transfer.creation >= start_datetime if start_datetime else and_(True), - models_myeclpay.Transfer.creation <= end_datetime + models_mypayment.Transfer.creation <= end_datetime if end_datetime else and_(True), ), @@ -799,10 +799,10 @@ async def get_transfers_and_sellers_by_wallet_id( async def get_transfer_by_transfer_identifier( db: AsyncSession, transfer_identifier: str, -) -> models_myeclpay.Transfer | None: +) -> models_mypayment.Transfer | None: result = await db.execute( - select(models_myeclpay.Transfer).where( - models_myeclpay.Transfer.transfer_identifier == transfer_identifier, + select(models_mypayment.Transfer).where( + models_mypayment.Transfer.transfer_identifier == transfer_identifier, ), ) return result.scalars().first() @@ -811,16 +811,16 @@ async def get_transfer_by_transfer_identifier( async def get_refunds( db: AsyncSession, last_checked: datetime | None = None, -) -> Sequence[schemas_myeclpay.RefundBase]: +) -> Sequence[schemas_mypayment.RefundBase]: result = await db.execute( - select(models_myeclpay.Refund).where( - models_myeclpay.Refund.creation >= last_checked + select(models_mypayment.Refund).where( + models_mypayment.Refund.creation >= last_checked if last_checked else and_(True), ), ) return [ - schemas_myeclpay.RefundBase( + schemas_mypayment.RefundBase( id=refund.id, transaction_id=refund.transaction_id, credited_wallet_id=refund.credited_wallet_id, @@ -834,10 +834,10 @@ async def get_refunds( async def create_refund( - refund: schemas_myeclpay.RefundBase, + refund: schemas_mypayment.RefundBase, db: AsyncSession, ) -> None: - refund_db = models_myeclpay.Refund( + refund_db = models_mypayment.Refund( id=refund.id, transaction_id=refund.transaction_id, credited_wallet_id=refund.credited_wallet_id, @@ -852,17 +852,17 @@ async def create_refund( async def get_refund_by_transaction_id( transaction_id: UUID, db: AsyncSession, -) -> schemas_myeclpay.Refund | None: +) -> schemas_mypayment.Refund | None: result = ( ( await db.execute( - select(models_myeclpay.Refund) + select(models_mypayment.Refund) .where( - models_myeclpay.Refund.transaction_id == transaction_id, + models_mypayment.Refund.transaction_id == transaction_id, ) .options( - selectinload(models_myeclpay.Refund.debited_wallet), - selectinload(models_myeclpay.Refund.credited_wallet), + selectinload(models_mypayment.Refund.debited_wallet), + selectinload(models_mypayment.Refund.credited_wallet), ), ) ) @@ -877,26 +877,26 @@ async def get_refunds_by_wallet_id( db: AsyncSession, start_datetime: datetime | None = None, end_datetime: datetime | None = None, -) -> Sequence[schemas_myeclpay.Refund]: +) -> Sequence[schemas_mypayment.Refund]: result = ( ( await db.execute( - select(models_myeclpay.Refund) + select(models_mypayment.Refund) .where( or_( - models_myeclpay.Refund.debited_wallet_id == wallet_id, - models_myeclpay.Refund.credited_wallet_id == wallet_id, + models_mypayment.Refund.debited_wallet_id == wallet_id, + models_mypayment.Refund.credited_wallet_id == wallet_id, ), - models_myeclpay.Refund.creation >= start_datetime + models_mypayment.Refund.creation >= start_datetime if start_datetime else and_(True), - models_myeclpay.Refund.creation <= end_datetime + models_mypayment.Refund.creation <= end_datetime if end_datetime else and_(True), ) .options( - selectinload(models_myeclpay.Refund.debited_wallet), - selectinload(models_myeclpay.Refund.credited_wallet), + selectinload(models_mypayment.Refund.debited_wallet), + selectinload(models_mypayment.Refund.credited_wallet), ), ) ) @@ -911,31 +911,31 @@ async def get_refunds_and_sellers_by_wallet_id( db: AsyncSession, start_datetime: datetime | None = None, end_datetime: datetime | None = None, -) -> Sequence[tuple[models_myeclpay.Refund, str | None]]: +) -> Sequence[tuple[models_mypayment.Refund, str | None]]: result = await db.execute( select( - models_myeclpay.Refund, + models_mypayment.Refund, models_users.CoreUser, ) .outerjoin( models_users.CoreUser, - models_users.CoreUser.id == models_myeclpay.Refund.seller_user_id, + models_users.CoreUser.id == models_mypayment.Refund.seller_user_id, ) .where( or_( - models_myeclpay.Refund.debited_wallet_id == wallet_id, - models_myeclpay.Refund.credited_wallet_id == wallet_id, + models_mypayment.Refund.debited_wallet_id == wallet_id, + models_mypayment.Refund.credited_wallet_id == wallet_id, ), - models_myeclpay.Refund.creation >= start_datetime + models_mypayment.Refund.creation >= start_datetime if start_datetime else and_(True), - models_myeclpay.Refund.creation <= end_datetime + models_mypayment.Refund.creation <= end_datetime if end_datetime else and_(True), ) .options( - selectinload(models_myeclpay.Refund.debited_wallet), - selectinload(models_myeclpay.Refund.credited_wallet), + selectinload(models_mypayment.Refund.debited_wallet), + selectinload(models_mypayment.Refund.credited_wallet), ), ) @@ -952,20 +952,20 @@ async def get_refunds_and_sellers_by_wallet_id( async def get_store( store_id: UUID, db: AsyncSession, -) -> models_myeclpay.Store | None: +) -> models_mypayment.Store | None: result = await db.execute( - select(models_myeclpay.Store).where( - models_myeclpay.Store.id == store_id, + select(models_mypayment.Store).where( + models_mypayment.Store.id == store_id, ), ) return result.scalars().first() async def create_used_qrcode( - qr_code: schemas_myeclpay.ScanInfo, + qr_code: schemas_mypayment.ScanInfo, db: AsyncSession, ) -> None: - wallet = models_myeclpay.UsedQRCode( + wallet = models_mypayment.UsedQRCode( qr_code_id=qr_code.id, qr_code_tot=qr_code.tot, qr_code_iat=qr_code.iat, @@ -979,10 +979,10 @@ async def create_used_qrcode( async def get_used_qrcode( qr_code_id: UUID, db: AsyncSession, -) -> models_myeclpay.UsedQRCode | None: +) -> models_mypayment.UsedQRCode | None: result = await db.execute( - select(models_myeclpay.UsedQRCode).where( - models_myeclpay.UsedQRCode.qr_code_id == qr_code_id, + select(models_mypayment.UsedQRCode).where( + models_mypayment.UsedQRCode.qr_code_id == qr_code_id, ), ) return result.scalars().first() @@ -993,8 +993,8 @@ async def delete_used_qrcode( db: AsyncSession, ) -> None: await db.execute( - delete(models_myeclpay.UsedQRCode).where( - models_myeclpay.UsedQRCode.qr_code_id == qr_code_id, + delete(models_mypayment.UsedQRCode).where( + models_mypayment.UsedQRCode.qr_code_id == qr_code_id, ), ) @@ -1006,20 +1006,20 @@ async def get_invoices( structures_ids: list[UUID] | None = None, start_date: datetime | None = None, end_date: datetime | None = None, -) -> list[schemas_myeclpay.Invoice]: +) -> list[schemas_mypayment.Invoice]: select_command = ( - select(models_myeclpay.Invoice) + select(models_mypayment.Invoice) .where( - models_myeclpay.Invoice.end_date >= start_date + models_mypayment.Invoice.end_date >= start_date if start_date else and_(True), - models_myeclpay.Invoice.end_date <= end_date if end_date else and_(True), - models_myeclpay.Invoice.structure_id.in_(structures_ids) + models_mypayment.Invoice.end_date <= end_date if end_date else and_(True), + models_mypayment.Invoice.structure_id.in_(structures_ids) if structures_ids else and_(True), ) .order_by( - models_myeclpay.Invoice.end_date.desc(), + models_mypayment.Invoice.end_date.desc(), ) ) if skip is not None: @@ -1033,13 +1033,13 @@ async def get_invoices( async def get_invoice_by_id( invoice_id: UUID, db: AsyncSession, -) -> schemas_myeclpay.Invoice | None: +) -> schemas_mypayment.Invoice | None: result = await db.execute( - select(models_myeclpay.Invoice) + select(models_mypayment.Invoice) .where( - models_myeclpay.Invoice.id == invoice_id, + models_mypayment.Invoice.id == invoice_id, ) - .with_for_update(of=models_myeclpay.Invoice), + .with_for_update(of=models_mypayment.Invoice), ) invoice = result.scalars().first() return invoice_model_to_schema(invoice) if invoice else None @@ -1048,11 +1048,11 @@ async def get_invoice_by_id( async def get_pending_invoices_by_structure_id( structure_id: UUID, db: AsyncSession, -) -> list[schemas_myeclpay.Invoice]: +) -> list[schemas_mypayment.Invoice]: result = await db.execute( - select(models_myeclpay.Invoice).where( - models_myeclpay.Invoice.structure_id == structure_id, - models_myeclpay.Invoice.received.is_(False), + select(models_mypayment.Invoice).where( + models_mypayment.Invoice.structure_id == structure_id, + models_mypayment.Invoice.received.is_(False), ), ) return [invoice_model_to_schema(invoice) for invoice in result.scalars().all()] @@ -1061,17 +1061,17 @@ async def get_pending_invoices_by_structure_id( async def get_unreceived_invoices_by_store_id( store_id: UUID, db: AsyncSession, -) -> list[schemas_myeclpay.InvoiceDetailBase]: +) -> list[schemas_mypayment.InvoiceDetailBase]: result = await db.execute( - select(models_myeclpay.InvoiceDetail) - .join(models_myeclpay.Invoice) + select(models_mypayment.InvoiceDetail) + .join(models_mypayment.Invoice) .where( - models_myeclpay.InvoiceDetail.store_id == store_id, - models_myeclpay.Invoice.received.is_(False), + models_mypayment.InvoiceDetail.store_id == store_id, + models_mypayment.Invoice.received.is_(False), ), ) return [ - schemas_myeclpay.InvoiceDetailBase( + schemas_mypayment.InvoiceDetailBase( invoice_id=detail.invoice_id, store_id=detail.store_id, total=detail.total, @@ -1081,10 +1081,10 @@ async def get_unreceived_invoices_by_store_id( async def create_invoice( - invoice: schemas_myeclpay.InvoiceInfo, + invoice: schemas_mypayment.InvoiceInfo, db: AsyncSession, ) -> None: - invoice_db = models_myeclpay.Invoice( + invoice_db = models_mypayment.Invoice( id=invoice.id, reference=invoice.reference, creation=invoice.creation, @@ -1096,7 +1096,7 @@ async def create_invoice( ) db.add(invoice_db) for detail in invoice.details: - detail_db = models_myeclpay.InvoiceDetail( + detail_db = models_mypayment.InvoiceDetail( invoice_id=invoice.id, store_id=detail.store_id, total=detail.total, @@ -1109,8 +1109,8 @@ async def update_invoice_received_status( db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.Invoice) - .where(models_myeclpay.Invoice.id == invoice_id) + update(models_mypayment.Invoice) + .where(models_mypayment.Invoice.id == invoice_id) .values(received=True), ) @@ -1121,8 +1121,8 @@ async def update_invoice_paid_status( db: AsyncSession, ) -> None: await db.execute( - update(models_myeclpay.Invoice) - .where(models_myeclpay.Invoice.id == invoice_id) + update(models_mypayment.Invoice) + .where(models_mypayment.Invoice.id == invoice_id) .values(paid=paid), ) @@ -1132,13 +1132,13 @@ async def delete_invoice( db: AsyncSession, ) -> None: await db.execute( - delete(models_myeclpay.InvoiceDetail).where( - models_myeclpay.InvoiceDetail.invoice_id == invoice_id, + delete(models_mypayment.InvoiceDetail).where( + models_mypayment.InvoiceDetail.invoice_id == invoice_id, ), ) await db.execute( - delete(models_myeclpay.Invoice).where( - models_myeclpay.Invoice.id == invoice_id, + delete(models_mypayment.Invoice).where( + models_mypayment.Invoice.id == invoice_id, ), ) @@ -1146,15 +1146,15 @@ async def delete_invoice( async def get_last_structure_invoice( structure_id: UUID, db: AsyncSession, -) -> schemas_myeclpay.Invoice | None: +) -> schemas_mypayment.Invoice | None: result = ( ( await db.execute( - select(models_myeclpay.Invoice) + select(models_mypayment.Invoice) .where( - models_myeclpay.Invoice.structure_id == structure_id, + models_mypayment.Invoice.structure_id == structure_id, ) - .order_by(models_myeclpay.Invoice.end_date.desc()) + .order_by(models_mypayment.Invoice.end_date.desc()) .limit(1), ) ) @@ -1165,10 +1165,10 @@ async def get_last_structure_invoice( async def add_withdrawal( - withdrawal: schemas_myeclpay.Withdrawal, + withdrawal: schemas_mypayment.Withdrawal, db: AsyncSession, ) -> None: - withdrawal_db = models_myeclpay.Withdrawal( + withdrawal_db = models_mypayment.Withdrawal( id=withdrawal.id, wallet_id=withdrawal.wallet_id, total=withdrawal.total, @@ -1179,10 +1179,10 @@ async def add_withdrawal( async def get_withdrawals( db: AsyncSession, -) -> list[schemas_myeclpay.Withdrawal]: - result = await db.execute(select(models_myeclpay.Withdrawal)) +) -> list[schemas_mypayment.Withdrawal]: + result = await db.execute(select(models_mypayment.Withdrawal)) return [ - schemas_myeclpay.Withdrawal( + schemas_mypayment.Withdrawal( id=withdrawal.id, wallet_id=withdrawal.wallet_id, total=withdrawal.total, @@ -1195,14 +1195,14 @@ async def get_withdrawals( async def get_withdrawals_by_wallet_id( wallet_id: UUID, db: AsyncSession, -) -> list[schemas_myeclpay.Withdrawal]: +) -> list[schemas_mypayment.Withdrawal]: result = await db.execute( - select(models_myeclpay.Withdrawal).where( - models_myeclpay.Withdrawal.wallet_id == wallet_id, + select(models_mypayment.Withdrawal).where( + models_mypayment.Withdrawal.wallet_id == wallet_id, ), ) return [ - schemas_myeclpay.Withdrawal( + schemas_mypayment.Withdrawal( id=withdrawal.id, wallet_id=withdrawal.wallet_id, total=withdrawal.total, diff --git a/app/core/myeclpay/dependencies_myeclpay.py b/app/core/mypayment/dependencies_mypayment.py similarity index 84% rename from app/core/myeclpay/dependencies_myeclpay.py rename to app/core/mypayment/dependencies_mypayment.py index 5d47a68e3f..bc8936bf54 100644 --- a/app/core/myeclpay/dependencies_myeclpay.py +++ b/app/core/mypayment/dependencies_mypayment.py @@ -1,8 +1,8 @@ from fastapi import Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession -from app.core.myeclpay.coredata_myeclpay import MyECLPayBankAccountHolder -from app.core.myeclpay.cruds_myeclpay import get_structure_by_id +from app.core.mypayment.coredata_mypayment import MyPaymentBankAccountHolder +from app.core.mypayment.cruds_mypayment import get_structure_by_id from app.core.users.models_users import CoreUser from app.dependencies import get_db, is_user from app.utils.tools import get_core_data @@ -14,7 +14,7 @@ async def is_user_bank_account_holder( ) -> CoreUser: """Check if the user is a bank account holder.""" account_holder = await get_core_data( - MyECLPayBankAccountHolder, + MyPaymentBankAccountHolder, db=db, ) structure = await get_structure_by_id( diff --git a/app/core/myeclpay/endpoints_myeclpay.py b/app/core/mypayment/endpoints_mypayment.py similarity index 80% rename from app/core/myeclpay/endpoints_myeclpay.py rename to app/core/mypayment/endpoints_mypayment.py index 0840be508a..b25e657e93 100644 --- a/app/core/myeclpay/endpoints_myeclpay.py +++ b/app/core/mypayment/endpoints_mypayment.py @@ -25,22 +25,22 @@ from app.core.memberships.utils_memberships import ( get_user_active_membership_to_association_membership, ) -from app.core.myeclpay import cruds_myeclpay, schemas_myeclpay -from app.core.myeclpay.coredata_myeclpay import MyECLPayBankAccountHolder -from app.core.myeclpay.dependencies_myeclpay import is_user_bank_account_holder -from app.core.myeclpay.exceptions_myeclpay import ( +from app.core.mypayment import cruds_mypayment, schemas_mypayment +from app.core.mypayment.coredata_mypayment import MyPaymentBankAccountHolder +from app.core.mypayment.dependencies_mypayment import is_user_bank_account_holder +from app.core.mypayment.exceptions_mypayment import ( InvoiceNotFoundAfterCreationError, ReferencedStructureNotFoundError, ) -from app.core.myeclpay.factory_myeclpay import MyECLPayFactory -from app.core.myeclpay.integrity_myeclpay import ( +from app.core.mypayment.factory_mypayment import MyPaymentFactory +from app.core.mypayment.integrity_mypayment import ( format_cancel_log, format_refund_log, format_transaction_log, format_withdrawal_log, ) -from app.core.myeclpay.models_myeclpay import Store, WalletDevice -from app.core.myeclpay.types_myeclpay import ( +from app.core.mypayment.models_mypayment import Store, WalletDevice +from app.core.mypayment.types_mypayment import ( HistoryType, TransactionStatus, TransactionType, @@ -49,8 +49,8 @@ WalletDeviceStatus, WalletType, ) -from app.core.myeclpay.utils.data_exporter import generate_store_history_csv -from app.core.myeclpay.utils_myeclpay import ( +from app.core.mypayment.utils.data_exporter import generate_store_history_csv +from app.core.mypayment.utils_mypayment import ( LATEST_TOS, QRCODE_EXPIRATION, is_user_latest_tos_signed, @@ -91,32 +91,32 @@ set_core_data, ) -router = APIRouter(tags=["MyECLPay"]) +router = APIRouter(tags=["MyPayment"]) core_module = CoreModule( - root="myeclpay", - tag="MyECLPay", + root="mypayment", + tag="MyPayment", router=router, payment_callback=validate_transfer_callback, - factory=MyECLPayFactory(), + factory=MyPaymentFactory(), ) hyperion_error_logger = logging.getLogger("hyperion.error") hyperion_security_logger = logging.getLogger("hyperion.security") -hyperion_myeclpay_logger = logging.getLogger("hyperion.myeclpay") +hyperion_mypayment_logger = logging.getLogger("hyperion.mypayment") -MYECLPAY_STRUCTURE_S3_SUBFOLDER = "structures" -MYECLPAY_STORES_S3_SUBFOLDER = "stores" -MYECLPAY_USERS_S3_SUBFOLDER = "users" -MYECLPAY_DEVICES_S3_SUBFOLDER = "devices" -MYECLPAY_LOGS_S3_SUBFOLDER = "logs" +MYPAYMENT_STRUCTURE_S3_SUBFOLDER = "structures" +MYPAYMENT_STORES_S3_SUBFOLDER = "stores" +MYPAYMENT_USERS_S3_SUBFOLDER = "users" +MYPAYMENT_DEVICES_S3_SUBFOLDER = "devices" +MYPAYMENT_LOGS_S3_SUBFOLDER = "logs" RETENTION_DURATION = 10 * 365 # 10 years in days @router.get( - "/myeclpay/bank-account-holder", - response_model=schemas_myeclpay.Structure, + "/mypayment/bank-account-holder", + response_model=schemas_mypayment.Structure, status_code=200, ) async def get_bank_account_holder( @@ -127,10 +127,10 @@ async def get_bank_account_holder( Get the current bank account holder information. """ bank_account_holder = await get_core_data( - MyECLPayBankAccountHolder, + MyPaymentBankAccountHolder, db=db, ) - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( db=db, structure_id=bank_account_holder.holder_structure_id, ) @@ -142,18 +142,18 @@ async def get_bank_account_holder( @router.post( - "/myeclpay/bank-account-holder", - response_model=schemas_myeclpay.Structure, + "/mypayment/bank-account-holder", + response_model=schemas_mypayment.Structure, status_code=201, ) async def set_bank_account_holder( - bank_account_info: MyECLPayBankAccountHolder, + bank_account_info: MyPaymentBankAccountHolder, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user_in(GroupType.admin)), ): """Set the bank account holder information.""" - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=bank_account_info.holder_structure_id, db=db, ) @@ -172,9 +172,9 @@ async def set_bank_account_holder( @router.get( - "/myeclpay/structures", + "/mypayment/structures", status_code=200, - response_model=list[schemas_myeclpay.Structure], + response_model=list[schemas_mypayment.Structure], ) async def get_structures( db: AsyncSession = Depends(get_db), @@ -183,18 +183,18 @@ async def get_structures( """ Get all structures. """ - return await cruds_myeclpay.get_structures( + return await cruds_mypayment.get_structures( db=db, ) @router.post( - "/myeclpay/structures", + "/mypayment/structures", status_code=201, - response_model=schemas_myeclpay.Structure, + response_model=schemas_mypayment.Structure, ) async def create_structure( - structure: schemas_myeclpay.StructureBase, + structure: schemas_mypayment.StructureBase, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user_in(GroupType.admin)), ): @@ -218,7 +218,7 @@ async def create_structure( status_code=404, detail="Manager user does not exist", ) - structure_db = schemas_myeclpay.StructureSimple( + structure_db = schemas_mypayment.StructureSimple( id=uuid.uuid4(), short_id=structure.short_id, name=structure.name, @@ -233,29 +233,29 @@ async def create_structure( bic=structure.bic, creation=datetime.now(tz=UTC), ) - await cruds_myeclpay.create_structure( + await cruds_mypayment.create_structure( structure=structure_db, db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( structure_db.name, extra={ - "s3_subfolder": MYECLPAY_STRUCTURE_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_STRUCTURE_S3_SUBFOLDER, "s3_filename": str(structure_db.id), }, ) - return await cruds_myeclpay.get_structure_by_id(structure_db.id, db) + return await cruds_mypayment.get_structure_by_id(structure_db.id, db) @router.patch( - "/myeclpay/structures/{structure_id}", + "/mypayment/structures/{structure_id}", status_code=204, ) async def update_structure( structure_id: UUID, - structure_update: schemas_myeclpay.StructureUpdate, + structure_update: schemas_mypayment.StructureUpdate, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user_in(GroupType.admin)), ): @@ -264,7 +264,7 @@ async def update_structure( **The user must be an admin to use this endpoint** """ - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=structure_id, db=db, ) @@ -274,23 +274,23 @@ async def update_structure( detail="Structure does not exist", ) - await cruds_myeclpay.update_structure( + await cruds_mypayment.update_structure( structure_id=structure_id, structure_update=structure_update, db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( structure.name, extra={ - "s3_subfolder": MYECLPAY_STRUCTURE_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_STRUCTURE_S3_SUBFOLDER, "s3_filename": str(structure.id), }, ) @router.delete( - "/myeclpay/structures/{structure_id}", + "/mypayment/structures/{structure_id}", status_code=204, ) async def delete_structure( @@ -303,7 +303,7 @@ async def delete_structure( **The user must be an admin to use this endpoint** """ - stores = await cruds_myeclpay.get_stores_by_structure_id( + stores = await cruds_mypayment.get_stores_by_structure_id( structure_id=structure_id, db=db, ) @@ -313,19 +313,19 @@ async def delete_structure( detail="Structure has stores", ) - await cruds_myeclpay.delete_structure( + await cruds_mypayment.delete_structure( structure_id=structure_id, db=db, ) @router.post( - "/myeclpay/structures/{structure_id}/init-manager-transfer", + "/mypayment/structures/{structure_id}/init-manager-transfer", status_code=201, ) async def init_transfer_structure_manager( structure_id: UUID, - transfer_info: schemas_myeclpay.StructureTranfert, + transfer_info: schemas_mypayment.StructureTranfert, background_tasks: BackgroundTasks, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), @@ -338,7 +338,7 @@ async def init_transfer_structure_manager( **The user must be the manager for this structure** """ - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=structure_id, db=db, ) @@ -354,7 +354,7 @@ async def init_transfer_structure_manager( ) # If a previous transfer request exists, delete it - await cruds_myeclpay.delete_structure_manager_transfer_by_structure( + await cruds_mypayment.delete_structure_manager_transfer_by_structure( structure_id=structure_id, db=db, ) @@ -371,19 +371,19 @@ async def init_transfer_structure_manager( confirmation_token = security.generate_token() - await cruds_myeclpay.init_structure_manager_transfer( + await cruds_mypayment.init_structure_manager_transfer( structure_id=structure_id, user_id=transfer_info.new_manager_user_id, confirmation_token=confirmation_token, valid_until=datetime.now(tz=UTC) - + timedelta(minutes=settings.MYECLPAY_MANAGER_TRANSFER_TOKEN_EXPIRES_MINUTES), + + timedelta(minutes=settings.MYPAYMENT_MANAGER_TRANSFER_TOKEN_EXPIRES_MINUTES), db=db, ) - confirmation_url = f"{settings.CLIENT_URL}myeclpay/structures/confirm-manager-transfer?token={confirmation_token}" + confirmation_url = f"{settings.CLIENT_URL}mypayment/structures/confirm-manager-transfer?token={confirmation_token}" if settings.SMTP_ACTIVE: - mail = mail_templates.get_mail_myeclpay_structure_transfer( + mail = mail_templates.get_mail_mypayment_structure_transfer( confirmation_url=confirmation_url, ) @@ -401,7 +401,7 @@ async def init_transfer_structure_manager( @router.get( - "/myeclpay/structures/confirm-manager-transfer", + "/mypayment/structures/confirm-manager-transfer", status_code=200, ) async def confirm_structure_manager_transfer( @@ -415,7 +415,7 @@ async def confirm_structure_manager_transfer( The user must have initiated the update of the manager with `init_update_structure_manager` """ - request = await cruds_myeclpay.get_structure_manager_transfer_by_secret( + request = await cruds_mypayment.get_structure_manager_transfer_by_secret( confirmation_token=token, db=db, ) @@ -431,25 +431,25 @@ async def confirm_structure_manager_transfer( detail="Request has expired", ) - await cruds_myeclpay.update_structure_manager( + await cruds_mypayment.update_structure_manager( structure_id=request.structure_id, manager_user_id=request.user_id, db=db, ) # We will add the new manager as a seller for all stores of the structure - stores = await cruds_myeclpay.get_stores_by_structure_id( + stores = await cruds_mypayment.get_stores_by_structure_id( structure_id=request.structure_id, db=db, ) - sellers = await cruds_myeclpay.get_sellers_by_user_id( + sellers = await cruds_mypayment.get_sellers_by_user_id( user_id=request.user_id, db=db, ) sellers_store_ids = [seller.store_id for seller in sellers] for store in stores: if store.id not in sellers_store_ids: - await cruds_myeclpay.create_seller( + await cruds_mypayment.create_seller( user_id=request.user_id, store_id=store.id, can_bank=True, @@ -459,10 +459,10 @@ async def confirm_structure_manager_transfer( db=db, ) else: - await cruds_myeclpay.update_seller( + await cruds_mypayment.update_seller( seller_user_id=request.user_id, store_id=store.id, - seller_update=schemas_myeclpay.SellerUpdate( + seller_update=schemas_mypayment.SellerUpdate( can_bank=True, can_see_history=True, can_cancel=True, @@ -474,19 +474,19 @@ async def confirm_structure_manager_transfer( return RedirectResponse( url=settings.CLIENT_URL + calypsso.get_message_relative_url( - message_type=calypsso.TypeMessage.myeclpay_structure_transfer_success, + message_type=calypsso.TypeMessage.mypayment_structure_transfer_success, ), ) @router.post( - "/myeclpay/structures/{structure_id}/stores", + "/mypayment/structures/{structure_id}/stores", status_code=201, - response_model=schemas_myeclpay.Store, + response_model=schemas_mypayment.Store, ) async def create_store( structure_id: UUID, - store: schemas_myeclpay.StoreBase, + store: schemas_mypayment.StoreBase, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), ): @@ -497,7 +497,7 @@ async def create_store( **The user must be the manager for this structure** """ - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=structure_id, db=db, ) @@ -512,7 +512,7 @@ async def create_store( detail="User is not the manager for this structure", ) - existing_store_with_name = await cruds_myeclpay.get_store_by_name( + existing_store_with_name = await cruds_mypayment.get_store_by_name( name=store.name, db=db, ) @@ -524,7 +524,7 @@ async def create_store( # Create new wallet for store wallet_id = uuid.uuid4() - await cruds_myeclpay.create_wallet( + await cruds_mypayment.create_wallet( wallet_id=wallet_id, wallet_type=WalletType.STORE, balance=0, @@ -538,14 +538,14 @@ async def create_store( wallet_id=wallet_id, creation=datetime.now(tz=UTC), ) - await cruds_myeclpay.create_store( + await cruds_mypayment.create_store( store=store_db, db=db, ) await db.flush() # Add manager as an full right seller for the store - await cruds_myeclpay.create_seller( + await cruds_mypayment.create_seller( user_id=user.id, store_id=store_db.id, can_bank=True, @@ -555,15 +555,15 @@ async def create_store( db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( f"store.name: {store_db.name}, structure_id: {store_db.structure_id}", extra={ - "s3_subfolder": MYECLPAY_STORES_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_STORES_S3_SUBFOLDER, "s3_filename": str(store_db.id), }, ) - return schemas_myeclpay.Store( + return schemas_mypayment.Store( id=store_db.id, name=store_db.name, structure_id=store_db.structure_id, @@ -574,9 +574,9 @@ async def create_store( @router.get( - "/myeclpay/stores/{store_id}/history", + "/mypayment/stores/{store_id}/history", status_code=200, - response_model=list[schemas_myeclpay.History], + response_model=list[schemas_mypayment.History], ) async def get_store_history( store_id: UUID, @@ -590,7 +590,7 @@ async def get_store_history( **The user must be authorized to see the store history** """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -600,7 +600,7 @@ async def get_store_history( detail="Store does not exist", ) - seller = await cruds_myeclpay.get_seller( + seller = await cruds_mypayment.get_seller( user_id=user.id, store_id=store_id, db=db, @@ -613,23 +613,23 @@ async def get_store_history( history = [] - transactions = await cruds_myeclpay.get_transactions_by_wallet_id( + transactions = await cruds_mypayment.get_transactions_by_wallet_id( wallet_id=store.wallet_id, db=db, start_datetime=start_date, end_datetime=end_date, ) for transaction in transactions: - history_refund: schemas_myeclpay.HistoryRefund | None = None + history_refund: schemas_mypayment.HistoryRefund | None = None if transaction.refund is not None: - history_refund = schemas_myeclpay.HistoryRefund( + history_refund = schemas_mypayment.HistoryRefund( total=transaction.refund.total, creation=transaction.refund.creation, ) if transaction.debited_wallet_id == store.wallet_id: history.append( - schemas_myeclpay.History( + schemas_mypayment.History( id=transaction.id, type=HistoryType.GIVEN, total=transaction.total, @@ -643,7 +643,7 @@ async def get_store_history( ) else: history.append( - schemas_myeclpay.History( + schemas_mypayment.History( id=transaction.id, type=HistoryType.RECEIVED, total=transaction.total, @@ -656,7 +656,7 @@ async def get_store_history( ), ) - transfers = await cruds_myeclpay.get_transfers_by_wallet_id( + transfers = await cruds_mypayment.get_transfers_by_wallet_id( wallet_id=store.wallet_id, db=db, start_datetime=start_date, @@ -668,7 +668,7 @@ async def get_store_history( ) # We add refunds - refunds = await cruds_myeclpay.get_refunds_by_wallet_id( + refunds = await cruds_mypayment.get_refunds_by_wallet_id( wallet_id=store.wallet_id, db=db, start_datetime=start_date, @@ -683,7 +683,7 @@ async def get_store_history( other_wallet_info = refund.debited_wallet history.append( - schemas_myeclpay.History( + schemas_mypayment.History( id=refund.id, type=transaction_type, other_wallet_name=other_wallet_info.owner_name or "Unknown", @@ -697,7 +697,7 @@ async def get_store_history( @router.get( - "/myeclpay/stores/{store_id}/history/data-export", + "/mypayment/stores/{store_id}/history/data-export", status_code=200, response_model=None, ) @@ -711,7 +711,7 @@ async def export_store_history( """ Export store payment history as a CSV file. """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -721,7 +721,7 @@ async def export_store_history( detail="Store does not exist", ) - seller = await cruds_myeclpay.get_seller( + seller = await cruds_mypayment.get_seller( user_id=user.id, store_id=store_id, db=db, @@ -733,7 +733,7 @@ async def export_store_history( ) transactions_with_sellers = ( - await cruds_myeclpay.get_transactions_and_sellers_by_wallet_id( + await cruds_mypayment.get_transactions_and_sellers_by_wallet_id( wallet_id=store.wallet_id, db=db, start_datetime=start_date, @@ -742,7 +742,7 @@ async def export_store_history( ) transfers_with_sellers = ( - await cruds_myeclpay.get_transfers_and_sellers_by_wallet_id( + await cruds_mypayment.get_transfers_and_sellers_by_wallet_id( wallet_id=store.wallet_id, db=db, start_datetime=start_date, @@ -755,7 +755,7 @@ async def export_store_history( ) # We add refunds - refunds_with_sellers = await cruds_myeclpay.get_refunds_and_sellers_by_wallet_id( + refunds_with_sellers = await cruds_mypayment.get_refunds_and_sellers_by_wallet_id( wallet_id=store.wallet_id, db=db, start_datetime=start_date, @@ -804,9 +804,9 @@ async def export_store_history( @router.get( - "/myeclpay/users/me/stores", + "/mypayment/users/me/stores", status_code=200, - response_model=list[schemas_myeclpay.UserStore], + response_model=list[schemas_mypayment.UserStore], ) async def get_user_stores( db: AsyncSession = Depends(get_db), @@ -817,20 +817,20 @@ async def get_user_stores( **The user must be authenticated to use this endpoint** """ - sellers = await cruds_myeclpay.get_sellers_by_user_id( + sellers = await cruds_mypayment.get_sellers_by_user_id( user_id=user.id, db=db, ) - stores: list[schemas_myeclpay.UserStore] = [] + stores: list[schemas_mypayment.UserStore] = [] for seller in sellers: - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=seller.store_id, db=db, ) if store is not None: stores.append( - schemas_myeclpay.UserStore( + schemas_mypayment.UserStore( id=store.id, name=store.name, creation=store.creation, @@ -848,12 +848,12 @@ async def get_user_stores( @router.patch( - "/myeclpay/stores/{store_id}", + "/mypayment/stores/{store_id}", status_code=204, ) async def update_store( store_id: UUID, - store_update: schemas_myeclpay.StoreUpdate, + store_update: schemas_mypayment.StoreUpdate, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), ): @@ -862,7 +862,7 @@ async def update_store( **The user must be the manager for this store's structure** """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -872,7 +872,7 @@ async def update_store( detail="Store does not exist", ) - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=store.structure_id, db=db, ) @@ -882,23 +882,23 @@ async def update_store( detail="User is not the manager for this structure", ) - await cruds_myeclpay.update_store( + await cruds_mypayment.update_store( store_id=store_id, store_update=store_update, db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( f"store.name: {store.name}, structure_id: {store.structure_id}", extra={ - "s3_subfolder": MYECLPAY_STORES_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_STORES_S3_SUBFOLDER, "s3_filename": str(store.id), }, ) @router.delete( - "/myeclpay/stores/{store_id}", + "/mypayment/stores/{store_id}", status_code=204, ) async def delete_store( @@ -911,7 +911,7 @@ async def delete_store( **The user must be the manager for this store's structure** """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -921,7 +921,7 @@ async def delete_store( detail="Store does not exist", ) - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=store.structure_id, db=db, ) @@ -931,15 +931,15 @@ async def delete_store( detail="User is not the manager for this structure", ) - transactions = await cruds_myeclpay.get_transactions_by_wallet_id( + transactions = await cruds_mypayment.get_transactions_by_wallet_id( wallet_id=store.wallet_id, db=db, ) - transfers = await cruds_myeclpay.get_transfers_by_wallet_id( + transfers = await cruds_mypayment.get_transfers_by_wallet_id( wallet_id=store.wallet_id, db=db, ) - refunds = await cruds_myeclpay.get_refunds_by_wallet_id( + refunds = await cruds_mypayment.get_refunds_by_wallet_id( wallet_id=store.wallet_id, db=db, ) @@ -949,31 +949,31 @@ async def delete_store( detail="Store has items in history and cannot be deleted anymore", ) - sellers = await cruds_myeclpay.get_sellers_by_store_id( + sellers = await cruds_mypayment.get_sellers_by_store_id( store_id=store_id, db=db, ) for seller in sellers: - await cruds_myeclpay.delete_seller( + await cruds_mypayment.delete_seller( seller_user_id=seller.user_id, store_id=store_id, db=db, ) - await cruds_myeclpay.delete_store( + await cruds_mypayment.delete_store( store_id=store_id, db=db, ) @router.post( - "/myeclpay/stores/{store_id}/sellers", + "/mypayment/stores/{store_id}/sellers", status_code=201, - response_model=schemas_myeclpay.Seller, + response_model=schemas_mypayment.Seller, ) async def create_store_seller( store_id: UUID, - seller: schemas_myeclpay.SellerCreation, + seller: schemas_mypayment.SellerCreation, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), ): @@ -988,7 +988,7 @@ async def create_store_seller( **The user must have the `can_manage_sellers` permission for this store** """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -998,7 +998,7 @@ async def create_store_seller( detail="Store does not exist", ) - seller_admin = await cruds_myeclpay.get_seller( + seller_admin = await cruds_mypayment.get_seller( user_id=user.id, store_id=store_id, db=db, @@ -1009,7 +1009,7 @@ async def create_store_seller( detail="User does not have the permission to manage sellers", ) - existing_seller = await cruds_myeclpay.get_seller( + existing_seller = await cruds_mypayment.get_seller( user_id=seller.user_id, store_id=store_id, db=db, @@ -1020,7 +1020,7 @@ async def create_store_seller( detail="Seller already exists", ) - await cruds_myeclpay.create_seller( + await cruds_mypayment.create_seller( user_id=seller.user_id, store_id=store_id, can_bank=seller.can_bank, @@ -1030,7 +1030,7 @@ async def create_store_seller( db=db, ) - return await cruds_myeclpay.get_seller( + return await cruds_mypayment.get_seller( user_id=seller.user_id, store_id=store_id, db=db, @@ -1038,9 +1038,9 @@ async def create_store_seller( @router.get( - "/myeclpay/stores/{store_id}/sellers", + "/mypayment/stores/{store_id}/sellers", status_code=200, - response_model=list[schemas_myeclpay.Seller], + response_model=list[schemas_mypayment.Seller], ) async def get_store_sellers( store_id: UUID, @@ -1052,7 +1052,7 @@ async def get_store_sellers( **The user must have the `can_manage_sellers` permission for this store** """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -1062,7 +1062,7 @@ async def get_store_sellers( detail="Store does not exist", ) - seller_admin = await cruds_myeclpay.get_seller( + seller_admin = await cruds_mypayment.get_seller( user_id=user.id, store_id=store_id, db=db, @@ -1073,20 +1073,20 @@ async def get_store_sellers( detail="User does not have the permission to manage sellers", ) - return await cruds_myeclpay.get_sellers_by_store_id( + return await cruds_mypayment.get_sellers_by_store_id( store_id=store_id, db=db, ) @router.patch( - "/myeclpay/stores/{store_id}/sellers/{seller_user_id}", + "/mypayment/stores/{store_id}/sellers/{seller_user_id}", status_code=204, ) async def update_store_seller( store_id: UUID, seller_user_id: str, - seller_update: schemas_myeclpay.SellerUpdate, + seller_update: schemas_mypayment.SellerUpdate, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), ): @@ -1097,7 +1097,7 @@ async def update_store_seller( **The user must have the `can_manage_sellers` permission for this store** """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -1107,7 +1107,7 @@ async def update_store_seller( detail="Store does not exist", ) - seller_admin = await cruds_myeclpay.get_seller( + seller_admin = await cruds_mypayment.get_seller( user_id=user.id, store_id=store_id, db=db, @@ -1118,7 +1118,7 @@ async def update_store_seller( detail="User does not have the permission to manage sellers", ) - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=store.structure_id, db=db, ) @@ -1128,7 +1128,7 @@ async def update_store_seller( detail="User is the manager for this structure and cannot be updated as a seller", ) - seller = await cruds_myeclpay.get_seller( + seller = await cruds_mypayment.get_seller( user_id=seller_user_id, store_id=store_id, db=db, @@ -1140,7 +1140,7 @@ async def update_store_seller( detail="Seller does not exist", ) - await cruds_myeclpay.update_seller( + await cruds_mypayment.update_seller( seller_user_id=seller_user_id, store_id=store_id, seller_update=seller_update, @@ -1149,7 +1149,7 @@ async def update_store_seller( @router.delete( - "/myeclpay/stores/{store_id}/sellers/{seller_user_id}", + "/mypayment/stores/{store_id}/sellers/{seller_user_id}", status_code=204, ) async def delete_store_seller( @@ -1164,7 +1164,7 @@ async def delete_store_seller( **The user must have the `can_manage_sellers` permission for this store** """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -1174,7 +1174,7 @@ async def delete_store_seller( detail="Store does not exist", ) - seller_admin = await cruds_myeclpay.get_seller( + seller_admin = await cruds_mypayment.get_seller( user_id=user.id, store_id=store_id, db=db, @@ -1185,7 +1185,7 @@ async def delete_store_seller( detail="User does not have the permission to manage sellers", ) - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=store.structure_id, db=db, ) @@ -1195,7 +1195,7 @@ async def delete_store_seller( detail="User is the manager for this structure and cannot be deleted as a seller", ) - seller = await cruds_myeclpay.get_seller( + seller = await cruds_mypayment.get_seller( user_id=seller_user_id, store_id=store_id, db=db, @@ -1207,7 +1207,7 @@ async def delete_store_seller( detail="Seller does not exist", ) - await cruds_myeclpay.delete_seller( + await cruds_mypayment.delete_seller( seller_user_id=seller_user_id, store_id=store_id, db=db, @@ -1215,7 +1215,7 @@ async def delete_store_seller( @router.post( - "/myeclpay/users/me/register", + "/mypayment/users/me/register", status_code=204, ) async def register_user( @@ -1231,7 +1231,7 @@ async def register_user( """ # Check if user is already registered - existing_user_payment = await cruds_myeclpay.get_user_payment( + existing_user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1243,7 +1243,7 @@ async def register_user( # Create new wallet for user wallet_id = uuid.uuid4() - await cruds_myeclpay.create_wallet( + await cruds_mypayment.create_wallet( wallet_id=wallet_id, wallet_type=WalletType.USER, balance=0, @@ -1253,7 +1253,7 @@ async def register_user( await db.flush() # Create new payment user with wallet - await cruds_myeclpay.create_user_payment( + await cruds_mypayment.create_user_payment( user_id=user.id, wallet_id=wallet_id, accepted_tos_signature=datetime.now(UTC), @@ -1261,19 +1261,19 @@ async def register_user( db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( wallet_id, extra={ - "s3_subfolder": MYECLPAY_USERS_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_USERS_S3_SUBFOLDER, "s3_filename": str(user.id), }, ) @router.get( - "/myeclpay/users/me/tos", + "/mypayment/users/me/tos", status_code=200, - response_model=schemas_myeclpay.TOSSignatureResponse, + response_model=schemas_mypayment.TOSSignatureResponse, ) async def get_user_tos( db: AsyncSession = Depends(get_db), @@ -1286,7 +1286,7 @@ async def get_user_tos( **The user must be authenticated to use this endpoint** """ # Check if user is already registered - existing_user_payment = await cruds_myeclpay.get_user_payment( + existing_user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1296,20 +1296,20 @@ async def get_user_tos( detail="User is not registered for MyECL Pay", ) - return schemas_myeclpay.TOSSignatureResponse( + return schemas_mypayment.TOSSignatureResponse( accepted_tos_version=existing_user_payment.accepted_tos_version, latest_tos_version=LATEST_TOS, - tos_content=Path("assets/myeclpay-terms-of-service.txt").read_text(), - max_wallet_balance=settings.MYECLPAY_MAXIMUM_WALLET_BALANCE, + tos_content=Path("assets/mypayment-terms-of-service.txt").read_text(), + max_wallet_balance=settings.MYPAYMENT_MAXIMUM_WALLET_BALANCE, ) @router.post( - "/myeclpay/users/me/tos", + "/mypayment/users/me/tos", status_code=204, ) async def sign_tos( - signature: schemas_myeclpay.TOSSignature, + signature: schemas_mypayment.TOSSignature, background_tasks: BackgroundTasks, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), @@ -1319,7 +1319,7 @@ async def sign_tos( """ Sign MyECL Pay TOS for the given user. - If the user is already registered in the MyECLPay system, this will update the TOS version. + If the user is already registered in the MyPayment system, this will update the TOS version. **The user must be authenticated to use this endpoint** """ @@ -1330,7 +1330,7 @@ async def sign_tos( ) # Check if user is already registered - existing_user_payment = await cruds_myeclpay.get_user_payment( + existing_user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1341,7 +1341,7 @@ async def sign_tos( ) # Update existing user payment - await cruds_myeclpay.update_user_payment( + await cruds_mypayment.update_user_payment( user_id=user.id, accepted_tos_signature=datetime.now(UTC), accepted_tos_version=signature.accepted_tos_version, @@ -1350,27 +1350,27 @@ async def sign_tos( # TODO: add logs if settings.SMTP_ACTIVE: - mail = mail_templates.get_mail_myeclpay_tos_signed( + mail = mail_templates.get_mail_mypayment_tos_signed( tos_version=signature.accepted_tos_version, tos_url=settings.CLIENT_URL + calypsso.get_asset_relative_url( - asset=calypsso.Asset.myeclpay_terms_of_service, + asset=calypsso.Asset.mypayment_terms_of_service, ), ) background_tasks.add_task( send_email, recipient=user.email, - subject="MyECL - You signed the Terms of Service for MyECLPay", + subject="MyECL - You signed the Terms of Service for MyPayment", content=mail, settings=settings, ) @router.get( - "/myeclpay/users/me/wallet/devices", + "/mypayment/users/me/wallet/devices", status_code=200, - response_model=list[schemas_myeclpay.WalletDevice], + response_model=list[schemas_mypayment.WalletDevice], ) async def get_user_devices( db: AsyncSession = Depends(get_db), @@ -1382,7 +1382,7 @@ async def get_user_devices( **The user must be authenticated to use this endpoint** """ # Check if user is already registered - user_payment = await cruds_myeclpay.get_user_payment( + user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1392,16 +1392,16 @@ async def get_user_devices( detail="User is not registered for MyECL Pay", ) - return await cruds_myeclpay.get_wallet_devices_by_wallet_id( + return await cruds_mypayment.get_wallet_devices_by_wallet_id( wallet_id=user_payment.wallet_id, db=db, ) @router.get( - "/myeclpay/users/me/wallet/devices/{wallet_device_id}", + "/mypayment/users/me/wallet/devices/{wallet_device_id}", status_code=200, - response_model=schemas_myeclpay.WalletDevice, + response_model=schemas_mypayment.WalletDevice, ) async def get_user_device( wallet_device_id: UUID, @@ -1414,7 +1414,7 @@ async def get_user_device( **The user must be authenticated to use this endpoint** """ # Check if user is already registered - user_payment = await cruds_myeclpay.get_user_payment( + user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1424,7 +1424,7 @@ async def get_user_device( detail="User is not registered for MyECL Pay", ) - wallet_device = await cruds_myeclpay.get_wallet_device( + wallet_device = await cruds_mypayment.get_wallet_device( wallet_device_id=wallet_device_id, db=db, ) @@ -1445,9 +1445,9 @@ async def get_user_device( @router.get( - "/myeclpay/users/me/wallet", + "/mypayment/users/me/wallet", status_code=200, - response_model=schemas_myeclpay.Wallet, + response_model=schemas_mypayment.Wallet, ) async def get_user_wallet( db: AsyncSession = Depends(get_db), @@ -1459,7 +1459,7 @@ async def get_user_wallet( **The user must be authenticated to use this endpoint** """ # Check if user is already registered - user_payment = await cruds_myeclpay.get_user_payment( + user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1469,7 +1469,7 @@ async def get_user_wallet( detail="User is not registered for MyECL Pay", ) - wallet = await cruds_myeclpay.get_wallet( + wallet = await cruds_mypayment.get_wallet( wallet_id=user_payment.wallet_id, db=db, ) @@ -1484,12 +1484,12 @@ async def get_user_wallet( @router.post( - "/myeclpay/users/me/wallet/devices", + "/mypayment/users/me/wallet/devices", status_code=201, - response_model=schemas_myeclpay.WalletDevice, + response_model=schemas_mypayment.WalletDevice, ) async def create_user_devices( - wallet_device_creation: schemas_myeclpay.WalletDeviceCreation, + wallet_device_creation: schemas_mypayment.WalletDeviceCreation, background_tasks: BackgroundTasks, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), @@ -1503,7 +1503,7 @@ async def create_user_devices( **The user must be authenticated to use this endpoint** """ # Check if user is already registered - user_payment = await cruds_myeclpay.get_user_payment( + user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1527,14 +1527,14 @@ async def create_user_devices( activation_token=activation_token, ) - await cruds_myeclpay.create_wallet_device( + await cruds_mypayment.create_wallet_device( wallet_device=wallet_device_db, db=db, ) if settings.SMTP_ACTIVE: - mail = mail_templates.get_mail_myeclpay_device_activation( - activation_url=f"{settings.CLIENT_URL}myeclpay/devices/activate?token={activation_token}", + mail = mail_templates.get_mail_mypayment_device_activation( + activation_url=f"{settings.CLIENT_URL}mypayment/devices/activate?token={activation_token}", ) background_tasks.add_task( @@ -1546,12 +1546,12 @@ async def create_user_devices( ) else: hyperion_error_logger.warning( - f"MyECLPay: activate your device using the token: {activation_token}", + f"MyPayment: activate your device using the token: {activation_token}", ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( wallet_device_creation.ed25519_public_key, extra={ - "s3_subfolder": f"{MYECLPAY_DEVICES_S3_SUBFOLDER}/{user.id}", + "s3_subfolder": f"{MYPAYMENT_DEVICES_S3_SUBFOLDER}/{user.id}", "s3_filename": str(wallet_device_db.id), }, ) @@ -1560,7 +1560,7 @@ async def create_user_devices( @router.get( - "/myeclpay/devices/activate", + "/mypayment/devices/activate", status_code=200, ) async def activate_user_device( @@ -1573,7 +1573,7 @@ async def activate_user_device( Activate a wallet device """ - wallet_device = await cruds_myeclpay.get_wallet_device_by_activation_token( + wallet_device = await cruds_mypayment.get_wallet_device_by_activation_token( activation_token=token, db=db, ) @@ -1588,17 +1588,17 @@ async def activate_user_device( return RedirectResponse( url=settings.CLIENT_URL + calypsso.get_message_relative_url( - message_type=calypsso.TypeMessage.myeclpay_wallet_device_already_activated_or_revoked, + message_type=calypsso.TypeMessage.mypayment_wallet_device_already_activated_or_revoked, ), ) - await cruds_myeclpay.update_wallet_device_status( + await cruds_mypayment.update_wallet_device_status( wallet_device_id=wallet_device.id, status=WalletDeviceStatus.ACTIVE, db=db, ) - wallet = await cruds_myeclpay.get_wallet( + wallet = await cruds_mypayment.get_wallet( wallet_id=wallet_device.wallet_id, db=db, ) @@ -1617,7 +1617,7 @@ async def activate_user_device( message = Message( title="💳 Paiement - appareil activé", content=f"Vous avez activé l'appareil {wallet_device.name}", - action_module="MyECLPay", + action_module=settings.school.payment_name, ) await notification_tool.send_notification_to_user( user_id=user.id, @@ -1629,13 +1629,13 @@ async def activate_user_device( return RedirectResponse( url=settings.CLIENT_URL + calypsso.get_message_relative_url( - message_type=calypsso.TypeMessage.myeclpay_wallet_device_activation_success, + message_type=calypsso.TypeMessage.mypayment_wallet_device_activation_success, ), ) @router.post( - "/myeclpay/users/me/wallet/devices/{wallet_device_id}/revoke", + "/mypayment/users/me/wallet/devices/{wallet_device_id}/revoke", status_code=204, ) async def revoke_user_devices( @@ -1643,6 +1643,7 @@ async def revoke_user_devices( db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), notification_tool: NotificationTool = Depends(get_notification_tool), + settings: Settings = Depends(get_settings), ): """ Revoke a device for the user. @@ -1650,7 +1651,7 @@ async def revoke_user_devices( **The user must be authenticated to use this endpoint** """ # Check if user is already registered - user_payment = await cruds_myeclpay.get_user_payment( + user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1660,7 +1661,7 @@ async def revoke_user_devices( detail="User is not registered for MyECL Pay", ) - wallet_device = await cruds_myeclpay.get_wallet_device( + wallet_device = await cruds_mypayment.get_wallet_device( wallet_device_id=wallet_device_id, db=db, ) @@ -1677,7 +1678,7 @@ async def revoke_user_devices( detail="Wallet device does not belong to the user", ) - await cruds_myeclpay.update_wallet_device_status( + await cruds_mypayment.update_wallet_device_status( wallet_device_id=wallet_device_id, status=WalletDeviceStatus.REVOKED, db=db, @@ -1690,7 +1691,7 @@ async def revoke_user_devices( message = Message( title="💳 Paiement - appareil revoqué", content=f"Vous avez revoqué l'appareil {wallet_device.name}", - action_module="MyECLPay", + action_module=settings.school.payment_name, ) await notification_tool.send_notification_to_user( user_id=user_payment.user_id, @@ -1699,8 +1700,8 @@ async def revoke_user_devices( @router.get( - "/myeclpay/users/me/wallet/history", - response_model=list[schemas_myeclpay.History], + "/mypayment/users/me/wallet/history", + response_model=list[schemas_mypayment.History], ) async def get_user_wallet_history( db: AsyncSession = Depends(get_db), @@ -1713,7 +1714,7 @@ async def get_user_wallet_history( **The user must be authenticated to use this endpoint** """ - user_payment = await cruds_myeclpay.get_user_payment( + user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1724,10 +1725,10 @@ async def get_user_wallet_history( detail="User is not registered for MyECL Pay", ) - history: list[schemas_myeclpay.History] = [] + history: list[schemas_mypayment.History] = [] # First we get all received and send transactions - transactions = await cruds_myeclpay.get_transactions_by_wallet_id( + transactions = await cruds_mypayment.get_transactions_by_wallet_id( wallet_id=user_payment.wallet_id, db=db, start_datetime=start_date, @@ -1752,14 +1753,14 @@ async def get_user_wallet_history( else: raise UnexpectedError("Transaction has no credited or debited wallet") # noqa: TRY003 - history_refund: schemas_myeclpay.HistoryRefund | None = None + history_refund: schemas_mypayment.HistoryRefund | None = None if transaction.refund is not None: - history_refund = schemas_myeclpay.HistoryRefund( + history_refund = schemas_mypayment.HistoryRefund( total=transaction.refund.total, creation=transaction.refund.creation, ) history.append( - schemas_myeclpay.History( + schemas_mypayment.History( id=transaction.id, type=transaction_type, other_wallet_name=other_wallet_name, @@ -1771,7 +1772,7 @@ async def get_user_wallet_history( ) # We also want to include transfers - transfers = await cruds_myeclpay.get_transfers_by_wallet_id( + transfers = await cruds_mypayment.get_transfers_by_wallet_id( wallet_id=user_payment.wallet_id, db=db, start_datetime=start_date, @@ -1787,7 +1788,7 @@ async def get_user_wallet_history( status = TransactionStatus.CANCELED history.append( - schemas_myeclpay.History( + schemas_mypayment.History( id=transfer.id, type=HistoryType.TRANSFER, other_wallet_name="Transfer", @@ -1798,7 +1799,7 @@ async def get_user_wallet_history( ) # We add refunds - refunds = await cruds_myeclpay.get_refunds_by_wallet_id( + refunds = await cruds_mypayment.get_refunds_by_wallet_id( wallet_id=user_payment.wallet_id, db=db, start_datetime=start_date, @@ -1813,7 +1814,7 @@ async def get_user_wallet_history( other_wallet_info = refund.debited_wallet history.append( - schemas_myeclpay.History( + schemas_mypayment.History( id=refund.id, type=transaction_type, other_wallet_name=other_wallet_info.owner_name or "Unknown", @@ -1827,16 +1828,18 @@ async def get_user_wallet_history( @router.post( - "/myeclpay/transfer/init", + "/mypayment/transfer/init", response_model=schemas_payment.PaymentUrl, status_code=201, ) async def init_ha_transfer( - transfer_info: schemas_myeclpay.TransferInfo, + transfer_info: schemas_mypayment.TransferInfo, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), settings: Settings = Depends(get_settings), - payment_tool: PaymentTool = Depends(get_payment_tool(HelloAssoConfigName.MYECLPAY)), + payment_tool: PaymentTool = Depends( + get_payment_tool(HelloAssoConfigName.MYPAYMENT), + ), ): """ Initiate HelloAsso transfer, return a payment url to complete the transaction on HelloAsso website. @@ -1857,7 +1860,7 @@ async def init_ha_transfer( detail="Please give an amount in cents, greater than 1€.", ) - user_payment = await cruds_myeclpay.get_user_payment( + user_payment = await cruds_mypayment.get_user_payment( user_id=user.id, db=db, ) @@ -1873,7 +1876,7 @@ async def init_ha_transfer( detail="User has not signed the latest TOS", ) - wallet = await cruds_myeclpay.get_wallet( + wallet = await cruds_mypayment.get_wallet( wallet_id=user_payment.wallet_id, db=db, ) @@ -1882,7 +1885,10 @@ async def init_ha_transfer( status_code=404, detail="Wallet does not exist", ) - if wallet.balance + transfer_info.amount > settings.MYECLPAY_MAXIMUM_WALLET_BALANCE: + if ( + wallet.balance + transfer_info.amount + > settings.MYPAYMENT_MAXIMUM_WALLET_BALANCE + ): raise HTTPException( status_code=403, detail="Wallet balance would exceed the maximum allowed balance", @@ -1904,17 +1910,17 @@ async def init_ha_transfer( nickname=user.nickname, ) checkout = await payment_tool.init_checkout( - module="myeclpay", + module="mypayment", checkout_amount=transfer_info.amount, - checkout_name="Recharge MyECL Pay", - redirection_uri=f"{settings.CLIENT_URL}myeclpay/transfer/redirect?url={transfer_info.redirect_url}", + checkout_name=f"Recharge {settings.school.payment_name}", + redirection_uri=f"{settings.CLIENT_URL}mypayment/transfer/redirect?url={transfer_info.redirect_url}", payer_user=user_schema, db=db, ) - await cruds_myeclpay.create_transfer( + await cruds_mypayment.create_transfer( db=db, - transfer=schemas_myeclpay.Transfer( + transfer=schemas_mypayment.Transfer( id=uuid.uuid4(), type=TransferType.HELLO_ASSO, approver_user_id=None, @@ -1932,7 +1938,7 @@ async def init_ha_transfer( @router.get( - "/myeclpay/transfer/redirect", + "/mypayment/transfer/redirect", response_model=schemas_payment.PaymentUrl, status_code=201, ) @@ -1946,7 +1952,7 @@ async def redirect_from_ha_transfer( ): """ HelloAsso checkout should be configured to redirect the user to: - - f"{settings.CLIENT_URL}myeclpay/transfer/redirect?url={redirect_url}" + - f"{settings.CLIENT_URL}mypayment/transfer/redirect?url={redirect_url}" Redirect the user to the provided redirect `url`. The parameters `checkoutIntentId`, `code`, `orderId` and `error` passed by HelloAsso will be added to the redirect URL. The redirect `url` must be trusted by Hyperion in the dotenv. """ @@ -1976,13 +1982,13 @@ async def redirect_from_ha_transfer( @router.post( - "/myeclpay/stores/{store_id}/scan/check", + "/mypayment/stores/{store_id}/scan/check", response_model=standard_responses.Result, status_code=200, ) async def validate_can_scan_qrcode( store_id: UUID, - scan_info: schemas_myeclpay.ScanInfo, + scan_info: schemas_mypayment.ScanInfo, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user_an_ecl_member), ): @@ -1996,7 +2002,7 @@ async def validate_can_scan_qrcode( **The user must be authenticated to use this endpoint** """ - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -2006,7 +2012,7 @@ async def validate_can_scan_qrcode( detail="Store does not exist", ) - seller = await cruds_myeclpay.get_seller( + seller = await cruds_mypayment.get_seller( store_id=store_id, user_id=user.id, db=db, @@ -2018,7 +2024,7 @@ async def validate_can_scan_qrcode( detail="User does not have `can_bank` permission for this store", ) - debited_wallet_device = await cruds_myeclpay.get_wallet_device( + debited_wallet_device = await cruds_mypayment.get_wallet_device( wallet_device_id=scan_info.key, db=db, ) @@ -2028,13 +2034,13 @@ async def validate_can_scan_qrcode( detail="Wallet device does not exist", ) - debited_wallet = await cruds_myeclpay.get_wallet( + debited_wallet = await cruds_mypayment.get_wallet( wallet_id=debited_wallet_device.wallet_id, db=db, ) if debited_wallet is None: hyperion_error_logger.error( - f"MyECLPay: Could not find wallet associated with the debited wallet device {debited_wallet_device.id}, this should never happen", + f"MyPayment: Could not find wallet associated with the debited wallet device {debited_wallet_device.id}, this should never happen", ) raise HTTPException( status_code=400, @@ -2042,7 +2048,7 @@ async def validate_can_scan_qrcode( ) if debited_wallet.user is None: hyperion_error_logger.error( - f"MyECLPay: Debited wallet device {debited_wallet_device.id} does not contains a user, this should never happen", + f"MyPayment: Debited wallet device {debited_wallet_device.id} does not contains a user, this should never happen", ) raise HTTPException( status_code=400, @@ -2064,16 +2070,17 @@ async def validate_can_scan_qrcode( @router.post( - "/myeclpay/stores/{store_id}/scan", + "/mypayment/stores/{store_id}/scan", status_code=201, ) async def store_scan_qrcode( store_id: UUID, - scan_info: schemas_myeclpay.ScanInfo, + scan_info: schemas_mypayment.ScanInfo, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user_an_ecl_member), request_id: str = Depends(get_request_id), notification_tool: NotificationTool = Depends(get_notification_tool), + settings: Settings = Depends(get_settings), ): """ Scan and bank a QR code for this store. @@ -2102,7 +2109,7 @@ async def store_scan_qrcode( **The user must have the `can_bank` permission for this store** """ # If the QR Code is already used, we return an error - already_existing_used_qrcode = await cruds_myeclpay.get_used_qrcode( + already_existing_used_qrcode = await cruds_mypayment.get_used_qrcode( qr_code_id=scan_info.id, db=db, ) @@ -2114,7 +2121,7 @@ async def store_scan_qrcode( # After scanning a QR Code, we want to add it to the list of already scanned QR Code # even if it fail to be banked - await cruds_myeclpay.create_used_qrcode( + await cruds_mypayment.create_used_qrcode( qr_code=scan_info, db=db, ) @@ -2124,7 +2131,7 @@ async def store_scan_qrcode( # We start a SAVEPOINT to ensure that even if the following code fails due to a database exception, # after roleback the `used_qrcode` will still be created and committed in db. async with db.begin_nested(): - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=store_id, db=db, ) @@ -2134,7 +2141,7 @@ async def store_scan_qrcode( detail="Store does not exist", ) - seller = await cruds_myeclpay.get_seller( + seller = await cruds_mypayment.get_seller( store_id=store_id, user_id=user.id, db=db, @@ -2147,7 +2154,7 @@ async def store_scan_qrcode( ) # We verify the signature - debited_wallet_device = await cruds_myeclpay.get_wallet_device( + debited_wallet_device = await cruds_mypayment.get_wallet_device( wallet_device_id=scan_info.key, db=db, ) @@ -2198,13 +2205,13 @@ async def store_scan_qrcode( ) # We verify that the debited walled contains enough money - debited_wallet = await cruds_myeclpay.get_wallet( + debited_wallet = await cruds_mypayment.get_wallet( wallet_id=debited_wallet_device.wallet_id, db=db, ) if debited_wallet is None: hyperion_error_logger.error( - f"MyECLPay: Could not find wallet associated with the debited wallet device {debited_wallet_device.id}, this should never happen", + f"MyPayment: Could not find wallet associated with the debited wallet device {debited_wallet_device.id}, this should never happen", ) raise HTTPException( status_code=400, @@ -2216,7 +2223,7 @@ async def store_scan_qrcode( detail="Stores are not allowed to make transaction by QR code", ) - debited_user_payment = await cruds_myeclpay.get_user_payment( + debited_user_payment = await cruds_mypayment.get_user_payment( debited_wallet.user.id, db=db, ) @@ -2250,21 +2257,21 @@ async def store_scan_qrcode( ) # We increment the receiving wallet balance - await cruds_myeclpay.increment_wallet_balance( + await cruds_mypayment.increment_wallet_balance( wallet_id=store.wallet_id, amount=scan_info.tot, db=db, ) # We decrement the debited wallet balance - await cruds_myeclpay.increment_wallet_balance( + await cruds_mypayment.increment_wallet_balance( wallet_id=debited_wallet.id, amount=-scan_info.tot, db=db, ) transaction_id = uuid.uuid4() creation_date = datetime.now(UTC) - transaction = schemas_myeclpay.TransactionBase( + transaction = schemas_mypayment.TransactionBase( id=transaction_id, debited_wallet_id=debited_wallet_device.wallet_id, credited_wallet_id=store.wallet_id, @@ -2276,24 +2283,24 @@ async def store_scan_qrcode( qr_code_id=scan_info.id, ) # We create a transaction - await cruds_myeclpay.create_transaction( + await cruds_mypayment.create_transaction( transaction=transaction, debited_wallet_device_id=debited_wallet_device.id, store_note=None, db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( format_transaction_log(transaction), extra={ - "s3_subfolder": MYECLPAY_LOGS_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_LOGS_S3_SUBFOLDER, "s3_retention": RETENTION_DURATION, }, ) message = Message( title=f"💳 Paiement - {store.name}", content=f"Une transaction de {scan_info.tot / 100} € a été effectuée", - action_module="MyECLPay", + action_module=settings.school.payment_name, ) await notification_tool.send_notification_to_user( user_id=debited_wallet.user.id, @@ -2303,26 +2310,27 @@ async def store_scan_qrcode( @router.post( - "/myeclpay/transactions/{transaction_id}/refund", + "/mypayment/transactions/{transaction_id}/refund", status_code=204, ) async def refund_transaction( transaction_id: UUID, - refund_info: schemas_myeclpay.RefundInfo, + refund_info: schemas_mypayment.RefundInfo, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user_an_ecl_member), notification_tool: NotificationTool = Depends(get_notification_tool), + settings: Settings = Depends(get_settings), ): """ Refund a transaction. Only transactions made in the last 30 days can be refunded. Currently transactions between users are forbidden and can thus not be refunded. - To cancel a transaction made in the last 30 seconds, the endpoint `/myeclpay/transactions/{transaction_id}/cancel` should be used. + To cancel a transaction made in the last 30 seconds, the endpoint `/mypayment/transactions/{transaction_id}/cancel` should be used. **The user must either be the credited user or a seller with cancel permissions of the credited store of the transaction** """ - transaction = await cruds_myeclpay.get_transaction( + transaction = await cruds_mypayment.get_transaction( transaction_id=transaction_id, db=db, ) @@ -2346,7 +2354,7 @@ async def refund_transaction( ) # The wallet that was credited if the one that will be de debited during the refund - wallet_previously_credited = await cruds_myeclpay.get_wallet( + wallet_previously_credited = await cruds_mypayment.get_wallet( wallet_id=transaction.credited_wallet_id, db=db, ) @@ -2362,7 +2370,7 @@ async def refund_transaction( status_code=404, detail="Missing store in store wallet", ) - seller = await cruds_myeclpay.get_seller( + seller = await cruds_mypayment.get_seller( store_id=wallet_previously_credited.store.id, user_id=user.id, db=db, @@ -2412,7 +2420,7 @@ async def refund_transaction( refund_amount = refund_info.amount # The wallet that was debited is the one that will be credited during the refund - wallet_previously_debited = await cruds_myeclpay.get_wallet( + wallet_previously_debited = await cruds_mypayment.get_wallet( wallet_id=transaction.debited_wallet_id, db=db, ) @@ -2422,14 +2430,14 @@ async def refund_transaction( detail="The wallet that should be credited during the refund does not exist", ) - await cruds_myeclpay.update_transaction_status( + await cruds_mypayment.update_transaction_status( transaction_id=transaction_id, status=TransactionStatus.REFUNDED, db=db, ) creation_date = datetime.now(UTC) - refund = schemas_myeclpay.RefundBase( + refund = schemas_mypayment.RefundBase( id=uuid.uuid4(), transaction_id=transaction_id, total=refund_amount, @@ -2441,28 +2449,28 @@ async def refund_transaction( creation=creation_date, ) - await cruds_myeclpay.create_refund( + await cruds_mypayment.create_refund( refund=refund, db=db, ) # We add the amount to the wallet that was previously debited - await cruds_myeclpay.increment_wallet_balance( + await cruds_mypayment.increment_wallet_balance( wallet_id=wallet_previously_debited.id, amount=refund_amount, db=db, ) - await cruds_myeclpay.increment_wallet_balance( + await cruds_mypayment.increment_wallet_balance( wallet_id=wallet_previously_credited.id, amount=-refund_amount, db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( format_refund_log(refund), extra={ - "s3_subfolder": MYECLPAY_LOGS_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_LOGS_S3_SUBFOLDER, "s3_retention": RETENTION_DURATION, }, ) @@ -2471,7 +2479,7 @@ async def refund_transaction( message = Message( title="💳 Remboursement", content=f"La transaction pour {wallet_previously_credited_name} ({transaction.total / 100} €) a été remboursée de {refund_amount / 100} €", - action_module="MyECLPay", + action_module=settings.school.payment_name, ) await notification_tool.send_notification_to_user( user_id=wallet_previously_debited.user.id, @@ -2486,7 +2494,7 @@ async def refund_transaction( message = Message( title="💳 Remboursement", content=f"Vous avez remboursé la transaction de {wallet_previously_debited_name} ({transaction.total / 100} €) de {refund_amount / 100} €", - action_module="MyECLPay", + action_module=settings.school.payment_name, ) await notification_tool.send_notification_to_user( user_id=wallet_previously_credited.user.id, @@ -2495,7 +2503,7 @@ async def refund_transaction( @router.post( - "/myeclpay/transactions/{transaction_id}/cancel", + "/mypayment/transactions/{transaction_id}/cancel", status_code=204, ) async def cancel_transaction( @@ -2504,16 +2512,17 @@ async def cancel_transaction( user: CoreUser = Depends(is_user_an_ecl_member), request_id: str = Depends(get_request_id), notification_tool: NotificationTool = Depends(get_notification_tool), + settings: Settings = Depends(get_settings), ): """ Cancel a transaction. A transaction can be canceled in the first 30 seconds after it has been created. - To refund an older transaction, use the `/myeclpay/transactions/{transaction_id}/refund` endpoint. + To refund an older transaction, use the `/mypayment/transactions/{transaction_id}/refund` endpoint. **The user must either be the credited user or the seller of the transaction** """ - transaction = await cruds_myeclpay.get_transaction( + transaction = await cruds_mypayment.get_transaction( transaction_id=transaction_id, db=db, ) @@ -2530,7 +2539,7 @@ async def cancel_transaction( detail="Transaction is older than 30 seconds and can not be canceled", ) - canceller_wallet = await cruds_myeclpay.get_wallet( + canceller_wallet = await cruds_mypayment.get_wallet( wallet_id=transaction.credited_wallet_id, db=db, ) @@ -2546,7 +2555,7 @@ async def cancel_transaction( status_code=404, detail="Store does not exist", ) - seller = await cruds_myeclpay.get_seller( + seller = await cruds_mypayment.get_seller( store_id=canceller_wallet.store.id, user_id=user.id, db=db, @@ -2581,7 +2590,7 @@ async def cancel_transaction( detail="Only confirmed transactions can be canceled", ) - debited_wallet = await cruds_myeclpay.get_wallet( + debited_wallet = await cruds_mypayment.get_wallet( wallet_id=transaction.debited_wallet_id, db=db, ) @@ -2591,28 +2600,28 @@ async def cancel_transaction( detail="Debited wallet does not exist", ) - await cruds_myeclpay.update_transaction_status( + await cruds_mypayment.update_transaction_status( transaction_id=transaction_id, status=TransactionStatus.CANCELED, db=db, ) - await cruds_myeclpay.increment_wallet_balance( + await cruds_mypayment.increment_wallet_balance( wallet_id=transaction.debited_wallet_id, amount=transaction.total, db=db, ) - await cruds_myeclpay.increment_wallet_balance( + await cruds_mypayment.increment_wallet_balance( wallet_id=transaction.credited_wallet_id, amount=-transaction.total, db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( format_cancel_log(transaction_id), extra={ - "s3_subfolder": MYECLPAY_LOGS_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_LOGS_S3_SUBFOLDER, "s3_retention": RETENTION_DURATION, }, ) @@ -2621,7 +2630,7 @@ async def cancel_transaction( message = Message( title="💳 Paiement annulé", content=f"La transaction de {transaction.total / 100} € a été annulée", - action_module="MyECLPay", + action_module=settings.school.payment_name, ) await notification_tool.send_notification_to_user( user_id=debited_wallet.user.id, @@ -2630,8 +2639,8 @@ async def cancel_transaction( @router.get( - "/myeclpay/invoices", - response_model=list[schemas_myeclpay.Invoice], + "/mypayment/invoices", + response_model=list[schemas_mypayment.Invoice], ) async def get_invoices( page: int | None = None, @@ -2641,13 +2650,13 @@ async def get_invoices( end_date: datetime | None = None, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user_bank_account_holder), -) -> list[schemas_myeclpay.Invoice]: +) -> list[schemas_mypayment.Invoice]: """ Get all invoices. **The user must be authenticated to use this endpoint** """ - return await cruds_myeclpay.get_invoices( + return await cruds_mypayment.get_invoices( db=db, skip=(page - 1) * page_size if page and page_size else None, limit=page_size, @@ -2658,8 +2667,8 @@ async def get_invoices( @router.get( - "/myeclpay/invoices/structures/{structure_id}", - response_model=list[schemas_myeclpay.Invoice], + "/mypayment/invoices/structures/{structure_id}", + response_model=list[schemas_mypayment.Invoice], ) async def get_structure_invoices( structure_id: UUID, @@ -2669,13 +2678,13 @@ async def get_structure_invoices( end_date: datetime | None = None, db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), -) -> list[schemas_myeclpay.Invoice]: +) -> list[schemas_mypayment.Invoice]: """ Get all invoices. **The user must be the structure manager** """ - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=structure_id, db=db, ) @@ -2690,7 +2699,7 @@ async def get_structure_invoices( detail="User is not allowed to access this structure invoices", ) - return await cruds_myeclpay.get_invoices( + return await cruds_mypayment.get_invoices( db=db, skip=(page - 1) * page_size if page and page_size else None, limit=page_size, @@ -2701,7 +2710,7 @@ async def get_structure_invoices( @router.get( - "/myeclpay/invoices/{invoice_id}", + "/mypayment/invoices/{invoice_id}", response_class=FileResponse, ) async def download_invoice( @@ -2709,13 +2718,13 @@ async def download_invoice( db: AsyncSession = Depends(get_db), user: CoreUser = Depends(is_user()), ): - invoice = await cruds_myeclpay.get_invoice_by_id(invoice_id, db) + invoice = await cruds_mypayment.get_invoice_by_id(invoice_id, db) if invoice is None: raise HTTPException( status_code=404, detail="Invoice does not exist", ) - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=invoice.structure_id, db=db, ) @@ -2737,20 +2746,21 @@ async def download_invoice( detail="User is not allowed to access this invoice", ) return get_file_from_data( - directory="myeclpay/invoices", + directory="mypayment/invoices", filename=str(invoice_id), ) @router.post( - "/myeclpay/invoices/structures/{structure_id}", - response_model=schemas_myeclpay.Invoice, + "/mypayment/invoices/structures/{structure_id}", + response_model=schemas_mypayment.Invoice, status_code=201, ) async def create_structure_invoice( structure_id: UUID, db: AsyncSession = Depends(get_db), token_data: schemas_auth.TokenData = Depends(get_token_data), + settings: Settings = Depends(get_settings), ): """ Create an invoice for a structure. @@ -2782,7 +2792,7 @@ async def create_structure_invoice( status_code=403, detail="User is not the bank account holder", ) - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=structure_id, db=db, ) @@ -2792,36 +2802,36 @@ async def create_structure_invoice( detail="Structure does not exist", ) - stores = await cruds_myeclpay.get_stores_by_structure_id( + stores = await cruds_mypayment.get_stores_by_structure_id( structure_id=structure_id, db=db, ) - invoice_details: list[schemas_myeclpay.InvoiceDetailBase] = [] + invoice_details: list[schemas_mypayment.InvoiceDetailBase] = [] invoice_id = uuid.uuid4() # We use a 30 seconds delay to avoid unstable transactions # as they can be canceled during the 30 seconds after their creation security_now = now - timedelta(seconds=30) - to_substract_transactions = await cruds_myeclpay.get_transactions( + to_substract_transactions = await cruds_mypayment.get_transactions( db=db, start_date=security_now, exclude_canceled=True, ) for store in stores: - store_wallet_db = await cruds_myeclpay.get_wallet( + store_wallet_db = await cruds_mypayment.get_wallet( wallet_id=store.wallet_id, db=db, ) if store_wallet_db is None: hyperion_error_logger.error( - "MyECLPAy: Could not find wallet associated with a store, this should never happen", + "MyPayment: Could not find wallet associated with a store, this should never happen", ) raise HTTPException( status_code=500, detail="Could not find wallet associated with the store", ) - store_wallet = schemas_myeclpay.Wallet( + store_wallet = schemas_mypayment.Wallet( id=store_wallet_db.id, type=store_wallet_db.type, balance=store_wallet_db.balance, @@ -2834,7 +2844,7 @@ async def create_structure_invoice( elif transaction.debited_wallet_id == store_wallet.id: store_wallet.balance += transaction.total store_pending_invoices = ( - await cruds_myeclpay.get_unreceived_invoices_by_store_id( + await cruds_mypayment.get_unreceived_invoices_by_store_id( store_id=store.id, db=db, ) @@ -2843,7 +2853,7 @@ async def create_structure_invoice( store_wallet.balance -= pending_invoice.total if store_wallet.balance != 0: invoice_details.append( - schemas_myeclpay.InvoiceDetailBase( + schemas_mypayment.InvoiceDetailBase( invoice_id=invoice_id, store_id=store.id, store_name=store.name, @@ -2856,7 +2866,7 @@ async def create_structure_invoice( status_code=400, detail="No invoice to create", ) - last_structure_invoice = await cruds_myeclpay.get_last_structure_invoice( + last_structure_invoice = await cruds_mypayment.get_last_structure_invoice( structure_id=structure_id, db=db, ) @@ -2866,7 +2876,7 @@ async def create_structure_invoice( and int(last_structure_invoice.reference[5:9]) == security_now.year else 0 ) - invoice = schemas_myeclpay.InvoiceInfo( + invoice = schemas_mypayment.InvoiceInfo( id=invoice_id, reference=f"PAY{security_now.year}{structure.short_id}{last_invoice_number + 1:04d}", structure_id=structure_id, @@ -2878,11 +2888,11 @@ async def create_structure_invoice( total=sum(detail.total for detail in invoice_details), details=invoice_details, ) - await cruds_myeclpay.create_invoice( + await cruds_mypayment.create_invoice( invoice=invoice, db=db, ) - invoice_db = await cruds_myeclpay.get_invoice_by_id( + invoice_db = await cruds_mypayment.get_invoice_by_id( invoice_id=invoice_id, db=db, ) @@ -2891,7 +2901,7 @@ async def create_structure_invoice( context = { "invoice": invoice_db.model_dump(), - "payment_name": "MyECLPay", + "payment_name": settings.school.payment_name, "holder_coordinates": { "name": bank_holder_structure.name, "address_street": bank_holder_structure.siege_address_street, @@ -2902,8 +2912,8 @@ async def create_structure_invoice( }, } await generate_pdf_from_template( - template_name="myeclpay_invoice.html", - directory="myeclpay/invoices", + template_name="mypayment_invoice.html", + directory="mypayment/invoices", filename=invoice.id, context=context, ) @@ -2911,7 +2921,7 @@ async def create_structure_invoice( @router.patch( - "/myeclpay/invoices/{invoice_id}/paid", + "/mypayment/invoices/{invoice_id}/paid", status_code=204, ) async def update_invoice_paid_status( @@ -2928,7 +2938,7 @@ async def update_invoice_paid_status( hyperion_error_logger.debug( f"User {user.id} requested to update the paid status of invoice {invoice_id} to {paid}", ) - invoice = await cruds_myeclpay.get_invoice_by_id( + invoice = await cruds_mypayment.get_invoice_by_id( invoice_id=invoice_id, db=db, ) @@ -2937,7 +2947,7 @@ async def update_invoice_paid_status( status_code=404, detail="Invoice does not exist", ) - await cruds_myeclpay.update_invoice_paid_status( + await cruds_mypayment.update_invoice_paid_status( invoice_id=invoice.id, paid=paid, db=db, @@ -2945,7 +2955,7 @@ async def update_invoice_paid_status( @router.patch( - "/myeclpay/invoices/{invoice_id}/received", + "/mypayment/invoices/{invoice_id}/received", status_code=204, ) async def aknowledge_invoice_as_received( @@ -2958,7 +2968,7 @@ async def aknowledge_invoice_as_received( **The user must be the structure manager** """ - invoice = await cruds_myeclpay.get_invoice_by_id( + invoice = await cruds_mypayment.get_invoice_by_id( invoice_id=invoice_id, db=db, ) @@ -2977,7 +2987,7 @@ async def aknowledge_invoice_as_received( status_code=400, detail="Invoice is already marked as received", ) - structure = await cruds_myeclpay.get_structure_by_id( + structure = await cruds_mypayment.get_structure_by_id( structure_id=invoice.structure_id, db=db, ) @@ -2992,30 +3002,30 @@ async def aknowledge_invoice_as_received( detail="User is not allowed to edit this structure invoice", ) - await cruds_myeclpay.update_invoice_received_status( + await cruds_mypayment.update_invoice_received_status( invoice_id=invoice.id, db=db, ) for detail in invoice.details: - store = await cruds_myeclpay.get_store( + store = await cruds_mypayment.get_store( store_id=detail.store_id, db=db, ) if store is None: hyperion_error_logger.error( - "MyECLPay: Could not find store associated with an invoice, this should never happen", + "MyPayment: Could not find store associated with an invoice, this should never happen", ) raise HTTPException( status_code=500, detail="Could not find store associated with the invoice", ) - await cruds_myeclpay.increment_wallet_balance( + await cruds_mypayment.increment_wallet_balance( wallet_id=store.wallet_id, amount=-detail.total, db=db, ) - await cruds_myeclpay.add_withdrawal( - schemas_myeclpay.Withdrawal( + await cruds_mypayment.add_withdrawal( + schemas_mypayment.Withdrawal( id=uuid.uuid4(), wallet_id=store.wallet_id, total=detail.total, @@ -3024,20 +3034,20 @@ async def aknowledge_invoice_as_received( db=db, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( format_withdrawal_log( wallet_id=store.wallet_id, total=detail.total, ), extra={ - "s3_subfolder": MYECLPAY_LOGS_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_LOGS_S3_SUBFOLDER, "s3_retention": RETENTION_DURATION, }, ) @router.delete( - "/myeclpay/invoices/{invoice_id}", + "/mypayment/invoices/{invoice_id}", status_code=204, ) async def delete_structure_invoice( @@ -3050,7 +3060,7 @@ async def delete_structure_invoice( **The user must be the bank account holder** """ - invoice = await cruds_myeclpay.get_invoice_by_id( + invoice = await cruds_mypayment.get_invoice_by_id( invoice_id=invoice_id, db=db, ) @@ -3065,20 +3075,20 @@ async def delete_structure_invoice( detail="Cannot delete an invoice that has already been paid", ) - await cruds_myeclpay.delete_invoice( + await cruds_mypayment.delete_invoice( invoice_id=invoice.id, db=db, ) @router.get( - "/myeclpay/integrity-check", + "/mypayment/integrity-check", status_code=200, - response_model=schemas_myeclpay.IntegrityCheckData, + response_model=schemas_mypayment.IntegrityCheckData, ) async def get_data_for_integrity_check( - headers: schemas_myeclpay.IntegrityCheckHeaders = Header(), - query_params: schemas_myeclpay.IntegrityCheckQuery = Query(), + headers: schemas_mypayment.IntegrityCheckHeaders = Header(), + query_params: schemas_mypayment.IntegrityCheckQuery = Query(), db: AsyncSession = Depends(get_db), settings: Settings = Depends(get_settings), ): @@ -3090,17 +3100,17 @@ async def get_data_for_integrity_check( - Transfers - Refunds - **The header must contain the MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN defined in the settings in the `x-data-verifier-token` field** + **The header must contain the MYPAYMENT_DATA_VERIFIER_ACCESS_TOKEN defined in the settings in the `x-data-verifier-token` field** """ - if settings.MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN is None: + if settings.MYPAYMENT_DATA_VERIFIER_ACCESS_TOKEN is None: raise HTTPException( status_code=301, - detail="MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN is not set in the settings", + detail="MYPAYMENT_DATA_VERIFIER_ACCESS_TOKEN is not set in the settings", ) - if headers.x_data_verifier_token != settings.MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN: + if headers.x_data_verifier_token != settings.MYPAYMENT_DATA_VERIFIER_ACCESS_TOKEN: hyperion_security_logger.warning( - f"A request to /myeclpay/integrity-check has been made with an invalid token, request_content: {headers}", + f"A request to /mypayment/integrity-check has been made with an invalid token, request_content: {headers}", ) raise HTTPException( status_code=403, @@ -3112,10 +3122,10 @@ async def get_data_for_integrity_check( # as they can be canceled during the 30 seconds after their creation security_now = now - timedelta(seconds=30) - wallets = await cruds_myeclpay.get_wallets( + wallets = await cruds_mypayment.get_wallets( db=db, ) - to_substract_transactions = await cruds_myeclpay.get_transactions( + to_substract_transactions = await cruds_mypayment.get_transactions( db=db, start_date=security_now, exclude_canceled=True, @@ -3136,28 +3146,28 @@ async def get_data_for_integrity_check( credited_wallet.balance -= transaction.total if query_params.isInitialisation: - return schemas_myeclpay.IntegrityCheckData( + return schemas_mypayment.IntegrityCheckData( date=security_now, wallets=wallets, transactions=[], transfers=[], refunds=[], ) - transactions = await cruds_myeclpay.get_transactions( + transactions = await cruds_mypayment.get_transactions( db=db, start_date=query_params.lastChecked, end_date=security_now, ) - transfers = await cruds_myeclpay.get_transfers( + transfers = await cruds_mypayment.get_transfers( db=db, last_checked=query_params.lastChecked, ) - refunds = await cruds_myeclpay.get_refunds( + refunds = await cruds_mypayment.get_refunds( db=db, last_checked=query_params.lastChecked, ) - return schemas_myeclpay.IntegrityCheckData( + return schemas_mypayment.IntegrityCheckData( date=security_now, wallets=wallets, transactions=transactions, diff --git a/app/core/myeclpay/exceptions_myeclpay.py b/app/core/mypayment/exceptions_mypayment.py similarity index 100% rename from app/core/myeclpay/exceptions_myeclpay.py rename to app/core/mypayment/exceptions_mypayment.py diff --git a/app/core/myeclpay/factory_myeclpay.py b/app/core/mypayment/factory_mypayment.py similarity index 85% rename from app/core/myeclpay/factory_myeclpay.py rename to app/core/mypayment/factory_mypayment.py index c727af281b..ad936ca1d2 100644 --- a/app/core/myeclpay/factory_myeclpay.py +++ b/app/core/mypayment/factory_mypayment.py @@ -5,8 +5,8 @@ from faker import Faker from sqlalchemy.ext.asyncio import AsyncSession -from app.core.myeclpay import cruds_myeclpay, models_myeclpay, schemas_myeclpay -from app.core.myeclpay.types_myeclpay import WalletType +from app.core.mypayment import cruds_mypayment, models_mypayment, schemas_mypayment +from app.core.mypayment.types_mypayment import WalletType from app.core.users.factory_users import CoreUsersFactory from app.core.utils.config import Settings from app.types.factory import Factory @@ -16,7 +16,7 @@ OTHER_STRUCTURES = 2 -class MyECLPayFactory(Factory): +class MyPaymentFactory(Factory): depends_on = [CoreUsersFactory] demo_structures_id: list[uuid.UUID] @@ -29,8 +29,8 @@ class MyECLPayFactory(Factory): async def create_structures(cls, db: AsyncSession): cls.demo_structures_id = [uuid.uuid4() for _ in CoreUsersFactory.demo_users_id] for i, user_id in enumerate(CoreUsersFactory.demo_users_id): - await cruds_myeclpay.create_structure( - schemas_myeclpay.StructureSimple( + await cruds_mypayment.create_structure( + schemas_mypayment.StructureSimple( id=uuid.uuid4(), short_id="".join(faker.random_letters(3)).upper(), name=CoreUsersFactory.demo_users[i].nickname, @@ -47,8 +47,8 @@ async def create_structures(cls, db: AsyncSession): ) cls.other_structures_id = [uuid.uuid4() for _ in range(OTHER_STRUCTURES)] for i, structure_id in enumerate(cls.other_structures_id): - await cruds_myeclpay.create_structure( - schemas_myeclpay.StructureSimple( + await cruds_mypayment.create_structure( + schemas_mypayment.StructureSimple( id=structure_id, short_id="".join(faker.random_letters(3)).upper(), name=faker.company(), @@ -74,14 +74,14 @@ async def create_other_structures_stores(cls, db: AsyncSession): wallet_id = uuid.uuid4() structure_store_ids.append(store_id) structure_wallet_ids.append(wallet_id) - await cruds_myeclpay.create_wallet( + await cruds_mypayment.create_wallet( wallet_id=wallet_id, wallet_type=WalletType.STORE, balance=100000, db=db, ) - await cruds_myeclpay.create_store( - models_myeclpay.Store( + await cruds_mypayment.create_store( + models_mypayment.Store( id=store_id, structure_id=structure_id, name=faker.company(), @@ -97,8 +97,8 @@ async def create_other_structures_stores(cls, db: AsyncSession): async def create_other_structures_invoices(cls, db: AsyncSession): for i, structure_id in enumerate(cls.other_structures_id): invoice_id = uuid.uuid4() - await cruds_myeclpay.create_invoice( - schemas_myeclpay.InvoiceInfo( + await cruds_mypayment.create_invoice( + schemas_mypayment.InvoiceInfo( id=invoice_id, structure_id=structure_id, reference=faker.bothify(text="MYPAY2025???####"), @@ -109,7 +109,7 @@ async def create_other_structures_invoices(cls, db: AsyncSession): end_date=datetime.now(UTC), creation=datetime.now(UTC), details=[ - schemas_myeclpay.InvoiceDetailBase( + schemas_mypayment.InvoiceDetailBase( invoice_id=invoice_id, store_id=store_id, total=1000, @@ -128,4 +128,4 @@ async def run(cls, db: AsyncSession, settings: Settings) -> None: @classmethod async def should_run(cls, db: AsyncSession): - return len(await cruds_myeclpay.get_structures(db=db)) == 0 + return len(await cruds_mypayment.get_structures(db=db)) == 0 diff --git a/app/core/myeclpay/integrity_myeclpay.py b/app/core/mypayment/integrity_mypayment.py similarity index 76% rename from app/core/myeclpay/integrity_myeclpay.py rename to app/core/mypayment/integrity_mypayment.py index a296dc3bea..03658bcca9 100644 --- a/app/core/myeclpay/integrity_myeclpay.py +++ b/app/core/mypayment/integrity_mypayment.py @@ -1,52 +1,52 @@ -######################################################################################### -######################################################################################### -#### /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ #### -#### #### -#### Following functions are used to format MyECLPay actions for S3 storage. #### -#### Modifying them will break the verification #### -#### of MyECLPay's integrity via S3 validation. #### -#### #### -#### Please do not modify them without understanding the consequences. #### -#### #### -#### /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ #### -######################################################################################### -######################################################################################### - - -from uuid import UUID - -from app.core.myeclpay import models_myeclpay, schemas_myeclpay -from app.core.myeclpay.types_myeclpay import ActionType - - -def format_transfer_log( - transfer: schemas_myeclpay.Transfer | models_myeclpay.Transfer, -): - return f"{ActionType.TRANSFER.name} {transfer.id} {transfer.type.name} {transfer.total} {transfer.wallet_id}" - - -def format_transaction_log( - transaction: schemas_myeclpay.TransactionBase, -): - return f"{ActionType.TRANSACTION.name} {transaction.id} {transaction.debited_wallet_id} {transaction.credited_wallet_id} {transaction.total}" - - -def format_refund_log( - refund: schemas_myeclpay.RefundBase, -): - return ( - f"{ActionType.REFUND.name} {refund.id} {refund.transaction_id} {refund.total}" - ) - - -def format_cancel_log( - transaction_id: UUID, -): - return f"{ActionType.CANCEL.name} {transaction_id}" - - -def format_withdrawal_log( - wallet_id: UUID, - total: int, -): - return f"{ActionType.WITHDRAWAL.name} {wallet_id} {total}" +######################################################################################### +######################################################################################### +#### /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ #### +#### #### +#### Following functions are used to format MyPayment actions for S3 storage. #### +#### Modifying them will break the verification #### +#### of MyPayment's integrity via S3 validation. #### +#### #### +#### Please do not modify them without understanding the consequences. #### +#### #### +#### /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ /!\ Warning /!\ #### +######################################################################################### +######################################################################################### + + +from uuid import UUID + +from app.core.mypayment import models_mypayment, schemas_mypayment +from app.core.mypayment.types_mypayment import ActionType + + +def format_transfer_log( + transfer: schemas_mypayment.Transfer | models_mypayment.Transfer, +): + return f"{ActionType.TRANSFER.name} {transfer.id} {transfer.type.name} {transfer.total} {transfer.wallet_id}" + + +def format_transaction_log( + transaction: schemas_mypayment.TransactionBase, +): + return f"{ActionType.TRANSACTION.name} {transaction.id} {transaction.debited_wallet_id} {transaction.credited_wallet_id} {transaction.total}" + + +def format_refund_log( + refund: schemas_mypayment.RefundBase, +): + return ( + f"{ActionType.REFUND.name} {refund.id} {refund.transaction_id} {refund.total}" + ) + + +def format_cancel_log( + transaction_id: UUID, +): + return f"{ActionType.CANCEL.name} {transaction_id}" + + +def format_withdrawal_log( + wallet_id: UUID, + total: int, +): + return f"{ActionType.WITHDRAWAL.name} {wallet_id} {total}" diff --git a/app/core/myeclpay/models_myeclpay.py b/app/core/mypayment/models_mypayment.py similarity index 79% rename from app/core/myeclpay/models_myeclpay.py rename to app/core/mypayment/models_mypayment.py index 77dfb29a6b..b6af28ce2f 100644 --- a/app/core/myeclpay/models_myeclpay.py +++ b/app/core/mypayment/models_mypayment.py @@ -5,7 +5,7 @@ from sqlalchemy.orm import Mapped, mapped_column, relationship from app.core.memberships import models_memberships -from app.core.myeclpay.types_myeclpay import ( +from app.core.mypayment.types_mypayment import ( RequestStatus, TransactionStatus, TransactionType, @@ -18,7 +18,7 @@ class Wallet(Base): - __tablename__ = "myeclpay_wallet" + __tablename__ = "mypayment_wallet" id: Mapped[PrimaryKey] type: Mapped[WalletType] @@ -27,17 +27,17 @@ class Wallet(Base): store: Mapped["Store | None"] = relationship(init=False, lazy="joined") user: Mapped[models_users.CoreUser | None] = relationship( init=False, - secondary="myeclpay_user_payment", + secondary="mypayment_user_payment", lazy="joined", ) class WalletDevice(Base): - __tablename__ = "myeclpay_wallet_device" + __tablename__ = "mypayment_wallet_device" id: Mapped[PrimaryKey] name: Mapped[str] - wallet_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_wallet.id")) + wallet_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_wallet.id")) ed25519_public_key: Mapped[bytes] = mapped_column(unique=True) creation: Mapped[datetime] status: Mapped[WalletDeviceStatus] @@ -45,14 +45,14 @@ class WalletDevice(Base): class Transaction(Base): - __tablename__ = "myeclpay_transaction" + __tablename__ = "mypayment_transaction" id: Mapped[PrimaryKey] - debited_wallet_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_wallet.id")) + debited_wallet_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_wallet.id")) debited_wallet_device_id: Mapped[UUID] = mapped_column( - ForeignKey("myeclpay_wallet_device.id"), + ForeignKey("mypayment_wallet_device.id"), ) - credited_wallet_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_wallet.id")) + credited_wallet_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_wallet.id")) transaction_type: Mapped[TransactionType] # User that scanned the qr code @@ -67,7 +67,7 @@ class Transaction(Base): store_note: Mapped[str | None] qr_code_id: Mapped[UUID | None] = mapped_column( - ForeignKey("myeclpay_used_qrcode.qr_code_id"), + ForeignKey("mypayment_used_qrcode.qr_code_id"), ) debited_wallet: Mapped[Wallet] = relationship( @@ -88,15 +88,15 @@ class Transaction(Base): class Refund(Base): - __tablename__ = "myeclpay_refund" + __tablename__ = "mypayment_refund" id: Mapped[PrimaryKey] transaction_id: Mapped[UUID] = mapped_column( - ForeignKey("myeclpay_transaction.id"), + ForeignKey("mypayment_transaction.id"), unique=True, ) - debited_wallet_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_wallet.id")) - credited_wallet_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_wallet.id")) + debited_wallet_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_wallet.id")) + credited_wallet_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_wallet.id")) total: Mapped[int] # Stored in cents creation: Mapped[datetime] seller_user_id: Mapped[str | None] = mapped_column(ForeignKey("core_user.id")) @@ -117,7 +117,7 @@ class Refund(Base): class Structure(Base): - __tablename__ = "myeclpay_structure" + __tablename__ = "mypayment_structure" id: Mapped[PrimaryKey] short_id: Mapped[str] = mapped_column(unique=True) @@ -146,10 +146,10 @@ class Structure(Base): class StructureManagerTransfert(Base): - __tablename__ = "myeclpay_structure_manager_transfer" + __tablename__ = "mypayment_structure_manager_transfer" structure_id: Mapped[UUID] = mapped_column( - ForeignKey("myeclpay_structure.id"), + ForeignKey("mypayment_structure.id"), primary_key=True, ) user_id: Mapped[str] = mapped_column(ForeignKey("core_user.id")) @@ -158,14 +158,14 @@ class StructureManagerTransfert(Base): class Store(Base): - __tablename__ = "myeclpay_store" + __tablename__ = "mypayment_store" id: Mapped[PrimaryKey] name: Mapped[str] = mapped_column(unique=True) - structure_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_structure.id")) + structure_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_structure.id")) wallet_id: Mapped[UUID] = mapped_column( - ForeignKey("myeclpay_wallet.id"), + ForeignKey("mypayment_wallet.id"), unique=True, ) creation: Mapped[datetime] @@ -174,25 +174,25 @@ class Store(Base): class Request(Base): - __tablename__ = "myeclpay_request" + __tablename__ = "mypayment_request" id: Mapped[PrimaryKey] - wallet_id: Mapped[str] = mapped_column(ForeignKey("myeclpay_wallet.id")) + wallet_id: Mapped[str] = mapped_column(ForeignKey("mypayment_wallet.id")) creation: Mapped[datetime] total: Mapped[int] # Stored in cents - store_id: Mapped[str] = mapped_column(ForeignKey("myeclpay_store.id")) + store_id: Mapped[str] = mapped_column(ForeignKey("mypayment_store.id")) name: Mapped[str] store_note: Mapped[str | None] callback: Mapped[str] status: Mapped[RequestStatus] transaction_id: Mapped[UUID | None] = mapped_column( - ForeignKey("myeclpay_transaction.id"), + ForeignKey("mypayment_transaction.id"), unique=True, ) class Transfer(Base): - __tablename__ = "myeclpay_transfer" + __tablename__ = "mypayment_transfer" id: Mapped[PrimaryKey] type: Mapped[TransferType] @@ -201,21 +201,21 @@ class Transfer(Base): # TODO remove if we only accept hello asso approver_user_id: Mapped[str | None] = mapped_column(ForeignKey("core_user.id")) - wallet_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_wallet.id")) + wallet_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_wallet.id")) total: Mapped[int] # Stored in cents creation: Mapped[datetime] confirmed: Mapped[bool] class Seller(Base): - __tablename__ = "myeclpay_seller" + __tablename__ = "mypayment_seller" user_id: Mapped[str] = mapped_column( ForeignKey("core_user.id"), primary_key=True, ) store_id: Mapped[UUID] = mapped_column( - ForeignKey("myeclpay_store.id"), + ForeignKey("mypayment_store.id"), primary_key=True, ) can_bank: Mapped[bool] @@ -227,14 +227,14 @@ class Seller(Base): class UserPayment(Base): - __tablename__ = "myeclpay_user_payment" + __tablename__ = "mypayment_user_payment" user_id: Mapped[str] = mapped_column( ForeignKey("core_user.id"), primary_key=True, ) wallet_id: Mapped[UUID] = mapped_column( - ForeignKey("myeclpay_wallet.id"), + ForeignKey("mypayment_wallet.id"), unique=True, ) accepted_tos_signature: Mapped[datetime] @@ -242,7 +242,7 @@ class UserPayment(Base): class UsedQRCode(Base): - __tablename__ = "myeclpay_used_qrcode" + __tablename__ = "mypayment_used_qrcode" qr_code_id: Mapped[PrimaryKey] qr_code_tot: Mapped[int | None] @@ -253,7 +253,7 @@ class UsedQRCode(Base): class Invoice(Base): - __tablename__ = "myeclpay_invoice" + __tablename__ = "mypayment_invoice" id: Mapped[PrimaryKey] reference: Mapped[str] = mapped_column(unique=True) @@ -261,7 +261,7 @@ class Invoice(Base): start_date: Mapped[datetime] end_date: Mapped[datetime] total: Mapped[int] # Stored in cents - structure_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_structure.id")) + structure_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_structure.id")) paid: Mapped[bool] = mapped_column(default=False) received: Mapped[bool] = mapped_column(default=False) @@ -276,14 +276,14 @@ class Invoice(Base): class InvoiceDetail(Base): - __tablename__ = "myeclpay_invoice_detail" + __tablename__ = "mypayment_invoice_detail" invoice_id: Mapped[UUID] = mapped_column( - ForeignKey("myeclpay_invoice.id"), + ForeignKey("mypayment_invoice.id"), primary_key=True, ) store_id: Mapped[UUID] = mapped_column( - ForeignKey("myeclpay_store.id"), + ForeignKey("mypayment_store.id"), primary_key=True, ) total: Mapped[int] # Stored in cents @@ -292,9 +292,9 @@ class InvoiceDetail(Base): class Withdrawal(Base): - __tablename__ = "myeclpay_withdrawal" + __tablename__ = "mypayment_withdrawal" id: Mapped[PrimaryKey] - wallet_id: Mapped[UUID] = mapped_column(ForeignKey("myeclpay_wallet.id")) + wallet_id: Mapped[UUID] = mapped_column(ForeignKey("mypayment_wallet.id")) total: Mapped[int] # Stored in cents creation: Mapped[datetime] diff --git a/app/core/myeclpay/schemas_myeclpay.py b/app/core/mypayment/schemas_mypayment.py similarity index 99% rename from app/core/myeclpay/schemas_myeclpay.py rename to app/core/mypayment/schemas_mypayment.py index 546c3fdd09..8825a457de 100644 --- a/app/core/myeclpay/schemas_myeclpay.py +++ b/app/core/mypayment/schemas_mypayment.py @@ -8,7 +8,7 @@ ) from app.core.memberships import schemas_memberships -from app.core.myeclpay.types_myeclpay import ( +from app.core.mypayment.types_mypayment import ( HistoryType, TransactionStatus, TransactionType, diff --git a/app/core/myeclpay/types_myeclpay.py b/app/core/mypayment/types_mypayment.py similarity index 100% rename from app/core/myeclpay/types_myeclpay.py rename to app/core/mypayment/types_mypayment.py diff --git a/app/core/myeclpay/utils/__init__.py b/app/core/mypayment/utils/__init__.py similarity index 100% rename from app/core/myeclpay/utils/__init__.py rename to app/core/mypayment/utils/__init__.py diff --git a/app/core/myeclpay/utils/data_exporter.py b/app/core/mypayment/utils/data_exporter.py similarity index 92% rename from app/core/myeclpay/utils/data_exporter.py rename to app/core/mypayment/utils/data_exporter.py index 41b22a186e..42e356b5f3 100644 --- a/app/core/myeclpay/utils/data_exporter.py +++ b/app/core/mypayment/utils/data_exporter.py @@ -1,88 +1,88 @@ -import csv -from io import StringIO - -from app.core.myeclpay import models_myeclpay - - -def generate_store_history_csv( - transactions_with_sellers: list[tuple[models_myeclpay.Transaction, str | None]], - refunds_map: dict, - store_wallet_id, -) -> str: - """ - Generate a CSV string containing the store payment history. - - Args: - transactions_with_sellers: List of tuples (Transaction, seller_full_name) - refunds_map: Dictionary mapping transaction_id to (Refund, seller_name) tuples - store_wallet_id: UUID of the store's wallet to determine transaction direction - - Returns: - CSV string with UTF-8 BOM for Excel compatibility - """ - csv_io = StringIO() - # Add UTF-8 BOM for Excel compatibility - csv_io.write("\ufeff") - - writer = csv.writer(csv_io, delimiter=";", quoting=csv.QUOTE_MINIMAL) - - # Write headers - writer.writerow( - [ - "Date/Heure", - "Type", - "Autre partie", - "Montant (€)", - "Statut", - "Vendeur", - "Montant remboursé (€)", - "Date remboursement", - "Note magasin", - ], - ) - - # Write transaction data - for transaction, seller_full_name in transactions_with_sellers: - transaction_type = ( - "REÇU" if transaction.credited_wallet_id == store_wallet_id else "DONNÉ" - ) - other_party_wallet = ( - transaction.debited_wallet - if transaction.credited_wallet_id == store_wallet_id - else transaction.credited_wallet - ) - other_party = "Inconnu" - if other_party_wallet.user: - other_party = ( - f"{other_party_wallet.user.firstname} {other_party_wallet.user.name}" - ) - elif other_party_wallet.store: - other_party = other_party_wallet.store.name - - # Check if transaction has a refund - refund_data = refunds_map.get(transaction.id) - refund_amount = "" - refund_date = "" - if refund_data: - refund, _ = refund_data - refund_amount = str(refund.total / 100) - refund_date = refund.creation.strftime("%d/%m/%Y %H:%M:%S") - - writer.writerow( - [ - transaction.creation.strftime("%d/%m/%Y %H:%M:%S"), - transaction_type, - other_party, - str(transaction.total / 100), - transaction.status.value, - seller_full_name or "N/A", - refund_amount, - refund_date, - transaction.store_note or "", - ], - ) - - csv_content = csv_io.getvalue() - csv_io.close() - - return csv_content +import csv +from io import StringIO + +from app.core.mypayment import models_mypayment + + +def generate_store_history_csv( + transactions_with_sellers: list[tuple[models_mypayment.Transaction, str | None]], + refunds_map: dict, + store_wallet_id, +) -> str: + """ + Generate a CSV string containing the store payment history. + + Args: + transactions_with_sellers: List of tuples (Transaction, seller_full_name) + refunds_map: Dictionary mapping transaction_id to (Refund, seller_name) tuples + store_wallet_id: UUID of the store's wallet to determine transaction direction + + Returns: + CSV string with UTF-8 BOM for Excel compatibility + """ + csv_io = StringIO() + # Add UTF-8 BOM for Excel compatibility + csv_io.write("\ufeff") + + writer = csv.writer(csv_io, delimiter=";", quoting=csv.QUOTE_MINIMAL) + + # Write headers + writer.writerow( + [ + "Date/Heure", + "Type", + "Autre partie", + "Montant (€)", + "Statut", + "Vendeur", + "Montant remboursé (€)", + "Date remboursement", + "Note magasin", + ], + ) + + # Write transaction data + for transaction, seller_full_name in transactions_with_sellers: + transaction_type = ( + "REÇU" if transaction.credited_wallet_id == store_wallet_id else "DONNÉ" + ) + other_party_wallet = ( + transaction.debited_wallet + if transaction.credited_wallet_id == store_wallet_id + else transaction.credited_wallet + ) + other_party = "Inconnu" + if other_party_wallet.user: + other_party = ( + f"{other_party_wallet.user.firstname} {other_party_wallet.user.name}" + ) + elif other_party_wallet.store: + other_party = other_party_wallet.store.name + + # Check if transaction has a refund + refund_data = refunds_map.get(transaction.id) + refund_amount = "" + refund_date = "" + if refund_data: + refund, _ = refund_data + refund_amount = str(refund.total / 100) + refund_date = refund.creation.strftime("%d/%m/%Y %H:%M:%S") + + writer.writerow( + [ + transaction.creation.strftime("%d/%m/%Y %H:%M:%S"), + transaction_type, + other_party, + str(transaction.total / 100), + transaction.status.value, + seller_full_name or "N/A", + refund_amount, + refund_date, + transaction.store_note or "", + ], + ) + + csv_content = csv_io.getvalue() + csv_io.close() + + return csv_content diff --git a/app/core/myeclpay/utils_myeclpay.py b/app/core/mypayment/utils_mypayment.py similarity index 78% rename from app/core/myeclpay/utils_myeclpay.py rename to app/core/mypayment/utils_mypayment.py index 73464fd555..ff6ea477d6 100644 --- a/app/core/myeclpay/utils_myeclpay.py +++ b/app/core/mypayment/utils_mypayment.py @@ -7,13 +7,13 @@ from sqlalchemy.ext.asyncio import AsyncSession from app.core.memberships import schemas_memberships -from app.core.myeclpay import cruds_myeclpay, models_myeclpay, schemas_myeclpay -from app.core.myeclpay.integrity_myeclpay import format_transfer_log -from app.core.myeclpay.models_myeclpay import UserPayment -from app.core.myeclpay.schemas_myeclpay import ( +from app.core.mypayment import cruds_mypayment, models_mypayment, schemas_mypayment +from app.core.mypayment.integrity_mypayment import format_transfer_log +from app.core.mypayment.models_mypayment import UserPayment +from app.core.mypayment.schemas_mypayment import ( QRCodeContentData, ) -from app.core.myeclpay.types_myeclpay import ( +from app.core.mypayment.types_mypayment import ( TransferAlreadyConfirmedInCallbackError, TransferNotFoundByCallbackError, TransferTotalDontMatchInCallbackError, @@ -22,12 +22,12 @@ from app.core.users import schemas_users hyperion_security_logger = logging.getLogger("hyperion.security") -hyperion_myeclpay_logger = logging.getLogger("hyperion.myeclpay") +hyperion_mypayment_logger = logging.getLogger("hyperion.mypayment") hyperion_error_logger = logging.getLogger("hyperion.error") LATEST_TOS = 2 QRCODE_EXPIRATION = 5 # minutes -MYECLPAY_LOGS_S3_SUBFOLDER = "logs" +MYPAYMENT_LOGS_S3_SUBFOLDER = "logs" RETENTION_DURATION = 10 * 365 # 10 years in days @@ -51,12 +51,12 @@ def verify_signature( ) except InvalidSignature: hyperion_security_logger.info( - f"MyECLPay: Invalid signature for QR Code with WalletDevice {wallet_device_id} ({request_id})", + f"MyPayment: Invalid signature for QR Code with WalletDevice {wallet_device_id} ({request_id})", ) return False except Exception as error: hyperion_security_logger.info( - f"MyECLPay: Failed to verify signature for QR Code with WalletDevice {wallet_device_id}: {error} ({request_id})", + f"MyPayment: Failed to verify signature for QR Code with WalletDevice {wallet_device_id}: {error} ({request_id})", ) return False return True @@ -79,54 +79,54 @@ async def validate_transfer_callback( paid_amount = checkout_payment.paid_amount checkout_id = checkout_payment.checkout_id - transfer = await cruds_myeclpay.get_transfer_by_transfer_identifier( + transfer = await cruds_mypayment.get_transfer_by_transfer_identifier( db=db, transfer_identifier=str(checkout_id), ) if not transfer: hyperion_error_logger.error( - f"MyECLPay payment callback: user transfer with transfer identifier {checkout_id} not found.", + f"MyPayment payment callback: user transfer with transfer identifier {checkout_id} not found.", ) raise TransferNotFoundByCallbackError(checkout_id) if transfer.total != paid_amount: hyperion_error_logger.error( - f"MyECLPay payment callback: user transfer {transfer.id} amount does not match the paid amount.", + f"MyPayment payment callback: user transfer {transfer.id} amount does not match the paid amount.", ) raise TransferTotalDontMatchInCallbackError(checkout_id) if transfer.confirmed: hyperion_error_logger.error( - f"MyECLPay payment callback: user transfer {transfer.id} is already confirmed.", + f"MyPayment payment callback: user transfer {transfer.id} is already confirmed.", ) raise TransferAlreadyConfirmedInCallbackError(checkout_id) - await cruds_myeclpay.confirm_transfer( + await cruds_mypayment.confirm_transfer( db=db, transfer_id=transfer.id, ) - await cruds_myeclpay.increment_wallet_balance( + await cruds_mypayment.increment_wallet_balance( db=db, wallet_id=transfer.wallet_id, amount=paid_amount, ) - hyperion_myeclpay_logger.info( + hyperion_mypayment_logger.info( format_transfer_log(transfer), extra={ - "s3_subfolder": MYECLPAY_LOGS_S3_SUBFOLDER, + "s3_subfolder": MYPAYMENT_LOGS_S3_SUBFOLDER, "s3_retention": RETENTION_DURATION, }, ) def structure_model_to_schema( - structure: models_myeclpay.Structure, -) -> schemas_myeclpay.Structure: + structure: models_mypayment.Structure, +) -> schemas_mypayment.Structure: """ Convert a structure model to a schema. """ - return schemas_myeclpay.Structure( + return schemas_mypayment.Structure( id=structure.id, short_id=structure.short_id, name=structure.name, @@ -159,12 +159,12 @@ def structure_model_to_schema( def refund_model_to_schema( - refund: models_myeclpay.Refund, -) -> schemas_myeclpay.Refund: + refund: models_mypayment.Refund, +) -> schemas_mypayment.Refund: """ Convert a refund model to a schema. """ - return schemas_myeclpay.Refund( + return schemas_mypayment.Refund( id=refund.id, transaction_id=refund.transaction_id, credited_wallet_id=refund.credited_wallet_id, @@ -172,7 +172,7 @@ def refund_model_to_schema( total=refund.total, creation=refund.creation, seller_user_id=refund.seller_user_id, - transaction=schemas_myeclpay.Transaction( + transaction=schemas_mypayment.Transaction( id=refund.transaction.id, debited_wallet_id=refund.transaction.debited_wallet_id, credited_wallet_id=refund.transaction.credited_wallet_id, @@ -182,7 +182,7 @@ def refund_model_to_schema( creation=refund.transaction.creation, status=refund.transaction.status, ), - debited_wallet=schemas_myeclpay.WalletInfo( + debited_wallet=schemas_mypayment.WalletInfo( id=refund.debited_wallet.id, type=refund.debited_wallet.type, owner_name=refund.debited_wallet.store.name @@ -191,7 +191,7 @@ def refund_model_to_schema( if refund.debited_wallet.user else None, ), - credited_wallet=schemas_myeclpay.WalletInfo( + credited_wallet=schemas_mypayment.WalletInfo( id=refund.credited_wallet.id, type=refund.credited_wallet.type, owner_name=refund.credited_wallet.store.name @@ -204,12 +204,12 @@ def refund_model_to_schema( def invoice_model_to_schema( - invoice: models_myeclpay.Invoice, -) -> schemas_myeclpay.Invoice: + invoice: models_mypayment.Invoice, +) -> schemas_mypayment.Invoice: """ Convert an invoice model to a schema. """ - return schemas_myeclpay.Invoice( + return schemas_mypayment.Invoice( id=invoice.id, reference=invoice.reference, structure_id=invoice.structure_id, @@ -221,11 +221,11 @@ def invoice_model_to_schema( received=invoice.received, structure=structure_model_to_schema(invoice.structure), details=[ - schemas_myeclpay.InvoiceDetail( + schemas_mypayment.InvoiceDetail( invoice_id=invoice.id, store_id=detail.store_id, total=detail.total, - store=schemas_myeclpay.StoreSimple( + store=schemas_mypayment.StoreSimple( id=detail.store.id, name=detail.store.name, structure_id=detail.store.structure_id, diff --git a/app/core/payment/models_payment.py b/app/core/payment/models_payment.py index 1e36369073..1fd554c571 100644 --- a/app/core/payment/models_payment.py +++ b/app/core/payment/models_payment.py @@ -7,10 +7,10 @@ class CheckoutPayment(Base): - __tablename__ = "payment_checkout_payment" + __tablename__ = "checkout_checkout_payment" id: Mapped[PrimaryKey] - checkout_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("payment_checkout.id")) + checkout_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("checkout_checkout.id")) paid_amount: Mapped[int] tip_amount: Mapped[int | None] @@ -22,7 +22,7 @@ class Checkout(Base): The checkout table store data about HelloAsso checkouts. """ - __tablename__ = "payment_checkout" + __tablename__ = "checkout_checkout" id: Mapped[PrimaryKey] # Module should match the module root for the payment callback to be called diff --git a/app/core/payment/types_payment.py b/app/core/payment/types_payment.py index ac81dc74a7..79b03820f7 100644 --- a/app/core/payment/types_payment.py +++ b/app/core/payment/types_payment.py @@ -38,7 +38,7 @@ class HelloAssoConfigName(Enum): CDR = "CDR" RAID = "RAID" - MYECLPAY = "MYECLPAY" + MYPAYMENT = "MYPAYMENT" CHALLENGER = "CHALLENGER" diff --git a/app/core/users/factory_users.py b/app/core/users/factory_users.py index bb0835ec2c..468dcfbe06 100644 --- a/app/core/users/factory_users.py +++ b/app/core/users/factory_users.py @@ -15,7 +15,6 @@ from app.core.utils import security from app.core.utils.config import Settings, UserDemoFactoryConfig from app.types.factory import Factory -from app.types.floors_type import FloorsType NB_USERS = 100 @@ -66,7 +65,10 @@ async def create_core_users(cls, db: AsyncSession): randint(datetime.now(tz=UTC).year - 5, datetime.now(tz=UTC).year) # noqa: S311 for _ in range(NB_USERS) ] - floors = [random.choice(list(FloorsType)) for _ in range(NB_USERS)] # noqa: S311 + floors = [ + random.choice(["V3", "V45", "T21", "X3", "Adoma", "X2"]) # noqa: S311 + for _ in range(NB_USERS) + ] for i in range(NB_USERS): hyperion_error_logger.debug( "Creating user %s/%s", diff --git a/app/core/users/models_users.py b/app/core/users/models_users.py index b3b4682323..3802326f72 100644 --- a/app/core/users/models_users.py +++ b/app/core/users/models_users.py @@ -7,7 +7,6 @@ from app.core.groups.groups_type import AccountType from app.core.schools.models_schools import CoreSchool -from app.types.floors_type import FloorsType from app.types.sqlalchemy import Base if TYPE_CHECKING: @@ -36,7 +35,7 @@ class CoreUser(Base): birthday: Mapped[date | None] promo: Mapped[int | None] phone: Mapped[str | None] - floor: Mapped[FloorsType | None] + floor: Mapped[str | None] created_on: Mapped[datetime | None] # We use list["CoreGroup"] with quotes as CoreGroup is only defined after this class diff --git a/app/core/users/schemas_users.py b/app/core/users/schemas_users.py index df9f2b0be3..d4cdf9f23e 100644 --- a/app/core/users/schemas_users.py +++ b/app/core/users/schemas_users.py @@ -5,7 +5,6 @@ from app.core.groups.groups_type import AccountType from app.core.schools.schemas_schools import CoreSchool -from app.types.floors_type import FloorsType from app.utils import validators from app.utils.examples import examples_core @@ -42,7 +41,7 @@ class CoreUser(CoreUserSimple): email: str birthday: date | None = None promo: int | None = None - floor: FloorsType | None = None + floor: str | None = None phone: str | None = None created_on: datetime | None = None groups: "list[CoreGroupSimple]" = [] @@ -55,7 +54,7 @@ class CoreUserUpdate(BaseModel): nickname: str | None = None birthday: date | None = None phone: str | None = None - floor: FloorsType | None = None + floor: str | None = None _normalize_nickname = field_validator("nickname")( validators.trailing_spaces_remover, @@ -83,7 +82,7 @@ class CoreUserUpdateAdmin(BaseModel): nickname: str | None = None birthday: date | None = None phone: str | None = None - floor: FloorsType | None = None + floor: str | None = None _normalize_name = field_validator("name")(validators.trailing_spaces_remover) _normalize_firstname = field_validator("firstname")( @@ -140,7 +139,7 @@ class CoreUserActivateRequest(CoreUserBase): password: str birthday: date | None = None phone: str | None = None - floor: FloorsType | None = None + floor: str | None = None promo: int | None = Field( default=None, description="Promotion of the student, an integer like 2021", diff --git a/app/core/utils/config.py b/app/core/utils/config.py index 9ad7c664a8..b53ab3e501 100644 --- a/app/core/utils/config.py +++ b/app/core/utils/config.py @@ -1,5 +1,6 @@ from functools import cached_property from pathlib import Path +from re import Pattern from typing import Any, ClassVar import jwt @@ -7,6 +8,7 @@ from cryptography.hazmat.primitives.asymmetric import rsa from cryptography.hazmat.primitives.serialization import load_pem_private_key from pydantic import BaseModel, computed_field, model_validator +from pydantic_extra_types.color import Color from pydantic_settings import ( BaseSettings, PydanticBaseSettingsSource, @@ -14,6 +16,7 @@ YamlConfigSettingsSource, ) +from app.core.core_endpoints.schemas_core import MainActivationForm from app.core.payment.types_payment import HelloAssoConfig, HelloAssoConfigName from app.types.exceptions import ( DotenvInvalidAuthClientNameInError, @@ -24,6 +27,52 @@ from app.utils.auth import providers +class School(BaseModel): + """ + Configuration for a school. + This class is used to store the configuration of a school. + It is used to create an instance of the school. + """ + + # Name of the school (ex: École Centrale Lyon) + school_name: str + # Name of the application (ex: MyECL) + application_name: str + # Name of the payment solution (ex: MyECLPay) + payment_name: str + # Domain name of the application (ex: myecl.fr) + application_domain_name: str + # Name of the entity managing the application (ex: ÉCLAIR) + entity_name: str + # The entity website url, used for promotion (ex: "https://myecl.fr/") + entity_site_url: str + # The entity email, used for contact + entity_email: str + # Date of the end of support for the application (ex: 2025-08-25) + end_of_support: str + # Colors used for the application + primary_color: Color + # Email placeholder + email_placeholder: str + # Main activation form configuration + main_activation_form: MainActivationForm + # Apple Store URL + app_store_url: str | None = None + # Google Play Store URL + play_store_url: str | None = None + + # Regex for email account type validation + # On registration, user whose email match these regex will be automatically assigned to the corresponding account type + # Use simple quotes to avoid escaping the regex + # Ex: `student_email_regex: '^[\w\-.]*@domain.fr$'` + student_email_regex: Pattern + staff_email_regex: Pattern | None = None + former_student_email_regex: Pattern | None = None + + # If event should be confirmed by a moderator before being added to the calendar + require_event_confirmation: bool = True + + class AuthClientConfig(BaseModel): """ Configuration for an auth client. @@ -214,6 +263,11 @@ def settings_customise_sources( # This file can be created and downloaded from [Google cloud, IAM and administration, Service account](https://console.cloud.google.com/iam-admin/serviceaccounts) page. USE_FIREBASE: bool = False + ######################## + # School Configuration # + ######################## + school: School + ######################## # Matrix configuration # ######################## @@ -237,7 +291,7 @@ def settings_customise_sources( #################### # S3 configuration # #################### - # S3 configuration is needed to use the S3 storage for MyECLPay logs + # S3 configuration is needed to use the S3 storage for MyPayment logs S3_BUCKET_NAME: str | None = None S3_ACCESS_KEY_ID: str | None = None @@ -270,17 +324,17 @@ def settings_customise_sources( HELLOASSO_CONFIGURATIONS: dict[HelloAssoConfigName, HelloAssoConfig] = {} HELLOASSO_API_BASE: str | None = None - # Maximum wallet balance for MyECLPay in cents, we will prevent user from adding more money to their wallet if it will make their balance exceed this value - MYECLPAY_MAXIMUM_WALLET_BALANCE: int = 1000 + # Maximum wallet balance for MyPayment in cents, we will prevent user from adding more money to their wallet if it will make their balance exceed this value + MYPAYMENT_MAXIMUM_WALLET_BALANCE: int = 1000 # Trusted urls is a list of redirect payment url that can be trusted by Hyperion. # These urls will be used to validate the redirect url provided by the front TRUSTED_PAYMENT_REDIRECT_URLS: list[str] = [] - # MyECLPay requires an external service to recurrently check for transactions and state integrity, this service needs an access to all the data related to the transactions and the users involved + # MyPayment requires an external service to recurrently check for transactions and state integrity, this service needs an access to all the data related to the transactions and the users involved # This service will use a special token to access the data # If this token is not set, the service will not be able to access the data and no integrity check will be performed - MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN: str | None = None + MYPAYMENT_DATA_VERIFIER_ACCESS_TOKEN: str | None = None ################### # Tokens validity # @@ -291,7 +345,7 @@ def settings_customise_sources( ACCESS_TOKEN_EXPIRE_MINUTES: int = 30 REFRESH_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 14 # 14 days AUTHORIZATION_CODE_EXPIRE_MINUTES: int = 7 - MYECLPAY_MANAGER_TRANSFER_TOKEN_EXPIRES_MINUTES: int = 20 + MYPAYMENT_MANAGER_TRANSFER_TOKEN_EXPIRES_MINUTES: int = 20 ############################# # pyproject.toml parameters # diff --git a/app/core/utils/log.py b/app/core/utils/log.py index f6fe2d68d8..07a74335e2 100644 --- a/app/core/utils/log.py +++ b/app/core/utils/log.py @@ -74,7 +74,7 @@ class console_color: LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" MATRIX_LOG_FORMAT: str = "%(asctime)s - %(name)s - %(levelname)s - %(message)s" - MYECLPAY_LOG_FORMAT: str = "%(message)s" # Do not change at any cost + MYPAYMENT_LOG_FORMAT: str = "%(message)s" # Do not change at any cost # Logging config # See https://docs.python.org/3/library/logging.config.html#logging-config-dictschema @@ -83,7 +83,7 @@ def _get_config_dict(self, settings: Settings): # /!\ WARNING /!\ # MINIMUM_LOG_LEVEL should never be set higher than INFO - # as it would prevent important information to be logged, like MyECLPay operations + # as it would prevent important information to be logged, like MyPayment operations MINIMUM_LOG_LEVEL: str = ( "DEBUG" if settings.LOG_DEBUG_MESSAGES else "INFO" ) # /!\ read warning before modifying this /!\ @@ -104,8 +104,8 @@ def _get_config_dict(self, settings: Settings): "format": self.MATRIX_LOG_FORMAT, "datefmt": "%d-%b-%y %H:%M:%S", }, - "myeclpay": { - "format": self.MYECLPAY_LOG_FORMAT, + "mypayment": { + "format": self.MYPAYMENT_LOG_FORMAT, }, }, "handlers": { @@ -141,17 +141,17 @@ def _get_config_dict(self, settings: Settings): ), "level": "INFO", }, - "myeclpay_s3": { - "formatter": "myeclpay", + "mypayment_s3": { + "formatter": "mypayment", "class": "app.utils.loggers_tools.s3_handler.S3LogHandler", - "failure_logger": "hyperion.myeclpay.fallback", + "failure_logger": "hyperion.mypayment.fallback", "s3_bucket_name": settings.S3_BUCKET_NAME, "s3_access_key_id": settings.S3_ACCESS_KEY_ID, "s3_secret_access_key": settings.S3_SECRET_ACCESS_KEY, - "folder": "myeclpay", + "folder": "mypayment", }, "s3": { - "formatter": "myeclpay", + "formatter": "mypayment", "class": "app.utils.loggers_tools.s3_handler.S3LogHandler", "failure_logger": "hyperion.s3.fallback", "s3_bucket_name": settings.S3_BUCKET_NAME, @@ -190,17 +190,17 @@ def _get_config_dict(self, settings: Settings): "backupCount": 50, "level": "INFO", }, - "file_myeclpay": { - # file_myeclpay is there to log all operations related to MyECLPay that failed to be logged in the S3 bucket + "file_mypayment": { + # file_mypayment is there to log all operations related to MyPayment that failed to be logged in the S3 bucket "formatter": "default", "class": "logging.handlers.RotatingFileHandler", - "filename": "logs/myeclpay.log", + "filename": "logs/mypayment.log", "maxBytes": 1024 * 1024 * 40, # ~ 40 MB "backupCount": 100, "level": "DEBUG", }, "file_s3": { - # file_myeclpay is there to log all operations related to MyECLPay that failed to be logged in the S3 bucket + # file_mypayment is there to log all operations related to MyPayment that failed to be logged in the S3 bucket "formatter": "default", "class": "logging.handlers.RotatingFileHandler", "filename": "logs/s3.log", @@ -266,18 +266,18 @@ def _get_config_dict(self, settings: Settings): ], "level": MINIMUM_LOG_LEVEL, }, - "hyperion.myeclpay.fallback": { + "hyperion.mypayment.fallback": { "handlers": [ - "file_myeclpay", + "file_mypayment", "matrix_errors", "console", ], "level": MINIMUM_LOG_LEVEL, "propagate": False, }, - "hyperion.myeclpay": { + "hyperion.mypayment": { "handlers": [ - "myeclpay_s3", + "mypayment_s3", ], "level": MINIMUM_LOG_LEVEL, }, diff --git a/app/modules/cdr/models_cdr.py b/app/modules/cdr/models_cdr.py index 9640204b94..f01411ea74 100644 --- a/app/modules/cdr/models_cdr.py +++ b/app/modules/cdr/models_cdr.py @@ -265,7 +265,7 @@ class Checkout(Base): user_id: Mapped[str] = mapped_column( ForeignKey("core_user.id"), ) - checkout_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("payment_checkout.id")) + checkout_id: Mapped[uuid.UUID] = mapped_column(ForeignKey("checkout_checkout.id")) class Ticket(Base): diff --git a/app/modules/cdr/schemas_cdr.py b/app/modules/cdr/schemas_cdr.py index 7d99fca733..4571809c6b 100644 --- a/app/modules/cdr/schemas_cdr.py +++ b/app/modules/cdr/schemas_cdr.py @@ -10,7 +10,6 @@ DocumentSignatureType, PaymentType, ) -from app.types.floors_type import FloorsType from app.types.websocket import WSMessageModel from app.utils import validators @@ -45,7 +44,7 @@ class CdrUser(CdrUserPreview): email: str birthday: date | None = None phone: str | None = None - floor: FloorsType | None = None + floor: str | None = None model_config = ConfigDict(from_attributes=True) @@ -56,7 +55,7 @@ class CdrUserUpdate(BaseModel): email: str | None = None birthday: date | None = None phone: str | None = None - floor: FloorsType | None = None + floor: str | None = None _normalize_nickname = field_validator("nickname")( validators.trailing_spaces_remover, @@ -259,7 +258,7 @@ class PaymentUrl(BaseModel): class UserTicket(CoreUserSimple): promo: int | None = None - floor: FloorsType | None = None + floor: str | None = None created_on: datetime | None = None diff --git a/app/modules/myeclpay/__init__.py b/app/modules/mypayment/__init__.py similarity index 100% rename from app/modules/myeclpay/__init__.py rename to app/modules/mypayment/__init__.py diff --git a/app/modules/myeclpay/endpoints_myeclpay.py b/app/modules/mypayment/endpoints_mypayment.py similarity index 70% rename from app/modules/myeclpay/endpoints_myeclpay.py rename to app/modules/mypayment/endpoints_mypayment.py index 213cde1f2b..a101a85116 100644 --- a/app/modules/myeclpay/endpoints_myeclpay.py +++ b/app/modules/mypayment/endpoints_mypayment.py @@ -3,14 +3,14 @@ from app.types.module import Module -class MyECLPayPermissions(ModulePermissions): +class MyPaymentPermissions(ModulePermissions): access_payment = "access_payment" module = Module( - root="payment", - tag="MyECLPay", + root="mypayment", + tag="MyPayment", default_allowed_account_types=[AccountType.student, AccountType.staff], factory=None, - permissions=MyECLPayPermissions, + permissions=MyPaymentPermissions, ) diff --git a/app/modules/raid/models_raid.py b/app/modules/raid/models_raid.py index a363248d21..fceff2d839 100644 --- a/app/modules/raid/models_raid.py +++ b/app/modules/raid/models_raid.py @@ -306,4 +306,4 @@ class RaidParticipantCheckout(Base): participant_id: Mapped[str] = mapped_column( ForeignKey("raid_participant.id"), ) - checkout_id: Mapped[str] = mapped_column(ForeignKey("payment_checkout.id")) + checkout_id: Mapped[str] = mapped_column(ForeignKey("checkout_checkout.id")) diff --git a/app/modules/sport_competition/models_sport_competition.py b/app/modules/sport_competition/models_sport_competition.py index 91e53f37fa..f9b0163f0b 100644 --- a/app/modules/sport_competition/models_sport_competition.py +++ b/app/modules/sport_competition/models_sport_competition.py @@ -437,7 +437,7 @@ class CompetitionCheckout(Base): edition_id: Mapped[UUID] = mapped_column( ForeignKey("competition_edition.id"), ) - checkout_id: Mapped[UUID] = mapped_column(ForeignKey("payment_checkout.id")) + checkout_id: Mapped[UUID] = mapped_column(ForeignKey("checkout_checkout.id")) class VolunteerShift(Base): diff --git a/app/types/floors_type.py b/app/types/floors_type.py deleted file mode 100644 index f079f8b770..0000000000 --- a/app/types/floors_type.py +++ /dev/null @@ -1,29 +0,0 @@ -from enum import Enum - - -class FloorsType(str, Enum): - # WARNING: the key is used in the database. Use the same key and value. - Autre = "Autre" - Adoma = "Adoma" - Exte = "Exte" - T1 = "T1" - T2 = "T2" - T3 = "T3" - T4 = "T4" - T56 = "T56" - U1 = "U1" - U2 = "U2" - U3 = "U3" - U4 = "U4" - U56 = "U56" - V1 = "V1" - V2 = "V2" - V3 = "V3" - V45 = "V45" - V6 = "V6" - X1 = "X1" - X2 = "X2" - X3 = "X3" - X4 = "X4" - X5 = "X5" - X6 = "X6" diff --git a/app/utils/auth/providers.py b/app/utils/auth/providers.py index 8aaef0bd76..dc0b8c3685 100644 --- a/app/utils/auth/providers.py +++ b/app/utils/auth/providers.py @@ -8,7 +8,6 @@ ) from app.core.permissions.type_permissions import ModulePermissions from app.core.users import models_users -from app.types.floors_type import FloorsType from app.types.scopes_type import ScopeType from app.utils.tools import is_user_member_of_any_group @@ -273,7 +272,7 @@ def get_userinfo(cls, user: models_users.CoreUser): "id": user.id, "nickname": user.nickname, "promo": user.promo, - "floor": user.floor or FloorsType.Autre, + "floor": user.floor or "Autre", } diff --git a/app/utils/state.py b/app/utils/state.py index 0a31dde7fe..cbb8f4cc1a 100644 --- a/app/utils/state.py +++ b/app/utils/state.py @@ -172,7 +172,7 @@ def init_mail_templates( ) -> calypsso.MailTemplates: return calypsso.MailTemplates( product_name="MyECL", - payment_product_name="MyECLPay", + payment_product_name=settings.school.payment_name, entity_name="ÉCLAIR", entity_site_url="https://myecl.fr/", api_base_url=settings.CLIENT_URL, diff --git a/app/utils/tools.py b/app/utils/tools.py index e1d2ab9576..794bc70575 100644 --- a/app/utils/tools.py +++ b/app/utils/tools.py @@ -599,3 +599,17 @@ async def execute_async_or_sync_method( if iscoroutinefunction(job_function): return await job_function(**kwargs) return job_function(**kwargs) + + +def patch_identity_in_text( + text: str, + settings: "Settings", +): + """ + Patch the given text with the identity of the school. + This is used to replace the identity placeholders in the legal texts with the values defined in the settings. + """ + for key, value in settings.school.model_dump().items(): + if isinstance(value, str): + text = text.replace(f"{{{key}}}", value) + return text diff --git a/assets/myeclpay-terms-of-service.txt b/assets/myeclpay-terms-of-service.txt deleted file mode 100644 index d1dd40d3ae..0000000000 --- a/assets/myeclpay-terms-of-service.txt +++ /dev/null @@ -1,30 +0,0 @@ -Version 2 - -# CGU MyECLPay - -## Objet des CGU -Les présentes Conditions Générales d’Utilisation (CGU) ont pour objet de définir les modalités et conditions d’utilisation de la solution de paiement dématérialisée MyECLPay, éditée par l’association AEECL, destinée aux élèves et étudiants d'École Centrale Lyon. - -## Présentation de MyECLPay -MyECLPay est une solution de paiement virtuel et dématérialisé utilisable au sein de l'École Centrale Lyon exclusivement, avec les associations participantes. Elle repose sur une monnaie virtuelle appelée , qui n’a aucune valeur légale et ne constitue pas une monnaie électronique au sens du Code monétaire et financier. Un (1) euro correspond à un (1) . - -## Fonctionnement du portefeuille virtuel -Lors de son inscription, l’utilisateur se voit attribuer un portefeuille numérique personnel plafonné. Il s’engage à ne pas tenter de dépasser ce plafond par quelque moyen que ce soit. En validant son inscription, l’utilisateur reconnaît renoncer expressément à son droit de rétractation, conformément à l’article L221-28 du Code de la Consommation. -La monnaie virtuelle ne peut pas être convertie en euros ou en toute autre devise à cours légal. Elle est non remboursable, non réversible, et ne peut pas être cédée ou transférée à d’autres utilisateurs. Un portefeuille ne peut jamais être en solde négatif. - -## Recharge du portefeuille via HelloAsso -L’utilisateur peut recharger son portefeuille par carte bancaire via la plateforme HelloAsso. Les fonds seront versés directement sur le compte bancaire de l’association AEECL, et un équivalent en est crédité sur le portefeuille numérique de l’utilisateur. -HelloAsso est une plateforme française de paiement pour les associations, fonctionnant sur un modèle solidaire, garantissant que 100 % de votre paiement sera versé à l’association choisie. -Elle se finance uniquement par des 'contribution volontaire' et par défaut, HelloAsso proposera à l’utilisateur de faire une 'contribution volontaire', qui peut librement refuser sans que cela empêche la transaction. Si vous choisissez de faire cette contribution, celle-ci soutiendra l’aide qu’HelloAsso apporte aux associations et seul HelloAsso en bénéficiera. - -## Utilisation des fonds et paiements -Le paiement avec MyECLPay est uniquement possible auprès des associations partenaires. L’utilisateur doit préalablement activer son appareil par un lien unique reçu par email. Chaque paiement est validé par une vérification biométrique effectuée localement par l’appareil de l’utilisateur. - -## Sécurité, responsabilité et données personnelles -L’utilisateur est responsable de la sécurité de son appareil et de son accès à MyECLPay. Toute utilisation frauduleuse, perte ou vol doit être signalée sans délai. Le compte pourra alors être suspendu temporairement. Il est interdit de prêter ou partager son compte. -MyECLPay respecte le Règlement Général sur la Protection des Données (RGPD). Les données collectées sont strictement nécessaires au fonctionnement du service : identifiants, email, historique de transactions, identifiant de l’appareil. Aucune donnée bancaire n’est collectée ni conservée par MyECLPay. -MyECLPay fait partie de la plateforme MyECL, en utilisant le service, l’utilisateur reconnait et accepte les conditions générales d’utilisations et la politique de confidentialité de MyECL - -## Modifications des CGU -L'AEECL se réserve le droit de modifier les présentes CGU à tout moment. L’utilisation du service après notification est conditionné par l’acceptation des nouvelles CGU. -Pour toute question, demande d’assistance ou réclamation, l’utilisateur peut contacter : eclair@myecl.fr. diff --git a/assets/mypayment-terms-of-service.txt b/assets/mypayment-terms-of-service.txt new file mode 100644 index 0000000000..192c841438 --- /dev/null +++ b/assets/mypayment-terms-of-service.txt @@ -0,0 +1,59 @@ +**Privacy Policy** + +This privacy policy is applicable to the {application_name} app (hereinafter referred to as "Application"), which was developed by {entity_name} (hereinafter referred to as "Service Provider") as a Free service. + +This service is provided "AS IS". + +**What information does the Application obtain and how is it used?** +**User Provided Information** + +The Application acquires the information you supply when you download and register the Application. Registration with the Service Provider is not mandatory. However, bear in mind that you might not be able to utilize some of the features offered by the Application unless you register with them. + +The Service Provider may also use the information you provided them to contact you from time to time to provide you with important information, required notices and marketing promotions. + +**Automatically Collected Information** + +In addition, the Application may collect certain information automatically, including, but not limited to, the type of mobile device you use, your mobile devices unique device ID, the IP address of your mobile device, your mobile operating system, the type of mobile Internet browsers you use, and information about the way you use the Application. + +**Does the Application collect precise real time location information of the device?** + +This Application does not gather precise information about the location of your mobile device. + +**Do third parties see and/or have access to information obtained by the Application?** + +The Service Provider may disclose User Provided and Automatically Collected Information: +- as required by law, such as to comply with a subpoena, or similar legal process; +- when they believe in good faith that disclosure is necessary to protect their rights, protect your safety or the safety of others, investigate fraud, or respond to a government request; +- with their trusted services providers who work on their behalf, do not have an independent use of the information we disclose to them, and have agreed to adhere to the rules set forth in this privacy statement. + +**What are my opt-out rights?** + +You can halt all collection of information by the Application easily by uninstalling the Application. You may use the standard uninstall processes as may be available as part of your mobile device or via the mobile application marketplace or network. + +**Data Retention Policy, Managing Your Information** + +The Service Provider will retain User Provided data for as long as you use the Application and for a reasonable time thereafter. The Service Provider will retain Automatically Collected information for up to 24 months and thereafter may store it in aggregate. If you'd like the Service Provider to delete User Provided Data that you have provided via the Application, please contact them at {entity_email} and we will respond in a reasonable time. Please note that some or all of the User Provided Data may be required in order for the Application to function properly. + +**Children** + +The Service Provider does not use the Application to knowingly solicit data from or market to children under the age of 13. + +The Service Provider does not knowingly collect personally identifiable information from children. The Service Provider encourages all children to never submit any personally identifiable information through the Application and/or Services. The Service Provider encourage parents and legal guardians to monitor their children's Internet usage and to help enforce this Policy by instructing their children never to provide personally identifiable information through the Application and/or Services without their permission. If you have reason to believe that a child has provided personally identifiable information to the Service Provider through the Application and/or Services, please contact the Service Provider ({entity_email}) so that they will be able to take the necessary actions. You must also be at least 16 years of age to consent to the processing of your personally identifiable information in your country (in some countries we may allow your parent or guardian to do so on your behalf). + +**Security** + +The Service Provider are concerned about safeguarding the confidentiality of your information. The Service Provider provide physical, electronic, and procedural safeguards to protect information we process and maintain. For example, we limit access to this information to authorized employees and contractors who need to know that information in order to operate, develop or improve their Application. Please be aware that, although we endeavor provide reasonable security for information we process and maintain, no security system can prevent all potential security breaches. + +**Changes** + +This Privacy Policy may be updated from time to time for any reason. The Service Provider will notify you of any changes to the Privacy Policy by updating this page with the new Privacy Policy. You are advised to consult this Privacy Policy regularly for any changes, as continued use is deemed approval of all changes. + +This privacy policy is effective as of 2025-08-12 + +**Your Consent** + +By using the Application, you are giving your consent to the Service Provider processing of your information as set forth in this Privacy Policy now and as amended by us. "Processing,” means using cookies on a computer/hand held device or using or touching information in any way, including, but not limited to, collecting, storing, deleting, using, combining and disclosing information. + +**Contact us** + +If you have any questions regarding privacy while using the Application, or have questions about the practices, please contact the Service Provider via email at {entity_email}. \ No newline at end of file diff --git a/assets/security.txt b/assets/security.txt index 11f8cb41da..bc513ac18f 100644 --- a/assets/security.txt +++ b/assets/security.txt @@ -1,5 +1,3 @@ -Contact: mailto:security@myecl.fr -Expires: 2023-02-28T13:00:00.000Z -Preferred-Languages: en, fr -Canonical: https://api.myecl.fr/.well-known/security.txt -Canonical: https://myecl.fr/.well-known/security.txt +Contact: mailto:{entity_email} +Expires: {end_of_support}T00:00:00.000Z +Preferred-Languages: en, fr \ No newline at end of file diff --git a/assets/support.txt b/assets/support.txt index d1191e3440..da3b205523 100644 --- a/assets/support.txt +++ b/assets/support.txt @@ -1,5 +1,31 @@ -Welcome on MyECL support page. +**Terms & Conditions** -You can create an user by choosing "Créer un compte" on the main page of the application. You will receive a message on the adresse you entered asking you to confirm your account. +By downloading or using the app, these terms will automatically apply to you – you should make sure therefore that you read them carefully before using the app. The app itself, and all the trade marks, copyright, database rights and other intellectual property rights related to it, belong to their respective owners. -If you have any problems using MyECL, please contact us at eclair@myecl.fr. We undertake to process your request as soon as possible. +{entity_name} is committed to ensuring that the app is as useful and efficient as possible. For that reason, we reserve the right to make changes to the app or to charge for its services, at any time and for any reason. We will never charge you for the app or its services without making it very clear to you exactly what you’re paying for. + +The {application_name} app stores and processes personal data that you have provided to us, in order to provide our Service. It’s your responsibility to keep your phone and access to the app secure. We therefore recommend that you do not jailbreak or root your phone, which is the process of removing software restrictions and limitations imposed by the official operating system of your device. It could make your phone vulnerable to malware/viruses/malicious programs, compromise your phone’s security features and it could mean that the {application_name} app won’t work properly or at all. + +The app does use third party services that declare their own Terms and Conditions. + +Link to Terms and Conditions of third party service providers used by the app + +You should be aware that there are certain things that {entity_name} will not take responsibility for. Certain functions of the app will require the app to have an active internet connection. The connection can be Wi-Fi, or provided by your mobile network provider, but {entity_name} cannot take responsibility for the app not working at full functionality if you don’t have access to Wi-Fi, and you don’t have any of your data allowance left. + +If you’re using the app outside of an area with Wi-Fi, you should remember that your terms of the agreement with your mobile network provider will still apply. As a result, you may be charged by your mobile provider for the cost of data for the duration of the connection while accessing the app, or other third party charges. In using the app, you’re accepting responsibility for any such charges, including roaming data charges if you use the app outside of your home territory (i.e. region or country) without turning off data roaming. If you are not the bill payer for the device on which you’re using the app, please be aware that we assume that you have received permission from the bill payer for using the app. + +Along the same lines, {entity_name} cannot always take responsibility for the way you use the app i.e. You need to make sure that your device stays charged – if it runs out of battery and you can’t turn it on to avail the Service, {entity_name} cannot accept responsibility. + +With respect to {entity_name}’s responsibility for your use of the app, when you’re using the app, it’s important to bear in mind that although we endeavour to ensure that it is updated and correct at all times, we do rely on third parties to provide information to us so that we can make it available to you. {entity_name} accepts no liability for any loss, direct or indirect, you experience as a result of relying wholly on this functionality of the app. + +At some point, we may wish to update the app. The app is currently available on Android & iOS – the requirements for both systems (and for any additional systems we decide to extend the availability of the app to) may change, and you’ll need to download the updates if you want to keep using the app. {entity_name} does not promise that it will always update the app so that it is relevant to you and/or works with the Android & iOS version that you have installed on your device. However, you promise to always accept updates to the application when offered to you, We may also wish to stop providing the app, and may terminate use of it at any time without giving notice of termination to you. Unless we tell you otherwise, upon any termination, (a) the rights and licenses granted to you in these terms will end; (b) you must stop using the app, and (if needed) delete it from your device. + +**Changes to This Terms and Conditions** + +We may update our Terms and Conditions from time to time. Thus, you are advised to review this page periodically for any changes. We will notify you of any changes by posting the new Terms and Conditions on this page. + +These terms and conditions are effective as of 2025-08-12. + +**Contact Us** + +If you have any questions or suggestions about our Terms and Conditions, do not hesitate to contact us at {entity_email}. \ No newline at end of file diff --git a/assets/templates/generate.py b/assets/templates/generate.py index c64f96b61d..53dac229ee 100644 --- a/assets/templates/generate.py +++ b/assets/templates/generate.py @@ -1,6 +1,6 @@ from weasyprint import CSS, HTML -html = HTML("./myeclpay_invoice.html") +html = HTML("./mypayment_invoice.html") css = CSS("./output.css") # cssextra = CSS("./outputextra.css") diff --git a/assets/templates/myeclpay_invoice.html b/assets/templates/mypayment_invoice.html similarity index 100% rename from assets/templates/myeclpay_invoice.html rename to assets/templates/mypayment_invoice.html diff --git a/config.template.yaml b/config.template.yaml index a2754959f9..b7ed5a7ea0 100644 --- a/config.template.yaml +++ b/config.template.yaml @@ -152,7 +152,87 @@ SMTP_EMAIL: # To enable Firebase push notification capabilities, a JSON key file named `firebase.json` should be placed at Hyperion root. # This file can be created and downloaded from [Google cloud, IAM and administration, Service account](https://console.cloud.google.com/iam-admin/serviceaccounts) page. -USE_FIREBASE: False +USE_FIREBASE: false + +######################## +# School configuration # +######################## + +school: + # Name of the school (ex: École Centrale Lyon) + school_name: "École Centrale Lyon" + # Name of the application (ex: MyECL) + application_name: MyECL + # Name of the payment solution (ex: MyECLPay) + payment_name: MyECLPay + # Domain name of the application (ex: myecl.fr) + application_domain_name: myecl.fr + # Name of the entity managing the application (ex: ÉCLAIR) + entity_name: ÉCLAIR + # The entity website url, used for promotion (ex: "https://myecl.fr/") + entity_site_url: "https://myecl.fr/" + # The entity email, used for contact + entity_email: "eclair@myecl.fr" + # Email placeholder + email_placeholder: "prenom.nom@etu.ec-lyon.fr" + # Apple Store URL + app_store_url: https://apps.apple.com/fr/app/myecl/id6444443430 + # Google Play Store URL + play_store_url: https://play.google.com/store/apps/details?id=fr.myecl.titan + + # Date of the end of support for the application (ex: 2025-08-25) + end_of_support: "2030-01-01" + + # Regex for email account type validation + # On registration, user whose email match these regex will be automatically assigned to the corresponding account type + # Use simple quotes to avoid escaping the regex + # Ex: `student_email_regex: '^[\w\-.]*@domain.fr$'` + student_email_regex: '^[\w\-.]*@etu(-enise)?\.ec-lyon\.fr$' + staff_email_regex: + former_student_email_regex: + # Colors used for the application + primary_color: "#F97315" + + # Questions and options for the form of account activation + main_activation_form: + fields: + - birthdate + - promotion + - phone + - floor + - nickname + floor_choices: + - Autre + - Adoma + - Exte + - T1 + - T2 + - T3 + - T4 + - T56 + - U1 + - U2 + - U3 + - U4 + - U56 + - V1 + - V2 + - V3 + - V45 + - V6 + - X1 + - X2 + - X3 + - X4 + - X5 + - X6 + promotion_offset: 0 + + # If event should be confirmed by a moderator before being added to the calendar + #require_event_confirmation: bool = False + + # If event should be confirmed by a moderator before being added to the calendar + #require_event_confirmation: bool = False ######################## # Matrix configuration # ######################## @@ -179,7 +259,7 @@ USE_FIREBASE: False # S3 configuration # #################### -# S3 configuration is needed to use the S3 storage for MyECLPay logs +# S3 configuration is needed to use the S3 storage for MyPayment logs #S3_BUCKET_NAME: #S3_ACCESS_KEY_ID: @@ -218,15 +298,15 @@ USE_FIREBASE: False # redirection_uri: null #HELLOASSO_API_BASE: api.helloasso-sandbox.com -# Maximum wallet balance for MyECLPay in cents, we will prevent user from adding more money to their wallet if it will make their balance exceed this value -#MYECLPAY_MAXIMUM_WALLET_BALANCE: 8000 +# Maximum wallet balance for MyPayment in cents, we will prevent user from adding more money to their wallet if it will make their balance exceed this value +#MYPAYMENT_MAXIMUM_WALLET_BALANCE: 1000 # Trusted urls is a list of redirect payment url that can be trusted by Hyperion. # These urls will be used to validate the redirect url provided by the front #TRUSTED_PAYMENT_REDIRECT_URLS: # - http://localhost:3000/static.html -# MyECLPay requires an external service to recurrently check for transactions and state integrity, this service needs an access to all the data related to the transactions and the users involved +# MyPayment requires an external service to recurrently check for transactions and state integrity, this service needs an access to all the data related to the transactions and the users involved # This service will use a special token to access the data # If this token is not set, the service will not be able to access the data and no integrity check will be performed -#MYECLPAY_DATA_VERIFIER_ACCESS_TOKEN: +#MYPAYMENT_DATA_VERIFIER_ACCESS_TOKEN: diff --git a/migrations/versions/50_myeclpay_to_mypayment.py b/migrations/versions/50_myeclpay_to_mypayment.py new file mode 100644 index 0000000000..5516c3a155 --- /dev/null +++ b/migrations/versions/50_myeclpay_to_mypayment.py @@ -0,0 +1,190 @@ +"""MyECLPay to MyPayment + +Create Date: 2025-11-29 22:50:53.781596 +""" + +from collections.abc import Sequence +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pytest_alembic import MigrationContext + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "467ad07734c0" +down_revision: str | None = "1051d705419e" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +def upgrade() -> None: + op.rename_table( + "payment_checkout_payment", + "checkout_checkout_payment", + ) + op.rename_table( + "payment_checkout", + "checkout_checkout", + ) + op.rename_table( + "myeclpay_wallet", + "mypayment_wallet", + ) + op.rename_table( + "myeclpay_wallet_device", + "mypayment_wallet_device", + ) + op.rename_table( + "myeclpay_transaction", + "mypayment_transaction", + ) + op.rename_table( + "myeclpay_refund", + "mypayment_refund", + ) + op.rename_table( + "myeclpay_structure", + "mypayment_structure", + ) + op.rename_table( + "myeclpay_structure_manager_transfer", + "mypayment_structure_manager_transfer", + ) + op.rename_table( + "myeclpay_store", + "mypayment_store", + ) + op.rename_table( + "myeclpay_request", + "mypayment_request", + ) + op.rename_table("myeclpay_transfer", "mypayment_transfer") + op.rename_table( + "myeclpay_seller", + "mypayment_seller", + ) + op.rename_table( + "myeclpay_user_payment", + "mypayment_user_payment", + ) + op.rename_table( + "myeclpay_used_qrcode", + "mypayment_used_qrcode", + ) + op.rename_table( + "myeclpay_invoice", + "mypayment_invoice", + ) + op.rename_table( + "myeclpay_invoice_detail", + "mypayment_invoice_detail", + ) + op.rename_table( + "myeclpay_withdrawal", + "mypayment_withdrawal", + ) + op.drop_index( + "ix_payment_checkout_payment_hello_asso_payment_id", + table_name="checkout_checkout_payment", + ) + op.create_index( + op.f("ix_checkout_checkout_payment_hello_asso_payment_id"), + "checkout_checkout_payment", + ["hello_asso_payment_id"], + unique=True, + ) + # ### end Alembic commands ###s + + +def downgrade() -> None: + op.rename_table( + "checkout_checkout_payment", + "payment_checkout_payment", + ) + op.rename_table( + "checkout_checkout", + "payment_checkout", + ) + op.rename_table( + "mypayment_wallet", + "myeclpay_wallet", + ) + op.rename_table( + "mypayment_wallet_device", + "myeclpay_wallet_device", + ) + op.rename_table( + "mypayment_transaction", + "myeclpay_transaction", + ) + op.rename_table( + "mypayment_refund", + "myeclpay_refund", + ) + op.rename_table( + "mypayment_structure", + "myeclpay_structure", + ) + op.rename_table( + "mypayment_structure_manager_transfer", + "myeclpay_structure_manager_transfer", + ) + op.rename_table( + "mypayment_store", + "myeclpay_store", + ) + op.rename_table( + "mypayment_request", + "myeclpay_request", + ) + op.rename_table("mypayment_transfer", "myeclpay_transfer") + op.rename_table( + "mypayment_seller", + "myeclpay_seller", + ) + op.rename_table( + "mypayment_user_payment", + "myeclpay_user_payment", + ) + op.rename_table( + "mypayment_used_qrcode", + "myeclpay_used_qrcode", + ) + op.rename_table( + "mypayment_invoice", + "myeclpay_invoice", + ) + op.rename_table( + "mypayment_invoice_detail", + "myeclpay_invoice_detail", + ) + op.rename_table( + "mypayment_withdrawal", + "myeclpay_withdrawal", + ) + op.drop_index( + "ix_checkout_checkout_payment_hello_asso_payment_id", + table_name="checkout_checkout_payment", + ) + op.create_index( + "ix_payment_checkout_payment_hello_asso_payment_id", + "payment_checkout_payment", + ["hello_asso_payment_id"], + unique=True, + ) + + +def pre_test_upgrade( + alembic_runner: "MigrationContext", + alembic_connection: sa.Connection, +) -> None: + pass + + +def test_upgrade( + alembic_runner: "MigrationContext", + alembic_connection: sa.Connection, +) -> None: + pass diff --git a/migrations/versions/51_remove_hardcoded_floor.py b/migrations/versions/51_remove_hardcoded_floor.py new file mode 100644 index 0000000000..e904376d62 --- /dev/null +++ b/migrations/versions/51_remove_hardcoded_floor.py @@ -0,0 +1,86 @@ +"""Remove hardcoded floor + +Create Date: 2025-11-30 01:50:06.674367 +""" + +from collections.abc import Sequence +from enum import Enum +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from pytest_alembic import MigrationContext + +import sqlalchemy as sa +from alembic import op + +# revision identifiers, used by Alembic. +revision: str = "b04f76f4198f" +down_revision: str | None = "467ad07734c0" +branch_labels: str | Sequence[str] | None = None +depends_on: str | Sequence[str] | None = None + + +class FloorsType(str, Enum): + # WARNING: the key is used in the database. Use the same key and value. + Autre = "Autre" + Adoma = "Adoma" + Exte = "Exte" + T1 = "T1" + T2 = "T2" + T3 = "T3" + T4 = "T4" + T56 = "T56" + U1 = "U1" + U2 = "U2" + U3 = "U3" + U4 = "U4" + U56 = "U56" + V1 = "V1" + V2 = "V2" + V3 = "V3" + V45 = "V45" + V6 = "V6" + X1 = "X1" + X2 = "X2" + X3 = "X3" + X4 = "X4" + X5 = "X5" + X6 = "X6" + + +def upgrade() -> None: + op.alter_column( + "core_user", + "floor", + type_=sa.String(), + ) + sa.Enum(FloorsType, name="floorstype", create_type=False).drop(op.get_bind()) + + +def downgrade() -> None: + sa.Enum( + FloorsType, + name="floorstype", + create_type=True, + ).create(op.get_bind(), checkfirst=True) + op.alter_column( + "core_user", + "floor", + existing_type=sa.String(), + type_=sa.Enum(FloorsType, name="floorstype"), + postgresql_using="floor::text::floorstype", + ) + + +def pre_test_upgrade( + alembic_runner: "MigrationContext", + alembic_connection: sa.Connection, +) -> None: + pass + + +def test_upgrade( + alembic_runner: "MigrationContext", + alembic_connection: sa.Connection, +) -> None: + pass diff --git a/pyproject.toml b/pyproject.toml index 8ee04b34ba..c962f972d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,7 +14,7 @@ license-files = [ "LICENSE", "assets/privacy.txt", "assets/terms-and-conditions.txt", - "assets/myeclpay-terms-of-service.txt", + "assets/mypayment-terms-of-service.txt", ] [tool.titan] diff --git a/requirements.txt b/requirements.txt index e6b1629564..f09c236b9d 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ authlib==1.6.5 bcrypt==4.1.3 # password hashing boto3==1.38.23 broadcaster==0.3.1 # Working with websockets with multiple workers. -calypsso==2.2.1 +calypsso==2.7.0 Faker==37.1.0 fastapi[standard]==0.122.0 firebase-admin==7.1.0 # Firebase is used for push notification @@ -19,7 +19,8 @@ jellyfish==1.2.1 # String Matching Jinja2==3.1.6 # template engine for html files phonenumbers==8.13.43 # Used for phone number validation psutil==7.0.0 # psutil is used to determine the number of Hyperion workers -psycopg[binary]==3.2.13 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) +psycopg[binary]==3.2.13 # PostgreSQL adapter for *synchronous* operations at startup (database initializations & migrations) +pydantic-extra-types==2.10.5 pydantic-settings==2.3.4 pydantic==2.12.5 pyjwt[crypto]==2.10.1 # generate and verify the JWT tokens, imported as `jwt` diff --git a/tests/commons.py b/tests/commons.py index 93cc64896c..3a748e1420 100644 --- a/tests/commons.py +++ b/tests/commons.py @@ -25,7 +25,6 @@ from app.core.utils import security from app.core.utils.config import Settings from app.types import core_data -from app.types.floors_type import FloorsType from app.types.scheduler import OfflineScheduler from app.types.sqlalchemy import Base, SessionLocalType from app.utils.communication.notifications import NotificationManager @@ -239,7 +238,7 @@ async def create_user_with_groups( password: str | None = None, name: str | None = None, firstname: str | None = None, - floor: FloorsType | None = None, + floor: str | None = None, nickname: str | None = None, ) -> models_users.CoreUser: """ diff --git a/tests/config.test.yaml b/tests/config.test.yaml index 183315b857..ac1281abe5 100644 --- a/tests/config.test.yaml +++ b/tests/config.test.yaml @@ -128,13 +128,50 @@ SMTP_PASSWORD: "" SMTP_EMAIL: "" ########################## -# Firebase Configuration # +# Firebase configuration # ########################## # To enable Firebase push notification capabilities, a JSON key file named `firebase.json` should be placed at Hyperion root. # This file can be created and downloaded from [Google cloud, IAM and administration, Service account](https://console.cloud.google.com/iam-admin/serviceaccounts) page. USE_FIREBASE: False +######################## +# School configuration # +######################## + +school: + school_name: "École Centrale Lyon" + application_name: Tests MyECL + payment_name: Tests MyECLPay + application_domain_name: myecl.fr + entity_name: ÉCLAIR + entity_site_url: "https://myecl.fr/" + entity_email: "eclair@myecl.fr" + end_of_support: "2030-01-01" + email_placeholder: prenom.nom@etu.ec-lyon.fr + main_activation_form: + fields: + - birthdate + - promotion + - phone + - floor + - nickname + floor_choices: + - V3 + - V45 + - T21 + - X3 + - Adoma + - "Exté" + - X2 + promotion_offset: 0 + + primary_color: "#F97315" + + student_email_regex: '^[\w\-.]*@etu(-enise)?\.ec-lyon\.fr$' + staff_email_regex: '^[\w\-.]*@(enise\.)?ec-lyon\.fr$' + former_student_email_regex: '^[\w\-.]*@centraliens-lyon\.net$' + ########################### # HelloAsso configuration # ########################### @@ -144,6 +181,7 @@ USE_FIREBASE: False # HELLOASSO_API_BASE should have the format: `api.helloasso-sandbox.com` # HelloAsso only allow 20 simultaneous active access token. Note that each Hyperion worker will need its own access token. +MYPAYMENT_MAXIMUM_WALLET_BALANCE: 5000 HELLOASSO_CONFIGURATIONS: {} # [["name", "helloasso_client_id", "helloasso_client_secret", "helloasso_slug", "redirection_uri"]] # MYECLPAY: # helloasso_client_id: ... @@ -153,7 +191,7 @@ HELLOASSO_CONFIGURATIONS: {} # [["name", "helloasso_client_id", "helloasso_clien HELLOASSO_API_BASE: api.helloasso-sandbox.com # Maximum wallet balance for MyECLPay in cents, we will prevent user from adding more money to their wallet if it will make their balance exceed this value -MYECLPAY_MAXIMUM_WALLET_BALANCE: 8000 +MYPAYMENT_MAXIMUM_WALLET_BALANCE: 5000 # Trusted urls is a list of redirect payment url that can be trusted by Hyperion. # These urls will be used to validate the redirect url provided by the front diff --git a/tests/core/test_core.py b/tests/core/test_core.py index 1f8bf28304..cc4bd14a04 100644 --- a/tests/core/test_core.py +++ b/tests/core/test_core.py @@ -24,9 +24,9 @@ def test_get_terms_and_conditions(client: TestClient) -> None: assert response.status_code == 200 -def test_get_myeclpay_tos(client: TestClient) -> None: +def test_get_mypayment_tos(client: TestClient) -> None: response = client.get( - "/myeclpay-terms-of-service", + "/mypayment-terms-of-service", ) assert response.status_code == 200 @@ -52,19 +52,6 @@ def test_get_wellknown_security_txt(client: TestClient) -> None: assert response.status_code == 200 -def test_get_stylesheet(client: TestClient) -> None: - response = client.get( - "/style/connexion.css", - ) - assert response.status_code == 200 - - # This request should return a 404 as the stylesheet does not exist - response = client.get( - "/style/dontexist.css", - ) - assert response.status_code == 404 - - def test_get_favicon(client: TestClient) -> None: response = client.get( "/favicon.ico", diff --git a/tests/core/test_myeclpay.py b/tests/core/test_mypayment.py similarity index 87% rename from tests/core/test_myeclpay.py rename to tests/core/test_mypayment.py index c9205a05fa..9829d1df91 100644 --- a/tests/core/test_myeclpay.py +++ b/tests/core/test_mypayment.py @@ -14,19 +14,19 @@ from app.core.groups import models_groups from app.core.groups.groups_type import GroupType from app.core.memberships import models_memberships -from app.core.myeclpay import cruds_myeclpay, models_myeclpay -from app.core.myeclpay.coredata_myeclpay import ( - MyECLPayBankAccountHolder, +from app.core.mypayment import cruds_mypayment, models_mypayment +from app.core.mypayment.coredata_mypayment import ( + MyPaymentBankAccountHolder, ) -from app.core.myeclpay.schemas_myeclpay import QRCodeContentData -from app.core.myeclpay.types_myeclpay import ( +from app.core.mypayment.schemas_mypayment import QRCodeContentData +from app.core.mypayment.types_mypayment import ( TransactionStatus, TransactionType, TransferType, WalletDeviceStatus, WalletType, ) -from app.core.myeclpay.utils_myeclpay import LATEST_TOS +from app.core.mypayment.utils_mypayment import LATEST_TOS from app.core.users import models_users from tests.commons import ( add_coredata_to_db, @@ -48,45 +48,45 @@ ecl_user: models_users.CoreUser ecl_user_access_token: str -ecl_user_wallet: models_myeclpay.Wallet +ecl_user_wallet: models_mypayment.Wallet ecl_user_wallet_device_private_key: Ed25519PrivateKey ecl_user_wallet_device_public_key: Ed25519PublicKey -ecl_user_wallet_device: models_myeclpay.WalletDevice -ecl_user_wallet_device_inactive: models_myeclpay.WalletDevice -ecl_user_payment: models_myeclpay.UserPayment -ecl_user_transfer: models_myeclpay.Transfer +ecl_user_wallet_device: models_mypayment.WalletDevice +ecl_user_wallet_device_inactive: models_mypayment.WalletDevice +ecl_user_payment: models_mypayment.UserPayment +ecl_user_transfer: models_mypayment.Transfer ecl_user2: models_users.CoreUser ecl_user2_access_token: str -ecl_user2_wallet: models_myeclpay.Wallet -ecl_user2_wallet_device: models_myeclpay.WalletDevice -ecl_user2_payment: models_myeclpay.UserPayment +ecl_user2_wallet: models_mypayment.Wallet +ecl_user2_wallet_device: models_mypayment.WalletDevice +ecl_user2_payment: models_mypayment.UserPayment association_membership: models_memberships.CoreAssociationMembership association_membership_user: models_memberships.CoreAssociationUserMembership -structure: models_myeclpay.Structure -structure2: models_myeclpay.Structure -store_wallet: models_myeclpay.Wallet -store: models_myeclpay.Store -store2: models_myeclpay.Store -store3: models_myeclpay.Store +structure: models_mypayment.Structure +structure2: models_mypayment.Structure +store_wallet: models_mypayment.Wallet +store: models_mypayment.Store +store2: models_mypayment.Store +store3: models_mypayment.Store store_wallet_device_private_key: Ed25519PrivateKey -store_wallet_device: models_myeclpay.WalletDevice +store_wallet_device: models_mypayment.WalletDevice -transaction_from_ecl_user_to_store: models_myeclpay.Transaction -transaction_from_ecl_user_to_ecl_user2: models_myeclpay.Transaction -transaction_from_store_to_ecl_user: models_myeclpay.Transaction -transaction_from_ecl_user2_to_ecl_user: models_myeclpay.Transaction +transaction_from_ecl_user_to_store: models_mypayment.Transaction +transaction_from_ecl_user_to_ecl_user2: models_mypayment.Transaction +transaction_from_store_to_ecl_user: models_mypayment.Transaction +transaction_from_ecl_user2_to_ecl_user: models_mypayment.Transaction -used_qr_code: models_myeclpay.UsedQRCode +used_qr_code: models_mypayment.UsedQRCode -invoice1: models_myeclpay.Invoice -invoice2: models_myeclpay.Invoice -invoice3: models_myeclpay.Invoice -invoice1_detail: models_myeclpay.InvoiceDetail -invoice2_detail: models_myeclpay.InvoiceDetail -invoice3_detail: models_myeclpay.InvoiceDetail +invoice1: models_mypayment.Invoice +invoice2: models_mypayment.Invoice +invoice3: models_mypayment.Invoice +invoice1_detail: models_mypayment.InvoiceDetail +invoice2_detail: models_mypayment.InvoiceDetail +invoice3_detail: models_mypayment.InvoiceDetail store_seller_can_bank_user: models_users.CoreUser store_seller_no_permission_user_access_token: str @@ -132,7 +132,7 @@ async def init_objects() -> None: structure_manager_user = await create_user_with_groups(groups=[]) structure_manager_user_token = create_api_access_token(structure_manager_user) - structure = models_myeclpay.Structure( + structure = models_mypayment.Structure( id=uuid4(), name="Test Structure", creation=datetime.now(UTC), @@ -150,7 +150,7 @@ async def init_objects() -> None: await add_object_to_db(structure) await add_coredata_to_db( - MyECLPayBankAccountHolder( + MyPaymentBankAccountHolder( holder_structure_id=structure.id, ), ) @@ -158,7 +158,7 @@ async def init_objects() -> None: structure2_manager_user = await create_user_with_groups(groups=[]) structure2_manager_user_token = create_api_access_token(structure2_manager_user) - structure2 = models_myeclpay.Structure( + structure2 = models_mypayment.Structure( id=uuid4(), name="Test Structure 2", creation=datetime.now(UTC), @@ -192,7 +192,7 @@ async def init_objects() -> None: await add_object_to_db(association_membership_user) global ecl_user_wallet - ecl_user_wallet = models_myeclpay.Wallet( + ecl_user_wallet = models_mypayment.Wallet( id=uuid4(), type=WalletType.USER, balance=1000, # 10€ @@ -200,7 +200,7 @@ async def init_objects() -> None: await add_object_to_db(ecl_user_wallet) global ecl_user_payment - ecl_user_payment = models_myeclpay.UserPayment( + ecl_user_payment = models_mypayment.UserPayment( user_id=ecl_user.id, wallet_id=ecl_user_wallet.id, accepted_tos_signature=datetime.now(UTC), @@ -215,7 +215,7 @@ async def init_objects() -> None: ecl_user_wallet_device_inactive ecl_user_wallet_device_private_key = Ed25519PrivateKey.generate() ecl_user_wallet_device_public_key = ecl_user_wallet_device_private_key.public_key() - ecl_user_wallet_device = models_myeclpay.WalletDevice( + ecl_user_wallet_device = models_mypayment.WalletDevice( id=uuid4(), name="Test device", wallet_id=ecl_user_wallet.id, @@ -228,7 +228,7 @@ async def init_objects() -> None: activation_token="activation_token_ecl_user_wallet_device", ) await add_object_to_db(ecl_user_wallet_device) - ecl_user_wallet_device_inactive = models_myeclpay.WalletDevice( + ecl_user_wallet_device_inactive = models_mypayment.WalletDevice( id=uuid4(), name="Test device inactive", wallet_id=ecl_user_wallet.id, @@ -250,7 +250,7 @@ async def init_objects() -> None: ecl_user2_access_token = create_api_access_token(ecl_user2) global ecl_user2_wallet - ecl_user2_wallet = models_myeclpay.Wallet( + ecl_user2_wallet = models_mypayment.Wallet( id=uuid4(), type=WalletType.USER, balance=2000, # 20€ @@ -258,7 +258,7 @@ async def init_objects() -> None: await add_object_to_db(ecl_user2_wallet) global ecl_user2_payment - ecl_user2_payment = models_myeclpay.UserPayment( + ecl_user2_payment = models_mypayment.UserPayment( user_id=ecl_user2.id, wallet_id=ecl_user2_wallet.id, accepted_tos_signature=datetime.now(UTC), @@ -267,7 +267,7 @@ async def init_objects() -> None: await add_object_to_db(ecl_user2_payment) global ecl_user2_wallet_device - ecl_user2_wallet_device = models_myeclpay.WalletDevice( + ecl_user2_wallet_device = models_mypayment.WalletDevice( id=uuid4(), name="Test device", wallet_id=ecl_user2_wallet.id, @@ -280,19 +280,19 @@ async def init_objects() -> None: # store global store_wallet - store_wallet = models_myeclpay.Wallet( + store_wallet = models_mypayment.Wallet( id=uuid4(), type=WalletType.STORE, balance=5000, # 50€ ) await add_object_to_db(store_wallet) - store2_wallet = models_myeclpay.Wallet( + store2_wallet = models_mypayment.Wallet( id=uuid4(), type=WalletType.STORE, balance=5000, # 50€ ) await add_object_to_db(store2_wallet) - store3_wallet = models_myeclpay.Wallet( + store3_wallet = models_mypayment.Wallet( id=uuid4(), type=WalletType.STORE, balance=5000, # 50€ @@ -300,7 +300,7 @@ async def init_objects() -> None: await add_object_to_db(store3_wallet) global store, store2 - store = models_myeclpay.Store( + store = models_mypayment.Store( id=uuid4(), wallet_id=store_wallet.id, name="Test Store", @@ -308,7 +308,7 @@ async def init_objects() -> None: creation=datetime.now(UTC), ) await add_object_to_db(store) - store2 = models_myeclpay.Store( + store2 = models_mypayment.Store( id=uuid4(), wallet_id=store2_wallet.id, name="Test Store 2", @@ -316,7 +316,7 @@ async def init_objects() -> None: creation=datetime.now(UTC), ) await add_object_to_db(store2) - store3 = models_myeclpay.Store( + store3 = models_mypayment.Store( id=uuid4(), wallet_id=store3_wallet.id, name="Test Store 3", @@ -325,7 +325,7 @@ async def init_objects() -> None: ) await add_object_to_db(store3) - manager_as_admin = models_myeclpay.Seller( + manager_as_admin = models_mypayment.Seller( user_id=structure_manager_user.id, store_id=store.id, can_bank=True, @@ -338,7 +338,7 @@ async def init_objects() -> None: # NOTE: in practice we won't allow a store to emit transactions and to have a WalletDevice global store_wallet_device, store_wallet_device_private_key store_wallet_device_private_key = Ed25519PrivateKey.generate() - store_wallet_device = models_myeclpay.WalletDevice( + store_wallet_device = models_mypayment.WalletDevice( id=uuid4(), name="Store test device", wallet_id=store_wallet.id, @@ -354,7 +354,7 @@ async def init_objects() -> None: # Create test transactions global transaction_from_ecl_user_to_store - transaction_from_ecl_user_to_store = models_myeclpay.Transaction( + transaction_from_ecl_user_to_store = models_mypayment.Transaction( id=uuid4(), debited_wallet_id=ecl_user_wallet.id, debited_wallet_device_id=ecl_user_wallet_device.id, @@ -372,7 +372,7 @@ async def init_objects() -> None: await add_object_to_db(transaction_from_ecl_user_to_store) global transaction_from_ecl_user_to_ecl_user2 - transaction_from_ecl_user_to_ecl_user2 = models_myeclpay.Transaction( + transaction_from_ecl_user_to_ecl_user2 = models_mypayment.Transaction( id=uuid4(), debited_wallet_id=ecl_user_wallet.id, debited_wallet_device_id=ecl_user_wallet_device.id, @@ -388,7 +388,7 @@ async def init_objects() -> None: await add_object_to_db(transaction_from_ecl_user_to_ecl_user2) global transaction_from_store_to_ecl_user - transaction_from_store_to_ecl_user = models_myeclpay.Transaction( + transaction_from_store_to_ecl_user = models_mypayment.Transaction( id=uuid4(), debited_wallet_id=store_wallet.id, debited_wallet_device_id=store_wallet_device.id, @@ -404,7 +404,7 @@ async def init_objects() -> None: await add_object_to_db(transaction_from_store_to_ecl_user) global transaction_from_ecl_user2_to_ecl_user - transaction_from_ecl_user2_to_ecl_user = models_myeclpay.Transaction( + transaction_from_ecl_user2_to_ecl_user = models_mypayment.Transaction( id=uuid4(), debited_wallet_id=ecl_user2_wallet.id, debited_wallet_device_id=ecl_user2_wallet_device.id, @@ -421,7 +421,7 @@ async def init_objects() -> None: # Add a transfer global ecl_user_transfer - ecl_user_transfer = models_myeclpay.Transfer( + ecl_user_transfer = models_mypayment.Transfer( id=uuid4(), type=TransferType.HELLO_ASSO, transfer_identifier="transfer_identifier", @@ -435,7 +435,7 @@ async def init_objects() -> None: # QR Code global used_qr_code - used_qr_code = models_myeclpay.UsedQRCode( + used_qr_code = models_mypayment.UsedQRCode( qr_code_id=uuid4(), qr_code_iat=datetime.now(UTC) - timedelta(days=1), qr_code_key=ecl_user2_wallet_device.id, @@ -453,7 +453,7 @@ async def init_objects() -> None: store_seller_no_permission_user_access_token = create_api_access_token( store_seller_no_permission_user, ) - store_seller_no_permission = models_myeclpay.Seller( + store_seller_no_permission = models_mypayment.Seller( user_id=store_seller_no_permission_user.id, store_id=store.id, can_bank=False, @@ -470,7 +470,7 @@ async def init_objects() -> None: store_seller_can_bank_user_access_token = create_api_access_token( store_seller_can_bank_user, ) - store_seller_can_bank = models_myeclpay.Seller( + store_seller_can_bank = models_mypayment.Seller( user_id=store_seller_can_bank_user.id, store_id=store.id, can_bank=True, @@ -487,7 +487,7 @@ async def init_objects() -> None: store_seller_can_cancel_user_access_token = create_api_access_token( store_seller_can_cancel_user, ) - store_seller_can_cancel = models_myeclpay.Seller( + store_seller_can_cancel = models_mypayment.Seller( user_id=store_seller_can_cancel_user.id, store_id=store.id, can_bank=False, @@ -504,7 +504,7 @@ async def init_objects() -> None: store_seller_can_manage_sellers_user_access_token = create_api_access_token( store_seller_can_manage_sellers_user, ) - store_seller_can_manage_sellers = models_myeclpay.Seller( + store_seller_can_manage_sellers = models_mypayment.Seller( user_id=store_seller_can_manage_sellers_user.id, store_id=store.id, can_bank=False, @@ -518,7 +518,7 @@ async def init_objects() -> None: store_seller_can_see_history_user = await create_user_with_groups( groups=[], ) - store_seller_can_see_history_seller = models_myeclpay.Seller( + store_seller_can_see_history_seller = models_mypayment.Seller( user_id=store_seller_can_see_history_user.id, store_id=store.id, can_bank=False, @@ -544,7 +544,7 @@ async def init_objects() -> None: invoice2_detail, \ invoice3, \ invoice3_detail - invoice1 = models_myeclpay.Invoice( + invoice1 = models_mypayment.Invoice( id=uuid4(), reference=f"MYPAY{datetime.now(UTC).year}{structure.short_id}0001", structure_id=structure.id, @@ -556,13 +556,13 @@ async def init_objects() -> None: end_date=datetime.now(UTC) - timedelta(days=20), ) await add_object_to_db(invoice1) - invoice1_detail = models_myeclpay.InvoiceDetail( + invoice1_detail = models_mypayment.InvoiceDetail( invoice_id=invoice1.id, store_id=store.id, total=1000, ) await add_object_to_db(invoice1_detail) - invoice2 = models_myeclpay.Invoice( + invoice2 = models_mypayment.Invoice( id=uuid4(), reference=f"MYPAY{datetime.now(UTC).year}{structure.short_id}0002", structure_id=structure.id, @@ -574,13 +574,13 @@ async def init_objects() -> None: end_date=datetime.now(UTC) - timedelta(days=10), ) await add_object_to_db(invoice2) - invoice2_detail = models_myeclpay.InvoiceDetail( + invoice2_detail = models_mypayment.InvoiceDetail( invoice_id=invoice2.id, store_id=store.id, total=1000, ) await add_object_to_db(invoice2_detail) - invoice3 = models_myeclpay.Invoice( + invoice3 = models_mypayment.Invoice( id=uuid4(), reference=f"MYPAY{datetime.now(UTC).year}{structure2.short_id}0001", structure_id=structure2.id, @@ -592,7 +592,7 @@ async def init_objects() -> None: end_date=datetime.now(UTC) - timedelta(days=20), ) await add_object_to_db(invoice3) - invoice3_detail = models_myeclpay.InvoiceDetail( + invoice3_detail = models_mypayment.InvoiceDetail( invoice_id=invoice3.id, store_id=store2.id, total=1000, @@ -602,7 +602,7 @@ async def init_objects() -> None: async def test_get_structures(client: TestClient): response = client.get( - "/myeclpay/structures", + "/mypayment/structures", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 200 @@ -611,7 +611,7 @@ async def test_get_structures(client: TestClient): async def test_create_structure(client: TestClient): response = client.post( - "/myeclpay/structures", + "/mypayment/structures", headers={"Authorization": f"Bearer {admin_user_token}"}, json={ "name": "Test Structure USEECL", @@ -633,7 +633,7 @@ async def test_create_structure(client: TestClient): async def test_patch_structure_as_lambda(client: TestClient): response = client.patch( - f"/myeclpay/structures/{structure.id}", + f"/mypayment/structures/{structure.id}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "name": "Test Structure Updated", @@ -644,7 +644,7 @@ async def test_patch_structure_as_lambda(client: TestClient): async def test_patch_structure_as_admin(client: TestClient): response = client.patch( - f"/myeclpay/structures/{structure.id}", + f"/mypayment/structures/{structure.id}", headers={"Authorization": f"Bearer {admin_user_token}"}, json={ "name": "Test Structure Updated", @@ -655,7 +655,7 @@ async def test_patch_structure_as_admin(client: TestClient): async def test_patch_non_existing_structure(client: TestClient): response = client.patch( - f"/myeclpay/structures/{uuid4()}", + f"/mypayment/structures/{uuid4()}", headers={"Authorization": f"Bearer {admin_user_token}"}, json={ "name": "Test Structure Updated", @@ -667,7 +667,7 @@ async def test_patch_non_existing_structure(client: TestClient): async def test_delete_structure_as_lambda(client: TestClient): response = client.delete( - f"/myeclpay/structures/{structure.id}", + f"/mypayment/structures/{structure.id}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 403 @@ -675,7 +675,7 @@ async def test_delete_structure_as_lambda(client: TestClient): async def test_delete_structure_as_admin_with_stores(client: TestClient): response = client.delete( - f"/myeclpay/structures/{structure.id}", + f"/mypayment/structures/{structure.id}", headers={"Authorization": f"Bearer {admin_user_token}"}, ) assert response.status_code == 400 @@ -683,7 +683,7 @@ async def test_delete_structure_as_admin_with_stores(client: TestClient): async def test_delete_structure_as_admin(client: TestClient): - new_structure = models_myeclpay.Structure( + new_structure = models_mypayment.Structure( id=uuid4(), short_id="TSA", name="Test Structure add", @@ -699,7 +699,7 @@ async def test_delete_structure_as_admin(client: TestClient): ) await add_object_to_db(new_structure) response = client.delete( - f"/myeclpay/structures/{new_structure.id}", + f"/mypayment/structures/{new_structure.id}", headers={"Authorization": f"Bearer {admin_user_token}"}, ) assert response.status_code == 204 @@ -707,7 +707,7 @@ async def test_delete_structure_as_admin(client: TestClient): async def test_transfer_non_existing_structure_manager(client: TestClient): response = client.post( - f"/myeclpay/structures/{uuid4()}/init-manager-transfer", + f"/mypayment/structures/{uuid4()}/init-manager-transfer", headers={"Authorization": f"Bearer {admin_user_token}"}, json={ "new_manager_user_id": ecl_user2.id, @@ -719,7 +719,7 @@ async def test_transfer_non_existing_structure_manager(client: TestClient): async def test_transfer_structure_manager_as_admin(client: TestClient): response = client.post( - f"/myeclpay/structures/{structure.id}/init-manager-transfer", + f"/mypayment/structures/{structure.id}/init-manager-transfer", headers={"Authorization": f"Bearer {admin_user_token}"}, json={ "new_manager_user_id": ecl_user2.id, @@ -730,7 +730,7 @@ async def test_transfer_structure_manager_as_admin(client: TestClient): async def test_transfer_structure_manager_with_wrong_token(client: TestClient): - tranfert = models_myeclpay.StructureManagerTransfert( + tranfert = models_mypayment.StructureManagerTransfert( structure_id=structure.id, user_id=ecl_user2.id, confirmation_token="RANDOM_TOKEN", @@ -739,14 +739,14 @@ async def test_transfer_structure_manager_with_wrong_token(client: TestClient): await add_object_to_db(tranfert) response = client.get( - "/myeclpay/structures/confirm-manager-transfer", + "/mypayment/structures/confirm-manager-transfer", params={"token": "WRONG_TOKEN"}, ) assert response.status_code == 404 assert response.json()["detail"] == "Request does not exist" response = client.get( - "/myeclpay/structures/confirm-manager-transfer", + "/mypayment/structures/confirm-manager-transfer", params={"token": "RANDOM_TOKEN"}, ) assert response.status_code == 400 @@ -757,7 +757,7 @@ async def test_transfer_structure_manager_as_manager_but_invalid_new_manager_id( client: TestClient, ): response = client.post( - f"/myeclpay/structures/{structure.id}/init-manager-transfer", + f"/mypayment/structures/{structure.id}/init-manager-transfer", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, json={ "new_manager_user_id": str(uuid4()), @@ -771,7 +771,7 @@ async def test_transfer_structure_manager_as_manager( client: TestClient, mocker: MockerFixture, ): - new_structure = models_myeclpay.Structure( + new_structure = models_mypayment.Structure( id=uuid4(), name="Test Structure 3", manager_user_id=structure_manager_user.id, @@ -786,13 +786,13 @@ async def test_transfer_structure_manager_as_manager( bic="AZERTYUIOP", ) await add_object_to_db(new_structure) - new_wallet = models_myeclpay.Wallet( + new_wallet = models_mypayment.Wallet( id=uuid4(), type=WalletType.STORE, balance=5000, ) await add_object_to_db(new_wallet) - new_store = models_myeclpay.Store( + new_store = models_mypayment.Store( id=uuid4(), creation=datetime.now(UTC), wallet_id=new_wallet.id, @@ -800,13 +800,13 @@ async def test_transfer_structure_manager_as_manager( structure_id=new_structure.id, ) await add_object_to_db(new_store) - new_wallet2 = models_myeclpay.Wallet( + new_wallet2 = models_mypayment.Wallet( id=uuid4(), type=WalletType.STORE, balance=5000, ) await add_object_to_db(new_wallet2) - new_store2_where_new_manager_already_seller = models_myeclpay.Store( + new_store2_where_new_manager_already_seller = models_mypayment.Store( id=uuid4(), creation=datetime.now(UTC), wallet_id=new_wallet2.id, @@ -814,7 +814,7 @@ async def test_transfer_structure_manager_as_manager( structure_id=new_structure.id, ) await add_object_to_db(new_store2_where_new_manager_already_seller) - seller = models_myeclpay.Seller( + seller = models_mypayment.Seller( user_id=ecl_user2.id, store_id=new_store2_where_new_manager_already_seller.id, can_bank=True, @@ -830,7 +830,7 @@ async def test_transfer_structure_manager_as_manager( return_value=UNIQUE_TOKEN, ) response = client.post( - f"/myeclpay/structures/{new_structure.id}/init-manager-transfer", + f"/mypayment/structures/{new_structure.id}/init-manager-transfer", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, json={ "new_manager_user_id": ecl_user2.id, @@ -839,13 +839,13 @@ async def test_transfer_structure_manager_as_manager( assert response.status_code == 201 response = client.get( - "/myeclpay/structures/confirm-manager-transfer", + "/mypayment/structures/confirm-manager-transfer", params={"token": UNIQUE_TOKEN}, ) assert response.status_code == 200 result = client.get( - "/myeclpay/users/me/stores", + "/mypayment/users/me/stores", headers={"Authorization": f"Bearer {ecl_user2_access_token}"}, ) stores = result.json() @@ -866,7 +866,7 @@ async def test_transfer_structure_manager_as_manager( async def test_create_store_for_non_existing_structure(client: TestClient): response = client.post( - f"/myeclpay/structures/{uuid4()}/stores", + f"/mypayment/structures/{uuid4()}/stores", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, json={ "name": "test_create_store Test Store", @@ -878,7 +878,7 @@ async def test_create_store_for_non_existing_structure(client: TestClient): async def test_create_store(client: TestClient): response = client.post( - f"/myeclpay/structures/{structure.id}/stores", + f"/mypayment/structures/{structure.id}/stores", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, json={ "name": "test_create_store Test Store", @@ -888,7 +888,7 @@ async def test_create_store(client: TestClient): assert response.json()["id"] is not None stores = client.get( - "/myeclpay/users/me/stores", + "/mypayment/users/me/stores", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) stores_ids = [store["id"] for store in stores.json()] @@ -897,7 +897,7 @@ async def test_create_store(client: TestClient): async def test_create_store_when_user_not_manager_of_structure(client: TestClient): response = client.post( - f"/myeclpay/structures/{structure.id}/stores", + f"/mypayment/structures/{structure.id}/stores", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "name": "test_create_store Test Store", @@ -909,7 +909,7 @@ async def test_create_store_when_user_not_manager_of_structure(client: TestClien async def test_create_store_with_name_already_exist(client: TestClient): response = client.post( - f"/myeclpay/structures/{structure.id}/stores", + f"/mypayment/structures/{structure.id}/stores", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, json={ "name": "Test Store", @@ -924,7 +924,7 @@ async def test_create_store_with_name_already_exist(client: TestClient): async def test_get_store_history_for_non_existing_store(client: TestClient): response = client.get( - f"/myeclpay/stores/{uuid4()}/history", + f"/mypayment/stores/{uuid4()}/history", headers={"Authorization": f"Bearer {ecl_user2_access_token}"}, ) @@ -934,7 +934,7 @@ async def test_get_store_history_for_non_existing_store(client: TestClient): async def test_get_store_history_when_not_seller_can_see_history(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/history", + f"/mypayment/stores/{store.id}/history", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, ) @@ -946,7 +946,7 @@ async def test_get_store_history_when_not_seller_can_see_history(client: TestCli async def test_get_store_history(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/history", + f"/mypayment/stores/{store.id}/history", headers={ "Authorization": f"Bearer {store_seller_can_see_history_user_access_token}", }, @@ -965,7 +965,7 @@ async def test_get_store_history(client: TestClient): async def test_get_store_history_with_date(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/history", + f"/mypayment/stores/{store.id}/history", params={ "start_date": "2025-05-18T00:00:00Z", "end_date": "2025-05-19T00:00:00Z", @@ -986,7 +986,7 @@ async def test_get_store_history_with_date(client: TestClient): async def test_export_store_history_for_non_existing_store(client: TestClient): response = client.get( - f"/myeclpay/stores/{uuid4()}/history/data-export", + f"/mypayment/stores/{uuid4()}/history/data-export", headers={"Authorization": f"Bearer {ecl_user2_access_token}"}, ) @@ -996,7 +996,7 @@ async def test_export_store_history_for_non_existing_store(client: TestClient): async def test_export_store_history_when_not_seller_can_see_history(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/history/data-export", + f"/mypayment/stores/{store.id}/history/data-export", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, ) @@ -1008,7 +1008,7 @@ async def test_export_store_history_when_not_seller_can_see_history(client: Test async def test_export_store_history(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/history/data-export", + f"/mypayment/stores/{store.id}/history/data-export", headers={ "Authorization": f"Bearer {store_seller_can_see_history_user_access_token}", }, @@ -1048,7 +1048,7 @@ async def test_export_store_history(client: TestClient): async def test_export_store_history_with_date(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/history/data-export", + f"/mypayment/stores/{store.id}/history/data-export", params={ "start_date": "2025-05-18T00:00:00Z", "end_date": "2025-05-19T00:00:00Z", @@ -1075,7 +1075,7 @@ async def test_export_store_history_with_date(client: TestClient): async def test_export_store_history_with_refund(client: TestClient): # Create a transaction and its refund - transaction_to_refund = models_myeclpay.Transaction( + transaction_to_refund = models_mypayment.Transaction( id=uuid4(), debited_wallet_id=ecl_user_wallet.id, debited_wallet_device_id=ecl_user_wallet_device.id, @@ -1090,7 +1090,7 @@ async def test_export_store_history_with_refund(client: TestClient): ) await add_object_to_db(transaction_to_refund) - refund_test = models_myeclpay.Refund( + refund_test = models_mypayment.Refund( id=uuid4(), transaction_id=transaction_to_refund.id, debited_wallet_id=store_wallet.id, @@ -1102,7 +1102,7 @@ async def test_export_store_history_with_refund(client: TestClient): await add_object_to_db(refund_test) response = client.get( - f"/myeclpay/stores/{store.id}/history/data-export", + f"/mypayment/stores/{store.id}/history/data-export", headers={ "Authorization": f"Bearer {store_seller_can_see_history_user_access_token}", }, @@ -1119,7 +1119,7 @@ async def test_export_store_history_with_refund(client: TestClient): async def test_export_store_history_encoding(client: TestClient): # Test that special characters (accents, etc.) are properly encoded response = client.get( - f"/myeclpay/stores/{store.id}/history/data-export", + f"/mypayment/stores/{store.id}/history/data-export", headers={ "Authorization": f"Bearer {store_seller_can_see_history_user_access_token}", }, @@ -1138,7 +1138,7 @@ async def test_export_store_history_encoding(client: TestClient): async def test_get_stores_as_lambda(client: TestClient): response = client.get( - "/myeclpay/users/me/stores", + "/mypayment/users/me/stores", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 200 @@ -1147,7 +1147,7 @@ async def test_get_stores_as_lambda(client: TestClient): async def test_get_stores_as_seller(client: TestClient): response = client.get( - "/myeclpay/users/me/stores", + "/mypayment/users/me/stores", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, ) assert response.status_code == 200 @@ -1156,7 +1156,7 @@ async def test_get_stores_as_seller(client: TestClient): async def test_get_stores_as_manager(client: TestClient): response = client.get( - "/myeclpay/users/me/stores", + "/mypayment/users/me/stores", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) assert response.status_code == 200 @@ -1165,7 +1165,7 @@ async def test_get_stores_as_manager(client: TestClient): async def test_update_store_non_existing(client: TestClient): response = client.patch( - f"/myeclpay/stores/{uuid4()}", + f"/mypayment/stores/{uuid4()}", headers={ "Authorization": f"Bearer {store_seller_can_bank_user_access_token}", }, @@ -1179,7 +1179,7 @@ async def test_update_store_non_existing(client: TestClient): async def test_update_store_non_store_admin(client: TestClient): response = client.patch( - f"/myeclpay/stores/{store.id}", + f"/mypayment/stores/{store.id}", headers={ "Authorization": f"Bearer {store_seller_can_bank_user_access_token}", }, @@ -1193,7 +1193,7 @@ async def test_update_store_non_store_admin(client: TestClient): async def test_delete_store_does_not_exist(client: TestClient): response = client.delete( - f"/myeclpay/stores/{uuid4()}", + f"/mypayment/stores/{uuid4()}", headers={ "Authorization": f"Bearer {structure_manager_user_token}", }, @@ -1204,7 +1204,7 @@ async def test_delete_store_does_not_exist(client: TestClient): async def test_delete_store_by_non_manager(client: TestClient): response = client.delete( - f"/myeclpay/stores/{store.id}", + f"/mypayment/stores/{store.id}", headers={ "Authorization": f"Bearer {ecl_user2_access_token}", }, @@ -1215,7 +1215,7 @@ async def test_delete_store_by_non_manager(client: TestClient): async def test_delete_store_with_history(client: TestClient): response = client.delete( - f"/myeclpay/stores/{store.id}", + f"/mypayment/stores/{store.id}", headers={ "Authorization": f"Bearer {structure_manager_user_token}", }, @@ -1229,13 +1229,13 @@ async def test_delete_store_with_history(client: TestClient): async def test_delete_store(client: TestClient): store_id = uuid4() - new_wallet = models_myeclpay.Wallet( + new_wallet = models_mypayment.Wallet( id=store_id, type=WalletType.STORE, balance=5000, ) await add_object_to_db(new_wallet) - new_store = models_myeclpay.Store( + new_store = models_mypayment.Store( id=store_id, creation=datetime.now(UTC), wallet_id=new_wallet.id, @@ -1243,7 +1243,7 @@ async def test_delete_store(client: TestClient): structure_id=structure.id, ) await add_object_to_db(new_store) - sellet = models_myeclpay.Seller( + sellet = models_mypayment.Seller( user_id=structure_manager_user.id, store_id=new_store.id, can_bank=True, @@ -1254,7 +1254,7 @@ async def test_delete_store(client: TestClient): await add_object_to_db(sellet) response = client.delete( - f"/myeclpay/stores/{store_id}", + f"/mypayment/stores/{store_id}", headers={ "Authorization": f"Bearer {structure_manager_user_token}", }, @@ -1263,13 +1263,13 @@ async def test_delete_store(client: TestClient): async def test_update_store(client: TestClient): - new_wallet = models_myeclpay.Wallet( + new_wallet = models_mypayment.Wallet( id=uuid4(), type=WalletType.STORE, balance=5000, ) await add_object_to_db(new_wallet) - new_store = models_myeclpay.Store( + new_store = models_mypayment.Store( id=uuid4(), creation=datetime.now(UTC), wallet_id=new_wallet.id, @@ -1278,7 +1278,7 @@ async def test_update_store(client: TestClient): ) await add_object_to_db(new_store) response = client.patch( - f"/myeclpay/stores/{new_store.id}", + f"/mypayment/stores/{new_store.id}", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, json={ "name": "Test Store Updated", @@ -1289,7 +1289,7 @@ async def test_update_store(client: TestClient): async def test_get_user_stores(client: TestClient): response = client.get( - "/myeclpay/users/me/stores", + "/mypayment/users/me/stores", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, ) assert response.status_code == 200 @@ -1300,7 +1300,7 @@ async def test_get_user_stores(client: TestClient): async def test_add_seller_for_non_existing_store(client: TestClient): response = client.post( - f"/myeclpay/stores/{uuid4()}/sellers", + f"/mypayment/stores/{uuid4()}/sellers", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "user_id": ecl_user2.id, @@ -1316,7 +1316,7 @@ async def test_add_seller_for_non_existing_store(client: TestClient): async def test_add_seller_as_lambda(client: TestClient): response = client.post( - f"/myeclpay/stores/{store.id}/sellers", + f"/mypayment/stores/{store.id}/sellers", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "user_id": ecl_user2.id, @@ -1338,7 +1338,7 @@ async def test_add_seller_as_seller_with_permission(client: TestClient): groups=[], ) response = client.post( - f"/myeclpay/stores/{store.id}/sellers", + f"/mypayment/stores/{store.id}/sellers", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1358,7 +1358,7 @@ async def test_add_seller_as_seller_without_permission(client: TestClient): groups=[], ) response = client.post( - f"/myeclpay/stores/{store.id}/sellers", + f"/mypayment/stores/{store.id}/sellers", headers={ "Authorization": f"Bearer {store_seller_no_permission_user_access_token}", }, @@ -1381,7 +1381,7 @@ async def test_add_already_existing_seller(client: TestClient): user = await create_user_with_groups( groups=[], ) - seller = models_myeclpay.Seller( + seller = models_mypayment.Seller( user_id=user.id, store_id=store.id, can_bank=True, @@ -1392,7 +1392,7 @@ async def test_add_already_existing_seller(client: TestClient): await add_object_to_db(seller) response = client.post( - f"/myeclpay/stores/{store.id}/sellers", + f"/mypayment/stores/{store.id}/sellers", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1410,7 +1410,7 @@ async def test_add_already_existing_seller(client: TestClient): async def test_get_sellers_for_non_existing_store(client: TestClient): response = client.get( - f"/myeclpay/stores/{uuid4()}/sellers", + f"/mypayment/stores/{uuid4()}/sellers", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 404 @@ -1419,7 +1419,7 @@ async def test_get_sellers_for_non_existing_store(client: TestClient): async def test_get_sellers_as_lambda(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/sellers", + f"/mypayment/stores/{store.id}/sellers", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 403 @@ -1431,7 +1431,7 @@ async def test_get_sellers_as_lambda(client: TestClient): async def test_get_sellers_as_seller_with_permission(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/sellers", + f"/mypayment/stores/{store.id}/sellers", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1442,7 +1442,7 @@ async def test_get_sellers_as_seller_with_permission(client: TestClient): async def test_get_sellers_as_seller_without_permission(client: TestClient): response = client.get( - f"/myeclpay/stores/{store.id}/sellers", + f"/mypayment/stores/{store.id}/sellers", headers={ "Authorization": f"Bearer {store_seller_no_permission_user_access_token}", }, @@ -1456,7 +1456,7 @@ async def test_get_sellers_as_seller_without_permission(client: TestClient): async def test_update_seller_of_non_existing_store(client: TestClient): response = client.patch( - f"/myeclpay/stores/{uuid4()}/sellers/{store_seller_can_bank_user.id}", + f"/mypayment/stores/{uuid4()}/sellers/{store_seller_can_bank_user.id}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "can_bank": False, @@ -1471,7 +1471,7 @@ async def test_update_seller_of_non_existing_store(client: TestClient): async def test_update_seller_as_lambda(client: TestClient): response = client.patch( - f"/myeclpay/stores/{store.id}/sellers/{store_seller_can_bank_user.id}", + f"/mypayment/stores/{store.id}/sellers/{store_seller_can_bank_user.id}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "can_bank": False, @@ -1489,7 +1489,7 @@ async def test_update_seller_as_lambda(client: TestClient): async def test_update_seller_as_seller_without_permission(client: TestClient): response = client.patch( - f"/myeclpay/stores/{store.id}/sellers/{store_seller_can_bank_user.id}", + f"/mypayment/stores/{store.id}/sellers/{store_seller_can_bank_user.id}", headers={ "Authorization": f"Bearer {store_seller_no_permission_user_access_token}", }, @@ -1511,7 +1511,7 @@ async def test_update_non_existing_seller(client: TestClient): user = await create_user_with_groups( groups=[], ) - seller = models_myeclpay.Seller( + seller = models_mypayment.Seller( user_id=user.id, store_id=store.id, can_bank=False, @@ -1521,7 +1521,7 @@ async def test_update_non_existing_seller(client: TestClient): ) await add_object_to_db(seller) response = client.patch( - f"/myeclpay/stores/{store.id}/sellers/{uuid4()}", + f"/mypayment/stores/{store.id}/sellers/{uuid4()}", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1538,7 +1538,7 @@ async def test_update_seller_as_seller_with_permission(client: TestClient): user = await create_user_with_groups( groups=[], ) - seller = models_myeclpay.Seller( + seller = models_mypayment.Seller( user_id=user.id, store_id=store.id, can_bank=False, @@ -1548,7 +1548,7 @@ async def test_update_seller_as_seller_with_permission(client: TestClient): ) await add_object_to_db(seller) response = client.patch( - f"/myeclpay/stores/{store.id}/sellers/{user.id}", + f"/mypayment/stores/{store.id}/sellers/{user.id}", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1560,7 +1560,7 @@ async def test_update_seller_as_seller_with_permission(client: TestClient): assert response.status_code == 204 response = client.get( - f"/myeclpay/stores/{store.id}/sellers", + f"/mypayment/stores/{store.id}/sellers", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1578,7 +1578,7 @@ async def test_update_seller_as_seller_with_permission(client: TestClient): async def test_update_manager_seller(client: TestClient): response = client.patch( - f"/myeclpay/stores/{store.id}/sellers/{structure_manager_user.id}", + f"/mypayment/stores/{store.id}/sellers/{structure_manager_user.id}", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1598,7 +1598,7 @@ async def test_update_manager_seller(client: TestClient): async def test_delete_seller_of_non_existing_store(client: TestClient): response = client.delete( - f"/myeclpay/stores/{uuid4()}/sellers/{store_seller_can_bank_user.id}", + f"/mypayment/stores/{uuid4()}/sellers/{store_seller_can_bank_user.id}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 404 @@ -1607,7 +1607,7 @@ async def test_delete_seller_of_non_existing_store(client: TestClient): async def test_delete_seller_as_lambda(client: TestClient): response = client.delete( - f"/myeclpay/stores/{store.id}/sellers/{store_seller_can_bank_user.id}", + f"/mypayment/stores/{store.id}/sellers/{store_seller_can_bank_user.id}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 403 @@ -1619,7 +1619,7 @@ async def test_delete_seller_as_lambda(client: TestClient): async def test_delete_seller_as_seller_without_permission(client: TestClient): response = client.delete( - f"/myeclpay/stores/{store.id}/sellers/{store_seller_can_bank_user.id}", + f"/mypayment/stores/{store.id}/sellers/{store_seller_can_bank_user.id}", headers={ "Authorization": f"Bearer {store_seller_no_permission_user_access_token}", }, @@ -1633,7 +1633,7 @@ async def test_delete_seller_as_seller_without_permission(client: TestClient): async def test_delete_non_existing_seller(client: TestClient): response = client.delete( - f"/myeclpay/stores/{store.id}/sellers/{uuid4()}", + f"/mypayment/stores/{store.id}/sellers/{uuid4()}", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1646,7 +1646,7 @@ async def test_delete_seller_as_seller_with_permission(client: TestClient): user = await create_user_with_groups( groups=[], ) - seller = models_myeclpay.Seller( + seller = models_mypayment.Seller( user_id=user.id, store_id=store.id, can_bank=False, @@ -1656,7 +1656,7 @@ async def test_delete_seller_as_seller_with_permission(client: TestClient): ) await add_object_to_db(seller) response = client.delete( - f"/myeclpay/stores/{store.id}/sellers/{user.id}", + f"/mypayment/stores/{store.id}/sellers/{user.id}", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1666,7 +1666,7 @@ async def test_delete_seller_as_seller_with_permission(client: TestClient): async def test_delete_manager_seller(client: TestClient): response = client.delete( - f"/myeclpay/stores/{store.id}/sellers/{structure_manager_user.id}", + f"/mypayment/stores/{store.id}/sellers/{structure_manager_user.id}", headers={ "Authorization": f"Bearer {store_seller_can_manage_sellers_user_access_token}", }, @@ -1680,7 +1680,7 @@ async def test_delete_manager_seller(client: TestClient): async def test_get_tos_for_unregistered_user(client: TestClient): response = client.get( - "/myeclpay/users/me/tos", + "/mypayment/users/me/tos", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, ) assert response.status_code == 400 @@ -1689,7 +1689,7 @@ async def test_get_tos_for_unregistered_user(client: TestClient): async def test_get_user_tos(client: TestClient): response = client.get( - "/myeclpay/users/me/tos", + "/mypayment/users/me/tos", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 200 @@ -1704,13 +1704,13 @@ async def test_register_new_user(client: TestClient): user_to_register_token = create_api_access_token(user_to_register) response = client.post( - "/myeclpay/users/me/register", + "/mypayment/users/me/register", headers={"Authorization": f"Bearer {user_to_register_token}"}, ) assert response.status_code == 204 response = client.post( - "/myeclpay/users/me/register", + "/mypayment/users/me/register", headers={"Authorization": f"Bearer {user_to_register_token}"}, ) assert response.status_code == 400 @@ -1719,7 +1719,7 @@ async def test_register_new_user(client: TestClient): async def test_sign_tos_for_old_tos_version(client: TestClient): response = client.post( - "/myeclpay/users/me/tos", + "/mypayment/users/me/tos", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, json={"accepted_tos_version": 0}, ) @@ -1729,7 +1729,7 @@ async def test_sign_tos_for_old_tos_version(client: TestClient): async def test_sign_tos_for_unregistered_user(client: TestClient): response = client.post( - "/myeclpay/users/me/tos", + "/mypayment/users/me/tos", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, json={"accepted_tos_version": LATEST_TOS}, ) @@ -1744,13 +1744,13 @@ async def test_sign_tos(client: TestClient): unregistered_user_token = create_api_access_token(unregistered_user) response = client.post( - "/myeclpay/users/me/register", + "/mypayment/users/me/register", headers={"Authorization": f"Bearer {unregistered_user_token}"}, ) assert response.status_code == 204 response = client.post( - "/myeclpay/users/me/tos", + "/mypayment/users/me/tos", headers={"Authorization": f"Bearer {unregistered_user_token}"}, json={"accepted_tos_version": LATEST_TOS}, ) @@ -1759,7 +1759,7 @@ async def test_sign_tos(client: TestClient): async def test_get_user_devices_with_unregistred_user(client: TestClient): response = client.get( - "/myeclpay/users/me/wallet/devices", + "/mypayment/users/me/wallet/devices", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, ) assert response.status_code == 400 @@ -1768,7 +1768,7 @@ async def test_get_user_devices_with_unregistred_user(client: TestClient): async def test_get_user_devices(client: TestClient): response = client.get( - "/myeclpay/users/me/wallet/devices", + "/mypayment/users/me/wallet/devices", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 200 @@ -1777,7 +1777,7 @@ async def test_get_user_devices(client: TestClient): async def test_get_user_wallet_unregistred_user(client: TestClient): response = client.get( - "/myeclpay/users/me/wallet", + "/mypayment/users/me/wallet", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, ) assert response.status_code == 400 @@ -1786,7 +1786,7 @@ async def test_get_user_wallet_unregistred_user(client: TestClient): async def test_get_user_wallet(client: TestClient): response = client.get( - "/myeclpay/users/me/wallet", + "/mypayment/users/me/wallet", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 200 @@ -1795,7 +1795,7 @@ async def test_get_user_wallet(client: TestClient): async def test_get_user_device_non_existing_user(client: TestClient): response = client.get( - "/myeclpay/users/me/wallet/devices/f33a6034-0420-4c08-8afd-46ef662d0b28", + "/mypayment/users/me/wallet/devices/f33a6034-0420-4c08-8afd-46ef662d0b28", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, ) assert response.status_code == 400 @@ -1804,7 +1804,7 @@ async def test_get_user_device_non_existing_user(client: TestClient): async def test_get_user_device_non_existing_device(client: TestClient): response = client.get( - "/myeclpay/users/me/wallet/devices/f33a6034-0420-4c08-8afd-46ef662d0b28", + "/mypayment/users/me/wallet/devices/f33a6034-0420-4c08-8afd-46ef662d0b28", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 404 @@ -1813,7 +1813,7 @@ async def test_get_user_device_non_existing_device(client: TestClient): async def test_get_user_device_with_device_from_an_other_user(client: TestClient): response = client.get( - f"/myeclpay/users/me/wallet/devices/{store_wallet_device.id}", + f"/mypayment/users/me/wallet/devices/{store_wallet_device.id}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 400 @@ -1822,7 +1822,7 @@ async def test_get_user_device_with_device_from_an_other_user(client: TestClient async def test_get_user_device(client: TestClient): response = client.get( - f"/myeclpay/users/me/wallet/devices/{ecl_user_wallet_device.id}", + f"/mypayment/users/me/wallet/devices/{ecl_user_wallet_device.id}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 200 @@ -1831,7 +1831,7 @@ async def test_get_user_device(client: TestClient): async def test_create_user_device_unregistred_user(client: TestClient): response = client.post( - "/myeclpay/users/me/wallet/devices", + "/mypayment/users/me/wallet/devices", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, json={ "name": "MyDevice", @@ -1862,7 +1862,7 @@ async def test_create_and_activate_user_device( public_key = private_key.public_key() response = client.post( - "/myeclpay/users/me/wallet/devices", + "/mypayment/users/me/wallet/devices", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "name": "MySuperDevice", @@ -1879,7 +1879,7 @@ async def test_create_and_activate_user_device( async with get_TestingSessionLocal()() as db: wallet_device = await db.get( - models_myeclpay.WalletDevice, + models_mypayment.WalletDevice, response.json()["id"], ) assert wallet_device is not None @@ -1889,14 +1889,14 @@ async def test_create_and_activate_user_device( ) response = client.get( - f"/myeclpay/devices/activate?token={UNIQUE_TOKEN}", + f"/mypayment/devices/activate?token={UNIQUE_TOKEN}", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, follow_redirects=False, ) assert response.status_code == 307 assert response.next_request is not None assert str(response.next_request.url).endswith( - "calypsso/message?type=myeclpay_wallet_device_activation_success", + "calypsso/message?type=mypayment_wallet_device_activation_success", ) @@ -1904,7 +1904,7 @@ async def test_activate_non_existing_device( client: TestClient, ) -> None: response = client.get( - "/myeclpay/devices/activate?token=invalid_token", + "/mypayment/devices/activate?token=invalid_token", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 404 @@ -1915,14 +1915,14 @@ async def test_activate_already_activated_device( client: TestClient, ) -> None: response = client.get( - "/myeclpay/devices/activate?token=activation_token_ecl_user_wallet_device", + "/mypayment/devices/activate?token=activation_token_ecl_user_wallet_device", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, follow_redirects=False, ) assert response.status_code == 307 assert response.next_request is not None assert str(response.next_request.url).endswith( - "calypsso/message?type=myeclpay_wallet_device_already_activated_or_revoked", + "calypsso/message?type=mypayment_wallet_device_already_activated_or_revoked", ) @@ -1931,7 +1931,7 @@ async def test_revoke_user_device_unregistered_user( ) -> None: wallet_device_id = uuid4() response = client.post( - f"/myeclpay/users/me/wallet/devices/{wallet_device_id}/revoke", + f"/mypayment/users/me/wallet/devices/{wallet_device_id}/revoke", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, ) assert response.status_code == 400 @@ -1943,7 +1943,7 @@ async def test_revoke_user_device_device_does_not_exist( ) -> None: wallet_device_id = uuid4() response = client.post( - f"/myeclpay/users/me/wallet/devices/{wallet_device_id}/revoke", + f"/mypayment/users/me/wallet/devices/{wallet_device_id}/revoke", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 404 @@ -1954,7 +1954,7 @@ async def test_revoke_user_device_device_does_not_belong_to_user( client: TestClient, ) -> None: response = client.post( - f"/myeclpay/users/me/wallet/devices/{ecl_user_wallet_device.id}/revoke", + f"/mypayment/users/me/wallet/devices/{ecl_user_wallet_device.id}/revoke", headers={"Authorization": f"Bearer {ecl_user2_access_token}"}, ) assert response.status_code == 400 @@ -1964,7 +1964,7 @@ async def test_revoke_user_device_device_does_not_belong_to_user( async def test_revoke_user_device( client: TestClient, ) -> None: - wallet_device = models_myeclpay.WalletDevice( + wallet_device = models_mypayment.WalletDevice( id=uuid4(), name="Will revoke device", wallet_id=ecl_user_wallet.id, @@ -1975,14 +1975,14 @@ async def test_revoke_user_device( ) await add_object_to_db(wallet_device) response = client.post( - f"/myeclpay/users/me/wallet/devices/{wallet_device.id}/revoke", + f"/mypayment/users/me/wallet/devices/{wallet_device.id}/revoke", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 204 # We want to verify the device is now revoked response = client.get( - "/myeclpay/users/me/wallet/devices/", + "/mypayment/users/me/wallet/devices/", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 200 @@ -1994,7 +1994,7 @@ async def test_revoke_user_device( async def test_get_transactions_unregistered(client: TestClient): response = client.get( - "/myeclpay/users/me/wallet/history", + "/mypayment/users/me/wallet/history", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, ) @@ -2005,7 +2005,7 @@ async def test_get_transactions_unregistered(client: TestClient): def test_get_transactions_success(client: TestClient): """Test successfully getting user transactions""" response = client.get( - "/myeclpay/users/me/wallet/history", + "/mypayment/users/me/wallet/history", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, ) assert response.status_code == 200 @@ -2073,7 +2073,7 @@ def test_get_transactions_success(client: TestClient): def test_get_transactions_success_with_date(client: TestClient): """Test successfully getting user transactions""" response = client.get( - "/myeclpay/users/me/wallet/history", + "/mypayment/users/me/wallet/history", params={ "start_date": "2025-05-18T00:00:00Z", "end_date": "2025-05-19T23:59:59Z", @@ -2118,7 +2118,7 @@ def test_get_transactions_success_with_date(client: TestClient): def test_transfer_with_redirect_url_not_trusted(client: TestClient): """Test transferring with an unregistered user""" response = client.post( - "/myeclpay/transfer/init", + "/mypayment/transfer/init", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, json={ "amount": 1000, @@ -2133,7 +2133,7 @@ def test_transfer_with_redirect_url_not_trusted(client: TestClient): def test_transfer_with_unregistered_user(client: TestClient): """Test transferring with an unregistered user""" response = client.post( - "/myeclpay/transfer/init", + "/mypayment/transfer/init", headers={"Authorization": f"Bearer {unregistered_ecl_user_access_token}"}, json={ "amount": 1000, @@ -2148,7 +2148,7 @@ def test_transfer_with_unregistered_user(client: TestClient): def test_transfer_with_too_small_amount(client: TestClient): """Test transferring with an amount that is too small""" response = client.post( - "/myeclpay/transfer/init", + "/mypayment/transfer/init", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "amount": 99, @@ -2164,7 +2164,7 @@ def test_transfer_with_too_small_amount(client: TestClient): def test_transfer_with_too_big_amount(client: TestClient): """Test transferring with an amount that is too big""" response = client.post( - "/myeclpay/transfer/init", + "/mypayment/transfer/init", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "amount": 8001, @@ -2184,7 +2184,7 @@ def test_hello_asso_transfer( ): """Test transferring with the hello_asso transfer type""" response = client.post( - "/myeclpay/transfer/init", + "/mypayment/transfer/init", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "amount": 1000, @@ -2212,7 +2212,7 @@ def test_redirect_from_ha_transfer_non_trusted_url( client: TestClient, ): response = client.get( - "/myeclpay/transfer/redirect?url=http://localhost:3000/nottrusted", + "/mypayment/transfer/redirect?url=http://localhost:3000/nottrusted", ) assert response.status_code == 400 assert response.json()["detail"] == "Redirect URL is not trusted by hyperion" @@ -2222,7 +2222,7 @@ def test_redirect_from_ha_transfer_trusted_url( client: TestClient, ): response = client.get( - "/myeclpay/transfer/redirect?url=http://localhost:3000/payment_callback", + "/mypayment/transfer/redirect?url=http://localhost:3000/payment_callback", follow_redirects=False, ) assert response.status_code == 307 @@ -2232,7 +2232,7 @@ def test_redirect_from_ha_transfer_trusted_url( def ensure_qr_code_id_is_already_used(qr_code_id: str | UUID, client: TestClient): response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "id": str(qr_code_id), @@ -2256,7 +2256,7 @@ def test_store_scan_invalid_store_id(client: TestClient): qr_code_id = str(uuid4()) response = client.post( - f"/myeclpay/stores/{uuid4()}/scan", + f"/mypayment/stores/{uuid4()}/scan", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "id": qr_code_id, @@ -2277,7 +2277,7 @@ def test_store_scan_store_when_not_seller(client: TestClient): qr_code_id = str(uuid4()) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={ "id": qr_code_id, @@ -2301,7 +2301,7 @@ def test_store_scan_store_when_seller_but_can_not_bank(client: TestClient): qr_code_id = str(uuid4()) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={ "Authorization": f"Bearer {store_seller_no_permission_user_access_token}", }, @@ -2327,7 +2327,7 @@ def test_store_scan_store_invalid_wallet_device_id(client: TestClient): qr_code_id = str(uuid4()) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": qr_code_id, @@ -2348,7 +2348,7 @@ def test_store_scan_store_non_active_wallet_device_id(client: TestClient): qr_code_id = str(uuid4()) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": qr_code_id, @@ -2369,7 +2369,7 @@ def test_store_scan_store_invalid_signature(client: TestClient): qr_code_id = str(uuid4()) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": qr_code_id, @@ -2402,7 +2402,7 @@ def test_store_scan_store_with_non_store_qr_code(client: TestClient): ) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": str(qr_code_content.id), @@ -2437,7 +2437,7 @@ def test_store_scan_store_negative_total(client: TestClient): ) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": str(qr_code_content.id), @@ -2460,7 +2460,7 @@ def test_store_scan_store_missing_wallet( ): # This should never happen, as an user should never have a WalletDevice without an existing associated Wallet mocker.patch( - "app.core.myeclpay.cruds_myeclpay.get_wallet", + "app.core.mypayment.cruds_mypayment.get_wallet", return_value=None, ) @@ -2479,7 +2479,7 @@ def test_store_scan_store_missing_wallet( ) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": str(qr_code_content.id), @@ -2515,7 +2515,7 @@ def test_store_scan_store_from_store_wallet(client: TestClient): ) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": str(qr_code_content.id), @@ -2540,14 +2540,14 @@ async def test_store_scan_store_from_wallet_with_old_tos_version(client: TestCli groups=[], ) - ecl_user_wallet = models_myeclpay.Wallet( + ecl_user_wallet = models_mypayment.Wallet( id=uuid4(), type=WalletType.USER, balance=1000, # 10€ ) await add_object_to_db(ecl_user_wallet) - ecl_user_payment = models_myeclpay.UserPayment( + ecl_user_payment = models_mypayment.UserPayment( user_id=ecl_user.id, wallet_id=ecl_user_wallet.id, accepted_tos_signature=datetime.now(UTC), @@ -2556,7 +2556,7 @@ async def test_store_scan_store_from_wallet_with_old_tos_version(client: TestCli await add_object_to_db(ecl_user_payment) ecl_user_wallet_device_private_key = Ed25519PrivateKey.generate() - ecl_user_wallet_device = models_myeclpay.WalletDevice( + ecl_user_wallet_device = models_mypayment.WalletDevice( id=uuid4(), name="Test device", wallet_id=ecl_user_wallet.id, @@ -2585,7 +2585,7 @@ async def test_store_scan_store_from_wallet_with_old_tos_version(client: TestCli ) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": str(qr_code_content.id), @@ -2618,7 +2618,7 @@ def test_store_scan_store_insufficient_ballance(client: TestClient): ) response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": str(qr_code_content.id), @@ -2651,11 +2651,11 @@ async def test_store_scan_store_successful_scan(client: TestClient): ) async with get_TestingSessionLocal()() as db: - store_wallet_before_scan = await cruds_myeclpay.get_wallet( + store_wallet_before_scan = await cruds_mypayment.get_wallet( db=db, wallet_id=store_wallet.id, ) - user_wallet_before_scan = await cruds_myeclpay.get_wallet( + user_wallet_before_scan = await cruds_mypayment.get_wallet( db=db, wallet_id=ecl_user_wallet_device.wallet_id, ) @@ -2663,7 +2663,7 @@ async def test_store_scan_store_successful_scan(client: TestClient): assert user_wallet_before_scan is not None response = client.post( - f"/myeclpay/stores/{store.id}/scan", + f"/mypayment/stores/{store.id}/scan", headers={"Authorization": f"Bearer {store_seller_can_bank_user_access_token}"}, json={ "id": str(qr_code_content.id), @@ -2679,11 +2679,11 @@ async def test_store_scan_store_successful_scan(client: TestClient): ensure_qr_code_id_is_already_used(qr_code_id=qr_code_id, client=client) async with get_TestingSessionLocal()() as db: - store_wallet_after_scan = await cruds_myeclpay.get_wallet( + store_wallet_after_scan = await cruds_mypayment.get_wallet( db=db, wallet_id=store_wallet.id, ) - user_wallet_after_scan = await cruds_myeclpay.get_wallet( + user_wallet_after_scan = await cruds_mypayment.get_wallet( db=db, wallet_id=ecl_user_wallet_device.wallet_id, ) @@ -2706,7 +2706,7 @@ async def test_store_scan_store_successful_scan(client: TestClient): async def test_unknown_transaction_refund(client: TestClient): response = client.post( - f"/myeclpay/transactions/{uuid4()}/refund", + f"/mypayment/transactions/{uuid4()}/refund", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={"complete_refund": True}, ) @@ -2715,7 +2715,7 @@ async def test_unknown_transaction_refund(client: TestClient): async def test_transaction_refund_unconfirmed_transaction(client: TestClient): - transaction_canceled = models_myeclpay.Transaction( + transaction_canceled = models_mypayment.Transaction( id=uuid4(), debited_wallet_id=ecl_user_wallet.id, credited_wallet_id=store_wallet.id, @@ -2731,7 +2731,7 @@ async def test_transaction_refund_unconfirmed_transaction(client: TestClient): await add_object_to_db(transaction_canceled) response = client.post( - f"/myeclpay/transactions/{transaction_canceled.id}/refund", + f"/mypayment/transactions/{transaction_canceled.id}/refund", headers={"Authorization": f"Bearer {ecl_user_access_token}"}, json={"complete_refund": True}, ) @@ -2741,7 +2741,7 @@ async def test_transaction_refund_unconfirmed_transaction(client: TestClient): async def test_transaction_refund_unauthorized_user(client: TestClient): response = client.post( - f"/myeclpay/transactions/{transaction_from_ecl_user_to_store.id}/refund", + f"/mypayment/transactions/{transaction_from_ecl_user_to_store.id}/refund", headers={"Authorization": f"Bearer {ecl_user2_access_token}"}, json={"complete_refund": True}, ) @@ -2754,18 +2754,18 @@ async def test_transaction_refund_unauthorized_user(client: TestClient): async def test_transaction_refund_complete(client: TestClient): async with get_TestingSessionLocal()() as db: - debited_wallet_before_refund = await cruds_myeclpay.get_wallet( + debited_wallet_before_refund = await cruds_mypayment.get_wallet( db=db, wallet_id=ecl_user_wallet.id, ) - credited_wallet_before_refund = await cruds_myeclpay.get_wallet( + credited_wallet_before_refund = await cruds_mypayment.get_wallet( db=db, wallet_id=store_wallet.id, ) assert debited_wallet_before_refund is not None assert credited_wallet_before_refund is not None - transaction = models_myeclpay.Transaction( + transaction = models_mypayment.Transaction( id=uuid4(), debited_wallet_id=ecl_user_wallet.id, credited_wallet_id=store_wallet.id, @@ -2780,7 +2780,7 @@ async def test_transaction_refund_complete(client: TestClient): ) await add_object_to_db(transaction) response = client.post( - f"/myeclpay/transactions/{transaction.id}/refund", + f"/mypayment/transactions/{transaction.id}/refund", headers={ "Authorization": f"Bearer {store_seller_can_cancel_user_access_token}", }, @@ -2789,19 +2789,19 @@ async def test_transaction_refund_complete(client: TestClient): assert response.status_code == 204 async with get_TestingSessionLocal()() as db: - transaction_after_refund = await cruds_myeclpay.get_transaction( + transaction_after_refund = await cruds_mypayment.get_transaction( db=db, transaction_id=transaction.id, ) - refund = await cruds_myeclpay.get_refund_by_transaction_id( + refund = await cruds_mypayment.get_refund_by_transaction_id( db=db, transaction_id=transaction.id, ) - debited_wallet_after_refund = await cruds_myeclpay.get_wallet( + debited_wallet_after_refund = await cruds_mypayment.get_wallet( db=db, wallet_id=ecl_user_wallet.id, ) - credited_wallet_after_refund = await cruds_myeclpay.get_wallet( + credited_wallet_after_refund = await cruds_mypayment.get_wallet( db=db, wallet_id=store_wallet.id, ) @@ -2826,7 +2826,7 @@ async def test_transaction_refund_complete(client: TestClient): async def test_transaction_refund_partial_incomplete_amount(client: TestClient): response = client.post( - f"/myeclpay/transactions/{transaction_from_ecl_user_to_store.id}/refund", + f"/mypayment/transactions/{transaction_from_ecl_user_to_store.id}/refund", headers={ "Authorization": f"Bearer {store_seller_can_cancel_user_access_token}", }, @@ -2843,7 +2843,7 @@ async def test_transaction_refund_partial_incomplete_amount(client: TestClient): async def test_transaction_refund_partial_invalid_amount(client: TestClient): response = client.post( - f"/myeclpay/transactions/{transaction_from_ecl_user_to_store.id}/refund", + f"/mypayment/transactions/{transaction_from_ecl_user_to_store.id}/refund", headers={ "Authorization": f"Bearer {store_seller_can_cancel_user_access_token}", }, @@ -2859,7 +2859,7 @@ async def test_transaction_refund_partial_invalid_amount(client: TestClient): ) response = client.post( - f"/myeclpay/transactions/{transaction_from_ecl_user_to_store.id}/refund", + f"/mypayment/transactions/{transaction_from_ecl_user_to_store.id}/refund", headers={ "Authorization": f"Bearer {store_seller_can_cancel_user_access_token}", }, @@ -2874,18 +2874,18 @@ async def test_transaction_refund_partial_invalid_amount(client: TestClient): async def test_transaction_refund_partial(client: TestClient): async with get_TestingSessionLocal()() as db: - debited_wallet_before_refund = await cruds_myeclpay.get_wallet( + debited_wallet_before_refund = await cruds_mypayment.get_wallet( db=db, wallet_id=ecl_user_wallet.id, ) - credited_wallet_before_refund = await cruds_myeclpay.get_wallet( + credited_wallet_before_refund = await cruds_mypayment.get_wallet( db=db, wallet_id=store_wallet.id, ) assert debited_wallet_before_refund is not None assert credited_wallet_before_refund is not None - transaction = models_myeclpay.Transaction( + transaction = models_mypayment.Transaction( id=uuid4(), debited_wallet_id=ecl_user_wallet.id, credited_wallet_id=store_wallet.id, @@ -2900,7 +2900,7 @@ async def test_transaction_refund_partial(client: TestClient): ) await add_object_to_db(transaction) response = client.post( - f"/myeclpay/transactions/{transaction.id}/refund", + f"/mypayment/transactions/{transaction.id}/refund", headers={ "Authorization": f"Bearer {store_seller_can_cancel_user_access_token}", }, @@ -2912,19 +2912,19 @@ async def test_transaction_refund_partial(client: TestClient): assert response.status_code == 204 async with get_TestingSessionLocal()() as db: - transaction_after_refund = await cruds_myeclpay.get_transaction( + transaction_after_refund = await cruds_mypayment.get_transaction( db=db, transaction_id=transaction.id, ) - refund = await cruds_myeclpay.get_refund_by_transaction_id( + refund = await cruds_mypayment.get_refund_by_transaction_id( db=db, transaction_id=transaction.id, ) - debited_wallet_after_refund = await cruds_myeclpay.get_wallet( + debited_wallet_after_refund = await cruds_mypayment.get_wallet( db=db, wallet_id=ecl_user_wallet.id, ) - credited_wallet_after_refund = await cruds_myeclpay.get_wallet( + credited_wallet_after_refund = await cruds_mypayment.get_wallet( db=db, wallet_id=store_wallet.id, ) @@ -2948,7 +2948,7 @@ async def test_transaction_refund_partial(client: TestClient): async def test_get_invoices_as_random_user(client: TestClient): response = client.get( - "/myeclpay/invoices", + "/mypayment/invoices", headers={"Authorization": f"Bearer {structure2_manager_user_token}"}, ) @@ -2958,7 +2958,7 @@ async def test_get_invoices_as_random_user(client: TestClient): async def test_get_invoices_as_bank_account_holder(client: TestClient): response = client.get( - "/myeclpay/invoices", + "/mypayment/invoices", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) @@ -2970,7 +2970,7 @@ async def test_get_invoices_as_bank_account_holder_with_date( client: TestClient, ): response = client.get( - "/myeclpay/invoices", + "/mypayment/invoices", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, params={ "start_date": (datetime.now(UTC) - timedelta(days=40)).strftime( @@ -2990,7 +2990,7 @@ async def test_get_invoices_as_bank_account_holder_with_structure_id( client: TestClient, ): response = client.get( - f"/myeclpay/invoices?structures_ids={structure2.id}", + f"/mypayment/invoices?structures_ids={structure2.id}", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) @@ -3002,7 +3002,7 @@ async def test_get_invoices_as_bank_account_holder_with_limit( client: TestClient, ): response = client.get( - "/myeclpay/invoices", + "/mypayment/invoices", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, params={ "page": 1, @@ -3024,7 +3024,7 @@ async def test_get_structure_invoices_as_structure_manager( client: TestClient, ): response = client.get( - f"/myeclpay/invoices/structures/{structure.id}", + f"/mypayment/invoices/structures/{structure.id}", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) @@ -3036,7 +3036,7 @@ async def test_generate_invoice_as_structure_manager( client: TestClient, ): response = client.post( - f"/myeclpay/invoices/structures/{structure.id}", + f"/mypayment/invoices/structures/{structure.id}", headers={"Authorization": f"Bearer {structure2_manager_user_token}"}, ) @@ -3048,7 +3048,7 @@ async def test_generate_invoice_as_bank_account_holder( client: TestClient, ): response = client.post( - f"/myeclpay/invoices/structures/{structure2.id}", + f"/mypayment/invoices/structures/{structure2.id}", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) @@ -3063,7 +3063,7 @@ async def test_generate_invoice_as_bank_account_holder( assert response.json()["total"] == 9000 invoices = client.get( - f"/myeclpay/invoices/structures/{structure2.id}", + f"/mypayment/invoices/structures/{structure2.id}", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) assert len(invoices.json()) == 2 @@ -3073,7 +3073,7 @@ async def test_empty_invoice_on_null_details( client: TestClient, ): response = client.post( - f"/myeclpay/invoices/structures/{structure2.id}", + f"/mypayment/invoices/structures/{structure2.id}", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) @@ -3085,7 +3085,7 @@ async def test_update_invoice_paid_status_as_structure_manager( client: TestClient, ): response = client.patch( - f"/myeclpay/invoices/{invoice3.id}/paid", + f"/mypayment/invoices/{invoice3.id}/paid", headers={"Authorization": f"Bearer {structure2_manager_user_token}"}, params={"paid": True}, ) @@ -3098,7 +3098,7 @@ async def test_update_invoice_paid_status_as_bank_account_holder( client: TestClient, ): response = client.patch( - f"/myeclpay/invoices/{invoice2.id}/paid", + f"/mypayment/invoices/{invoice2.id}/paid", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, params={"paid": True}, ) @@ -3106,7 +3106,7 @@ async def test_update_invoice_paid_status_as_bank_account_holder( assert response.status_code == 204, response.text async with get_TestingSessionLocal()() as db: - invoice = await cruds_myeclpay.get_invoice_by_id( + invoice = await cruds_mypayment.get_invoice_by_id( db=db, invoice_id=invoice2.id, ) @@ -3114,7 +3114,7 @@ async def test_update_invoice_paid_status_as_bank_account_holder( assert invoice.paid is True response = client.patch( - f"/myeclpay/invoices/{invoice2.id}/paid", + f"/mypayment/invoices/{invoice2.id}/paid", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, params={"paid": False}, ) @@ -3122,7 +3122,7 @@ async def test_update_invoice_paid_status_as_bank_account_holder( assert response.status_code == 204 async with get_TestingSessionLocal()() as db: - invoice = await cruds_myeclpay.get_invoice_by_id( + invoice = await cruds_mypayment.get_invoice_by_id( db=db, invoice_id=invoice2.id, ) @@ -3134,19 +3134,19 @@ async def test_update_invoice_received_status_as_structure_manager( client: TestClient, ): async with get_TestingSessionLocal()() as db: - await cruds_myeclpay.update_invoice_paid_status( + await cruds_mypayment.update_invoice_paid_status( db=db, invoice_id=invoice2.id, paid=True, ) await db.commit() - invoice = await cruds_myeclpay.get_invoice_by_id( + invoice = await cruds_mypayment.get_invoice_by_id( db=db, invoice_id=invoice2.id, ) assert invoice is not None - store_wallet = await cruds_myeclpay.get_wallet( + store_wallet = await cruds_mypayment.get_wallet( db=db, wallet_id=invoice.details[0].store.wallet_id, ) @@ -3154,27 +3154,27 @@ async def test_update_invoice_received_status_as_structure_manager( store_balance = store_wallet.balance response = client.patch( - f"/myeclpay/invoices/{invoice2.id}/received", + f"/mypayment/invoices/{invoice2.id}/received", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) assert response.status_code == 204, response.text async with get_TestingSessionLocal()() as db: - invoice = await cruds_myeclpay.get_invoice_by_id( + invoice = await cruds_mypayment.get_invoice_by_id( db=db, invoice_id=invoice2.id, ) assert invoice is not None assert invoice.received is True - store_wallet = await cruds_myeclpay.get_wallet( + store_wallet = await cruds_mypayment.get_wallet( db=db, wallet_id=invoice.details[0].store.wallet_id, ) assert store_wallet is not None assert store_wallet.balance == store_balance - invoice.details[0].total - withdrawals = await cruds_myeclpay.get_withdrawals_by_wallet_id( + withdrawals = await cruds_mypayment.get_withdrawals_by_wallet_id( db=db, wallet_id=store_wallet.id, ) @@ -3186,7 +3186,7 @@ async def test_delete_paid_invoice( client: TestClient, ): response = client.delete( - f"/myeclpay/invoices/{invoice2.id}", + f"/mypayment/invoices/{invoice2.id}", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) assert response.status_code == 400, response.text @@ -3200,13 +3200,13 @@ async def test_delete_invoice( client: TestClient, ): response = client.delete( - f"/myeclpay/invoices/{invoice3.id}", + f"/mypayment/invoices/{invoice3.id}", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) assert response.status_code == 204, response.text response = client.get( - "/myeclpay/invoices", + "/mypayment/invoices", headers={"Authorization": f"Bearer {structure_manager_user_token}"}, ) assert response.status_code == 200