from dataclasses import dataclass, field from dataclasses_json import config, dataclass_json from datetime import datetime, timezone from marshmallow import fields from typing import Optional import dataclasses_json @dataclass_json @dataclass class Subscription: billing_code: str expires_at: Optional[datetime] = field( default=None, metadata=config( encoder=lambda datetime_instance: Subscription._iso_format(datetime_instance), decoder=lambda datetime_string: Subscription.from_iso_format(datetime_string), mm_field=fields.DateTime(format='iso'), undefined=dataclasses_json.Undefined.EXCLUDE, exclude=lambda value: value is None ) ) def has_been_activated(self): return self.expires_at is not None def is_active(self): return self.has_been_activated() and self.expires_at > datetime.now(timezone.utc) @staticmethod def from_iso_format(datetime_string: str): date_string = datetime_string.replace('Z', '+00:00') return datetime.fromisoformat(date_string) @staticmethod def _iso_format(datetime_instance: datetime): return datetime.isoformat(datetime_instance).replace('+00:00', 'Z')