diff --git a/src/pretix/plugins/banktransfer/api.py b/src/pretix/plugins/banktransfer/api.py index 8b682c96e5..8197f51410 100644 --- a/src/pretix/plugins/banktransfer/api.py +++ b/src/pretix/plugins/banktransfer/api.py @@ -26,7 +26,7 @@ from django.db.models import Q from django.utils.timezone import now from django_filters.rest_framework import DjangoFilterBackend, FilterSet from rest_framework import serializers, status, viewsets -from rest_framework.exceptions import PermissionDenied +from rest_framework.exceptions import PermissionDenied, ValidationError from rest_framework.mixins import CreateModelMixin from rest_framework.response import Response @@ -46,7 +46,7 @@ class BankTransactionSerializer(serializers.ModelSerializer): class Meta: model = BankTransaction fields = ('state', 'message', 'checksum', 'payer', 'reference', 'amount', 'date', 'order', - 'comment', 'iban', 'bic') + 'comment', 'iban', 'bic', 'currency') class BankImportJobSerializer(serializers.ModelSerializer): @@ -57,7 +57,7 @@ class BankImportJobSerializer(serializers.ModelSerializer): class Meta: model = BankImportJob - fields = ('id', 'event', 'created', 'state', 'transactions') + fields = ('id', 'event', 'created', 'state', 'transactions', 'currency') def __init__(self, *args, **kwargs): self.organizer = kwargs.pop('organizer') @@ -65,6 +65,18 @@ class BankImportJobSerializer(serializers.ModelSerializer): self.fields['event'].queryset = self.organizer.events.all() super().__init__(*args, **kwargs) + def validate(self, attrs): + if not attrs.get("event"): + if "currency" not in attrs: + currencies = list( + self.organizer.events.order_by('currency').values_list('currency', flat=True).distinct() + ) + if len(currencies) != 1: + raise ValidationError({"currency": ["Currency is ambiguous, please set explicitly."]}) + else: + attrs["currency"] = currencies[0] + return attrs + def create(self, validated_data): trans_data = validated_data.pop('transactions') job = BankImportJob.objects.create(organizer=self.organizer, **validated_data) diff --git a/src/pretix/plugins/banktransfer/migrations/0009_banktransaction_currency.py b/src/pretix/plugins/banktransfer/migrations/0009_banktransaction_currency.py new file mode 100644 index 0000000000..1a878d840f --- /dev/null +++ b/src/pretix/plugins/banktransfer/migrations/0009_banktransaction_currency.py @@ -0,0 +1,81 @@ +# Generated by Django 3.2.18 on 2023-03-22 13:10 + +from django.db import migrations, models +from django.db.models import Q +from django_scopes import scopes_disabled + +from pretix.base.models import Event + + +@scopes_disabled() +def set_currency(apps, schema_editor): + BankTransaction = apps.get_model('banktransfer', 'BankTransaction') + + for row in BankTransaction.objects.order_by('organizer', 'event').values('organizer', 'event', + 'order__event').distinct(): + if row['event'] or row['order__event']: + currency = Event.objects.get(pk=row['event'] or row['order__event']).currency + BankTransaction.objects.filter( + Q(event_id=row['event'] or row['order__event']) | Q( + order__event_id=row['event'] or row['order__event']), + organizer_id=row['organizer'], + ).update( + currency=currency + ) + else: + currencies = list( + Event.objects.filter(organizer_id=row['organizer']).order_by('currency').values_list('currency', + flat=True).distinct()) + if len(currencies) == 1: + BankTransaction.objects.filter( + organizer_id=row['organizer'], + ).update( + currency=currencies[0] + ) + + RefundExport = apps.get_model('banktransfer', 'RefundExport') + + for row in RefundExport.objects.order_by('organizer', 'event').values('organizer', 'event').distinct(): + if row['event']: + currency = Event.objects.get(pk=row['event']).currency + RefundExport.objects.filter( + event_id=row['event'], + organizer_id=row['organizer'], + ).update( + currency=currency + ) + else: + currencies = list( + Event.objects.filter(organizer_id=row['organizer']).order_by('currency').values_list('currency', flat=True).distinct() + ) + if len(currencies) == 1: + RefundExport.objects.filter( + organizer_id=row['organizer'], + ).update( + currency=currencies[0] + ) + + +class Migration(migrations.Migration): + dependencies = [ + ('banktransfer', '0008_alter_banktransaction_amount'), + ] + + operations = [ + migrations.AddField( + model_name='banktransaction', + name='currency', + field=models.CharField(max_length=10, null=True), + ), + migrations.AddField( + model_name='bankimportjob', + name='currency', + field=models.CharField(max_length=10, null=True), + ), + migrations.AddField( + model_name='refundexport', + name='currency', + field=models.CharField(max_length=10, null=True), + ), + migrations.RunPython(set_currency, migrations.RunPython.noop), + ] diff --git a/src/pretix/plugins/banktransfer/models.py b/src/pretix/plugins/banktransfer/models.py index fe4830c848..c034fb0357 100644 --- a/src/pretix/plugins/banktransfer/models.py +++ b/src/pretix/plugins/banktransfer/models.py @@ -42,6 +42,7 @@ class BankImportJob(models.Model): event = models.ForeignKey('pretixbase.Event', null=True, on_delete=models.CASCADE) organizer = models.ForeignKey('pretixbase.Organizer', null=True, on_delete=models.CASCADE) + currency = models.CharField(max_length=10, null=True) created = models.DateTimeField(auto_now_add=True) state = models.CharField(max_length=32, choices=STATES, default=STATE_PENDING) @@ -78,6 +79,7 @@ class BankTransaction(models.Model): event = models.ForeignKey('pretixbase.Event', null=True, on_delete=models.CASCADE) organizer = models.ForeignKey('pretixbase.Organizer', null=True, on_delete=models.CASCADE) import_job = models.ForeignKey('BankImportJob', related_name='transactions', on_delete=models.CASCADE) + currency = models.CharField(max_length=10, null=True) state = models.CharField(max_length=32, choices=STATES, default=STATE_UNCHECKED) message = models.TextField() checksum = models.CharField(max_length=190, db_index=True) @@ -112,6 +114,7 @@ class BankTransaction(models.Model): class RefundExport(models.Model): event = models.ForeignKey('pretixbase.Event', related_name='banktransfer_refund_exports', on_delete=models.CASCADE, null=True, blank=True) organizer = models.ForeignKey('pretixbase.Organizer', related_name='banktransfer_refund_exports', on_delete=models.PROTECT, null=True, blank=True) + currency = models.CharField(max_length=10, null=True) datetime = models.DateTimeField(auto_now_add=True) testmode = models.BooleanField(default=False) rows = models.TextField(default="[]") @@ -124,12 +127,6 @@ class RefundExport(models.Model): else: return self.event.slug - @cached_property - def currency(self): - if self.event: - return self.event.currency - return self.organizer.events.first().currency - @property def rows_data(self): return json.loads(self.rows) diff --git a/src/pretix/plugins/banktransfer/tasks.py b/src/pretix/plugins/banktransfer/tasks.py index 36a5f17cc2..75877576c2 100644 --- a/src/pretix/plugins/banktransfer/tasks.py +++ b/src/pretix/plugins/banktransfer/tasks.py @@ -171,6 +171,12 @@ def _handle_transaction(trans: BankTransaction, matches: tuple, event: Event = N trans.save() return + if trans.currency is not None and trans.currency != o.event.currency: + trans.state = BankTransaction.STATE_ERROR + trans.message = gettext_noop('Currencies do not match.') + trans.save() + return + if len(orders) > 1: # Multi-match! Can we split this automatically? order_pending_sum = sum(o.pending_sum for o in orders) @@ -280,7 +286,8 @@ def _get_unknown_transactions(job: BankImportJob, data: list, event: Event = Non payer=row.get('payer', ''), reference=row.get('reference', ''), amount=amount, date=row.get('date', ''), - iban=row.get('iban', ''), bic=row.get('bic', '')) + iban=row.get('iban', ''), bic=row.get('bic', ''), + currency=event.currency if event else job.currency) trans.date_parsed = parse_date(trans.date) diff --git a/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_assign.html b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_assign.html index 91c8d58530..3734e1e63b 100644 --- a/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_assign.html +++ b/src/pretix/plugins/banktransfer/templates/pretixplugins/banktransfer/import_assign.html @@ -99,6 +99,9 @@ + {% if "currency" in request.POST %} + + {% endif %}