forked from CGM_Public/pretix_original
cleanup
# Conflicts: # src/pretix/base/services/orders.py
This commit is contained in:
@@ -1,30 +1,20 @@
|
||||
import dataclasses
|
||||
|
||||
from dataclasses import dataclass
|
||||
from decimal import Decimal
|
||||
from functools import reduce
|
||||
from typing import Callable, Dict, List, Literal, Optional, Set, Union
|
||||
from typing import Callable, Dict, List, Literal, Set
|
||||
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
from django.db.models import Prefetch
|
||||
from django.dispatch import receiver
|
||||
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django_scopes import ScopedManager
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
from pretix.base.models import Checkin
|
||||
from pretix.base.models import Event, Order, OrderPosition
|
||||
from pretix.base.models import Item
|
||||
from pretix.base.models import ItemVariation
|
||||
from pretix.base.models import Event, Item, ItemVariation, Order, OrderPosition
|
||||
from pretix.base.reldate import ModelRelativeDateTimeField
|
||||
from pretix.base.services.orders import CancellationCheck
|
||||
from pretix.base.signals import self_service_cancellation_checks
|
||||
from pretix.base.timemachine import time_machine_now
|
||||
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class OrderDiff:
|
||||
order: Order
|
||||
@@ -37,17 +27,22 @@ class OrderDiff:
|
||||
def cancel_all(order: Order) -> "OrderDiff":
|
||||
return OrderDiff(order=order, prev=set(order.positions.all()), next=set())
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CancellationCheckResult:
|
||||
cancellation_possible: bool
|
||||
reason: str
|
||||
|
||||
|
||||
# Maps Check identifier → cancellation check result
|
||||
CancellationCheckResultsById = Dict[str, CancellationCheckResult]
|
||||
CheckFn=Callable[[Order, Set[OrderPosition], OrderPosition], CancellationCheckResultsById]
|
||||
|
||||
|
||||
CheckFn = Callable[[Order, Set[OrderPosition], OrderPosition], CancellationCheckResultsById]
|
||||
|
||||
FeeType = Literal['position_fee', 'process_fee']
|
||||
|
||||
|
||||
class Ruling:
|
||||
"""
|
||||
A Ruling is the result of applying a CancellationRule onto an Order or OrderPosition.
|
||||
@@ -69,9 +64,7 @@ class Ruling:
|
||||
self.results = results
|
||||
self.fee_type = fee_type
|
||||
self.fee = fee
|
||||
self.cancellation_possible = all(ruling.cancellation_possible
|
||||
for ruling in results.values()
|
||||
)
|
||||
self.cancellation_possible = all(ruling.cancellation_possible for ruling in results.values())
|
||||
|
||||
@classmethod
|
||||
def from_absolute_fee(
|
||||
@@ -103,7 +96,7 @@ class Ruling:
|
||||
) -> "Ruling":
|
||||
"""
|
||||
Constructs a Ruling with an absolute fee.
|
||||
:param rule_id: Id of the rule
|
||||
:param rule_id: ID of the rule
|
||||
:param results: CheckResult object
|
||||
:param fee_type: Must be a position_fee as the fee can only be in reference to a position
|
||||
:param reference_price: Price of the position to reference
|
||||
@@ -114,7 +107,12 @@ class Ruling:
|
||||
if fee_type == "process_fee":
|
||||
raise ValidationError("Process fee cannot be used with relative fees")
|
||||
|
||||
return Ruling(rule_id=rule_id, results=results, fee_type=fee_type, fee=round_decimal(reference_price * (percentage/100), currency))
|
||||
return Ruling(
|
||||
rule_id=rule_id,
|
||||
results=results,
|
||||
fee_type=fee_type,
|
||||
fee=round_decimal(reference_price * (percentage / 100), currency)
|
||||
)
|
||||
|
||||
def __lt__(self, other):
|
||||
if not isinstance(other, Ruling):
|
||||
@@ -130,7 +128,7 @@ class Ruling:
|
||||
|
||||
|
||||
def validate_status_chars(value):
|
||||
invalid=set(value) - Order.ALLOWED_STATUS_CHARS
|
||||
invalid = set(value) - Order.ALLOWED_STATUS_CHARS
|
||||
if invalid:
|
||||
raise ValidationError(
|
||||
f"Invalid characters: {invalid}. Allowed: {Order.ALLOWED_STATUS_CHARS}"
|
||||
@@ -139,51 +137,48 @@ def validate_status_chars(value):
|
||||
raise ValidationError("Duplicate characters are not allowed.")
|
||||
|
||||
|
||||
|
||||
class CancellationRule(models.Model):
|
||||
event=models.ForeignKey(
|
||||
event = models.ForeignKey(
|
||||
Event,
|
||||
verbose_name=_("Event"),
|
||||
related_name="orders",
|
||||
on_delete=models.CASCADE
|
||||
)
|
||||
|
||||
all_products=models.BooleanField(
|
||||
all_products = models.BooleanField(
|
||||
verbose_name=_("All products and variations"),
|
||||
default=True,
|
||||
)
|
||||
limit_products=models.ManyToManyField(Item, verbose_name=_("Products"), blank=True)
|
||||
limit_variations=models.ManyToManyField(
|
||||
limit_products = models.ManyToManyField(Item, verbose_name=_("Products"), blank=True)
|
||||
limit_variations = models.ManyToManyField(
|
||||
ItemVariation, blank=True, verbose_name=_("Variations")
|
||||
)
|
||||
|
||||
|
||||
allowed_if_in_order_status=models.CharField(
|
||||
allowed_if_in_order_status = models.CharField(
|
||||
max_length=4,
|
||||
choices=Order.STATUS_CHOICE,
|
||||
verbose_name=_("Cancellation possible if order is in status"),
|
||||
validators=[validate_status_chars],
|
||||
default="".join(Order.ALLOWED_STATUS_CHARS),
|
||||
)
|
||||
allowed_until=ModelRelativeDateTimeField(null=True, blank=True)
|
||||
except_after=ModelRelativeDateTimeField(null=True, blank=True)
|
||||
allowed_until = ModelRelativeDateTimeField(null=True, blank=True)
|
||||
except_after = ModelRelativeDateTimeField(null=True, blank=True)
|
||||
|
||||
fee_percentage_per_item=models.DecimalField(
|
||||
fee_percentage_per_item = models.DecimalField(
|
||||
max_digits=5,
|
||||
decimal_places=2,
|
||||
validators=[MinValueValidator("0.00"), MaxValueValidator("100.00")],
|
||||
verbose_name=_("Fee Percentage per OrderPosition"),
|
||||
default=Decimal("0.00"),
|
||||
) # wird als sum() kombiniert
|
||||
fee_absolute_per_item=models.DecimalField(
|
||||
fee_absolute_per_item = models.DecimalField(
|
||||
max_digits=13,
|
||||
decimal_places=2,
|
||||
verbose_name=_("Absolute fee per OrderPosition"),
|
||||
default=Decimal("0.00"),
|
||||
) # wird als sum() kombiniert
|
||||
|
||||
|
||||
fee_cancellation_process=models.DecimalField(
|
||||
fee_cancellation_process = models.DecimalField(
|
||||
max_digits=13,
|
||||
decimal_places=2,
|
||||
verbose_name=_("Absolute fee per Cancellation"),
|
||||
@@ -200,14 +195,14 @@ class CancellationRule(models.Model):
|
||||
if not self.allowed_until and not self.allowed_until:
|
||||
return {check_id: CancellationCheckResult(
|
||||
cancellation_possible=True,
|
||||
reason=f"No time window specified",
|
||||
reason="No time window specified",
|
||||
)}
|
||||
|
||||
relevant_event=order_position.subevent or order_position.event
|
||||
in_allowed_until=time_machine_now() < self.allowed_until.datetime(
|
||||
relevant_event) if self.allowed_until else False
|
||||
in_exemption=time_machine_now() > self.except_after.datetime(
|
||||
relevant_event) if self.except_after else False
|
||||
relevant_event = order_position.subevent or order_position.event
|
||||
in_allowed_until = time_machine_now() < self.allowed_until.datetime(
|
||||
relevant_event) if self.allowed_until else False
|
||||
in_exemption = time_machine_now() > self.except_after.datetime(
|
||||
relevant_event) if self.except_after else False
|
||||
|
||||
if in_allowed_until and not in_exemption:
|
||||
except_after_message = f" and not after {self.except_after.datetime(relevant_event)}" if self.except_after else ""
|
||||
@@ -226,14 +221,13 @@ class CancellationRule(models.Model):
|
||||
reason=f"Cancellation after time window ending on {self.allowed_until.datetime(relevant_event)}",
|
||||
)}
|
||||
|
||||
|
||||
def _check_order_status(self, diff: OrderDiff, order_position: OrderPosition) -> CancellationCheckResultsById:
|
||||
check_id = "ORDER_STATUS"
|
||||
|
||||
if diff.order.status == "".join(Order.ALLOWED_STATUS_CHARS):
|
||||
if diff.order.status == "".join([]):
|
||||
return {check_id: CancellationCheckResult(
|
||||
cancellation_possible=True,
|
||||
reason=f"Orders in every status can be cancelled",
|
||||
reason="Orders in every status can be cancelled",
|
||||
)}
|
||||
elif diff.order.status in self.allowed_if_in_order_status:
|
||||
return {check_id: CancellationCheckResult(
|
||||
@@ -245,3 +239,12 @@ class CancellationRule(models.Model):
|
||||
cancellation_possible=False,
|
||||
reason=f"Order in status '{diff.order.status}' cannot be canceled",
|
||||
)}
|
||||
|
||||
|
||||
class CancellationCheck:
|
||||
id: str
|
||||
prefetches: List[Prefetch] = []
|
||||
related_selects: List[str] = []
|
||||
|
||||
def check(self, order: Order, keep: Set[OrderPosition], order_position: OrderPosition) -> CancellationCheckResult:
|
||||
raise NotImplementedError()
|
||||
|
||||
Reference in New Issue
Block a user