# Copyright (c) 2025 Patrick Motsch # All rights reserved. """Enterprise subscription auto-renewal scheduler. Runs daily via eventManager (APScheduler). Checks all enterprise subscriptions with autoRenew=True whose period has ended and renews them automatically (old -> EXPIRED, new -> ACTIVE with same duration and params, budget credit, invoice email). """ import logging from datetime import datetime, timezone logger = logging.getLogger(__name__) async def _runEnterpriseAutoRenewal() -> None: """Scheduled task: auto-renew enterprise subscriptions whose period has ended.""" try: from modules.interfaces.interfaceDbSubscription import getRootInterface as _getSubRoot from modules.datamodels.datamodelSubscription import SubscriptionStatusEnum subIface = _getSubRoot() allSubs = subIface.listAll([SubscriptionStatusEnum.ACTIVE]) nowTs = datetime.now(timezone.utc).timestamp() renewed = 0 for sub in allSubs: if not sub.get("isEnterprise"): continue if not sub.get("recurring"): continue periodEnd = sub.get("currentPeriodEnd") if not periodEnd or periodEnd > nowTs: continue mandateId = sub["mandateId"] subId = sub["id"] periodStart = sub.get("currentPeriodStart") or sub.get("startedAt") or nowTs periodDuration = periodEnd - periodStart if periodDuration <= 0: periodDuration = 30 * 86400 newEndDate = nowTs + periodDuration try: from modules.serviceCenter.services.serviceSubscription.mainServiceSubscription import ( getService as getSubscriptionService, ) from modules.security.rootAccess import getRootUser rootUser = getRootUser() subService = getSubscriptionService(rootUser, mandateId) subService.renewEnterprise(subId, newEndDate) renewed += 1 logger.info( "Auto-renewed enterprise subscription %s for mandate %s (new end: %s)", subId, mandateId, datetime.fromtimestamp(newEndDate, tz=timezone.utc).isoformat(), ) except Exception as e: logger.error( "Auto-renewal failed for enterprise subscription %s mandate %s: %s", subId, mandateId, e, ) if renewed: logger.info("Enterprise auto-renewal completed: %d subscription(s) renewed", renewed) except Exception as e: logger.error("Enterprise auto-renewal task failed: %s", e) def registerEnterpriseRenewalScheduler() -> None: """Register the enterprise auto-renewal cron job (daily at 06:00 UTC).""" try: from modules.shared.eventManagement import eventManager eventManager.registerCron( jobId="enterprise_auto_renewal", func=_runEnterpriseAutoRenewal, cronKwargs={ "hour": "6", "minute": "0", }, ) logger.info("Enterprise auto-renewal scheduler registered (daily at 06:00 UTC)") except Exception as e: logger.error("Failed to register enterprise auto-renewal scheduler: %s", e)