From d5226a5599206ece56235b2a64e48ba136a14cb2 Mon Sep 17 00:00:00 2001 From: patrick-motsch Date: Wed, 4 Feb 2026 22:34:41 +0100 Subject: [PATCH] boot running without errors --- modules/interfaces/interfaceDbBilling.py | 43 +++++--- modules/routes/routeBilling.py | 98 ++++++++----------- .../serviceBilling/mainServiceBilling.py | 13 +-- 3 files changed, 77 insertions(+), 77 deletions(-) diff --git a/modules/interfaces/interfaceDbBilling.py b/modules/interfaces/interfaceDbBilling.py index ebbe3ae5..141fc118 100644 --- a/modules/interfaces/interfaceDbBilling.py +++ b/modules/interfaces/interfaceDbBilling.py @@ -92,11 +92,11 @@ class BillingObjects: def _initializeDatabase(self): """Initialize database connection.""" self.db = DatabaseConnector( - databaseName=BILLING_DATABASE, - host=APP_CONFIG.get('Database_Host', 'localhost'), - port=int(APP_CONFIG.get('Database_Port', '5432')), - user=APP_CONFIG.get('Database_User', 'admin'), - password=APP_CONFIG.get('Database_Password', 'admin') + dbDatabase=BILLING_DATABASE, + dbHost=APP_CONFIG.get('DB_HOST', 'localhost'), + dbPort=int(APP_CONFIG.get('DB_PORT', '5432')), + dbUser=APP_CONFIG.get('DB_USER'), + dbPassword=APP_CONFIG.get('DB_PASSWORD_SECRET') ) def setUserContext(self, currentUser: User, mandateId: str = None): @@ -128,7 +128,7 @@ class BillingObjects: try: results = self.db.getRecordset( BillingSettings, - filterDict={"mandateId": mandateId} + recordFilter={"mandateId": mandateId} ) return results[0] if results else None except Exception as e: @@ -200,7 +200,7 @@ class BillingObjects: try: results = self.db.getRecordset( BillingAccount, - filterDict={"id": accountId} + recordFilter={"id": accountId} ) return results[0] if results else None except Exception as e: @@ -220,7 +220,7 @@ class BillingObjects: try: results = self.db.getRecordset( BillingAccount, - filterDict={ + recordFilter={ "mandateId": mandateId, "accountType": AccountTypeEnum.MANDATE.value } @@ -244,7 +244,7 @@ class BillingObjects: try: results = self.db.getRecordset( BillingAccount, - filterDict={ + recordFilter={ "mandateId": mandateId, "userId": userId, "accountType": AccountTypeEnum.USER.value @@ -255,6 +255,25 @@ class BillingObjects: logger.error(f"Error getting user account: {e}") return None + def getAccountsByMandate(self, mandateId: str) -> List[Dict[str, Any]]: + """ + Get all billing accounts for a mandate. + + Args: + mandateId: Mandate ID + + Returns: + List of BillingAccount dicts + """ + try: + return self.db.getRecordset( + BillingAccount, + recordFilter={"mandateId": mandateId} + ) + except Exception as e: + logger.error(f"Error getting accounts for mandate: {e}") + return [] + def createAccount(self, account: BillingAccount) -> Dict[str, Any]: """ Create a new billing account. @@ -405,7 +424,7 @@ class BillingObjects: """ try: filterDict = {"accountId": accountId} - results = self.db.getRecordset(BillingTransaction, filterDict=filterDict) + results = self.db.getRecordset(BillingTransaction, recordFilter=filterDict) # Apply date filters if provided if startDate or endDate: @@ -442,7 +461,7 @@ class BillingObjects: List of transaction dicts """ # Get all accounts for mandate - accounts = self.db.getRecordset(BillingAccount, filterDict={"mandateId": mandateId}) + accounts = self.db.getRecordset(BillingAccount, recordFilter={"mandateId": mandateId}) allTransactions = [] for account in accounts: @@ -616,7 +635,7 @@ class BillingObjects: "periodType": periodType.value } - results = self.db.getRecordset(UsageStatistics, filterDict=filterDict) + results = self.db.getRecordset(UsageStatistics, recordFilter=filterDict) # Filter by year filtered = [s for s in results if s.get("periodStart") and s["periodStart"].year == year] diff --git a/modules/routes/routeBilling.py b/modules/routes/routeBilling.py index c191e793..e3698509 100644 --- a/modules/routes/routeBilling.py +++ b/modules/routes/routeBilling.py @@ -136,11 +136,11 @@ async def getBalance( raise HTTPException(status_code=500, detail=str(e)) -@router.get("/balance/{mandateId}", response_model=BillingBalanceResponse) +@router.get("/balance/{targetMandateId}", response_model=BillingBalanceResponse) @limiter.limit("60/minute") async def getBalanceForMandate( request: Request, - mandateId: str = Path(..., description="Mandate ID"), + targetMandateId: str = Path(..., description="Mandate ID"), ctx: RequestContext = Depends(getRequestContext) ): """ @@ -149,7 +149,7 @@ async def getBalanceForMandate( try: billingService = getBillingService( ctx.currentUser, - mandateId, + targetMandateId, featureCode="billing" ) @@ -158,12 +158,12 @@ async def getBalanceForMandate( # Get mandate name from app interface from modules.interfaces.interfaceDbApp import getInterface as getAppInterface - appInterface = getAppInterface(ctx.currentUser, mandateId=mandateId) - mandate = appInterface.getMandate(mandateId) + appInterface = getAppInterface(ctx.currentUser, mandateId=targetMandateId) + mandate = appInterface.getMandate(targetMandateId) mandateName = mandate.get("name", "") if mandate else "" return BillingBalanceResponse( - mandateId=mandateId, + mandateId=targetMandateId, mandateName=mandateName, billingModel=checkResult.billingModel or BillingModelEnum.UNLIMITED, balance=checkResult.currentBalance or 0.0, @@ -173,7 +173,7 @@ async def getBalanceForMandate( ) except Exception as e: - logger.error(f"Error getting billing balance for mandate {mandateId}: {e}") + logger.error(f"Error getting billing balance for mandate {targetMandateId}: {e}") raise HTTPException(status_code=500, detail=str(e)) @@ -332,20 +332,20 @@ async def getAllowedProviders( # Admin Endpoints # ============================================================================= -@router.get("/admin/settings/{mandateId}", response_model=Dict[str, Any]) +@router.get("/admin/settings/{targetMandateId}", response_model=Dict[str, Any]) @limiter.limit("30/minute") -@requireSysAdmin async def getSettingsAdmin( request: Request, - mandateId: str = Path(..., description="Mandate ID"), - ctx: RequestContext = Depends(getRequestContext) + targetMandateId: str = Path(..., description="Mandate ID"), + ctx: RequestContext = Depends(getRequestContext), + _admin = Depends(requireSysAdmin) ): """ Get billing settings for a mandate (SysAdmin only). """ try: - billingInterface = getBillingInterface(ctx.currentUser, mandateId) - settings = billingInterface.getSettings(mandateId) + billingInterface = getBillingInterface(ctx.currentUser, targetMandateId) + settings = billingInterface.getSettings(targetMandateId) if not settings: raise HTTPException(status_code=404, detail="Billing settings not found") @@ -359,21 +359,21 @@ async def getSettingsAdmin( raise HTTPException(status_code=500, detail=str(e)) -@router.post("/admin/settings/{mandateId}", response_model=Dict[str, Any]) +@router.post("/admin/settings/{targetMandateId}", response_model=Dict[str, Any]) @limiter.limit("10/minute") -@requireSysAdmin async def createOrUpdateSettings( request: Request, - mandateId: str = Path(..., description="Mandate ID"), + targetMandateId: str = Path(..., description="Mandate ID"), settingsUpdate: BillingSettingsUpdate = Body(...), - ctx: RequestContext = Depends(getRequestContext) + ctx: RequestContext = Depends(getRequestContext), + _admin = Depends(requireSysAdmin) ): """ Create or update billing settings for a mandate (SysAdmin only). """ try: - billingInterface = getBillingInterface(ctx.currentUser, mandateId) - existingSettings = billingInterface.getSettings(mandateId) + billingInterface = getBillingInterface(ctx.currentUser, targetMandateId) + existingSettings = billingInterface.getSettings(targetMandateId) if existingSettings: # Update existing settings @@ -387,7 +387,7 @@ async def createOrUpdateSettings( from modules.datamodels.datamodelBilling import BillingSettings newSettings = BillingSettings( - mandateId=mandateId, + mandateId=targetMandateId, billingModel=settingsUpdate.billingModel or BillingModelEnum.UNLIMITED, defaultUserCredit=settingsUpdate.defaultUserCredit or 10.0, warningThresholdPercent=settingsUpdate.warningThresholdPercent or 10.0, @@ -406,14 +406,14 @@ async def createOrUpdateSettings( raise HTTPException(status_code=500, detail=str(e)) -@router.post("/admin/credit/{mandateId}", response_model=Dict[str, Any]) +@router.post("/admin/credit/{targetMandateId}", response_model=Dict[str, Any]) @limiter.limit("10/minute") -@requireSysAdmin async def addCredit( request: Request, - mandateId: str = Path(..., description="Mandate ID"), + targetMandateId: str = Path(..., description="Mandate ID"), creditRequest: CreditAddRequest = Body(...), - ctx: RequestContext = Depends(getRequestContext) + ctx: RequestContext = Depends(getRequestContext), + _admin = Depends(requireSysAdmin) ): """ Add credit to a billing account (SysAdmin only). @@ -421,8 +421,8 @@ async def addCredit( """ try: # Get settings to determine billing model - billingInterface = getBillingInterface(ctx.currentUser, mandateId) - settings = billingInterface.getSettings(mandateId) + billingInterface = getBillingInterface(ctx.currentUser, targetMandateId) + settings = billingInterface.getSettings(targetMandateId) if not settings: raise HTTPException(status_code=404, detail="Billing settings not found for this mandate") @@ -436,13 +436,13 @@ async def addCredit( # Create user-level account if needed and add credit account = billingInterface.getOrCreateUserAccount( - mandateId, + targetMandateId, creditRequest.userId, initialBalance=0.0 ) elif billingModel in [BillingModelEnum.PREPAY_MANDATE, BillingModelEnum.CREDIT_POSTPAY]: # Create mandate-level account if needed and add credit - account = billingInterface.getOrCreateMandateAccount(mandateId, initialBalance=0.0) + account = billingInterface.getOrCreateMandateAccount(targetMandateId, initialBalance=0.0) else: raise HTTPException(status_code=400, detail=f"Cannot add credit to {billingModel.value} billing model") @@ -459,7 +459,7 @@ async def addCredit( result = billingInterface.createTransaction(transaction) - logger.info(f"Added {creditRequest.amount} CHF credit to account {account['id']} in mandate {mandateId}") + logger.info(f"Added {creditRequest.amount} CHF credit to account {account['id']} in mandate {targetMandateId}") return result @@ -470,34 +470,22 @@ async def addCredit( raise HTTPException(status_code=500, detail=str(e)) -@router.get("/admin/accounts/{mandateId}", response_model=List[AccountSummary]) +@router.get("/admin/accounts/{targetMandateId}", response_model=List[AccountSummary]) @limiter.limit("30/minute") -@requireSysAdmin async def getAccounts( request: Request, - mandateId: str = Path(..., description="Mandate ID"), - ctx: RequestContext = Depends(getRequestContext) + targetMandateId: str = Path(..., description="Mandate ID"), + ctx: RequestContext = Depends(getRequestContext), + _admin = Depends(requireSysAdmin) ): """ Get all billing accounts for a mandate (SysAdmin only). """ try: - billingInterface = getBillingInterface(ctx.currentUser, mandateId) + billingInterface = getBillingInterface(ctx.currentUser, targetMandateId) - # Get all accounts for this mandate - from modules.connectors.connectorDbPostgre import DatabaseConnector - from modules.shared.configuration import APP_CONFIG - from modules.datamodels.datamodelBilling import BillingAccount - - db = DatabaseConnector( - databaseName="poweron_billing", - host=APP_CONFIG.get('Database_Host', 'localhost'), - port=int(APP_CONFIG.get('Database_Port', '5432')), - user=APP_CONFIG.get('Database_User', 'admin'), - password=APP_CONFIG.get('Database_Password', 'admin') - ) - - accounts = db.getRecordset(BillingAccount, filterDict={"mandateId": mandateId}) + # Get all accounts for this mandate via interface + accounts = billingInterface.getAccountsByMandate(targetMandateId) result = [] for acc in accounts: @@ -519,21 +507,21 @@ async def getAccounts( raise HTTPException(status_code=500, detail=str(e)) -@router.get("/admin/transactions/{mandateId}", response_model=List[TransactionResponse]) +@router.get("/admin/transactions/{targetMandateId}", response_model=List[TransactionResponse]) @limiter.limit("30/minute") -@requireSysAdmin async def getTransactionsAdmin( request: Request, - mandateId: str = Path(..., description="Mandate ID"), + targetMandateId: str = Path(..., description="Mandate ID"), limit: int = Query(default=100, ge=1, le=1000), - ctx: RequestContext = Depends(getRequestContext) + ctx: RequestContext = Depends(getRequestContext), + _admin = Depends(requireSysAdmin) ): """ Get all transactions for a mandate (SysAdmin only). """ try: - billingInterface = getBillingInterface(ctx.currentUser, mandateId) - transactions = billingInterface.getTransactionsByMandate(mandateId, limit=limit) + billingInterface = getBillingInterface(ctx.currentUser, targetMandateId) + transactions = billingInterface.getTransactionsByMandate(targetMandateId, limit=limit) result = [] for t in transactions: @@ -553,5 +541,5 @@ async def getTransactionsAdmin( return result except Exception as e: - logger.error(f"Error getting billing transactions for mandate {mandateId}: {e}") + logger.error(f"Error getting billing transactions for mandate {targetMandateId}: {e}") raise HTTPException(status_code=500, detail=str(e)) diff --git a/modules/services/serviceBilling/mainServiceBilling.py b/modules/services/serviceBilling/mainServiceBilling.py index 709ab61a..c7a08a1c 100644 --- a/modules/services/serviceBilling/mainServiceBilling.py +++ b/modules/services/serviceBilling/mainServiceBilling.py @@ -255,17 +255,10 @@ class BillingService: try: from modules.security.rbac import RbacClass from modules.datamodels.datamodelRbac import AccessRuleContext - from modules.connectors.connectorDbPostgre import DatabaseConnector - from modules.shared.configuration import APP_CONFIG + from modules.security.rootAccess import getRootDbAppConnector - # Get database connectors - dbApp = DatabaseConnector( - databaseName="poweron_app", - host=APP_CONFIG.get('Database_Host', 'localhost'), - port=int(APP_CONFIG.get('Database_Port', '5432')), - user=APP_CONFIG.get('Database_User', 'admin'), - password=APP_CONFIG.get('Database_Password', 'admin') - ) + # Get database connector via established pattern + dbApp = getRootDbAppConnector() rbac = RbacClass(dbApp, dbApp) resourceKey = f"resource.aicore.{provider}"