Changeset View
Changeset View
Standalone View
Standalone View
looper/models.py
| import datetime | import datetime | ||||
| import functools | |||||
| import logging | import logging | ||||
| from typing import ( | from typing import ( | ||||
| Any, | Any, | ||||
| Dict, | Dict, | ||||
| Iterable, | Iterable, | ||||
| Mapping, | Mapping, | ||||
| Optional, | Optional, | ||||
| Sequence, | Sequence, | ||||
| Set, | Set, | ||||
| TYPE_CHECKING, | TYPE_CHECKING, | ||||
| Tuple, | Tuple, | ||||
| Type, | Type, | ||||
| Union, | Union, | ||||
| cast, | cast, | ||||
| ) | ) | ||||
| import dateutil.relativedelta | import dateutil.relativedelta | ||||
| from django.contrib.auth.models import User | from django.contrib.auth.models import User | ||||
| from django.db import models | from django.db import models | ||||
| import django.utils.timezone | import django.utils.timezone | ||||
| from django.urls import reverse | from django.urls import reverse | ||||
| from django.utils.html import format_html | from django.utils.html import format_html | ||||
| from django_countries.fields import CountryField | from django_countries.fields import CountryField | ||||
| from looper import admin_log, form_fields, gateways, model_mixins | |||||
| from looper.decorators import requires_status | |||||
| from looper.money import Money, CurrencyMismatch | from looper.money import Money, CurrencyMismatch | ||||
| from . import gateways, model_mixins, admin_log, form_fields | |||||
| import looper.signals | |||||
| import looper.exceptions | import looper.exceptions | ||||
| import looper.signals | |||||
| DEFAULT_CURRENCY = 'EUR' | DEFAULT_CURRENCY = 'EUR' | ||||
| CURRENCIES = ( | CURRENCIES = ( | ||||
| ('USD', 'USD'), | ('USD', 'USD'), | ||||
| ('EUR', 'EUR'), | ('EUR', 'EUR'), | ||||
| ) | ) | ||||
| log = logging.getLogger(__name__) | log = logging.getLogger(__name__) | ||||
| UpdateFieldsType = Optional[Set[str]] | UpdateFieldsType = Optional[Set[str]] | ||||
| """The type used by Django's save(update_field=...) parameter.""" | """The type used by Django's save(update_field=...) parameter.""" | ||||
| def requires_status(*required_statuses): | |||||
| """Function decorator to assert a model has a certain status. | |||||
| :raise looper.exceptions.IncorrectStatusError: | |||||
| """ | |||||
| _required_statuses = set(required_statuses) | |||||
| def decorator(wrapped): | |||||
| @functools.wraps(wrapped) | |||||
| def checker(self, *args, **kwargs): | |||||
| if self.status not in _required_statuses: | |||||
| raise looper.exceptions.IncorrectStatusError( | |||||
| f'To call {self.__class__}.{wrapped}, {self} needs to have ' | |||||
| f'status in {_required_statuses} but it has {self.status!r}', | |||||
| self.status, | |||||
| _required_statuses, | |||||
| ) | |||||
| return wrapped(self, *args, **kwargs) | |||||
| return checker | |||||
| return decorator | |||||
| class CurrencyField(models.CharField): | class CurrencyField(models.CharField): | ||||
| def __init__(self, **kwargs): | def __init__(self, **kwargs): | ||||
| kwargs.setdefault('max_length', 3) | kwargs.setdefault('max_length', 3) | ||||
| kwargs.setdefault('choices', CURRENCIES) | kwargs.setdefault('choices', CURRENCIES) | ||||
| kwargs.setdefault('default', DEFAULT_CURRENCY) | kwargs.setdefault('default', DEFAULT_CURRENCY) | ||||
| super().__init__(**kwargs) | super().__init__(**kwargs) | ||||
| ▲ Show 20 Lines • Show All 992 Lines • Show Last 20 Lines | |||||