forked from CGM_Public/pretix_original
better order_max handling
This commit is contained in:
@@ -23,7 +23,7 @@
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from math import ceil
|
from math import ceil, inf
|
||||||
from typing import Dict, Optional, Tuple
|
from typing import Dict, Optional, Tuple
|
||||||
|
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
@@ -268,7 +268,7 @@ class Discount(LoggedModel):
|
|||||||
|
|
||||||
if collect_potential_discounts is not None:
|
if collect_potential_discounts is not None:
|
||||||
for idx in condition_idx_group:
|
for idx in condition_idx_group:
|
||||||
collect_potential_discounts[idx] = [(self, None, -1)]
|
collect_potential_discounts[idx] = [(self, inf, -1)]
|
||||||
|
|
||||||
def _apply_min_count(self, positions, condition_idx_group, benefit_idx_group, result, collect_potential_discounts):
|
def _apply_min_count(self, positions, condition_idx_group, benefit_idx_group, result, collect_potential_discounts):
|
||||||
if len(condition_idx_group) < self.condition_min_count:
|
if len(condition_idx_group) < self.condition_min_count:
|
||||||
@@ -321,7 +321,7 @@ class Discount(LoggedModel):
|
|||||||
|
|
||||||
if collect_potential_discounts is not None:
|
if collect_potential_discounts is not None:
|
||||||
for idx in consume_idx:
|
for idx in consume_idx:
|
||||||
collect_potential_discounts[idx] = [(self, None, -1)]
|
collect_potential_discounts[idx] = [(self, inf, -1)]
|
||||||
|
|
||||||
for idx in benefit_idx:
|
for idx in benefit_idx:
|
||||||
previous_price = positions[idx][LINE_PRICE_GROSS]
|
previous_price = positions[idx][LINE_PRICE_GROSS]
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ from django.utils.translation import gettext_lazy as _, pgettext_lazy
|
|||||||
from django_countries.fields import Country
|
from django_countries.fields import Country
|
||||||
from django_scopes import ScopedManager
|
from django_scopes import ScopedManager
|
||||||
from i18nfield.fields import I18nCharField, I18nTextField
|
from i18nfield.fields import I18nCharField, I18nTextField
|
||||||
|
from math import inf
|
||||||
|
|
||||||
from pretix.base.models.base import LoggedModel
|
from pretix.base.models.base import LoggedModel
|
||||||
from pretix.base.models.fields import MultiStringField
|
from pretix.base.models.fields import MultiStringField
|
||||||
@@ -160,6 +161,7 @@ class ItemCategory(LoggedModel):
|
|||||||
if self.cross_selling_condition == 'always':
|
if self.cross_selling_condition == 'always':
|
||||||
return self.items.all(), {}
|
return self.items.all(), {}
|
||||||
if self.cross_selling_condition == 'products':
|
if self.cross_selling_condition == 'products':
|
||||||
|
# TODO set max_count for products with max_per_order
|
||||||
match = set(match.pk for match in self.cross_selling_match_products.only('pk')) # TODO prefetch this
|
match = set(match.pk for match in self.cross_selling_match_products.only('pk')) # TODO prefetch this
|
||||||
return (self.items.all(), {}) if any(pos.item.pk in match for pos in cart) else ([], {})
|
return (self.items.all(), {}) if any(pos.item.pk in match for pos in cart) else ([], {})
|
||||||
if self.cross_selling_condition == 'discounts':
|
if self.cross_selling_condition == 'discounts':
|
||||||
@@ -183,8 +185,19 @@ class ItemCategory(LoggedModel):
|
|||||||
# - max_count for product: sum up max_counts
|
# - max_count for product: sum up max_counts
|
||||||
# - discount_rule for product: take first discount_rule
|
# - discount_rule for product: take first discount_rule
|
||||||
|
|
||||||
|
def discount_info(item, infos_for_item):
|
||||||
|
infos_for_item = list(infos_for_item)
|
||||||
|
return (
|
||||||
|
item,
|
||||||
|
min(
|
||||||
|
sum(max_count for (item, discount_rule, max_count, i) in infos_for_item),
|
||||||
|
(item.max_per_order - sum(1 for pos in cart if pos.item_id == item.pk)) if item.max_per_order else inf
|
||||||
|
),
|
||||||
|
next(discount_rule for (item, discount_rule, max_count, i) in infos_for_item)
|
||||||
|
)
|
||||||
|
|
||||||
grouped_by_item = [
|
grouped_by_item = [
|
||||||
(item, list(infos_for_item)) for item, infos_for_item in
|
discount_info(item, infos_for_item) for item, infos_for_item in
|
||||||
groupby(
|
groupby(
|
||||||
sorted(
|
sorted(
|
||||||
(
|
(
|
||||||
@@ -197,17 +210,11 @@ class ItemCategory(LoggedModel):
|
|||||||
lambda tup: tup[0])
|
lambda tup: tup[0])
|
||||||
]
|
]
|
||||||
|
|
||||||
def sum_or_none(iter):
|
|
||||||
return functools.reduce(lambda x, y: None if x is None or y is None else x + y, iter, 0)
|
|
||||||
|
|
||||||
my_item_pks = self.items.values_list('pk', flat=True)
|
my_item_pks = self.items.values_list('pk', flat=True)
|
||||||
potential_discount_items = {
|
potential_discount_items = {
|
||||||
item.pk: (
|
item.pk: (max_count, discount_rule)
|
||||||
sum_or_none(max_count for (item, discount_rule, max_count, i) in infos_for_item),
|
for item, max_count, discount_rule in grouped_by_item
|
||||||
next(discount_rule for (item, discount_rule, max_count, i) in infos_for_item)
|
if max_count > 0 and item.pk in my_item_pks and item.is_available()
|
||||||
)
|
|
||||||
for item, infos_for_item in grouped_by_item
|
|
||||||
if item.pk in my_item_pks
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return self.items.filter(pk__in=potential_discount_items), potential_discount_items
|
return self.items.filter(pk__in=potential_discount_items), potential_discount_items
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ from django.utils.translation import (
|
|||||||
)
|
)
|
||||||
from django.views.generic.base import TemplateResponseMixin
|
from django.views.generic.base import TemplateResponseMixin
|
||||||
from django_scopes import scopes_disabled
|
from django_scopes import scopes_disabled
|
||||||
|
from math import inf
|
||||||
|
|
||||||
from pretix.base.models import Customer, Membership, Order
|
from pretix.base.models import Customer, Membership, Order
|
||||||
from pretix.base.models.items import Question
|
from pretix.base.models.items import Question
|
||||||
@@ -665,7 +666,7 @@ class AddOnsStep(CartMixin, AsyncAction, TemplateFlowStep):
|
|||||||
(max_count, discount_rule) = discount_info[item.pk]
|
(max_count, discount_rule) = discount_info[item.pk]
|
||||||
|
|
||||||
# set item.order_max for benefit_only_apply_to_cheapest_n_matches discounted items
|
# set item.order_max for benefit_only_apply_to_cheapest_n_matches discounted items
|
||||||
if max_count:
|
if max_count and max_count != inf:
|
||||||
item.order_max = min(item.order_max, max_count)
|
item.order_max = min(item.order_max, max_count)
|
||||||
|
|
||||||
# calculate discounted price
|
# calculate discounted price
|
||||||
|
|||||||
Reference in New Issue
Block a user