89 lines
3.3 KiB
Python
89 lines
3.3 KiB
Python
# 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)
|