Checkout: Prefill is_business heuristically (Z#23126061) (#3533)

This commit is contained in:
Mira
2023-08-24 17:06:47 +02:00
committed by GitHub
parent 21864885cb
commit 9ba3227837
2 changed files with 42 additions and 8 deletions

View File

@@ -62,27 +62,27 @@ class NamespacedCache:
prefix = int(time.time()) prefix = int(time.time())
self.cache.set(self.prefixkey, prefix) self.cache.set(self.prefixkey, prefix)
def set(self, key: str, value: str, timeout: int=300): def set(self, key: str, value: any, timeout: int=300):
return self.cache.set(self._prefix_key(key), value, timeout) return self.cache.set(self._prefix_key(key), value, timeout)
def get(self, key: str) -> str: def get(self, key: str) -> any:
return self.cache.get(self._prefix_key(key, known_prefix=self._last_prefix)) return self.cache.get(self._prefix_key(key, known_prefix=self._last_prefix))
def get_or_set(self, key: str, default: Callable, timeout=300) -> str: def get_or_set(self, key: str, default: Callable, timeout=300) -> any:
return self.cache.get_or_set( return self.cache.get_or_set(
self._prefix_key(key, known_prefix=self._last_prefix), self._prefix_key(key, known_prefix=self._last_prefix),
default=default, default=default,
timeout=timeout timeout=timeout
) )
def get_many(self, keys: List[str]) -> Dict[str, str]: def get_many(self, keys: List[str]) -> Dict[str, any]:
values = self.cache.get_many([self._prefix_key(key) for key in keys]) values = self.cache.get_many([self._prefix_key(key) for key in keys])
newvalues = {} newvalues = {}
for k, v in values.items(): for k, v in values.items():
newvalues[self._strip_prefix(k)] = v newvalues[self._strip_prefix(k)] = v
return newvalues return newvalues
def set_many(self, values: Dict[str, str], timeout=300): def set_many(self, values: Dict[str, any], timeout=300):
newvalues = {} newvalues = {}
for k, v in values.items(): for k, v in values.items():
newvalues[self._prefix_key(k)] = v newvalues[self._prefix_key(k)] = v

View File

@@ -39,10 +39,13 @@ from decimal import Decimal
from django.conf import settings from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.core.cache import caches
from django.core.exceptions import ImproperlyConfigured, ValidationError from django.core.exceptions import ImproperlyConfigured, ValidationError
from django.core.signing import BadSignature, loads from django.core.signing import BadSignature, loads
from django.core.validators import EmailValidator from django.core.validators import EmailValidator
from django.db.models import F, Q from django.db import models
from django.db.models import Count, F, Q, Sum
from django.db.models.functions import Cast
from django.http import HttpResponseNotAllowed, JsonResponse from django.http import HttpResponseNotAllowed, JsonResponse
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils import translation from django.utils import translation
@@ -62,12 +65,14 @@ from pretix.base.services.cart import (
) )
from pretix.base.services.memberships import validate_memberships_in_order from pretix.base.services.memberships import validate_memberships_in_order
from pretix.base.services.orders import perform_order from pretix.base.services.orders import perform_order
from pretix.base.services.tasks import EventTask
from pretix.base.settings import PERSON_NAME_SCHEMES from pretix.base.settings import PERSON_NAME_SCHEMES
from pretix.base.signals import validate_cart_addons from pretix.base.signals import validate_cart_addons
from pretix.base.templatetags.money import money_filter from pretix.base.templatetags.money import money_filter
from pretix.base.templatetags.phone_format import phone_format from pretix.base.templatetags.phone_format import phone_format
from pretix.base.templatetags.rich_text import rich_text_snippet from pretix.base.templatetags.rich_text import rich_text_snippet
from pretix.base.views.tasks import AsyncAction from pretix.base.views.tasks import AsyncAction
from pretix.celery_app import app
from pretix.multidomain.urlreverse import eventreverse from pretix.multidomain.urlreverse import eventreverse
from pretix.presale.forms.checkout import ( from pretix.presale.forms.checkout import (
ContactForm, InvoiceAddressForm, InvoiceNameForm, MembershipForm, ContactForm, InvoiceAddressForm, InvoiceNameForm, MembershipForm,
@@ -802,7 +807,9 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
@cached_property @cached_property
def invoice_form(self): def invoice_form(self):
wd = self.cart_session.get('widget_data', {}) wd = self.cart_session.get('widget_data', {})
if not self.invoice_address.pk: if self.invoice_address.pk:
wd_initial = {}
elif wd:
wd_initial = { wd_initial = {
'name_parts': { 'name_parts': {
k[21:].replace('-', '_'): v k[21:].replace('-', '_'): v
@@ -817,7 +824,9 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
'country': wd.get('invoice-address-country', ''), 'country': wd.get('invoice-address-country', ''),
} }
else: else:
wd_initial = {} wd_initial = {
'is_business': self._get_is_business_heuristic(),
}
initial = dict(wd_initial) initial = dict(wd_initial)
if self.cart_customer: if self.cart_customer:
@@ -1133,6 +1142,31 @@ class QuestionsStep(QuestionsViewMixin, CartMixin, TemplateFlowStep):
ctx['profiles_data'] = profiles_list ctx['profiles_data'] = profiles_list
return ctx return ctx
def _get_is_business_heuristic(self):
key = 'checkout_heuristic_is_business:' + str(self.event.pk)
cached_result = caches['default'].get(key)
if cached_result is None:
if caches['default'].add(key, False, timeout=10): # return False while query is running
QuestionsStep._update_is_business_heuristic.apply_async(args=(self.event.pk,))
return False
else:
return cached_result
@staticmethod
@app.task(base=EventTask)
def _update_is_business_heuristic(event):
result = InvoiceAddress.objects.filter(order__event=event).aggregate(
total=Count('*'), business=Sum(Cast('is_business', output_field=models.IntegerField())))
if result['total'] < 100:
result = InvoiceAddress.objects.filter(order__event__organizer=event.organizer).aggregate(
total=Count('*'), business=Sum(Cast('is_business', output_field=models.IntegerField())))
if result['business'] and result['total']:
is_business = result['business'] / result['total'] >= 0.6
else:
is_business = False
key = 'checkout_heuristic_is_business:' + str(event.pk)
caches['default'].set(key, is_business, timeout=12 * 3600) # 12 hours
class PaymentStep(CartMixin, TemplateFlowStep): class PaymentStep(CartMixin, TemplateFlowStep):
priority = 200 priority = 200