forked from CGM_Public/pretix_original
Bank transfer: Allow dashes in event slug to be missing (Z#23216859) (#5682)
* Bank transfer: Allow dashes in event slug to be missing (Z#23216859) * Update src/pretix/plugins/banktransfer/tasks.py Co-authored-by: Richard Schreiber <schreiber@pretix.eu> * Update src/pretix/plugins/banktransfer/tasks.py Co-authored-by: Richard Schreiber <schreiber@pretix.eu> * Apply suggestions from code review Co-authored-by: Richard Schreiber <schreiber@pretix.eu> --------- Co-authored-by: Richard Schreiber <schreiber@pretix.eu>
This commit is contained in:
@@ -34,8 +34,10 @@
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import operator
|
||||||
import re
|
import re
|
||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
|
from functools import reduce
|
||||||
|
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
from celery.exceptions import MaxRetriesExceededError
|
from celery.exceptions import MaxRetriesExceededError
|
||||||
@@ -117,20 +119,26 @@ def _find_order_for_code(base_qs, code):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def _find_order_for_invoice_id(base_qs, prefix, number):
|
def _find_order_for_invoice_id(base_qs, prefixes, number):
|
||||||
try:
|
try:
|
||||||
# Working with __iregex here is an experiment, if this turns out to be too slow in production
|
# Working with __iregex here is an experiment, if this turns out to be too slow in production
|
||||||
# we might need to switch to a different approach.
|
# we might need to switch to a different approach.
|
||||||
|
r = [
|
||||||
|
Q(
|
||||||
|
prefix__istartswith=prefix, # redundant, but hopefully makes it a little faster
|
||||||
|
full_invoice_no__iregex=prefix + r'[\- ]*0*' + number
|
||||||
|
)
|
||||||
|
for prefix in set(prefixes)
|
||||||
|
]
|
||||||
return base_qs.select_related('order').get(
|
return base_qs.select_related('order').get(
|
||||||
prefix__istartswith=prefix, # redundant, but hopefully makes it a little faster
|
reduce(operator.or_, r)
|
||||||
full_invoice_no__iregex=prefix + r'[\- ]*0*' + number
|
|
||||||
).order
|
).order
|
||||||
except (Invoice.DoesNotExist, Invoice.MultipleObjectsReturned):
|
except (Invoice.DoesNotExist, Invoice.MultipleObjectsReturned):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
@transaction.atomic
|
@transaction.atomic
|
||||||
def _handle_transaction(trans: BankTransaction, matches: tuple, event: Event = None, organizer: Organizer = None):
|
def _handle_transaction(trans: BankTransaction, matches: tuple, regex_match_to_slug, event: Event = None, organizer: Organizer = None):
|
||||||
orders = []
|
orders = []
|
||||||
if event:
|
if event:
|
||||||
for slug, code in matches:
|
for slug, code in matches:
|
||||||
@@ -139,18 +147,19 @@ def _handle_transaction(trans: BankTransaction, matches: tuple, event: Event = N
|
|||||||
if order.code not in {o.code for o in orders}:
|
if order.code not in {o.code for o in orders}:
|
||||||
orders.append(order)
|
orders.append(order)
|
||||||
else:
|
else:
|
||||||
order = _find_order_for_invoice_id(Invoice.objects.filter(event=event), slug, code)
|
order = _find_order_for_invoice_id(Invoice.objects.filter(event=event), (slug, regex_match_to_slug.get(slug, slug)), code)
|
||||||
if order and order.code not in {o.code for o in orders}:
|
if order and order.code not in {o.code for o in orders}:
|
||||||
orders.append(order)
|
orders.append(order)
|
||||||
else:
|
else:
|
||||||
qs = Order.objects.filter(event__organizer=organizer)
|
qs = Order.objects.filter(event__organizer=organizer)
|
||||||
for slug, code in matches:
|
for slug, code in matches:
|
||||||
order = _find_order_for_code(qs.filter(event__slug__iexact=slug), code)
|
original_slug = regex_match_to_slug.get(slug, slug)
|
||||||
|
order = _find_order_for_code(qs.filter(Q(event__slug__iexact=slug) | Q(event__slug__iexact=original_slug)), code)
|
||||||
if order:
|
if order:
|
||||||
if order.code not in {o.code for o in orders}:
|
if order.code not in {o.code for o in orders}:
|
||||||
orders.append(order)
|
orders.append(order)
|
||||||
else:
|
else:
|
||||||
order = _find_order_for_invoice_id(Invoice.objects.filter(event__organizer=organizer), slug, code)
|
order = _find_order_for_invoice_id(Invoice.objects.filter(event__organizer=organizer), (slug, original_slug), code)
|
||||||
if order and order.code not in {o.code for o in orders}:
|
if order and order.code not in {o.code for o in orders}:
|
||||||
orders.append(order)
|
orders.append(order)
|
||||||
|
|
||||||
@@ -366,22 +375,37 @@ def process_banktransfers(self, job: int, data: list) -> None:
|
|||||||
transactions = _get_unknown_transactions(job, data, **job.owner_kwargs)
|
transactions = _get_unknown_transactions(job, data, **job.owner_kwargs)
|
||||||
|
|
||||||
# Match order codes
|
# Match order codes
|
||||||
|
regex_match_to_slug = {}
|
||||||
code_len_agg = Order.objects.filter(event__organizer=job.organizer).annotate(
|
code_len_agg = Order.objects.filter(event__organizer=job.organizer).annotate(
|
||||||
clen=Length('code')
|
clen=Length('code')
|
||||||
).aggregate(min=Min('clen'), max=Max('clen'))
|
).aggregate(min=Min('clen'), max=Max('clen'))
|
||||||
if job.event:
|
if job.event:
|
||||||
prefixes = {job.event.slug.upper()}
|
prefixes = {job.event.slug.upper(), job.event.slug.upper().replace("-", "")}
|
||||||
|
if "-" in job.event.slug:
|
||||||
|
regex_match_to_slug[job.event.slug.upper().replace("-", "")] = job.event.slug
|
||||||
else:
|
else:
|
||||||
prefixes = {e.slug.upper() for e in job.organizer.events.all()}
|
prefixes = set()
|
||||||
|
for e in job.organizer.events.all():
|
||||||
|
prefixes.add(e.slug.upper())
|
||||||
|
if "-" in e.slug:
|
||||||
|
prefixes.add(e.slug.upper().replace("-", ""))
|
||||||
|
regex_match_to_slug[e.slug.upper().replace("-", "")] = e.slug
|
||||||
|
|
||||||
# Match invoice numbers
|
# Match invoice numbers
|
||||||
inr_len_agg = Invoice.objects.filter(event__organizer=job.organizer).annotate(
|
inr_len_agg = Invoice.objects.filter(event__organizer=job.organizer).annotate(
|
||||||
clen=Length('invoice_no')
|
clen=Length('invoice_no')
|
||||||
).aggregate(min=Min('clen'), max=Max('clen'))
|
).aggregate(min=Min('clen'), max=Max('clen'))
|
||||||
if job.event:
|
if job.event:
|
||||||
prefixes |= {p.rstrip(' -') for p in Invoice.objects.filter(event=job.event).distinct().values_list('prefix', flat=True)}
|
invoice_prefixes = Invoice.objects.filter(event=job.event)
|
||||||
else:
|
else:
|
||||||
prefixes |= {p.rstrip(' -') for p in Invoice.objects.filter(event__organizer=job.organizer).distinct().values_list('prefix', flat=True)}
|
invoice_prefixes = Invoice.objects.filter(event__organizer=job.organizer)
|
||||||
|
for p in invoice_prefixes.order_by().distinct().values_list('prefix', flat=True):
|
||||||
|
prefix = p.rstrip(" -")
|
||||||
|
prefixes.add(prefix)
|
||||||
|
if "-" in prefix:
|
||||||
|
prefix_nodash = prefix.replace("-", "")
|
||||||
|
prefixes.add(prefix_nodash)
|
||||||
|
regex_match_to_slug[prefix_nodash] = prefix
|
||||||
|
|
||||||
pattern = re.compile(
|
pattern = re.compile(
|
||||||
"(%s)[ \\-_]*([A-Z0-9]{%s,%s})" % (
|
"(%s)[ \\-_]*([A-Z0-9]{%s,%s})" % (
|
||||||
@@ -409,9 +433,9 @@ def process_banktransfers(self, job: int, data: list) -> None:
|
|||||||
|
|
||||||
if matches:
|
if matches:
|
||||||
if job.event:
|
if job.event:
|
||||||
_handle_transaction(trans, matches, event=job.event)
|
_handle_transaction(trans, matches, regex_match_to_slug, event=job.event)
|
||||||
else:
|
else:
|
||||||
_handle_transaction(trans, matches, organizer=job.organizer)
|
_handle_transaction(trans, matches, regex_match_to_slug, organizer=job.organizer)
|
||||||
else:
|
else:
|
||||||
trans.state = BankTransaction.STATE_NOMATCH
|
trans.state = BankTransaction.STATE_NOMATCH
|
||||||
trans.save()
|
trans.save()
|
||||||
|
|||||||
@@ -385,6 +385,20 @@ def test_mark_paid_organizer_dash_in_slug(env, orga_job):
|
|||||||
assert env[2].status == Order.STATUS_PAID
|
assert env[2].status == Order.STATUS_PAID
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_mark_paid_organizer_dash_in_slug_missing(env, orga_job):
|
||||||
|
env[0].slug = "foo-bar"
|
||||||
|
env[0].save()
|
||||||
|
process_banktransfers(orga_job, [{
|
||||||
|
'payer': 'Karla Kundin',
|
||||||
|
'reference': 'Bestellung FOOBAR1234S',
|
||||||
|
'date': '2016-01-26',
|
||||||
|
'amount': '23.00'
|
||||||
|
}])
|
||||||
|
env[2].refresh_from_db()
|
||||||
|
assert env[2].status == Order.STATUS_PAID
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_mark_paid_organizer_varying_order_code_length(env, orga_job):
|
def test_mark_paid_organizer_varying_order_code_length(env, orga_job):
|
||||||
env[2].code = "123412341234"
|
env[2].code = "123412341234"
|
||||||
|
|||||||
Reference in New Issue
Block a user