Files
dknog-membership/admidio/model.py
Allan Eising c2ceaeb989
Some checks failed
release-tag / release-image (push) Failing after 3m50s
Initial commit
2025-03-03 21:59:08 +01:00

162 lines
4.9 KiB
Python

"""High-levle api."""
import logging
from datetime import date
from dataclasses import dataclass
from functools import cached_property
from typing import Final
from .db import AdmidioDB
MEMBER_ROLE = "Member"
FIELD_PAID_DATE = "PMB_PAID"
FIELD_FEE = "PMB_FEE"
FIELD_DUEDATE = "PMB_DUEDATE"
FIELD_EMAIL = "SYS_EMAIL"
LOG = logging.getLogger(__name__)
@dataclass
class AdmidioDBSettings:
"""Database settings class."""
user: str
password: str
host: str
database: str
port: int = 3306
class AdmidioMemberFee:
"""Admidio member fee manager."""
def __init__(self, user_id: int, connection: AdmidioDBSettings) -> None:
"""Create member fee manager class."""
self.db: AdmidioDB = AdmidioDB(
connection.user,
connection.password,
connection.host,
connection.database,
connection.port,
)
self.user_id: Final = user_id
self._user_data: dict[str, str] | None = None
@property
def is_member(self) -> bool:
"""Check if user is a member."""
role_ids = self.db.get_user_roles(self.user_id)
role_map = self.db.get_roles()
roles = [role_map[role_id] for role_id in role_ids]
return MEMBER_ROLE in roles
@property
def member_fee(self) -> int:
"""Get membership fee."""
roles = self.db.get_roles()
member_role_id = next(
iter(
[
role_id
for role_id, role_name in roles.items()
if role_name == MEMBER_ROLE
]
)
)
role_payments = self.db.get_role_payments()
fee = role_payments.get(member_role_id)
if not fee:
raise RuntimeError("Error: No membership cost set on Member role.")
return int(fee)
@property
def user_data(self) -> dict[str, str]:
"""Get user data."""
if not self._user_data:
self._user_data = self._get_user_data()
return self._user_data
def _get_user_data(self) -> dict[str, str]:
"""Get user data."""
user_fields = self.db.get_custom_fields()
user_field_ids = {value: key for key, value in user_fields.items()}
adm_user_data = self.db.get_adm_user_data(self.user_id)
user_data: dict[str, str] = {}
for field_id, data in adm_user_data.items():
if field_name := user_field_ids.get(field_id):
user_data[field_name] = data
else:
LOG.warning("Could not find a field definition for %s", field_id)
return user_data
def _lookup_user_field(self, name: str) -> int:
"""Lookup the ID of a user field."""
user_fields = self.db.get_custom_fields()
field_id = user_fields.get(name)
if not field_id:
raise RuntimeError(f"Unable to find field ID for field {name}")
return field_id
@property
def last_paid(self) -> date | None:
"""Get the date of last payment."""
paid_data = self.user_data.get(FIELD_PAID_DATE)
if not paid_data:
return None
paid_date = date.fromisoformat(paid_data)
return paid_date
@property
def has_paid(self) -> bool:
"""Check if a user has paid."""
if not self.last_paid:
return False
paid_days = date.today() - self.last_paid
if paid_days.days > 365:
return False
return True
@property
def amount_due(self) -> int:
"""Get amount due."""
if fee := self.user_data.get(FIELD_FEE):
return int(fee)
if not self.is_member:
raise RuntimeError(
"User does not seem to be a member, and has no due fees."
)
return self.member_fee
def register_payment(self, amount_paid: int | None = None) -> None:
"""Register payment,"""
date_field = self._lookup_user_field(FIELD_PAID_DATE)
amount_field = self._lookup_user_field(FIELD_FEE)
date_paid = date.today().isoformat()
if not amount_paid:
amount_paid = self.member_fee
self.db.create_user_data(self.user_id, date_field, date_paid)
self.db.create_user_data(self.user_id, amount_field, str(amount_paid))
@classmethod
def lookup_email(
cls, email: str, settings: AdmidioDBSettings
) -> "AdmidioMemberFee | None":
"""Create instance by lookup up user email address."""
db = AdmidioDB(
settings.user,
settings.password,
settings.host,
settings.database,
settings.port,
)
fields = db.get_custom_fields()
email_field_id = fields.get(FIELD_EMAIL)
if not email_field_id:
raise RuntimeError("Could not resolve email address field in database.")
if user_id := db.get_user_id_by_field(email_field_id, email):
return cls(user_id, settings)
return None